Changeset 209086 in webkit
- Timestamp:
- Nov 29, 2016 1:08:12 PM (7 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r209085 r209086 1 2016-11-29 Brady Eidson <beidson@apple.com> 2 3 IndexedDB 2.0: The client's transaction operation queue should flush as much to the server as possible. 4 https://bugs.webkit.org/show_bug.cgi?id=164932 5 6 Reviewed by Alex Christensen. 7 8 No new tests (No new test necessary, covered extensively by all existing tests). 9 10 Profiles showed that on tests with lots of rapid IDBRequests in a row, both the main thread and database 11 threads were largely idle. 12 13 The explanation was simple. Currently the client IDBTransaction queues up operations and only vends them out 14 to the server 1 at a time, waiting for the previous operation to complete. 15 16 While some operations do need to wait for the server to reply, by making the change to send most operations 17 (all operations with an associated IDBRequest) to the server without waiting we get rid of most of the idleness. 18 19 It is possible we can find a few other types of operations to send without waiting, but we haven't yet seen any 20 test case where they would show up on profiles. 21 22 Sending more than one operation at a time was actually a very small part of this change. 23 As many "edge case" regression tests revealed, we also needed to start having IDBTransaction track all of their 24 "in progress" operations such that they could be aborted on the client side in exceptional circumstances. 25 26 * Modules/indexeddb/IDBTransaction.cpp: 27 (WebCore::IDBTransaction::abortInProgressOperations): Abort's all in-progress operations (ones that have already 28 been sent to the server) 29 (WebCore::IDBTransaction::abortOnServerAndCancelRequests): Abort in-progress operations before pending ones. 30 (WebCore::IDBTransaction::operationTimerFired): If we just started an operation with an associated IDBRequest, 31 schedule the timer to send another one right away. 32 (WebCore::IDBTransaction::operationDidComplete): 33 (WebCore::IDBTransaction::connectionClosedFromServer): Abort in-progress operations before pending ones. 34 * Modules/indexeddb/IDBTransaction.h: 35 36 * Modules/indexeddb/client/TransactionOperation.cpp: 37 (WebCore::IDBClient::TransactionOperation::TransactionOperation): 38 * Modules/indexeddb/client/TransactionOperation.h: 39 (WebCore::IDBClient::TransactionOperation::completed): 40 (WebCore::IDBClient::TransactionOperation::hasIDBRequest): 41 1 42 2016-11-29 Dave Hyatt <hyatt@apple.com> 2 43 -
trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.cpp
r209069 r209086 252 252 } 253 253 254 void IDBTransaction::abortInProgressOperations(const IDBError& error) 255 { 256 LOG(IndexedDB, "IDBTransaction::abortInProgressOperations"); 257 258 Vector<RefPtr<IDBClient::TransactionOperation>> inProgressAbortVector; 259 inProgressAbortVector.reserveInitialCapacity(m_transactionOperationsInProgressQueue.size()); 260 while (!m_transactionOperationsInProgressQueue.isEmpty()) 261 inProgressAbortVector.uncheckedAppend(m_transactionOperationsInProgressQueue.takeFirst()); 262 263 for (auto& operation : inProgressAbortVector) { 264 m_transactionOperationsInProgressQueue.append(operation.get()); 265 m_currentlyCompletingRequest = nullptr; 266 operation->doComplete(IDBResultData::error(operation->identifier(), error)); 267 } 268 269 Vector<RefPtr<IDBClient::TransactionOperation>> completedOnServerAbortVector; 270 completedOnServerAbortVector.reserveInitialCapacity(m_completedOnServerQueue.size()); 271 while (!m_completedOnServerQueue.isEmpty()) 272 completedOnServerAbortVector.uncheckedAppend(m_completedOnServerQueue.takeFirst().first); 273 274 for (auto& operation : completedOnServerAbortVector) { 275 m_currentlyCompletingRequest = nullptr; 276 operation->doComplete(IDBResultData::error(operation->identifier(), error)); 277 } 278 279 connectionProxy().forgetActiveOperations(inProgressAbortVector); 280 } 281 254 282 void IDBTransaction::abortOnServerAndCancelRequests(IDBClient::TransactionOperation& operation) 255 283 { … … 261 289 262 290 ASSERT(m_transactionOperationMap.contains(operation.identifier())); 291 ASSERT(m_transactionOperationsInProgressQueue.last() == &operation); 263 292 m_transactionOperationMap.remove(operation.identifier()); 293 m_transactionOperationsInProgressQueue.removeLast(); 264 294 265 295 m_currentlyCompletingRequest = nullptr; 266 296 267 297 IDBError error(IDBDatabaseException::AbortError); 298 299 abortInProgressOperations(error); 300 268 301 for (auto& operation : m_abortQueue) { 269 302 m_currentlyCompletingRequest = nullptr; 303 m_transactionOperationsInProgressQueue.append(operation.get()); 270 304 operation->doComplete(IDBResultData::error(operation->identifier(), error)); 271 305 } … … 368 402 return; 369 403 404 // If the last in-progress operation we've sent to the server is not an IDBRequest operation, 405 // then we have to wait until it completes before sending any more. 406 if (!m_transactionOperationsInProgressQueue.isEmpty() && !m_transactionOperationsInProgressQueue.last()->nextRequestCanGoToServer()) 407 return; 408 370 409 if (!m_pendingTransactionOperationQueue.isEmpty()) { 371 410 auto operation = m_pendingTransactionOperationQueue.takeFirst(); 411 m_transactionOperationsInProgressQueue.append(operation.get()); 372 412 operation->perform(); 413 414 // If this operation we just started has an associated IDBRequest, we might be able to send 415 // another operation to the server before it completes. 416 if (operation->idbRequest() && !m_pendingTransactionOperationQueue.isEmpty()) 417 schedulePendingOperationTimer(); 373 418 374 419 return; … … 1148 1193 } 1149 1194 1195 // Since this request won't actually go to the server until the blob writes are complete, 1196 // stop future requests from going to the server ahead of it. 1197 operation.setNextRequestCanGoToServer(false); 1198 1150 1199 value->writeBlobsToDiskForIndexedDB([protectedThis = makeRef(*this), this, protectedOperation = Ref<IDBClient::TransactionOperation>(operation), keyData = IDBKeyData(key.get()).isolatedCopy(), overwriteMode](const IDBValue& idbValue) mutable { 1151 1200 ASSERT(currentThread() == originThreadID()); … … 1239 1288 LOG(IndexedDB, "IDBTransaction::operationCompletedOnClient"); 1240 1289 1290 ASSERT(currentThread() == m_database->originThreadID()); 1291 ASSERT(currentThread() == operation.originThreadID()); 1241 1292 ASSERT(m_transactionOperationMap.get(operation.identifier()) == &operation); 1242 ASSERT(currentThread() == m_database->originThreadID()); 1243 ASSERT(currentThread() == operation.originThreadID()); 1293 ASSERT(m_transactionOperationsInProgressQueue.first() == &operation); 1244 1294 1245 1295 m_transactionOperationMap.remove(operation.identifier()); 1296 m_transactionOperationsInProgressQueue.removeFirst(); 1246 1297 1247 1298 schedulePendingOperationTimer(); … … 1282 1333 m_state = IndexedDB::TransactionState::Aborting; 1283 1334 1335 abortInProgressOperations(error); 1336 1284 1337 Vector<RefPtr<IDBClient::TransactionOperation>> operations; 1285 1338 copyValuesToVector(m_transactionOperationMap, operations); … … 1287 1340 for (auto& operation : operations) { 1288 1341 m_currentlyCompletingRequest = nullptr; 1342 m_transactionOperationsInProgressQueue.append(operation.get()); 1343 ASSERT(m_transactionOperationsInProgressQueue.first() == operation.get()); 1289 1344 operation->doComplete(IDBResultData::error(operation->identifier(), error)); 1290 1345 } -
trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.h
r209069 r209086 161 161 void notifyDidAbort(const IDBError&); 162 162 void finishAbortOrCommit(); 163 void abortInProgressOperations(const IDBError&); 163 164 164 165 void scheduleOperation(RefPtr<IDBClient::TransactionOperation>&&); … … 244 245 245 246 Deque<RefPtr<IDBClient::TransactionOperation>> m_pendingTransactionOperationQueue; 247 Deque<IDBClient::TransactionOperation*> m_transactionOperationsInProgressQueue; 246 248 Deque<std::pair<RefPtr<IDBClient::TransactionOperation>, IDBResultData>> m_completedOnServerQueue; 247 249 Deque<RefPtr<IDBClient::TransactionOperation>> m_abortQueue; 250 248 251 HashMap<IDBResourceIdentifier, RefPtr<IDBClient::TransactionOperation>> m_transactionOperationMap; 249 252 -
trunk/Source/WebCore/Modules/indexeddb/client/TransactionOperation.h
r209069 r209086 84 84 { 85 85 ASSERT(m_originThreadID == currentThread()); 86 ASSERT(m_completeFunction); 86 87 // Due to race conditions between the server sending an "operation complete" message and the client 88 // forcefully aborting an operation, it's unavoidable that this method might be called twice. 89 // It's okay to handle that gracefully with an early return. 90 if (!m_completeFunction) 91 return; 92 87 93 m_completeFunction(data); 88 94 m_transaction->operationCompletedOnClient(*this); … … 99 105 100 106 IDBRequest* idbRequest() { return m_idbRequest.get(); } 107 108 bool nextRequestCanGoToServer() const { return m_nextRequestCanGoToServer && m_idbRequest; } 109 void setNextRequestCanGoToServer(bool nextRequestCanGoToServer) { m_nextRequestCanGoToServer = nextRequestCanGoToServer; } 101 110 102 111 protected: … … 128 137 ThreadIdentifier m_originThreadID { currentThread() }; 129 138 RefPtr<IDBRequest> m_idbRequest; 139 bool m_nextRequestCanGoToServer { true }; 130 140 }; 131 141
Note: See TracChangeset
for help on using the changeset viewer.