Title: [278786] trunk/Source/WebKit
Revision
278786
Author
cdu...@apple.com
Date
2021-06-11 15:56:18 -0700 (Fri, 11 Jun 2021)

Log Message

[WK2] Batch local storage database writes using transactions
https://bugs.webkit.org/show_bug.cgi?id=226938

Reviewed by Geoff Garen.

Batch local storage writes using transactions, to improve performance
and reduce disk writes. In this patch, we use a simple time-based
approach where we batch transactions happening in the same 500ms
period.

* NetworkProcess/WebStorage/LocalStorageDatabase.cpp:
(WebKit::LocalStorageDatabase::create):
(WebKit::LocalStorageDatabase::LocalStorageDatabase):
(WebKit::LocalStorageDatabase::startTransactionIfNecessary):
(WebKit::LocalStorageDatabase::removeItem):
(WebKit::LocalStorageDatabase::setItem):
(WebKit::LocalStorageDatabase::clear):
(WebKit::LocalStorageDatabase::close):
* NetworkProcess/WebStorage/LocalStorageDatabase.h:
* NetworkProcess/WebStorage/StorageArea.cpp:
(WebKit::StorageArea::ensureDatabase const):

Modified Paths

Diff

Modified: trunk/Source/WebKit/ChangeLog (278785 => 278786)


--- trunk/Source/WebKit/ChangeLog	2021-06-11 22:37:40 UTC (rev 278785)
+++ trunk/Source/WebKit/ChangeLog	2021-06-11 22:56:18 UTC (rev 278786)
@@ -1,3 +1,27 @@
+2021-06-11  Chris Dumez  <cdu...@apple.com>
+
+        [WK2] Batch local storage database writes using transactions
+        https://bugs.webkit.org/show_bug.cgi?id=226938
+
+        Reviewed by Geoff Garen.
+
+        Batch local storage writes using transactions, to improve performance
+        and reduce disk writes. In this patch, we use a simple time-based
+        approach where we batch transactions happening in the same 500ms
+        period.
+
+        * NetworkProcess/WebStorage/LocalStorageDatabase.cpp:
+        (WebKit::LocalStorageDatabase::create):
+        (WebKit::LocalStorageDatabase::LocalStorageDatabase):
+        (WebKit::LocalStorageDatabase::startTransactionIfNecessary):
+        (WebKit::LocalStorageDatabase::removeItem):
+        (WebKit::LocalStorageDatabase::setItem):
+        (WebKit::LocalStorageDatabase::clear):
+        (WebKit::LocalStorageDatabase::close):
+        * NetworkProcess/WebStorage/LocalStorageDatabase.h:
+        * NetworkProcess/WebStorage/StorageArea.cpp:
+        (WebKit::StorageArea::ensureDatabase const):
+
 2021-06-11  Alex Christensen  <achristen...@webkit.org>
 
         Don't include certificate info in WebURLSchemeTask::didReceiveResponse

Modified: trunk/Source/WebKit/NetworkProcess/WebStorage/LocalStorageDatabase.cpp (278785 => 278786)


--- trunk/Source/WebKit/NetworkProcess/WebStorage/LocalStorageDatabase.cpp	2021-06-11 22:37:40 UTC (rev 278785)
+++ trunk/Source/WebKit/NetworkProcess/WebStorage/LocalStorageDatabase.cpp	2021-06-11 22:56:18 UTC (rev 278786)
@@ -40,14 +40,16 @@
 
 constexpr auto getItemsQueryString { "SELECT key, value FROM ItemTable"_s };
 constexpr unsigned maximumSizeForValuesKeptInMemory { 1024 }; // 1 KB
+constexpr Seconds transactionDuration { 500_ms };
 
-Ref<LocalStorageDatabase> LocalStorageDatabase::create(String&& databasePath, unsigned quotaInBytes)
+Ref<LocalStorageDatabase> LocalStorageDatabase::create(Ref<WorkQueue>&& workQueue, String&& databasePath, unsigned quotaInBytes)
 {
-    return adoptRef(*new LocalStorageDatabase(WTFMove(databasePath), quotaInBytes));
+    return adoptRef(*new LocalStorageDatabase(WTFMove(workQueue), WTFMove(databasePath), quotaInBytes));
 }
 
