Bug 1286798 - Part 44: Switch Connection to use WriteOptimizer too; r=asuth draft
authorJan Varga <jan.varga@gmail.com>
Wed, 24 Oct 2018 06:59:09 +0200
changeset 481722 7fe2c3512187460b4deed2618f56553e717bd4bd
parent 481721 413cee18d1f90f3d668495e7bae4c36a72540cf3
child 481723 2d1ec32bf081c00c73f70dd7741338eeb2c9e5ef
push id10
push userbugmail@asutherland.org
push dateSun, 18 Nov 2018 18:57:42 +0000
reviewersasuth
bugs1286798
milestone65.0a1
Bug 1286798 - Part 44: Switch Connection to use WriteOptimizer too; r=asuth This eliminates some code duplication.
dom/localstorage/ActorsParent.cpp
--- a/dom/localstorage/ActorsParent.cpp
+++ b/dom/localstorage/ActorsParent.cpp
@@ -871,55 +871,70 @@ DetachShadowDatabase(mozIStorageConnecti
  ******************************************************************************/
 
 class WriteOptimizer final
 {
   class WriteInfo;
   class AddItemInfo;
   class UpdateItemInfo;
   class RemoveItemInfo;
-
+  class ClearInfo;
+
+  nsAutoPtr<WriteInfo> mClearInfo;
   nsClassHashtable<nsStringHashKey, WriteInfo> mWriteInfos;
-  bool mClearedWriteInfos;
 
 public:
   WriteOptimizer()
-    : mClearedWriteInfos(false)
   { }
 
+  WriteOptimizer(WriteOptimizer&& aWriteOptimizer)
+    : mClearInfo(std::move(aWriteOptimizer.mClearInfo))
+  {
+    MOZ_ASSERT(&aWriteOptimizer != this);
+
+    mWriteInfos.SwapElements(aWriteOptimizer.mWriteInfos);
+  }
+
   void
   AddItem(const nsString& aKey,
           const nsString& aValue);
 
   void
   UpdateItem(const nsString& aKey,
              const nsString& aValue);
 
   void
   RemoveItem(const nsString& aKey);
 
   void
   Clear();
 
   void
   ApplyWrites(nsTArray<LSItemInfo>& aOrderedItems);
+
+  nsresult
+  PerformWrites(Connection* aConnection);
 };
 
 class WriteOptimizer::WriteInfo
 {
 public:
   enum Type {
     AddItem = 0,
     UpdateItem,
-    RemoveItem
+    RemoveItem,
+    Clear
   };
 
   virtual Type
   GetType() = 0;
 
+  virtual nsresult
+  Perform(Connection* aConnection) = 0;
+
   virtual ~WriteInfo() = default;
 };
 
 class WriteOptimizer::AddItemInfo
   : public WriteInfo
 {
   nsString mKey;
   nsString mValue;
@@ -944,16 +959,19 @@ public:
   }
 
 private:
   Type
   GetType() override
   {
     return AddItem;
   }
+
+  nsresult
+  Perform(Connection* aConnection) override;
 };
 
 class WriteOptimizer::UpdateItemInfo final
   : public AddItemInfo
 {
 public:
   UpdateItemInfo(const nsAString& aKey,
                  const nsAString& aValue)
@@ -985,16 +1003,37 @@ public:
   }
 
 private:
   Type
   GetType() override
   {
     return RemoveItem;
   }
