Title: [276689] trunk
Revision
276689
Author
cdu...@apple.com
Date
2021-04-27 21:43:38 -0700 (Tue, 27 Apr 2021)

Log Message

Improve local storage size estimation for quota limitation
https://bugs.webkit.org/show_bug.cgi?id=225123

Reviewed by Alex Christensen.

Source/WebCore:

Improve local storage size estimation for quota limitation:
- Rely on String::sizeInBytes() to compute the String size, instead of using
  String::length() * sizeof(UChar)
- Make estimation consistent between StorageMap & LocalStorageDatabase

* storage/StorageMap.cpp:
(WebCore::StorageMap::setItem):
(WebCore::StorageMap::setItemIgnoringQuota):
(WebCore::StorageMap::removeItem):
(WebCore::StorageMap::clear):
(WebCore::StorageMap::importItems):
(WebCore::StorageMap::Impl::copy const):
* storage/StorageMap.h:

Source/WebKit:

Improve local storage size estimation for quota limitation:
- Rely on String::sizeInBytes() to compute the String size, instead of using
  String::length() * sizeof(UChar)
- Make estimation consistent between StorageMap & LocalStorageDatabase

* NetworkProcess/WebStorage/LocalStorageDatabase.cpp:
(WebKit::LocalStorageDatabase::removeItem):
(WebKit::LocalStorageDatabase::setItem):
(WebKit::estimateEntrySize): Deleted.
* NetworkProcess/WebStorage/LocalStorageDatabase.h:

LayoutTests:

Update test to use unicode in the Strings so that the file reaches the quota without
changing the test too much. The test was using ASCII and was thus able to store all
the strings without reaching the quota due to our updated String size calculation.

* storage/domstorage/quota.html:

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (276688 => 276689)


--- trunk/LayoutTests/ChangeLog	2021-04-28 02:54:40 UTC (rev 276688)
+++ trunk/LayoutTests/ChangeLog	2021-04-28 04:43:38 UTC (rev 276689)
@@ -1,3 +1,16 @@
+2021-04-27  Chris Dumez  <cdu...@apple.com>
+
+        Improve local storage size estimation for quota limitation
+        https://bugs.webkit.org/show_bug.cgi?id=225123
+
+        Reviewed by Alex Christensen.
+
+        Update test to use unicode in the Strings so that the file reaches the quota without
+        changing the test too much. The test was using ASCII and was thus able to store all
+        the strings without reaching the quota due to our updated String size calculation.
+
+        * storage/domstorage/quota.html:
+
 2021-04-27  Wenson Hsieh  <wenson_hs...@apple.com>
 
         [iOS] Web content process occasionally crashes under VisibleSelection::adjustPositionForEnd

Modified: trunk/LayoutTests/storage/domstorage/quota.html (276688 => 276689)


--- trunk/LayoutTests/storage/domstorage/quota.html	2021-04-28 02:54:40 UTC (rev 276688)
+++ trunk/LayoutTests/storage/domstorage/quota.html	2021-04-28 04:43:38 UTC (rev 276689)
@@ -22,7 +22,7 @@
     shouldBe("storage.length", "0");
 
     debug("Creating 'data' which contains 64K of data");
-    data = ""
+    data = ""
     for (var i=0; i<16; i++)
         data += data;
     shouldBe("data.length", "65536");

Modified: trunk/Source/WebCore/ChangeLog (276688 => 276689)


--- trunk/Source/WebCore/ChangeLog	2021-04-28 02:54:40 UTC (rev 276688)
+++ trunk/Source/WebCore/ChangeLog	2021-04-28 04:43:38 UTC (rev 276689)
@@ -1,3 +1,24 @@
+2021-04-27  Chris Dumez  <cdu...@apple.com>
+
+        Improve local storage size estimation for quota limitation
+        https://bugs.webkit.org/show_bug.cgi?id=225123
+
+        Reviewed by Alex Christensen.
+
+        Improve local storage size estimation for quota limitation:
+        - Rely on String::sizeInBytes() to compute the String size, instead of using
+          String::length() * sizeof(UChar)
+        - Make estimation consistent between StorageMap & LocalStorageDatabase
+
+        * storage/StorageMap.cpp:
+        (WebCore::StorageMap::setItem):
+        (WebCore::StorageMap::setItemIgnoringQuota):
+        (WebCore::StorageMap::removeItem):
+        (WebCore::StorageMap::clear):
+        (WebCore::StorageMap::importItems):
+        (WebCore::StorageMap::Impl::copy const):
+        * storage/StorageMap.h:
+
 2021-04-27  Wenson Hsieh  <wenson_hs...@apple.com>
 
         [iOS] Web content process occasionally crashes under VisibleSelection::adjustPositionForEnd

