Bug 1286798 - Part 39: Reduce number of hash lookups; r=asuth draft
authorJan Varga <jan.varga@gmail.com>
Wed, 24 Oct 2018 06:59:07 +0200
changeset 481717 e6484c48d5ae8152fbb7b183c9f6e6a349c19b3a
parent 481716 91604e07a92350fdb5898fcabbcafa15bf97a5f5
child 481718 0492574cd8ea95cf0022c71ed64469b96534fa52
push id10
push userbugmail@asutherland.org
push dateSun, 18 Nov 2018 18:57:42 +0000
reviewersasuth
bugs1286798
milestone65.0a1
Bug 1286798 - Part 39: Reduce number of hash lookups; r=asuth
dom/localstorage/LSSnapshot.cpp
dom/localstorage/LSSnapshot.h
--- a/dom/localstorage/LSSnapshot.cpp
+++ b/dom/localstorage/LSSnapshot.cpp
@@ -153,84 +153,19 @@ LSSnapshot::GetItem(const nsAString& aKe
                     nsAString& aResult)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mActor);
   MOZ_ASSERT(mInitialized);
   MOZ_ASSERT(!mSentFinish);
 
   nsString result;
-
-  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 {
-        if (NS_WARN_IF(!mActor->SendLoadItem(nsString(aKey), &result))) {
-          return NS_ERROR_FAILURE;
-        }
-
-        if (result.IsVoid()) {
-          mUnknownItems.PutEntry(aKey);
-        } else {
-          mLoadedItems.PutEntry(aKey);
-          mValues.Put(aKey, result);
-
-          if (mLoadedItems.Count() == mInitLength) {
-            mLoadedItems.Clear();
-            mUnknownItems.Clear();
-            mLength = 0;
-            mLoadState = LoadState::AllUnorderedItems;
-          }
-        }
-      }
-
-      break;
-    }
-
-    case LoadState::AllOrderedKeys: {
-      if (mValues.Get(aKey, &result)) {
-        if (result.IsVoid()) {
-          if (NS_WARN_IF(!mActor->SendLoadItem(nsString(aKey), &result))) {
-            return NS_ERROR_FAILURE;
-          }
-
-          MOZ_ASSERT(!result.IsVoid());
-
-          mLoadedItems.PutEntry(aKey);
-          mValues.Put(aKey, result);
-
-          if (mLoadedItems.Count() == mInitLength) {
-            mLoadedItems.Clear();
-            MOZ_ASSERT(mLength == 0);
-            mLoadState = LoadState::AllOrderedItems;
-          }
-        }
-      } else {
-        result.SetIsVoid(true);
-      }
-
-      break;
-    }
-
-    case LoadState::AllUnorderedItems:
-    case LoadState::AllOrderedItems: {
-      if (mValues.Get(aKey, &result)) {
-        MOZ_ASSERT(!result.IsVoid());
-      } else {
-        result.SetIsVoid(true);
-      }
-
-      break;
-    }
-
-    default:
-      MOZ_CRASH("Bad state!");
+  nsresult rv = GetItemInternal(aKey, Optional<nsString>(), result);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
   }
 
   aResult = result;
   return NS_OK;
 }
 
 nsresult
 LSSnapshot::GetKeys(nsTArray<nsString>& aKeys)
@@ -258,17 +193,18 @@ LSSnapshot::SetItem(const nsAString& aKe
                     LSNotifyInfo& aNotifyInfo)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mActor);
   MOZ_ASSERT(mInitialized);
   MOZ_ASSERT(!mSentFinish);
 
   nsString oldValue;
-  nsresult rv = GetItem(aKey, oldValue);
+  nsresult rv =
+    GetItemInternal(aKey, Optional<nsString>(nsString(aValue)), oldValue);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   bool changed;
   if (oldValue == aValue && oldValue.IsVoid() == aValue.IsVoid()) {
     changed = false;
   } else {
@@ -278,21 +214,24 @@ LSSnapshot::SetItem(const nsAString& aKe
                     static_cast<int64_t>(oldValue.Length());
 
     if (oldValue.IsVoid()) {
       delta += static_cast<int64_t>(aKey.Length());
     }
 
     rv = UpdateUsage(delta);
     if (NS_WARN_IF(NS_FAILED(rv))) {
+      if (oldValue.IsVoid()) {
+        mValues.Remove(aKey);
+      } else {
+        mValues.Put(aKey, oldValue);
+      }
       return rv;
     }
 
-    mValues.Put(aKey, nsString(aValue));
-
     if (oldValue.IsVoid() && mLoadState == LoadState::Partial) {
       mLength++;
     }
 
     LSSetItemInfo setItemInfo;
     setItemInfo.key() = aKey;
     setItemInfo.oldValue() = oldValue;
     setItemInfo.value() = aValue;
@@ -311,35 +250,34 @@ LSSnapshot::RemoveItem(const nsAString& 
                        LSNotifyInfo& aNotifyInfo)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mActor);
   MOZ_ASSERT(mInitialized);
   MOZ_ASSERT(!mSentFinish);
 
   nsString oldValue;
-  nsresult rv = GetItem(aKey, oldValue);
+  nsresult rv =
+    GetItemInternal(aKey, Optional<nsString>(VoidString()), oldValue);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   bool changed;
   if (oldValue.IsVoid()) {
     changed = false;
   } else {
     changed = true;
 
     int64_t delta = -(static_cast<int64_t>(aKey.Length()) +
                       static_cast<int64_t>(oldValue.Length()));
 
     DebugOnly<nsresult> rv = UpdateUsage(delta);
     MOZ_ASSERT(NS_SUCCEEDED(rv));
 
-    mValues.Remove(aKey);
-
     if (mLoadState == LoadState::Partial) {
       mLength--;
     }
 
     LSRemoveItemInfo removeItemInfo;
     removeItemInfo.key() = aKey;
     removeItemInfo.oldValue() = oldValue;
 
@@ -424,16 +362,141 @@ LSSnapshot::Finish()
   } else {
     MOZ_ASSERT(!mSelfRef);
   }
 
   return NS_OK;
 }
 
 nsresult
