Title: [256621] trunk/Source/WebCore
Revision
256621
Author
sihui_...@apple.com
Date
2020-02-14 10:08:03 -0800 (Fri, 14 Feb 2020)

Log Message

IndexedDB: prefetch cursor records on client side
https://bugs.webkit.org/show_bug.cgi?id=207602
<rdar://problem/58483927>

Reviewed by Brady Eidson.

Cache cursor records on client side and use those records for iterate operations.

This makes cursor continue/advance tests in PerformanceTests/IndexedDB/basics ~3x faster.

* Headers.cmake:

* Modules/indexeddb/IDBCursor.cpp:
(WebCore::IDBCursor::setGetResult): Record the ID of TransactionOperation that updates cached record.
(WebCore::IDBCursor::iterateWithPrefetchedRecords): IDBCursor uses cached records for iterate opertaions if
there is no write operation between last cached records update and current iteration operation.
(WebCore::IDBCursor::clearPrefetchedRecords):
* Modules/indexeddb/IDBCursor.h:

* Modules/indexeddb/IDBGetResult.cpp:
(WebCore::IDBGetResult::isolatedCopy):
* Modules/indexeddb/IDBGetResult.h:
(WebCore::IDBGetResult::IDBGetResult):
(WebCore::IDBGetResult::prefetchedRecords const):
(WebCore::IDBGetResult::encode const):
(WebCore::IDBGetResult::decode):

* Modules/indexeddb/IDBRequest.cpp: Record corresponding TransactionOperation ID in request.
(WebCore::IDBRequest::didOpenOrIterateCursor):
* Modules/indexeddb/IDBRequest.h:
(WebCore::IDBRequest::pendingCursor const):
(WebCore::IDBRequest::setTransactionOperationID):

* Modules/indexeddb/IDBTransaction.cpp: If a cursor iterate request can be handled with cached records,
IDBClient does not need to send request to IDBServer and wait for response. But requests before that iterate
request may need to wait server to answer, and spec requires to handle requests in order. Therefore, we now keep
all the results in m_transactionOperationResultMap and handle them according to the ordering in
m_transactionOperationsInProgressQueue.
(WebCore::IDBTransaction::abortInProgressOperations):
(WebCore::IDBTransaction::removeRequest): Because result of a cursor request can be answered sooner, it is
possible that in finishedDispatchEventForRequest, m_currentlyCompletingRequest (which is a cursor request) is
set to nullptr, and then it is set back to the same cursor request in handleOperationsCompletedOnServer right
after. This happens in dispatchEvent of the cursor request, where request would remove itself from request list
of transaction at the end.
In this case, when request list becomes empty, transaction may commit automatically. But transaction should not
because that request is still valid as m_currentlyCompletingRequest and should not be removed from list.
(WebCore::IDBTransaction::scheduleOperation):
(WebCore::IDBTransaction::operationCompletedOnServer):
(WebCore::IDBTransaction::handleOperationsCompletedOnServer): All requests were sent to IDBServer and the
response/result ordering would naturally be the same as request order. Now that results can be created in both
IDBClient and IDBServer, we no longer handle requests using m_completedOnServerQueue.
(WebCore::IDBTransaction::createObjectStore): Mark as write operation to track last write operation.
(WebCore::IDBTransaction::renameObjectStore): Ditto.
(WebCore::IDBTransaction::createIndex): Ditto.
(WebCore::IDBTransaction::renameIndex): Ditto.
(WebCore::IDBTransaction::requestDeleteRecord): Ditto.
(WebCore::IDBTransaction::requestClearObjectStore): Ditto.
(WebCore::IDBTransaction::requestPutOrAdd): Ditto.
(WebCore::IDBTransaction::deleteObjectStore): Ditto.
(WebCore::IDBTransaction::deleteIndex): Ditto.
(WebCore::IDBTransaction::iterateCursorOnServer): Only use cached records if the request does not specify target
key. If cursor is iterated successfully with cache, send a message to IDBServer to notify about the progress.
Otherwise, fall back to depend on IDBServer to answer the request.
(WebCore::IDBTransaction::generateOperationID): TransactionOperation ID is unique in a transaction.
* Modules/indexeddb/IDBTransaction.h:

* Modules/indexeddb/IndexedDB.h:
* Modules/indexeddb/client/IDBConnectionProxy.cpp:
(WebCore::IDBClient::IDBConnectionProxy::iterateCursor): Don't track result of TransactionOperation in
IDBConnectionProxy if TransactionOperation does not need a reply from IDBServer.

* Modules/indexeddb/client/TransactionOperation.cpp:
(WebCore::IDBClient::TransactionOperation::TransactionOperation):
* Modules/indexeddb/client/TransactionOperation.h: Add ID to TransactionOperation.
(WebCore::IDBClient::TransactionOperation::operationID const):
(WebCore::IDBClient::TransactionOperation::TransactionOperation):

* Modules/indexeddb/server/IDBBackingStore.h: remove prefetchCursor as it is not used now.
* Modules/indexeddb/server/MemoryIDBBackingStore.h: Ditto. Also this patch only deals with prefetching in
persistent store.
* Modules/indexeddb/server/MemoryIDBBackingStore.h:
* Modules/indexeddb/server/SQLiteIDBBackingStore.cpp:
(WebCore::IDBServer::SQLiteIDBBackingStore::createIndex):
(WebCore::IDBServer::SQLiteIDBBackingStore::getAllIndexRecords):
(WebCore::IDBServer::SQLiteIDBBackingStore::getIndexRecord):
(WebCore::IDBServer::SQLiteIDBBackingStore::iterateCursor): Only prefetch at when request needs to be answered.
(WebCore::IDBServer::SQLiteIDBBackingStore::prefetchCursor): Deleted.
* Modules/indexeddb/server/SQLiteIDBBackingStore.h:

* Modules/indexeddb/server/SQLiteIDBCursor.cpp:
(WebCore::IDBServer::SQLiteIDBCursor::currentData): Provide an option to include prefetched records in result.
(WebCore::IDBServer::SQLiteIDBCursor::objectStoreRecordsChanged): Reset count to prefetch when there is a
change. This is used with increaseCountToPrefetch to make prefetch adaptive.
(WebCore::IDBServer::SQLiteIDBCursor::objectStoreRecordsChanged):
(WebCore::IDBServer::SQLiteIDBCursor::prefetchOneRecord):
(WebCore::IDBServer::SQLiteIDBCursor::increaseCountToPrefetch):
(WebCore::IDBServer::SQLiteIDBCursor::prefetch): Count to prefetch is decided by SQLiteCursor now.
(WebCore::IDBServer::SQLiteIDBCursor::internalFetchNextRecord):
(WebCore::IDBServer::SQLiteIDBCursor::currentValue const):
* Modules/indexeddb/server/SQLiteIDBCursor.h:

* Modules/indexeddb/server/UniqueIDBDatabase.cpp:
(WebCore::IDBServer::UniqueIDBDatabase::iterateCursor): Move call to prefetch cursor to SQLiteIDBBackingStore.
(WebCore::IDBServer::UniqueIDBDatabase::prefetchCursor): Deleted.
* Modules/indexeddb/server/UniqueIDBDatabase.h:
* Modules/indexeddb/server/UniqueIDBDatabaseTransaction.cpp:
(WebCore::IDBServer::UniqueIDBDatabaseTransaction::iterateCursor):

* Modules/indexeddb/shared/IDBCursorRecord.h: Stop using pointer for IDBValue for easier encoding and decoding.
(WebCore::IDBCursorRecord::size const):
(WebCore::IDBCursorRecord::isolatedCopy const):

* Modules/indexeddb/shared/IDBIterateCursorData.cpp:
(WebCore::IDBIterateCursorData::isolatedCopy const):
* Modules/indexeddb/shared/IDBIterateCursorData.h: Add an option to let IDBServer know whether it should answer
the cursor request.
(WebCore::IDBIterateCursorData::encode const):
(WebCore::IDBIterateCursorData::decode):

* WebCore.xcodeproj/project.pbxproj:

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (256620 => 256621)


