IDB: Implement cross-thread and IPC plumbing for 'get' support
[WebKit-https.git] / Source / WebKit2 / DatabaseProcess / IndexedDB / UniqueIDBDatabase.cpp
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 "UniqueIDBDatabaseBackingStoreSQLite.h"
37 #include "WebCrossThreadCopier.h"
38 #include <WebCore/FileSystem.h>
39 #include <WebCore/IDBDatabaseBackend.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
47 using namespace WebCore;
48
49 namespace WebKit {
50
51 UniqueIDBDatabase::UniqueIDBDatabase(const UniqueIDBDatabaseIdentifier& identifier)
52     : m_identifier(identifier)
53     , m_acceptingNewRequests(true)
54     , m_didGetMetadataFromBackingStore(false)
55 {
56     m_inMemory = !canShareDatabases(identifier.openingOrigin(), identifier.mainFrameOrigin());
57     if (m_inMemory)
58         return;
59
60     // Each unique Indexed Database exists in a directory named for the database, which exists in a directory representing its opening origin.
61     m_databaseRelativeDirectory = pathByAppendingComponent(databaseFilenameIdentifier(identifier.openingOrigin()), filenameForDatabaseName());
62
63     DatabaseProcess::shared().ensureIndexedDatabaseRelativePathExists(m_databaseRelativeDirectory);
64 }
65
66 UniqueIDBDatabase::~UniqueIDBDatabase()
67 {
68     ASSERT(!m_acceptingNewRequests);
69     ASSERT(m_pendingMetadataRequests.isEmpty());
70 }
71
72 String UniqueIDBDatabase::filenameForDatabaseName() const
73 {
74     ASSERT(!m_identifier.databaseName().isNull());
75
76     if (m_identifier.databaseName().isEmpty())
77         return "%00";
78
79     String filename = encodeForFileName(m_identifier.databaseName());
80     filename.replace('.', "%2E");
81
82     return filename;
83 }
84
85 String UniqueIDBDatabase::databaseFilenameIdentifier(const SecurityOriginData& originData) const
86 {
87     RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::create(originData.protocol, originData.host, originData.port);
88     return securityOrigin->databaseIdentifier();
89 }
90
91 bool UniqueIDBDatabase::canShareDatabases(const SecurityOriginData& openingOrigin, const SecurityOriginData& mainFrameOrigin) const
92 {
93     // For now, an origin's database access is predicated on equality with the other origin.
94     // We might need to make this more nuanced later.
95     return openingOrigin == mainFrameOrigin;
96 }
97
98 void UniqueIDBDatabase::registerConnection(DatabaseProcessIDBConnection& connection)
99 {
100     ASSERT(!m_connections.contains(&connection));
101     m_connections.add(&connection);
102 }
103
104 void UniqueIDBDatabase::unregisterConnection(DatabaseProcessIDBConnection& connection)
105 {
106     ASSERT(m_connections.contains(&connection));
107     m_connections.remove(&connection);
108
109     if (m_connections.isEmpty()) {
110         shutdown();
111         DatabaseProcess::shared().removeUniqueIDBDatabase(*this);
112     }
113 }
114
115 void UniqueIDBDatabase::shutdown()
116 {
117     ASSERT(isMainThread());
118
119     m_acceptingNewRequests = false;
120
121     {
122         MutexLocker locker(m_databaseTaskMutex);
123         m_databaseTasks.clear();
124     }
125
126     {
127         MutexLocker locker(m_mainThreadTaskMutex);
128         m_mainThreadTasks.clear();
129     }
130
131     for (const auto& it : m_pendingMetadataRequests)
132         it->requestAborted();
133
134     for (const auto& it : m_pendingTransactionRequests)
135         it.value->requestAborted();
136
137     for (const auto& it : m_pendingDatabaseTasks)
138         it.value->requestAborted();
139         
140     // Balanced by an adoptRef in ::didShutdownBackingStore()
141     ref();
142
143     DatabaseProcess::shared().queue().dispatch(bind(&UniqueIDBDatabase::shutdownBackingStore, this));
144 }
145
146 void UniqueIDBDatabase::shutdownBackingStore()
147 {
148     ASSERT(!isMainThread());
149     if (m_backingStore)
150         m_backingStore.clear();
151
152     RunLoop::main()->dispatch(bind(&UniqueIDBDatabase::didShutdownBackingStore, this));
153 }
154
155 void UniqueIDBDatabase::didShutdownBackingStore()
156 {
157     ASSERT(isMainThread());
158
159     // Balanced by a ref in ::shutdown()
160     RefPtr<UniqueIDBDatabase> protector(adoptRef(this));
161 }
162
163 void UniqueIDBDatabase::getOrEstablishIDBDatabaseMetadata(std::function<void(bool, const IDBDatabaseMetadata&)> completionCallback)
164 {
165     ASSERT(isMainThread());
166
167     if (!m_acceptingNewRequests) {
168         completionCallback(false, IDBDatabaseMetadata());
169         return;
170     }
171
172     // If we've already retrieved metadata from the backing store, return it now.
173     if (m_didGetMetadataFromBackingStore) {
174         if (m_metadata)
175             completionCallback(true, *m_metadata);
176         else
177             completionCallback(false, IDBDatabaseMetadata());
178
179         return;
180     }
181
182     // If this is the first unanswered metadata request, post a task to open the backing store and get metadata.
183     if (m_pendingMetadataRequests.isEmpty())
184         postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::openBackingStoreAndReadMetadata, m_identifier, absoluteDatabaseDirectory()));
185
186     // Then remember this metadata request to be answered later.
187     RefPtr<AsyncRequest> request = AsyncRequestImpl<>::create([completionCallback, this]() {
188         completionCallback(!!m_metadata, m_metadata ? *m_metadata : IDBDatabaseMetadata());
189     }, [completionCallback]() {
190         // The boolean flag to the completion callback represents whether the
191         // attempt to get/establish metadata succeeded or failed.
192         // Since we're aborting the attempt, it failed, so we always pass in false.
193         completionCallback(false, IDBDatabaseMetadata());
194     });
195
196     m_pendingMetadataRequests.append(request.release());
197 }
198
199 void UniqueIDBDatabase::openBackingStoreAndReadMetadata(const UniqueIDBDatabaseIdentifier& identifier, const String& databaseDirectory)
200 {
201     ASSERT(!isMainThread());
202     ASSERT(!m_backingStore);
203
204     if (m_inMemory) {
205         LOG_ERROR("Support for in-memory databases not yet implemented");
206         return;
207     }
208
209     m_backingStore = UniqueIDBDatabaseBackingStoreSQLite::create(identifier, databaseDirectory);
210     std::unique_ptr<IDBDatabaseMetadata> metadata = m_backingStore->getOrEstablishMetadata();
211
212     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didOpenBackingStoreAndReadMetadata, metadata ? *metadata : IDBDatabaseMetadata(), !!metadata));
213 }
214
215 void UniqueIDBDatabase::didOpenBackingStoreAndReadMetadata(const IDBDatabaseMetadata& metadata, bool success)
216 {
217     ASSERT(isMainThread());
218     ASSERT(!m_metadata);
219
220     m_didGetMetadataFromBackingStore = true;
221
222     if (success)
223         m_metadata = std::make_unique<IDBDatabaseMetadata>(metadata);
224
225     while (!m_pendingMetadataRequests.isEmpty()) {
226         RefPtr<AsyncRequest> request = m_pendingMetadataRequests.takeFirst();
227         request->completeRequest();
228     }
229 }
230
231 void UniqueIDBDatabase::openTransaction(const IDBTransactionIdentifier& identifier, const Vector<int64_t>& objectStoreIDs, IndexedDB::TransactionMode mode, std::function<void(bool)> successCallback)
232 {
233     postTransactionOperation(identifier, createAsyncTask(*this, &UniqueIDBDatabase::openBackingStoreTransaction, identifier, objectStoreIDs, mode), successCallback);
234 }
235
236 void UniqueIDBDatabase::beginTransaction(const IDBTransactionIdentifier& identifier, std::function<void(bool)> successCallback)
237 {
238     postTransactionOperation(identifier, createAsyncTask(*this, &UniqueIDBDatabase::beginBackingStoreTransaction, identifier), successCallback);
239 }
240
241 void UniqueIDBDatabase::commitTransaction(const IDBTransactionIdentifier& identifier, std::function<void(bool)> successCallback)
242 {
243     postTransactionOperation(identifier, createAsyncTask(*this, &UniqueIDBDatabase::commitBackingStoreTransaction, identifier), successCallback);
244 }
245
246 void UniqueIDBDatabase::resetTransaction(const IDBTransactionIdentifier& identifier, std::function<void(bool)> successCallback)
247 {
248     postTransactionOperation(identifier, createAsyncTask(*this, &UniqueIDBDatabase::resetBackingStoreTransaction, identifier), successCallback);
249 }
250
251 void UniqueIDBDatabase::rollbackTransaction(const IDBTransactionIdentifier& identifier, std::function<void(bool)> successCallback)
252 {
253     postTransactionOperation(identifier, createAsyncTask(*this, &UniqueIDBDatabase::rollbackBackingStoreTransaction, identifier), successCallback);
254 }
255
256 void UniqueIDBDatabase::postTransactionOperation(const IDBTransactionIdentifier& identifier, std::unique_ptr<AsyncTask> task, std::function<void(bool)> successCallback)
257 {
258     ASSERT(isMainThread());
259
260     if (!m_acceptingNewRequests) {
261         successCallback(false);
262         return;
263     }
264
265     if (m_pendingTransactionRequests.contains(identifier)) {
266         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.");
267         successCallback(false);
268         return;
269     }
270
271     postDatabaseTask(std::move(task));
272
273     RefPtr<AsyncRequest> request = AsyncRequestImpl<bool>::create([successCallback](bool success) {
274         successCallback(success);
275     }, [successCallback]() {
276         successCallback(false);
277     });
278
279     m_pendingTransactionRequests.add(identifier, request.release());
280 }
281
282 void UniqueIDBDatabase::didCompleteTransactionOperation(const IDBTransactionIdentifier& identifier, bool success)
283 {
284     ASSERT(isMainThread());
285
286     RefPtr<AsyncRequest> request = m_pendingTransactionRequests.take(identifier);
287     if (!request)
288         return;
289
290     request->completeRequest(success);
291 }
292
293 void UniqueIDBDatabase::changeDatabaseVersion(const IDBTransactionIdentifier& identifier, uint64_t newVersion, std::function<void(bool)> successCallback)
294 {
295     ASSERT(isMainThread());
296
297     if (!m_acceptingNewRequests) {
298         successCallback(false);
299         return;
300     }
301
302     uint64_t oldVersion = m_metadata->version;
303     m_metadata->version = newVersion;
304
305     RefPtr<AsyncRequest> request = AsyncRequestImpl<bool>::create([this, oldVersion, successCallback](bool success) {
306         if (!success)
307             m_metadata->version = oldVersion;
308         successCallback(success);
309     }, [this, oldVersion, successCallback]() {
310         m_metadata->version = oldVersion;
311         successCallback(false);
312     });
313
314     uint64_t requestID = request->requestID();
315     m_pendingDatabaseTasks.add(requestID, request.release());
316
317     postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::changeDatabaseVersionInBackingStore, requestID, identifier, newVersion));
318 }
319
320 void UniqueIDBDatabase::didChangeDatabaseVersion(uint64_t requestID, bool success)
321 {
322     didCompleteBoolRequest(requestID, success);
323 }
324
325 void UniqueIDBDatabase::didCreateObjectStore(uint64_t requestID, bool success)
326 {
327     didCompleteBoolRequest(requestID, success);
328 }
329
330 void UniqueIDBDatabase::didDeleteObjectStore(uint64_t requestID, bool success)
331 {
332     didCompleteBoolRequest(requestID, success);
333 }
334
335 void UniqueIDBDatabase::didCompleteBoolRequest(uint64_t requestID, bool success)
336 {
337     RefPtr<AsyncRequest> request = m_pendingDatabaseTasks.take(requestID);
338     ASSERT(request);
339
340     request->completeRequest(success);
341 }
342
343 void UniqueIDBDatabase::createObjectStore(const IDBTransactionIdentifier& identifier, const IDBObjectStoreMetadata& metadata, std::function<void(bool)> successCallback)
344 {
345     ASSERT(isMainThread());
346
347     if (!m_acceptingNewRequests) {
348         successCallback(false);
349         return;
350     }
351
352     ASSERT(!m_metadata->objectStores.contains(metadata.id));
353     m_metadata->objectStores.set(metadata.id, metadata);
354     int64_t addedObjectStoreID = metadata.id;
355
356     RefPtr<AsyncRequest> request = AsyncRequestImpl<bool>::create([this, addedObjectStoreID, successCallback](bool success) {
357         if (!success)
358             m_metadata->objectStores.remove(addedObjectStoreID);
359         successCallback(success);
360     }, [this, addedObjectStoreID, successCallback]() {
361         m_metadata->objectStores.remove(addedObjectStoreID);
362         successCallback(false);
363     });
364
365     uint64_t requestID = request->requestID();
366     m_pendingDatabaseTasks.add(requestID, request.release());
367
368     postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::createObjectStoreInBackingStore, requestID, identifier, metadata));
369 }
370
371 void UniqueIDBDatabase::deleteObjectStore(const IDBTransactionIdentifier& identifier, int64_t objectStoreID, std::function<void(bool)> successCallback)
372 {
373     ASSERT(isMainThread());
374
375     if (!m_acceptingNewRequests) {
376         successCallback(false);
377         return;
378     }
379
380     ASSERT(m_metadata->objectStores.contains(objectStoreID));
381     IDBObjectStoreMetadata metadata = m_metadata->objectStores.take(objectStoreID);
382
383     RefPtr<AsyncRequest> request = AsyncRequestImpl<bool>::create([this, metadata, successCallback](bool success) {
384         if (!success)
385             m_metadata->objectStores.set(metadata.id, metadata);
386         successCallback(success);
387     }, [this, metadata, successCallback]() {
388         m_metadata->objectStores.set(metadata.id, metadata);
389         successCallback(false);
390     });
391
392     uint64_t requestID = request->requestID();
393     m_pendingDatabaseTasks.add(requestID, request.release());
394
395     postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::deleteObjectStoreInBackingStore, requestID, identifier, objectStoreID));
396 }
397
398 void UniqueIDBDatabase::putRecord(const IDBTransactionIdentifier& identifier, 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)
399 {
400     ASSERT(isMainThread());
401
402     if (!m_acceptingNewRequests) {
403         callback(IDBKeyData(), INVALID_STATE_ERR, "Unable to put record into database because it has shut down");
404         return;
405     }
406
407     ASSERT(m_metadata->objectStores.contains(objectStoreID));
408
409     RefPtr<AsyncRequest> request = AsyncRequestImpl<const IDBKeyData&, uint32_t, const String&>::create([this, callback](const IDBKeyData& keyData, uint32_t errorCode, const String& errorMessage) {
410         callback(keyData, errorCode, errorMessage);
411     }, [this, callback]() {
412         callback(IDBKeyData(), INVALID_STATE_ERR, "Unable to put record into database");
413     });
414
415     uint64_t requestID = request->requestID();
416     m_pendingDatabaseTasks.add(requestID, request.release());
417
418     postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::putRecordInBackingStore, requestID, identifier, m_metadata->objectStores.get(objectStoreID), keyData, value.vector(), putMode, indexIDs, indexKeys));
419 }
420
421 void UniqueIDBDatabase::getRecord(const IDBTransactionIdentifier& identifier, int64_t objectStoreID, int64_t indexID, const WebCore::IDBKeyRangeData& keyRangeData, WebCore::IndexedDB::CursorType cursorType, std::function<void(const WebCore::IDBGetResult&, uint32_t, const String&)> callback)
422 {
423     ASSERT(isMainThread());
424
425     if (!m_acceptingNewRequests) {
426         callback(IDBGetResult(), INVALID_STATE_ERR, "Unable to get record from database because it has shut down");
427         return;
428     }
429
430     ASSERT(m_metadata->objectStores.contains(objectStoreID));
431
432     RefPtr<AsyncRequest> request = AsyncRequestImpl<const IDBGetResult&, uint32_t, const String&>::create([this, callback](const IDBGetResult& result, uint32_t errorCode, const String& errorMessage) {
433         callback(result, errorCode, errorMessage);
434     }, [this, callback]() {
435         callback(IDBGetResult(), INVALID_STATE_ERR, "Unable to get record from database");
436     });
437
438     uint64_t requestID = request->requestID();
439     m_pendingDatabaseTasks.add(requestID, request.release());
440
441     postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::getRecordFromBackingStore, requestID, identifier, m_metadata->objectStores.get(objectStoreID), indexID, keyRangeData, cursorType));
442 }
443
444 void UniqueIDBDatabase::openBackingStoreTransaction(const IDBTransactionIdentifier& identifier, const Vector<int64_t>& objectStoreIDs, IndexedDB::TransactionMode mode)
445 {
446     ASSERT(!isMainThread());
447     ASSERT(m_backingStore);
448
449     bool success = m_backingStore->establishTransaction(identifier, objectStoreIDs, mode);
450
451     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCompleteTransactionOperation, identifier, success));
452 }
453
454 void UniqueIDBDatabase::beginBackingStoreTransaction(const IDBTransactionIdentifier& identifier)
455 {
456     ASSERT(!isMainThread());
457     ASSERT(m_backingStore);
458
459     bool success = m_backingStore->beginTransaction(identifier);
460
461     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCompleteTransactionOperation, identifier, success));
462 }
463
464 void UniqueIDBDatabase::commitBackingStoreTransaction(const IDBTransactionIdentifier& identifier)
465 {
466     ASSERT(!isMainThread());
467     ASSERT(m_backingStore);
468
469     bool success = m_backingStore->commitTransaction(identifier);
470
471     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCompleteTransactionOperation, identifier, success));
472 }
473
474 void UniqueIDBDatabase::resetBackingStoreTransaction(const IDBTransactionIdentifier& identifier)
475 {
476     ASSERT(!isMainThread());
477     ASSERT(m_backingStore);
478
479     bool success = m_backingStore->resetTransaction(identifier);
480
481     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCompleteTransactionOperation, identifier, success));
482 }
483
484 void UniqueIDBDatabase::rollbackBackingStoreTransaction(const IDBTransactionIdentifier& identifier)
485 {
486     ASSERT(!isMainThread());
487     ASSERT(m_backingStore);
488
489     bool success = m_backingStore->rollbackTransaction(identifier);
490
491     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCompleteTransactionOperation, identifier, success));
492 }
493
494 void UniqueIDBDatabase::changeDatabaseVersionInBackingStore(uint64_t requestID, const IDBTransactionIdentifier& identifier, uint64_t newVersion)
495 {
496     ASSERT(!isMainThread());
497     ASSERT(m_backingStore);
498
499     bool success = m_backingStore->changeDatabaseVersion(identifier, newVersion);
500
501     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didChangeDatabaseVersion, requestID, success));
502 }
503
504 void UniqueIDBDatabase::createObjectStoreInBackingStore(uint64_t requestID, const IDBTransactionIdentifier& identifier, const IDBObjectStoreMetadata& metadata)
505 {
506     ASSERT(!isMainThread());
507     ASSERT(m_backingStore);
508
509     bool success = m_backingStore->createObjectStore(identifier, metadata);
510
511     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCreateObjectStore, requestID, success));
512 }
513
514 void UniqueIDBDatabase::deleteObjectStoreInBackingStore(uint64_t requestID, const IDBTransactionIdentifier& identifier, int64_t objectStoreID)
515 {
516     ASSERT(!isMainThread());
517     ASSERT(m_backingStore);
518
519     bool success = m_backingStore->deleteObjectStore(identifier, objectStoreID);
520
521     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didDeleteObjectStore, requestID, success));
522 }
523
524 void UniqueIDBDatabase::putRecordInBackingStore(uint64_t requestID, const IDBTransactionIdentifier& transaction, const IDBObjectStoreMetadata& objectStoreMetadata, const IDBKeyData& keyData, const Vector<uint8_t>& value, int64_t putMode, const Vector<int64_t>& indexIDs, const Vector<Vector<IDBKeyData>>& indexKeys)
525 {
526     ASSERT(!isMainThread());
527     ASSERT(m_backingStore);
528
529     bool keyWasGenerated = false;
530     RefPtr<IDBKey> key;
531
532     if (putMode != IDBDatabaseBackend::CursorUpdate && objectStoreMetadata.autoIncrement && keyData.isNull) {
533         key = m_backingStore->generateKey(transaction, objectStoreMetadata.id);
534         keyWasGenerated = true;
535     } else
536         key = keyData.maybeCreateIDBKey();
537
538     ASSERT(key);
539     ASSERT(key->isValid());
540
541     if (putMode == IDBDatabaseBackend::AddOnly) {
542         bool keyExists;
543         if (!m_backingStore->keyExistsInObjectStore(transaction, objectStoreMetadata.id, *key, keyExists)) {
544             postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didPutRecordInBackingStore, requestID, IDBKeyData(), IDBDatabaseException::UnknownError, ASCIILiteral("Internal backing store error checking for key existence")));
545             return;
546         }
547         if (keyExists) {
548             postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didPutRecordInBackingStore, requestID, IDBKeyData(), IDBDatabaseException::ConstraintError, ASCIILiteral("Key already exists in the object store")));
549             return;
550         }
551     }
552
553     // FIXME: The LevelDB port performs "makeIndexWriters" here. Necessary?
554
555     if (!m_backingStore->putRecord(transaction, objectStoreMetadata.id, *key, value.data(), value.size())) {
556         postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didPutRecordInBackingStore, requestID, IDBKeyData(), IDBDatabaseException::UnknownError, ASCIILiteral("Internal backing store error putting a record")));
557         return;
558     }
559
560     // FIXME: The LevelDB port updates index keys here. Necessary?
561
562     if (putMode != IDBDatabaseBackend::CursorUpdate && objectStoreMetadata.autoIncrement && key->type() == IDBKey::NumberType) {
563         if (!m_backingStore->updateKeyGenerator(transaction, objectStoreMetadata.id, *key, keyWasGenerated)) {
564             postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didPutRecordInBackingStore, requestID, IDBKeyData(), IDBDatabaseException::UnknownError, ASCIILiteral("Internal backing store error updating key generator")));
565             return;
566         }
567     }
568
569     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didPutRecordInBackingStore, requestID, IDBKeyData(key.get()), 0, String(StringImpl::empty())));
570 }
571
572 void UniqueIDBDatabase::didPutRecordInBackingStore(uint64_t requestID, const IDBKeyData& keyData, uint32_t errorCode, const String& errorMessage)
573 {
574     RefPtr<AsyncRequest> request = m_pendingDatabaseTasks.take(requestID);
575     ASSERT(request);
576
577     request->completeRequest(keyData, errorCode, errorMessage);
578 }
579
580 void UniqueIDBDatabase::getRecordFromBackingStore(uint64_t requestID, const IDBTransactionIdentifier&, const WebCore::IDBObjectStoreMetadata&, int64_t indexID, const WebCore::IDBKeyRangeData&, WebCore::IndexedDB::CursorType)
581 {
582     // FIXME: Implement (https://bugs.webkit.org/show_bug.cgi?id=127502)
583
584     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didGetRecordFromBackingStore, requestID, IDBGetResult(), IDBDatabaseException::UnknownError, ASCIILiteral("'get' support not yet implemented")));
585 }
586
587 void UniqueIDBDatabase::didGetRecordFromBackingStore(uint64_t requestID, const IDBGetResult& result, uint32_t errorCode, const String& errorMessage)
588 {
589     RefPtr<AsyncRequest> request = m_pendingDatabaseTasks.take(requestID);
590     ASSERT(request);
591
592     request->completeRequest(result, errorCode, errorMessage);
593 }
594
595 String UniqueIDBDatabase::absoluteDatabaseDirectory() const
596 {
597     ASSERT(isMainThread());
598     return DatabaseProcess::shared().absoluteIndexedDatabasePathFromDatabaseRelativePath(m_databaseRelativeDirectory);
599 }
600
601 void UniqueIDBDatabase::postMainThreadTask(std::unique_ptr<AsyncTask> task)
602 {
603     ASSERT(!isMainThread());
604
605     if (!m_acceptingNewRequests)
606         return;
607
608     MutexLocker locker(m_mainThreadTaskMutex);
609
610     m_mainThreadTasks.append(std::move(task));
611
612     // Balanced by an adoptRef() in ::performNextMainThreadTask
613     ref();
614     RunLoop::main()->dispatch(bind(&UniqueIDBDatabase::performNextMainThreadTask, this));
615 }
616
617 void UniqueIDBDatabase::performNextMainThreadTask()
618 {
619     ASSERT(isMainThread());
620
621     // Balanced by a ref() in ::postMainThreadTask
622     RefPtr<UniqueIDBDatabase> protector(adoptRef(this));
623
624     std::unique_ptr<AsyncTask> task;
625     {
626         MutexLocker locker(m_mainThreadTaskMutex);
627
628         // This database might be shutting down, in which case the task queue might be empty.
629         if (m_mainThreadTasks.isEmpty())
630             return;
631
632         task = m_mainThreadTasks.takeFirst();
633     }
634
635     task->performTask();
636 }
637
638 void UniqueIDBDatabase::postDatabaseTask(std::unique_ptr<AsyncTask> task)
639 {
640     ASSERT(isMainThread());
641
642     if (!m_acceptingNewRequests)
643         return;
644
645     MutexLocker locker(m_databaseTaskMutex);
646
647     m_databaseTasks.append(std::move(task));
648
649     DatabaseProcess::shared().queue().dispatch(bind(&UniqueIDBDatabase::performNextDatabaseTask, this));
650 }
651
652 void UniqueIDBDatabase::performNextDatabaseTask()
653 {
654     ASSERT(!isMainThread());
655
656     // It is possible that this database might be shutting down on the main thread.
657     // In this case, immediately after releasing m_databaseTaskMutex, this database might get deleted.
658     // We take a ref() to make sure the database is still live while this last task is performed.
659     RefPtr<UniqueIDBDatabase> protector(this);
660
661     std::unique_ptr<AsyncTask> task;
662     {
663         MutexLocker locker(m_databaseTaskMutex);
664
665         // This database might be shutting down on the main thread, in which case the task queue might be empty.
666         if (m_databaseTasks.isEmpty())
667             return;
668
669         task = m_databaseTasks.takeFirst();
670     }
671
672     task->performTask();
673 }
674
675 } // namespace WebKit
676
677 #endif // ENABLE(INDEXED_DATABASE) && ENABLE(DATABASE_PROCESS)