Bug 1645943 - Check results from nsIFile's functions rather than mozStorage's/SQLite's in LockedGetPaddingSizeFromDB; r=janv,dom-workers-and-storage-reviewers,sg
authorTom Tung <ttung@mozilla.com>
Tue, 23 Jun 2020 06:38:25 +0000
changeset 536730 5e40accdea69d32cba2f37927f734f08146d8836
parent 536729 b09c7ddea2a4f6fd64cbb16e1e93d54c1ec8cf60
child 536731 9556117ca7806e17b79f8e894a13ba226b09c300
push id37532
push userabutkovits@mozilla.com
push dateTue, 23 Jun 2020 16:15:06 +0000
treeherdermozilla-central@3add3a174755 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjanv, dom-workers-and-storage-reviewers, sg
bugs1645943
milestone79.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1645943 - Check results from nsIFile's functions rather than mozStorage's/SQLite's in LockedGetPaddingSizeFromDB; r=janv,dom-workers-and-storage-reviewers,sg Differential Revision: https://phabricator.services.mozilla.com/D79959
dom/cache/DBAction.cpp
dom/cache/DBAction.h
dom/cache/QuotaClient.cpp
dom/cache/QuotaClient.h
--- a/dom/cache/DBAction.cpp
+++ b/dom/cache/DBAction.cpp
@@ -28,36 +28,42 @@ namespace cache {
 using mozilla::dom::quota::AssertIsOnIOThread;
 using mozilla::dom::quota::Client;
 using mozilla::dom::quota::IntCString;
 using mozilla::dom::quota::PERSISTENCE_TYPE_DEFAULT;
 using mozilla::dom::quota::PersistenceType;
 
 namespace {
 
-nsresult WipeDatabase(const QuotaInfo& aQuotaInfo, nsIFile* aDBFile,
-                      nsIFile* aDBDir) {
+nsresult WipeDatabase(const QuotaInfo& aQuotaInfo, nsIFile* aDBFile) {
   MOZ_DIAGNOSTIC_ASSERT(aDBFile);
-  MOZ_DIAGNOSTIC_ASSERT(aDBDir);
 
-  nsresult rv = RemoveNsIFile(aQuotaInfo, aDBFile);
+  nsCOMPtr<nsIFile> dbDir;
+  nsresult rv = aDBFile->GetParent(getter_AddRefs(dbDir));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  MOZ_ASSERT(dbDir);
+
+  rv = RemoveNsIFile(aQuotaInfo, aDBFile);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   // Note, the -wal journal file will be automatically deleted by sqlite when
   // the new database is created.  No need to explicitly delete it here.
 
   // Delete the morgue as well.
-  rv = BodyDeleteDir(aQuotaInfo, aDBDir);
+  rv = BodyDeleteDir(aQuotaInfo, dbDir);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
-  rv = WipePaddingFile(aQuotaInfo, aDBDir);
+  rv = WipePaddingFile(aQuotaInfo, dbDir);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   return rv;
 }
 
 }  // namespace
@@ -139,19 +145,28 @@ nsresult DBAction::OpenConnection(const 
       return NS_ERROR_FILE_NOT_FOUND;
     }
     rv = aDBDir->Create(nsIFile::DIRECTORY_TYPE, 0755);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 
-  rv = OpenDBConnection(aQuotaInfo, aDBDir, aConnOut);
+  nsCOMPtr<nsIFile> dbFile;
+  rv = aDBDir->Clone(getter_AddRefs(dbFile));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
 
-  return rv;
+  rv = dbFile->Append(kCachesSQLiteFilename);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  return OpenDBConnection(aQuotaInfo, dbFile, aConnOut);
 }
 
 SyncDBAction::SyncDBAction(Mode aMode) : DBAction(aMode) {}
 
 SyncDBAction::~SyncDBAction() = default;
 
 void SyncDBAction::RunWithDBOnTarget(Resolver* aResolver,
                                      const QuotaInfo& aQuotaInfo,
@@ -162,54 +177,35 @@ void SyncDBAction::RunWithDBOnTarget(Res
   MOZ_DIAGNOSTIC_ASSERT(aDBDir);
   MOZ_DIAGNOSTIC_ASSERT(aConn);
 
   nsresult rv = RunSyncWithDBOnTarget(aQuotaInfo, aDBDir, aConn);
   aResolver->Resolve(rv);
 }
 
 // static
-nsresult OpenDBConnection(const QuotaInfo& aQuotaInfo, nsIFile* aDBDir,
+nsresult OpenDBConnection(const QuotaInfo& aQuotaInfo, nsIFile* aDBFile,
                           mozIStorageConnection** aConnOut) {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_DIAGNOSTIC_ASSERT(aQuotaInfo.mDirectoryLockId >= -1);
-  MOZ_DIAGNOSTIC_ASSERT(aDBDir);
+  MOZ_DIAGNOSTIC_ASSERT(aDBFile);
   MOZ_DIAGNOSTIC_ASSERT(aConnOut);
 
-  nsCOMPtr<mozIStorageConnection> conn;
-
-  nsCOMPtr<nsIFile> dbFile;
-  nsresult rv = aDBDir->Clone(getter_AddRefs(dbFile));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  rv = dbFile->Append(NS_LITERAL_STRING("caches.sqlite"));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  bool exists = false;
-  rv = dbFile->Exists(&exists);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
   // Use our default file:// protocol handler directly to construct the database
   // URL.  This avoids any problems if a plugin registers a custom file://
   // handler.  If such a custom handler used javascript, then we would have a
   // bad time running off the main thread here.
   RefPtr<nsFileProtocolHandler> handler = new nsFileProtocolHandler();
-  rv = handler->Init();
+  nsresult rv = handler->Init();
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   nsCOMPtr<nsIURIMutator> mutator;
-  rv = handler->NewFileURIMutator(dbFile, getter_AddRefs(mutator));
+  rv = handler->NewFileURIMutator(aDBFile, getter_AddRefs(mutator));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   nsCOMPtr<nsIFileURL> dbFileUrl;
 
   const nsCString directoryLockIdClause =
       aQuotaInfo.mDirectoryLockId >= 0
@@ -226,25 +222,26 @@ nsresult OpenDBConnection(const QuotaInf
   }
 
   nsCOMPtr<mozIStorageService> ss =
       do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
   if (NS_WARN_IF(!ss)) {
     return NS_ERROR_UNEXPECTED;
   }
 
+  nsCOMPtr<mozIStorageConnection> conn;
   rv = ss->OpenDatabaseWithFileURL(dbFileUrl, getter_AddRefs(conn));
   if (rv == NS_ERROR_FILE_CORRUPTED) {
     NS_WARNING("Cache database corrupted. Recreating empty database.");
 
     conn = nullptr;
 
     // There is nothing else we can do to recover.  Also, this data can
     // be deleted by QuotaManager at any time anyways.
-    rv = WipeDatabase(aQuotaInfo, dbFile, aDBDir);
+    rv = WipeDatabase(aQuotaInfo, aDBFile);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     rv = ss->OpenDatabaseWithFileURL(dbFileUrl, getter_AddRefs(conn));
   }
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
@@ -253,17 +250,17 @@ nsresult OpenDBConnection(const QuotaInf
   // Check the schema to make sure it is not too old.
   int32_t schemaVersion = 0;
   rv = conn->GetSchemaVersion(&schemaVersion);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
   if (schemaVersion > 0 && schemaVersion < db::kFirstShippedSchemaVersion) {
     conn = nullptr;
-    rv = WipeDatabase(aQuotaInfo, dbFile, aDBDir);
+    rv = WipeDatabase(aQuotaInfo, aDBFile);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     rv = ss->OpenDatabaseWithFileURL(dbFileUrl, getter_AddRefs(conn));
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
--- a/dom/cache/DBAction.h
+++ b/dom/cache/DBAction.h
@@ -13,17 +13,17 @@
 
 class mozIStorageConnection;
 class nsIFile;
 
 namespace mozilla {
 namespace dom {
 namespace cache {
 
-nsresult OpenDBConnection(const QuotaInfo& aQuotaInfo, nsIFile* aDBDir,
+nsresult OpenDBConnection(const QuotaInfo& aQuotaInfo, nsIFile* aDBFile,
                           mozIStorageConnection** aConnOut);
 
 class DBAction : public Action {
  protected:
   // The mode specifies whether the database should already exist or if its
   // ok to create a new database.
   enum Mode { Existing, Create };
 
--- a/dom/cache/QuotaClient.cpp
+++ b/dom/cache/QuotaClient.cpp
@@ -22,16 +22,17 @@
 namespace {
 
 using mozilla::Atomic;
 using mozilla::MutexAutoLock;
 using mozilla::Some;
 using mozilla::Unused;
 using mozilla::dom::ContentParentId;
 using mozilla::dom::cache::DirPaddingFile;
+using mozilla::dom::cache::kCachesSQLiteFilename;
 using mozilla::dom::cache::Manager;
 using mozilla::dom::cache::QuotaInfo;
 using mozilla::dom::quota::AssertIsOnIOThread;
 using mozilla::dom::quota::Client;
 using mozilla::dom::quota::PERSISTENCE_TYPE_DEFAULT;
 using mozilla::dom::quota::PersistenceType;
 using mozilla::dom::quota::QuotaManager;
 using mozilla::dom::quota::UsageInfo;
@@ -119,25 +120,45 @@ static nsresult LockedGetPaddingSizeFrom
   // because this method should only be called from QuotaClient::InitOrigin
   // (via QuotaClient::GetUsageForOriginInternal) when the temporary storage
   // hasn't been initialized yet. At that time, the in-memory objects (e.g.
   // OriginInfo) are only being created so it doesn't make sense to tunnel
   // quota information to TelemetryVFS to get corresponding QuotaObject instance
   // for the SQLite file).
   MOZ_DIAGNOSTIC_ASSERT(quotaInfo.mDirectoryLockId == -1);
 
-  nsCOMPtr<mozIStorageConnection> conn;
-  nsresult rv = mozilla::dom::cache::OpenDBConnection(quotaInfo, aDir,
-                                                      getter_AddRefs(conn));
-  if (rv == NS_ERROR_FILE_NOT_FOUND ||
-      rv == NS_ERROR_FILE_TARGET_DOES_NOT_EXIST) {
-    // Return NS_OK with size = 0 if both the db and padding file don't exist.
-    // There is no other way to get the overall padding size of an origin.
+  nsCOMPtr<nsIFile> dbFile;
+  nsresult rv = aDir->Clone(getter_AddRefs(dbFile));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = dbFile->Append(kCachesSQLiteFilename);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  bool exists = false;
+  rv = dbFile->Exists(&exists);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  // Return NS_OK with size = 0 if caches.sqlite doesn't exist.
+  // This function is only called if the value of the padding size couldn't be
+  // determined from the padding file, possibly because it doesn't exist, or a
+  // leftover temporary padding file was found.
+  // There is no other way to get the overall padding size of an origin.
+  if (!exists) {
     return NS_OK;
   }
+
+  nsCOMPtr<mozIStorageConnection> conn;
+  rv = mozilla::dom::cache::OpenDBConnection(quotaInfo, dbFile,
+                                             getter_AddRefs(conn));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   // Make sure that the database has the latest schema before we try to read
   // from it. We have to do this because LockedGetPaddingSizeFromDB is called
   // by QuotaClient::GetUsageForOrigin which may run at any time (there's no
   // guarantee that SetupAction::RunSyncWithDBOnTarget already checked the
@@ -160,16 +181,18 @@ static nsresult LockedGetPaddingSizeFrom
 }
 
 }  // namespace
 
 namespace mozilla {
 namespace dom {
 namespace cache {
 
+NS_NAMED_LITERAL_STRING(kCachesSQLiteFilename, "caches.sqlite");
+
 CacheQuotaClient::CacheQuotaClient()
     : mDirPaddingFileMutex("DOMCacheQuotaClient.mDirPaddingFileMutex") {
   AssertIsOnBackgroundThread();
   MOZ_DIAGNOSTIC_ASSERT(!sInstance);
   sInstance = this;
 }
 
 // static
@@ -455,17 +478,17 @@ nsresult CacheQuotaClient::GetUsageForOr
     if (leafName.EqualsLiteral("caches.sqlite-journal") ||
         leafName.EqualsLiteral("caches.sqlite-shm") ||
         leafName.Find(NS_LITERAL_CSTRING("caches.sqlite-mj"), false, 0, 0) ==
             0 ||
         leafName.EqualsLiteral("context_open.marker")) {
       continue;
     }
 
-    if (leafName.EqualsLiteral("caches.sqlite") ||
+    if (leafName.Equals(kCachesSQLiteFilename) ||
         leafName.EqualsLiteral("caches.sqlite-wal")) {
       int64_t fileSize;
       rv = file->GetFileSize(&fileSize);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         REPORT_TELEMETRY_ERR_IN_INIT(aInitializing, kQuotaExternalError,
                                      Cache_GetFileSize);
         return rv;
       }
--- a/dom/cache/QuotaClient.h
+++ b/dom/cache/QuotaClient.h
@@ -36,13 +36,15 @@ already_AddRefed<quota::Client> CreateQu
  * represents that the previous action is failed and the content of padding file
  * cannot be trusted, and we need to restore the padding file from the database.
  */
 
 nsresult RestorePaddingFile(nsIFile* aBaseDir, mozIStorageConnection* aConn);
 
 nsresult WipePaddingFile(const QuotaInfo& aQuotaInfo, nsIFile* aBaseDir);
 
+extern const nsLiteralString kCachesSQLiteFilename;
+
 }  // namespace cache
 }  // namespace dom
 }  // namespace mozilla
 
 #endif  // mozilla_dom_cache_QuotaClient_h