Backed out 8 changesets (bug 1513937, bug 1546310, bug 1548788, bug 1547688, bug 1547452, bug 1540777, bug 1542669, bug 1547454) for causing bug 1549362.
authorRyan VanderMeulen <ryanvm@gmail.com>
Mon, 06 May 2019 09:02:54 -0400
changeset 472696 df3eadfa74a8061f4c88496404d51baf47e21070
parent 472695 a40e9f3da7aca0279d4a1b58f3bf87e169e24b58
child 472697 7d7cbdf93a2199d37af5d6d997f8f623b89a08f3
child 472797 7057d330f834bdab12ab7415040a52589c740b33
child 472805 c52835481c084fecff479ddf35e06054c5e0ba32
push id84787
push userryanvm@gmail.com
push dateMon, 06 May 2019 13:17:53 +0000
treeherderautoland@7d7cbdf93a21 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1513937, 1546310, 1548788, 1547688, 1547452, 1540777, 1542669, 1547454, 1549362
milestone68.0a1
backs out8dca7df2949204ed09622839bb0bbb0da11cbfca
688f361e8bb6aee726c30e3eb89cea01bca56183
b5d8d57838a32c46a5579fab4eb15ffef62b7432
d1bd31177b1456ec930df76ba7806806bc919891
df97dfbb526adfe2fdf14a94dcc6bf83b5a2cab5
ade08d6dc3614c3ec3a3adee85a058cf666831f8
b622431054b74071311a6613942d93ae278f5c72
ad73e560441111bcc93c125674fe0e9bc61a53d7
first release with
nightly linux32
df3eadfa74a8 / 68.0a1 / 20190506130308 / files
nightly linux64
df3eadfa74a8 / 68.0a1 / 20190506130308 / files
nightly mac
df3eadfa74a8 / 68.0a1 / 20190506130308 / files
nightly win32
df3eadfa74a8 / 68.0a1 / 20190506130308 / files
nightly win64
df3eadfa74a8 / 68.0a1 / 20190506130308 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out 8 changesets (bug 1513937, bug 1546310, bug 1548788, bug 1547688, bug 1547452, bug 1540777, bug 1542669, bug 1547454) for causing bug 1549362. Backed out changeset 8dca7df29492 (bug 1548788) Backed out changeset 688f361e8bb6 (bug 1547688) Backed out changeset b5d8d57838a3 (bug 1540777) Backed out changeset d1bd31177b14 (bug 1513937) Backed out changeset df97dfbb526a (bug 1546310) Backed out changeset ade08d6dc361 (bug 1547454) Backed out changeset b622431054b7 (bug 1547452) Backed out changeset ad73e5604411 (bug 1542669)
dom/cache/Context.cpp
dom/indexedDB/ActorsParent.cpp
dom/localstorage/ActorsChild.cpp
dom/localstorage/ActorsChild.h
dom/localstorage/ActorsParent.cpp
dom/localstorage/LSDatabase.cpp
dom/localstorage/LSDatabase.h
dom/localstorage/LSSnapshot.cpp
dom/localstorage/LSSnapshot.h
dom/localstorage/LSValue.cpp
dom/localstorage/LSValue.h
dom/localstorage/PBackgroundLSDatabase.ipdl
dom/localstorage/PBackgroundLSObserver.ipdl
dom/localstorage/PBackgroundLSSharedTypes.ipdlh
dom/localstorage/PBackgroundLSSnapshot.ipdl
dom/localstorage/SerializationHelpers.h
dom/localstorage/SnappyUtils.cpp
dom/localstorage/SnappyUtils.h
dom/localstorage/moz.build
dom/quota/ActorsParent.cpp
dom/quota/QuotaManager.h
dom/quota/test/unit/localStorageArchive2upgrade_profile.zip
dom/quota/test/unit/localStorageArchive3upgrade_profile.zip
dom/quota/test/unit/test_localStorageArchive2upgrade.js
dom/quota/test/unit/test_localStorageArchive3upgrade.js
dom/quota/test/unit/xpcshell.ini
dom/simpledb/ActorsParent.cpp
--- a/dom/cache/Context.cpp
+++ b/dom/cache/Context.cpp
@@ -384,17 +384,18 @@ Context::QuotaInitRunnable::Run() {
         resolver->Resolve(NS_ERROR_ABORT);
         break;
       }
 
       QuotaManager* qm = QuotaManager::Get();
       MOZ_DIAGNOSTIC_ASSERT(qm);
       nsresult rv = qm->EnsureOriginIsInitialized(
           PERSISTENCE_TYPE_DEFAULT, mQuotaInfo.mSuffix, mQuotaInfo.mGroup,
-          mQuotaInfo.mOrigin, getter_AddRefs(mQuotaInfo.mDir));
+          mQuotaInfo.mOrigin,
+          /* aCreateIfNotExists */ true, getter_AddRefs(mQuotaInfo.mDir));
       if (NS_FAILED(rv)) {
         resolver->Resolve(rv);
         break;
       }
 
       mState = STATE_RUN_ON_TARGET;
 
       MOZ_ALWAYS_SUCCEEDS(mTarget->Dispatch(this, nsIThread::DISPATCH_NORMAL));
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -17154,17 +17154,18 @@ nsresult Maintenance::DirectoryWork() {
             persistenceType, group, origin, std::move(databasePaths)));
 
         nsCOMPtr<nsIFile> directory;
 
         // Idle maintenance may occur before origin is initailized.
         // Ensure origin is initialized first. It will initialize all origins
         // for temporary storage including IDB origins.
         rv = quotaManager->EnsureOriginIsInitialized(
-            persistenceType, suffix, group, origin, getter_AddRefs(directory));
+            persistenceType, suffix, group, origin,
+            /* aCreateIfNotExists */ true, getter_AddRefs(directory));
 
         if (NS_WARN_IF(NS_FAILED(rv))) {
           return rv;
         }
       }
     }
   }
 
@@ -19863,17 +19864,18 @@ nsresult OpenDatabaseOp::DoDatabaseWork(
   PersistenceType persistenceType = mCommonParams.metadata().persistenceType();
 
   QuotaManager* quotaManager = QuotaManager::Get();
   MOZ_ASSERT(quotaManager);
 
   nsCOMPtr<nsIFile> dbDirectory;
 
   nsresult rv = quotaManager->EnsureOriginIsInitialized(
-      persistenceType, mSuffix, mGroup, mOrigin, getter_AddRefs(dbDirectory));
+      persistenceType, mSuffix, mGroup, mOrigin,
+      /* aCreateIfNotExists */ true, getter_AddRefs(dbDirectory));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   rv = dbDirectory->Append(NS_LITERAL_STRING(IDB_DIRECTORY_NAME));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
--- a/dom/localstorage/ActorsChild.cpp
+++ b/dom/localstorage/ActorsChild.cpp
@@ -65,19 +65,19 @@ mozilla::ipc::IPCResult LSDatabaseChild:
     //       datastore right here, but asynchronously.
     //       However, we probably shouldn't do that if we are shutting down.
   }
 
   return IPC_OK();
 }
 
 PBackgroundLSSnapshotChild* LSDatabaseChild::AllocPBackgroundLSSnapshotChild(
-    const nsString& aDocumentURI, const nsString& aKey,
-    const bool& aIncreasePeakUsage, const int64_t& aRequestedSize,
-    const int64_t& aMinSize, LSSnapshotInitInfo* aInitInfo) {
+    const nsString& aDocumentURI, const bool& aIncreasePeakUsage,
+    const int64_t& aRequestedSize, const int64_t& aMinSize,
+    LSSnapshotInitInfo* aInitInfo) {
   MOZ_CRASH("PBackgroundLSSnapshotChild actor should be manually constructed!");
 }
 
 bool LSDatabaseChild::DeallocPBackgroundLSSnapshotChild(
     PBackgroundLSSnapshotChild* aActor) {
   MOZ_ASSERT(aActor);
 
   delete aActor;
@@ -121,32 +121,32 @@ void LSObserverChild::ActorDestroy(Actor
     mObserver = nullptr;
 #endif
   }
 }
 
 mozilla::ipc::IPCResult LSObserverChild::RecvObserve(
     const PrincipalInfo& aPrincipalInfo, const uint32_t& aPrivateBrowsingId,
     const nsString& aDocumentURI, const nsString& aKey,
-    const LSValue& aOldValue, const LSValue& aNewValue) {
+    const nsString& aOldValue, const nsString& aNewValue) {
   AssertIsOnOwningThread();
 
   if (!mObserver) {
     return IPC_OK();
   }
 
   nsresult rv;
   nsCOMPtr<nsIPrincipal> principal =
       PrincipalInfoToPrincipal(aPrincipalInfo, &rv);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return IPC_FAIL_NO_REASON(this);
   }
 
-  Storage::NotifyChange(/* aStorage */ nullptr, principal, aKey,
-                        aOldValue.AsString(), aNewValue.AsString(),
+  Storage::NotifyChange(/* aStorage */ nullptr, principal, aKey, aOldValue,
+                        aNewValue,
                         /* aStorageType */ kLocalStorageType, aDocumentURI,
                         /* aIsPrivate */ !!aPrivateBrowsingId,
                         /* aImmediateDispatch */ true);
 
   return IPC_OK();
 }
 
 /*******************************************************************************
--- a/dom/localstorage/ActorsChild.h
+++ b/dom/localstorage/ActorsChild.h
@@ -73,19 +73,19 @@ class LSDatabaseChild final : public PBa
   void SendDeleteMeInternal();
 
   // IPDL methods are only called by IPDL.
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
   mozilla::ipc::IPCResult RecvRequestAllowToClose() override;
 
   PBackgroundLSSnapshotChild* AllocPBackgroundLSSnapshotChild(
-      const nsString& aDocumentURI, const nsString& aKey,
-      const bool& aIncreasePeakUsage, const int64_t& aRequestedSize,
-      const int64_t& aMinSize, LSSnapshotInitInfo* aInitInfo) override;
+      const nsString& aDocumentURI, const bool& aIncreasePeakUsage,
+      const int64_t& aRequestedSize, const int64_t& aMinSize,
+      LSSnapshotInitInfo* aInitInfo) override;
 
   bool DeallocPBackgroundLSSnapshotChild(
       PBackgroundLSSnapshotChild* aActor) override;
 };
 
 /**
  * Minimal IPC-managed (new/delete) actor that exists to receive and relay
  * "storage" events from changes to LocalStorage that take place in other
@@ -119,18 +119,18 @@ class LSObserverChild final : public PBa
 
   // IPDL methods are only called by IPDL.
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
   mozilla::ipc::IPCResult RecvObserve(const PrincipalInfo& aPrinciplaInfo,
                                       const uint32_t& aPrivateBrowsingId,
                                       const nsString& aDocumentURI,
                                       const nsString& aKey,
-                                      const LSValue& aOldValue,
-                                      const LSValue& aNewValue) override;
+                                      const nsString& aOldValue,
+                                      const nsString& aNewValue) override;
 };
 
 /**
  * Minimal glue IPC-managed (new/delete) actor that is used by LSObject and its
  * RequestHelper to perform synchronous requests on top of an asynchronous
  * protocol.
  *
  * Takes an `LSReuestChildCallback` to be invoked when a response is received
--- a/dom/localstorage/ActorsParent.cpp
+++ b/dom/localstorage/ActorsParent.cpp
@@ -88,17 +88,17 @@ class Snapshot;
 typedef nsClassHashtable<nsCStringHashKey, ArchivedOriginInfo>
     ArchivedOriginHashtable;
 
 /*******************************************************************************
  * Constants
  ******************************************************************************/
 
 // Major schema version. Bump for almost everything.
-const uint32_t kMajorSchemaVersion = 4;
+const uint32_t kMajorSchemaVersion = 2;
 
 // Minor schema version. Should almost always be 0 (maybe bump on release
 // branches if we have to).
 const uint32_t kMinorSchemaVersion = 0;
 
 // The schema version we store in the SQLite database is a (signed) 32-bit
 // integer. The major version is left-shifted 4 bits so the max value is
 // 0xFFFFFFF. The minor version occupies the lower 4 bits and its max is 0xF.
