blob: 74ec9b26abe42d10ac0eda00a0edc0f55a293994 [file] [log] [blame]
/*
* 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 "IDBTransactionImpl.h"
#if ENABLE(INDEXED_DATABASE)
#include "DOMError.h"
#include "EventQueue.h"
#include "IDBCursorWithValueImpl.h"
#include "IDBDatabaseImpl.h"
#include "IDBError.h"
#include "IDBEventDispatcher.h"
#include "IDBKeyData.h"
#include "IDBKeyRangeData.h"
#include "IDBObjectStore.h"
#include "IDBOpenDBRequestImpl.h"
#include "IDBRequestImpl.h"
#include "IDBResultData.h"
#include "JSDOMWindowBase.h"
#include "Logging.h"
#include "ScriptExecutionContext.h"
#include "TransactionOperation.h"
namespace WebCore {
namespace IDBClient {
Ref<IDBTransaction> IDBTransaction::create(IDBDatabase& database, const IDBTransactionInfo& info)
{
return adoptRef(*new IDBTransaction(database, info, nullptr));
}
Ref<IDBTransaction> IDBTransaction::create(IDBDatabase& database, const IDBTransactionInfo& info, IDBOpenDBRequest& request)
{
return adoptRef(*new IDBTransaction(database, info, &request));
}
IDBTransaction::IDBTransaction(IDBDatabase& database, const IDBTransactionInfo& info, IDBOpenDBRequest* request)
: WebCore::IDBTransaction(database.scriptExecutionContext())
, m_database(database)
, m_info(info)
, m_operationTimer(*this, &IDBTransaction::operationTimerFired)
, m_openDBRequest(request)
{
relaxAdoptionRequirement();
if (m_info.mode() == IndexedDB::TransactionMode::VersionChange) {
ASSERT(m_openDBRequest);
m_originalDatabaseInfo = std::make_unique<IDBDatabaseInfo>(m_database->info());
m_startedOnServer = true;
} else {
activate();
RefPtr<IDBTransaction> self;
JSC::VM& vm = JSDOMWindowBase::commonVM();
vm.whenIdle([self, this]() {
deactivate();
});
establishOnServer();
}
suspendIfNeeded();
}
IDBTransaction::~IDBTransaction()
{
}
const String& IDBTransaction::mode() const
{
switch (m_info.mode()) {
case IndexedDB::TransactionMode::ReadOnly:
return IDBTransaction::modeReadOnly();
case IndexedDB::TransactionMode::ReadWrite:
return IDBTransaction::modeReadWrite();
case IndexedDB::TransactionMode::VersionChange:
return IDBTransaction::modeVersionChange();
}
RELEASE_ASSERT_NOT_REACHED();
}
WebCore::IDBDatabase* IDBTransaction::db()
{
return &m_database.get();
}
IDBConnectionToServer& IDBTransaction::serverConnection()
{
return m_database->serverConnection();
}
RefPtr<DOMError> IDBTransaction::error() const
{
ASSERT_NOT_REACHED();
return nullptr;
}
RefPtr<WebCore::IDBObjectStore> IDBTransaction::objectStore(const String& objectStoreName, ExceptionCode& ec)
{
LOG(IndexedDB, "IDBTransaction::objectStore");
if (objectStoreName.isEmpty()) {
ec = NOT_FOUND_ERR;
return nullptr;
}
if (isFinishedOrFinishing()) {
ec = INVALID_STATE_ERR;
return nullptr;
}
auto iterator = m_referencedObjectStores.find(objectStoreName);
if (iterator != m_referencedObjectStores.end())
return iterator->value;
bool found = false;
for (auto& objectStore : m_info.objectStores()) {
if (objectStore == objectStoreName) {
found = true;
break;
}
}
auto* info = m_database->info().infoForExistingObjectStore(objectStoreName);
if (!info) {
ec = NOT_FOUND_ERR;
return nullptr;
}
// Version change transactions are scoped to every object store in the database.
if (!found && !isVersionChange()) {
ec = NOT_FOUND_ERR;
return nullptr;
}
auto objectStore = IDBObjectStore::create(*info, *this);
m_referencedObjectStores.set(objectStoreName, &objectStore.get());
return adoptRef(&objectStore.leakRef());
}
void IDBTransaction::abort(ExceptionCode& ec)
{
LOG(IndexedDB, "IDBTransaction::abort");
if (isFinishedOrFinishing()) {
ec = INVALID_STATE_ERR;
return;
}
m_state = IndexedDB::TransactionState::Aborting;
m_database->willAbortTransaction(*this);
if (isVersionChange()) {
ASSERT(m_openDBRequest);
m_openDBRequest->versionChangeTransactionWillFinish();
}
m_abortQueue.swap(m_transactionOperationQueue);
auto operation = createTransactionOperation(*this, nullptr, &IDBTransaction::abortOnServerAndCancelRequests);
scheduleOperation(WTF::move(operation));
}
void IDBTransaction::abortOnServerAndCancelRequests(TransactionOperation&)
{
LOG(IndexedDB, "IDBTransaction::abortOnServerAndCancelRequests");
ASSERT(m_transactionOperationQueue.isEmpty());
serverConnection().abortTransaction(*this);
IDBError error(IDBExceptionCode::AbortError);
for (auto& operation : m_abortQueue)
operation->completed(IDBResultData::error(operation->identifier(), error));
// Since we're aborting, this abortOnServerAndCancelRequests() operation should be the only
// in-progress operation, and it should be impossible to have queued any further operations.
ASSERT(m_transactionOperationMap.size() == 1);
ASSERT(m_transactionOperationQueue.isEmpty());
}
const char* IDBTransaction::activeDOMObjectName() const
{
return "IDBTransaction";
}
bool IDBTransaction::canSuspendForDocumentSuspension() const
{
return false;
}
bool IDBTransaction::hasPendingActivity() const
{
return m_state != IndexedDB::TransactionState::Finished;
}
bool IDBTransaction::isActive() const
{
return m_state == IndexedDB::TransactionState::Active;
}
bool IDBTransaction::isFinishedOrFinishing() const
{
return m_state == IndexedDB::TransactionState::Committing
|| m_state == IndexedDB::TransactionState::Aborting
|| m_state == IndexedDB::TransactionState::Finished;
}
void IDBTransaction::addRequest(IDBRequest& request)
{
m_openRequests.add(&request);
}
void IDBTransaction::removeRequest(IDBRequest& request)
{
ASSERT(m_openRequests.contains(&request));
m_openRequests.remove(&request);
}
void IDBTransaction::scheduleOperation(RefPtr<TransactionOperation>&& operation)
{
ASSERT(!m_transactionOperationMap.contains(operation->identifier()));
m_transactionOperationQueue.append(operation);
m_transactionOperationMap.set(operation->identifier(), WTF::move(operation));
scheduleOperationTimer();
}
void IDBTransaction::scheduleOperationTimer()
{
if (!m_operationTimer.isActive())
m_operationTimer.startOneShot(0);
}
void IDBTransaction::operationTimerFired()
{
LOG(IndexedDB, "IDBTransaction::operationTimerFired (%p)", this);
if (!m_startedOnServer)
return;
if (!m_transactionOperationQueue.isEmpty()) {
auto operation = m_transactionOperationQueue.takeFirst();
operation->perform();
return;
}
if (!m_transactionOperationMap.isEmpty() || !m_openRequests.isEmpty())
return;
if (!isFinishedOrFinishing())
commit();
}
void IDBTransaction::commit()
{
LOG(IndexedDB, "IDBTransaction::commit");
ASSERT(!isFinishedOrFinishing());
m_state = IndexedDB::TransactionState::Committing;
m_database->willCommitTransaction(*this);
if (isVersionChange()) {
ASSERT(m_openDBRequest);
m_openDBRequest->versionChangeTransactionWillFinish();
}
auto operation = createTransactionOperation(*this, nullptr, &IDBTransaction::commitOnServer);
scheduleOperation(WTF::move(operation));
}
void IDBTransaction::commitOnServer(TransactionOperation&)
{
LOG(IndexedDB, "IDBTransaction::commitOnServer");
serverConnection().commitTransaction(*this);
}
void IDBTransaction::finishAbortOrCommit()
{
ASSERT(m_state != IndexedDB::TransactionState::Finished);
m_state = IndexedDB::TransactionState::Finished;
m_originalDatabaseInfo = nullptr;
}
void IDBTransaction::didStart(const IDBError& error)
{
LOG(IndexedDB, "IDBTransaction::didStart");
m_database->didStartTransaction(*this);
m_startedOnServer = true;
// It's possible the transaction failed to start on the server.
// That equates to an abort.
if (!error.isNull()) {
didAbort(error);
return;
}
scheduleOperationTimer();
}
void IDBTransaction::notifyDidAbort(const IDBError& error)
{
m_database->didAbortTransaction(*this);
m_idbError = error;
fireOnAbort();
if (isVersionChange()) {
ASSERT(m_openDBRequest);
m_openDBRequest->fireErrorAfterVersionChangeAbort();
}
}
void IDBTransaction::didAbort(const IDBError& error)
{
LOG(IndexedDB, "IDBTransaction::didAbort");
if (m_state == IndexedDB::TransactionState::Finished)
return;
notifyDidAbort(error);
finishAbortOrCommit();
}
void IDBTransaction::didCommit(const IDBError& error)
{
LOG(IndexedDB, "IDBTransaction::didCommit");
ASSERT(m_state == IndexedDB::TransactionState::Committing);
if (error.isNull()) {
m_database->didCommitTransaction(*this);
fireOnComplete();
} else
notifyDidAbort(error);
finishAbortOrCommit();
}
void IDBTransaction::fireOnComplete()
{
LOG(IndexedDB, "IDBTransaction::fireOnComplete");
enqueueEvent(Event::create(eventNames().completeEvent, false, false));
}
void IDBTransaction::fireOnAbort()
{
LOG(IndexedDB, "IDBTransaction::fireOnAbort");
enqueueEvent(Event::create(eventNames().abortEvent, true, false));
}
void IDBTransaction::enqueueEvent(Ref<Event>&& event)
{
ASSERT(m_state != IndexedDB::TransactionState::Finished);
if (!scriptExecutionContext())
return;
event->setTarget(this);
scriptExecutionContext()->eventQueue().enqueueEvent(WTF::move(event));
}
bool IDBTransaction::dispatchEvent(Event& event)
{
LOG(IndexedDB, "IDBTransaction::dispatchEvent");
ASSERT(scriptExecutionContext());
ASSERT(event.target() == this);
ASSERT(event.type() == eventNames().completeEvent || event.type() == eventNames().abortEvent);
Vector<RefPtr<EventTarget>> targets;
targets.append(this);
targets.append(db());
bool result = IDBEventDispatcher::dispatch(event, targets);
if (isVersionChange() && event.type() == eventNames().completeEvent) {
ASSERT(m_openDBRequest);
m_openDBRequest->fireSuccessAfterVersionChangeCommit();
}
return result;
}
Ref<IDBObjectStore> IDBTransaction::createObjectStore(const IDBObjectStoreInfo& info)
{
LOG(IndexedDB, "IDBTransaction::createObjectStore");
ASSERT(isVersionChange());
Ref<IDBObjectStore> objectStore = IDBObjectStore::create(info, *this);
m_referencedObjectStores.set(info.name(), &objectStore.get());
auto operation = createTransactionOperation(*this, &IDBTransaction::didCreateObjectStoreOnServer, &IDBTransaction::createObjectStoreOnServer, info);
scheduleOperation(WTF::move(operation));
return WTF::move(objectStore);
}
void IDBTransaction::createObjectStoreOnServer(TransactionOperation& operation, const IDBObjectStoreInfo& info)
{
LOG(IndexedDB, "IDBTransaction::createObjectStoreOnServer");
ASSERT(isVersionChange());
m_database->serverConnection().createObjectStore(operation, info);
}
void IDBTransaction::didCreateObjectStoreOnServer(const IDBResultData& resultData)
{
LOG(IndexedDB, "IDBTransaction::didCreateObjectStoreOnServer");
ASSERT_UNUSED(resultData, resultData.type() == IDBResultType::CreateObjectStoreSuccess || resultData.type() == IDBResultType::Error);
}
Ref<IDBIndex> IDBTransaction::createIndex(IDBObjectStore& objectStore, const IDBIndexInfo& info)
{
LOG(IndexedDB, "IDBTransaction::createIndex");
ASSERT(isVersionChange());
Ref<IDBIndex> index = IDBIndex::create(info, objectStore);
auto operation = createTransactionOperation(*this, &IDBTransaction::didCreateIndexOnServer, &IDBTransaction::createIndexOnServer, info);
scheduleOperation(WTF::move(operation));
return WTF::move(index);
}
void IDBTransaction::createIndexOnServer(TransactionOperation& operation, const IDBIndexInfo& info)
{
LOG(IndexedDB, "IDBTransaction::createIndexOnServer");
ASSERT(isVersionChange());
m_database->serverConnection().createIndex(operation, info);
}
void IDBTransaction::didCreateIndexOnServer(const IDBResultData& resultData)
{
LOG(IndexedDB, "IDBTransaction::didCreateIndexOnServer");
if (resultData.type() == IDBResultType::CreateIndexSuccess)
return;
ASSERT(resultData.type() == IDBResultType::Error);
// This operation might have failed because the transaction is already aborting.
if (m_state == IndexedDB::TransactionState::Aborting)
return;
// Otherwise, failure to create an index forced abortion of the transaction.
ExceptionCode ec;
abort(ec);
}
Ref<IDBRequest> IDBTransaction::requestOpenCursor(ScriptExecutionContext& context, IDBObjectStore& objectStore, const IDBCursorInfo& info)
{
LOG(IndexedDB, "IDBTransaction::requestOpenCursor");
return doRequestOpenCursor(context, IDBCursorWithValue::create(*this, objectStore, info));
}
Ref<IDBRequest> IDBTransaction::requestOpenCursor(ScriptExecutionContext& context, IDBIndex& index, const IDBCursorInfo& info)
{
LOG(IndexedDB, "IDBTransaction::requestOpenCursor");
if (info.cursorType() == IndexedDB::CursorType::KeyOnly)
return doRequestOpenCursor(context, IDBCursor::create(*this, index, info));
return doRequestOpenCursor(context, IDBCursorWithValue::create(*this, index, info));
}
Ref<IDBRequest> IDBTransaction::doRequestOpenCursor(ScriptExecutionContext& context, Ref<IDBCursor>&& cursor)
{
ASSERT(isActive());
Ref<IDBRequest> request = IDBRequest::create(context, cursor.get(), *this);
addRequest(request.get());
auto operation = createTransactionOperation(*this, request.get(), &IDBTransaction::didOpenCursorOnServer, &IDBTransaction::openCursorOnServer, cursor->info());
scheduleOperation(WTF::move(operation));
return WTF::move(request);
}
void IDBTransaction::openCursorOnServer(TransactionOperation& operation, const IDBCursorInfo& info)
{
LOG(IndexedDB, "IDBTransaction::openCursorOnServer");
m_database->serverConnection().openCursor(operation, info);
}
void IDBTransaction::didOpenCursorOnServer(IDBRequest& request, const IDBResultData& resultData)
{
LOG(IndexedDB, "IDBTransaction::didOpenCursorOnServer");
request.didOpenOrIterateCursor(resultData);
}
void IDBTransaction::iterateCursor(IDBCursor& cursor, const IDBKeyData& key, unsigned long count)
{
LOG(IndexedDB, "IDBTransaction::iterateCursor");
ASSERT(isActive());
ASSERT(cursor.request());
addRequest(*cursor.request());
auto operation = createTransactionOperation(*this, *cursor.request(), &IDBTransaction::didIterateCursorOnServer, &IDBTransaction::iterateCursorOnServer, key, count);
scheduleOperation(WTF::move(operation));
}
void IDBTransaction::iterateCursorOnServer(TransactionOperation& operation, const IDBKeyData& key, const unsigned long& count)
{
LOG(IndexedDB, "IDBTransaction::iterateCursorOnServer");
serverConnection().iterateCursor(operation, key, count);
}
void IDBTransaction::didIterateCursorOnServer(IDBRequest& request, const IDBResultData& resultData)
{
LOG(IndexedDB, "IDBTransaction::didIterateCursorOnServer");
request.didOpenOrIterateCursor(resultData);
}
Ref<IDBRequest> IDBTransaction::requestGetRecord(ScriptExecutionContext& context, IDBObjectStore& objectStore, const IDBKeyRangeData& keyRangeData)
{
LOG(IndexedDB, "IDBTransaction::requestGetRecord");
ASSERT(isActive());
ASSERT(!keyRangeData.isNull);
Ref<IDBRequest> request = IDBRequest::create(context, objectStore, *this);
addRequest(request.get());
auto operation = createTransactionOperation(*this, request.get(), &IDBTransaction::didGetRecordOnServer, &IDBTransaction::getRecordOnServer, keyRangeData);
scheduleOperation(WTF::move(operation));
return WTF::move(request);
}
Ref<IDBRequest> IDBTransaction::requestGetValue(ScriptExecutionContext& context, IDBIndex& index, const IDBKeyRangeData& range)
{
LOG(IndexedDB, "IDBTransaction::requestGetValue");
return requestIndexRecord(context, index, IndexedDB::IndexRecordType::Value, range);
}
Ref<IDBRequest> IDBTransaction::requestGetKey(ScriptExecutionContext& context, IDBIndex& index, const IDBKeyRangeData& range)
{
LOG(IndexedDB, "IDBTransaction::requestGetValue");
return requestIndexRecord(context, index, IndexedDB::IndexRecordType::Key, range);
}
Ref<IDBRequest> IDBTransaction::requestIndexRecord(ScriptExecutionContext& context, IDBIndex& index, IndexedDB::IndexRecordType type, const IDBKeyRangeData&range)
{
LOG(IndexedDB, "IDBTransaction::requestGetValue");
ASSERT(isActive());
ASSERT(!range.isNull);
Ref<IDBRequest> request = IDBRequest::createGet(context, index, type, *this);
addRequest(request.get());
auto operation = createTransactionOperation(*this, request.get(), &IDBTransaction::didGetRecordOnServer, &IDBTransaction::getRecordOnServer, range);
scheduleOperation(WTF::move(operation));
return WTF::move(request);
}
void IDBTransaction::getRecordOnServer(TransactionOperation& operation, const IDBKeyRangeData& keyRange)
{
LOG(IndexedDB, "IDBTransaction::getRecordOnServer");
serverConnection().getRecord(operation, keyRange);
}
void IDBTransaction::didGetRecordOnServer(IDBRequest& request, const IDBResultData& resultData)
{
LOG(IndexedDB, "IDBTransaction::didGetRecordOnServer");
if (resultData.type() == IDBResultType::Error) {
request.requestCompleted(resultData);
return;
}
ASSERT(resultData.type() == IDBResultType::GetRecordSuccess);
const IDBGetResult& result = resultData.getResult();
if (request.sourceIndexIdentifier() && request.requestedIndexRecordType() == IndexedDB::IndexRecordType::Key) {
if (!result.keyData().isNull())
request.setResult(&result.keyData());
else
request.setResultToUndefined();
} else {
if (resultData.getResult().valueBuffer().data())
request.setResultToStructuredClone(resultData.getResult().valueBuffer());
else
request.setResultToUndefined();
}
request.requestCompleted(resultData);
}
Ref<IDBRequest> IDBTransaction::requestCount(ScriptExecutionContext& context, IDBObjectStore& objectStore, const IDBKeyRangeData& range)
{
LOG(IndexedDB, "IDBTransaction::requestCount (IDBObjectStore)");
ASSERT(isActive());
ASSERT(!range.isNull);
Ref<IDBRequest> request = IDBRequest::create(context, objectStore, *this);
addRequest(request.get());
scheduleOperation(createTransactionOperation(*this, request.get(), &IDBTransaction::didGetCountOnServer, &IDBTransaction::getCountOnServer, range));
return request;
}
Ref<IDBRequest> IDBTransaction::requestCount(ScriptExecutionContext& context, IDBIndex& index, const IDBKeyRangeData& range)
{
LOG(IndexedDB, "IDBTransaction::requestCount (IDBIndex)");
ASSERT(isActive());
ASSERT(!range.isNull);
Ref<IDBRequest> request = IDBRequest::createCount(context, index, *this);
addRequest(request.get());
scheduleOperation(createTransactionOperation(*this, request.get(), &IDBTransaction::didGetCountOnServer, &IDBTransaction::getCountOnServer, range));
return request;
}
void IDBTransaction::getCountOnServer(TransactionOperation& operation, const IDBKeyRangeData& keyRange)
{
LOG(IndexedDB, "IDBTransaction::getCountOnServer");
serverConnection().getCount(operation, keyRange);
}
void IDBTransaction::didGetCountOnServer(IDBRequest& request, const IDBResultData& resultData)
{
LOG(IndexedDB, "IDBTransaction::didGetCountOnServer");
request.setResult(resultData.resultInteger());
request.requestCompleted(resultData);
}
Ref<IDBRequest> IDBTransaction::requestDeleteRecord(ScriptExecutionContext& context, IDBObjectStore& objectStore, const IDBKeyRangeData& range)
{
LOG(IndexedDB, "IDBTransaction::requestDeleteRecord");
ASSERT(isActive());
ASSERT(!range.isNull);
Ref<IDBRequest> request = IDBRequest::create(context, objectStore, *this);
addRequest(request.get());
scheduleOperation(createTransactionOperation(*this, request.get(), &IDBTransaction::didDeleteRecordOnServer, &IDBTransaction::deleteRecordOnServer, range));
return request;
}
void IDBTransaction::deleteRecordOnServer(TransactionOperation& operation, const IDBKeyRangeData& keyRange)
{
LOG(IndexedDB, "IDBTransaction::deleteRecordOnServer");
serverConnection().deleteRecord(operation, keyRange);
}
void IDBTransaction::didDeleteRecordOnServer(IDBRequest& request, const IDBResultData& resultData)
{
LOG(IndexedDB, "IDBTransaction::didDeleteRecordOnServer");
request.setResultToUndefined();
request.requestCompleted(resultData);
}
Ref<IDBRequest> IDBTransaction::requestClearObjectStore(ScriptExecutionContext& context, IDBObjectStore& objectStore)
{
LOG(IndexedDB, "IDBTransaction::requestClearObjectStore");
ASSERT(isActive());
Ref<IDBRequest> request = IDBRequest::create(context, objectStore, *this);
addRequest(request.get());
uint64_t objectStoreIdentifier = objectStore.info().identifier();
auto operation = createTransactionOperation(*this, request.get(), &IDBTransaction::didClearObjectStoreOnServer, &IDBTransaction::clearObjectStoreOnServer, objectStoreIdentifier);
scheduleOperation(WTF::move(operation));
return WTF::move(request);
}
void IDBTransaction::clearObjectStoreOnServer(TransactionOperation& operation, const uint64_t& objectStoreIdentifier)
{
LOG(IndexedDB, "IDBTransaction::clearObjectStoreOnServer");
serverConnection().clearObjectStore(operation, objectStoreIdentifier);
}
void IDBTransaction::didClearObjectStoreOnServer(IDBRequest& request, const IDBResultData& resultData)
{
LOG(IndexedDB, "IDBTransaction::didClearObjectStoreOnServer");
request.setResultToUndefined();
request.requestCompleted(resultData);
}
Ref<IDBRequest> IDBTransaction::requestPutOrAdd(ScriptExecutionContext& context, IDBObjectStore& objectStore, IDBKey* key, SerializedScriptValue& value, IndexedDB::ObjectStoreOverwriteMode overwriteMode)
{
LOG(IndexedDB, "IDBTransaction::requestPutOrAdd");
ASSERT(isActive());
ASSERT(!isReadOnly());
ASSERT(objectStore.info().autoIncrement() || key);
Ref<IDBRequest> request = IDBRequest::create(context, objectStore, *this);
addRequest(request.get());
auto operation = createTransactionOperation(*this, request.get(), &IDBTransaction::didPutOrAddOnServer, &IDBTransaction::putOrAddOnServer, key, &value, overwriteMode);
scheduleOperation(WTF::move(operation));
return WTF::move(request);
}
void IDBTransaction::putOrAddOnServer(TransactionOperation& operation, RefPtr<IDBKey> key, RefPtr<SerializedScriptValue> value, const IndexedDB::ObjectStoreOverwriteMode& overwriteMode)
{
LOG(IndexedDB, "IDBTransaction::putOrAddOnServer");
ASSERT(!isReadOnly());
serverConnection().putOrAdd(operation, key, value, overwriteMode);
}
void IDBTransaction::didPutOrAddOnServer(IDBRequest& request, const IDBResultData& resultData)
{
LOG(IndexedDB, "IDBTransaction::didPutOrAddOnServer");
request.setResult(resultData.resultKey());
request.requestCompleted(resultData);
}
void IDBTransaction::deleteObjectStore(const String& objectStoreName)
{
LOG(IndexedDB, "IDBTransaction::deleteObjectStore");
ASSERT(isVersionChange());
if (auto objectStore = m_referencedObjectStores.take(objectStoreName))
objectStore->markAsDeleted();
auto operation = createTransactionOperation(*this, &IDBTransaction::didDeleteObjectStoreOnServer, &IDBTransaction::deleteObjectStoreOnServer, objectStoreName);
scheduleOperation(WTF::move(operation));
}
void IDBTransaction::deleteObjectStoreOnServer(TransactionOperation& operation, const String& objectStoreName)
{
LOG(IndexedDB, "IDBTransaction::deleteObjectStoreOnServer");
ASSERT(isVersionChange());
serverConnection().deleteObjectStore(operation, objectStoreName);
}
void IDBTransaction::didDeleteObjectStoreOnServer(const IDBResultData& resultData)
{
LOG(IndexedDB, "IDBTransaction::didDeleteObjectStoreOnServer");
ASSERT_UNUSED(resultData, resultData.type() == IDBResultType::DeleteObjectStoreSuccess || resultData.type() == IDBResultType::Error);
}
void IDBTransaction::deleteIndex(uint64_t objectStoreIdentifier, const String& indexName)
{
LOG(IndexedDB, "IDBTransaction::deleteIndex");
ASSERT(isVersionChange());
auto operation = createTransactionOperation(*this, &IDBTransaction::didDeleteIndexOnServer, &IDBTransaction::deleteIndexOnServer, objectStoreIdentifier, indexName);
scheduleOperation(WTF::move(operation));
}
void IDBTransaction::deleteIndexOnServer(TransactionOperation& operation, const uint64_t& objectStoreIdentifier, const String& indexName)
{
LOG(IndexedDB, "IDBTransaction::deleteIndexOnServer");
ASSERT(isVersionChange());
serverConnection().deleteIndex(operation, objectStoreIdentifier, indexName);
}
void IDBTransaction::didDeleteIndexOnServer(const IDBResultData& resultData)
{
LOG(IndexedDB, "IDBTransaction::didDeleteIndexOnServer");
ASSERT_UNUSED(resultData, resultData.type() == IDBResultType::DeleteIndexSuccess || resultData.type() == IDBResultType::Error);
}
void IDBTransaction::operationDidComplete(TransactionOperation& operation)
{
ASSERT(m_transactionOperationMap.get(operation.identifier()) == &operation);
m_transactionOperationMap.remove(operation.identifier());
scheduleOperationTimer();
}
void IDBTransaction::establishOnServer()
{
LOG(IndexedDB, "IDBTransaction::establishOnServer");
serverConnection().establishTransaction(*this);
}
void IDBTransaction::activate()
{
if (isFinishedOrFinishing())
return;
m_state = IndexedDB::TransactionState::Active;
}
void IDBTransaction::deactivate()
{
if (m_state == IndexedDB::TransactionState::Active)
m_state = IndexedDB::TransactionState::Inactive;
scheduleOperationTimer();
}
} // namespace IDBClient
} // namespace WebCore
#endif // ENABLE(INDEXED_DATABASE)