9c1943b7b363e079800b846a0cdc73b3beba9432
[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 "IDBCursorInfo.h"
32 #include "IDBKeyRangeData.h"
33 #include "IDBResultData.h"
34 #include "IDBServer.h"
35 #include "IDBTransactionInfo.h"
36 #include "Logging.h"
37 #include "ScopeGuard.h"
38 #include "UniqueIDBDatabaseConnection.h"
39 #include <wtf/MainThread.h>
40 #include <wtf/NeverDestroyed.h>
41 #include <wtf/ThreadSafeRefCounted.h>
42
43 using namespace JSC;
44
45 namespace WebCore {
46 namespace IDBServer {
47     
48 UniqueIDBDatabase::UniqueIDBDatabase(IDBServer& server, const IDBDatabaseIdentifier& identifier)
49     : m_server(server)
50     , m_identifier(identifier)
51     , m_operationAndTransactionTimer(*this, &UniqueIDBDatabase::operationAndTransactionTimerFired)
52 {
53 }
54
55 UniqueIDBDatabase::~UniqueIDBDatabase()
56 {
57     LOG(IndexedDB, "UniqueIDBDatabase::~UniqueIDBDatabase() (%p)", this);
58     ASSERT(!hasAnyPendingCallbacks());
59     ASSERT(m_inProgressTransactions.isEmpty());
60     ASSERT(m_pendingTransactions.isEmpty());
61     ASSERT(m_openDatabaseConnections.isEmpty());
62 }
63
64 const IDBDatabaseInfo& UniqueIDBDatabase::info() const
65 {
66     RELEASE_ASSERT(m_databaseInfo);
67     return *m_databaseInfo;
68 }
69
70 void UniqueIDBDatabase::openDatabaseConnection(IDBConnectionToClient& connection, const IDBRequestData& requestData)
71 {
72     auto operation = ServerOpenDBRequest::create(connection, requestData);
73     m_pendingOpenDBRequests.append(WTFMove(operation));
74
75     // An open operation is already in progress, so we can't possibly handle this one yet.
76     if (m_isOpeningBackingStore)
77         return;
78
79     handleDatabaseOperations();
80 }
81
82 bool UniqueIDBDatabase::hasAnyPendingCallbacks() const
83 {
84     return !m_errorCallbacks.isEmpty()
85         || !m_keyDataCallbacks.isEmpty()
86         || !m_getResultCallbacks.isEmpty()
87         || !m_countCallbacks.isEmpty();
88 }
89
90 bool UniqueIDBDatabase::isVersionChangeInProgress()
91 {
92 #ifndef NDEBUG
93     if (m_versionChangeTransaction)
94         ASSERT(m_versionChangeDatabaseConnection);
95 #endif
96
97     return m_versionChangeDatabaseConnection;
98 }
99
100 void UniqueIDBDatabase::performCurrentOpenOperation()
101 {
102     LOG(IndexedDB, "(main) UniqueIDBDatabase::performCurrentOpenOperation");
103
104     ASSERT(m_currentOpenDBRequest);
105     ASSERT(m_currentOpenDBRequest->isOpenRequest());
106
107     if (!m_databaseInfo) {
108         m_isOpeningBackingStore = true;
109         m_server.postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::openBackingStore, m_identifier));
110         return;
111     }
112
113     // If we previously started a version change operation but were blocked by having open connections,
114     // we might now be unblocked.
115     if (m_versionChangeDatabaseConnection) {
116         if (!m_versionChangeTransaction && !hasAnyOpenConnections())
117             startVersionChangeTransaction();
118         return;
119     }
120
121     // 3.3.1 Opening a database
122     // If requested version is undefined, then let requested version be 1 if db was created in the previous step,
123     // or the current version of db otherwise.
124     uint64_t requestedVersion = m_currentOpenDBRequest->requestData().requestedVersion();
125     if (!requestedVersion)
126         requestedVersion = m_databaseInfo->version() ? m_databaseInfo->version() : 1;
127
128     // 3.3.1 Opening a database
129     // If the database version higher than the requested version, abort these steps and return a VersionError.
130     if (requestedVersion < m_databaseInfo->version()) {
131         auto result = IDBResultData::error(m_currentOpenDBRequest->requestData().requestIdentifier(), IDBError(IDBDatabaseException::VersionError));
132         m_currentOpenDBRequest->connection().didOpenDatabase(result);
133         m_currentOpenDBRequest = nullptr;
134
135         return;
136     }
137
138     Ref<UniqueIDBDatabaseConnection> connection = UniqueIDBDatabaseConnection::create(*this, m_currentOpenDBRequest->connection());
139     UniqueIDBDatabaseConnection* rawConnection = &connection.get();
140
141     if (requestedVersion == m_databaseInfo->version()) {
142         addOpenDatabaseConnection(WTFMove(connection));
143
144         auto result = IDBResultData::openDatabaseSuccess(m_currentOpenDBRequest->requestData().requestIdentifier(), *rawConnection);
145         m_currentOpenDBRequest->connection().didOpenDatabase(result);
146         m_currentOpenDBRequest = nullptr;
147
148         return;
149     }
150
151     ASSERT(!m_versionChangeDatabaseConnection);
152     m_versionChangeDatabaseConnection = rawConnection;
153
154     // 3.3.7 "versionchange" transaction steps
155     // If there's no other open connections to this database, the version change process can begin immediately.
156     if (!hasAnyOpenConnections()) {
157         startVersionChangeTransaction();
158         return;
159     }
160
161     // Otherwise we have to notify all those open connections and wait for them to close.
162     maybeNotifyConnectionsOfVersionChange();
163 }
164
165 void UniqueIDBDatabase::performCurrentDeleteOperation()
166 {
167     ASSERT(isMainThread());
168     LOG(IndexedDB, "(main) UniqueIDBDatabase::performCurrentDeleteOperation - %s", m_identifier.debugString().utf8().data());
169
170     ASSERT(m_currentOpenDBRequest);
171     ASSERT(m_currentOpenDBRequest->isDeleteRequest());
172
173     if (m_deleteBackingStoreInProgress)
174         return;
175
176     if (hasAnyOpenConnections()) {
177         maybeNotifyConnectionsOfVersionChange();
178         return;
179     }
180
181     // Even though we have no open database connections, we might have close-pending database connections
182     // that are waiting on transactions to complete.
183     if (!m_inProgressTransactions.isEmpty()) {
184         ASSERT(!m_closePendingDatabaseConnections.isEmpty());
185         return;
186     }
187
188     ASSERT(!hasAnyPendingCallbacks());
189     ASSERT(m_pendingTransactions.isEmpty());
190     ASSERT(m_openDatabaseConnections.isEmpty());
191
192     // It's possible to have multiple delete requests queued up in a row.
193     // In that scenario only the first request will actually have to delete the database.
194     // Subsequent requests can immediately notify their completion.
195
196     if (m_databaseInfo) {
197         m_deleteBackingStoreInProgress = true;
198         m_server.postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::deleteBackingStore));
199     } else {
200         ASSERT(m_mostRecentDeletedDatabaseInfo);
201         didDeleteBackingStore();
202     }
203 }
204
205 void UniqueIDBDatabase::deleteBackingStore()
206 {
207     ASSERT(!isMainThread());
208     LOG(IndexedDB, "(db) UniqueIDBDatabase::deleteBackingStore");
209
210     if (m_backingStore) {
211         m_backingStore->deleteBackingStore();
212         m_backingStore = nullptr;
213         m_backingStoreSupportsSimultaneousTransactions = false;
214     }
215
216     m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didDeleteBackingStore));
217 }
218
219 void UniqueIDBDatabase::didDeleteBackingStore()
220 {
221     ASSERT(isMainThread());
222     LOG(IndexedDB, "(main) UniqueIDBDatabase::didDeleteBackingStore");
223
224     ASSERT(m_currentOpenDBRequest);
225     ASSERT(m_currentOpenDBRequest->isDeleteRequest());
226     ASSERT(!hasAnyPendingCallbacks());
227     ASSERT(m_inProgressTransactions.isEmpty());
228     ASSERT(m_pendingTransactions.isEmpty());
229     ASSERT(m_openDatabaseConnections.isEmpty());
230
231     if (m_databaseInfo)
232         m_mostRecentDeletedDatabaseInfo = WTFMove(m_databaseInfo);
233
234     ASSERT(m_mostRecentDeletedDatabaseInfo);
235     m_currentOpenDBRequest->notifyDidDeleteDatabase(*m_mostRecentDeletedDatabaseInfo);
236     m_currentOpenDBRequest = nullptr;
237
238     m_deletePending = false;
239     m_deleteBackingStoreInProgress = false;
240
241     if (m_pendingOpenDBRequests.isEmpty())
242         m_server.deleteUniqueIDBDatabase(*this);
243     else
244         invokeOperationAndTransactionTimer();
245 }
246
247 void UniqueIDBDatabase::handleDatabaseOperations()
248 {
249     ASSERT(isMainThread());
250     LOG(IndexedDB, "(main) UniqueIDBDatabase::handleDatabaseOperations - There are %zu pending", m_pendingOpenDBRequests.size());
251
252     if (m_versionChangeDatabaseConnection || m_versionChangeTransaction || m_currentOpenDBRequest) {
253         // We can't start any new open-database operations right now, but we might be able to start handling a delete operation.
254         if (!m_currentOpenDBRequest && !m_pendingOpenDBRequests.isEmpty() && m_pendingOpenDBRequests.first()->isDeleteRequest())
255             m_currentOpenDBRequest = m_pendingOpenDBRequests.takeFirst();
256
257         // Some operations (such as the first open operation after a delete) require multiple passes to completely handle
258         if (m_currentOpenDBRequest)
259             handleCurrentOperation();
260
261         return;
262     }
263
264     if (m_pendingOpenDBRequests.isEmpty())
265         return;
266
267     m_currentOpenDBRequest = m_pendingOpenDBRequests.takeFirst();
268     LOG(IndexedDB, "UniqueIDBDatabase::handleDatabaseOperations - Popped an operation, now there are %zu pending", m_pendingOpenDBRequests.size());
269
270     handleCurrentOperation();
271 }
272
273 void UniqueIDBDatabase::handleCurrentOperation()
274 {
275     ASSERT(m_currentOpenDBRequest);
276
277     RefPtr<UniqueIDBDatabase> protector(this);
278
279     if (m_currentOpenDBRequest->isOpenRequest())
280         performCurrentOpenOperation();
281     else if (m_currentOpenDBRequest->isDeleteRequest())
282         performCurrentDeleteOperation();
283     else
284         ASSERT_NOT_REACHED();
285
286     if (!m_currentOpenDBRequest)
287         invokeOperationAndTransactionTimer();
288 }
289
290 bool UniqueIDBDatabase::hasAnyOpenConnections() const
291 {
292     return !m_openDatabaseConnections.isEmpty();
293 }
294
295 static uint64_t generateUniqueCallbackIdentifier()
296 {
297     ASSERT(isMainThread());
298     static uint64_t currentID = 0;
299     return ++currentID;
300 }
301
302 uint64_t UniqueIDBDatabase::storeCallback(ErrorCallback callback)
303 {
304     uint64_t identifier = generateUniqueCallbackIdentifier();
305     ASSERT(!m_errorCallbacks.contains(identifier));
306     m_errorCallbacks.add(identifier, callback);
307     return identifier;
308 }
309
310 uint64_t UniqueIDBDatabase::storeCallback(KeyDataCallback callback)
311 {
312     uint64_t identifier = generateUniqueCallbackIdentifier();
313     ASSERT(!m_keyDataCallbacks.contains(identifier));
314     m_keyDataCallbacks.add(identifier, callback);
315     return identifier;
316 }
317
318 uint64_t UniqueIDBDatabase::storeCallback(GetResultCallback callback)
319 {
320     uint64_t identifier = generateUniqueCallbackIdentifier();
321     ASSERT(!m_getResultCallbacks.contains(identifier));
322     m_getResultCallbacks.add(identifier, callback);
323     return identifier;
324 }
325
326 uint64_t UniqueIDBDatabase::storeCallback(CountCallback callback)
327 {
328     uint64_t identifier = generateUniqueCallbackIdentifier();
329     ASSERT(!m_countCallbacks.contains(identifier));
330     m_countCallbacks.add(identifier, callback);
331     return identifier;
332 }
333
334 void UniqueIDBDatabase::handleDelete(IDBConnectionToClient& connection, const IDBRequestData& requestData)
335 {
336     LOG(IndexedDB, "(main) UniqueIDBDatabase::handleDelete");
337
338     m_pendingOpenDBRequests.append(ServerOpenDBRequest::create(connection, requestData));
339     handleDatabaseOperations();
340 }
341
342 void UniqueIDBDatabase::startVersionChangeTransaction()
343 {
344     LOG(IndexedDB, "(main) UniqueIDBDatabase::startVersionChangeTransaction");
345
346     ASSERT(!m_versionChangeTransaction);
347     ASSERT(m_currentOpenDBRequest);
348     ASSERT(m_currentOpenDBRequest->isOpenRequest());
349     ASSERT(m_versionChangeDatabaseConnection);
350
351     auto operation = WTFMove(m_currentOpenDBRequest);
352
353     uint64_t requestedVersion = operation->requestData().requestedVersion();
354     if (!requestedVersion)
355         requestedVersion = m_databaseInfo->version() ? m_databaseInfo->version() : 1;
356
357     addOpenDatabaseConnection(*m_versionChangeDatabaseConnection);
358
359     m_versionChangeTransaction = &m_versionChangeDatabaseConnection->createVersionChangeTransaction(requestedVersion);
360     m_databaseInfo->setVersion(requestedVersion);
361
362     m_inProgressTransactions.set(m_versionChangeTransaction->info().identifier(), m_versionChangeTransaction);
363     m_server.postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::beginTransactionInBackingStore, m_versionChangeTransaction->info()));
364
365     auto result = IDBResultData::openDatabaseUpgradeNeeded(operation->requestData().requestIdentifier(), *m_versionChangeTransaction);
366     operation->connection().didOpenDatabase(result);
367 }
368
369 void UniqueIDBDatabase::beginTransactionInBackingStore(const IDBTransactionInfo& info)
370 {
371     LOG(IndexedDB, "(db) UniqueIDBDatabase::beginTransactionInBackingStore");
372     m_backingStore->beginTransaction(info);
373 }
374
375 void UniqueIDBDatabase::maybeNotifyConnectionsOfVersionChange()
376 {
377     ASSERT(m_currentOpenDBRequest);
378
379     if (m_currentOpenDBRequest->hasNotifiedConnectionsOfVersionChange())
380         return;
381
382     uint64_t newVersion = m_currentOpenDBRequest->isOpenRequest() ? m_currentOpenDBRequest->requestData().requestedVersion() : 0;
383     auto requestIdentifier = m_currentOpenDBRequest->requestData().requestIdentifier();
384
385     LOG(IndexedDB, "(main) UniqueIDBDatabase::notifyConnectionsOfVersionChange - %" PRIu64, newVersion);
386
387     // 3.3.7 "versionchange" transaction steps
388     // Fire a versionchange event at each connection in m_openDatabaseConnections that is open.
389     // The event must not be fired on connections which has the closePending flag set.
390     HashSet<uint64_t> connectionIdentifiers;
391     for (auto connection : m_openDatabaseConnections) {
392         if (connection->closePending())
393             continue;
394
395         connection->fireVersionChangeEvent(requestIdentifier, newVersion);
396         connectionIdentifiers.add(connection->identifier());
397     }
398
399     m_currentOpenDBRequest->notifiedConnectionsOfVersionChange(WTFMove(connectionIdentifiers));
400 }
401
402 void UniqueIDBDatabase::notifyCurrentRequestConnectionClosedOrFiredVersionChangeEvent(uint64_t connectionIdentifier)
403 {
404     LOG(IndexedDB, "UniqueIDBDatabase::notifyCurrentRequestConnectionClosedOrFiredVersionChangeEvent - %" PRIu64, connectionIdentifier);
405
406     ASSERT(m_currentOpenDBRequest);
407
408     m_currentOpenDBRequest->connectionClosedOrFiredVersionChangeEvent(connectionIdentifier);
409
410     if (m_currentOpenDBRequest->hasConnectionsPendingVersionChangeEvent())
411         return;
412
413     if (!hasAnyOpenConnections()) {
414         invokeOperationAndTransactionTimer();
415         return;
416     }
417
418     if (m_currentOpenDBRequest->hasNotifiedBlocked())
419         return;
420
421     // Since all open connections have fired their version change events but not all of them have closed,
422     // this request is officially blocked.
423     m_currentOpenDBRequest->notifyRequestBlocked(m_databaseInfo->version());
424 }
425
426 void UniqueIDBDatabase::didFireVersionChangeEvent(UniqueIDBDatabaseConnection& connection, const IDBResourceIdentifier& requestIdentifier)
427 {
428     LOG(IndexedDB, "UniqueIDBDatabase::didFireVersionChangeEvent");
429
430     if (!m_currentOpenDBRequest)
431         return;
432
433     ASSERT_UNUSED(requestIdentifier, m_currentOpenDBRequest->requestData().requestIdentifier() == requestIdentifier);
434
435     notifyCurrentRequestConnectionClosedOrFiredVersionChangeEvent(connection.identifier());
436 }
437
438 void UniqueIDBDatabase::addOpenDatabaseConnection(Ref<UniqueIDBDatabaseConnection>&& connection)
439 {
440     ASSERT(!m_openDatabaseConnections.contains(&connection.get()));
441     m_openDatabaseConnections.add(adoptRef(connection.leakRef()));
442 }
443
444 void UniqueIDBDatabase::openBackingStore(const IDBDatabaseIdentifier& identifier)
445 {
446     ASSERT(!isMainThread());
447     LOG(IndexedDB, "(db) UniqueIDBDatabase::openBackingStore");
448
449     ASSERT(!m_backingStore);
450     m_backingStore = m_server.createBackingStore(identifier);
451     m_backingStoreSupportsSimultaneousTransactions = m_backingStore->supportsSimultaneousTransactions();
452     auto databaseInfo = m_backingStore->getOrEstablishDatabaseInfo();
453
454     m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didOpenBackingStore, databaseInfo));
455 }
456
457 void UniqueIDBDatabase::didOpenBackingStore(const IDBDatabaseInfo& info)
458 {
459     ASSERT(isMainThread());
460     LOG(IndexedDB, "(main) UniqueIDBDatabase::didOpenBackingStore");
461     
462     m_databaseInfo = std::make_unique<IDBDatabaseInfo>(info);
463
464     ASSERT(m_isOpeningBackingStore);
465     m_isOpeningBackingStore = false;
466
467     handleDatabaseOperations();
468 }
469
470 void UniqueIDBDatabase::createObjectStore(UniqueIDBDatabaseTransaction& transaction, const IDBObjectStoreInfo& info, ErrorCallback callback)
471 {
472     ASSERT(isMainThread());
473     LOG(IndexedDB, "(main) UniqueIDBDatabase::createObjectStore");
474
475     uint64_t callbackID = storeCallback(callback);
476     m_server.postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performCreateObjectStore, callbackID, transaction.info().identifier(), info));
477 }
478
479 void UniqueIDBDatabase::performCreateObjectStore(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, const IDBObjectStoreInfo& info)
480 {
481     ASSERT(!isMainThread());
482     LOG(IndexedDB, "(db) UniqueIDBDatabase::performCreateObjectStore");
483
484     ASSERT(m_backingStore);
485     m_backingStore->createObjectStore(transactionIdentifier, info);
486
487     IDBError error;
488     m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformCreateObjectStore, callbackIdentifier, error, info));
489 }
490
491 void UniqueIDBDatabase::didPerformCreateObjectStore(uint64_t callbackIdentifier, const IDBError& error, const IDBObjectStoreInfo& info)
492 {
493     ASSERT(isMainThread());
494     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformCreateObjectStore");
495
496     if (error.isNull())
497         m_databaseInfo->addExistingObjectStore(info);
498
499     performErrorCallback(callbackIdentifier, error);
500 }
501
502 void UniqueIDBDatabase::deleteObjectStore(UniqueIDBDatabaseTransaction& transaction, const String& objectStoreName, ErrorCallback callback)
503 {
504     ASSERT(isMainThread());
505     LOG(IndexedDB, "(main) UniqueIDBDatabase::deleteObjectStore");
506
507     uint64_t callbackID = storeCallback(callback);
508
509     auto* info = m_databaseInfo->infoForExistingObjectStore(objectStoreName);
510     if (!info) {
511         performErrorCallback(callbackID, { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to delete non-existant object store") });
512         return;
513     }
514
515     m_server.postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performDeleteObjectStore, callbackID, transaction.info().identifier(), info->identifier()));
516 }
517
518 void UniqueIDBDatabase::performDeleteObjectStore(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier)
519 {
520     ASSERT(!isMainThread());
521     LOG(IndexedDB, "(db) UniqueIDBDatabase::performDeleteObjectStore");
522
523     ASSERT(m_backingStore);
524     m_backingStore->deleteObjectStore(transactionIdentifier, objectStoreIdentifier);
525
526     IDBError error;
527     m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformDeleteObjectStore, callbackIdentifier, error, objectStoreIdentifier));
528 }
529
530 void UniqueIDBDatabase::didPerformDeleteObjectStore(uint64_t callbackIdentifier, const IDBError& error, uint64_t objectStoreIdentifier)
531 {
532     ASSERT(isMainThread());
533     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformDeleteObjectStore");
534
535     if (error.isNull())
536         m_databaseInfo->deleteObjectStore(objectStoreIdentifier);
537
538     performErrorCallback(callbackIdentifier, error);
539 }
540
541 void UniqueIDBDatabase::clearObjectStore(UniqueIDBDatabaseTransaction& transaction, uint64_t objectStoreIdentifier, ErrorCallback callback)
542 {
543     ASSERT(isMainThread());
544     LOG(IndexedDB, "(main) UniqueIDBDatabase::clearObjectStore");
545
546     uint64_t callbackID = storeCallback(callback);
547     m_server.postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performClearObjectStore, callbackID, transaction.info().identifier(), objectStoreIdentifier));
548 }
549
550 void UniqueIDBDatabase::performClearObjectStore(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier)
551 {
552     ASSERT(!isMainThread());
553     LOG(IndexedDB, "(db) UniqueIDBDatabase::performClearObjectStore");
554
555     ASSERT(m_backingStore);
556     m_backingStore->clearObjectStore(transactionIdentifier, objectStoreIdentifier);
557
558     IDBError error;
559     m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformClearObjectStore, callbackIdentifier, error));
560 }
561
562 void UniqueIDBDatabase::didPerformClearObjectStore(uint64_t callbackIdentifier, const IDBError& error)
563 {
564     ASSERT(isMainThread());
565     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformClearObjectStore");
566
567     performErrorCallback(callbackIdentifier, error);
568 }
569
570 void UniqueIDBDatabase::createIndex(UniqueIDBDatabaseTransaction& transaction, const IDBIndexInfo& info, ErrorCallback callback)
571 {
572     ASSERT(isMainThread());
573     LOG(IndexedDB, "(main) UniqueIDBDatabase::createIndex");
574
575     uint64_t callbackID = storeCallback(callback);
576     m_server.postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performCreateIndex, callbackID, transaction.info().identifier(), info));
577 }
578
579 void UniqueIDBDatabase::performCreateIndex(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, const IDBIndexInfo& info)
580 {
581     ASSERT(!isMainThread());
582     LOG(IndexedDB, "(db) UniqueIDBDatabase::performCreateIndex");
583
584     ASSERT(m_backingStore);
585     IDBError error = m_backingStore->createIndex(transactionIdentifier, info);
586
587     m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformCreateIndex, callbackIdentifier, error, info));
588 }
589
590 void UniqueIDBDatabase::didPerformCreateIndex(uint64_t callbackIdentifier, const IDBError& error, const IDBIndexInfo& info)
591 {
592     ASSERT(isMainThread());
593     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformCreateIndex");
594
595     if (error.isNull()) {
596         ASSERT(m_databaseInfo);
597         auto* objectStoreInfo = m_databaseInfo->infoForExistingObjectStore(info.objectStoreIdentifier());
598         ASSERT(objectStoreInfo);
599         objectStoreInfo->addExistingIndex(info);
600     }
601
602     performErrorCallback(callbackIdentifier, error);
603 }
604
605 void UniqueIDBDatabase::deleteIndex(UniqueIDBDatabaseTransaction& transaction, uint64_t objectStoreIdentifier, const String& indexName, ErrorCallback callback)
606 {
607     ASSERT(isMainThread());
608     LOG(IndexedDB, "(main) UniqueIDBDatabase::deleteIndex");
609
610     uint64_t callbackID = storeCallback(callback);
611
612     auto* objectStoreInfo = m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
613     if (!objectStoreInfo) {
614         performErrorCallback(callbackID, { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to delete index from non-existant object store") });
615         return;
616     }
617
618     auto* indexInfo = objectStoreInfo->infoForExistingIndex(indexName);
619     if (!indexInfo) {
620         performErrorCallback(callbackID, { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to delete non-existant index") });
621         return;
622     }
623
624     m_server.postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performDeleteIndex, callbackID, transaction.info().identifier(), objectStoreIdentifier, indexInfo->identifier()));
625 }
626
627 void UniqueIDBDatabase::performDeleteIndex(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const uint64_t indexIdentifier)
628 {
629     ASSERT(!isMainThread());
630     LOG(IndexedDB, "(db) UniqueIDBDatabase::performDeleteIndex");
631
632     ASSERT(m_backingStore);
633     m_backingStore->deleteIndex(transactionIdentifier, objectStoreIdentifier, indexIdentifier);
634
635     IDBError error;
636     m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformDeleteIndex, callbackIdentifier, error, objectStoreIdentifier, indexIdentifier));
637 }
638
639 void UniqueIDBDatabase::didPerformDeleteIndex(uint64_t callbackIdentifier, const IDBError& error, uint64_t objectStoreIdentifier, uint64_t indexIdentifier)
640 {
641     ASSERT(isMainThread());
642     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformDeleteIndex");
643
644     if (error.isNull()) {
645         auto* objectStoreInfo = m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
646         if (objectStoreInfo)
647             objectStoreInfo->deleteIndex(indexIdentifier);
648     }
649
650     performErrorCallback(callbackIdentifier, error);
651 }
652
653 void UniqueIDBDatabase::putOrAdd(const IDBRequestData& requestData, const IDBKeyData& keyData, const ThreadSafeDataBuffer& valueData, IndexedDB::ObjectStoreOverwriteMode overwriteMode, KeyDataCallback callback)
654 {
655     ASSERT(isMainThread());
656     LOG(IndexedDB, "(main) UniqueIDBDatabase::putOrAdd");
657
658     uint64_t callbackID = storeCallback(callback);
659     m_server.postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performPutOrAdd, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), keyData, valueData, overwriteMode));
660 }
661
662 VM& UniqueIDBDatabase::databaseThreadVM()
663 {
664     ASSERT(!isMainThread());
665     static VM* vm = &VM::create().leakRef();
666     return *vm;
667 }
668
669 ExecState& UniqueIDBDatabase::databaseThreadExecState()
670 {
671     ASSERT(!isMainThread());
672
673     static NeverDestroyed<Strong<JSGlobalObject>> globalObject(databaseThreadVM(), JSGlobalObject::create(databaseThreadVM(), JSGlobalObject::createStructure(databaseThreadVM(), jsNull())));
674
675     RELEASE_ASSERT(globalObject.get()->globalExec());
676     return *globalObject.get()->globalExec();
677 }
678
679 void UniqueIDBDatabase::performPutOrAdd(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyData& keyData, const ThreadSafeDataBuffer& originalRecordValue, IndexedDB::ObjectStoreOverwriteMode overwriteMode)
680 {
681     ASSERT(!isMainThread());
682     LOG(IndexedDB, "(db) UniqueIDBDatabase::performPutOrAdd");
683
684     ASSERT(m_backingStore);
685     ASSERT(objectStoreIdentifier);
686
687     IDBKeyData usedKey;
688     IDBError error;
689
690     auto objectStoreInfo = m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
691     if (!objectStoreInfo) {
692         error = IDBError(IDBDatabaseException::InvalidStateError, ASCIILiteral("Object store cannot be found in the backing store"));
693         m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));
694         return;
695     }
696
697     bool usedKeyIsGenerated = false;
698     ScopeGuard generatedKeyResetter;
699     if (objectStoreInfo->autoIncrement() && !keyData.isValid()) {
700         uint64_t keyNumber;
701         error = m_backingStore->generateKeyNumber(transactionIdentifier, objectStoreIdentifier, keyNumber);
702         if (!error.isNull()) {
703             m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));
704             return;
705         }
706         
707         usedKey.setNumberValue(keyNumber);
708         usedKeyIsGenerated = true;
709         generatedKeyResetter.enable([this, transactionIdentifier, objectStoreIdentifier, keyNumber]() {
710             m_backingStore->revertGeneratedKeyNumber(transactionIdentifier, objectStoreIdentifier, keyNumber);
711         });
712     } else
713         usedKey = keyData;
714
715     if (overwriteMode == IndexedDB::ObjectStoreOverwriteMode::NoOverwrite) {
716         bool keyExists;
717         error = m_backingStore->keyExistsInObjectStore(transactionIdentifier, objectStoreIdentifier, usedKey, keyExists);
718         if (error.isNull() && keyExists)
719             error = IDBError(IDBDatabaseException::ConstraintError, ASCIILiteral("Key already exists in the object store"));
720
721         if (!error.isNull()) {
722             m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));
723             return;
724         }
725     }
726
727     // 3.4.1.2 Object Store Storage Operation
728     // If ObjectStore has a key path and the key is autogenerated, then inject the key into the value
729     // using steps to assign a key to a value using a key path.
730     ThreadSafeDataBuffer injectedRecordValue;
731     if (usedKeyIsGenerated && !objectStoreInfo->keyPath().isNull()) {
732         JSLockHolder locker(databaseThreadVM());
733
734         JSValue value = deserializeIDBValueDataToJSValue(databaseThreadExecState(), originalRecordValue);
735         if (value.isUndefined()) {
736             m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, IDBError(IDBDatabaseException::ConstraintError, ASCIILiteral("Unable to deserialize record value for record key injection")), usedKey));
737             return;
738         }
739
740         if (!injectIDBKeyIntoScriptValue(databaseThreadExecState(), usedKey, value, objectStoreInfo->keyPath())) {
741             m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, IDBError(IDBDatabaseException::ConstraintError, ASCIILiteral("Unable to inject record key into record value")), usedKey));
742             return;
743         }
744
745         auto serializedValue = SerializedScriptValue::create(&databaseThreadExecState(), value, nullptr, nullptr);
746         if (databaseThreadExecState().hadException()) {
747             m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, IDBError(IDBDatabaseException::ConstraintError, ASCIILiteral("Unable to serialize record value after injecting record key")), usedKey));
748             return;
749         }
750
751         injectedRecordValue = ThreadSafeDataBuffer::copyVector(serializedValue->data());
752     }
753
754     // 3.4.1 Object Store Storage Operation
755     // ...If a record already exists in store ...
756     // then remove the record from store using the steps for deleting records from an object store...
757     // This is important because formally deleting it from from the object store also removes it from the appropriate indexes.
758     error = m_backingStore->deleteRange(transactionIdentifier, objectStoreIdentifier, usedKey);
759     if (!error.isNull()) {
760         m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));
761         return;
762     }
763
764     error = m_backingStore->addRecord(transactionIdentifier, *objectStoreInfo, usedKey, injectedRecordValue.data() ? injectedRecordValue : originalRecordValue);
765     if (!error.isNull()) {
766         m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));
767         return;
768     }
769
770     if (overwriteMode != IndexedDB::ObjectStoreOverwriteMode::OverwriteForCursor && objectStoreInfo->autoIncrement() && keyData.type() == IndexedDB::KeyType::Number)
771         error = m_backingStore->maybeUpdateKeyGeneratorNumber(transactionIdentifier, objectStoreIdentifier, keyData.number());
772
773     generatedKeyResetter.disable();
774     m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));
775 }
776
777 void UniqueIDBDatabase::didPerformPutOrAdd(uint64_t callbackIdentifier, const IDBError& error, const IDBKeyData& resultKey)
778 {
779     ASSERT(isMainThread());
780     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformPutOrAdd");
781
782     performKeyDataCallback(callbackIdentifier, error, resultKey);
783 }
784
785 void UniqueIDBDatabase::getRecord(const IDBRequestData& requestData, const IDBKeyRangeData& range, GetResultCallback callback)
786 {
787     ASSERT(isMainThread());
788     LOG(IndexedDB, "(main) UniqueIDBDatabase::getRecord");
789
790     uint64_t callbackID = storeCallback(callback);
791
792     if (uint64_t indexIdentifier = requestData.indexIdentifier())
793         m_server.postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performGetIndexRecord, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), indexIdentifier, requestData.indexRecordType(), range));
794     else
795         m_server.postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performGetRecord, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), range));
796 }
797
798 void UniqueIDBDatabase::performGetRecord(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyRangeData& keyRangeData)
799 {
800     ASSERT(!isMainThread());
801     LOG(IndexedDB, "(db) UniqueIDBDatabase::performGetRecord");
802
803     ASSERT(m_backingStore);
804
805     ThreadSafeDataBuffer valueData;
806     IDBError error = m_backingStore->getRecord(transactionIdentifier, objectStoreIdentifier, keyRangeData, valueData);
807
808     m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformGetRecord, callbackIdentifier, error, valueData));
809 }
810
811 void UniqueIDBDatabase::performGetIndexRecord(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, IndexedDB::IndexRecordType recordType, const IDBKeyRangeData& range)
812 {
813     ASSERT(!isMainThread());
814     LOG(IndexedDB, "(db) UniqueIDBDatabase::performGetIndexRecord");
815
816     ASSERT(m_backingStore);
817
818     IDBGetResult result;
819     IDBError error = m_backingStore->getIndexRecord(transactionIdentifier, objectStoreIdentifier, indexIdentifier, recordType, range, result);
820
821     m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformGetRecord, callbackIdentifier, error, result));
822 }
823
824 void UniqueIDBDatabase::didPerformGetRecord(uint64_t callbackIdentifier, const IDBError& error, const IDBGetResult& result)
825 {
826     ASSERT(isMainThread());
827     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformGetRecord");
828
829     performGetResultCallback(callbackIdentifier, error, result);
830 }
831
832 void UniqueIDBDatabase::getCount(const IDBRequestData& requestData, const IDBKeyRangeData& range, CountCallback callback)
833 {
834     ASSERT(isMainThread());
835     LOG(IndexedDB, "(main) UniqueIDBDatabase::getCount");
836
837     uint64_t callbackID = storeCallback(callback);
838     m_server.postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performGetCount, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), requestData.indexIdentifier(), range));
839 }
840
841 void UniqueIDBDatabase::performGetCount(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const IDBKeyRangeData& keyRangeData)
842 {
843     ASSERT(!isMainThread());
844     LOG(IndexedDB, "(db) UniqueIDBDatabase::performGetCount");
845
846     ASSERT(m_backingStore);
847     ASSERT(objectStoreIdentifier);
848
849     uint64_t count;
850     IDBError error = m_backingStore->getCount(transactionIdentifier, objectStoreIdentifier, indexIdentifier, keyRangeData, count);
851
852     m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformGetCount, callbackIdentifier, error, count));
853 }
854
855 void UniqueIDBDatabase::didPerformGetCount(uint64_t callbackIdentifier, const IDBError& error, uint64_t count)
856 {
857     ASSERT(isMainThread());
858     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformGetCount");
859
860     performCountCallback(callbackIdentifier, error, count);
861 }
862
863 void UniqueIDBDatabase::deleteRecord(const IDBRequestData& requestData, const IDBKeyRangeData& keyRangeData, ErrorCallback callback)
864 {
865     ASSERT(isMainThread());
866     LOG(IndexedDB, "(main) UniqueIDBDatabase::deleteRecord");
867
868     uint64_t callbackID = storeCallback(callback);
869     m_server.postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performDeleteRecord, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), keyRangeData));
870 }
871
872 void UniqueIDBDatabase::performDeleteRecord(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyRangeData& range)
873 {
874     ASSERT(!isMainThread());
875     LOG(IndexedDB, "(db) UniqueIDBDatabase::performDeleteRecord");
876
877     IDBError error = m_backingStore->deleteRange(transactionIdentifier, objectStoreIdentifier, range);
878
879     m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformDeleteRecord, callbackIdentifier, error));
880 }
881
882 void UniqueIDBDatabase::didPerformDeleteRecord(uint64_t callbackIdentifier, const IDBError& error)
883 {
884     ASSERT(isMainThread());
885     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformDeleteRecord");
886
887     performErrorCallback(callbackIdentifier, error);
888 }
889
890 void UniqueIDBDatabase::openCursor(const IDBRequestData& requestData, const IDBCursorInfo& info, GetResultCallback callback)
891 {
892     ASSERT(isMainThread());
893     LOG(IndexedDB, "(main) UniqueIDBDatabase::openCursor");
894
895     uint64_t callbackID = storeCallback(callback);
896     m_server.postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performOpenCursor, callbackID, requestData.transactionIdentifier(), info));
897 }
898
899 void UniqueIDBDatabase::performOpenCursor(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, const IDBCursorInfo& info)
900 {
901     ASSERT(!isMainThread());
902     LOG(IndexedDB, "(db) UniqueIDBDatabase::performOpenCursor");
903
904     IDBGetResult result;
905     IDBError error = m_backingStore->openCursor(transactionIdentifier, info, result);
906
907     m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformOpenCursor, callbackIdentifier, error, result));
908 }
909
910 void UniqueIDBDatabase::didPerformOpenCursor(uint64_t callbackIdentifier, const IDBError& error, const IDBGetResult& result)
911 {
912     ASSERT(isMainThread());
913     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformOpenCursor");
914
915     performGetResultCallback(callbackIdentifier, error, result);
916 }
917
918 void UniqueIDBDatabase::iterateCursor(const IDBRequestData& requestData, const IDBKeyData& key, unsigned long count, GetResultCallback callback)
919 {
920     ASSERT(isMainThread());
921     LOG(IndexedDB, "(main) UniqueIDBDatabase::iterateCursor");
922
923     uint64_t callbackID = storeCallback(callback);
924     m_server.postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performIterateCursor, callbackID, requestData.transactionIdentifier(), requestData.cursorIdentifier(), key, count));
925 }
926
927 void UniqueIDBDatabase::performIterateCursor(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, const IDBResourceIdentifier& cursorIdentifier, const IDBKeyData& key, unsigned long count)
928 {
929     ASSERT(!isMainThread());
930     LOG(IndexedDB, "(db) UniqueIDBDatabase::performIterateCursor");
931
932     IDBGetResult result;
933     IDBError error = m_backingStore->iterateCursor(transactionIdentifier, cursorIdentifier, key, count, result);
934
935     m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformIterateCursor, callbackIdentifier, error, result));
936 }
937
938 void UniqueIDBDatabase::didPerformIterateCursor(uint64_t callbackIdentifier, const IDBError& error, const IDBGetResult& result)
939 {
940     ASSERT(isMainThread());
941     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformIterateCursor");
942
943     performGetResultCallback(callbackIdentifier, error, result);
944 }
945
946 void UniqueIDBDatabase::commitTransaction(UniqueIDBDatabaseTransaction& transaction, ErrorCallback callback)
947 {
948     ASSERT(isMainThread());
949     LOG(IndexedDB, "(main) UniqueIDBDatabase::commitTransaction");
950
951     ASSERT(&transaction.databaseConnection().database() == this);
952
953     if (m_versionChangeTransaction == &transaction) {
954         ASSERT(!m_versionChangeDatabaseConnection || &m_versionChangeTransaction->databaseConnection() == m_versionChangeDatabaseConnection);
955         ASSERT(m_databaseInfo->version() == transaction.info().newVersion());
956
957         invokeOperationAndTransactionTimer();
958     }
959
960     uint64_t callbackID = storeCallback(callback);
961     m_server.postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performCommitTransaction, callbackID, transaction.info().identifier()));
962 }
963
964 void UniqueIDBDatabase::performCommitTransaction(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier)
965 {
966     ASSERT(!isMainThread());
967     LOG(IndexedDB, "(db) UniqueIDBDatabase::performCommitTransaction");
968
969     IDBError error = m_backingStore->commitTransaction(transactionIdentifier);
970     m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformCommitTransaction, callbackIdentifier, error, transactionIdentifier));
971 }
972
973 void UniqueIDBDatabase::didPerformCommitTransaction(uint64_t callbackIdentifier, const IDBError& error, const IDBResourceIdentifier& transactionIdentifier)
974 {
975     ASSERT(isMainThread());
976     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformCommitTransaction");
977
978     inProgressTransactionCompleted(transactionIdentifier);
979
980     performErrorCallback(callbackIdentifier, error);
981 }
982
983 void UniqueIDBDatabase::abortTransaction(UniqueIDBDatabaseTransaction& transaction, ErrorCallback callback)
984 {
985     ASSERT(isMainThread());
986     LOG(IndexedDB, "(main) UniqueIDBDatabase::abortTransaction");
987
988     ASSERT(&transaction.databaseConnection().database() == this);
989
990     uint64_t callbackID = storeCallback(callback);
991     m_server.postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performAbortTransaction, callbackID, transaction.info().identifier()));
992 }
993
994 void UniqueIDBDatabase::didFinishHandlingVersionChange(UniqueIDBDatabaseTransaction& transaction)
995 {
996     ASSERT(isMainThread());
997     LOG(IndexedDB, "(main) UniqueIDBDatabase::didFinishHandlingVersionChange");
998
999     ASSERT(m_versionChangeTransaction);
1000     ASSERT_UNUSED(transaction, m_versionChangeTransaction == &transaction);
1001
1002     m_versionChangeTransaction = nullptr;
1003     m_versionChangeDatabaseConnection = nullptr;
1004
1005     invokeOperationAndTransactionTimer();
1006 }
1007
1008 void UniqueIDBDatabase::performAbortTransaction(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier)
1009 {
1010     ASSERT(!isMainThread());
1011     LOG(IndexedDB, "(db) UniqueIDBDatabase::performAbortTransaction");
1012
1013     IDBError error = m_backingStore->abortTransaction(transactionIdentifier);
1014     m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformAbortTransaction, callbackIdentifier, error, transactionIdentifier));
1015 }
1016
1017 void UniqueIDBDatabase::didPerformAbortTransaction(uint64_t callbackIdentifier, const IDBError& error, const IDBResourceIdentifier& transactionIdentifier)
1018 {
1019     ASSERT(isMainThread());
1020     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformAbortTransaction");
1021
1022     if (m_versionChangeTransaction && m_versionChangeTransaction->info().identifier() == transactionIdentifier) {
1023         ASSERT(!m_versionChangeDatabaseConnection || &m_versionChangeTransaction->databaseConnection() == m_versionChangeDatabaseConnection);
1024         ASSERT(m_versionChangeTransaction->originalDatabaseInfo());
1025         m_databaseInfo = std::make_unique<IDBDatabaseInfo>(*m_versionChangeTransaction->originalDatabaseInfo());
1026     }
1027
1028     inProgressTransactionCompleted(transactionIdentifier);
1029
1030     performErrorCallback(callbackIdentifier, error);
1031 }
1032
1033 void UniqueIDBDatabase::transactionDestroyed(UniqueIDBDatabaseTransaction& transaction)
1034 {
1035     if (m_versionChangeTransaction == &transaction)
1036         m_versionChangeTransaction = nullptr;
1037 }
1038
1039 void UniqueIDBDatabase::connectionClosedFromClient(UniqueIDBDatabaseConnection& connection)
1040 {
1041     ASSERT(isMainThread());
1042     LOG(IndexedDB, "(main) UniqueIDBDatabase::connectionClosedFromClient");
1043
1044     if (m_versionChangeDatabaseConnection == &connection)
1045         m_versionChangeDatabaseConnection = nullptr;
1046
1047     ASSERT(m_openDatabaseConnections.contains(&connection));
1048
1049     Deque<RefPtr<UniqueIDBDatabaseTransaction>> pendingTransactions;
1050     while (!m_pendingTransactions.isEmpty()) {
1051         auto transaction = m_pendingTransactions.takeFirst();
1052         if (&transaction->databaseConnection() != &connection)
1053             pendingTransactions.append(WTFMove(transaction));
1054     }
1055
1056     if (!pendingTransactions.isEmpty())
1057         m_pendingTransactions.swap(pendingTransactions);
1058
1059     RefPtr<UniqueIDBDatabaseConnection> refConnection(&connection);
1060     m_openDatabaseConnections.remove(&connection);
1061
1062     if (m_currentOpenDBRequest)
1063         notifyCurrentRequestConnectionClosedOrFiredVersionChangeEvent(connection.identifier());
1064
1065     if (connection.hasNonFinishedTransactions()) {
1066         m_closePendingDatabaseConnections.add(WTFMove(refConnection));
1067         return;
1068     }
1069
1070     // Now that a database connection has closed, previously blocked operations might be runnable.
1071     invokeOperationAndTransactionTimer();
1072 }
1073
1074 void UniqueIDBDatabase::enqueueTransaction(Ref<UniqueIDBDatabaseTransaction>&& transaction)
1075 {
1076     LOG(IndexedDB, "UniqueIDBDatabase::enqueueTransaction - %s", transaction->info().loggingString().utf8().data());
1077
1078     ASSERT(transaction->info().mode() != IndexedDB::TransactionMode::VersionChange);
1079
1080     m_pendingTransactions.append(WTFMove(transaction));
1081
1082     invokeOperationAndTransactionTimer();
1083 }
1084
1085 void UniqueIDBDatabase::invokeOperationAndTransactionTimer()
1086 {
1087     LOG(IndexedDB, "UniqueIDBDatabase::invokeOperationAndTransactionTimer()");
1088     if (!m_operationAndTransactionTimer.isActive())
1089         m_operationAndTransactionTimer.startOneShot(0);
1090 }
1091
1092 void UniqueIDBDatabase::operationAndTransactionTimerFired()
1093 {
1094     LOG(IndexedDB, "(main) UniqueIDBDatabase::operationAndTransactionTimerFired");
1095
1096     RefPtr<UniqueIDBDatabase> protector(this);
1097
1098     // The current operation might require multiple attempts to handle, so try to
1099     // make further progress on it now.
1100     if (m_currentOpenDBRequest)
1101         handleCurrentOperation();
1102
1103     if (!m_currentOpenDBRequest)
1104         handleDatabaseOperations();
1105
1106     bool hadDeferredTransactions = false;
1107     auto transaction = takeNextRunnableTransaction(hadDeferredTransactions);
1108
1109     if (transaction) {
1110         m_inProgressTransactions.set(transaction->info().identifier(), transaction);
1111         for (auto objectStore : transaction->objectStoreIdentifiers()) {
1112             m_objectStoreTransactionCounts.add(objectStore);
1113             if (!transaction->isReadOnly()) {
1114                 m_objectStoreWriteTransactions.add(objectStore);
1115                 ASSERT(m_objectStoreTransactionCounts.count(objectStore) == 1);
1116             }
1117         }
1118
1119         activateTransactionInBackingStore(*transaction);
1120
1121         // If no transactions were deferred, it's possible we can start another transaction right now.
1122         if (!hadDeferredTransactions)
1123             invokeOperationAndTransactionTimer();
1124     }
1125 }
1126
1127 void UniqueIDBDatabase::activateTransactionInBackingStore(UniqueIDBDatabaseTransaction& transaction)
1128 {
1129     LOG(IndexedDB, "(main) UniqueIDBDatabase::activateTransactionInBackingStore");
1130
1131     RefPtr<UniqueIDBDatabase> self(this);
1132     RefPtr<UniqueIDBDatabaseTransaction> refTransaction(&transaction);
1133
1134     auto callback = [this, self, refTransaction](const IDBError& error) {
1135         refTransaction->didActivateInBackingStore(error);
1136     };
1137
1138     uint64_t callbackID = storeCallback(callback);
1139     m_server.postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performActivateTransactionInBackingStore, callbackID, transaction.info()));
1140 }
1141
1142 void UniqueIDBDatabase::performActivateTransactionInBackingStore(uint64_t callbackIdentifier, const IDBTransactionInfo& info)
1143 {
1144     LOG(IndexedDB, "(db) UniqueIDBDatabase::performActivateTransactionInBackingStore");
1145
1146     IDBError error = m_backingStore->beginTransaction(info);
1147     m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformActivateTransactionInBackingStore, callbackIdentifier, error));
1148 }
1149
1150 void UniqueIDBDatabase::didPerformActivateTransactionInBackingStore(uint64_t callbackIdentifier, const IDBError& error)
1151 {
1152     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformActivateTransactionInBackingStore");
1153
1154     invokeOperationAndTransactionTimer();
1155
1156     performErrorCallback(callbackIdentifier, error);
1157 }
1158
1159 template<typename T> bool scopesOverlap(const T& aScopes, const Vector<uint64_t>& bScopes)
1160 {
1161     for (auto scope : bScopes) {
1162         if (aScopes.contains(scope))
1163             return true;
1164     }
1165
1166     return false;
1167 }
1168
1169 RefPtr<UniqueIDBDatabaseTransaction> UniqueIDBDatabase::takeNextRunnableTransaction(bool& hadDeferredTransactions)
1170 {
1171     hadDeferredTransactions = false;
1172     if (!m_backingStoreSupportsSimultaneousTransactions && !m_inProgressTransactions.isEmpty()) {
1173         LOG(IndexedDB, "UniqueIDBDatabase::takeNextRunnableTransaction - Backing store only supports 1 transaction, and we already have 1");
1174         return nullptr;
1175     }
1176
1177     Deque<RefPtr<UniqueIDBDatabaseTransaction>> deferredTransactions;
1178     RefPtr<UniqueIDBDatabaseTransaction> currentTransaction;
1179
1180     HashSet<uint64_t> deferredReadWriteScopes;
1181
1182     while (!m_pendingTransactions.isEmpty()) {
1183         currentTransaction = m_pendingTransactions.takeFirst();
1184
1185         switch (currentTransaction->info().mode()) {
1186         case IndexedDB::TransactionMode::ReadOnly: {
1187             bool hasOverlappingScopes = scopesOverlap(deferredReadWriteScopes, currentTransaction->objectStoreIdentifiers());
1188             hasOverlappingScopes |= scopesOverlap(m_objectStoreWriteTransactions, currentTransaction->objectStoreIdentifiers());
1189
1190             if (hasOverlappingScopes)
1191                 deferredTransactions.append(WTFMove(currentTransaction));
1192
1193             break;
1194         }
1195         case IndexedDB::TransactionMode::ReadWrite: {
1196             bool hasOverlappingScopes = scopesOverlap(m_objectStoreTransactionCounts, currentTransaction->objectStoreIdentifiers());
1197             hasOverlappingScopes |= scopesOverlap(deferredReadWriteScopes, currentTransaction->objectStoreIdentifiers());
1198
1199             if (hasOverlappingScopes) {
1200                 for (auto objectStore : currentTransaction->objectStoreIdentifiers())
1201                     deferredReadWriteScopes.add(objectStore);
1202                 deferredTransactions.append(WTFMove(currentTransaction));
1203             }
1204
1205             break;
1206         }
1207         case IndexedDB::TransactionMode::VersionChange:
1208             // Version change transactions should never be scheduled in the traditional manner.
1209             RELEASE_ASSERT_NOT_REACHED();
1210         }
1211
1212         // If we didn't defer the currentTransaction above, it can be run now.
1213         if (currentTransaction)
1214             break;
1215     }
1216
1217     hadDeferredTransactions = !deferredTransactions.isEmpty();
1218     if (!hadDeferredTransactions)
1219         return currentTransaction;
1220
1221     // Prepend the deferred transactions back on the beginning of the deque for future scheduling passes.
1222     while (!deferredTransactions.isEmpty())
1223         m_pendingTransactions.prepend(deferredTransactions.takeLast());
1224
1225     return currentTransaction;
1226 }
1227
1228 void UniqueIDBDatabase::inProgressTransactionCompleted(const IDBResourceIdentifier& transactionIdentifier)
1229 {
1230     auto transaction = m_inProgressTransactions.take(transactionIdentifier);
1231     ASSERT(transaction);
1232
1233     for (auto objectStore : transaction->objectStoreIdentifiers()) {
1234         if (!transaction->isReadOnly()) {
1235             m_objectStoreWriteTransactions.remove(objectStore);
1236             ASSERT(m_objectStoreTransactionCounts.count(objectStore) == 1);
1237         }
1238         m_objectStoreTransactionCounts.remove(objectStore);
1239     }
1240
1241     if (!transaction->databaseConnection().hasNonFinishedTransactions())
1242         m_closePendingDatabaseConnections.remove(&transaction->databaseConnection());
1243
1244     // Previously blocked operations might be runnable.
1245     invokeOperationAndTransactionTimer();
1246 }
1247
1248 void UniqueIDBDatabase::performErrorCallback(uint64_t callbackIdentifier, const IDBError& error)
1249 {
1250     auto callback = m_errorCallbacks.take(callbackIdentifier);
1251     ASSERT(callback);
1252     callback(error);
1253 }
1254
1255 void UniqueIDBDatabase::performKeyDataCallback(uint64_t callbackIdentifier, const IDBError& error, const IDBKeyData& resultKey)
1256 {
1257     auto callback = m_keyDataCallbacks.take(callbackIdentifier);
1258     ASSERT(callback);
1259     callback(error, resultKey);
1260 }
1261
1262 void UniqueIDBDatabase::performGetResultCallback(uint64_t callbackIdentifier, const IDBError& error, const IDBGetResult& resultData)
1263 {
1264     auto callback = m_getResultCallbacks.take(callbackIdentifier);
1265     ASSERT(callback);
1266     callback(error, resultData);
1267 }
1268
1269 void UniqueIDBDatabase::performCountCallback(uint64_t callbackIdentifier, const IDBError& error, uint64_t count)
1270 {
1271     auto callback = m_countCallbacks.take(callbackIdentifier);
1272     ASSERT(callback);
1273     callback(error, count);
1274 }
1275
1276 } // namespace IDBServer
1277 } // namespace WebCore
1278
1279 #endif // ENABLE(INDEXED_DATABASE)