Bug 1286798 - Part 37: Always preallocate quota when initializing a snapshot; r=asuth draft
authorJan Varga <jan.varga@gmail.com>
Wed, 24 Oct 2018 06:59:07 +0200
changeset 481715 88337fbca5231155430229d21838990be3718ea5
parent 481714 1385b34dc1677bce59a8c409ea1d3e53471d9e16
child 481716 91604e07a92350fdb5898fcabbcafa15bf97a5f5
push id10
push userbugmail@asutherland.org
push dateSun, 18 Nov 2018 18:57:42 +0000
reviewersasuth
bugs1286798
milestone65.0a1
Bug 1286798 - Part 37: Always preallocate quota when initializing a snapshot; r=asuth Besides always preallocating quota we now also preallocate more. This mitigates number of additional sync calls.
dom/localstorage/ActorsChild.cpp
dom/localstorage/ActorsChild.h
dom/localstorage/ActorsParent.cpp
dom/localstorage/LSDatabase.cpp
dom/localstorage/LSDatabase.h
dom/localstorage/PBackgroundLSDatabase.ipdl
--- a/dom/localstorage/ActorsChild.cpp
+++ b/dom/localstorage/ActorsChild.cpp
@@ -75,17 +75,19 @@ LSDatabaseChild::RecvRequestAllowToClose
     //       However, we probably shouldn't do that if we are shutting down.
   }
 
   return IPC_OK();
 }
 
 PBackgroundLSSnapshotChild*
 LSDatabaseChild::AllocPBackgroundLSSnapshotChild(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)
--- a/dom/localstorage/ActorsChild.h
+++ b/dom/localstorage/ActorsChild.h
@@ -63,17 +63,19 @@ private:
   void
   ActorDestroy(ActorDestroyReason aWhy) override;
 
   mozilla::ipc::IPCResult
   RecvRequestAllowToClose() override;
 
   PBackgroundLSSnapshotChild*
   AllocPBackgroundLSSnapshotChild(const nsString& aDocumentURI,
+                                  const bool& aIncreasePeakUsage,
                                   const int64_t& aRequestedSize,
+                                  const int64_t& aMinSize,
                                   LSSnapshotInitInfo* aInitInfo) override;
 
   bool
   DeallocPBackgroundLSSnapshotChild(PBackgroundLSSnapshotChild* aActor)
                                     override;
 };
 
 class LSObserverChild final
--- a/dom/localstorage/ActorsParent.cpp
+++ b/dom/localstorage/ActorsParent.cpp
@@ -1366,18 +1366,17 @@ public:
 
   void
   NoteActiveDatabase(Database* aDatabase);
 
   void
   NoteInactiveDatabase(Database* aDatabase);
 
   void
-  GetSnapshotInitInfo(int64_t aRequestedSize,
-                      nsTHashtable<nsStringHashKey>& aLoadedItems,
+  GetSnapshotInitInfo(nsTHashtable<nsStringHashKey>& aLoadedItems,
                       nsTArray<LSItemInfo>& aItemInfos,
                       uint32_t& aTotalLength,
                       int64_t& aInitialUsage,
                       int64_t& aPeakUsage,
                       LSSnapshot::LoadState& aLoadState);
 
   void
   GetItem(const nsString& aKey, nsString& aValue) const;
@@ -1406,25 +1405,29 @@ public:
   PrivateBrowsingClear();
 
   void
   BeginUpdateBatch(int64_t aSnapshotInitialUsage);
 
   void
   EndUpdateBatch(int64_t aSnapshotPeakUsage);
 
-  bool
-  UpdateUsage(int64_t aDelta);
+  int64_t
+  RequestUpdateUsage(int64_t aRequestedSize,
+                     int64_t aMinSize);
 
   NS_INLINE_DECL_REFCOUNTING(Datastore)
 
 private:
   // Reference counted.
   ~Datastore();
 
+  bool
+  UpdateUsage(int64_t aDelta);
+
   void
   MaybeClose();
 
   void
   ConnectionClosedCallback();
 
   void
   CleanupMetadata();
@@ -1627,23 +1630,27 @@ private:
   mozilla::ipc::IPCResult
   RecvDeleteMe() override;
 
   mozilla::ipc::IPCResult
   RecvAllowToClose() override;
 
   PBackgroundLSSnapshotParent*
   AllocPBackgroundLSSnapshotParent(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 bool& aIncreasePeakUsage,
                                        const int64_t& aRequestedSize,
+                                       const int64_t& aMinSize,
                                        LSSnapshotInitInfo* aInitInfo) override;
 
   bool
   DeallocPBackgroundLSSnapshotParent(PBackgroundLSSnapshotParent* aActor)
                                      override;
 };
 
 class Snapshot final
