Backed out changeset f594e6f00208 (bug 1940883) for causing crashes in bug 1941164.
[gecko.git] / dom / quota / QuotaManager.h
blobca0b6c8ad5b1853f2b6c0dc54811de069507a7af
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef mozilla_dom_quota_quotamanager_h__
8 #define mozilla_dom_quota_quotamanager_h__
10 #include <cstdint>
11 #include <utility>
12 #include "Client.h"
13 #include "ErrorList.h"
14 #include "mozilla/AlreadyAddRefed.h"
15 #include "mozilla/Assertions.h"
16 #include "mozilla/InitializedOnce.h"
17 #include "mozilla/MozPromise.h"
18 #include "mozilla/Mutex.h"
19 #include "mozilla/RefPtr.h"
20 #include "mozilla/Result.h"
21 #include "mozilla/ThreadBound.h"
22 #include "mozilla/dom/Nullable.h"
23 #include "mozilla/dom/ipc/IdType.h"
24 #include "mozilla/dom/quota/Assertions.h"
25 #include "mozilla/dom/quota/BackgroundThreadObject.h"
26 #include "mozilla/dom/quota/CommonMetadata.h"
27 #include "mozilla/dom/quota/DirectoryLockCategory.h"
28 #include "mozilla/dom/quota/ForwardDecls.h"
29 #include "mozilla/dom/quota/HashKeys.h"
30 #include "mozilla/dom/quota/InitializationTypes.h"
31 #include "mozilla/dom/quota/NotifyUtils.h"
32 #include "mozilla/dom/quota/OriginOperationCallbacks.h"
33 #include "mozilla/dom/quota/PersistenceType.h"
34 #include "nsCOMPtr.h"
35 #include "nsClassHashtable.h"
36 #include "nsTHashMap.h"
37 #include "nsDebug.h"
38 #include "nsHashKeys.h"
39 #include "nsISupports.h"
40 #include "nsStringFwd.h"
41 #include "nsTArray.h"
42 #include "nsTStringRepr.h"
43 #include "nscore.h"
44 #include "prenv.h"
46 #define GTEST_CLASS(testFixture, testName) testFixture##_##testName##_Test
48 class mozIStorageConnection;
49 class nsIEventTarget;
50 class nsIFile;
51 class nsIRunnable;
52 class nsIThread;
53 class nsITimer;
55 namespace mozilla {
57 class OriginAttributes;
58 class OriginAttributesPattern;
60 namespace ipc {
62 class PrincipalInfo;
64 } // namespace ipc
66 } // namespace mozilla
68 namespace mozilla::dom::quota {
70 class CanonicalQuotaObject;
71 class ClearDataOp;
72 class ClearRequestBase;
73 class ClientUsageArray;
74 class ClientDirectoryLock;
75 class DirectoryLockImpl;
76 class GroupInfo;
77 class GroupInfoPair;
78 class NormalOriginOperationBase;
79 class OriginDirectoryLock;
80 class OriginInfo;
81 class OriginScope;
82 class QuotaObject;
83 class UniversalDirectoryLock;
85 namespace test {
86 class GTEST_CLASS(TestQuotaManagerAndShutdownFixture,
87 ThumbnailPrivateIdentityTemporaryOriginCount);
90 class QuotaManager final : public BackgroundThreadObject {
91 friend class CanonicalQuotaObject;
92 friend class ClearDataOp;
93 friend class ClearRequestBase;
94 friend class ClearStorageOp;
95 friend class DirectoryLockImpl;
96 friend class FinalizeOriginEvictionOp;
97 friend class GroupInfo;
98 friend class InitOp;
99 friend class InitializePersistentOriginOp;
100 friend class InitializePersistentStorageOp;
101 friend class InitializeTemporaryGroupOp;
102 friend class InitializeTemporaryOriginOp;
103 friend class InitTemporaryStorageOp;
104 friend class ListCachedOriginsOp;
105 friend class OriginInfo;
106 friend class PersistOp;
107 friend class ShutdownStorageOp;
108 friend class test::GTEST_CLASS(TestQuotaManagerAndShutdownFixture,
109 ThumbnailPrivateIdentityTemporaryOriginCount);
110 friend class UniversalDirectoryLock;
112 friend Result<PrincipalMetadata, nsresult> GetInfoFromValidatedPrincipalInfo(
113 QuotaManager& aQuotaManager,
114 const mozilla::ipc::PrincipalInfo& aPrincipalInfo);
116 using PrincipalInfo = mozilla::ipc::PrincipalInfo;
117 using DirectoryLockTable =
118 nsClassHashtable<nsCStringHashKey, nsTArray<NotNull<DirectoryLockImpl*>>>;
120 class Observer;
122 public:
123 QuotaManager(const nsAString& aBasePath, const nsAString& aStorageName);
125 NS_INLINE_DECL_REFCOUNTING(QuotaManager)
127 static nsresult Initialize();
129 static bool IsRunningXPCShellTests() {
130 static bool kRunningXPCShellTests =
131 !!PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR");
132 return kRunningXPCShellTests;
135 static bool IsRunningGTests() {
136 static bool kRunningGTests = !!PR_GetEnv("MOZ_RUN_GTEST");
137 return kRunningGTests;
140 static const char kReplaceChars[];
141 static const char16_t kReplaceChars16[];
143 static Result<MovingNotNull<RefPtr<QuotaManager>>, nsresult> GetOrCreate();
145 static Result<Ok, nsresult> EnsureCreated();
147 // Returns a non-owning reference.
148 static QuotaManager* Get();
150 // Use only in gtests!
151 static nsIObserver* GetObserver();
153 // Returns true if we've begun the shutdown process.
154 static bool IsShuttingDown();
156 static void ShutdownInstance();
158 // Use only in gtests!
159 static void Reset();
161 static bool IsOSMetadata(const nsAString& aFileName);
163 static bool IsDotFile(const nsAString& aFileName);
165 void RegisterNormalOriginOp(NormalOriginOperationBase& aNormalOriginOp);
167 void UnregisterNormalOriginOp(NormalOriginOperationBase& aNormalOriginOp);
169 bool IsPersistentOriginInitializedInternal(const nsACString& aOrigin) const {
170 AssertIsOnIOThread();
172 return mInitializedOriginsInternal.Contains(aOrigin);
175 bool IsTemporaryStorageInitializedInternal() const {
176 AssertIsOnIOThread();
178 return mTemporaryStorageInitializedInternal;
182 * For initialization of an origin where the directory either exists or it
183 * does not. The directory exists case is used by InitializeOrigin once it
184 * has tallied origin usage by calling each of the QuotaClient InitOrigin
185 * methods. It's also used by LoadQuota when quota information is available
186 * from the cache. EnsureTemporaryStorageIsInitializedInternal calls this
187 * either if the directory exists or it does not depending on requirements
188 * of a particular quota client. The special case when origin directory is
189 * not created during origin initialization is currently utilized only by
190 * LSNG.
192 void InitQuotaForOrigin(const FullOriginMetadata& aFullOriginMetadata,
193 const ClientUsageArray& aClientUsages,
194 uint64_t aUsageBytes, bool aDirectoryExists = true);
196 // XXX clients can use QuotaObject instead of calling this method directly.
197 void DecreaseUsageForClient(const ClientMetadata& aClientMetadata,
198 int64_t aSize);
200 void ResetUsageForClient(const ClientMetadata& aClientMetadata);
202 UsageInfo GetUsageForClient(PersistenceType aPersistenceType,
203 const OriginMetadata& aOriginMetadata,
204 Client::Type aClientType);
206 void UpdateOriginAccessTime(PersistenceType aPersistenceType,
207 const OriginMetadata& aOriginMetadata);
209 void RemoveQuota();
211 void RemoveQuotaForRepository(PersistenceType aPersistenceType) {
212 MutexAutoLock lock(mQuotaMutex);
213 LockedRemoveQuotaForRepository(aPersistenceType);
216 void RemoveQuotaForOrigin(PersistenceType aPersistenceType,
217 const OriginMetadata& aOriginMetadata) {
218 MutexAutoLock lock(mQuotaMutex);
219 LockedRemoveQuotaForOrigin(aOriginMetadata);
222 nsresult LoadQuota();
224 void UnloadQuota();
226 void RemoveOriginFromCache(const OriginMetadata& aOriginMetadata);
228 already_AddRefed<QuotaObject> GetQuotaObject(
229 PersistenceType aPersistenceType, const OriginMetadata& aOriginMetadata,
230 Client::Type aClientType, nsIFile* aFile, int64_t aFileSize = -1,
231 int64_t* aFileSizeOut = nullptr);
233 already_AddRefed<QuotaObject> GetQuotaObject(
234 PersistenceType aPersistenceType, const OriginMetadata& aOriginMetadata,
235 Client::Type aClientType, const nsAString& aPath, int64_t aFileSize = -1,
236 int64_t* aFileSizeOut = nullptr);
238 already_AddRefed<QuotaObject> GetQuotaObject(const int64_t aDirectoryLockId,
239 const nsAString& aPath);
241 Nullable<bool> OriginPersisted(const OriginMetadata& aOriginMetadata);
243 void PersistOrigin(const OriginMetadata& aOriginMetadata);
245 template <typename F>
246 auto WithOriginInfo(const OriginMetadata& aOriginMetadata, F aFunction)
247 -> std::invoke_result_t<F, const RefPtr<OriginInfo>&>;
249 using DirectoryLockIdTableArray =
250 AutoTArray<Client::DirectoryLockIdTable, Client::TYPE_MAX>;
251 void AbortOperationsForLocks(const DirectoryLockIdTableArray& aLockIds);
253 // Called when a process is being shot down. Aborts any running operations
254 // for the given process.
255 void AbortOperationsForProcess(ContentParentId aContentParentId);
257 Result<nsCOMPtr<nsIFile>, nsresult> GetOriginDirectory(
258 const OriginMetadata& aOriginMetadata) const;
260 Result<bool, nsresult> DoesOriginDirectoryExist(
261 const OriginMetadata& aOriginMetadata) const;
263 Result<nsCOMPtr<nsIFile>, nsresult> GetOrCreateTemporaryOriginDirectory(
264 const OriginMetadata& aOriginMetadata);
266 Result<Ok, nsresult> EnsureTemporaryOriginDirectoryCreated(
267 const OriginMetadata& aOriginMetadata);
269 static nsresult CreateDirectoryMetadata(
270 nsIFile& aDirectory, int64_t aTimestamp,
271 const OriginMetadata& aOriginMetadata);
273 static nsresult CreateDirectoryMetadata2(
274 nsIFile& aDirectory, int64_t aTimestamp, bool aPersisted,
275 const OriginMetadata& aOriginMetadata);
277 nsresult RestoreDirectoryMetadata2(nsIFile* aDirectory);
279 // XXX Remove aPersistenceType argument once the persistence type is stored
280 // in the metadata file.
281 Result<FullOriginMetadata, nsresult> LoadFullOriginMetadata(
282 nsIFile* aDirectory, PersistenceType aPersistenceType);
284 Result<FullOriginMetadata, nsresult> LoadFullOriginMetadataWithRestore(
285 nsIFile* aDirectory);
287 Result<OriginMetadata, nsresult> GetOriginMetadata(nsIFile* aDirectory);
289 Result<Ok, nsresult> RemoveOriginDirectory(nsIFile& aDirectory);
291 Result<bool, nsresult> DoesClientDirectoryExist(
292 const ClientMetadata& aClientMetadata) const;
294 RefPtr<UniversalDirectoryLockPromise> OpenStorageDirectory(
295 const PersistenceScope& aPersistenceScope,
296 const OriginScope& aOriginScope,
297 const Nullable<Client::Type>& aClientType, bool aExclusive,
298 bool aInitializeOrigins = false,
299 DirectoryLockCategory aCategory = DirectoryLockCategory::None,
300 Maybe<RefPtr<UniversalDirectoryLock>&> aPendingDirectoryLockOut =
301 Nothing());
303 // This is the main entry point into the QuotaManager API.
304 // Any storage API implementation (quota client) that participates in
305 // centralized quota and storage handling should call this method to get
306 // a directory lock which will protect client's files from being deleted
307 // while they are still in use.
308 // After a lock is acquired, client is notified by resolving the returned
309 // promise. If the lock couldn't be acquired, client is notified by rejecting
310 // the returned promise. The returned lock could have been invalidated by a
311 // clear operation so consumers are supposed to check that and eventually
312 // release the lock as soon as possible (this is usually not needed for short
313 // lived operations).
314 // A lock is a reference counted object and at the time the returned promise
315 // is resolved, there are no longer other strong references except the one
316 // held by the resolve value itself. So it's up to client to add a new
317 // reference in order to keep the lock alive.
318 // Unlocking is simply done by calling lock object's Drop method. Unlocking
319 // must be always done explicitly before the lock object is destroyed (when
320 // the last strong reference is removed).
321 RefPtr<ClientDirectoryLockPromise> OpenClientDirectory(
322 const ClientMetadata& aClientMetadata, bool aInitializeOrigins = true,
323 bool aCreateIfNonExistent = true,
324 Maybe<RefPtr<ClientDirectoryLock>&> aPendingDirectoryLockOut = Nothing());
326 RefPtr<ClientDirectoryLock> CreateDirectoryLock(
327 const ClientMetadata& aClientMetadata, bool aExclusive);
329 // XXX RemoveMe once bug 1170279 gets fixed.
330 RefPtr<UniversalDirectoryLock> CreateDirectoryLockInternal(
331 const PersistenceScope& aPersistenceScope,
332 const OriginScope& aOriginScope,
333 const Nullable<Client::Type>& aClientType, bool aExclusive,
334 DirectoryLockCategory aCategory = DirectoryLockCategory::None);
336 // Collect inactive and the least recently used origins.
337 uint64_t CollectOriginsForEviction(
338 uint64_t aMinSizeToBeFreed,
339 nsTArray<RefPtr<OriginDirectoryLock>>& aLocks);
342 * Helper method to invoke the provided predicate on all "pending" OriginInfo
343 * instances. These are origins for which the origin directory has not yet
344 * been created but for which quota is already being tracked. This happens,
345 * for example, for the LocalStorage client where an origin that previously
346 * was not using LocalStorage can start issuing writes which it buffers until
347 * eventually flushing them. We defer creating the origin directory for as
348 * long as possible in that case, so the directory won't exist. Logic that
349 * would otherwise only consult the filesystem also needs to use this method.
351 template <typename P>
352 void CollectPendingOriginsForListing(P aPredicate);
354 bool IsPendingOrigin(const OriginMetadata& aOriginMetadata) const;
356 RefPtr<BoolPromise> InitializeStorage();
358 RefPtr<BoolPromise> InitializeStorage(
359 RefPtr<UniversalDirectoryLock> aDirectoryLock);
361 RefPtr<BoolPromise> StorageInitialized();
363 bool IsStorageInitialized() const {
364 AssertIsOnOwningThread();
366 return mStorageInitialized;
369 bool IsStorageInitializedInternal() const {
370 AssertIsOnIOThread();
371 return static_cast<bool>(mStorageConnection);
374 void AssertStorageIsInitializedInternal() const
375 #ifdef DEBUG
377 #else
380 #endif
382 RefPtr<BoolPromise> TemporaryStorageInitialized();
384 private:
385 nsresult EnsureStorageIsInitializedInternal();
387 public:
388 RefPtr<BoolPromise> InitializePersistentStorage();
390 RefPtr<BoolPromise> InitializePersistentStorage(
391 RefPtr<UniversalDirectoryLock> aDirectoryLock);
393 RefPtr<BoolPromise> PersistentStorageInitialized();
395 bool IsPersistentStorageInitialized() const {
396 AssertIsOnOwningThread();
398 return mPersistentStorageInitialized;
401 bool IsPersistentStorageInitializedInternal() const {
402 AssertIsOnIOThread();
404 return mPersistentStorageInitializedInternal;
407 private:
408 nsresult EnsurePersistentStorageIsInitializedInternal();
410 public:
411 RefPtr<BoolPromise> InitializeTemporaryGroup(
412 const PrincipalMetadata& aPrincipalMetadata);
414 RefPtr<BoolPromise> InitializeTemporaryGroup(
415 const PrincipalMetadata& aPrincipalMetadata,
416 RefPtr<UniversalDirectoryLock> aDirectoryLock);
418 RefPtr<BoolPromise> TemporaryGroupInitialized(
419 const PrincipalMetadata& aPrincipalMetadata);
421 bool IsTemporaryGroupInitialized(const PrincipalMetadata& aPrincipalMetadata);
423 bool IsTemporaryGroupInitializedInternal(
424 const PrincipalMetadata& aPrincipalMetadata) const;
426 private:
427 Result<Ok, nsresult> EnsureTemporaryGroupIsInitializedInternal(
428 const PrincipalMetadata& aPrincipalMetadata);
430 public:
431 RefPtr<BoolPromise> InitializePersistentOrigin(
432 const OriginMetadata& aOriginMetadata);
434 RefPtr<BoolPromise> InitializePersistentOrigin(
435 const OriginMetadata& aOriginMetadata,
436 RefPtr<UniversalDirectoryLock> aDirectoryLock);
438 RefPtr<BoolPromise> PersistentOriginInitialized(
439 const OriginMetadata& aOriginMetadata);
441 bool IsPersistentOriginInitialized(const OriginMetadata& aOriginMetadata);
443 bool IsPersistentOriginInitializedInternal(
444 const OriginMetadata& aOriginMetadata) const;
446 private:
447 // Returns a pair of an nsIFile object referring to the directory, and a bool
448 // indicating whether the directory was newly created.
449 Result<std::pair<nsCOMPtr<nsIFile>, bool>, nsresult>
450 EnsurePersistentOriginIsInitializedInternal(
451 const OriginMetadata& aOriginMetadata);
453 public:
454 RefPtr<BoolPromise> InitializeTemporaryOrigin(
455 const OriginMetadata& aOriginMetadata, bool aCreateIfNonExistent);
457 RefPtr<BoolPromise> InitializeTemporaryOrigin(
458 const OriginMetadata& aOriginMetadata, bool aCreateIfNonExistent,
459 RefPtr<UniversalDirectoryLock> aDirectoryLock);
461 RefPtr<BoolPromise> TemporaryOriginInitialized(
462 const OriginMetadata& aOriginMetadata);
464 bool IsTemporaryOriginInitialized(const OriginMetadata& aOriginMetadata);
466 bool IsTemporaryOriginInitializedInternal(
467 const OriginMetadata& aOriginMetadata) const;
469 private:
470 // Returns a pair of an nsIFile object referring to the directory, and a bool
471 // indicating whether the directory was newly created.
472 Result<std::pair<nsCOMPtr<nsIFile>, bool>, nsresult>
473 EnsureTemporaryOriginIsInitializedInternal(
474 const OriginMetadata& aOriginMetadata, bool aCreateIfNonExistent);
476 public:
477 RefPtr<BoolPromise> InitializePersistentClient(
478 const PrincipalInfo& aPrincipalInfo, Client::Type aClientType);
480 // Returns a pair of an nsIFile object referring to the directory, and a bool
481 // indicating whether the directory was newly created.
482 Result<std::pair<nsCOMPtr<nsIFile>, bool>, nsresult>
483 EnsurePersistentClientIsInitialized(const ClientMetadata& aClientMetadata);
485 RefPtr<BoolPromise> InitializeTemporaryClient(
486 PersistenceType aPersistenceType, const PrincipalInfo& aPrincipalInfo,
487 Client::Type aClientType);
489 // Returns a pair of an nsIFile object referring to the directory, and a bool
490 // indicating whether the directory was newly created.
491 Result<std::pair<nsCOMPtr<nsIFile>, bool>, nsresult>
492 EnsureTemporaryClientIsInitialized(const ClientMetadata& aClientMetadata);
494 RefPtr<BoolPromise> InitializeTemporaryStorage();
496 RefPtr<BoolPromise> InitializeTemporaryStorage(
497 RefPtr<UniversalDirectoryLock> aDirectoryLock);
499 bool IsTemporaryStorageInitialized() const {
500 AssertIsOnOwningThread();
502 return mTemporaryStorageInitialized;
505 private:
506 nsresult EnsureTemporaryStorageIsInitializedInternal();
508 public:
509 RefPtr<BoolPromise> InitializeAllTemporaryOrigins();
511 RefPtr<OriginUsageMetadataArrayPromise> GetUsage(
512 bool aGetAll, RefPtr<BoolPromise> aOnCancelPromise = nullptr);
514 RefPtr<UsageInfoPromise> GetOriginUsage(
515 const PrincipalInfo& aPrincipalInfo,
516 RefPtr<BoolPromise> aOnCancelPromise = nullptr);
518 RefPtr<UInt64Promise> GetCachedOriginUsage(
519 const PrincipalInfo& aPrincipalInfo);
521 RefPtr<CStringArrayPromise> ListOrigins();
523 RefPtr<CStringArrayPromise> ListCachedOrigins();
525 RefPtr<BoolPromise> ClearStoragesForOrigin(
526 const Maybe<PersistenceType>& aPersistenceType,
527 const PrincipalInfo& aPrincipalInfo);
529 RefPtr<BoolPromise> ClearStoragesForClient(
530 Maybe<PersistenceType> aPersistenceType,
531 const PrincipalInfo& aPrincipalInfo, Client::Type aClientType);
533 RefPtr<BoolPromise> ClearStoragesForOriginPrefix(
534 const Maybe<PersistenceType>& aPersistenceType,
535 const PrincipalInfo& aPrincipalInfo);
537 RefPtr<BoolPromise> ClearStoragesForOriginAttributesPattern(
538 const OriginAttributesPattern& aPattern);
540 RefPtr<BoolPromise> ClearPrivateRepository();
542 RefPtr<BoolPromise> ClearStorage();
544 RefPtr<BoolPromise> ShutdownStoragesForOrigin(
545 Maybe<PersistenceType> aPersistenceType,
546 const PrincipalInfo& aPrincipalInfo);
548 RefPtr<BoolPromise> ShutdownStoragesForClient(
549 Maybe<PersistenceType> aPersistenceType,
550 const PrincipalInfo& aPrincipalInfo, Client::Type aClientType);
552 RefPtr<BoolPromise> ShutdownStorage(
553 Maybe<OriginOperationCallbackOptions> aCallbackOptions = Nothing(),
554 Maybe<OriginOperationCallbacks&> aCallbacks = Nothing());
556 void ShutdownStorageInternal();
558 // Returns a bool indicating whether the directory was newly created.
559 Result<bool, nsresult> EnsureOriginDirectory(nsIFile& aDirectory);
561 nsresult AboutToClearOrigins(const PersistenceScope& aPersistenceScope,
562 const OriginScope& aOriginScope,
563 const Nullable<Client::Type>& aClientType);
565 void OriginClearCompleted(const OriginMetadata& aOriginMetadata,
566 const Nullable<Client::Type>& aClientType);
568 void RepositoryClearCompleted(PersistenceType aPersistenceType);
570 void StartIdleMaintenance() {
571 AssertIsOnOwningThread();
573 for (const auto& client : *mClients) {
574 client->StartIdleMaintenance();
577 NotifyMaintenanceStarted(*this);
580 void StopIdleMaintenance() {
581 AssertIsOnOwningThread();
583 for (const auto& client : *mClients) {
584 client->StopIdleMaintenance();
588 void AssertCurrentThreadOwnsQuotaMutex() {
589 mQuotaMutex.AssertCurrentThreadOwns();
592 void AssertNotCurrentThreadOwnsQuotaMutex() {
593 mQuotaMutex.AssertNotCurrentThreadOwns();
596 nsIThread* IOThread() { return mIOThread->get(); }
598 Client* GetClient(Client::Type aClientType);
600 const AutoTArray<Client::Type, Client::TYPE_MAX>& AllClientTypes();
602 const nsString& GetBasePath() const { return mBasePath; }
604 const nsString& GetStorageName() const { return mStorageName; }
606 const nsString& GetStoragePath() const { return *mStoragePath; }
608 const nsString& GetStoragePath(PersistenceType aPersistenceType) const {
609 if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
610 return *mPermanentStoragePath;
613 if (aPersistenceType == PERSISTENCE_TYPE_TEMPORARY) {
614 return *mTemporaryStoragePath;
617 if (aPersistenceType == PERSISTENCE_TYPE_DEFAULT) {
618 return *mDefaultStoragePath;
621 MOZ_ASSERT(aPersistenceType == PERSISTENCE_TYPE_PRIVATE);
623 return *mPrivateStoragePath;
626 bool IsThumbnailPrivateIdentityIdKnown() const;
628 uint32_t GetThumbnailPrivateIdentityId() const;
630 void SetThumbnailPrivateIdentityId(uint32_t aThumbnailPrivateIdentityId);
632 uint64_t GetGroupLimit() const;
634 std::pair<uint64_t, uint64_t> GetUsageAndLimitForEstimate(
635 const OriginMetadata& aOriginMetadata);
637 uint64_t GetOriginUsage(const PrincipalMetadata& aPrincipalMetadata);
639 Maybe<FullOriginMetadata> GetFullOriginMetadata(
640 const OriginMetadata& aOriginMetadata);
643 * Retrieves the total number of directory iterations performed.
645 * @return The total count of directory iterations, which is currently
646 * incremented only during clearing operations.
648 uint64_t TotalDirectoryIterations() const;
650 // Record a quota client shutdown step, if shutting down.
651 // Assumes that the QuotaManager singleton is alive.
652 static void MaybeRecordQuotaClientShutdownStep(
653 const Client::Type aClientType, const nsACString& aStepDescription);
655 // Record a quota client shutdown step, if shutting down.
656 // Checks if the QuotaManager singleton is alive.
657 static void SafeMaybeRecordQuotaClientShutdownStep(
658 Client::Type aClientType, const nsACString& aStepDescription);
660 // Record a quota manager shutdown step, use only if shutdown is active.
661 void RecordQuotaManagerShutdownStep(const nsACString& aStepDescription);
663 // Record a quota manager shutdown step, if shutting down.
664 void MaybeRecordQuotaManagerShutdownStep(const nsACString& aStepDescription);
666 template <typename F>
667 void MaybeRecordQuotaManagerShutdownStepWith(F&& aFunc);
669 static void GetStorageId(PersistenceType aPersistenceType,
670 const nsACString& aOrigin, Client::Type aClientType,
671 nsACString& aDatabaseId);
673 static bool IsOriginInternal(const nsACString& aOrigin);
675 static bool AreOriginsEqualOnDisk(const nsACString& aOrigin1,
676 const nsACString& aOrigin2);
678 // XXX This method currently expects the original origin string (not yet
679 // sanitized).
680 static Result<PrincipalInfo, nsresult> ParseOrigin(const nsACString& aOrigin);
682 static void InvalidateQuotaCache();
684 private:
685 virtual ~QuotaManager();
687 nsresult Init();
689 void Shutdown();
691 void RegisterDirectoryLock(DirectoryLockImpl& aLock);
693 void UnregisterDirectoryLock(DirectoryLockImpl& aLock);
695 void AddPendingDirectoryLock(DirectoryLockImpl& aLock);
697 void RemovePendingDirectoryLock(DirectoryLockImpl& aLock);
699 uint64_t LockedCollectOriginsForEviction(
700 uint64_t aMinSizeToBeFreed,
701 nsTArray<RefPtr<OriginDirectoryLock>>& aLocks);
703 void LockedRemoveQuotaForRepository(PersistenceType aPersistenceType);
705 void LockedRemoveQuotaForOrigin(const OriginMetadata& aOriginMetadata);
707 bool LockedHasGroupInfoPair(const nsACString& aGroup) const;
709 already_AddRefed<GroupInfo> LockedGetOrCreateGroupInfo(
710 PersistenceType aPersistenceType, const nsACString& aSuffix,
711 const nsACString& aGroup);
713 already_AddRefed<OriginInfo> LockedGetOriginInfo(
714 PersistenceType aPersistenceType,
715 const OriginMetadata& aOriginMetadata) const;
717 nsresult UpgradeFromIndexedDBDirectoryToPersistentStorageDirectory(
718 nsIFile* aIndexedDBDir);
720 nsresult UpgradeFromPersistentStorageDirectoryToDefaultStorageDirectory(
721 nsIFile* aPersistentStorageDir);
723 nsresult MaybeUpgradeToDefaultStorageDirectory(nsIFile& aStorageFile);
725 template <typename Helper>
726 nsresult UpgradeStorage(const int32_t aOldVersion, const int32_t aNewVersion,
727 mozIStorageConnection* aConnection);
729 nsresult UpgradeStorageFrom0_0To1_0(mozIStorageConnection* aConnection);
731 nsresult UpgradeStorageFrom1_0To2_0(mozIStorageConnection* aConnection);
733 nsresult UpgradeStorageFrom2_0To2_1(mozIStorageConnection* aConnection);
735 nsresult UpgradeStorageFrom2_1To2_2(mozIStorageConnection* aConnection);
737 nsresult UpgradeStorageFrom2_2To2_3(mozIStorageConnection* aConnection);
739 nsresult MaybeCreateOrUpgradeStorage(mozIStorageConnection& aConnection);
741 OkOrErr MaybeRemoveLocalStorageArchiveTmpFile();
743 nsresult MaybeRemoveLocalStorageDataAndArchive(nsIFile& aLsArchiveFile);
745 nsresult MaybeRemoveLocalStorageDirectories();
747 Result<Ok, nsresult> CopyLocalStorageArchiveFromWebAppsStore(
748 nsIFile& aLsArchiveFile) const;
750 Result<nsCOMPtr<mozIStorageConnection>, nsresult>
751 CreateLocalStorageArchiveConnection(nsIFile& aLsArchiveFile) const;
753 Result<nsCOMPtr<mozIStorageConnection>, nsresult>
754 RecopyLocalStorageArchiveFromWebAppsStore(nsIFile& aLsArchiveFile);
756 Result<nsCOMPtr<mozIStorageConnection>, nsresult>
757 DowngradeLocalStorageArchive(nsIFile& aLsArchiveFile);
759 Result<nsCOMPtr<mozIStorageConnection>, nsresult>
760 UpgradeLocalStorageArchiveFromLessThan4To4(nsIFile& aLsArchiveFile);
763 nsresult UpgradeLocalStorageArchiveFrom4To5();
766 Result<Ok, nsresult> MaybeCreateOrUpgradeLocalStorageArchive(
767 nsIFile& aLsArchiveFile);
769 Result<Ok, nsresult> CreateEmptyLocalStorageArchive(
770 nsIFile& aLsArchiveFile) const;
772 template <typename OriginFunc>
773 nsresult InitializeRepository(PersistenceType aPersistenceType,
774 OriginFunc&& aOriginFunc);
776 nsresult InitializeOrigin(PersistenceType aPersistenceType,
777 const OriginMetadata& aOriginMetadata,
778 int64_t aAccessTime, bool aPersisted,
779 nsIFile* aDirectory, bool aForGroup = false);
781 using OriginInfosFlatTraversable =
782 nsTArray<NotNull<RefPtr<const OriginInfo>>>;
784 using OriginInfosNestedTraversable =
785 nsTArray<nsTArray<NotNull<RefPtr<const OriginInfo>>>>;
787 OriginInfosNestedTraversable GetOriginInfosExceedingGroupLimit() const;
789 OriginInfosNestedTraversable GetOriginInfosExceedingGlobalLimit() const;
791 void ClearOrigins(const OriginInfosNestedTraversable& aDoomedOriginInfos);
793 void CleanupTemporaryStorage();
795 void DeleteOriginDirectory(const OriginMetadata& aOriginMetadata);
797 void FinalizeOriginEviction(nsTArray<RefPtr<OriginDirectoryLock>>&& aLocks);
799 Result<Ok, nsresult> ArchiveOrigins(
800 const nsTArray<FullOriginMetadata>& aFullOriginMetadatas);
802 void ReleaseIOThreadObjects() {
803 AssertIsOnIOThread();
805 for (Client::Type type : AllClientTypes()) {
806 (*mClients)[type]->ReleaseIOThreadObjects();
810 DirectoryLockTable& GetDirectoryLockTable(PersistenceType aPersistenceType);
812 void ClearDirectoryLockTables();
814 void AddTemporaryOrigin(const FullOriginMetadata& aFullOriginMetadata);
816 void RemoveTemporaryOrigin(const OriginMetadata& aOriginMetadata);
818 void RemoveTemporaryOrigins(PersistenceType aPersistenceType);
820 void RemoveTemporaryOrigins();
823 * Retrieves the count of thumbnail private identity temporary origins.
825 * This method returns the current count of temporary origins associated with
826 * thumbnail private identity contexts. It requires that the thumbnail
827 * private identity id is known.
829 * @return The count of thumbnail private identity temporary origins.
831 * @note The thumbnail private identity id must be known before calling this
832 * method. If the id is not known, it will cause a debug assertion failure
833 * due to the `MOZ_ASSERT`.
835 uint32_t ThumbnailPrivateIdentityTemporaryOriginCount() const;
837 PrincipalMetadataArray GetAllTemporaryGroups() const;
839 OriginMetadataArray GetAllTemporaryOrigins() const;
841 void NoteInitializedOrigin(PersistenceType aPersistenceType,
842 const nsACString& aOrigin);
844 void NoteUninitializedOrigins(
845 const OriginMetadataArray& aOriginMetadataArray);
847 void NoteUninitializedRepository(PersistenceType aPersistenceType);
849 bool IsOriginInitialized(PersistenceType aPersistenceType,
850 const nsACString& aOrigin) const;
852 bool IsSanitizedOriginValid(const nsACString& aSanitizedOrigin);
854 Result<nsCString, nsresult> EnsureStorageOriginFromOrigin(
855 const nsACString& aOrigin);
857 Result<nsCString, nsresult> GetOriginFromStorageOrigin(
858 const nsACString& aStorageOrigin);
860 int64_t GenerateDirectoryLockId();
862 bool ShutdownStarted() const;
864 void RecordShutdownStep(Maybe<Client::Type> aClientType,
865 const nsACString& aStepDescription);
867 template <typename Func>
868 auto ExecuteInitialization(Initialization aInitialization, Func&& aFunc)
869 -> std::invoke_result_t<Func, const FirstInitializationAttempt<
870 Initialization, StringGenerator>&>;
872 template <typename Func>
873 auto ExecuteInitialization(Initialization aInitialization,
874 const nsACString& aContext, Func&& aFunc)
875 -> std::invoke_result_t<Func, const FirstInitializationAttempt<
876 Initialization, StringGenerator>&>;
878 template <typename Func>
879 auto ExecuteGroupInitialization(const nsACString& aGroup,
880 const GroupInitialization aInitialization,
881 const nsACString& aContext, Func&& aFunc)
882 -> std::invoke_result_t<Func, const FirstInitializationAttempt<
883 Initialization, StringGenerator>&>;
885 template <typename Func>
886 auto ExecuteOriginInitialization(const nsACString& aOrigin,
887 const OriginInitialization aInitialization,
888 const nsACString& aContext, Func&& aFunc)
889 -> std::invoke_result_t<Func, const FirstInitializationAttempt<
890 Initialization, StringGenerator>&>;
893 * Increments the counter tracking the total number of directory iterations.
895 * @note This is currently called only during clearing operations to update
896 * the mTotalDirectoryIterations member.
898 void IncreaseTotalDirectoryIterations();
900 template <typename Iterator>
901 static void MaybeInsertNonPersistedOriginInfos(
902 Iterator aDest, const RefPtr<GroupInfo>& aTemporaryGroupInfo,
903 const RefPtr<GroupInfo>& aDefaultGroupInfo,
904 const RefPtr<GroupInfo>& aPrivateGroupInfo);
906 template <typename Collect, typename Pred>
907 static OriginInfosFlatTraversable CollectLRUOriginInfosUntil(
908 Collect&& aCollect, Pred&& aPred);
910 // Thread on which IO is performed.
911 LazyInitializedOnceNotNull<const nsCOMPtr<nsIThread>> mIOThread;
913 nsCOMPtr<mozIStorageConnection> mStorageConnection;
915 EnumeratedArray<Client::Type, nsCString, size_t(Client::TYPE_MAX)>
916 mShutdownSteps;
917 LazyInitializedOnce<const TimeStamp> mShutdownStartedAt;
919 // Accesses to mQuotaManagerShutdownSteps must be protected by mQuotaMutex.
920 nsCString mQuotaManagerShutdownSteps;
922 mutable mozilla::Mutex mQuotaMutex MOZ_UNANNOTATED;
924 nsClassHashtable<nsCStringHashKey, GroupInfoPair> mGroupInfoPairs;
926 // Maintains a list of directory locks that are queued.
927 nsTArray<RefPtr<DirectoryLockImpl>> mPendingDirectoryLocks;
929 // Maintains a list of directory locks that are acquired or queued. It can be
930 // accessed on the owning (PBackground) thread only.
931 nsTArray<NotNull<DirectoryLockImpl*>> mDirectoryLocks;
933 // Only modifed on the owning thread, but read on multiple threads. Therefore
934 // all modifications (including those on the owning thread) and all reads off
935 // the owning thread must be protected by mQuotaMutex. In other words, only
936 // reads on the owning thread don't have to be protected by mQuotaMutex.
937 nsTHashMap<nsUint64HashKey, NotNull<DirectoryLockImpl*>>
938 mDirectoryLockIdTable;
940 // Directory lock tables that are used to update origin access time.
941 DirectoryLockTable mTemporaryDirectoryLockTable;
942 DirectoryLockTable mDefaultDirectoryLockTable;
943 DirectoryLockTable mPrivateDirectoryLockTable;
945 // Things touched on the owning (PBackground) thread only.
946 struct BackgroundThreadAccessible {
947 PrincipalMetadataArray mUninitializedGroups;
948 nsTHashSet<nsCString> mInitializedGroups;
950 ThreadBound<BackgroundThreadAccessible> mBackgroundThreadAccessible;
952 using BoolArray = AutoTArray<bool, PERSISTENCE_TYPE_INVALID>;
953 nsTHashMap<nsCStringHashKeyWithDisabledMemmove, BoolArray>
954 mInitializedOrigins;
956 // Things touched on the IO thread only.
957 struct IOThreadAccessible {
958 nsTHashMap<nsCStringHashKey, nsTArray<FullOriginMetadata>>
959 mAllTemporaryOrigins;
960 Maybe<uint32_t> mThumbnailPrivateIdentityId;
961 // Tracks the total number of directory iterations.
962 // Note: This is currently incremented only during clearing operations.
963 uint64_t mTotalDirectoryIterations = 0;
964 // Tracks the count of thumbnail private identity temporary origins.
965 uint32_t mThumbnailPrivateIdentityTemporaryOriginCount = 0;
967 ThreadBound<IOThreadAccessible> mIOThreadAccessible;
969 // A list of all successfully initialized persistent origins. This list isn't
970 // protected by any mutex but it is only ever touched on the IO thread.
971 nsTArray<nsCString> mInitializedOriginsInternal;
973 // A hash table that is used to cache origin parser results for given
974 // sanitized origin strings. This hash table isn't protected by any mutex but
975 // it is only ever touched on the IO thread.
976 nsTHashMap<nsCStringHashKey, bool> mValidOrigins;
978 // These maps are protected by mQuotaMutex.
979 nsTHashMap<nsCStringHashKey, nsCString> mOriginToStorageOriginMap;
980 nsTHashMap<nsCStringHashKey, nsCString> mStorageOriginToOriginMap;
982 // This array is populated at initialization time and then never modified, so
983 // it can be iterated on any thread.
984 LazyInitializedOnce<const AutoTArray<RefPtr<Client>, Client::TYPE_MAX>>
985 mClients;
987 using ClientTypesArray = AutoTArray<Client::Type, Client::TYPE_MAX>;
988 LazyInitializedOnce<const ClientTypesArray> mAllClientTypes;
989 LazyInitializedOnce<const ClientTypesArray> mAllClientTypesExceptLS;
991 // This object isn't protected by any mutex but it is only ever touched on
992 // the IO thread.
993 InitializationInfo mInitializationInfo;
995 const nsString mBasePath;
996 const nsString mStorageName;
997 LazyInitializedOnce<const nsString> mIndexedDBPath;
998 LazyInitializedOnce<const nsString> mStoragePath;
999 LazyInitializedOnce<const nsString> mStorageArchivesPath;
1000 LazyInitializedOnce<const nsString> mPermanentStoragePath;
1001 LazyInitializedOnce<const nsString> mTemporaryStoragePath;
1002 LazyInitializedOnce<const nsString> mDefaultStoragePath;
1003 LazyInitializedOnce<const nsString> mPrivateStoragePath;
1004 LazyInitializedOnce<const nsString> mToBeRemovedStoragePath;
1006 MozPromiseHolder<BoolPromise> mInitializeAllTemporaryOriginsPromiseHolder;
1008 uint64_t mTemporaryStorageLimit;
1009 uint64_t mTemporaryStorageUsage;
1010 int64_t mNextDirectoryLockId;
1011 bool mStorageInitialized;
1012 bool mPersistentStorageInitialized;
1013 bool mPersistentStorageInitializedInternal;
1014 bool mTemporaryStorageInitialized;
1015 bool mTemporaryStorageInitializedInternal;
1016 bool mInitializingAllTemporaryOrigins;
1017 bool mAllTemporaryOriginsInitialized;
1018 bool mCacheUsable;
1021 } // namespace mozilla::dom::quota
1023 #endif /* mozilla_dom_quota_quotamanager_h__ */