Bug 1951283 - Speedup id lookups by using a hash set in BodyDeleteOrphanedFiles. r=dom-storage-reviewers,asuth

The basic functionality remains the same, including the use of
BodyTraverseFile with all its cleanups.

Differential Revision: https://phabricator.services.mozilla.com/D240734
This commit is contained in:
Jens Stutte
2025-03-08 22:11:09 +00:00
parent 968563f972
commit 4506cefa1a
5 changed files with 38 additions and 16 deletions

View File

@@ -727,19 +727,36 @@ Result<int64_t, nsresult> GetTotalDiskUsage(mozIStorageConnection& aConn) {
QM_TRY_RETURN(MOZ_TO_RESULT_INVOKE_MEMBER(*state, GetInt64, 0)); QM_TRY_RETURN(MOZ_TO_RESULT_INVOKE_MEMBER(*state, GetInt64, 0));
} }
Result<nsTArray<nsID>, nsresult> GetKnownBodyIds(mozIStorageConnection& aConn) { Result<nsTHashSet<nsID>, nsresult> GetKnownBodyIds(
mozIStorageConnection& aConn) {
MOZ_ASSERT(!NS_IsMainThread()); MOZ_ASSERT(!NS_IsMainThread());
int32_t numEntries = 0;
{
QM_TRY_INSPECT(const auto& cnt,
MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(
nsCOMPtr<mozIStorageStatement>, aConn, CreateStatement,
"SELECT COUNT(*) FROM entries;"_ns));
QM_TRY(quota::CollectWhileHasResult(
*cnt, [&numEntries](auto& stmt) -> Result<Ok, nsresult> {
QM_TRY(MOZ_TO_RESULT(stmt.GetInt32(0, &numEntries)));
return Ok{};
}));
}
// Each row can have 0 to 2 nsID values, prepare for the maximum.
nsTHashSet<nsID> idSet(numEntries * 2);
QM_TRY_INSPECT( QM_TRY_INSPECT(
const auto& state, const auto& state,
MOZ_TO_RESULT_INVOKE_MEMBER_TYPED( MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(
nsCOMPtr<mozIStorageStatement>, aConn, CreateStatement, nsCOMPtr<mozIStorageStatement>, aConn, CreateStatement,
"SELECT request_body_id, response_body_id FROM entries;"_ns)); "SELECT request_body_id, response_body_id FROM entries;"_ns));
AutoTArray<nsID, 64> idList;
QM_TRY(quota::CollectWhileHasResult( QM_TRY(quota::CollectWhileHasResult(
*state, [&idList](auto& stmt) -> Result<Ok, nsresult> { *state, [&idSet](auto& stmt) -> Result<Ok, nsresult> {
// extract 0 to 2 nsID structs per row // extract 0 to 2 nsID structs per row
for (uint32_t i = 0; i < 2; ++i) { for (uint32_t i = 0; i < 2; ++i) {
QM_TRY_INSPECT(const bool& isNull, QM_TRY_INSPECT(const bool& isNull,
@@ -748,14 +765,14 @@ Result<nsTArray<nsID>, nsresult> GetKnownBodyIds(mozIStorageConnection& aConn) {
if (!isNull) { if (!isNull) {
QM_TRY_INSPECT(const auto& id, ExtractId(stmt, i)); QM_TRY_INSPECT(const auto& id, ExtractId(stmt, i));
idList.AppendElement(id); idSet.Insert(id);
} }
} }
return Ok{}; return Ok{};
})); }));
return std::move(idList); return std::move(idSet);
} }
Result<Maybe<SavedResponse>, nsresult> CacheMatch( Result<Maybe<SavedResponse>, nsresult> CacheMatch(

View File

@@ -44,7 +44,8 @@ Result<int64_t, nsresult> FindOverallPaddingSize(mozIStorageConnection& aConn);
Result<int64_t, nsresult> GetTotalDiskUsage(mozIStorageConnection& aConn); Result<int64_t, nsresult> GetTotalDiskUsage(mozIStorageConnection& aConn);
Result<nsTArray<nsID>, nsresult> GetKnownBodyIds(mozIStorageConnection& aConn); Result<nsTHashSet<nsID>, nsresult> GetKnownBodyIds(
mozIStorageConnection& aConn);
Result<Maybe<SavedResponse>, nsresult> CacheMatch( Result<Maybe<SavedResponse>, nsresult> CacheMatch(
mozIStorageConnection& aConn, CacheId aCacheId, mozIStorageConnection& aConn, CacheId aCacheId,

View File

@@ -376,7 +376,7 @@ nsresult DirectoryPaddingWrite(nsIFile& aBaseDir,
nsresult BodyDeleteOrphanedFiles( nsresult BodyDeleteOrphanedFiles(
const CacheDirectoryMetadata& aDirectoryMetadata, nsIFile& aBaseDir, const CacheDirectoryMetadata& aDirectoryMetadata, nsIFile& aBaseDir,
const nsTArray<nsID>& aKnownBodyIdList) { nsTHashSet<nsID>& aKnownBodyIds) {
// body files are stored in a directory structure like: // body files are stored in a directory structure like:
// //
// /morgue/01/{01fdddb2-884d-4c3d-95ba-0c8062f6c325}.final // /morgue/01/{01fdddb2-884d-4c3d-95ba-0c8062f6c325}.final
@@ -388,14 +388,14 @@ nsresult BodyDeleteOrphanedFiles(
// Iterate over all the intermediate morgue subdirs // Iterate over all the intermediate morgue subdirs
QM_TRY(quota::CollectEachFile( QM_TRY(quota::CollectEachFile(
*dir, *dir,
[&aDirectoryMetadata, &aKnownBodyIdList]( [&aDirectoryMetadata, &aKnownBodyIds](
const nsCOMPtr<nsIFile>& subdir) -> Result<Ok, nsresult> { const nsCOMPtr<nsIFile>& subdir) -> Result<Ok, nsresult> {
QM_TRY_INSPECT(const auto& dirEntryKind, GetDirEntryKind(*subdir)); QM_TRY_INSPECT(const auto& dirEntryKind, GetDirEntryKind(*subdir));
switch (dirEntryKind) { switch (dirEntryKind) {
case nsIFileKind::ExistsAsDirectory: { case nsIFileKind::ExistsAsDirectory: {
const auto removeOrphanedFiles = const auto removeOrphanedFiles =
[&aDirectoryMetadata, &aKnownBodyIdList]( [&aDirectoryMetadata, &aKnownBodyIds](
nsIFile& bodyFile, nsIFile& bodyFile,
const nsACString& leafName) -> Result<bool, nsresult> { const nsACString& leafName) -> Result<bool, nsresult> {
// Finally, parse the uuid out of the name. If it fails to parse, // Finally, parse the uuid out of the name. If it fails to parse,
@@ -409,7 +409,7 @@ nsresult BodyDeleteOrphanedFiles(
nsID id; nsID id;
QM_TRY(OkIf(id.Parse(leafName.BeginReading())), true); QM_TRY(OkIf(id.Parse(leafName.BeginReading())), true);
if (!aKnownBodyIdList.Contains(id)) { if (!aKnownBodyIds.Contains(id)) {
return true; return true;
} }

View File

@@ -57,9 +57,11 @@ nsresult BodyMaybeUpdatePaddingSize(
nsresult BodyDeleteFiles(const CacheDirectoryMetadata& aDirectoryMetadata, nsresult BodyDeleteFiles(const CacheDirectoryMetadata& aDirectoryMetadata,
nsIFile& aBaseDir, const nsTArray<nsID>& aIdList); nsIFile& aBaseDir, const nsTArray<nsID>& aIdList);
// Traverse all cache directorys and do a cleanup, leaving only files that
// belong to known body ids behind.
nsresult BodyDeleteOrphanedFiles( nsresult BodyDeleteOrphanedFiles(
const CacheDirectoryMetadata& aDirectoryMetadata, nsIFile& aBaseDir, const CacheDirectoryMetadata& aDirectoryMetadata, nsIFile& aBaseDir,
const nsTArray<nsID>& aKnownBodyIdList); nsTHashSet<nsID>& aKnownBodyIds);
// If aCanRemoveFiles is true, that means we are safe to touch the files which // If aCanRemoveFiles is true, that means we are safe to touch the files which
// can be accessed in other threads. // can be accessed in other threads.

10
dom/cache/Manager.cpp vendored
View File

@@ -149,11 +149,13 @@ class SetupAction final : public SyncDBAction {
return oldValue + deletionInfo.mDeletedPaddingSize; return oldValue + deletionInfo.mDeletedPaddingSize;
})); }));
// Clean up orphaned body objects // Clean up orphaned body objects.
QM_TRY_INSPECT(const auto& knownBodyIdList, db::GetKnownBodyIds(*aConn)); QM_TRY_UNWRAP(auto knownBodyIds, db::GetKnownBodyIds(*aConn));
QM_TRY(MOZ_TO_RESULT(BodyDeleteOrphanedFiles(aDirectoryMetadata, *aDBDir, // Note that this causes a scan of all cached files. See bug 1952550 that
knownBodyIdList))); // wants to reduce the probability to find the marker file above.
QM_TRY(MOZ_TO_RESULT(
BodyDeleteOrphanedFiles(aDirectoryMetadata, *aDBDir, knownBodyIds)));
// Commit() explicitly here, because we want to ensure the padding file // Commit() explicitly here, because we want to ensure the padding file
// has the correct content. // has the correct content.