2 * Copyright (C) 2015, 2016 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
27 #include "UniqueIDBDatabase.h"
29 #if ENABLE(INDEXED_DATABASE)
31 #include "IDBCursorInfo.h"
32 #include "IDBGetAllRecordsData.h"
33 #include "IDBGetAllResult.h"
34 #include "IDBGetRecordData.h"
35 #include "IDBIterateCursorData.h"
36 #include "IDBKeyRangeData.h"
37 #include "IDBResultData.h"
38 #include "IDBServer.h"
39 #include "IDBTransactionInfo.h"
42 #include "ScopeGuard.h"
43 #include "SerializedScriptValue.h"
44 #include "UniqueIDBDatabaseConnection.h"
45 #include <heap/HeapInlines.h>
46 #include <runtime/AuxiliaryBarrierInlines.h>
47 #include <runtime/StructureInlines.h>
48 #include <wtf/MainThread.h>
49 #include <wtf/NeverDestroyed.h>
56 UniqueIDBDatabase::UniqueIDBDatabase(IDBServer& server, const IDBDatabaseIdentifier& identifier)
58 , m_identifier(identifier)
59 , m_operationAndTransactionTimer(*this, &UniqueIDBDatabase::operationAndTransactionTimerFired)
61 LOG(IndexedDB, "UniqueIDBDatabase::UniqueIDBDatabase() (%p) %s", this, m_identifier.debugString().utf8().data());
64 UniqueIDBDatabase::~UniqueIDBDatabase()
66 LOG(IndexedDB, "UniqueIDBDatabase::~UniqueIDBDatabase() (%p) %s", this, m_identifier.debugString().utf8().data());
67 ASSERT(isMainThread());
68 ASSERT(!hasAnyPendingCallbacks());
69 ASSERT(!hasUnfinishedTransactions());
70 ASSERT(m_pendingTransactions.isEmpty());
71 ASSERT(m_openDatabaseConnections.isEmpty());
72 ASSERT(m_clientClosePendingDatabaseConnections.isEmpty());
73 ASSERT(m_serverClosePendingDatabaseConnections.isEmpty());
74 ASSERT(!m_queuedTaskCount);
77 const IDBDatabaseInfo& UniqueIDBDatabase::info() const
79 RELEASE_ASSERT(m_databaseInfo);
80 return *m_databaseInfo;
83 void UniqueIDBDatabase::openDatabaseConnection(IDBConnectionToClient& connection, const IDBRequestData& requestData)
85 LOG(IndexedDB, "UniqueIDBDatabase::openDatabaseConnection");
86 ASSERT(!m_hardClosedForUserDelete);
88 m_pendingOpenDBRequests.add(ServerOpenDBRequest::create(connection, requestData));
90 // An open operation is already in progress, so we can't possibly handle this one yet.
91 if (m_isOpeningBackingStore)
94 handleDatabaseOperations();
97 bool UniqueIDBDatabase::hasAnyPendingCallbacks() const
99 return !m_errorCallbacks.isEmpty()
100 || !m_keyDataCallbacks.isEmpty()
101 || !m_getResultCallbacks.isEmpty()
102 || !m_getAllResultsCallbacks.isEmpty()
103 || !m_countCallbacks.isEmpty();
106 bool UniqueIDBDatabase::isVersionChangeInProgress()
109 if (m_versionChangeTransaction)
110 ASSERT(m_versionChangeDatabaseConnection);
113 return m_versionChangeDatabaseConnection;
116 void UniqueIDBDatabase::performCurrentOpenOperation()
118 LOG(IndexedDB, "(main) UniqueIDBDatabase::performCurrentOpenOperation (%p)", this);
120 ASSERT(m_currentOpenDBRequest);
121 ASSERT(m_currentOpenDBRequest->isOpenRequest());
123 if (!m_databaseInfo) {
124 if (!m_isOpeningBackingStore) {
125 m_isOpeningBackingStore = true;
126 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::openBackingStore, m_identifier));
132 // If we previously started a version change operation but were blocked by having open connections,
133 // we might now be unblocked.
134 if (m_versionChangeDatabaseConnection) {
135 if (!m_versionChangeTransaction && !hasAnyOpenConnections())
136 startVersionChangeTransaction();
140 // 3.3.1 Opening a database
141 // If requested version is undefined, then let requested version be 1 if db was created in the previous step,
142 // or the current version of db otherwise.
143 uint64_t requestedVersion = m_currentOpenDBRequest->requestData().requestedVersion();
144 if (!requestedVersion)
145 requestedVersion = m_databaseInfo->version() ? m_databaseInfo->version() : 1;
147 // 3.3.1 Opening a database
148 // If the database version higher than the requested version, abort these steps and return a VersionError.
149 if (requestedVersion < m_databaseInfo->version()) {
150 auto result = IDBResultData::error(m_currentOpenDBRequest->requestData().requestIdentifier(), IDBError(IDBDatabaseException::VersionError));
151 m_currentOpenDBRequest->connection().didOpenDatabase(result);
152 m_currentOpenDBRequest = nullptr;
157 if (!m_backingStoreOpenError.isNull()) {
158 auto result = IDBResultData::error(m_currentOpenDBRequest->requestData().requestIdentifier(), m_backingStoreOpenError);
159 m_currentOpenDBRequest->connection().didOpenDatabase(result);
160 m_currentOpenDBRequest = nullptr;
165 Ref<UniqueIDBDatabaseConnection> connection = UniqueIDBDatabaseConnection::create(*this, *m_currentOpenDBRequest);
167 if (requestedVersion == m_databaseInfo->version()) {
168 auto* rawConnection = &connection.get();
169 addOpenDatabaseConnection(WTFMove(connection));
171 auto result = IDBResultData::openDatabaseSuccess(m_currentOpenDBRequest->requestData().requestIdentifier(), *rawConnection);
172 m_currentOpenDBRequest->connection().didOpenDatabase(result);
173 m_currentOpenDBRequest = nullptr;
178 ASSERT(!m_versionChangeDatabaseConnection);
179 m_versionChangeDatabaseConnection = WTFMove(connection);
181 // 3.3.7 "versionchange" transaction steps
182 // If there's no other open connections to this database, the version change process can begin immediately.
183 if (!hasAnyOpenConnections()) {
184 startVersionChangeTransaction();
188 // Otherwise we have to notify all those open connections and wait for them to close.
189 maybeNotifyConnectionsOfVersionChange();
192 void UniqueIDBDatabase::performCurrentDeleteOperation()
194 ASSERT(isMainThread());
195 LOG(IndexedDB, "(main) UniqueIDBDatabase::performCurrentDeleteOperation - %s", m_identifier.debugString().utf8().data());
197 ASSERT(m_currentOpenDBRequest);
198 ASSERT(m_currentOpenDBRequest->isDeleteRequest());
200 if (m_deleteBackingStoreInProgress)
203 if (hasAnyOpenConnections()) {
204 maybeNotifyConnectionsOfVersionChange();
208 if (hasUnfinishedTransactions())
211 ASSERT(!hasAnyPendingCallbacks());
212 ASSERT(m_pendingTransactions.isEmpty());
213 ASSERT(m_openDatabaseConnections.isEmpty());
215 // It's possible to have multiple delete requests queued up in a row.
216 // In that scenario only the first request will actually have to delete the database.
217 // Subsequent requests can immediately notify their completion.
219 if (!m_deleteBackingStoreInProgress) {
220 if (!m_databaseInfo && m_mostRecentDeletedDatabaseInfo)
221 didDeleteBackingStore(0);
223 m_deleteBackingStoreInProgress = true;
224 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::deleteBackingStore, m_identifier));
229 void UniqueIDBDatabase::deleteBackingStore(const IDBDatabaseIdentifier& identifier)
231 ASSERT(!isMainThread());
232 LOG(IndexedDB, "(db) UniqueIDBDatabase::deleteBackingStore");
234 uint64_t deletedVersion = 0;
236 if (m_backingStore) {
237 m_backingStore->deleteBackingStore();
238 m_backingStore = nullptr;
239 m_backingStoreSupportsSimultaneousTransactions = false;
240 m_backingStoreIsEphemeral = false;
242 auto backingStore = m_server.createBackingStore(identifier);
244 IDBDatabaseInfo databaseInfo;
245 auto error = backingStore->getOrEstablishDatabaseInfo(databaseInfo);
247 LOG_ERROR("Error getting database info from database %s that we are trying to delete", identifier.debugString().utf8().data());
249 deletedVersion = databaseInfo.version();
250 backingStore->deleteBackingStore();
253 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didDeleteBackingStore, deletedVersion));
256 void UniqueIDBDatabase::performUnconditionalDeleteBackingStore()
258 ASSERT(!isMainThread());
259 LOG(IndexedDB, "(db) UniqueIDBDatabase::performUnconditionalDeleteBackingStore");
264 m_backingStore->deleteBackingStore();
265 m_backingStore = nullptr;
266 m_backingStoreSupportsSimultaneousTransactions = false;
267 m_backingStoreIsEphemeral = false;
270 void UniqueIDBDatabase::didDeleteBackingStore(uint64_t deletedVersion)
272 ASSERT(isMainThread());
273 LOG(IndexedDB, "(main) UniqueIDBDatabase::didDeleteBackingStore");
275 ASSERT(!hasAnyPendingCallbacks());
276 ASSERT(!hasUnfinishedTransactions());
277 ASSERT(m_pendingTransactions.isEmpty());
278 ASSERT(m_openDatabaseConnections.isEmpty());
280 // It's possible that the openDBRequest was cancelled from client-side after the delete was already dispatched to the backingstore.
281 // So it's okay if we don't have a currentOpenDBRequest, but if we do it has to be a deleteRequest.
282 ASSERT(!m_currentOpenDBRequest || m_currentOpenDBRequest->isDeleteRequest());
285 m_mostRecentDeletedDatabaseInfo = WTFMove(m_databaseInfo);
287 // If this UniqueIDBDatabase was brought into existence for the purpose of deleting the file on disk,
288 // we won't have a m_mostRecentDeletedDatabaseInfo. In that case, we'll manufacture one using the
289 // passed in deletedVersion argument.
290 if (!m_mostRecentDeletedDatabaseInfo)
291 m_mostRecentDeletedDatabaseInfo = std::make_unique<IDBDatabaseInfo>(m_identifier.databaseName(), deletedVersion);
293 if (m_currentOpenDBRequest) {
294 m_currentOpenDBRequest->notifyDidDeleteDatabase(*m_mostRecentDeletedDatabaseInfo);
295 m_currentOpenDBRequest = nullptr;
298 m_deleteBackingStoreInProgress = false;
300 if (m_clientClosePendingDatabaseConnections.isEmpty() && m_pendingOpenDBRequests.isEmpty()) {
301 m_server.closeUniqueIDBDatabase(*this);
305 invokeOperationAndTransactionTimer();
308 void UniqueIDBDatabase::didPerformUnconditionalDeleteBackingStore()
310 // This function is a placeholder so the database thread can message back to the main thread.
311 ASSERT(m_hardClosedForUserDelete);
314 void UniqueIDBDatabase::handleDatabaseOperations()
316 ASSERT(isMainThread());
317 LOG(IndexedDB, "(main) UniqueIDBDatabase::handleDatabaseOperations - There are %u pending", m_pendingOpenDBRequests.size());
318 ASSERT(!m_hardClosedForUserDelete);
320 if (m_deleteBackingStoreInProgress)
323 if (m_versionChangeDatabaseConnection || m_versionChangeTransaction || m_currentOpenDBRequest) {
324 // We can't start any new open-database operations right now, but we might be able to start handling a delete operation.
325 if (!m_currentOpenDBRequest && !m_pendingOpenDBRequests.isEmpty() && m_pendingOpenDBRequests.first()->isDeleteRequest())
326 m_currentOpenDBRequest = m_pendingOpenDBRequests.takeFirst();
328 // Some operations (such as the first open operation after a delete) require multiple passes to completely handle
329 if (m_currentOpenDBRequest)
330 handleCurrentOperation();
335 if (m_pendingOpenDBRequests.isEmpty())
338 m_currentOpenDBRequest = m_pendingOpenDBRequests.takeFirst();
339 LOG(IndexedDB, "UniqueIDBDatabase::handleDatabaseOperations - Popped an operation, now there are %u pending", m_pendingOpenDBRequests.size());
341 handleCurrentOperation();
344 void UniqueIDBDatabase::handleCurrentOperation()
346 LOG(IndexedDB, "(main) UniqueIDBDatabase::handleCurrentOperation");
347 ASSERT(!m_hardClosedForUserDelete);
348 ASSERT(m_currentOpenDBRequest);
350 RefPtr<UniqueIDBDatabase> protectedThis(this);
352 if (m_currentOpenDBRequest->isOpenRequest())
353 performCurrentOpenOperation();
354 else if (m_currentOpenDBRequest->isDeleteRequest())
355 performCurrentDeleteOperation();
357 ASSERT_NOT_REACHED();
359 if (!m_currentOpenDBRequest)
360 invokeOperationAndTransactionTimer();
363 bool UniqueIDBDatabase::hasAnyOpenConnections() const
365 return !m_openDatabaseConnections.isEmpty();
368 bool UniqueIDBDatabase::allConnectionsAreClosedOrClosing() const
370 for (auto& connection : m_openDatabaseConnections) {
371 if (!connection->connectionIsClosing())
378 static uint64_t generateUniqueCallbackIdentifier()
380 ASSERT(isMainThread());
381 static uint64_t currentID = 0;
385 uint64_t UniqueIDBDatabase::storeCallbackOrFireError(ErrorCallback callback)
387 if (m_hardClosedForUserDelete) {
388 callback(IDBError::userDeleteError());
392 uint64_t identifier = generateUniqueCallbackIdentifier();
393 ASSERT(!m_errorCallbacks.contains(identifier));
394 m_errorCallbacks.add(identifier, callback);
398 uint64_t UniqueIDBDatabase::storeCallbackOrFireError(KeyDataCallback callback)
400 if (m_hardClosedForUserDelete) {
401 callback(IDBError::userDeleteError(), { });
405 uint64_t identifier = generateUniqueCallbackIdentifier();
406 ASSERT(!m_keyDataCallbacks.contains(identifier));
407 m_keyDataCallbacks.add(identifier, callback);
411 uint64_t UniqueIDBDatabase::storeCallbackOrFireError(GetResultCallback callback)
413 if (m_hardClosedForUserDelete) {
414 callback(IDBError::userDeleteError(), { });
418 uint64_t identifier = generateUniqueCallbackIdentifier();
419 ASSERT(!m_getResultCallbacks.contains(identifier));
420 m_getResultCallbacks.add(identifier, callback);
424 uint64_t UniqueIDBDatabase::storeCallbackOrFireError(GetAllResultsCallback callback)
426 if (m_hardClosedForUserDelete) {
427 callback(IDBError::userDeleteError(), { });
431 uint64_t identifier = generateUniqueCallbackIdentifier();
432 ASSERT(!m_getAllResultsCallbacks.contains(identifier));
433 m_getAllResultsCallbacks.add(identifier, callback);
437 uint64_t UniqueIDBDatabase::storeCallbackOrFireError(CountCallback callback)
439 if (m_hardClosedForUserDelete) {
440 callback(IDBError::userDeleteError(), 0);
444 uint64_t identifier = generateUniqueCallbackIdentifier();
445 ASSERT(!m_countCallbacks.contains(identifier));
446 m_countCallbacks.add(identifier, callback);
450 void UniqueIDBDatabase::handleDelete(IDBConnectionToClient& connection, const IDBRequestData& requestData)
452 LOG(IndexedDB, "(main) UniqueIDBDatabase::handleDelete");
453 ASSERT(!m_hardClosedForUserDelete);
455 m_pendingOpenDBRequests.add(ServerOpenDBRequest::create(connection, requestData));
456 handleDatabaseOperations();
459 void UniqueIDBDatabase::startVersionChangeTransaction()
461 LOG(IndexedDB, "(main) UniqueIDBDatabase::startVersionChangeTransaction");
463 ASSERT(!m_versionChangeTransaction);
464 ASSERT(m_currentOpenDBRequest);
465 ASSERT(m_currentOpenDBRequest->isOpenRequest());
466 ASSERT(m_versionChangeDatabaseConnection);
468 auto operation = WTFMove(m_currentOpenDBRequest);
470 uint64_t requestedVersion = operation->requestData().requestedVersion();
471 if (!requestedVersion)
472 requestedVersion = m_databaseInfo->version() ? m_databaseInfo->version() : 1;
474 addOpenDatabaseConnection(*m_versionChangeDatabaseConnection);
476 m_versionChangeTransaction = &m_versionChangeDatabaseConnection->createVersionChangeTransaction(requestedVersion);
477 m_databaseInfo->setVersion(requestedVersion);
479 m_inProgressTransactions.set(m_versionChangeTransaction->info().identifier(), m_versionChangeTransaction);
480 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::beginTransactionInBackingStore, m_versionChangeTransaction->info()));
482 auto result = IDBResultData::openDatabaseUpgradeNeeded(operation->requestData().requestIdentifier(), *m_versionChangeTransaction);
483 operation->connection().didOpenDatabase(result);
486 void UniqueIDBDatabase::beginTransactionInBackingStore(const IDBTransactionInfo& info)
488 LOG(IndexedDB, "(db) UniqueIDBDatabase::beginTransactionInBackingStore");
489 m_backingStore->beginTransaction(info);
492 void UniqueIDBDatabase::maybeNotifyConnectionsOfVersionChange()
494 ASSERT(m_currentOpenDBRequest);
496 if (m_currentOpenDBRequest->hasNotifiedConnectionsOfVersionChange())
499 uint64_t newVersion = m_currentOpenDBRequest->isOpenRequest() ? m_currentOpenDBRequest->requestData().requestedVersion() : 0;
500 auto requestIdentifier = m_currentOpenDBRequest->requestData().requestIdentifier();
502 LOG(IndexedDB, "(main) UniqueIDBDatabase::notifyConnectionsOfVersionChange - %" PRIu64, newVersion);
504 // 3.3.7 "versionchange" transaction steps
505 // Fire a versionchange event at each connection in m_openDatabaseConnections that is open.
506 // The event must not be fired on connections which has the closePending flag set.
507 HashSet<uint64_t> connectionIdentifiers;
508 for (auto connection : m_openDatabaseConnections) {
509 if (connection->closePending())
512 connection->fireVersionChangeEvent(requestIdentifier, newVersion);
513 connectionIdentifiers.add(connection->identifier());
516 if (!connectionIdentifiers.isEmpty())
517 m_currentOpenDBRequest->notifiedConnectionsOfVersionChange(WTFMove(connectionIdentifiers));
519 m_currentOpenDBRequest->maybeNotifyRequestBlocked(m_databaseInfo->version());
522 void UniqueIDBDatabase::notifyCurrentRequestConnectionClosedOrFiredVersionChangeEvent(uint64_t connectionIdentifier)
524 LOG(IndexedDB, "UniqueIDBDatabase::notifyCurrentRequestConnectionClosedOrFiredVersionChangeEvent - %" PRIu64, connectionIdentifier);
526 ASSERT(m_currentOpenDBRequest);
528 m_currentOpenDBRequest->connectionClosedOrFiredVersionChangeEvent(connectionIdentifier);
530 if (m_currentOpenDBRequest->hasConnectionsPendingVersionChangeEvent())
533 if (!hasAnyOpenConnections() || allConnectionsAreClosedOrClosing()) {
534 invokeOperationAndTransactionTimer();
538 // Since all open connections have fired their version change events but not all of them have closed,
539 // this request is officially blocked.
540 m_currentOpenDBRequest->maybeNotifyRequestBlocked(m_databaseInfo->version());
543 void UniqueIDBDatabase::didFireVersionChangeEvent(UniqueIDBDatabaseConnection& connection, const IDBResourceIdentifier& requestIdentifier)
545 LOG(IndexedDB, "UniqueIDBDatabase::didFireVersionChangeEvent");
547 if (!m_currentOpenDBRequest)
550 ASSERT_UNUSED(requestIdentifier, m_currentOpenDBRequest->requestData().requestIdentifier() == requestIdentifier);
552 notifyCurrentRequestConnectionClosedOrFiredVersionChangeEvent(connection.identifier());
555 void UniqueIDBDatabase::openDBRequestCancelled(const IDBResourceIdentifier& requestIdentifier)
557 LOG(IndexedDB, "UniqueIDBDatabase::openDBRequestCancelled - %s", requestIdentifier.loggingString().utf8().data());
559 if (m_currentOpenDBRequest && m_currentOpenDBRequest->requestData().requestIdentifier() == requestIdentifier)
560 m_currentOpenDBRequest = nullptr;
562 if (m_versionChangeDatabaseConnection && m_versionChangeDatabaseConnection->openRequestIdentifier() == requestIdentifier) {
563 ASSERT(!m_versionChangeTransaction || m_versionChangeTransaction->databaseConnection().openRequestIdentifier() == requestIdentifier);
564 ASSERT(!m_versionChangeTransaction || &m_versionChangeTransaction->databaseConnection() == m_versionChangeDatabaseConnection);
566 connectionClosedFromClient(*m_versionChangeDatabaseConnection);
569 for (auto& request : m_pendingOpenDBRequests) {
570 if (request->requestData().requestIdentifier() == requestIdentifier) {
571 m_pendingOpenDBRequests.remove(request);
577 void UniqueIDBDatabase::addOpenDatabaseConnection(Ref<UniqueIDBDatabaseConnection>&& connection)
579 ASSERT(!m_openDatabaseConnections.contains(&connection.get()));
580 m_openDatabaseConnections.add(adoptRef(connection.leakRef()));
583 void UniqueIDBDatabase::openBackingStore(const IDBDatabaseIdentifier& identifier)
585 ASSERT(!isMainThread());
586 LOG(IndexedDB, "(db) UniqueIDBDatabase::openBackingStore (%p)", this);
588 ASSERT(!m_backingStore);
589 m_backingStore = m_server.createBackingStore(identifier);
590 m_backingStoreSupportsSimultaneousTransactions = m_backingStore->supportsSimultaneousTransactions();
591 m_backingStoreIsEphemeral = m_backingStore->isEphemeral();
593 IDBDatabaseInfo databaseInfo;
594 auto error = m_backingStore->getOrEstablishDatabaseInfo(databaseInfo);
596 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didOpenBackingStore, databaseInfo, error));
599 void UniqueIDBDatabase::didOpenBackingStore(const IDBDatabaseInfo& info, const IDBError& error)
601 ASSERT(isMainThread());
602 LOG(IndexedDB, "(main) UniqueIDBDatabase::didOpenBackingStore");
604 m_databaseInfo = std::make_unique<IDBDatabaseInfo>(info);
605 m_backingStoreOpenError = error;
607 ASSERT(m_isOpeningBackingStore);
608 m_isOpeningBackingStore = false;
610 handleDatabaseOperations();
613 void UniqueIDBDatabase::createObjectStore(UniqueIDBDatabaseTransaction& transaction, const IDBObjectStoreInfo& info, ErrorCallback callback)
615 ASSERT(isMainThread());
616 LOG(IndexedDB, "(main) UniqueIDBDatabase::createObjectStore");
618 uint64_t callbackID = storeCallbackOrFireError(callback);
622 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performCreateObjectStore, callbackID, transaction.info().identifier(), info));
625 void UniqueIDBDatabase::performCreateObjectStore(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, const IDBObjectStoreInfo& info)
627 ASSERT(!isMainThread());
628 LOG(IndexedDB, "(db) UniqueIDBDatabase::performCreateObjectStore");
630 ASSERT(m_backingStore);
631 m_backingStore->createObjectStore(transactionIdentifier, info);
634 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformCreateObjectStore, callbackIdentifier, error, info));
637 void UniqueIDBDatabase::didPerformCreateObjectStore(uint64_t callbackIdentifier, const IDBError& error, const IDBObjectStoreInfo& info)
639 ASSERT(isMainThread());
640 LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformCreateObjectStore");
643 m_databaseInfo->addExistingObjectStore(info);
645 performErrorCallback(callbackIdentifier, error);
648 void UniqueIDBDatabase::deleteObjectStore(UniqueIDBDatabaseTransaction& transaction, const String& objectStoreName, ErrorCallback callback)
650 ASSERT(isMainThread());
651 LOG(IndexedDB, "(main) UniqueIDBDatabase::deleteObjectStore");
653 uint64_t callbackID = storeCallbackOrFireError(callback);
657 auto* info = m_databaseInfo->infoForExistingObjectStore(objectStoreName);
659 performErrorCallback(callbackID, { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to delete non-existant object store") });
663 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performDeleteObjectStore, callbackID, transaction.info().identifier(), info->identifier()));
666 void UniqueIDBDatabase::performDeleteObjectStore(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier)
668 ASSERT(!isMainThread());
669 LOG(IndexedDB, "(db) UniqueIDBDatabase::performDeleteObjectStore");
671 ASSERT(m_backingStore);
672 m_backingStore->deleteObjectStore(transactionIdentifier, objectStoreIdentifier);
675 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformDeleteObjectStore, callbackIdentifier, error, objectStoreIdentifier));
678 void UniqueIDBDatabase::didPerformDeleteObjectStore(uint64_t callbackIdentifier, const IDBError& error, uint64_t objectStoreIdentifier)
680 ASSERT(isMainThread());
681 LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformDeleteObjectStore");
684 m_databaseInfo->deleteObjectStore(objectStoreIdentifier);
686 performErrorCallback(callbackIdentifier, error);
689 void UniqueIDBDatabase::renameObjectStore(UniqueIDBDatabaseTransaction& transaction, uint64_t objectStoreIdentifier, const String& newName, ErrorCallback callback)
691 ASSERT(isMainThread());
692 LOG(IndexedDB, "(main) UniqueIDBDatabase::renameObjectStore");
694 uint64_t callbackID = storeCallbackOrFireError(callback);
698 auto* info = m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
700 performErrorCallback(callbackID, { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to rename non-existant object store") });
704 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performRenameObjectStore, callbackID, transaction.info().identifier(), objectStoreIdentifier, newName));
707 void UniqueIDBDatabase::performRenameObjectStore(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const String& newName)
709 ASSERT(!isMainThread());
710 LOG(IndexedDB, "(db) UniqueIDBDatabase::performRenameObjectStore");
712 ASSERT(m_backingStore);
713 m_backingStore->renameObjectStore(transactionIdentifier, objectStoreIdentifier, newName);
716 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformRenameObjectStore, callbackIdentifier, error, objectStoreIdentifier, newName));
719 void UniqueIDBDatabase::didPerformRenameObjectStore(uint64_t callbackIdentifier, const IDBError& error, uint64_t objectStoreIdentifier, const String& newName)
721 ASSERT(isMainThread());
722 LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformRenameObjectStore");
725 m_databaseInfo->renameObjectStore(objectStoreIdentifier, newName);
727 performErrorCallback(callbackIdentifier, error);
730 void UniqueIDBDatabase::clearObjectStore(UniqueIDBDatabaseTransaction& transaction, uint64_t objectStoreIdentifier, ErrorCallback callback)
732 ASSERT(isMainThread());
733 LOG(IndexedDB, "(main) UniqueIDBDatabase::clearObjectStore");
735 uint64_t callbackID = storeCallbackOrFireError(callback);
738 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performClearObjectStore, callbackID, transaction.info().identifier(), objectStoreIdentifier));
741 void UniqueIDBDatabase::performClearObjectStore(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier)
743 ASSERT(!isMainThread());
744 LOG(IndexedDB, "(db) UniqueIDBDatabase::performClearObjectStore");
746 ASSERT(m_backingStore);
747 m_backingStore->clearObjectStore(transactionIdentifier, objectStoreIdentifier);
750 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformClearObjectStore, callbackIdentifier, error));
753 void UniqueIDBDatabase::didPerformClearObjectStore(uint64_t callbackIdentifier, const IDBError& error)
755 ASSERT(isMainThread());
756 LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformClearObjectStore");
758 performErrorCallback(callbackIdentifier, error);
761 void UniqueIDBDatabase::createIndex(UniqueIDBDatabaseTransaction& transaction, const IDBIndexInfo& info, ErrorCallback callback)
763 ASSERT(isMainThread());
764 LOG(IndexedDB, "(main) UniqueIDBDatabase::createIndex");
766 uint64_t callbackID = storeCallbackOrFireError(callback);
769 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performCreateIndex, callbackID, transaction.info().identifier(), info));
772 void UniqueIDBDatabase::performCreateIndex(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, const IDBIndexInfo& info)
774 ASSERT(!isMainThread());
775 LOG(IndexedDB, "(db) UniqueIDBDatabase::performCreateIndex");
777 ASSERT(m_backingStore);
778 IDBError error = m_backingStore->createIndex(transactionIdentifier, info);
780 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformCreateIndex, callbackIdentifier, error, info));
783 void UniqueIDBDatabase::didPerformCreateIndex(uint64_t callbackIdentifier, const IDBError& error, const IDBIndexInfo& info)
785 ASSERT(isMainThread());
786 LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformCreateIndex");
788 if (error.isNull()) {
789 ASSERT(m_databaseInfo);
790 auto* objectStoreInfo = m_databaseInfo->infoForExistingObjectStore(info.objectStoreIdentifier());
791 ASSERT(objectStoreInfo);
792 objectStoreInfo->addExistingIndex(info);
795 performErrorCallback(callbackIdentifier, error);
798 void UniqueIDBDatabase::deleteIndex(UniqueIDBDatabaseTransaction& transaction, uint64_t objectStoreIdentifier, const String& indexName, ErrorCallback callback)
800 ASSERT(isMainThread());
801 LOG(IndexedDB, "(main) UniqueIDBDatabase::deleteIndex");
803 uint64_t callbackID = storeCallbackOrFireError(callback);
807 auto* objectStoreInfo = m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
808 if (!objectStoreInfo) {
809 performErrorCallback(callbackID, { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to delete index from non-existant object store") });
813 auto* indexInfo = objectStoreInfo->infoForExistingIndex(indexName);
815 performErrorCallback(callbackID, { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to delete non-existant index") });
819 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performDeleteIndex, callbackID, transaction.info().identifier(), objectStoreIdentifier, indexInfo->identifier()));
822 void UniqueIDBDatabase::performDeleteIndex(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const uint64_t indexIdentifier)
824 ASSERT(!isMainThread());
825 LOG(IndexedDB, "(db) UniqueIDBDatabase::performDeleteIndex");
827 ASSERT(m_backingStore);
828 m_backingStore->deleteIndex(transactionIdentifier, objectStoreIdentifier, indexIdentifier);
831 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformDeleteIndex, callbackIdentifier, error, objectStoreIdentifier, indexIdentifier));
834 void UniqueIDBDatabase::didPerformDeleteIndex(uint64_t callbackIdentifier, const IDBError& error, uint64_t objectStoreIdentifier, uint64_t indexIdentifier)
836 ASSERT(isMainThread());
837 LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformDeleteIndex");
839 if (error.isNull()) {
840 auto* objectStoreInfo = m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
842 objectStoreInfo->deleteIndex(indexIdentifier);
845 performErrorCallback(callbackIdentifier, error);
848 void UniqueIDBDatabase::renameIndex(UniqueIDBDatabaseTransaction& transaction, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const String& newName, ErrorCallback callback)
850 ASSERT(isMainThread());
851 LOG(IndexedDB, "(main) UniqueIDBDatabase::renameIndex");
853 uint64_t callbackID = storeCallbackOrFireError(callback);
857 auto* objectStoreInfo = m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
858 if (!objectStoreInfo) {
859 performErrorCallback(callbackID, { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to rename index in non-existant object store") });
863 auto* indexInfo = objectStoreInfo->infoForExistingIndex(indexIdentifier);
865 performErrorCallback(callbackID, { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to rename non-existant index") });
869 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performRenameIndex, callbackID, transaction.info().identifier(), objectStoreIdentifier, indexIdentifier, newName));
872 void UniqueIDBDatabase::performRenameIndex(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const String& newName)
874 ASSERT(!isMainThread());
875 LOG(IndexedDB, "(db) UniqueIDBDatabase::performRenameIndex");
877 ASSERT(m_backingStore);
878 m_backingStore->renameIndex(transactionIdentifier, objectStoreIdentifier, indexIdentifier, newName);
881 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformRenameIndex, callbackIdentifier, error, objectStoreIdentifier, indexIdentifier, newName));
884 void UniqueIDBDatabase::didPerformRenameIndex(uint64_t callbackIdentifier, const IDBError& error, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const String& newName)
886 ASSERT(isMainThread());
887 LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformRenameIndex");
889 if (error.isNull()) {
890 auto* objectStoreInfo = m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
891 ASSERT(objectStoreInfo);
892 if (objectStoreInfo) {
893 auto* indexInfo = objectStoreInfo->infoForExistingIndex(indexIdentifier);
895 indexInfo->rename(newName);
899 performErrorCallback(callbackIdentifier, error);
902 void UniqueIDBDatabase::putOrAdd(const IDBRequestData& requestData, const IDBKeyData& keyData, const IDBValue& value, IndexedDB::ObjectStoreOverwriteMode overwriteMode, KeyDataCallback callback)
904 ASSERT(isMainThread());
905 LOG(IndexedDB, "(main) UniqueIDBDatabase::putOrAdd");
907 uint64_t callbackID = storeCallbackOrFireError(callback);
910 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performPutOrAdd, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), keyData, value, overwriteMode));
913 VM& UniqueIDBDatabase::databaseThreadVM()
915 ASSERT(!isMainThread());
916 static VM* vm = &VM::create().leakRef();
920 ExecState& UniqueIDBDatabase::databaseThreadExecState()
922 ASSERT(!isMainThread());
924 static NeverDestroyed<Strong<JSGlobalObject>> globalObject(databaseThreadVM(), JSGlobalObject::create(databaseThreadVM(), JSGlobalObject::createStructure(databaseThreadVM(), jsNull())));
926 RELEASE_ASSERT(globalObject.get()->globalExec());
927 return *globalObject.get()->globalExec();
930 void UniqueIDBDatabase::performPutOrAdd(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyData& keyData, const IDBValue& originalRecordValue, IndexedDB::ObjectStoreOverwriteMode overwriteMode)
932 ASSERT(!isMainThread());
933 LOG(IndexedDB, "(db) UniqueIDBDatabase::performPutOrAdd");
935 ASSERT(m_backingStore);
936 ASSERT(objectStoreIdentifier);
941 auto* objectStoreInfo = m_backingStore->infoForObjectStore(objectStoreIdentifier);
942 if (!objectStoreInfo) {
943 error = IDBError(IDBDatabaseException::InvalidStateError, ASCIILiteral("Object store cannot be found in the backing store"));
944 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));
948 bool usedKeyIsGenerated = false;
949 ScopeGuard generatedKeyResetter;
950 if (objectStoreInfo->autoIncrement() && !keyData.isValid()) {
952 error = m_backingStore->generateKeyNumber(transactionIdentifier, objectStoreIdentifier, keyNumber);
953 if (!error.isNull()) {
954 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));
958 usedKey.setNumberValue(keyNumber);
959 usedKeyIsGenerated = true;
960 generatedKeyResetter.enable([this, transactionIdentifier, objectStoreIdentifier, keyNumber]() {
961 m_backingStore->revertGeneratedKeyNumber(transactionIdentifier, objectStoreIdentifier, keyNumber);
966 if (overwriteMode == IndexedDB::ObjectStoreOverwriteMode::NoOverwrite) {
968 error = m_backingStore->keyExistsInObjectStore(transactionIdentifier, objectStoreIdentifier, usedKey, keyExists);
969 if (error.isNull() && keyExists)
970 error = IDBError(IDBDatabaseException::ConstraintError, ASCIILiteral("Key already exists in the object store"));
972 if (!error.isNull()) {
973 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));
978 // 3.4.1.2 Object Store Storage Operation
979 // If ObjectStore has a key path and the key is autogenerated, then inject the key into the value
980 // using steps to assign a key to a value using a key path.
981 ThreadSafeDataBuffer injectedRecordValue;
982 if (usedKeyIsGenerated && objectStoreInfo->keyPath()) {
983 VM& vm = databaseThreadVM();
984 JSLockHolder locker(vm);
985 auto scope = DECLARE_THROW_SCOPE(vm);
987 auto value = deserializeIDBValueToJSValue(databaseThreadExecState(), originalRecordValue.data());
988 if (value.isUndefined()) {
989 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, IDBError(IDBDatabaseException::ConstraintError, ASCIILiteral("Unable to deserialize record value for record key injection")), usedKey));
993 if (!injectIDBKeyIntoScriptValue(databaseThreadExecState(), usedKey, value, objectStoreInfo->keyPath().value())) {
994 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, IDBError(IDBDatabaseException::ConstraintError, ASCIILiteral("Unable to inject record key into record value")), usedKey));
998 auto serializedValue = SerializedScriptValue::create(databaseThreadExecState(), value);
999 if (UNLIKELY(scope.exception())) {
1000 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, IDBError(IDBDatabaseException::ConstraintError, ASCIILiteral("Unable to serialize record value after injecting record key")), usedKey));
1004 injectedRecordValue = ThreadSafeDataBuffer::copyVector(serializedValue->data());
1007 // 3.4.1 Object Store Storage Operation
1008 // ...If a record already exists in store ...
1009 // then remove the record from store using the steps for deleting records from an object store...
1010 // This is important because formally deleting it from from the object store also removes it from the appropriate indexes.
1011 error = m_backingStore->deleteRange(transactionIdentifier, objectStoreIdentifier, usedKey);
1012 if (!error.isNull()) {
1013 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));
1017 if (injectedRecordValue.data())
1018 error = m_backingStore->addRecord(transactionIdentifier, *objectStoreInfo, usedKey, { injectedRecordValue, originalRecordValue.blobURLs(), originalRecordValue.blobFilePaths() });
1020 error = m_backingStore->addRecord(transactionIdentifier, *objectStoreInfo, usedKey, originalRecordValue);
1022 if (!error.isNull()) {
1023 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));
1027 if (overwriteMode != IndexedDB::ObjectStoreOverwriteMode::OverwriteForCursor && objectStoreInfo->autoIncrement() && keyData.type() == IndexedDB::KeyType::Number)
1028 error = m_backingStore->maybeUpdateKeyGeneratorNumber(transactionIdentifier, objectStoreIdentifier, keyData.number());
1030 generatedKeyResetter.disable();
1031 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));
1034 void UniqueIDBDatabase::didPerformPutOrAdd(uint64_t callbackIdentifier, const IDBError& error, const IDBKeyData& resultKey)
1036 ASSERT(isMainThread());
1037 LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformPutOrAdd");
1039 performKeyDataCallback(callbackIdentifier, error, resultKey);
1042 void UniqueIDBDatabase::getRecord(const IDBRequestData& requestData, const IDBGetRecordData& getRecordData, GetResultCallback callback)
1044 ASSERT(isMainThread());
1045 LOG(IndexedDB, "(main) UniqueIDBDatabase::getRecord");
1047 uint64_t callbackID = storeCallbackOrFireError(callback);
1051 if (uint64_t indexIdentifier = requestData.indexIdentifier())
1052 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performGetIndexRecord, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), indexIdentifier, requestData.indexRecordType(), getRecordData.keyRangeData));
1054 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performGetRecord, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), getRecordData.keyRangeData, getRecordData.type));
1057 void UniqueIDBDatabase::getAllRecords(const IDBRequestData& requestData, const IDBGetAllRecordsData& getAllRecordsData, GetAllResultsCallback callback)
1059 ASSERT(isMainThread());
1060 LOG(IndexedDB, "(main) UniqueIDBDatabase::getAllRecords");
1062 uint64_t callbackID = storeCallbackOrFireError(callback);
1066 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performGetAllRecords, callbackID, requestData.transactionIdentifier(), getAllRecordsData));
1069 void UniqueIDBDatabase::performGetRecord(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyRangeData& keyRangeData, IDBGetRecordDataType type)
1071 ASSERT(!isMainThread());
1072 LOG(IndexedDB, "(db) UniqueIDBDatabase::performGetRecord");
1074 ASSERT(m_backingStore);
1076 IDBGetResult result;
1077 IDBError error = m_backingStore->getRecord(transactionIdentifier, objectStoreIdentifier, keyRangeData, type, result);
1079 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformGetRecord, callbackIdentifier, error, result));
1082 void UniqueIDBDatabase::performGetIndexRecord(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, IndexedDB::IndexRecordType recordType, const IDBKeyRangeData& range)
1084 ASSERT(!isMainThread());
1085 LOG(IndexedDB, "(db) UniqueIDBDatabase::performGetIndexRecord");
1087 ASSERT(m_backingStore);
1089 IDBGetResult result;
1090 IDBError error = m_backingStore->getIndexRecord(transactionIdentifier, objectStoreIdentifier, indexIdentifier, recordType, range, result);
1092 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformGetRecord, callbackIdentifier, error, result));
1095 void UniqueIDBDatabase::didPerformGetRecord(uint64_t callbackIdentifier, const IDBError& error, const IDBGetResult& result)
1097 ASSERT(isMainThread());
1098 LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformGetRecord");
1100 performGetResultCallback(callbackIdentifier, error, result);
1103 void UniqueIDBDatabase::performGetAllRecords(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, const IDBGetAllRecordsData& getAllRecordsData)
1105 ASSERT(!isMainThread());
1106 LOG(IndexedDB, "(db) UniqueIDBDatabase::performGetAllRecords");
1108 ASSERT(m_backingStore);
1110 IDBGetAllResult result;
1111 IDBError error = m_backingStore->getAllRecords(transactionIdentifier, getAllRecordsData, result);
1113 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformGetAllRecords, callbackIdentifier, error, WTFMove(result)));
1116 void UniqueIDBDatabase::didPerformGetAllRecords(uint64_t callbackIdentifier, const IDBError& error, const IDBGetAllResult& result)
1118 ASSERT(isMainThread());
1119 LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformGetAllRecords");
1121 performGetAllResultsCallback(callbackIdentifier, error, result);
1124 void UniqueIDBDatabase::getCount(const IDBRequestData& requestData, const IDBKeyRangeData& range, CountCallback callback)
1126 ASSERT(isMainThread());
1127 LOG(IndexedDB, "(main) UniqueIDBDatabase::getCount");
1129 uint64_t callbackID = storeCallbackOrFireError(callback);
1132 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performGetCount, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), requestData.indexIdentifier(), range));
1135 void UniqueIDBDatabase::performGetCount(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const IDBKeyRangeData& keyRangeData)
1137 ASSERT(!isMainThread());
1138 LOG(IndexedDB, "(db) UniqueIDBDatabase::performGetCount");
1140 ASSERT(m_backingStore);
1141 ASSERT(objectStoreIdentifier);
1144 IDBError error = m_backingStore->getCount(transactionIdentifier, objectStoreIdentifier, indexIdentifier, keyRangeData, count);
1146 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformGetCount, callbackIdentifier, error, count));
1149 void UniqueIDBDatabase::didPerformGetCount(uint64_t callbackIdentifier, const IDBError& error, uint64_t count)
1151 ASSERT(isMainThread());
1152 LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformGetCount");
1154 performCountCallback(callbackIdentifier, error, count);
1157 void UniqueIDBDatabase::deleteRecord(const IDBRequestData& requestData, const IDBKeyRangeData& keyRangeData, ErrorCallback callback)
1159 ASSERT(isMainThread());
1160 LOG(IndexedDB, "(main) UniqueIDBDatabase::deleteRecord");
1162 uint64_t callbackID = storeCallbackOrFireError(callback);
1165 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performDeleteRecord, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), keyRangeData));
1168 void UniqueIDBDatabase::performDeleteRecord(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyRangeData& range)
1170 ASSERT(!isMainThread());
1171 LOG(IndexedDB, "(db) UniqueIDBDatabase::performDeleteRecord");
1173 IDBError error = m_backingStore->deleteRange(transactionIdentifier, objectStoreIdentifier, range);
1175 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformDeleteRecord, callbackIdentifier, error));
1178 void UniqueIDBDatabase::didPerformDeleteRecord(uint64_t callbackIdentifier, const IDBError& error)
1180 ASSERT(isMainThread());
1181 LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformDeleteRecord");
1183 performErrorCallback(callbackIdentifier, error);
1186 void UniqueIDBDatabase::openCursor(const IDBRequestData& requestData, const IDBCursorInfo& info, GetResultCallback callback)
1188 ASSERT(isMainThread());
1189 LOG(IndexedDB, "(main) UniqueIDBDatabase::openCursor");
1191 uint64_t callbackID = storeCallbackOrFireError(callback);
1194 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performOpenCursor, callbackID, requestData.transactionIdentifier(), info));
1197 void UniqueIDBDatabase::performOpenCursor(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, const IDBCursorInfo& info)
1199 ASSERT(!isMainThread());
1200 LOG(IndexedDB, "(db) UniqueIDBDatabase::performOpenCursor");
1202 IDBGetResult result;
1203 IDBError error = m_backingStore->openCursor(transactionIdentifier, info, result);
1205 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformOpenCursor, callbackIdentifier, error, result));
1208 void UniqueIDBDatabase::didPerformOpenCursor(uint64_t callbackIdentifier, const IDBError& error, const IDBGetResult& result)
1210 ASSERT(isMainThread());
1211 LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformOpenCursor");
1213 performGetResultCallback(callbackIdentifier, error, result);
1216 void UniqueIDBDatabase::iterateCursor(const IDBRequestData& requestData, const IDBIterateCursorData& data, GetResultCallback callback)
1218 ASSERT(isMainThread());
1219 LOG(IndexedDB, "(main) UniqueIDBDatabase::iterateCursor");
1221 uint64_t callbackID = storeCallbackOrFireError(callback);
1224 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performIterateCursor, callbackID, requestData.transactionIdentifier(), requestData.cursorIdentifier(), data));
1227 void UniqueIDBDatabase::performIterateCursor(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, const IDBResourceIdentifier& cursorIdentifier, const IDBIterateCursorData& data)
1229 ASSERT(!isMainThread());
1230 LOG(IndexedDB, "(db) UniqueIDBDatabase::performIterateCursor");
1232 IDBGetResult result;
1233 IDBError error = m_backingStore->iterateCursor(transactionIdentifier, cursorIdentifier, data, result);
1235 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformIterateCursor, callbackIdentifier, error, result));
1238 void UniqueIDBDatabase::didPerformIterateCursor(uint64_t callbackIdentifier, const IDBError& error, const IDBGetResult& result)
1240 ASSERT(isMainThread());
1241 LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformIterateCursor");
1243 performGetResultCallback(callbackIdentifier, error, result);
1246 bool UniqueIDBDatabase::prepareToFinishTransaction(UniqueIDBDatabaseTransaction& transaction)
1248 auto takenTransaction = m_inProgressTransactions.take(transaction.info().identifier());
1249 if (!takenTransaction)
1252 ASSERT(!m_finishingTransactions.contains(transaction.info().identifier()));
1253 m_finishingTransactions.set(transaction.info().identifier(), WTFMove(takenTransaction));
1258 void UniqueIDBDatabase::commitTransaction(UniqueIDBDatabaseTransaction& transaction, ErrorCallback callback)
1260 ASSERT(isMainThread());
1261 LOG(IndexedDB, "(main) UniqueIDBDatabase::commitTransaction - %s", transaction.info().identifier().loggingString().utf8().data());
1263 ASSERT(&transaction.databaseConnection().database() == this);
1265 uint64_t callbackID = storeCallbackOrFireError(callback);
1269 if (!prepareToFinishTransaction(transaction)) {
1270 if (!m_openDatabaseConnections.contains(&transaction.databaseConnection())) {
1271 // This database connection is closing or has already closed, so there is no point in messaging back to it about the commit failing.
1272 forgetErrorCallback(callbackID);
1276 performErrorCallback(callbackID, { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to commit transaction that is already finishing") });
1280 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performCommitTransaction, callbackID, transaction.info().identifier()));
1283 void UniqueIDBDatabase::performCommitTransaction(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier)
1285 ASSERT(!isMainThread());
1286 LOG(IndexedDB, "(db) UniqueIDBDatabase::performCommitTransaction - %s", transactionIdentifier.loggingString().utf8().data());
1288 IDBError error = m_backingStore->commitTransaction(transactionIdentifier);
1289 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformCommitTransaction, callbackIdentifier, error, transactionIdentifier));
1292 void UniqueIDBDatabase::didPerformCommitTransaction(uint64_t callbackIdentifier, const IDBError& error, const IDBResourceIdentifier& transactionIdentifier)
1294 ASSERT(isMainThread());
1295 LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformCommitTransaction - %s", transactionIdentifier.loggingString().utf8().data());
1297 performErrorCallback(callbackIdentifier, error);
1299 transactionCompleted(m_finishingTransactions.take(transactionIdentifier));
1302 void UniqueIDBDatabase::abortTransaction(UniqueIDBDatabaseTransaction& transaction, ErrorCallback callback)
1304 ASSERT(isMainThread());
1305 LOG(IndexedDB, "(main) UniqueIDBDatabase::abortTransaction - %s", transaction.info().identifier().loggingString().utf8().data());
1307 ASSERT(&transaction.databaseConnection().database() == this);
1309 uint64_t callbackID = storeCallbackOrFireError(callback);
1313 if (!prepareToFinishTransaction(transaction)) {
1314 if (!m_openDatabaseConnections.contains(&transaction.databaseConnection())) {
1315 // This database connection is closing or has already closed, so there is no point in messaging back to it about the abort failing.
1316 forgetErrorCallback(callbackID);
1320 performErrorCallback(callbackID, { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to abort transaction that is already finishing") });
1324 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performAbortTransaction, callbackID, transaction.info().identifier()));
1327 void UniqueIDBDatabase::didFinishHandlingVersionChange(UniqueIDBDatabaseConnection& connection, const IDBResourceIdentifier& transactionIdentifier)
1329 ASSERT(isMainThread());
1330 LOG(IndexedDB, "(main) UniqueIDBDatabase::didFinishHandlingVersionChange");
1332 ASSERT_UNUSED(transactionIdentifier, !m_versionChangeTransaction || m_versionChangeTransaction->info().identifier() == transactionIdentifier);
1333 ASSERT_UNUSED(connection, !m_versionChangeDatabaseConnection || m_versionChangeDatabaseConnection.get() == &connection);
1335 m_versionChangeTransaction = nullptr;
1336 m_versionChangeDatabaseConnection = nullptr;
1338 if (m_hardClosedForUserDelete) {
1339 maybeFinishHardClose();
1343 invokeOperationAndTransactionTimer();
1346 void UniqueIDBDatabase::performAbortTransaction(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier)
1348 ASSERT(!isMainThread());
1349 LOG(IndexedDB, "(db) UniqueIDBDatabase::performAbortTransaction - %s", transactionIdentifier.loggingString().utf8().data());
1351 IDBError error = m_backingStore->abortTransaction(transactionIdentifier);
1352 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformAbortTransaction, callbackIdentifier, error, transactionIdentifier));
1355 void UniqueIDBDatabase::didPerformAbortTransaction(uint64_t callbackIdentifier, const IDBError& error, const IDBResourceIdentifier& transactionIdentifier)
1357 ASSERT(isMainThread());
1358 LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformAbortTransaction - %s", transactionIdentifier.loggingString().utf8().data());
1360 auto transaction = m_finishingTransactions.take(transactionIdentifier);
1361 ASSERT(transaction);
1363 if (m_versionChangeTransaction && m_versionChangeTransaction->info().identifier() == transactionIdentifier) {
1364 ASSERT(m_versionChangeTransaction == transaction);
1365 ASSERT(!m_versionChangeDatabaseConnection || &m_versionChangeTransaction->databaseConnection() == m_versionChangeDatabaseConnection);
1366 ASSERT(m_versionChangeTransaction->originalDatabaseInfo());
1367 m_databaseInfo = std::make_unique<IDBDatabaseInfo>(*m_versionChangeTransaction->originalDatabaseInfo());
1370 performErrorCallback(callbackIdentifier, error);
1372 transactionCompleted(WTFMove(transaction));
1375 void UniqueIDBDatabase::transactionDestroyed(UniqueIDBDatabaseTransaction& transaction)
1377 if (m_versionChangeTransaction == &transaction)
1378 m_versionChangeTransaction = nullptr;
1381 void UniqueIDBDatabase::connectionClosedFromClient(UniqueIDBDatabaseConnection& connection)
1383 ASSERT(isMainThread());
1384 LOG(IndexedDB, "(main) UniqueIDBDatabase::connectionClosedFromClient - %s (%" PRIu64 ")", connection.openRequestIdentifier().loggingString().utf8().data(), connection.identifier());
1386 Ref<UniqueIDBDatabaseConnection> protectedConnection(connection);
1387 m_openDatabaseConnections.remove(&connection);
1389 if (m_versionChangeDatabaseConnection == &connection) {
1390 if (m_versionChangeTransaction) {
1391 m_clientClosePendingDatabaseConnections.add(WTFMove(m_versionChangeDatabaseConnection));
1393 auto transactionIdentifier = m_versionChangeTransaction->info().identifier();
1394 if (m_inProgressTransactions.contains(transactionIdentifier)) {
1395 ASSERT(!m_finishingTransactions.contains(transactionIdentifier));
1396 connection.abortTransactionWithoutCallback(*m_versionChangeTransaction);
1402 m_versionChangeDatabaseConnection = nullptr;
1405 Deque<RefPtr<UniqueIDBDatabaseTransaction>> pendingTransactions;
1406 while (!m_pendingTransactions.isEmpty()) {
1407 auto transaction = m_pendingTransactions.takeFirst();
1408 if (&transaction->databaseConnection() != &connection)
1409 pendingTransactions.append(WTFMove(transaction));
1412 if (!pendingTransactions.isEmpty())
1413 m_pendingTransactions.swap(pendingTransactions);
1415 Deque<RefPtr<UniqueIDBDatabaseTransaction>> transactionsToAbort;
1416 for (auto& transaction : m_inProgressTransactions.values()) {
1417 if (&transaction->databaseConnection() == &connection)
1418 transactionsToAbort.append(transaction);
1421 for (auto& transaction : transactionsToAbort)
1422 transaction->abortWithoutCallback();
1424 if (m_currentOpenDBRequest)
1425 notifyCurrentRequestConnectionClosedOrFiredVersionChangeEvent(connection.identifier());
1427 if (connection.hasNonFinishedTransactions()) {
1428 m_clientClosePendingDatabaseConnections.add(WTFMove(protectedConnection));
1432 if (m_hardClosedForUserDelete) {
1433 maybeFinishHardClose();
1437 // Now that a database connection has closed, previously blocked operations might be runnable.
1438 invokeOperationAndTransactionTimer();
1441 void UniqueIDBDatabase::connectionClosedFromServer(UniqueIDBDatabaseConnection& connection)
1443 ASSERT(isMainThread());
1444 LOG(IndexedDB, "UniqueIDBDatabase::connectionClosedFromServer - %s (%" PRIu64 ")", connection.openRequestIdentifier().loggingString().utf8().data(), connection.identifier());
1446 if (m_clientClosePendingDatabaseConnections.contains(&connection)) {
1447 ASSERT(!m_openDatabaseConnections.contains(&connection));
1448 ASSERT(!m_serverClosePendingDatabaseConnections.contains(&connection));
1452 Ref<UniqueIDBDatabaseConnection> protectedConnection(connection);
1453 m_openDatabaseConnections.remove(&connection);
1455 connection.connectionToClient().didCloseFromServer(connection, IDBError::userDeleteError());
1457 m_serverClosePendingDatabaseConnections.add(WTFMove(protectedConnection));
1460 void UniqueIDBDatabase::confirmDidCloseFromServer(UniqueIDBDatabaseConnection& connection)
1462 ASSERT(isMainThread());
1463 LOG(IndexedDB, "UniqueIDBDatabase::confirmDidCloseFromServer - %s (%" PRIu64 ")", connection.openRequestIdentifier().loggingString().utf8().data(), connection.identifier());
1465 ASSERT(m_serverClosePendingDatabaseConnections.contains(&connection));
1466 m_serverClosePendingDatabaseConnections.remove(&connection);
1469 void UniqueIDBDatabase::enqueueTransaction(Ref<UniqueIDBDatabaseTransaction>&& transaction)
1471 LOG(IndexedDB, "UniqueIDBDatabase::enqueueTransaction - %s", transaction->info().loggingString().utf8().data());
1472 ASSERT(!m_hardClosedForUserDelete);
1474 ASSERT(transaction->info().mode() != IDBTransactionMode::Versionchange);
1476 m_pendingTransactions.append(WTFMove(transaction));
1478 invokeOperationAndTransactionTimer();
1481 bool UniqueIDBDatabase::isCurrentlyInUse() const
1483 return !m_openDatabaseConnections.isEmpty() || !m_clientClosePendingDatabaseConnections.isEmpty() || !m_pendingOpenDBRequests.isEmpty() || m_currentOpenDBRequest || m_versionChangeDatabaseConnection || m_versionChangeTransaction || m_isOpeningBackingStore || m_deleteBackingStoreInProgress;
1486 bool UniqueIDBDatabase::hasUnfinishedTransactions() const
1488 return !m_inProgressTransactions.isEmpty() || !m_finishingTransactions.isEmpty();
1491 void UniqueIDBDatabase::invokeOperationAndTransactionTimer()
1493 LOG(IndexedDB, "UniqueIDBDatabase::invokeOperationAndTransactionTimer()");
1494 ASSERT(!m_hardClosedForUserDelete);
1496 if (!m_operationAndTransactionTimer.isActive())
1497 m_operationAndTransactionTimer.startOneShot(0);
1500 void UniqueIDBDatabase::operationAndTransactionTimerFired()
1502 LOG(IndexedDB, "(main) UniqueIDBDatabase::operationAndTransactionTimerFired");
1503 ASSERT(!m_hardClosedForUserDelete);
1505 RefPtr<UniqueIDBDatabase> protectedThis(this);
1507 // This UniqueIDBDatabase might be no longer in use by any web page.
1508 // Assuming it is not ephemeral, the server should now close it to free up resources.
1509 if (!m_backingStoreIsEphemeral && !isCurrentlyInUse()) {
1510 ASSERT(m_pendingTransactions.isEmpty());
1511 ASSERT(!hasUnfinishedTransactions());
1512 m_server.closeUniqueIDBDatabase(*this);
1516 // The current operation might require multiple attempts to handle, so try to
1517 // make further progress on it now.
1518 if (m_currentOpenDBRequest)
1519 handleCurrentOperation();
1521 if (!m_currentOpenDBRequest)
1522 handleDatabaseOperations();
1524 bool hadDeferredTransactions = false;
1525 auto transaction = takeNextRunnableTransaction(hadDeferredTransactions);
1528 m_inProgressTransactions.set(transaction->info().identifier(), transaction);
1529 for (auto objectStore : transaction->objectStoreIdentifiers()) {
1530 m_objectStoreTransactionCounts.add(objectStore);
1531 if (!transaction->isReadOnly()) {
1532 m_objectStoreWriteTransactions.add(objectStore);
1533 ASSERT(m_objectStoreTransactionCounts.count(objectStore) == 1);
1537 activateTransactionInBackingStore(*transaction);
1539 // If no transactions were deferred, it's possible we can start another transaction right now.
1540 if (!hadDeferredTransactions)
1541 invokeOperationAndTransactionTimer();
1545 void UniqueIDBDatabase::activateTransactionInBackingStore(UniqueIDBDatabaseTransaction& transaction)
1547 LOG(IndexedDB, "(main) UniqueIDBDatabase::activateTransactionInBackingStore");
1549 RefPtr<UniqueIDBDatabase> protectedThis(this);
1550 RefPtr<UniqueIDBDatabaseTransaction> refTransaction(&transaction);
1552 auto callback = [this, protectedThis, refTransaction](const IDBError& error) {
1553 refTransaction->didActivateInBackingStore(error);
1556 uint64_t callbackID = storeCallbackOrFireError(callback);
1559 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performActivateTransactionInBackingStore, callbackID, transaction.info()));
1562 void UniqueIDBDatabase::performActivateTransactionInBackingStore(uint64_t callbackIdentifier, const IDBTransactionInfo& info)
1564 LOG(IndexedDB, "(db) UniqueIDBDatabase::performActivateTransactionInBackingStore");
1566 IDBError error = m_backingStore->beginTransaction(info);
1567 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformActivateTransactionInBackingStore, callbackIdentifier, error));
1570 void UniqueIDBDatabase::didPerformActivateTransactionInBackingStore(uint64_t callbackIdentifier, const IDBError& error)
1572 LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformActivateTransactionInBackingStore");
1574 invokeOperationAndTransactionTimer();
1576 performErrorCallback(callbackIdentifier, error);
1579 template<typename T> bool scopesOverlap(const T& aScopes, const Vector<uint64_t>& bScopes)
1581 for (auto scope : bScopes) {
1582 if (aScopes.contains(scope))
1589 RefPtr<UniqueIDBDatabaseTransaction> UniqueIDBDatabase::takeNextRunnableTransaction(bool& hadDeferredTransactions)
1591 hadDeferredTransactions = false;
1593 if (m_pendingTransactions.isEmpty())
1596 if (!m_backingStoreSupportsSimultaneousTransactions && hasUnfinishedTransactions()) {
1597 LOG(IndexedDB, "UniqueIDBDatabase::takeNextRunnableTransaction - Backing store only supports 1 transaction, and we already have 1");
1601 Deque<RefPtr<UniqueIDBDatabaseTransaction>> deferredTransactions;
1602 RefPtr<UniqueIDBDatabaseTransaction> currentTransaction;
1604 HashSet<uint64_t> deferredReadWriteScopes;
1606 while (!m_pendingTransactions.isEmpty()) {
1607 currentTransaction = m_pendingTransactions.takeFirst();
1609 switch (currentTransaction->info().mode()) {
1610 case IDBTransactionMode::Readonly: {
1611 bool hasOverlappingScopes = scopesOverlap(deferredReadWriteScopes, currentTransaction->objectStoreIdentifiers());
1612 hasOverlappingScopes |= scopesOverlap(m_objectStoreWriteTransactions, currentTransaction->objectStoreIdentifiers());
1614 if (hasOverlappingScopes)
1615 deferredTransactions.append(WTFMove(currentTransaction));
1619 case IDBTransactionMode::Readwrite: {
1620 bool hasOverlappingScopes = scopesOverlap(m_objectStoreTransactionCounts, currentTransaction->objectStoreIdentifiers());
1621 hasOverlappingScopes |= scopesOverlap(deferredReadWriteScopes, currentTransaction->objectStoreIdentifiers());
1623 if (hasOverlappingScopes) {
1624 for (auto objectStore : currentTransaction->objectStoreIdentifiers())
1625 deferredReadWriteScopes.add(objectStore);
1626 deferredTransactions.append(WTFMove(currentTransaction));
1631 case IDBTransactionMode::Versionchange:
1632 // Version change transactions should never be scheduled in the traditional manner.
1633 RELEASE_ASSERT_NOT_REACHED();
1636 // If we didn't defer the currentTransaction above, it can be run now.
1637 if (currentTransaction)
1641 hadDeferredTransactions = !deferredTransactions.isEmpty();
1642 if (!hadDeferredTransactions)
1643 return currentTransaction;
1645 // Prepend the deferred transactions back on the beginning of the deque for future scheduling passes.
1646 while (!deferredTransactions.isEmpty())
1647 m_pendingTransactions.prepend(deferredTransactions.takeLast());
1649 return currentTransaction;
1652 void UniqueIDBDatabase::transactionCompleted(RefPtr<UniqueIDBDatabaseTransaction>&& transaction)
1654 ASSERT(transaction);
1655 ASSERT(!m_inProgressTransactions.contains(transaction->info().identifier()));
1656 ASSERT(!m_finishingTransactions.contains(transaction->info().identifier()));
1658 for (auto objectStore : transaction->objectStoreIdentifiers()) {
1659 if (!transaction->isReadOnly()) {
1660 m_objectStoreWriteTransactions.remove(objectStore);
1661 ASSERT(m_objectStoreTransactionCounts.count(objectStore) == 1);
1663 m_objectStoreTransactionCounts.remove(objectStore);
1666 if (!transaction->databaseConnection().hasNonFinishedTransactions())
1667 m_clientClosePendingDatabaseConnections.remove(&transaction->databaseConnection());
1669 if (m_versionChangeTransaction == transaction)
1670 m_versionChangeTransaction = nullptr;
1672 // It's possible that this database had its backing store deleted but there were a few outstanding asynchronous operations.
1673 // If this transaction completing was the last of those operations, we can finally delete this UniqueIDBDatabase.
1674 if (m_clientClosePendingDatabaseConnections.isEmpty() && m_pendingOpenDBRequests.isEmpty() && !m_databaseInfo) {
1675 m_server.closeUniqueIDBDatabase(*this);
1679 // Previously blocked operations might be runnable.
1680 if (!m_hardClosedForUserDelete)
1681 invokeOperationAndTransactionTimer();
1683 maybeFinishHardClose();
1686 void UniqueIDBDatabase::postDatabaseTask(CrossThreadTask&& task)
1688 ASSERT(isMainThread());
1689 m_databaseQueue.append(WTFMove(task));
1690 ++m_queuedTaskCount;
1692 m_server.postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::executeNextDatabaseTask));
1695 void UniqueIDBDatabase::postDatabaseTaskReply(CrossThreadTask&& task)
1697 ASSERT(!isMainThread());
1698 m_databaseReplyQueue.append(WTFMove(task));
1699 ++m_queuedTaskCount;
1701 m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::executeNextDatabaseTaskReply));
1704 void UniqueIDBDatabase::executeNextDatabaseTask()
1706 ASSERT(!isMainThread());
1707 ASSERT(m_queuedTaskCount);
1709 auto task = m_databaseQueue.tryGetMessage();
1712 // Performing the task might end up removing the last reference to this.
1713 Ref<UniqueIDBDatabase> protectedThis(*this);
1715 task->performTask();
1716 --m_queuedTaskCount;
1718 // Release the ref in the main thread to ensure it's deleted there as expected in case of being the last reference.
1719 callOnMainThread([protectedThis = WTFMove(protectedThis)] {
1723 void UniqueIDBDatabase::executeNextDatabaseTaskReply()
1725 ASSERT(isMainThread());
1726 ASSERT(m_queuedTaskCount);
1728 auto task = m_databaseReplyQueue.tryGetMessage();
1731 // Performing the task might end up removing the last reference to this.
1732 Ref<UniqueIDBDatabase> protectedThis(*this);
1734 task->performTask();
1735 --m_queuedTaskCount;
1737 // If this database was force closed (e.g. for a user delete) and there are no more
1738 // cleanup tasks left, delete this.
1739 maybeFinishHardClose();
1742 void UniqueIDBDatabase::maybeFinishHardClose()
1744 if (m_hardCloseProtector && isDoneWithHardClose()) {
1745 callOnMainThread([this] {
1746 ASSERT(isDoneWithHardClose());
1747 m_hardCloseProtector = nullptr;
1752 bool UniqueIDBDatabase::isDoneWithHardClose()
1754 return !m_queuedTaskCount && m_clientClosePendingDatabaseConnections.isEmpty() && m_serverClosePendingDatabaseConnections.isEmpty();
1757 static void errorOpenDBRequestForUserDelete(ServerOpenDBRequest& request)
1759 auto result = IDBResultData::error(request.requestData().requestIdentifier(), IDBError::userDeleteError());
1760 if (request.isOpenRequest())
1761 request.connection().didOpenDatabase(result);
1763 request.connection().didDeleteDatabase(result);
1766 void UniqueIDBDatabase::immediateCloseForUserDelete()
1768 LOG(IndexedDB, "UniqueIDBDatabase::immediateCloseForUserDelete - Cancelling (%i, %i, %i, %i) callbacks", m_errorCallbacks.size(), m_keyDataCallbacks.size(), m_getResultCallbacks.size(), m_countCallbacks.size());
1770 // Error out all transactions
1771 Vector<IDBResourceIdentifier> inProgressIdentifiers;
1772 copyKeysToVector(m_inProgressTransactions, inProgressIdentifiers);
1773 for (auto& identifier : inProgressIdentifiers)
1774 m_inProgressTransactions.get(identifier)->abortWithoutCallback();
1776 ASSERT(m_inProgressTransactions.isEmpty());
1778 m_pendingTransactions.clear();
1779 m_objectStoreTransactionCounts.clear();
1780 m_objectStoreWriteTransactions.clear();
1782 // Error out all pending callbacks
1783 Vector<uint64_t> callbackIdentifiers;
1784 IDBError error = IDBError::userDeleteError();
1786 IDBGetResult getResult;
1788 copyKeysToVector(m_errorCallbacks, callbackIdentifiers);
1789 for (auto identifier : callbackIdentifiers)
1790 performErrorCallback(identifier, error);
1792 callbackIdentifiers.clear();
1793 copyKeysToVector(m_keyDataCallbacks, callbackIdentifiers);
1794 for (auto identifier : callbackIdentifiers)
1795 performKeyDataCallback(identifier, error, keyData);
1797 callbackIdentifiers.clear();
1798 copyKeysToVector(m_getResultCallbacks, callbackIdentifiers);
1799 for (auto identifier : callbackIdentifiers)
1800 performGetResultCallback(identifier, error, getResult);
1802 callbackIdentifiers.clear();
1803 copyKeysToVector(m_countCallbacks, callbackIdentifiers);
1804 for (auto identifier : callbackIdentifiers)
1805 performCountCallback(identifier, error, 0);
1807 // Error out all IDBOpenDBRequests
1808 if (m_currentOpenDBRequest) {
1809 errorOpenDBRequestForUserDelete(*m_currentOpenDBRequest);
1810 m_currentOpenDBRequest = nullptr;
1813 for (auto& request : m_pendingOpenDBRequests)
1814 errorOpenDBRequestForUserDelete(*request);
1816 m_pendingOpenDBRequests.clear();
1818 // Close all open connections
1819 ListHashSet<RefPtr<UniqueIDBDatabaseConnection>> openDatabaseConnections = m_openDatabaseConnections;
1820 for (auto& connection : openDatabaseConnections)
1821 connectionClosedFromServer(*connection);
1823 // Cancel the operation timer
1824 m_operationAndTransactionTimer.stop();
1826 // Set up the database to remain alive-but-inert until all of its background activity finishes and all
1827 // database connections confirm that they have closed.
1828 m_hardClosedForUserDelete = true;
1829 m_hardCloseProtector = this;
1831 // Have the database unconditionally delete itself on the database task queue.
1832 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performUnconditionalDeleteBackingStore));
1834 // Remove the database from the IDBServer's set of open databases.
1835 // If there is no in-progress background thread activity for this database, it will be deleted here.
1836 m_server.closeUniqueIDBDatabase(*this);
1839 void UniqueIDBDatabase::performErrorCallback(uint64_t callbackIdentifier, const IDBError& error)
1841 auto callback = m_errorCallbacks.take(callbackIdentifier);
1842 ASSERT(callback || m_hardClosedForUserDelete);
1847 void UniqueIDBDatabase::performKeyDataCallback(uint64_t callbackIdentifier, const IDBError& error, const IDBKeyData& resultKey)
1849 auto callback = m_keyDataCallbacks.take(callbackIdentifier);
1850 ASSERT(callback || m_hardClosedForUserDelete);
1852 callback(error, resultKey);
1855 void UniqueIDBDatabase::performGetResultCallback(uint64_t callbackIdentifier, const IDBError& error, const IDBGetResult& resultData)
1857 auto callback = m_getResultCallbacks.take(callbackIdentifier);
1858 ASSERT(callback || m_hardClosedForUserDelete);
1860 callback(error, resultData);
1863 void UniqueIDBDatabase::performGetAllResultsCallback(uint64_t callbackIdentifier, const IDBError& error, const IDBGetAllResult& resultData)
1865 auto callback = m_getAllResultsCallbacks.take(callbackIdentifier);
1866 ASSERT(callback || m_hardClosedForUserDelete);
1868 callback(error, resultData);
1871 void UniqueIDBDatabase::performCountCallback(uint64_t callbackIdentifier, const IDBError& error, uint64_t count)
1873 auto callback = m_countCallbacks.take(callbackIdentifier);
1874 ASSERT(callback || m_hardClosedForUserDelete);
1876 callback(error, count);
1879 void UniqueIDBDatabase::forgetErrorCallback(uint64_t callbackIdentifier)
1881 ASSERT(m_errorCallbacks.contains(callbackIdentifier));
1882 m_errorCallbacks.remove(callbackIdentifier);
1885 } // namespace IDBServer
1886 } // namespace WebCore
1888 #endif // ENABLE(INDEXED_DATABASE)