Bug 1546723 - Part 6: Mark snapshot as dirty if the hasOtherProcessObservers flag changes; r=asuth a=jcristau
authorJan Varga <jan.varga@gmail.com>
Wed, 15 May 2019 06:11:11 +0200
changeset 536842 0a94dff558b1e7fc4ca7779e25c5d1f777574b4d
parent 536841 e23ee28c87d7fc3bd4e37b43a5f4a0b845ddaa38
child 536843 ad7c72a799ba407c6117261260593942d3a50f75
push id2082
push userffxbld-merge
push dateMon, 01 Jul 2019 08:34:18 +0000
treeherdermozilla-release@2fb19d0466d2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersasuth, jcristau
bugs1546723
milestone68.0
Bug 1546723 - Part 6: Mark snapshot as dirty if the hasOtherProcessObservers flag changes; r=asuth a=jcristau Differential Revision: https://phabricator.services.mozilla.com/D31201
dom/localstorage/ActorsParent.cpp
modules/libpref/init/all.js
--- a/dom/localstorage/ActorsParent.cpp
+++ b/dom/localstorage/ActorsParent.cpp
@@ -78,16 +78,17 @@ using namespace mozilla::ipc;
 
 namespace {
 
 struct ArchivedOriginInfo;
 class ArchivedOriginScope;
 class Connection;
 class ConnectionThread;
 class Database;
+class Observer;
 class PrepareDatastoreOp;
 class PreparedDatastore;
 class QuotaClient;
 class Snapshot;
 
 typedef nsClassHashtable<nsCStringHashKey, ArchivedOriginInfo>
     ArchivedOriginHashtable;
 
@@ -1771,16 +1772,18 @@ class Datastore final
   bool HasOtherProcessObservers(Database* aDatabase);
 
   void NotifyOtherProcessObservers(Database* aDatabase,
                                    const nsString& aDocumentURI,
                                    const nsString& aKey,
                                    const LSValue& aOldValue,
                                    const LSValue& aNewValue);
 
+  void NoteChangedObserverArray(const nsTArray<Observer*>& aObservers);
+
   NS_INLINE_DECL_REFCOUNTING(Datastore)
 
  private:
   // Reference counted.
   ~Datastore();
 
   bool UpdateUsage(int64_t aDelta);
 
@@ -2063,25 +2066,27 @@ class Snapshot final : public PBackgroun
   /**
    * True if LSSnapshot's mLoadState should be LoadState::AllOrderedItems or
    * AllOrderedKeys.  This can occur because of the initial snapshot, or because
    * a RecvLoadKeys request was received.
    */
   bool mLoadKeysReceived;
   bool mSentMarkDirty;
 
+  bool mHasOtherProcessObservers;
+
  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) {
+            LSSnapshot::LoadState aLoadState, bool aHasOtherProcessObservers) {
     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);
@@ -2098,28 +2103,41 @@ class Snapshot final : public PBackgroun
     } 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;
     }