--- trunk/Source/WebCore/ChangeLog	2020-02-14 18:05:04 UTC (rev 256620)
+++ trunk/Source/WebCore/ChangeLog	2020-02-14 18:08:03 UTC (rev 256621)
@@ -1,3 +1,126 @@
+2020-02-14  Sihui Liu  <sihui_...@apple.com>
+
+        IndexedDB: prefetch cursor records on client side
+        https://bugs.webkit.org/show_bug.cgi?id=207602
+        <rdar://problem/58483927>
+
+        Reviewed by Brady Eidson.
+
+        Cache cursor records on client side and use those records for iterate operations.
+
+        This makes cursor continue/advance tests in PerformanceTests/IndexedDB/basics ~3x faster.
+
+        * Headers.cmake:
+
+        * Modules/indexeddb/IDBCursor.cpp:
+        (WebCore::IDBCursor::setGetResult): Record the ID of TransactionOperation that updates cached record.
+        (WebCore::IDBCursor::iterateWithPrefetchedRecords): IDBCursor uses cached records for iterate opertaions if 
+        there is no write operation between last cached records update and current iteration operation.
+        (WebCore::IDBCursor::clearPrefetchedRecords):
+        * Modules/indexeddb/IDBCursor.h:
+
+        * Modules/indexeddb/IDBGetResult.cpp:
+        (WebCore::IDBGetResult::isolatedCopy):
+        * Modules/indexeddb/IDBGetResult.h:
+        (WebCore::IDBGetResult::IDBGetResult):
+        (WebCore::IDBGetResult::prefetchedRecords const):
+        (WebCore::IDBGetResult::encode const):
+        (WebCore::IDBGetResult::decode):
+
+        * Modules/indexeddb/IDBRequest.cpp: Record corresponding TransactionOperation ID in request.
+        (WebCore::IDBRequest::didOpenOrIterateCursor):
+        * Modules/indexeddb/IDBRequest.h:
+        (WebCore::IDBRequest::pendingCursor const):
+        (WebCore::IDBRequest::setTransactionOperationID):
+
+        * Modules/indexeddb/IDBTransaction.cpp: If a cursor iterate request can be handled with cached records,
+        IDBClient does not need to send request to IDBServer and wait for response. But requests before that iterate 
+        request may need to wait server to answer, and spec requires to handle requests in order. Therefore, we now keep
+        all the results in m_transactionOperationResultMap and handle them according to the ordering in 
+        m_transactionOperationsInProgressQueue.
+        (WebCore::IDBTransaction::abortInProgressOperations):
+        (WebCore::IDBTransaction::removeRequest): Because result of a cursor request can be answered sooner, it is 
+        possible that in finishedDispatchEventForRequest, m_currentlyCompletingRequest (which is a cursor request) is 
+        set to nullptr, and then it is set back to the same cursor request in handleOperationsCompletedOnServer right 
+        after. This happens in dispatchEvent of the cursor request, where request would remove itself from request list
+        of transaction at the end.
+        In this case, when request list becomes empty, transaction may commit automatically. But transaction should not 
+        because that request is still valid as m_currentlyCompletingRequest and should not be removed from list.
+        (WebCore::IDBTransaction::scheduleOperation):
+        (WebCore::IDBTransaction::operationCompletedOnServer):
+        (WebCore::IDBTransaction::handleOperationsCompletedOnServer): All requests were sent to IDBServer and the
+        response/result ordering would naturally be the same as request order. Now that results can be created in both 
+        IDBClient and IDBServer, we no longer handle requests using m_completedOnServerQueue.
+        (WebCore::IDBTransaction::createObjectStore): Mark as write operation to track last write operation.
+        (WebCore::IDBTransaction::renameObjectStore): Ditto.
+        (WebCore::IDBTransaction::createIndex): Ditto.
+        (WebCore::IDBTransaction::renameIndex): Ditto.
+        (WebCore::IDBTransaction::requestDeleteRecord): Ditto.
+        (WebCore::IDBTransaction::requestClearObjectStore): Ditto.
+        (WebCore::IDBTransaction::requestPutOrAdd): Ditto.
+        (WebCore::IDBTransaction::deleteObjectStore): Ditto.
+        (WebCore::IDBTransaction::deleteIndex): Ditto.
+        (WebCore::IDBTransaction::iterateCursorOnServer): Only use cached records if the request does not specify target
+        key. If cursor is iterated successfully with cache, send a message to IDBServer to notify about the progress.
+        Otherwise, fall back to depend on IDBServer to answer the request.
+        (WebCore::IDBTransaction::generateOperationID): TransactionOperation ID is unique in a transaction.
+        * Modules/indexeddb/IDBTransaction.h:
+
+        * Modules/indexeddb/IndexedDB.h:
+        * Modules/indexeddb/client/IDBConnectionProxy.cpp: 
+        (WebCore::IDBClient::IDBConnectionProxy::iterateCursor): Don't track result of TransactionOperation in 
+        IDBConnectionProxy if TransactionOperation does not need a reply from IDBServer.
+
+        * Modules/indexeddb/client/TransactionOperation.cpp:
+        (WebCore::IDBClient::TransactionOperation::TransactionOperation):
+        * Modules/indexeddb/client/TransactionOperation.h: Add ID to TransactionOperation.
+        (WebCore::IDBClient::TransactionOperation::operationID const):
+        (WebCore::IDBClient::TransactionOperation::TransactionOperation):
+
+        * Modules/indexeddb/server/IDBBackingStore.h: remove prefetchCursor as it is not used now.
+        * Modules/indexeddb/server/MemoryIDBBackingStore.h: Ditto. Also this patch only deals with prefetching in 
+        persistent store.
+        * Modules/indexeddb/server/MemoryIDBBackingStore.h:
+        * Modules/indexeddb/server/SQLiteIDBBackingStore.cpp:
+        (WebCore::IDBServer::SQLiteIDBBackingStore::createIndex):
+        (WebCore::IDBServer::SQLiteIDBBackingStore::getAllIndexRecords):
+        (WebCore::IDBServer::SQLiteIDBBackingStore::getIndexRecord):
+        (WebCore::IDBServer::SQLiteIDBBackingStore::iterateCursor): Only prefetch at when request needs to be answered.
+        (WebCore::IDBServer::SQLiteIDBBackingStore::prefetchCursor): Deleted.
+        * Modules/indexeddb/server/SQLiteIDBBackingStore.h:
+
+        * Modules/indexeddb/server/SQLiteIDBCursor.cpp:
+        (WebCore::IDBServer::SQLiteIDBCursor::currentData): Provide an option to include prefetched records in result.
+        (WebCore::IDBServer::SQLiteIDBCursor::objectStoreRecordsChanged): Reset count to prefetch when there is a 
+        change. This is used with increaseCountToPrefetch to make prefetch adaptive.
+        (WebCore::IDBServer::SQLiteIDBCursor::objectStoreRecordsChanged):
+        (WebCore::IDBServer::SQLiteIDBCursor::prefetchOneRecord):
+        (WebCore::IDBServer::SQLiteIDBCursor::increaseCountToPrefetch):
+        (WebCore::IDBServer::SQLiteIDBCursor::prefetch): Count to prefetch is decided by SQLiteCursor now.
+        (WebCore::IDBServer::SQLiteIDBCursor::internalFetchNextRecord):
+        (WebCore::IDBServer::SQLiteIDBCursor::currentValue const):
+        * Modules/indexeddb/server/SQLiteIDBCursor.h:
+
+        * Modules/indexeddb/server/UniqueIDBDatabase.cpp:
+        (WebCore::IDBServer::UniqueIDBDatabase::iterateCursor): Move call to prefetch cursor to SQLiteIDBBackingStore.
+        (WebCore::IDBServer::UniqueIDBDatabase::prefetchCursor): Deleted.
+        * Modules/indexeddb/server/UniqueIDBDatabase.h:
+        * Modules/indexeddb/server/UniqueIDBDatabaseTransaction.cpp:
+        (WebCore::IDBServer::UniqueIDBDatabaseTransaction::iterateCursor):
+
+        * Modules/indexeddb/shared/IDBCursorRecord.h: Stop using pointer for IDBValue for easier encoding and decoding.
+        (WebCore::IDBCursorRecord::size const):
+        (WebCore::IDBCursorRecord::isolatedCopy const):
+
+        * Modules/indexeddb/shared/IDBIterateCursorData.cpp:
+        (WebCore::IDBIterateCursorData::isolatedCopy const):
+        * Modules/indexeddb/shared/IDBIterateCursorData.h: Add an option to let IDBServer know whether it should answer
+        the cursor request. 
+        (WebCore::IDBIterateCursorData::encode const):
+        (WebCore::IDBIterateCursorData::decode):
+
+        * WebCore.xcodeproj/project.pbxproj:
+
 2020-02-14  Charles Turner  <ctur...@igalia.com>
 
         [GStreamer][EME] Fix warnings in LOG_DISABLED build

