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