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