Changeset 200598 in webkit
- Timestamp:
- May 9, 2016 4:59:55 PM (8 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r200596 r200598 1 2016-05-09 Brady Eidson <beidson@apple.com> 2 3 Modern IDB: Prevent the same transaction from being commited/aborted twice. 4 https://bugs.webkit.org/show_bug.cgi?id=157494 5 6 Reviewed by Tim Horton. 7 8 When a page navigates or a worker terminates, in rare cases with specific unfortunate timing, the IDBServer 9 might receive a request to commit/abort a transaction that is already in the process of committing/aborting. 10 11 By moving transactions that are finishing into their own map we can at least detect this situation and 12 return an error. This seems like an improvement over some mysterious ASSERTs/timeouts. 13 14 No new tests: 15 While apparent that this is at least partially to blame for some existing timeouts/ASSERTs, I could not nail 16 down a reliable way to reproduce this with a dedicated test. 17 18 * Modules/indexeddb/server/UniqueIDBDatabase.cpp: 19 (WebCore::IDBServer::UniqueIDBDatabase::~UniqueIDBDatabase): 20 (WebCore::IDBServer::UniqueIDBDatabase::performCurrentDeleteOperation): 21 (WebCore::IDBServer::UniqueIDBDatabase::didDeleteBackingStore): 22 (WebCore::IDBServer::UniqueIDBDatabase::prepareToFinishTransaction): 23 (WebCore::IDBServer::UniqueIDBDatabase::commitTransaction): 24 (WebCore::IDBServer::UniqueIDBDatabase::didPerformCommitTransaction): 25 (WebCore::IDBServer::UniqueIDBDatabase::abortTransaction): 26 (WebCore::IDBServer::UniqueIDBDatabase::didPerformAbortTransaction): 27 (WebCore::IDBServer::UniqueIDBDatabase::hasUnfinishedTransactions): 28 (WebCore::IDBServer::UniqueIDBDatabase::operationAndTransactionTimerFired): 29 (WebCore::IDBServer::UniqueIDBDatabase::takeNextRunnableTransaction): 30 (WebCore::IDBServer::UniqueIDBDatabase::transactionCompleted): Renamed from inProgressTransactionCompleted. 31 (WebCore::IDBServer::UniqueIDBDatabase::inProgressTransactionCompleted): Deleted. 32 * Modules/indexeddb/server/UniqueIDBDatabase.h: 33 1 34 2016-05-09 Tim Horton <timothy_horton@apple.com> 2 35 -
trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp
r199668 r200598 61 61 LOG(IndexedDB, "UniqueIDBDatabase::~UniqueIDBDatabase() (%p) %s", this, m_identifier.debugString().utf8().data()); 62 62 ASSERT(!hasAnyPendingCallbacks()); 63 ASSERT( m_inProgressTransactions.isEmpty());63 ASSERT(!hasUnfinishedTransactions()); 64 64 ASSERT(m_pendingTransactions.isEmpty()); 65 65 ASSERT(m_openDatabaseConnections.isEmpty()); … … 195 195 } 196 196 197 if ( !m_inProgressTransactions.isEmpty())197 if (hasUnfinishedTransactions()) 198 198 return; 199 199 … … 251 251 ASSERT(m_currentOpenDBRequest->isDeleteRequest()); 252 252 ASSERT(!hasAnyPendingCallbacks()); 253 ASSERT( m_inProgressTransactions.isEmpty());253 ASSERT(!hasUnfinishedTransactions()); 254 254 ASSERT(m_pendingTransactions.isEmpty()); 255 255 ASSERT(m_openDatabaseConnections.isEmpty()); … … 984 984 } 985 985 986 bool UniqueIDBDatabase::prepareToFinishTransaction(UniqueIDBDatabaseTransaction& transaction) 987 { 988 auto takenTransaction = m_inProgressTransactions.take(transaction.info().identifier()); 989 if (!takenTransaction) 990 return false; 991 992 ASSERT(!m_finishingTransactions.contains(transaction.info().identifier())); 993 m_finishingTransactions.set(transaction.info().identifier(), WTFMove(takenTransaction)); 994 995 return true; 996 } 997 986 998 void UniqueIDBDatabase::commitTransaction(UniqueIDBDatabaseTransaction& transaction, ErrorCallback callback) 987 999 { … … 991 1003 ASSERT(&transaction.databaseConnection().database() == this); 992 1004 993 if (m_versionChangeTransaction == &transaction) {994 ASSERT(!m_versionChangeDatabaseConnection || &m_versionChangeTransaction->databaseConnection() == m_versionChangeDatabaseConnection);995 ASSERT(m_databaseInfo->version() == transaction.info().newVersion());996 997 invokeOperationAndTransactionTimer();998 }999 1000 1005 uint64_t callbackID = storeCallback(callback); 1006 1007 if (!prepareToFinishTransaction(transaction)) { 1008 performErrorCallback(callbackID, { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to commit transaction that is already finishing") }); 1009 return; 1010 } 1011 1001 1012 m_server.postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performCommitTransaction, callbackID, transaction.info().identifier())); 1002 1013 } … … 1018 1029 performErrorCallback(callbackIdentifier, error); 1019 1030 1020 inProgressTransactionCompleted(transactionIdentifier);1031 transactionCompleted(m_finishingTransactions.take(transactionIdentifier)); 1021 1032 } 1022 1033 … … 1029 1040 1030 1041 uint64_t callbackID = storeCallback(callback); 1042 1043 if (!prepareToFinishTransaction(transaction)) { 1044 performErrorCallback(callbackID, { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to abort transaction that is already finishing") }); 1045 return; 1046 } 1047 1031 1048 m_server.postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performAbortTransaction, callbackID, transaction.info().identifier())); 1032 1049 } … … 1060 1077 LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformAbortTransaction"); 1061 1078 1079 auto transaction = m_finishingTransactions.take(transactionIdentifier); 1080 ASSERT(transaction); 1081 1062 1082 if (m_versionChangeTransaction && m_versionChangeTransaction->info().identifier() == transactionIdentifier) { 1083 ASSERT(m_versionChangeTransaction == transaction); 1063 1084 ASSERT(!m_versionChangeDatabaseConnection || &m_versionChangeTransaction->databaseConnection() == m_versionChangeDatabaseConnection); 1064 1085 ASSERT(m_versionChangeTransaction->originalDatabaseInfo()); … … 1068 1089 performErrorCallback(callbackIdentifier, error); 1069 1090 1070 inProgressTransactionCompleted(transactionIdentifier);1091 transactionCompleted(WTFMove(transaction)); 1071 1092 } 1072 1093 … … 1128 1149 } 1129 1150 1151 bool UniqueIDBDatabase::hasUnfinishedTransactions() const 1152 { 1153 return !m_inProgressTransactions.isEmpty() || !m_finishingTransactions.isEmpty(); 1154 } 1155 1130 1156 void UniqueIDBDatabase::invokeOperationAndTransactionTimer() 1131 1157 { … … 1145 1171 if (!m_backingStoreIsEphemeral && !isCurrentlyInUse()) { 1146 1172 ASSERT(m_pendingTransactions.isEmpty()); 1147 ASSERT( m_inProgressTransactions.isEmpty());1173 ASSERT(!hasUnfinishedTransactions()); 1148 1174 m_server.closeUniqueIDBDatabase(*this); 1149 1175 return; … … 1224 1250 { 1225 1251 hadDeferredTransactions = false; 1226 if (!m_backingStoreSupportsSimultaneousTransactions && !m_inProgressTransactions.isEmpty()) {1252 if (!m_backingStoreSupportsSimultaneousTransactions && hasUnfinishedTransactions()) { 1227 1253 LOG(IndexedDB, "UniqueIDBDatabase::takeNextRunnableTransaction - Backing store only supports 1 transaction, and we already have 1"); 1228 1254 return nullptr; … … 1280 1306 } 1281 1307 1282 void UniqueIDBDatabase::inProgressTransactionCompleted(const IDBResourceIdentifier& transactionIdentifier) 1283 { 1284 auto transaction = m_inProgressTransactions.take(transactionIdentifier); 1308 void UniqueIDBDatabase::transactionCompleted(RefPtr<UniqueIDBDatabaseTransaction>&& transaction) 1309 { 1285 1310 ASSERT(transaction); 1311 ASSERT(!m_inProgressTransactions.contains(transaction->info().identifier())); 1312 ASSERT(!m_finishingTransactions.contains(transaction->info().identifier())); 1286 1313 1287 1314 for (auto objectStore : transaction->objectStoreIdentifiers()) { -
trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.h
r199668 r200598 125 125 126 126 void activateTransactionInBackingStore(UniqueIDBDatabaseTransaction&); 127 void inProgressTransactionCompleted(const IDBResourceIdentifier&);127 void transactionCompleted(RefPtr<UniqueIDBDatabaseTransaction>&&); 128 128 129 129 // Database thread operations … … 177 177 bool hasAnyPendingCallbacks() const; 178 178 bool isCurrentlyInUse() const; 179 bool hasUnfinishedTransactions() const; 179 180 180 181 void invokeOperationAndTransactionTimer(); 181 182 void operationAndTransactionTimerFired(); 182 183 RefPtr<UniqueIDBDatabaseTransaction> takeNextRunnableTransaction(bool& hadDeferredTransactions); 184 185 bool prepareToFinishTransaction(UniqueIDBDatabaseTransaction&); 183 186 184 187 IDBServer& m_server; … … 212 215 Deque<RefPtr<UniqueIDBDatabaseTransaction>> m_pendingTransactions; 213 216 HashMap<IDBResourceIdentifier, RefPtr<UniqueIDBDatabaseTransaction>> m_inProgressTransactions; 217 HashMap<IDBResourceIdentifier, RefPtr<UniqueIDBDatabaseTransaction>> m_finishingTransactions; 214 218 215 219 // The keys into these sets are the object store ID.
Note: See TracChangeset
for help on using the changeset viewer.