@@ -295,17 +295,17 @@ int32_t MakeSchemaVersion(uint32_t aMajo
 }
 
 nsCString GetArchivedOriginHashKey(const nsACString& aOriginSuffix,
                                    const nsACString& aOriginNoSuffix) {
   return aOriginSuffix + NS_LITERAL_CSTRING(":") + aOriginNoSuffix;
 }
 
 nsresult CreateTables(mozIStorageConnection* aConnection) {
-  MOZ_ASSERT(IsOnIOThread() || IsOnConnectionThread());
+  AssertIsOnIOThread();
   MOZ_ASSERT(aConnection);
 
   // Table `database`
   nsresult rv = aConnection->ExecuteSimpleSQL(
       NS_LITERAL_CSTRING("CREATE TABLE database"
                          "( origin TEXT NOT NULL"
                          ", usage INTEGER NOT NULL DEFAULT 0"
                          ", last_vacuum_time INTEGER NOT NULL DEFAULT 0"
@@ -316,17 +316,16 @@ nsresult CreateTables(mozIStorageConnect
     return rv;
   }
 
   // Table `data`
   rv = aConnection->ExecuteSimpleSQL(
       NS_LITERAL_CSTRING("CREATE TABLE data"
                          "( key TEXT PRIMARY KEY"
                          ", value TEXT NOT NULL"
-                         ", utf16Length INTEGER NOT NULL DEFAULT 0"
                          ", compressed INTEGER NOT NULL DEFAULT 0"
                          ", lastAccessTime INTEGER NOT NULL DEFAULT 0"
                          ");"));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   rv = aConnection->SetSchemaVersion(kSQLiteSchemaVersion);
@@ -358,54 +357,16 @@ nsresult UpgradeSchemaFrom1_0To2_0(mozIS
   rv = aConnection->SetSchemaVersion(MakeSchemaVersion(2, 0));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   return NS_OK;
 }
 
-nsresult UpgradeSchemaFrom2_0To3_0(mozIStorageConnection* aConnection) {
-  AssertIsOnIOThread();
-  MOZ_ASSERT(aConnection);
-
-  nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-      "ALTER TABLE data ADD COLUMN utf16Length INTEGER NOT NULL DEFAULT 0;"));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  rv = aConnection->ExecuteSimpleSQL(
-      NS_LITERAL_CSTRING("UPDATE data "
-                         "SET utf16Length = utf16Length(value) "
-                         "FROM data);"));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  rv = aConnection->SetSchemaVersion(MakeSchemaVersion(3, 0));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  return NS_OK;
-}
-
-nsresult UpgradeSchemaFrom3_0To4_0(mozIStorageConnection* aConnection) {
-  AssertIsOnIOThread();
-  MOZ_ASSERT(aConnection);
-
-  nsresult rv = aConnection->SetSchemaVersion(MakeSchemaVersion(4, 0));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  return NS_OK;
-}
-
 nsresult SetDefaultPragmas(mozIStorageConnection* aConnection) {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(aConnection);
 
   nsresult rv = aConnection->ExecuteSimpleSQL(
       NS_LITERAL_CSTRING("PRAGMA synchronous = FULL;"));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
@@ -425,17 +386,17 @@ nsresult SetDefaultPragmas(mozIStorageCo
 
   return NS_OK;
 }
 
 nsresult CreateStorageConnection(nsIFile* aDBFile, nsIFile* aUsageFile,
                                  const nsACString& aOrigin,
                                  mozIStorageConnection** aConnection,
                                  bool* aRemovedUsageFile) {
-  MOZ_ASSERT(IsOnIOThread() || IsOnConnectionThread());
+  AssertIsOnIOThread();
   MOZ_ASSERT(aDBFile);
   MOZ_ASSERT(aUsageFile);
   MOZ_ASSERT(aConnection);
   MOZ_ASSERT(aRemovedUsageFile);
 
   // aRemovedUsageFile has to be initialized even when this method fails.
   *aRemovedUsageFile = false;
 
@@ -545,26 +506,22 @@ nsresult CreateStorageConnection(nsIFile
       }
 
       rv = stmt->Execute();
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
     } else {
       // This logic needs to change next time we change the schema!
-      static_assert(kSQLiteSchemaVersion == int32_t((4 << 4) + 0),
+      static_assert(kSQLiteSchemaVersion == int32_t((2 << 4) + 0),
                     "Upgrade function needed due to schema version increase.");
 
       while (schemaVersion != kSQLiteSchemaVersion) {
         if (schemaVersion == MakeSchemaVersion(1, 0)) {
           rv = UpgradeSchemaFrom1_0To2_0(connection);
-        } else if (schemaVersion == MakeSchemaVersion(2, 0)) {
-          rv = UpgradeSchemaFrom2_0To3_0(connection);
-        } else if (schemaVersion == MakeSchemaVersion(3, 0)) {
-          rv = UpgradeSchemaFrom3_0To4_0(connection);
         } else {
           LS_WARNING(
               "Unable to open LocalStorage database, no upgrade path is "
               "available!");
           return NS_ERROR_FAILURE;
         }
 
         if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -839,17 +796,17 @@ nsresult GetShadowFile(const nsAString& 
     return rv;
   }
 
   archiveFile.forget(aArchiveFile);
   return NS_OK;
 }
 
 nsresult SetShadowJournalMode(mozIStorageConnection* aConnection) {
-  MOZ_ASSERT(IsOnIOThread() || IsOnConnectionThread());
+  AssertIsOnIOThread();
   MOZ_ASSERT(aConnection);
 
   // Try enabling WAL mode. This can fail in various circumstances so we have to
   // check the results here.
   NS_NAMED_LITERAL_CSTRING(journalModeQueryStart, "PRAGMA journal_mode = ");
   NS_NAMED_LITERAL_CSTRING(journalModeWAL, "wal");
 
   nsCOMPtr<mozIStorageStatement> stmt;
@@ -927,17 +884,17 @@ nsresult SetShadowJournalMode(mozIStorag
     }
   }
 
   return NS_OK;
 }
 
 nsresult CreateShadowStorageConnection(const nsAString& aBasePath,
                                        mozIStorageConnection** aConnection) {
-  MOZ_ASSERT(IsOnIOThread() || IsOnConnectionThread());
+  AssertIsOnIOThread();
   MOZ_ASSERT(!aBasePath.IsEmpty());
   MOZ_ASSERT(aConnection);
 
   nsCOMPtr<nsIFile> shadowFile;
   nsresult rv = GetShadowFile(aBasePath, getter_AddRefs(shadowFile));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
@@ -1265,19 +1222,20 @@ class WriteOptimizer final {
     AssertIsOnBackgroundThread();
     MOZ_ASSERT(&aWriteOptimizer != this);
 
     mWriteInfos.SwapElements(aWriteOptimizer.mWriteInfos);
     mTotalDelta = aWriteOptimizer.mTotalDelta;
     aWriteOptimizer.mTotalDelta = 0;
   }
 
-  void AddItem(const nsString& aKey, const LSValue& aValue, int64_t aDelta = 0);
-
-  void UpdateItem(const nsString& aKey, const LSValue& aValue,
+  void AddItem(const nsString& aKey, const nsString& aValue,
+               int64_t aDelta = 0);
+
+  void UpdateItem(const nsString& aKey, const nsString& aValue,
                   int64_t aDelta = 0);
 
   void RemoveItem(const nsString& aKey, int64_t aDelta = 0);
 
   void Clear(int64_t aDelta = 0);
 
   bool HasWrites() const {
     AssertIsOnBackgroundThread();
@@ -1308,38 +1266,38 @@ class WriteOptimizer::WriteInfo {
   virtual ~WriteInfo() = default;
 };
 
 /**
  * SetItem mutation where the key did not previously exist.
  */
 class WriteOptimizer::AddItemInfo : public WriteInfo {
   nsString mKey;
-  LSValue mValue;
+  nsString mValue;
 
  public:
-  AddItemInfo(const nsAString& aKey, const LSValue& aValue)
+  AddItemInfo(const nsAString& aKey, const nsAString& aValue)
       : mKey(aKey), mValue(aValue) {}
 
   const nsAString& GetKey() const { return mKey; }
 
-  const LSValue& GetValue() const { return mValue; }
+  const nsAString& GetValue() const { return mValue; }
 
  private:
   Type GetType() override { return AddItem; }
 
   nsresult Perform(Connection* aConnection, bool aShadowWrites) override;
 };
 
 /**
  * SetItem mutation where the key already existed.
  */
 class WriteOptimizer::UpdateItemInfo final : public AddItemInfo {
  public:
-  UpdateItemInfo(const nsAString& aKey, const LSValue& aValue)
+  UpdateItemInfo(const nsAString& aKey, const nsAString& aValue)
       : AddItemInfo(aKey, aValue) {}
 
  private:
   Type GetType() override { return UpdateItem; }
 };
 
 class WriteOptimizer::RemoveItemInfo final : public WriteInfo {
   nsString mKey;
@@ -1439,30 +1397,25 @@ class DatastoreOperationBase : public Ru
         mMayProceed(true) {}
 
   ~DatastoreOperationBase() override { MOZ_ASSERT(!mMayProceed); }
 };
 
 class ConnectionDatastoreOperationBase : public DatastoreOperationBase {
  protected:
   RefPtr<Connection> mConnection;
-  /**
-   * This boolean flag is used by the CloseOp to avoid creating empty databases.
-   */
-  const bool mEnsureStorageConnection;
 
  public:
   // This callback will be called on the background thread before releasing the
   // final reference to this request object. Subclasses may perform any
   // additional cleanup here but must always call the base class implementation.
   virtual void Cleanup();
 
  protected:
-  ConnectionDatastoreOperationBase(Connection* aConnection,
-                                   bool aEnsureStorageConnection = true);
+  ConnectionDatastoreOperationBase(Connection* aConnection);
 
   ~ConnectionDatastoreOperationBase();
 
   // Must be overridden in subclasses. Called on the target thread to allow the
   // subclass to perform necessary datastore operations. A successful return
   // value will trigger an OnSuccess callback on the background thread while
   // while a failure value will trigger an OnFailure callback.
   virtual nsresult DoDatastoreWork() = 0;
@@ -1483,42 +1436,28 @@ class ConnectionDatastoreOperationBase :
 
 class Connection final {
   friend class ConnectionThread;
 
  public:
   class CachedStatement;
 
  private:
-  class InitOriginHelper;
-
   class FlushOp;
   class CloseOp;
 
   RefPtr<ConnectionThread> mConnectionThread;
-  RefPtr<QuotaClient> mQuotaClient;
   nsCOMPtr<nsITimer> mFlushTimer;
   nsCOMPtr<mozIStorageConnection> mStorageConnection;
   nsAutoPtr<ArchivedOriginScope> mArchivedOriginScope;
   nsInterfaceHashtable<nsCStringHashKey, mozIStorageStatement>
       mCachedStatements;
   WriteOptimizer mWriteOptimizer;
-  const nsCString mSuffix;
-  const nsCString mGroup;
   const nsCString mOrigin;
-  nsString mDirectoryPath;
-  /**
-   * Propagated from PrepareDatastoreOp. PrepareDatastoreOp may defer the
-   * creation of the localstorage client directory and database on the
-   * QuotaManager IO thread in its DatabaseWork method to
-   * Connection::EnsureStorageConnection, in which case the method needs to know
-   * it is responsible for taking those actions (without redundantly performing
-   * the existence checks).
-   */
-  const bool mDatabaseNotAvailable;
+  const nsString mDirectoryPath;
   bool mFlushScheduled;
 #ifdef DEBUG
   bool mInUpdateBatch;
 #endif
 
  public:
   NS_INLINE_DECL_REFCOUNTING(mozilla::dom::Connection)
 
@@ -1538,50 +1477,50 @@ class Connection final {
   // This method is used to asynchronously execute a connection datastore
   // operation on the connection thread.
   void Dispatch(ConnectionDatastoreOperationBase* aOp);
 
   // This method is used to asynchronously close the storage connection on the
   // connection thread.
   void Close(nsIRunnable* aCallback);
 
-  void AddItem(const nsString& aKey, const LSValue& aValue, int64_t aDelta);
-
-  void UpdateItem(const nsString& aKey, const LSValue& aValue, int64_t aDelta);
+  void AddItem(const nsString& aKey, const nsString& aValue, int64_t aDelta);
+
+  void UpdateItem(const nsString& aKey, const nsString& aValue, int64_t aDelta);
 
   void RemoveItem(const nsString& aKey, int64_t aDelta);
 
   void Clear(int64_t aDelta);
 
   void BeginUpdateBatch();
 
   void EndUpdateBatch();
 
   //////////////////////////////////////////////////////////////////////////////
   // Methods which can only be called on the connection thread.
 
   nsresult EnsureStorageConnection();
 
   mozIStorageConnection* StorageConnection() const {
     AssertIsOnConnectionThread();
+    MOZ_ASSERT(mStorageConnection);
 
     return mStorageConnection;
   }
 
   void CloseStorageConnection();
 
   nsresult GetCachedStatement(const nsACString& aQuery,
                               CachedStatement* aCachedStatement);
 
  private:
   // Only created by ConnectionThread.
-  Connection(ConnectionThread* aConnectionThread, const nsACString& aSuffix,
-             const nsACString& aGroup, const nsACString& aOrigin,
-             nsAutoPtr<ArchivedOriginScope>&& aArchivedOriginScope,
-             bool aDatabaseNotAvailable);
+  Connection(ConnectionThread* aConnectionThread, const nsACString& aOrigin,
+             const nsAString& aDirectoryPath,
+             nsAutoPtr<ArchivedOriginScope>&& aArchivedOriginScope);
 
   ~Connection();
 
   void ScheduleFlush();
 
   void Flush();
 
   static void FlushTimerCallback(nsITimer* aTimer, void* aClosure);
@@ -1606,77 +1545,34 @@ class Connection::CachedStatement final 
   void Assign(Connection* aConnection,
               already_AddRefed<mozIStorageStatement> aStatement);
 
   // No funny business allowed.
   CachedStatement(const CachedStatement&) = delete;
   CachedStatement& operator=(const CachedStatement&) = delete;
 };
 
-/**
- * Helper to invoke EnsureOriginIsInitialized and InitUsageForOrigin on the
- * QuotaManager IO thread from the LocalStorage connection thread when creating
- * a database connection on demand. This is necessary because we attempt to
- * defer the creation of the origin directory and the database until absolutely
- * needed, but the directory creation and origin initialization must happen on
- * the QM IO thread for invariant reasons. (We can't just use a mutex because
- * there could be logic on the IO thread that also wants to deal with the same
- * origin, so we need to queue a runnable and wait our turn.)
- */
-class Connection::InitOriginHelper final : public Runnable {
-  mozilla::Monitor mMonitor;
-  const nsCString mSuffix;
-  const nsCString mGroup;
-  const nsCString mOrigin;
-  nsString mOriginDirectoryPath;
-  nsresult mIOThreadResultCode;
-  bool mWaiting;
-
- public:
-  InitOriginHelper(const nsACString& aSuffix, const nsACString& aGroup,
-                   const nsACString& aOrigin)
-      : Runnable("dom::localstorage::Connection::InitOriginHelper"),
-        mMonitor("InitOriginHelper::mMonitor"),
-        mSuffix(aSuffix),
-        mGroup(aGroup),
-        mOrigin(aOrigin),
-        mIOThreadResultCode(NS_OK),
-        mWaiting(true) {
-    AssertIsOnConnectionThread();
-  }
-
-  nsresult BlockAndReturnOriginDirectoryPath(nsAString& aOriginDirectoryPath);
-
- private:
-  ~InitOriginHelper() {}
-
-  nsresult RunOnIOThread();
-
-  NS_DECL_NSIRUNNABLE
-};
-
 class Connection::FlushOp final : public ConnectionDatastoreOperationBase {
+  RefPtr<QuotaClient> mQuotaClient;
   WriteOptimizer mWriteOptimizer;
   bool mShadowWrites;
 
  public:
   FlushOp(Connection* aConnection, WriteOptimizer&& aWriteOptimizer);
 
  private:
   nsresult DoDatastoreWork() override;
 };
 
 class Connection::CloseOp final : public ConnectionDatastoreOperationBase {
   nsCOMPtr<nsIRunnable> mCallback;
 
  public:
   CloseOp(Connection* aConnection, nsIRunnable* aCallback)
-      : ConnectionDatastoreOperationBase(aConnection,
-                                         /* aEnsureStorageConnection */ false),
-        mCallback(aCallback) {}
+      : ConnectionDatastoreOperationBase(aConnection), mCallback(aCallback) {}
 
  private:
   nsresult DoDatastoreWork() override;
 
   void Cleanup() override;
 };
 
 class ConnectionThread final {
@@ -1692,20 +1588,18 @@ class ConnectionThread final {
     NS_ASSERT_OWNINGTHREAD(ConnectionThread);
   }
 
   bool IsOnConnectionThread();
 
   void AssertIsOnConnectionThread();
 
   already_AddRefed<Connection> CreateConnection(
-      const nsACString& aSuffix, const nsACString& aGroup,
-      const nsACString& aOrigin,
-      nsAutoPtr<ArchivedOriginScope>&& aArchivedOriginScope,
-      bool aDatabaseNotAvailable);
+      const nsACString& aOrigin, const nsAString& aDirectoryPath,
+      nsAutoPtr<ArchivedOriginScope>&& aArchivedOriginScope);
 
   void Shutdown();
 
   NS_INLINE_DECL_REFCOUNTING(ConnectionThread)
 
  private:
   ~ConnectionThread();
 };
@@ -1748,17 +1642,17 @@ class Datastore final
    * are any active databases final deltas can't be calculated and
    * `UpdateUsage()` can't be invoked.
    */
   nsTHashtable<nsPtrHashKey<Database>> mActiveDatabases;
   /**
    * Non-authoritative hashtable representation of mOrderedItems for efficient
    * lookup.
    */
-  nsDataHashtable<nsStringHashKey, LSValue> mValues;
+  nsDataHashtable<nsStringHashKey, nsString> mValues;
   /**
    * The authoritative ordered state of the Datastore; mValue also exists as an
    * unordered hashtable for efficient lookup.
    */
   nsTArray<LSItemInfo> mOrderedItems;
   nsTArray<int64_t> mPendingUsageDeltas;
   WriteOptimizer mWriteOptimizer;
   const nsCString mOrigin;
@@ -1774,17 +1668,17 @@ class Datastore final
 
  public:
   // Created by PrepareDatastoreOp.
   Datastore(const nsACString& aOrigin, uint32_t aPrivateBrowsingId,
             int64_t aUsage, int64_t aSizeOfKeys, int64_t aSizeOfItems,
             already_AddRefed<DirectoryLock>&& aDirectoryLock,
             already_AddRefed<Connection>&& aConnection,
             already_AddRefed<QuotaObject>&& aQuotaObject,
-            nsDataHashtable<nsStringHashKey, LSValue>& aValues,
+            nsDataHashtable<nsStringHashKey, nsString>& aValues,
             nsTArray<LSItemInfo>& aOrderedItems);
 
   const nsCString& Origin() const { return mOrigin; }
 
   uint32_t PrivateBrowsingId() const { return mPrivateBrowsingId; }
 
   bool IsPersistent() const {
     // Private-browsing is forbidden from touching disk, but
@@ -1814,44 +1708,43 @@ class Datastore final
   void NoteLiveDatabase(Database* aDatabase);
 
   void NoteFinishedDatabase(Database* aDatabase);
 
   void NoteActiveDatabase(Database* aDatabase);
 
   void NoteInactiveDatabase(Database* aDatabase);
 
-  void GetSnapshotInitInfo(const nsString& aKey, bool& aAddKeyToUnknownItems,
-                           nsTHashtable<nsStringHashKey>& aLoadedItems,
+  void GetSnapshotInitInfo(nsTHashtable<nsStringHashKey>& aLoadedItems,
                            nsTArray<LSItemInfo>& aItemInfos,
                            uint32_t& aNextLoadIndex, uint32_t& aTotalLength,
                            int64_t& aInitialUsage, int64_t& aPeakUsage,
                            LSSnapshot::LoadState& aLoadState);
 
   const nsTArray<LSItemInfo>& GetOrderedItems() const { return mOrderedItems; }
 
-  void GetItem(const nsString& aKey, LSValue& aValue) const;
+  void GetItem(const nsString& aKey, nsString& aValue) const;
 
   void GetKeys(nsTArray<nsString>& aKeys) const;
 
   //////////////////////////////////////////////////////////////////////////////
   // Mutation Methods
   //
   // These are only called during Snapshot::RecvCheckpoint
 
   /**
    * Used by Snapshot::RecvCheckpoint to set a key/value pair as part of a an
    * explicit batch.
    */
   void SetItem(Database* aDatabase, const nsString& aDocumentURI,
-               const nsString& aKey, const LSValue& aOldValue,
-               const LSValue& aValue);
+               const nsString& aKey, const nsString& aOldValue,
+               const nsString& aValue);
 
   void RemoveItem(Database* aDatabase, const nsString& aDocumentURI,
-                  const nsString& aKey, const LSValue& aOldValue);
+                  const nsString& aKey, const nsString& aOldValue);
 
   void Clear(Database* aDatabase, const nsString& aDocumentURI);
 
   void PrivateBrowsingClear();
 
   void BeginUpdateBatch(int64_t aSnapshotInitialUsage);
 
   int64_t EndUpdateBatch(int64_t aSnapshotPeakUsage);
@@ -1868,23 +1761,23 @@ class Datastore final
 
   void MaybeClose();
 
   void ConnectionClosedCallback();
 
   void CleanupMetadata();
 
   void NotifySnapshots(Database* aDatabase, const nsAString& aKey,
-                       const LSValue& aOldValue, bool aAffectsOrder);
+                       const nsAString& aOldValue, bool aAffectsOrder);
 
   void MarkSnapshotsDirty();
 
   void NotifyObservers(Database* aDatabase, const nsString& aDocumentURI,
-                       const nsString& aKey, const LSValue& aOldValue,
-                       const LSValue& aNewValue);
+                       const nsString& aKey, const nsString& aOldValue,
+                       const nsString& aNewValue);
 };
 
 class PreparedDatastore {
   RefPtr<Datastore> mDatastore;
   nsCOMPtr<nsITimer> mTimer;
   const Maybe<ContentParentId> mContentParentId;
   // Strings share buffers if possible, so it's not a problem to duplicate the
   // origin here.
@@ -2031,25 +1924,24 @@ class Database final
   // IPDL methods are only called by IPDL.
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
   mozilla::ipc::IPCResult RecvDeleteMe() override;
 
   mozilla::ipc::IPCResult RecvAllowToClose() override;
 
   PBackgroundLSSnapshotParent* AllocPBackgroundLSSnapshotParent(
-      const nsString& aDocumentURI, const nsString& aKey,
-      const bool& aIncreasePeakUsage, const int64_t& aRequestedSize,
-      const int64_t& aMinSize, LSSnapshotInitInfo* aInitInfo) override;
+      const nsString& aDocumentURI, const bool& aIncreasePeakUsage,
+      const int64_t& aRequestedSize, const int64_t& aMinSize,
+      LSSnapshotInitInfo* aInitInfo) override;
 
   mozilla::ipc::IPCResult RecvPBackgroundLSSnapshotConstructor(
       PBackgroundLSSnapshotParent* aActor, const nsString& aDocumentURI,
-      const nsString& aKey, const bool& aIncreasePeakUsage,
-      const int64_t& aRequestedSize, const int64_t& aMinSize,
-      LSSnapshotInitInfo* aInitInfo) override;
+      const bool& aIncreasePeakUsage, const int64_t& aRequestedSize,
+      const int64_t& aMinSize, LSSnapshotInitInfo* aInitInfo) override;
 
   bool DeallocPBackgroundLSSnapshotParent(
       PBackgroundLSSnapshotParent* aActor) override;
 };
 
 /**
  * Attempts to capture the state of the underlying Datastore at the time of its
  * creation so run-to-completion semantics can be honored.
@@ -2097,17 +1989,17 @@ class Snapshot final : public PBackgroun
    * notifications that are not yet known to the child LSSnapshot.
    *
    * The naive way to snapshot the state of mDatastore would be to duplicate its
    * internal mValues at the time of our creation, but that is wasteful if few
    * changes are made to the Datastore's state.  So we only track values that
    * are changed/evicted from the Datastore as they happen, as reported to us by
    * SaveItem notifications.
    */
-  nsDataHashtable<nsStringHashKey, LSValue> mValues;
+  nsDataHashtable<nsStringHashKey, nsString> mValues;
   /**
    * Latched state of mDatastore's keys during a SaveItem notification with
    * aAffectsOrder=true.  The ordered keys needed to be saved off so that a
    * consistent ordering could be presented to the child LSSnapshot when it asks
    * for them via RecvLoadKeys.
    */
   nsTArray<nsString> mKeys;
   nsString mDocumentURI;
@@ -2154,54 +2046,50 @@ class Snapshot final : public PBackgroun
   bool mLoadKeysReceived;
   bool mSentMarkDirty;
 
  public:
   // Created in AllocPBackgroundLSSnapshotParent.
   Snapshot(Database* aDatabase, const nsAString& aDocumentURI);
 
   void Init(nsTHashtable<nsStringHashKey>& aLoadedItems,
-            nsTHashtable<nsStringHashKey>& aUnknownItems,
             uint32_t aNextLoadIndex, uint32_t aTotalLength,
             int64_t aInitialUsage, int64_t aPeakUsage,
             LSSnapshot::LoadState aLoadState) {
     AssertIsOnBackgroundThread();
     MOZ_ASSERT(aInitialUsage >= 0);
     MOZ_ASSERT(aPeakUsage >= aInitialUsage);
     MOZ_ASSERT_IF(aLoadState != LSSnapshot::LoadState::AllOrderedItems,
                   aNextLoadIndex < aTotalLength);
     MOZ_ASSERT(mTotalLength == 0);
     MOZ_ASSERT(mUsage == -1);
     MOZ_ASSERT(mPeakUsage == -1);
 
     mLoadedItems.SwapElements(aLoadedItems);
-    mUnknownItems.SwapElements(aUnknownItems);
     mNextLoadIndex = aNextLoadIndex;
     mTotalLength = aTotalLength;
     mUsage = aInitialUsage;
     mPeakUsage = aPeakUsage;
     if (aLoadState == LSSnapshot::LoadState::AllOrderedKeys) {
-      MOZ_ASSERT(mUnknownItems.Count() == 0);
       mLoadKeysReceived = true;
     } else if (aLoadState == LSSnapshot::LoadState::AllOrderedItems) {
       MOZ_ASSERT(mLoadedItems.Count() == 0);
-      MOZ_ASSERT(mUnknownItems.Count() == 0);
       MOZ_ASSERT(mNextLoadIndex == mTotalLength);
       mLoadedReceived = true;
       mLoadedAllItems = true;
       mLoadKeysReceived = true;
     }
   }
 
   /**
    * Called via NotifySnapshots by Datastore whenever it is updating its
    * internal state so that snapshots can save off the state of a value at the
    * time of their creation.
    */
-  void SaveItem(const nsAString& aKey, const LSValue& aOldValue,
+  void SaveItem(const nsAString& aKey, const nsAString& aOldValue,
                 bool aAffectsOrder);
 
   void MarkDirty();
 
   NS_INLINE_DECL_REFCOUNTING(mozilla::dom::Snapshot)
 
  private:
   // Reference counted.
@@ -2217,17 +2105,17 @@ class Snapshot final : public PBackgroun
   mozilla::ipc::IPCResult RecvCheckpoint(
       nsTArray<LSWriteInfo>&& aWriteInfos) override;
 
   mozilla::ipc::IPCResult RecvFinish() override;
 
   mozilla::ipc::IPCResult RecvLoaded() override;
 
   mozilla::ipc::IPCResult RecvLoadValueAndMoreItems(
-      const nsString& aKey, LSValue* aValue,
+      const nsString& aKey, nsString* aValue,
       nsTArray<LSItemInfo>* aItemInfos) override;
 
   mozilla::ipc::IPCResult RecvLoadKeys(nsTArray<nsString>* aKeys) override;
 
   mozilla::ipc::IPCResult RecvIncreasePeakUsage(const int64_t& aRequestedSize,
                                                 const int64_t& aMinSize,
                                                 int64_t* aSize) override;
 
@@ -2240,18 +2128,18 @@ class Observer final : public PBackgroun
 
  public:
   // Created in AllocPBackgroundLSObserverParent.
   explicit Observer(const nsACString& aOrigin);
 
   const nsCString& Origin() const { return mOrigin; }
 
   void Observe(Database* aDatabase, const nsString& aDocumentURI,
-               const nsString& aKey, const LSValue& aOldValue,
-               const LSValue& aNewValue);
+               const nsString& aKey, const nsString& aOldValue,
+               const nsString& aNewValue);
 
   NS_INLINE_DECL_REFCOUNTING(mozilla::dom::Observer)
 
  private:
   // Reference counted.
   ~Observer();
 
   // IPDL methods are only called by IPDL.
@@ -2397,32 +2285,33 @@ class PrepareDatastoreOp
   nsCOMPtr<nsIEventTarget> mMainEventTarget;
   RefPtr<PrepareDatastoreOp> mDelayedOp;
   RefPtr<DirectoryLock> mPendingDirectoryLock;
   RefPtr<DirectoryLock> mDirectoryLock;
   RefPtr<Connection> mConnection;
   RefPtr<Datastore> mDatastore;
   nsAutoPtr<ArchivedOriginScope> mArchivedOriginScope;
   LoadDataOp* mLoadDataOp;
-  nsDataHashtable<nsStringHashKey, LSValue> mValues;
+  nsDataHashtable<nsStringHashKey, nsString> mValues;
   nsTArray<LSItemInfo> mOrderedItems;
   const LSRequestCommonParams mParams;
   Maybe<ContentParentId> mContentParentId;
   nsCString mSuffix;
   nsCString mGroup;
   nsCString mMainThreadOrigin;
   nsCString mOrigin;
+  nsString mDirectoryPath;
   nsString mDatabaseFilePath;
   uint32_t mPrivateBrowsingId;
   int64_t mUsage;
   int64_t mSizeOfKeys;
   int64_t mSizeOfItems;
   uint64_t mDatastoreId;
   NestedState mNestedState;
-  const bool mForPreload;
+  const bool mCreateIfNotExists;
   bool mDatabaseNotAvailable;
   bool mRequestedDirectoryLock;
   bool mInvalidated;
 
 #ifdef DEBUG
   int64_t mDEBUGUsage;
 #endif
 
@@ -2943,32 +2832,16 @@ void InitUsageForOrigin(const nsACString
   if (!gUsages) {
     gUsages = new UsageHashtable();
   }
 
   MOZ_ASSERT(!gUsages->Contains(aOrigin));
   gUsages->Put(aOrigin, aUsage);
 }
 
-bool GetUsageForOrigin(const nsACString& aOrigin, int64_t& aUsage) {
-  AssertIsOnIOThread();
-
-  if (gUsages) {
-    int64_t usage;
-    if (gUsages->Get(aOrigin, &usage)) {
-      MOZ_ASSERT(usage >= 0);
-
-      aUsage = usage;
-      return true;
-    }
-  }
-
-  return false;
-}
-
 void UpdateUsageForOrigin(const nsACString& aOrigin, int64_t aUsage) {
   AssertIsOnIOThread();
   MOZ_ASSERT(gUsages);
   MOZ_ASSERT(gUsages->Contains(aOrigin));
 
   gUsages->Put(aOrigin, aUsage);
 }
 
@@ -3694,34 +3567,34 @@ already_AddRefed<mozilla::dom::quota::Cl
 }
 
 }  // namespace localstorage
 
 /*******************************************************************************
  * WriteOptimizer
  ******************************************************************************/
 
