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>
50 #include <wtf/ThreadSafeRefCounted.h>
57 UniqueIDBDatabase::UniqueIDBDatabase(IDBServer& server, const IDBDatabaseIdentifier& identifier)
59 , m_identifier(identifier)
60 , m_operationAndTransactionTimer(*this, &UniqueIDBDatabase::operationAndTransactionTimerFired)
62 LOG(IndexedDB, "UniqueIDBDatabase::UniqueIDBDatabase() (%p) %s", this, m_identifier.debugString().utf8().data());
65 UniqueIDBDatabase::~UniqueIDBDatabase()
67 LOG(IndexedDB, "UniqueIDBDatabase::~UniqueIDBDatabase() (%p) %s", this, m_identifier.debugString().utf8().data());
68 ASSERT(isMainThread());
69 ASSERT(!hasAnyPendingCallbacks());
70 ASSERT(!hasUnfinishedTransactions());
71 ASSERT(m_pendingTransactions.isEmpty());
72 ASSERT(m_openDatabaseConnections.isEmpty());
73 ASSERT(m_clientClosePendingDatabaseConnections.isEmpty());
74 ASSERT(m_serverClosePendingDatabaseConnections.isEmpty());
75 ASSERT(!m_queuedTaskCount);
78 const IDBDatabaseInfo& UniqueIDBDatabase::info() const
80 RELEASE_ASSERT(m_databaseInfo);
81 return *m_databaseInfo;
84 void UniqueIDBDatabase::openDatabaseConnection(IDBConnectionToClient& connection, const IDBRequestData& requestData)
86 LOG(IndexedDB, "UniqueIDBDatabase::openDatabaseConnection");
87 ASSERT(!m_hardClosedForUserDelete);
89 m_pendingOpenDBRequests.add(ServerOpenDBRequest::create(connection, requestData));
91 // An open operation is already in progress, so we can't possibly handle this one yet.
92 if (m_isOpeningBackingStore)
95 handleDatabaseOperations();
98 bool UniqueIDBDatabase::hasAnyPendingCallbacks() const
100 return !m_errorCallbacks.isEmpty()
101 || !m_keyDataCallbacks.isEmpty()
102 || !m_getResultCallbacks.isEmpty()
103 || !m_getAllResultsCallbacks.isEmpty()
104 || !m_countCallbacks.isEmpty();
107 bool UniqueIDBDatabase::isVersionChangeInProgress()
110 if (m_versionChangeTransaction)
111 ASSERT(m_versionChangeDatabaseConnection);
114 return m_versionChangeDatabaseConnection;
117 void UniqueIDBDatabase::performCurrentOpenOperation()
119 LOG(IndexedDB, "(main) UniqueIDBDatabase::performCurrentOpenOperation (%p)", this);
121 ASSERT(m_currentOpenDBRequest);
122 ASSERT(m_currentOpenDBRequest->isOpenRequest());
124 if (!m_databaseInfo) {
125 if (!m_isOpeningBackingStore) {
126 m_isOpeningBackingStore = true;
127 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::openBackingStore, m_identifier));
133 // If we previously started a version change operation but were blocked by having open connections,
134 // we might now be unblocked.
135 if (m_versionChangeDatabaseConnection) {
136 if (!m_versionChangeTransaction && !hasAnyOpenConnections())
137 startVersionChangeTransaction();
141 // 3.3.1 Opening a database
142 // If requested version is undefined, then let requested version be 1 if db was created in the previous step,
143 // or the current version of db otherwise.
144 uint64_t requestedVersion = m_currentOpenDBRequest->requestData().requestedVersion();
145 if (!requestedVersion)
146 requestedVersion = m_databaseInfo->version() ? m_databaseInfo->version() : 1;
148 // 3.3.1 Opening a database
149 // If the database version higher than the requested version, abort these steps and return a VersionError.
150 if (requestedVersion < m_databaseInfo->version()) {
151 auto result = IDBResultData::error(m_currentOpenDBRequest->requestData().requestIdentifier(), IDBError(IDBDatabaseException::VersionError));
152 m_currentOpenDBRequest->connection().didOpenDatabase(result);
153 m_currentOpenDBRequest = nullptr;
158 if (!m_backingStoreOpenError.isNull()) {
159 auto result = IDBResultData::error(m_currentOpenDBRequest->requestData().requestIdentifier(), m_backingStoreOpenError);
160 m_currentOpenDBRequest->connection().didOpenDatabase(result);
161 m_currentOpenDBRequest = nullptr;
166 Ref<UniqueIDBDatabaseConnection> connection = UniqueIDBDatabaseConnection::create(*this, *m_currentOpenDBRequest);
168 if (requestedVersion == m_databaseInfo->version()) {
169 auto* rawConnection = &connection.get();
170 addOpenDatabaseConnection(WTFMove(connection));
172 auto result = IDBResultData::openDatabaseSuccess(m_currentOpenDBRequest->requestData().requestIdentifier(), *rawConnection);
173 m_currentOpenDBRequest->connection().didOpenDatabase(result);
174 m_currentOpenDBRequest = nullptr;
179 ASSERT(!m_versionChangeDatabaseConnection);
180 m_versionChangeDatabaseConnection = WTFMove(connection);
182 // 3.3.7 "versionchange" transaction steps
183 // If there's no other open connections to this database, the version change process can begin immediately.
184 if (!hasAnyOpenConnections()) {
185 startVersionChangeTransaction();
189 // Otherwise we have to notify all those open connections and wait for them to close.
190 maybeNotifyConnectionsOfVersionChange();
193 void UniqueIDBDatabase::performCurrentDeleteOperation()
195 ASSERT(isMainThread());
196 LOG(IndexedDB, "(main) UniqueIDBDatabase::performCurrentDeleteOperation - %s", m_identifier.debugString().utf8().data());
198 ASSERT(m_currentOpenDBRequest);
199 ASSERT(m_currentOpenDBRequest->isDeleteRequest());
201 if (m_deleteBackingStoreInProgress)
204 if (hasAnyOpenConnections()) {
205 maybeNotifyConnectionsOfVersionChange();
209 if (hasUnfinishedTransactions())
212 ASSERT(!hasAnyPendingCallbacks());
213 ASSERT(m_pendingTransactions.isEmpty());
214 ASSERT(m_openDatabaseConnections.isEmpty());
216 // It's possible to have multiple delete requests queued up in a row.
217 // In that scenario only the first request will actually have to delete the database.
218 // Subsequent requests can immediately notify their completion.
220 if (!m_deleteBackingStoreInProgress) {
221 if (!m_databaseInfo && m_mostRecentDeletedDatabaseInfo)
222 didDeleteBackingStore(0);
224 m_deleteBackingStoreInProgress = true;
225 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::deleteBackingStore, m_identifier));
230 void UniqueIDBDatabase::deleteBackingStore(const IDBDatabaseIdentifier& identifier)
232 ASSERT(!isMainThread());
233 LOG(IndexedDB, "(db) UniqueIDBDatabase::deleteBackingStore");
235 uint64_t deletedVersion = 0;
237 if (m_backingStore) {
238 m_backingStore->deleteBackingStore();
239 m_backingStore = nullptr;
240 m_backingStoreSupportsSimultaneousTransactions = false;
241 m_backingStoreIsEphemeral = false;
243 auto backingStore = m_server.createBackingStore(identifier);
245 IDBDatabaseInfo databaseInfo;
246 auto error = backingStore->getOrEstablishDatabaseInfo(databaseInfo);
248 LOG_ERROR("Error getting database info from database %s that we are trying to delete", identifier.debugString().utf8().data());
250 deletedVersion = databaseInfo.version();
251 backingStore->deleteBackingStore();
254 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didDeleteBackingStore, deletedVersion));
257 void UniqueIDBDatabase::performUnconditionalDeleteBackingStore()
259 ASSERT(!isMainThread());
260 LOG(IndexedDB, "(db) UniqueIDBDatabase::performUnconditionalDeleteBackingStore");
265 m_backingStore->deleteBackingStore();
266 m_backingStore = nullptr;
267 m_backingStoreSupportsSimultaneousTransactions = false;
268 m_backingStoreIsEphemeral = false;
271 void UniqueIDBDatabase::didDeleteBackingStore(uint64_t deletedVersion)
273 ASSERT(isMainThread());
274 LOG(IndexedDB, "(main) UniqueIDBDatabase::didDeleteBackingStore");
276 ASSERT(!hasAnyPendingCallbacks());
277 ASSERT(!hasUnfinishedTransactions());
278 ASSERT(m_pendingTransactions.isEmpty());
279 ASSERT(m_openDatabaseConnections.isEmpty());
281 // It's possible that the openDBRequest was cancelled from client-side after the delete was already dispatched to the backingstore.
282 // So it's okay if we don't have a currentOpenDBRequest, but if we do it has to be a deleteRequest.
283 ASSERT(!m_currentOpenDBRequest || m_currentOpenDBRequest->isDeleteRequest());
286 m_mostRecentDeletedDatabaseInfo = WTFMove(m_databaseInfo);
288 // If this UniqueIDBDatabase was brought into existence for the purpose of deleting the file on disk,
289 // we won't have a m_mostRecentDeletedDatabaseInfo. In that case, we'll manufacture one using the
290 // passed in deletedVersion argument.
291 if (!m_mostRecentDeletedDatabaseInfo)
292 m_mostRecentDeletedDatabaseInfo = std::make_unique<IDBDatabaseInfo>(m_identifier.databaseName(), deletedVersion);
294 if (m_currentOpenDBRequest) {
295 m_currentOpenDBRequest->notifyDidDeleteDatabase(*m_mostRecentDeletedDatabaseInfo);
296 m_currentOpenDBRequest = nullptr;
299 m_deleteBackingStoreInProgress = false;
301 if (m_clientClosePendingDatabaseConnections.isEmpty() && m_pendingOpenDBRequests.isEmpty()) {
302 m_server.closeUniqueIDBDatabase(*this);
306 invokeOperationAndTransactionTimer();
309 void UniqueIDBDatabase::didPerformUnconditionalDeleteBackingStore()
311 // This function is a placeholder so the database thread can message back to the main thread.
312 ASSERT(m_hardClosedForUserDelete);
315 void UniqueIDBDatabase::handleDatabaseOperations()
317 ASSERT(isMainThread());
318 LOG(IndexedDB, "(main) UniqueIDBDatabase::handleDatabaseOperations - There are %u pending", m_pendingOpenDBRequests.size());
319 ASSERT(!m_hardClosedForUserDelete);
321 if (m_deleteBackingStoreInProgress)
324 if (m_versionChangeDatabaseConnection || m_versionChangeTransaction || m_currentOpenDBRequest) {
325 // We can't start any new open-database operations right now, but we might be able to start handling a delete operation.
326 if (!m_currentOpenDBRequest && !m_pendingOpenDBRequests.isEmpty() && m_pendingOpenDBRequests.first()->isDeleteRequest())
327 m_currentOpenDBRequest = m_pendingOpenDBRequests.takeFirst();
329 // Some operations (such as the first open operation after a delete) require multiple passes to completely handle
330 if (m_currentOpenDBRequest)
331 handleCurrentOperation();
336 if (m_pendingOpenDBRequests.isEmpty())
339 m_currentOpenDBRequest = m_pendingOpenDBRequests.takeFirst();
340 LOG(IndexedDB, "UniqueIDBDatabase::handleDatabaseOperations - Popped an operation, now there are %u pending", m_pendingOpenDBRequests.size());
342 handleCurrentOperation();
345 void UniqueIDBDatabase::handleCurrentOperation()
347 LOG(IndexedDB, "(main) UniqueIDBDatabase::handleCurrentOperation");
348 ASSERT(!m_hardClosedForUserDelete);
349 ASSERT(m_currentOpenDBRequest);
351 RefPtr<UniqueIDBDatabase> protectedThis(this);
353 if (m_currentOpenDBRequest->isOpenRequest())
354 performCurrentOpenOperation();
355 else if (m_currentOpenDBRequest->isDeleteRequest())
356 performCurrentDeleteOperation();
358 ASSERT_NOT_REACHED();
360 if (!m_currentOpenDBRequest)
361 invokeOperationAndTransactionTimer();
364 bool UniqueIDBDatabase::hasAnyOpenConnections() const
366 return !m_openDatabaseConnections.isEmpty();
369 bool UniqueIDBDatabase::allConnectionsAreClosedOrClosing() const
371 for (auto& connection : m_openDatabaseConnections) {
372 if (!connection->connectionIsClosing())
379 static uint64_t generateUniqueCallbackIdentifier()
381 ASSERT(isMainThread());
382 static uint64_t currentID = 0;
386 uint64_t UniqueIDBDatabase::storeCallbackOrFireError(ErrorCallback callback)
388 if (m_hardClosedForUserDelete) {
389 callback(IDBError::userDeleteError());
393 uint64_t identifier = generateUniqueCallbackIdentifier();
394 ASSERT(!m_errorCallbacks.contains(identifier));
395 m_errorCallbacks.add(identifier, callback);
399 uint64_t UniqueIDBDatabase::storeCallbackOrFireError(KeyDataCallback callback)
401 if (m_hardClosedForUserDelete) {
402 callback(IDBError::userDeleteError(), { });
406 uint64_t identifier = generateUniqueCallbackIdentifier();
407 ASSERT(!m_keyDataCallbacks.contains(identifier));
408 m_keyDataCallbacks.add(identifier, callback);
412 uint64_t UniqueIDBDatabase::storeCallbackOrFireError(GetResultCallback callback)
414 if (m_hardClosedForUserDelete) {
415 callback(IDBError::userDeleteError(), { });
419 uint64_t identifier = generateUniqueCallbackIdentifier();
420 ASSERT(!m_getResultCallbacks.contains(identifier));
421 m_getResultCallbacks.add(identifier, callback);
425 uint64_t UniqueIDBDatabase::storeCallbackOrFireError(GetAllResultsCallback callback)
427 if (m_hardClosedForUserDelete) {
428 callback(IDBError::userDeleteError(), { });
432 uint64_t identifier = generateUniqueCallbackIdentifier();
433 ASSERT(!m_getAllResultsCallbacks.contains(identifier));
434 m_getAllResultsCallbacks.add(identifier, callback);
438 uint64_t UniqueIDBDatabase::storeCallbackOrFireError(CountCallback callback)
440 if (m_hardClosedForUserDelete) {
441 callback(IDBError::userDeleteError(), 0);
445 uint64_t identifier = generateUniqueCallbackIdentifier();
446 ASSERT(!m_countCallbacks.contains(identifier));
447 m_countCallbacks.add(identifier, callback);
451 void UniqueIDBDatabase::handleDelete(IDBConnectionToClient& connection, const IDBRequestData& requestData)
453 LOG(IndexedDB, "(main) UniqueIDBDatabase::handleDelete");
454 ASSERT(!m_hardClosedForUserDelete);
456 m_pendingOpenDBRequests.add(ServerOpenDBRequest::create(connection, requestData));
457 handleDatabaseOperations();
460 void UniqueIDBDatabase::startVersionChangeTransaction()
462 LOG(IndexedDB, "(main) UniqueIDBDatabase::startVersionChangeTransaction");
464 ASSERT(!m_versionChangeTransaction);
465 ASSERT(m_currentOpenDBRequest);
466 ASSERT(m_currentOpenDBRequest->isOpenRequest());
467 ASSERT(m_versionChangeDatabaseConnection);
469 auto operation = WTFMove(m_currentOpenDBRequest);
471 uint64_t requestedVersion = operation->requestData().requestedVersion();
472 if (!requestedVersion)
473 requestedVersion = m_databaseInfo->version() ? m_databaseInfo->version() : 1;
475 addOpenDatabaseConnection(*m_versionChangeDatabaseConnection);
477 m_versionChangeTransaction = &m_versionChangeDatabaseConnection->createVersionChangeTransaction(requestedVersion);
478 m_databaseInfo->setVersion(requestedVersion);
480 m_inProgressTransactions.set(m_versionChangeTransaction->info().identifier(), m_versionChangeTransaction);
481 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::beginTransactionInBackingStore, m_versionChangeTransaction->info()));
483 auto result = IDBResultData::openDatabaseUpgradeNeeded(operation->requestData().requestIdentifier(), *m_versionChangeTransaction);
484 operation->connection().didOpenDatabase(result);
487 void UniqueIDBDatabase::beginTransactionInBackingStore(const IDBTransactionInfo& info)
489 LOG(IndexedDB, "(db) UniqueIDBDatabase::beginTransactionInBackingStore");
490 m_backingStore->beginTransaction(info);
493 void UniqueIDBDatabase::maybeNotifyConnectionsOfVersionChange()
495 ASSERT(m_currentOpenDBRequest);
497 if (m_currentOpenDBRequest->hasNotifiedConnectionsOfVersionChange())
500 uint64_t newVersion = m_currentOpenDBRequest->isOpenRequest() ? m_currentOpenDBRequest->requestData().requestedVersion() : 0;
501 auto requestIdentifier = m_currentOpenDBRequest->requestData().requestIdentifier();
503 LOG(IndexedDB, "(main) UniqueIDBDatabase::notifyConnectionsOfVersionChange - %" PRIu64, newVersion);
505 // 3.3.7 "versionchange" transaction steps
506 // Fire a versionchange event at each connection in m_openDatabaseConnections that is open.
507 // The event must not be fired on connections which has the closePending flag set.
508 HashSet<uint64_t> connectionIdentifiers;
509 for (auto connection : m_openDatabaseConnections) {
510 if (connection->closePending())
513 connection->fireVersionChangeEvent(requestIdentifier, newVersion);
514 connectionIdentifiers.add(connection->identifier());
517 if (!connectionIdentifiers.isEmpty())
518 m_currentOpenDBRequest->notifiedConnectionsOfVersionChange(WTFMove(connectionIdentifiers));
520 m_currentOpenDBRequest->maybeNotifyRequestBlocked(m_databaseInfo->version());
523 void UniqueIDBDatabase::notifyCurrentRequestConnectionClosedOrFiredVersionChangeEvent(uint64_t connectionIdentifier)
525 LOG(IndexedDB, "UniqueIDBDatabase::notifyCurrentRequestConnectionClosedOrFiredVersionChangeEvent - %" PRIu64, connectionIdentifier);
527 ASSERT(m_currentOpenDBRequest);
529 m_currentOpenDBRequest->connectionClosedOrFiredVersionChangeEvent(connectionIdentifier);
531 if (m_currentOpenDBRequest->hasConnectionsPendingVersionChangeEvent())
534 if (!hasAnyOpenConnections() || allConnectionsAreClosedOrClosing()) {
535 invokeOperationAndTransactionTimer();
539 // Since all open connections have fired their version change events but not all of them have closed,
540 // this request is officially blocked.
541 m_currentOpenDBRequest->maybeNotifyRequestBlocked(m_databaseInfo->version());
544 void UniqueIDBDatabase::didFireVersionChangeEvent(UniqueIDBDatabaseConnection& connection, const IDBResourceIdentifier& requestIdentifier)
546 LOG(IndexedDB, "UniqueIDBDatabase::didFireVersionChangeEvent");
548 if (!m_currentOpenDBRequest)
551 ASSERT_UNUSED(requestIdentifier, m_currentOpenDBRequest->requestData().requestIdentifier() == requestIdentifier);
553 notifyCurrentRequestConnectionClosedOrFiredVersionChangeEvent(connection.identifier());
556 void UniqueIDBDatabase::openDBRequestCancelled(const IDBResourceIdentifier& requestIdentifier)
558 LOG(IndexedDB, "UniqueIDBDatabase::openDBRequestCancelled - %s", requestIdentifier.loggingString().utf8().data());
560 if (m_currentOpenDBRequest && m_currentOpenDBRequest->requestData().requestIdentifier() == requestIdentifier)
561 m_currentOpenDBRequest = nullptr;
563 if (m_versionChangeDatabaseConnection && m_versionChangeDatabaseConnection->openRequestIdentifier() == requestIdentifier) {
564 ASSERT(!m_versionChangeTransaction || m_versionChangeTransaction->databaseConnection().openRequestIdentifier() == requestIdentifier);
565 ASSERT(!m_versionChangeTransaction || &m_versionChangeTransaction->databaseConnection() == m_versionChangeDatabaseConnection);
567 connectionClosedFromClient(*m_versionChangeDatabaseConnection);
570 for (auto& request : m_pendingOpenDBRequests) {
571 if (request->requestData().requestIdentifier() == requestIdentifier) {
572 m_pendingOpenDBRequests.remove(request);
578 void UniqueIDBDatabase::addOpenDatabaseConnection(Ref<UniqueIDBDatabaseConnection>&& connection)
580 ASSERT(!m_openDatabaseConnections.contains(&connection.get()));
581 m_openDatabaseConnections.add(adoptRef(connection.leakRef()));
584 void UniqueIDBDatabase::openBackingStore(const IDBDatabaseIdentifier& identifier)
586 ASSERT(!isMainThread());
587 LOG(IndexedDB, "(db) UniqueIDBDatabase::openBackingStore (%p)", this);
589 ASSERT(!m_backingStore);
590 m_backingStore = m_server.createBackingStore(identifier);
591 m_backingStoreSupportsSimultaneousTransactions = m_backingStore->supportsSimultaneousTransactions();
592 m_backingStoreIsEphemeral = m_backingStore->isEphemeral();
594 IDBDatabaseInfo databaseInfo;
595 auto error = m_backingStore->getOrEstablishDatabaseInfo(databaseInfo);
597 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didOpenBackingStore, databaseInfo, error));
600 void UniqueIDBDatabase::didOpenBackingStore(const IDBDatabaseInfo& info, const IDBError& error)
602 ASSERT(isMainThread());
603 LOG(IndexedDB, "(main) UniqueIDBDatabase::didOpenBackingStore");
605 m_databaseInfo = std::make_unique<IDBDatabaseInfo>(info);
606 m_backingStoreOpenError = error;
608 ASSERT(m_isOpeningBackingStore);
609 m_isOpeningBackingStore = false;
611 handleDatabaseOperations();
614 void UniqueIDBDatabase::createObjectStore(UniqueIDBDatabaseTransaction& transaction, const IDBObjectStoreInfo& info, ErrorCallback callback)
616 ASSERT(isMainThread());
617 LOG(IndexedDB, "(main) UniqueIDBDatabase::createObjectStore");
619 uint64_t callbackID = storeCallbackOrFireError(callback);
623 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performCreateObjectStore, callbackID, transaction.info().identifier(), info));
626 void UniqueIDBDatabase::performCreateObjectStore(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, const IDBObjectStoreInfo& info)
628 ASSERT(!isMainThread());
629 LOG(IndexedDB, "(db) UniqueIDBDatabase::performCreateObjectStore");
631 ASSERT(m_backingStore);
632 m_backingStore->createObjectStore(transactionIdentifier, info);
635 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformCreateObjectStore, callbackIdentifier, error, info));
638 void UniqueIDBDatabase::didPerformCreateObjectStore(uint64_t callbackIdentifier, const IDBError& error, const IDBObjectStoreInfo& info)
640 ASSERT(isMainThread());
641 LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformCreateObjectStore");
644 m_databaseInfo->addExistingObjectStore(info);
646 performErrorCallback(callbackIdentifier, error);
649 void UniqueIDBDatabase::deleteObjectStore(UniqueIDBDatabaseTransaction& transaction, const String& objectStoreName, ErrorCallback callback)
651 ASSERT(isMainThread());
652 LOG(IndexedDB, "(main) UniqueIDBDatabase::deleteObjectStore");
654 uint64_t callbackID = storeCallbackOrFireError(callback);
658 auto* info = m_databaseInfo->infoForExistingObjectStore(objectStoreName);
660 performErrorCallback(callbackID, { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to delete non-existant object store") });
664 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performDeleteObjectStore, callbackID, transaction.info().identifier(), info->identifier()));
667 void UniqueIDBDatabase::performDeleteObjectStore(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier)
669 ASSERT(!isMainThread());
670 LOG(IndexedDB, "(db) UniqueIDBDatabase::performDeleteObjectStore");
672 ASSERT(m_backingStore);
673 m_backingStore->deleteObjectStore(transactionIdentifier, objectStoreIdentifier);
676 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformDeleteObjectStore, callbackIdentifier, error, objectStoreIdentifier));
679 void UniqueIDBDatabase::didPerformDeleteObjectStore(uint64_t callbackIdentifier, const IDBError& error, uint64_t objectStoreIdentifier)
681 ASSERT(isMainThread());
682 LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformDeleteObjectStore");
685 m_databaseInfo->deleteObjectStore(objectStoreIdentifier);
687 performErrorCallback(callbackIdentifier, error);
690 void UniqueIDBDatabase::renameObjectStore(UniqueIDBDatabaseTransaction& transaction, uint64_t objectStoreIdentifier, const String& newName, ErrorCallback callback)
692 ASSERT(isMainThread());
693 LOG(IndexedDB, "(main) UniqueIDBDatabase::renameObjectStore");
695 uint64_t callbackID = storeCallbackOrFireError(callback);
699 auto* info = m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
701 performErrorCallback(callbackID, { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to rename non-existant object store") });
705 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performRenameObjectStore, callbackID, transaction.info().identifier(), objectStoreIdentifier, newName));
708 void UniqueIDBDatabase::performRenameObjectStore(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const String& newName)
710 ASSERT(!isMainThread());
711 LOG(IndexedDB, "(db) UniqueIDBDatabase::performRenameObjectStore");
713 ASSERT(m_backingStore);
714 m_backingStore->renameObjectStore(transactionIdentifier, objectStoreIdentifier, newName);
717 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformRenameObjectStore, callbackIdentifier, error, objectStoreIdentifier, newName));
720 void UniqueIDBDatabase::didPerformRenameObjectStore(uint64_t callbackIdentifier, const IDBError& error, uint64_t objectStoreIdentifier, const String& newName)
722 ASSERT(isMainThread());
723 LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformRenameObjectStore");
726 m_databaseInfo->renameObjectStore(objectStoreIdentifier, newName);
728 performErrorCallback(callbackIdentifier, error);
731 void UniqueIDBDatabase::clearObjectStore(UniqueIDBDatabaseTransaction& transaction, uint64_t objectStoreIdentifier, ErrorCallback callback)
733 ASSERT(isMainThread());
734 LOG(IndexedDB, "(main) UniqueIDBDatabase::clearObjectStore");
736 uint64_t callbackID = storeCallbackOrFireError(callback);
739 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performClearObjectStore, callbackID, transaction.info().identifier(), objectStoreIdentifier));
742 void UniqueIDBDatabase::performClearObjectStore(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier)
744 ASSERT(!isMainThread());
745 LOG(IndexedDB, "(db) UniqueIDBDatabase::performClearObjectStore");
747 ASSERT(m_backingStore);
748 m_backingStore->clearObjectStore(transactionIdentifier, objectStoreIdentifier);
751 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformClearObjectStore, callbackIdentifier, error));
754 void UniqueIDBDatabase::didPerformClearObjectStore(uint64_t callbackIdentifier, const IDBError& error)
756 ASSERT(isMainThread());
757 LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformClearObjectStore");
759 performErrorCallback(callbackIdentifier, error);
762 void UniqueIDBDatabase::createIndex(UniqueIDBDatabaseTransaction& transaction, const IDBIndexInfo& info, ErrorCallback callback)
764 ASSERT(isMainThread());
765 LOG(IndexedDB, "(main) UniqueIDBDatabase::createIndex");
767 uint64_t callbackID = storeCallbackOrFireError(callback);
770 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performCreateIndex, callbackID, transaction.info().identifier(), info));
773 void UniqueIDBDatabase::performCreateIndex(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, const IDBIndexInfo& info)
775 ASSERT(!isMainThread());
776 LOG(IndexedDB, "(db) UniqueIDBDatabase::performCreateIndex");
778 ASSERT(m_backingStore);
779 IDBError error = m_backingStore->createIndex(transactionIdentifier, info);
781 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformCreateIndex, callbackIdentifier, error, info));
784 void UniqueIDBDatabase::didPerformCreateIndex(uint64_t callbackIdentifier, const IDBError& error, const IDBIndexInfo& info)
786 ASSERT(isMainThread());
787 LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformCreateIndex");
789 if (error.isNull()) {
790 ASSERT(m_databaseInfo);
791 auto* objectStoreInfo = m_databaseInfo->infoForExistingObjectStore(info.objectStoreIdentifier());
792 ASSERT(objectStoreInfo);
793 objectStoreInfo->addExistingIndex(info);
796 performErrorCallback(callbackIdentifier, error);
799 void UniqueIDBDatabase::deleteIndex(UniqueIDBDatabaseTransaction& transaction, uint64_t objectStoreIdentifier, const String& indexName, ErrorCallback callback)
801 ASSERT(isMainThread());
802 LOG(IndexedDB, "(main) UniqueIDBDatabase::deleteIndex");
804 uint64_t callbackID = storeCallbackOrFireError(callback);
808 auto* objectStoreInfo = m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
809 if (!objectStoreInfo) {
810 performErrorCallback(callbackID, { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to delete index from non-existant object store") });
814 auto* indexInfo = objectStoreInfo->infoForExistingIndex(indexName);
816 performErrorCallback(callbackID, { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to delete non-existant index") });
820 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performDeleteIndex, callbackID, transaction.info().identifier(), objectStoreIdentifier, indexInfo->identifier()));
823 void UniqueIDBDatabase::performDeleteIndex(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const uint64_t indexIdentifier)
825 ASSERT(!isMainThread());
826 LOG(IndexedDB, "(db) UniqueIDBDatabase::performDeleteIndex");
828 ASSERT(m_backingStore);
829 m_backingStore->deleteIndex(transactionIdentifier, objectStoreIdentifier, indexIdentifier);
832 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformDeleteIndex, callbackIdentifier, error, objectStoreIdentifier, indexIdentifier));
835 void UniqueIDBDatabase::didPerformDeleteIndex(uint64_t callbackIdentifier, const IDBError& error, uint64_t objectStoreIdentifier, uint64_t indexIdentifier)
837 ASSERT(isMainThread());
838 LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformDeleteIndex");
840 if (error.isNull()) {
841 auto* objectStoreInfo = m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
843 objectStoreInfo->deleteIndex(indexIdentifier);
846 performErrorCallback(callbackIdentifier, error);
849 void UniqueIDBDatabase::renameIndex(UniqueIDBDatabaseTransaction& transaction, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const String& newName, ErrorCallback callback)
851 ASSERT(isMainThread());
852 LOG(IndexedDB, "(main) UniqueIDBDatabase::renameIndex");
854 uint64_t callbackID = storeCallbackOrFireError(callback);
858 auto* objectStoreInfo = m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
859 if (!objectStoreInfo) {
860 performErrorCallback(callbackID, { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to rename index in non-existant object store") });
864 auto* indexInfo = objectStoreInfo->infoForExistingIndex(indexIdentifier);
866 performErrorCallback(callbackID, { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to rename non-existant index") });
870 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performRenameIndex, callbackID, transaction.info().identifier(), objectStoreIdentifier, indexIdentifier, newName));
873 void UniqueIDBDatabase::performRenameIndex(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const String& newName)
875 ASSERT(!isMainThread());
876 LOG(IndexedDB, "(db) UniqueIDBDatabase::performRenameIndex");
878 ASSERT(m_backingStore);
879 m_backingStore->renameIndex(transactionIdentifier, objectStoreIdentifier, indexIdentifier, newName);
882 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformRenameIndex, callbackIdentifier, error, objectStoreIdentifier, indexIdentifier, newName));
885 void UniqueIDBDatabase::didPerformRenameIndex(uint64_t callbackIdentifier, const IDBError& error, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const String& newName)
887 ASSERT(isMainThread());
888 LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformRenameIndex");
890 if (error.isNull()) {
891 auto* objectStoreInfo = m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
892 ASSERT(objectStoreInfo);
893 if (objectStoreInfo) {
894 auto* indexInfo = objectStoreInfo->infoForExistingIndex(indexIdentifier);
896 indexInfo->rename(newName);
900 performErrorCallback(callbackIdentifier, error);
903 void UniqueIDBDatabase::putOrAdd(const IDBRequestData& requestData, const IDBKeyData& keyData, const IDBValue& value, IndexedDB::ObjectStoreOverwriteMode overwriteMode, KeyDataCallback callback)
905 ASSERT(isMainThread());
906 LOG(IndexedDB, "(main) UniqueIDBDatabase::putOrAdd");
908 uint64_t callbackID = storeCallbackOrFireError(callback);
911 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performPutOrAdd, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), keyData, value, overwriteMode));
914 VM& UniqueIDBDatabase::databaseThreadVM()
916 ASSERT(!isMainThread());
917 static VM* vm = &VM::create().leakRef();
921 ExecState& UniqueIDBDatabase::databaseThreadExecState()
923 ASSERT(!isMainThread());
925 static NeverDestroyed<Strong<JSGlobalObject>> globalObject(databaseThreadVM(), JSGlobalObject::create(databaseThreadVM(), JSGlobalObject::createStructure(databaseThreadVM(), jsNull())));
927 RELEASE_ASSERT(globalObject.get()->globalExec());
928 return *globalObject.get()->globalExec();
931 void UniqueIDBDatabase::performPutOrAdd(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyData& keyData, const IDBValue& originalRecordValue, IndexedDB::ObjectStoreOverwriteMode overwriteMode)
933 ASSERT(!isMainThread());
934 LOG(IndexedDB, "(db) UniqueIDBDatabase::performPutOrAdd");
936 ASSERT(m_backingStore);
937 ASSERT(objectStoreIdentifier);
942 auto* objectStoreInfo = m_backingStore->infoForObjectStore(objectStoreIdentifier);
943 if (!objectStoreInfo) {
944 error = IDBError(IDBDatabaseException::InvalidStateError, ASCIILiteral("Object store cannot be found in the backing store"));
945 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));
949 bool usedKeyIsGenerated = false;
950 ScopeGuard generatedKeyResetter;
951 if (objectStoreInfo->autoIncrement() && !keyData.isValid()) {
953 error = m_backingStore->generateKeyNumber(transactionIdentifier, objectStoreIdentifier, keyNumber);
954 if (!error.isNull()) {
955 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));
959 usedKey.setNumberValue(keyNumber);
960 usedKeyIsGenerated = true;
961 generatedKeyResetter.enable([this, transactionIdentifier, objectStoreIdentifier, keyNumber]() {
962 m_backingStore->revertGeneratedKeyNumber(transactionIdentifier, objectStoreIdentifier, keyNumber);
967 if (overwriteMode == IndexedDB::ObjectStoreOverwriteMode::NoOverwrite) {
969 error = m_backingStore->keyExistsInObjectStore(transactionIdentifier, objectStoreIdentifier, usedKey, keyExists);
970 if (error.isNull() && keyExists)
971 error = IDBError(IDBDatabaseException::ConstraintError, ASCIILiteral("Key already exists in the object store"));
973 if (!error.isNull()) {
974 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));
979 // 3.4.1.2 Object Store Storage Operation
980 // If ObjectStore has a key path and the key is autogenerated, then inject the key into the value
981 // using steps to assign a key to a value using a key path.
982 ThreadSafeDataBuffer injectedRecordValue;
983 if (usedKeyIsGenerated && objectStoreInfo->keyPath()) {
984 VM& vm = databaseThreadVM();
985 JSLockHolder locker(vm);
986 auto scope = DECLARE_THROW_SCOPE(vm);
988 auto value = deserializeIDBValueToJSValue(databaseThreadExecState(), originalRecordValue.data());
989 if (value.isUndefined()) {
990 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, IDBError(IDBDatabaseException::ConstraintError, ASCIILiteral("Unable to deserialize record value for record key injection")), usedKey));
994 if (!injectIDBKeyIntoScriptValue(databaseThreadExecState(), usedKey, value, objectStoreInfo->keyPath().value())) {
995 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, IDBError(IDBDatabaseException::ConstraintError, ASCIILiteral("Unable to inject record key into record value")), usedKey));
999 auto serializedValue = SerializedScriptValue::create(databaseThreadExecState(), value);
1000 if (UNLIKELY(scope.exception())) {
1001 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, IDBError(IDBDatabaseException::ConstraintError, ASCIILiteral("Unable to serialize record value after injecting record key")), usedKey));
1005 injectedRecordValue = ThreadSafeDataBuffer::copyVector(serializedValue->data());
1008 // 3.4.1 Object Store Storage Operation
1009 // ...If a record already exists in store ...
1010 // then remove the record from store using the steps for deleting records from an object store...
1011 // This is important because formally deleting it from from the object store also removes it from the appropriate indexes.
1012 error = m_backingStore->deleteRange(transactionIdentifier, objectStoreIdentifier, usedKey);
1013 if (!error.isNull()) {
1014 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));
1018 if (injectedRecordValue.data())
1019 error = m_backingStore->addRecord(transactionIdentifier, *objectStoreInfo, usedKey, { injectedRecordValue, originalRecordValue.blobURLs(), originalRecordValue.blobFilePaths() });
1021 error = m_backingStore->addRecord(transactionIdentifier, *objectStoreInfo, usedKey, originalRecordValue);
1023 if (!error.isNull()) {
1024 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));
1028 if (overwriteMode != IndexedDB::ObjectStoreOverwriteMode::OverwriteForCursor && objectStoreInfo->autoIncrement() && keyData.type() == IndexedDB::KeyType::Number)
1029 error = m_backingStore->maybeUpdateKeyGeneratorNumber(transactionIdentifier, objectStoreIdentifier, keyData.number());
1031 generatedKeyResetter.disable();
1032 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));
1035 void UniqueIDBDatabase::didPerformPutOrAdd(uint64_t callbackIdentifier, const IDBError& error, const IDBKeyData& resultKey)
1037 ASSERT(isMainThread());
1038 LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformPutOrAdd");
1040 performKeyDataCallback(callbackIdentifier, error, resultKey);
1043 void UniqueIDBDatabase::getRecord(const IDBRequestData& requestData, const IDBGetRecordData& getRecordData, GetResultCallback callback)
1045 ASSERT(isMainThread());
1046 LOG(IndexedDB, "(main) UniqueIDBDatabase::getRecord");
1048 uint64_t callbackID = storeCallbackOrFireError(callback);
1052 if (uint64_t indexIdentifier = requestData.indexIdentifier())
1053 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performGetIndexRecord, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), indexIdentifier, requestData.indexRecordType(), getRecordData.keyRangeData));
1055 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performGetRecord, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), getRecordData.keyRangeData));
1058 void UniqueIDBDatabase::getAllRecords(const IDBRequestData& requestData, const IDBGetAllRecordsData& getAllRecordsData, GetAllResultsCallback callback)
1060 ASSERT(isMainThread());
1061 LOG(IndexedDB, "(main) UniqueIDBDatabase::getAllRecords");
1063 uint64_t callbackID = storeCallbackOrFireError(callback);
1067 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performGetAllRecords, callbackID, requestData.transactionIdentifier(), getAllRecordsData));
1070 void UniqueIDBDatabase::performGetRecord(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyRangeData& keyRangeData)
1072 ASSERT(!isMainThread());
1073 LOG(IndexedDB, "(db) UniqueIDBDatabase::performGetRecord");
1075 ASSERT(m_backingStore);
1077 IDBGetResult result;
1078 IDBError error = m_backingStore->getRecord(transactionIdentifier, objectStoreIdentifier, keyRangeData, result);
1080 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformGetRecord, callbackIdentifier, error, result));
1083 void UniqueIDBDatabase::performGetIndexRecord(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, IndexedDB::IndexRecordType recordType, const IDBKeyRangeData& range)
1085 ASSERT(!isMainThread());
1086 LOG(IndexedDB, "(db) UniqueIDBDatabase::performGetIndexRecord");
1088 ASSERT(m_backingStore);
1090 IDBGetResult result;
1091 IDBError error = m_backingStore->getIndexRecord(transactionIdentifier, objectStoreIdentifier, indexIdentifier, recordType, range, result);
1093 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformGetRecord, callbackIdentifier, error, result));
1096 void UniqueIDBDatabase::didPerformGetRecord(uint64_t callbackIdentifier, const IDBError& error, const IDBGetResult& result)
1098 ASSERT(isMainThread());
1099 LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformGetRecord");
1101 performGetResultCallback(callbackIdentifier, error, result);
1104 void UniqueIDBDatabase::performGetAllRecords(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, const IDBGetAllRecordsData& getAllRecordsData)
1106 ASSERT(!isMainThread());
1107 LOG(IndexedDB, "(db) UniqueIDBDatabase::performGetAllRecords");
1109 ASSERT(m_backingStore);
1111 IDBGetAllResult result;
1112 IDBError error = m_backingStore->getAllRecords(transactionIdentifier, getAllRecordsData, result);
1114 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformGetAllRecords, callbackIdentifier, error, WTFMove(result)));
1117 void UniqueIDBDatabase::didPerformGetAllRecords(uint64_t callbackIdentifier, const IDBError& error, const IDBGetAllResult& result)
1119 ASSERT(isMainThread());
1120 LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformGetAllRecords");
1122 performGetAllResultsCallback(callbackIdentifier, error, result);
1125 void UniqueIDBDatabase::getCount(const IDBRequestData& requestData, const IDBKeyRangeData& range, CountCallback callback)
1127 ASSERT(isMainThread());
1128 LOG(IndexedDB, "(main) UniqueIDBDatabase::getCount");
1130 uint64_t callbackID = storeCallbackOrFireError(callback);
1133 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performGetCount, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), requestData.indexIdentifier(), range));
1136 void UniqueIDBDatabase::performGetCount(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const IDBKeyRangeData& keyRangeData)
1138 ASSERT(!isMainThread());
1139 LOG(IndexedDB, "(db) UniqueIDBDatabase::performGetCount");
1141 ASSERT(m_backingStore);
1142 ASSERT(objectStoreIdentifier);
1145 IDBError error = m_backingStore->getCount(transactionIdentifier, objectStoreIdentifier, indexIdentifier, keyRangeData, count);
1147 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformGetCount, callbackIdentifier, error, count));
1150 void UniqueIDBDatabase::didPerformGetCount(uint64_t callbackIdentifier, const IDBError& error, uint64_t count)
1152 ASSERT(isMainThread());
1153 LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformGetCount");
1155 performCountCallback(callbackIdentifier, error, count);
1158 void UniqueIDBDatabase::deleteRecord(const IDBRequestData& requestData, const IDBKeyRangeData& keyRangeData, ErrorCallback callback)
1160 ASSERT(isMainThread());
1161 LOG(IndexedDB, "(main) UniqueIDBDatabase::deleteRecord");
1163 uint64_t callbackID = storeCallbackOrFireError(callback);
1166 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performDeleteRecord, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), keyRangeData));
1169 void UniqueIDBDatabase::performDeleteRecord(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyRangeData& range)
1171 ASSERT(!isMainThread());
1172 LOG(IndexedDB, "(db) UniqueIDBDatabase::performDeleteRecord");
1174 IDBError error = m_backingStore->deleteRange(transactionIdentifier, objectStoreIdentifier, range);
1176 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformDeleteRecord, callbackIdentifier, error));
1179 void UniqueIDBDatabase::didPerformDeleteRecord(uint64_t callbackIdentifier, const IDBError& error)
1181 ASSERT(isMainThread());
1182 LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformDeleteRecord");
1184 performErrorCallback(callbackIdentifier, error);
1187 void UniqueIDBDatabase::openCursor(const IDBRequestData& requestData, const IDBCursorInfo& info, GetResultCallback callback)
1189 ASSERT(isMainThread());
1190 LOG(IndexedDB, "(main) UniqueIDBDatabase::openCursor");
1192 uint64_t callbackID = storeCallbackOrFireError(callback);
1195 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performOpenCursor, callbackID, requestData.transactionIdentifier(), info));
1198 void UniqueIDBDatabase::performOpenCursor(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, const IDBCursorInfo& info)
1200 ASSERT(!isMainThread());
1201 LOG(IndexedDB, "(db) UniqueIDBDatabase::performOpenCursor");
1203 IDBGetResult result;
1204 IDBError error = m_backingStore->openCursor(transactionIdentifier, info, result);
1206 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformOpenCursor, callbackIdentifier, error, result));
1209 void UniqueIDBDatabase::didPerformOpenCursor(uint64_t callbackIdentifier, const IDBError& error, const IDBGetResult& result)
1211 ASSERT(isMainThread());
1212 LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformOpenCursor");
1214 performGetResultCallback(callbackIdentifier, error, result);
1217 void UniqueIDBDatabase::iterateCursor(const IDBRequestData& requestData, const IDBIterateCursorData& data, GetResultCallback callback)
1219 ASSERT(isMainThread());
1220 LOG(IndexedDB, "(main) UniqueIDBDatabase::iterateCursor");
1222 uint64_t callbackID = storeCallbackOrFireError(callback);
1225 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performIterateCursor, callbackID, requestData.transactionIdentifier(), requestData.cursorIdentifier(), data));
1228 void UniqueIDBDatabase::performIterateCursor(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, const IDBResourceIdentifier& cursorIdentifier, const IDBIterateCursorData& data)
1230 ASSERT(!isMainThread());
1231 LOG(IndexedDB, "(db) UniqueIDBDatabase::performIterateCursor");
1233 IDBGetResult result;
1234 IDBError error = m_backingStore->iterateCursor(transactionIdentifier, cursorIdentifier, data, result);
1236 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformIterateCursor, callbackIdentifier, error, result));
1239 void UniqueIDBDatabase::didPerformIterateCursor(uint64_t callbackIdentifier, const IDBError& error, const IDBGetResult& result)
1241 ASSERT(isMainThread());
1242 LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformIterateCursor");
1244 performGetResultCallback(callbackIdentifier, error, result);
1247 bool UniqueIDBDatabase::prepareToFinishTransaction(UniqueIDBDatabaseTransaction& transaction)
1249 auto takenTransaction = m_inProgressTransactions.take(transaction.info().identifier());
1250 if (!takenTransaction)
1253 ASSERT(!m_finishingTransactions.contains(transaction.info().identifier()));
1254 m_finishingTransactions.set(transaction.info().identifier(), WTFMove(takenTransaction));
1259 void UniqueIDBDatabase::commitTransaction(UniqueIDBDatabaseTransaction& transaction, ErrorCallback callback)
1261 ASSERT(isMainThread());
1262 LOG(IndexedDB, "(main) UniqueIDBDatabase::commitTransaction - %s", transaction.info().identifier().loggingString().utf8().data());
1264 ASSERT(&transaction.databaseConnection().database() == this);
1266 uint64_t callbackID = storeCallbackOrFireError(callback);
1270 if (!prepareToFinishTransaction(transaction)) {
1271 if (!m_openDatabaseConnections.contains(&transaction.databaseConnection())) {
1272 // This database connection is closing or has already closed, so there is no point in messaging back to it about the commit failing.
1273 forgetErrorCallback(callbackID);
1277 performErrorCallback(callbackID, { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to commit transaction that is already finishing") });
1281 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performCommitTransaction, callbackID, transaction.info().identifier()));
1284 void UniqueIDBDatabase::performCommitTransaction(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier)
1286 ASSERT(!isMainThread());
1287 LOG(IndexedDB, "(db) UniqueIDBDatabase::performCommitTransaction - %s", transactionIdentifier.loggingString().utf8().data());
1289 IDBError error = m_backingStore->commitTransaction(transactionIdentifier);
1290 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformCommitTransaction, callbackIdentifier, error, transactionIdentifier));
1293 void UniqueIDBDatabase::didPerformCommitTransaction(uint64_t callbackIdentifier, const IDBError& error, const IDBResourceIdentifier& transactionIdentifier)
1295 ASSERT(isMainThread());
1296 LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformCommitTransaction - %s", transactionIdentifier.loggingString().utf8().data());
1298 performErrorCallback(callbackIdentifier, error);
1300 transactionCompleted(m_finishingTransactions.take(transactionIdentifier));
1303 void UniqueIDBDatabase::abortTransaction(UniqueIDBDatabaseTransaction& transaction, ErrorCallback callback)
1305 ASSERT(isMainThread());
1306 LOG(IndexedDB, "(main) UniqueIDBDatabase::abortTransaction - %s", transaction.info().identifier().loggingString().utf8().data());
1308 ASSERT(&transaction.databaseConnection().database() == this);
1310 uint64_t callbackID = storeCallbackOrFireError(callback);
1314 if (!prepareToFinishTransaction(transaction)) {
1315 if (!m_openDatabaseConnections.contains(&transaction.databaseConnection())) {
1316 // This database connection is closing or has already closed, so there is no point in messaging back to it about the abort failing.
1317 forgetErrorCallback(callbackID);
1321 performErrorCallback(callbackID, { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to abort transaction that is already finishing") });
1325 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performAbortTransaction, callbackID, transaction.info().identifier()));
1328 void UniqueIDBDatabase::didFinishHandlingVersionChange(UniqueIDBDatabaseConnection& connection, const IDBResourceIdentifier& transactionIdentifier)
1330 ASSERT(isMainThread());
1331 LOG(IndexedDB, "(main) UniqueIDBDatabase::didFinishHandlingVersionChange");
1333 ASSERT_UNUSED(transactionIdentifier, !m_versionChangeTransaction || m_versionChangeTransaction->info().identifier() == transactionIdentifier);
1334 ASSERT_UNUSED(connection, !m_versionChangeDatabaseConnection || m_versionChangeDatabaseConnection.get() == &connection);
1336 m_versionChangeTransaction = nullptr;
1337 m_versionChangeDatabaseConnection = nullptr;
1339 if (m_hardClosedForUserDelete) {
1340 maybeFinishHardClose();
1344 invokeOperationAndTransactionTimer();
1347 void UniqueIDBDatabase::performAbortTransaction(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier)
1349 ASSERT(!isMainThread());
1350 LOG(IndexedDB, "(db) UniqueIDBDatabase::performAbortTransaction - %s", transactionIdentifier.loggingString().utf8().data());
1352 IDBError error = m_backingStore->abortTransaction(transactionIdentifier);
1353 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformAbortTransaction, callbackIdentifier, error, transactionIdentifier));
1356 void UniqueIDBDatabase::didPerformAbortTransaction(uint64_t callbackIdentifier, const IDBError& error, const IDBResourceIdentifier& transactionIdentifier)
1358 ASSERT(isMainThread());
1359 LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformAbortTransaction - %s", transactionIdentifier.loggingString().utf8().data());
1361 auto transaction = m_finishingTransactions.take(transactionIdentifier);
1362 ASSERT(transaction);
1364 if (m_versionChangeTransaction && m_versionChangeTransaction->info().identifier() == transactionIdentifier) {
1365 ASSERT(m_versionChangeTransaction == transaction);
1366 ASSERT(!m_versionChangeDatabaseConnection || &m_versionChangeTransaction->databaseConnection() == m_versionChangeDatabaseConnection);
1367 ASSERT(m_versionChangeTransaction->originalDatabaseInfo());
1368 m_databaseInfo = std::make_unique<IDBDatabaseInfo>(*m_versionChangeTransaction->originalDatabaseInfo());
1371 performErrorCallback(callbackIdentifier, error);
1373 transactionCompleted(WTFMove(transaction));
1376 void UniqueIDBDatabase::transactionDestroyed(UniqueIDBDatabaseTransaction& transaction)
1378 if (m_versionChangeTransaction == &transaction)
1379 m_versionChangeTransaction = nullptr;
1382 void UniqueIDBDatabase::connectionClosedFromClient(UniqueIDBDatabaseConnection& connection)
1384 ASSERT(isMainThread());
1385 LOG(IndexedDB, "(main) UniqueIDBDatabase::connectionClosedFromClient - %s (%" PRIu64 ")", connection.openRequestIdentifier().loggingString().utf8().data(), connection.identifier());
1387 Ref<UniqueIDBDatabaseConnection> protectedConnection(connection);
1388 m_openDatabaseConnections.remove(&connection);
1390 if (m_versionChangeDatabaseConnection == &connection) {
1391 if (m_versionChangeTransaction) {
1392 m_clientClosePendingDatabaseConnections.add(WTFMove(m_versionChangeDatabaseConnection));
1394 auto transactionIdentifier = m_versionChangeTransaction->info().identifier();
1395 if (m_inProgressTransactions.contains(transactionIdentifier)) {
1396 ASSERT(!m_finishingTransactions.contains(transactionIdentifier));
1397 connection.abortTransactionWithoutCallback(*m_versionChangeTransaction);
1403 m_versionChangeDatabaseConnection = nullptr;
1406 Deque<RefPtr<UniqueIDBDatabaseTransaction>> pendingTransactions;
1407 while (!m_pendingTransactions.isEmpty()) {
1408 auto transaction = m_pendingTransactions.takeFirst();
1409 if (&transaction->databaseConnection() != &connection)
1410 pendingTransactions.append(WTFMove(transaction));
1413 if (!pendingTransactions.isEmpty())
1414 m_pendingTransactions.swap(pendingTransactions);
1416 Deque<RefPtr<UniqueIDBDatabaseTransaction>> transactionsToAbort;
1417 for (auto& transaction : m_inProgressTransactions.values()) {
1418 if (&transaction->databaseConnection() == &connection)
1419 transactionsToAbort.append(transaction);
1422 for (auto& transaction : transactionsToAbort)
1423 transaction->abortWithoutCallback();
1425 if (m_currentOpenDBRequest)
1426 notifyCurrentRequestConnectionClosedOrFiredVersionChangeEvent(connection.identifier());
1428 if (connection.hasNonFinishedTransactions()) {
1429 m_clientClosePendingDatabaseConnections.add(WTFMove(protectedConnection));
1433 if (m_hardClosedForUserDelete) {
1434 maybeFinishHardClose();
1438 // Now that a database connection has closed, previously blocked operations might be runnable.
1439 invokeOperationAndTransactionTimer();
1442 void UniqueIDBDatabase::connectionClosedFromServer(UniqueIDBDatabaseConnection& connection)
1444 ASSERT(isMainThread());
1445 LOG(IndexedDB, "UniqueIDBDatabase::connectionClosedFromServer - %s (%" PRIu64 ")", connection.openRequestIdentifier().loggingString().utf8().data(), connection.identifier());
1447 if (m_clientClosePendingDatabaseConnections.contains(&connection)) {
1448 ASSERT(!m_openDatabaseConnections.contains(&connection));
1449 ASSERT(!m_serverClosePendingDatabaseConnections.contains(&connection));
1453 Ref<UniqueIDBDatabaseConnection> protectedConnection(connection);
1454 m_openDatabaseConnections.remove(&connection);
1456 connection.connectionToClient().didCloseFromServer(connection, IDBError::userDeleteError());
1458 m_serverClosePendingDatabaseConnections.add(WTFMove(protectedConnection));
1461 void UniqueIDBDatabase::confirmDidCloseFromServer(UniqueIDBDatabaseConnection& connection)
1463 ASSERT(isMainThread());
1464 LOG(IndexedDB, "UniqueIDBDatabase::confirmDidCloseFromServer - %s (%" PRIu64 ")", connection.openRequestIdentifier().loggingString().utf8().data(), connection.identifier());
1466 ASSERT(m_serverClosePendingDatabaseConnections.contains(&connection));
1467 m_serverClosePendingDatabaseConnections.remove(&connection);
1470 void UniqueIDBDatabase::enqueueTransaction(Ref<UniqueIDBDatabaseTransaction>&& transaction)
1472 LOG(IndexedDB, "UniqueIDBDatabase::enqueueTransaction - %s", transaction->info().loggingString().utf8().data());
1473 ASSERT(!m_hardClosedForUserDelete);
1475 ASSERT(transaction->info().mode() != IDBTransactionMode::Versionchange);
1477 m_pendingTransactions.append(WTFMove(transaction));
1479 invokeOperationAndTransactionTimer();
1482 bool UniqueIDBDatabase::isCurrentlyInUse() const
1484 return !m_openDatabaseConnections.isEmpty() || !m_clientClosePendingDatabaseConnections.isEmpty() || !m_pendingOpenDBRequests.isEmpty() || m_currentOpenDBRequest || m_versionChangeDatabaseConnection || m_versionChangeTransaction || m_isOpeningBackingStore || m_deleteBackingStoreInProgress;
1487 bool UniqueIDBDatabase::hasUnfinishedTransactions() const
1489 return !m_inProgressTransactions.isEmpty() || !m_finishingTransactions.isEmpty();
1492 void UniqueIDBDatabase::invokeOperationAndTransactionTimer()
1494 LOG(IndexedDB, "UniqueIDBDatabase::invokeOperationAndTransactionTimer()");
1495 ASSERT(!m_hardClosedForUserDelete);
1497 if (!m_operationAndTransactionTimer.isActive())
1498 m_operationAndTransactionTimer.startOneShot(0);
1501 void UniqueIDBDatabase::operationAndTransactionTimerFired()
1503 LOG(IndexedDB, "(main) UniqueIDBDatabase::operationAndTransactionTimerFired");
1504 ASSERT(!m_hardClosedForUserDelete);
1506 RefPtr<UniqueIDBDatabase> protectedThis(this);
1508 // This UniqueIDBDatabase might be no longer in use by any web page.
1509 // Assuming it is not ephemeral, the server should now close it to free up resources.
1510 if (!m_backingStoreIsEphemeral && !isCurrentlyInUse()) {
1511 ASSERT(m_pendingTransactions.isEmpty());
1512 ASSERT(!hasUnfinishedTransactions());
1513 m_server.closeUniqueIDBDatabase(*this);
1517 // The current operation might require multiple attempts to handle, so try to
1518 // make further progress on it now.
1519 if (m_currentOpenDBRequest)
1520 handleCurrentOperation();
1522 if (!m_currentOpenDBRequest)
1523 handleDatabaseOperations();
1525 bool hadDeferredTransactions = false;
1526 auto transaction = takeNextRunnableTransaction(hadDeferredTransactions);
1529 m_inProgressTransactions.set(transaction->info().identifier(), transaction);
1530 for (auto objectStore : transaction->objectStoreIdentifiers()) {
1531 m_objectStoreTransactionCounts.add(objectStore);
1532 if (!transaction->isReadOnly()) {
1533 m_objectStoreWriteTransactions.add(objectStore);
1534 ASSERT(m_objectStoreTransactionCounts.count(objectStore) == 1);
1538 activateTransactionInBackingStore(*transaction);
1540 // If no transactions were deferred, it's possible we can start another transaction right now.
1541 if (!hadDeferredTransactions)
1542 invokeOperationAndTransactionTimer();
1546 void UniqueIDBDatabase::activateTransactionInBackingStore(UniqueIDBDatabaseTransaction& transaction)
1548 LOG(IndexedDB, "(main) UniqueIDBDatabase::activateTransactionInBackingStore");
1550 RefPtr<UniqueIDBDatabase> protectedThis(this);
1551 RefPtr<UniqueIDBDatabaseTransaction> refTransaction(&transaction);
1553 auto callback = [this, protectedThis, refTransaction](const IDBError& error) {
1554 refTransaction->didActivateInBackingStore(error);
1557 uint64_t callbackID = storeCallbackOrFireError(callback);
1560 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performActivateTransactionInBackingStore, callbackID, transaction.info()));
1563 void UniqueIDBDatabase::performActivateTransactionInBackingStore(uint64_t callbackIdentifier, const IDBTransactionInfo& info)
1565 LOG(IndexedDB, "(db) UniqueIDBDatabase::performActivateTransactionInBackingStore");
1567 IDBError error = m_backingStore->beginTransaction(info);
1568 postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformActivateTransactionInBackingStore, callbackIdentifier, error));
1571 void UniqueIDBDatabase::didPerformActivateTransactionInBackingStore(uint64_t callbackIdentifier, const IDBError& error)
1573 LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformActivateTransactionInBackingStore");
1575 invokeOperationAndTransactionTimer();
1577 performErrorCallback(callbackIdentifier, error);
1580 template<typename T> bool scopesOverlap(const T& aScopes, const Vector<uint64_t>& bScopes)
1582 for (auto scope : bScopes) {
1583 if (aScopes.contains(scope))
1590 RefPtr<UniqueIDBDatabaseTransaction> UniqueIDBDatabase::takeNextRunnableTransaction(bool& hadDeferredTransactions)
1592 hadDeferredTransactions = false;
1594 if (m_pendingTransactions.isEmpty())
1597 if (!m_backingStoreSupportsSimultaneousTransactions && hasUnfinishedTransactions()) {
1598 LOG(IndexedDB, "UniqueIDBDatabase::takeNextRunnableTransaction - Backing store only supports 1 transaction, and we already have 1");
1602 Deque<RefPtr<UniqueIDBDatabaseTransaction>> deferredTransactions;
1603 RefPtr<UniqueIDBDatabaseTransaction> currentTransaction;
1605 HashSet<uint64_t> deferredReadWriteScopes;
1607 while (!m_pendingTransactions.isEmpty()) {
1608 currentTransaction = m_pendingTransactions.takeFirst();
1610 switch (currentTransaction->info().mode()) {
1611 case IDBTransactionMode::Readonly: {
1612 bool hasOverlappingScopes = scopesOverlap(deferredReadWriteScopes, currentTransaction->objectStoreIdentifiers());
1613 hasOverlappingScopes |= scopesOverlap(m_objectStoreWriteTransactions, currentTransaction->objectStoreIdentifiers());
1615 if (hasOverlappingScopes)
1616 deferredTransactions.append(WTFMove(currentTransaction));
1620 case IDBTransactionMode::Readwrite: {
1621 bool hasOverlappingScopes = scopesOverlap(m_objectStoreTransactionCounts, currentTransaction->objectStoreIdentifiers());
1622 hasOverlappingScopes |= scopesOverlap(deferredReadWriteScopes, currentTransaction->objectStoreIdentifiers());
1624 if (hasOverlappingScopes) {
1625 for (auto objectStore : currentTransaction->objectStoreIdentifiers())
1626 deferredReadWriteScopes.add(objectStore);
1627 deferredTransactions.append(WTFMove(currentTransaction));
1632 case IDBTransactionMode::Versionchange:
1633 // Version change transactions should never be scheduled in the traditional manner.
1634 RELEASE_ASSERT_NOT_REACHED();
1637 // If we didn't defer the currentTransaction above, it can be run now.
1638 if (currentTransaction)
1642 hadDeferredTransactions = !deferredTransactions.isEmpty();
1643 if (!hadDeferredTransactions)
1644 return currentTransaction;
1646 // Prepend the deferred transactions back on the beginning of the deque for future scheduling passes.
1647 while (!deferredTransactions.isEmpty())
1648 m_pendingTransactions.prepend(deferredTransactions.takeLast());
1650 return currentTransaction;
1653 void UniqueIDBDatabase::transactionCompleted(RefPtr<UniqueIDBDatabaseTransaction>&& transaction)
1655 ASSERT(transaction);
1656 ASSERT(!m_inProgressTransactions.contains(transaction->info().identifier()));
1657 ASSERT(!m_finishingTransactions.contains(transaction->info().identifier()));
1659 for (auto objectStore : transaction->objectStoreIdentifiers()) {
1660 if (!transaction->isReadOnly()) {
1661 m_objectStoreWriteTransactions.remove(objectStore);
1662 ASSERT(m_objectStoreTransactionCounts.count(objectStore) == 1);
1664 m_objectStoreTransactionCounts.remove(objectStore);
1667 if (!transaction->databaseConnection().hasNonFinishedTransactions())
1668 m_clientClosePendingDatabaseConnections.remove(&transaction->databaseConnection());
1670 if (m_versionChangeTransaction == transaction)
1671 m_versionChangeTransaction = nullptr;
1673 // It's possible that this database had its backing store deleted but there were a few outstanding asynchronous operations.
1674 // If this transaction completing was the last of those operations, we can finally delete this UniqueIDBDatabase.
1675 if (m_clientClosePendingDatabaseConnections.isEmpty() && m_pendingOpenDBRequests.isEmpty() && !m_databaseInfo) {
1676 m_server.closeUniqueIDBDatabase(*this);
1680 // Previously blocked operations might be runnable.
1681 if (!m_hardClosedForUserDelete)
1682 invokeOperationAndTransactionTimer();
1684 maybeFinishHardClose();
1687 void UniqueIDBDatabase::postDatabaseTask(CrossThreadTask&& task)
1689 ASSERT(isMainThread());
1690 m_databaseQueue.append(WTFMove(task));
1691 ++m_queuedTaskCount;
1693 m_server.postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::executeNextDatabaseTask));
1696 void UniqueIDBDatabase::postDatabaseTaskReply(CrossThreadTask&& task)
1698 ASSERT(!isMainThread());
1699 m_databaseReplyQueue.append(WTFMove(task));
1700 ++m_queuedTaskCount;
1702 m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::executeNextDatabaseTaskReply));
1705 void UniqueIDBDatabase::executeNextDatabaseTask()
1707 ASSERT(!isMainThread());
1708 ASSERT(m_queuedTaskCount);
1710 auto task = m_databaseQueue.tryGetMessage();
1713 // Performing the task might end up removing the last reference to this.
1714 Ref<UniqueIDBDatabase> protectedThis(*this);
1716 task->performTask();
1717 --m_queuedTaskCount;
1719 // Release the ref in the main thread to ensure it's deleted there as expected in case of being the last reference.
1720 callOnMainThread([protectedThis = WTFMove(protectedThis)] {
1724 void UniqueIDBDatabase::executeNextDatabaseTaskReply()
1726 ASSERT(isMainThread());
1727 ASSERT(m_queuedTaskCount);
1729 auto task = m_databaseReplyQueue.tryGetMessage();
1732 // Performing the task might end up removing the last reference to this.
1733 Ref<UniqueIDBDatabase> protectedThis(*this);
1735 task->performTask();
1736 --m_queuedTaskCount;
1738 // If this database was force closed (e.g. for a user delete) and there are no more
1739 // cleanup tasks left, delete this.
1740 maybeFinishHardClose();
1743 void UniqueIDBDatabase::maybeFinishHardClose()
1745 if (m_hardCloseProtector && isDoneWithHardClose()) {
1746 callOnMainThread([this] {
1747 ASSERT(isDoneWithHardClose());
1748 m_hardCloseProtector = nullptr;
1753 bool UniqueIDBDatabase::isDoneWithHardClose()
1755 return !m_queuedTaskCount && m_clientClosePendingDatabaseConnections.isEmpty() && m_serverClosePendingDatabaseConnections.isEmpty();
1758 static void errorOpenDBRequestForUserDelete(ServerOpenDBRequest& request)
1760 auto result = IDBResultData::error(request.requestData().requestIdentifier(), IDBError::userDeleteError());
1761 if (request.isOpenRequest())
1762 request.connection().didOpenDatabase(result);
1764 request.connection().didDeleteDatabase(result);
1767 void UniqueIDBDatabase::immediateCloseForUserDelete()
1769 LOG(IndexedDB, "UniqueIDBDatabase::immediateCloseForUserDelete - Cancelling (%i, %i, %i, %i) callbacks", m_errorCallbacks.size(), m_keyDataCallbacks.size(), m_getResultCallbacks.size(), m_countCallbacks.size());
1771 // Error out all transactions
1772 Vector<IDBResourceIdentifier> inProgressIdentifiers;
1773 copyKeysToVector(m_inProgressTransactions, inProgressIdentifiers);
1774 for (auto& identifier : inProgressIdentifiers)
1775 m_inProgressTransactions.get(identifier)->abortWithoutCallback();
1777 ASSERT(m_inProgressTransactions.isEmpty());
1779 m_pendingTransactions.clear();
1780 m_objectStoreTransactionCounts.clear();
1781 m_objectStoreWriteTransactions.clear();
1783 // Error out all pending callbacks
1784 Vector<uint64_t> callbackIdentifiers;
1785 IDBError error = IDBError::userDeleteError();
1787 IDBGetResult getResult;
1789 copyKeysToVector(m_errorCallbacks, callbackIdentifiers);
1790 for (auto identifier : callbackIdentifiers)
1791 performErrorCallback(identifier, error);
1793 callbackIdentifiers.clear();
1794 copyKeysToVector(m_keyDataCallbacks, callbackIdentifiers);
1795 for (auto identifier : callbackIdentifiers)
1796 performKeyDataCallback(identifier, error, keyData);
1798 callbackIdentifiers.clear();
1799 copyKeysToVector(m_getResultCallbacks, callbackIdentifiers);
1800 for (auto identifier : callbackIdentifiers)
1801 performGetResultCallback(identifier, error, getResult);
1803 callbackIdentifiers.clear();
1804 copyKeysToVector(m_countCallbacks, callbackIdentifiers);
1805 for (auto identifier : callbackIdentifiers)
1806 performCountCallback(identifier, error, 0);
1808 // Error out all IDBOpenDBRequests
1809 if (m_currentOpenDBRequest) {
1810 errorOpenDBRequestForUserDelete(*m_currentOpenDBRequest);
1811 m_currentOpenDBRequest = nullptr;
1814 for (auto& request : m_pendingOpenDBRequests)
1815 errorOpenDBRequestForUserDelete(*request);
1817 m_pendingOpenDBRequests.clear();
1819 // Close all open connections
1820 ListHashSet<RefPtr<UniqueIDBDatabaseConnection>> openDatabaseConnections = m_openDatabaseConnections;
1821 for (auto& connection : openDatabaseConnections)
1822 connectionClosedFromServer(*connection);
1824 // Cancel the operation timer
1825 m_operationAndTransactionTimer.stop();
1827 // Set up the database to remain alive-but-inert until all of its background activity finishes and all
1828 // database connections confirm that they have closed.
1829 m_hardClosedForUserDelete = true;
1830 m_hardCloseProtector = this;
1832 // Have the database unconditionally delete itself on the database task queue.
1833 postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performUnconditionalDeleteBackingStore));
1835 // Remove the database from the IDBServer's set of open databases.
1836 // If there is no in-progress background thread activity for this database, it will be deleted here.
1837 m_server.closeUniqueIDBDatabase(*this);
1840 void UniqueIDBDatabase::performErrorCallback(uint64_t callbackIdentifier, const IDBError& error)
1842 auto callback = m_errorCallbacks.take(callbackIdentifier);
1843 ASSERT(callback || m_hardClosedForUserDelete);
1848 void UniqueIDBDatabase::performKeyDataCallback(uint64_t callbackIdentifier, const IDBError& error, const IDBKeyData& resultKey)
1850 auto callback = m_keyDataCallbacks.take(callbackIdentifier);
1851 ASSERT(callback || m_hardClosedForUserDelete);
1853 callback(error, resultKey);
1856 void UniqueIDBDatabase::performGetResultCallback(uint64_t callbackIdentifier, const IDBError& error, const IDBGetResult& resultData)
1858 auto callback = m_getResultCallbacks.take(callbackIdentifier);
1859 ASSERT(callback || m_hardClosedForUserDelete);
1861 callback(error, resultData);
1864 void UniqueIDBDatabase::performGetAllResultsCallback(uint64_t callbackIdentifier, const IDBError& error, const IDBGetAllResult& resultData)
1866 auto callback = m_getAllResultsCallbacks.take(callbackIdentifier);
1867 ASSERT(callback || m_hardClosedForUserDelete);
1869 callback(error, resultData);
1872 void UniqueIDBDatabase::performCountCallback(uint64_t callbackIdentifier, const IDBError& error, uint64_t count)
1874 auto callback = m_countCallbacks.take(callbackIdentifier);
1875 ASSERT(callback || m_hardClosedForUserDelete);
1877 callback(error, count);
1880 void UniqueIDBDatabase::forgetErrorCallback(uint64_t callbackIdentifier)
1882 ASSERT(m_errorCallbacks.contains(callbackIdentifier));
1883 m_errorCallbacks.remove(callbackIdentifier);
1886 } // namespace IDBServer
1887 } // namespace WebCore
1889 #endif // ENABLE(INDEXED_DATABASE)