@@ -3737,18 +3744,17 @@ Datastore::NoteInactiveDatabase(Database
       MOZ_ASSERT(ok);
     }
 
     mPendingUsageDeltas.Clear();
   }
 }
 
 void
-Datastore::GetSnapshotInitInfo(int64_t aRequestedSize,
-                               nsTHashtable<nsStringHashKey>& aLoadedItems,
+Datastore::GetSnapshotInitInfo(nsTHashtable<nsStringHashKey>& aLoadedItems,
                                nsTArray<LSItemInfo>& aItemInfos,
                                uint32_t& aTotalLength,
                                int64_t& aInitialUsage,
                                int64_t& aPeakUsage,
                                LSSnapshot::LoadState& aLoadState)
 {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(!mClosed);
@@ -3812,19 +3818,16 @@ Datastore::GetSnapshotInitInfo(int64_t a
     MOZ_ASSERT(aItemInfos.Length() < mKeys.Length());
     aLoadState = LSSnapshot::LoadState::Partial;
   }
 
   aTotalLength = mValues.Count();
 
   aInitialUsage = mUsage;
   aPeakUsage = aInitialUsage;
-  if (aRequestedSize && UpdateUsage(aRequestedSize)) {
-    aPeakUsage += aRequestedSize;
-  }
 }
 
 void
 Datastore::GetItem(const nsString& aKey, nsString& aValue) const
 {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(!mClosed);
 
@@ -4058,16 +4061,35 @@ Datastore::EndUpdateBatch(int64_t aSnaps
     mConnection->EndUpdateBatch();
   }
 
 #ifdef DEBUG
   mInUpdateBatch = false;
 #endif
 }
 
+int64_t
+Datastore::RequestUpdateUsage(int64_t aRequestedSize,
+                              int64_t aMinSize)
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(aRequestedSize > 0);
+  MOZ_ASSERT(aMinSize > 0);
+
+  if (UpdateUsage(aRequestedSize)) {
+    return aRequestedSize;
+  }
+
+  if (UpdateUsage(aMinSize)) {
+    return aMinSize;
+  }
+
+  return 0;
+}
+
 bool
 Datastore::UpdateUsage(int64_t aDelta)
 {
   AssertIsOnBackgroundThread();
 
   // Check internal LocalStorage origin limit.
   int64_t newUsage = mUsage + aDelta;
   if (newUsage > gOriginLimitKB * 1024) {
@@ -4391,22 +4413,29 @@ Database::RecvAllowToClose()
 
   AllowToClose();
 
   return IPC_OK();
 }
 
 PBackgroundLSSnapshotParent*
 Database::AllocPBackgroundLSSnapshotParent(const nsString& aDocumentURI,
+                                           const bool& aIncreasePeakUsage,
                                            const int64_t& aRequestedSize,
+                                           const int64_t& aMinSize,
                                            LSSnapshotInitInfo* aInitInfo)
 {
   AssertIsOnBackgroundThread();
 
-  if (NS_WARN_IF(aRequestedSize < 0)) {
+  if (NS_WARN_IF(aIncreasePeakUsage && aRequestedSize <= 0)) {
+    ASSERT_UNLESS_FUZZING();
+    return nullptr;
+  }
+
+  if (NS_WARN_IF(aIncreasePeakUsage && aMinSize <= 0)) {
     ASSERT_UNLESS_FUZZING();
     return nullptr;
   }
 
   if (NS_WARN_IF(mAllowedToClose)) {
     ASSERT_UNLESS_FUZZING();
     return nullptr;
   }
@@ -4416,42 +4445,49 @@ Database::AllocPBackgroundLSSnapshotPare
   // Transfer ownership to IPDL.
   return snapshot.forget().take();
 }
 
 mozilla::ipc::IPCResult
 Database::RecvPBackgroundLSSnapshotConstructor(
                                             PBackgroundLSSnapshotParent* aActor,
                                             const nsString& aDocumentURI,
+                                            const bool& aIncreasePeakUsage,
                                             const int64_t& aRequestedSize,
+                                            const int64_t& aMinSize,
                                             LSSnapshotInitInfo* aInitInfo)
 {
   AssertIsOnBackgroundThread();
-  MOZ_ASSERT(aRequestedSize >= 0);
+  MOZ_ASSERT_IF(aIncreasePeakUsage, aRequestedSize > 0);
+  MOZ_ASSERT_IF(aIncreasePeakUsage, aMinSize > 0);
   MOZ_ASSERT(aInitInfo);
   MOZ_ASSERT(!mAllowedToClose);
 
   auto* snapshot = static_cast<Snapshot*>(aActor);
 
   // 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 totalLength;
   int64_t initialUsage;
   int64_t peakUsage;
   LSSnapshot::LoadState loadState;
-  mDatastore->GetSnapshotInitInfo(aRequestedSize,
-                                  loadedItems,
+  mDatastore->GetSnapshotInitInfo(loadedItems,
                                   itemInfos,
                                   totalLength,
                                   initialUsage,
                                   peakUsage,
                                   loadState);
 
+  if (aIncreasePeakUsage) {
+    int64_t size = mDatastore->RequestUpdateUsage(aRequestedSize, aMinSize);
+    peakUsage += size;
+  }
+
   snapshot->Init(loadedItems, totalLength, initialUsage, peakUsage, loadState);
 
   RegisterSnapshot(snapshot);
 
   aInitInfo->itemInfos() = std::move(itemInfos);
   aInitInfo->totalLength() = totalLength;
   aInitInfo->initialUsage() = initialUsage;
   aInitInfo->peakUsage() = peakUsage;
@@ -4761,25 +4797,21 @@ Snapshot::RecvIncreasePeakUsage(const in
     return IPC_FAIL_NO_REASON(this);
   }
 
   if (NS_WARN_IF(mFinishReceived)) {
     ASSERT_UNLESS_FUZZING();
     return IPC_FAIL_NO_REASON(this);
   }
 
-  if (mDatastore->UpdateUsage(aRequestedSize)) {
-    mPeakUsage += aRequestedSize;
-    *aSize = aRequestedSize;
-  } else if (mDatastore->UpdateUsage(aMinSize)) {
-    mPeakUsage += aMinSize;
-    *aSize = aMinSize;
-  } else {
-    *aSize = 0;
-  }
+  int64_t size = mDatastore->RequestUpdateUsage(aRequestedSize, aMinSize);
+
+  mPeakUsage += size;
+
+  *aSize = size;
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 Snapshot::RecvPing()
 {
   AssertIsOnBackgroundThread();
--- a/dom/localstorage/LSDatabase.cpp
+++ b/dom/localstorage/LSDatabase.cpp
@@ -96,17 +96,17 @@ nsresult
 LSDatabase::GetLength(LSObject* aObject,
                       uint32_t* aResult)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aObject);
   MOZ_ASSERT(mActor);
   MOZ_ASSERT(!mAllowedToClose);
 
-  nsresult rv = EnsureSnapshot(aObject, /* aRequestedBySetItem */ false);
+  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;
   }
@@ -119,17 +119,17 @@ LSDatabase::GetKey(LSObject* aObject,
                    uint32_t aIndex,
                    nsAString& aResult)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aObject);
   MOZ_ASSERT(mActor);
   MOZ_ASSERT(!mAllowedToClose);
 
-  nsresult rv = EnsureSnapshot(aObject, /* aRequestedBySetItem */ false);
+  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;
   }
@@ -142,17 +142,17 @@ LSDatabase::GetItem(LSObject* aObject,
                     const nsAString& aKey,
                     nsAString& aResult)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aObject);
   MOZ_ASSERT(mActor);
   MOZ_ASSERT(!mAllowedToClose);
 
