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