-void WriteOptimizer::AddItem(const nsString& aKey, const LSValue& aValue,
+void WriteOptimizer::AddItem(const nsString& aKey, const nsString& aValue,
                              int64_t aDelta) {
   AssertIsOnBackgroundThread();
 
   WriteInfo* existingWriteInfo;
   nsAutoPtr<WriteInfo> newWriteInfo;
   if (mWriteInfos.Get(aKey, &existingWriteInfo) &&
       existingWriteInfo->GetType() == WriteInfo::RemoveItem) {
     newWriteInfo = new UpdateItemInfo(aKey, aValue);
   } else {
     newWriteInfo = new AddItemInfo(aKey, aValue);
   }
   mWriteInfos.Put(aKey, newWriteInfo.forget());
 
   mTotalDelta += aDelta;
 }
 
-void WriteOptimizer::UpdateItem(const nsString& aKey, const LSValue& aValue,
+void WriteOptimizer::UpdateItem(const nsString& aKey, const nsString& aValue,
                                 int64_t aDelta) {
   AssertIsOnBackgroundThread();
 
   WriteInfo* existingWriteInfo;
   nsAutoPtr<WriteInfo> newWriteInfo;
   if (mWriteInfos.Get(aKey, &existingWriteInfo) &&
       existingWriteInfo->GetType() == WriteInfo::AddItem) {
     newWriteInfo = new AddItemInfo(aKey, aValue);
@@ -3880,42 +3753,29 @@ nsresult WriteOptimizer::PerformWrites(C
 
 nsresult WriteOptimizer::AddItemInfo::Perform(Connection* aConnection,
                                               bool aShadowWrites) {
   AssertIsOnConnectionThread();
   MOZ_ASSERT(aConnection);
 
   Connection::CachedStatement stmt;
   nsresult rv = aConnection->GetCachedStatement(
-      NS_LITERAL_CSTRING(
-          "INSERT OR REPLACE INTO data (key, value, utf16Length, compressed) "
-          "VALUES(:key, :value, :utf16Length, :compressed)"),
+      NS_LITERAL_CSTRING("INSERT OR REPLACE INTO data (key, value) "
+                         "VALUES(:key, :value)"),
       &stmt);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   rv = stmt->BindStringByName(NS_LITERAL_CSTRING("key"), mKey);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
-  rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("value"), mValue);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("utf16Length"),
-                             mValue.UTF16Length());
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("compressed"),
-                             mValue.IsCompressed());
+  rv = stmt->BindStringByName(NS_LITERAL_CSTRING("value"), mValue);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   rv = stmt->Execute();
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
@@ -3950,25 +3810,17 @@ nsresult WriteOptimizer::AddItemInfo::Pe
     return rv;
   }
 
   rv = stmt->BindStringByName(NS_LITERAL_CSTRING("key"), mKey);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
-  if (mValue.IsCompressed()) {
-    nsCString value;
-    if (NS_WARN_IF(!SnappyUncompress(mValue, value))) {
-      return NS_ERROR_FAILURE;
-    }
-    rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("value"), value);
-  } else {
-    rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("value"), mValue);
-  }
+  rv = stmt->BindStringByName(NS_LITERAL_CSTRING("value"), mValue);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   rv = stmt->Execute();
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
@@ -4079,19 +3931,18 @@ nsresult WriteOptimizer::ClearInfo::Perf
  * DatastoreOperationBase
  ******************************************************************************/
 
 /*******************************************************************************
  * ConnectionDatastoreOperationBase
  ******************************************************************************/
 
 ConnectionDatastoreOperationBase::ConnectionDatastoreOperationBase(
-    Connection* aConnection, bool aEnsureStorageConnection)
-    : mConnection(aConnection),
-      mEnsureStorageConnection(aEnsureStorageConnection) {
+    Connection* aConnection)
+    : mConnection(aConnection) {
   MOZ_ASSERT(aConnection);
 }
 
 ConnectionDatastoreOperationBase::~ConnectionDatastoreOperationBase() {
   MOZ_ASSERT(!mConnection,
              "ConnectionDatabaseOperationBase::Cleanup() was not called by a "
              "subclass!");
 }
@@ -4115,30 +3966,22 @@ void ConnectionDatastoreOperationBase::O
 void ConnectionDatastoreOperationBase::RunOnConnectionThread() {
   AssertIsOnConnectionThread();
   MOZ_ASSERT(mConnection);
   MOZ_ASSERT(NS_SUCCEEDED(ResultCode()));
 
   if (!MayProceedOnNonOwningThread()) {
     SetFailureCode(NS_ERROR_FAILURE);
   } else {
-    nsresult rv = NS_OK;
-
-    // The boolean flag is only used by the CloseOp to avoid creating empty
-    // databases.
-    if (mEnsureStorageConnection) {
-      rv = mConnection->EnsureStorageConnection();
-      if (NS_WARN_IF(NS_FAILED(rv))) {
-        SetFailureCode(rv);
-      } else {
-        MOZ_ASSERT(mConnection->StorageConnection());
-      }
-    }
-
-    if (NS_SUCCEEDED(rv)) {
+    nsresult rv = mConnection->EnsureStorageConnection();
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      SetFailureCode(rv);
+    } else {
+      MOZ_ASSERT(mConnection->StorageConnection());
+
       rv = DoDatastoreWork();
       if (NS_FAILED(rv)) {
         SetFailureCode(rv);
       }
     }
   }
 
   MOZ_ALWAYS_SUCCEEDS(OwningEventTarget()->Dispatch(this, NS_DISPATCH_NORMAL));
@@ -4172,36 +4015,32 @@ ConnectionDatastoreOperationBase::Run() 
   return NS_OK;
 }
 
 /*******************************************************************************
  * Connection implementation
  ******************************************************************************/
 
 Connection::Connection(ConnectionThread* aConnectionThread,
-                       const nsACString& aSuffix, const nsACString& aGroup,
                        const nsACString& aOrigin,
-                       nsAutoPtr<ArchivedOriginScope>&& aArchivedOriginScope,
-                       bool aDatabaseNotAvailable)
+                       const nsAString& aDirectoryPath,
+                       nsAutoPtr<ArchivedOriginScope>&& aArchivedOriginScope)
     : mConnectionThread(aConnectionThread),
-      mQuotaClient(QuotaClient::GetInstance()),
       mArchivedOriginScope(std::move(aArchivedOriginScope)),
-      mSuffix(aSuffix),
-      mGroup(aGroup),
       mOrigin(aOrigin),
-      mDatabaseNotAvailable(aDatabaseNotAvailable),
+      mDirectoryPath(aDirectoryPath),
       mFlushScheduled(false)
 #ifdef DEBUG
       ,
       mInUpdateBatch(false)
 #endif
 {
   AssertIsOnOwningThread();
-  MOZ_ASSERT(!aGroup.IsEmpty());
   MOZ_ASSERT(!aOrigin.IsEmpty());
+  MOZ_ASSERT(!aDirectoryPath.IsEmpty());
 }
 
 Connection::~Connection() {
   AssertIsOnOwningThread();
   MOZ_ASSERT(!mStorageConnection);
   MOZ_ASSERT(!mCachedStatements.Count());
   MOZ_ASSERT(!mInUpdateBatch);
   MOZ_ASSERT(!mFlushScheduled);
@@ -4228,25 +4067,25 @@ void Connection::Close(nsIRunnable* aCal
     mFlushTimer = nullptr;
   }
 
   RefPtr<CloseOp> op = new CloseOp(this, aCallback);
 
   Dispatch(op);
 }
 
-void Connection::AddItem(const nsString& aKey, const LSValue& aValue,
+void Connection::AddItem(const nsString& aKey, const nsString& aValue,
                          int64_t aDelta) {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mInUpdateBatch);
 
   mWriteOptimizer.AddItem(aKey, aValue, aDelta);
 }
 
-void Connection::UpdateItem(const nsString& aKey, const LSValue& aValue,
+void Connection::UpdateItem(const nsString& aKey, const nsString& aValue,
                             int64_t aDelta) {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mInUpdateBatch);
 
   mWriteOptimizer.UpdateItem(aKey, aValue, aDelta);
 }
 
 void Connection::RemoveItem(const nsString& aKey, int64_t aDelta) {
@@ -4283,145 +4122,42 @@ void Connection::EndUpdateBatch() {
 #ifdef DEBUG
   mInUpdateBatch = false;
 #endif
 }
 
 nsresult Connection::EnsureStorageConnection() {
   AssertIsOnConnectionThread();
 
-  if (mStorageConnection) {
-    return NS_OK;
-  }
-
-  nsresult rv;
-
-  QuotaManager* quotaManager = QuotaManager::Get();
-  MOZ_ASSERT(quotaManager);
-
-  if (!mDatabaseNotAvailable) {
-    nsCOMPtr<nsIFile> directoryEntry;
-    rv = quotaManager->GetDirectoryForOrigin(PERSISTENCE_TYPE_DEFAULT, mOrigin,
-                                             getter_AddRefs(directoryEntry));
+  if (!mStorageConnection) {
+    nsCOMPtr<nsIFile> file;
+    nsresult rv = NS_NewLocalFile(mDirectoryPath, false, getter_AddRefs(file));
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
-    rv = directoryEntry->Append(NS_LITERAL_STRING(LS_DIRECTORY_NAME));
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-
-    rv = directoryEntry->GetPath(mDirectoryPath);
+    rv = file->Append(NS_LITERAL_STRING(DATA_FILE_NAME));
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
-    rv = directoryEntry->Append(NS_LITERAL_STRING(DATA_FILE_NAME));
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-
-    nsString databaseFilePath;
-    rv = directoryEntry->GetPath(databaseFilePath);
+    nsString filePath;
+    rv = file->GetPath(filePath);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     nsCOMPtr<mozIStorageConnection> storageConnection;
-    rv = GetStorageConnection(databaseFilePath,
-                              getter_AddRefs(storageConnection));
+    rv = GetStorageConnection(filePath, getter_AddRefs(storageConnection));
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     mStorageConnection = storageConnection;
-
-    return NS_OK;
-  }
-
-  RefPtr<InitOriginHelper> helper =
-      new InitOriginHelper(mSuffix, mGroup, mOrigin);
-
-  nsString originDirectoryPath;
-  rv = helper->BlockAndReturnOriginDirectoryPath(originDirectoryPath);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  nsCOMPtr<nsIFile> directoryEntry;
-  rv = NS_NewLocalFile(originDirectoryPath, false,
-                       getter_AddRefs(directoryEntry));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  rv = directoryEntry->Append(NS_LITERAL_STRING(LS_DIRECTORY_NAME));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  rv = directoryEntry->GetPath(mDirectoryPath);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  bool exists;
-  rv = directoryEntry->Exists(&exists);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  if (!exists) {
-    rv = directoryEntry->Create(nsIFile::DIRECTORY_TYPE, 0755);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-  }
-
-  rv = directoryEntry->Append(NS_LITERAL_STRING(DATA_FILE_NAME));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  nsCOMPtr<nsIFile> usageFile;
-  rv = GetUsageFile(mDirectoryPath, getter_AddRefs(usageFile));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  nsCOMPtr<mozIStorageConnection> storageConnection;
-  bool removedUsageFile;
-
-  rv = CreateStorageConnection(directoryEntry, usageFile, mOrigin,
-                               getter_AddRefs(storageConnection),
-                               &removedUsageFile);
-
-  MOZ_ASSERT(!removedUsageFile);
-
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  MOZ_ASSERT(mQuotaClient);
-
-  MutexAutoLock shadowDatabaseLock(mQuotaClient->ShadowDatabaseMutex());
-
-  nsCOMPtr<mozIStorageConnection> shadowConnection;
-  if (!gInitializedShadowStorage) {
-    rv = CreateShadowStorageConnection(quotaManager->GetBasePath(),
-                                       getter_AddRefs(shadowConnection));
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-
-    gInitializedShadowStorage = true;
-  }
-
-  mStorageConnection = storageConnection;
+  }
 
   return NS_OK;
 }
 
 void Connection::CloseStorageConnection() {
   AssertIsOnConnectionThread();
   MOZ_ASSERT(mStorageConnection);
 
@@ -4540,86 +4276,24 @@ void Connection::CachedStatement::Assign
 
   mStatement = aStatement;
 
   if (mStatement) {
     mScoper.emplace(mStatement);
   }
 }
 
-nsresult Connection::InitOriginHelper::BlockAndReturnOriginDirectoryPath(
-    nsAString& aOriginDirectoryPath) {
-  AssertIsOnConnectionThread();
-
-  QuotaManager* quotaManager = QuotaManager::Get();
-  MOZ_ASSERT(quotaManager);
-
-  MOZ_ALWAYS_SUCCEEDS(
-      quotaManager->IOThread()->Dispatch(this, NS_DISPATCH_NORMAL));
-
-  mozilla::MonitorAutoLock lock(mMonitor);
-  while (mWaiting) {
-    lock.Wait();
-  }
-
-  if (NS_WARN_IF(NS_FAILED(mIOThreadResultCode))) {
-    return mIOThreadResultCode;
-  }
-
-  aOriginDirectoryPath = mOriginDirectoryPath;
-  return NS_OK;
-}
-
-nsresult Connection::InitOriginHelper::RunOnIOThread() {
-  AssertIsOnIOThread();
-
-  QuotaManager* quotaManager = QuotaManager::Get();
-  MOZ_ASSERT(quotaManager);
-
-  nsCOMPtr<nsIFile> directoryEntry;
-  nsresult rv = quotaManager->EnsureOriginIsInitialized(
-      PERSISTENCE_TYPE_DEFAULT, mSuffix, mGroup, mOrigin,
-      getter_AddRefs(directoryEntry));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  rv = directoryEntry->GetPath(mOriginDirectoryPath);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  InitUsageForOrigin(mOrigin, 0);
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-Connection::InitOriginHelper::Run() {
-  AssertIsOnIOThread();
-
-  nsresult rv = RunOnIOThread();
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    mIOThreadResultCode = rv;
-  }
-
-  mozilla::MonitorAutoLock lock(mMonitor);
-  MOZ_ASSERT(mWaiting);
-
-  mWaiting = false;
-  lock.Notify();
-
-  return NS_OK;
-}
-
 Connection::FlushOp::FlushOp(Connection* aConnection,
                              WriteOptimizer&& aWriteOptimizer)
     : ConnectionDatastoreOperationBase(aConnection),
+      mQuotaClient(QuotaClient::GetInstance()),
       mWriteOptimizer(std::move(aWriteOptimizer)),
-      mShadowWrites(gShadowWrites) {}
+      mShadowWrites(gShadowWrites) {
+  MOZ_ASSERT(mQuotaClient);
+}
 
 nsresult Connection::FlushOp::DoDatastoreWork() {
   AssertIsOnConnectionThread();
   MOZ_ASSERT(mConnection);
 
   QuotaManager* quotaManager = QuotaManager::Get();
   MOZ_ASSERT(quotaManager);
 
@@ -4627,20 +4301,19 @@ nsresult Connection::FlushOp::DoDatastor
       mConnection->StorageConnection();
   MOZ_ASSERT(storageConnection);
 
   nsresult rv;
 
   Maybe<MutexAutoLock> shadowDatabaseLock;
 
   if (mShadowWrites) {
-    MOZ_ASSERT(mConnection->mQuotaClient);
-
-    shadowDatabaseLock.emplace(
-        mConnection->mQuotaClient->ShadowDatabaseMutex());
+    MOZ_ASSERT(mQuotaClient);
+
+    shadowDatabaseLock.emplace(mQuotaClient->ShadowDatabaseMutex());
 
     rv = AttachShadowDatabase(quotaManager->GetBasePath(), storageConnection);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 
   CachedStatement stmt;
@@ -4714,19 +4387,17 @@ nsresult Connection::FlushOp::DoDatastor
 
   return NS_OK;
 }
 
 nsresult Connection::CloseOp::DoDatastoreWork() {
   AssertIsOnConnectionThread();
   MOZ_ASSERT(mConnection);
 
-  if (mConnection->StorageConnection()) {
-    mConnection->CloseStorageConnection();
-  }
+  mConnection->CloseStorageConnection();
 
   return NS_OK;
 }
 
 void Connection::CloseOp::Cleanup() {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mConnection);
 
@@ -4763,27 +4434,24 @@ bool ConnectionThread::IsOnConnectionThr
   return NS_SUCCEEDED(mThread->IsOnCurrentThread(&current)) && current;
 }
 
 void ConnectionThread::AssertIsOnConnectionThread() {
   MOZ_ASSERT(IsOnConnectionThread());
 }
 
 already_AddRefed<Connection> ConnectionThread::CreateConnection(
-    const nsACString& aSuffix, const nsACString& aGroup,
-    const nsACString& aOrigin,
-    nsAutoPtr<ArchivedOriginScope>&& aArchivedOriginScope,
-    bool aDatabaseNotAvailable) {
+    const nsACString& aOrigin, const nsAString& aDirectoryPath,
+    nsAutoPtr<ArchivedOriginScope>&& aArchivedOriginScope) {
   AssertIsOnOwningThread();
   MOZ_ASSERT(!aOrigin.IsEmpty());
   MOZ_ASSERT(!mConnections.GetWeak(aOrigin));
 
-  RefPtr<Connection> connection =
-      new Connection(this, aSuffix, aGroup, aOrigin,
-                     std::move(aArchivedOriginScope), aDatabaseNotAvailable);
+  RefPtr<Connection> connection = new Connection(
+      this, aOrigin, aDirectoryPath, std::move(aArchivedOriginScope));
   mConnections.Put(aOrigin, connection);
 
   return connection.forget();
 }
 
 void ConnectionThread::Shutdown() {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mThread);
@@ -4795,17 +4463,17 @@ void ConnectionThread::Shutdown() {
  * Datastore
  ******************************************************************************/
 
 Datastore::Datastore(const nsACString& aOrigin, uint32_t aPrivateBrowsingId,
                      int64_t aUsage, int64_t aSizeOfKeys, int64_t aSizeOfItems,
                      already_AddRefed<DirectoryLock>&& aDirectoryLock,
                      already_AddRefed<Connection>&& aConnection,
                      already_AddRefed<QuotaObject>&& aQuotaObject,
-                     nsDataHashtable<nsStringHashKey, LSValue>& aValues,
+                     nsDataHashtable<nsStringHashKey, nsString>& aValues,
                      nsTArray<LSItemInfo>& aOrderedItems)
     : mDirectoryLock(std::move(aDirectoryLock)),
       mConnection(std::move(aConnection)),
       mQuotaObject(std::move(aQuotaObject)),
       mOrigin(aOrigin),
       mPrivateBrowsingId(aPrivateBrowsingId),
       mUsage(aUsage),
       mUpdateBatchUsage(-1),
@@ -4973,19 +4641,17 @@ void Datastore::NoteInactiveDatabase(Dat
       DebugOnly<bool> ok = UpdateUsage(finalDelta);
       MOZ_ASSERT(ok);
     }
 
     mPendingUsageDeltas.Clear();
   }
 }
 
