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