-  nsresult rv = EnsureSnapshot(aObject, /* aRequestedBySetItem */ false);
+  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;
   }
@@ -164,17 +164,17 @@ nsresult
 LSDatabase::GetKeys(LSObject* aObject,
                     nsTArray<nsString>& aKeys)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aObject);
   MOZ_ASSERT(mActor);
   MOZ_ASSERT(!mAllowedToClose);
 
-  nsresult rv = EnsureSnapshot(aObject, /* aRequestedBySetItem */ false);
+  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;
   }
@@ -188,17 +188,17 @@ LSDatabase::SetItem(LSObject* aObject,
                     const nsAString& aValue,
                     LSNotifyInfo& aNotifyInfo)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aObject);
   MOZ_ASSERT(mActor);
   MOZ_ASSERT(!mAllowedToClose);
 
-  nsresult rv = EnsureSnapshot(aObject, /* aRequestedBySetItem */ true);
+  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;
   }
@@ -211,17 +211,17 @@ LSDatabase::RemoveItem(LSObject* aObject
                        const nsAString& aKey,
                        LSNotifyInfo& aNotifyInfo)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aObject);
   MOZ_ASSERT(mActor);
   MOZ_ASSERT(!mAllowedToClose);
 
-  nsresult rv = EnsureSnapshot(aObject, /* aRequestedBySetItem */ false);
+  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;
   }