-void Datastore::GetSnapshotInitInfo(const nsString& aKey,
-                                    bool& aAddKeyToUnknownItems,
-                                    nsTHashtable<nsStringHashKey>& aLoadedItems,
+void Datastore::GetSnapshotInitInfo(nsTHashtable<nsStringHashKey>& aLoadedItems,
                                     nsTArray<LSItemInfo>& aItemInfos,
                                     uint32_t& aNextLoadIndex,
                                     uint32_t& aTotalLength,
                                     int64_t& aInitialUsage, int64_t& aPeakUsage,
                                     LSSnapshot::LoadState& aLoadState) {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(!mClosed);
   MOZ_ASSERT(!mInUpdateBatch);
@@ -4997,200 +4663,90 @@ void Datastore::GetSnapshotInitInfo(cons
     int64_t sizeOfKey = static_cast<int64_t>(item.key().Length());
     sizeOfKeys += sizeOfKey;
     sizeOfItems += sizeOfKey + static_cast<int64_t>(item.value().Length());
   }
   MOZ_ASSERT(mSizeOfKeys == sizeOfKeys);
   MOZ_ASSERT(mSizeOfItems == sizeOfItems);
 #endif
 
-  // Computes load state optimized for current size of keys and items.
-  // Zero key length and value can be passed to do a quick initial estimation.
-  // If computed load state is already AllOrderedItems then excluded key length
-  // and value length can't make it any better.
-  auto GetLoadState = [&](auto aKeyLength, auto aValueLength) {
-    if (mSizeOfKeys - aKeyLength <= gSnapshotPrefill) {
-      if (mSizeOfItems - aKeyLength - aValueLength <= gSnapshotPrefill) {
-        return LSSnapshot::LoadState::AllOrderedItems;
-      }
-
-      return LSSnapshot::LoadState::AllOrderedKeys;
-    }
-
-    return LSSnapshot::LoadState::Partial;
-  };
-
-  // Value for given aKey if aKey is not void (can be void too if value doesn't
-  // exist for given aKey).
-  LSValue value;
-  // If aKey and value are not void, checkKey will be set to true. Once we find
-  // an item for given aKey in one of the loops below, checkKey is set to false
-  // to prevent additional comparison of strings (string implementation compares
-  // string lengths first to avoid char by char comparison if possible).
-  bool checkKey = false;
-
-  // Avoid additional hash lookup if all ordered items fit into initial prefill
-  // already.
-  LSSnapshot::LoadState loadState = GetLoadState(/* aKeyLength */ 0,
-                                                 /* aValueLength */ 0);
-  if (loadState != LSSnapshot::LoadState::AllOrderedItems && !aKey.IsVoid()) {
-    GetItem(aKey, value);
-    if (!value.IsVoid()) {
-      // Ok, we have a non void aKey and value.
-
-      // We have to watch for aKey during one of the loops below to exclude it
-      // from the size computation. The super fast mode (AllOrderedItems)
-      // doesn't have to do that though.
-      checkKey = true;
-
-      // We have to compute load state again because aKey length and value
-      // length is excluded from the size in this case.
-      loadState = GetLoadState(aKey.Length(), value.Length());
-    }
-  }
-
-  switch (loadState) {
-    case LSSnapshot::LoadState::AllOrderedItems: {
-      // We're sending all ordered items, we don't need to check keys because
-      // mOrderedItems must contain a value for aKey if checkKey is true.
-
+  if (mSizeOfKeys <= gSnapshotPrefill) {
+    if (mSizeOfItems <= gSnapshotPrefill) {
       aItemInfos.AppendElements(mOrderedItems);
 
       MOZ_ASSERT(aItemInfos.Length() == mValues.Count());
       aNextLoadIndex = mValues.Count();
 
-      aAddKeyToUnknownItems = false;
-
-      break;
-    }
-
-    case LSSnapshot::LoadState::AllOrderedKeys: {
-      // We don't have enough snapshot budget to send all items, but we do have
-      // enough to send all of the keys and to make a best effort to populate as
-      // many values as possible. We send void string values once we run out of
-      // budget. A complicating factor is that we want to make sure that we send
-      // the value for aKey which is a localStorage read that's triggering this
-      // request. Since that key can happen anywhere in the list of items, we
-      // need to handle it specially.
-      //
-      // The loop is effectively doing 2 things in parallel:
-      //
-      //   1. Looking for the `aKey` to send. This is tracked by `checkKey`
-      //      which is true if there was an `aKey` specified and until we
-      //      populate its value, and false thereafter.
-      //   2. Sending values until we run out of `size` budget and switch to
-      //      sending void values. `doneSendingValues` tracks when we've run out
-      //      of size budget, with `setVoidValue` tracking whether a value
-      //      should be sent for each turn of the event loop but can be
-      //      overridden when `aKey` is found.
-
+      aLoadState = LSSnapshot::LoadState::AllOrderedItems;
+    } else {
       int64_t size = mSizeOfKeys;
-      bool setVoidValue = false;
-      bool doneSendingValues = false;
+      nsString value;
       for (uint32_t index = 0; index < mOrderedItems.Length(); index++) {
         const LSItemInfo& item = mOrderedItems[index];
 
         const nsString& key = item.key();
-        const LSValue& value = item.value();
-
-        if (checkKey && key == aKey) {
-          checkKey = false;
-          setVoidValue = false;
-        } else if (!setVoidValue) {
-          if (doneSendingValues) {
-            setVoidValue = true;
+
+        if (!value.IsVoid()) {
+          value = item.value();
+
+          size += static_cast<int64_t>(value.Length());
+
+          if (size <= gSnapshotPrefill) {
+            aLoadedItems.PutEntry(key);
           } else {
-            size += static_cast<int64_t>(value.Length());
-
-            if (size > gSnapshotPrefill) {
-              setVoidValue = true;
-              doneSendingValues = true;
-
-              // We set doneSendingValues to true and that will guard against
-              // entering this branch during next iterations. So aNextLoadIndex
-              // is set only once.
-              aNextLoadIndex = index;
-            }
+            value.SetIsVoid(true);
+
+            // We set value to void so that will guard against entering the
+            // parent branch during next iterations. So aNextLoadIndex is set
+            // only once.
+            aNextLoadIndex = index;
           }
         }
 
         LSItemInfo* itemInfo = aItemInfos.AppendElement();
         itemInfo->key() = key;
-        if (setVoidValue) {
-          itemInfo->value().SetIsVoid(true);
-        } else {
-          aLoadedItems.PutEntry(key);
-          itemInfo->value() = value;
-        }
-      }
-
-      aAddKeyToUnknownItems = false;
-
-      break;
-    }
-
-    case LSSnapshot::LoadState::Partial: {
-      int64_t size = 0;
-      for (uint32_t index = 0; index < mOrderedItems.Length(); index++) {
-        const LSItemInfo& item = mOrderedItems[index];
-
-        const nsString& key = item.key();
-        const LSValue& value = item.value();
-
-        if (checkKey && key == aKey) {
-          checkKey = false;
-        } else {
-          size += static_cast<int64_t>(key.Length()) +
-                  static_cast<int64_t>(value.Length());
-
-          if (size > gSnapshotPrefill) {
-            aNextLoadIndex = index;
-            break;
-          }
-        }
-
-        aLoadedItems.PutEntry(key);
-
-        LSItemInfo* itemInfo = aItemInfos.AppendElement();
-        itemInfo->key() = key;
         itemInfo->value() = value;
       }
 
-      aAddKeyToUnknownItems = false;
-
-      if (!aKey.IsVoid()) {
-        if (value.IsVoid()) {
-          aAddKeyToUnknownItems = true;
-        } else if (checkKey) {
-          // The item wasn't added in the loop above, add it here.
-
-          LSItemInfo* itemInfo = aItemInfos.AppendElement();
-          itemInfo->key() = aKey;
-          itemInfo->value() = value;
-        }
+      aLoadState = LSSnapshot::LoadState::AllOrderedKeys;
+    }
+  } else {
+    int64_t size = 0;
+    for (uint32_t index = 0; index < mOrderedItems.Length(); index++) {
+      const LSItemInfo& item = mOrderedItems[index];
+
+      const nsString& key = item.key();
+      const nsString& value = item.value();
+
+      size += static_cast<int64_t>(key.Length()) +
+              static_cast<int64_t>(value.Length());
+
+      if (size > gSnapshotPrefill) {
+        aNextLoadIndex = index;
+        break;
       }
 
-      MOZ_ASSERT(aItemInfos.Length() < mOrderedItems.Length());
-
-      break;
-    }
-
-    default:
-      MOZ_CRASH("Bad load state value!");
+      aLoadedItems.PutEntry(key);
+
+      LSItemInfo* itemInfo = aItemInfos.AppendElement();
+      itemInfo->key() = key;
+      itemInfo->value() = value;
+    }
+
+    MOZ_ASSERT(aItemInfos.Length() < mOrderedItems.Length());
+    aLoadState = LSSnapshot::LoadState::Partial;
   }
 
   aTotalLength = mValues.Count();
 
   aInitialUsage = mUsage;
   aPeakUsage = aInitialUsage;
-
-  aLoadState = loadState;
-}
-
-void Datastore::GetItem(const nsString& aKey, LSValue& aValue) const {
+}
+
+void Datastore::GetItem(const nsString& aKey, nsString& aValue) const {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(!mClosed);
 
   if (!mValues.Get(aKey, &aValue)) {
     aValue.SetIsVoid(true);
   }
 }
 
@@ -5199,139 +4755,135 @@ void Datastore::GetKeys(nsTArray<nsStrin
   MOZ_ASSERT(!mClosed);
 
   for (auto item : mOrderedItems) {
     aKeys.AppendElement(item.key());
   }
 }
 
 void Datastore::SetItem(Database* aDatabase, const nsString& aDocumentURI,
-                        const nsString& aKey, const LSValue& aOldValue,
-                        const LSValue& aValue) {
+                        const nsString& aKey, const nsString& aOldValue,
+                        const nsString& aValue) {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aDatabase);
   MOZ_ASSERT(!mClosed);
   MOZ_ASSERT(mInUpdateBatch);
 
-  LSValue oldValue;
+  nsString oldValue;
   GetItem(aKey, oldValue);
 
-  if (oldValue != aValue) {
+  if (oldValue != aValue || oldValue.IsVoid() != aValue.IsVoid()) {
     bool isNewItem = oldValue.IsVoid();
 
     NotifySnapshots(aDatabase, aKey, oldValue, /* affectsOrder */ isNewItem);
 
     mValues.Put(aKey, aValue);
 
-    int64_t delta;
+    int64_t sizeOfItem;
 
     if (isNewItem) {
       mWriteOptimizer.AddItem(aKey, aValue);
 
       int64_t sizeOfKey = static_cast<int64_t>(aKey.Length());
-
-      delta = sizeOfKey + static_cast<int64_t>(aValue.UTF16Length());
-
-      mUpdateBatchUsage += delta;
+      sizeOfItem = sizeOfKey + static_cast<int64_t>(aValue.Length());
+
+      mUpdateBatchUsage += sizeOfItem;
 
       mSizeOfKeys += sizeOfKey;
-      mSizeOfItems += sizeOfKey + static_cast<int64_t>(aValue.Length());
-      ;
+      mSizeOfItems += sizeOfItem;
     } else {
       mWriteOptimizer.UpdateItem(aKey, aValue);
 
-      delta = static_cast<int64_t>(aValue.UTF16Length()) -
-              static_cast<int64_t>(oldValue.UTF16Length());
-
-      mUpdateBatchUsage += delta;
-
-      mSizeOfItems += static_cast<int64_t>(aValue.Length()) -
-                      static_cast<int64_t>(oldValue.Length());
+      sizeOfItem = static_cast<int64_t>(aValue.Length()) -
+                   static_cast<int64_t>(oldValue.Length());
+
+      mUpdateBatchUsage += sizeOfItem;
+
+      mSizeOfItems += sizeOfItem;
     }
 
     if (IsPersistent()) {
       if (oldValue.IsVoid()) {
-        mConnection->AddItem(aKey, aValue, delta);
+        mConnection->AddItem(aKey, aValue, sizeOfItem);
       } else {
-        mConnection->UpdateItem(aKey, aValue, delta);
+        mConnection->UpdateItem(aKey, aValue, sizeOfItem);
       }
     }
   }
 
   NotifyObservers(aDatabase, aDocumentURI, aKey, aOldValue, aValue);
 }
 
 void Datastore::RemoveItem(Database* aDatabase, const nsString& aDocumentURI,
-                           const nsString& aKey, const LSValue& aOldValue) {
+                           const nsString& aKey, const nsString& aOldValue) {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aDatabase);
   MOZ_ASSERT(!mClosed);
   MOZ_ASSERT(mInUpdateBatch);
 
-  LSValue oldValue;
+  nsString oldValue;
   GetItem(aKey, oldValue);
 
   if (!oldValue.IsVoid()) {
     NotifySnapshots(aDatabase, aKey, oldValue, /* aAffectsOrder */ true);
 
     mValues.Remove(aKey);
 
     mWriteOptimizer.RemoveItem(aKey);
 
     int64_t sizeOfKey = static_cast<int64_t>(aKey.Length());
-
-    int64_t delta = -sizeOfKey - static_cast<int64_t>(oldValue.UTF16Length());
-
-    mUpdateBatchUsage += delta;
+    int64_t sizeOfItem = sizeOfKey + static_cast<int64_t>(oldValue.Length());
+
+    mUpdateBatchUsage -= sizeOfItem;
 
     mSizeOfKeys -= sizeOfKey;
-    mSizeOfItems -= sizeOfKey + static_cast<int64_t>(oldValue.Length());
+    mSizeOfItems -= sizeOfItem;
 
     if (IsPersistent()) {
-      mConnection->RemoveItem(aKey, delta);
-    }
-  }
-
-  NotifyObservers(aDatabase, aDocumentURI, aKey, aOldValue, VoidLSValue());
+      mConnection->RemoveItem(aKey, -sizeOfItem);
+    }
+  }
+
+  NotifyObservers(aDatabase, aDocumentURI, aKey, aOldValue, VoidString());
 }
 
 void Datastore::Clear(Database* aDatabase, const nsString& aDocumentURI) {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aDatabase);
   MOZ_ASSERT(!mClosed);
   MOZ_ASSERT(mInUpdateBatch);
 
   if (mValues.Count()) {
-    int64_t delta = 0;
+    int64_t sizeOfItems = 0;
     for (auto iter = mValues.ConstIter(); !iter.Done(); iter.Next()) {
       const nsAString& key = iter.Key();
-      const LSValue& value = iter.Data();
-
-      delta += -static_cast<int64_t>(key.Length()) -
-               static_cast<int64_t>(value.UTF16Length());
+      const nsAString& value = iter.Data();
+
+      sizeOfItems += (static_cast<int64_t>(key.Length()) +
+                      static_cast<int64_t>(value.Length()));
 
       NotifySnapshots(aDatabase, key, value, /* aAffectsOrder */ true);
     }
 
     mValues.Clear();
 
     mWriteOptimizer.Clear();
 
-    mUpdateBatchUsage += delta;
+    mUpdateBatchUsage -= sizeOfItems;
 
     mSizeOfKeys = 0;
     mSizeOfItems = 0;
 
     if (IsPersistent()) {
-      mConnection->Clear(delta);
-    }
-  }
-
-  NotifyObservers(aDatabase, aDocumentURI, VoidString(), VoidLSValue(),
-                  VoidLSValue());
+      mConnection->Clear(-sizeOfItems);
+    }
+  }
+
+  NotifyObservers(aDatabase, aDocumentURI, VoidString(), VoidString(),
+                  VoidString());
 }
 
 void Datastore::PrivateBrowsingClear() {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(mPrivateBrowsingId);
   MOZ_ASSERT(!mClosed);
   MOZ_ASSERT(!mInUpdateBatch);
 
@@ -5492,17 +5044,18 @@ void Datastore::CleanupMetadata() {
   gDatastores->Remove(mOrigin);
 
   if (!gDatastores->Count()) {
     gDatastores = nullptr;
   }
 }
 
 void Datastore::NotifySnapshots(Database* aDatabase, const nsAString& aKey,
-                                const LSValue& aOldValue, bool aAffectsOrder) {
+                                const nsAString& aOldValue,
+                                bool aAffectsOrder) {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aDatabase);
 
   for (auto iter = mDatabases.ConstIter(); !iter.Done(); iter.Next()) {
     Database* database = iter.Get()->GetKey();
     if (database == aDatabase) {
       continue;
     }
@@ -5524,18 +5077,18 @@ void Datastore::MarkSnapshotsDirty() {
     if (snapshot) {
       snapshot->MarkDirty();
     }
   }
 }
 
 void Datastore::NotifyObservers(Database* aDatabase,
                                 const nsString& aDocumentURI,
-                                const nsString& aKey, const LSValue& aOldValue,
-                                const LSValue& aNewValue) {
+                                const nsString& aKey, const nsString& aOldValue,
+                                const nsString& aNewValue) {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aDatabase);
 
   if (!gObservers) {
     return;
   }
 
   nsTArray<Observer*>* array;
@@ -5725,19 +5278,19 @@ mozilla::ipc::IPCResult Database::RecvAl
   }
 
   AllowToClose();
 
   return IPC_OK();
 }
 
 PBackgroundLSSnapshotParent* Database::AllocPBackgroundLSSnapshotParent(
-    const nsString& aDocumentURI, const nsString& aKey,
-    const bool& aIncreasePeakUsage, const int64_t& aRequestedSize,
-    const int64_t& aMinSize, LSSnapshotInitInfo* aInitInfo) {
+    const nsString& aDocumentURI, const bool& aIncreasePeakUsage,
+    const int64_t& aRequestedSize, const int64_t& aMinSize,
+    LSSnapshotInitInfo* aInitInfo) {
   AssertIsOnBackgroundThread();
 
   if (NS_WARN_IF(aIncreasePeakUsage && aRequestedSize <= 0)) {
     ASSERT_UNLESS_FUZZING();
     return nullptr;
   }
 
   if (NS_WARN_IF(aIncreasePeakUsage && aMinSize <= 0)) {
@@ -5753,55 +5306,49 @@ PBackgroundLSSnapshotParent* Database::A
   RefPtr<Snapshot> snapshot = new Snapshot(this, aDocumentURI);
 
   // Transfer ownership to IPDL.
   return snapshot.forget().take();
 }
 
 mozilla::ipc::IPCResult Database::RecvPBackgroundLSSnapshotConstructor(
     PBackgroundLSSnapshotParent* aActor, const nsString& aDocumentURI,
-    const nsString& aKey, const bool& aIncreasePeakUsage,
-    const int64_t& aRequestedSize, const int64_t& aMinSize,
-    LSSnapshotInitInfo* aInitInfo) {
+    const bool& aIncreasePeakUsage, const int64_t& aRequestedSize,
+    const int64_t& aMinSize, LSSnapshotInitInfo* aInitInfo) {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT_IF(aIncreasePeakUsage, aRequestedSize > 0);
   MOZ_ASSERT_IF(aIncreasePeakUsage, aMinSize > 0);
   MOZ_ASSERT(aInitInfo);
   MOZ_ASSERT(!mAllowedToClose);
 
   auto* snapshot = static_cast<Snapshot*>(aActor);
 
-  bool addKeyToUnknownItems;
+  // TODO: This can be optimized depending on which operation triggers snapshot
+  //       creation. For example clear() doesn't need to receive items at all.
   nsTHashtable<nsStringHashKey> loadedItems;
   nsTArray<LSItemInfo> itemInfos;
   uint32_t nextLoadIndex;
   uint32_t totalLength;
   int64_t initialUsage;
   int64_t peakUsage;
   LSSnapshot::LoadState loadState;
-  mDatastore->GetSnapshotInitInfo(aKey, addKeyToUnknownItems, loadedItems,
-                                  itemInfos, nextLoadIndex, totalLength,
-                                  initialUsage, peakUsage, loadState);
-
-  nsTHashtable<nsStringHashKey> unknownItems;
-  if (addKeyToUnknownItems) {
-    unknownItems.PutEntry(aKey);
-  }
+  mDatastore->GetSnapshotInitInfo(loadedItems, itemInfos, nextLoadIndex,
+                                  totalLength, initialUsage, peakUsage,
+                                  loadState);
 
   if (aIncreasePeakUsage) {
     int64_t size = mDatastore->RequestUpdateUsage(aRequestedSize, aMinSize);
     peakUsage += size;
   }
 
-  snapshot->Init(loadedItems, unknownItems, nextLoadIndex, totalLength,
-                 initialUsage, peakUsage, loadState);
+  snapshot->Init(loadedItems, nextLoadIndex, totalLength, initialUsage,
+                 peakUsage, loadState);
 
   RegisterSnapshot(snapshot);
 
-  aInitInfo->addKeyToUnknownItems() = addKeyToUnknownItems;
   aInitInfo->itemInfos() = std::move(itemInfos);
   aInitInfo->totalLength() = totalLength;
   aInitInfo->initialUsage() = initialUsage;
   aInitInfo->peakUsage() = peakUsage;
   aInitInfo->loadState() = loadState;
 
   return IPC_OK();
 }
@@ -5839,28 +5386,28 @@ Snapshot::Snapshot(Database* aDatabase, 
   MOZ_ASSERT(aDatabase);
 }
 
 Snapshot::~Snapshot() {
   MOZ_ASSERT(mActorDestroyed);
   MOZ_ASSERT(mFinishReceived);
 }
 
-void Snapshot::SaveItem(const nsAString& aKey, const LSValue& aOldValue,
+void Snapshot::SaveItem(const nsAString& aKey, const nsAString& aOldValue,
                         bool aAffectsOrder) {
   AssertIsOnBackgroundThread();
 
   MarkDirty();
 
   if (mLoadedAllItems) {
     return;
   }
 
   if (!mLoadedItems.GetEntry(aKey) && !mUnknownItems.GetEntry(aKey)) {
-    LSValue oldValue(aOldValue);
+    nsString oldValue(aOldValue);
     mValues.LookupForAdd(aKey).OrInsert([oldValue]() { return oldValue; });
   }
 
   if (aAffectsOrder && !mSavedKeys) {
     mDatastore->GetKeys(mKeys);
     mSavedKeys = true;
   }
 }
@@ -6005,17 +5552,17 @@ mozilla::ipc::IPCResult Snapshot::RecvLo
   mKeys.Clear();
   mLoadedAllItems = true;
   mLoadKeysReceived = true;
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult Snapshot::RecvLoadValueAndMoreItems(
-    const nsString& aKey, LSValue* aValue, nsTArray<LSItemInfo>* aItemInfos) {
+    const nsString& aKey, nsString* aValue, nsTArray<LSItemInfo>* aItemInfos) {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aValue);
   MOZ_ASSERT(aItemInfos);
   MOZ_ASSERT(mDatastore);
 
   if (NS_WARN_IF(mFinishReceived)) {
     ASSERT_UNLESS_FUZZING();
     return IPC_FAIL_NO_REASON(this);
@@ -6094,17 +5641,17 @@ mozilla::ipc::IPCResult Snapshot::RecvLo
       if (countBeforePut != mLoadedItems.Count()) {
         // Check mValues first since that contains values as they existed when
         // our snapshot was created, but have since been changed/removed in the
         // datastore. If it's not there, then the datastore has the
         // still-current value. However, if the datastore's key ordering has
         // changed, we need to do a hash lookup rather than being able to do an
         // optimized direct access to the index.
 
-        LSValue value;
+        nsString value;
         auto valueEntry = mValues.Lookup(key);
         if (valueEntry) {
           value = valueEntry.Data();
         } else if (mSavedKeys) {
           mDatastore->GetItem(nsString(key), value);
         } else {
           value = orderedItems[mNextLoadIndex].value();
         }
@@ -6227,18 +5774,18 @@ mozilla::ipc::IPCResult Snapshot::RecvPi
 Observer::Observer(const nsACString& aOrigin)
     : mOrigin(aOrigin), mActorDestroyed(false) {
   AssertIsOnBackgroundThread();
 }
 
 Observer::~Observer() { MOZ_ASSERT(mActorDestroyed); }
 
 void Observer::Observe(Database* aDatabase, const nsString& aDocumentURI,
-                       const nsString& aKey, const LSValue& aOldValue,
-                       const LSValue& aNewValue) {
+                       const nsString& aKey, const nsString& aOldValue,
+                       const nsString& aNewValue) {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aDatabase);
 
   Unused << SendObserve(aDatabase->GetPrincipalInfo(),
                         aDatabase->PrivateBrowsingId(), aDocumentURI, aKey,
                         aOldValue, aNewValue);
 }
 
@@ -6548,18 +6095,18 @@ PrepareDatastoreOp::PrepareDatastoreOp(
               : aParams.get_LSRequestPrepareDatastoreParams().commonParams()),
       mContentParentId(aContentParentId),
       mPrivateBrowsingId(0),
       mUsage(0),
       mSizeOfKeys(0),
       mSizeOfItems(0),
       mDatastoreId(0),
       mNestedState(NestedState::BeforeNesting),
-      mForPreload(aParams.type() ==
-                  LSRequestParams::TLSRequestPreloadDatastoreParams),
+      mCreateIfNotExists(aParams.type() ==
+                         LSRequestParams::TLSRequestPrepareDatastoreParams),
       mDatabaseNotAvailable(false),
       mRequestedDirectoryLock(false),
       mInvalidated(false)
 #ifdef DEBUG
       ,
       mDEBUGUsage(0)
 #endif
 {
@@ -6861,136 +6408,91 @@ nsresult PrepareDatastoreOp::DatabaseWor
   if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonBackgroundThread()) ||
       !MayProceedOnNonOwningThread()) {
     return NS_ERROR_FAILURE;
   }
 
   QuotaManager* quotaManager = QuotaManager::Get();
   MOZ_ASSERT(quotaManager);
 
-  // This must be called before EnsureTemporaryStorageIsInitialized.
-  nsresult rv = quotaManager->EnsureStorageIsInitialized();
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  // This ensures that gUsages gets populated with usages for existings origin
-  // directories.
-  rv = quotaManager->EnsureTemporaryStorageIsInitialized();
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
+  nsresult rv;
 
   if (!gArchivedOrigins) {
     rv = LoadArchivedOrigins();
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
     MOZ_ASSERT(gArchivedOrigins);
   }
 
   bool hasDataForMigration = mArchivedOriginScope->HasMatches(gArchivedOrigins);
 
-  // If there's nothing to preload (except the case when we want to migrate data
-  // during preloading), then we can finish the operation without creating a
-  // datastore in GetResponse (GetResponse won't create a datastore if
-  // mDatatabaseNotAvailable and mForPreload are both true).
-  int64_t usage;
-  if (mForPreload && !GetUsageForOrigin(mOrigin, usage) &&
-      !hasDataForMigration) {
-    return DatabaseNotAvailable();
-  }
-
-  // The origin directory doesn't need to be created when we don't have data for
-  // migration. It will be created on the connection thread in
-  // Connection::EnsureStorageConnection.
-  // However, origin quota must be initialized, GetQuotaObject in GetResponse
-  // would fail otherwise.
+  bool createIfNotExists = mCreateIfNotExists || hasDataForMigration;
+
   nsCOMPtr<nsIFile> directoryEntry;
-  if (hasDataForMigration) {
-    rv = quotaManager->EnsureOriginIsInitialized(
-        PERSISTENCE_TYPE_DEFAULT, mSuffix, mGroup, mOrigin,
-        getter_AddRefs(directoryEntry));
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-  } else {
-    rv = quotaManager->GetDirectoryForOrigin(PERSISTENCE_TYPE_DEFAULT, mOrigin,
-                                             getter_AddRefs(directoryEntry));
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-
-    quotaManager->EnsureQuotaForOrigin(PERSISTENCE_TYPE_DEFAULT, mGroup,
-                                       mOrigin);
+  rv = quotaManager->EnsureOriginIsInitialized(
+      PERSISTENCE_TYPE_DEFAULT, mSuffix, mGroup, mOrigin, createIfNotExists,
+      getter_AddRefs(directoryEntry));
+  if (rv == NS_ERROR_NOT_AVAILABLE) {
+    return DatabaseNotAvailable();
+  }
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
   }
 
   rv = directoryEntry->Append(NS_LITERAL_STRING(LS_DIRECTORY_NAME));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
-  nsString directoryPath;
-  rv = directoryEntry->GetPath(directoryPath);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  // The ls directory doesn't need to be created when we don't have data for
-  // migration. It will be created on the connection thread in
-  // Connection::EnsureStorageConnection.
-  rv = EnsureDirectoryEntry(directoryEntry,
-                            /* aCreateIfNotExists */ hasDataForMigration,
+  rv = EnsureDirectoryEntry(directoryEntry, createIfNotExists,
                             /* aIsDirectory */ true);
+  if (rv == NS_ERROR_NOT_AVAILABLE) {
+    return DatabaseNotAvailable();
+  }
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = directoryEntry->GetPath(mDirectoryPath);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   rv = directoryEntry->Append(NS_LITERAL_STRING(DATA_FILE_NAME));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
-  rv = directoryEntry->GetPath(mDatabaseFilePath);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  // The database doesn't need to be created when we don't have data for
-  // migration. It will be created on the connection thread in
-  // Connection::EnsureStorageConnection.
   bool alreadyExisted;
-  rv = EnsureDirectoryEntry(directoryEntry,
-                            /* aCreateIfNotExists */ hasDataForMigration,
+  rv = EnsureDirectoryEntry(directoryEntry, createIfNotExists,
                             /* aIsDirectory */ false, &alreadyExisted);
+  if (rv == NS_ERROR_NOT_AVAILABLE) {
+    return DatabaseNotAvailable();
+  }
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   if (alreadyExisted) {
     MOZ_ASSERT(gUsages);
     DebugOnly<bool> hasUsage = gUsages->Get(mOrigin, &mUsage);
     MOZ_ASSERT(hasUsage);
   } else {
-    // The database doesn't exist.
-
-    if (!hasDataForMigration) {
-      // The database doesn't exist and we don't have data for migration.
-      // Finish the operation, but create an empty datastore in GetResponse
-      // (GetResponse will create an empty datastore if mDatabaseNotAvailable
-      // is true and mForPreload is false).
-      return DatabaseNotAvailable();
-    }
-
     MOZ_ASSERT(mUsage == 0);
     InitUsageForOrigin(mOrigin, mUsage);
   }
 
+  rv = directoryEntry->GetPath(mDatabaseFilePath);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
   nsCOMPtr<nsIFile> usageFile;
-  rv = GetUsageFile(directoryPath, getter_AddRefs(usageFile));
+  rv = GetUsageFile(mDirectoryPath, getter_AddRefs(usageFile));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   nsCOMPtr<mozIStorageConnection> connection;
   bool removedUsageFile;
 
   rv = CreateStorageConnection(directoryEntry, usageFile, mOrigin,
@@ -7033,18 +6535,18 @@ nsresult PrepareDatastoreOp::DatabaseWor
       return NS_ERROR_FILE_NO_DEVICE_SPACE;
     }
 
     mozStorageTransaction transaction(
         connection, false, mozIStorageConnection::TRANSACTION_IMMEDIATE);
 
     nsCOMPtr<mozIStorageStatement> stmt;
     rv = connection->CreateStatement(
-        NS_LITERAL_CSTRING("INSERT INTO data (key, value, utf16Length) "
-                           "SELECT key, value, utf16Length(value) "
+        NS_LITERAL_CSTRING("INSERT INTO data (key, value) "
+                           "SELECT key, value "
                            "FROM webappsstore2 "
                            "WHERE originKey = :originKey "
                            "AND originAttributes = :originAttributes;"
 
                            ),
         getter_AddRefs(stmt));
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
@@ -7173,20 +6675,17 @@ nsresult PrepareDatastoreOp::EnsureDirec
   bool exists;
   nsresult rv = aEntry->Exists(&exists);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   if (!exists) {
     if (!aCreateIfNotExists) {
-      if (aAlreadyExisted) {
-        *aAlreadyExisted = false;
-      }
-      return NS_OK;
+      return NS_ERROR_NOT_AVAILABLE;
     }
 
     if (aIsDirectory) {
       rv = aEntry->Create(nsIFile::DIRECTORY_TYPE, 0755);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
     }
@@ -7269,18 +6768,17 @@ nsresult PrepareDatastoreOp::BeginLoadDa
     return NS_ERROR_FAILURE;
   }
 
   if (!gConnectionThread) {
     gConnectionThread = new ConnectionThread();
   }
 
   mConnection = gConnectionThread->CreateConnection(
-      mSuffix, mGroup, mOrigin, std::move(mArchivedOriginScope),
-      /* aDatabaseNotAvailable */ false);
+      mOrigin, mDirectoryPath, std::move(mArchivedOriginScope));
   MOZ_ASSERT(mConnection);
 
   // Must set this before dispatching otherwise we will race with the
   // connection thread.
   mNestedState = NestedState::DatabaseWorkLoadData;
 
   // Can't assign to mLoadDataOp directly since that's a weak reference and
   // LoadDataOp is reference counted.
@@ -7367,48 +6865,32 @@ nsresult PrepareDatastoreOp::NestedRun()
   return NS_OK;
 }
 
 void PrepareDatastoreOp::GetResponse(LSRequestResponse& aResponse) {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mState == State::SendingResults);
   MOZ_ASSERT(NS_SUCCEEDED(ResultCode()));
 
-  // A datastore is not created when we are just trying to preload data and
-  // there's no database file.
-  if (mDatabaseNotAvailable && mForPreload) {
+  if (mDatabaseNotAvailable) {
+    MOZ_ASSERT(!mCreateIfNotExists);
+
     LSRequestPreloadDatastoreResponse preloadDatastoreResponse;
 
     aResponse = preloadDatastoreResponse;
 
     return;
   }
 
   if (!mDatastore) {
     MOZ_ASSERT(mUsage == mDEBUGUsage);
 
     RefPtr<QuotaObject> quotaObject;
 
     if (mPrivateBrowsingId == 0) {
-      if (!mConnection) {
-        // This can happen when there's no database file.
-        MOZ_ASSERT(mDatabaseNotAvailable);
-
-        // Even though there's no database file, we need to create a connection
-        // and pass it to datastore.
-        if (!gConnectionThread) {
-          gConnectionThread = new ConnectionThread();
-        }
-
-        mConnection = gConnectionThread->CreateConnection(
-            mSuffix, mGroup, mOrigin, std::move(mArchivedOriginScope),
-            /* aDatabaseNotAvailable */ true);
-        MOZ_ASSERT(mConnection);
-      }
-
       quotaObject = GetQuotaObject();
       MOZ_ASSERT(quotaObject);
     }
 
     mDatastore = new Datastore(mOrigin, mPrivateBrowsingId, mUsage, mSizeOfKeys,
                                mSizeOfItems, mDirectoryLock.forget(),
                                mConnection.forget(), quotaObject.forget(),
                                mValues, mOrderedItems);
@@ -7422,38 +6904,38 @@ void PrepareDatastoreOp::GetResponse(LSR
     MOZ_ASSERT(!gDatastores->Get(mOrigin));
     gDatastores->Put(mOrigin, mDatastore);
   }
 
   mDatastoreId = ++gLastDatastoreId;
 
   nsAutoPtr<PreparedDatastore> preparedDatastore(
       new PreparedDatastore(mDatastore, mContentParentId, mOrigin, mDatastoreId,
-                            /* aForPreload */ mForPreload));
+                            /* aForPreload */ !mCreateIfNotExists));
 
   if (!gPreparedDatastores) {
     gPreparedDatastores = new PreparedDatastoreHashtable();
   }
   gPreparedDatastores->Put(mDatastoreId, preparedDatastore);
 
   if (mInvalidated) {
     preparedDatastore->Invalidate();
   }
 
   preparedDatastore.forget();
 
-  if (mForPreload) {
-    LSRequestPreloadDatastoreResponse preloadDatastoreResponse;
-
-    aResponse = preloadDatastoreResponse;
-  } else {
+  if (mCreateIfNotExists) {
     LSRequestPrepareDatastoreResponse prepareDatastoreResponse;
     prepareDatastoreResponse.datastoreId() = mDatastoreId;
 
     aResponse = prepareDatastoreResponse;
+  } else {
+    LSRequestPreloadDatastoreResponse preloadDatastoreResponse;
+
+    aResponse = preloadDatastoreResponse;
   }
 }
 
 void PrepareDatastoreOp::Cleanup() {
   AssertIsOnOwningThread();
 
   if (mDatastore) {
     MOZ_ASSERT(mDatastoreId > 0);
@@ -7675,60 +7157,46 @@ nsresult PrepareDatastoreOp::LoadDataOp:
              NestedState::DatabaseWorkLoadData);
 
   if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonBackgroundThread()) ||
       !MayProceedOnNonOwningThread()) {
     return NS_ERROR_FAILURE;
   }
 
   Connection::CachedStatement stmt;
-  nsresult rv = mConnection->GetCachedStatement(
-      NS_LITERAL_CSTRING("SELECT key, value, utf16Length, compressed "
-                         "FROM data;"),
-      &stmt);
+  nsresult rv =
+      mConnection->GetCachedStatement(NS_LITERAL_CSTRING("SELECT key, value "
+                                                         "FROM data;"),
+                                      &stmt);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   bool hasResult;
   while (NS_SUCCEEDED(rv = stmt->ExecuteStep(&hasResult)) && hasResult) {
     nsString key;
     rv = stmt->GetString(0, key);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
-    nsCString buffer;
-    rv = stmt->GetUTF8String(1, buffer);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-
-    int32_t utf16Length;
-    rv = stmt->GetInt32(2, &utf16Length);
+    nsString value;
+    rv = stmt->GetString(1, value);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
-    int32_t compressed;
-    rv = stmt->GetInt32(3, &compressed);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-
-    LSValue value(buffer, utf16Length, compressed);
-
     mPrepareDatastoreOp->mValues.Put(key, value);
     auto item = mPrepareDatastoreOp->mOrderedItems.AppendElement();
     item->key() = key;
     item->value() = value;
     mPrepareDatastoreOp->mSizeOfKeys += key.Length();
     mPrepareDatastoreOp->mSizeOfItems += key.Length() + value.Length();
 #ifdef DEBUG
-    mPrepareDatastoreOp->mDEBUGUsage += key.Length() + value.UTF16Length();
+    mPrepareDatastoreOp->mDEBUGUsage += key.Length() + value.Length();
 #endif
   }
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   return NS_OK;
 }
@@ -8469,20 +7937,22 @@ nsresult QuotaClient::GetUsageForOrigin(
                                         UsageInfo* aUsageInfo) {
   AssertIsOnIOThread();
   MOZ_ASSERT(aPersistenceType == PERSISTENCE_TYPE_DEFAULT);
   MOZ_ASSERT(aUsageInfo);
 
   // We can't open the database at this point, since it can be already used
   // by the connection thread. Use the cached value instead.
 
-  int64_t usage;
-  if (mozilla::dom::GetUsageForOrigin(aOrigin, usage)) {
-    MOZ_ASSERT(usage >= 0);
-    aUsageInfo->AppendToDatabaseUsage(usage);
+  if (gUsages) {
+    int64_t usage;
+    if (gUsages->Get(aOrigin, &usage)) {
+      MOZ_ASSERT(usage >= 0);
+      aUsageInfo->AppendToDatabaseUsage(usage);
+    }
   }
 
   return NS_OK;
 }
 
 nsresult QuotaClient::AboutToClearOrigins(
     const Nullable<PersistenceType>& aPersistenceType,
     const OriginScope& aOriginScope) {
--- a/dom/localstorage/LSDatabase.cpp
+++ b/dom/localstorage/LSDatabase.cpp
@@ -115,17 +115,17 @@ void LSDatabase::NoteFinishedSnapshot(LS
 }
 
 nsresult LSDatabase::GetLength(LSObject* aObject, uint32_t* aResult) {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aObject);
   MOZ_ASSERT(mActor);
   MOZ_ASSERT(!mAllowedToClose);
 
-  nsresult rv = EnsureSnapshot(aObject, VoidString());
+  nsresult rv = EnsureSnapshot(aObject);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   rv = mSnapshot->GetLength(aResult);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
@@ -135,17 +135,17 @@ nsresult LSDatabase::GetLength(LSObject*
 
 nsresult LSDatabase::GetKey(LSObject* aObject, uint32_t aIndex,
                             nsAString& aResult) {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aObject);
   MOZ_ASSERT(mActor);
   MOZ_ASSERT(!mAllowedToClose);
 
-  nsresult rv = EnsureSnapshot(aObject, VoidString());
+  nsresult rv = EnsureSnapshot(aObject);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   rv = mSnapshot->GetKey(aIndex, aResult);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
@@ -155,17 +155,17 @@ nsresult LSDatabase::GetKey(LSObject* aO
 
 nsresult LSDatabase::GetItem(LSObject* aObject, const nsAString& aKey,
                              nsAString& aResult) {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aObject);
   MOZ_ASSERT(mActor);
   MOZ_ASSERT(!mAllowedToClose);
 
-  nsresult rv = EnsureSnapshot(aObject, aKey);
+  nsresult rv = EnsureSnapshot(aObject);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   rv = mSnapshot->GetItem(aKey, aResult);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
@@ -174,17 +174,17 @@ nsresult LSDatabase::GetItem(LSObject* a
 }
 
 nsresult LSDatabase::GetKeys(LSObject* aObject, nsTArray<nsString>& aKeys) {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aObject);
   MOZ_ASSERT(mActor);
   MOZ_ASSERT(!mAllowedToClose);
 
-  nsresult rv = EnsureSnapshot(aObject, VoidString());
+  nsresult rv = EnsureSnapshot(aObject);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   rv = mSnapshot->GetKeys(aKeys);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
@@ -195,17 +195,17 @@ nsresult LSDatabase::GetKeys(LSObject* a
 nsresult LSDatabase::SetItem(LSObject* aObject, const nsAString& aKey,
                              const nsAString& aValue,
                              LSNotifyInfo& aNotifyInfo) {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aObject);
   MOZ_ASSERT(mActor);
   MOZ_ASSERT(!mAllowedToClose);
 
-  nsresult rv = EnsureSnapshot(aObject, aKey);
+  nsresult rv = EnsureSnapshot(aObject);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   rv = mSnapshot->SetItem(aKey, aValue, aNotifyInfo);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
@@ -215,17 +215,17 @@ nsresult LSDatabase::SetItem(LSObject* a
 
 nsresult LSDatabase::RemoveItem(LSObject* aObject, const nsAString& aKey,
                                 LSNotifyInfo& aNotifyInfo) {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aObject);
   MOZ_ASSERT(mActor);
   MOZ_ASSERT(!mAllowedToClose);
 
-  nsresult rv = EnsureSnapshot(aObject, aKey);
+  nsresult rv = EnsureSnapshot(aObject);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   rv = mSnapshot->RemoveItem(aKey, aNotifyInfo);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
@@ -234,17 +234,17 @@ nsresult LSDatabase::RemoveItem(LSObject
 }
 
 nsresult LSDatabase::Clear(LSObject* aObject, LSNotifyInfo& aNotifyInfo) {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aObject);
   MOZ_ASSERT(mActor);
   MOZ_ASSERT(!mAllowedToClose);
 
-  nsresult rv = EnsureSnapshot(aObject, VoidString());
+  nsresult rv = EnsureSnapshot(aObject);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   rv = mSnapshot->Clear(aNotifyInfo);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
@@ -257,17 +257,17 @@ nsresult LSDatabase::BeginExplicitSnapsh
   MOZ_ASSERT(aObject);
   MOZ_ASSERT(mActor);
   MOZ_ASSERT(!mAllowedToClose);
 
   if (mSnapshot) {
     return NS_ERROR_ALREADY_INITIALIZED;
   }
 
-  nsresult rv = EnsureSnapshot(aObject, VoidString(), /* aExplicit */ true);
+  nsresult rv = EnsureSnapshot(aObject, /* aExplicit */ true);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   return NS_OK;
 }
 
 nsresult LSDatabase::EndExplicitSnapshot(LSObject* aObject) {
@@ -285,45 +285,44 @@ nsresult LSDatabase::EndExplicitSnapshot
   nsresult rv = mSnapshot->End();
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   return NS_OK;
 }
 
-nsresult LSDatabase::EnsureSnapshot(LSObject* aObject, const nsAString& aKey,
-                                    bool aExplicit) {
+nsresult LSDatabase::EnsureSnapshot(LSObject* aObject, bool aExplicit) {
   MOZ_ASSERT(aObject);
   MOZ_ASSERT(mActor);
   MOZ_ASSERT_IF(mSnapshot, !aExplicit);
   MOZ_ASSERT(!mAllowedToClose);
 
   if (mSnapshot) {
     return NS_OK;
   }
 
   RefPtr<LSSnapshot> snapshot = new LSSnapshot(this);
 
   LSSnapshotChild* actor = new LSSnapshotChild(snapshot);
 
   LSSnapshotInitInfo initInfo;
   bool ok = mActor->SendPBackgroundLSSnapshotConstructor(
-      actor, aObject->DocumentURI(), nsString(aKey),
+      actor, aObject->DocumentURI(),
       /* increasePeakUsage */ true,
       /* requestedSize */ 131072,
       /* minSize */ 4096, &initInfo);
   if (NS_WARN_IF(!ok)) {
     return NS_ERROR_FAILURE;
   }
 
   snapshot->SetActor(actor);
 
   // This add refs snapshot.
-  nsresult rv = snapshot->Init(aKey, initInfo, aExplicit);
+  nsresult rv = snapshot->Init(initInfo, aExplicit);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   // This is cleared in LSSnapshot::Run() before the snapshot is destroyed.
   mSnapshot = snapshot;
 
   return NS_OK;
--- a/dom/localstorage/LSDatabase.h
+++ b/dom/localstorage/LSDatabase.h
@@ -74,18 +74,17 @@ class LSDatabase final {
 
   nsresult BeginExplicitSnapshot(LSObject* aObject);
 
   nsresult EndExplicitSnapshot(LSObject* aObject);
 
  private:
   ~LSDatabase();
 
-  nsresult EnsureSnapshot(LSObject* aObject, const nsAString& aKey,
-                          bool aExplicit = false);
+  nsresult EnsureSnapshot(LSObject* aObject, bool aExplicit = false);
 
   void AllowToClose();
 };
 
 }  // namespace dom
 }  // namespace mozilla
 
 #endif  // mozilla_dom_localstorage_LSDatabase_h
--- a/dom/localstorage/LSSnapshot.cpp
+++ b/dom/localstorage/LSSnapshot.cpp
@@ -54,46 +54,42 @@ LSSnapshot::~LSSnapshot() {
 void LSSnapshot::SetActor(LSSnapshotChild* aActor) {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aActor);
   MOZ_ASSERT(!mActor);
 
   mActor = aActor;
 }
 
-nsresult LSSnapshot::Init(const nsAString& aKey,
-                          const LSSnapshotInitInfo& aInitInfo, bool aExplicit) {
+nsresult LSSnapshot::Init(const LSSnapshotInitInfo& aInitInfo, bool aExplicit) {
   AssertIsOnOwningThread();
   MOZ_ASSERT(!mSelfRef);
   MOZ_ASSERT(mActor);
   MOZ_ASSERT(mLoadState == LoadState::Initial);
   MOZ_ASSERT(!mInitialized);
   MOZ_ASSERT(!mSentFinish);
 
   mSelfRef = this;
 
   LoadState loadState = aInitInfo.loadState();
 
   const nsTArray<LSItemInfo>& itemInfos = aInitInfo.itemInfos();
   for (uint32_t i = 0; i < itemInfos.Length(); i++) {
     const LSItemInfo& itemInfo = itemInfos[i];
 
-    const LSValue& value = itemInfo.value();
+    const nsString& value = itemInfo.value();
 
     if (loadState != LoadState::AllOrderedItems && !value.IsVoid()) {
       mLoadedItems.PutEntry(itemInfo.key());
     }
 
-    mValues.Put(itemInfo.key(), value.AsString());
+    mValues.Put(itemInfo.key(), value);
   }
 
   if (loadState == LoadState::Partial) {
-    if (aInitInfo.addKeyToUnknownItems()) {
-      mUnknownItems.PutEntry(aKey);
-    }
     mInitLength = aInitInfo.totalLength();
     mLength = mInitLength;
   } else if (loadState == LoadState::AllOrderedKeys) {
     mInitLength = aInitInfo.totalLength();
   } else {
     MOZ_ASSERT(loadState == LoadState::AllOrderedItems);
   }
 
@@ -238,18 +234,18 @@ nsresult LSSnapshot::SetItem(const nsASt
     }
 
     if (oldValue.IsVoid() && mLoadState == LoadState::Partial) {
       mLength++;
     }
 
     LSSetItemInfo setItemInfo;
     setItemInfo.key() = aKey;
-    setItemInfo.oldValue() = LSValue(oldValue);
-    setItemInfo.value() = LSValue(aValue);
+    setItemInfo.oldValue() = oldValue;
+    setItemInfo.value() = aValue;
 
     mWriteInfos.AppendElement(std::move(setItemInfo));
   }
 
   aNotifyInfo.changed() = changed;
   aNotifyInfo.oldValue() = oldValue;
 
   return NS_OK;
@@ -284,17 +280,17 @@ nsresult LSSnapshot::RemoveItem(const ns
     MOZ_ASSERT(NS_SUCCEEDED(rv));
 
     if (mLoadState == LoadState::Partial) {
       mLength--;
     }
 
     LSRemoveItemInfo removeItemInfo;
     removeItemInfo.key() = aKey;
-    removeItemInfo.oldValue() = LSValue(oldValue);
+    removeItemInfo.oldValue() = oldValue;
 
     mWriteInfos.AppendElement(std::move(removeItemInfo));
   }
 
   aNotifyInfo.changed() = changed;
   aNotifyInfo.oldValue() = oldValue;
 
   return NS_OK;
@@ -431,39 +427,36 @@ nsresult LSSnapshot::GetItemInternal(con
 
   switch (mLoadState) {
     case LoadState::Partial: {
       if (mValues.Get(aKey, &result)) {
         MOZ_ASSERT(!result.IsVoid());
       } else if (mLoadedItems.GetEntry(aKey) || mUnknownItems.GetEntry(aKey)) {
         result.SetIsVoid(true);
       } else {
-        LSValue value;
         nsTArray<LSItemInfo> itemInfos;
         if (NS_WARN_IF(!mActor->SendLoadValueAndMoreItems(
-                nsString(aKey), &value, &itemInfos))) {
+                nsString(aKey), &result, &itemInfos))) {
           return NS_ERROR_FAILURE;
         }
 
-        result = value.AsString();
-
         if (result.IsVoid()) {
           mUnknownItems.PutEntry(aKey);
         } else {
           mLoadedItems.PutEntry(aKey);
           mValues.Put(aKey, result);
 
           // mLoadedItems.Count()==mInitLength is checked below.
         }
 
         for (uint32_t i = 0; i < itemInfos.Length(); i++) {
           const LSItemInfo& itemInfo = itemInfos[i];
 
           mLoadedItems.PutEntry(itemInfo.key());
-          mValues.Put(itemInfo.key(), itemInfo.value().AsString());
+          mValues.Put(itemInfo.key(), itemInfo.value());
         }
 
         if (mLoadedItems.Count() == mInitLength) {
           mLoadedItems.Clear();
           mUnknownItems.Clear();
           mLength = 0;
           mLoadState = LoadState::AllUnorderedItems;
         }
@@ -479,37 +472,34 @@ nsresult LSSnapshot::GetItemInternal(con
       }
 
       break;
     }
 
     case LoadState::AllOrderedKeys: {
       if (mValues.Get(aKey, &result)) {
         if (result.IsVoid()) {
-          LSValue value;
           nsTArray<LSItemInfo> itemInfos;
           if (NS_WARN_IF(!mActor->SendLoadValueAndMoreItems(
-                  nsString(aKey), &value, &itemInfos))) {
+                  nsString(aKey), &result, &itemInfos))) {
             return NS_ERROR_FAILURE;
           }
 
-          result = value.AsString();
-
           MOZ_ASSERT(!result.IsVoid());
 
           mLoadedItems.PutEntry(aKey);
           mValues.Put(aKey, result);
 
           // mLoadedItems.Count()==mInitLength is checked below.
 
           for (uint32_t i = 0; i < itemInfos.Length(); i++) {
             const LSItemInfo& itemInfo = itemInfos[i];
 
             mLoadedItems.PutEntry(itemInfo.key());
-            mValues.Put(itemInfo.key(), itemInfo.value().AsString());
+            mValues.Put(itemInfo.key(), itemInfo.value());
           }
 
           if (mLoadedItems.Count() == mInitLength) {
             mLoadedItems.Clear();
             MOZ_ASSERT(mLength == 0);
             mLoadState = LoadState::AllOrderedItems;
           }
         }
--- a/dom/localstorage/LSSnapshot.h
+++ b/dom/localstorage/LSSnapshot.h
@@ -2,18 +2,16 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_localstorage_LSSnapshot_h
 #define mozilla_dom_localstorage_LSSnapshot_h
 
-#include "LSValue.h"
-
 namespace mozilla {
 namespace dom {
 
 class LSDatabase;
 class LSNotifyInfo;
 class LSSnapshotChild;
 class LSSnapshotInitInfo;
 class LSWriteInfo;
@@ -109,18 +107,17 @@ class LSSnapshot final : public nsIRunna
     AssertIsOnOwningThread();
     MOZ_ASSERT(mActor);
 
     mActor = nullptr;
   }
 
   bool Explicit() const { return mExplicit; }
 
-  nsresult Init(const nsAString& aKey, const LSSnapshotInitInfo& aInitInfo,
-                bool aExplicit);
+  nsresult Init(const LSSnapshotInitInfo& aInitInfo, bool aExplicit);
 
   nsresult GetLength(uint32_t* aResult);
 
   nsresult GetKey(uint32_t aIndex, nsAString& aResult);
 
   nsresult GetItem(const nsAString& aKey, nsAString& aResult);
 
   nsresult GetKeys(nsTArray<nsString>& aKeys);
deleted file mode 100644
--- a/dom/localstorage/LSValue.cpp
+++ /dev/null
@@ -1,19 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "LSValue.h"
-
-namespace mozilla {
-namespace dom {
-
-const LSValue& VoidLSValue() {
-  static const LSValue sVoidLSValue(VoidCString(), 0, false);
-
-  return sVoidLSValue;
-}
-
-}  // namespace dom
-}  // namespace mozilla
deleted file mode 100644
--- a/dom/localstorage/LSValue.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_dom_localstorage_LSValue_h
-#define mozilla_dom_localstorage_LSValue_h
-
-#include "SnappyUtils.h"
-
-namespace mozilla {
-namespace dom {
-
-/**
- * Represents a LocalStorage value. From content's perspective, values (if
- * present) are always DOMStrings. This is also true from a quota-tracking
- * perspective. However, for memory and disk efficiency it's preferable to store
- * the value in alternate compressed or utf-8 encoding representations. The
- * LSValue type exists to support these alternate representations, dynamically
- * decompressing/re-encoding to utf-16 while still tracking value size on a
- * utf-16 basis for quota purposes.
- */
-class LSValue final {
-  friend struct IPC::ParamTraits<LSValue>;
-
-  nsCString mBuffer;
-  uint32_t mUTF16Length;
-  bool mCompressed;
-
- public:
-  LSValue() : mUTF16Length(0), mCompressed(false) {}
-
-  explicit LSValue(const nsACString& aBuffer, uint32_t aUTF16Length,
-                   bool aCompressed)
-      : mBuffer(aBuffer),
-        mUTF16Length(aUTF16Length),
-        mCompressed(aCompressed) {}
-
-  explicit LSValue(const nsAString& aBuffer) : mUTF16Length(aBuffer.Length()) {
-    if (aBuffer.IsVoid()) {
-      mBuffer.SetIsVoid(true);
-      mCompressed = false;
-    } else {
-      CopyUTF16toUTF8(aBuffer, mBuffer);
-      nsCString buffer;
-      if ((mCompressed = SnappyCompress(mBuffer, buffer))) {
-        mBuffer = buffer;
-      }
-    }
-  }
-
-  bool IsVoid() const { return mBuffer.IsVoid(); }
-
-  void SetIsVoid(bool aVal) { mBuffer.SetIsVoid(aVal); }
-
-  /**
-   * This represents the "physical" length that the parent process uses for
-   * the size of value/item computation. This can also be used to see how much
-   * memory the value is using at rest or what the cost is for sending the value
-   * over IPC.
-   */
-  uint32_t Length() const { return mBuffer.Length(); }
-
-  /*
-   * This represents the "logical" length that content sees and that is also
-   * used for quota management purposes.
-   */
-  uint32_t UTF16Length() const { return mUTF16Length; }
-
-  bool IsCompressed() const { return mCompressed; }
-
-  bool Equals(const LSValue& aOther) const {
-    return mBuffer == aOther.mBuffer &&
-           mBuffer.IsVoid() == aOther.mBuffer.IsVoid() &&
-           mUTF16Length == aOther.mUTF16Length &&
-           mCompressed == aOther.mCompressed;
-  }
-
-  bool operator==(const LSValue& aOther) const { return Equals(aOther); }
-
-  bool operator!=(const LSValue& aOther) const { return !Equals(aOther); }
-
-  operator const nsCString&() const { return mBuffer; }
-
-  operator Span<const char>() const { return mBuffer; }
-
-  class Converter {
-    nsString mBuffer;
-
-   public:
-    explicit Converter(const LSValue& aValue) {
-      if (aValue.mBuffer.IsVoid()) {
-        mBuffer.SetIsVoid(true);
-      } else if (aValue.mCompressed) {
-        nsCString buffer;
-        MOZ_ALWAYS_TRUE(SnappyUncompress(aValue.mBuffer, buffer));
-        CopyUTF8toUTF16(buffer, mBuffer);
-      } else {
-        CopyUTF8toUTF16(aValue.mBuffer, mBuffer);
-      }
-    }
-    Converter(Converter&& aOther) : mBuffer(aOther.mBuffer) {}
-    ~Converter() {}
-
-    operator const nsString&() const { return mBuffer; }
-
-   private:
-    Converter() = delete;
-    Converter(const Converter&) = delete;
-    Converter& operator=(const Converter&) = delete;
-    Converter& operator=(const Converter&&) = delete;
-  };
-
-  Converter AsString() const { return Converter(const_cast<LSValue&>(*this)); }
-};
-
-const LSValue& VoidLSValue();
-
-}  // namespace dom
-}  // namespace mozilla
-
-#endif  // mozilla_dom_localstorage_LSValue_h
--- a/dom/localstorage/PBackgroundLSDatabase.ipdl
+++ b/dom/localstorage/PBackgroundLSDatabase.ipdl
@@ -18,24 +18,16 @@ namespace dom {
 /**
  * Initial LSSnapshot state as produced by Datastore::GetSnapshotInitInfo.  See
  * `LSSnapshot::LoadState` for more details about the possible states and a
  * high level overview.
  */
 struct LSSnapshotInitInfo
 {
   /**
-   * Boolean indicating whether the `key` provided as an argument to the
-   * PBackgroundLSSnapshot constructor did not exist in the Datastore and should
-   * be treated as an unknown and therefore undefined value. Note that `key` may
-   * have been provided as a void string, in which case this value is forced to
-   * be false.
-   */
-  bool addKeyToUnknownItems;
-  /**
    * As many key/value or key/void pairs as the snapshot prefill byte budget
    * allowed.
    */
   LSItemInfo[] itemInfos;
   /**
    * The total number of key/value pairs in LocalStorage for this origin at the
    * time the snapshot was created.  (And the point of the snapshot is to
    * conceptually freeze the state of the Datastore in time, so this value does
@@ -102,30 +94,21 @@ parent:
    * Datastore state in the parent.
    *
    * This needs to be synchronous because LocalStorage's semantics are
    * synchronous.  Note that the Datastore in the PBackground parent already
    * has the answers to this request immediately available without needing to
    * consult any other threads or perform any I/O.  Additionally, the response
    * is explicitly bounded in size by the tunable snapshot prefill byte limit.
    *
-   * @param key
-   *   If key is non-void, then the snapshot is being triggered by a direct
-   *   access to a localStorage key (get, set, or removal, with set/removal
-   *   requiring the old value in order to properly populate the "storage"
-   *   event), the key being requested. It's possible the key is not present in
-   *   localStorage, in which case LSSnapshotInitInfo::addKeyToUnknownItems will
-   *   be true indicating that there is no such key/value pair, otherwise it
-   *   will be false.
    * @param increasePeakUsage
    *   Whether the parent should attempt to pre-allocate some amount of quota
    *   usage to the Snapshot.
    */
   sync PBackgroundLSSnapshot(nsString documentURI,
-                             nsString key,
                              bool increasePeakUsage,
                              int64_t requestedSize,
                              int64_t minSize)
     returns (LSSnapshotInitInfo initInfo);
 
 child:
   /**
    * Only sent by the parent in response to the child's DeleteMe request.
--- a/dom/localstorage/PBackgroundLSObserver.ipdl
+++ b/dom/localstorage/PBackgroundLSObserver.ipdl
@@ -1,21 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include protocol PBackground;
 
 include PBackgroundSharedTypes;
 
-include "mozilla/dom/localstorage/SerializationHelpers.h";
-
-using mozilla::dom::LSValue
-  from "mozilla/dom/LSValue.h";
-
 namespace mozilla {
 namespace dom {
 
 /**
  * The observer protocol sends "storage" event notifications for changes to
  * LocalStorage that take place in other processes as their Snapshots are
  * Checkpointed to the canonical Datastore in the parent process.  Same-process
  * notifications are generated as mutations happen.
@@ -49,14 +44,14 @@ child:
    * Checkpointed, applying their mutations.  The child actor currently directly
    * shunts these to Storage::NotifyChange to generate "storage" events for
    * immediate dispatch.
    */
   async Observe(PrincipalInfo principalInfo,
                 uint32_t privateBrowsingId,
                 nsString documentURI,
                 nsString key,
-                LSValue oldValue,
-                LSValue newValue);
+                nsString oldValue,
+                nsString newValue);
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/localstorage/PBackgroundLSSharedTypes.ipdlh
+++ b/dom/localstorage/PBackgroundLSSharedTypes.ipdlh
@@ -1,20 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include PBackgroundSharedTypes;
 include ProtocolTypes;
 
-include "mozilla/dom/localstorage/SerializationHelpers.h";
-
-using mozilla::dom::LSValue
-  from "mozilla/dom/LSValue.h";
-
 namespace mozilla {
 namespace dom {
 
 struct LSRequestCommonParams
 {
   PrincipalInfo principalInfo;
   nsCString originKey;
 };
@@ -57,13 +52,13 @@ union LSSimpleRequestParams
  * LocalStorage key/value pair wire representations.  `value` may be void in
  * cases where there is a value but it is not being sent for memory/bandwidth
  * conservation purposes.  (It's not possible to have a null/undefined `value`
  * as Storage is defined explicitly as a String store.)
  */
 struct LSItemInfo
 {
   nsString key;
-  LSValue value;
+  nsString value;
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/localstorage/PBackgroundLSSnapshot.ipdl
+++ b/dom/localstorage/PBackgroundLSSnapshot.ipdl
@@ -2,35 +2,30 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include protocol PBackground;
 include protocol PBackgroundLSDatabase;
 
 include PBackgroundLSSharedTypes;
 
-include "mozilla/dom/localstorage/SerializationHelpers.h";
-
-using mozilla::dom::LSValue
-  from "mozilla/dom/LSValue.h";
-
 namespace mozilla {
 namespace dom {
 
 struct LSSetItemInfo
 {
   nsString key;
-  LSValue oldValue;
-  LSValue value;
+  nsString oldValue;
+  nsString value;
 };
 
 struct LSRemoveItemInfo
 {
   nsString key;
-  LSValue oldValue;
+  nsString oldValue;
 };
 
 struct LSClearInfo
 {
 };
 
 /**
  * Union of LocalStorage mutation types.
@@ -61,17 +56,17 @@ parent:
    * the need to use this synchronous message again.
    *
    * This needs to be synchronous because LocalStorage's semantics are
    * synchronous.  Note that the Snapshot in the PBackground parent already
    * has the answers to this request immediately available without needing to
    * consult any other threads or perform any I/O.
    */
   sync LoadValueAndMoreItems(nsString key)
-    returns (LSValue value, LSItemInfo[] itemInfos);
+    returns (nsString value, LSItemInfo[] itemInfos);
 
   /**
    * Invoked on demand to load all keys in in their canonical order if they
    * didn't fit into the initial snapshot prefill.
    *
    * This needs to be synchronous because LocalStorage's semantics are
    * synchronous.  Note that the Snapshot in the PBackground parent already
    * has the answers to this request immediately available without needing to
--- a/dom/localstorage/SerializationHelpers.h
+++ b/dom/localstorage/SerializationHelpers.h
@@ -5,46 +5,21 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_localstorage_SerializationHelpers_h
 #define mozilla_dom_localstorage_SerializationHelpers_h
 
 #include "ipc/IPCMessageUtils.h"
 
 #include "mozilla/dom/LSSnapshot.h"
-#include "mozilla/dom/LSValue.h"
 
 namespace IPC {
 
 template <>
 struct ParamTraits<mozilla::dom::LSSnapshot::LoadState>
     : public ContiguousEnumSerializer<
           mozilla::dom::LSSnapshot::LoadState,
           mozilla::dom::LSSnapshot::LoadState::Initial,
           mozilla::dom::LSSnapshot::LoadState::EndGuard> {};
 
-template <>
-struct ParamTraits<mozilla::dom::LSValue> {
-  typedef mozilla::dom::LSValue paramType;
-
-  static void Write(Message* aMsg, const paramType& aParam) {
-    WriteParam(aMsg, aParam.mBuffer);
-    WriteParam(aMsg, aParam.mUTF16Length);
-    WriteParam(aMsg, aParam.mCompressed);
-  }
-
-  static bool Read(const Message* aMsg, PickleIterator* aIter,
-                   paramType* aResult) {
-    return ReadParam(aMsg, aIter, &aResult->mBuffer) &&
-           ReadParam(aMsg, aIter, &aResult->mUTF16Length) &&
-           ReadParam(aMsg, aIter, &aResult->mCompressed);
-  }
-
-  static void Log(const paramType& aParam, std::wstring* aLog) {
-    LogParam(aParam.mBuffer, aLog);
-    LogParam(aParam.mUTF16Length, aLog);
-    LogParam(aParam.mCompressed, aLog);
-  }
-};
-
 }  // namespace IPC
 
 #endif  // mozilla_dom_localstorage_SerializationHelpers_h
deleted file mode 100644
--- a/dom/localstorage/SnappyUtils.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "SnappyUtils.h"
-
-#include "snappy/snappy.h"
-
-namespace mozilla {
-namespace dom {
-
-bool SnappyCompress(const nsACString& aSource, nsACString& aDest) {
-  MOZ_ASSERT(!aSource.IsVoid());
-
-  size_t uncompressedLength = aSource.Length();
-
-  if (uncompressedLength <= 16) {
-    return false;
-  }
-
-  size_t compressedLength = snappy::MaxCompressedLength(uncompressedLength);
-
-  aDest.SetLength(compressedLength);
-
-  snappy::RawCompress(aSource.BeginReading(), uncompressedLength,
-                      aDest.BeginWriting(), &compressedLength);
-
-  if (compressedLength >= uncompressedLength) {
-    return false;
-  }
-
-  aDest.SetLength(compressedLength);
-
-  return true;
-}
-
-bool SnappyUncompress(const nsACString& aSource, nsACString& aDest) {
-  MOZ_ASSERT(!aSource.IsVoid());
-
-  const char* compressed = aSource.BeginReading();
-
-  size_t compressedLength = aSource.Length();
-
-  size_t uncompressedLength;
-  if (!snappy::GetUncompressedLength(compressed, compressedLength,
-                                     &uncompressedLength)) {
-    return false;
-  }
-
-  aDest.SetLength(uncompressedLength);
-
-  if (!snappy::RawUncompress(compressed, compressedLength,
-                             aDest.BeginWriting())) {
-    return false;
-  }
-
-  return true;
-}
-
-}  // namespace dom
-}  // namespace mozilla
deleted file mode 100644
--- a/dom/localstorage/SnappyUtils.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_dom_localstorage_SnappyUtils_h
-#define mozilla_dom_localstorage_SnappyUtils_h
-
-namespace mozilla {
-namespace dom {
-
-bool SnappyCompress(const nsACString& aSource, nsACString& aDest);
-
-bool SnappyUncompress(const nsACString& aSource, nsACString& aDest);
-
-}  // namespace dom
-}  // namespace mozilla
-
-#endif  // mozilla_dom_localstorage_SnappyUtils_h
--- a/dom/localstorage/moz.build
+++ b/dom/localstorage/moz.build
@@ -29,32 +29,28 @@ EXPORTS.mozilla.dom.localstorage += [
 ]
 
 EXPORTS.mozilla.dom += [
     'LocalStorageCommon.h',
     'LocalStorageManager2.h',
     'LSObject.h',
     'LSObserver.h',
     'LSSnapshot.h',
-    'LSValue.h',
-    'SnappyUtils.h',
 ]
 
 UNIFIED_SOURCES += [
     'ActorsChild.cpp',
     'ActorsParent.cpp',
     'LocalStorageCommon.cpp',
     'LocalStorageManager2.cpp',
     'LSDatabase.cpp',
     'LSObject.cpp',
     'LSObserver.cpp',
     'LSSnapshot.cpp',
-    'LSValue.cpp',
     'ReportInternalError.cpp',
-    'SnappyUtils.cpp',
 ]
 
 IPDL_SOURCES += [
     'PBackgroundLSDatabase.ipdl',
     'PBackgroundLSObserver.ipdl',
     'PBackgroundLSRequest.ipdl',
     'PBackgroundLSSharedTypes.ipdlh',
     'PBackgroundLSSimpleRequest.ipdl',
--- a/dom/quota/ActorsParent.cpp
+++ b/dom/quota/ActorsParent.cpp
@@ -213,17 +213,17 @@ const char kResourceOriginPrefix[] = "re
 #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 = 3;
+const uint32_t kLocalStorageArchiveVersion = 1;
 
 const char kProfileDoChangeTopic[] = "profile-do-change";
 
 /******************************************************************************
  * SQLite functions
  ******************************************************************************/
 
 int32_t MakeStorageVersion(uint32_t aMajorStorageVersion,
@@ -441,16 +441,17 @@ nsresult LoadLocalStorageArchiveVersion(
   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;"),
@@ -466,16 +467,17 @@ nsresult SaveLocalStorageArchiveVersion(
 
   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 {
@@ -608,30 +610,20 @@ namespace {
 
 class OriginInfo final {
   friend class GroupInfo;
   friend class QuotaManager;
   friend class QuotaObject;
 
  public:
   OriginInfo(GroupInfo* aGroupInfo, const nsACString& aOrigin, uint64_t aUsage,
-             int64_t aAccessTime, bool aPersisted, bool aDirectoryExists);
+             int64_t aAccessTime, bool aPersisted);
 
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(OriginInfo)
 
-  GroupInfo* GetGroupInfo() const { return mGroupInfo; }
-
-  const nsCString& Origin() const { return mOrigin; }
-
-  int64_t LockedUsage() const {
-    AssertCurrentThreadOwnsQuotaMutex();
-
-    return mUsage;
-  }
-
   int64_t LockedAccessTime() const {
     AssertCurrentThreadOwnsQuotaMutex();
 
     return mAccessTime;
   }
 
   bool LockedPersisted() const {
     AssertCurrentThreadOwnsQuotaMutex();
@@ -659,29 +651,16 @@ class OriginInfo final {
 
   nsDataHashtable<nsStringHashKey, QuotaObject*> mQuotaObjects;
 
   GroupInfo* mGroupInfo;
   const nsCString mOrigin;
   uint64_t mUsage;
   int64_t mAccessTime;
   bool mPersisted;
-  /**
-   * In some special cases like the LocalStorage client where it's possible to
-   * create a Quota-using representation but not actually write any data, we
-   * want to be able to track quota for an origin without creating its origin
-   * directory or the per-client files until they are actually needed to store
-   * data. In those cases, the OriginInfo will be created by
-   * EnsureQuotaForOrigin and the resulting mDirectoryExists will be false until
-   * the origin actually needs to be created. It is possible for mUsage to be
-   * greater than zero while mDirectoryExists is false, representing a state
-   * where a client like LocalStorage has reserved quota for disk writes, but
-   * has not yet flushed the data to disk.
-   */
-  bool mDirectoryExists;
 };
 
 class OriginInfoLRUComparator {
  public:
   bool Equals(const OriginInfo* a, const OriginInfo* b) const {
     return a && b ? a->LockedAccessTime() == b->LockedAccessTime()
                   : !a && !b ? true : false;
   }
@@ -707,18 +686,16 @@ class GroupInfo final {
         mUsage(0) {
     MOZ_ASSERT(aPersistenceType != PERSISTENCE_TYPE_PERSISTENT);
 
     MOZ_COUNT_CTOR(GroupInfo);
   }
 
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GroupInfo)
 
-  PersistenceType GetPersistenceType() const { return mPersistenceType; }
-
  private:
   // Private destructor, to discourage deletion outside of Release():
   ~GroupInfo() { MOZ_COUNT_DTOR(GroupInfo); }
 
   already_AddRefed<OriginInfo> LockedGetOriginInfo(const nsACString& aOrigin);
 
   void LockedAddOriginInfo(OriginInfo* aOriginInfo);
 
@@ -1144,22 +1121,16 @@ class GetUsageOp final : public QuotaUsa
   bool mGetAll;
 
  public:
   explicit GetUsageOp(const UsageRequestParams& aParams);
 
  private:
   ~GetUsageOp() {}
 
-  void ProcessOriginInternal(QuotaManager* aQuotaManager,
-                             const PersistenceType aPersistenceType,
-                             const nsACString& aOrigin,
-                             const int64_t aTimestamp, const bool aPersisted,
-                             const uint64_t aUsage);
-
   nsresult DoDirectoryWork(QuotaManager* aQuotaManager) override;
 
   bool IsCanceled() override;
 
   nsresult ProcessOrigin(QuotaManager* aQuotaManager, nsIFile* aOriginDir,
                          const bool aPersistent,
                          const PersistenceType aPersistenceType) override;
 
@@ -2250,31 +2221,36 @@ nsresult CreateDirectoryMetadata2(nsIFil
 
   return NS_OK;
 }
 
 nsresult CreateDirectoryMetadataFiles(nsIFile* aDirectory, bool aPersisted,
                                       const nsACString& aSuffix,
                                       const nsACString& aGroup,
                                       const nsACString& aOrigin,
-                                      int64_t aTimestamp) {
+                                      int64_t* aTimestamp) {
   AssertIsOnIOThread();
 
+  int64_t timestamp = PR_Now();
+
   nsresult rv =
-      CreateDirectoryMetadata(aDirectory, aTimestamp, aSuffix, aGroup, aOrigin);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  rv = CreateDirectoryMetadata2(aDirectory, aTimestamp, aPersisted, aSuffix,
+      CreateDirectoryMetadata(aDirectory, timestamp, aSuffix, aGroup, aOrigin);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = CreateDirectoryMetadata2(aDirectory, timestamp, aPersisted, aSuffix,
                                 aGroup, aOrigin);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
+  if (aTimestamp) {
+    *aTimestamp = timestamp;
+  }
   return NS_OK;
 }
 
 nsresult GetBinaryInputStream(nsIFile* aDirectory, const nsAString& aFilename,
                               nsIBinaryInputStream** aStream) {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(aDirectory);
   MOZ_ASSERT(aStream);
@@ -3406,38 +3382,16 @@ uint64_t QuotaManager::CollectOriginsFor
     }
 
     return sizeToBeFreed;
   }
 
   return 0;
 }
 
-template <typename P>
-void QuotaManager::CollectPendingOriginsForListing(P aPredicate) {
-  MutexAutoLock lock(mQuotaMutex);
-
-  for (auto iter = mGroupInfoPairs.Iter(); !iter.Done(); iter.Next()) {
-    GroupInfoPair* pair = iter.UserData();
-
-    MOZ_ASSERT(!iter.Key().IsEmpty());
-    MOZ_ASSERT(pair);
-
-    RefPtr<GroupInfo> groupInfo =
-        pair->LockedGetGroupInfo(PERSISTENCE_TYPE_DEFAULT);
-    if (groupInfo) {
-      for (RefPtr<OriginInfo>& originInfo : groupInfo->mOriginInfos) {
-        if (!originInfo->mDirectoryExists) {
-          aPredicate(originInfo);
-        }
-      }
-    }
-  }
-}
-
 nsresult QuotaManager::Init(const nsAString& aBasePath) {
   mBasePath = aBasePath;
 
   nsCOMPtr<nsIFile> baseDir;
   nsresult rv = NS_NewLocalFile(aBasePath, false, getter_AddRefs(baseDir));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
@@ -3564,76 +3518,34 @@ void QuotaManager::InitQuotaForOrigin(Pe
                                       const nsACString& aOrigin,
                                       uint64_t aUsageBytes, int64_t aAccessTime,
                                       bool aPersisted) {
   AssertIsOnIOThread();
   MOZ_ASSERT(aPersistenceType != PERSISTENCE_TYPE_PERSISTENT);
 
   MutexAutoLock lock(mQuotaMutex);
 
-  RefPtr<GroupInfo> groupInfo =
-      LockedGetOrCreateGroupInfo(aPersistenceType, aGroup);
+  GroupInfoPair* pair;
+  if (!mGroupInfoPairs.Get(aGroup, &pair)) {
+    pair = new GroupInfoPair();
+    mGroupInfoPairs.Put(aGroup, pair);
+    // The hashtable is now responsible to delete the GroupInfoPair.
+  }
+
+  RefPtr<GroupInfo> groupInfo = pair->LockedGetGroupInfo(aPersistenceType);
+  if (!groupInfo) {
+    groupInfo = new GroupInfo(pair, aPersistenceType, aGroup);
+    pair->LockedSetGroupInfo(aPersistenceType, groupInfo);
+  }
 
   RefPtr<OriginInfo> originInfo =
-      new OriginInfo(groupInfo, aOrigin, aUsageBytes, aAccessTime, aPersisted,
-                     /* aDirectoryExists */ true);
+      new OriginInfo(groupInfo, aOrigin, aUsageBytes, aAccessTime, aPersisted);
   groupInfo->LockedAddOriginInfo(originInfo);
 }
 
-void QuotaManager::EnsureQuotaForOrigin(PersistenceType aPersistenceType,
-                                        const nsACString& aGroup,
-                                        const nsACString& aOrigin) {
-  AssertIsOnIOThread();
-  MOZ_ASSERT(aPersistenceType != PERSISTENCE_TYPE_PERSISTENT);
-
-  MutexAutoLock lock(mQuotaMutex);
-
-  RefPtr<GroupInfo> groupInfo =
-      LockedGetOrCreateGroupInfo(aPersistenceType, aGroup);
-
-  RefPtr<OriginInfo> originInfo = groupInfo->LockedGetOriginInfo(aOrigin);
-  if (!originInfo) {
-    originInfo = new OriginInfo(
-        groupInfo, aOrigin, /* aUsageBytes */ 0, /* aAccessTime */ PR_Now(),
-        /* aPersisted */ false, /* aDirectoryExists */ false);
-    groupInfo->LockedAddOriginInfo(originInfo);
-  }
-}
-
-void QuotaManager::NoteOriginDirectoryCreated(PersistenceType aPersistenceType,
-                                              const nsACString& aGroup,
-                                              const nsACString& aOrigin,
-                                              bool aPersisted,
-                                              int64_t& aTimestamp) {
-  AssertIsOnIOThread();
-  MOZ_ASSERT(aPersistenceType != PERSISTENCE_TYPE_PERSISTENT);
-
-  int64_t timestamp;
-
-  MutexAutoLock lock(mQuotaMutex);
-
-  RefPtr<GroupInfo> groupInfo =
-      LockedGetOrCreateGroupInfo(aPersistenceType, aGroup);
-
-  RefPtr<OriginInfo> originInfo = groupInfo->LockedGetOriginInfo(aOrigin);
-  if (originInfo) {
-    originInfo->mPersisted = aPersisted;
-    originInfo->mDirectoryExists = true;
-    timestamp = originInfo->LockedAccessTime();
-  } else {
-    timestamp = PR_Now();
-    RefPtr<OriginInfo> originInfo = new OriginInfo(
-        groupInfo, aOrigin, /* aUsageBytes */ 0, /* aAccessTime */ timestamp,
-        aPersisted, /* aDirectoryExists */ true);
-    groupInfo->LockedAddOriginInfo(originInfo);
-  }
-
-  aTimestamp = timestamp;
-}
-
 void QuotaManager::DecreaseUsageForOrigin(PersistenceType aPersistenceType,
                                           const nsACString& aGroup,
                                           const nsACString& aOrigin,
                                           int64_t aSize) {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(aPersistenceType != PERSISTENCE_TYPE_PERSISTENT);
 
   MutexAutoLock lock(mQuotaMutex);
@@ -5344,35 +5256,27 @@ nsresult QuotaManager::UpgradeLocalStora
   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;
 }
-
-nsresult QuotaManager::UpgradeLocalStorageArchiveFrom2To3(
-    nsCOMPtr<mozIStorageConnection>& aConnection) {
-  nsresult rv = SaveLocalStorageArchiveVersion(aConnection, 3);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  return NS_OK;
-}
+*/
 
 #ifdef DEBUG
 
 void QuotaManager::AssertStorageIsInitialized() const {
   AssertIsOnIOThread();
   MOZ_ASSERT(mStorageInitialized);
 }
 
@@ -5586,28 +5490,27 @@ nsresult QuotaManager::EnsureStorageIsIn
         MOZ_ASSERT(version == 0);
 
         rv = InitializeLocalStorageArchive(connection,
                                            kLocalStorageArchiveVersion);
         if (NS_WARN_IF(NS_FAILED(rv))) {
           return rv;
         }
       } else {
-        static_assert(kLocalStorageArchiveVersion == 3,
+        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) {
+          } /* else if (version == 1) {
             rv = UpgradeLocalStorageArchiveFrom1To2(connection);
-          } else if (version == 2) {
-            rv = UpgradeLocalStorageArchiveFrom2To3(connection);
-          } else {
+          } */
+          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;
@@ -5714,37 +5617,41 @@ void QuotaManager::OpenDirectoryInternal
         mClients[index]->AbortOperations(iter.Get()->GetKey());
       }
     }
   }
 }
 
 nsresult QuotaManager::EnsureOriginIsInitialized(
     PersistenceType aPersistenceType, const nsACString& aSuffix,
-    const nsACString& aGroup, const nsACString& aOrigin, nsIFile** aDirectory) {
+    const nsACString& aGroup, const nsACString& aOrigin,
+    bool aCreateIfNotExists, nsIFile** aDirectory) {
   AssertIsOnIOThread();
   MOZ_ASSERT(aDirectory);
 
   nsCOMPtr<nsIFile> directory;
   bool created;
   nsresult rv = EnsureOriginIsInitializedInternal(
-      aPersistenceType, aSuffix, aGroup, aOrigin, getter_AddRefs(directory),
-      &created);
+      aPersistenceType, aSuffix, aGroup, aOrigin, aCreateIfNotExists,
+      getter_AddRefs(directory), &created);
+  if (rv == NS_ERROR_NOT_AVAILABLE) {
+    return rv;
+  }
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   directory.forget(aDirectory);
   return NS_OK;
 }
 
 nsresult QuotaManager::EnsureOriginIsInitializedInternal(
     PersistenceType aPersistenceType, const nsACString& aSuffix,
-    const nsACString& aGroup, const nsACString& aOrigin, nsIFile** aDirectory,
-    bool* aCreated) {
+    const nsACString& aGroup, const nsACString& aOrigin,
+    bool aCreateIfNotExists, nsIFile** aDirectory, bool* aCreated) {
   AssertIsOnIOThread();
   MOZ_ASSERT(aDirectory);
   MOZ_ASSERT(aCreated);
 
   nsresult rv = EnsureStorageIsInitialized();
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Get directory for this origin and persistence type.
@@ -5762,29 +5669,30 @@ nsresult QuotaManager::EnsureOriginIsIni
   } else {
     rv = EnsureTemporaryStorageIsInitialized();
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 
   bool created;
-  rv = EnsureOriginDirectory(directory, &created);
+  rv = EnsureOriginDirectory(directory, aCreateIfNotExists, &created);
+  if (rv == NS_ERROR_NOT_AVAILABLE) {
+    return rv;
+  }
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   int64_t timestamp;
   if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
     if (created) {
-      timestamp = PR_Now();
-
       rv = CreateDirectoryMetadataFiles(directory,
                                         /* aPersisted */ true, aSuffix, aGroup,
-                                        aOrigin, timestamp);
+                                        aOrigin, &timestamp);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
     } else {
       rv = GetDirectoryMetadata2WithRestore(directory,
                                             /* aPersistent */ true, &timestamp,
                                             /* aPersisted */ nullptr);
       if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -5795,25 +5703,27 @@ nsresult QuotaManager::EnsureOriginIsIni
     }
 
     rv = InitializeOrigin(aPersistenceType, aGroup, aOrigin, timestamp,
                           /* aPersisted */ true, directory);
     NS_ENSURE_SUCCESS(rv, rv);
 
     mInitializedOrigins.AppendElement(aOrigin);
   } else if (created) {
-    NoteOriginDirectoryCreated(aPersistenceType, aGroup, aOrigin,
-                               /* aPersisted */ false, timestamp);
-
     rv = CreateDirectoryMetadataFiles(directory,
                                       /* aPersisted */ false, aSuffix, aGroup,
-                                      aOrigin, timestamp);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
+                                      aOrigin, &timestamp);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    // Don't need to traverse the directory, since it's empty.
+    InitQuotaForOrigin(aPersistenceType, aGroup, aOrigin,
+                       /* aUsageBytes */ 0, timestamp,
+                       /* aPersisted */ false);
   }
 
   directory.forget(aDirectory);
   *aCreated = created;
   return NS_OK;
 }
 
 nsresult QuotaManager::EnsureTemporaryStorageIsInitialized() {
@@ -5881,28 +5791,33 @@ nsresult QuotaManager::EnsureTemporarySt
   mTemporaryStorageInitialized = true;
 
   CheckTemporaryStorageLimits();
 
   return rv;
 }
 
 nsresult QuotaManager::EnsureOriginDirectory(nsIFile* aDirectory,
+                                             bool aCreateIfNotExists,
                                              bool* aCreated) {
   AssertIsOnIOThread();
   MOZ_ASSERT(aDirectory);
   MOZ_ASSERT(aCreated);
 
   bool exists;
   nsresult rv = aDirectory->Exists(&exists);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   if (!exists) {
+    if (!aCreateIfNotExists) {
+      return NS_ERROR_NOT_AVAILABLE;
+    }
+
     nsString leafName;
     rv = aDirectory->GetLeafName(leafName);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     if (!IsSanitizedOriginValid(NS_ConvertUTF16toUTF8(leafName))) {
       QM_WARNING(
@@ -6341,37 +6256,16 @@ void QuotaManager::LockedRemoveQuotaForO
 
       if (!pair->LockedHasGroupInfos()) {
         mGroupInfoPairs.Remove(aGroup);
       }
     }
   }
 }
 
-already_AddRefed<GroupInfo> QuotaManager::LockedGetOrCreateGroupInfo(
-    PersistenceType aPersistenceType, const nsACString& aGroup) {
-  mQuotaMutex.AssertCurrentThreadOwns();
-  MOZ_ASSERT(aPersistenceType != PERSISTENCE_TYPE_PERSISTENT);
-
-  GroupInfoPair* pair;
-  if (!mGroupInfoPairs.Get(aGroup, &pair)) {
-    pair = new GroupInfoPair();
-    mGroupInfoPairs.Put(aGroup, pair);
-    // The hashtable is now responsible to delete the GroupInfoPair.
-  }
-
-  RefPtr<GroupInfo> groupInfo = pair->LockedGetGroupInfo(aPersistenceType);
-  if (!groupInfo) {
-    groupInfo = new GroupInfo(pair, aPersistenceType, aGroup);
-    pair->LockedSetGroupInfo(aPersistenceType, groupInfo);
-  }
-
-  return groupInfo.forget();
-}
-
 already_AddRefed<OriginInfo> QuotaManager::LockedGetOriginInfo(
     PersistenceType aPersistenceType, const nsACString& aGroup,
     const nsACString& aOrigin) {
   mQuotaMutex.AssertCurrentThreadOwns();
   MOZ_ASSERT(aPersistenceType != PERSISTENCE_TYPE_PERSISTENT);
 
   GroupInfoPair* pair;
   if (mGroupInfoPairs.Get(aGroup, &pair)) {
@@ -6617,24 +6511,22 @@ bool QuotaManager::IsSanitizedOriginVali
   return valid;
 }
 
 /*******************************************************************************
  * Local class implementations
  ******************************************************************************/
 
 OriginInfo::OriginInfo(GroupInfo* aGroupInfo, const nsACString& aOrigin,
-                       uint64_t aUsage, int64_t aAccessTime, bool aPersisted,
-                       bool aDirectoryExists)
+                       uint64_t aUsage, int64_t aAccessTime, bool aPersisted)
     : mGroupInfo(aGroupInfo),
       mOrigin(aOrigin),
       mUsage(aUsage),
       mAccessTime(aAccessTime),
-      mPersisted(aPersisted),
-      mDirectoryExists(aDirectoryExists) {
+      mPersisted(aPersisted) {
   MOZ_ASSERT(aGroupInfo);
   MOZ_ASSERT_IF(aPersisted,
                 aGroupInfo->mPersistenceType == PERSISTENCE_TYPE_DEFAULT);
 
   MOZ_COUNT_CTOR(OriginInfo);
 }
 
 void OriginInfo::LockedDecreaseUsage(int64_t aSize) {
@@ -7727,57 +7619,16 @@ nsresult TraverseRepositoryHelper::Trave
 }
 
 GetUsageOp::GetUsageOp(const UsageRequestParams& aParams)
     : mGetAll(aParams.get_AllUsageParams().getAll()) {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aParams.type() == UsageRequestParams::TAllUsageParams);
 }
 
-void GetUsageOp::ProcessOriginInternal(QuotaManager* aQuotaManager,
-                                       const PersistenceType aPersistenceType,
-                                       const nsACString& aOrigin,
-                                       const int64_t aTimestamp,
-                                       const bool aPersisted,
-                                       const uint64_t aUsage) {
-  if (!mGetAll && aQuotaManager->IsOriginInternal(aOrigin)) {
-    return;
-  }
-
-  OriginUsage* originUsage;
-
-  // We can't store pointers to OriginUsage objects in the hashtable
-  // since AppendElement() reallocates its internal array buffer as number
-  // of elements grows.
-  uint32_t index;
-  if (mOriginUsagesIndex.Get(aOrigin, &index)) {
-    originUsage = &mOriginUsages[index];
-  } else {
-    index = mOriginUsages.Length();
-
-    originUsage = mOriginUsages.AppendElement();
-
-    originUsage->origin() = aOrigin;
-    originUsage->persisted() = false;
-    originUsage->usage() = 0;
-    originUsage->lastAccessed() = 0;
-
-    mOriginUsagesIndex.Put(aOrigin, index);
-  }
-
-  if (aPersistenceType == PERSISTENCE_TYPE_DEFAULT) {
-    originUsage->persisted() = aPersisted;
-  }
-
-  originUsage->usage() = originUsage->usage() + aUsage;
-
-  originUsage->lastAccessed() =
-      std::max<int64_t>(originUsage->lastAccessed(), aTimestamp);
-}
-
 bool GetUsageOp::IsCanceled() {
   AssertIsOnIOThread();
 
   return mCanceled;
 }
 
 nsresult GetUsageOp::ProcessOrigin(QuotaManager* aQuotaManager,
                                    nsIFile* aOriginDir, const bool aPersistent,
@@ -7792,25 +7643,54 @@ nsresult GetUsageOp::ProcessOrigin(Quota
   nsCString group;
   nsCString origin;
   nsresult rv = aQuotaManager->GetDirectoryMetadata2WithRestore(
       aOriginDir, aPersistent, &timestamp, &persisted, suffix, group, origin);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
+  if (!mGetAll && aQuotaManager->IsOriginInternal(origin)) {
+    return NS_OK;
+  }
+
+  OriginUsage* originUsage;
+
+  // We can't store pointers to OriginUsage objects in the hashtable
+  // since AppendElement() reallocates its internal array buffer as number
+  // of elements grows.
+  uint32_t index;
+  if (mOriginUsagesIndex.Get(origin, &index)) {
+    originUsage = &mOriginUsages[index];
+  } else {
+    index = mOriginUsages.Length();
+
+    originUsage = mOriginUsages.AppendElement();
+
+    originUsage->origin() = origin;
+    originUsage->persisted() = false;
+    originUsage->usage() = 0;
+
+    mOriginUsagesIndex.Put(origin, index);
+  }
+
+  if (aPersistenceType == PERSISTENCE_TYPE_DEFAULT) {
+    originUsage->persisted() = persisted;
+  }
+
+  originUsage->lastAccessed() = timestamp;
+
   UsageInfo usageInfo;
   rv = GetUsageForOrigin(aQuotaManager, aPersistenceType, group, origin,
                          &usageInfo);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
-  ProcessOriginInternal(aQuotaManager, aPersistenceType, origin, timestamp,
-                        persisted, usageInfo.TotalUsage());
+  originUsage->usage() = originUsage->usage() + usageInfo.TotalUsage();
 
   return NS_OK;
 }
 
 nsresult GetUsageOp::DoDirectoryWork(QuotaManager* aQuotaManager) {
   AssertIsOnIOThread();
 
   AUTO_PROFILER_LABEL("GetUsageOp::DoDirectoryWork", OTHER);
@@ -7819,28 +7699,16 @@ nsresult GetUsageOp::DoDirectoryWork(Quo
 
   for (const PersistenceType type : kAllPersistenceTypes) {
     rv = TraverseRepository(aQuotaManager, type);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 
-  // TraverseRepository above only consulted the filesystem. We also need to
-  // consider origins which may have pending quota usage, such as buffered
-  // LocalStorage writes for an origin which didn't previously have any
-  // LocalStorage data.
-
-  aQuotaManager->CollectPendingOriginsForListing([&](OriginInfo* aOriginInfo) {
-    ProcessOriginInternal(
-        aQuotaManager, aOriginInfo->GetGroupInfo()->GetPersistenceType(),
-        aOriginInfo->Origin(), aOriginInfo->LockedAccessTime(),
-        aOriginInfo->LockedPersisted(), aOriginInfo->LockedUsage());
-  });
-
   return NS_OK;
 }
 
 void GetUsageOp::GetResponse(UsageRequestResponse& aResponse) {
   AssertIsOnOwningThread();
 
   aResponse = AllUsageResponse();
 
@@ -8046,17 +7914,17 @@ nsresult InitOriginOp::DoDirectoryWork(Q
   MOZ_ASSERT(!mPersistenceType.IsNull());
 
   AUTO_PROFILER_LABEL("InitOriginOp::DoDirectoryWork", OTHER);
 
   nsCOMPtr<nsIFile> directory;
   bool created;
   nsresult rv = aQuotaManager->EnsureOriginIsInitializedInternal(
       mPersistenceType.Value(), mSuffix, mGroup, mOriginScope.GetOrigin(),
-      getter_AddRefs(directory), &created);
+      /* aCreateIfNotExists */ true, getter_AddRefs(directory), &created);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   mCreated = created;
 
   return NS_OK;
 }
@@ -8559,39 +8427,39 @@ nsresult PersistOp::DoDirectoryWork(Quot
   nsresult rv = aQuotaManager->GetDirectoryForOrigin(mPersistenceType.Value(),
                                                      mOriginScope.GetOrigin(),
                                                      getter_AddRefs(directory));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   bool created;
-  rv = aQuotaManager->EnsureOriginDirectory(directory, &created);
+  rv = aQuotaManager->EnsureOriginDirectory(directory,
+                                            /* aCreateIfNotExists */ true,
+                                            &created);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   if (created) {
     int64_t timestamp;
-
-    // Origin directory has been successfully created.
+    rv = CreateDirectoryMetadataFiles(directory,
+                                      /* aPersisted */ true, mSuffix, mGroup,
+                                      mOriginScope.GetOrigin(), &timestamp);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    // Directory metadata has been successfully created.
     // Create OriginInfo too if temporary storage was already initialized.
     if (aQuotaManager->IsTemporaryStorageInitialized()) {
-      aQuotaManager->NoteOriginDirectoryCreated(
-          mPersistenceType.Value(), mGroup, mOriginScope.GetOrigin(),
-          /* aPersisted */ true, timestamp);
-    } else {
-      timestamp = PR_Now();
-    }
-
-    rv = CreateDirectoryMetadataFiles(directory,
-                                      /* aPersisted */ true, mSuffix, mGroup,
-                                      mOriginScope.GetOrigin(), timestamp);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
+      aQuotaManager->InitQuotaForOrigin(mPersistenceType.Value(), mGroup,
+                                        mOriginScope.GetOrigin(),
+                                        /* aUsageBytes */ 0, timestamp,
+                                        /* aPersisted */ true);
     }
   } else {
     // Get the persisted flag (restore the metadata file if necessary).
     bool persisted;
     rv = aQuotaManager->GetDirectoryMetadata2WithRestore(
         directory,
         /* aPersistent */ false,
         /* aTimestamp */ nullptr, &persisted);
@@ -8676,24 +8544,16 @@ nsresult ListInitializedOriginsOp::DoDir
 
   for (const PersistenceType type : kAllPersistenceTypes) {
     rv = TraverseRepository(aQuotaManager, type);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 
-  // TraverseRepository above only consulted the file-system to get a list of
-  // known origins, but we also need to include origins that have pending quota
-  // usage.
-
-  aQuotaManager->CollectPendingOriginsForListing([&](OriginInfo* aOriginInfo) {
-    mOrigins.AppendElement(aOriginInfo->Origin());
-  });
-
   return NS_OK;
 }
 
 bool ListInitializedOriginsOp::IsCanceled() {
   AssertIsOnIOThread();
 
   return mCanceled;
 }
--- a/dom/quota/QuotaManager.h
+++ b/dom/quota/QuotaManager.h
@@ -140,51 +140,21 @@ class QuotaManager final : public Backgr
   }
 
   bool IsTemporaryStorageInitialized() const {
     AssertIsOnIOThread();
 
     return mTemporaryStorageInitialized;
   }
 
-  /**
-   * For initialization of an origin where the directory already exists. This is
-   * used by EnsureTemporaryStorageIsInitialized/InitializeRepository once it
-   * has tallied origin usage by calling each of the QuotaClient InitOrigin
-   * methods.
-   */
   void InitQuotaForOrigin(PersistenceType aPersistenceType,
                           const nsACString& aGroup, const nsACString& aOrigin,
                           uint64_t aUsageBytes, int64_t aAccessTime,
                           bool aPersisted);
 
-  /**
-   * For use in special-cases like LSNG where we need to be able to know that
-   * there is no data stored for an origin. LSNG knows that there is 0 usage for
-   * its storage of an origin and wants to make sure there is a QuotaObject
-   * tracking this. This method will create a non-persisted, 0-usage,
-   * mDirectoryExists=false OriginInfo if there isn't already an OriginInfo. If
-   * an OriginInfo already exists, it will be left as-is, because that implies a
-   * different client has usages for the origin (and there's no need to add
-   * LSNG's 0 usage to the QuotaObject).
-   */
-  void EnsureQuotaForOrigin(PersistenceType aPersistenceType,
-                            const nsACString& aGroup,
-                            const nsACString& aOrigin);
-
-  /**
-   * For use when creating an origin directory. It's possible that origin usage
-   * is already being tracked due to a call to EnsureQuotaForOrigin, and in that
-   * case we need to update the existing OriginInfo rather than create a new one.
-   */
-  void NoteOriginDirectoryCreated(PersistenceType aPersistenceType,
-                                  const nsACString& aGroup,
-                                  const nsACString& aOrigin, bool aPersisted,
-                                  int64_t& aTimestamp);
-
   void DecreaseUsageForOrigin(PersistenceType aPersistenceType,
                               const nsACString& aGroup,
                               const nsACString& aOrigin, int64_t aSize);
 
   void UpdateOriginAccessTime(PersistenceType aPersistenceType,
                               const nsACString& aGroup,
                               const nsACString& aOrigin);
 
@@ -273,55 +243,42 @@ class QuotaManager final : public Backgr
                              const Nullable<Client::Type>& aClientType,
                              bool aExclusive,
                              OpenDirectoryListener* aOpenListener);
 
   // Collect inactive and the least recently used origins.
   uint64_t CollectOriginsForEviction(
       uint64_t aMinSizeToBeFreed, nsTArray<RefPtr<DirectoryLockImpl>>& aLocks);
 
-  /**
-   * Helper method to invoke the provided predicate on all "pending" OriginInfo
-   * instances. These are origins for which the origin directory has not yet
-   * been created but for which quota is already being tracked. This happens,
-   * for example, for the LocalStorage client where an origin that previously
-   * was not using LocalStorage can start issuing writes which it buffers until
-   * eventually flushing them. We defer creating the origin directory for as
-   * long as possible in that case, so the directory won't exist. Logic that
-   * would otherwise only consult the filesystem also needs to use this method.
-   */
-  template <typename P>
-  void CollectPendingOriginsForListing(P aPredicate);
-
   void AssertStorageIsInitialized() const
 #ifdef DEBUG
       ;
 #else
   {
   }
 #endif
 
   nsresult EnsureStorageIsInitialized();
 
   nsresult EnsureOriginIsInitialized(PersistenceType aPersistenceType,
                                      const nsACString& aSuffix,
                                      const nsACString& aGroup,
                                      const nsACString& aOrigin,
+                                     bool aCreateIfNotExists,
                                      nsIFile** aDirectory);
 
-  nsresult EnsureOriginIsInitializedInternal(PersistenceType aPersistenceType,
-                                             const nsACString& aSuffix,
-                                             const nsACString& aGroup,
-                                             const nsACString& aOrigin,
-                                             nsIFile** aDirectory,
-                                             bool* aCreated);
+  nsresult EnsureOriginIsInitializedInternal(
+      PersistenceType aPersistenceType, const nsACString& aSuffix,
+      const nsACString& aGroup, const nsACString& aOrigin,
+      bool aCreateIfNotExists, nsIFile** aDirectory, bool* aCreated);
 
   nsresult EnsureTemporaryStorageIsInitialized();
 
-  nsresult EnsureOriginDirectory(nsIFile* aDirectory, bool* aCreated);
+  nsresult EnsureOriginDirectory(nsIFile* aDirectory, bool aCreateIfNotExists,
+                                 bool* aCreated);
 
   nsresult AboutToClearOrigins(
       const Nullable<PersistenceType>& aPersistenceType,
       const OriginScope& aOriginScope,
       const Nullable<Client::Type>& aClientType);
 
   void OriginClearCompleted(PersistenceType aPersistenceType,
                             const nsACString& aOrigin,
@@ -437,19 +394,16 @@ class QuotaManager final : public Backgr
 
   uint64_t LockedCollectOriginsForEviction(
       uint64_t aMinSizeToBeFreed, nsTArray<RefPtr<DirectoryLockImpl>>& aLocks);
 
   void LockedRemoveQuotaForOrigin(PersistenceType aPersistenceType,
                                   const nsACString& aGroup,
                                   const nsACString& aOrigin);
 
-  already_AddRefed<GroupInfo> LockedGetOrCreateGroupInfo(
-      PersistenceType aPersistenceType, const nsACString& aGroup);
-
   already_AddRefed<OriginInfo> LockedGetOriginInfo(
       PersistenceType aPersistenceType, const nsACString& aGroup,
       const nsACString& aOrigin);
 
   nsresult MaybeUpgradeIndexedDBDirectory();
 
   nsresult MaybeUpgradePersistentStorageDirectory();
 
@@ -481,21 +435,20 @@ class QuotaManager final : public Backgr
       nsCOMPtr<mozIStorageConnection>& aConnection);
 
   nsresult DowngradeLocalStorageArchive(
       nsCOMPtr<mozIStorageConnection>& aConnection);
 
   nsresult UpgradeLocalStorageArchiveFrom0To1(
       nsCOMPtr<mozIStorageConnection>& aConnection);
 
-  nsresult UpgradeLocalStorageArchiveFrom1To2(
-      nsCOMPtr<mozIStorageConnection>& aConnection);
-
-  nsresult UpgradeLocalStorageArchiveFrom2To3(
-      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);
 
deleted file mode 100644
index 8883ea4630468f1c63076254109d53429752b8ca..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index e475d3d17540b10922e395f28afeb97a56e07bff..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
--- a/dom/quota/test/unit/test_localStorageArchive2upgrade.js
+++ /dev/null
@@ -1,65 +0,0 @@
-/**
- * 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 not removed
- * during local storage archive upgrade from version 1 to version 2.
- * See bug 1546310.
- */
-
-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 with
-  // local storage archive version 1), 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("localStorageArchive2upgrade_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 does exist");
-  }
-}
deleted file mode 100644
--- a/dom/quota/test/unit/test_localStorageArchive3upgrade.js
+++ /dev/null
@@ -1,65 +0,0 @@
-/**
- * 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 not removed
- * during local storage archive upgrade from version 2 to version 3.
- * See bug 1513937.
- */
-
-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 with
-  // local storage archive version 2), 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("localStorageArchive3upgrade_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 does exist");
-  }
-}
--- a/dom/quota/test/unit/xpcshell.ini
+++ b/dom/quota/test/unit/xpcshell.ini
@@ -9,18 +9,16 @@ support-files =
   clearStorageForPrincipal_profile.zip
   createLocalStorage_profile.zip
   defaultStorageUpgrade_profile.zip
   getUsage_profile.zip
   groupMismatch_profile.zip
   idbSubdirUpgrade1_profile.zip
   idbSubdirUpgrade2_profile.zip
   localStorageArchive1upgrade_profile.zip
-  localStorageArchive2upgrade_profile.zip
-  localStorageArchive3upgrade_profile.zip
   localStorageArchiveDowngrade_profile.zip
   morgueCleanup_profile.zip
   obsoleteOriginAttributes_profile.zip
   originAttributesUpgrade_profile.zip
   removeLocalStorage1_profile.zip
   removeLocalStorage2_profile.zip
   storagePersistentUpgrade_profile.zip
   tempMetadataCleanup_profile.zip
@@ -33,18 +31,16 @@ support-files =
 [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_localStorageArchive2upgrade.js]
-[test_localStorageArchive3upgrade.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]
--- a/dom/simpledb/ActorsParent.cpp
+++ b/dom/simpledb/ActorsParent.cpp
@@ -1147,17 +1147,17 @@ nsresult OpenOp::DatabaseWork() {
   }
 
   QuotaManager* quotaManager = QuotaManager::Get();
   MOZ_ASSERT(quotaManager);
 
   nsCOMPtr<nsIFile> dbDirectory;
   nsresult rv = quotaManager->EnsureOriginIsInitialized(
       PERSISTENCE_TYPE_DEFAULT, mSuffix, mGroup, mOrigin,
-      getter_AddRefs(dbDirectory));
+      /* aCreateIfNotExists */ true, getter_AddRefs(dbDirectory));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   rv = dbDirectory->Append(NS_LITERAL_STRING(SDB_DIRECTORY_NAME));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }