summaryrefslogtreecommitdiffstats
path: root/dom/quota/QuotaManager.h
diff options
context:
space:
mode:
Diffstat (limited to 'dom/quota/QuotaManager.h')
-rw-r--r--dom/quota/QuotaManager.h808
1 files changed, 808 insertions, 0 deletions
diff --git a/dom/quota/QuotaManager.h b/dom/quota/QuotaManager.h
new file mode 100644
index 0000000000..42e5de961a
--- /dev/null
+++ b/dom/quota/QuotaManager.h
@@ -0,0 +1,808 @@
+/* -*- 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 <cstdint>
+#include <utility>
+#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/dom/Nullable.h"
+#include "mozilla/dom/ipc/IdType.h"
+#include "mozilla/dom/quota/Assertions.h"
+#include "mozilla/dom/quota/CommonMetadata.h"
+#include "mozilla/dom/quota/DirectoryLockCategory.h"
+#include "mozilla/dom/quota/ForwardDecls.h"
+#include "mozilla/dom/quota/InitializationTypes.h"
+#include "mozilla/dom/quota/PersistenceType.h"
+#include "mozilla/dom/quota/QuotaCommon.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 QUOTA_MANAGER_CONTRACTID "@mozilla.org/dom/quota/manager;1"
+
+class mozIStorageConnection;
+class nsIEventTarget;
+class nsIFile;
+class nsIPrincipal;
+class nsIRunnable;
+class nsIThread;
+class nsITimer;
+class nsPIDOMWindowOuter;
+
+namespace mozilla {
+
+class OriginAttributes;
+class OriginAttributesPattern;
+
+namespace ipc {
+
+class PrincipalInfo;
+
+} // namespace ipc
+
+} // namespace mozilla
+
+namespace mozilla::dom::quota {
+
+class CanonicalQuotaObject;
+class ClientUsageArray;
+class ClientDirectoryLock;
+class DirectoryLockImpl;
+class GroupInfo;
+class GroupInfoPair;
+class NormalOriginOperationBase;
+class OriginDirectoryLock;
+class OriginInfo;
+class OriginScope;
+class QuotaObject;
+class UniversalDirectoryLock;
+
+class QuotaManager final : public BackgroundThreadObject {
+ friend class CanonicalQuotaObject;
+ friend class ClearStorageOp;
+ friend class DirectoryLockImpl;
+ friend class GroupInfo;
+ friend class InitOp;
+ friend class OriginInfo;
+ friend class ShutdownStorageOp;
+
+ using PrincipalInfo = mozilla::ipc::PrincipalInfo;
+ using DirectoryLockTable =
+ nsClassHashtable<nsCStringHashKey, nsTArray<NotNull<DirectoryLockImpl*>>>;
+
+ class Observer;
+
+ public:
+ 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<MovingNotNull<RefPtr<QuotaManager>>, nsresult> GetOrCreate();
+
+ static Result<Ok, nsresult> EnsureCreated();
+
+ // Returns a non-owning reference.
+ static QuotaManager* Get();
+
+ // Use only in gtests!
+ static nsIObserver* GetObserver();
+
+ // 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 IsOriginInitialized(const nsACString& aOrigin) const {
+ AssertIsOnIOThread();
+
+ return mInitializedOrigins.Contains(aOrigin);
+ }
+
+ bool IsTemporaryStorageInitializedInternal() const {
+ AssertIsOnIOThread();
+
+ return mTemporaryStorageInitializedInternal;
+ }
+
+ /**
+ * For initialization of an origin where the directory already exists. This is
+ * used by EnsureTemporaryStorageIsInitializedInternal/InitializeRepository
+ * once it has tallied origin usage by calling each of the QuotaClient
+ * InitOrigin methods.
+ */
+ void InitQuotaForOrigin(const FullOriginMetadata& aFullOriginMetadata,
+ const ClientUsageArray& aClientUsages,
+ uint64_t aUsageBytes);
+
+ /**
+ * For use in special-cases like LSNG where we need to be able to know that
+ * there is no data stored for an origin. LSNG knows that there is 0 usage for
+ * its storage of an origin and wants to make sure there is a QuotaObject
+ * tracking this. This method will create a non-persisted, 0-usage,
+ * mDirectoryExists=false OriginInfo if there isn't already an OriginInfo. If
+ * an OriginInfo already exists, it will be left as-is, because that implies a
+ * different client has usages for the origin (and there's no need to add
+ * LSNG's 0 usage to the QuotaObject).
+ */
+ void EnsureQuotaForOrigin(const OriginMetadata& aOriginMetadata);
+
+ /**
+ * For use when creating an origin directory. It's possible that origin usage
+ * is already being tracked due to a call to EnsureQuotaForOrigin, and in that
+ * case we need to update the existing OriginInfo rather than create a new
+ * one.
+ *
+ * @return last access time of the origin.
+ */
+ int64_t NoteOriginDirectoryCreated(const OriginMetadata& aOriginMetadata,
+ bool aPersisted);
+
+ // 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();
+
+ already_AddRefed<QuotaObject> GetQuotaObject(
+ PersistenceType aPersistenceType, const OriginMetadata& aOriginMetadata,
+ Client::Type aClientType, nsIFile* aFile, int64_t aFileSize = -1,
+ int64_t* aFileSizeOut = nullptr);
+
+ already_AddRefed<QuotaObject> GetQuotaObject(
+ PersistenceType aPersistenceType, const OriginMetadata& aOriginMetadata,
+ Client::Type aClientType, const nsAString& aPath, int64_t aFileSize = -1,
+ int64_t* aFileSizeOut = nullptr);
+
+ already_AddRefed<QuotaObject> GetQuotaObject(const int64_t aDirectoryLockId,
+ const nsAString& aPath);
+
+ Nullable<bool> OriginPersisted(const OriginMetadata& aOriginMetadata);
+
+ void PersistOrigin(const OriginMetadata& aOriginMetadata);
+
+ using DirectoryLockIdTableArray =
+ AutoTArray<Client::DirectoryLockIdTable, Client::TYPE_MAX>;
+ 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<nsCOMPtr<nsIFile>, nsresult> GetOriginDirectory(
+ const OriginMetadata& aOriginMetadata) const;
+
+ static nsresult CreateDirectoryMetadata(
+ nsIFile& aDirectory, int64_t aTimestamp,
+ 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<FullOriginMetadata, nsresult> LoadFullOriginMetadata(
+ nsIFile* aDirectory, PersistenceType aPersistenceType);
+
+ Result<FullOriginMetadata, nsresult> LoadFullOriginMetadataWithRestore(
+ nsIFile* aDirectory);
+
+ Result<OriginMetadata, nsresult> GetOriginMetadata(nsIFile* aDirectory);
+
+ Result<Ok, nsresult> RemoveOriginDirectory(nsIFile& aDirectory);
+
+ RefPtr<UniversalDirectoryLockPromise> OpenStorageDirectory(
+ const Nullable<PersistenceType>& aPersistenceType,
+ const OriginScope& aOriginScope,
+ const Nullable<Client::Type>& aClientType, bool aExclusive,
+ DirectoryLockCategory aCategory = DirectoryLockCategory::None,
+ Maybe<RefPtr<UniversalDirectoryLock>&> 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 get
+ // a directory lock which will protect client's files from being deleted
+ // while they are still in use.
+ // After a lock is acquired, client is notified by resolving the returned
+ // promise. If the lock couldn't be acquired, client is notified by rejecting
+ // the returned promise.
+ // A lock is a reference counted object and at the time the returned promise
+ // is resolved, there are no longer other strong references except the one
+ // held by the resolve value itself. So it's up to client to add a new
+ // reference in order to keep the lock alive.
+ // Unlocking is simply done by dropping all references to the lock object.
+ // In other words, protection which the lock represents dies with the lock
+ // object itself (Note that it's now possible to release directory locks
+ // sooner by calling newly added Drop method).
+ RefPtr<ClientDirectoryLockPromise> OpenClientDirectory(
+ const ClientMetadata& aClientMetadata,
+ Maybe<RefPtr<ClientDirectoryLock>&> aPendingDirectoryLockOut = Nothing());
+
+ RefPtr<ClientDirectoryLock> CreateDirectoryLock(
+ const ClientMetadata& aClientMetadata, bool aExclusive);
+
+ // XXX RemoveMe once bug 1170279 gets fixed.
+ RefPtr<UniversalDirectoryLock> CreateDirectoryLockInternal(
+ const Nullable<PersistenceType>& aPersistenceType,
+ const OriginScope& aOriginScope,
+ const Nullable<Client::Type>& aClientType, bool aExclusive,
+ DirectoryLockCategory aCategory = DirectoryLockCategory::None);
+
+ // Collect inactive and the least recently used origins.
+ uint64_t CollectOriginsForEviction(
+ uint64_t aMinSizeToBeFreed,
+ nsTArray<RefPtr<OriginDirectoryLock>>& 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 <typename P>
+ void CollectPendingOriginsForListing(P aPredicate);
+
+ RefPtr<BoolPromise> InitializeStorage();
+
+ RefPtr<BoolPromise> InitializeStorage(
+ RefPtr<UniversalDirectoryLock> aDirectoryLock);
+
+ RefPtr<BoolPromise> StorageInitialized();
+
+ bool IsStorageInitialized() const {
+ AssertIsOnOwningThread();
+
+ return mStorageInitialized;
+ }
+
+ bool IsStorageInitializedInternal() const {
+ AssertIsOnIOThread();
+ return static_cast<bool>(mStorageConnection);
+ }
+
+ void AssertStorageIsInitializedInternal() const
+#ifdef DEBUG
+ ;
+#else
+ {
+ }
+#endif
+
+ RefPtr<BoolPromise> TemporaryStorageInitialized();
+
+ private:
+ nsresult EnsureStorageIsInitializedInternal();
+
+ public:
+ // Returns a pair of an nsIFile object referring to the directory, and a bool
+ // indicating whether the directory was newly created.
+ Result<std::pair<nsCOMPtr<nsIFile>, bool>, nsresult>
+ EnsurePersistentOriginIsInitialized(const OriginMetadata& aOriginMetadata);
+
+ bool IsTemporaryOriginInitialized(
+ const OriginMetadata& aOriginMetadata) const;
+
+ // Returns a pair of an nsIFile object referring to the directory, and a bool
+ // indicating whether the directory was newly created.
+ Result<std::pair<nsCOMPtr<nsIFile>, bool>, nsresult>
+ EnsureTemporaryOriginIsInitialized(PersistenceType aPersistenceType,
+ const OriginMetadata& aOriginMetadata);
+
+ RefPtr<BoolPromise> InitializePersistentClient(
+ const PrincipalInfo& aPrincipalInfo, Client::Type aClientType);
+
+ // Returns a pair of an nsIFile object referring to the directory, and a bool
+ // indicating whether the directory was newly created.
+ Result<std::pair<nsCOMPtr<nsIFile>, bool>, nsresult>
+ EnsurePersistentClientIsInitialized(const ClientMetadata& aClientMetadata);
+
+ RefPtr<BoolPromise> InitializeTemporaryClient(
+ PersistenceType aPersistenceType, const PrincipalInfo& aPrincipalInfo,
+ Client::Type aClientType);
+
+ // Returns a pair of an nsIFile object referring to the directory, and a bool
+ // indicating whether the directory was newly created.
+ Result<std::pair<nsCOMPtr<nsIFile>, bool>, nsresult>
+ EnsureTemporaryClientIsInitialized(const ClientMetadata& aClientMetadata);
+
+ RefPtr<BoolPromise> InitializeTemporaryStorage();
+
+ RefPtr<BoolPromise> InitializeTemporaryStorage(
+ RefPtr<UniversalDirectoryLock> aDirectoryLock);
+
+ bool IsTemporaryStorageInitialized() const {
+ AssertIsOnOwningThread();
+
+ return mTemporaryStorageInitialized;
+ }
+
+ nsresult EnsureTemporaryStorageIsInitializedInternal();
+
+ RefPtr<BoolPromise> ClearStoragesForOrigin(
+ const Maybe<PersistenceType>& aPersistenceType,
+ const PrincipalInfo& aPrincipalInfo,
+ const Maybe<Client::Type>& aClientType);
+
+ RefPtr<BoolPromise> ClearStoragesForOriginPrefix(
+ const Maybe<PersistenceType>& aPersistenceType,
+ const PrincipalInfo& aPrincipalInfo);
+
+ RefPtr<BoolPromise> ClearStoragesForOriginAttributesPattern(
+ const OriginAttributesPattern& aPattern);
+
+ RefPtr<BoolPromise> ClearPrivateRepository();
+
+ RefPtr<BoolPromise> ClearStorage();
+
+ RefPtr<BoolPromise> ShutdownStorage();
+
+ void ShutdownStorageInternal();
+
+ // Returns a bool indicating whether the directory was newly created.
+ Result<bool, nsresult> EnsureOriginDirectory(nsIFile& aDirectory);
+
+ nsresult AboutToClearOrigins(
+ const Nullable<PersistenceType>& aPersistenceType,
+ const OriginScope& aOriginScope,
+ const Nullable<Client::Type>& aClientType);
+
+ void OriginClearCompleted(PersistenceType aPersistenceType,
+ const nsACString& aOrigin,
+ const Nullable<Client::Type>& aClientType);
+
+ void RepositoryClearCompleted(PersistenceType aPersistenceType);
+
+ void StartIdleMaintenance() {
+ AssertIsOnOwningThread();
+
+ for (const auto& client : *mClients) {
+ client->StartIdleMaintenance();
+ }
+ }
+
+ void StopIdleMaintenance() {
+ AssertIsOnOwningThread();
+
+ for (const auto& client : *mClients) {
+ client->StopIdleMaintenance();
+ }
+ }
+
+ void AssertCurrentThreadOwnsQuotaMutex() {
+ mQuotaMutex.AssertCurrentThreadOwns();
+ }
+
+ nsIThread* IOThread() { return mIOThread->get(); }
+
+ Client* GetClient(Client::Type aClientType);
+
+ const AutoTArray<Client::Type, Client::TYPE_MAX>& 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;
+ }
+
+ uint64_t GetGroupLimit() const;
+
+ std::pair<uint64_t, uint64_t> GetUsageAndLimitForEstimate(
+ const OriginMetadata& aOriginMetadata);
+
+ uint64_t GetOriginUsage(const PrincipalMetadata& aPrincipalMetadata);
+
+ Maybe<FullOriginMetadata> GetFullOriginMetadata(
+ const OriginMetadata& aOriginMetadata);
+
+ void NotifyStoragePressure(uint64_t aUsage);
+
+ // 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 <typename F>
+ void MaybeRecordQuotaManagerShutdownStepWith(F&& aFunc);
+
+ static void GetStorageId(PersistenceType aPersistenceType,
+ const nsACString& aOrigin, Client::Type aClientType,
+ nsACString& aDatabaseId);
+
+ static bool IsPrincipalInfoValid(const PrincipalInfo& aPrincipalInfo);
+
+ Result<PrincipalMetadata, nsresult> GetInfoFromValidatedPrincipalInfo(
+ const PrincipalInfo& aPrincipalInfo);
+
+ static nsAutoCString GetOriginFromValidatedPrincipalInfo(
+ const PrincipalInfo& aPrincipalInfo);
+
+ static Result<PrincipalMetadata, nsresult> GetInfoFromPrincipal(
+ nsIPrincipal* aPrincipal);
+
+ static Result<PrincipalMetadata, nsresult> GetInfoFromWindow(
+ nsPIDOMWindowOuter* aWindow);
+
+ static Result<nsAutoCString, nsresult> GetOriginFromPrincipal(
+ nsIPrincipal* aPrincipal);
+
+ static Result<nsAutoCString, nsresult> GetOriginFromWindow(
+ nsPIDOMWindowOuter* aWindow);
+
+ static nsLiteralCString GetOriginForChrome();
+
+ static PrincipalMetadata GetInfoForChrome();
+
+ 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<PrincipalInfo, nsresult> 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<RefPtr<OriginDirectoryLock>>& aLocks);
+
+ void LockedRemoveQuotaForRepository(PersistenceType aPersistenceType);
+
+ void LockedRemoveQuotaForOrigin(const OriginMetadata& aOriginMetadata);
+
+ already_AddRefed<GroupInfo> LockedGetOrCreateGroupInfo(
+ PersistenceType aPersistenceType, const nsACString& aSuffix,
+ const nsACString& aGroup);
+
+ already_AddRefed<OriginInfo> LockedGetOriginInfo(
+ PersistenceType aPersistenceType,
+ const OriginMetadata& aOriginMetadata) const;
+
+ nsresult UpgradeFromIndexedDBDirectoryToPersistentStorageDirectory(
+ nsIFile* aIndexedDBDir);
+
+ nsresult UpgradeFromPersistentStorageDirectoryToDefaultStorageDirectory(
+ nsIFile* aPersistentStorageDir);
+
+ nsresult MaybeUpgradeToDefaultStorageDirectory(nsIFile& aStorageFile);
+
+ template <typename Helper>
+ 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<Ok, nsresult> CopyLocalStorageArchiveFromWebAppsStore(
+ nsIFile& aLsArchiveFile) const;
+
+ Result<nsCOMPtr<mozIStorageConnection>, nsresult>
+ CreateLocalStorageArchiveConnection(nsIFile& aLsArchiveFile) const;
+
+ Result<nsCOMPtr<mozIStorageConnection>, nsresult>
+ RecopyLocalStorageArchiveFromWebAppsStore(nsIFile& aLsArchiveFile);
+
+ Result<nsCOMPtr<mozIStorageConnection>, nsresult>
+ DowngradeLocalStorageArchive(nsIFile& aLsArchiveFile);
+
+ Result<nsCOMPtr<mozIStorageConnection>, nsresult>
+ UpgradeLocalStorageArchiveFromLessThan4To4(nsIFile& aLsArchiveFile);
+
+ /*
+ nsresult UpgradeLocalStorageArchiveFrom4To5();
+ */
+
+ Result<Ok, nsresult> MaybeCreateOrUpgradeLocalStorageArchive(
+ nsIFile& aLsArchiveFile);
+
+ Result<Ok, nsresult> CreateEmptyLocalStorageArchive(
+ nsIFile& aLsArchiveFile) const;
+
+ template <typename OriginFunc>
+ nsresult InitializeRepository(PersistenceType aPersistenceType,
+ OriginFunc&& aOriginFunc);
+
+ nsresult InitializeOrigin(PersistenceType aPersistenceType,
+ const OriginMetadata& aOriginMetadata,
+ int64_t aAccessTime, bool aPersisted,
+ nsIFile* aDirectory);
+
+ using OriginInfosFlatTraversable =
+ nsTArray<NotNull<RefPtr<const OriginInfo>>>;
+
+ using OriginInfosNestedTraversable =
+ nsTArray<nsTArray<NotNull<RefPtr<const OriginInfo>>>>;
+
+ OriginInfosNestedTraversable GetOriginInfosExceedingGroupLimit() const;
+
+ OriginInfosNestedTraversable GetOriginInfosExceedingGlobalLimit() const;
+
+ void ClearOrigins(const OriginInfosNestedTraversable& aDoomedOriginInfos);
+
+ void CleanupTemporaryStorage();
+
+ void DeleteOriginDirectory(const OriginMetadata& aOriginMetadata);
+
+ void FinalizeOriginEviction(nsTArray<RefPtr<OriginDirectoryLock>>&& aLocks);
+
+ Result<Ok, nsresult> ArchiveOrigins(
+ const nsTArray<FullOriginMetadata>& aFullOriginMetadatas);
+
+ void ReleaseIOThreadObjects() {
+ AssertIsOnIOThread();
+
+ for (Client::Type type : AllClientTypes()) {
+ (*mClients)[type]->ReleaseIOThreadObjects();
+ }
+ }
+
+ DirectoryLockTable& GetDirectoryLockTable(PersistenceType aPersistenceType);
+
+ void ClearDirectoryLockTables();
+
+ bool IsSanitizedOriginValid(const nsACString& aSanitizedOrigin);
+
+ Result<nsCString, nsresult> EnsureStorageOriginFromOrigin(
+ const nsACString& aOrigin);
+
+ Result<nsCString, nsresult> GetOriginFromStorageOrigin(
+ const nsACString& aStorageOrigin);
+
+ int64_t GenerateDirectoryLockId();
+
+ bool ShutdownStarted() const;
+
+ void RecordShutdownStep(Maybe<Client::Type> aClientType,
+ const nsACString& aStepDescription);
+
+ template <typename Func>
+ auto ExecuteInitialization(Initialization aInitialization, Func&& aFunc)
+ -> std::invoke_result_t<Func, const FirstInitializationAttempt<
+ Initialization, StringGenerator>&>;
+
+ template <typename Func>
+ auto ExecuteInitialization(Initialization aInitialization,
+ const nsACString& aContext, Func&& aFunc)
+ -> std::invoke_result_t<Func, const FirstInitializationAttempt<
+ Initialization, StringGenerator>&>;
+
+ template <typename Func>
+ auto ExecuteOriginInitialization(const nsACString& aOrigin,
+ const OriginInitialization aInitialization,
+ const nsACString& aContext, Func&& aFunc)
+ -> std::invoke_result_t<Func, const FirstInitializationAttempt<
+ Initialization, StringGenerator>&>;
+
+ template <typename Iterator>
+ static void MaybeInsertNonPersistedOriginInfos(
+ Iterator aDest, const RefPtr<GroupInfo>& aTemporaryGroupInfo,
+ const RefPtr<GroupInfo>& aDefaultGroupInfo,
+ const RefPtr<GroupInfo>& aPrivateGroupInfo);
+
+ template <typename Collect, typename Pred>
+ static OriginInfosFlatTraversable CollectLRUOriginInfosUntil(
+ Collect&& aCollect, Pred&& aPred);
+
+ // Thread on which IO is performed.
+ LazyInitializedOnceNotNull<const nsCOMPtr<nsIThread>> mIOThread;
+
+ nsCOMPtr<mozIStorageConnection> mStorageConnection;
+
+ EnumeratedArray<Client::Type, Client::TYPE_MAX, nsCString> mShutdownSteps;
+ LazyInitializedOnce<const TimeStamp> mShutdownStartedAt;
+
+ // Accesses to mQuotaManagerShutdownSteps must be protected by mQuotaMutex.
+ nsCString mQuotaManagerShutdownSteps;
+
+ mutable mozilla::Mutex mQuotaMutex MOZ_UNANNOTATED;
+
+ nsClassHashtable<nsCStringHashKey, GroupInfoPair> mGroupInfoPairs;
+
+ // Maintains a list of directory locks that are queued.
+ nsTArray<RefPtr<DirectoryLockImpl>> mPendingDirectoryLocks;
+
+ // Maintains a list of directory locks that are acquired or queued. It can be
+ // accessed on the owning (PBackground) thread only.
+ nsTArray<NotNull<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.
+ nsTHashMap<nsUint64HashKey, NotNull<DirectoryLockImpl*>>
+ mDirectoryLockIdTable;
+
+ // Directory lock tables that are used to update origin access time.
+ DirectoryLockTable mTemporaryDirectoryLockTable;
+ DirectoryLockTable mDefaultDirectoryLockTable;
+ DirectoryLockTable mPrivateDirectoryLockTable;
+
+ // 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<nsCString> mInitializedOrigins;
+
+ // 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<nsCStringHashKey, bool> mValidOrigins;
+
+ // These maps are protected by mQuotaMutex.
+ nsTHashMap<nsCStringHashKey, nsCString> mOriginToStorageOriginMap;
+ nsTHashMap<nsCStringHashKey, nsCString> mStorageOriginToOriginMap;
+
+ // This array is populated at initialization time and then never modified, so
+ // it can be iterated on any thread.
+ LazyInitializedOnce<const AutoTArray<RefPtr<Client>, Client::TYPE_MAX>>
+ mClients;
+
+ using ClientTypesArray = AutoTArray<Client::Type, Client::TYPE_MAX>;
+ LazyInitializedOnce<const ClientTypesArray> mAllClientTypes;
+ LazyInitializedOnce<const ClientTypesArray> 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<const nsString> mIndexedDBPath;
+ LazyInitializedOnce<const nsString> mStoragePath;
+ LazyInitializedOnce<const nsString> mStorageArchivesPath;
+ LazyInitializedOnce<const nsString> mPermanentStoragePath;
+ LazyInitializedOnce<const nsString> mTemporaryStoragePath;
+ LazyInitializedOnce<const nsString> mDefaultStoragePath;
+ LazyInitializedOnce<const nsString> mPrivateStoragePath;
+ LazyInitializedOnce<const nsString> mToBeRemovedStoragePath;
+
+ uint64_t mTemporaryStorageLimit;
+ uint64_t mTemporaryStorageUsage;
+ int64_t mNextDirectoryLockId;
+ uint64_t mShutdownStorageOpCount;
+ bool mStorageInitialized;
+ bool mTemporaryStorageInitialized;
+ bool mTemporaryStorageInitializedInternal;
+ bool mCacheUsable;
+};
+
+} // namespace mozilla::dom::quota
+
+#endif /* mozilla_dom_quota_quotamanager_h__ */