Modified: trunk/Source/WebCore/Headers.cmake (256620 => 256621)


--- trunk/Source/WebCore/Headers.cmake	2020-02-14 18:05:04 UTC (rev 256620)
+++ trunk/Source/WebCore/Headers.cmake	2020-02-14 18:08:03 UTC (rev 256621)
@@ -68,6 +68,7 @@
     Modules/indexeddb/server/UniqueIDBDatabaseTransaction.h
 
     Modules/indexeddb/shared/IDBCursorInfo.h
+    Modules/indexeddb/shared/IDBCursorRecord.h
     Modules/indexeddb/shared/IDBDatabaseInfo.h
     Modules/indexeddb/shared/IDBError.h
     Modules/indexeddb/shared/IDBGetAllRecordsData.h

Modified: trunk/Source/WebCore/Modules/indexeddb/IDBCursor.cpp (256620 => 256621)


--- trunk/Source/WebCore/Modules/indexeddb/IDBCursor.cpp	2020-02-14 18:05:04 UTC (rev 256620)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBCursor.cpp	2020-02-14 18:08:03 UTC (rev 256621)
@@ -312,7 +312,7 @@
     return request;
 }
 
-bool IDBCursor::setGetResult(IDBRequest& request, const IDBGetResult& getResult)
+bool IDBCursor::setGetResult(IDBRequest& request, const IDBGetResult& getResult, uint64_t operationID)
 {
     LOG(IndexedDB, "IDBCursor::setGetResult - current key %s", getResult.keyData().loggingString().substring(0, 100).utf8().data());
     ASSERT(canCurrentThreadAccessThreadLocalData(effectiveObjectStore().transaction().database().originThread()));
@@ -349,6 +349,13 @@
         m_keyPath = getResult.keyPath();
     }
 
+    auto prefetchedRecords = getResult.prefetchedRecords();
+    if (!prefetchedRecords.isEmpty()) {
+        for (auto& record : prefetchedRecords)
+            m_prefetchedRecords.append(record);
+        m_prefetchOperationID = operationID;
+    }
+
     m_gotValue = true;
     return true;
 }
@@ -360,6 +367,26 @@
     m_valueWrapper.clear();
 }
 
+Optional<IDBGetResult> IDBCursor::iterateWithPrefetchedRecords(unsigned count, uint64_t lastWriteOperationID)
+{
+    unsigned step = count > 0 ? count : 1;
+    if (step > m_prefetchedRecords.size() || m_prefetchOperationID <= lastWriteOperationID)
+        return WTF::nullopt;
+
+    while (--step)
+        m_prefetchedRecords.removeFirst();
+
+    auto record = m_prefetchedRecords.takeFirst();
+
+    LOG(IndexedDB, "IDBTransaction::iterateWithPrefetchedRecords consumes %u records", count > 0 ? count : 1);
+    return IDBGetResult(record.key, record.primaryKey, IDBValue(record.value), effectiveObjectStore().keyPath());
+}
+
+void IDBCursor::clearPrefetchedRecords()
+{
+    m_prefetchedRecords.clear();
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(INDEXED_DATABASE)

Modified: trunk/Source/WebCore/Modules/indexeddb/IDBCursor.h (256620 => 256621)


--- trunk/Source/WebCore/Modules/indexeddb/IDBCursor.h	2020-02-14 18:05:04 UTC (rev 256620)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBCursor.h	2020-02-14 18:08:03 UTC (rev 256621)
@@ -81,10 +81,13 @@
     void clearWrappers();
     IDBRequest* request() { return m_request.get(); }
 
-    bool setGetResult(IDBRequest&, const IDBGetResult&);
+    bool setGetResult(IDBRequest&, const IDBGetResult&, uint64_t operationID);
 
     virtual bool isKeyCursorWithValue() const { return false; }
 
+    Optional<IDBGetResult> iterateWithPrefetchedRecords(unsigned count, uint64_t lastWriteOperationID);
+    void clearPrefetchedRecords();
+
 protected:
     IDBCursor(IDBObjectStore&, const IDBCursorInfo&);
     IDBCursor(IDBIndex&, const IDBCursorInfo&);
@@ -113,6 +116,9 @@
     JSValueInWrappedObject m_keyWrapper;
     JSValueInWrappedObject m_primaryKeyWrapper;
     JSValueInWrappedObject m_valueWrapper;
+
+    Deque<IDBCursorRecord> m_prefetchedRecords;
+    uint64_t m_prefetchOperationID { 0 };
 };
 
 

Modified: trunk/Source/WebCore/Modules/indexeddb/IDBGetResult.cpp (256620 => 256621)


--- trunk/Source/WebCore/Modules/indexeddb/IDBGetResult.cpp	2020-02-14 18:05:04 UTC (rev 256620)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBGetResult.cpp	2020-02-14 18:08:03 UTC (rev 256621)
@@ -55,6 +55,7 @@
     destination.m_primaryKeyData = source.m_primaryKeyData.isolatedCopy();
     destination.m_keyPath = WebCore::isolatedCopy(source.m_keyPath);
     destination.m_isDefined = source.m_isDefined;
+    destination.m_prefetchedRecords = source.m_prefetchedRecords.isolatedCopy();
 }
 
 void IDBGetResult::setValue(IDBValue&& value)

Modified: trunk/Source/WebCore/Modules/indexeddb/IDBGetResult.h (256620 => 256621)


--- trunk/Source/WebCore/Modules/indexeddb/IDBGetResult.h	2020-02-14 18:05:04 UTC (rev 256620)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBGetResult.h	2020-02-14 18:08:03 UTC (rev 256621)
@@ -27,6 +27,7 @@
 
 #if ENABLE(INDEXED_DATABASE)
 
+#include "IDBCursorRecord.h"
 #include "IDBKey.h"
 #include "IDBKeyData.h"
 #include "IDBKeyPath.h"
@@ -76,6 +77,15 @@
     {
     }
 
+    IDBGetResult(const IDBKeyData& keyData, const IDBKeyData& primaryKeyData, IDBValue&& value, const Optional<IDBKeyPath>& keyPath, Vector<IDBCursorRecord>&& prefetechedRecords)
+        : m_value(WTFMove(value))
+        , m_keyData(keyData)
+        , m_primaryKeyData(primaryKeyData)
+        , m_keyPath(keyPath)
+        , m_prefetchedRecords(WTFMove(prefetechedRecords))
+    {
+    }
+
     enum IsolatedCopyTag { IsolatedCopy };
     IDBGetResult(const IDBGetResult&, IsolatedCopyTag);
 
@@ -87,6 +97,7 @@
     const IDBKeyData& keyData() const { return m_keyData; }
     const IDBKeyData& primaryKeyData() const { return m_primaryKeyData; }
     const Optional<IDBKeyPath>& keyPath() const { return m_keyPath; }
+    const Vector<IDBCursorRecord>& prefetchedRecords() const { return m_prefetchedRecords; }
     bool isDefined() const { return m_isDefined; }
 
     template<class Encoder> void encode(Encoder&) const;
@@ -101,6 +112,7 @@
     IDBKeyData m_keyData;
     IDBKeyData m_primaryKeyData;
     Optional<IDBKeyPath> m_keyPath;
+    Vector<IDBCursorRecord> m_prefetchedRecords;
     bool m_isDefined { true };
 };
 
@@ -107,7 +119,7 @@
 template<class Encoder>
 void IDBGetResult::encode(Encoder& encoder) const
 {
-    encoder << m_keyData << m_primaryKeyData << m_keyPath << m_isDefined << m_value;
+    encoder << m_keyData << m_primaryKeyData << m_keyPath << m_isDefined << m_value << m_prefetchedRecords;
 }
 
 template<class Decoder>
