tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 4d851b34a0aa8b743a08cb64cc00efcfbf2cb9e5
parent 3102e96a538277a8797d7029c46258738ddfecaa
Author: Jan Varga <Jan.Varga@gmail.com>
Date:   Fri, 28 Nov 2025 11:35:14 +0000

Bug 1988590 - QM: Clear non-persisted zero-usage origins; r=dom-storage-reviewers,jari

This patch introduces the actual clearing of non-persisted origins that have
zero quota-charged usage during final steps of temporary storage initialization.

Key aspects:
- Honors the new pref
  dom.quotaManager.temporaryStorage.clearNonPersistedZeroUsageOrigins.
- Excludes recently used origins.
- Uses debug-only assertions to catch accidental clearing of unrelated origins.
- Supports batching to avoid large I/O spikes when many origins need removal.

Telemetry shows a large number of zero-sized origin directories in some cases,
especially on Desktop. This cleanup should help reduce storage bloat and
improve initialization performance, particularly for long-lived profiles with
thousands of unused origins.

Testing: The clearing is exercised in test_temporaryStorageCleanup.js added in
a follow-up patch for this bug.

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

Diffstat:
Mdom/quota/ActorsParent.cpp | 38+++++++++++++++++++++++++++++++++++---
Mdom/quota/Constants.h | 13+++++++++++++
Mdom/quota/Date.h | 7+------
Mmodules/libpref/init/StaticPrefList.yaml | 12+++++++-----
4 files changed, 56 insertions(+), 14 deletions(-)

diff --git a/dom/quota/ActorsParent.cpp b/dom/quota/ActorsParent.cpp @@ -8077,9 +8077,41 @@ void QuotaManager::ClearOrigins( void QuotaManager::CleanupTemporaryStorage() { AssertIsOnIOThread(); - // XXX Maybe clear non-persistent zero usage origins here. Ideally the - // clearing would be done asynchronously by storage maintenance service once - // available. + if (StaticPrefs:: + dom_quotaManager_temporaryStorage_clearNonPersistedZeroUsageOrigins()) { + // XXX Ideally the clearing would be done asynchronously by storage + // maintenance service once available. + + // We hardcode a 7-day cutoff for "recently used" origins. Even if such + // origins have zero usage, skipping them avoids the performance penalty + // of repeatedly recreating origin directories and metadata files. The + // value is fixed for now to keep things simple, but could be made + // configurable in the future if needed. + static_assert(aDefaultCutoffAccessTime == kSecPerWeek * PR_USEC_PER_SEC); + + // Calculate cutoff time (one week ago). PR_Now() returns microseconds + // since epoch, so this cannot realistically overflow. + const int64_t cutoffTime = PR_Now() - aDefaultCutoffAccessTime; + +#ifdef DEBUG + // Verify that origins being cleared meet our criteria: + // non-persisted, zero usage, and outside cutoff window + auto checker = [&self = *this, cutoffTime](const auto& doomedOriginInfo) { + MutexAutoLock lock(self.mQuotaMutex); + MOZ_ASSERT(!doomedOriginInfo->LockedPersisted()); + MOZ_ASSERT(doomedOriginInfo->LockedUsage() == 0); + MOZ_ASSERT(doomedOriginInfo->LockedAccessTime() < cutoffTime); + }; +#else + auto checker = [](const auto&) {}; +#endif + + const size_t maxOriginsToClear = StaticPrefs:: + dom_quotaManager_temporaryStorage_maxOriginsToClearDuringCleanup(); + + ClearOrigins(GetOriginInfosWithZeroUsage(Some(cutoffTime)), + std::move(checker), Some(maxOriginsToClear)); + } // Evicting origins that exceed their group limit also affects the global // temporary storage usage, so these steps have to be taken sequentially. diff --git a/dom/quota/Constants.h b/dom/quota/Constants.h @@ -8,6 +8,7 @@ #define DOM_QUOTA_CONSTANTS_H_ #include "nsLiteralString.h" +#include "prtime.h" // The name of the file that we use to load/save the last access time of an // origin. @@ -19,6 +20,18 @@ namespace mozilla::dom::quota { +// Seconds in one day (24 * 60 * 60). Used for time based calculations across +// quota manager code. +constexpr int64_t kSecPerDay = 86400; + +// Seconds in one week. +constexpr int64_t kSecPerWeek = 7 * kSecPerDay; + +// Default cutoff access time (in microseconds) used for temporary storage +// cleanup. Corresponds to "one week ago" and is used as the threshold when +// clearing non persisted zero usage origins. +constexpr int64_t aDefaultCutoffAccessTime = kSecPerWeek * PR_USEC_PER_SEC; + const char kChromeOrigin[] = "chrome"; constexpr auto kSQLiteSuffix = u".sqlite"_ns; diff --git a/dom/quota/Date.h b/dom/quota/Date.h @@ -8,16 +8,11 @@ #define DOM_QUOTA_DATE_H_ #include "mozilla/CheckedInt.h" +#include "mozilla/dom/quota/Constants.h" #include "prtime.h" namespace mozilla::dom::quota { -namespace { - -const int64_t kSecPerDay = 86400; - -} - /** * A lightweight utility class representing a date as the number of days since * the Unix epoch (1970-01-01 UTC). diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml @@ -4083,11 +4083,13 @@ # temporary storage initialization? # When enabled, the QuotaManager will automatically clear non-persisted # origins that have zero quota-charged usage during final steps of temporary -# storage initialization. This removes directories and files belonging to -# origins that do not store any real data but still consume resources through -# bookkeeping structures on disk. The feature helps reduce storage bloat and -# improve initialization performance, especially on long-lived profiles with a -# large number of unused origins. +# storage initialization. Recently used origins (within the last week) are +# excluded, and clearing is performed in batches to avoid large I/O spikes +# when many origins need to be removed. This removes directories and files +# belonging to origins that do not store any real data but still consume +# resources through bookkeeping structures on disk. The feature helps reduce +# storage bloat and improve initialization performance, especially on +# long-lived profiles with a large number of unused origins. - name: dom.quotaManager.temporaryStorage.clearNonPersistedZeroUsageOrigins type: RelaxedAtomicBool value: false