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