@@ -137,6 +149,12 @@
         return false;
     result.m_value = WTFMove(*value);
 
+    Optional<Vector<IDBCursorRecord>> prefetchedRecords;
+    decoder >> prefetchedRecords;
+    if (!prefetchedRecords)
+        return false;
+    result.m_prefetchedRecords = WTFMove(*prefetchedRecords);
+
     return true;
 }
 

Modified: trunk/Source/WebCore/Modules/indexeddb/IDBRequest.cpp (256620 => 256621)


--- trunk/Source/WebCore/Modules/indexeddb/IDBRequest.cpp	2020-02-14 18:05:04 UTC (rev 256620)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBRequest.cpp	2020-02-14 18:08:03 UTC (rev 256621)
@@ -499,7 +499,7 @@
     m_resultWrapper = { };
 
     if (resultData.type() == IDBResultType::IterateCursorSuccess || resultData.type() == IDBResultType::OpenCursorSuccess) {
-        if (m_pendingCursor->setGetResult(*this, resultData.getResult()) && m_cursorWrapper)
+        if (m_pendingCursor->setGetResult(*this, resultData.getResult(), m_currentTransactionOperationID) && m_cursorWrapper)
             m_resultWrapper = m_cursorWrapper;
         if (resultData.getResult().isDefined())
             m_result = m_pendingCursor;

Modified: trunk/Source/WebCore/Modules/indexeddb/IDBRequest.h (256620 => 256621)


--- trunk/Source/WebCore/Modules/indexeddb/IDBRequest.h	2020-02-14 18:05:04 UTC (rev 256620)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBRequest.h	2020-02-14 18:08:03 UTC (rev 256621)
@@ -118,7 +118,7 @@
     void willIterateCursor(IDBCursor&);
     void didOpenOrIterateCursor(const IDBResultData&);
 
-    const IDBCursor* pendingCursor() const { return m_pendingCursor.get(); }
+    IDBCursor* pendingCursor() const { return m_pendingCursor ? m_pendingCursor.get() : nullptr; }
 
     void setSource(IDBCursor&);
     void setVersionChangeTransaction(IDBTransaction&);
@@ -127,6 +127,8 @@
 
     bool hasPendingActivity() const final;
 
+    void setTransactionOperationID(uint64_t transactionOperationID) { m_currentTransactionOperationID = transactionOperationID; }
+
 protected:
     IDBRequest(ScriptExecutionContext&, IDBClient::IDBConnectionProxy&);
 
@@ -191,6 +193,8 @@
 
     bool m_dispatchingEvent { false };
     bool m_hasUncaughtException { false };
+
+    uint64_t m_currentTransactionOperationID { 0 };
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.cpp (256620 => 256621)


--- trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.cpp	2020-02-14 18:05:04 UTC (rev 256620)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.cpp	2020-02-14 18:08:03 UTC (rev 256621)
@@ -272,16 +272,8 @@
         operation->doComplete(IDBResultData::error(operation->identifier(), error));
     }
 
-    Vector<RefPtr<IDBClient::TransactionOperation>> completedOnServerAbortVector;
-    completedOnServerAbortVector.reserveInitialCapacity(m_completedOnServerQueue.size());
-    while (!m_completedOnServerQueue.isEmpty())
-        completedOnServerAbortVector.uncheckedAppend(m_completedOnServerQueue.takeFirst().first);
+    m_transactionOperationResultMap.clear();
 
-    for (auto& operation : completedOnServerAbortVector) {
-        m_currentlyCompletingRequest = nullptr;
-        operation->doComplete(IDBResultData::error(operation->identifier(), error));
-    }
-
     m_currentlyCompletingRequest = nullptr;
     connectionProxy().forgetActiveOperations(inProgressAbortVector);
 }
@@ -376,16 +368,22 @@
 void IDBTransaction::removeRequest(IDBRequest& request)
 {
     ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));
+    if (m_currentlyCompletingRequest == &request)
+        return;
+
     m_openRequests.remove(&request);
 
     autoCommit();
 }
 
-void IDBTransaction::scheduleOperation(Ref<IDBClient::TransactionOperation>&& operation)
+void IDBTransaction::scheduleOperation(Ref<IDBClient::TransactionOperation>&& operation, IsWriteOperation isWriteOperation)
 {
     ASSERT(!m_transactionOperationMap.contains(operation->identifier()));
     ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));
 
+    if (isWriteOperation == IsWriteOperation::Yes)
+        m_lastWriteOperationID = operation->operationID();
+
     auto identifier = operation->identifier();
     m_pendingTransactionOperationQueue.append(operation.copyRef());
     m_transactionOperationMap.set(identifier, WTFMove(operation));
@@ -398,8 +396,11 @@
     ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));
     ASSERT(canCurrentThreadAccessThreadLocalData(operation.originThread()));
 
-    m_completedOnServerQueue.append({ &operation, data });
+    if (!m_transactionOperationMap.contains(operation.identifier()))
+        return;
 
+    m_transactionOperationResultMap.set(&operation, IDBResultData(data));
+
     if (!m_currentlyCompletingRequest)
         handleOperationsCompletedOnServer();
 }
@@ -406,12 +407,15 @@
 
 void IDBTransaction::handleOperationsCompletedOnServer()
 {
-    LOG(IndexedDB, "IDBTransaction::completedOperationTimerFired (%p)", this);
+    LOG(IndexedDB, "IDBTransaction::handleOperationsCompletedOnServer");
     ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));
 
-    while (!m_completedOnServerQueue.isEmpty() && !m_currentlyCompletingRequest) {
-        auto iterator = m_completedOnServerQueue.takeFirst();
-        iterator.first->doComplete(iterator.second);
+    while (!m_transactionOperationsInProgressQueue.isEmpty() && !m_currentlyCompletingRequest) {
+        RefPtr<IDBClient::TransactionOperation> currentOperation = m_transactionOperationsInProgressQueue.first();
+        if (!m_transactionOperationResultMap.contains(currentOperation))
+            return;
+
+        currentOperation->doComplete(m_transactionOperationResultMap.take(currentOperation));
     }
 }
 
@@ -622,7 +626,7 @@
         protectedThis->didCreateObjectStoreOnServer(result);
     }, [protectedThis = makeRef(*this), info = info.isolatedCopy()] (auto& operation) {
         protectedThis->createObjectStoreOnServer(operation, info);
-    }));
+    }), IsWriteOperation::Yes);
 
     return *rawObjectStore;
 }
@@ -664,7 +668,7 @@
         protectedThis->didRenameObjectStoreOnServer(result);
     }, [protectedThis = makeRef(*this), objectStoreIdentifier, newName = newName.isolatedCopy()] (auto& operation) {
         protectedThis->renameObjectStoreOnServer(operation, objectStoreIdentifier, newName);
-    }));
+    }), IsWriteOperation::Yes);
 
     m_referencedObjectStores.set(newName, m_referencedObjectStores.take(objectStore.info().name()));
 }
@@ -699,7 +703,7 @@
         protectedThis->didCreateIndexOnServer(result);
     }, [protectedThis = makeRef(*this), info = info.isolatedCopy()] (auto& operation) {
         protectedThis->createIndexOnServer(operation, info);
-    }));
+    }), IsWriteOperation::Yes);
 
     return makeUnique<IDBIndex>(*scriptExecutionContext(), info, objectStore);
 }
@@ -753,7 +757,7 @@
         protectedThis->didRenameIndexOnServer(result);
     }, [protectedThis = makeRef(*this), objectStoreIdentifier, indexIdentifier, newName = newName.isolatedCopy()] (auto& operation) {
         protectedThis->renameIndexOnServer(operation, objectStoreIdentifier, indexIdentifier, newName);
-    }));
+    }), IsWriteOperation::Yes);
 }
 
 void IDBTransaction::renameIndexOnServer(IDBClient::TransactionOperation& operation, const uint64_t& objectStoreIdentifier, const uint64_t& indexIdentifier, const String& newName)
@@ -852,7 +856,23 @@
 {
     LOG(IndexedDB, "IDBTransaction::iterateCursorOnServer");
     ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));
+    ASSERT(operation.idbRequest());
 