-LocalStorageDatabase::LocalStorageDatabase(String&& databasePath, unsigned quotaInBytes)
-    : m_databasePath(WTFMove(databasePath))
+LocalStorageDatabase::LocalStorageDatabase(Ref<WorkQueue>&& workQueue, String&& databasePath, unsigned quotaInBytes)
+    : m_workQueue(WTFMove(workQueue))
+    , m_databasePath(WTFMove(databasePath))
     , m_quotaInBytes(quotaInBytes)
 {
     ASSERT(!RunLoop::isMain());
@@ -100,6 +102,21 @@
     return true;
 }
 
+void LocalStorageDatabase::startTransactionIfNecessary()
+{
+    if (!m_transaction)
+        m_transaction = makeUnique<SQLiteTransaction>(m_database);
+
+    if (m_transaction->inProgress())
+        return;
+
+    m_transaction->begin();
+    m_workQueue->dispatchAfter(transactionDuration, [weakThis = makeWeakPtr(*this)] {
+        if (weakThis)
+            weakThis->m_transaction->commit();
+    });
+}
+
 bool LocalStorageDatabase::migrateItemTableIfNeeded()
 {
     ASSERT(!RunLoop::isMain());
@@ -184,6 +201,7 @@
     if (!m_database.isOpen())
         return;
 
+    startTransactionIfNecessary();
     oldValue = item(key);
     if (oldValue.isNull())
         return;
@@ -248,6 +266,7 @@
     if (!m_database.isOpen())
         return;
 
+    startTransactionIfNecessary();
     oldValue = item(key);
 
     auto insertStatement = scopedStatement(m_insertStatement, "INSERT INTO ItemTable VALUES (?, ?)"_s);
@@ -280,6 +299,7 @@
     if (m_items && m_items->isEmpty())
         return false;
 
+    startTransactionIfNecessary();
     auto clearStatement = scopedStatement(m_clearStatement, "DELETE FROM ItemTable"_s);
     if (!clearStatement) {
         LOG_ERROR("Failed to prepare clear statement - cannot write to local storage database");
@@ -300,6 +320,12 @@
     return m_database.lastChanges() > 0;
 }
 
+void LocalStorageDatabase::flushToDisk()
+{
+    if (m_transaction)
+        m_transaction->commit();
+}
+
 void LocalStorageDatabase::close()
 {
     ASSERT(!RunLoop::isMain());
@@ -315,6 +341,8 @@
     m_getItemsStatement = nullptr;
     m_deleteItemStatement = nullptr;
     m_items = std::nullopt;
+    if (auto transaction = std::exchange(m_transaction, nullptr))
+        transaction->commit();
 
     if (m_database.isOpen())
         m_database.close();

Modified: trunk/Source/WebKit/NetworkProcess/WebStorage/LocalStorageDatabase.h (278785 => 278786)


--- trunk/Source/WebKit/NetworkProcess/WebStorage/LocalStorageDatabase.h	2021-06-11 22:37:40 UTC (rev 278785)
+++ trunk/Source/WebKit/NetworkProcess/WebStorage/LocalStorageDatabase.h	2021-06-11 22:56:18 UTC (rev 278786)
@@ -27,9 +27,12 @@
 
 #include <WebCore/SQLiteDatabase.h>
 #include <wtf/HashMap.h>
+#include <wtf/WeakPtr.h>
+#include <wtf/WorkQueue.h>
 
 namespace WebCore {
 class SQLiteStatementAutoResetScope;
+class SQLiteTransaction;
 
 struct SecurityOriginData;
 }
@@ -36,9 +39,9 @@
 
 namespace WebKit {
 
-class LocalStorageDatabase : public RefCounted<LocalStorageDatabase> {
+class LocalStorageDatabase : public RefCounted<LocalStorageDatabase>, public CanMakeWeakPtr<LocalStorageDatabase> {
 public:
-    static Ref<LocalStorageDatabase> create(String&& databasePath, unsigned quotaInBytes);
+    static Ref<LocalStorageDatabase> create(Ref<WorkQueue>&&, String&& databasePath, unsigned quotaInBytes);
     ~LocalStorageDatabase();
 
     HashMap<String, String> items() const;
@@ -51,14 +54,16 @@
     // Will block until all pending changes have been written to disk.
     void close();
 
+    void flushToDisk();
     void handleLowMemoryWarning();
 
 private:
-    LocalStorageDatabase(String&& databasePath, unsigned quotaInBytes);
+    LocalStorageDatabase(Ref<WorkQueue>&&, String&& databasePath, unsigned quotaInBytes);
 
     enum class ShouldCreateDatabase : bool { No, Yes };
     bool openDatabase(ShouldCreateDatabase);
 
+    void startTransactionIfNecessary();
     bool migrateItemTableIfNeeded();
     bool databaseIsEmpty() const;
 
@@ -66,8 +71,10 @@
 
     WebCore::SQLiteStatementAutoResetScope scopedStatement(std::unique_ptr<WebCore::SQLiteStatement>&, ASCIILiteral query) const;
 
+    Ref<WorkQueue> m_workQueue;
     String m_databasePath;
     mutable WebCore::SQLiteDatabase m_database;
+    std::unique_ptr<WebCore::SQLiteTransaction> m_transaction;
     const unsigned m_quotaInBytes { 0 };
     bool m_isClosed { false };
 

Modified: trunk/Source/WebKit/NetworkProcess/WebStorage/StorageArea.cpp (278785 => 278786)


--- trunk/Source/WebKit/NetworkProcess/WebStorage/StorageArea.cpp	2021-06-11 22:37:40 UTC (rev 278785)
+++ trunk/Source/WebKit/NetworkProcess/WebStorage/StorageArea.cpp	2021-06-11 22:56:18 UTC (rev 278786)
@@ -175,7 +175,7 @@
     // We open the database here even if we've already imported our items to ensure that the database is open if we need to write to it.
     if (!m_localStorageDatabase) {
         auto* localStorageDatabaseTracker = m_localStorageNamespace->storageManager()->localStorageDatabaseTracker();
-        m_localStorageDatabase = LocalStorageDatabase::create(localStorageDatabaseTracker->databasePath(m_securityOrigin), m_quotaInBytes);
+        m_localStorageDatabase = LocalStorageDatabase::create(m_queue.copyRef(), localStorageDatabaseTracker->databasePath(m_securityOrigin), m_quotaInBytes);
         m_localStorageDatabase->openIfExisting();
     }
     return *m_localStorageDatabase;
@@ -199,6 +199,12 @@
     m_localStorageDatabase->close();
 }
 
+void StorageArea::syncToDatabase()
+{
+    if (m_localStorageDatabase)
+        m_localStorageDatabase->flushToDisk();
+}
+
 void StorageArea::handleLowMemoryWarning()
 {
     if (m_localStorageDatabase)

Modified: trunk/Source/WebKit/NetworkProcess/WebStorage/StorageArea.h (278785 => 278786)


--- trunk/Source/WebKit/NetworkProcess/WebStorage/StorageArea.h	2021-06-11 22:37:40 UTC (rev 278785)
+++ trunk/Source/WebKit/NetworkProcess/WebStorage/StorageArea.h	2021-06-11 22:56:18 UTC (rev 278786)
@@ -71,6 +71,7 @@
 
     void close();
 
+    void syncToDatabase();
     void handleLowMemoryWarning();
 
 private:

Modified: trunk/Source/WebKit/NetworkProcess/WebStorage/StorageManagerSet.cpp (278785 => 278786)


--- trunk/Source/WebKit/NetworkProcess/WebStorage/StorageManagerSet.cpp	2021-06-11 22:37:40 UTC (rev 278785)
+++ trunk/Source/WebKit/NetworkProcess/WebStorage/StorageManagerSet.cpp	2021-06-11 22:56:18 UTC (rev 278786)
@@ -155,7 +155,16 @@
 {
     ASSERT(RunLoop::isMain());
 
-    m_queue->dispatchSync([] { });
+    BinarySemaphore semaphore;
+    m_queue->dispatch([this, &semaphore] {
+        for (const auto& storageArea : m_storageAreas.values()) {
+            ASSERT(storageArea);
+            if (storageArea)
+                storageArea->syncToDatabase();
+        }
+        semaphore.signal();
+    });
+    semaphore.wait();
 }
 
 void StorageManagerSet::suspend(CompletionHandler<void()>&& completionHandler)
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to