+
+  nsresult
+  Perform(Connection* aConnection) override;
+};
+
+class WriteOptimizer::ClearInfo final
+  : public WriteInfo
+{
+public:
+  ClearInfo()
+  { }
+
+private:
+  Type
+  GetType() override
+  {
+    return Clear;
+  }
+
+  nsresult
+  Perform(Connection* aConnection) override;
 };
 
 class DatastoreOperationBase
   : public Runnable
 {
   nsCOMPtr<nsIEventTarget> mOwningEventTarget;
   nsresult mResultCode;
   Atomic<bool> mMayProceedOnNonOwningThread;
@@ -1137,31 +1176,25 @@ private:
 class Connection final
 {
   friend class ConnectionThread;
 
 public:
   class CachedStatement;
 
 private:
-  class WriteInfo;
-  class AddItemInfo;
-  class UpdateItemInfo;
-  class RemoveItemInfo;
-  class ClearInfo;
   class EndUpdateBatchOp;
   class CloseOp;
 
   RefPtr<ConnectionThread> mConnectionThread;
   nsCOMPtr<mozIStorageConnection> mStorageConnection;
   nsAutoPtr<ArchivedOriginInfo> mArchivedOriginInfo;
-  nsAutoPtr<WriteInfo> mClearInfo;
-  nsClassHashtable<nsStringHashKey, WriteInfo> mWriteInfos;
   nsInterfaceHashtable<nsCStringHashKey, mozIStorageStatement>
     mCachedStatements;
+  WriteOptimizer mWriteOptimizer;
   const nsCString mOrigin;
   const nsString mFilePath;
 #ifdef DEBUG
   bool mInUpdateBatch;
 #endif
 
 public:
   NS_INLINE_DECL_REFCOUNTING(mozilla::dom::Connection)
@@ -1263,133 +1296,27 @@ private:
   Assign(Connection* aConnection,
          already_AddRefed<mozIStorageStatement> aStatement);
 
   // No funny business allowed.
   CachedStatement(const CachedStatement&) = delete;
   CachedStatement& operator=(const CachedStatement&) = delete;
 };
 
-class Connection::WriteInfo
-{
-public:
-  enum Type {
-    AddItem = 0,
-    UpdateItem,
-    RemoveItem,
-    Clear,
-  };
-
-  virtual Type
-  GetType() = 0;
-
-  virtual nsresult
-  Perform(Connection* aConnection) = 0;
-
-  virtual ~WriteInfo() = default;
-};
-
-class Connection::AddItemInfo
-  : public WriteInfo
-{
-  nsString mKey;
-  nsString mValue;
-
-public:
-  AddItemInfo(const nsAString& aKey,
-              const nsAString& aValue)
-    : mKey(aKey)
-    , mValue(aValue)
-  { }
-
-private:
-  Type
-  GetType() override
-  {
-    return AddItem;
-  }
-
-  nsresult
-  Perform(Connection* aConnection) override;
-};
-
-class Connection::UpdateItemInfo final
-  : public AddItemInfo
-{
-  nsString mKey;
-  nsString mValue;
-
-public:
-  UpdateItemInfo(const nsAString& aKey,
-                 const nsAString& aValue)
-    : AddItemInfo(aKey, aValue)
-  { }
-
-private:
-  Type
-  GetType() override
-  {
-    return UpdateItem;
-  }
-};
-
-class Connection::RemoveItemInfo final
-  : public WriteInfo
-{
-  nsString mKey;
-
-public:
-  explicit RemoveItemInfo(const nsAString& aKey)
-    : mKey(aKey)
-  { }
-
-private:
-Type
-  GetType() override
-  {
-    return RemoveItem;
-  }
-
-  nsresult
-  Perform(Connection* aConnection) override;
-};
-
-class Connection::ClearInfo final
-  : public WriteInfo
-{
-public:
-  ClearInfo()
-  { }
-
-private:
-  Type
-  GetType() override
-  {
-    return Clear;
-  }
-
-  nsresult
-  Perform(Connection* aConnection) override;
-};
-
 class Connection::EndUpdateBatchOp final
   : public ConnectionDatastoreOperationBase
 {
-  nsAutoPtr<WriteInfo> mClearInfo;
-  nsClassHashtable<nsStringHashKey, WriteInfo> mWriteInfos;
+  WriteOptimizer mWriteOptimizer;
 
 public:
   EndUpdateBatchOp(Connection* aConnection,
-                   nsAutoPtr<WriteInfo>&& aClearInfo,
-                   nsClassHashtable<nsStringHashKey, WriteInfo>& aWriteInfos)
+                   WriteOptimizer&& aWriteOptimizer)
     : ConnectionDatastoreOperationBase(aConnection)
-    , mClearInfo(std::move(aClearInfo))
-  {
-    mWriteInfos.SwapElements(aWriteInfos);
-  }
+    , mWriteOptimizer(std::move(aWriteOptimizer))
+  { }
 
 private:
   nsresult
   DoDatastoreWork() override;
 };
 
 class Connection::CloseOp final
   : public ConnectionDatastoreOperationBase
