8332503ecb07094caf762cc67db6f8fdcd37b1ff
[WebKit-https.git] / Source / WebCore / Modules / indexeddb / server / UniqueIDBDatabase.cpp
1 /*
2  * Copyright (C) 2015, 2016 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
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.
12  *
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.
24  */
25
26 #include "config.h"
27 #include "UniqueIDBDatabase.h"
28
29 #if ENABLE(INDEXED_DATABASE)
30
31 #include "IDBBindingUtilities.h"
32 #include "IDBCursorInfo.h"
33 #include "IDBGetAllRecordsData.h"
34 #include "IDBGetAllResult.h"
35 #include "IDBGetRecordData.h"
36 #include "IDBIterateCursorData.h"
37 #include "IDBKeyRangeData.h"
38 #include "IDBResultData.h"
39 #include "IDBServer.h"
40 #include "IDBTransactionInfo.h"
41 #include "IDBValue.h"
42 #include "Logging.h"
43 #include "SerializedScriptValue.h"
44 #include "StorageQuotaManager.h"
45 #include "UniqueIDBDatabaseConnection.h"
46 #include <JavaScriptCore/AuxiliaryBarrierInlines.h>
47 #include <JavaScriptCore/HeapInlines.h>
48 #include <JavaScriptCore/StrongInlines.h>
49 #include <JavaScriptCore/StructureInlines.h>
50 #include <wtf/MainThread.h>
51 #include <wtf/NeverDestroyed.h>
52 #include <wtf/Scope.h>
53
54 namespace WebCore {
55 using namespace JSC;
56 namespace IDBServer {
57
58 static const uint64_t defaultWriteOperationCost = 4;
59
60 static inline uint64_t estimateSize(const IDBKeyData& keyData)
61 {
62     uint64_t size = 4;
63     switch (keyData.type()) {
64     case IndexedDB::KeyType::String:
65         size += keyData.string().sizeInBytes();
66         break;
67     case IndexedDB::KeyType::Binary: {
68         size += keyData.binary().size();
69         break;
70     }
71     case IndexedDB::KeyType::Array:
72         for (auto& data : keyData.array())
73             size += estimateSize(data);
74         break;
75     default:
76         break;
77     }
78     return size;
79 }
80
81 static inline uint64_t estimateSize(const IDBValue& value)
82 {
83     uint64_t size = 4;
84     size += value.data().size();
85     for (auto& url : value.blobURLs())
86         size += url.sizeInBytes();
87     for (auto& path : value.blobFilePaths())
88         size += path.sizeInBytes();
89     return size;
90 }
91
92 static inline uint64_t estimateSize(const IDBIndexInfo& info)
93 {
94     uint64_t size = 4;
95     size += info.name().sizeInBytes();
96     return size;
97 }
98
99 static inline uint64_t estimateSize(const IDBObjectStoreInfo& info)
100 {
101     uint64_t size = 4;
102     size += info.name().sizeInBytes();
103     // FIXME: estimate keyPath.
104     for (auto& indexInfo : info.indexMap().values())
105         size += estimateSize(indexInfo);
106     return size;
107 }
108
109 UniqueIDBDatabase::UniqueIDBDatabase(IDBServer& server, const IDBDatabaseIdentifier& identifier)
110     : m_server(server)
111     , m_identifier(identifier)
112     , m_operationAndTransactionTimer(*this, &UniqueIDBDatabase::operationAndTransactionTimerFired)
113 {
114     LOG(IndexedDB, "UniqueIDBDatabase::UniqueIDBDatabase() (%p) %s", this, m_identifier.debugString().utf8().data());
115 }
116
117 UniqueIDBDatabase::~UniqueIDBDatabase()
118 {
119     LOG(IndexedDB, "UniqueIDBDatabase::~UniqueIDBDatabase() (%p) %s", this, m_identifier.debugString().utf8().data());
120     ASSERT(isMainThread());
121     ASSERT(!hasAnyPendingCallbacks());
122     ASSERT(!hasUnfinishedTransactions());
123     ASSERT(m_pendingTransactions.isEmpty());
124     ASSERT(m_openDatabaseConnections.isEmpty());
125     ASSERT(m_clientClosePendingDatabaseConnections.isEmpty());
126     ASSERT(m_serverClosePendingDatabaseConnections.isEmpty());
127
128     RELEASE_ASSERT(m_databaseQueue.isKilled());
129     RELEASE_ASSERT(m_databaseReplyQueue.isKilled());
130     RELEASE_ASSERT(!m_backingStore);
131 }
132
133 const IDBDatabaseInfo& UniqueIDBDatabase::info() const
134 {
135     RELEASE_ASSERT(m_databaseInfo);
136     return *m_databaseInfo;
137 }
138
139 void UniqueIDBDatabase::openDatabaseConnection(IDBConnectionToClient& connection, const IDBRequestData& requestData)
140 {
141     LOG(IndexedDB, "UniqueIDBDatabase::openDatabaseConnection");
142     ASSERT(!m_hardClosedForUserDelete);
143     ASSERT(isMainThread());
144
145     m_pendingOpenDBRequests.add(ServerOpenDBRequest::create(connection, requestData));
146
147     // An open operation is already in progress, so we can't possibly handle this one yet.
148     if (m_isOpeningBackingStore)
149         return;
150
151     handleDatabaseOperations();
152 }
153
154 bool UniqueIDBDatabase::hasAnyPendingCallbacks() const
155 {
156     return !m_errorCallbacks.isEmpty()
157         || !m_keyDataCallbacks.isEmpty()
158         || !m_getResultCallbacks.isEmpty()
159         || !m_getAllResultsCallbacks.isEmpty()
160         || !m_countCallbacks.isEmpty();
161 }
162
163 bool UniqueIDBDatabase::isVersionChangeInProgress()
164 {
165 #if !LOG_DISABLED
166     if (m_versionChangeTransaction)
167         ASSERT(m_versionChangeDatabaseConnection);
168 #endif
169
170     return m_versionChangeDatabaseConnection;
171 }
172
173 static inline String quotaErrorMessageName(const char* taskName)
174 {
175     return makeString("Failed to ", taskName, " in database because not enough space for domain");
176 }
177
178 void UniqueIDBDatabase::requestSpace(uint64_t taskSize, const char* taskName, CompletionHandler<void(Optional<IDBError>&&)>&& callback)
179 {
180     m_server->requestSpace(m_identifier.origin(), taskSize, [weakThis = makeWeakPtr(this), this, taskName, callback = WTFMove(callback)](auto decision) mutable {
181         if (!weakThis) {
182             callback(IDBError { UnknownError });
183             return;
184         }
185
186         if (m_owningPointerForClose) {
187             // We are closing the database, there is no point in trying to modify the database at that point.
188             callback(IDBError { UnknownError });
189             return;
190         }
191
192         switch (decision) {
193         case StorageQuotaManager::Decision::Deny:
194             callback(IDBError { QuotaExceededError, quotaErrorMessageName(taskName) });
195             return;
196         case StorageQuotaManager::Decision::Grant:
197             callback({ });
198         };
199     });
200 }
201
202 void UniqueIDBDatabase::waitForRequestSpaceCompletion(CompletionHandler<void(Optional<IDBError>&&)>&& callback)
203 {
204     requestSpace(0, "", WTFMove(callback));
205 }
206
207 void UniqueIDBDatabase::performCurrentOpenOperation()
208 {
209     LOG(IndexedDB, "(main) UniqueIDBDatabase::performCurrentOpenOperation (%p)", this);
210
211     ASSERT(m_currentOpenDBRequest);
212     ASSERT(m_currentOpenDBRequest->isOpenRequest());
213
214     if (!m_databaseInfo) {
215         if (!m_isOpeningBackingStore) {
216             m_isOpeningBackingStore = true;
217             // We do not know whether this is an existing or a new database.
218             // We set a small cost so that it is not possible to open an infinite number of database.
219             m_server->requestSpace(m_identifier.origin(), defaultWriteOperationCost, [this, weakThis = makeWeakPtr(this)](auto decision) mutable {
220                 if (!weakThis)
221                     return;
222
223                 if (m_owningPointerForClose)
224                     return;
225
226                 switch (decision) {
227                 case StorageQuotaManager::Decision::Deny: {
228                     auto result = IDBResultData::error(m_currentOpenDBRequest->requestData().requestIdentifier(), IDBError { QuotaExceededError, quotaErrorMessageName("openDatabase") });
229                     m_currentOpenDBRequest->connection().didOpenDatabase(result);
230                     m_currentOpenDBRequest = nullptr;
231                     break;
232                 }
233                 case StorageQuotaManager::Decision::Grant:
234                     this->postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::openBackingStore, m_identifier));
235                 };
236             });
237         }
238         return;
239     }
240
241     // If we previously started a version change operation but were blocked by having open connections,
242     // we might now be unblocked.
243     if (m_versionChangeDatabaseConnection) {
244         if (!m_versionChangeTransaction && !hasAnyOpenConnections())
245             startVersionChangeTransaction();
246         return;
247     }
248
249     // 3.3.1 Opening a database
250     // If requested version is undefined, then let requested version be 1 if db was created in the previous step,
251     // or the current version of db otherwise.
252     uint64_t requestedVersion = m_currentOpenDBRequest->requestData().requestedVersion();
253     if (!requestedVersion)
254         requestedVersion = m_databaseInfo->version() ? m_databaseInfo->version() : 1;
255
256     // 3.3.1 Opening a database
257     // If the database version higher than the requested version, abort these steps and return a VersionError.
258     if (requestedVersion < m_databaseInfo->version()) {
259         auto result = IDBResultData::error(m_currentOpenDBRequest->requestData().requestIdentifier(), IDBError(VersionError));
260         m_currentOpenDBRequest->connection().didOpenDatabase(result);
261         m_currentOpenDBRequest = nullptr;
262
263         return;
264     }
265
266     if (!m_backingStoreOpenError.isNull()) {
267         auto result = IDBResultData::error(m_currentOpenDBRequest->requestData().requestIdentifier(), m_backingStoreOpenError);
268         m_currentOpenDBRequest->connection().didOpenDatabase(result);
269         m_currentOpenDBRequest = nullptr;
270
271         return;
272     }
273
274     Ref<UniqueIDBDatabaseConnection> connection = UniqueIDBDatabaseConnection::create(*this, *m_currentOpenDBRequest);
275
276     if (requestedVersion == m_databaseInfo->version()) {
277         auto* rawConnection = &connection.get();
278         addOpenDatabaseConnection(WTFMove(connection));
279
280         auto result = IDBResultData::openDatabaseSuccess(m_currentOpenDBRequest->requestData().requestIdentifier(), *rawConnection);
281         m_currentOpenDBRequest->connection().didOpenDatabase(result);
282         m_currentOpenDBRequest = nullptr;
283
284         return;
285     }
286
287     ASSERT(!m_versionChangeDatabaseConnection);
288     m_versionChangeDatabaseConnection = WTFMove(connection);
289
290     // 3.3.7 "versionchange" transaction steps
291     // If there's no other open connections to this database, the version change process can begin immediately.
292     if (!hasAnyOpenConnections()) {
293         startVersionChangeTransaction();
294         return;
295     }
296
297     // Otherwise we have to notify all those open connections and wait for them to close.
298     maybeNotifyConnectionsOfVersionChange();
299 }
300
301 void UniqueIDBDatabase::performCurrentDeleteOperation()
302 {
303     ASSERT(isMainThread());
304     LOG(IndexedDB, "(main) UniqueIDBDatabase::performCurrentDeleteOperation - %s", m_identifier.debugString().utf8().data());
305
306     ASSERT(m_currentOpenDBRequest);
307     ASSERT(m_currentOpenDBRequest->isDeleteRequest());
308
309     if (m_deleteBackingStoreInProgress)
310         return;
311
312     if (hasAnyOpenConnections()) {
313         maybeNotifyConnectionsOfVersionChange();
314         return;
315     }
316
317     if (hasUnfinishedTransactions())
318         return;
319
320     ASSERT(!hasAnyPendingCallbacks());
321     ASSERT(m_pendingTransactions.isEmpty());
322     ASSERT(m_openDatabaseConnections.isEmpty());
323
324     // It's possible to have multiple delete requests queued up in a row.
325     // In that scenario only the first request will actually have to delete the database.
326     // Subsequent requests can immediately notify their completion.
327
328     if (!m_deleteBackingStoreInProgress) {
329         if (!m_databaseInfo && m_mostRecentDeletedDatabaseInfo)
330             didDeleteBackingStore(0);
331         else {
332             m_deleteBackingStoreInProgress = true;
333             notifyServerAboutClose(CloseState::Start);
334             postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::deleteBackingStore, m_identifier));
335         }
336     }
337 }
338
339 void UniqueIDBDatabase::deleteBackingStore(const IDBDatabaseIdentifier& identifier)
340 {
341     ASSERT(!isMainThread());
342     LOG(IndexedDB, "(db) UniqueIDBDatabase::deleteBackingStore");
343
344     uint64_t deletedVersion = 0;
345
346     if (m_backingStore) {
347         m_backingStore->deleteBackingStore();
348         m_backingStore = nullptr;
349         m_backingStoreSupportsSimultaneousTransactions = false;
350         m_backingStoreIsEphemeral = false;
351     } else {
352         auto backingStore = m_server->createBackingStore(identifier);
353
354         IDBDatabaseInfo databaseInfo;
355         auto error = backingStore->getOrEstablishDatabaseInfo(databaseInfo);
356         if (!error.isNull())
357             LOG_ERROR("Error getting database info from database %s that we are trying to delete", identifier.debugString().utf8().data());
358
359         deletedVersion = databaseInfo.version();
360         backingStore->deleteBackingStore();
361     }
362
363     postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didDeleteBackingStore, deletedVersion));
364 }
365
366 void UniqueIDBDatabase::performUnconditionalDeleteBackingStore()
367 {
368     ASSERT(!isMainThread());
369     LOG(IndexedDB, "(db) UniqueIDBDatabase::performUnconditionalDeleteBackingStore");
370
371     if (m_backingStore)
372         m_backingStore->deleteBackingStore();
373
374     shutdownForClose();
375 }
376
377 void UniqueIDBDatabase::scheduleShutdownForClose()
378 {
379     ASSERT(isMainThread());
380
381     m_operationAndTransactionTimer.stop();
382
383     RELEASE_ASSERT(!m_owningPointerForClose);
384     m_owningPointerForClose = m_server->closeAndTakeUniqueIDBDatabase(*this);
385
386     notifyServerAboutClose(CloseState::Start);
387     postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::shutdownForClose));
388 }
389
390 void UniqueIDBDatabase::shutdownForClose()
391 {
392     ASSERT(!isMainThread());
393     ASSERT(m_owningPointerForClose.get() == this);
394
395     LOG(IndexedDB, "(db) UniqueIDBDatabase::shutdownForClose");
396
397     m_backingStore = nullptr;
398     m_backingStoreSupportsSimultaneousTransactions = false;
399     m_backingStoreIsEphemeral = false;
400
401     if (!m_databaseQueue.isEmpty()) {
402         postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::shutdownForClose));
403         return;
404     }
405     m_databaseQueue.kill();
406
407     postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didShutdownForClose));
408 }
409
410 void UniqueIDBDatabase::didShutdownForClose()
411 {
412     ASSERT(m_databaseReplyQueue.isEmpty());
413     m_databaseReplyQueue.kill();
414     notifyServerAboutClose(CloseState::Done);
415 }
416
417 void UniqueIDBDatabase::didDeleteBackingStore(uint64_t deletedVersion)
418 {
419     ASSERT(isMainThread());
420     LOG(IndexedDB, "(main) UniqueIDBDatabase::didDeleteBackingStore");
421
422     ASSERT(!hasAnyPendingCallbacks());
423     ASSERT(!hasUnfinishedTransactions());
424     ASSERT(m_pendingTransactions.isEmpty());
425     ASSERT(m_openDatabaseConnections.isEmpty());
426     ASSERT(!m_backingStore);
427
428     // It's possible that the openDBRequest was cancelled from client-side after the delete was already dispatched to the backingstore.
429     // So it's okay if we don't have a currentOpenDBRequest, but if we do it has to be a deleteRequest.
430     ASSERT(!m_currentOpenDBRequest || m_currentOpenDBRequest->isDeleteRequest());
431
432     if (m_databaseInfo)
433         m_mostRecentDeletedDatabaseInfo = WTFMove(m_databaseInfo);
434
435     // If this UniqueIDBDatabase was brought into existence for the purpose of deleting the file on disk,
436     // we won't have a m_mostRecentDeletedDatabaseInfo. In that case, we'll manufacture one using the
437     // passed in deletedVersion argument.
438     if (!m_mostRecentDeletedDatabaseInfo)
439         m_mostRecentDeletedDatabaseInfo = std::make_unique<IDBDatabaseInfo>(m_identifier.databaseName(), deletedVersion);
440
441     if (m_currentOpenDBRequest) {
442         m_currentOpenDBRequest->notifyDidDeleteDatabase(*m_mostRecentDeletedDatabaseInfo);
443         m_currentOpenDBRequest = nullptr;
444     }
445
446     m_deleteBackingStoreInProgress = false;
447
448     if (m_hardClosedForUserDelete)
449         return;
450     notifyServerAboutClose(CloseState::Done);
451
452     invokeOperationAndTransactionTimer();
453 }
454
455 void UniqueIDBDatabase::clearStalePendingOpenDBRequests()
456 {
457     while (!m_pendingOpenDBRequests.isEmpty() && m_pendingOpenDBRequests.first()->connection().isClosed())
458         m_pendingOpenDBRequests.removeFirst();
459 }
460
461 void UniqueIDBDatabase::handleDatabaseOperations()
462 {
463     ASSERT(isMainThread());
464     LOG(IndexedDB, "(main) UniqueIDBDatabase::handleDatabaseOperations - There are %u pending", m_pendingOpenDBRequests.size());
465     ASSERT(!m_hardClosedForUserDelete);
466
467     if (m_deleteBackingStoreInProgress)
468         return;
469
470     clearStalePendingOpenDBRequests();
471
472     if (m_versionChangeDatabaseConnection || m_versionChangeTransaction || (m_currentOpenDBRequest && !m_currentOpenDBRequest->connection().isClosed())) {
473         // We can't start any new open-database operations right now, but we might be able to start handling a delete operation.
474         if (!m_currentOpenDBRequest && !m_pendingOpenDBRequests.isEmpty() && m_pendingOpenDBRequests.first()->isDeleteRequest())
475             m_currentOpenDBRequest = m_pendingOpenDBRequests.takeFirst();
476
477         // Some operations (such as the first open operation after a delete) require multiple passes to completely handle
478         if (m_currentOpenDBRequest)
479             handleCurrentOperation();
480
481         return;
482     }
483
484     if (m_pendingOpenDBRequests.isEmpty()) {
485         m_currentOpenDBRequest = nullptr;
486         return;
487     }
488
489     m_currentOpenDBRequest = m_pendingOpenDBRequests.takeFirst();
490     LOG(IndexedDB, "UniqueIDBDatabase::handleDatabaseOperations - Popped an operation, now there are %u pending", m_pendingOpenDBRequests.size());
491
492     handleCurrentOperation();
493 }
494
495 void UniqueIDBDatabase::handleCurrentOperation()
496 {
497     LOG(IndexedDB, "(main) UniqueIDBDatabase::handleCurrentOperation");
498     ASSERT(!m_hardClosedForUserDelete);
499     ASSERT(m_currentOpenDBRequest);
500
501     if (m_currentOpenDBRequest->isOpenRequest())
502         performCurrentOpenOperation();
503     else if (m_currentOpenDBRequest->isDeleteRequest())
504         performCurrentDeleteOperation();
505     else
506         ASSERT_NOT_REACHED();
507
508     if (!m_currentOpenDBRequest)
509         invokeOperationAndTransactionTimer();
510 }
511
512 bool UniqueIDBDatabase::hasAnyOpenConnections() const
513 {
514     return !m_openDatabaseConnections.isEmpty();
515 }
516
517 bool UniqueIDBDatabase::allConnectionsAreClosedOrClosing() const
518 {
519     for (auto& connection : m_openDatabaseConnections) {
520         if (!connection->connectionIsClosing())
521             return false;
522     }
523
524     return true;
525 }
526
527 static uint64_t generateUniqueCallbackIdentifier()
528 {
529     ASSERT(isMainThread());
530     static uint64_t currentID = 0;
531     return ++currentID;
532 }
533
534 uint64_t UniqueIDBDatabase::storeCallbackOrFireError(ErrorCallback&& callback, uint64_t taskSize)
535 {
536     if (m_hardClosedForUserDelete) {
537         callback(IDBError::userDeleteError());
538         return 0;
539     }
540
541     uint64_t identifier = generateUniqueCallbackIdentifier();
542     ASSERT(!m_errorCallbacks.contains(identifier));
543     m_errorCallbacks.add(identifier, WTFMove(callback));
544
545     if (taskSize) {
546         m_server->increasePotentialSpaceUsed(m_identifier.origin(), taskSize);
547         m_pendingSpaceIncreasingTasks.add(identifier, taskSize);
548     }
549
550     m_callbackQueue.append(identifier);
551     return identifier;
552 }
553
554 uint64_t UniqueIDBDatabase::storeCallbackOrFireError(KeyDataCallback&& callback, uint64_t taskSize)
555 {
556     if (m_hardClosedForUserDelete) {
557         callback(IDBError::userDeleteError(), { });
558         return 0;
559     }
560
561     uint64_t identifier = generateUniqueCallbackIdentifier();
562     ASSERT(!m_keyDataCallbacks.contains(identifier));
563     m_keyDataCallbacks.add(identifier, WTFMove(callback));
564
565     if (taskSize) {
566         m_server->increasePotentialSpaceUsed(m_identifier.origin(), taskSize);
567         m_pendingSpaceIncreasingTasks.add(identifier, taskSize);
568     }
569
570     m_callbackQueue.append(identifier);
571     return identifier;
572 }
573
574 uint64_t UniqueIDBDatabase::storeCallbackOrFireError(GetResultCallback&& callback)
575 {
576     if (m_hardClosedForUserDelete) {
577         callback(IDBError::userDeleteError(), { });
578         return 0;
579     }
580
581     uint64_t identifier = generateUniqueCallbackIdentifier();
582     ASSERT(!m_getResultCallbacks.contains(identifier));
583     m_getResultCallbacks.add(identifier, WTFMove(callback));
584     m_callbackQueue.append(identifier);
585     return identifier;
586 }
587
588 uint64_t UniqueIDBDatabase::storeCallbackOrFireError(GetAllResultsCallback&& callback)
589 {
590     if (m_hardClosedForUserDelete) {
591         callback(IDBError::userDeleteError(), { });
592         return 0;
593     }
594
595     uint64_t identifier = generateUniqueCallbackIdentifier();
596     ASSERT(!m_getAllResultsCallbacks.contains(identifier));
597     m_getAllResultsCallbacks.add(identifier, WTFMove(callback));
598     m_callbackQueue.append(identifier);
599     return identifier;
600 }
601
602 uint64_t UniqueIDBDatabase::storeCallbackOrFireError(CountCallback&& callback)
603 {
604     if (m_hardClosedForUserDelete) {
605         callback(IDBError::userDeleteError(), 0);
606         return 0;
607     }
608
609     uint64_t identifier = generateUniqueCallbackIdentifier();
610     ASSERT(!m_countCallbacks.contains(identifier));
611     m_countCallbacks.add(identifier, WTFMove(callback));
612     m_callbackQueue.append(identifier);
613     return identifier;
614 }
615
616 void UniqueIDBDatabase::handleDelete(IDBConnectionToClient& connection, const IDBRequestData& requestData)
617 {
618     LOG(IndexedDB, "(main) UniqueIDBDatabase::handleDelete");
619     ASSERT(!m_hardClosedForUserDelete);
620
621     m_pendingOpenDBRequests.add(ServerOpenDBRequest::create(connection, requestData));
622     handleDatabaseOperations();
623 }
624
625 void UniqueIDBDatabase::startVersionChangeTransaction()
626 {
627     LOG(IndexedDB, "(main) UniqueIDBDatabase::startVersionChangeTransaction");
628
629     ASSERT(!m_versionChangeTransaction);
630     ASSERT(m_currentOpenDBRequest);
631     ASSERT(m_currentOpenDBRequest->isOpenRequest());
632     ASSERT(m_versionChangeDatabaseConnection);
633
634     auto operation = WTFMove(m_currentOpenDBRequest);
635
636     uint64_t requestedVersion = operation->requestData().requestedVersion();
637     if (!requestedVersion)
638         requestedVersion = m_databaseInfo->version() ? m_databaseInfo->version() : 1;
639
640     addOpenDatabaseConnection(*m_versionChangeDatabaseConnection);
641
642     m_versionChangeTransaction = &m_versionChangeDatabaseConnection->createVersionChangeTransaction(requestedVersion);
643     m_databaseInfo->setVersion(requestedVersion);
644
645     m_inProgressTransactions.set(m_versionChangeTransaction->info().identifier(), m_versionChangeTransaction);
646     postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::beginTransactionInBackingStore, m_versionChangeTransaction->info()));
647
648     auto result = IDBResultData::openDatabaseUpgradeNeeded(operation->requestData().requestIdentifier(), *m_versionChangeTransaction);
649     operation->connection().didOpenDatabase(result);
650 }
651
652 void UniqueIDBDatabase::beginTransactionInBackingStore(const IDBTransactionInfo& info)
653 {
654     LOG(IndexedDB, "(db) UniqueIDBDatabase::beginTransactionInBackingStore");
655     m_backingStore->beginTransaction(info);
656 }
657
658 void UniqueIDBDatabase::maybeNotifyConnectionsOfVersionChange()
659 {
660     ASSERT(m_currentOpenDBRequest);
661
662     if (m_currentOpenDBRequest->hasNotifiedConnectionsOfVersionChange())
663         return;
664
665     uint64_t newVersion = m_currentOpenDBRequest->isOpenRequest() ? m_currentOpenDBRequest->requestData().requestedVersion() : 0;
666     auto requestIdentifier = m_currentOpenDBRequest->requestData().requestIdentifier();
667
668     LOG(IndexedDB, "(main) UniqueIDBDatabase::notifyConnectionsOfVersionChange - %" PRIu64, newVersion);
669
670     // 3.3.7 "versionchange" transaction steps
671     // Fire a versionchange event at each connection in m_openDatabaseConnections that is open.
672     // The event must not be fired on connections which has the closePending flag set.
673     HashSet<uint64_t> connectionIdentifiers;
674     for (const auto& connection : m_openDatabaseConnections) {
675         if (connection->closePending())
676             continue;
677
678         connection->fireVersionChangeEvent(requestIdentifier, newVersion);
679         connectionIdentifiers.add(connection->identifier());
680     }
681
682     if (!connectionIdentifiers.isEmpty())
683         m_currentOpenDBRequest->notifiedConnectionsOfVersionChange(WTFMove(connectionIdentifiers));
684     else
685         m_currentOpenDBRequest->maybeNotifyRequestBlocked(m_databaseInfo->version());
686 }
687
688 void UniqueIDBDatabase::notifyCurrentRequestConnectionClosedOrFiredVersionChangeEvent(uint64_t connectionIdentifier)
689 {
690     LOG(IndexedDB, "UniqueIDBDatabase::notifyCurrentRequestConnectionClosedOrFiredVersionChangeEvent - %" PRIu64, connectionIdentifier);
691
692     ASSERT(m_currentOpenDBRequest);
693
694     m_currentOpenDBRequest->connectionClosedOrFiredVersionChangeEvent(connectionIdentifier);
695
696     if (m_currentOpenDBRequest->hasConnectionsPendingVersionChangeEvent())
697         return;
698
699     if (!hasAnyOpenConnections() || allConnectionsAreClosedOrClosing()) {
700         invokeOperationAndTransactionTimer();
701         return;
702     }
703
704     // Since all open connections have fired their version change events but not all of them have closed,
705     // this request is officially blocked.
706     m_currentOpenDBRequest->maybeNotifyRequestBlocked(m_databaseInfo->version());
707 }
708
709 void UniqueIDBDatabase::didFireVersionChangeEvent(UniqueIDBDatabaseConnection& connection, const IDBResourceIdentifier& requestIdentifier)
710 {
711     LOG(IndexedDB, "UniqueIDBDatabase::didFireVersionChangeEvent");
712
713     if (!m_currentOpenDBRequest)
714         return;
715
716     ASSERT_UNUSED(requestIdentifier, m_currentOpenDBRequest->requestData().requestIdentifier() == requestIdentifier);
717
718     notifyCurrentRequestConnectionClosedOrFiredVersionChangeEvent(connection.identifier());
719 }
720
721 void UniqueIDBDatabase::openDBRequestCancelled(const IDBResourceIdentifier& requestIdentifier)
722 {
723     LOG(IndexedDB, "UniqueIDBDatabase::openDBRequestCancelled - %s", requestIdentifier.loggingString().utf8().data());
724
725     if (m_currentOpenDBRequest && m_currentOpenDBRequest->requestData().requestIdentifier() == requestIdentifier)
726         m_currentOpenDBRequest = nullptr;
727
728     if (m_versionChangeDatabaseConnection && m_versionChangeDatabaseConnection->openRequestIdentifier() == requestIdentifier) {
729         ASSERT(!m_versionChangeTransaction || m_versionChangeTransaction->databaseConnection().openRequestIdentifier() == requestIdentifier);
730         ASSERT(!m_versionChangeTransaction || &m_versionChangeTransaction->databaseConnection() == m_versionChangeDatabaseConnection);
731
732         connectionClosedFromClient(*m_versionChangeDatabaseConnection);
733     }
734
735     for (auto& request : m_pendingOpenDBRequests) {
736         if (request->requestData().requestIdentifier() == requestIdentifier) {
737             m_pendingOpenDBRequests.remove(request);
738             return;
739         }
740     }
741 }
742
743 void UniqueIDBDatabase::addOpenDatabaseConnection(Ref<UniqueIDBDatabaseConnection>&& connection)
744 {
745     ASSERT(!m_openDatabaseConnections.contains(&connection.get()));
746     m_openDatabaseConnections.add(adoptRef(connection.leakRef()));
747 }
748
749 void UniqueIDBDatabase::openBackingStore(const IDBDatabaseIdentifier& identifier)
750 {
751     ASSERT(!isMainThread());
752     LOG(IndexedDB, "(db) UniqueIDBDatabase::openBackingStore (%p)", this);
753
754     ASSERT(!m_backingStore);
755     m_backingStore = m_server->createBackingStore(identifier);
756     m_backingStoreSupportsSimultaneousTransactions = m_backingStore->supportsSimultaneousTransactions();
757     m_backingStoreIsEphemeral = m_backingStore->isEphemeral();
758
759     IDBDatabaseInfo databaseInfo;
760     auto error = m_backingStore->getOrEstablishDatabaseInfo(databaseInfo);
761
762     postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didOpenBackingStore, databaseInfo, error));
763 }
764
765 void UniqueIDBDatabase::didOpenBackingStore(const IDBDatabaseInfo& info, const IDBError& error)
766 {
767     ASSERT(isMainThread());
768     LOG(IndexedDB, "(main) UniqueIDBDatabase::didOpenBackingStore");
769     
770     m_databaseInfo = std::make_unique<IDBDatabaseInfo>(info);
771     m_backingStoreOpenError = error;
772
773     ASSERT(m_isOpeningBackingStore);
774     m_isOpeningBackingStore = false;
775
776     if (m_hardClosedForUserDelete)
777         return;
778
779     handleDatabaseOperations();
780 }
781
782 void UniqueIDBDatabase::createObjectStore(UniqueIDBDatabaseTransaction& transaction, const IDBObjectStoreInfo& info, ErrorCallback callback)
783 {
784     ASSERT(isMainThread());
785     LOG(IndexedDB, "(main) UniqueIDBDatabase::createObjectStore");
786
787     auto taskSize = defaultWriteOperationCost + estimateSize(info);
788     requestSpace(taskSize, "createObjectStore", [this, taskSize, transaction = makeRef(transaction), info, callback = WTFMove(callback)](auto error) mutable {
789         if (error) {
790             callback(WTFMove(*error));
791             return;
792         }
793         this->createObjectStoreAfterQuotaCheck(taskSize, transaction.get(), info, WTFMove(callback));
794     });
795 }
796
797 void UniqueIDBDatabase::createObjectStoreAfterQuotaCheck(uint64_t taskSize, UniqueIDBDatabaseTransaction& transaction, const IDBObjectStoreInfo& info, ErrorCallback callback)
798 {
799     uint64_t callbackID = storeCallbackOrFireError(WTFMove(callback), taskSize);
800     if (!callbackID)
801         return;
802
803     postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performCreateObjectStore, callbackID, transaction.info().identifier(), info));
804 }
805
806 void UniqueIDBDatabase::performCreateObjectStore(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, const IDBObjectStoreInfo& info)
807 {
808     ASSERT(!isMainThread());
809     LOG(IndexedDB, "(db) UniqueIDBDatabase::performCreateObjectStore");
810
811     ASSERT(m_backingStore);
812     m_backingStore->createObjectStore(transactionIdentifier, info);
813
814     IDBError error;
815     postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformCreateObjectStore, callbackIdentifier, error, info));
816 }
817
818 void UniqueIDBDatabase::didPerformCreateObjectStore(uint64_t callbackIdentifier, const IDBError& error, const IDBObjectStoreInfo& info)
819 {
820     ASSERT(isMainThread());
821     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformCreateObjectStore");
822
823     if (error.isNull())
824         m_databaseInfo->addExistingObjectStore(info);
825
826     performErrorCallback(callbackIdentifier, error);
827 }
828
829 void UniqueIDBDatabase::deleteObjectStore(UniqueIDBDatabaseTransaction& transaction, const String& objectStoreName, ErrorCallback callback)
830 {
831     ASSERT(isMainThread());
832     LOG(IndexedDB, "(main) UniqueIDBDatabase::deleteObjectStore");
833
834     waitForRequestSpaceCompletion([this, transaction = makeRef(transaction), objectStoreName, callback = WTFMove(callback)](auto error) mutable {
835         if (error) {
836             callback(WTFMove(*error));
837             return;
838         }
839         this->deleteObjectStoreAfterQuotaCheck(transaction, objectStoreName, WTFMove(callback));
840     });
841 }
842
843 void UniqueIDBDatabase::deleteObjectStoreAfterQuotaCheck(UniqueIDBDatabaseTransaction& transaction, const String& objectStoreName, ErrorCallback callback)
844 {
845     uint64_t callbackID = storeCallbackOrFireError(WTFMove(callback));
846     if (!callbackID)
847         return;
848
849     auto* info = m_databaseInfo->infoForExistingObjectStore(objectStoreName);
850     if (!info) {
851         performErrorCallback(callbackID, IDBError { UnknownError, "Attempt to delete non-existant object store"_s });
852         return;
853     }
854
855     postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performDeleteObjectStore, callbackID, transaction.info().identifier(), info->identifier()));
856 }
857
858 void UniqueIDBDatabase::performDeleteObjectStore(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier)
859 {
860     ASSERT(!isMainThread());
861     LOG(IndexedDB, "(db) UniqueIDBDatabase::performDeleteObjectStore");
862
863     ASSERT(m_backingStore);
864     m_backingStore->deleteObjectStore(transactionIdentifier, objectStoreIdentifier);
865
866     IDBError error;
867     postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformDeleteObjectStore, callbackIdentifier, error, objectStoreIdentifier));
868 }
869
870 void UniqueIDBDatabase::didPerformDeleteObjectStore(uint64_t callbackIdentifier, const IDBError& error, uint64_t objectStoreIdentifier)
871 {
872     ASSERT(isMainThread());
873     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformDeleteObjectStore");
874
875     if (error.isNull())
876         m_databaseInfo->deleteObjectStore(objectStoreIdentifier);
877
878     performErrorCallback(callbackIdentifier, error);
879 }
880
881 void UniqueIDBDatabase::renameObjectStore(UniqueIDBDatabaseTransaction& transaction, uint64_t objectStoreIdentifier, const String& newName, ErrorCallback callback)
882 {
883     ASSERT(isMainThread());
884     LOG(IndexedDB, "(main) UniqueIDBDatabase::renameObjectStore");
885
886     auto taskSize = defaultWriteOperationCost + newName.sizeInBytes();
887     requestSpace(taskSize, "renameObjectStore", [this, taskSize, transaction = makeRef(transaction), objectStoreIdentifier, newName, callback = WTFMove(callback)](auto error) mutable {
888         if (error) {
889             callback(WTFMove(*error));
890             return;
891         }
892         this->renameObjectStoreAfterQuotaCheck(taskSize, transaction.get(), objectStoreIdentifier, newName, WTFMove(callback));
893     });
894 }
895
896 void UniqueIDBDatabase::renameObjectStoreAfterQuotaCheck(uint64_t taskSize, UniqueIDBDatabaseTransaction& transaction, uint64_t objectStoreIdentifier, const String& newName, ErrorCallback callback)
897 {
898     uint64_t callbackID = storeCallbackOrFireError(WTFMove(callback), taskSize);
899     if (!callbackID)
900         return;
901
902     auto* info = m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
903     if (!info) {
904         performErrorCallback(callbackID, IDBError { UnknownError, "Attempt to rename non-existant object store"_s });
905         return;
906     }
907
908     postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performRenameObjectStore, callbackID, transaction.info().identifier(), objectStoreIdentifier, newName));
909 }
910
911 void UniqueIDBDatabase::performRenameObjectStore(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const String& newName)
912 {
913     ASSERT(!isMainThread());
914     LOG(IndexedDB, "(db) UniqueIDBDatabase::performRenameObjectStore");
915
916     ASSERT(m_backingStore);
917     m_backingStore->renameObjectStore(transactionIdentifier, objectStoreIdentifier, newName);
918
919     IDBError error;
920     postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformRenameObjectStore, callbackIdentifier, error, objectStoreIdentifier, newName));
921 }
922
923 void UniqueIDBDatabase::didPerformRenameObjectStore(uint64_t callbackIdentifier, const IDBError& error, uint64_t objectStoreIdentifier, const String& newName)
924 {
925     ASSERT(isMainThread());
926     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformRenameObjectStore");
927
928     if (error.isNull())
929         m_databaseInfo->renameObjectStore(objectStoreIdentifier, newName);
930
931     performErrorCallback(callbackIdentifier, error);
932 }
933
934 void UniqueIDBDatabase::clearObjectStore(UniqueIDBDatabaseTransaction& transaction, uint64_t objectStoreIdentifier, ErrorCallback callback)
935 {
936     ASSERT(isMainThread());
937     LOG(IndexedDB, "(main) UniqueIDBDatabase::clearObjectStore");
938
939     waitForRequestSpaceCompletion([this, transaction = makeRef(transaction), objectStoreIdentifier, callback = WTFMove(callback)](auto error) mutable {
940         if (error) {
941             callback(WTFMove(*error));
942             return;
943         }
944         this->clearObjectStoreAfetQuotaCheck(transaction, objectStoreIdentifier, WTFMove(callback));
945     });
946 }
947
948 void UniqueIDBDatabase::clearObjectStoreAfetQuotaCheck(UniqueIDBDatabaseTransaction& transaction, uint64_t objectStoreIdentifier, ErrorCallback callback)
949 {
950     uint64_t callbackID = storeCallbackOrFireError(WTFMove(callback));
951     if (!callbackID)
952         return;
953     postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performClearObjectStore, callbackID, transaction.info().identifier(), objectStoreIdentifier));
954 }
955
956 void UniqueIDBDatabase::performClearObjectStore(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier)
957 {
958     ASSERT(!isMainThread());
959     LOG(IndexedDB, "(db) UniqueIDBDatabase::performClearObjectStore");
960
961     ASSERT(m_backingStore);
962     m_backingStore->clearObjectStore(transactionIdentifier, objectStoreIdentifier);
963
964     IDBError error;
965     postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformClearObjectStore, callbackIdentifier, error));
966 }
967
968 void UniqueIDBDatabase::didPerformClearObjectStore(uint64_t callbackIdentifier, const IDBError& error)
969 {
970     ASSERT(isMainThread());
971     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformClearObjectStore");
972
973     performErrorCallback(callbackIdentifier, error);
974 }
975
976 void UniqueIDBDatabase::createIndex(UniqueIDBDatabaseTransaction& transaction, const IDBIndexInfo& info, ErrorCallback callback)
977 {
978     ASSERT(isMainThread());
979     LOG(IndexedDB, "(main) UniqueIDBDatabase::createIndex");
980
981     auto taskSize = defaultWriteOperationCost + estimateSize(info);
982     requestSpace(taskSize, "createIndex", [this, taskSize, transaction = makeRef(transaction), info, callback = WTFMove(callback)](auto error) mutable {
983         if (error) {
984             callback(WTFMove(*error));
985             return;
986         }
987         this->createIndexAfterQuotaCheck(taskSize, transaction.get(), info, WTFMove(callback));
988     });
989 }
990
991 void UniqueIDBDatabase::createIndexAfterQuotaCheck(uint64_t taskSize, UniqueIDBDatabaseTransaction& transaction, const IDBIndexInfo& info, ErrorCallback callback)
992 {
993     uint64_t callbackID = storeCallbackOrFireError(WTFMove(callback), taskSize);
994     if (!callbackID)
995         return;
996     postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performCreateIndex, callbackID, transaction.info().identifier(), info));
997 }
998
999 void UniqueIDBDatabase::performCreateIndex(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, const IDBIndexInfo& info)
1000 {
1001     ASSERT(!isMainThread());
1002     LOG(IndexedDB, "(db) UniqueIDBDatabase::performCreateIndex");
1003
1004     IDBError error;
1005     ASSERT(m_backingStore);
1006     if (!m_backingStore) {
1007         RELEASE_LOG_ERROR(IndexedDB, "%p - UniqueIDBDatabase::performCreateIndex: m_backingStore is null", this);
1008         error = IDBError(InvalidStateError, "Backing store is invalid for call to create index"_s);
1009         postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformCreateIndex, callbackIdentifier, error, info));
1010         return;
1011     }
1012
1013     error = m_backingStore->createIndex(transactionIdentifier, info);
1014     postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformCreateIndex, callbackIdentifier, error, info));
1015 }
1016
1017 void UniqueIDBDatabase::didPerformCreateIndex(uint64_t callbackIdentifier, const IDBError& error, const IDBIndexInfo& info)
1018 {
1019     ASSERT(isMainThread());
1020     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformCreateIndex");
1021
1022     if (error.isNull()) {
1023         ASSERT(m_databaseInfo);
1024         auto* objectStoreInfo = m_databaseInfo->infoForExistingObjectStore(info.objectStoreIdentifier());
1025         ASSERT(objectStoreInfo);
1026         objectStoreInfo->addExistingIndex(info);
1027     }
1028
1029     performErrorCallback(callbackIdentifier, error);
1030 }
1031
1032 void UniqueIDBDatabase::deleteIndex(UniqueIDBDatabaseTransaction& transaction, uint64_t objectStoreIdentifier, const String& indexName, ErrorCallback callback)
1033 {
1034     ASSERT(isMainThread());
1035     LOG(IndexedDB, "(main) UniqueIDBDatabase::deleteIndex");
1036
1037     waitForRequestSpaceCompletion([this, transaction = makeRef(transaction), objectStoreIdentifier, indexName, callback = WTFMove(callback)](auto error) mutable {
1038         if (error) {
1039             callback(WTFMove(*error));
1040             return;
1041         }
1042         this->deleteIndexAfterQuotaCheck(transaction, objectStoreIdentifier, indexName, WTFMove(callback));
1043     });
1044 }
1045
1046 void UniqueIDBDatabase::deleteIndexAfterQuotaCheck(UniqueIDBDatabaseTransaction& transaction, uint64_t objectStoreIdentifier, const String& indexName, ErrorCallback callback)
1047 {
1048     uint64_t callbackID = storeCallbackOrFireError(WTFMove(callback));
1049     if (!callbackID)
1050         return;
1051
1052     auto* objectStoreInfo = m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
1053     if (!objectStoreInfo) {
1054         performErrorCallback(callbackID, IDBError { UnknownError, "Attempt to delete index from non-existant object store"_s });
1055         return;
1056     }
1057
1058     auto* indexInfo = objectStoreInfo->infoForExistingIndex(indexName);
1059     if (!indexInfo) {
1060         performErrorCallback(callbackID, IDBError { UnknownError, "Attempt to delete non-existant index"_s });
1061         return;
1062     }
1063
1064     postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performDeleteIndex, callbackID, transaction.info().identifier(), objectStoreIdentifier, indexInfo->identifier()));
1065 }
1066
1067 void UniqueIDBDatabase::performDeleteIndex(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const uint64_t indexIdentifier)
1068 {
1069     ASSERT(!isMainThread());
1070     LOG(IndexedDB, "(db) UniqueIDBDatabase::performDeleteIndex");
1071
1072     ASSERT(m_backingStore);
1073     m_backingStore->deleteIndex(transactionIdentifier, objectStoreIdentifier, indexIdentifier);
1074
1075     IDBError error;
1076     postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformDeleteIndex, callbackIdentifier, error, objectStoreIdentifier, indexIdentifier));
1077 }
1078
1079 void UniqueIDBDatabase::didPerformDeleteIndex(uint64_t callbackIdentifier, const IDBError& error, uint64_t objectStoreIdentifier, uint64_t indexIdentifier)
1080 {
1081     ASSERT(isMainThread());
1082     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformDeleteIndex");
1083
1084     if (error.isNull()) {
1085         auto* objectStoreInfo = m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
1086         if (objectStoreInfo)
1087             objectStoreInfo->deleteIndex(indexIdentifier);
1088     }
1089
1090     performErrorCallback(callbackIdentifier, error);
1091 }
1092
1093 void UniqueIDBDatabase::renameIndex(UniqueIDBDatabaseTransaction& transaction, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const String& newName, ErrorCallback callback)
1094 {
1095     ASSERT(isMainThread());
1096     LOG(IndexedDB, "(main) UniqueIDBDatabase::renameIndex");
1097
1098     auto taskSize = defaultWriteOperationCost + newName.sizeInBytes();
1099     requestSpace(taskSize, "renameIndex", [this, taskSize, transaction = makeRef(transaction), objectStoreIdentifier, indexIdentifier, newName, callback = WTFMove(callback)](auto error) mutable {
1100         if (error) {
1101             callback(WTFMove(*error));
1102             return;
1103         }
1104         this->renameIndexAfterQuotaCheck(taskSize, transaction.get(), objectStoreIdentifier, indexIdentifier, newName, WTFMove(callback));
1105     });
1106 }
1107
1108 void UniqueIDBDatabase::renameIndexAfterQuotaCheck(uint64_t taskSize, UniqueIDBDatabaseTransaction& transaction, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const String& newName, ErrorCallback callback)
1109 {
1110     uint64_t callbackID = storeCallbackOrFireError(WTFMove(callback), taskSize);
1111     if (!callbackID)
1112         return;
1113
1114     auto* objectStoreInfo = m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
1115     if (!objectStoreInfo) {
1116         performErrorCallback(callbackID, IDBError { UnknownError, "Attempt to rename index in non-existant object store"_s });
1117         return;
1118     }
1119
1120     auto* indexInfo = objectStoreInfo->infoForExistingIndex(indexIdentifier);
1121     if (!indexInfo) {
1122         performErrorCallback(callbackID, IDBError { UnknownError, "Attempt to rename non-existant index"_s });
1123         return;
1124     }
1125
1126     postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performRenameIndex, callbackID, transaction.info().identifier(), objectStoreIdentifier, indexIdentifier, newName));
1127 }
1128
1129 void UniqueIDBDatabase::performRenameIndex(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const String& newName)
1130 {
1131     ASSERT(!isMainThread());
1132     LOG(IndexedDB, "(db) UniqueIDBDatabase::performRenameIndex");
1133
1134     ASSERT(m_backingStore);
1135     m_backingStore->renameIndex(transactionIdentifier, objectStoreIdentifier, indexIdentifier, newName);
1136
1137     IDBError error;
1138     postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformRenameIndex, callbackIdentifier, error, objectStoreIdentifier, indexIdentifier, newName));
1139 }
1140
1141 void UniqueIDBDatabase::didPerformRenameIndex(uint64_t callbackIdentifier, const IDBError& error, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const String& newName)
1142 {
1143     ASSERT(isMainThread());
1144     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformRenameIndex");
1145
1146     if (error.isNull()) {
1147         auto* objectStoreInfo = m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
1148         ASSERT(objectStoreInfo);
1149         if (objectStoreInfo) {
1150             auto* indexInfo = objectStoreInfo->infoForExistingIndex(indexIdentifier);
1151             ASSERT(indexInfo);
1152             indexInfo->rename(newName);
1153         }
1154     }
1155
1156     performErrorCallback(callbackIdentifier, error);
1157 }
1158
1159 void UniqueIDBDatabase::putOrAdd(const IDBRequestData& requestData, const IDBKeyData& keyData, const IDBValue& value, IndexedDB::ObjectStoreOverwriteMode overwriteMode, KeyDataCallback callback)
1160 {
1161     ASSERT(isMainThread());
1162     LOG(IndexedDB, "(main) UniqueIDBDatabase::putOrAdd");
1163
1164     auto taskSize = defaultWriteOperationCost + estimateSize(keyData) + estimateSize(value);
1165     requestSpace(taskSize, "putOrAdd", [this, taskSize, requestData, keyData, value, callback = WTFMove(callback), overwriteMode](auto error) mutable {
1166         if (error) {
1167             callback(WTFMove(*error), { });
1168             return;
1169         }
1170         this->putOrAddAfterQuotaCheck(taskSize, requestData, keyData, value, overwriteMode, WTFMove(callback));
1171     });
1172 }
1173
1174 void UniqueIDBDatabase::putOrAddAfterQuotaCheck(uint64_t taskSize, const IDBRequestData& requestData, const IDBKeyData& keyData, const IDBValue& value, IndexedDB::ObjectStoreOverwriteMode overwriteMode, KeyDataCallback callback)
1175 {
1176     uint64_t callbackID = storeCallbackOrFireError(WTFMove(callback), taskSize);
1177     if (!callbackID)
1178         return;
1179     postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performPutOrAdd, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), keyData, value, overwriteMode));
1180 }
1181
1182 VM& UniqueIDBDatabase::databaseThreadVM()
1183 {
1184     ASSERT(!isMainThread());
1185     static VM* vm = &VM::create().leakRef();
1186     return *vm;
1187 }
1188
1189 ExecState& UniqueIDBDatabase::databaseThreadExecState()
1190 {
1191     ASSERT(!isMainThread());
1192
1193     static NeverDestroyed<Strong<JSGlobalObject>> globalObject(databaseThreadVM(), JSGlobalObject::create(databaseThreadVM(), JSGlobalObject::createStructure(databaseThreadVM(), jsNull())));
1194
1195     RELEASE_ASSERT(globalObject.get()->globalExec());
1196     return *globalObject.get()->globalExec();
1197 }
1198
1199 void UniqueIDBDatabase::performPutOrAdd(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyData& keyData, const IDBValue& originalRecordValue, IndexedDB::ObjectStoreOverwriteMode overwriteMode)
1200 {
1201     ASSERT(!isMainThread());
1202     LOG(IndexedDB, "(db) UniqueIDBDatabase::performPutOrAdd");
1203
1204     ASSERT(m_backingStore);
1205     ASSERT(objectStoreIdentifier);
1206
1207     IDBKeyData usedKey;
1208     IDBError error;
1209
1210     if (!m_backingStore) {
1211         RELEASE_LOG_ERROR(IndexedDB, "%p - UniqueIDBDatabase::performPutOrAdd: m_backingStore is null", this);
1212         error = IDBError(InvalidStateError, "Backing store is invalid for call to put or add"_s);
1213         postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));
1214         return;
1215     }
1216
1217     auto* objectStoreInfo = m_backingStore->infoForObjectStore(objectStoreIdentifier);
1218     if (!objectStoreInfo) {
1219         error = IDBError(InvalidStateError, "Object store cannot be found in the backing store"_s);
1220         postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));
1221         return;
1222     }
1223
1224     bool usedKeyIsGenerated = false;
1225     uint64_t keyNumber;
1226     auto generatedKeyResetter = WTF::makeScopeExit([this, transactionIdentifier, objectStoreIdentifier, &keyNumber, &usedKeyIsGenerated]() {
1227         if (usedKeyIsGenerated)
1228             m_backingStore->revertGeneratedKeyNumber(transactionIdentifier, objectStoreIdentifier, keyNumber);
1229     });
1230     if (objectStoreInfo->autoIncrement() && !keyData.isValid()) {
1231         error = m_backingStore->generateKeyNumber(transactionIdentifier, objectStoreIdentifier, keyNumber);
1232         if (!error.isNull()) {
1233             postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));
1234             return;
1235         }
1236         
1237         usedKey.setNumberValue(keyNumber);
1238         usedKeyIsGenerated = true;
1239     } else
1240         usedKey = keyData;
1241
1242     if (overwriteMode == IndexedDB::ObjectStoreOverwriteMode::NoOverwrite) {
1243         bool keyExists;
1244         error = m_backingStore->keyExistsInObjectStore(transactionIdentifier, objectStoreIdentifier, usedKey, keyExists);
1245         if (error.isNull() && keyExists)
1246             error = IDBError(ConstraintError, "Key already exists in the object store"_s);
1247
1248         if (!error.isNull()) {
1249             postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));
1250             return;
1251         }
1252     }
1253
1254     // 3.4.1.2 Object Store Storage Operation
1255     // If ObjectStore has a key path and the key is autogenerated, then inject the key into the value
1256     // using steps to assign a key to a value using a key path.
1257     ThreadSafeDataBuffer injectedRecordValue;
1258     if (usedKeyIsGenerated && objectStoreInfo->keyPath()) {
1259         VM& vm = databaseThreadVM();
1260         JSLockHolder locker(vm);
1261         auto scope = DECLARE_THROW_SCOPE(vm);
1262
1263         auto value = deserializeIDBValueToJSValue(databaseThreadExecState(), originalRecordValue.data());
1264         if (value.isUndefined()) {
1265             postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, IDBError(ConstraintError, "Unable to deserialize record value for record key injection"_s), usedKey));
1266             return;
1267         }
1268
1269         if (!injectIDBKeyIntoScriptValue(databaseThreadExecState(), usedKey, value, objectStoreInfo->keyPath().value())) {
1270             postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, IDBError(ConstraintError, "Unable to inject record key into record value"_s), usedKey));
1271             return;
1272         }
1273
1274         auto serializedValue = SerializedScriptValue::create(databaseThreadExecState(), value);
1275         if (UNLIKELY(scope.exception())) {
1276             postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, IDBError(ConstraintError, "Unable to serialize record value after injecting record key"_s), usedKey));
1277             return;
1278         }
1279
1280         injectedRecordValue = ThreadSafeDataBuffer::copyVector(serializedValue->data());
1281     }
1282
1283     // 3.4.1 Object Store Storage Operation
1284     // ...If a record already exists in store ...
1285     // then remove the record from store using the steps for deleting records from an object store...
1286     // This is important because formally deleting it from from the object store also removes it from the appropriate indexes.
1287     error = m_backingStore->deleteRange(transactionIdentifier, objectStoreIdentifier, usedKey);
1288     if (!error.isNull()) {
1289         postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));
1290         return;
1291     }
1292
1293     if (injectedRecordValue.data())
1294         error = m_backingStore->addRecord(transactionIdentifier, *objectStoreInfo, usedKey, { injectedRecordValue, originalRecordValue.blobURLs(), originalRecordValue.sessionID(), originalRecordValue.blobFilePaths() });
1295     else
1296         error = m_backingStore->addRecord(transactionIdentifier, *objectStoreInfo, usedKey, originalRecordValue);
1297
1298     if (!error.isNull()) {
1299         postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));
1300         return;
1301     }
1302
1303     if (overwriteMode != IndexedDB::ObjectStoreOverwriteMode::OverwriteForCursor && objectStoreInfo->autoIncrement() && keyData.type() == IndexedDB::KeyType::Number)
1304         error = m_backingStore->maybeUpdateKeyGeneratorNumber(transactionIdentifier, objectStoreIdentifier, keyData.number());
1305
1306     generatedKeyResetter.release();
1307     postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));
1308 }
1309
1310 void UniqueIDBDatabase::didPerformPutOrAdd(uint64_t callbackIdentifier, const IDBError& error, const IDBKeyData& resultKey)
1311 {
1312     ASSERT(isMainThread());
1313     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformPutOrAdd");
1314
1315     performKeyDataCallback(callbackIdentifier, error, resultKey);
1316 }
1317
1318 void UniqueIDBDatabase::getRecord(const IDBRequestData& requestData, const IDBGetRecordData& getRecordData, GetResultCallback callback)
1319 {
1320     ASSERT(isMainThread());
1321     LOG(IndexedDB, "(main) UniqueIDBDatabase::getRecord");
1322
1323     waitForRequestSpaceCompletion([this, requestData, getRecordData, callback = WTFMove(callback)](auto error) mutable {
1324         if (error) {
1325             callback(WTFMove(*error), { });
1326             return;
1327         }
1328         this->getRecordAfterQuotaCheck(requestData, getRecordData, WTFMove(callback));
1329     });
1330 }
1331
1332 void UniqueIDBDatabase::getRecordAfterQuotaCheck(const IDBRequestData& requestData, const IDBGetRecordData& getRecordData, GetResultCallback callback)
1333 {
1334     uint64_t callbackID = storeCallbackOrFireError(WTFMove(callback));
1335     if (!callbackID)
1336         return;
1337
1338     if (uint64_t indexIdentifier = requestData.indexIdentifier())
1339         postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performGetIndexRecord, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), indexIdentifier, requestData.indexRecordType(), getRecordData.keyRangeData));
1340     else
1341         postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performGetRecord, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), getRecordData.keyRangeData, getRecordData.type));
1342 }
1343
1344 void UniqueIDBDatabase::getAllRecords(const IDBRequestData& requestData, const IDBGetAllRecordsData& getAllRecordsData, GetAllResultsCallback callback)
1345 {
1346     ASSERT(isMainThread());
1347     LOG(IndexedDB, "(main) UniqueIDBDatabase::getAllRecords");
1348
1349     waitForRequestSpaceCompletion([this, requestData, getAllRecordsData, callback = WTFMove(callback)](auto error) mutable {
1350         if (error) {
1351             callback(WTFMove(*error), { });
1352             return;
1353         }
1354         this->getAllRecordsAfterQuotaCheck(requestData, getAllRecordsData, WTFMove(callback));
1355     });
1356 }
1357
1358 void UniqueIDBDatabase::getAllRecordsAfterQuotaCheck(const IDBRequestData& requestData, const IDBGetAllRecordsData& getAllRecordsData, GetAllResultsCallback callback)
1359 {
1360     uint64_t callbackID = storeCallbackOrFireError(WTFMove(callback));
1361     if (!callbackID)
1362         return;
1363
1364     postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performGetAllRecords, callbackID, requestData.transactionIdentifier(), getAllRecordsData));
1365 }
1366
1367 void UniqueIDBDatabase::performGetRecord(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyRangeData& keyRangeData, IDBGetRecordDataType type)
1368 {
1369     ASSERT(!isMainThread());
1370     LOG(IndexedDB, "(db) UniqueIDBDatabase::performGetRecord");
1371
1372     ASSERT(m_backingStore);
1373
1374     IDBGetResult result;
1375     IDBError error = m_backingStore->getRecord(transactionIdentifier, objectStoreIdentifier, keyRangeData, type, result);
1376
1377     postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformGetRecord, callbackIdentifier, error, result));
1378 }
1379
1380 void UniqueIDBDatabase::performGetIndexRecord(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, IndexedDB::IndexRecordType recordType, const IDBKeyRangeData& range)
1381 {
1382     ASSERT(!isMainThread());
1383     LOG(IndexedDB, "(db) UniqueIDBDatabase::performGetIndexRecord");
1384
1385     ASSERT(m_backingStore);
1386
1387     IDBGetResult result;
1388     IDBError error = m_backingStore->getIndexRecord(transactionIdentifier, objectStoreIdentifier, indexIdentifier, recordType, range, result);
1389
1390     postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformGetRecord, callbackIdentifier, error, result));
1391 }
1392
1393 void UniqueIDBDatabase::didPerformGetRecord(uint64_t callbackIdentifier, const IDBError& error, const IDBGetResult& result)
1394 {
1395     ASSERT(isMainThread());
1396     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformGetRecord");
1397
1398     performGetResultCallback(callbackIdentifier, error, result);
1399 }
1400
1401 void UniqueIDBDatabase::performGetAllRecords(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, const IDBGetAllRecordsData& getAllRecordsData)
1402 {
1403     ASSERT(!isMainThread());
1404     LOG(IndexedDB, "(db) UniqueIDBDatabase::performGetAllRecords");
1405
1406     ASSERT(m_backingStore);
1407
1408     IDBGetAllResult result;
1409     IDBError error = m_backingStore->getAllRecords(transactionIdentifier, getAllRecordsData, result);
1410
1411     postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformGetAllRecords, callbackIdentifier, error, WTFMove(result)));
1412 }
1413
1414 void UniqueIDBDatabase::didPerformGetAllRecords(uint64_t callbackIdentifier, const IDBError& error, const IDBGetAllResult& result)
1415 {
1416     ASSERT(isMainThread());
1417     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformGetAllRecords");
1418
1419     performGetAllResultsCallback(callbackIdentifier, error, result);
1420 }
1421
1422 void UniqueIDBDatabase::getCount(const IDBRequestData& requestData, const IDBKeyRangeData& range, CountCallback callback)
1423 {
1424     ASSERT(isMainThread());
1425     LOG(IndexedDB, "(main) UniqueIDBDatabase::getCount");
1426
1427     waitForRequestSpaceCompletion([this, requestData, range, callback = WTFMove(callback)](auto error) mutable {
1428         if (error) {
1429             callback(WTFMove(*error), { });
1430             return;
1431         }
1432         this->getCountAfterQuotaCheck(requestData, range, WTFMove(callback));
1433     });
1434 }
1435
1436 void UniqueIDBDatabase::getCountAfterQuotaCheck(const IDBRequestData& requestData, const IDBKeyRangeData& range, CountCallback callback)
1437 {
1438     uint64_t callbackID = storeCallbackOrFireError(WTFMove(callback));
1439     if (!callbackID)
1440         return;
1441     postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performGetCount, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), requestData.indexIdentifier(), range));
1442 }
1443
1444 void UniqueIDBDatabase::performGetCount(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const IDBKeyRangeData& keyRangeData)
1445 {
1446     ASSERT(!isMainThread());
1447     LOG(IndexedDB, "(db) UniqueIDBDatabase::performGetCount");
1448
1449     ASSERT(m_backingStore);
1450     ASSERT(objectStoreIdentifier);
1451
1452     uint64_t count;
1453     IDBError error = m_backingStore->getCount(transactionIdentifier, objectStoreIdentifier, indexIdentifier, keyRangeData, count);
1454
1455     postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformGetCount, callbackIdentifier, error, count));
1456 }
1457
1458 void UniqueIDBDatabase::didPerformGetCount(uint64_t callbackIdentifier, const IDBError& error, uint64_t count)
1459 {
1460     ASSERT(isMainThread());
1461     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformGetCount");
1462
1463     performCountCallback(callbackIdentifier, error, count);
1464 }
1465
1466 void UniqueIDBDatabase::deleteRecord(const IDBRequestData& requestData, const IDBKeyRangeData& keyRangeData, ErrorCallback callback)
1467 {
1468     ASSERT(isMainThread());
1469     LOG(IndexedDB, "(main) UniqueIDBDatabase::deleteRecord");
1470
1471     waitForRequestSpaceCompletion([this, requestData, keyRangeData, callback = WTFMove(callback)](auto error) mutable {
1472         if (error) {
1473             callback(WTFMove(*error));
1474             return;
1475         }
1476         this->deleteRecordAfterQuotaCheck(requestData, keyRangeData, WTFMove(callback));
1477     });
1478 }
1479
1480 void UniqueIDBDatabase::deleteRecordAfterQuotaCheck(const IDBRequestData& requestData, const IDBKeyRangeData& keyRangeData, ErrorCallback callback)
1481 {
1482     uint64_t callbackID = storeCallbackOrFireError(WTFMove(callback));
1483     if (!callbackID)
1484         return;
1485     postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performDeleteRecord, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), keyRangeData));
1486 }
1487
1488 void UniqueIDBDatabase::performDeleteRecord(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyRangeData& range)
1489 {
1490     ASSERT(!isMainThread());
1491     LOG(IndexedDB, "(db) UniqueIDBDatabase::performDeleteRecord");
1492
1493     IDBError error = m_backingStore->deleteRange(transactionIdentifier, objectStoreIdentifier, range);
1494
1495     postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformDeleteRecord, callbackIdentifier, error));
1496 }
1497
1498 void UniqueIDBDatabase::didPerformDeleteRecord(uint64_t callbackIdentifier, const IDBError& error)
1499 {
1500     ASSERT(isMainThread());
1501     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformDeleteRecord");
1502
1503     performErrorCallback(callbackIdentifier, error);
1504 }
1505
1506 void UniqueIDBDatabase::openCursor(const IDBRequestData& requestData, const IDBCursorInfo& info, GetResultCallback callback)
1507 {
1508     ASSERT(isMainThread());
1509     LOG(IndexedDB, "(main) UniqueIDBDatabase::openCursor");
1510
1511     waitForRequestSpaceCompletion([this, requestData, info, callback = WTFMove(callback)](auto error) mutable {
1512         if (error) {
1513             callback(WTFMove(*error), { });
1514             return;
1515         }
1516         this->openCursorAfterQuotaCheck(requestData, info, WTFMove(callback));
1517     });
1518 }
1519
1520 void UniqueIDBDatabase::openCursorAfterQuotaCheck(const IDBRequestData& requestData, const IDBCursorInfo& info, GetResultCallback callback)
1521 {
1522     uint64_t callbackID = storeCallbackOrFireError(WTFMove(callback));
1523     if (!callbackID)
1524         return;
1525     postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performOpenCursor, callbackID, requestData.transactionIdentifier(), info));
1526 }
1527
1528 void UniqueIDBDatabase::performOpenCursor(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, const IDBCursorInfo& info)
1529 {
1530     ASSERT(!isMainThread());
1531     LOG(IndexedDB, "(db) UniqueIDBDatabase::performOpenCursor");
1532
1533     IDBGetResult result;
1534     IDBError error = m_backingStore->openCursor(transactionIdentifier, info, result);
1535
1536     postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformOpenCursor, callbackIdentifier, error, result));
1537 }
1538
1539 void UniqueIDBDatabase::didPerformOpenCursor(uint64_t callbackIdentifier, const IDBError& error, const IDBGetResult& result)
1540 {
1541     ASSERT(isMainThread());
1542     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformOpenCursor");
1543
1544     performGetResultCallback(callbackIdentifier, error, result);
1545 }
1546
1547 void UniqueIDBDatabase::iterateCursor(const IDBRequestData& requestData, const IDBIterateCursorData& data, GetResultCallback callback)
1548 {
1549     ASSERT(isMainThread());
1550     LOG(IndexedDB, "(main) UniqueIDBDatabase::iterateCursor");
1551
1552     waitForRequestSpaceCompletion([this, requestData, data, callback = WTFMove(callback)](auto error) mutable {
1553         if (error) {
1554             callback(WTFMove(*error), { });
1555             return;
1556         }
1557         this->iterateCursorAfterQuotaCheck(requestData, data, WTFMove(callback));
1558     });
1559 }
1560
1561 void UniqueIDBDatabase::iterateCursorAfterQuotaCheck(const IDBRequestData& requestData, const IDBIterateCursorData& data, GetResultCallback callback)
1562 {
1563     uint64_t callbackID = storeCallbackOrFireError(WTFMove(callback));
1564     if (!callbackID)
1565         return;
1566     postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performIterateCursor, callbackID, requestData.transactionIdentifier(), requestData.cursorIdentifier(), data));
1567 }
1568
1569 void UniqueIDBDatabase::performIterateCursor(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, const IDBResourceIdentifier& cursorIdentifier, const IDBIterateCursorData& data)
1570 {
1571     ASSERT(!isMainThread());
1572     LOG(IndexedDB, "(db) UniqueIDBDatabase::performIterateCursor");
1573
1574     IDBGetResult result;
1575     IDBError error = m_backingStore->iterateCursor(transactionIdentifier, cursorIdentifier, data, result);
1576
1577     if (error.isNull()) {
1578         auto addResult = m_cursorPrefetches.add(cursorIdentifier);
1579         if (addResult.isNewEntry)
1580             postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performPrefetchCursor, transactionIdentifier, cursorIdentifier));
1581     }
1582
1583     postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformIterateCursor, callbackIdentifier, error, result));
1584 }
1585
1586 void UniqueIDBDatabase::performPrefetchCursor(const IDBResourceIdentifier& transactionIdentifier, const IDBResourceIdentifier& cursorIdentifier)
1587 {
1588     ASSERT(!isMainThread());
1589     ASSERT(m_cursorPrefetches.contains(cursorIdentifier));
1590     LOG(IndexedDB, "(db) UniqueIDBDatabase::performPrefetchCursor");
1591
1592     if (m_hardClosedForUserDelete || !m_backingStore->prefetchCursor(transactionIdentifier, cursorIdentifier))
1593         m_cursorPrefetches.remove(cursorIdentifier);
1594     else
1595         postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performPrefetchCursor, transactionIdentifier, cursorIdentifier));
1596 }
1597
1598 void UniqueIDBDatabase::didPerformIterateCursor(uint64_t callbackIdentifier, const IDBError& error, const IDBGetResult& result)
1599 {
1600     ASSERT(isMainThread());
1601     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformIterateCursor");
1602
1603     performGetResultCallback(callbackIdentifier, error, result);
1604 }
1605
1606 bool UniqueIDBDatabase::prepareToFinishTransaction(UniqueIDBDatabaseTransaction& transaction)
1607 {
1608     auto takenTransaction = m_inProgressTransactions.take(transaction.info().identifier());
1609     if (!takenTransaction)
1610         return false;
1611
1612     ASSERT(!m_finishingTransactions.contains(transaction.info().identifier()));
1613     m_finishingTransactions.set(transaction.info().identifier(), WTFMove(takenTransaction));
1614
1615     return true;
1616 }
1617
1618 void UniqueIDBDatabase::commitTransaction(UniqueIDBDatabaseTransaction& transaction, ErrorCallback callback)
1619 {
1620     ASSERT(isMainThread());
1621     LOG(IndexedDB, "(main) UniqueIDBDatabase::commitTransaction - %s", transaction.info().identifier().loggingString().utf8().data());
1622
1623     ASSERT(transaction.databaseConnection().database() == this);
1624
1625     waitForRequestSpaceCompletion([this, transaction = makeRef(transaction), callback = WTFMove(callback)](auto error) mutable {
1626         if (error) {
1627             callback(WTFMove(*error));
1628             return;
1629         }
1630         this->commitTransactionAfterQuotaCheck(transaction, WTFMove(callback));
1631     });
1632 }
1633
1634 void UniqueIDBDatabase::commitTransactionAfterQuotaCheck(UniqueIDBDatabaseTransaction& transaction, ErrorCallback callback)
1635 {
1636     uint64_t callbackID = storeCallbackOrFireError(WTFMove(callback));
1637     if (!callbackID)
1638         return;
1639
1640     if (!prepareToFinishTransaction(transaction)) {
1641         if (!m_openDatabaseConnections.contains(&transaction.databaseConnection())) {
1642             // This database connection is closing or has already closed, so there is no point in messaging back to it about the commit failing.
1643             forgetErrorCallback(callbackID);
1644             return;
1645         }
1646
1647         performErrorCallback(callbackID, IDBError { UnknownError, "Attempt to commit transaction that is already finishing"_s });
1648         return;
1649     }
1650
1651     postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performCommitTransaction, callbackID, transaction.info().identifier()));
1652 }
1653
1654 void UniqueIDBDatabase::performCommitTransaction(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier)
1655 {
1656     ASSERT(!isMainThread());
1657     LOG(IndexedDB, "(db) UniqueIDBDatabase::performCommitTransaction - %s", transactionIdentifier.loggingString().utf8().data());
1658
1659     IDBError error = m_backingStore->commitTransaction(transactionIdentifier);
1660     postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformCommitTransaction, callbackIdentifier, error, transactionIdentifier));
1661 }
1662
1663 void UniqueIDBDatabase::didPerformCommitTransaction(uint64_t callbackIdentifier, const IDBError& error, const IDBResourceIdentifier& transactionIdentifier)
1664 {
1665     ASSERT(isMainThread());
1666     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformCommitTransaction - %s", transactionIdentifier.loggingString().utf8().data());
1667
1668     performErrorCallback(callbackIdentifier, error);
1669
1670     transactionCompleted(m_finishingTransactions.take(transactionIdentifier));
1671 }
1672
1673 void UniqueIDBDatabase::abortTransaction(UniqueIDBDatabaseTransaction& transaction, WaitForPendingTasks waitForPendingTasks, ErrorCallback callback)
1674 {
1675     ASSERT(isMainThread());
1676     LOG(IndexedDB, "(main) UniqueIDBDatabase::abortTransaction - %s", transaction.info().identifier().loggingString().utf8().data());
1677
1678     ASSERT(transaction.databaseConnection().database() == this);
1679
1680     if (waitForPendingTasks == WaitForPendingTasks::Yes) {
1681         waitForRequestSpaceCompletion([this, transaction = makeRef(transaction), callback = WTFMove(callback)](auto&& error) mutable {
1682             if (error) {
1683                 callback(WTFMove(*error));
1684                 return;
1685             }
1686             this->abortTransaction(transaction, WaitForPendingTasks::No, WTFMove(callback));
1687         });
1688         return;
1689     }
1690
1691     uint64_t callbackID = storeCallbackOrFireError(WTFMove(callback));
1692     if (!callbackID)
1693         return;
1694
1695     if (!prepareToFinishTransaction(transaction)) {
1696         if (!m_openDatabaseConnections.contains(&transaction.databaseConnection())) {
1697             // This database connection is closing or has already closed, so there is no point in messaging back to it about the abort failing.
1698             forgetErrorCallback(callbackID);
1699             return;
1700         }
1701
1702         performErrorCallback(callbackID, IDBError { UnknownError, "Attempt to abort transaction that is already finishing"_s });
1703         return;
1704     }
1705
1706     postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performAbortTransaction, callbackID, transaction.info().identifier()));
1707 }
1708
1709 void UniqueIDBDatabase::didFinishHandlingVersionChange(UniqueIDBDatabaseConnection& connection, const IDBResourceIdentifier& transactionIdentifier)
1710 {
1711     ASSERT(isMainThread());
1712     LOG(IndexedDB, "(main) UniqueIDBDatabase::didFinishHandlingVersionChange");
1713
1714     ASSERT_UNUSED(transactionIdentifier, !m_versionChangeTransaction || m_versionChangeTransaction->info().identifier() == transactionIdentifier);
1715     ASSERT_UNUSED(connection, !m_versionChangeDatabaseConnection || m_versionChangeDatabaseConnection.get() == &connection);
1716
1717     m_versionChangeTransaction = nullptr;
1718     m_versionChangeDatabaseConnection = nullptr;
1719
1720     if (m_hardClosedForUserDelete) {
1721         maybeFinishHardClose();
1722         return;
1723     }
1724
1725     invokeOperationAndTransactionTimer();
1726 }
1727
1728 void UniqueIDBDatabase::performAbortTransaction(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier)
1729 {
1730     ASSERT(!isMainThread());
1731     LOG(IndexedDB, "(db) UniqueIDBDatabase::performAbortTransaction - %s", transactionIdentifier.loggingString().utf8().data());
1732
1733     IDBError error = m_backingStore->abortTransaction(transactionIdentifier);
1734     postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformAbortTransaction, callbackIdentifier, error, transactionIdentifier));
1735 }
1736
1737 void UniqueIDBDatabase::didPerformAbortTransaction(uint64_t callbackIdentifier, const IDBError& error, const IDBResourceIdentifier& transactionIdentifier)
1738 {
1739     ASSERT(isMainThread());
1740     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformAbortTransaction - %s", transactionIdentifier.loggingString().utf8().data());
1741
1742     auto transaction = m_finishingTransactions.take(transactionIdentifier);
1743     ASSERT(transaction);
1744
1745     if (m_versionChangeTransaction && m_versionChangeTransaction->info().identifier() == transactionIdentifier) {
1746         ASSERT(m_versionChangeTransaction == transaction);
1747         ASSERT(!m_versionChangeDatabaseConnection || &m_versionChangeTransaction->databaseConnection() == m_versionChangeDatabaseConnection);
1748         ASSERT(m_versionChangeTransaction->originalDatabaseInfo());
1749         m_databaseInfo = std::make_unique<IDBDatabaseInfo>(*m_versionChangeTransaction->originalDatabaseInfo());
1750     }
1751
1752     performErrorCallback(callbackIdentifier, error);
1753
1754     transactionCompleted(WTFMove(transaction));
1755 }
1756
1757 void UniqueIDBDatabase::transactionDestroyed(UniqueIDBDatabaseTransaction& transaction)
1758 {
1759     if (m_versionChangeTransaction == &transaction)
1760         m_versionChangeTransaction = nullptr;
1761 }
1762
1763 void UniqueIDBDatabase::connectionClosedFromClient(UniqueIDBDatabaseConnection& connection)
1764 {
1765     ASSERT(isMainThread());
1766     LOG(IndexedDB, "(main) UniqueIDBDatabase::connectionClosedFromClient - %s (%" PRIu64 ")", connection.openRequestIdentifier().loggingString().utf8().data(), connection.identifier());
1767
1768     if (m_serverClosePendingDatabaseConnections.contains(&connection)) {
1769         m_serverClosePendingDatabaseConnections.remove(&connection);
1770         if (m_hardClosedForUserDelete)
1771             maybeFinishHardClose();
1772         return;
1773     }
1774
1775     Ref<UniqueIDBDatabaseConnection> protectedConnection(connection);
1776     m_openDatabaseConnections.remove(&connection);
1777
1778     if (m_versionChangeDatabaseConnection == &connection) {
1779         if (m_versionChangeTransaction) {
1780             m_clientClosePendingDatabaseConnections.add(WTFMove(m_versionChangeDatabaseConnection));
1781
1782             auto transactionIdentifier = m_versionChangeTransaction->info().identifier();
1783             if (m_inProgressTransactions.contains(transactionIdentifier)) {
1784                 ASSERT(!m_finishingTransactions.contains(transactionIdentifier));
1785                 connection.abortTransactionWithoutCallback(*m_versionChangeTransaction);
1786             }
1787
1788             return;
1789         }
1790
1791         m_versionChangeDatabaseConnection = nullptr;
1792     }
1793
1794     Deque<RefPtr<UniqueIDBDatabaseTransaction>> pendingTransactions;
1795     while (!m_pendingTransactions.isEmpty()) {
1796         auto transaction = m_pendingTransactions.takeFirst();
1797         if (&transaction->databaseConnection() != &connection)
1798             pendingTransactions.append(WTFMove(transaction));
1799     }
1800
1801     if (!pendingTransactions.isEmpty())
1802         m_pendingTransactions.swap(pendingTransactions);
1803
1804     Deque<RefPtr<UniqueIDBDatabaseTransaction>> transactionsToAbort;
1805     for (auto& transaction : m_inProgressTransactions.values()) {
1806         if (&transaction->databaseConnection() == &connection)
1807             transactionsToAbort.append(transaction);
1808     }
1809
1810     for (auto& transaction : transactionsToAbort)
1811         transaction->abortWithoutCallback();
1812
1813     if (m_currentOpenDBRequest)
1814         notifyCurrentRequestConnectionClosedOrFiredVersionChangeEvent(connection.identifier());
1815
1816     if (connection.hasNonFinishedTransactions()) {
1817         m_clientClosePendingDatabaseConnections.add(WTFMove(protectedConnection));
1818         return;
1819     }
1820
1821     if (m_hardClosedForUserDelete) {
1822         maybeFinishHardClose();
1823         return;
1824     }
1825
1826     // Now that a database connection has closed, previously blocked operations might be runnable.
1827     invokeOperationAndTransactionTimer();
1828 }
1829
1830 void UniqueIDBDatabase::connectionClosedFromServer(UniqueIDBDatabaseConnection& connection)
1831 {
1832     ASSERT(isMainThread());
1833     LOG(IndexedDB, "UniqueIDBDatabase::connectionClosedFromServer - %s (%" PRIu64 ")", connection.openRequestIdentifier().loggingString().utf8().data(), connection.identifier());
1834
1835     if (m_clientClosePendingDatabaseConnections.contains(&connection)) {
1836         ASSERT(!m_openDatabaseConnections.contains(&connection));
1837         ASSERT(!m_serverClosePendingDatabaseConnections.contains(&connection));
1838         return;
1839     }
1840
1841     Ref<UniqueIDBDatabaseConnection> protectedConnection(connection);
1842     m_openDatabaseConnections.remove(&connection);
1843
1844     connection.connectionToClient().didCloseFromServer(connection, IDBError::userDeleteError());
1845
1846     m_serverClosePendingDatabaseConnections.add(WTFMove(protectedConnection));
1847 }
1848
1849 void UniqueIDBDatabase::confirmDidCloseFromServer(UniqueIDBDatabaseConnection& connection)
1850 {
1851     ASSERT(isMainThread());
1852     LOG(IndexedDB, "UniqueIDBDatabase::confirmDidCloseFromServer - %s (%" PRIu64 ")", connection.openRequestIdentifier().loggingString().utf8().data(), connection.identifier());
1853
1854     if (!m_serverClosePendingDatabaseConnections.contains(&connection))
1855         return;
1856     m_serverClosePendingDatabaseConnections.remove(&connection);
1857
1858     if (m_hardClosedForUserDelete)
1859         maybeFinishHardClose();
1860 }
1861
1862 void UniqueIDBDatabase::enqueueTransaction(Ref<UniqueIDBDatabaseTransaction>&& transaction)
1863 {
1864     LOG(IndexedDB, "UniqueIDBDatabase::enqueueTransaction - %s", transaction->info().loggingString().utf8().data());
1865     ASSERT(!m_hardClosedForUserDelete);
1866
1867     ASSERT(transaction->info().mode() != IDBTransactionMode::Versionchange);
1868
1869     m_pendingTransactions.append(WTFMove(transaction));
1870
1871     invokeOperationAndTransactionTimer();
1872 }
1873
1874 bool UniqueIDBDatabase::isCurrentlyInUse() const
1875 {
1876     return !m_openDatabaseConnections.isEmpty() || !m_clientClosePendingDatabaseConnections.isEmpty() || !m_pendingOpenDBRequests.isEmpty() || m_currentOpenDBRequest || m_versionChangeDatabaseConnection || m_versionChangeTransaction || m_isOpeningBackingStore || m_deleteBackingStoreInProgress;
1877 }
1878
1879 bool UniqueIDBDatabase::hasUnfinishedTransactions() const
1880 {
1881     return !m_inProgressTransactions.isEmpty() || !m_finishingTransactions.isEmpty();
1882 }
1883
1884 void UniqueIDBDatabase::invokeOperationAndTransactionTimer()
1885 {
1886     LOG(IndexedDB, "UniqueIDBDatabase::invokeOperationAndTransactionTimer()");
1887     RELEASE_ASSERT(!m_hardClosedForUserDelete);
1888     RELEASE_ASSERT(!m_owningPointerForClose);
1889
1890     if (!m_operationAndTransactionTimer.isActive())
1891         m_operationAndTransactionTimer.startOneShot(0_s);
1892 }
1893
1894 void UniqueIDBDatabase::operationAndTransactionTimerFired()
1895 {
1896     LOG(IndexedDB, "(main) UniqueIDBDatabase::operationAndTransactionTimerFired");
1897     ASSERT(!m_hardClosedForUserDelete);
1898     ASSERT(isMainThread());
1899
1900     // This UniqueIDBDatabase might be no longer in use by any web page.
1901     // Assuming it is not ephemeral, the server should now close it to free up resources.
1902     if (!m_backingStoreIsEphemeral && !isCurrentlyInUse()) {
1903         ASSERT(m_pendingTransactions.isEmpty());
1904         ASSERT(!hasUnfinishedTransactions());
1905
1906         scheduleShutdownForClose();
1907         return;
1908     }
1909
1910     // The current operation might require multiple attempts to handle, so try to
1911     // make further progress on it now.
1912     if (m_currentOpenDBRequest && !m_currentOpenDBRequest->connection().isClosed())
1913         handleCurrentOperation();
1914     else
1915         handleDatabaseOperations();
1916
1917     bool hadDeferredTransactions = false;
1918     auto transaction = takeNextRunnableTransaction(hadDeferredTransactions);
1919
1920     if (transaction) {
1921         m_inProgressTransactions.set(transaction->info().identifier(), transaction);
1922         for (auto objectStore : transaction->objectStoreIdentifiers()) {
1923             m_objectStoreTransactionCounts.add(objectStore);
1924             if (!transaction->isReadOnly()) {
1925                 m_objectStoreWriteTransactions.add(objectStore);
1926                 ASSERT(m_objectStoreTransactionCounts.count(objectStore) == 1 || m_hardClosedForUserDelete);
1927             }
1928         }
1929
1930         activateTransactionInBackingStore(*transaction);
1931
1932         // If no transactions were deferred, it's possible we can start another transaction right now.
1933         if (!hadDeferredTransactions)
1934             invokeOperationAndTransactionTimer();
1935     }
1936 }
1937
1938 void UniqueIDBDatabase::activateTransactionInBackingStore(UniqueIDBDatabaseTransaction& transaction)
1939 {
1940     LOG(IndexedDB, "(main) UniqueIDBDatabase::activateTransactionInBackingStore");
1941     ASSERT(isMainThread());
1942
1943     RefPtr<UniqueIDBDatabaseTransaction> refTransaction(&transaction);
1944
1945     ErrorCallback callback = [refTransaction](const IDBError& error) {
1946         refTransaction->didActivateInBackingStore(error);
1947     };
1948
1949     uint64_t callbackID = storeCallbackOrFireError(WTFMove(callback));
1950     if (!callbackID)
1951         return;
1952     postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performActivateTransactionInBackingStore, callbackID, transaction.info()));
1953 }
1954
1955 void UniqueIDBDatabase::performActivateTransactionInBackingStore(uint64_t callbackIdentifier, const IDBTransactionInfo& info)
1956 {
1957     LOG(IndexedDB, "(db) UniqueIDBDatabase::performActivateTransactionInBackingStore");
1958
1959     IDBError error = m_backingStore->beginTransaction(info);
1960     postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformActivateTransactionInBackingStore, callbackIdentifier, error));
1961 }
1962
1963 void UniqueIDBDatabase::didPerformActivateTransactionInBackingStore(uint64_t callbackIdentifier, const IDBError& error)
1964 {
1965     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformActivateTransactionInBackingStore");
1966
1967     if (m_hardClosedForUserDelete)
1968         return;
1969
1970     invokeOperationAndTransactionTimer();
1971
1972     performErrorCallback(callbackIdentifier, error);
1973 }
1974
1975 template<typename T> bool scopesOverlap(const T& aScopes, const Vector<uint64_t>& bScopes)
1976 {
1977     for (auto scope : bScopes) {
1978         if (aScopes.contains(scope))
1979             return true;
1980     }
1981
1982     return false;
1983 }
1984
1985 RefPtr<UniqueIDBDatabaseTransaction> UniqueIDBDatabase::takeNextRunnableTransaction(bool& hadDeferredTransactions)
1986 {
1987     hadDeferredTransactions = false;
1988
1989     if (m_pendingTransactions.isEmpty())
1990         return nullptr;
1991
1992     if (!m_backingStoreSupportsSimultaneousTransactions && hasUnfinishedTransactions()) {
1993         LOG(IndexedDB, "UniqueIDBDatabase::takeNextRunnableTransaction - Backing store only supports 1 transaction, and we already have 1");
1994         return nullptr;
1995     }
1996
1997     Deque<RefPtr<UniqueIDBDatabaseTransaction>> deferredTransactions;
1998     RefPtr<UniqueIDBDatabaseTransaction> currentTransaction;
1999
2000     HashSet<uint64_t> deferredReadWriteScopes;
2001
2002     while (!m_pendingTransactions.isEmpty()) {
2003         currentTransaction = m_pendingTransactions.takeFirst();
2004
2005         switch (currentTransaction->info().mode()) {
2006         case IDBTransactionMode::Readonly: {
2007             bool hasOverlappingScopes = scopesOverlap(deferredReadWriteScopes, currentTransaction->objectStoreIdentifiers());
2008             hasOverlappingScopes |= scopesOverlap(m_objectStoreWriteTransactions, currentTransaction->objectStoreIdentifiers());
2009
2010             if (hasOverlappingScopes)
2011                 deferredTransactions.append(WTFMove(currentTransaction));
2012
2013             break;
2014         }
2015         case IDBTransactionMode::Readwrite: {
2016             bool hasOverlappingScopes = scopesOverlap(m_objectStoreTransactionCounts, currentTransaction->objectStoreIdentifiers());
2017             hasOverlappingScopes |= scopesOverlap(deferredReadWriteScopes, currentTransaction->objectStoreIdentifiers());
2018
2019             if (hasOverlappingScopes) {
2020                 for (auto objectStore : currentTransaction->objectStoreIdentifiers())
2021                     deferredReadWriteScopes.add(objectStore);
2022                 deferredTransactions.append(WTFMove(currentTransaction));
2023             }
2024
2025             break;
2026         }
2027         case IDBTransactionMode::Versionchange:
2028             // Version change transactions should never be scheduled in the traditional manner.
2029             RELEASE_ASSERT_NOT_REACHED();
2030         }
2031
2032         // If we didn't defer the currentTransaction above, it can be run now.
2033         if (currentTransaction)
2034             break;
2035     }
2036
2037     hadDeferredTransactions = !deferredTransactions.isEmpty();
2038     if (!hadDeferredTransactions)
2039         return currentTransaction;
2040
2041     // Prepend the deferred transactions back on the beginning of the deque for future scheduling passes.
2042     while (!deferredTransactions.isEmpty())
2043         m_pendingTransactions.prepend(deferredTransactions.takeLast());
2044
2045     return currentTransaction;
2046 }
2047
2048 void UniqueIDBDatabase::transactionCompleted(RefPtr<UniqueIDBDatabaseTransaction>&& transaction)
2049 {
2050     ASSERT(transaction);
2051     ASSERT(!m_inProgressTransactions.contains(transaction->info().identifier()));
2052     ASSERT(!m_finishingTransactions.contains(transaction->info().identifier()));
2053     ASSERT(isMainThread());
2054
2055     for (auto objectStore : transaction->objectStoreIdentifiers()) {
2056         if (!transaction->isReadOnly()) {
2057             m_objectStoreWriteTransactions.remove(objectStore);
2058             ASSERT(m_objectStoreTransactionCounts.count(objectStore) == 1 || m_hardClosedForUserDelete);
2059         }
2060         m_objectStoreTransactionCounts.remove(objectStore);
2061     }
2062
2063     if (!transaction->databaseConnection().hasNonFinishedTransactions())
2064         m_clientClosePendingDatabaseConnections.remove(&transaction->databaseConnection());
2065
2066     if (m_versionChangeTransaction == transaction)
2067         m_versionChangeTransaction = nullptr;
2068
2069     // It's possible that this database had its backing store deleted but there were a few outstanding asynchronous operations.
2070     // If this transaction completing was the last of those operations, we can finally delete this UniqueIDBDatabase.
2071     if (m_clientClosePendingDatabaseConnections.isEmpty() && m_pendingOpenDBRequests.isEmpty() && !m_databaseInfo) {
2072         scheduleShutdownForClose();
2073         return;
2074     }
2075
2076     // Previously blocked operations might be runnable.
2077     if (!m_hardClosedForUserDelete)
2078         invokeOperationAndTransactionTimer();
2079     else
2080         maybeFinishHardClose();
2081 }
2082
2083 void UniqueIDBDatabase::postDatabaseTask(CrossThreadTask&& task)
2084 {
2085     m_databaseQueue.append(WTFMove(task));
2086     m_server->postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::executeNextDatabaseTask));
2087 }
2088
2089 void UniqueIDBDatabase::postDatabaseTaskReply(CrossThreadTask&& task)
2090 {
2091     // FIXME: We might want to compute total size only for modification operations.
2092     if (m_backingStore)
2093         m_databasesSizeForOrigin = m_backingStore->databasesSizeForOrigin();
2094     m_databaseReplyQueue.append(WTFMove(task));
2095     m_server->postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::executeNextDatabaseTaskReply));
2096 }
2097
2098 void UniqueIDBDatabase::executeNextDatabaseTask()
2099 {
2100     ASSERT(!isMainThread());
2101     ASSERT(!m_databaseQueue.isKilled());
2102
2103     auto task = m_databaseQueue.tryGetMessage();
2104     ASSERT(task);
2105
2106     task->performTask();
2107 }
2108
2109 void UniqueIDBDatabase::executeNextDatabaseTaskReply()
2110 {
2111     ASSERT(isMainThread());
2112     ASSERT(!m_databaseReplyQueue.isKilled());
2113
2114     auto task = m_databaseReplyQueue.tryGetMessage();
2115     ASSERT(task);
2116
2117     task->performTask();
2118
2119     // If this database was force closed (e.g. for a user delete) and there are no more
2120     // cleanup tasks left, delete this.
2121     maybeFinishHardClose();
2122 }
2123
2124 void UniqueIDBDatabase::maybeFinishHardClose()
2125 {
2126     if (m_owningPointerForClose && isDoneWithHardClose()) {
2127         if (m_owningPointerReleaseScheduled)
2128             return;
2129         m_owningPointerReleaseScheduled = true;
2130
2131         callOnMainThread([this] {
2132             ASSERT(isDoneWithHardClose());
2133             m_owningPointerForClose = nullptr;
2134         });
2135     }
2136 }
2137
2138 bool UniqueIDBDatabase::isDoneWithHardClose()
2139 {
2140     return m_databaseReplyQueue.isKilled() && m_clientClosePendingDatabaseConnections.isEmpty() && m_serverClosePendingDatabaseConnections.isEmpty();
2141 }
2142
2143 static void errorOpenDBRequestForUserDelete(ServerOpenDBRequest& request)
2144 {
2145     auto result = IDBResultData::error(request.requestData().requestIdentifier(), IDBError::userDeleteError());
2146     if (request.isOpenRequest())
2147         request.connection().didOpenDatabase(result);
2148     else
2149         request.connection().didDeleteDatabase(result);
2150 }
2151
2152 void UniqueIDBDatabase::immediateCloseForUserDelete()
2153 {
2154     LOG(IndexedDB, "UniqueIDBDatabase::immediateCloseForUserDelete - Cancelling (%i, %i, %i, %i) callbacks", m_errorCallbacks.size(), m_keyDataCallbacks.size(), m_getResultCallbacks.size(), m_countCallbacks.size());
2155
2156     ASSERT(isMainThread());
2157
2158     m_pendingSpaceIncreasingTasks.clear();
2159     m_server->resetSpaceUsed(m_identifier.origin());
2160
2161     // Error out all transactions
2162     for (auto& identifier : copyToVector(m_inProgressTransactions.keys()))
2163         m_inProgressTransactions.get(identifier)->abortWithoutCallback();
2164
2165     ASSERT(m_inProgressTransactions.isEmpty());
2166
2167     for (auto& transaction : m_pendingTransactions)
2168         transaction->databaseConnection().deleteTransaction(*transaction);
2169     m_pendingTransactions.clear();
2170     m_objectStoreTransactionCounts.clear();
2171     m_objectStoreWriteTransactions.clear();
2172
2173     // Error out all pending callbacks
2174     IDBError error = IDBError::userDeleteError();
2175     IDBKeyData keyData;
2176     IDBGetResult getResult;
2177     IDBGetAllResult getAllResult;
2178
2179     while (!m_callbackQueue.isEmpty()) {
2180         auto identifier = m_callbackQueue.first();
2181         if (m_errorCallbacks.contains(identifier))
2182             performErrorCallback(identifier, error);
2183         else if (m_keyDataCallbacks.contains(identifier))
2184             performKeyDataCallback(identifier, error, keyData);
2185         else if (m_getResultCallbacks.contains(identifier))
2186             performGetResultCallback(identifier, error, getResult);
2187         else if (m_countCallbacks.contains(identifier))
2188             performCountCallback(identifier, error, 0);
2189         else if (m_getAllResultsCallbacks.contains(identifier))
2190             performGetAllResultsCallback(identifier, error, getAllResult);
2191         else
2192             ASSERT_NOT_REACHED();
2193     }
2194
2195     // Error out all IDBOpenDBRequests
2196     if (m_currentOpenDBRequest) {
2197         errorOpenDBRequestForUserDelete(*m_currentOpenDBRequest);
2198         m_currentOpenDBRequest = nullptr;
2199     }
2200
2201     for (auto& request : m_pendingOpenDBRequests)
2202         errorOpenDBRequestForUserDelete(*request);
2203
2204     m_pendingOpenDBRequests.clear();
2205
2206     // Close all open connections
2207     auto openDatabaseConnections = m_openDatabaseConnections;
2208     for (auto& connection : openDatabaseConnections)
2209         connectionClosedFromServer(*connection);
2210
2211     // Cancel the operation timer
2212     m_operationAndTransactionTimer.stop();
2213
2214     // Set up the database to remain alive-but-inert until all of its background activity finishes and all
2215     // database connections confirm that they have closed.
2216     m_hardClosedForUserDelete = true;
2217
2218     // If this database already owns itself, it is already closing on the background thread.
2219     // After that close completes, the next database thread task will be "delete all currently closed databases"
2220     // which will also cover this database.
2221     if (m_owningPointerForClose)
2222         return;
2223
2224     notifyServerAboutClose(CloseState::Start);
2225     // Otherwise, this database is still potentially active.
2226     // So we'll have it own itself and then perform a clean unconditional delete on the background thread.
2227     m_owningPointerForClose = m_server->closeAndTakeUniqueIDBDatabase(*this);
2228     postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performUnconditionalDeleteBackingStore));
2229 }
2230
2231 void UniqueIDBDatabase::updateSpaceUsedIfNeeded(uint64_t callbackIdentifier)
2232 {
2233     auto iterator = m_pendingSpaceIncreasingTasks.find(callbackIdentifier);
2234     if (iterator == m_pendingSpaceIncreasingTasks.end())
2235         return;
2236
2237     m_server->decreasePotentialSpaceUsed(m_identifier.origin(), iterator->value);
2238     m_server->setSpaceUsed(m_identifier.origin(), m_databasesSizeForOrigin);
2239     m_pendingSpaceIncreasingTasks.remove(iterator);
2240 }
2241
2242 void UniqueIDBDatabase::performErrorCallback(uint64_t callbackIdentifier, const IDBError& error)
2243 {
2244     updateSpaceUsedIfNeeded(callbackIdentifier);
2245
2246     auto callback = m_errorCallbacks.take(callbackIdentifier);
2247     ASSERT(callback || m_hardClosedForUserDelete);
2248     if (callback) {
2249         callback(error);
2250         ASSERT(m_callbackQueue.first() == callbackIdentifier);
2251         m_callbackQueue.removeFirst();
2252     }
2253 }
2254
2255 void UniqueIDBDatabase::performKeyDataCallback(uint64_t callbackIdentifier, const IDBError& error, const IDBKeyData& resultKey)
2256 {
2257     updateSpaceUsedIfNeeded(callbackIdentifier);
2258
2259     auto callback = m_keyDataCallbacks.take(callbackIdentifier);
2260     ASSERT(callback || m_hardClosedForUserDelete);
2261     if (callback) {
2262         callback(error, resultKey);
2263         ASSERT(m_callbackQueue.first() == callbackIdentifier);
2264         m_callbackQueue.removeFirst();
2265     }
2266 }
2267
2268 void UniqueIDBDatabase::performGetResultCallback(uint64_t callbackIdentifier, const IDBError& error, const IDBGetResult& resultData)
2269 {
2270     auto callback = m_getResultCallbacks.take(callbackIdentifier);
2271     ASSERT(callback || m_hardClosedForUserDelete);
2272     if (callback) {
2273         callback(error, resultData);
2274         ASSERT(m_callbackQueue.first() == callbackIdentifier);
2275         m_callbackQueue.removeFirst();
2276     }
2277 }
2278
2279 void UniqueIDBDatabase::performGetAllResultsCallback(uint64_t callbackIdentifier, const IDBError& error, const IDBGetAllResult& resultData)
2280 {
2281     auto callback = m_getAllResultsCallbacks.take(callbackIdentifier);
2282     ASSERT(callback || m_hardClosedForUserDelete);
2283     if (callback) {
2284         callback(error, resultData);
2285         ASSERT(m_callbackQueue.first() == callbackIdentifier);
2286         m_callbackQueue.removeFirst();
2287     }
2288 }
2289
2290 void UniqueIDBDatabase::performCountCallback(uint64_t callbackIdentifier, const IDBError& error, uint64_t count)
2291 {
2292     auto callback = m_countCallbacks.take(callbackIdentifier);
2293     ASSERT(callback || m_hardClosedForUserDelete);
2294     if (callback) {
2295         callback(error, count);
2296         ASSERT(m_callbackQueue.first() == callbackIdentifier);
2297         m_callbackQueue.removeFirst();
2298     }
2299 }
2300
2301 void UniqueIDBDatabase::forgetErrorCallback(uint64_t callbackIdentifier)
2302 {
2303     updateSpaceUsedIfNeeded(callbackIdentifier);
2304
2305     ASSERT(m_errorCallbacks.contains(callbackIdentifier));
2306     ASSERT(m_callbackQueue.last() == callbackIdentifier);
2307     m_callbackQueue.removeLast();
2308     m_errorCallbacks.remove(callbackIdentifier);
2309 }
2310
2311 void UniqueIDBDatabase::setQuota(uint64_t quota)
2312 {
2313     if (m_backingStore)
2314         m_backingStore->setQuota(quota);
2315 }
2316
2317 void UniqueIDBDatabase::notifyServerAboutClose(CloseState state)
2318 {
2319     ASSERT(isMainThread());
2320 #if PLATFORM(IOS_FAMILY)
2321     if (state == CloseState::Start) 
2322         m_server->closeDatabase(this);
2323     else
2324         m_server->didCloseDatabase(this);
2325 #else
2326     UNUSED_PARAM(state);
2327 #endif
2328 }
2329
2330 } // namespace IDBServer
2331 } // namespace WebCore
2332
2333 #endif // ENABLE(INDEXED_DATABASE)