1/*
2 * Copyright (C) 2013 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) && ENABLE(DATABASE_PROCESS)
30
31#include "AsyncRequest.h"
32#include "AsyncTask.h"
33#include "DataReference.h"
34#include "DatabaseProcess.h"
35#include "DatabaseProcessIDBConnection.h"
36#include "Logging.h"
37#include "UniqueIDBDatabaseBackingStoreSQLite.h"
38#include "WebCrossThreadCopier.h"
39#include <WebCore/FileSystem.h>
40#include <WebCore/IDBDatabaseMetadata.h>
41#include <WebCore/IDBGetResult.h>
42#include <WebCore/IDBKeyData.h>
43#include <WebCore/IDBKeyRangeData.h>
44#include <wtf/MainThread.h>
45#include <wtf/text/WTFString.h>
46
47using namespace WebCore;
48
49namespace WebKit {
50
51String UniqueIDBDatabase::calculateAbsoluteDatabaseFilename(const String& absoluteDatabaseDirectory)
52{
53    return pathByAppendingComponent(absoluteDatabaseDirectory, "IndexedDB.sqlite3");
54}
55
56UniqueIDBDatabase::UniqueIDBDatabase(const UniqueIDBDatabaseIdentifier& identifier)
57    : m_identifier(identifier)
58    , m_acceptingNewRequests(true)
59    , m_didGetMetadataFromBackingStore(false)
60{
61    m_inMemory = !canShareDatabases(identifier.openingOrigin(), identifier.mainFrameOrigin());
62    if (m_inMemory)
63        return;
64
65    // *********
66    // IMPORTANT: Do not change the directory structure for indexed databases on disk without first consulting a reviewer from Apple (<rdar://problem/17454712>)
67    // *********
68
69    // Each unique Indexed Database exists in a directory named for the database, which exists in a directory representing its opening origin.
70    m_databaseRelativeDirectory = pathByAppendingComponent(databaseFilenameIdentifier(identifier.openingOrigin()), filenameForDatabaseName());
71
72    DatabaseProcess::shared().ensureIndexedDatabaseRelativePathExists(m_databaseRelativeDirectory);
73}
74
75UniqueIDBDatabase::~UniqueIDBDatabase()
76{
77    ASSERT(!m_acceptingNewRequests);
78    ASSERT(m_pendingMetadataRequests.isEmpty());
79}
80
81String UniqueIDBDatabase::filenameForDatabaseName() const
82{
83    ASSERT(!m_identifier.databaseName().isNull());
84
85    if (m_identifier.databaseName().isEmpty())
86        return "%00";
87
88    String filename = encodeForFileName(m_identifier.databaseName());
89    filename.replace('.', "%2E");
90
91    return filename;
92}
93
94String UniqueIDBDatabase::databaseFilenameIdentifier(const SecurityOriginData& originData) const
95{
96    RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::create(originData.protocol, originData.host, originData.port);
97    return securityOrigin->databaseIdentifier();
98}
99
100bool UniqueIDBDatabase::canShareDatabases(const SecurityOriginData& openingOrigin, const SecurityOriginData& mainFrameOrigin) const
101{
102    // For now, an origin's database access is predicated on equality with the other origin.
103    // We might need to make this more nuanced later.
104    return openingOrigin == mainFrameOrigin;
105}
106
107void UniqueIDBDatabase::registerConnection(DatabaseProcessIDBConnection& connection)
108{
109    ASSERT(!m_connections.contains(&connection));
110    m_connections.add(&connection);
111}
112
113void UniqueIDBDatabase::unregisterConnection(DatabaseProcessIDBConnection& connection)
114{
115    ASSERT(m_connections.contains(&connection));
116    resetAllTransactions(connection);
117    m_connections.remove(&connection);
118
119    if (m_connections.isEmpty() && m_pendingTransactionRollbacks.isEmpty()) {
120        shutdown(UniqueIDBDatabaseShutdownType::NormalShutdown);
121        DatabaseProcess::shared().removeUniqueIDBDatabase(*this);
122    }
123}
124
125void UniqueIDBDatabase::shutdown(UniqueIDBDatabaseShutdownType type)
126{
127    ASSERT(RunLoop::isMain());
128
129    if (!m_acceptingNewRequests)
130        return;
131
132    m_acceptingNewRequests = false;
133
134    // Balanced by an adoptRef in ::didShutdownBackingStore()
135    ref();
136
137    {
138        MutexLocker locker(m_databaseTaskMutex);
139        m_databaseTasks.clear();
140    }
141
142    postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::shutdownBackingStore, type, absoluteDatabaseDirectory()), DatabaseTaskType::Shutdown);
143}
144
145void UniqueIDBDatabase::shutdownBackingStore(UniqueIDBDatabaseShutdownType type, const String& databaseDirectory)
146{
147    ASSERT(!RunLoop::isMain());
148
149    m_backingStore.clear();
150
151    if (type == UniqueIDBDatabaseShutdownType::DeleteShutdown) {
152        String dbFilename = UniqueIDBDatabase::calculateAbsoluteDatabaseFilename(databaseDirectory);
153        LOG(IDB, "UniqueIDBDatabase::shutdownBackingStore deleting file '%s' on disk", dbFilename.utf8().data());
154        deleteFile(dbFilename);
155        deleteEmptyDirectory(databaseDirectory);
156    }
157
158    postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didShutdownBackingStore, type), DatabaseTaskType::Shutdown);
159}
160
161void UniqueIDBDatabase::didShutdownBackingStore(UniqueIDBDatabaseShutdownType type)
162{
163    ASSERT(RunLoop::isMain());
164
165    // Balanced by a ref in ::shutdown()
166    RefPtr<UniqueIDBDatabase> protector(adoptRef(this));
167
168    // Empty out remaining main thread tasks.
169    while (performNextMainThreadTaskWithoutAdoptRef()) {
170    }
171
172    // No more requests will be handled, so abort all outstanding requests.
173    for (const auto& it : m_pendingMetadataRequests)
174        it->requestAborted();
175    for (const auto& it : m_pendingTransactionRequests)
176        it.value->requestAborted();
177    for (const auto& it : m_pendingDatabaseTasks)
178        it.value->requestAborted();
179
180    m_pendingMetadataRequests.clear();
181    m_pendingTransactionRequests.clear();
182    m_pendingDatabaseTasks.clear();
183
184    if (m_pendingShutdownTask)
185        m_pendingShutdownTask->completeRequest(type);
186
187    m_pendingShutdownTask = nullptr;
188}
189
190void UniqueIDBDatabase::deleteDatabase(std::function<void(bool)> successCallback)
191{
192    ASSERT(RunLoop::isMain());
193
194    if (!m_acceptingNewRequests) {
195        // Someone else has already shutdown this database, so we can't request a delete.
196        callOnMainThread([successCallback]() {
197            successCallback(false);
198        });
199        return;
200    }
201
202    RefPtr<UniqueIDBDatabase> protector(this);
203    m_pendingShutdownTask = AsyncRequestImpl<UniqueIDBDatabaseShutdownType>::create([this, protector, successCallback](UniqueIDBDatabaseShutdownType type) {
204        // If the shutdown just completed was a Delete shutdown then we succeeded.
205        // If not report failure instead of trying again.
206        successCallback(type == UniqueIDBDatabaseShutdownType::DeleteShutdown);
207    }, [this, protector, successCallback]() {
208        successCallback(false);
209    });
210
211    shutdown(UniqueIDBDatabaseShutdownType::DeleteShutdown);
212}
213
214void UniqueIDBDatabase::getOrEstablishIDBDatabaseMetadata(std::function<void(bool, const IDBDatabaseMetadata&)> completionCallback)
215{
216    ASSERT(RunLoop::isMain());
217
218    if (!m_acceptingNewRequests) {
219        completionCallback(false, IDBDatabaseMetadata());
220        return;
221    }
222
223    // If we've already retrieved metadata from the backing store, return it now.
224    if (m_didGetMetadataFromBackingStore) {
225        if (m_metadata)
226            completionCallback(true, *m_metadata);
227        else
228            completionCallback(false, IDBDatabaseMetadata());
229
230        return;
231    }
232
233    // If this is the first unanswered metadata request, then later we need to
234    // post a task to open the backing store and get metadata.
235    bool shouldOpenBackingStore = m_pendingMetadataRequests.isEmpty();
236
237    // Then remember this metadata request to be answered later.
238    RefPtr<AsyncRequest> request = AsyncRequestImpl<>::create([completionCallback, this]() {
239        completionCallback(!!m_metadata, m_metadata ? *m_metadata : IDBDatabaseMetadata());
240    }, [completionCallback]() {
241        // The boolean flag to the completion callback represents whether the
242        // attempt to get/establish metadata succeeded or failed.
243        // Since we're aborting the attempt, it failed, so we always pass in false.
244        completionCallback(false, IDBDatabaseMetadata());
245    });
246
247    m_pendingMetadataRequests.append(request.release());
248
249    if (shouldOpenBackingStore)
250        postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::openBackingStoreAndReadMetadata, m_identifier, absoluteDatabaseDirectory()));
251}
252
253void UniqueIDBDatabase::openBackingStoreAndReadMetadata(const UniqueIDBDatabaseIdentifier& identifier, const String& databaseDirectory)
254{
255    ASSERT(!RunLoop::isMain());
256    ASSERT(!m_backingStore);
257
258    if (m_inMemory) {
259        LOG_ERROR("Support for in-memory databases not yet implemented");
260        return;
261    }
262
263    m_backingStore = UniqueIDBDatabaseBackingStoreSQLite::create(identifier, databaseDirectory);
264    std::unique_ptr<IDBDatabaseMetadata> metadata = m_backingStore->getOrEstablishMetadata();
265
266    postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didOpenBackingStoreAndReadMetadata, metadata ? *metadata : IDBDatabaseMetadata(), !!metadata));
267}
268
269void UniqueIDBDatabase::didOpenBackingStoreAndReadMetadata(const IDBDatabaseMetadata& metadata, bool success)
270{
271    ASSERT(RunLoop::isMain());
272    ASSERT(!m_metadata);
273
274    m_didGetMetadataFromBackingStore = true;
275
276    if (success)
277        m_metadata = std::make_unique<IDBDatabaseMetadata>(metadata);
278
279    while (!m_pendingMetadataRequests.isEmpty()) {
280        RefPtr<AsyncRequest> request = m_pendingMetadataRequests.takeFirst();
281        request->completeRequest();
282    }
283}
284
285void UniqueIDBDatabase::openTransaction(const IDBIdentifier& transactionIdentifier, const Vector<int64_t>& objectStoreIDs, IndexedDB::TransactionMode mode, std::function<void(bool)> successCallback)
286{
287    postTransactionOperation(transactionIdentifier, createAsyncTask(*this, &UniqueIDBDatabase::openBackingStoreTransaction, transactionIdentifier, objectStoreIDs, mode), successCallback);
288}
289
290void UniqueIDBDatabase::beginTransaction(const IDBIdentifier& transactionIdentifier, std::function<void(bool)> successCallback)
291{
292    postTransactionOperation(transactionIdentifier, createAsyncTask(*this, &UniqueIDBDatabase::beginBackingStoreTransaction, transactionIdentifier), successCallback);
293}
294
295void UniqueIDBDatabase::commitTransaction(const IDBIdentifier& transactionIdentifier, std::function<void(bool)> successCallback)
296{
297    postTransactionOperation(transactionIdentifier, createAsyncTask(*this, &UniqueIDBDatabase::commitBackingStoreTransaction, transactionIdentifier), successCallback);
298}
299
300void UniqueIDBDatabase::resetTransaction(const IDBIdentifier& transactionIdentifier, std::function<void(bool)> successCallback)
301{
302    postTransactionOperation(transactionIdentifier, createAsyncTask(*this, &UniqueIDBDatabase::resetBackingStoreTransaction, transactionIdentifier), successCallback);
303}
304
305void UniqueIDBDatabase::rollbackTransaction(const IDBIdentifier& transactionIdentifier, std::function<void(bool)> successCallback)
306{
307    postTransactionOperation(transactionIdentifier, createAsyncTask(*this, &UniqueIDBDatabase::rollbackBackingStoreTransaction, transactionIdentifier), successCallback);
308}
309
310void UniqueIDBDatabase::postTransactionOperation(const IDBIdentifier& transactionIdentifier, std::unique_ptr<AsyncTask> task, std::function<void(bool)> successCallback)
311{
312    ASSERT(RunLoop::isMain());
313
314    if (!m_acceptingNewRequests) {
315        successCallback(false);
316        return;
317    }
318
319    if (m_pendingTransactionRequests.contains(transactionIdentifier)) {
320        LOG_ERROR("Attempting to queue an operation for a transaction that already has an operation pending. Each transaction should only have one operation pending at a time.");
321        successCallback(false);
322        return;
323    }
324
325    postDatabaseTask(WTF::move(task));
326
327    RefPtr<AsyncRequest> request = AsyncRequestImpl<bool>::create([successCallback](bool success) {
328        successCallback(success);
329    }, [successCallback]() {
330        successCallback(false);
331    });
332
333    m_pendingTransactionRequests.add(transactionIdentifier, request.release());
334}
335
336void UniqueIDBDatabase::didCompleteTransactionOperation(const IDBIdentifier& transactionIdentifier, bool success)
337{
338    ASSERT(RunLoop::isMain());
339
340    RefPtr<AsyncRequest> request = m_pendingTransactionRequests.take(transactionIdentifier);
341
342    if (request)
343        request->completeRequest(success);
344
345    if (m_pendingTransactionRollbacks.contains(transactionIdentifier))
346        finalizeRollback(transactionIdentifier);
347}
348
349void UniqueIDBDatabase::changeDatabaseVersion(const IDBIdentifier& transactionIdentifier, uint64_t newVersion, std::function<void(bool)> successCallback)
350{
351    ASSERT(RunLoop::isMain());
352
353    if (!m_acceptingNewRequests) {
354        successCallback(false);
355        return;
356    }
357
358    uint64_t oldVersion = m_metadata->version;
359    m_metadata->version = newVersion;
360
361    RefPtr<AsyncRequest> request = AsyncRequestImpl<bool>::create([this, oldVersion, successCallback](bool success) {
362        if (!success)
363            m_metadata->version = oldVersion;
364        successCallback(success);
365    }, [this, oldVersion, successCallback]() {
366        m_metadata->version = oldVersion;
367        successCallback(false);
368    });
369
370    uint64_t requestID = request->requestID();
371    m_pendingDatabaseTasks.add(requestID, request.release());
372
373    postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::changeDatabaseVersionInBackingStore, requestID, transactionIdentifier, newVersion));
374}
375
376void UniqueIDBDatabase::didChangeDatabaseVersion(uint64_t requestID, bool success)
377{
378    didCompleteBoolRequest(requestID, success);
379}
380
381void UniqueIDBDatabase::didCreateObjectStore(uint64_t requestID, bool success)
382{
383    didCompleteBoolRequest(requestID, success);
384}
385
386void UniqueIDBDatabase::didDeleteObjectStore(uint64_t requestID, bool success)
387{
388    didCompleteBoolRequest(requestID, success);
389}
390
391void UniqueIDBDatabase::didClearObjectStore(uint64_t requestID, bool success)
392{
393    didCompleteBoolRequest(requestID, success);
394}
395
396void UniqueIDBDatabase::didCreateIndex(uint64_t requestID, bool success)
397{
398    didCompleteBoolRequest(requestID, success);
399}
400
401void UniqueIDBDatabase::didDeleteIndex(uint64_t requestID, bool success)
402{
403    didCompleteBoolRequest(requestID, success);
404}
405
406void UniqueIDBDatabase::didCompleteBoolRequest(uint64_t requestID, bool success)
407{
408    RefPtr<AsyncRequest> request = m_pendingDatabaseTasks.take(requestID);
409    ASSERT(request);
410
411    request->completeRequest(success);
412}
413
414void UniqueIDBDatabase::createObjectStore(const IDBIdentifier& transactionIdentifier, const IDBObjectStoreMetadata& metadata, std::function<void(bool)> successCallback)
415{
416    ASSERT(RunLoop::isMain());
417
418    if (!m_acceptingNewRequests) {
419        successCallback(false);
420        return;
421    }
422
423    ASSERT(!m_metadata->objectStores.contains(metadata.id));
424    m_metadata->objectStores.set(metadata.id, metadata);
425    int64_t addedObjectStoreID = metadata.id;
426
427    RefPtr<AsyncRequest> request = AsyncRequestImpl<bool>::create([this, addedObjectStoreID, successCallback](bool success) {
428        if (!success)
429            m_metadata->objectStores.remove(addedObjectStoreID);
430        successCallback(success);
431    }, [this, addedObjectStoreID, successCallback]() {
432        m_metadata->objectStores.remove(addedObjectStoreID);
433        successCallback(false);
434    });
435
436    uint64_t requestID = request->requestID();
437    m_pendingDatabaseTasks.add(requestID, request.release());
438
439    postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::createObjectStoreInBackingStore, requestID, transactionIdentifier, metadata));
440}
441
442void UniqueIDBDatabase::deleteObjectStore(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, std::function<void(bool)> successCallback)
443{
444    ASSERT(RunLoop::isMain());
445
446    if (!m_acceptingNewRequests) {
447        successCallback(false);
448        return;
449    }
450
451    ASSERT(m_metadata->objectStores.contains(objectStoreID));
452    IDBObjectStoreMetadata metadata = m_metadata->objectStores.take(objectStoreID);
453
454    RefPtr<AsyncRequest> request = AsyncRequestImpl<bool>::create([this, metadata, successCallback](bool success) {
455        if (!success)
456            m_metadata->objectStores.set(metadata.id, metadata);
457        successCallback(success);
458    }, [this, metadata, successCallback]() {
459        m_metadata->objectStores.set(metadata.id, metadata);
460        successCallback(false);
461    });
462
463    uint64_t requestID = request->requestID();
464    m_pendingDatabaseTasks.add(requestID, request.release());
465
466    postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::deleteObjectStoreInBackingStore, requestID, transactionIdentifier, objectStoreID));
467}
468
469void UniqueIDBDatabase::clearObjectStore(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, std::function<void(bool)> successCallback)
470{
471    ASSERT(RunLoop::isMain());
472
473    if (!m_acceptingNewRequests) {
474        successCallback(false);
475        return;
476    }
477
478    ASSERT(m_metadata->objectStores.contains(objectStoreID));
479
480    RefPtr<AsyncRequest> request = AsyncRequestImpl<bool>::create([this, successCallback](bool success) {
481        successCallback(success);
482    }, [this, successCallback]() {
483        successCallback(false);
484    });
485
486    uint64_t requestID = request->requestID();
487    m_pendingDatabaseTasks.add(requestID, request.release());
488
489    postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::clearObjectStoreInBackingStore, requestID, transactionIdentifier, objectStoreID));
490}
491
492void UniqueIDBDatabase::createIndex(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, const IDBIndexMetadata& metadata, std::function<void(bool)> successCallback)
493{
494    ASSERT(RunLoop::isMain());
495
496    if (!m_acceptingNewRequests) {
497        successCallback(false);
498        return;
499    }
500
501    ASSERT(m_metadata->objectStores.contains(objectStoreID));
502    ASSERT(!m_metadata->objectStores.get(objectStoreID).indexes.contains(metadata.id));
503    m_metadata->objectStores.get(objectStoreID).indexes.set(metadata.id, metadata);
504    int64_t addedIndexID = metadata.id;
505
506    RefPtr<AsyncRequest> request = AsyncRequestImpl<bool>::create([this, objectStoreID, addedIndexID, successCallback](bool success) {
507        if (!success) {
508            auto objectStoreFind = m_metadata->objectStores.find(objectStoreID);
509            if (objectStoreFind != m_metadata->objectStores.end())
510                objectStoreFind->value.indexes.remove(addedIndexID);
511        }
512        successCallback(success);
513    }, [this, objectStoreID, addedIndexID, successCallback]() {
514        auto objectStoreFind = m_metadata->objectStores.find(objectStoreID);
515        if (objectStoreFind != m_metadata->objectStores.end())
516            objectStoreFind->value.indexes.remove(addedIndexID);
517        successCallback(false);
518    });
519
520    uint64_t requestID = request->requestID();
521    m_pendingDatabaseTasks.add(requestID, request.release());
522
523    postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::createIndexInBackingStore, requestID, transactionIdentifier, objectStoreID, metadata));
524}
525
526void UniqueIDBDatabase::deleteIndex(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, int64_t indexID, std::function<void(bool)> successCallback)
527{
528    ASSERT(RunLoop::isMain());
529
530    if (!m_acceptingNewRequests) {
531        successCallback(false);
532        return;
533    }
534
535    ASSERT(m_metadata->objectStores.contains(objectStoreID));
536    ASSERT(m_metadata->objectStores.get(objectStoreID).indexes.contains(indexID));
537
538    IDBIndexMetadata metadata = m_metadata->objectStores.get(objectStoreID).indexes.take(indexID);
539
540    RefPtr<AsyncRequest> request = AsyncRequestImpl<bool>::create([this, objectStoreID, metadata, successCallback](bool success) {
541        if (!success) {
542            auto objectStoreFind = m_metadata->objectStores.find(objectStoreID);
543            if (objectStoreFind != m_metadata->objectStores.end())
544                objectStoreFind->value.indexes.set(metadata.id, metadata);
545        }
546        successCallback(success);
547    }, [this, objectStoreID, metadata, successCallback]() {
548        auto objectStoreFind = m_metadata->objectStores.find(objectStoreID);
549        if (objectStoreFind != m_metadata->objectStores.end())
550            objectStoreFind->value.indexes.set(metadata.id, metadata);
551        successCallback(false);
552    });
553
554    uint64_t requestID = request->requestID();
555    m_pendingDatabaseTasks.add(requestID, request.release());
556
557    postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::deleteIndexInBackingStore, requestID, transactionIdentifier, objectStoreID, indexID));
558}
559
560void UniqueIDBDatabase::putRecord(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, const IDBKeyData& keyData, const IPC::DataReference& value, int64_t putMode, const Vector<int64_t>& indexIDs, const Vector<Vector<IDBKeyData>>& indexKeys, std::function<void(const IDBKeyData&, uint32_t, const String&)> callback)
561{
562    ASSERT(RunLoop::isMain());
563
564    if (!m_acceptingNewRequests) {
565        callback(IDBKeyData(), INVALID_STATE_ERR, "Unable to put record into database because it has shut down");
566        return;
567    }
568
569    ASSERT(m_metadata->objectStores.contains(objectStoreID));
570
571    RefPtr<AsyncRequest> request = AsyncRequestImpl<const IDBKeyData&, uint32_t, const String&>::create([this, callback](const IDBKeyData& keyData, uint32_t errorCode, const String& errorMessage) {
572        callback(keyData, errorCode, errorMessage);
573    }, [this, callback]() {
574        callback(IDBKeyData(), INVALID_STATE_ERR, "Unable to put record into database");
575    });
576
577    uint64_t requestID = request->requestID();
578    m_pendingDatabaseTasks.add(requestID, request.release());
579
580    postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::putRecordInBackingStore, requestID, transactionIdentifier, m_metadata->objectStores.get(objectStoreID), keyData, value.vector(), putMode, indexIDs, indexKeys));
581}
582
583void UniqueIDBDatabase::getRecord(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, int64_t indexID, const IDBKeyRangeData& keyRangeData, IndexedDB::CursorType cursorType, std::function<void(const IDBGetResult&, uint32_t, const String&)> callback)
584{
585    ASSERT(RunLoop::isMain());
586
587    if (!m_acceptingNewRequests) {
588        callback(IDBGetResult(), INVALID_STATE_ERR, "Unable to get record from database because it has shut down");
589        return;
590    }
591
592    ASSERT(m_metadata->objectStores.contains(objectStoreID));
593
594    RefPtr<AsyncRequest> request = AsyncRequestImpl<const IDBGetResult&, uint32_t, const String&>::create([this, callback](const IDBGetResult& result, uint32_t errorCode, const String& errorMessage) {
595        callback(result, errorCode, errorMessage);
596    }, [this, callback]() {
597        callback(IDBGetResult(), INVALID_STATE_ERR, "Unable to get record from database");
598    });
599
600    uint64_t requestID = request->requestID();
601    m_pendingDatabaseTasks.add(requestID, request.release());
602
603    postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::getRecordFromBackingStore, requestID, transactionIdentifier, m_metadata->objectStores.get(objectStoreID), indexID, keyRangeData, cursorType));
604}
605
606void UniqueIDBDatabase::openCursor(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, int64_t indexID, IndexedDB::CursorDirection cursorDirection, IndexedDB::CursorType cursorType, IDBDatabaseBackend::TaskType taskType, const IDBKeyRangeData& keyRangeData, std::function<void(int64_t, const IDBKeyData&, const IDBKeyData&, PassRefPtr<SharedBuffer>, uint32_t, const String&)> callback)
607{
608    ASSERT(RunLoop::isMain());
609
610    if (!m_acceptingNewRequests) {
611        callback(0, nullptr, nullptr, nullptr, INVALID_STATE_ERR, "Unable to open cursor in database because it has shut down");
612        return;
613    }
614
615    ASSERT(m_metadata->objectStores.contains(objectStoreID));
616
617    RefPtr<AsyncRequest> request = AsyncRequestImpl<int64_t, const IDBKeyData&, const IDBKeyData&, PassRefPtr<SharedBuffer>, uint32_t, const String&>::create([this, callback](int64_t cursorID, const IDBKeyData& key, const IDBKeyData& primaryKey, PassRefPtr<SharedBuffer> value, uint32_t errorCode, const String& errorMessage) {
618        callback(cursorID, key, primaryKey, value, errorCode, errorMessage);
619    }, [this, callback]() {
620        callback(0, nullptr, nullptr, nullptr, INVALID_STATE_ERR, "Unable to get record from database");
621    });
622
623    uint64_t requestID = request->requestID();
624    m_pendingDatabaseTasks.add(requestID, request.release());
625
626    postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::openCursorInBackingStore, requestID, transactionIdentifier, objectStoreID, indexID, cursorDirection, cursorType, taskType, keyRangeData));
627}
628
629void UniqueIDBDatabase::cursorAdvance(const IDBIdentifier& cursorIdentifier, uint64_t count, std::function<void(const IDBKeyData&, const IDBKeyData&, PassRefPtr<SharedBuffer>, uint32_t, const String&)> callback)
630{
631    ASSERT(RunLoop::isMain());
632
633    if (!m_acceptingNewRequests) {
634        callback(nullptr, nullptr, nullptr, INVALID_STATE_ERR, "Unable to advance cursor in database because it has shut down");
635        return;
636    }
637
638    RefPtr<AsyncRequest> request = AsyncRequestImpl<const IDBKeyData&, const IDBKeyData&, PassRefPtr<SharedBuffer>, uint32_t, const String&>::create([this, callback](const IDBKeyData& key, const IDBKeyData& primaryKey, PassRefPtr<SharedBuffer> value, uint32_t errorCode, const String& errorMessage) {
639        callback(key, primaryKey, value, errorCode, errorMessage);
640    }, [this, callback]() {
641        callback(nullptr, nullptr, nullptr, INVALID_STATE_ERR, "Unable to advance cursor in database");
642    });
643
644    uint64_t requestID = request->requestID();
645    m_pendingDatabaseTasks.add(requestID, request.release());
646
647    postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::advanceCursorInBackingStore, requestID, cursorIdentifier, count));
648}
649
650void UniqueIDBDatabase::cursorIterate(const IDBIdentifier& cursorIdentifier, const IDBKeyData& key, std::function<void(const IDBKeyData&, const IDBKeyData&, PassRefPtr<SharedBuffer>, uint32_t, const String&)> callback)
651{
652    ASSERT(RunLoop::isMain());
653
654    if (!m_acceptingNewRequests) {
655        callback(nullptr, nullptr, nullptr, INVALID_STATE_ERR, "Unable to iterate cursor in database because it has shut down");
656        return;
657    }
658
659    RefPtr<AsyncRequest> request = AsyncRequestImpl<const IDBKeyData&, const IDBKeyData&, PassRefPtr<SharedBuffer>, uint32_t, const String&>::create([this, callback](const IDBKeyData& key, const IDBKeyData& primaryKey, PassRefPtr<SharedBuffer> value, uint32_t errorCode, const String& errorMessage) {
660        callback(key, primaryKey, value, errorCode, errorMessage);
661    }, [this, callback]() {
662        callback(nullptr, nullptr, nullptr, INVALID_STATE_ERR, "Unable to iterate cursor in database");
663    });
664
665    uint64_t requestID = request->requestID();
666    m_pendingDatabaseTasks.add(requestID, request.release());
667
668    postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::iterateCursorInBackingStore, requestID, cursorIdentifier, key));
669}
670
671void UniqueIDBDatabase::count(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, int64_t indexID, const IDBKeyRangeData& keyRangeData, std::function<void(int64_t, uint32_t, const String&)> callback)
672{
673    ASSERT(RunLoop::isMain());
674
675    if (!m_acceptingNewRequests) {
676        callback(0, INVALID_STATE_ERR, "Unable to get count from database because it has shut down");
677        return;
678    }
679
680    RefPtr<AsyncRequest> request = AsyncRequestImpl<int64_t, uint32_t, const String&>::create([this, callback](int64_t count, uint32_t errorCode, const String& errorMessage) {
681        callback(count, errorCode, errorMessage);
682    }, [this, callback]() {
683        callback(0, INVALID_STATE_ERR, "Unable to get count from database");
684    });
685
686    uint64_t requestID = request->requestID();
687    m_pendingDatabaseTasks.add(requestID, request.release());
688
689    postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::countInBackingStore, requestID, transactionIdentifier, objectStoreID, indexID, keyRangeData));
690}
691
692void UniqueIDBDatabase::deleteRange(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, const IDBKeyRangeData& keyRangeData, std::function<void(uint32_t, const String&)> callback)
693{
694    ASSERT(RunLoop::isMain());
695
696    if (!m_acceptingNewRequests) {
697        callback(INVALID_STATE_ERR, "Unable to deleteRange from database because it has shut down");
698        return;
699    }
700
701    RefPtr<AsyncRequest> request = AsyncRequestImpl<uint32_t, const String&>::create([callback](uint32_t errorCode, const String& errorMessage) {
702        callback(errorCode, errorMessage);
703    }, [callback]() {
704        callback(INVALID_STATE_ERR, "Unable to deleteRange from database");
705    });
706
707    uint64_t requestID = request->requestID();
708    m_pendingDatabaseTasks.add(requestID, request.release());
709
710    postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::deleteRangeInBackingStore, requestID, transactionIdentifier, objectStoreID, keyRangeData));
711}
712
713void UniqueIDBDatabase::openBackingStoreTransaction(const IDBIdentifier& transactionIdentifier, const Vector<int64_t>& objectStoreIDs, IndexedDB::TransactionMode mode)
714{
715    ASSERT(!RunLoop::isMain());
716    ASSERT(m_backingStore);
717
718    bool success = m_backingStore->establishTransaction(transactionIdentifier, objectStoreIDs, mode);
719
720    postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didEstablishTransaction, transactionIdentifier, success));
721    postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCompleteTransactionOperation, transactionIdentifier, success));
722}
723
724void UniqueIDBDatabase::beginBackingStoreTransaction(const IDBIdentifier& transactionIdentifier)
725{
726    ASSERT(!RunLoop::isMain());
727    ASSERT(m_backingStore);
728
729    bool success = m_backingStore->beginTransaction(transactionIdentifier);
730
731    postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCompleteTransactionOperation, transactionIdentifier, success));
732}
733
734void UniqueIDBDatabase::commitBackingStoreTransaction(const IDBIdentifier& transactionIdentifier)
735{
736    ASSERT(!RunLoop::isMain());
737    ASSERT(m_backingStore);
738
739    bool success = m_backingStore->commitTransaction(transactionIdentifier);
740
741    postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCompleteTransactionOperation, transactionIdentifier, success));
742}
743
744void UniqueIDBDatabase::resetBackingStoreTransaction(const IDBIdentifier& transactionIdentifier)
745{
746    ASSERT(!RunLoop::isMain());
747    ASSERT(m_backingStore);
748
749    bool success = m_backingStore->resetTransaction(transactionIdentifier);
750
751    postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didResetTransaction, transactionIdentifier, success));
752    postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCompleteTransactionOperation, transactionIdentifier, success));
753}
754
755void UniqueIDBDatabase::rollbackBackingStoreTransaction(const IDBIdentifier& transactionIdentifier)
756{
757    ASSERT(!RunLoop::isMain());
758    ASSERT(m_backingStore);
759
760    bool success = m_backingStore->rollbackTransaction(transactionIdentifier);
761
762    postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCompleteTransactionOperation, transactionIdentifier, success));
763}
764
765void UniqueIDBDatabase::changeDatabaseVersionInBackingStore(uint64_t requestID, const IDBIdentifier& transactionIdentifier, uint64_t newVersion)
766{
767    ASSERT(!RunLoop::isMain());
768    ASSERT(m_backingStore);
769
770    bool success = m_backingStore->changeDatabaseVersion(transactionIdentifier, newVersion);
771
772    postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didChangeDatabaseVersion, requestID, success));
773}
774
775void UniqueIDBDatabase::createObjectStoreInBackingStore(uint64_t requestID, const IDBIdentifier& transactionIdentifier, const IDBObjectStoreMetadata& metadata)
776{
777    ASSERT(!RunLoop::isMain());
778    ASSERT(m_backingStore);
779
780    bool success = m_backingStore->createObjectStore(transactionIdentifier, metadata);
781
782    postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCreateObjectStore, requestID, success));
783}
784
785void UniqueIDBDatabase::deleteObjectStoreInBackingStore(uint64_t requestID, const IDBIdentifier& transactionIdentifier, int64_t objectStoreID)
786{
787    ASSERT(!RunLoop::isMain());
788    ASSERT(m_backingStore);
789
790    bool success = m_backingStore->deleteObjectStore(transactionIdentifier, objectStoreID);
791
792    postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didDeleteObjectStore, requestID, success));
793}
794
795void UniqueIDBDatabase::clearObjectStoreInBackingStore(uint64_t requestID, const IDBIdentifier& transactionIdentifier, int64_t objectStoreID)
796{
797    ASSERT(!RunLoop::isMain());
798    ASSERT(m_backingStore);
799
800    bool success = m_backingStore->clearObjectStore(transactionIdentifier, objectStoreID);
801
802    postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didClearObjectStore, requestID, success));
803}
804
805void UniqueIDBDatabase::createIndexInBackingStore(uint64_t requestID, const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, const IDBIndexMetadata& metadata)
806{
807    ASSERT(!RunLoop::isMain());
808    ASSERT(m_backingStore);
809
810    bool success = m_backingStore->createIndex(transactionIdentifier, objectStoreID, metadata);
811
812    postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCreateIndex, requestID, success));
813}
814
815void UniqueIDBDatabase::deleteIndexInBackingStore(uint64_t requestID, const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, int64_t indexID)
816{
817    ASSERT(!RunLoop::isMain());
818    ASSERT(m_backingStore);
819
820    bool success = m_backingStore->deleteIndex(transactionIdentifier, objectStoreID, indexID);
821
822    postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didDeleteIndex, requestID, success));
823}
824
825void UniqueIDBDatabase::putRecordInBackingStore(uint64_t requestID, const IDBIdentifier& transaction, const IDBObjectStoreMetadata& objectStoreMetadata, const IDBKeyData& inputKeyData, const Vector<uint8_t>& value, int64_t putMode, const Vector<int64_t>& indexIDs, const Vector<Vector<IDBKeyData>>& indexKeys)
826{
827    ASSERT(!RunLoop::isMain());
828    ASSERT(m_backingStore);
829
830    bool keyWasGenerated = false;
831    IDBKeyData key;
832    int64_t keyNumber = 0;
833
834    if (putMode != IDBDatabaseBackend::CursorUpdate && objectStoreMetadata.autoIncrement && inputKeyData.isNull) {
835        if (!m_backingStore->generateKeyNumber(transaction, objectStoreMetadata.id, keyNumber)) {
836            postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didPutRecordInBackingStore, requestID, IDBKeyData(), IDBDatabaseException::UnknownError, ASCIILiteral("Internal backing store error checking for key existence")));
837            return;
838        }
839        key.setNumberValue(keyNumber);
840        keyWasGenerated = true;
841    } else
842        key = inputKeyData;
843
844    if (putMode == IDBDatabaseBackend::AddOnly) {
845        bool keyExists;
846        if (!m_backingStore->keyExistsInObjectStore(transaction, objectStoreMetadata.id, key, keyExists)) {
847            postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didPutRecordInBackingStore, requestID, IDBKeyData(), IDBDatabaseException::UnknownError, ASCIILiteral("Internal backing store error checking for key existence")));
848            return;
849        }
850        if (keyExists) {
851            postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didPutRecordInBackingStore, requestID, IDBKeyData(), IDBDatabaseException::ConstraintError, ASCIILiteral("Key already exists in the object store")));
852            return;
853        }
854    }
855
856    // The spec says that even if we're about to overwrite the record, perform the steps to delete it first.
857    // This is important because formally deleting it from from the object store also removes it from the appropriate indexes.
858    if (!m_backingStore->deleteRecord(transaction, objectStoreMetadata.id, key)) {
859        postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didPutRecordInBackingStore, requestID, IDBKeyData(), IDBDatabaseException::UnknownError, ASCIILiteral("Replacing an existing key in backing store, unable to delete previous record.")));
860        return;
861    }
862
863    if (!m_backingStore->putRecord(transaction, objectStoreMetadata.id, key, value.data(), value.size())) {
864        postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didPutRecordInBackingStore, requestID, IDBKeyData(), IDBDatabaseException::UnknownError, ASCIILiteral("Internal backing store error putting a record")));
865        return;
866    }
867
868    ASSERT(indexIDs.size() == indexKeys.size());
869    for (size_t i = 0; i < indexIDs.size(); ++i) {
870        for (size_t j = 0; j < indexKeys[i].size(); ++j) {
871            if (!m_backingStore->putIndexRecord(transaction, objectStoreMetadata.id, indexIDs[i], key, indexKeys[i][j])) {
872                postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didPutRecordInBackingStore, requestID, IDBKeyData(), IDBDatabaseException::UnknownError, ASCIILiteral("Internal backing store error writing index key")));
873                return;
874            }
875        }
876    }
877
878    m_backingStore->notifyCursorsOfChanges(transaction, objectStoreMetadata.id);
879
880    if (putMode != IDBDatabaseBackend::CursorUpdate && objectStoreMetadata.autoIncrement && key.type == IDBKey::NumberType) {
881        if (!m_backingStore->updateKeyGeneratorNumber(transaction, objectStoreMetadata.id, keyNumber, keyWasGenerated)) {
882            postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didPutRecordInBackingStore, requestID, IDBKeyData(), IDBDatabaseException::UnknownError, ASCIILiteral("Internal backing store error updating key generator")));
883            return;
884        }
885    }
886
887    postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didPutRecordInBackingStore, requestID, key, 0, String(StringImpl::empty())));
888}
889
890void UniqueIDBDatabase::didPutRecordInBackingStore(uint64_t requestID, const IDBKeyData& keyData, uint32_t errorCode, const String& errorMessage)
891{
892    RefPtr<AsyncRequest> request = m_pendingDatabaseTasks.take(requestID);
893    ASSERT(request);
894
895    request->completeRequest(keyData, errorCode, errorMessage);
896}
897
898void UniqueIDBDatabase::getRecordFromBackingStore(uint64_t requestID, const IDBIdentifier& transaction, const IDBObjectStoreMetadata& objectStoreMetadata, int64_t indexID, const IDBKeyRangeData& keyRangeData, IndexedDB::CursorType cursorType)
899{
900    ASSERT(!RunLoop::isMain());
901    ASSERT(m_backingStore);
902
903    RefPtr<IDBKeyRange> keyRange = keyRangeData.maybeCreateIDBKeyRange();
904    ASSERT(keyRange);
905    if (!keyRange) {
906        postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didGetRecordFromBackingStore, requestID, IDBGetResult(), IDBDatabaseException::UnknownError, ASCIILiteral("Invalid IDBKeyRange requested from backing store")));
907        return;
908    }
909
910    if (indexID == IDBIndexMetadata::InvalidId) {
911        // IDBObjectStore get record
912        RefPtr<SharedBuffer> result;
913
914        if (keyRange->isOnlyKey()) {
915            if (!m_backingStore->getKeyRecordFromObjectStore(transaction, objectStoreMetadata.id, *keyRange->lower(), result))
916                postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didGetRecordFromBackingStore, requestID, IDBGetResult(), IDBDatabaseException::UnknownError, ASCIILiteral("Failed to get key record from object store in backing store")));
917            else {
918                IDBGetResult getResult = result ? IDBGetResult(result.release(), keyRange->lower(), objectStoreMetadata.keyPath) : IDBGetResult();
919                postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didGetRecordFromBackingStore, requestID, getResult, 0, String(StringImpl::empty())));
920            }
921
922            return;
923        }
924
925        RefPtr<IDBKey> resultKey;
926
927        if (!m_backingStore->getKeyRangeRecordFromObjectStore(transaction, objectStoreMetadata.id, *keyRange, result, resultKey))
928            postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didGetRecordFromBackingStore, requestID, IDBGetResult(), IDBDatabaseException::UnknownError, ASCIILiteral("Failed to get key range record from object store in backing store")));
929        else {
930            IDBGetResult getResult = result ? IDBGetResult(result.release(), resultKey.release(), objectStoreMetadata.keyPath) : IDBGetResult();
931            postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didGetRecordFromBackingStore, requestID, getResult, 0, String(StringImpl::empty())));
932        }
933
934        return;
935    }
936
937    // IDBIndex get record
938
939    IDBGetResult result;
940    if (!m_backingStore->getIndexRecord(transaction, objectStoreMetadata.id, indexID, keyRangeData, cursorType, result)) {
941        postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didGetRecordFromBackingStore, requestID, IDBGetResult(), IDBDatabaseException::UnknownError, ASCIILiteral("Failed to get index record from backing store")));
942        return;
943    }
944
945    // We must return a key path to know how to inject the result key into the result value object.
946    result.keyPath = objectStoreMetadata.keyPath;
947
948    postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didGetRecordFromBackingStore, requestID, result, 0, String(StringImpl::empty())));
949}
950
951void UniqueIDBDatabase::didGetRecordFromBackingStore(uint64_t requestID, const IDBGetResult& result, uint32_t errorCode, const String& errorMessage)
952{
953    RefPtr<AsyncRequest> request = m_pendingDatabaseTasks.take(requestID);
954    ASSERT(request);
955
956    request->completeRequest(result, errorCode, errorMessage);
957}
958
959void UniqueIDBDatabase::openCursorInBackingStore(uint64_t requestID, const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, int64_t indexID, IndexedDB::CursorDirection cursorDirection, IndexedDB::CursorType cursorType, IDBDatabaseBackend::TaskType taskType, const IDBKeyRangeData& keyRange)
960{
961    ASSERT(!RunLoop::isMain());
962    ASSERT(m_backingStore);
963
964    int64_t cursorID = 0;
965    IDBKeyData key;
966    IDBKeyData primaryKey;
967    Vector<uint8_t> valueBuffer;
968    int32_t errorCode = 0;
969    String errorMessage;
970    bool success = m_backingStore->openCursor(transactionIdentifier, objectStoreID, indexID, cursorDirection, cursorType, taskType, keyRange, cursorID, key, primaryKey, valueBuffer);
971
972    if (!success) {
973        errorCode = IDBDatabaseException::UnknownError;
974        errorMessage = ASCIILiteral("Unknown error opening cursor in backing store");
975    }
976
977    postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didOpenCursorInBackingStore, requestID, cursorID, key, primaryKey, valueBuffer, errorCode, errorMessage));
978}
979
980void UniqueIDBDatabase::didOpenCursorInBackingStore(uint64_t requestID, int64_t cursorID, const IDBKeyData& key, const IDBKeyData& primaryKey, const Vector<uint8_t>& valueBuffer, uint32_t errorCode, const String& errorMessage)
981{
982    RefPtr<AsyncRequest> request = m_pendingDatabaseTasks.take(requestID);
983    ASSERT(request);
984
985    request->completeRequest(cursorID, key, primaryKey, SharedBuffer::create(valueBuffer.data(), valueBuffer.size()), errorCode, errorMessage);
986}
987
988void UniqueIDBDatabase::advanceCursorInBackingStore(uint64_t requestID, const IDBIdentifier& cursorIdentifier, uint64_t count)
989{
990    IDBKeyData key;
991    IDBKeyData primaryKey;
992    Vector<uint8_t> valueBuffer;
993    int32_t errorCode = 0;
994    String errorMessage;
995    bool success = m_backingStore->advanceCursor(cursorIdentifier, count, key, primaryKey, valueBuffer);
996
997    if (!success) {
998        errorCode = IDBDatabaseException::UnknownError;
999        errorMessage = ASCIILiteral("Unknown error advancing cursor in backing store");
1000    }
1001
1002    postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didAdvanceCursorInBackingStore, requestID, key, primaryKey, valueBuffer, errorCode, errorMessage));
1003}
1004
1005void UniqueIDBDatabase::didAdvanceCursorInBackingStore(uint64_t requestID, const IDBKeyData& key, const IDBKeyData& primaryKey, const Vector<uint8_t>& valueBuffer, uint32_t errorCode, const String& errorMessage)
1006{
1007    RefPtr<AsyncRequest> request = m_pendingDatabaseTasks.take(requestID);
1008    ASSERT(request);
1009
1010    request->completeRequest(key, primaryKey, SharedBuffer::create(valueBuffer.data(), valueBuffer.size()), errorCode, errorMessage);
1011}
1012
1013void UniqueIDBDatabase::iterateCursorInBackingStore(uint64_t requestID, const IDBIdentifier& cursorIdentifier, const IDBKeyData& iterateKey)
1014{
1015    IDBKeyData key;
1016    IDBKeyData primaryKey;
1017    Vector<uint8_t> valueBuffer;
1018    int32_t errorCode = 0;
1019    String errorMessage;
1020    bool success = m_backingStore->iterateCursor(cursorIdentifier, iterateKey, key, primaryKey, valueBuffer);
1021
1022    if (!success) {
1023        errorCode = IDBDatabaseException::UnknownError;
1024        errorMessage = ASCIILiteral("Unknown error iterating cursor in backing store");
1025    }
1026
1027    postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didIterateCursorInBackingStore, requestID, key, primaryKey, valueBuffer, errorCode, errorMessage));
1028}
1029
1030void UniqueIDBDatabase::didIterateCursorInBackingStore(uint64_t requestID, const IDBKeyData& key, const IDBKeyData& primaryKey, const Vector<uint8_t>& valueBuffer, uint32_t errorCode, const String& errorMessage)
1031{
1032    RefPtr<AsyncRequest> request = m_pendingDatabaseTasks.take(requestID);
1033    ASSERT(request);
1034
1035    request->completeRequest(key, primaryKey, SharedBuffer::create(valueBuffer.data(), valueBuffer.size()), errorCode, errorMessage);
1036}
1037
1038void UniqueIDBDatabase::countInBackingStore(uint64_t requestID, const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, int64_t indexID, const IDBKeyRangeData& keyRangeData)
1039{
1040    int64_t count;
1041
1042    if (!m_backingStore->count(transactionIdentifier, objectStoreID, indexID, keyRangeData, count)) {
1043        LOG_ERROR("Failed to get count from backing store.");
1044        postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCountInBackingStore, requestID, 0, IDBDatabaseException::UnknownError, ASCIILiteral("Failed to get count from backing store")));
1045    }
1046
1047    postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCountInBackingStore, requestID, count, 0, String(StringImpl::empty())));
1048}
1049
1050void UniqueIDBDatabase::didCountInBackingStore(uint64_t requestID, int64_t count, uint32_t errorCode, const String& errorMessage)
1051{
1052    RefPtr<AsyncRequest> request = m_pendingDatabaseTasks.take(requestID);
1053    ASSERT(request);
1054
1055    request->completeRequest(count, errorCode, errorMessage);
1056}
1057
1058void UniqueIDBDatabase::deleteRangeInBackingStore(uint64_t requestID, const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, const IDBKeyRangeData& keyRangeData)
1059{
1060    if (!m_backingStore->deleteRange(transactionIdentifier, objectStoreID, keyRangeData)) {
1061        LOG_ERROR("Failed to delete range from backing store.");
1062        postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didDeleteRangeInBackingStore, requestID, IDBDatabaseException::UnknownError, ASCIILiteral("Failed to get count from backing store")));
1063    }
1064
1065    m_backingStore->notifyCursorsOfChanges(transactionIdentifier, objectStoreID);
1066
1067    postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didDeleteRangeInBackingStore, requestID, 0, String(StringImpl::empty())));
1068}
1069
1070void UniqueIDBDatabase::didDeleteRangeInBackingStore(uint64_t requestID, uint32_t errorCode, const String& errorMessage)
1071{
1072    RefPtr<AsyncRequest> request = m_pendingDatabaseTasks.take(requestID);
1073    ASSERT(request);
1074
1075    request->completeRequest(errorCode, errorMessage);
1076}
1077
1078void UniqueIDBDatabase::didEstablishTransaction(const IDBIdentifier& transactionIdentifier, bool success)
1079{
1080    ASSERT(RunLoop::isMain());
1081    if (!success)
1082        return;
1083
1084    auto transactions = m_establishedTransactions.add(&transactionIdentifier.connection(), HashSet<IDBIdentifier>());
1085    transactions.iterator->value.add(transactionIdentifier);
1086}
1087
1088void UniqueIDBDatabase::didResetTransaction(const IDBIdentifier& transactionIdentifier, bool success)
1089{
1090    ASSERT(RunLoop::isMain());
1091    if (!success)
1092        return;
1093
1094    auto transactions = m_establishedTransactions.find(&transactionIdentifier.connection());
1095    if (transactions != m_establishedTransactions.end())
1096        transactions.get()->value.remove(transactionIdentifier);
1097}
1098
1099void UniqueIDBDatabase::resetAllTransactions(const DatabaseProcessIDBConnection& connection)
1100{
1101    ASSERT(RunLoop::isMain());
1102    auto transactions = m_establishedTransactions.find(&connection);
1103    if (transactions == m_establishedTransactions.end() || !m_acceptingNewRequests)
1104        return;
1105
1106    for (auto& transactionIdentifier : transactions.get()->value) {
1107        m_pendingTransactionRollbacks.add(transactionIdentifier);
1108        if (!m_pendingTransactionRequests.contains(transactionIdentifier))
1109            finalizeRollback(transactionIdentifier);
1110    }
1111}
1112
1113void UniqueIDBDatabase::finalizeRollback(const WebKit::IDBIdentifier& transactionId)
1114{
1115    ASSERT(RunLoop::isMain());
1116    ASSERT(m_pendingTransactionRollbacks.contains(transactionId));
1117    ASSERT(!m_pendingTransactionRequests.contains(transactionId));
1118    rollbackTransaction(transactionId, [this, transactionId](bool) {
1119        ASSERT(RunLoop::isMain());
1120        if (m_pendingTransactionRequests.contains(transactionId))
1121            return;
1122
1123        ASSERT(m_pendingTransactionRollbacks.contains(transactionId));
1124        m_pendingTransactionRollbacks.remove(transactionId);
1125        resetTransaction(transactionId, [this, transactionId](bool) {
1126            if (m_acceptingNewRequests && m_connections.isEmpty() && m_pendingTransactionRollbacks.isEmpty()) {
1127                shutdown(UniqueIDBDatabaseShutdownType::NormalShutdown);
1128                DatabaseProcess::shared().removeUniqueIDBDatabase(*this);
1129            }
1130        });
1131    });
1132}
1133
1134String UniqueIDBDatabase::absoluteDatabaseDirectory() const
1135{
1136    ASSERT(RunLoop::isMain());
1137    return DatabaseProcess::shared().absoluteIndexedDatabasePathFromDatabaseRelativePath(m_databaseRelativeDirectory);
1138}
1139
1140void UniqueIDBDatabase::postMainThreadTask(std::unique_ptr<AsyncTask> task, DatabaseTaskType taskType)
1141{
1142    ASSERT(!RunLoop::isMain());
1143
1144    if (!m_acceptingNewRequests && taskType == DatabaseTaskType::Normal)
1145        return;
1146
1147    MutexLocker locker(m_mainThreadTaskMutex);
1148
1149    m_mainThreadTasks.append(WTF::move(task));
1150
1151    // Balanced by an adoptRef() in ::performNextMainThreadTask
1152    ref();
1153    RunLoop::main().dispatch(bind(&UniqueIDBDatabase::performNextMainThreadTask, this));
1154}
1155
1156void UniqueIDBDatabase::performNextMainThreadTask()
1157{
1158    ASSERT(RunLoop::isMain());
1159
1160    // Balanced by a ref() in ::postMainThreadTask
1161    RefPtr<UniqueIDBDatabase> protector(adoptRef(this));
1162
1163    performNextMainThreadTaskWithoutAdoptRef();
1164}
1165
1166bool UniqueIDBDatabase::performNextMainThreadTaskWithoutAdoptRef()
1167{
1168    bool moreTasks;
1169
1170    std::unique_ptr<AsyncTask> task;
1171    {
1172        MutexLocker locker(m_mainThreadTaskMutex);
1173
1174        // This database might be shutting down, in which case the task queue might be empty.
1175        if (m_mainThreadTasks.isEmpty())
1176            return false;
1177
1178        task = m_mainThreadTasks.takeFirst();
1179        moreTasks = !m_mainThreadTasks.isEmpty();
1180    }
1181
1182    task->performTask();
1183
1184    return moreTasks;
1185}
1186
1187void UniqueIDBDatabase::postDatabaseTask(std::unique_ptr<AsyncTask> task, DatabaseTaskType taskType)
1188{
1189    ASSERT(RunLoop::isMain());
1190
1191    if (!m_acceptingNewRequests && taskType == DatabaseTaskType::Normal)
1192        return;
1193
1194    MutexLocker locker(m_databaseTaskMutex);
1195
1196    m_databaseTasks.append(WTF::move(task));
1197
1198    DatabaseProcess::shared().queue().dispatch(bind(&UniqueIDBDatabase::performNextDatabaseTask, this));
1199}
1200
1201void UniqueIDBDatabase::performNextDatabaseTask()
1202{
1203    ASSERT(!RunLoop::isMain());
1204
1205    // It is possible that this database might be shutting down on the main thread.
1206    // In this case, immediately after releasing m_databaseTaskMutex, this database might get deleted.
1207    // We take a ref() to make sure the database is still live while this last task is performed.
1208    RefPtr<UniqueIDBDatabase> protector(this);
1209
1210    std::unique_ptr<AsyncTask> task;
1211    {
1212        MutexLocker locker(m_databaseTaskMutex);
1213
1214        // This database might be shutting down on the main thread, in which case the task queue might be empty.
1215        if (m_databaseTasks.isEmpty())
1216            return;
1217
1218        task = m_databaseTasks.takeFirst();
1219    }
1220
1221    task->performTask();
1222}
1223
1224} // namespace WebKit
1225
1226#endif // ENABLE(INDEXED_DATABASE) && ENABLE(DATABASE_PROCESS)
1227