@@ -233,17 +233,17 @@ nsresult
 LSDatabase::Clear(LSObject* aObject,
                   LSNotifyInfo& aNotifyInfo)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aObject);
   MOZ_ASSERT(mActor);
   MOZ_ASSERT(!mAllowedToClose);
 
-  nsresult rv = EnsureSnapshot(aObject, /* aRequestedBySetItem */ false);
+  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;
   }
@@ -258,19 +258,17 @@ LSDatabase::BeginExplicitSnapshot(LSObje
   MOZ_ASSERT(aObject);
   MOZ_ASSERT(mActor);
   MOZ_ASSERT(!mAllowedToClose);
 
   if (mSnapshot) {
     return NS_ERROR_ALREADY_INITIALIZED;
   }
 
-  nsresult rv = EnsureSnapshot(aObject,
-                               /* aRequestedBySetItem */ false,
-                               /* aExplicit */ true);
+  nsresult rv = EnsureSnapshot(aObject, /* aExplicit */ true);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   return NS_OK;
 }
 
 nsresult
@@ -292,39 +290,38 @@ LSDatabase::EndExplicitSnapshot(LSObject
     return rv;
   }
 
   return NS_OK;
 }
 
 nsresult
 LSDatabase::EnsureSnapshot(LSObject* aObject,
-                           bool aRequestedBySetItem,
                            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);
 
-  int64_t requestedSize = aRequestedBySetItem ? 4096 : 0;
-
   LSSnapshotInitInfo initInfo;
   bool ok =
     mActor->SendPBackgroundLSSnapshotConstructor(actor,
                                                  aObject->DocumentURI(),
-                                                 requestedSize,
+                                                 /* increasePeakUsage */ true,
+                                                 /* requestedSize */ 131072,
+                                                 /* minSize */ 4096,
                                                  &initInfo);
   if (NS_WARN_IF(!ok)) {
     return NS_ERROR_FAILURE;
   }
 
   snapshot->SetActor(actor);
 
   // This add refs snapshot.
--- a/dom/localstorage/LSDatabase.h
+++ b/dom/localstorage/LSDatabase.h
@@ -103,17 +103,16 @@ public:
   nsresult
   EndExplicitSnapshot(LSObject* aObject);
 
 private:
   ~LSDatabase();
 
   nsresult
   EnsureSnapshot(LSObject* aObject,
-                 bool aRequestedBySetItem,
                  bool aExplicit = false);
 
   void
   AllowToClose();
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/localstorage/PBackgroundLSDatabase.ipdl
+++ b/dom/localstorage/PBackgroundLSDatabase.ipdl
@@ -43,17 +43,19 @@ parent:
   // error typically causes a crash. The race can be prevented by doing the
   // teardown in two steps. First, we send the DeleteMe message to the parent
   // and the parent then sends the __delete__ message to the child.
   async DeleteMe();
 
   async AllowToClose();
 
   sync PBackgroundLSSnapshot(nsString documentURI,
-                             int64_t requestedSize)
+                             bool increasePeakUsage,
+                             int64_t requestedSize,
+                             int64_t minSize)
     returns (LSSnapshotInitInfo initInfo);
 
 child:
   async __delete__();
 
   async RequestAllowToClose();
 };