Modified: trunk/Source/WebCore/storage/StorageMap.cpp (276688 => 276689)


--- trunk/Source/WebCore/storage/StorageMap.cpp	2021-04-28 02:54:40 UTC (rev 276688)
+++ trunk/Source/WebCore/storage/StorageMap.cpp	2021-04-28 04:43:38 UTC (rev 276689)
@@ -26,6 +26,7 @@
 #include "config.h"
 #include "StorageMap.h"
 
+#include <wtf/CheckedArithmetic.h>
 #include <wtf/SetForScope.h>
 
 namespace WebCore {
@@ -93,26 +94,19 @@
     if (m_impl->refCount() > 1)
         m_impl = m_impl->copy();
 
-    // Quota tracking.  This is done in a couple of steps to keep the overflow tracking simple.
-    unsigned newLength = m_impl->currentLength;
-    bool overflow = newLength + value.length() < newLength;
-    newLength += value.length();
-
     oldValue = m_impl->map.get(key);
-    overflow |= newLength - oldValue.length() > newLength;
-    newLength -= oldValue.length();
 
-    unsigned adjustedKeyLength = oldValue.isNull() ? key.length() : 0;
-    overflow |= newLength + adjustedKeyLength < newLength;
-    newLength += adjustedKeyLength;
-
-    ASSERT(!overflow);  // Overflow is bad...even if quotas are off.
-    bool overQuota = newLength > m_quotaSize / sizeof(UChar);
-    if (m_quotaSize != noQuota && (overflow || overQuota)) {
+    // Quota tracking. This is done in a couple of steps to keep the overflow tracking simple.
+    CheckedUint32 newSize = m_impl->currentSize;
+    newSize -= oldValue.sizeInBytes();
+    newSize += value.sizeInBytes();
+    if (oldValue.isNull())
+        newSize += key.sizeInBytes();
+    if (m_quotaSize != noQuota && (newSize.hasOverflowed() || newSize.unsafeGet() > m_quotaSize)) {
         quotaException = true;
         return;
     }
-    m_impl->currentLength = newLength;
+    m_impl->currentSize = newSize.unsafeGet();
 
     HashMap<String, String>::AddResult addResult = m_impl->map.add(key, value);
     if (!addResult.isNewEntry)
@@ -123,7 +117,7 @@
 
 void StorageMap::setItemIgnoringQuota(const String& key, const String& value)
 {
-    SetForScope<unsigned> quotaSizeChange(m_quotaSize, static_cast<unsigned>(noQuota));
+    SetForScope<unsigned> quotaSizeChange(m_quotaSize, noQuota);
 
     String oldValue;
     bool quotaException;
@@ -138,13 +132,14 @@
         m_impl = m_impl->copy();
 
     oldValue = m_impl->map.take(key);
-    if (!oldValue.isNull()) {
-        invalidateIterator();
-        ASSERT(m_impl->currentLength - key.length() <= m_impl->currentLength);
-        m_impl->currentLength -= key.length();
-    }
-    ASSERT(m_impl->currentLength - oldValue.length() <= m_impl->currentLength);
-    m_impl->currentLength -= oldValue.length();
+    if (oldValue.isNull())
+        return;
+
+    invalidateIterator();
+    ASSERT(m_impl->currentSize - key.sizeInBytes() <= m_impl->currentSize);
+    m_impl->currentSize -= key.sizeInBytes();
+    ASSERT(m_impl->currentSize - oldValue.sizeInBytes() <= m_impl->currentSize);
+    m_impl->currentSize -= oldValue.sizeInBytes();
 }
 
 void StorageMap::clear()
@@ -154,7 +149,7 @@
         return;
     }
     m_impl->map.clear();
-    m_impl->currentLength = 0;
+    m_impl->currentSize = 0;
 }
 
 bool StorageMap::contains(const String& key) const
