Modern IDB: Pipe through cursor functions from client to server.
[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     m_backingStore->createIndex(transactionIdentifier, info);
357
358     IDBError error;
359     m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformCreateIndex, callbackIdentifier, error, info));
360 }
361
362 void UniqueIDBDatabase::didPerformCreateIndex(uint64_t callbackIdentifier, const IDBError& error, const IDBIndexInfo& info)
363 {
364     ASSERT(isMainThread());
365     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformCreateIndex");
366
367     if (error.isNull()) {
368         ASSERT(m_databaseInfo);
369         auto* objectStoreInfo = m_databaseInfo->infoForExistingObjectStore(info.objectStoreIdentifier());
370         ASSERT(objectStoreInfo);
371         objectStoreInfo->addExistingIndex(info);
372     }
373
374     performErrorCallback(callbackIdentifier, error);
375 }
376
377 void UniqueIDBDatabase::putOrAdd(const IDBRequestData& requestData, const IDBKeyData& keyData, const ThreadSafeDataBuffer& valueData, IndexedDB::ObjectStoreOverwriteMode overwriteMode, KeyDataCallback callback)
378 {
379     ASSERT(isMainThread());
380     LOG(IndexedDB, "(main) UniqueIDBDatabase::putOrAdd");
381
382     uint64_t callbackID = storeCallback(callback);
383     m_server.postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performPutOrAdd, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), keyData, valueData, overwriteMode));
384 }
385
386 void UniqueIDBDatabase::performPutOrAdd(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyData& keyData, const ThreadSafeDataBuffer& valueData, IndexedDB::ObjectStoreOverwriteMode overwriteMode)
387 {
388     ASSERT(!isMainThread());
389     LOG(IndexedDB, "(db) UniqueIDBDatabase::performPutOrAdd");
390
391     ASSERT(m_backingStore);
392     ASSERT(objectStoreIdentifier);
393
394     IDBKeyData usedKey;
395     IDBError error;
396
397     auto objectStoreInfo = m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
398     if (!objectStoreInfo) {
399         error = IDBError(IDBExceptionCode::InvalidStateError, ASCIILiteral("Object store cannot be found in the backing store"));
400         m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));
401         return;
402     }
403
404     if (objectStoreInfo->autoIncrement() && !keyData.isValid()) {
405         uint64_t keyNumber;
406         error = m_backingStore->generateKeyNumber(transactionIdentifier, objectStoreIdentifier, keyNumber);
407         if (!error.isNull()) {
408             m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));
409             return;
410         }
411         
412         usedKey.setNumberValue(keyNumber);
413     } else
414         usedKey = keyData;
415
416     if (overwriteMode == IndexedDB::ObjectStoreOverwriteMode::NoOverwrite) {
417         bool keyExists;
418         error = m_backingStore->keyExistsInObjectStore(transactionIdentifier, objectStoreIdentifier, usedKey, keyExists);
419         if (error.isNull() && keyExists)
420             error = IDBError(IDBExceptionCode::ConstraintError, ASCIILiteral("Key already exists in the object store"));
421
422         if (!error.isNull()) {
423             m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));
424             return;
425         }
426     }
427
428     // 3.4.1 Object Store Storage Operation
429     // ...If a record already exists in store ...
430     // then remove the record from store using the steps for deleting records from an object store...
431     // This is important because formally deleting it from from the object store also removes it from the appropriate indexes.
432     error = m_backingStore->deleteRange(transactionIdentifier, objectStoreIdentifier, usedKey);
433     if (!error.isNull()) {
434         m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));
435         return;
436     }
437
438     error = m_backingStore->addRecord(transactionIdentifier, objectStoreIdentifier, usedKey, valueData);
439
440     m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));
441 }
442
443 void UniqueIDBDatabase::didPerformPutOrAdd(uint64_t callbackIdentifier, const IDBError& error, const IDBKeyData& resultKey)
444 {
445     ASSERT(isMainThread());
446     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformPutOrAdd");
447
448     performKeyDataCallback(callbackIdentifier, error, resultKey);
449 }
450
451 void UniqueIDBDatabase::getRecord(const IDBRequestData& requestData, const IDBKeyRangeData& range, GetResultCallback callback)
452 {
453     ASSERT(isMainThread());
454     LOG(IndexedDB, "(main) UniqueIDBDatabase::getRecord");
455
456     uint64_t callbackID = storeCallback(callback);
457
458     if (uint64_t indexIdentifier = requestData.indexIdentifier())
459         m_server.postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performGetIndexRecord, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), indexIdentifier, requestData.indexRecordType(), range));
460     else
461         m_server.postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performGetRecord, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), range));
462 }
463
464 void UniqueIDBDatabase::performGetRecord(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyRangeData& keyRangeData)
465 {
466     ASSERT(!isMainThread());
467     LOG(IndexedDB, "(db) UniqueIDBDatabase::performGetRecord");
468
469     ASSERT(m_backingStore);
470
471     ThreadSafeDataBuffer valueData;
472     IDBError error = m_backingStore->getRecord(transactionIdentifier, objectStoreIdentifier, keyRangeData, valueData);
473
474     m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformGetRecord, callbackIdentifier, error, valueData));
475 }
476
477 void UniqueIDBDatabase::performGetIndexRecord(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, IndexedDB::IndexRecordType recordType, const IDBKeyRangeData& range)
478 {
479     ASSERT(!isMainThread());
480     LOG(IndexedDB, "(db) UniqueIDBDatabase::performGetIndexRecord");
481
482     ASSERT(m_backingStore);
483
484     IDBGetResult result;
485     IDBError error = m_backingStore->getIndexRecord(transactionIdentifier, objectStoreIdentifier, indexIdentifier, recordType, range, result);
486
487     m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformGetRecord, callbackIdentifier, error, result));
488 }
489
490 void UniqueIDBDatabase::didPerformGetRecord(uint64_t callbackIdentifier, const IDBError& error, const IDBGetResult& result)
491 {
492     ASSERT(isMainThread());
493     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformGetRecord");
494
495     performGetResultCallback(callbackIdentifier, error, result);
496 }
497
498 void UniqueIDBDatabase::getCount(const IDBRequestData& requestData, const IDBKeyRangeData& range, CountCallback callback)
499 {
500     ASSERT(isMainThread());
501     LOG(IndexedDB, "(main) UniqueIDBDatabase::getCount");
502
503     uint64_t callbackID = storeCallback(callback);
504     m_server.postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performGetCount, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), requestData.indexIdentifier(), range));
505 }
506
507 void UniqueIDBDatabase::performGetCount(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const IDBKeyRangeData& keyRangeData)
508 {
509     ASSERT(!isMainThread());
510     LOG(IndexedDB, "(db) UniqueIDBDatabase::performGetCount");
511
512     ASSERT(m_backingStore);
513     ASSERT(objectStoreIdentifier);
514
515     uint64_t count;
516     IDBError error = m_backingStore->getCount(transactionIdentifier, objectStoreIdentifier, indexIdentifier, keyRangeData, count);
517
518     m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformGetCount, callbackIdentifier, error, count));
519 }
520
521 void UniqueIDBDatabase::didPerformGetCount(uint64_t callbackIdentifier, const IDBError& error, uint64_t count)
522 {
523     ASSERT(isMainThread());
524     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformGetCount");
525
526     performCountCallback(callbackIdentifier, error, count);
527 }
528
529 void UniqueIDBDatabase::deleteRecord(const IDBRequestData& requestData, const IDBKeyRangeData& keyRangeData, ErrorCallback callback)
530 {
531     ASSERT(isMainThread());
532     LOG(IndexedDB, "(main) UniqueIDBDatabase::deleteRecord");
533
534     uint64_t callbackID = storeCallback(callback);
535     m_server.postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performDeleteRecord, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), keyRangeData));
536 }
537
538 void UniqueIDBDatabase::performDeleteRecord(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyRangeData& range)
539 {
540     ASSERT(!isMainThread());
541     LOG(IndexedDB, "(db) UniqueIDBDatabase::performDeleteRecord");
542
543     IDBError error = m_backingStore->deleteRange(transactionIdentifier, objectStoreIdentifier, range);
544
545     m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformDeleteRecord, callbackIdentifier, error));
546 }
547
548 void UniqueIDBDatabase::didPerformDeleteRecord(uint64_t callbackIdentifier, const IDBError& error)
549 {
550     ASSERT(isMainThread());
551     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformDeleteRecord");
552
553     performErrorCallback(callbackIdentifier, error);
554 }
555
556 void UniqueIDBDatabase::openCursor(const IDBRequestData& requestData, const IDBCursorInfo& info, GetResultCallback callback)
557 {
558     ASSERT(isMainThread());
559     LOG(IndexedDB, "(main) UniqueIDBDatabase::openCursor");
560
561     uint64_t callbackID = storeCallback(callback);
562     m_server.postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performOpenCursor, callbackID, requestData.transactionIdentifier(), info));
563 }
564
565 void UniqueIDBDatabase::performOpenCursor(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, const IDBCursorInfo& info)
566 {
567     ASSERT(!isMainThread());
568     LOG(IndexedDB, "(db) UniqueIDBDatabase::performOpenCursor");
569
570     IDBGetResult result;
571     IDBError error = m_backingStore->openCursor(transactionIdentifier, info, result);
572
573     m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformOpenCursor, callbackIdentifier, error, result));
574 }
575
576 void UniqueIDBDatabase::didPerformOpenCursor(uint64_t callbackIdentifier, const IDBError& error, const IDBGetResult& result)
577 {
578     ASSERT(isMainThread());
579     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformOpenCursor");
580
581     performGetResultCallback(callbackIdentifier, error, result);
582 }
583
584 void UniqueIDBDatabase::iterateCursor(const IDBRequestData& requestData, const IDBKeyData& key, unsigned long count, GetResultCallback callback)
585 {
586     ASSERT(isMainThread());
587     LOG(IndexedDB, "(main) UniqueIDBDatabase::iterateCursor");
588
589     uint64_t callbackID = storeCallback(callback);
590     m_server.postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performIterateCursor, callbackID, requestData.transactionIdentifier(), key, count));
591 }
592
593 void UniqueIDBDatabase::performIterateCursor(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, const IDBKeyData& key, unsigned long count)
594 {
595     ASSERT(!isMainThread());
596     LOG(IndexedDB, "(db) UniqueIDBDatabase::performIterateCursor");
597
598     IDBGetResult result;
599     IDBError error = m_backingStore->iterateCursor(transactionIdentifier, key, count, result);
600
601     m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformIterateCursor, callbackIdentifier, error, result));
602 }
603
604 void UniqueIDBDatabase::didPerformIterateCursor(uint64_t callbackIdentifier, const IDBError& error, const IDBGetResult& result)
605 {
606     ASSERT(isMainThread());
607     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformIterateCursor");
608
609     performGetResultCallback(callbackIdentifier, error, result);
610 }
611
612 void UniqueIDBDatabase::commitTransaction(UniqueIDBDatabaseTransaction& transaction, ErrorCallback callback)
613 {
614     ASSERT(isMainThread());
615     LOG(IndexedDB, "(main) UniqueIDBDatabase::commitTransaction");
616
617     ASSERT(&transaction.databaseConnection().database() == this);
618
619     if (m_versionChangeTransaction == &transaction) {
620         ASSERT(&m_versionChangeTransaction->databaseConnection() == m_versionChangeDatabaseConnection);
621         m_databaseInfo->setVersion(transaction.info().newVersion());
622         m_versionChangeTransaction = nullptr;
623         m_versionChangeDatabaseConnection = nullptr;
624     }
625
626     uint64_t callbackID = storeCallback(callback);
627     m_server.postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performCommitTransaction, callbackID, transaction.info().identifier()));
628 }
629
630 void UniqueIDBDatabase::performCommitTransaction(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier)
631 {
632     ASSERT(!isMainThread());
633     LOG(IndexedDB, "(db) UniqueIDBDatabase::performCommitTransaction");
634
635     IDBError error = m_backingStore->commitTransaction(transactionIdentifier);
636     m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformCommitTransaction, callbackIdentifier, error, transactionIdentifier));
637 }
638
639 void UniqueIDBDatabase::didPerformCommitTransaction(uint64_t callbackIdentifier, const IDBError& error, const IDBResourceIdentifier& transactionIdentifier)
640 {
641     ASSERT(isMainThread());
642     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformCommitTransaction");
643
644     inProgressTransactionCompleted(transactionIdentifier);
645
646     performErrorCallback(callbackIdentifier, error);
647 }
648
649 void UniqueIDBDatabase::abortTransaction(UniqueIDBDatabaseTransaction& transaction, ErrorCallback callback)
650 {
651     ASSERT(isMainThread());
652     LOG(IndexedDB, "(main) UniqueIDBDatabase::abortTransaction");
653
654     ASSERT(&transaction.databaseConnection().database() == this);
655
656     uint64_t callbackID = storeCallback(callback);
657     m_server.postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performAbortTransaction, callbackID, transaction.info().identifier()));
658 }
659
660 void UniqueIDBDatabase::performAbortTransaction(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier)
661 {
662     ASSERT(!isMainThread());
663     LOG(IndexedDB, "(db) UniqueIDBDatabase::performAbortTransaction");
664
665     IDBError error = m_backingStore->abortTransaction(transactionIdentifier);
666     m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformAbortTransaction, callbackIdentifier, error, transactionIdentifier));
667 }
668
669 void UniqueIDBDatabase::didPerformAbortTransaction(uint64_t callbackIdentifier, const IDBError& error, const IDBResourceIdentifier& transactionIdentifier)
670 {
671     ASSERT(isMainThread());
672     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformAbortTransaction");
673
674     if (m_versionChangeTransaction && m_versionChangeTransaction->info().identifier() == transactionIdentifier) {
675         ASSERT(&m_versionChangeTransaction->databaseConnection() == m_versionChangeDatabaseConnection);
676         ASSERT(m_versionChangeTransaction->originalDatabaseInfo());
677         m_databaseInfo = std::make_unique<IDBDatabaseInfo>(*m_versionChangeTransaction->originalDatabaseInfo());
678
679         m_versionChangeTransaction = nullptr;
680         m_versionChangeDatabaseConnection = nullptr;
681     }
682
683     inProgressTransactionCompleted(transactionIdentifier);
684
685     performErrorCallback(callbackIdentifier, error);
686 }
687
688 void UniqueIDBDatabase::transactionDestroyed(UniqueIDBDatabaseTransaction& transaction)
689 {
690     if (m_versionChangeTransaction == &transaction)
691         m_versionChangeTransaction = nullptr;
692 }
693
694 void UniqueIDBDatabase::connectionClosedFromClient(UniqueIDBDatabaseConnection& connection)
695 {
696     ASSERT(isMainThread());
697     LOG(IndexedDB, "(main) UniqueIDBDatabase::connectionClosedFromClient");
698
699     if (m_versionChangeDatabaseConnection == &connection)
700         m_versionChangeDatabaseConnection = nullptr;
701
702     ASSERT(m_openDatabaseConnections.contains(&connection));
703
704     auto removedConnection = m_openDatabaseConnections.take(&connection);
705     if (removedConnection->hasNonFinishedTransactions()) {
706         m_closePendingDatabaseConnections.add(WTF::move(removedConnection));
707         return;
708     }
709
710     // Now that a database connection has closed, previously blocked transactions might be runnable.
711     invokeTransactionScheduler();
712 }
713
714 void UniqueIDBDatabase::enqueueTransaction(Ref<UniqueIDBDatabaseTransaction>&& transaction)
715 {
716     LOG(IndexedDB, "UniqueIDBDatabase::enqueueTransaction");
717
718     ASSERT(transaction->info().mode() != IndexedDB::TransactionMode::VersionChange);
719
720     m_pendingTransactions.append(WTF::move(transaction));
721
722     invokeTransactionScheduler();
723 }
724
725 void UniqueIDBDatabase::invokeTransactionScheduler()
726 {
727     if (!m_transactionSchedulingTimer.isActive())
728         m_transactionSchedulingTimer.startOneShot(0);
729 }
730
731 void UniqueIDBDatabase::transactionSchedulingTimerFired()
732 {
733     LOG(IndexedDB, "(main) UniqueIDBDatabase::transactionSchedulingTimerFired");
734
735     if (m_pendingTransactions.isEmpty()) {
736         if (!hasAnyOpenConnections() && m_versionChangeOperation) {
737             startVersionChangeTransaction();
738             return;
739         }
740     }
741
742     bool hadDeferredTransactions = false;
743     auto transaction = takeNextRunnableTransaction(hadDeferredTransactions);
744
745     if (transaction) {
746         m_inProgressTransactions.set(transaction->info().identifier(), transaction);
747         for (auto objectStore : transaction->objectStoreIdentifiers())
748             m_objectStoreTransactionCounts.add(objectStore);
749
750         activateTransactionInBackingStore(*transaction);
751
752         // If no transactions were deferred, it's possible we can start another transaction right now.
753         if (!hadDeferredTransactions)
754             invokeTransactionScheduler();
755     }
756 }
757
758 void UniqueIDBDatabase::activateTransactionInBackingStore(UniqueIDBDatabaseTransaction& transaction)
759 {
760     LOG(IndexedDB, "(main) UniqueIDBDatabase::activateTransactionInBackingStore");
761
762     RefPtr<UniqueIDBDatabase> self(this);
763     RefPtr<UniqueIDBDatabaseTransaction> refTransaction(&transaction);
764
765     auto callback = [this, self, refTransaction](const IDBError& error) {
766         refTransaction->didActivateInBackingStore(error);
767     };
768
769     uint64_t callbackID = storeCallback(callback);
770     m_server.postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performActivateTransactionInBackingStore, callbackID, transaction.info()));
771 }
772
773 void UniqueIDBDatabase::performActivateTransactionInBackingStore(uint64_t callbackIdentifier, const IDBTransactionInfo& info)
774 {
775     LOG(IndexedDB, "(db) UniqueIDBDatabase::performActivateTransactionInBackingStore");
776
777     IDBError error = m_backingStore->beginTransaction(info);
778     m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformActivateTransactionInBackingStore, callbackIdentifier, error));
779 }
780
781 void UniqueIDBDatabase::didPerformActivateTransactionInBackingStore(uint64_t callbackIdentifier, const IDBError& error)
782 {
783     LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformActivateTransactionInBackingStore");
784
785     invokeTransactionScheduler();
786
787     performErrorCallback(callbackIdentifier, error);
788 }
789
790 template<typename T> bool scopesOverlap(const T& aScopes, const Vector<uint64_t>& bScopes)
791 {
792     for (auto scope : bScopes) {
793         if (aScopes.contains(scope))
794             return true;
795     }
796
797     return false;
798 }
799
800 RefPtr<UniqueIDBDatabaseTransaction> UniqueIDBDatabase::takeNextRunnableTransaction(bool& hadDeferredTransactions)
801 {
802     Deque<RefPtr<UniqueIDBDatabaseTransaction>> deferredTransactions;
803     RefPtr<UniqueIDBDatabaseTransaction> currentTransaction;
804
805     while (!m_pendingTransactions.isEmpty()) {
806         currentTransaction = m_pendingTransactions.takeFirst();
807
808         switch (currentTransaction->info().mode()) {
809         case IndexedDB::TransactionMode::ReadOnly:
810             // If there are any deferred transactions, the first one is a read-write transaction we need to unblock.
811             // Therefore, skip this read-only transaction if its scope overlaps with that read-write transaction.
812             if (!deferredTransactions.isEmpty()) {
813                 ASSERT(deferredTransactions.first()->info().mode() == IndexedDB::TransactionMode::ReadWrite);
814                 if (scopesOverlap(deferredTransactions.first()->objectStoreIdentifiers(), currentTransaction->objectStoreIdentifiers()))
815                     deferredTransactions.append(WTF::move(currentTransaction));
816             }
817
818             break;
819         case IndexedDB::TransactionMode::ReadWrite:
820             // If this read-write transaction's scope overlaps with running transactions, it must be deferred.
821             if (scopesOverlap(m_objectStoreTransactionCounts, currentTransaction->objectStoreIdentifiers()))
822                 deferredTransactions.append(WTF::move(currentTransaction));
823
824             break;
825         case IndexedDB::TransactionMode::VersionChange:
826             // Version change transactions should never be scheduled in the traditional manner.
827             RELEASE_ASSERT_NOT_REACHED();
828         }
829
830         // If we didn't defer the currentTransaction above, it can be run now.
831         if (currentTransaction)
832             break;
833     }
834
835     hadDeferredTransactions = !deferredTransactions.isEmpty();
836     if (!hadDeferredTransactions)
837         return WTF::move(currentTransaction);
838
839     // Prepend the deferred transactions back on the beginning of the deque for future scheduling passes.
840     while (!deferredTransactions.isEmpty())
841         m_pendingTransactions.prepend(deferredTransactions.takeLast());
842
843     return WTF::move(currentTransaction);
844 }
845
846 void UniqueIDBDatabase::inProgressTransactionCompleted(const IDBResourceIdentifier& transactionIdentifier)
847 {
848     auto transaction = m_inProgressTransactions.take(transactionIdentifier);
849     ASSERT(transaction);
850
851     if (m_versionChangeTransaction == transaction)
852         m_versionChangeTransaction = nullptr;
853
854     for (auto objectStore : transaction->objectStoreIdentifiers())
855         m_objectStoreTransactionCounts.remove(objectStore);
856
857     // Previously blocked transactions might now be unblocked.
858     invokeTransactionScheduler();
859 }
860
861 void UniqueIDBDatabase::performErrorCallback(uint64_t callbackIdentifier, const IDBError& error)
862 {
863     auto callback = m_errorCallbacks.take(callbackIdentifier);
864     ASSERT(callback);
865     callback(error);
866 }
867
868 void UniqueIDBDatabase::performKeyDataCallback(uint64_t callbackIdentifier, const IDBError& error, const IDBKeyData& resultKey)
869 {
870     auto callback = m_keyDataCallbacks.take(callbackIdentifier);
871     ASSERT(callback);
872     callback(error, resultKey);
873 }
874
875 void UniqueIDBDatabase::performGetResultCallback(uint64_t callbackIdentifier, const IDBError& error, const IDBGetResult& resultData)
876 {
877     auto callback = m_getResultCallbacks.take(callbackIdentifier);
878     ASSERT(callback);
879     callback(error, resultData);
880 }
881
882 void UniqueIDBDatabase::performCountCallback(uint64_t callbackIdentifier, const IDBError& error, uint64_t count)
883 {
884     auto callback = m_countCallbacks.take(callbackIdentifier);
885     ASSERT(callback);
886     callback(error, count);
887 }
888
889 } // namespace IDBServer
890 } // namespace WebCore
891
892 #endif // ENABLE(INDEXED_DATABASE)