+    auto* cursor = operation.idbRequest()->pendingCursor();
+    ASSERT(cursor);
+
+    if (data.keyData.isNull() && data.primaryKeyData.isNull()) {
+        if (auto getResult = cursor->iterateWithPrefetchedRecords(data.count, m_lastWriteOperationID)) {
+            auto result = IDBResultData::iterateCursorSuccess(operation.identifier(), getResult.value());
+            m_database->connectionProxy().iterateCursor(operation, { data.keyData, data.primaryKeyData, data.count, IndexedDB::CursorIterateOption::DoNotReply });
+            operationCompletedOnServer(result, operation);
+            return;
+        }
+    }
+
+    cursor->clearPrefetchedRecords();
+
+    ASSERT(data.option == IndexedDB::CursorIterateOption::Reply);
     m_database->connectionProxy().iterateCursor(operation, data);
 }
 
@@ -1126,7 +1146,7 @@
         protectedThis->didDeleteRecordOnServer(request.get(), result);
     }, [protectedThis = makeRef(*this), range = range.isolatedCopy()] (auto& operation) {
         protectedThis->deleteRecordOnServer(operation, range);
-    }));
+    }), IsWriteOperation::Yes);
     return request;
 }
 
@@ -1165,7 +1185,7 @@
         protectedThis->didClearObjectStoreOnServer(request.get(), result);
     }, [protectedThis = makeRef(*this), objectStoreIdentifier] (auto& operation) {
         protectedThis->clearObjectStoreOnServer(operation, objectStoreIdentifier);
-    }));
+    }), IsWriteOperation::Yes);
 
     return request;
 }
@@ -1205,7 +1225,7 @@
         protectedThis->didPutOrAddOnServer(request.get(), result);
     }, [protectedThis = makeRef(*this), key, value = makeRef(value), overwriteMode] (auto& operation) {
         protectedThis->putOrAddOnServer(operation, key.get(), value.ptr(), overwriteMode);
-    }));
+    }), IsWriteOperation::Yes);
 
     return request;
 }
@@ -1293,7 +1313,7 @@
         protectedThis->didDeleteObjectStoreOnServer(result);
     }, [protectedThis = makeRef(*this), objectStoreName = objectStoreName.isolatedCopy()] (auto& operation) {
         protectedThis->deleteObjectStoreOnServer(operation, objectStoreName);
-    }));
+    }), IsWriteOperation::Yes);
 }
 
 void IDBTransaction::deleteObjectStoreOnServer(IDBClient::TransactionOperation& operation, const String& objectStoreName)
@@ -1323,7 +1343,7 @@
         protectedThis->didDeleteIndexOnServer(result);
     }, [protectedThis = makeRef(*this), objectStoreIdentifier, indexName = indexName.isolatedCopy()] (auto& operation) {
         protectedThis->deleteIndexOnServer(operation, objectStoreIdentifier, indexName);
-    }));
+    }), IsWriteOperation::Yes);
 }
 
 void IDBTransaction::deleteIndexOnServer(IDBClient::TransactionOperation& operation, const uint64_t& objectStoreIdentifier, const String& indexName)
@@ -1474,6 +1494,12 @@
     commit();
 }
 
+uint64_t IDBTransaction::generateOperationID()
+{
+    static std::atomic<uint64_t> currentOperationID(1);
+    return currentOperationID += 1;
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(INDEXED_DATABASE)

Modified: trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.h (256620 => 256621)


--- trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.h	2020-02-14 18:05:04 UTC (rev 256620)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.h	2020-02-14 18:08:03 UTC (rev 256621)
@@ -71,6 +71,8 @@
     static Ref<IDBTransaction> create(IDBDatabase&, const IDBTransactionInfo&);
     static Ref<IDBTransaction> create(IDBDatabase&, const IDBTransactionInfo&, IDBOpenDBRequest&);
 
+    static uint64_t generateOperationID();
+
     WEBCORE_EXPORT ~IDBTransaction() final;
 
     // IDBTransaction IDL
@@ -165,7 +167,8 @@
     void finishAbortOrCommit();
     void abortInProgressOperations(const IDBError&);
 
-    void scheduleOperation(Ref<IDBClient::TransactionOperation>&&);
+    enum class IsWriteOperation : bool { No, Yes };
+    void scheduleOperation(Ref<IDBClient::TransactionOperation>&&, IsWriteOperation = IsWriteOperation::No);
     void handleOperationsCompletedOnServer();
     void handlePendingOperations();
     void autoCommit();
@@ -244,8 +247,8 @@
 
     Deque<RefPtr<IDBClient::TransactionOperation>> m_pendingTransactionOperationQueue;
     Deque<IDBClient::TransactionOperation*> m_transactionOperationsInProgressQueue;
-    Deque<std::pair<RefPtr<IDBClient::TransactionOperation>, IDBResultData>> m_completedOnServerQueue;
     Deque<RefPtr<IDBClient::TransactionOperation>> m_abortQueue;
+    HashMap<RefPtr<IDBClient::TransactionOperation>, IDBResultData> m_transactionOperationResultMap;
 
     HashMap<IDBResourceIdentifier, RefPtr<IDBClient::TransactionOperation>> m_transactionOperationMap;
 
@@ -258,6 +261,8 @@
 
     bool m_contextStopped { false };
     bool m_didDispatchAbortOrCommit { false };
+
+    uint64_t m_lastWriteOperationID { 0 };
 };
 
 class TransactionActivator {

Modified: trunk/Source/WebCore/Modules/indexeddb/IndexedDB.h (256620 => 256621)


--- trunk/Source/WebCore/Modules/indexeddb/IndexedDB.h	2020-02-14 18:05:04 UTC (rev 256620)
+++ trunk/Source/WebCore/Modules/indexeddb/IndexedDB.h	2020-02-14 18:08:03 UTC (rev 256621)
@@ -106,6 +106,11 @@
 
 enum class ConnectionClosedOnBehalfOfServer : bool { No, Yes };
 
+enum class CursorIterateOption {
+    DoNotReply,
+    Reply,
+};
+
 } // namespace IndexedDB
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/Modules/indexeddb/client/IDBConnectionProxy.cpp (256620 => 256621)


--- trunk/Source/WebCore/Modules/indexeddb/client/IDBConnectionProxy.cpp	2020-02-14 18:05:04 UTC (rev 256620)
+++ trunk/Source/WebCore/Modules/indexeddb/client/IDBConnectionProxy.cpp	2020-02-14 18:08:03 UTC (rev 256621)
@@ -238,7 +238,8 @@
 void IDBConnectionProxy::iterateCursor(TransactionOperation& operation, const IDBIterateCursorData& data)
 {
     const IDBRequestData requestData { operation };
-    saveOperation(operation);
+    if (data.option != IndexedDB::CursorIterateOption::DoNotReply)
+        saveOperation(operation);
 
     callConnectionOnMainThread(&IDBConnectionToServer::iterateCursor, requestData, data);
 }

Modified: trunk/Source/WebCore/Modules/indexeddb/client/TransactionOperation.cpp (256620 => 256621)


--- trunk/Source/WebCore/Modules/indexeddb/client/TransactionOperation.cpp	2020-02-14 18:05:04 UTC (rev 256620)
+++ trunk/Source/WebCore/Modules/indexeddb/client/TransactionOperation.cpp	2020-02-14 18:08:03 UTC (rev 256621)
@@ -44,6 +44,7 @@
     if (auto* cursor = request.pendingCursor())
         m_cursorIdentifier = makeUnique<IDBResourceIdentifier>(cursor->info().identifier());
 
+    request.setTransactionOperationID(m_operationID);
     m_idbRequest = &request;
 }
 

Modified: trunk/Source/WebCore/Modules/indexeddb/client/TransactionOperation.h (256620 => 256621)


--- trunk/Source/WebCore/Modules/indexeddb/client/TransactionOperation.h	2020-02-14 18:05:04 UTC (rev 256620)
+++ trunk/Source/WebCore/Modules/indexeddb/client/TransactionOperation.h	2020-02-14 18:08:03 UTC (rev 256621)
@@ -112,10 +112,13 @@
     bool nextRequestCanGoToServer() const { return m_nextRequestCanGoToServer && m_idbRequest; }
     void setNextRequestCanGoToServer(bool nextRequestCanGoToServer) { m_nextRequestCanGoToServer = nextRequestCanGoToServer; }
 