@@ -168,8 +163,8 @@
         // Fast path.
         m_impl->map = WTFMove(items);
         for (auto& pair : m_impl->map) {
-            ASSERT(m_impl->currentLength + pair.key.length() + pair.value.length() >= m_impl->currentLength);
-            m_impl->currentLength += (pair.key.length() + pair.value.length());
+            ASSERT(m_impl->currentSize + pair.key.sizeInBytes() + pair.value.sizeInBytes() >= m_impl->currentSize);
+            m_impl->currentSize += (pair.key.sizeInBytes() + pair.value.sizeInBytes());
         }
         return;
     }
@@ -178,9 +173,9 @@
         auto& key = item.key;
         auto& value = item.value;
 
-        ASSERT(m_impl->currentLength + key.length() + value.length() >= m_impl->currentLength);
-        m_impl->currentLength += (key.length() + value.length());
-        
+        ASSERT(m_impl->currentSize + key.sizeInBytes() + value.sizeInBytes() >= m_impl->currentSize);
+        m_impl->currentSize += (key.sizeInBytes() + value.sizeInBytes());
+
         auto result = m_impl->map.add(WTFMove(key), WTFMove(value));
         ASSERT_UNUSED(result, result.isNewEntry); // True if the key didn't exist previously.
     }
@@ -190,7 +185,7 @@
 {
     auto copy = Impl::create();
     copy->map = map;
-    copy->currentLength = currentLength;
+    copy->currentSize = currentSize;
     return copy;
 }
 

Modified: trunk/Source/WebCore/storage/StorageMap.h (276688 => 276689)


--- trunk/Source/WebCore/storage/StorageMap.h	2021-04-28 02:54:40 UTC (rev 276688)
+++ trunk/Source/WebCore/storage/StorageMap.h	2021-04-28 04:43:38 UTC (rev 276689)
@@ -56,7 +56,7 @@
 
     bool isShared() const { return !m_impl->hasOneRef(); }
 
-    static constexpr unsigned noQuota = UINT_MAX;
+    static constexpr unsigned noQuota = std::numeric_limits<unsigned>::max();
 
 private:
     void invalidateIterator();
@@ -73,7 +73,7 @@
         HashMap<String, String> map;
         HashMap<String, String>::iterator iterator { map.end() };
         unsigned iteratorIndex { std::numeric_limits<unsigned>::max() };
-        unsigned currentLength { 0 }; // Measured in UChars.
+        unsigned currentSize { 0 };
     };
 
     Ref<Impl> m_impl;

Modified: trunk/Source/WebKit/ChangeLog (276688 => 276689)


--- trunk/Source/WebKit/ChangeLog	2021-04-28 02:54:40 UTC (rev 276688)
+++ trunk/Source/WebKit/ChangeLog	2021-04-28 04:43:38 UTC (rev 276689)
@@ -1,3 +1,21 @@
+2021-04-27  Chris Dumez  <cdu...@apple.com>
+
+        Improve local storage size estimation for quota limitation
+        https://bugs.webkit.org/show_bug.cgi?id=225123
+
+        Reviewed by Alex Christensen.
+
+        Improve local storage size estimation for quota limitation:
+        - Rely on String::sizeInBytes() to compute the String size, instead of using
+          String::length() * sizeof(UChar)
+        - Make estimation consistent between StorageMap & LocalStorageDatabase
+
+        * NetworkProcess/WebStorage/LocalStorageDatabase.cpp:
+        (WebKit::LocalStorageDatabase::removeItem):
+        (WebKit::LocalStorageDatabase::setItem):
+        (WebKit::estimateEntrySize): Deleted.
+        * NetworkProcess/WebStorage/LocalStorageDatabase.h:
+
 2021-04-27  Wenson Hsieh  <wenson_hs...@apple.com>
 
         [iOS] Web content process occasionally crashes under VisibleSelection::adjustPositionForEnd

Modified: trunk/Source/WebKit/NetworkProcess/WebStorage/LocalStorageDatabase.cpp (276688 => 276689)