@@ -3158,25 +3085,28 @@ WriteOptimizer::RemoveItem(const nsStrin
 }
 
 void
 WriteOptimizer::Clear()
 {
   AssertIsOnBackgroundThread();
 
   mWriteInfos.Clear();
-  mClearedWriteInfos = true;
+
+  if (!mClearInfo) {
+    mClearInfo = new ClearInfo();
+  }
 }
 
 void
 WriteOptimizer::ApplyWrites(nsTArray<LSItemInfo>& aOrderedItems)
 {
-  if (mClearedWriteInfos) {
+  if (mClearInfo) {
     aOrderedItems.Clear();
-    mClearedWriteInfos = false;
+    mClearInfo = nullptr;
   }
 
   for (int32_t index = aOrderedItems.Length() - 1;
        index >= 0;
        index--) {
     LSItemInfo& item = aOrderedItems[index];
 
     if (auto entry = mWriteInfos.Lookup(item.key())) {
@@ -3214,16 +3144,211 @@ WriteOptimizer::ApplyWrites(nsTArray<LSI
     LSItemInfo* itemInfo = aOrderedItems.AppendElement();
     itemInfo->key() = addItemInfo->GetKey();
     itemInfo->value() = addItemInfo->GetValue();
   }
 
   mWriteInfos.Clear();
 }
 
+nsresult
+WriteOptimizer::PerformWrites(Connection* aConnection)
+{
+  AssertIsOnConnectionThread();
+  MOZ_ASSERT(aConnection);
+
+  nsresult rv;
+
+  if (mClearInfo) {
+    rv = mClearInfo->Perform(aConnection);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+  }
+
+  for (auto iter = mWriteInfos.ConstIter(); !iter.Done(); iter.Next()) {
+    rv = iter.Data()->Perform(aConnection);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+  }
+
+  return NS_OK;
+}
+
+nsresult
+WriteOptimizer::
+AddItemInfo::Perform(Connection* aConnection)
+{
+  AssertIsOnConnectionThread();
+  MOZ_ASSERT(aConnection);
+
+  Connection::CachedStatement stmt;
+  nsresult rv = aConnection->GetCachedStatement(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->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;
+  }
+
+  rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
+    "INSERT OR REPLACE INTO shadow.webappsstore2 "
+      "(originAttributes, originKey, scope, key, value) "
+      "VALUES (:originAttributes, :originKey, :scope, :key, :value) "),
+    &stmt);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  ArchivedOriginInfo* archivedOriginInfo = aConnection->GetArchivedOriginInfo();
+
+  rv = archivedOriginInfo->BindToStatement(stmt);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  nsCString scope = Scheme0Scope(archivedOriginInfo->OriginSuffix(),
+                                 archivedOriginInfo->OriginNoSuffix());
+
+  rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("scope"),
+                                  scope);
+  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->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;
+  }
+
+  return NS_OK;
+}
+
+nsresult
+WriteOptimizer::
+RemoveItemInfo::Perform(Connection* aConnection)
+{
+  AssertIsOnConnectionThread();
+  MOZ_ASSERT(aConnection);
+
+  Connection::CachedStatement stmt;
+  nsresult rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
+    "DELETE FROM data "
+      "WHERE key = :key;"),
+    &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->Execute();
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
+    "DELETE FROM shadow.webappsstore2 "
+      "WHERE originAttributes = :originAttributes "
+      "AND originKey = :originKey "
+      "AND key = :key;"),
+    &stmt);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = aConnection->GetArchivedOriginInfo()->BindToStatement(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->Execute();
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  return NS_OK;
+}
+
+nsresult
+WriteOptimizer::
+ClearInfo::Perform(Connection* aConnection)
+{
+  AssertIsOnConnectionThread();
+  MOZ_ASSERT(aConnection);
+
+  Connection::CachedStatement stmt;
+  nsresult rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
+    "DELETE FROM data;"),
+    &stmt);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = stmt->Execute();
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
+    "DELETE FROM shadow.webappsstore2 "
+      "WHERE originAttributes = :originAttributes "
+      "AND originKey = :originKey;"),
+    &stmt);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = aConnection->GetArchivedOriginInfo()->BindToStatement(stmt);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = stmt->Execute();
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  return NS_OK;
+}
+
 /*******************************************************************************
  * DatastoreOperationBase
  ******************************************************************************/
 
 /*******************************************************************************
  * ConnectionDatastoreOperationBase
  ******************************************************************************/
 
@@ -3374,75 +3499,45 @@ Connection::Close(nsIRunnable* aCallback
 
 void
 Connection::AddItem(const nsString& aKey,
                     const nsString& aValue)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mInUpdateBatch);
 
-  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());
+  mWriteOptimizer.AddItem(aKey, aValue);
 }
 
 void
 Connection::UpdateItem(const nsString& aKey,
                        const nsString& aValue)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mInUpdateBatch);
 
-  WriteInfo* existingWriteInfo;
-  nsAutoPtr<WriteInfo> newWriteInfo;
-  if (mWriteInfos.Get(aKey, &existingWriteInfo) &&
-      existingWriteInfo->GetType() == WriteInfo::AddItem) {
-    newWriteInfo = new AddItemInfo(aKey, aValue);
-  } else {
-    newWriteInfo = new UpdateItemInfo(aKey, aValue);
-  }
-
-  mWriteInfos.Put(aKey, newWriteInfo.forget());
+  mWriteOptimizer.UpdateItem(aKey, aValue);
 }
 
 void
 Connection::RemoveItem(const nsString& aKey)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mInUpdateBatch);
 