+    uint64_t operationID() const { return m_operationID; }
+
 protected:
     TransactionOperation(IDBTransaction& transaction)
         : m_transaction(transaction)
         , m_identifier(transaction.connectionProxy())
+        , m_operationID(transaction.generateOperationID())
     {
     }
 
@@ -142,6 +145,8 @@
     RefPtr<IDBRequest> m_idbRequest;
     bool m_nextRequestCanGoToServer { true };
     bool m_didComplete { false };
+
+    uint64_t m_operationID { 0 };
 };
 
 class TransactionOperationImpl final : public TransactionOperation {

Modified: trunk/Source/WebCore/Modules/indexeddb/server/IDBBackingStore.h (256620 => 256621)


--- trunk/Source/WebCore/Modules/indexeddb/server/IDBBackingStore.h	2020-02-14 18:05:04 UTC (rev 256620)
+++ trunk/Source/WebCore/Modules/indexeddb/server/IDBBackingStore.h	2020-02-14 18:08:03 UTC (rev 256621)
@@ -85,7 +85,6 @@
     virtual IDBError maybeUpdateKeyGeneratorNumber(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, double newKeyNumber) = 0;
     virtual IDBError openCursor(const IDBResourceIdentifier& transactionIdentifier, const IDBCursorInfo&, IDBGetResult& outResult) = 0;
     virtual IDBError iterateCursor(const IDBResourceIdentifier& transactionIdentifier, const IDBResourceIdentifier& cursorIdentifier, const IDBIterateCursorData&, IDBGetResult& outResult) = 0;
-    virtual bool prefetchCursor(const IDBResourceIdentifier& transactionIdentifier, const IDBResourceIdentifier& cursorIdentifier) = 0;
 
     virtual IDBObjectStoreInfo* infoForObjectStore(uint64_t objectStoreIdentifier) = 0;
     virtual void deleteBackingStore() = 0;

Modified: trunk/Source/WebCore/Modules/indexeddb/server/MemoryIDBBackingStore.h (256620 => 256621)


--- trunk/Source/WebCore/Modules/indexeddb/server/MemoryIDBBackingStore.h	2020-02-14 18:05:04 UTC (rev 256620)
+++ trunk/Source/WebCore/Modules/indexeddb/server/MemoryIDBBackingStore.h	2020-02-14 18:08:03 UTC (rev 256621)
@@ -74,7 +74,6 @@
     IDBError maybeUpdateKeyGeneratorNumber(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, double newKeyNumber) final;
     IDBError openCursor(const IDBResourceIdentifier& transactionIdentifier, const IDBCursorInfo&, IDBGetResult& outResult) final;
     IDBError iterateCursor(const IDBResourceIdentifier& transactionIdentifier, const IDBResourceIdentifier& cursorIdentifier, const IDBIterateCursorData&, IDBGetResult& outResult) final;
-    bool prefetchCursor(const IDBResourceIdentifier&, const IDBResourceIdentifier&) final { return false; }
 
     IDBObjectStoreInfo* infoForObjectStore(uint64_t objectStoreIdentifier) final;
     void deleteBackingStore() final;

Modified: trunk/Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.cpp (256620 => 256621)


--- trunk/Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.cpp	2020-02-14 18:05:04 UTC (rev 256620)
+++ trunk/Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.cpp	2020-02-14 18:08:03 UTC (rev 256621)
@@ -1366,8 +1366,8 @@
 
     while (!cursor->currentKey().isNull()) {
         auto& key = cursor->currentKey();
-        auto* value = cursor->currentValue();
-        ThreadSafeDataBuffer valueBuffer = value ? value->data() : ThreadSafeDataBuffer();
+        auto value = cursor->currentValue();
+        ThreadSafeDataBuffer valueBuffer = value.data();
 
         ASSERT(cursor->currentRecordRowID());
 
@@ -2354,7 +2354,7 @@
         IDBKeyData keyCopy = cursor->currentPrimaryKey();
         result.addKey(WTFMove(keyCopy));
         if (getAllRecordsData.getAllType == IndexedDB::GetAllType::Values)
-            result.addValue(cursor->currentValue() ? *cursor->currentValue() : IDBValue());
+            result.addValue(IDBValue(cursor->currentValue()));
 
         ++currentCount;
         cursor->advance(1);
@@ -2401,7 +2401,7 @@
         else {
             auto* objectStoreInfo = infoForObjectStore(objectStoreID);
             ASSERT(objectStoreInfo);
-            getResult = { cursor->currentPrimaryKey(), cursor->currentPrimaryKey(), cursor->currentValue() ? *cursor->currentValue() : IDBValue(), objectStoreInfo->keyPath() };
+            getResult = { cursor->currentPrimaryKey(), cursor->currentPrimaryKey(), IDBValue(cursor->currentValue()), objectStoreInfo->keyPath() };
         }
     }
 
@@ -2721,26 +2721,18 @@
         }
     }
 
-    auto* objectStoreInfo = infoForObjectStore(cursor->objectStoreID());
-    ASSERT(objectStoreInfo);
-    cursor->currentData(result, objectStoreInfo->keyPath());
-    return IDBError { };
-}
+    if (data.option == IndexedDB::CursorIterateOption::Reply) {
+        auto* objectStoreInfo = infoForObjectStore(cursor->objectStoreID());
+        ASSERT(objectStoreInfo);
 
-bool SQLiteIDBBackingStore::prefetchCursor(const IDBResourceIdentifier& transactionIdentifier, const IDBResourceIdentifier& cursorIdentifier)
-{
-    LOG(IndexedDB, "SQLiteIDBBackingStore::prefetchCursor");
+        bool shouldPrefetch = key.isNull() && primaryKey.isNull();
+        if (shouldPrefetch)
+            cursor->prefetch();
 
-    ASSERT(m_sqliteDB);
-    ASSERT(m_sqliteDB->isOpen());
+        cursor->currentData(result, objectStoreInfo->keyPath(), shouldPrefetch ? SQLiteIDBCursor::ShouldIncludePrefetchedRecords::Yes : SQLiteIDBCursor::ShouldIncludePrefetchedRecords::No);
+    }
 
-    auto* cursor = m_cursors.get(cursorIdentifier);
-    if (!cursor || !cursor->transaction() || !cursor->transaction()->inProgress())
-        return false;
-
-    ASSERT_UNUSED(transactionIdentifier, cursor->transaction()->transactionIdentifier() == transactionIdentifier);
-
-    return cursor->prefetch();
+    return IDBError { };
 }
 
 IDBObjectStoreInfo* SQLiteIDBBackingStore::infoForObjectStore(uint64_t objectStoreIdentifier)

Modified: trunk/Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.h (256620 => 256621)


--- trunk/Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.h	2020-02-14 18:05:04 UTC (rev 256620)
+++ trunk/Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.h	2020-02-14 18:08:03 UTC (rev 256621)
@@ -80,7 +80,6 @@
     IDBError maybeUpdateKeyGeneratorNumber(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, double newKeyNumber) final;
     IDBError openCursor(const IDBResourceIdentifier& transactionIdentifier, const IDBCursorInfo&, IDBGetResult& outResult) final;
     IDBError iterateCursor(const IDBResourceIdentifier& transactionIdentifier, const IDBResourceIdentifier& cursorIdentifier, const IDBIterateCursorData&, IDBGetResult& outResult) final;
-    bool prefetchCursor(const IDBResourceIdentifier&, const IDBResourceIdentifier&) final;
 
     IDBObjectStoreInfo* infoForObjectStore(uint64_t objectStoreIdentifier) final;
     void deleteBackingStore() final;

Modified: trunk/Source/WebCore/Modules/indexeddb/server/SQLiteIDBCursor.cpp (256620 => 256621)


