Bug 1546305 - LSNG: Add temporary support for downgrading; r=asuth
authorJan Varga <jan.varga@gmail.com>
Thu, 25 Apr 2019 11:25:52 +0200
changeset 530261 da2a8881bec105a4ba75ff77a9e61300c1b6141c
parent 530260 58e4cb8fa6400778d4962986c6dec5e63b22ea7d
child 530262 1ac79bd52a1106f850bc78af12c964cba0d3af5c
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersasuth
bugs1546305
milestone68.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 1546305 - LSNG: Add temporary support for downgrading; r=asuth Differential Revision: https://phabricator.services.mozilla.com/D28800
dom/localstorage/test/unit/corruptedDatabase_profile.zip
dom/quota/ActorsParent.cpp
dom/quota/QuotaManager.h
dom/quota/test/unit/localStorageArchive1upgrade_profile.zip
dom/quota/test/unit/localStorageArchiveDowngrade_profile.zip
dom/quota/test/unit/test_localStorageArchive1upgrade.js
dom/quota/test/unit/test_localStorageArchiveDowngrade.js
dom/quota/test/unit/xpcshell.ini
index 732920171d6cdd06162a11d6bb5c7be1183bc387..6ee654e4223e64a0443995bed683e4f044e83efc
GIT binary patch
literal 4095
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
--- a/dom/quota/ActorsParent.cpp
+++ b/dom/quota/ActorsParent.cpp
@@ -218,16 +218,18 @@ enum AppId {
 #define METADATA_TMP_FILE_NAME ".metadata-tmp"
 #define METADATA_V2_FILE_NAME ".metadata-v2"
 #define METADATA_V2_TMP_FILE_NAME ".metadata-v2-tmp"
 
 #define WEB_APPS_STORE_FILE_NAME "webappsstore.sqlite"
 #define LS_ARCHIVE_FILE_NAME "ls-archive.sqlite"
 #define LS_ARCHIVE_TMP_FILE_NAME "ls-archive-tmp.sqlite"
 
+const uint32_t kLocalStorageArchiveVersion = 1;
+
 const char kProfileDoChangeTopic[] = "profile-do-change";
 
 /******************************************************************************
  * SQLite functions
  ******************************************************************************/
 
 int32_t MakeStorageVersion(uint32_t aMajorStorageVersion,
                            uint32_t aMinorStorageVersion) {
@@ -320,16 +322,168 @@ nsresult CreateWebAppsStoreConnection(ns
     *aConnection = nullptr;
     return NS_OK;
   }
 
   connection.forget(aConnection);
   return NS_OK;
 }
 
+nsresult GetLocalStorageArchiveFile(const nsAString& aDirectoryPath,
+                                    nsIFile** aLsArchiveFile) {
+  AssertIsOnIOThread();
+  MOZ_ASSERT(!aDirectoryPath.IsEmpty());
+  MOZ_ASSERT(aLsArchiveFile);
+
+  nsCOMPtr<nsIFile> lsArchiveFile;
+  nsresult rv =
+      NS_NewLocalFile(aDirectoryPath, false, getter_AddRefs(lsArchiveFile));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = lsArchiveFile->Append(NS_LITERAL_STRING(LS_ARCHIVE_FILE_NAME));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  lsArchiveFile.forget(aLsArchiveFile);
+  return NS_OK;
+}
+
+nsresult GetLocalStorageArchiveTmpFile(const nsAString& aDirectoryPath,
+                                       nsIFile** aLsArchiveTmpFile) {
+  AssertIsOnIOThread();
+  MOZ_ASSERT(!aDirectoryPath.IsEmpty());
+  MOZ_ASSERT(aLsArchiveTmpFile);
+
+  nsCOMPtr<nsIFile> lsArchiveTmpFile;
+  nsresult rv =
+      NS_NewLocalFile(aDirectoryPath, false, getter_AddRefs(lsArchiveTmpFile));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = lsArchiveTmpFile->Append(NS_LITERAL_STRING(LS_ARCHIVE_TMP_FILE_NAME));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  lsArchiveTmpFile.forget(aLsArchiveTmpFile);
+  return NS_OK;
+}
+
+nsresult InitializeLocalStorageArchive(mozIStorageConnection* aConnection,
+                                       uint32_t aVersion) {
+  AssertIsOnIOThread();
+  MOZ_ASSERT(aConnection);
+
+  nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+      "CREATE TABLE database(version INTEGER NOT NULL DEFAULT 0);"));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  nsCOMPtr<mozIStorageStatement> stmt;
+  rv = aConnection->CreateStatement(
+      NS_LITERAL_CSTRING("INSERT INTO database (version) VALUES (:version)"),
+      getter_AddRefs(stmt));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("version"), aVersion);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = stmt->Execute();
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  return NS_OK;
+}
+
+nsresult IsLocalStorageArchiveInitialized(mozIStorageConnection* aConnection,
+                                          bool& aInitialized) {
+  AssertIsOnIOThread();
+  MOZ_ASSERT(aConnection);
+
+  bool exists;
+  nsresult rv =
+      aConnection->TableExists(NS_LITERAL_CSTRING("database"), &exists);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  aInitialized = exists;
+  return NS_OK;
+}
+
+nsresult LoadLocalStorageArchiveVersion(mozIStorageConnection* aConnection,
+                                        uint32_t& aVersion) {
+  AssertIsOnIOThread();
+  MOZ_ASSERT(aConnection);
+
+  nsCOMPtr<mozIStorageStatement> stmt;
+  nsresult rv = aConnection->CreateStatement(
+      NS_LITERAL_CSTRING("SELECT version FROM database"), getter_AddRefs(stmt));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  bool hasResult;
+  rv = stmt->ExecuteStep(&hasResult);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  if (NS_WARN_IF(!hasResult)) {
+    return NS_ERROR_FILE_CORRUPTED;
+  }
+
+  int32_t version;
+  rv = stmt->GetInt32(0, &version);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  aVersion = version;
+  return NS_OK;
+}
+
+/*
+nsresult SaveLocalStorageArchiveVersion(mozIStorageConnection* aConnection,
+                                        uint32_t aVersion) {
+  AssertIsOnIOThread();
+  MOZ_ASSERT(aConnection);
+
+  nsCOMPtr<mozIStorageStatement> stmt;
+  nsresult rv = aConnection->CreateStatement(
+      NS_LITERAL_CSTRING("UPDATE database SET version = :version;"),
+      getter_AddRefs(stmt));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("version"), aVersion);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = stmt->Execute();
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  return NS_OK;
+}
+*/
+
 /******************************************************************************
  * Quota manager class declarations
  ******************************************************************************/
 
 }  // namespace
 
 class DirectoryLockImpl final : public DirectoryLock {
   RefPtr<QuotaManager> mQuotaManager;
@@ -4548,23 +4702,18 @@ nsresult QuotaManager::UpgradeStorageFro
 }
 
 nsresult QuotaManager::MaybeRemoveLocalStorageData() {
   AssertIsOnIOThread();
   MOZ_ASSERT(!CachedNextGenLocalStorageEnabled());
 
   // Cleanup the tmp file first, if there's any.
   nsCOMPtr<nsIFile> lsArchiveTmpFile;
-  nsresult rv =
-      NS_NewLocalFile(mStoragePath, false, getter_AddRefs(lsArchiveTmpFile));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  rv = lsArchiveTmpFile->Append(NS_LITERAL_STRING(LS_ARCHIVE_TMP_FILE_NAME));
+  nsresult rv = GetLocalStorageArchiveTmpFile(mStoragePath,
+                                              getter_AddRefs(lsArchiveTmpFile));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   bool exists;
   rv = lsArchiveTmpFile->Exists(&exists);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
@@ -4574,22 +4723,17 @@ nsresult QuotaManager::MaybeRemoveLocalS
     rv = lsArchiveTmpFile->Remove(false);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 
   // Now check the real archive file.
   nsCOMPtr<nsIFile> lsArchiveFile;
-  rv = NS_NewLocalFile(mStoragePath, false, getter_AddRefs(lsArchiveFile));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  rv = lsArchiveFile->Append(NS_LITERAL_STRING(LS_ARCHIVE_FILE_NAME));
+  rv = GetLocalStorageArchiveFile(mStoragePath, getter_AddRefs(lsArchiveFile));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   rv = lsArchiveFile->Exists(&exists);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
@@ -4735,43 +4879,37 @@ nsresult QuotaManager::MaybeRemoveLocalS
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 
   return NS_OK;
 }
 