--- trunk/Source/WebKit/NetworkProcess/WebStorage/LocalStorageDatabase.cpp	2021-04-28 02:54:40 UTC (rev 276688)
+++ trunk/Source/WebKit/NetworkProcess/WebStorage/LocalStorageDatabase.cpp	2021-04-28 04:43:38 UTC (rev 276689)
@@ -47,14 +47,6 @@
 
 static const char getItemsQueryString[] = "SELECT key, value FROM ItemTable";
 
-static CheckedUint64 estimateEntrySize(const String& key, const String& value)
-{
-    CheckedUint64 entrySize;
-    entrySize += key.length() * sizeof(UChar);
-    entrySize += value.length() * sizeof(UChar);
-    return entrySize;
-}
-
 Ref<LocalStorageDatabase> LocalStorageDatabase::create(Ref<WorkQueue>&& queue, Ref<LocalStorageDatabaseTracker>&& tracker, const SecurityOriginData& securityOrigin, unsigned quotaInBytes)
 {
     return adoptRef(*new LocalStorageDatabase(WTFMove(queue), WTFMove(tracker), securityOrigin, quotaInBytes));
@@ -217,11 +209,11 @@
     }
 
     if (m_databaseSize) {
-        CheckedUint64 entrySize = estimateEntrySize(key, oldValue);
-        if (entrySize.hasOverflowed() || entrySize.unsafeGet() >= *m_databaseSize)
+        auto sizeDecrease = key.sizeInBytes() + oldValue.sizeInBytes();
+        if (sizeDecrease >= *m_databaseSize)
             *m_databaseSize = 0;
         else
-            *m_databaseSize -= entrySize.unsafeGet();
+            *m_databaseSize -= sizeDecrease;
     }
 }
 
@@ -254,15 +246,16 @@
     if (!m_database.isOpen())
         return;
 
+    oldValue = item(key);
+
     if (m_quotaInBytes != WebCore::StorageMap::noQuota) {
         if (!m_databaseSize)
             m_databaseSize = SQLiteFileSystem::getDatabaseFileSize(m_databasePath);
-        if (*m_databaseSize >= m_quotaInBytes) {
-            quotaException = true;
-            return;
-        }
-        CheckedUint64 newDatabaseSize = *m_databaseSize;
-        newDatabaseSize += estimateEntrySize(key, value);
+        CheckedUint32 newDatabaseSize = *m_databaseSize;
+        newDatabaseSize -= oldValue.sizeInBytes();
+        newDatabaseSize += value.sizeInBytes();
+        if (oldValue.isNull())
+            newDatabaseSize += key.sizeInBytes();
         if (newDatabaseSize.hasOverflowed() || newDatabaseSize.unsafeGet() > m_quotaInBytes) {
             quotaException = true;
             return;
@@ -270,8 +263,6 @@
         m_databaseSize = newDatabaseSize.unsafeGet();
     }
 
-    oldValue = item(key);
-
     auto insertStatement = scopedStatement(m_insertStatement, "INSERT INTO ItemTable VALUES (?, ?)"_s);
     if (!insertStatement) {
         LOG_ERROR("Failed to prepare insert statement - cannot write to local storage database");

Modified: trunk/Source/WebKit/NetworkProcess/WebStorage/LocalStorageDatabase.h (276688 => 276689)


--- trunk/Source/WebKit/NetworkProcess/WebStorage/LocalStorageDatabase.h	2021-04-28 02:54:40 UTC (rev 276688)
+++ trunk/Source/WebKit/NetworkProcess/WebStorage/LocalStorageDatabase.h	2021-04-28 04:43:38 UTC (rev 276689)
@@ -75,10 +75,10 @@
 
     String m_databasePath;
     mutable WebCore::SQLiteDatabase m_database;
-    unsigned m_quotaInBytes { 0 };
+    const unsigned m_quotaInBytes { 0 };
     bool m_failedToOpenDatabase { false };
     bool m_isClosed { false };
-    Optional<uint64_t> m_databaseSize;
+    Optional<unsigned> m_databaseSize;
 
     std::unique_ptr<WebCore::SuddenTerminationDisabler> m_disableSuddenTerminationWhileWritingToLocalStorage;
     mutable std::unique_ptr<WebCore::SQLiteStatement> m_clearStatement;
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to