--- trunk/Source/WebCore/Modules/indexeddb/server/SQLiteIDBCursor.cpp	2020-02-14 18:05:04 UTC (rev 256620)
+++ trunk/Source/WebCore/Modules/indexeddb/server/SQLiteIDBCursor.cpp	2020-02-14 18:08:03 UTC (rev 256621)
@@ -42,8 +42,8 @@
 namespace WebCore {
 namespace IDBServer {
 
-static const size_t prefetchLimit = 128;
-static const size_t prefetchSizeLimit = 8 * MB;
+static const size_t prefetchLimit = 256;
+static const size_t prefetchSizeLimit = 1 * MB;
 
 std::unique_ptr<SQLiteIDBCursor> SQLiteIDBCursor::maybeCreate(SQLiteIDBTransaction& transaction, const IDBCursorInfo& info)
 {
@@ -102,7 +102,7 @@
         m_transaction->closeCursor(*this);
 }
 
-void SQLiteIDBCursor::currentData(IDBGetResult& result, const Optional<IDBKeyPath>& keyPath)
+void SQLiteIDBCursor::currentData(IDBGetResult& result, const Optional<IDBKeyPath>& keyPath, ShouldIncludePrefetchedRecords shouldIncludePrefetchedRecords)
 {
     ASSERT(!m_fetchedRecords.isEmpty());
 
@@ -113,7 +113,25 @@
         return;
     }
 
-    result = { currentRecord.record.key, currentRecord.record.primaryKey, currentRecord.record.value ? *currentRecord.record.value : IDBValue(), keyPath};
+    if (shouldIncludePrefetchedRecords == ShouldIncludePrefetchedRecords::No) {
+        result = { currentRecord.record.key, currentRecord.record.primaryKey, IDBValue(currentRecord.record.value), keyPath };
+        return;
+    }
+
+    Vector<IDBCursorRecord> prefetchedRecords;
+    prefetchedRecords.reserveCapacity(m_fetchedRecords.size());
+    for (auto& record : m_fetchedRecords) {
+        if (record.isTerminalRecord())
+            break;
+
+        prefetchedRecords.append(record.record);
+    }
+
+    // First record will be returned as current record.
+    if (!prefetchedRecords.isEmpty())
+        prefetchedRecords.remove(0);
+
+    result = { currentRecord.record.key, currentRecord.record.primaryKey, IDBValue(currentRecord.record.value), keyPath, WTFMove(prefetchedRecords) };
 }
 
 static String buildPreIndexStatement(bool isDirectionNext)
@@ -263,6 +281,8 @@
     // We also need to throw away any fetched records as they may no longer be valid.
     m_fetchedRecords.clear();
     m_fetchedRecordsSize = 0;
+
+    m_prefetchCount = 0;
 }
 
 void SQLiteIDBCursor::resetAndRebindStatement()
@@ -359,19 +379,34 @@
     return true;
 }
 
-bool SQLiteIDBCursor::prefetch()
+bool SQLiteIDBCursor::prefetchOneRecord()
 {
-    LOG(IndexedDB, "SQLiteIDBCursor::prefetch() - Cursor already has %zu fetched records", m_fetchedRecords.size());
+    LOG(IndexedDB, "SQLiteIDBCursor::prefetchOneRecord() - Cursor already has %zu fetched records", m_fetchedRecords.size());
 
     if (m_fetchedRecordsSize >= prefetchSizeLimit || m_fetchedRecords.isEmpty() || m_fetchedRecords.size() >= prefetchLimit || m_fetchedRecords.last().isTerminalRecord())
         return false;
 
     m_currentKeyForUniqueness = m_fetchedRecords.last().record.key;
-    fetch();
 
-    return m_fetchedRecords.size() < prefetchLimit && m_fetchedRecordsSize < prefetchSizeLimit;
+    return fetch() && m_fetchedRecords.size() < prefetchLimit && m_fetchedRecordsSize < prefetchSizeLimit;
 }
 
+void SQLiteIDBCursor::increaseCountToPrefetch()
+{
+    m_prefetchCount = m_prefetchCount ? m_prefetchCount * 2 : 1;
+}
+
+bool SQLiteIDBCursor::prefetch()
+{
+    for (unsigned i = 0; i < m_prefetchCount; ++i) {
+        if (!prefetchOneRecord())
+            return false;
+    }
+
+    increaseCountToPrefetch();
+    return true;
+}
+
 bool SQLiteIDBCursor::advance(uint64_t count)
 {
     LOG(IndexedDB, "SQLiteIDBCursor::advance() - Count %" PRIu64 ", %zu fetched records", count, m_fetchedRecords.size());
@@ -488,7 +523,7 @@
     ASSERT(!m_fetchedRecords.isEmpty());
     ASSERT(!m_fetchedRecords.last().isTerminalRecord());
 
-    record.record.value = nullptr;
+    record.record.value = { };
 
     auto& database = m_transaction->sqliteTransaction()->database();
     SQLiteStatement* statement = nullptr;
@@ -546,7 +581,7 @@
         }
 
         if (m_cursorType == IndexedDB::CursorType::KeyAndValue)
-            record.record.value = makeUnique<IDBValue>(ThreadSafeDataBuffer::create(WTFMove(keyData)), blobURLs, blobFilePaths);
+            record.record.value = { ThreadSafeDataBuffer::create(WTFMove(keyData)), blobURLs, blobFilePaths };
     } else {
         if (!deserializeIDBKeyData(keyData.data(), keyData.size(), record.record.primaryKey)) {
             LOG_ERROR("Unable to deserialize value data from database while advancing index cursor");
@@ -572,7 +607,7 @@
 
         if (result == SQLITE_ROW) {
             m_cachedObjectStoreStatement->getColumnBlobAsVector(0, keyData);
-            record.record.value = makeUnique<IDBValue>(ThreadSafeDataBuffer::create(WTFMove(keyData)));
+            record.record.value = { ThreadSafeDataBuffer::create(WTFMove(keyData)) };
         } else if (result == SQLITE_DONE) {
             // This indicates that the record we're trying to retrieve has been removed from the object store.
             // Skip over it.
@@ -645,10 +680,10 @@
     return m_fetchedRecords.first().record.primaryKey;
 }
 
-IDBValue* SQLiteIDBCursor::currentValue() const
+const IDBValue& SQLiteIDBCursor::currentValue() const
 {
     ASSERT(!m_fetchedRecords.isEmpty());
-    return m_fetchedRecords.first().record.value.get();
+    return m_fetchedRecords.first().record.value;
 }
 
 bool SQLiteIDBCursor::didComplete() const

Modified: trunk/Source/WebCore/Modules/indexeddb/server/SQLiteIDBCursor.h (256620 => 256621)


--- trunk/Source/WebCore/Modules/indexeddb/server/SQLiteIDBCursor.h	2020-02-14 18:05:04 UTC (rev 256620)
+++ trunk/Source/WebCore/Modules/indexeddb/server/SQLiteIDBCursor.h	2020-02-14 18:08:03 UTC (rev 256621)
@@ -66,10 +66,11 @@
 
     const IDBKeyData& currentKey() const;
     const IDBKeyData& currentPrimaryKey() const;
-    IDBValue* currentValue() const;
+    const IDBValue& currentValue() const;
 
     bool advance(uint64_t count);
     bool iterate(const IDBKeyData& targetKey, const IDBKeyData& targetPrimaryKey);
+    bool prefetchOneRecord();
     bool prefetch();
 
     bool didComplete() const;
@@ -77,7 +78,8 @@
 
     void objectStoreRecordsChanged();
 
-    void currentData(IDBGetResult&, const Optional<IDBKeyPath>&);
+    enum class ShouldIncludePrefetchedRecords { No, Yes };
+    void currentData(IDBGetResult&, const Optional<IDBKeyPath>&, ShouldIncludePrefetchedRecords = ShouldIncludePrefetchedRecords::No);
 
 private:
     bool establishStatement();
@@ -109,6 +111,8 @@
 
     bool isDirectionNext() const { return m_cursorDirection == IndexedDB::CursorDirection::Next || m_cursorDirection == IndexedDB::CursorDirection::Nextunique; }
 
+    void increaseCountToPrefetch();
+
     SQLiteIDBTransaction* m_transaction;
     IDBResourceIdentifier m_cursorIdentifier;
     int64_t m_objectStoreID;
@@ -133,6 +137,8 @@
     int64_t m_boundID { 0 };
 
     bool m_backingStoreCursor { false };
+
+    unsigned m_prefetchCount { 0 };
 };
 
 } // namespace IDBServer

Modified: trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp (256620 => 256621)


--- trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp	2020-02-14 18:05:04 UTC (rev 256620)
+++ trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp	2020-02-14 18:08:03 UTC (rev 256621)
@@ -854,24 +854,8 @@
     auto error = m_backingStore->iterateCursor(transactionIdentifier, cursorIdentifier, data, result);
 
     callback(error, result);
-
-    if (error.isNull())
-        prefetchCursor(transactionIdentifier, cursorIdentifier, data.count ? data.count : 1);
 }
 
-void UniqueIDBDatabase::prefetchCursor(const IDBResourceIdentifier& transactionIdentifier, const IDBResourceIdentifier& cursorIdentifier, uint64_t step)
-{
-    LOG(IndexedDB, "UniqueIDBDatabase::prefetchCursor");
-
-    ASSERT(!isMainThread());
-
-    uint64_t countToPrefetch = step * 2;
-    while (countToPrefetch --) {
-        if (!m_backingStore->prefetchCursor(transactionIdentifier, cursorIdentifier))
-            return;
-    }
-}
-
 void UniqueIDBDatabase::commitTransaction(UniqueIDBDatabaseTransaction& transaction, ErrorCallback callback)
 {
     ASSERT(!isMainThread());

Modified: trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.h (256620 => 256621)


--- trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.h	2020-02-14 18:05:04 UTC (rev 256620)
+++ trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.h	2020-02-14 18:08:03 UTC (rev 256621)
@@ -142,8 +142,6 @@
 
     void clearTransactionsOnConnection(UniqueIDBDatabaseConnection&);
 
-    void prefetchCursor(const IDBResourceIdentifier&, const IDBResourceIdentifier&, uint64_t step);
-
     IDBServer& m_server;
     IDBDatabaseIdentifier m_identifier;
 

Modified: trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabaseTransaction.cpp (256620 => 256621)


--- trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabaseTransaction.cpp	2020-02-14 18:05:04 UTC (rev 256620)
+++ trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabaseTransaction.cpp	2020-02-14 18:08:03 UTC (rev 256621)
@@ -374,9 +374,12 @@
     auto database = m_databaseConnection->database();
     ASSERT(database);
     
-    database->iterateCursor(requestData, data, [this, requestData](auto& error, const IDBGetResult& result) {
+    database->iterateCursor(requestData, data, [this, requestData, option = data.option](auto& error, const IDBGetResult& result) {
         LOG(IndexedDB, "UniqueIDBDatabaseTransaction::iterateCursor (callback)");
 
+        if (option == IndexedDB::CursorIterateOption::DoNotReply)
+            return;
+
         if (error.isNull())
             m_databaseConnection->connectionToClient().didIterateCursor(IDBResultData::iterateCursorSuccess(requestData.requestIdentifier(), result));
         else

Modified: trunk/Source/WebCore/Modules/indexeddb/shared/IDBCursorRecord.h (256620 => 256621)


--- trunk/Source/WebCore/Modules/indexeddb/shared/IDBCursorRecord.h	2020-02-14 18:05:04 UTC (rev 256620)
+++ trunk/Source/WebCore/Modules/indexeddb/shared/IDBCursorRecord.h	2020-02-14 18:08:03 UTC (rev 256621)
@@ -35,12 +35,13 @@
 struct IDBCursorRecord {
     IDBKeyData key;
     IDBKeyData primaryKey;
-    std::unique_ptr<IDBValue> value;
+    IDBValue value;
 
     template<class Encoder> void encode(Encoder&) const;
     template<class Decoder> static bool decode(Decoder&, IDBCursorRecord&);
 
-    size_t size() const { return key.size() + primaryKey.size() + (value ? value->size() : 0); }
+    IDBCursorRecord isolatedCopy() const;
+    size_t size() const { return key.size() + primaryKey.size() + value.size(); }
 };
 
 template<class Encoder>
@@ -64,6 +65,11 @@
     return true;
 }
 
+inline IDBCursorRecord IDBCursorRecord::isolatedCopy() const
+{
+    return { key.isolatedCopy(), primaryKey.isolatedCopy(), value.isolatedCopy() };
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(INDEXED_DATABASE)

Modified: trunk/Source/WebCore/Modules/indexeddb/shared/IDBIterateCursorData.cpp (256620 => 256621)


--- trunk/Source/WebCore/Modules/indexeddb/shared/IDBIterateCursorData.cpp	2020-02-14 18:05:04 UTC (rev 256620)
+++ trunk/Source/WebCore/Modules/indexeddb/shared/IDBIterateCursorData.cpp	2020-02-14 18:08:03 UTC (rev 256621)
@@ -33,7 +33,7 @@
 
 IDBIterateCursorData IDBIterateCursorData::isolatedCopy() const
 {
-    return { keyData.isolatedCopy(), primaryKeyData.isolatedCopy(), count };
+    return { keyData.isolatedCopy(), primaryKeyData.isolatedCopy(), count, option };
 }
 
 #if !LOG_DISABLED

Modified: trunk/Source/WebCore/Modules/indexeddb/shared/IDBIterateCursorData.h (256620 => 256621)


--- trunk/Source/WebCore/Modules/indexeddb/shared/IDBIterateCursorData.h	2020-02-14 18:05:04 UTC (rev 256620)
+++ trunk/Source/WebCore/Modules/indexeddb/shared/IDBIterateCursorData.h	2020-02-14 18:08:03 UTC (rev 256621)
@@ -35,6 +35,7 @@
     IDBKeyData keyData;
     IDBKeyData primaryKeyData;
     unsigned count;
+    IndexedDB::CursorIterateOption option { IndexedDB::CursorIterateOption::Reply };
 
     WEBCORE_EXPORT IDBIterateCursorData isolatedCopy() const;
 
@@ -50,6 +51,7 @@
 void IDBIterateCursorData::encode(Encoder& encoder) const
 {
     encoder << keyData << primaryKeyData << static_cast<uint64_t>(count);
+    encoder.encodeEnum(option);
 }
 
 template<class Decoder>
@@ -73,9 +75,11 @@
 
     if (count > std::numeric_limits<unsigned>::max())
         return false;
-
     iteratorCursorData.count = static_cast<unsigned>(count);
 
+    if (!decoder.decodeEnum(iteratorCursorData.option))
+        return false;
+
     return true;
 }
 

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (256620 => 256621)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2020-02-14 18:05:04 UTC (rev 256620)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2020-02-14 18:08:03 UTC (rev 256621)
@@ -1399,7 +1399,7 @@
 		510D4A34103165EE0049EA54 /* SocketStreamError.h in Headers */ = {isa = PBXBuildFile; fileRef = 510D4A2E103165EE0049EA54 /* SocketStreamError.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		510D4A37103165EE0049EA54 /* SocketStreamHandle.h in Headers */ = {isa = PBXBuildFile; fileRef = 510D4A31103165EE0049EA54 /* SocketStreamHandle.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		510D4A38103165EE0049EA54 /* SocketStreamHandleClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 510D4A32103165EE0049EA54 /* SocketStreamHandleClient.h */; settings = {ATTRIBUTES = (Private, ); }; };
-		5110FCFC1E03641D006F8D0B /* IDBCursorRecord.h in Headers */ = {isa = PBXBuildFile; fileRef = 5110FCFB1E0362A5006F8D0B /* IDBCursorRecord.h */; };
+		5110FCFC1E03641D006F8D0B /* IDBCursorRecord.h in Headers */ = {isa = PBXBuildFile; fileRef = 5110FCFB1E0362A5006F8D0B /* IDBCursorRecord.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		511EC1281C50AACA0032F983 /* IDBSerialization.h in Headers */ = {isa = PBXBuildFile; fileRef = 511EC1261C50AA570032F983 /* IDBSerialization.h */; };
 		511EC12C1C50ABBF0032F983 /* SQLiteIDBTransaction.h in Headers */ = {isa = PBXBuildFile; fileRef = 511EC12A1C50ABBA0032F983 /* SQLiteIDBTransaction.h */; };
 		511EC1301C50ABF50032F983 /* SQLiteIDBCursor.h in Headers */ = {isa = PBXBuildFile; fileRef = 511EC12E1C50ABEC0032F983 /* SQLiteIDBCursor.h */; };
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to