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