/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_dom_quota_quotamanager_h__ #define mozilla_dom_quota_quotamanager_h__ #include #include #include "Client.h" #include "ErrorList.h" #include "mozilla/AlreadyAddRefed.h" #include "mozilla/Assertions.h" #include "mozilla/InitializedOnce.h" #include "mozilla/MozPromise.h" #include "mozilla/Mutex.h" #include "mozilla/RefPtr.h" #include "mozilla/Result.h" #include "mozilla/ThreadBound.h" #include "mozilla/dom/Nullable.h" #include "mozilla/dom/ipc/IdType.h" #include "mozilla/dom/quota/Assertions.h" #include "mozilla/dom/quota/BackgroundThreadObject.h" #include "mozilla/dom/quota/CommonMetadata.h" #include "mozilla/dom/quota/DirectoryLockCategory.h" #include "mozilla/dom/quota/ForwardDecls.h" #include "mozilla/dom/quota/HashKeys.h" #include "mozilla/dom/quota/InitializationTypes.h" #include "mozilla/dom/quota/NotifyUtils.h" #include "mozilla/dom/quota/OriginOperationCallbacks.h" #include "mozilla/dom/quota/PersistenceType.h" #include "nsCOMPtr.h" #include "nsClassHashtable.h" #include "nsTHashMap.h" #include "nsDebug.h" #include "nsHashKeys.h" #include "nsISupports.h" #include "nsStringFwd.h" #include "nsTArray.h" #include "nsTStringRepr.h" #include "nscore.h" #include "prenv.h" #define GTEST_CLASS(testFixture, testName) testFixture##_##testName##_Test class mozIStorageConnection; class nsIEventTarget; class nsIFile; class nsIRunnable; class nsIThread; class nsITimer; namespace mozilla { class OriginAttributes; class OriginAttributesPattern; namespace ipc { class PrincipalInfo; } // namespace ipc } // namespace mozilla namespace mozilla::dom::quota { class CanonicalQuotaObject; class ClearDataOp; class ClearRequestBase; class ClientStorageScope; class ClientUsageArray; class ClientDirectoryLock; class ClientDirectoryLockHandle; class DirectoryLockImpl; class GroupInfo; class GroupInfoPair; class NormalOriginOperationBase; class OriginDirectoryLock; class OriginInfo; class OriginScope; class QuotaObject; class SaveOriginAccessTimeOp; class UniversalDirectoryLock; namespace test { class GTEST_CLASS(TestQuotaManagerAndShutdownFixture, ThumbnailPrivateIdentityTemporaryOriginCount); } class QuotaManager final : public BackgroundThreadObject { friend class CanonicalQuotaObject; friend class ClearDataOp; friend class ClearRequestBase; friend class ClearStorageOp; friend class DirectoryLockImpl; friend class FinalizeOriginEvictionOp; friend class GroupInfo; friend class InitOp; friend class InitializePersistentOriginOp; friend class InitializePersistentStorageOp; friend class InitializeTemporaryGroupOp; friend class InitializeTemporaryOriginOp; friend class InitTemporaryStorageOp; friend class ListCachedOriginsOp; friend class OriginInfo; friend class PersistOp; friend class SaveOriginAccessTimeOp; friend class ShutdownStorageOp; friend class test::GTEST_CLASS(TestQuotaManagerAndShutdownFixture, ThumbnailPrivateIdentityTemporaryOriginCount); friend class UniversalDirectoryLock; friend Result GetInfoFromValidatedPrincipalInfo( QuotaManager& aQuotaManager, const mozilla::ipc::PrincipalInfo& aPrincipalInfo); using PrincipalInfo = mozilla::ipc::PrincipalInfo; using DirectoryLockTable = nsClassHashtable>>; class Observer; public: using ClientDirectoryLockHandlePromise = MozPromise; QuotaManager(const nsAString& aBasePath, const nsAString& aStorageName); NS_INLINE_DECL_REFCOUNTING(QuotaManager) static nsresult Initialize(); static bool IsRunningXPCShellTests() { static bool kRunningXPCShellTests = !!PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR"); return kRunningXPCShellTests; } static bool IsRunningGTests() { static bool kRunningGTests = !!PR_GetEnv("MOZ_RUN_GTEST"); return kRunningGTests; } static const char kReplaceChars[]; static const char16_t kReplaceChars16[]; static Result>, nsresult> GetOrCreate(); static Result EnsureCreated(); // Returns a non-owning reference. static QuotaManager* Get(); // Use only in gtests! static nsIObserver* GetObserver(); /** * Ensures that all pending normal origin operations and their follow-up * events are processed and completed. * * This is useful in cases where operations are scheduled asynchronously * without a way to explicitly await their completion, and must be finalized * before continuing with further checks or logic. * * This method asserts that gtests are currently running and must not be used * outside of gtest code. */ static void ProcessPendingNormalOriginOperations(); // Returns true if we've begun the shutdown process. static bool IsShuttingDown(); static void ShutdownInstance(); // Use only in gtests! static void Reset(); static bool IsOSMetadata(const nsAString& aFileName); static bool IsDotFile(const nsAString& aFileName); void RegisterNormalOriginOp(NormalOriginOperationBase& aNormalOriginOp); void UnregisterNormalOriginOp(NormalOriginOperationBase& aNormalOriginOp); bool IsPersistentOriginInitializedInternal(const nsACString& aOrigin) const { AssertIsOnIOThread(); return mInitializedOriginsInternal.Contains(aOrigin); } bool IsTemporaryStorageInitializedInternal() const { AssertIsOnIOThread(); return mTemporaryStorageInitializedInternal; } /** * For initialization of an origin where the directory either exists or it * does not. The directory exists case is used by InitializeOrigin once it * has tallied origin usage by calling each of the QuotaClient InitOrigin * methods. It's also used by LoadQuota when quota information is available * from the cache. EnsureTemporaryStorageIsInitializedInternal calls this * either if the directory exists or it does not depending on requirements * of a particular quota client. The special case when origin directory is * not created during origin initialization is currently utilized only by * LSNG. */ void InitQuotaForOrigin(const FullOriginMetadata& aFullOriginMetadata, const ClientUsageArray& aClientUsages, uint64_t aUsageBytes, bool aDirectoryExists = true); // XXX clients can use QuotaObject instead of calling this method directly. void DecreaseUsageForClient(const ClientMetadata& aClientMetadata, int64_t aSize); void ResetUsageForClient(const ClientMetadata& aClientMetadata); UsageInfo GetUsageForClient(PersistenceType aPersistenceType, const OriginMetadata& aOriginMetadata, Client::Type aClientType); void UpdateOriginAccessTime(PersistenceType aPersistenceType, const OriginMetadata& aOriginMetadata); void RemoveQuota(); void RemoveQuotaForRepository(PersistenceType aPersistenceType) { MutexAutoLock lock(mQuotaMutex); LockedRemoveQuotaForRepository(aPersistenceType); } void RemoveQuotaForOrigin(PersistenceType aPersistenceType, const OriginMetadata& aOriginMetadata) { MutexAutoLock lock(mQuotaMutex); LockedRemoveQuotaForOrigin(aOriginMetadata); } nsresult LoadQuota(); void UnloadQuota(); void RemoveOriginFromCache(const OriginMetadata& aOriginMetadata); already_AddRefed GetQuotaObject( PersistenceType aPersistenceType, const OriginMetadata& aOriginMetadata, Client::Type aClientType, nsIFile* aFile, int64_t aFileSize = -1, int64_t* aFileSizeOut = nullptr); already_AddRefed GetQuotaObject( PersistenceType aPersistenceType, const OriginMetadata& aOriginMetadata, Client::Type aClientType, const nsAString& aPath, int64_t aFileSize = -1, int64_t* aFileSizeOut = nullptr); already_AddRefed GetQuotaObject(const int64_t aDirectoryLockId, const nsAString& aPath); Nullable OriginPersisted(const OriginMetadata& aOriginMetadata); void PersistOrigin(const OriginMetadata& aOriginMetadata); template auto WithOriginInfo(const OriginMetadata& aOriginMetadata, F aFunction) -> std::invoke_result_t&>; using DirectoryLockIdTableArray = AutoTArray; void AbortOperationsForLocks(const DirectoryLockIdTableArray& aLockIds); // Called when a process is being shot down. Aborts any running operations // for the given process. void AbortOperationsForProcess(ContentParentId aContentParentId); Result, nsresult> GetOriginDirectory( const OriginMetadata& aOriginMetadata) const; Result DoesOriginDirectoryExist( const OriginMetadata& aOriginMetadata) const; Result, nsresult> GetOrCreateTemporaryOriginDirectory( const OriginMetadata& aOriginMetadata); Result EnsureTemporaryOriginDirectoryCreated( const OriginMetadata& aOriginMetadata); static nsresult CreateDirectoryMetadata2( nsIFile& aDirectory, int64_t aTimestamp, bool aPersisted, const OriginMetadata& aOriginMetadata); nsresult RestoreDirectoryMetadata2(nsIFile* aDirectory); // XXX Remove aPersistenceType argument once the persistence type is stored // in the metadata file. Result LoadFullOriginMetadata( nsIFile* aDirectory, PersistenceType aPersistenceType); Result LoadFullOriginMetadataWithRestore( nsIFile* aDirectory); Result GetOriginMetadata(nsIFile* aDirectory); Result RemoveOriginDirectory(nsIFile& aDirectory); Result DoesClientDirectoryExist( const ClientMetadata& aClientMetadata) const; RefPtr OpenStorageDirectory( const PersistenceScope& aPersistenceScope, const OriginScope& aOriginScope, const ClientStorageScope& aClientStorageScope, bool aExclusive, bool aInitializeOrigins = false, DirectoryLockCategory aCategory = DirectoryLockCategory::None, Maybe&> aPendingDirectoryLockOut = Nothing()); // This is the main entry point into the QuotaManager API. // Any storage API implementation (quota client) that participates in // centralized quota and storage handling should call this method to obtain // a directory lock, ensuring the client’s files are protected from deletion // while in use. // // After a lock is acquired, the client is notified by resolving the returned // promise. If the lock couldn't be acquired, the promise is rejected. // // The returned lock is encapsulated in ClientDirectoryLockHandle, which // manages ownership and automatically drops the lock when destroyed. Clients // should retain ownership of the handle for as long as the lock is needed. // // The lock may still be invalidated by a clear operation, so consumers // should check its validity and release it as soon as it is no longer // required. // // Internally, QuotaManager may perform various initialization steps before // resolving the promise. This can include storage, temporary storage, group // and origin initialization. // // Optionally, an output parameter (aPendingDirectoryLockOut) can be provided // to receive a reference to the ClientDirectoryLock before wrapping it in // ClientDirectoryLockHandle. This allows tracking pending locks separately. RefPtr OpenClientDirectory( const ClientMetadata& aClientMetadata, bool aInitializeOrigins = true, bool aCreateIfNonExistent = true, Maybe&> aPendingDirectoryLockOut = Nothing()); RefPtr CreateDirectoryLock( const ClientMetadata& aClientMetadata, bool aExclusive); // XXX RemoveMe once bug 1170279 gets fixed. RefPtr CreateDirectoryLockInternal( const PersistenceScope& aPersistenceScope, const OriginScope& aOriginScope, const ClientStorageScope& aClientStorageScope, bool aExclusive, DirectoryLockCategory aCategory = DirectoryLockCategory::None); // Collect inactive and the least recently used origins. uint64_t CollectOriginsForEviction( uint64_t aMinSizeToBeFreed, nsTArray>& aLocks); /** * Helper method to invoke the provided predicate on all "pending" OriginInfo * instances. These are origins for which the origin directory has not yet * been created but for which quota is already being tracked. This happens, * for example, for the LocalStorage client where an origin that previously * was not using LocalStorage can start issuing writes which it buffers until * eventually flushing them. We defer creating the origin directory for as * long as possible in that case, so the directory won't exist. Logic that * would otherwise only consult the filesystem also needs to use this method. */ template void CollectPendingOriginsForListing(P aPredicate); bool IsPendingOrigin(const OriginMetadata& aOriginMetadata) const; RefPtr InitializeStorage(); RefPtr InitializeStorage( RefPtr aDirectoryLock); RefPtr StorageInitialized(); bool IsStorageInitialized() const { AssertIsOnOwningThread(); return mStorageInitialized; } bool IsStorageInitializedInternal() const { AssertIsOnIOThread(); return static_cast(mStorageConnection); } void AssertStorageIsInitializedInternal() const #ifdef DEBUG ; #else { } #endif RefPtr TemporaryStorageInitialized(); private: nsresult EnsureStorageIsInitializedInternal(); public: RefPtr InitializePersistentStorage(); RefPtr InitializePersistentStorage( RefPtr aDirectoryLock); RefPtr PersistentStorageInitialized(); bool IsPersistentStorageInitialized() const { AssertIsOnOwningThread(); return mPersistentStorageInitialized; } bool IsPersistentStorageInitializedInternal() const { AssertIsOnIOThread(); return mPersistentStorageInitializedInternal; } private: nsresult EnsurePersistentStorageIsInitializedInternal(); public: RefPtr InitializeTemporaryGroup( const PrincipalMetadata& aPrincipalMetadata); RefPtr InitializeTemporaryGroup( const PrincipalMetadata& aPrincipalMetadata, RefPtr aDirectoryLock); RefPtr TemporaryGroupInitialized( const PrincipalMetadata& aPrincipalMetadata); bool IsTemporaryGroupInitialized(const PrincipalMetadata& aPrincipalMetadata); bool IsTemporaryGroupInitializedInternal( const PrincipalMetadata& aPrincipalMetadata) const; private: Result EnsureTemporaryGroupIsInitializedInternal( const PrincipalMetadata& aPrincipalMetadata); public: RefPtr InitializePersistentOrigin( const OriginMetadata& aOriginMetadata); RefPtr InitializePersistentOrigin( const OriginMetadata& aOriginMetadata, RefPtr aDirectoryLock); RefPtr PersistentOriginInitialized( const OriginMetadata& aOriginMetadata); bool IsPersistentOriginInitialized(const OriginMetadata& aOriginMetadata); bool IsPersistentOriginInitializedInternal( const OriginMetadata& aOriginMetadata) const; private: // Returns a pair of an nsIFile object referring to the directory, and a bool // indicating whether the directory was newly created. Result, bool>, nsresult> EnsurePersistentOriginIsInitializedInternal( const OriginMetadata& aOriginMetadata); public: RefPtr InitializeTemporaryOrigin( const OriginMetadata& aOriginMetadata, bool aCreateIfNonExistent); RefPtr InitializeTemporaryOrigin( const OriginMetadata& aOriginMetadata, bool aCreateIfNonExistent, RefPtr aDirectoryLock); RefPtr TemporaryOriginInitialized( const OriginMetadata& aOriginMetadata); bool IsTemporaryOriginInitialized(const OriginMetadata& aOriginMetadata); bool IsTemporaryOriginInitializedInternal( const OriginMetadata& aOriginMetadata) const; private: // Returns a pair of an nsIFile object referring to the directory, and a bool // indicating whether the directory was newly created. Result, bool>, nsresult> EnsureTemporaryOriginIsInitializedInternal( const OriginMetadata& aOriginMetadata, bool aCreateIfNonExistent); public: RefPtr InitializePersistentClient( const ClientMetadata& aClientMetadata); RefPtr InitializePersistentClient( const ClientMetadata& aClientMetadata, RefPtr aDirectoryLock); // Returns a pair of an nsIFile object referring to the directory, and a bool // indicating whether the directory was newly created. Result, bool>, nsresult> EnsurePersistentClientIsInitialized(const ClientMetadata& aClientMetadata); RefPtr InitializeTemporaryClient( const ClientMetadata& aClientMetadata, bool aCreateIfNonExistent); RefPtr InitializeTemporaryClient( const ClientMetadata& aClientMetadata, bool aCreateIfNonExistent, RefPtr aDirectoryLock); // Returns a pair of an nsIFile object referring to the directory, and a bool // indicating whether the directory was newly created. Result, bool>, nsresult> EnsureTemporaryClientIsInitialized(const ClientMetadata& aClientMetadata, bool aCreateIfNonExistent); RefPtr InitializeTemporaryStorage(); RefPtr InitializeTemporaryStorage( RefPtr aDirectoryLock); bool IsTemporaryStorageInitialized() const { AssertIsOnOwningThread(); return mTemporaryStorageInitialized; } private: nsresult InitializeTemporaryStorageInternal(); nsresult EnsureTemporaryStorageIsInitializedInternal(); public: RefPtr InitializeAllTemporaryOrigins(); RefPtr SaveOriginAccessTime( const OriginMetadata& aOriginMetadata, int64_t aTimestamp); RefPtr GetUsage( bool aGetAll, RefPtr aOnCancelPromise = nullptr); RefPtr GetOriginUsage( const PrincipalInfo& aPrincipalInfo, RefPtr aOnCancelPromise = nullptr); RefPtr GetCachedOriginUsage( const PrincipalInfo& aPrincipalInfo); RefPtr ListOrigins(); RefPtr ListCachedOrigins(); RefPtr ClearStoragesForOrigin( const Maybe& aPersistenceType, const PrincipalInfo& aPrincipalInfo); RefPtr ClearStoragesForClient( Maybe aPersistenceType, const PrincipalInfo& aPrincipalInfo, Client::Type aClientType); RefPtr ClearStoragesForOriginPrefix( const Maybe& aPersistenceType, const PrincipalInfo& aPrincipalInfo); RefPtr ClearStoragesForOriginAttributesPattern( const OriginAttributesPattern& aPattern); RefPtr ClearPrivateRepository(); RefPtr ClearStorage(); RefPtr ShutdownStoragesForOrigin( Maybe aPersistenceType, const PrincipalInfo& aPrincipalInfo); RefPtr ShutdownStoragesForClient( Maybe aPersistenceType, const PrincipalInfo& aPrincipalInfo, Client::Type aClientType); RefPtr ShutdownStorage( Maybe aCallbackOptions = Nothing(), Maybe aCallbacks = Nothing()); void ShutdownStorageInternal(); // Returns a bool indicating whether the directory was newly created. Result EnsureOriginDirectory(nsIFile& aDirectory); nsresult AboutToClearOrigins(const PersistenceScope& aPersistenceScope, const OriginScope& aOriginScope, const ClientStorageScope& aClientStorageScope); void OriginClearCompleted(const OriginMetadata& aOriginMetadata, const ClientStorageScope& aClientStorageScope); void RepositoryClearCompleted(PersistenceType aPersistenceType); void StartIdleMaintenance() { AssertIsOnOwningThread(); for (const auto& client : *mClients) { client->StartIdleMaintenance(); } NotifyMaintenanceStarted(*this); } void StopIdleMaintenance() { AssertIsOnOwningThread(); for (const auto& client : *mClients) { client->StopIdleMaintenance(); } } void AssertCurrentThreadOwnsQuotaMutex() { mQuotaMutex.AssertCurrentThreadOwns(); } void AssertNotCurrentThreadOwnsQuotaMutex() { mQuotaMutex.AssertNotCurrentThreadOwns(); } nsIThread* IOThread() { return mIOThread->get(); } Client* GetClient(Client::Type aClientType); const AutoTArray& AllClientTypes(); const nsString& GetBasePath() const { return mBasePath; } const nsString& GetStorageName() const { return mStorageName; } const nsString& GetStoragePath() const { return *mStoragePath; } const nsString& GetStoragePath(PersistenceType aPersistenceType) const { if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) { return *mPermanentStoragePath; } if (aPersistenceType == PERSISTENCE_TYPE_TEMPORARY) { return *mTemporaryStoragePath; } if (aPersistenceType == PERSISTENCE_TYPE_DEFAULT) { return *mDefaultStoragePath; } MOZ_ASSERT(aPersistenceType == PERSISTENCE_TYPE_PRIVATE); return *mPrivateStoragePath; } bool IsThumbnailPrivateIdentityIdKnown() const; uint32_t GetThumbnailPrivateIdentityId() const; void SetThumbnailPrivateIdentityId(uint32_t aThumbnailPrivateIdentityId); uint64_t GetGroupLimit() const; std::pair GetUsageAndLimitForEstimate( const OriginMetadata& aOriginMetadata); uint64_t GetOriginUsage(const PrincipalMetadata& aPrincipalMetadata); Maybe GetFullOriginMetadata( const OriginMetadata& aOriginMetadata); /** * Retrieves the total number of directory iterations performed. * * @return The total count of directory iterations, which is currently * incremented only during clearing operations. */ uint64_t TotalDirectoryIterations() const; /** * Retrieves the number of metadata updates performed by SaveOriginAccessTime * operation, as tracked on the background thread. This count is incremented * after the operation has fully completed. */ uint64_t SaveOriginAccessTimeCount() const; /** * Retrieves the number of metadata updates performed by SaveOriginAccessTime * operation, as tracked internally on the I/O thread. This count is * incremented when the actual metadata file update occurs. */ uint64_t SaveOriginAccessTimeCountInternal() const; // Record a quota client shutdown step, if shutting down. // Assumes that the QuotaManager singleton is alive. static void MaybeRecordQuotaClientShutdownStep( const Client::Type aClientType, const nsACString& aStepDescription); // Record a quota client shutdown step, if shutting down. // Checks if the QuotaManager singleton is alive. static void SafeMaybeRecordQuotaClientShutdownStep( Client::Type aClientType, const nsACString& aStepDescription); // Record a quota manager shutdown step, use only if shutdown is active. void RecordQuotaManagerShutdownStep(const nsACString& aStepDescription); // Record a quota manager shutdown step, if shutting down. void MaybeRecordQuotaManagerShutdownStep(const nsACString& aStepDescription); template void MaybeRecordQuotaManagerShutdownStepWith(F&& aFunc); static void GetStorageId(PersistenceType aPersistenceType, const nsACString& aOrigin, Client::Type aClientType, nsACString& aDatabaseId); static bool IsOriginInternal(const nsACString& aOrigin); static bool AreOriginsEqualOnDisk(const nsACString& aOrigin1, const nsACString& aOrigin2); // XXX This method currently expects the original origin string (not yet // sanitized). static Result ParseOrigin(const nsACString& aOrigin); static void InvalidateQuotaCache(); private: virtual ~QuotaManager(); nsresult Init(); void Shutdown(); void RegisterDirectoryLock(DirectoryLockImpl& aLock); void UnregisterDirectoryLock(DirectoryLockImpl& aLock); void AddPendingDirectoryLock(DirectoryLockImpl& aLock); void RemovePendingDirectoryLock(DirectoryLockImpl& aLock); uint64_t LockedCollectOriginsForEviction( uint64_t aMinSizeToBeFreed, nsTArray>& aLocks); void LockedRemoveQuotaForRepository(PersistenceType aPersistenceType); void LockedRemoveQuotaForOrigin(const OriginMetadata& aOriginMetadata); bool LockedHasGroupInfoPair(const nsACString& aGroup) const; already_AddRefed LockedGetOrCreateGroupInfo( PersistenceType aPersistenceType, const nsACString& aSuffix, const nsACString& aGroup); already_AddRefed LockedGetOriginInfo( PersistenceType aPersistenceType, const OriginMetadata& aOriginMetadata) const; nsresult UpgradeFromIndexedDBDirectoryToPersistentStorageDirectory( nsIFile* aIndexedDBDir); nsresult UpgradeFromPersistentStorageDirectoryToDefaultStorageDirectory( nsIFile* aPersistentStorageDir); nsresult MaybeUpgradeToDefaultStorageDirectory(nsIFile& aStorageFile); template nsresult UpgradeStorage(const int32_t aOldVersion, const int32_t aNewVersion, mozIStorageConnection* aConnection); nsresult UpgradeStorageFrom0_0To1_0(mozIStorageConnection* aConnection); nsresult UpgradeStorageFrom1_0To2_0(mozIStorageConnection* aConnection); nsresult UpgradeStorageFrom2_0To2_1(mozIStorageConnection* aConnection); nsresult UpgradeStorageFrom2_1To2_2(mozIStorageConnection* aConnection); nsresult UpgradeStorageFrom2_2To2_3(mozIStorageConnection* aConnection); nsresult MaybeCreateOrUpgradeStorage(mozIStorageConnection& aConnection); OkOrErr MaybeRemoveLocalStorageArchiveTmpFile(); nsresult MaybeRemoveLocalStorageDataAndArchive(nsIFile& aLsArchiveFile); nsresult MaybeRemoveLocalStorageDirectories(); Result CopyLocalStorageArchiveFromWebAppsStore( nsIFile& aLsArchiveFile) const; Result, nsresult> CreateLocalStorageArchiveConnection(nsIFile& aLsArchiveFile) const; Result, nsresult> RecopyLocalStorageArchiveFromWebAppsStore(nsIFile& aLsArchiveFile); Result, nsresult> DowngradeLocalStorageArchive(nsIFile& aLsArchiveFile); Result, nsresult> UpgradeLocalStorageArchiveFromLessThan4To4(nsIFile& aLsArchiveFile); /* nsresult UpgradeLocalStorageArchiveFrom4To5(); */ Result MaybeCreateOrUpgradeLocalStorageArchive( nsIFile& aLsArchiveFile); Result CreateEmptyLocalStorageArchive( nsIFile& aLsArchiveFile) const; template nsresult InitializeRepository(PersistenceType aPersistenceType, OriginFunc&& aOriginFunc); nsresult InitializeOrigin(PersistenceType aPersistenceType, const OriginMetadata& aOriginMetadata, int64_t aAccessTime, bool aPersisted, nsIFile* aDirectory, bool aForGroup = false); using OriginInfosFlatTraversable = nsTArray>>; using OriginInfosNestedTraversable = nsTArray>>>; OriginInfosNestedTraversable GetOriginInfosExceedingGroupLimit() const; OriginInfosNestedTraversable GetOriginInfosExceedingGlobalLimit() const; void ClearOrigins(const OriginInfosNestedTraversable& aDoomedOriginInfos); void CleanupTemporaryStorage(); void DeleteOriginDirectory(const OriginMetadata& aOriginMetadata); void FinalizeOriginEviction(nsTArray>&& aLocks); Result ArchiveOrigins( const nsTArray& aFullOriginMetadatas); void ReleaseIOThreadObjects() { AssertIsOnIOThread(); for (Client::Type type : AllClientTypes()) { (*mClients)[type]->ReleaseIOThreadObjects(); } } DirectoryLockTable& GetDirectoryLockTable(PersistenceType aPersistenceType); void ClearDirectoryLockTables(); void AddTemporaryOrigin(const FullOriginMetadata& aFullOriginMetadata); void RemoveTemporaryOrigin(const OriginMetadata& aOriginMetadata); void RemoveTemporaryOrigins(PersistenceType aPersistenceType); void RemoveTemporaryOrigins(); /** * Retrieves the count of thumbnail private identity temporary origins. * * This method returns the current count of temporary origins associated with * thumbnail private identity contexts. It requires that the thumbnail * private identity id is known. * * @return The count of thumbnail private identity temporary origins. * * @note The thumbnail private identity id must be known before calling this * method. If the id is not known, it will cause a debug assertion failure * due to the `MOZ_ASSERT`. */ uint32_t ThumbnailPrivateIdentityTemporaryOriginCount() const; PrincipalMetadataArray GetAllTemporaryGroups() const; OriginMetadataArray GetAllTemporaryOrigins() const; void NoteInitializedOrigin(PersistenceType aPersistenceType, const nsACString& aOrigin); void NoteUninitializedOrigins( const OriginMetadataArray& aOriginMetadataArray); void NoteUninitializedRepository(PersistenceType aPersistenceType); bool IsOriginInitialized(PersistenceType aPersistenceType, const nsACString& aOrigin) const; bool IsSanitizedOriginValid(const nsACString& aSanitizedOrigin); Result EnsureStorageOriginFromOrigin( const nsACString& aOrigin); Result GetOriginFromStorageOrigin( const nsACString& aStorageOrigin); int64_t GenerateDirectoryLockId(); bool ShutdownStarted() const; void RecordShutdownStep(Maybe aClientType, const nsACString& aStepDescription); template auto ExecuteInitialization(Initialization aInitialization, Func&& aFunc) -> std::invoke_result_t&>; template auto ExecuteInitialization(Initialization aInitialization, const nsACString& aContext, Func&& aFunc) -> std::invoke_result_t&>; template auto ExecuteGroupInitialization(const nsACString& aGroup, const GroupInitialization aInitialization, const nsACString& aContext, Func&& aFunc) -> std::invoke_result_t&>; template auto ExecuteOriginInitialization(const nsACString& aOrigin, const OriginInitialization aInitialization, const nsACString& aContext, Func&& aFunc) -> std::invoke_result_t&>; /** * Increments the counter tracking the total number of directory iterations. * * @note This is currently called only during clearing operations to update * the mTotalDirectoryIterations member. */ void IncreaseTotalDirectoryIterations(); /** * Increments the counter tracking SaveOriginAccessTime metadata updates, * recorded on the background thread after the operation has completed. */ void IncreaseSaveOriginAccessTimeCount(); /** * Increments the counter tracking SaveOriginAccessTime metadata updates, * recorded internally on the I/O thread when the metadata file is updated. */ void IncreaseSaveOriginAccessTimeCountInternal(); template static void MaybeInsertNonPersistedOriginInfos( Iterator aDest, const RefPtr& aTemporaryGroupInfo, const RefPtr& aDefaultGroupInfo, const RefPtr& aPrivateGroupInfo); template static OriginInfosFlatTraversable CollectLRUOriginInfosUntil( Collect&& aCollect, Pred&& aPred); // Thread on which IO is performed. LazyInitializedOnceNotNull> mIOThread; nsCOMPtr mStorageConnection; EnumeratedArray mShutdownSteps; LazyInitializedOnce mShutdownStartedAt; // Accesses to mQuotaManagerShutdownSteps must be protected by mQuotaMutex. nsCString mQuotaManagerShutdownSteps; mutable mozilla::Mutex mQuotaMutex MOZ_UNANNOTATED; nsClassHashtable mGroupInfoPairs; // Maintains a list of directory locks that are queued. nsTArray> mPendingDirectoryLocks; // Maintains a list of directory locks that are acquired or queued. It can be // accessed on the owning (PBackground) thread only. nsTArray> 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. nsTHashMap> mDirectoryLockIdTable; // Directory lock tables that are used to update origin access time. DirectoryLockTable mTemporaryDirectoryLockTable; DirectoryLockTable mDefaultDirectoryLockTable; DirectoryLockTable mPrivateDirectoryLockTable; // Things touched on the owning (PBackground) thread only. struct BackgroundThreadAccessible { PrincipalMetadataArray mUninitializedGroups; nsTHashSet mInitializedGroups; // Tracks how many times SaveOriginAccessTime resulted in updating metadata. uint64_t mSaveOriginAccessTimeCount = 0; }; ThreadBound mBackgroundThreadAccessible; using BoolArray = AutoTArray; nsTHashMap mInitializedOrigins; // Things touched on the IO thread only. struct IOThreadAccessible { nsTHashMap> mAllTemporaryOrigins; Maybe mThumbnailPrivateIdentityId; // Tracks the total number of directory iterations. // Note: This is currently incremented only during clearing operations. uint64_t mTotalDirectoryIterations = 0; // Tracks how many times SaveOriginAccessTime resulted in updating metadata. uint64_t mSaveOriginAccessTimeCount = 0; // Tracks the count of thumbnail private identity temporary origins. uint32_t mThumbnailPrivateIdentityTemporaryOriginCount = 0; }; ThreadBound mIOThreadAccessible; // A list of all successfully initialized persistent origins. This list isn't // protected by any mutex but it is only ever touched on the IO thread. nsTArray mInitializedOriginsInternal; // A hash table that is used to cache origin parser results for given // sanitized origin strings. This hash table isn't protected by any mutex but // it is only ever touched on the IO thread. nsTHashMap mValidOrigins; // These maps are protected by mQuotaMutex. nsTHashMap mOriginToStorageOriginMap; nsTHashMap mStorageOriginToOriginMap; // This array is populated at initialization time and then never modified, so // it can be iterated on any thread. LazyInitializedOnce, Client::TYPE_MAX>> mClients; using ClientTypesArray = AutoTArray; LazyInitializedOnce mAllClientTypes; LazyInitializedOnce mAllClientTypesExceptLS; // This object isn't protected by any mutex but it is only ever touched on // the IO thread. InitializationInfo mInitializationInfo; const nsString mBasePath; const nsString mStorageName; LazyInitializedOnce mIndexedDBPath; LazyInitializedOnce mStoragePath; LazyInitializedOnce mStorageArchivesPath; LazyInitializedOnce mPermanentStoragePath; LazyInitializedOnce mTemporaryStoragePath; LazyInitializedOnce mDefaultStoragePath; LazyInitializedOnce mPrivateStoragePath; LazyInitializedOnce mToBeRemovedStoragePath; MozPromiseHolder mInitializeAllTemporaryOriginsPromiseHolder; uint64_t mTemporaryStorageLimit; uint64_t mTemporaryStorageUsage; int64_t mNextDirectoryLockId; bool mStorageInitialized; bool mPersistentStorageInitialized; bool mPersistentStorageInitializedInternal; bool mTemporaryStorageInitialized; bool mTemporaryStorageInitializedInternal; bool mInitializingAllTemporaryOrigins; bool mAllTemporaryOriginsInitialized; bool mCacheUsable; }; } // namespace mozilla::dom::quota #endif /* mozilla_dom_quota_quotamanager_h__ */