diff options
Diffstat (limited to 'Source/WebCore/Modules/indexeddb/client')
7 files changed, 1761 insertions, 0 deletions
diff --git a/Source/WebCore/Modules/indexeddb/client/IDBConnectionProxy.cpp b/Source/WebCore/Modules/indexeddb/client/IDBConnectionProxy.cpp new file mode 100644 index 000000000..4db50c0b9 --- /dev/null +++ b/Source/WebCore/Modules/indexeddb/client/IDBConnectionProxy.cpp @@ -0,0 +1,562 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "IDBConnectionProxy.h" + +#if ENABLE(INDEXED_DATABASE) + +#include "IDBCursorInfo.h" +#include "IDBDatabase.h" +#include "IDBGetRecordData.h" +#include "IDBIterateCursorData.h" +#include "IDBKeyRangeData.h" +#include "IDBOpenDBRequest.h" +#include "IDBRequestData.h" +#include "IDBResultData.h" +#include "ScriptExecutionContext.h" +#include "SecurityOrigin.h" +#include <wtf/MainThread.h> + +namespace WebCore { +namespace IDBClient { + +IDBConnectionProxy::IDBConnectionProxy(IDBConnectionToServer& connection) + : m_connectionToServer(connection) + , m_serverConnectionIdentifier(connection.identifier()) +{ + ASSERT(isMainThread()); +} + +void IDBConnectionProxy::ref() +{ + m_connectionToServer.ref(); +} + +void IDBConnectionProxy::deref() +{ + m_connectionToServer.deref(); +} + +Ref<IDBOpenDBRequest> IDBConnectionProxy::openDatabase(ScriptExecutionContext& context, const IDBDatabaseIdentifier& databaseIdentifier, uint64_t version) +{ + RefPtr<IDBOpenDBRequest> request; + { + Locker<Lock> locker(m_openDBRequestMapLock); + + request = IDBOpenDBRequest::createOpenRequest(context, *this, databaseIdentifier, version); + ASSERT(!m_openDBRequestMap.contains(request->resourceIdentifier())); + m_openDBRequestMap.set(request->resourceIdentifier(), request.get()); + } + + callConnectionOnMainThread(&IDBConnectionToServer::openDatabase, IDBRequestData(*this, *request)); + + return request.releaseNonNull(); +} + +Ref<IDBOpenDBRequest> IDBConnectionProxy::deleteDatabase(ScriptExecutionContext& context, const IDBDatabaseIdentifier& databaseIdentifier) +{ + RefPtr<IDBOpenDBRequest> request; + { + Locker<Lock> locker(m_openDBRequestMapLock); + + request = IDBOpenDBRequest::createDeleteRequest(context, *this, databaseIdentifier); + ASSERT(!m_openDBRequestMap.contains(request->resourceIdentifier())); + m_openDBRequestMap.set(request->resourceIdentifier(), request.get()); + } + + callConnectionOnMainThread(&IDBConnectionToServer::deleteDatabase, IDBRequestData(*this, *request)); + + return request.releaseNonNull(); +} + +void IDBConnectionProxy::didOpenDatabase(const IDBResultData& resultData) +{ + completeOpenDBRequest(resultData); +} + +void IDBConnectionProxy::didDeleteDatabase(const IDBResultData& resultData) +{ + completeOpenDBRequest(resultData); +} + +void IDBConnectionProxy::completeOpenDBRequest(const IDBResultData& resultData) +{ + ASSERT(isMainThread()); + + RefPtr<IDBOpenDBRequest> request; + { + Locker<Lock> locker(m_openDBRequestMapLock); + request = m_openDBRequestMap.take(resultData.requestIdentifier()); + } + + if (!request) + return; + + request->performCallbackOnOriginThread(*request, &IDBOpenDBRequest::requestCompleted, resultData); +} + +void IDBConnectionProxy::createObjectStore(TransactionOperation& operation, const IDBObjectStoreInfo& info) +{ + const IDBRequestData requestData { operation }; + saveOperation(operation); + + callConnectionOnMainThread(&IDBConnectionToServer::createObjectStore, requestData, info); +} + +void IDBConnectionProxy::renameObjectStore(TransactionOperation& operation, uint64_t objectStoreIdentifier, const String& newName) +{ + const IDBRequestData requestData { operation }; + saveOperation(operation); + + callConnectionOnMainThread(&IDBConnectionToServer::renameObjectStore, requestData, objectStoreIdentifier, newName); +} + +void IDBConnectionProxy::renameIndex(TransactionOperation& operation, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const String& newName) +{ + const IDBRequestData requestData { operation }; + saveOperation(operation); + + callConnectionOnMainThread(&IDBConnectionToServer::renameIndex, requestData, objectStoreIdentifier, indexIdentifier, newName); +} + +void IDBConnectionProxy::deleteObjectStore(TransactionOperation& operation, const String& objectStoreName) +{ + const IDBRequestData requestData { operation }; + saveOperation(operation); + + callConnectionOnMainThread(&IDBConnectionToServer::deleteObjectStore, requestData, objectStoreName); +} + +void IDBConnectionProxy::clearObjectStore(TransactionOperation& operation, uint64_t objectStoreIdentifier) +{ + const IDBRequestData requestData { operation }; + saveOperation(operation); + + callConnectionOnMainThread(&IDBConnectionToServer::clearObjectStore, requestData, objectStoreIdentifier); +} + +void IDBConnectionProxy::createIndex(TransactionOperation& operation, const IDBIndexInfo& info) +{ + const IDBRequestData requestData { operation }; + saveOperation(operation); + + callConnectionOnMainThread(&IDBConnectionToServer::createIndex, requestData, info); +} + +void IDBConnectionProxy::deleteIndex(TransactionOperation& operation, uint64_t objectStoreIdentifier, const String& indexName) +{ + const IDBRequestData requestData { operation }; + saveOperation(operation); + + callConnectionOnMainThread(&IDBConnectionToServer::deleteIndex, requestData, WTFMove(objectStoreIdentifier), indexName); +} + +void IDBConnectionProxy::putOrAdd(TransactionOperation& operation, IDBKeyData&& keyData, const IDBValue& value, const IndexedDB::ObjectStoreOverwriteMode mode) +{ + const IDBRequestData requestData { operation }; + saveOperation(operation); + + callConnectionOnMainThread(&IDBConnectionToServer::putOrAdd, requestData, keyData, value, mode); +} + +void IDBConnectionProxy::getRecord(TransactionOperation& operation, const IDBGetRecordData& getRecordData) +{ + const IDBRequestData requestData { operation }; + saveOperation(operation); + + callConnectionOnMainThread(&IDBConnectionToServer::getRecord, requestData, getRecordData); +} + +void IDBConnectionProxy::getAllRecords(TransactionOperation& operation, const IDBGetAllRecordsData& getAllRecordsData) +{ + const IDBRequestData requestData { operation }; + saveOperation(operation); + + callConnectionOnMainThread(&IDBConnectionToServer::getAllRecords, requestData, getAllRecordsData); +} + +void IDBConnectionProxy::getCount(TransactionOperation& operation, const IDBKeyRangeData& keyRange) +{ + const IDBRequestData requestData { operation }; + saveOperation(operation); + + callConnectionOnMainThread(&IDBConnectionToServer::getCount, requestData, keyRange); +} + +void IDBConnectionProxy::deleteRecord(TransactionOperation& operation, const IDBKeyRangeData& keyRange) +{ + const IDBRequestData requestData { operation }; + saveOperation(operation); + + callConnectionOnMainThread(&IDBConnectionToServer::deleteRecord, requestData, keyRange); +} + +void IDBConnectionProxy::openCursor(TransactionOperation& operation, const IDBCursorInfo& info) +{ + const IDBRequestData requestData { operation }; + saveOperation(operation); + + callConnectionOnMainThread(&IDBConnectionToServer::openCursor, requestData, info); +} + +void IDBConnectionProxy::iterateCursor(TransactionOperation& operation, const IDBIterateCursorData& data) +{ + const IDBRequestData requestData { operation }; + saveOperation(operation); + + callConnectionOnMainThread(&IDBConnectionToServer::iterateCursor, requestData, data); +} + +void IDBConnectionProxy::saveOperation(TransactionOperation& operation) +{ + Locker<Lock> locker(m_transactionOperationLock); + + ASSERT(!m_activeOperations.contains(operation.identifier())); + m_activeOperations.set(operation.identifier(), &operation); +} + +void IDBConnectionProxy::completeOperation(const IDBResultData& resultData) +{ + RefPtr<TransactionOperation> operation; + { + Locker<Lock> locker(m_transactionOperationLock); + operation = m_activeOperations.take(resultData.requestIdentifier()); + } + + if (!operation) + return; + + operation->transitionToComplete(resultData, WTFMove(operation)); +} + +void IDBConnectionProxy::abortOpenAndUpgradeNeeded(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& transactionIdentifier) +{ + callConnectionOnMainThread(&IDBConnectionToServer::abortOpenAndUpgradeNeeded, databaseConnectionIdentifier, transactionIdentifier); +} + +void IDBConnectionProxy::fireVersionChangeEvent(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& requestIdentifier, uint64_t requestedVersion) +{ + RefPtr<IDBDatabase> database; + { + Locker<Lock> locker(m_databaseConnectionMapLock); + database = m_databaseConnectionMap.get(databaseConnectionIdentifier); + } + + if (!database) + return; + + database->performCallbackOnOriginThread(*database, &IDBDatabase::fireVersionChangeEvent, requestIdentifier, requestedVersion); +} + +void IDBConnectionProxy::didFireVersionChangeEvent(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& requestIdentifier) +{ + callConnectionOnMainThread(&IDBConnectionToServer::didFireVersionChangeEvent, databaseConnectionIdentifier, requestIdentifier); +} + +void IDBConnectionProxy::notifyOpenDBRequestBlocked(const IDBResourceIdentifier& requestIdentifier, uint64_t oldVersion, uint64_t newVersion) +{ + ASSERT(isMainThread()); + + RefPtr<IDBOpenDBRequest> request; + { + Locker<Lock> locker(m_openDBRequestMapLock); + request = m_openDBRequestMap.get(requestIdentifier); + } + + if (!request) + return; + + request->performCallbackOnOriginThread(*request, &IDBOpenDBRequest::requestBlocked, oldVersion, newVersion); +} + +void IDBConnectionProxy::openDBRequestCancelled(const IDBRequestData& requestData) +{ + callConnectionOnMainThread(&IDBConnectionToServer::openDBRequestCancelled, requestData); +} + +void IDBConnectionProxy::establishTransaction(IDBTransaction& transaction) +{ + { + Locker<Lock> locker(m_transactionMapLock); + ASSERT(!hasRecordOfTransaction(transaction)); + m_pendingTransactions.set(transaction.info().identifier(), &transaction); + } + + callConnectionOnMainThread(&IDBConnectionToServer::establishTransaction, transaction.database().databaseConnectionIdentifier(), transaction.info()); +} + +void IDBConnectionProxy::didStartTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError& error) +{ + RefPtr<IDBTransaction> transaction; + { + Locker<Lock> locker(m_transactionMapLock); + transaction = m_pendingTransactions.take(transactionIdentifier); + } + + ASSERT(transaction); + + transaction->performCallbackOnOriginThread(*transaction, &IDBTransaction::didStart, error); +} + +void IDBConnectionProxy::commitTransaction(IDBTransaction& transaction) +{ + { + Locker<Lock> locker(m_transactionMapLock); + ASSERT(!m_committingTransactions.contains(transaction.info().identifier())); + m_committingTransactions.set(transaction.info().identifier(), &transaction); + } + + callConnectionOnMainThread(&IDBConnectionToServer::commitTransaction, transaction.info().identifier()); +} + +void IDBConnectionProxy::didCommitTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError& error) +{ + RefPtr<IDBTransaction> transaction; + { + Locker<Lock> locker(m_transactionMapLock); + transaction = m_committingTransactions.take(transactionIdentifier); + } + + if (!transaction) + return; + + transaction->performCallbackOnOriginThread(*transaction, &IDBTransaction::didCommit, error); +} + +void IDBConnectionProxy::abortTransaction(IDBTransaction& transaction) +{ + { + Locker<Lock> locker(m_transactionMapLock); + ASSERT(!m_abortingTransactions.contains(transaction.info().identifier())); + m_abortingTransactions.set(transaction.info().identifier(), &transaction); + } + + callConnectionOnMainThread(&IDBConnectionToServer::abortTransaction, transaction.info().identifier()); +} + +void IDBConnectionProxy::didAbortTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError& error) +{ + RefPtr<IDBTransaction> transaction; + { + Locker<Lock> locker(m_transactionMapLock); + transaction = m_abortingTransactions.take(transactionIdentifier); + } + + if (!transaction) + return; + + transaction->performCallbackOnOriginThread(*transaction, &IDBTransaction::didAbort, error); +} + +bool IDBConnectionProxy::hasRecordOfTransaction(const IDBTransaction& transaction) const +{ + ASSERT(m_transactionMapLock.isLocked()); + + auto identifier = transaction.info().identifier(); + return m_pendingTransactions.contains(identifier) || m_committingTransactions.contains(identifier) || m_abortingTransactions.contains(identifier); +} + +void IDBConnectionProxy::didFinishHandlingVersionChangeTransaction(uint64_t databaseConnectionIdentifier, IDBTransaction& transaction) +{ + callConnectionOnMainThread(&IDBConnectionToServer::didFinishHandlingVersionChangeTransaction, databaseConnectionIdentifier, transaction.info().identifier()); +} + +void IDBConnectionProxy::databaseConnectionPendingClose(IDBDatabase& database) +{ + callConnectionOnMainThread(&IDBConnectionToServer::databaseConnectionPendingClose, database.databaseConnectionIdentifier()); +} + +void IDBConnectionProxy::databaseConnectionClosed(IDBDatabase& database) +{ + callConnectionOnMainThread(&IDBConnectionToServer::databaseConnectionClosed, database.databaseConnectionIdentifier()); +} + +void IDBConnectionProxy::didCloseFromServer(uint64_t databaseConnectionIdentifier, const IDBError& error) +{ + RefPtr<IDBDatabase> database; + { + Locker<Lock> locker(m_databaseConnectionMapLock); + database = m_databaseConnectionMap.get(databaseConnectionIdentifier); + } + + // If the IDBDatabase object is gone, message back to the server so it doesn't hang + // waiting for a reply that will never come. + if (!database) { + m_connectionToServer.confirmDidCloseFromServer(databaseConnectionIdentifier); + return; + } + + database->performCallbackOnOriginThread(*database, &IDBDatabase::didCloseFromServer, error); +} + +void IDBConnectionProxy::confirmDidCloseFromServer(IDBDatabase& database) +{ + callConnectionOnMainThread(&IDBConnectionToServer::confirmDidCloseFromServer, database.databaseConnectionIdentifier()); +} + +void IDBConnectionProxy::connectionToServerLost(const IDBError& error) +{ + Vector<uint64_t> databaseConnectionIdentifiers; + { + Locker<Lock> locker(m_databaseConnectionMapLock); + copyKeysToVector(m_databaseConnectionMap, databaseConnectionIdentifiers); + } + + for (auto connectionIdentifier : databaseConnectionIdentifiers) { + RefPtr<IDBDatabase> database; + { + Locker<Lock> locker(m_databaseConnectionMapLock); + database = m_databaseConnectionMap.get(connectionIdentifier); + } + + if (!database) + continue; + + database->performCallbackOnOriginThread(*database, &IDBDatabase::connectionToServerLost, error); + } + + Vector<IDBResourceIdentifier> openDBRequestIdentifiers; + { + Locker<Lock> locker(m_openDBRequestMapLock); + copyKeysToVector(m_openDBRequestMap, openDBRequestIdentifiers); + } + + for (auto& requestIdentifier : openDBRequestIdentifiers) { + RefPtr<IDBOpenDBRequest> request; + { + Locker<Lock> locker(m_openDBRequestMapLock); + request = m_openDBRequestMap.get(requestIdentifier); + } + + if (!request) + continue; + + auto result = IDBResultData::error(requestIdentifier, error); + request->performCallbackOnOriginThread(*request, &IDBOpenDBRequest::requestCompleted, result); + } +} + +void IDBConnectionProxy::scheduleMainThreadTasks() +{ + Locker<Lock> locker(m_mainThreadTaskLock); + if (m_mainThreadProtector) + return; + + m_mainThreadProtector = &m_connectionToServer; + callOnMainThread([this] { + handleMainThreadTasks(); + }); +} + +void IDBConnectionProxy::handleMainThreadTasks() +{ + RefPtr<IDBConnectionToServer> protector; + { + Locker<Lock> locker(m_mainThreadTaskLock); + ASSERT(m_mainThreadProtector); + protector = WTFMove(m_mainThreadProtector); + } + + while (auto task = m_mainThreadQueue.tryGetMessage()) + task->performTask(); +} + +void IDBConnectionProxy::getAllDatabaseNames(const SecurityOrigin& mainFrameOrigin, const SecurityOrigin& openingOrigin, std::function<void (const Vector<String>&)> callback) +{ + // This method is only meant to be called by the web inspector on the main thread. + RELEASE_ASSERT(isMainThread()); + + m_connectionToServer.getAllDatabaseNames(mainFrameOrigin, openingOrigin, callback); +} + +void IDBConnectionProxy::registerDatabaseConnection(IDBDatabase& database) +{ + Locker<Lock> locker(m_databaseConnectionMapLock); + + ASSERT(!m_databaseConnectionMap.contains(database.databaseConnectionIdentifier())); + m_databaseConnectionMap.set(database.databaseConnectionIdentifier(), &database); +} + +void IDBConnectionProxy::unregisterDatabaseConnection(IDBDatabase& database) +{ + Locker<Lock> locker(m_databaseConnectionMapLock); + + ASSERT(!m_databaseConnectionMap.contains(database.databaseConnectionIdentifier()) || m_databaseConnectionMap.get(database.databaseConnectionIdentifier()) == &database); + m_databaseConnectionMap.remove(database.databaseConnectionIdentifier()); +} + +void IDBConnectionProxy::forgetActiveOperations(const Vector<RefPtr<TransactionOperation>>& operations) +{ + Locker<Lock> locker(m_transactionOperationLock); + + for (auto& operation : operations) + m_activeOperations.remove(operation->identifier()); +} + +template<typename KeyType, typename ValueType> +void removeItemsMatchingCurrentThread(HashMap<KeyType, ValueType>& map) +{ + auto currentThreadID = currentThread(); + + Vector<KeyType> keys; + keys.reserveInitialCapacity(map.size()); + for (auto& iterator : map) { + if (iterator.value->originThreadID() == currentThreadID) + keys.uncheckedAppend(iterator.key); + } + + for (auto& key : keys) + map.remove(key); +} + +void IDBConnectionProxy::forgetActivityForCurrentThread() +{ + ASSERT(!isMainThread()); + + { + Locker<Lock> lock(m_databaseConnectionMapLock); + removeItemsMatchingCurrentThread(m_databaseConnectionMap); + } + { + Locker<Lock> lock(m_openDBRequestMapLock); + removeItemsMatchingCurrentThread(m_openDBRequestMap); + } + { + Locker<Lock> lock(m_transactionMapLock); + removeItemsMatchingCurrentThread(m_pendingTransactions); + removeItemsMatchingCurrentThread(m_committingTransactions); + removeItemsMatchingCurrentThread(m_abortingTransactions); + } + { + Locker<Lock> lock(m_transactionOperationLock); + removeItemsMatchingCurrentThread(m_activeOperations); + } +} + +} // namesapce IDBClient +} // namespace WebCore + +#endif // ENABLE(INDEXED_DATABASE) diff --git a/Source/WebCore/Modules/indexeddb/client/IDBConnectionProxy.h b/Source/WebCore/Modules/indexeddb/client/IDBConnectionProxy.h new file mode 100644 index 000000000..5c01ac34c --- /dev/null +++ b/Source/WebCore/Modules/indexeddb/client/IDBConnectionProxy.h @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if ENABLE(INDEXED_DATABASE) + +#include "IDBConnectionToServer.h" +#include "IDBResourceIdentifier.h" +#include "TransactionOperation.h" +#include <functional> +#include <wtf/CrossThreadQueue.h> +#include <wtf/CrossThreadTask.h> +#include <wtf/HashMap.h> +#include <wtf/MainThread.h> +#include <wtf/RefPtr.h> +#include <wtf/Vector.h> +#include <wtf/text/WTFString.h> + +namespace WebCore { + +class IDBDatabase; +class IDBDatabaseIdentifier; +class IDBError; +class IDBOpenDBRequest; +class IDBResultData; +class IDBTransaction; +class ScriptExecutionContext; +class SecurityOrigin; + +struct IDBGetRecordData; +struct IDBIterateCursorData; + +namespace IDBClient { + +class IDBConnectionToServer; + +class IDBConnectionProxy { +public: + IDBConnectionProxy(IDBConnectionToServer&); + + Ref<IDBOpenDBRequest> openDatabase(ScriptExecutionContext&, const IDBDatabaseIdentifier&, uint64_t version); + void didOpenDatabase(const IDBResultData&); + + Ref<IDBOpenDBRequest> deleteDatabase(ScriptExecutionContext&, const IDBDatabaseIdentifier&); + void didDeleteDatabase(const IDBResultData&); + + void createObjectStore(TransactionOperation&, const IDBObjectStoreInfo&); + void deleteObjectStore(TransactionOperation&, const String& objectStoreName); + void clearObjectStore(TransactionOperation&, uint64_t objectStoreIdentifier); + void createIndex(TransactionOperation&, const IDBIndexInfo&); + void deleteIndex(TransactionOperation&, uint64_t objectStoreIdentifier, const String& indexName); + void putOrAdd(TransactionOperation&, IDBKeyData&&, const IDBValue&, const IndexedDB::ObjectStoreOverwriteMode); + void getRecord(TransactionOperation&, const IDBGetRecordData&); + void getAllRecords(TransactionOperation&, const IDBGetAllRecordsData&); + void getCount(TransactionOperation&, const IDBKeyRangeData&); + void deleteRecord(TransactionOperation&, const IDBKeyRangeData&); + void openCursor(TransactionOperation&, const IDBCursorInfo&); + void iterateCursor(TransactionOperation&, const IDBIterateCursorData&); + void renameObjectStore(TransactionOperation&, uint64_t objectStoreIdentifier, const String& newName); + void renameIndex(TransactionOperation&, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const String& newName); + + void fireVersionChangeEvent(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& requestIdentifier, uint64_t requestedVersion); + void didFireVersionChangeEvent(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& requestIdentifier); + + void notifyOpenDBRequestBlocked(const IDBResourceIdentifier& requestIdentifier, uint64_t oldVersion, uint64_t newVersion); + void openDBRequestCancelled(const IDBRequestData&); + + void establishTransaction(IDBTransaction&); + void commitTransaction(IDBTransaction&); + void abortTransaction(IDBTransaction&); + + void didStartTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError&); + void didCommitTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError&); + void didAbortTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError&); + + void didFinishHandlingVersionChangeTransaction(uint64_t databaseConnectionIdentifier, IDBTransaction&); + void databaseConnectionPendingClose(IDBDatabase&); + void databaseConnectionClosed(IDBDatabase&); + + void didCloseFromServer(uint64_t databaseConnectionIdentifier, const IDBError&); + void confirmDidCloseFromServer(IDBDatabase&); + + void connectionToServerLost(const IDBError&); + + void abortOpenAndUpgradeNeeded(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& transactionIdentifier); + + void completeOperation(const IDBResultData&); + + uint64_t serverConnectionIdentifier() const { return m_serverConnectionIdentifier; } + + void ref(); + void deref(); + + void getAllDatabaseNames(const SecurityOrigin& mainFrameOrigin, const SecurityOrigin& openingOrigin, std::function<void (const Vector<String>&)>); + + void registerDatabaseConnection(IDBDatabase&); + void unregisterDatabaseConnection(IDBDatabase&); + + void forgetActiveOperations(const Vector<RefPtr<TransactionOperation>>&); + void forgetActivityForCurrentThread(); + +private: + void completeOpenDBRequest(const IDBResultData&); + bool hasRecordOfTransaction(const IDBTransaction&) const; + + void saveOperation(TransactionOperation&); + + template<typename... Parameters, typename... Arguments> + void callConnectionOnMainThread(void (IDBConnectionToServer::*method)(Parameters...), Arguments&&... arguments) + { + if (isMainThread()) + (m_connectionToServer.*method)(std::forward<Arguments>(arguments)...); + else + postMainThreadTask(m_connectionToServer, method, arguments...); + } + + template<typename... Arguments> + void postMainThreadTask(Arguments&&... arguments) + { + auto task = createCrossThreadTask(arguments...); + m_mainThreadQueue.append(WTFMove(task)); + + scheduleMainThreadTasks(); + } + + void scheduleMainThreadTasks(); + void handleMainThreadTasks(); + + IDBConnectionToServer& m_connectionToServer; + uint64_t m_serverConnectionIdentifier; + + HashMap<uint64_t, IDBDatabase*> m_databaseConnectionMap; + Lock m_databaseConnectionMapLock; + + HashMap<IDBResourceIdentifier, RefPtr<IDBOpenDBRequest>> m_openDBRequestMap; + Lock m_openDBRequestMapLock; + + HashMap<IDBResourceIdentifier, RefPtr<IDBTransaction>> m_pendingTransactions; + HashMap<IDBResourceIdentifier, RefPtr<IDBTransaction>> m_committingTransactions; + HashMap<IDBResourceIdentifier, RefPtr<IDBTransaction>> m_abortingTransactions; + Lock m_transactionMapLock; + + HashMap<IDBResourceIdentifier, RefPtr<TransactionOperation>> m_activeOperations; + Lock m_transactionOperationLock; + + CrossThreadQueue<CrossThreadTask> m_mainThreadQueue; + Lock m_mainThreadTaskLock; + RefPtr<IDBConnectionToServer> m_mainThreadProtector; +}; + +} // namespace IDBClient +} // namespace WebCore + +#endif // ENABLE(INDEXED_DATABASE) diff --git a/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServer.cpp b/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServer.cpp new file mode 100644 index 000000000..75c5773a5 --- /dev/null +++ b/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServer.cpp @@ -0,0 +1,446 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "IDBConnectionToServer.h" + +#if ENABLE(INDEXED_DATABASE) + +#include "IDBConnectionProxy.h" +#include "IDBDatabase.h" +#include "IDBGetRecordData.h" +#include "IDBKeyRangeData.h" +#include "IDBOpenDBRequest.h" +#include "IDBRequestData.h" +#include "IDBResultData.h" +#include "Logging.h" +#include "TransactionOperation.h" +#include <wtf/MainThread.h> + +namespace WebCore { +namespace IDBClient { + +Ref<IDBConnectionToServer> IDBConnectionToServer::create(IDBConnectionToServerDelegate& delegate) +{ + return adoptRef(*new IDBConnectionToServer(delegate)); +} + +IDBConnectionToServer::IDBConnectionToServer(IDBConnectionToServerDelegate& delegate) + : m_delegate(delegate) + , m_proxy(std::make_unique<IDBConnectionProxy>(*this)) +{ +} + +uint64_t IDBConnectionToServer::identifier() const +{ + return m_delegate->identifier(); +} + +IDBConnectionProxy& IDBConnectionToServer::proxy() +{ + ASSERT(m_proxy); + return *m_proxy; +} + +void IDBConnectionToServer::deleteDatabase(const IDBRequestData& request) +{ + LOG(IndexedDB, "IDBConnectionToServer::deleteDatabase - %s", request.databaseIdentifier().debugString().utf8().data()); + m_delegate->deleteDatabase(request); +} + +void IDBConnectionToServer::didDeleteDatabase(const IDBResultData& resultData) +{ + LOG(IndexedDB, "IDBConnectionToServer::didDeleteDatabase"); + m_proxy->didDeleteDatabase(resultData); +} + +void IDBConnectionToServer::openDatabase(const IDBRequestData& request) +{ + LOG(IndexedDB, "IDBConnectionToServer::openDatabase - %s (%s) (%" PRIu64 ")", request.databaseIdentifier().debugString().utf8().data(), request.requestIdentifier().loggingString().utf8().data(), request.requestedVersion()); + m_delegate->openDatabase(request); +} + +void IDBConnectionToServer::didOpenDatabase(const IDBResultData& resultData) +{ + LOG(IndexedDB, "IDBConnectionToServer::didOpenDatabase"); + m_proxy->didOpenDatabase(resultData); +} + +void IDBConnectionToServer::createObjectStore(const IDBRequestData& requestData, const IDBObjectStoreInfo& info) +{ + LOG(IndexedDB, "IDBConnectionToServer::createObjectStore"); + ASSERT(isMainThread()); + + m_delegate->createObjectStore(requestData, info); +} + +void IDBConnectionToServer::didCreateObjectStore(const IDBResultData& resultData) +{ + LOG(IndexedDB, "IDBConnectionToServer::didCreateObjectStore"); + m_proxy->completeOperation(resultData); +} + +void IDBConnectionToServer::deleteObjectStore(const IDBRequestData& requestData, const String& objectStoreName) +{ + LOG(IndexedDB, "IDBConnectionToServer::deleteObjectStore"); + ASSERT(isMainThread()); + + m_delegate->deleteObjectStore(requestData, objectStoreName); +} + +void IDBConnectionToServer::didDeleteObjectStore(const IDBResultData& resultData) +{ + LOG(IndexedDB, "IDBConnectionToServer::didDeleteObjectStore"); + m_proxy->completeOperation(resultData); +} + +void IDBConnectionToServer::renameObjectStore(const IDBRequestData& requestData, uint64_t objectStoreIdentifier, const String& newName) +{ + LOG(IndexedDB, "IDBConnectionToServer::renameObjectStore"); + ASSERT(isMainThread()); + + m_delegate->renameObjectStore(requestData, objectStoreIdentifier, newName); +} + +void IDBConnectionToServer::didRenameObjectStore(const IDBResultData& resultData) +{ + LOG(IndexedDB, "IDBConnectionToServer::didRenameObjectStore"); + m_proxy->completeOperation(resultData); +} + +void IDBConnectionToServer::clearObjectStore(const IDBRequestData& requestData, uint64_t objectStoreIdentifier) +{ + LOG(IndexedDB, "IDBConnectionToServer::clearObjectStore"); + ASSERT(isMainThread()); + + m_delegate->clearObjectStore(requestData, objectStoreIdentifier); +} + +void IDBConnectionToServer::didClearObjectStore(const IDBResultData& resultData) +{ + LOG(IndexedDB, "IDBConnectionToServer::didClearObjectStore"); + m_proxy->completeOperation(resultData); +} + +void IDBConnectionToServer::createIndex(const IDBRequestData& requestData, const IDBIndexInfo& info) +{ + LOG(IndexedDB, "IDBConnectionToServer::createIndex"); + ASSERT(isMainThread()); + + m_delegate->createIndex(requestData, info); +} + +void IDBConnectionToServer::didCreateIndex(const IDBResultData& resultData) +{ + LOG(IndexedDB, "IDBConnectionToServer::didCreateIndex"); + m_proxy->completeOperation(resultData); +} + +void IDBConnectionToServer::deleteIndex(const IDBRequestData& requestData, uint64_t objectStoreIdentifier, const String& indexName) +{ + LOG(IndexedDB, "IDBConnectionToServer::deleteIndex"); + ASSERT(isMainThread()); + + m_delegate->deleteIndex(requestData, objectStoreIdentifier, indexName); +} + +void IDBConnectionToServer::didDeleteIndex(const IDBResultData& resultData) +{ + LOG(IndexedDB, "IDBConnectionToServer::didDeleteIndex"); + m_proxy->completeOperation(resultData); +} + +void IDBConnectionToServer::renameIndex(const IDBRequestData& requestData, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const String& newName) +{ + LOG(IndexedDB, "IDBConnectionToServer::renameIndex"); + ASSERT(isMainThread()); + + m_delegate->renameIndex(requestData, objectStoreIdentifier, indexIdentifier, newName); +} + +void IDBConnectionToServer::didRenameIndex(const IDBResultData& resultData) +{ + LOG(IndexedDB, "IDBConnectionToServer::didRenameIndex"); + m_proxy->completeOperation(resultData); +} + +void IDBConnectionToServer::putOrAdd(const IDBRequestData& requestData, const IDBKeyData& key, const IDBValue& value, const IndexedDB::ObjectStoreOverwriteMode overwriteMode) +{ + LOG(IndexedDB, "IDBConnectionToServer::putOrAdd"); + ASSERT(isMainThread()); + + m_delegate->putOrAdd(requestData, key, value, overwriteMode); +} + +void IDBConnectionToServer::didPutOrAdd(const IDBResultData& resultData) +{ + LOG(IndexedDB, "IDBConnectionToServer::didPutOrAdd"); + m_proxy->completeOperation(resultData); +} + +void IDBConnectionToServer::getRecord(const IDBRequestData& requestData, const IDBGetRecordData& getRecordData) +{ + LOG(IndexedDB, "IDBConnectionToServer::getRecord"); + ASSERT(isMainThread()); + ASSERT(!getRecordData.keyRangeData.isNull); + + m_delegate->getRecord(requestData, getRecordData); +} + +void IDBConnectionToServer::didGetRecord(const IDBResultData& resultData) +{ + LOG(IndexedDB, "IDBConnectionToServer::didGetRecord"); + m_proxy->completeOperation(resultData); +} + +void IDBConnectionToServer::getAllRecords(const IDBRequestData& requestData, const IDBGetAllRecordsData& getAllRecordsData) +{ + LOG(IndexedDB, "IDBConnectionToServer::getAllRecords"); + ASSERT(isMainThread()); + + m_delegate->getAllRecords(requestData, getAllRecordsData); +} + +void IDBConnectionToServer::didGetAllRecords(const IDBResultData& resultData) +{ + LOG(IndexedDB, "IDBConnectionToServer::didGetAllRecords"); + m_proxy->completeOperation(resultData); +} + +void IDBConnectionToServer::getCount(const IDBRequestData& requestData, const IDBKeyRangeData& keyRangeData) +{ + LOG(IndexedDB, "IDBConnectionToServer::getCount"); + ASSERT(isMainThread()); + ASSERT(!keyRangeData.isNull); + + m_delegate->getCount(requestData, keyRangeData); +} + +void IDBConnectionToServer::didGetCount(const IDBResultData& resultData) +{ + LOG(IndexedDB, "IDBConnectionToServer::didGetCount"); + m_proxy->completeOperation(resultData); +} + +void IDBConnectionToServer::deleteRecord(const IDBRequestData& requestData, const IDBKeyRangeData& keyRangeData) +{ + LOG(IndexedDB, "IDBConnectionToServer::deleteRecord"); + ASSERT(isMainThread()); + ASSERT(!keyRangeData.isNull); + + m_delegate->deleteRecord(requestData, keyRangeData); +} + +void IDBConnectionToServer::didDeleteRecord(const IDBResultData& resultData) +{ + LOG(IndexedDB, "IDBConnectionToServer::didDeleteRecord"); + m_proxy->completeOperation(resultData); +} + +void IDBConnectionToServer::openCursor(const IDBRequestData& requestData, const IDBCursorInfo& info) +{ + LOG(IndexedDB, "IDBConnectionToServer::openCursor"); + ASSERT(isMainThread()); + + m_delegate->openCursor(requestData, info); +} + +void IDBConnectionToServer::didOpenCursor(const IDBResultData& resultData) +{ + LOG(IndexedDB, "IDBConnectionToServer::didOpenCursor"); + m_proxy->completeOperation(resultData); +} + +void IDBConnectionToServer::iterateCursor(const IDBRequestData& requestData, const IDBIterateCursorData& data) +{ + LOG(IndexedDB, "IDBConnectionToServer::iterateCursor"); + ASSERT(isMainThread()); + + m_delegate->iterateCursor(requestData, data); +} + +void IDBConnectionToServer::didIterateCursor(const IDBResultData& resultData) +{ + LOG(IndexedDB, "IDBConnectionToServer::didIterateCursor"); + m_proxy->completeOperation(resultData); +} + +void IDBConnectionToServer::establishTransaction(uint64_t databaseConnectionIdentifier, const IDBTransactionInfo& info) +{ + LOG(IndexedDB, "IDBConnectionToServer::establishTransaction"); + ASSERT(isMainThread()); + + m_delegate->establishTransaction(databaseConnectionIdentifier, info); +} + +void IDBConnectionToServer::commitTransaction(const IDBResourceIdentifier& transactionIdentifier) +{ + LOG(IndexedDB, "IDBConnectionToServer::commitTransaction"); + ASSERT(isMainThread()); + + m_delegate->commitTransaction(transactionIdentifier); +} + +void IDBConnectionToServer::didCommitTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError& error) +{ + LOG(IndexedDB, "IDBConnectionToServer::didCommitTransaction"); + ASSERT(isMainThread()); + + m_proxy->didCommitTransaction(transactionIdentifier, error); +} + +void IDBConnectionToServer::didFinishHandlingVersionChangeTransaction(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& transactionIdentifier) +{ + LOG(IndexedDB, "IDBConnectionToServer::didFinishHandlingVersionChangeTransaction"); + ASSERT(isMainThread()); + + m_delegate->didFinishHandlingVersionChangeTransaction(databaseConnectionIdentifier, transactionIdentifier); +} + +void IDBConnectionToServer::abortTransaction(const IDBResourceIdentifier& transactionIdentifier) +{ + LOG(IndexedDB, "IDBConnectionToServer::abortTransaction"); + ASSERT(isMainThread()); + + m_delegate->abortTransaction(transactionIdentifier); +} + +void IDBConnectionToServer::didAbortTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError& error) +{ + LOG(IndexedDB, "IDBConnectionToServer::didAbortTransaction"); + ASSERT(isMainThread()); + + m_proxy->didAbortTransaction(transactionIdentifier, error); +} + +void IDBConnectionToServer::fireVersionChangeEvent(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& requestIdentifier, uint64_t requestedVersion) +{ + LOG(IndexedDB, "IDBConnectionToServer::fireVersionChangeEvent"); + ASSERT(isMainThread()); + + m_proxy->fireVersionChangeEvent(databaseConnectionIdentifier, requestIdentifier, requestedVersion); +} + +void IDBConnectionToServer::didFireVersionChangeEvent(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& requestIdentifier) +{ + LOG(IndexedDB, "IDBConnectionToServer::didFireVersionChangeEvent"); + ASSERT(isMainThread()); + + m_delegate->didFireVersionChangeEvent(databaseConnectionIdentifier, requestIdentifier); +} + +void IDBConnectionToServer::didStartTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError& error) +{ + LOG(IndexedDB, "IDBConnectionToServer::didStartTransaction"); + ASSERT(isMainThread()); + + m_proxy->didStartTransaction(transactionIdentifier, error); +} + +void IDBConnectionToServer::didCloseFromServer(uint64_t databaseConnectionIdentifier, const IDBError& error) +{ + LOG(IndexedDB, "IDBConnectionToServer::didCloseFromServer"); + ASSERT(isMainThread()); + + m_proxy->didCloseFromServer(databaseConnectionIdentifier, error); +} + +void IDBConnectionToServer::confirmDidCloseFromServer(uint64_t databaseConnectionIdentifier) +{ + LOG(IndexedDB, "IDBConnectionToServer::confirmDidCloseFromServer"); + ASSERT(isMainThread()); + + m_delegate->confirmDidCloseFromServer(databaseConnectionIdentifier); +} + +void IDBConnectionToServer::connectionToServerLost(const IDBError& error) +{ + LOG(IndexedDB, "IDBConnectionToServer::connectionToServerLost"); + ASSERT(isMainThread()); + + m_proxy->connectionToServerLost(error); +} + +void IDBConnectionToServer::notifyOpenDBRequestBlocked(const IDBResourceIdentifier& requestIdentifier, uint64_t oldVersion, uint64_t newVersion) +{ + LOG(IndexedDB, "IDBConnectionToServer::didStartTransaction"); + ASSERT(isMainThread()); + + m_proxy->notifyOpenDBRequestBlocked(requestIdentifier, oldVersion, newVersion); +} + +void IDBConnectionToServer::openDBRequestCancelled(const IDBRequestData& requestData) +{ + LOG(IndexedDB, "IDBConnectionToServer::openDBRequestCancelled"); + ASSERT(isMainThread()); + + m_delegate->openDBRequestCancelled(requestData); +} + +void IDBConnectionToServer::databaseConnectionPendingClose(uint64_t databaseConnectionIdentifier) +{ + LOG(IndexedDB, "IDBConnectionToServer::databaseConnectionPendingClose"); + ASSERT(isMainThread()); + + m_delegate->databaseConnectionPendingClose(databaseConnectionIdentifier); +} + +void IDBConnectionToServer::databaseConnectionClosed(uint64_t databaseConnectionIdentifier) +{ + LOG(IndexedDB, "IDBConnectionToServer::databaseConnectionClosed"); + ASSERT(isMainThread()); + + m_delegate->databaseConnectionClosed(databaseConnectionIdentifier); +} + +void IDBConnectionToServer::abortOpenAndUpgradeNeeded(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& transactionIdentifier) +{ + LOG(IndexedDB, "IDBConnectionToServer::abortOpenAndUpgradeNeeded"); + ASSERT(isMainThread()); + + m_delegate->abortOpenAndUpgradeNeeded(databaseConnectionIdentifier, transactionIdentifier); +} + +void IDBConnectionToServer::getAllDatabaseNames(const SecurityOrigin& mainFrameOrigin, const SecurityOrigin& openingOrigin, std::function<void (const Vector<String>&)> callback) +{ + static uint64_t callbackID = 0; + + m_getAllDatabaseNamesCallbacks.add(++callbackID, WTFMove(callback)); + + m_delegate->getAllDatabaseNames(SecurityOriginData::fromSecurityOrigin(mainFrameOrigin), SecurityOriginData::fromSecurityOrigin(openingOrigin), callbackID); +} + +void IDBConnectionToServer::didGetAllDatabaseNames(uint64_t callbackID, const Vector<String>& databaseNames) +{ + auto callback = m_getAllDatabaseNamesCallbacks.take(callbackID); + ASSERT(callback); + + callback(databaseNames); +} + +} // namespace IDBClient +} // namespace WebCore + +#endif // ENABLE(INDEXED_DATABASE) diff --git a/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServer.h b/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServer.h new file mode 100644 index 000000000..7651f4305 --- /dev/null +++ b/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServer.h @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2015, 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if ENABLE(INDEXED_DATABASE) + +#include "IDBConnectionProxy.h" +#include "IDBConnectionToServerDelegate.h" +#include "IDBResourceIdentifier.h" +#include <wtf/HashMap.h> +#include <wtf/Ref.h> +#include <wtf/ThreadSafeRefCounted.h> + +namespace WebCore { + +class IDBCursorInfo; +class IDBDatabase; +class IDBError; +class IDBObjectStoreInfo; +class IDBResultData; +class IDBValue; +class SecurityOrigin; + +struct IDBGetAllRecordsData; +struct IDBGetRecordData; +struct IDBIterateCursorData; + +namespace IDBClient { + +class IDBConnectionToServer : public ThreadSafeRefCounted<IDBConnectionToServer> { +public: + WEBCORE_EXPORT static Ref<IDBConnectionToServer> create(IDBConnectionToServerDelegate&); + + uint64_t identifier() const; + + IDBConnectionProxy& proxy(); + + void deleteDatabase(const IDBRequestData&); + WEBCORE_EXPORT void didDeleteDatabase(const IDBResultData&); + + void openDatabase(const IDBRequestData&); + WEBCORE_EXPORT void didOpenDatabase(const IDBResultData&); + + void createObjectStore(const IDBRequestData&, const IDBObjectStoreInfo&); + WEBCORE_EXPORT void didCreateObjectStore(const IDBResultData&); + + void deleteObjectStore(const IDBRequestData&, const String& objectStoreName); + WEBCORE_EXPORT void didDeleteObjectStore(const IDBResultData&); + + void renameObjectStore(const IDBRequestData&, uint64_t objectStoreIdentifier, const String& newName); + WEBCORE_EXPORT void didRenameObjectStore(const IDBResultData&); + + void clearObjectStore(const IDBRequestData&, uint64_t objectStoreIdentifier); + WEBCORE_EXPORT void didClearObjectStore(const IDBResultData&); + + void createIndex(const IDBRequestData&, const IDBIndexInfo&); + WEBCORE_EXPORT void didCreateIndex(const IDBResultData&); + + void deleteIndex(const IDBRequestData&, uint64_t objectStoreIdentifier, const String& indexName); + WEBCORE_EXPORT void didDeleteIndex(const IDBResultData&); + + void renameIndex(const IDBRequestData&, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const String& newName); + WEBCORE_EXPORT void didRenameIndex(const IDBResultData&); + + void putOrAdd(const IDBRequestData&, const IDBKeyData&, const IDBValue&, const IndexedDB::ObjectStoreOverwriteMode); + WEBCORE_EXPORT void didPutOrAdd(const IDBResultData&); + + void getRecord(const IDBRequestData&, const IDBGetRecordData&); + WEBCORE_EXPORT void didGetRecord(const IDBResultData&); + + void getAllRecords(const IDBRequestData&, const IDBGetAllRecordsData&); + WEBCORE_EXPORT void didGetAllRecords(const IDBResultData&); + + void getCount(const IDBRequestData&, const IDBKeyRangeData&); + WEBCORE_EXPORT void didGetCount(const IDBResultData&); + + void deleteRecord(const IDBRequestData&, const IDBKeyRangeData&); + WEBCORE_EXPORT void didDeleteRecord(const IDBResultData&); + + void openCursor(const IDBRequestData&, const IDBCursorInfo&); + WEBCORE_EXPORT void didOpenCursor(const IDBResultData&); + + void iterateCursor(const IDBRequestData&, const IDBIterateCursorData&); + WEBCORE_EXPORT void didIterateCursor(const IDBResultData&); + + void commitTransaction(const IDBResourceIdentifier& transactionIdentifier); + WEBCORE_EXPORT void didCommitTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError&); + + void didFinishHandlingVersionChangeTransaction(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier&); + + void abortTransaction(const IDBResourceIdentifier& transactionIdentifier); + WEBCORE_EXPORT void didAbortTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError&); + + WEBCORE_EXPORT void fireVersionChangeEvent(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& requestIdentifier, uint64_t requestedVersion); + void didFireVersionChangeEvent(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& requestIdentifier); + + WEBCORE_EXPORT void didStartTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError&); + + WEBCORE_EXPORT void didCloseFromServer(uint64_t databaseConnectionIdentifier, const IDBError&); + void confirmDidCloseFromServer(uint64_t databaseConnectionIdentifier); + + WEBCORE_EXPORT void connectionToServerLost(const IDBError&); + + WEBCORE_EXPORT void notifyOpenDBRequestBlocked(const IDBResourceIdentifier& requestIdentifier, uint64_t oldVersion, uint64_t newVersion); + void openDBRequestCancelled(const IDBRequestData&); + + void establishTransaction(uint64_t databaseConnectionIdentifier, const IDBTransactionInfo&); + + void databaseConnectionPendingClose(uint64_t databaseConnectionIdentifier); + void databaseConnectionClosed(uint64_t databaseConnectionIdentifier); + + // To be used when an IDBOpenDBRequest gets a new database connection, optionally with a + // versionchange transaction, but the page is already torn down. + void abortOpenAndUpgradeNeeded(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& transactionIdentifier); + + void getAllDatabaseNames(const SecurityOrigin& mainFrameOrigin, const SecurityOrigin& openingOrigin, std::function<void (const Vector<String>&)>); + WEBCORE_EXPORT void didGetAllDatabaseNames(uint64_t callbackID, const Vector<String>& databaseNames); + +private: + IDBConnectionToServer(IDBConnectionToServerDelegate&); + + Ref<IDBConnectionToServerDelegate> m_delegate; + + HashMap<uint64_t, std::function<void (const Vector<String>&)>> m_getAllDatabaseNamesCallbacks; + + std::unique_ptr<IDBConnectionProxy> m_proxy; +}; + +} // namespace IDBClient +} // namespace WebCore + +#endif // ENABLE(INDEXED_DATABASE) diff --git a/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServerDelegate.h b/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServerDelegate.h new file mode 100644 index 000000000..a61c283a2 --- /dev/null +++ b/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServerDelegate.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2015, 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if ENABLE(INDEXED_DATABASE) + +#include <wtf/text/WTFString.h> + +namespace WebCore { + +class IDBCursorInfo; +class IDBIndexInfo; +class IDBKeyData; +class IDBObjectStoreInfo; +class IDBRequestData; +class IDBResourceIdentifier; +class IDBTransactionInfo; +class IDBValue; + +struct IDBGetAllRecordsData; +struct IDBGetRecordData; +struct IDBIterateCursorData; +struct SecurityOriginData; + +namespace IndexedDB { +enum class ObjectStoreOverwriteMode; +} + +struct IDBKeyRangeData; + +namespace IDBClient { + +class IDBConnectionToServerDelegate { +public: + virtual ~IDBConnectionToServerDelegate() { } + + virtual uint64_t identifier() const = 0; + virtual void deleteDatabase(const IDBRequestData&) = 0; + virtual void openDatabase(const IDBRequestData&) = 0; + virtual void abortTransaction(const IDBResourceIdentifier&) = 0; + virtual void commitTransaction(const IDBResourceIdentifier&) = 0; + virtual void didFinishHandlingVersionChangeTransaction(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier&) = 0; + virtual void createObjectStore(const IDBRequestData&, const IDBObjectStoreInfo&) = 0; + virtual void deleteObjectStore(const IDBRequestData&, const String& objectStoreName) = 0; + virtual void renameObjectStore(const IDBRequestData&, uint64_t objectStoreIdentifier, const String& newName) = 0; + virtual void clearObjectStore(const IDBRequestData&, uint64_t objectStoreIdentifier) = 0; + virtual void createIndex(const IDBRequestData&, const IDBIndexInfo&) = 0; + virtual void deleteIndex(const IDBRequestData&, uint64_t objectStoreIdentifier, const String& indexName) = 0; + virtual void renameIndex(const IDBRequestData&, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const String& newName) = 0; + virtual void putOrAdd(const IDBRequestData&, const IDBKeyData&, const IDBValue&, const IndexedDB::ObjectStoreOverwriteMode) = 0; + virtual void getRecord(const IDBRequestData&, const IDBGetRecordData&) = 0; + virtual void getAllRecords(const IDBRequestData&, const IDBGetAllRecordsData&) = 0; + virtual void getCount(const IDBRequestData&, const IDBKeyRangeData&) = 0; + virtual void deleteRecord(const IDBRequestData&, const IDBKeyRangeData&) = 0; + virtual void openCursor(const IDBRequestData&, const IDBCursorInfo&) = 0; + virtual void iterateCursor(const IDBRequestData&, const IDBIterateCursorData&) = 0; + + virtual void establishTransaction(uint64_t databaseConnectionIdentifier, const IDBTransactionInfo&) = 0; + virtual void databaseConnectionPendingClose(uint64_t databaseConnectionIdentifier) = 0; + virtual void databaseConnectionClosed(uint64_t databaseConnectionIdentifier) = 0; + virtual void abortOpenAndUpgradeNeeded(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& transactionIdentifier) = 0; + virtual void didFireVersionChangeEvent(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& requestIdentifier) = 0; + virtual void openDBRequestCancelled(const IDBRequestData&) = 0; + virtual void confirmDidCloseFromServer(uint64_t databaseConnectionIdentifier) = 0; + + virtual void getAllDatabaseNames(const SecurityOriginData& mainFrameOrigin, const SecurityOriginData& openingOrigin, uint64_t callbackID) = 0; + + virtual void ref() = 0; + virtual void deref() = 0; +}; + +} // namespace IDBClient +} // namespace WebCore + +#endif // ENABLE(INDEXED_DATABASE) diff --git a/Source/WebCore/Modules/indexeddb/client/TransactionOperation.cpp b/Source/WebCore/Modules/indexeddb/client/TransactionOperation.cpp new file mode 100644 index 000000000..8f3547522 --- /dev/null +++ b/Source/WebCore/Modules/indexeddb/client/TransactionOperation.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "TransactionOperation.h" + +#if ENABLE(INDEXED_DATABASE) + +#include "IDBCursor.h" +#include <heap/HeapInlines.h> + +namespace WebCore { +namespace IDBClient { + +TransactionOperation::TransactionOperation(IDBTransaction& transaction, IDBRequest& request) + : TransactionOperation(transaction) +{ + m_objectStoreIdentifier = request.sourceObjectStoreIdentifier(); + m_indexIdentifier = request.sourceIndexIdentifier(); + if (m_indexIdentifier) + m_indexRecordType = request.requestedIndexRecordType(); + if (auto* cursor = request.pendingCursor()) + m_cursorIdentifier = std::make_unique<IDBResourceIdentifier>(cursor->info().identifier()); + + m_idbRequest = &request; +} + +} // namespace IDBClient +} // namespace WebCore + +#endif // ENABLE(INDEXED_DATABASE) diff --git a/Source/WebCore/Modules/indexeddb/client/TransactionOperation.h b/Source/WebCore/Modules/indexeddb/client/TransactionOperation.h new file mode 100644 index 000000000..cd95befd5 --- /dev/null +++ b/Source/WebCore/Modules/indexeddb/client/TransactionOperation.h @@ -0,0 +1,270 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if ENABLE(INDEXED_DATABASE) + +#include "IDBRequest.h" +#include "IDBRequestData.h" +#include "IDBResourceIdentifier.h" +#include "IDBResultData.h" +#include "IDBTransaction.h" +#include <wtf/MainThread.h> +#include <wtf/Threading.h> + +namespace WebCore { + +class IDBResultData; + +namespace IndexedDB { +enum class IndexRecordType; +} + +namespace IDBClient { + +class TransactionOperation : public ThreadSafeRefCounted<TransactionOperation> { + friend IDBRequestData::IDBRequestData(TransactionOperation&); +public: + virtual ~TransactionOperation() + { + ASSERT(m_originThreadID == currentThread()); + } + + void perform() + { + ASSERT(m_originThreadID == currentThread()); + ASSERT(m_performFunction); + m_performFunction(); + m_performFunction = { }; + } + + void transitionToCompleteOnThisThread(const IDBResultData& data) + { + ASSERT(m_originThreadID == currentThread()); + m_transaction->operationCompletedOnServer(data, *this); + } + + void transitionToComplete(const IDBResultData& data, RefPtr<TransactionOperation>&& lastRef) + { + ASSERT(isMainThread()); + + if (m_originThreadID == currentThread()) + transitionToCompleteOnThisThread(data); + else { + m_transaction->performCallbackOnOriginThread(*this, &TransactionOperation::transitionToCompleteOnThisThread, data); + m_transaction->callFunctionOnOriginThread([lastRef = WTFMove(lastRef)]() { + }); + } + } + + void doComplete(const IDBResultData& data) + { + ASSERT(m_originThreadID == currentThread()); + + // Due to race conditions between the server sending an "operation complete" message and the client + // forcefully aborting an operation, it's unavoidable that this method might be called twice. + // It's okay to handle that gracefully with an early return. + if (!m_completeFunction) + return; + + m_completeFunction(data); + m_transaction->operationCompletedOnClient(*this); + + // m_completeFunction might be holding the last ref to this TransactionOperation, + // so we need to do this trick to null it out without first destroying it. + std::function<void (const IDBResultData&)> oldCompleteFunction; + std::swap(m_completeFunction, oldCompleteFunction); + } + + const IDBResourceIdentifier& identifier() const { return m_identifier; } + + ThreadIdentifier originThreadID() const { return m_originThreadID; } + + IDBRequest* idbRequest() { return m_idbRequest.get(); } + + bool nextRequestCanGoToServer() const { return m_nextRequestCanGoToServer && m_idbRequest; } + void setNextRequestCanGoToServer(bool nextRequestCanGoToServer) { m_nextRequestCanGoToServer = nextRequestCanGoToServer; } + +protected: + TransactionOperation(IDBTransaction& transaction) + : m_transaction(transaction) + , m_identifier(transaction.connectionProxy()) + { + } + + TransactionOperation(IDBTransaction&, IDBRequest&); + + Ref<IDBTransaction> m_transaction; + IDBResourceIdentifier m_identifier; + uint64_t m_objectStoreIdentifier { 0 }; + uint64_t m_indexIdentifier { 0 }; + std::unique_ptr<IDBResourceIdentifier> m_cursorIdentifier; + IndexedDB::IndexRecordType m_indexRecordType; + std::function<void ()> m_performFunction; + std::function<void (const IDBResultData&)> m_completeFunction; + +private: + IDBResourceIdentifier transactionIdentifier() const { return m_transaction->info().identifier(); } + uint64_t objectStoreIdentifier() const { return m_objectStoreIdentifier; } + uint64_t indexIdentifier() const { return m_indexIdentifier; } + IDBResourceIdentifier* cursorIdentifier() const { return m_cursorIdentifier.get(); } + IDBTransaction& transaction() { return m_transaction.get(); } + IndexedDB::IndexRecordType indexRecordType() const { return m_indexRecordType; } + + ThreadIdentifier m_originThreadID { currentThread() }; + RefPtr<IDBRequest> m_idbRequest; + bool m_nextRequestCanGoToServer { true }; +}; + +template <typename... Arguments> +class TransactionOperationImpl final : public TransactionOperation { +public: + TransactionOperationImpl(IDBTransaction& transaction, void (IDBTransaction::*completeMethod)(const IDBResultData&), void (IDBTransaction::*performMethod)(TransactionOperation&, Arguments...), Arguments&&... arguments) + : TransactionOperation(transaction) + { + RefPtr<TransactionOperation> protectedThis(this); + + ASSERT(performMethod); + m_performFunction = [protectedThis, this, performMethod, arguments...] { + (&m_transaction.get()->*performMethod)(*this, arguments...); + }; + + if (completeMethod) { + m_completeFunction = [protectedThis, this, completeMethod](const IDBResultData& resultData) { + if (completeMethod) + (&m_transaction.get()->*completeMethod)(resultData); + }; + } + } + + TransactionOperationImpl(IDBTransaction& transaction, IDBRequest& request, void (IDBTransaction::*completeMethod)(IDBRequest&, const IDBResultData&), void (IDBTransaction::*performMethod)(TransactionOperation&, Arguments...), Arguments&&... arguments) + : TransactionOperation(transaction, request) + { + RefPtr<TransactionOperation> protectedThis(this); + + ASSERT(performMethod); + m_performFunction = [protectedThis, this, performMethod, arguments...] { + (&m_transaction.get()->*performMethod)(*this, arguments...); + }; + + if (completeMethod) { + RefPtr<IDBRequest> refRequest(&request); + m_completeFunction = [protectedThis, this, refRequest, completeMethod](const IDBResultData& resultData) { + if (completeMethod) + (&m_transaction.get()->*completeMethod)(*refRequest, resultData); + }; + } + } +}; + +inline RefPtr<TransactionOperation> createTransactionOperation( + IDBTransaction& transaction, + void (IDBTransaction::*complete)(const IDBResultData&), + void (IDBTransaction::*perform)(TransactionOperation&)) +{ + auto operation = new TransactionOperationImpl<>(transaction, complete, perform); + return adoptRef(operation); +} + +template<typename MP1, typename P1> +RefPtr<TransactionOperation> createTransactionOperation( + IDBTransaction& transaction, + void (IDBTransaction::*complete)(const IDBResultData&), + void (IDBTransaction::*perform)(TransactionOperation&, MP1), + const P1& parameter1) +{ + auto operation = new TransactionOperationImpl<MP1>(transaction, complete, perform, parameter1); + return adoptRef(operation); +} + +template<typename MP1, typename P1, typename MP2, typename P2> +RefPtr<TransactionOperation> createTransactionOperation( + IDBTransaction& transaction, + void (IDBTransaction::*complete)(const IDBResultData&), + void (IDBTransaction::*perform)(TransactionOperation&, MP1, MP2), + const P1& parameter1, + const P2& parameter2) +{ + auto operation = new TransactionOperationImpl<MP1, MP2>(transaction, complete, perform, parameter1, parameter2); + return adoptRef(operation); +} + +template<typename MP1, typename P1, typename MP2, typename P2, typename MP3, typename P3> +RefPtr<TransactionOperation> createTransactionOperation( + IDBTransaction& transaction, + void (IDBTransaction::*complete)(const IDBResultData&), + void (IDBTransaction::*perform)(TransactionOperation&, MP1, MP2, MP3), + const P1& parameter1, + const P2& parameter2, + const P3& parameter3) +{ + auto operation = new TransactionOperationImpl<MP1, MP2, MP3>(transaction, complete, perform, parameter1, parameter2, parameter3); + return adoptRef(operation); +} + +template<typename MP1, typename P1> +RefPtr<TransactionOperation> createTransactionOperation( + IDBTransaction& transaction, + IDBRequest& request, + void (IDBTransaction::*complete)(IDBRequest&, const IDBResultData&), + void (IDBTransaction::*perform)(TransactionOperation&, MP1), + const P1& parameter1) +{ + auto operation = new TransactionOperationImpl<MP1>(transaction, request, complete, perform, parameter1); + return adoptRef(operation); +} + +template<typename MP1, typename P1, typename MP2, typename P2> +RefPtr<TransactionOperation> createTransactionOperation( + IDBTransaction& transaction, + IDBRequest& request, + void (IDBTransaction::*complete)(IDBRequest&, const IDBResultData&), + void (IDBTransaction::*perform)(TransactionOperation&, MP1, MP2), + const P1& parameter1, + const P2& parameter2) +{ + auto operation = new TransactionOperationImpl<MP1, MP2>(transaction, request, complete, perform, parameter1, parameter2); + return adoptRef(operation); +} + +template<typename MP1, typename MP2, typename MP3, typename P1, typename P2, typename P3> +RefPtr<TransactionOperation> createTransactionOperation( + IDBTransaction& transaction, + IDBRequest& request, + void (IDBTransaction::*complete)(IDBRequest&, const IDBResultData&), + void (IDBTransaction::*perform)(TransactionOperation&, MP1, MP2, MP3), + const P1& parameter1, + const P2& parameter2, + const P3& parameter3) +{ + auto operation = new TransactionOperationImpl<MP1, MP2, MP3>(transaction, request, complete, perform, parameter1, parameter2, parameter3); + return adoptRef(operation); +} + +} // namespace IDBClient +} // namespace WebCore + +#endif // ENABLE(INDEXED_DATABASE) |