-  WriteInfo* existingWriteInfo;
-  if (mWriteInfos.Get(aKey, &existingWriteInfo) &&
-      existingWriteInfo->GetType() == WriteInfo::AddItem) {
-    mWriteInfos.Remove(aKey);
-    return;
-  }
-
-  nsAutoPtr<WriteInfo> newWriteInfo(new RemoveItemInfo(aKey));
-  mWriteInfos.Put(aKey, newWriteInfo.forget());
+  mWriteOptimizer.RemoveItem(aKey);
 }
 
 void
 Connection::Clear()
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mInUpdateBatch);
 
-  mWriteInfos.Clear();
-
-  if (!mClearInfo) {
-    mClearInfo = new ClearInfo();
-  }
+  mWriteOptimizer.Clear();
 }
 
 void
 Connection::BeginUpdateBatch()
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(!mInUpdateBatch);
 
@@ -3453,17 +3548,17 @@ Connection::BeginUpdateBatch()
 
 void
 Connection::EndUpdateBatch()
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mInUpdateBatch);
 
   RefPtr<EndUpdateBatchOp> op =
-    new EndUpdateBatchOp(this, std::move(mClearInfo), mWriteInfos);
+    new EndUpdateBatchOp(this, std::move(mWriteOptimizer));
 
   Dispatch(op);
 
 #ifdef DEBUG
   mInUpdateBatch = false;
 #endif
 }
 
@@ -3582,186 +3677,16 @@ CachedStatement::Assign(Connection* aCon
 
   if (mStatement) {
     mScoper.emplace(mStatement);
   }
 }
 
 nsresult
 Connection::
-AddItemInfo::Perform(Connection* aConnection)
-{
-  AssertIsOnConnectionThread();
-  MOZ_ASSERT(aConnection);
-
-  Connection::CachedStatement stmt;
-  nsresult rv = aConnection->GetCachedStatement(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->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;
-  }
-
-  rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
-    "INSERT OR REPLACE INTO shadow.webappsstore2 "
-      "(originAttributes, originKey, scope, key, value) "
-      "VALUES (:originAttributes, :originKey, :scope, :key, :value) "),
-    &stmt);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  ArchivedOriginInfo* archivedOriginInfo = aConnection->GetArchivedOriginInfo();
-
-  rv = archivedOriginInfo->BindToStatement(stmt);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  nsCString scope = Scheme0Scope(archivedOriginInfo->OriginSuffix(),
-                                 archivedOriginInfo->OriginNoSuffix());
-
-  rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("scope"),
-                                  scope);
-  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->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;
-  }
-
-  return NS_OK;
-}
-
-nsresult
-Connection::
-RemoveItemInfo::Perform(Connection* aConnection)
-{
-  AssertIsOnConnectionThread();
-  MOZ_ASSERT(aConnection);
-
-  Connection::CachedStatement stmt;
-  nsresult rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
-    "DELETE FROM data "
-      "WHERE key = :key;"),
-    &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->Execute();
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
-    "DELETE FROM shadow.webappsstore2 "
-      "WHERE originAttributes = :originAttributes "
-      "AND originKey = :originKey "
-      "AND key = :key;"),
-    &stmt);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  rv = aConnection->GetArchivedOriginInfo()->BindToStatement(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->Execute();
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  return NS_OK;
-}
-
-nsresult
-Connection::
-ClearInfo::Perform(Connection* aConnection)
-{
-  AssertIsOnConnectionThread();
-  MOZ_ASSERT(aConnection);
-
-  Connection::CachedStatement stmt;
-  nsresult rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
-    "DELETE FROM data;"),
-    &stmt);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  rv = stmt->Execute();
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
-    "DELETE FROM shadow.webappsstore2 "
-      "WHERE originAttributes = :originAttributes "
-      "AND originKey = :originKey;"),
-    &stmt);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  rv = aConnection->GetArchivedOriginInfo()->BindToStatement(stmt);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  rv = stmt->Execute();
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  return NS_OK;
-}
-
-nsresult
-Connection::
 EndUpdateBatchOp::DoDatastoreWork()
 {
   AssertIsOnConnectionThread();
   MOZ_ASSERT(mConnection);
 
   QuotaManager* quotaManager = QuotaManager::Get();
   MOZ_ASSERT(quotaManager);
 
@@ -3782,22 +3707,19 @@ EndUpdateBatchOp::DoDatastoreWork()
     return rv;
   }
 
   rv = stmt->Execute();
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
-  if (mClearInfo) {
-    mClearInfo->Perform(mConnection);
-  }
-
-  for (auto iter = mWriteInfos.ConstIter(); !iter.Done(); iter.Next()) {
-    iter.Data()->Perform(mConnection);
+  rv = mWriteOptimizer.PerformWrites(mConnection);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
   }
 
   rv = mConnection->GetCachedStatement(NS_LITERAL_CSTRING("COMMIT;"), &stmt);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   rv = stmt->Execute();