-nsresult QuotaManager::MaybeCreateLocalStorageArchive() {
+nsresult QuotaManager::CreateLocalStorageArchiveConnectionFromWebAppsStore(
+    mozIStorageConnection** aConnection) {
   AssertIsOnIOThread();
   MOZ_ASSERT(CachedNextGenLocalStorageEnabled());
-
-  // Check if the archive was already successfully created.
+  MOZ_ASSERT(aConnection);
+
   nsCOMPtr<nsIFile> lsArchiveFile;
   nsresult rv =
-      NS_NewLocalFile(mStoragePath, false, getter_AddRefs(lsArchiveFile));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  rv = lsArchiveFile->Append(NS_LITERAL_STRING(LS_ARCHIVE_FILE_NAME));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
+      GetLocalStorageArchiveFile(mStoragePath, getter_AddRefs(lsArchiveFile));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+#ifdef DEBUG
   bool exists;
   rv = lsArchiveFile->Exists(&exists);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
-
-  if (exists) {
-    // ls-archive.sqlite already exists, nothing to create.
-    return NS_OK;
-  }
+  MOZ_ASSERT(!exists);
+#endif
 
   // Get the storage service first, we will need it at multiple places.
   nsCOMPtr<mozIStorageService> ss =
       do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID, &rv);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
@@ -4851,22 +4989,18 @@ nsresult QuotaManager::MaybeCreateLocalS
 
     rv = webAppsStoreFile->CopyTo(storageDir,
                                   NS_LITERAL_STRING(LS_ARCHIVE_TMP_FILE_NAME));
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     nsCOMPtr<nsIFile> lsArchiveTmpFile;
-    rv = NS_NewLocalFile(mStoragePath, false, getter_AddRefs(lsArchiveTmpFile));
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-
-    rv = lsArchiveTmpFile->Append(NS_LITERAL_STRING(LS_ARCHIVE_TMP_FILE_NAME));
+    rv = GetLocalStorageArchiveTmpFile(mStoragePath,
+                                       getter_AddRefs(lsArchiveTmpFile));
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     if (journalMode.EqualsLiteral("wal")) {
       nsCOMPtr<mozIStorageConnection> lsArchiveTmpConnection;
       rv = ss->OpenUnsharedDatabase(lsArchiveTmpFile,
                                     getter_AddRefs(lsArchiveTmpConnection));
@@ -4890,16 +5024,25 @@ nsresult QuotaManager::MaybeCreateLocalS
     }
 
     // Finally, rename ls-archive-tmp.sqlite to ls-archive.sqlite
     rv = lsArchiveTmpFile->MoveTo(nullptr,
                                   NS_LITERAL_STRING(LS_ARCHIVE_FILE_NAME));
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
+
+    nsCOMPtr<mozIStorageConnection> lsArchiveConnection;
+    rv = ss->OpenUnsharedDatabase(lsArchiveFile,
+                                  getter_AddRefs(lsArchiveConnection));
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    lsArchiveConnection.forget(aConnection);
   } else {
     // If webappsstore database is not useable, just create an empty archive.
 
     // Ensure the storage directory actually exists.
     nsCOMPtr<nsIFile> storageDirectory;
     rv = NS_NewLocalFile(GetStoragePath(), false,
                          getter_AddRefs(storageDirectory));
     if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -4918,20 +5061,236 @@ nsresult QuotaManager::MaybeCreateLocalS
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     rv = StorageDBUpdater::Update(lsArchiveConnection);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
-  }
-
-  return NS_OK;
-}
+
+    lsArchiveConnection.forget(aConnection);
+  }
+
+  return NS_OK;
+}
+
+nsresult QuotaManager::CreateLocalStorageArchiveConnection(
+    mozIStorageConnection** aConnection, bool& aNewlyCreated) {
+  AssertIsOnIOThread();
+  MOZ_ASSERT(CachedNextGenLocalStorageEnabled());
+  MOZ_ASSERT(aConnection);
+
+  nsCOMPtr<nsIFile> lsArchiveTmpFile;
+  nsresult rv = GetLocalStorageArchiveTmpFile(mStoragePath,
+                                              getter_AddRefs(lsArchiveTmpFile));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  bool exists;
+  rv = lsArchiveTmpFile->Exists(&exists);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  if (exists) {
+    rv = lsArchiveTmpFile->Remove(false);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+  }
+
+  // Check if the archive was already successfully created.
+  nsCOMPtr<nsIFile> lsArchiveFile;
+  rv = GetLocalStorageArchiveFile(mStoragePath, getter_AddRefs(lsArchiveFile));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = lsArchiveFile->Exists(&exists);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  if (exists) {
+    bool removed = false;
+
+    bool isDirectory;
+    rv = lsArchiveFile->IsDirectory(&isDirectory);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    if (isDirectory) {
+      rv = lsArchiveFile->Remove(true);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+
+      removed = true;
+    }
+
+    nsCOMPtr<mozIStorageService> ss =
+        do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID, &rv);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    nsCOMPtr<mozIStorageConnection> connection;
+    rv = ss->OpenUnsharedDatabase(lsArchiveFile, getter_AddRefs(connection));
+    if (!removed && rv == NS_ERROR_FILE_CORRUPTED) {
+      rv = lsArchiveFile->Remove(false);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+
+      removed = true;
+
+      rv = ss->OpenUnsharedDatabase(lsArchiveFile, getter_AddRefs(connection));
+    }
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    rv = StorageDBUpdater::Update(connection);
+    if (!removed && NS_FAILED(rv)) {
+      rv = connection->Close();
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+
+      rv = lsArchiveFile->Remove(false);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+
+      removed = true;
+
+      rv = ss->OpenUnsharedDatabase(lsArchiveFile, getter_AddRefs(connection));
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+
+      rv = StorageDBUpdater::Update(connection);
+    }
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    connection.forget(aConnection);
+    aNewlyCreated = removed;
+    return NS_OK;
+  }
+
+  nsCOMPtr<mozIStorageConnection> connection;
+  rv = CreateLocalStorageArchiveConnectionFromWebAppsStore(
+      getter_AddRefs(connection));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  connection.forget(aConnection);
+  aNewlyCreated = true;
+  return NS_OK;
+}
+
+nsresult QuotaManager::RecreateLocalStorageArchive(
+    nsCOMPtr<mozIStorageConnection>& aConnection) {
+  AssertIsOnIOThread();
+  MOZ_ASSERT(CachedNextGenLocalStorageEnabled());
+
+  // Close local storage archive connection. We are going to remove underlying
+  // file.
+  nsresult rv = aConnection->Close();
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = MaybeRemoveLocalStorageDirectories();
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  nsCOMPtr<nsIFile> lsArchiveFile;
+  rv = GetLocalStorageArchiveFile(mStoragePath, getter_AddRefs(lsArchiveFile));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+#ifdef DEBUG
+  bool exists;
+  rv = lsArchiveFile->Exists(&exists);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  MOZ_ASSERT(exists);
+#endif
+
+  rv = lsArchiveFile->Remove(false);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = CreateLocalStorageArchiveConnectionFromWebAppsStore(
+      getter_AddRefs(aConnection));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  return NS_OK;
+}
+
+nsresult QuotaManager::DowngradeLocalStorageArchive(
+    nsCOMPtr<mozIStorageConnection>& aConnection) {
+  AssertIsOnIOThread();
+  MOZ_ASSERT(CachedNextGenLocalStorageEnabled());
+
+  nsresult rv = RecreateLocalStorageArchive(aConnection);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = InitializeLocalStorageArchive(aConnection, kLocalStorageArchiveVersion);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  return NS_OK;
+}
+
+nsresult QuotaManager::UpgradeLocalStorageArchiveFrom0To1(
+    nsCOMPtr<mozIStorageConnection>& aConnection) {
+  AssertIsOnIOThread();
+  MOZ_ASSERT(CachedNextGenLocalStorageEnabled());
+
+  nsresult rv = RecreateLocalStorageArchive(aConnection);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = InitializeLocalStorageArchive(aConnection, 1);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  return NS_OK;
+}
+
+/*
+nsresult QuotaManager::UpgradeLocalStorageArchiveFrom1To2(
+    nsCOMPtr<mozIStorageConnection>& aConnection) {
+  nsresult rv = SaveLocalStorageArchiveVersion(aConnection, 2);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  return NS_OK;
+}
+*/
 
 #ifdef DEBUG
 
 void QuotaManager::AssertStorageIsInitialized() const {
   AssertIsOnIOThread();
   MOZ_ASSERT(mStorageInitialized);
 }
 
