Bug 1286798 - Part 44: Switch Connection to use WriteOptimizer too; r=asuth
authorJan Varga <jan.varga@gmail.com>
Thu, 29 Nov 2018 21:49:37 +0100
changeset 508042 c29b8b8fbf4d209d5e98cde786a6fe58c2dce5a5
parent 508041 5dbbe4015d16797f33ae37207b526dc81b89d50b
child 508043 fc0bce55c20d8acc8e099d0055978d9c167b3ed2
push id1905
push userffxbld-merge
push dateMon, 21 Jan 2019 12:33:13 +0000
treeherdermozilla-release@c2fca1944d8c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersasuth
bugs1286798
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 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
@@ -890,55 +890,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;
@@ -963,16 +978,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)
@@ -1004,16 +1022,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;
@@ -1156,31 +1195,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)
@@ -1282,133 +1315,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
@@ -3173,25 +3100,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())) {
@@ -3229,16 +3159,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
  ******************************************************************************/
 
@@ -3389,75 +3514,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);
 
@@ -3468,17 +3563,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
 }
 
@@ -3597,186 +3692,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);
 
@@ -3797,22 +3722,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();