Bug 1576593 - P2 - Change the way for tunneling quota information to SQLite; r=janv

Differential Revision: https://phabricator.services.mozilla.com/D48183

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Tom Tung 2019-10-25 12:02:10 +00:00
Родитель 20f43c02f7
Коммит a973874d9b
11 изменённых файлов: 226 добавлений и 116 удалений

4
dom/cache/Context.cpp поставляемый
Просмотреть файл

@ -233,11 +233,15 @@ void Context::QuotaInitRunnable::OpenDirectory() {
void Context::QuotaInitRunnable::DirectoryLockAcquired(DirectoryLock* aLock) {
NS_ASSERT_OWNINGTHREAD(QuotaInitRunnable);
MOZ_DIAGNOSTIC_ASSERT(aLock);
MOZ_DIAGNOSTIC_ASSERT(mState == STATE_WAIT_FOR_DIRECTORY_LOCK);
MOZ_DIAGNOSTIC_ASSERT(!mDirectoryLock);
mDirectoryLock = aLock;
MOZ_DIAGNOSTIC_ASSERT(mDirectoryLock->GetId() >= 0);
mQuotaInfo.mDirectoryLockId = mDirectoryLock->GetId();
if (mCanceled) {
Complete(NS_ERROR_ABORT);
return;

22
dom/cache/DBAction.cpp поставляемый
Просмотреть файл

@ -27,6 +27,7 @@ namespace cache {
using mozilla::dom::quota::AssertIsOnIOThread;
using mozilla::dom::quota::Client;
using mozilla::dom::quota::IntCString;
using mozilla::dom::quota::PERSISTENCE_TYPE_DEFAULT;
using mozilla::dom::quota::PersistenceType;
@ -123,6 +124,7 @@ void DBAction::RunOnTarget(Resolver* aResolver, const QuotaInfo& aQuotaInfo,
nsresult DBAction::OpenConnection(const QuotaInfo& aQuotaInfo, nsIFile* aDBDir,
mozIStorageConnection** aConnOut) {
MOZ_ASSERT(!NS_IsMainThread());
MOZ_DIAGNOSTIC_ASSERT(aQuotaInfo.mDirectoryLockId >= 0);
MOZ_DIAGNOSTIC_ASSERT(aDBDir);
MOZ_DIAGNOSTIC_ASSERT(aConnOut);
@ -168,6 +170,7 @@ void SyncDBAction::RunWithDBOnTarget(Resolver* aResolver,
nsresult OpenDBConnection(const QuotaInfo& aQuotaInfo, nsIFile* aDBDir,
mozIStorageConnection** aConnOut) {
MOZ_ASSERT(!NS_IsMainThread());
MOZ_DIAGNOSTIC_ASSERT(aQuotaInfo.mDirectoryLockId >= -1);
MOZ_DIAGNOSTIC_ASSERT(aDBDir);
MOZ_DIAGNOSTIC_ASSERT(aConnOut);
@ -208,18 +211,15 @@ nsresult OpenDBConnection(const QuotaInfo& aQuotaInfo, nsIFile* aDBDir,
nsCOMPtr<nsIFileURL> dbFileUrl;
nsAutoCString type;
PersistenceTypeToText(PERSISTENCE_TYPE_DEFAULT, type);
const nsCString directoryLockIdClause =
aQuotaInfo.mDirectoryLockId >= 0
? NS_LITERAL_CSTRING("&directoryLockId=") +
IntCString(aQuotaInfo.mDirectoryLockId)
: EmptyCString();
nsAutoCString clientType;
Client::TypeToText(Client::DOMCACHE, clientType);
rv = NS_MutateURI(mutator)
.SetQuery(NS_LITERAL_CSTRING("persistenceType=") + type +
NS_LITERAL_CSTRING("&group=") + aQuotaInfo.mGroup +
NS_LITERAL_CSTRING("&origin=") + aQuotaInfo.mOrigin +
NS_LITERAL_CSTRING("&clientType=") + clientType +
NS_LITERAL_CSTRING("&cache=private"))
rv =
NS_MutateURI(mutator)
.SetQuery(NS_LITERAL_CSTRING("cache=private") + directoryLockIdClause)
.Finalize(dbFileUrl);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;

2
dom/cache/DBAction.h поставляемый
Просмотреть файл

@ -40,7 +40,7 @@ class DBAction : public Action {
mozIStorageConnection* aConn) = 0;
private:
virtual void RunOnTarget(Resolver* aResolver, const QuotaInfo& aQuotaInfo,
void RunOnTarget(Resolver* aResolver, const QuotaInfo& aQuotaInfo,
Data* aOptionalData) override;
nsresult OpenConnection(const QuotaInfo& aQuotaInfo, nsIFile* aQuotaDir,

2
dom/cache/Manager.cpp поставляемый
Просмотреть файл

@ -148,7 +148,7 @@ class DeleteOrphanedBodyAction final : public Action {
mDeletedBodyIdList.AppendElement(aBodyId);
}
virtual void RunOnTarget(Resolver* aResolver, const QuotaInfo& aQuotaInfo,
void RunOnTarget(Resolver* aResolver, const QuotaInfo& aQuotaInfo,
Data*) override {
MOZ_DIAGNOSTIC_ASSERT(aResolver);
MOZ_DIAGNOSTIC_ASSERT(aQuotaInfo.mDir);

18
dom/cache/QuotaClient.cpp поставляемый
Просмотреть файл

@ -115,6 +115,11 @@ static nsresult LockedGetPaddingSizeFromDB(nsIFile* aDir,
QuotaInfo quotaInfo;
quotaInfo.mGroup = aGroup;
quotaInfo.mOrigin = aOrigin;
// This should only be called during the temporary storage is initializing.
// And at that moment, we haven't constructed in-memory objects
// (e.g. QuotaObject) yet. So, passing a specific id to not get a QuotaObject
// on the TelemetryVFS.
MOZ_DIAGNOSTIC_ASSERT(quotaInfo.mDirectoryLockId == -1);
nsresult rv = mozilla::dom::cache::OpenDBConnection(quotaInfo, aDir,
getter_AddRefs(conn));
if (rv == NS_ERROR_FILE_NOT_FOUND ||
@ -432,12 +437,25 @@ class CacheQuotaClient final : public Client {
dir, DirPaddingFile::TMP_FILE) ||
NS_WARN_IF(NS_FAILED(mozilla::dom::cache::LockedDirectoryPaddingGet(
dir, &paddingSize)))) {
if (aInitializing) {
rv = LockedGetPaddingSizeFromDB(dir, aGroup, aOrigin, &paddingSize);
if (NS_WARN_IF(NS_FAILED(rv))) {
REPORT_TELEMETRY_ERR_IN_INIT(aInitializing, kQuotaInternalError,
Cache_GetPaddingSize);
return rv;
}
} else {
// XXXtt This should be handled in a better way.
// If there is no another action/operation for Cache on other threads,
// it means the previous action failed. And we should be safe to get
// the padding size from the database.
// However, if there is other actions access the files on Cache IO
// thread, then we shouldn't touch the file here.
REPORT_TELEMETRY_ERR_IN_INIT(aInitializing, kQuotaInternalError,
Cache_GetPaddingSize);
return NS_ERROR_ABORT;
}
}
}

3
dom/cache/Types.h поставляемый
Просмотреть файл

@ -33,6 +33,9 @@ struct QuotaInfo {
nsCString mSuffix;
nsCString mGroup;
nsCString mOrigin;
int64_t mDirectoryLockId;
QuotaInfo() : mDirectoryLockId(-1) {}
};
typedef std::function<void(nsCOMPtr<nsIInputStream>&&)> InputStreamResolver;

Просмотреть файл

@ -3898,9 +3898,7 @@ nsresult UpgradeSchemaFrom25_0To26_0(mozIStorageConnection* aConnection) {
return NS_OK;
}
nsresult GetDatabaseFileURL(nsIFile* aDatabaseFile,
PersistenceType aPersistenceType,
const nsACString& aGroup, const nsACString& aOrigin,
nsresult GetDatabaseFileURL(nsIFile* aDatabaseFile, int64_t aDirectoryLockId,
uint32_t aTelemetryId, nsIFileURL** aResult) {
MOZ_ASSERT(aDatabaseFile);
MOZ_ASSERT(aResult);
@ -3927,11 +3925,14 @@ nsresult GetDatabaseFileURL(nsIFile* aDatabaseFile,
nsCOMPtr<nsIFileURL> fileUrl;
nsAutoCString type;
PersistenceTypeToText(aPersistenceType, type);
nsAutoCString clientType;
Client::TypeToText(Client::IDB, clientType);
// The aDirectoryLock should only be a nullptr when the temporary storage
// hasn't been initialized. At that time, we don't have in-memory objects
// (e.g. originInfo) so that it doesn't make sense to tunnel the
// directoryLockId to TelemetryVFS to get the quotaObject.
const nsCString directoryLockIdClause =
aDirectoryLockId >= 0 ? NS_LITERAL_CSTRING("&directoryLockId=") +
IntCString(aDirectoryLockId)
: EmptyCString();
nsAutoCString telemetryFilenameClause;
if (aTelemetryId) {
@ -3941,12 +3942,8 @@ nsresult GetDatabaseFileURL(nsIFile* aDatabaseFile,
}
rv = NS_MutateURI(mutator)
.SetQuery(NS_LITERAL_CSTRING("persistenceType=") + type +
NS_LITERAL_CSTRING("&group=") + aGroup +
NS_LITERAL_CSTRING("&origin=") + aOrigin +
NS_LITERAL_CSTRING("&clientType=") + clientType +
NS_LITERAL_CSTRING("&cache=private") +
telemetryFilenameClause)
.SetQuery(NS_LITERAL_CSTRING("cache=private") +
directoryLockIdClause + telemetryFilenameClause)
.Finalize(fileUrl);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
@ -4167,14 +4164,14 @@ nsresult OpenDatabaseAndHandleBusy(mozIStorageService* aStorageService,
nsresult CreateStorageConnection(nsIFile* aDBFile, nsIFile* aFMDirectory,
const nsAString& aName,
PersistenceType aPersistenceType,
const nsACString& aGroup,
const nsACString& aOrigin,
int64_t aDirectoryLockId,
uint32_t aTelemetryId,
mozIStorageConnection** aConnection) {
AssertIsOnIOThread();
MOZ_ASSERT(aDBFile);
MOZ_ASSERT(aFMDirectory);
MOZ_ASSERT(aDirectoryLockId >= -1);
MOZ_ASSERT(aConnection);
AUTO_PROFILER_LABEL("CreateStorageConnection", DOM);
@ -4183,8 +4180,8 @@ nsresult CreateStorageConnection(nsIFile* aDBFile, nsIFile* aFMDirectory,
bool exists;
nsCOMPtr<nsIFileURL> dbFileUrl;
rv = GetDatabaseFileURL(aDBFile, aPersistenceType, aGroup, aOrigin,
aTelemetryId, getter_AddRefs(dbFileUrl));
rv = GetDatabaseFileURL(aDBFile, aDirectoryLockId, aTelemetryId,
getter_AddRefs(dbFileUrl));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -4629,14 +4626,13 @@ already_AddRefed<nsIFile> GetFileForPath(const nsAString& aPath) {
return file.forget();
}
nsresult GetStorageConnection(nsIFile* aDatabaseFile,
PersistenceType aPersistenceType,
const nsACString& aGroup,
const nsACString& aOrigin, uint32_t aTelemetryId,
nsresult GetStorageConnection(nsIFile* aDatabaseFile, int64_t aDirectoryLockId,
uint32_t aTelemetryId,
mozIStorageConnection** aConnection) {
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(!IsOnBackgroundThread());
MOZ_ASSERT(aDatabaseFile);
MOZ_ASSERT(aDirectoryLockId >= 0);
MOZ_ASSERT(aConnection);
AUTO_PROFILER_LABEL("GetStorageConnection", DOM);
@ -4653,8 +4649,8 @@ nsresult GetStorageConnection(nsIFile* aDatabaseFile,
}
nsCOMPtr<nsIFileURL> dbFileUrl;
rv = GetDatabaseFileURL(aDatabaseFile, aPersistenceType, aGroup, aOrigin,
aTelemetryId, getter_AddRefs(dbFileUrl));
rv = GetDatabaseFileURL(aDatabaseFile, aDirectoryLockId, aTelemetryId,
getter_AddRefs(dbFileUrl));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -4686,14 +4682,13 @@ nsresult GetStorageConnection(nsIFile* aDatabaseFile,
}
nsresult GetStorageConnection(const nsAString& aDatabaseFilePath,
PersistenceType aPersistenceType,
const nsACString& aGroup,
const nsACString& aOrigin, uint32_t aTelemetryId,
int64_t aDirectoryLockId, uint32_t aTelemetryId,
mozIStorageConnection** aConnection) {
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(!IsOnBackgroundThread());
MOZ_ASSERT(!aDatabaseFilePath.IsEmpty());
MOZ_ASSERT(StringEndsWith(aDatabaseFilePath, kSQLiteSuffix));
MOZ_ASSERT(aDirectoryLockId >= 0);
MOZ_ASSERT(aConnection);
nsCOMPtr<nsIFile> dbFile = GetFileForPath(aDatabaseFilePath);
@ -4702,8 +4697,8 @@ nsresult GetStorageConnection(const nsAString& aDatabaseFilePath,
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
return GetStorageConnection(dbFile, aPersistenceType, aGroup, aOrigin,
aTelemetryId, aConnection);
return GetStorageConnection(dbFile, aDirectoryLockId, aTelemetryId,
aConnection);
}
/*******************************************************************************
@ -5796,6 +5791,7 @@ class Database final
const nsCString mId;
const nsString mFilePath;
uint32_t mActiveMutableFileCount;
int64_t mDirectoryLockId;
const uint32_t mTelemetryId;
const PersistenceType mPersistenceType;
const bool mFileHandleDisabled;
@ -5846,6 +5842,8 @@ class Database final
const nsCString& Id() const { return mId; }
int64_t DirectoryLockId() const { return mDirectoryLockId; }
uint32_t TelemetryId() const { return mTelemetryId; }
PersistenceType Type() const { return mPersistenceType; }
@ -6672,6 +6670,7 @@ class FactoryOp
nsCString mOrigin;
nsCString mDatabaseId;
nsString mDatabaseFilePath;
int64_t mDirectoryLockId;
State mState;
bool mWaitingForPermissionRetry;
bool mEnforcingQuota;
@ -8333,6 +8332,7 @@ class DatabaseMaintenance final : public Runnable {
const nsCString mGroup;
const nsCString mOrigin;
const nsString mDatabasePath;
int64_t mDirectoryLockId;
nsCOMPtr<nsIRunnable> mCompleteCallback;
const PersistenceType mPersistenceType;
@ -8346,7 +8346,12 @@ class DatabaseMaintenance final : public Runnable {
mGroup(aGroup),
mOrigin(aOrigin),
mDatabasePath(aDatabasePath),
mPersistenceType(aPersistenceType) {}
mPersistenceType(aPersistenceType) {
MOZ_ASSERT(aDirectoryLock);
MOZ_ASSERT(mDirectoryLock->GetId() >= 0);
mDirectoryLockId = mDirectoryLock->GetId();
}
const nsString& DatabasePath() const { return mDatabasePath; }
@ -10910,10 +10915,9 @@ nsresult ConnectionPool::GetOrCreateConnection(
MOZ_ASSERT(!dbInfo->mDEBUGConnectionThread);
nsCOMPtr<mozIStorageConnection> storageConnection;
nsresult rv = GetStorageConnection(aDatabase->FilePath(), aDatabase->Type(),
aDatabase->Group(), aDatabase->Origin(),
aDatabase->TelemetryId(),
getter_AddRefs(storageConnection));
nsresult rv = GetStorageConnection(
aDatabase->FilePath(), aDatabase->DirectoryLockId(),
aDatabase->TelemetryId(), getter_AddRefs(storageConnection));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -12598,6 +12602,10 @@ Database::Database(Factory* aFactory, const PrincipalInfo& aPrincipalInfo,
MOZ_ASSERT(aFileManager);
MOZ_ASSERT_IF(aChromeWriteAccessAllowed,
aPrincipalInfo.type() == PrincipalInfo::TSystemPrincipalInfo);
MOZ_ASSERT(mDirectoryLock);
MOZ_ASSERT(mDirectoryLock->GetId() >= 0);
mDirectoryLockId = mDirectoryLock->GetId();
}
void Database::Invalidate() {
@ -15614,8 +15622,6 @@ already_AddRefed<nsIFile> FileManager::GetCheckedFileForId(nsIFile* aDirectory,
// static
nsresult FileManager::InitDirectory(nsIFile* aDirectory, nsIFile* aDatabaseFile,
PersistenceType aPersistenceType,
const nsACString& aGroup,
const nsACString& aOrigin,
uint32_t aTelemetryId) {
AssertIsOnIOThread();
@ -15683,7 +15689,7 @@ nsresult FileManager::InitDirectory(nsIFile* aDirectory, nsIFile* aDatabaseFile,
if (hasElements) {
nsCOMPtr<mozIStorageConnection> connection;
rv = CreateStorageConnection(aDatabaseFile, aDirectory, VoidString(),
aPersistenceType, aGroup, aOrigin,
aOrigin, /* aDirectoryLockId */ -1,
aTelemetryId, getter_AddRefs(connection));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
@ -16224,8 +16230,7 @@ nsresult QuotaClient::InitOrigin(PersistenceType aPersistenceType,
}
}
rv = FileManager::InitDirectory(fmDirectory, databaseFile, aPersistenceType,
aGroup, aOrigin,
rv = FileManager::InitDirectory(fmDirectory, databaseFile, aOrigin,
TelemetryIdForFile(databaseFile));
if (NS_WARN_IF(NS_FAILED(rv))) {
REPORT_TELEMETRY_INIT_ERR(kQuotaInternalError, IDB_InitDirectory);
@ -17612,8 +17617,8 @@ void DatabaseMaintenance::PerformMaintenanceOnDatabase() {
MOZ_ASSERT(databaseFile);
nsCOMPtr<mozIStorageConnection> connection;
nsresult rv = GetStorageConnection(databaseFile, mPersistenceType, mGroup,
mOrigin, TelemetryIdForFile(databaseFile),
nsresult rv = GetStorageConnection(databaseFile, mDirectoryLockId,
TelemetryIdForFile(databaseFile),
getter_AddRefs(connection));
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
@ -19294,6 +19299,7 @@ FactoryOp::FactoryOp(Factory* aFactory,
mFactory(aFactory),
mContentParent(std::move(aContentParent)),
mCommonParams(aCommonParams),
mDirectoryLockId(-1),
mState(State::Initial),
mWaitingForPermissionRetry(false),
mEnforcingQuota(true),
@ -20042,11 +20048,15 @@ FactoryOp::Run() {
void FactoryOp::DirectoryLockAcquired(DirectoryLock* aLock) {
AssertIsOnOwningThread();
MOZ_ASSERT(aLock);
MOZ_ASSERT(mState == State::DirectoryOpenPending);
MOZ_ASSERT(!mDirectoryLock);
mDirectoryLock = aLock;
MOZ_ASSERT(mDirectoryLock->GetId() >= 0);
mDirectoryLockId = mDirectoryLock->GetId();
nsresult rv = DirectoryOpen();
if (NS_WARN_IF(NS_FAILED(rv))) {
if (NS_SUCCEEDED(mResultCode)) {
@ -20267,8 +20277,8 @@ nsresult OpenDatabaseOp::DoDatabaseWork() {
}
nsCOMPtr<mozIStorageConnection> connection;
rv = CreateStorageConnection(dbFile, fmDirectory, databaseName,
persistenceType, mGroup, mOrigin, mTelemetryId,
rv = CreateStorageConnection(dbFile, fmDirectory, databaseName, mOrigin,
mDirectoryLockId, mTelemetryId,
getter_AddRefs(connection));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;

Просмотреть файл

@ -52,8 +52,6 @@ class FileManager final {
int64_t aId);
static nsresult InitDirectory(nsIFile* aDirectory, nsIFile* aDatabaseFile,
PersistenceType aPersistenceType,
const nsACString& aGroup,
const nsACString& aOrigin,
uint32_t aTelemetryId);

Просмотреть файл

@ -221,6 +221,8 @@ const char kProfileDoChangeTopic[] = "profile-do-change";
const int32_t kCacheVersion = 1;
const int64_t kBypassDirectoryLockIdTableId = -1;
/******************************************************************************
* SQLite functions
******************************************************************************/
@ -671,6 +673,8 @@ class DirectoryLockImpl final : public DirectoryLock {
nsTArray<DirectoryLockImpl*> mBlocking;
nsTArray<DirectoryLockImpl*> mBlockedOn;
const int64_t mId;
const bool mExclusive;
// Internal quota manager operations use this flag to prevent directory lock
@ -685,7 +689,8 @@ class DirectoryLockImpl final : public DirectoryLock {
const Nullable<PersistenceType>& aPersistenceType,
const nsACString& aGroup, const OriginScope& aOriginScope,
const Nullable<Client::Type>& aClientType, bool aExclusive,
bool aInternal, OpenDirectoryListener* aOpenListener);
bool aInternal, OpenDirectoryListener* aOpenListener,
const int64_t aDirectoryLockId);
void AssertIsOnOwningThread() const
#ifdef DEBUG
@ -703,10 +708,26 @@ class DirectoryLockImpl final : public DirectoryLock {
const OriginScope& GetOriginScope() const { return mOriginScope; }
const nsACString& GetOrigin() const {
MOZ_DIAGNOSTIC_ASSERT(GetOriginScope().IsOrigin());
return mOriginScope.GetOrigin();
}
const Nullable<Client::Type>& GetClientType() const { return mClientType; }
int64_t GetId() const { return mId; }
bool IsInternal() const { return mInternal; }
// To evict inactive oirigins, we need to register directorylocks for that.
// However, since accessing the QuotaMnaager::mDirectoryLockIdTable
// require to acquire the mQuotaMutex and so does the accessing the
// originInfo. Therefore, we decide not to access the
// QuotaManager::mDirectoryLockIdTable for the internal DirectoryLock.
bool ShouldUpdateLockIdTable() const {
return mId != kBypassDirectoryLockIdTableId;
}
void SetRegistered(bool aRegistered) { mRegistered = aRegistered; }
bool ShouldUpdateLockTable() {
@ -2684,6 +2705,14 @@ bool RecvShutdownQuotaManager() {
* Directory lock
******************************************************************************/
const nsACString& DirectoryLock::GetOrigin() const {
return GetDirectoryLockImpl(this)->GetOrigin();
}
int64_t DirectoryLock::GetId() const {
return GetDirectoryLockImpl(this)->GetId();
}
already_AddRefed<DirectoryLock> DirectoryLock::Specialize(
PersistenceType aPersistenceType, const nsACString& aGroup,
const nsACString& aOrigin, Client::Type aClientType) const {
@ -2697,13 +2726,15 @@ DirectoryLockImpl::DirectoryLockImpl(
QuotaManager* aQuotaManager,
const Nullable<PersistenceType>& aPersistenceType, const nsACString& aGroup,
const OriginScope& aOriginScope, const Nullable<Client::Type>& aClientType,
bool aExclusive, bool aInternal, OpenDirectoryListener* aOpenListener)
bool aExclusive, bool aInternal, OpenDirectoryListener* aOpenListener,
const int64_t aId)
: mQuotaManager(aQuotaManager),
mPersistenceType(aPersistenceType),
mGroup(aGroup),
mOriginScope(aOriginScope),
mClientType(aClientType),
mOpenListener(aOpenListener),
mId(aId),
mExclusive(aExclusive),
mInternal(aInternal),
mRegistered(false),
@ -2811,6 +2842,7 @@ already_AddRefed<DirectoryLock> DirectoryLockImpl::Specialize(
MOZ_ASSERT(aClientType < Client::TypeMax());
MOZ_ASSERT(!mOpenListener);
MOZ_ASSERT(mBlockedOn.IsEmpty());
MOZ_ASSERT(mQuotaManager);
if (NS_WARN_IF(mExclusive)) {
return nullptr;
@ -2819,7 +2851,8 @@ already_AddRefed<DirectoryLock> DirectoryLockImpl::Specialize(
RefPtr<DirectoryLockImpl> lock = new DirectoryLockImpl(
mQuotaManager, Nullable<PersistenceType>(aPersistenceType), aGroup,
OriginScope::FromOrigin(aOrigin), Nullable<Client::Type>(aClientType),
/* aExclusive */ false, mInternal, /* aOpenListener */ nullptr);
/* aExclusive */ false, mInternal, /* aOpenListener */ nullptr,
mQuotaManager->GenerateDirectoryLockId());
if (NS_WARN_IF(!Overlaps(*lock))) {
return nullptr;
@ -3425,6 +3458,7 @@ QuotaManager::QuotaManager()
: mQuotaMutex("QuotaManager.mQuotaMutex"),
mTemporaryStorageLimit(0),
mTemporaryStorageUsage(0),
mNextDirectoryLockId(0),
mTemporaryStorageInitialized(false),
mCacheUsable(false) {
AssertIsOnOwningThread();
@ -3532,9 +3566,9 @@ auto QuotaManager::CreateDirectoryLock(
MOZ_ASSERT_IF(!aInternal, aClientType.Value() < Client::TypeMax());
MOZ_ASSERT_IF(!aInternal, aOpenListener);
RefPtr<DirectoryLockImpl> lock =
new DirectoryLockImpl(this, aPersistenceType, aGroup, aOriginScope,
aClientType, aExclusive, aInternal, aOpenListener);
RefPtr<DirectoryLockImpl> lock = new DirectoryLockImpl(
this, aPersistenceType, aGroup, aOriginScope, aClientType, aExclusive,
aInternal, aOpenListener, GenerateDirectoryLockId());
mPendingDirectoryLocks.AppendElement(lock);
@ -3570,7 +3604,8 @@ auto QuotaManager::CreateDirectoryLockForEviction(
this, Nullable<PersistenceType>(aPersistenceType), aGroup,
OriginScope::FromOrigin(aOrigin), Nullable<Client::Type>(),
/* aExclusive */ true,
/* aInternal */ true, nullptr);
/* aInternal */ true, nullptr, /* aDirectoryLockId */
kBypassDirectoryLockIdTableId);
#ifdef DEBUG
for (uint32_t index = mDirectoryLocks.Length(); index > 0; index--) {
@ -3590,6 +3625,12 @@ void QuotaManager::RegisterDirectoryLock(DirectoryLockImpl* aLock) {
mDirectoryLocks.AppendElement(aLock);
if (aLock->ShouldUpdateLockIdTable()) {
MutexAutoLock lock(mQuotaMutex);
mDirectoryLockIdTable.Put(aLock->GetId(), aLock);
}
if (aLock->ShouldUpdateLockTable()) {
const Nullable<PersistenceType>& persistenceType =
aLock->GetPersistenceType();
@ -3621,9 +3662,17 @@ void QuotaManager::RegisterDirectoryLock(DirectoryLockImpl* aLock) {
void QuotaManager::UnregisterDirectoryLock(DirectoryLockImpl* aLock) {
AssertIsOnOwningThread();
MOZ_ASSERT(aLock);
MOZ_ALWAYS_TRUE(mDirectoryLocks.RemoveElement(aLock));
if (aLock->ShouldUpdateLockIdTable()) {
MutexAutoLock lock(mQuotaMutex);
MOZ_DIAGNOSTIC_ASSERT(mDirectoryLockIdTable.Get(aLock->GetId()));
mDirectoryLockIdTable.Remove(aLock->GetId());
}
if (aLock->ShouldUpdateLockTable()) {
const Nullable<PersistenceType>& persistenceType =
aLock->GetPersistenceType();
@ -4646,6 +4695,36 @@ already_AddRefed<QuotaObject> QuotaManager::GetQuotaObject(
aFileSize, aFileSizeOut);
}
already_AddRefed<QuotaObject> QuotaManager::GetQuotaObject(
const int64_t aDirectoryLockId, const nsAString& aPath) {
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
MOZ_DIAGNOSTIC_ASSERT(aDirectoryLockId != kBypassDirectoryLockIdTableId);
Maybe<MutexAutoLock> lock;
if (!IsOnBackgroundThread()) {
lock.emplace(mQuotaMutex);
}
DirectoryLockImpl* directoryLock;
if (!mDirectoryLockIdTable.Get(aDirectoryLockId, &directoryLock)) {
MOZ_CRASH("Getting quota object for an unregistered directory lock?");
}
MOZ_DIAGNOSTIC_ASSERT(directoryLock);
MOZ_DIAGNOSTIC_ASSERT(!directoryLock->GetPersistenceType().IsNull());
PersistenceType persistenceType = directoryLock->GetPersistenceType().Value();
nsCString group(directoryLock->GetGroup());
nsCString origin(directoryLock->GetOrigin());
MOZ_DIAGNOSTIC_ASSERT(!directoryLock->GetClientType().IsNull());
Client::Type clientType = directoryLock->GetClientType().Value();
lock.reset();
return GetQuotaObject(persistenceType, group, origin, clientType, aPath);
}
Nullable<bool> QuotaManager::OriginPersisted(const nsACString& aGroup,
const nsACString& aOrigin) {
AssertIsOnIOThread();
@ -7600,6 +7679,22 @@ bool QuotaManager::IsSanitizedOriginValid(const nsACString& aSanitizedOrigin) {
return valid;
}
int64_t QuotaManager::GenerateDirectoryLockId() {
const int64_t directroylockId = mNextDirectoryLockId;
CheckedInt64 result = CheckedInt64(mNextDirectoryLockId) + 1;
if (result.isValid()) {
mNextDirectoryLockId = result.value();
} else {
// When this happens, it means we have run out of ids for directory locks.
// To avoid something unexpected happen and assuming there shouldn't have
// INT64_MAX directorylock exist at the same time, we reset the id here.
mNextDirectoryLockId = 0;
}
return directroylockId;
}
/*******************************************************************************
* Local class implementations
******************************************************************************/

Просмотреть файл

@ -63,6 +63,10 @@ class DirectoryLock : public RefCountedObject {
friend class DirectoryLockImpl;
public:
const nsACString& GetOrigin() const;
int64_t GetId() const;
already_AddRefed<DirectoryLock> Specialize(PersistenceType aPersistenceType,
const nsACString& aGroup,
const nsACString& aOrigin,
@ -232,6 +236,9 @@ class QuotaManager final : public BackgroundThreadObject {
int64_t aFileSize = -1,
int64_t* aFileSizeOut = nullptr);
already_AddRefed<QuotaObject> GetQuotaObject(const int64_t aDirectoryLockId,
const nsAString& aPath);
Nullable<bool> OriginPersisted(const nsACString& aGroup,
const nsACString& aOrigin);
@ -545,6 +552,8 @@ class QuotaManager final : public BackgroundThreadObject {
bool IsSanitizedOriginValid(const nsACString& aSanitizedOrigin);
int64_t GenerateDirectoryLockId();
static void ShutdownTimerCallback(nsITimer* aTimer, void* aClosure);
// Thread on which IO is performed.
@ -562,9 +571,16 @@ class QuotaManager final : public BackgroundThreadObject {
// Maintains a list of directory locks that are queued.
nsTArray<RefPtr<DirectoryLockImpl>> mPendingDirectoryLocks;
// Maintains a list of directory locks that are acquired or queued.
// Maintains a list of directory locks that are acquired or queued. It can be
// accessed on the owning (PBackground) thread only.
nsTArray<DirectoryLockImpl*> mDirectoryLocks;
// Only modifed on the owning thread, but read on multiple threads. Therefore
// all modifications (including those on the owning thread) and all reads off
// the owning thread must be protected by mQuotaMutex. In other words, only
// reads on the owning thread don't have to be protected by mQuotaMutex.
nsDataHashtable<nsUint64HashKey, DirectoryLockImpl*> mDirectoryLockIdTable;
// Directory lock tables that are used to update origin access time.
DirectoryLockTable mTemporaryDirectoryLockTable;
DirectoryLockTable mDefaultDirectoryLockTable;
@ -594,6 +610,7 @@ class QuotaManager final : public BackgroundThreadObject {
uint64_t mTemporaryStorageLimit;
uint64_t mTemporaryStorageUsage;
int64_t mNextDirectoryLockId;
bool mTemporaryStorageInitialized;
bool mCacheUsable;
};

Просмотреть файл

@ -299,56 +299,21 @@ already_AddRefed<QuotaObject> GetQuotaObjectFromNameAndParameters(
MOZ_ASSERT(zName);
MOZ_ASSERT(zURIParameterKey);
const char* persistenceType =
sqlite3_uri_parameter(zURIParameterKey, "persistenceType");
if (!persistenceType) {
const char* directoryLockIdParam =
sqlite3_uri_parameter(zURIParameterKey, "directoryLockId");
if (!directoryLockIdParam) {
return nullptr;
}
const char* group = sqlite3_uri_parameter(zURIParameterKey, "group");
if (!group) {
NS_WARNING("SQLite URI had 'persistenceType' but not 'group'?!");
return nullptr;
}
const char* origin = sqlite3_uri_parameter(zURIParameterKey, "origin");
if (!origin) {
NS_WARNING(
"SQLite URI had 'persistenceType' and 'group' but not "
"'origin'?!");
return nullptr;
}
const char* clientType =
sqlite3_uri_parameter(zURIParameterKey, "clientType");
if (!clientType) {
NS_WARNING(
"SQLite URI had 'persistenceType', 'group' and 'origin' but not "
"'clientType'?!");
return nullptr;
}
// Re-escape group and origin to make sure we get the right quota group and
// origin.
nsAutoCString escGroup;
nsresult rv =
NS_EscapeURL(nsDependentCString(group), esc_Query, escGroup, fallible);
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
nsAutoCString escOrigin;
rv = NS_EscapeURL(nsDependentCString(origin), esc_Query, escOrigin, fallible);
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
nsresult rv;
const int64_t directoryLockId =
nsDependentCString(directoryLockIdParam).ToInteger64(&rv);
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
QuotaManager* quotaManager = QuotaManager::Get();
MOZ_ASSERT(quotaManager);
return quotaManager->GetQuotaObject(
PersistenceTypeFromText(nsDependentCString(persistenceType)), escGroup,
escOrigin, Client::TypeFromText(nsDependentCString(clientType)),
return quotaManager->GetQuotaObject(directoryLockId,
NS_ConvertUTF8toUTF16(zName));
}