@@ -5098,22 +5457,97 @@ nsresult QuotaManager::EnsureStorageIsIn
 
     rv = transaction.Commit();
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 
   if (CachedNextGenLocalStorageEnabled()) {
-    rv = MaybeCreateLocalStorageArchive();
+    nsCOMPtr<mozIStorageConnection> connection;
+    bool newlyCreated;
+    rv = CreateLocalStorageArchiveConnection(getter_AddRefs(connection),
+                                             newlyCreated);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    uint32_t version = 0;
+
+    if (!newlyCreated) {
+      bool initialized;
+      rv = IsLocalStorageArchiveInitialized(connection, initialized);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+
+      if (initialized) {
+        rv = LoadLocalStorageArchiveVersion(connection, version);
+        if (NS_WARN_IF(NS_FAILED(rv))) {
+          return rv;
+        }
+      }
+    }
+
+    if (version > kLocalStorageArchiveVersion) {
+      rv = DowngradeLocalStorageArchive(connection);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+
+      rv = LoadLocalStorageArchiveVersion(connection, version);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+
+      MOZ_ASSERT(version == kLocalStorageArchiveVersion);
+    } else if (version != kLocalStorageArchiveVersion) {
+      if (newlyCreated) {
+        MOZ_ASSERT(version == 0);
+
+        rv = InitializeLocalStorageArchive(connection,
+                                           kLocalStorageArchiveVersion);
+        if (NS_WARN_IF(NS_FAILED(rv))) {
+          return rv;
+        }
+      } else {
+        static_assert(kLocalStorageArchiveVersion == 1,
+                      "Upgrade function needed due to LocalStorage archive "
+                      "version increase.");
+
+        while (version != kLocalStorageArchiveVersion) {
+          if (version == 0) {
+            rv = UpgradeLocalStorageArchiveFrom0To1(connection);
+          } /* else if (version == 1) {
+            rv = UpgradeLocalStorageArchiveFrom1To2(connection);
+          } */ else {
+            QM_WARNING(
+                "Unable to initialize LocalStorage archive, no upgrade path is "
+                "available!");
+            return NS_ERROR_FAILURE;
+          }
+
+          if (NS_WARN_IF(NS_FAILED(rv))) {
+            return rv;
+          }
+
+          rv = LoadLocalStorageArchiveVersion(connection, version);
+          if (NS_WARN_IF(NS_FAILED(rv))) {
+            return rv;
+          }
+        }
+
+        MOZ_ASSERT(version == kLocalStorageArchiveVersion);
+      }
+    }
   } else {
     rv = MaybeRemoveLocalStorageData();
-  }
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
   }
 
   mStorageInitialized = true;
 
   return NS_OK;
 }
 
 already_AddRefed<DirectoryLock> QuotaManager::CreateDirectoryLock(
--- a/dom/quota/QuotaManager.h
+++ b/dom/quota/QuotaManager.h
@@ -420,17 +420,35 @@ class QuotaManager final : public Backgr
   nsresult UpgradeStorageFrom2_0To2_1(mozIStorageConnection* aConnection);
 
   nsresult UpgradeStorageFrom2_1To2_2(mozIStorageConnection* aConnection);
 
   nsresult MaybeRemoveLocalStorageData();
 
   nsresult MaybeRemoveLocalStorageDirectories();
 
-  nsresult MaybeCreateLocalStorageArchive();
+  nsresult CreateLocalStorageArchiveConnectionFromWebAppsStore(
+      mozIStorageConnection** aConnection);
+
+  nsresult CreateLocalStorageArchiveConnection(
+      mozIStorageConnection** aConnection, bool& aNewlyCreated);
+
+  nsresult RecreateLocalStorageArchive(
+      nsCOMPtr<mozIStorageConnection>& aConnection);
+
+  nsresult DowngradeLocalStorageArchive(
+      nsCOMPtr<mozIStorageConnection>& aConnection);
+
+  nsresult UpgradeLocalStorageArchiveFrom0To1(
+      nsCOMPtr<mozIStorageConnection>& aConnection);
+
+/*
+  nsresult UpgradeLocalStorageArchiveFrom1To2(
+      nsCOMPtr<mozIStorageConnection>& aConnection);
+*/
 
   nsresult InitializeRepository(PersistenceType aPersistenceType);
 
   nsresult InitializeOrigin(PersistenceType aPersistenceType,
                             const nsACString& aGroup, const nsACString& aOrigin,
                             int64_t aAccessTime, bool aPersisted,
                             nsIFile* aDirectory);
 
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a17b90dedfccb12bcd151c2d010af48ac46f2729
GIT binary patch
literal 7675
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
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..2f11abe85833b925e280b936e8ccf241900ecb91
GIT binary patch
literal 7799
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
Ldjz%{{{;L87BC<X
new file mode 100644
--- /dev/null
+++ b/dom/quota/test/unit/test_localStorageArchive1upgrade.js
@@ -0,0 +1,65 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+/**
+ * This test is mainly to verify that local storage directories are removed
+ * during local storage archive upgrade from version 0 to version 1.
+ * See bug 1546305.
+ */
+
+async function testSteps() {
+  const lsDirs = [
+    "storage/default/http+++example.com/ls",
+    "storage/default/http+++localhost/ls",
+    "storage/default/http+++www.mozilla.org/ls",
+  ];
+
+  info("Clearing");
+
+  let request = clear();
+  await requestFinished(request);
+
+  info("Installing package");
+
+  // The profile contains three initialized origin directories with local
+  // storage data, local storage archive, a script for origin initialization,
+  // the storage database and the web apps store database:
+  // - storage/default/https+++example.com
+  // - storage/default/https+++localhost
+  // - storage/default/https+++www.mozilla.org
+  // - storage/ls-archive.sqlite
+  // - create_db.js
+  // - storage.sqlite
+  // - webappsstore.sqlite
+  // The file create_db.js in the package was run locally (with a build that
+  // doesn't support local storage archive upgrades), specifically it was
+  // temporarily added to xpcshell.ini and then executed:
+  //   mach xpcshell-test --interactive dom/localstorage/test/unit/create_db.js
+  // Note: to make it become the profile in the test, additional manual steps
+  // are needed.
+  // 1. Remove the folder "storage/temporary".
+  installPackage("localStorageArchive1upgrade_profile");
+
+  info("Checking ls dirs");
+
+  for (let lsDir of lsDirs) {
+    let dir = getRelativeFile(lsDir);
+
+    exists = dir.exists();
+    ok(exists, "ls directory does exist");
+  }
+
+  request = init();
+  request = await requestFinished(request);
+
+  info("Checking ls dirs");
+
+  for (let lsDir of lsDirs) {
+    let dir = getRelativeFile(lsDir);
+
+    exists = dir.exists();
+    ok(!exists, "ls directory doesn't exist");
+  }
+}
new file mode 100644
--- /dev/null
+++ b/dom/quota/test/unit/test_localStorageArchiveDowngrade.js
@@ -0,0 +1,66 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+/**
+ * This test is mainly to verify that local storage directories are removed
+ * during local storage archive downgrade from any future version to current
+ * version. See bug 1546305.
+ */
+
+async function testSteps() {
+  const lsDirs = [
+    "storage/default/http+++example.com/ls",
+    "storage/default/http+++localhost/ls",
+    "storage/default/http+++www.mozilla.org/ls",
+  ];
+
+  info("Clearing");
+
+  let request = clear();
+  await requestFinished(request);
+
+  info("Installing package");
+
+  // The profile contains three initialized origin directories with local
+  // storage data, local storage archive, a script for origin initialization,
+  // the storage database and the web apps store database:
+  // - storage/default/https+++example.com
+  // - storage/default/https+++localhost
+  // - storage/default/https+++www.mozilla.org
+  // - storage/ls-archive.sqlite
+  // - create_db.js
+  // - storage.sqlite
+  // - webappsstore.sqlite
+  // The file create_db.js in the package was run locally (with a build that
+  // supports local storage archive upgrades and local storage archive version
+  // set to max integer), specifically it was temporarily added to xpcshell.ini
+  // and then executed:
+  //   mach xpcshell-test --interactive dom/localstorage/test/unit/create_db.js
+  // Note: to make it become the profile in the test, additional manual steps
+  // are needed.
+  // 1. Remove the folder "storage/temporary".
+  installPackage("localStorageArchiveDowngrade_profile");
+
+  info("Checking ls dirs");
+
+  for (let lsDir of lsDirs) {
+    let dir = getRelativeFile(lsDir);
+
+    exists = dir.exists();
+    ok(exists, "ls directory does exist");
+  }
+
+  request = init();
+  request = await requestFinished(request);
+
+  info("Checking ls dirs");
+
+  for (let lsDir of lsDirs) {
+    let dir = getRelativeFile(lsDir);
+
+    exists = dir.exists();
+    ok(!exists, "ls directory doesn't exist");
+  }
+}
--- a/dom/quota/test/unit/xpcshell.ini
+++ b/dom/quota/test/unit/xpcshell.ini
@@ -8,16 +8,18 @@ support-files =
   basics_profile.zip
   clearStorageForPrincipal_profile.zip
   createLocalStorage_profile.zip
   defaultStorageUpgrade_profile.zip
   getUsage_profile.zip
   groupMismatch_profile.zip
   idbSubdirUpgrade1_profile.zip
   idbSubdirUpgrade2_profile.zip
+  localStorageArchive1upgrade_profile.zip
+  localStorageArchiveDowngrade_profile.zip
   morgueCleanup_profile.zip
   obsoleteOriginAttributes_profile.zip
   originAttributesUpgrade_profile.zip
   removeAppsUpgrade_profile.zip
   removeLocalStorage1_profile.zip
   removeLocalStorage2_profile.zip
   storagePersistentUpgrade_profile.zip
   tempMetadataCleanup_profile.zip
@@ -29,16 +31,18 @@ support-files =
 [test_createLocalStorage.js]
 [test_clearStorageForPrincipal.js]
 [test_defaultStorageUpgrade.js]
 [test_getUsage.js]
 [test_groupMismatch.js]
 [test_idbSubdirUpgrade.js]
 [test_initTemporaryStorage.js]
 [test_listInitializedOrigins.js]
+[test_localStorageArchive1upgrade.js]
+[test_localStorageArchiveDowngrade.js]
 [test_morgueCleanup.js]
 [test_obsoleteOriginAttributesUpgrade.js]
 [test_obsoleteOrigins.js]
 [test_originAttributesUpgrade.js]
 [test_persist.js]
 [test_persist_eviction.js]
 [test_persist_globalLimit.js]
 [test_persist_groupLimit.js]