+    mHasOtherProcessObservers = aHasOtherProcessObservers;
   }
 
   /**
    * 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,
                 bool aAffectsOrder);
 
   void MarkDirty();
 
+  bool IsDirty() const {
+    AssertIsOnBackgroundThread();
+
+    return mSentMarkDirty;
+  }
+
+  bool HasOtherProcessObservers() const {
+    AssertIsOnBackgroundThread();
+
+    return mHasOtherProcessObservers;
+  }
+
   NS_INLINE_DECL_REFCOUNTING(mozilla::dom::Snapshot)
 
  private:
   // Reference counted.
   ~Snapshot();
 
   void Finish();
 
@@ -3296,16 +3314,20 @@ bool RecvPBackgroundLSObserverConstructo
 
   nsTArray<Observer*>* array;
   if (!gObservers->Get(observer->Origin(), &array)) {
     array = new nsTArray<Observer*>();
     gObservers->Put(observer->Origin(), array);
   }
   array->AppendElement(observer);
 
+  if (RefPtr<Datastore> datastore = GetDatastore(observer->Origin())) {
+    datastore->NoteChangedObserverArray(*array);
+  }
+
   return true;
 }
 
 bool DeallocPBackgroundLSObserverParent(PBackgroundLSObserverParent* aActor) {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aActor);
 
   // Transfer ownership back from IPDL.
@@ -5435,16 +5457,47 @@ void Datastore::NotifyOtherProcessObserv
 
   for (Observer* observer : *array) {
     if (observer->Manager() != databaseBackgroundActor) {
       observer->Observe(aDatabase, aDocumentURI, aKey, aOldValue, aNewValue);
     }
   }
 }
 
+void Datastore::NoteChangedObserverArray(
+    const nsTArray<Observer*>& aObservers) {
+  AssertIsOnBackgroundThread();
+
+  for (auto iter = mActiveDatabases.ConstIter(); !iter.Done(); iter.Next()) {
+    Database* database = iter.Get()->GetKey();
+
+    Snapshot* snapshot = database->GetSnapshot();
+    MOZ_ASSERT(snapshot);
+
+    if (snapshot->IsDirty()) {
+      continue;
+    }
+
+    bool hasOtherProcessObservers = false;
+
+    PBackgroundParent* databaseBackgroundActor = database->Manager();
+
+    for (Observer* observer : aObservers) {
+      if (observer->Manager() != databaseBackgroundActor) {
+        hasOtherProcessObservers = true;
+        break;
+      }
+    }
+
+    if (snapshot->HasOtherProcessObservers() != hasOtherProcessObservers) {
+      snapshot->MarkDirty();
+    }
+  }
+}
+
 bool Datastore::UpdateUsage(int64_t aDelta) {
   AssertIsOnBackgroundThread();
 
   // Check internal LocalStorage origin limit.
   int64_t newUsage = mUsage + aDelta;
 
   MOZ_ASSERT(newUsage >= 0);
 
@@ -5777,17 +5830,17 @@ mozilla::ipc::IPCResult Database::RecvPB
   if (aIncreasePeakUsage) {
     int64_t size = mDatastore->RequestUpdateUsage(aRequestedSize, aMinSize);
     peakUsage += size;
   }
 
   bool hasOtherProcessObservers = mDatastore->HasOtherProcessObservers(this);
 
   snapshot->Init(loadedItems, unknownItems, nextLoadIndex, totalLength,
-                 initialUsage, peakUsage, loadState);
+                 initialUsage, peakUsage, loadState, hasOtherProcessObservers);
 
   RegisterSnapshot(snapshot);
 
   aInitInfo->addKeyToUnknownItems() = addKeyToUnknownItems;
   aInitInfo->itemInfos() = std::move(itemInfos);
   aInitInfo->totalLength() = totalLength;
   aInitInfo->initialUsage() = initialUsage;
   aInitInfo->peakUsage() = peakUsage;
@@ -5908,16 +5961,21 @@ mozilla::ipc::IPCResult Snapshot::RecvCh
   MOZ_ASSERT(mUsage >= 0);
   MOZ_DIAGNOSTIC_ASSERT(mPeakUsage >= mUsage);
 
   if (NS_WARN_IF(aWriteInfos.IsEmpty())) {
     ASSERT_UNLESS_FUZZING();
     return IPC_FAIL_NO_REASON(this);
   }
 
+  if (NS_WARN_IF(mHasOtherProcessObservers)) {
+    ASSERT_UNLESS_FUZZING();
+    return IPC_FAIL_NO_REASON(this);
+  }
+
   mDatastore->BeginUpdateBatch(mUsage);
 
   for (uint32_t index = 0; index < aWriteInfos.Length(); index++) {
     const LSWriteInfo& writeInfo = aWriteInfos[index];
 
     switch (writeInfo.type()) {
       case LSWriteInfo::TLSSetItemInfo: {
         const LSSetItemInfo& info = writeInfo.get_LSSetItemInfo();
@@ -5957,16 +6015,21 @@ mozilla::ipc::IPCResult Snapshot::RecvCh
   MOZ_ASSERT(mUsage >= 0);
   MOZ_ASSERT(mPeakUsage >= mUsage);
 
   if (NS_WARN_IF(aWriteAndNotifyInfos.IsEmpty())) {
     ASSERT_UNLESS_FUZZING();
     return IPC_FAIL_NO_REASON(this);
   }
 
+  if (NS_WARN_IF(!mHasOtherProcessObservers)) {
+    ASSERT_UNLESS_FUZZING();
+    return IPC_FAIL_NO_REASON(this);
+  }
+
   mDatastore->BeginUpdateBatch(mUsage);
 
   for (uint32_t index = 0; index < aWriteAndNotifyInfos.Length(); index++) {
     const LSWriteAndNotifyInfo& writeAndNotifyInfo =
         aWriteAndNotifyInfos[index];
 
     switch (writeAndNotifyInfo.type()) {
       case LSWriteAndNotifyInfo::TLSSetItemAndNotifyInfo: {
@@ -6304,16 +6367,20 @@ void Observer::ActorDestroy(ActorDestroy
   MOZ_ASSERT(gObservers);
 
   nsTArray<Observer*>* array;
   gObservers->Get(mOrigin, &array);
   MOZ_ASSERT(array);
 
   array->RemoveElement(this);
 
+  if (RefPtr<Datastore> datastore = GetDatastore(mOrigin)) {
+    datastore->NoteChangedObserverArray(*array);
+  }
+
   if (array->IsEmpty()) {
     gObservers->Remove(mOrigin);
   }
 
   if (!gObservers->Count()) {
     gObservers = nullptr;
   }
 }
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -1280,17 +1280,17 @@ pref("dom.storage.enabled", true);
 // See bug 1517090 for enabling this on Nightly.
 // See bug 1534736 for changing it to EARLY_BETA_OR_EARLIER.
 // See bug 1539835 for enabling this unconditionally.
 pref("dom.storage.next_gen", true);
 pref("dom.storage.default_quota",      5120);
 pref("dom.storage.shadow_writes", true);
 pref("dom.storage.snapshot_prefill", 16384);
 pref("dom.storage.snapshot_gradual_prefill", 4096);
-pref("dom.storage.snapshot_reusing", false);
+pref("dom.storage.snapshot_reusing", true);
 pref("dom.storage.testing", false);
 pref("dom.storage.client_validation", true);
 
 pref("dom.send_after_paint_to_content", false);
 
 // Timeout clamp in ms for timeouts we clamp
 pref("dom.min_timeout_value", 4);
 // And for background windows