2 * Copyright (C) 2013 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "UniqueIDBDatabase.h"
29 #if ENABLE(INDEXED_DATABASE) && ENABLE(DATABASE_PROCESS)
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>
47 using namespace WebCore;
51 UniqueIDBDatabase::UniqueIDBDatabase(const UniqueIDBDatabaseIdentifier& identifier)
52 : m_identifier(identifier)
53 , m_acceptingNewRequests(true)
54 , m_didGetMetadataFromBackingStore(false)
56 m_inMemory = !canShareDatabases(identifier.openingOrigin(), identifier.mainFrameOrigin());
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());
63 DatabaseProcess::shared().ensureIndexedDatabaseRelativePathExists(m_databaseRelativeDirectory);
66 UniqueIDBDatabase::~UniqueIDBDatabase()
68 ASSERT(!m_acceptingNewRequests);
69 ASSERT(m_pendingMetadataRequests.isEmpty());
72 String UniqueIDBDatabase::filenameForDatabaseName() const
74 ASSERT(!m_identifier.databaseName().isNull());
76 if (m_identifier.databaseName().isEmpty())
79 String filename = encodeForFileName(m_identifier.databaseName());
80 filename.replace('.', "%2E");
85 String UniqueIDBDatabase::databaseFilenameIdentifier(const SecurityOriginData& originData) const
87 RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::create(originData.protocol, originData.host, originData.port);
88 return securityOrigin->databaseIdentifier();
91 bool UniqueIDBDatabase::canShareDatabases(const SecurityOriginData& openingOrigin, const SecurityOriginData& mainFrameOrigin) const
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;
98 void UniqueIDBDatabase::registerConnection(DatabaseProcessIDBConnection& connection)
100 ASSERT(!m_connections.contains(&connection));
101 m_connections.add(&connection);
104 void UniqueIDBDatabase::unregisterConnection(DatabaseProcessIDBConnection& connection)
106 ASSERT(m_connections.contains(&connection));
107 m_connections.remove(&connection);
109 if (m_connections.isEmpty()) {
111 DatabaseProcess::shared().removeUniqueIDBDatabase(*this);
115 void UniqueIDBDatabase::shutdown()
117 ASSERT(isMainThread());
119 m_acceptingNewRequests = false;
122 MutexLocker locker(m_databaseTaskMutex);
123 m_databaseTasks.clear();
127 MutexLocker locker(m_mainThreadTaskMutex);
128 m_mainThreadTasks.clear();
131 for (const auto& it : m_pendingMetadataRequests)
132 it->requestAborted();
134 for (const auto& it : m_pendingTransactionRequests)
135 it.value->requestAborted();
137 for (const auto& it : m_pendingDatabaseTasks)
138 it.value->requestAborted();
140 // Balanced by an adoptRef in ::didShutdownBackingStore()
143 DatabaseProcess::shared().queue().dispatch(bind(&UniqueIDBDatabase::shutdownBackingStore, this));
146 void UniqueIDBDatabase::shutdownBackingStore()
148 ASSERT(!isMainThread());
150 m_backingStore.clear();
152 RunLoop::main()->dispatch(bind(&UniqueIDBDatabase::didShutdownBackingStore, this));
155 void UniqueIDBDatabase::didShutdownBackingStore()
157 ASSERT(isMainThread());
159 // Balanced by a ref in ::shutdown()
160 RefPtr<UniqueIDBDatabase> protector(adoptRef(this));
163 void UniqueIDBDatabase::getOrEstablishIDBDatabaseMetadata(std::function<void(bool, const IDBDatabaseMetadata&)> completionCallback)
165 ASSERT(isMainThread());
167 if (!m_acceptingNewRequests) {
168 completionCallback(false, IDBDatabaseMetadata());
172 // If we've already retrieved metadata from the backing store, return it now.
173 if (m_didGetMetadataFromBackingStore) {
175 completionCallback(true, *m_metadata);
177 completionCallback(false, IDBDatabaseMetadata());
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()));
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());
196 m_pendingMetadataRequests.append(request.release());
199 void UniqueIDBDatabase::openBackingStoreAndReadMetadata(const UniqueIDBDatabaseIdentifier& identifier, const String& databaseDirectory)
201 ASSERT(!isMainThread());
202 ASSERT(!m_backingStore);
205 LOG_ERROR("Support for in-memory databases not yet implemented");
209 m_backingStore = UniqueIDBDatabaseBackingStoreSQLite::create(identifier, databaseDirectory);
210 std::unique_ptr<IDBDatabaseMetadata> metadata = m_backingStore->getOrEstablishMetadata();
212 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didOpenBackingStoreAndReadMetadata, metadata ? *metadata : IDBDatabaseMetadata(), !!metadata));
215 void UniqueIDBDatabase::didOpenBackingStoreAndReadMetadata(const IDBDatabaseMetadata& metadata, bool success)
217 ASSERT(isMainThread());
220 m_didGetMetadataFromBackingStore = true;
223 m_metadata = std::make_unique<IDBDatabaseMetadata>(metadata);
225 while (!m_pendingMetadataRequests.isEmpty()) {
226 RefPtr<AsyncRequest> request = m_pendingMetadataRequests.takeFirst();
227 request->completeRequest();
231 void UniqueIDBDatabase::openTransaction(const IDBTransactionIdentifier& identifier, const Vector<int64_t>& objectStoreIDs, IndexedDB::TransactionMode mode, std::function<void(bool)> successCallback)
233 postTransactionOperation(identifier, createAsyncTask(*this, &UniqueIDBDatabase::openBackingStoreTransaction, identifier, objectStoreIDs, mode), successCallback);
236 void UniqueIDBDatabase::beginTransaction(const IDBTransactionIdentifier& identifier, std::function<void(bool)> successCallback)
238 postTransactionOperation(identifier, createAsyncTask(*this, &UniqueIDBDatabase::beginBackingStoreTransaction, identifier), successCallback);
241 void UniqueIDBDatabase::commitTransaction(const IDBTransactionIdentifier& identifier, std::function<void(bool)> successCallback)
243 postTransactionOperation(identifier, createAsyncTask(*this, &UniqueIDBDatabase::commitBackingStoreTransaction, identifier), successCallback);
246 void UniqueIDBDatabase::resetTransaction(const IDBTransactionIdentifier& identifier, std::function<void(bool)> successCallback)
248 postTransactionOperation(identifier, createAsyncTask(*this, &UniqueIDBDatabase::resetBackingStoreTransaction, identifier), successCallback);
251 void UniqueIDBDatabase::rollbackTransaction(const IDBTransactionIdentifier& identifier, std::function<void(bool)> successCallback)
253 postTransactionOperation(identifier, createAsyncTask(*this, &UniqueIDBDatabase::rollbackBackingStoreTransaction, identifier), successCallback);
256 void UniqueIDBDatabase::postTransactionOperation(const IDBTransactionIdentifier& identifier, std::unique_ptr<AsyncTask> task, std::function<void(bool)> successCallback)
258 ASSERT(isMainThread());
260 if (!m_acceptingNewRequests) {
261 successCallback(false);
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);
271 postDatabaseTask(std::move(task));
273 RefPtr<AsyncRequest> request = AsyncRequestImpl<bool>::create([successCallback](bool success) {
274 successCallback(success);
275 }, [successCallback]() {
276 successCallback(false);
279 m_pendingTransactionRequests.add(identifier, request.release());
282 void UniqueIDBDatabase::didCompleteTransactionOperation(const IDBTransactionIdentifier& identifier, bool success)
284 ASSERT(isMainThread());
286 RefPtr<AsyncRequest> request = m_pendingTransactionRequests.take(identifier);
290 request->completeRequest(success);
293 void UniqueIDBDatabase::changeDatabaseVersion(const IDBTransactionIdentifier& identifier, uint64_t newVersion, std::function<void(bool)> successCallback)
295 ASSERT(isMainThread());
297 if (!m_acceptingNewRequests) {
298 successCallback(false);
302 uint64_t oldVersion = m_metadata->version;
303 m_metadata->version = newVersion;
305 RefPtr<AsyncRequest> request = AsyncRequestImpl<bool>::create([this, oldVersion, successCallback](bool success) {
307 m_metadata->version = oldVersion;
308 successCallback(success);
309 }, [this, oldVersion, successCallback]() {
310 m_metadata->version = oldVersion;
311 successCallback(false);
314 uint64_t requestID = request->requestID();
315 m_pendingDatabaseTasks.add(requestID, request.release());
317 postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::changeDatabaseVersionInBackingStore, requestID, identifier, newVersion));
320 void UniqueIDBDatabase::didChangeDatabaseVersion(uint64_t requestID, bool success)
322 didCompleteBoolRequest(requestID, success);
325 void UniqueIDBDatabase::didCreateObjectStore(uint64_t requestID, bool success)
327 didCompleteBoolRequest(requestID, success);
330 void UniqueIDBDatabase::didDeleteObjectStore(uint64_t requestID, bool success)
332 didCompleteBoolRequest(requestID, success);
335 void UniqueIDBDatabase::didCompleteBoolRequest(uint64_t requestID, bool success)
337 RefPtr<AsyncRequest> request = m_pendingDatabaseTasks.take(requestID);
340 request->completeRequest(success);
343 void UniqueIDBDatabase::createObjectStore(const IDBTransactionIdentifier& identifier, const IDBObjectStoreMetadata& metadata, std::function<void(bool)> successCallback)
345 ASSERT(isMainThread());
347 if (!m_acceptingNewRequests) {
348 successCallback(false);
352 ASSERT(!m_metadata->objectStores.contains(metadata.id));
353 m_metadata->objectStores.set(metadata.id, metadata);
354 int64_t addedObjectStoreID = metadata.id;
356 RefPtr<AsyncRequest> request = AsyncRequestImpl<bool>::create([this, addedObjectStoreID, successCallback](bool success) {
358 m_metadata->objectStores.remove(addedObjectStoreID);
359 successCallback(success);
360 }, [this, addedObjectStoreID, successCallback]() {
361 m_metadata->objectStores.remove(addedObjectStoreID);
362 successCallback(false);
365 uint64_t requestID = request->requestID();
366 m_pendingDatabaseTasks.add(requestID, request.release());
368 postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::createObjectStoreInBackingStore, requestID, identifier, metadata));
371 void UniqueIDBDatabase::deleteObjectStore(const IDBTransactionIdentifier& identifier, int64_t objectStoreID, std::function<void(bool)> successCallback)
373 ASSERT(isMainThread());
375 if (!m_acceptingNewRequests) {
376 successCallback(false);
380 ASSERT(m_metadata->objectStores.contains(objectStoreID));
381 IDBObjectStoreMetadata metadata = m_metadata->objectStores.take(objectStoreID);
383 RefPtr<AsyncRequest> request = AsyncRequestImpl<bool>::create([this, metadata, successCallback](bool 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);
392 uint64_t requestID = request->requestID();
393 m_pendingDatabaseTasks.add(requestID, request.release());
395 postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::deleteObjectStoreInBackingStore, requestID, identifier, objectStoreID));
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)
400 ASSERT(isMainThread());
402 if (!m_acceptingNewRequests) {
403 callback(IDBKeyData(), INVALID_STATE_ERR, "Unable to put record into database because it has shut down");
407 ASSERT(m_metadata->objectStores.contains(objectStoreID));
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");
415 uint64_t requestID = request->requestID();
416 m_pendingDatabaseTasks.add(requestID, request.release());
418 postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::putRecordInBackingStore, requestID, identifier, m_metadata->objectStores.get(objectStoreID), keyData, value.vector(), putMode, indexIDs, indexKeys));
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)
423 ASSERT(isMainThread());
425 if (!m_acceptingNewRequests) {
426 callback(IDBGetResult(), INVALID_STATE_ERR, "Unable to get record from database because it has shut down");
430 ASSERT(m_metadata->objectStores.contains(objectStoreID));
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");
438 uint64_t requestID = request->requestID();
439 m_pendingDatabaseTasks.add(requestID, request.release());
441 postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::getRecordFromBackingStore, requestID, identifier, m_metadata->objectStores.get(objectStoreID), indexID, keyRangeData, cursorType));
444 void UniqueIDBDatabase::openBackingStoreTransaction(const IDBTransactionIdentifier& identifier, const Vector<int64_t>& objectStoreIDs, IndexedDB::TransactionMode mode)
446 ASSERT(!isMainThread());
447 ASSERT(m_backingStore);
449 bool success = m_backingStore->establishTransaction(identifier, objectStoreIDs, mode);
451 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCompleteTransactionOperation, identifier, success));
454 void UniqueIDBDatabase::beginBackingStoreTransaction(const IDBTransactionIdentifier& identifier)
456 ASSERT(!isMainThread());
457 ASSERT(m_backingStore);
459 bool success = m_backingStore->beginTransaction(identifier);
461 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCompleteTransactionOperation, identifier, success));
464 void UniqueIDBDatabase::commitBackingStoreTransaction(const IDBTransactionIdentifier& identifier)
466 ASSERT(!isMainThread());
467 ASSERT(m_backingStore);
469 bool success = m_backingStore->commitTransaction(identifier);
471 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCompleteTransactionOperation, identifier, success));
474 void UniqueIDBDatabase::resetBackingStoreTransaction(const IDBTransactionIdentifier& identifier)
476 ASSERT(!isMainThread());
477 ASSERT(m_backingStore);
479 bool success = m_backingStore->resetTransaction(identifier);
481 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCompleteTransactionOperation, identifier, success));
484 void UniqueIDBDatabase::rollbackBackingStoreTransaction(const IDBTransactionIdentifier& identifier)
486 ASSERT(!isMainThread());
487 ASSERT(m_backingStore);
489 bool success = m_backingStore->rollbackTransaction(identifier);
491 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCompleteTransactionOperation, identifier, success));
494 void UniqueIDBDatabase::changeDatabaseVersionInBackingStore(uint64_t requestID, const IDBTransactionIdentifier& identifier, uint64_t newVersion)
496 ASSERT(!isMainThread());
497 ASSERT(m_backingStore);
499 bool success = m_backingStore->changeDatabaseVersion(identifier, newVersion);
501 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didChangeDatabaseVersion, requestID, success));
504 void UniqueIDBDatabase::createObjectStoreInBackingStore(uint64_t requestID, const IDBTransactionIdentifier& identifier, const IDBObjectStoreMetadata& metadata)
506 ASSERT(!isMainThread());
507 ASSERT(m_backingStore);
509 bool success = m_backingStore->createObjectStore(identifier, metadata);
511 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCreateObjectStore, requestID, success));
514 void UniqueIDBDatabase::deleteObjectStoreInBackingStore(uint64_t requestID, const IDBTransactionIdentifier& identifier, int64_t objectStoreID)
516 ASSERT(!isMainThread());
517 ASSERT(m_backingStore);
519 bool success = m_backingStore->deleteObjectStore(identifier, objectStoreID);
521 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didDeleteObjectStore, requestID, success));
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)
526 ASSERT(!isMainThread());
527 ASSERT(m_backingStore);
529 bool keyWasGenerated = false;
532 if (putMode != IDBDatabaseBackend::CursorUpdate && objectStoreMetadata.autoIncrement && keyData.isNull) {
533 key = m_backingStore->generateKey(transaction, objectStoreMetadata.id);
534 keyWasGenerated = true;
536 key = keyData.maybeCreateIDBKey();
539 ASSERT(key->isValid());
541 if (putMode == IDBDatabaseBackend::AddOnly) {
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")));
548 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didPutRecordInBackingStore, requestID, IDBKeyData(), IDBDatabaseException::ConstraintError, ASCIILiteral("Key already exists in the object store")));
553 // FIXME: The LevelDB port performs "makeIndexWriters" here. Necessary?
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")));
560 // FIXME: The LevelDB port updates index keys here. Necessary?
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")));
569 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didPutRecordInBackingStore, requestID, IDBKeyData(key.get()), 0, String(StringImpl::empty())));
572 void UniqueIDBDatabase::didPutRecordInBackingStore(uint64_t requestID, const IDBKeyData& keyData, uint32_t errorCode, const String& errorMessage)
574 RefPtr<AsyncRequest> request = m_pendingDatabaseTasks.take(requestID);
577 request->completeRequest(keyData, errorCode, errorMessage);
580 void UniqueIDBDatabase::getRecordFromBackingStore(uint64_t requestID, const IDBTransactionIdentifier&, const WebCore::IDBObjectStoreMetadata&, int64_t indexID, const WebCore::IDBKeyRangeData&, WebCore::IndexedDB::CursorType)
582 // FIXME: Implement (https://bugs.webkit.org/show_bug.cgi?id=127502)
584 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didGetRecordFromBackingStore, requestID, IDBGetResult(), IDBDatabaseException::UnknownError, ASCIILiteral("'get' support not yet implemented")));
587 void UniqueIDBDatabase::didGetRecordFromBackingStore(uint64_t requestID, const IDBGetResult& result, uint32_t errorCode, const String& errorMessage)
589 RefPtr<AsyncRequest> request = m_pendingDatabaseTasks.take(requestID);
592 request->completeRequest(result, errorCode, errorMessage);
595 String UniqueIDBDatabase::absoluteDatabaseDirectory() const
597 ASSERT(isMainThread());
598 return DatabaseProcess::shared().absoluteIndexedDatabasePathFromDatabaseRelativePath(m_databaseRelativeDirectory);
601 void UniqueIDBDatabase::postMainThreadTask(std::unique_ptr<AsyncTask> task)
603 ASSERT(!isMainThread());
605 if (!m_acceptingNewRequests)
608 MutexLocker locker(m_mainThreadTaskMutex);
610 m_mainThreadTasks.append(std::move(task));
612 // Balanced by an adoptRef() in ::performNextMainThreadTask
614 RunLoop::main()->dispatch(bind(&UniqueIDBDatabase::performNextMainThreadTask, this));
617 void UniqueIDBDatabase::performNextMainThreadTask()
619 ASSERT(isMainThread());
621 // Balanced by a ref() in ::postMainThreadTask
622 RefPtr<UniqueIDBDatabase> protector(adoptRef(this));
624 std::unique_ptr<AsyncTask> task;
626 MutexLocker locker(m_mainThreadTaskMutex);
628 // This database might be shutting down, in which case the task queue might be empty.
629 if (m_mainThreadTasks.isEmpty())
632 task = m_mainThreadTasks.takeFirst();
638 void UniqueIDBDatabase::postDatabaseTask(std::unique_ptr<AsyncTask> task)
640 ASSERT(isMainThread());
642 if (!m_acceptingNewRequests)
645 MutexLocker locker(m_databaseTaskMutex);
647 m_databaseTasks.append(std::move(task));
649 DatabaseProcess::shared().queue().dispatch(bind(&UniqueIDBDatabase::performNextDatabaseTask, this));
652 void UniqueIDBDatabase::performNextDatabaseTask()
654 ASSERT(!isMainThread());
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);
661 std::unique_ptr<AsyncTask> task;
663 MutexLocker locker(m_databaseTaskMutex);
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())
669 task = m_databaseTasks.takeFirst();
675 } // namespace WebKit
677 #endif // ENABLE(INDEXED_DATABASE) && ENABLE(DATABASE_PROCESS)