+LSSnapshot::GetItemInternal(const nsAString& aKey,
+                            const Optional<nsString>& aValue,
+                            nsAString& aResult)
+{
+  AssertIsOnOwningThread();
+  MOZ_ASSERT(mActor);
+  MOZ_ASSERT(mInitialized);
+  MOZ_ASSERT(!mSentFinish);
+
+  nsString result;
+
+  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 {
+        if (NS_WARN_IF(!mActor->SendLoadItem(nsString(aKey), &result))) {
+          return NS_ERROR_FAILURE;
+        }
+
+        if (result.IsVoid()) {
+          mUnknownItems.PutEntry(aKey);
+        } else {
+          mLoadedItems.PutEntry(aKey);
+          mValues.Put(aKey, result);
+
+          if (mLoadedItems.Count() == mInitLength) {
+            mLoadedItems.Clear();
+            mUnknownItems.Clear();
+            mLength = 0;
+            mLoadState = LoadState::AllUnorderedItems;
+          }
+        }
+      }
+
+      if (aValue.WasPassed()) {
+        const nsString& value = aValue.Value();
+        if (!value.IsVoid()) {
+          mValues.Put(aKey, value);
+        } else if (!result.IsVoid()) {
+          mValues.Remove(aKey);
+        }
+      }
+
+      break;
+    }
+
+    case LoadState::AllOrderedKeys: {
+      if (mValues.Get(aKey, &result)) {
+        if (result.IsVoid()) {
+          if (NS_WARN_IF(!mActor->SendLoadItem(nsString(aKey), &result))) {
+            return NS_ERROR_FAILURE;
+          }
+
+          MOZ_ASSERT(!result.IsVoid());
+
+          mLoadedItems.PutEntry(aKey);
+          mValues.Put(aKey, result);
+
+          if (mLoadedItems.Count() == mInitLength) {
+            mLoadedItems.Clear();
+            MOZ_ASSERT(mLength == 0);
+            mLoadState = LoadState::AllOrderedItems;
+          }
+        }
+      } else {
+        result.SetIsVoid(true);
+      }
+
+      if (aValue.WasPassed()) {
+        const nsString& value = aValue.Value();
+        if (!value.IsVoid()) {
+          mValues.Put(aKey, value);
+        } else if (!result.IsVoid()) {
+          mValues.Remove(aKey);
+        }
+      }
+
+      break;
+    }
+
+    case LoadState::AllUnorderedItems:
+    case LoadState::AllOrderedItems: {
+      if (aValue.WasPassed()) {
+        const nsString& value = aValue.Value();
+        if (!value.IsVoid()) {
+          auto entry = mValues.LookupForAdd(aKey);
+          if (entry) {
+            result = entry.Data();
+            entry.Data() = value;
+          } else {
+            result.SetIsVoid(true);
+            entry.OrInsert([value]() { return value; });
+          }
+        } else {
+          if (auto entry = mValues.Lookup(aKey)) {
+            result = entry.Data();
+            MOZ_ASSERT(!result.IsVoid());
+            entry.Remove();
+          } else {
+            result.SetIsVoid(true);
+          }
+        }
+      } else {
+        if (mValues.Get(aKey, &result)) {
+          MOZ_ASSERT(!result.IsVoid());
+        } else {
+          result.SetIsVoid(true);
+        }
+      }
+
+      break;
+    }
+
+    default:
+      MOZ_CRASH("Bad state!");
+  }
+
+  aResult = result;
+  return NS_OK;
+}
+
+nsresult
 LSSnapshot::EnsureAllKeys()
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mActor);
   MOZ_ASSERT(mInitialized);
   MOZ_ASSERT(!mSentFinish);
   MOZ_ASSERT(mLoadState != LoadState::Initial);
 
--- a/dom/localstorage/LSSnapshot.h
+++ b/dom/localstorage/LSSnapshot.h
@@ -115,16 +115,21 @@ public:
 
   nsresult
   Finish();
 
 private:
   ~LSSnapshot();
 
   nsresult
+  GetItemInternal(const nsAString& aKey,
+                  const Optional<nsString>& aValue,
+                  nsAString& aResult);
+
+  nsresult
   EnsureAllKeys();
 
   nsresult
   UpdateUsage(int64_t aDelta);
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIRUNNABLE
 };