/*
 * Copyright (C) 2015-2021 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 "IDBTransaction.h"

#include "DOMException.h"
#include "DOMStringList.h"
#include "DOMWindow.h"
#include "Event.h"
#include "EventDispatcher.h"
#include "EventLoop.h"
#include "EventNames.h"
#include "EventQueue.h"
#include "IDBCursorWithValue.h"
#include "IDBDatabase.h"
#include "IDBError.h"
#include "IDBGetRecordData.h"
#include "IDBIndex.h"
#include "IDBIterateCursorData.h"
#include "IDBKeyData.h"
#include "IDBKeyRangeData.h"
#include "IDBObjectStore.h"
#include "IDBOpenDBRequest.h"
#include "IDBRequest.h"
#include "IDBResultData.h"
#include "IDBValue.h"
#include "JSDOMWindowBase.h"
#include "Logging.h"
#include "ScriptExecutionContext.h"
#include "ScriptState.h"
#include "SerializedScriptValue.h"
#include "TransactionOperation.h"
#include <wtf/CompletionHandler.h>
#include <wtf/IsoMallocInlines.h>

namespace WebCore {
using namespace JSC;

WTF_MAKE_ISO_ALLOCATED_IMPL(IDBTransaction);

std::atomic<unsigned> IDBTransaction::numberOfIDBTransactions { 0 };

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)
    : IDBActiveDOMObject(database.scriptExecutionContext())
    , m_database(database)
    , m_info(info)
    , m_openDBRequest(request)
    , m_currentlyCompletingRequest(request)

{
    LOG(IndexedDB, "IDBTransaction::IDBTransaction - %s", m_info.loggingString().utf8().data());
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    ++numberOfIDBTransactions;

    if (m_info.mode() == IDBTransactionMode::Versionchange) {
        ASSERT(m_openDBRequest);
        m_openDBRequest->setVersionChangeTransaction(*this);
        m_startedOnServer = true;
    } else {
        activate();

        auto* context = scriptExecutionContext();
        ASSERT(context);

        context->eventLoop().runAtEndOfMicrotaskCheckpoint([protectedThis = Ref { *this }] {
            protectedThis->deactivate();
        });

        establishOnServer();
    }

    suspendIfNeeded();
}

IDBTransaction::~IDBTransaction()
{
    --numberOfIDBTransactions;
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));
}

IDBClient::IDBConnectionProxy& IDBTransaction::connectionProxy()
{
    return m_database->connectionProxy();
}

Ref<DOMStringList> IDBTransaction::objectStoreNames() const
{
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    const Vector<String> names = isVersionChange() ? m_database->info().objectStoreNames() : m_info.objectStores();

    Ref<DOMStringList> objectStoreNames = DOMStringList::create();
    for (auto& name : names)
        objectStoreNames->append(name);

    objectStoreNames->sort();
    return objectStoreNames;
}

IDBDatabase* IDBTransaction::db()
{
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));
    return m_database.ptr();
}

DOMException* IDBTransaction::error() const
{
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));
    return m_domError.get();
}

ExceptionOr<Ref<IDBObjectStore>> IDBTransaction::objectStore(const String& objectStoreName)
{
    LOG(IndexedDB, "IDBTransaction::objectStore");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    if (!scriptExecutionContext())
        return Exception { InvalidStateError };

    if (isFinishedOrFinishing())
        return Exception { InvalidStateError, "Failed to execute 'objectStore' on 'IDBTransaction': The transaction finished."_s };

    Locker locker { m_referencedObjectStoreLock };

    if (auto* store = m_referencedObjectStores.get(objectStoreName))
        return Ref { *store };

    bool found = false;
    for (auto& objectStore : m_info.objectStores()) {
        if (objectStore == objectStoreName) {
            found = true;
            break;
        }
    }

    auto* info = m_database->info().infoForExistingObjectStore(objectStoreName);
    if (!info)
        return Exception { NotFoundError, "Failed to execute 'objectStore' on 'IDBTransaction': The specified object store was not found."_s };

    // Version change transactions are scoped to every object store in the database.
    if (!info || (!found && !isVersionChange()))
        return Exception { NotFoundError, "Failed to execute 'objectStore' on 'IDBTransaction': The specified object store was not found."_s };

    auto objectStore = makeUnique<IDBObjectStore>(*scriptExecutionContext(), *info, *this);
    auto* rawObjectStore = objectStore.get();
    m_referencedObjectStores.set(objectStoreName, WTFMove(objectStore));

    return Ref<IDBObjectStore>(*rawObjectStore);
}


void IDBTransaction::abortDueToFailedRequest(DOMException& error)
{
    LOG(IndexedDB, "IDBTransaction::abortDueToFailedRequest");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    if (isFinishedOrFinishing())
        return;

    m_domError = &error;
    abortInternal();
}

void IDBTransaction::transitionedToFinishing(IndexedDB::TransactionState state)
{
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    ASSERT(!isFinishedOrFinishing());
    m_state = state;
    ASSERT(isFinishedOrFinishing());
}

ExceptionOr<void> IDBTransaction::abort()
{
    LOG(IndexedDB, "IDBTransaction::abort");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    if (isFinishedOrFinishing())
        return Exception { InvalidStateError, "Failed to execute 'abort' on 'IDBTransaction': The transaction is inactive or finished."_s };

    abortInternal();

    return { };
}

void IDBTransaction::abortInternal()
{
    LOG(IndexedDB, "IDBTransaction::abortInternal");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));
    ASSERT(!isFinishedOrFinishing());

    m_database->willAbortTransaction(*this);

    if (isVersionChange()) {
        Locker locker { m_referencedObjectStoreLock };

        auto& info = m_database->info();
        Vector<uint64_t> identifiersToRemove;
        Vector<std::unique_ptr<IDBObjectStore>> objectStoresToDelete;
        for (auto& iterator : m_deletedObjectStores) {
            if (info.infoForExistingObjectStore(iterator.key)) {
                auto name = iterator.value->info().name();
                auto result = m_referencedObjectStores.add(name, nullptr);
                if (!result.isNewEntry)
                    objectStoresToDelete.append(std::exchange(result.iterator->value, nullptr));
                result.iterator->value = std::exchange(iterator.value, nullptr);
                identifiersToRemove.append(iterator.key);
            }
        }

        for (auto identifier : identifiersToRemove)
            m_deletedObjectStores.remove(identifier);

        for (auto& objectStore : m_referencedObjectStores.values())
            objectStore->rollbackForVersionChangeAbort();

        for (auto& objectStore : objectStoresToDelete) {
            objectStore->rollbackForVersionChangeAbort();
            auto objectStoreIdentifier = objectStore->info().identifier();
            m_deletedObjectStores.set(objectStoreIdentifier, std::exchange(objectStore, nullptr));
        }
    }

    transitionedToFinishing(IndexedDB::TransactionState::Aborting);
    
    m_abortQueue.swap(m_pendingTransactionOperationQueue);

    LOG(IndexedDBOperations, "IDB abort-on-server operation: Transaction %s", info().identifier().loggingString().utf8().data());
    scheduleOperation(IDBClient::TransactionOperationImpl::create(*this, nullptr, [protectedThis = Ref { *this }] (auto& operation) {
        protectedThis->abortOnServerAndCancelRequests(operation);
    }));
}

void IDBTransaction::abortInProgressOperations(const IDBError& error)
{
    LOG(IndexedDB, "IDBTransaction::abortInProgressOperations");

    Vector<RefPtr<IDBClient::TransactionOperation>> inProgressAbortVector;
    inProgressAbortVector.reserveInitialCapacity(m_transactionOperationsInProgressQueue.size());
    while (!m_transactionOperationsInProgressQueue.isEmpty())
        inProgressAbortVector.uncheckedAppend(m_transactionOperationsInProgressQueue.takeFirst());

    for (auto& operation : inProgressAbortVector) {
        m_transactionOperationsInProgressQueue.append(operation.get());
        m_currentlyCompletingRequest = nullptr;
        operation->doComplete(IDBResultData::error(operation->identifier(), error));
    }

    m_transactionOperationResultMap.clear();

    m_currentlyCompletingRequest = nullptr;
    connectionProxy().forgetActiveOperations(inProgressAbortVector);
}

void IDBTransaction::abortOnServerAndCancelRequests(IDBClient::TransactionOperation& operation)
{
    LOG(IndexedDB, "IDBTransaction::abortOnServerAndCancelRequests");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));
    ASSERT(m_pendingTransactionOperationQueue.isEmpty());

    m_database->connectionProxy().abortTransaction(*this);

    ASSERT(m_transactionOperationMap.contains(operation.identifier()));
    ASSERT(m_transactionOperationsInProgressQueue.last() == &operation);
    m_transactionOperationMap.remove(operation.identifier());
    m_transactionOperationsInProgressQueue.removeLast();

    m_currentlyCompletingRequest = nullptr;
    
    IDBError error(AbortError);

    abortInProgressOperations(error);

    for (auto& operation : m_abortQueue) {
        m_transactionOperationsInProgressQueue.append(operation.get());
        operation->doComplete(IDBResultData::error(operation->identifier(), error));
        m_currentlyCompletingRequest = nullptr;
    }

    m_abortQueue.clear();
    m_openRequests.clear();
    // Since we're aborting, it should be impossible to have queued any further operations.
    ASSERT(m_pendingTransactionOperationQueue.isEmpty());
}

const char* IDBTransaction::activeDOMObjectName() const
{
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));
    return "IDBTransaction";
}

bool IDBTransaction::virtualHasPendingActivity() const
{
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()) || Thread::mayBeGCThread());
    return m_state != IndexedDB::TransactionState::Finished;
}

void IDBTransaction::stop()
{
    LOG(IndexedDB, "IDBTransaction::stop - %s", m_info.loggingString().utf8().data());
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    // IDBDatabase::stop() calls IDBTransaction::stop() for each of its active transactions.
    // Since the order of calling ActiveDOMObject::stop() is random, we might already have been stopped.
    if (m_isStopped)
        return;

    removeAllEventListeners();

    m_isStopped = true;

    if (isVersionChange())
        m_openDBRequest = nullptr;

    if (isFinishedOrFinishing())
        return;

    abortInternal();
}

bool IDBTransaction::isActive() const
{
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));
    return m_state == IndexedDB::TransactionState::Active;
}

bool IDBTransaction::isFinishedOrFinishing() const
{
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    return m_state == IndexedDB::TransactionState::Committing
        || m_state == IndexedDB::TransactionState::Aborting
        || m_state == IndexedDB::TransactionState::Finished;
}

void IDBTransaction::addRequest(IDBRequest& request)
{
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));
    m_openRequests.add(&request);
}

void IDBTransaction::removeRequest(IDBRequest& request)
{
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));
    if (m_currentlyCompletingRequest == &request)
        return;

    m_openRequests.remove(&request);

    autoCommit();
}

void IDBTransaction::scheduleOperation(Ref<IDBClient::TransactionOperation>&& operation, IsWriteOperation isWriteOperation)
{
    ASSERT(!m_transactionOperationMap.contains(operation->identifier()));
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    if (isWriteOperation == IsWriteOperation::Yes)
        m_lastWriteOperationID = operation->operationID();

    auto identifier = operation->identifier();
    m_pendingTransactionOperationQueue.append(operation.copyRef());
    m_transactionOperationMap.set(identifier, WTFMove(operation));

    handlePendingOperations();
}

void IDBTransaction::operationCompletedOnServer(const IDBResultData& data, IDBClient::TransactionOperation& operation)
{
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));
    ASSERT(canCurrentThreadAccessThreadLocalData(operation.originThread()));

    if (!m_transactionOperationMap.contains(operation.identifier()))
        return;

    m_transactionOperationResultMap.set(&operation, IDBResultData(data));

    if (!m_currentlyCompletingRequest)
        handleOperationsCompletedOnServer();
}

void IDBTransaction::handleOperationsCompletedOnServer()
{
    LOG(IndexedDB, "IDBTransaction::handleOperationsCompletedOnServer");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    while (!m_transactionOperationsInProgressQueue.isEmpty() && !m_currentlyCompletingRequest) {
        RefPtr<IDBClient::TransactionOperation> currentOperation = m_transactionOperationsInProgressQueue.first();
        if (!m_transactionOperationResultMap.contains(currentOperation))
            return;

        currentOperation->doComplete(m_transactionOperationResultMap.take(currentOperation));
    }
}

void IDBTransaction::completeNoncursorRequest(IDBRequest& request, const IDBResultData& result)
{
    ASSERT(!m_currentlyCompletingRequest);

    request.completeRequestAndDispatchEvent(result);

    m_currentlyCompletingRequest = &request;
}

void IDBTransaction::completeCursorRequest(IDBRequest& request, const IDBResultData& result)
{
    ASSERT(!m_currentlyCompletingRequest);

    request.didOpenOrIterateCursor(result);

    m_currentlyCompletingRequest = &request;
}

void IDBTransaction::finishedDispatchEventForRequest(IDBRequest& request)
{
    if (isFinished())
        return;

    ASSERT_UNUSED(request, !m_currentlyCompletingRequest || m_currentlyCompletingRequest == &request);

    m_currentlyCompletingRequest = nullptr;
    handleOperationsCompletedOnServer();
}

ExceptionOr<void> IDBTransaction::commit()
{
    LOG(IndexedDB, "IDBTransaction::commit");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    if (!isActive())
        return Exception { InvalidStateError, "Failed to execute 'commit' on 'IDBTransaction': The transaction is inactive."_s };

    if (m_currentlyCompletingRequest && m_currentlyCompletingRequest->willAbortTransactionAfterDispatchingEvent())
        return { };

    commitInternal();

    return { };
}

void IDBTransaction::commitInternal()
{
    LOG(IndexedDB, "IDBTransaction::commitInternal");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));
    ASSERT(!isFinishedOrFinishing());

    transitionedToFinishing(IndexedDB::TransactionState::Committing);
    m_database->willCommitTransaction(*this);

    LOG(IndexedDBOperations, "IDB commit operation: Transaction %s", info().identifier().loggingString().utf8().data());

    auto pendingRequestCount = std::count_if(m_openRequests.begin(), m_openRequests.end(), [](auto& request) {
        return !request->isDone();
    });

    scheduleOperation(IDBClient::TransactionOperationImpl::create(*this, nullptr, [protectedThis = Ref { *this }, pendingRequestCount] (auto& operation) {
        protectedThis->commitOnServer(operation, pendingRequestCount);
    }));
}

void IDBTransaction::commitOnServer(IDBClient::TransactionOperation& operation, uint64_t pendingRequestCount)
{
    LOG(IndexedDB, "IDBTransaction::commitOnServer");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    m_database->connectionProxy().commitTransaction(*this, pendingRequestCount);

    ASSERT(!m_transactionOperationsInProgressQueue.isEmpty());
    ASSERT(m_transactionOperationsInProgressQueue.last() == &operation);
    m_transactionOperationsInProgressQueue.removeLast();
    if (!m_transactionOperationsInProgressQueue.isEmpty())
        m_lastTransactionOperationBeforeCommit = m_transactionOperationsInProgressQueue.last()->identifier();

    ASSERT(m_transactionOperationMap.contains(operation.identifier()));
    m_transactionOperationMap.remove(operation.identifier());
}

void IDBTransaction::finishAbortOrCommit()
{
    ASSERT(m_state != IndexedDB::TransactionState::Finished);
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    m_state = IndexedDB::TransactionState::Finished;
}

void IDBTransaction::didStart(const IDBError& error)
{
    LOG(IndexedDB, "IDBTransaction::didStart");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    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;
    }

    handlePendingOperations();

    // It's possible transaction does not create requests (or creates but finishes them early
    // because of error) during intialization. In this case, since the transaction will
    // not be active any more, we can end it.
    autoCommit();
}

void IDBTransaction::notifyDidAbort(const IDBError& error)
{
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    m_database->didAbortTransaction(*this);
    m_idbError = error;
    fireOnAbort();

    if (isVersionChange() && !isContextStopped()) {
        ASSERT(m_openDBRequest);
        m_openDBRequest->fireErrorAfterVersionChangeCompletion();
    }
}

void IDBTransaction::didAbort(const IDBError& error)
{
    LOG(IndexedDB, "IDBTransaction::didAbort");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    if (m_state == IndexedDB::TransactionState::Finished)
        return;

    notifyDidAbort(error);

    finishAbortOrCommit();
}

void IDBTransaction::didCommit(const IDBError& error)
{
    LOG(IndexedDB, "IDBTransaction::didCommit");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));
    ASSERT(m_state == IndexedDB::TransactionState::Committing);

    // Delay commit until last request is completed.
    if (m_lastTransactionOperationBeforeCommit && m_transactionOperationMap.contains(*m_lastTransactionOperationBeforeCommit)) {
        m_commitResult = error;
        return;
    }

    if (error.isNull()) {
        m_database->didCommitTransaction(*this);
        fireOnComplete();
    } else {
        m_database->willAbortTransaction(*this);
        notifyDidAbort(error);
    }

    finishAbortOrCommit();
}

void IDBTransaction::fireOnComplete()
{
    LOG(IndexedDB, "IDBTransaction::fireOnComplete");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));
    enqueueEvent(Event::create(eventNames().completeEvent, Event::CanBubble::No, Event::IsCancelable::No));
}

void IDBTransaction::fireOnAbort()
{
    LOG(IndexedDB, "IDBTransaction::fireOnAbort");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));
    enqueueEvent(Event::create(eventNames().abortEvent, Event::CanBubble::Yes, Event::IsCancelable::No));
}

void IDBTransaction::enqueueEvent(Ref<Event>&& event)
{
    ASSERT(m_state != IndexedDB::TransactionState::Finished);
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    if (!scriptExecutionContext() || isContextStopped())
        return;

    m_abortOrCommitEvent = event.ptr();
    queueTaskToDispatchEvent(*this, TaskSource::DatabaseAccess, WTFMove(event));
}

void IDBTransaction::dispatchEvent(Event& event)
{
    LOG(IndexedDB, "IDBTransaction::dispatchEvent");

    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));
    ASSERT(scriptExecutionContext());
    ASSERT(!isContextStopped());
    

    Ref protectedThis { *this };

    EventDispatcher::dispatchEvent({ this, m_database.ptr() }, event);
    
    if (m_abortOrCommitEvent != &event)
        return;
    
    ASSERT(event.type() == eventNames().completeEvent || event.type() == eventNames().abortEvent);
    m_didDispatchAbortOrCommit = true;

    if (isVersionChange()) {
        m_openDBRequest->versionChangeTransactionDidFinish();

        if (event.type() == eventNames().completeEvent) {
            if (m_database->isClosingOrClosed())
                m_openDBRequest->fireErrorAfterVersionChangeCompletion();
            else
                m_openDBRequest->fireSuccessAfterVersionChangeCommit();
        }

        m_openDBRequest = nullptr;
    }
}

Ref<IDBObjectStore> IDBTransaction::createObjectStore(const IDBObjectStoreInfo& info)
{
    LOG(IndexedDB, "IDBTransaction::createObjectStore");
    ASSERT(isVersionChange());
    ASSERT(scriptExecutionContext());
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    Locker locker { m_referencedObjectStoreLock };

    auto objectStore = makeUnique<IDBObjectStore>(*scriptExecutionContext(), info, *this);
    auto* rawObjectStore = objectStore.get();
    m_referencedObjectStores.set(info.name(), WTFMove(objectStore));

    LOG(IndexedDBOperations, "IDB create object store operation: %s", info.condensedLoggingString().utf8().data());
    scheduleOperation(IDBClient::TransactionOperationImpl::create(*this, [protectedThis = Ref { *this }] (const auto& result) {
        protectedThis->didCreateObjectStoreOnServer(result);
    }, [protectedThis = Ref { *this }, info = info.isolatedCopy()] (auto& operation) {
        protectedThis->createObjectStoreOnServer(operation, info);
    }), IsWriteOperation::Yes);

    return *rawObjectStore;
}

void IDBTransaction::createObjectStoreOnServer(IDBClient::TransactionOperation& operation, const IDBObjectStoreInfo& info)
{
    LOG(IndexedDB, "IDBTransaction::createObjectStoreOnServer");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));
    ASSERT(isVersionChange());

    m_database->connectionProxy().createObjectStore(operation, info);
}

void IDBTransaction::didCreateObjectStoreOnServer(const IDBResultData& resultData)
{
    LOG(IndexedDB, "IDBTransaction::didCreateObjectStoreOnServer");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));
    ASSERT_UNUSED(resultData, resultData.type() == IDBResultType::CreateObjectStoreSuccess || resultData.type() == IDBResultType::Error);
}

void IDBTransaction::renameObjectStore(IDBObjectStore& objectStore, const String& newName)
{
    LOG(IndexedDB, "IDBTransaction::renameObjectStore");

    Locker locker { m_referencedObjectStoreLock };

    ASSERT(isVersionChange());
    ASSERT(scriptExecutionContext());
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    ASSERT(m_referencedObjectStores.contains(objectStore.info().name()));
    ASSERT(!m_referencedObjectStores.contains(newName));
    ASSERT(m_referencedObjectStores.get(objectStore.info().name()) == &objectStore);

    uint64_t objectStoreIdentifier = objectStore.info().identifier();

    LOG(IndexedDBOperations, "IDB rename object store operation: %s to %s", objectStore.info().condensedLoggingString().utf8().data(), newName.utf8().data());
    scheduleOperation(IDBClient::TransactionOperationImpl::create(*this, [protectedThis = Ref { *this }] (const auto& result) {
        protectedThis->didRenameObjectStoreOnServer(result);
    }, [protectedThis = Ref { *this }, objectStoreIdentifier, newName = newName.isolatedCopy()] (auto& operation) {
        protectedThis->renameObjectStoreOnServer(operation, objectStoreIdentifier, newName);
    }), IsWriteOperation::Yes);

    m_referencedObjectStores.set(newName, m_referencedObjectStores.take(objectStore.info().name()));
}

void IDBTransaction::renameObjectStoreOnServer(IDBClient::TransactionOperation& operation, const uint64_t& objectStoreIdentifier, const String& newName)
{
    LOG(IndexedDB, "IDBTransaction::renameObjectStoreOnServer");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));
    ASSERT(isVersionChange());

    m_database->connectionProxy().renameObjectStore(operation, objectStoreIdentifier, newName);
}

void IDBTransaction::didRenameObjectStoreOnServer(const IDBResultData& resultData)
{
    LOG(IndexedDB, "IDBTransaction::didRenameObjectStoreOnServer");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));
    ASSERT_UNUSED(resultData, resultData.type() == IDBResultType::RenameObjectStoreSuccess || resultData.type() == IDBResultType::Error);
}

std::unique_ptr<IDBIndex> IDBTransaction::createIndex(IDBObjectStore& objectStore, const IDBIndexInfo& info)
{
    LOG(IndexedDB, "IDBTransaction::createIndex");
    ASSERT(isVersionChange());
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    if (!scriptExecutionContext())
        return nullptr;

    LOG(IndexedDBOperations, "IDB create index operation: %s under object store %s", info.condensedLoggingString().utf8().data(), objectStore.info().condensedLoggingString().utf8().data());
    scheduleOperation(IDBClient::TransactionOperationImpl::create(*this, [protectedThis = Ref { *this }] (const auto& result) {
        protectedThis->didCreateIndexOnServer(result);
    }, [protectedThis = Ref { *this }, info = info.isolatedCopy()] (auto& operation) {
        protectedThis->createIndexOnServer(operation, info);
    }), IsWriteOperation::Yes);

    return makeUnique<IDBIndex>(*scriptExecutionContext(), info, objectStore);
}

void IDBTransaction::createIndexOnServer(IDBClient::TransactionOperation& operation, const IDBIndexInfo& info)
{
    LOG(IndexedDB, "IDBTransaction::createIndexOnServer");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));
    ASSERT(isVersionChange());

    m_database->connectionProxy().createIndex(operation, info);
}

void IDBTransaction::didCreateIndexOnServer(const IDBResultData& resultData)
{
    LOG(IndexedDB, "IDBTransaction::didCreateIndexOnServer");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    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.
    abortDueToFailedRequest(DOMException::create(resultData.error().message(), resultData.error().name()));
}

void IDBTransaction::renameIndex(IDBIndex& index, const String& newName)
{
    LOG(IndexedDB, "IDBTransaction::renameIndex");
    Locker locker { m_referencedObjectStoreLock };

    ASSERT(isVersionChange());
    ASSERT(scriptExecutionContext());
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    ASSERT(m_referencedObjectStores.contains(index.objectStore().info().name()));
    ASSERT(m_referencedObjectStores.get(index.objectStore().info().name()) == &index.objectStore());

    index.objectStore().renameReferencedIndex(index, newName);

    uint64_t objectStoreIdentifier = index.objectStore().info().identifier();
    uint64_t indexIdentifier = index.info().identifier();

    LOG(IndexedDBOperations, "IDB rename index operation: %s to %s under object store %" PRIu64, index.info().condensedLoggingString().utf8().data(), newName.utf8().data(), index.info().objectStoreIdentifier());
    scheduleOperation(IDBClient::TransactionOperationImpl::create(*this, [protectedThis = Ref { *this }] (const auto& result) {
        protectedThis->didRenameIndexOnServer(result);
    }, [protectedThis = Ref { *this }, objectStoreIdentifier, indexIdentifier, newName = newName.isolatedCopy()] (auto& operation) {
        protectedThis->renameIndexOnServer(operation, objectStoreIdentifier, indexIdentifier, newName);
    }), IsWriteOperation::Yes);
}

void IDBTransaction::renameIndexOnServer(IDBClient::TransactionOperation& operation, const uint64_t& objectStoreIdentifier, const uint64_t& indexIdentifier, const String& newName)
{
    LOG(IndexedDB, "IDBTransaction::renameIndexOnServer");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));
    ASSERT(isVersionChange());

    m_database->connectionProxy().renameIndex(operation, objectStoreIdentifier, indexIdentifier, newName);
}

void IDBTransaction::didRenameIndexOnServer(const IDBResultData& resultData)
{
    LOG(IndexedDB, "IDBTransaction::didRenameIndexOnServer");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));
    ASSERT_UNUSED(resultData, resultData.type() == IDBResultType::RenameIndexSuccess || resultData.type() == IDBResultType::Error);
}

Ref<IDBRequest> IDBTransaction::requestOpenCursor(IDBObjectStore& objectStore, const IDBCursorInfo& info)
{
    LOG(IndexedDB, "IDBTransaction::requestOpenCursor");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    if (info.cursorType() == IndexedDB::CursorType::KeyOnly)
        return doRequestOpenCursor(IDBCursor::create(objectStore, info));

    return doRequestOpenCursor(IDBCursorWithValue::create(objectStore, info));
}

Ref<IDBRequest> IDBTransaction::requestOpenCursor(IDBIndex& index, const IDBCursorInfo& info)
{
    LOG(IndexedDB, "IDBTransaction::requestOpenCursor");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    if (info.cursorType() == IndexedDB::CursorType::KeyOnly)
        return doRequestOpenCursor(IDBCursor::create(index, info));

    return doRequestOpenCursor(IDBCursorWithValue::create(index, info));
}

Ref<IDBRequest> IDBTransaction::doRequestOpenCursor(Ref<IDBCursor>&& cursor)
{
    ASSERT(isActive());
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    auto request = IDBRequest::create(*scriptExecutionContext(), cursor.get(), *this);
    addRequest(request.get());

    LOG(IndexedDBOperations, "IDB open cursor operation: %s", cursor->info().loggingString().utf8().data());
    scheduleOperation(IDBClient::TransactionOperationImpl::create(*this, request.get(), [protectedThis = Ref { *this }, request] (const auto& result) {
        protectedThis->didOpenCursorOnServer(request.get(), result);
    }, [protectedThis = Ref { *this }, info = cursor->info().isolatedCopy()] (auto& operation) {
        protectedThis->openCursorOnServer(operation, info);
    }));

    return request;
}

void IDBTransaction::openCursorOnServer(IDBClient::TransactionOperation& operation, const IDBCursorInfo& info)
{
    LOG(IndexedDB, "IDBTransaction::openCursorOnServer");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    m_database->connectionProxy().openCursor(operation, info);
}

void IDBTransaction::didOpenCursorOnServer(IDBRequest& request, const IDBResultData& resultData)
{
    LOG(IndexedDB, "IDBTransaction::didOpenCursorOnServer");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    completeCursorRequest(request, resultData);
}

void IDBTransaction::iterateCursor(IDBCursor& cursor, const IDBIterateCursorData& data)
{
    LOG(IndexedDB, "IDBTransaction::iterateCursor");
    ASSERT(isActive());
    ASSERT(cursor.request());
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    addRequest(*cursor.request());

    LOG(IndexedDBOperations, "IDB iterate cursor operation: %s %s", cursor.info().loggingString().utf8().data(), data.loggingString().utf8().data());
    scheduleOperation(IDBClient::TransactionOperationImpl::create(*this, *cursor.request(), [protectedThis = Ref { *this }, request = Ref { *cursor.request() }] (const auto& result) {
        protectedThis->didIterateCursorOnServer(request.get(), result);
    }, [protectedThis = Ref { *this }, data = data.isolatedCopy()] (auto& operation) {
        protectedThis->iterateCursorOnServer(operation, data);
    }));
}

// FIXME: changes here
void IDBTransaction::iterateCursorOnServer(IDBClient::TransactionOperation& operation, const IDBIterateCursorData& data)
{
    LOG(IndexedDB, "IDBTransaction::iterateCursorOnServer");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));
    ASSERT(operation.idbRequest());

    auto* cursor = operation.idbRequest()->pendingCursor();
    ASSERT(cursor);

    if (data.keyData.isNull() && data.primaryKeyData.isNull()) {
        if (auto getResult = cursor->iterateWithPrefetchedRecords(data.count, m_lastWriteOperationID)) {
            auto result = IDBResultData::iterateCursorSuccess(operation.identifier(), getResult.value());
            m_database->connectionProxy().iterateCursor(operation, { data.keyData, data.primaryKeyData, data.count, IndexedDB::CursorIterateOption::DoNotReply });
            operationCompletedOnServer(result, operation);
            return;
        }
    }

    cursor->clearPrefetchedRecords();

    ASSERT(data.option == IndexedDB::CursorIterateOption::Reply);
    m_database->connectionProxy().iterateCursor(operation, data);
}

void IDBTransaction::didIterateCursorOnServer(IDBRequest& request, const IDBResultData& resultData)
{
    LOG(IndexedDB, "IDBTransaction::didIterateCursorOnServer");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    completeCursorRequest(request, resultData);
}

Ref<IDBRequest> IDBTransaction::requestGetAllObjectStoreRecords(IDBObjectStore& objectStore, const IDBKeyRangeData& keyRangeData, IndexedDB::GetAllType getAllType, std::optional<uint32_t> count)
{
    LOG(IndexedDB, "IDBTransaction::requestGetAllObjectStoreRecords");
    ASSERT(isActive());
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    auto request = IDBRequest::create(*scriptExecutionContext(), objectStore, *this);
    addRequest(request.get());

    IDBGetAllRecordsData getAllRecordsData { keyRangeData, getAllType, count, objectStore.info().identifier(), 0 };

    LOG(IndexedDBOperations, "IDB get all object store records operation: %s", getAllRecordsData.loggingString().utf8().data());
    scheduleOperation(IDBClient::TransactionOperationImpl::create(*this, request.get(), [protectedThis = Ref { *this }, request] (const auto& result) {
        protectedThis->didGetAllRecordsOnServer(request.get(), result);
    }, [protectedThis = Ref { *this }, getAllRecordsData = getAllRecordsData.isolatedCopy()] (auto& operation) {
        protectedThis->getAllRecordsOnServer(operation, getAllRecordsData);
    }));

    return request;
}

Ref<IDBRequest> IDBTransaction::requestGetAllIndexRecords(IDBIndex& index, const IDBKeyRangeData& keyRangeData, IndexedDB::GetAllType getAllType, std::optional<uint32_t> count)
{
    LOG(IndexedDB, "IDBTransaction::requestGetAllIndexRecords");
    ASSERT(isActive());
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));


    auto request = IDBRequest::create(*scriptExecutionContext(), index, *this);
    addRequest(request.get());

    IDBGetAllRecordsData getAllRecordsData { keyRangeData, getAllType, count, index.objectStore().info().identifier(), index.info().identifier() };

    LOG(IndexedDBOperations, "IDB get all index records operation: %s", getAllRecordsData.loggingString().utf8().data());
    scheduleOperation(IDBClient::TransactionOperationImpl::create(*this, request.get(), [protectedThis = Ref { *this }, request] (const auto& result) {
        protectedThis->didGetAllRecordsOnServer(request.get(), result);
    }, [protectedThis = Ref { *this }, getAllRecordsData = getAllRecordsData.isolatedCopy()] (auto& operation) {
        protectedThis->getAllRecordsOnServer(operation, getAllRecordsData);
    }));

    return request;
}

void IDBTransaction::getAllRecordsOnServer(IDBClient::TransactionOperation& operation, const IDBGetAllRecordsData& getAllRecordsData)
{
    LOG(IndexedDB, "IDBTransaction::getAllRecordsOnServer");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    m_database->connectionProxy().getAllRecords(operation, getAllRecordsData);
}

void IDBTransaction::didGetAllRecordsOnServer(IDBRequest& request, const IDBResultData& resultData)
{
    LOG(IndexedDB, "IDBTransaction::didGetAllRecordsOnServer");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    if (resultData.type() == IDBResultType::Error) {
        completeNoncursorRequest(request, resultData);
        return;
    }

    ASSERT(resultData.type() == IDBResultType::GetAllRecordsSuccess);

    auto& getAllResult = resultData.getAllResult();
    switch (getAllResult.type()) {
    case IndexedDB::GetAllType::Keys:
        request.setResult(getAllResult.keys());
        break;
    case IndexedDB::GetAllType::Values:
        request.setResult(getAllResult);
        break;
    }

    completeNoncursorRequest(request, resultData);
}

Ref<IDBRequest> IDBTransaction::requestGetRecord(IDBObjectStore& objectStore, const IDBGetRecordData& getRecordData)
{
    LOG(IndexedDB, "IDBTransaction::requestGetRecord");
    ASSERT(isActive());
    ASSERT(!getRecordData.keyRangeData.isNull);
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    IndexedDB::ObjectStoreRecordType type = getRecordData.type == IDBGetRecordDataType::KeyAndValue ? IndexedDB::ObjectStoreRecordType::ValueOnly : IndexedDB::ObjectStoreRecordType::KeyOnly;

    auto request = IDBRequest::createObjectStoreGet(*scriptExecutionContext(), objectStore, type, *this);
    addRequest(request.get());

    LOG(IndexedDBOperations, "IDB get record operation: %s %s", objectStore.info().condensedLoggingString().utf8().data(), getRecordData.loggingString().utf8().data());
    scheduleOperation(IDBClient::TransactionOperationImpl::create(*this, request.get(), [protectedThis = Ref { *this }, request] (const auto& result) {
        protectedThis->didGetRecordOnServer(request.get(), result);
    }, [protectedThis = Ref { *this }, getRecordData = getRecordData.isolatedCopy()] (auto& operation) {
        protectedThis->getRecordOnServer(operation, getRecordData);
    }));

    return request;
}

Ref<IDBRequest> IDBTransaction::requestGetValue(IDBIndex& index, const IDBKeyRangeData& range)
{
    LOG(IndexedDB, "IDBTransaction::requestGetValue");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    return requestIndexRecord(index, IndexedDB::IndexRecordType::Value, range);
}

Ref<IDBRequest> IDBTransaction::requestGetKey(IDBIndex& index, const IDBKeyRangeData& range)
{
    LOG(IndexedDB, "IDBTransaction::requestGetValue");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    return requestIndexRecord(index, IndexedDB::IndexRecordType::Key, range);
}

Ref<IDBRequest> IDBTransaction::requestIndexRecord(IDBIndex& index, IndexedDB::IndexRecordType type, const IDBKeyRangeData& range)
{
    LOG(IndexedDB, "IDBTransaction::requestGetValue");
    ASSERT(isActive());
    ASSERT(!range.isNull);
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    auto request = IDBRequest::createIndexGet(*scriptExecutionContext(), index, type, *this);
    addRequest(request.get());

    IDBGetRecordData getRecordData = { range, IDBGetRecordDataType::KeyAndValue };

    LOG(IndexedDBOperations, "IDB get index record operation: %s %s", index.info().condensedLoggingString().utf8().data(), getRecordData.loggingString().utf8().data());
    scheduleOperation(IDBClient::TransactionOperationImpl::create(*this, request.get(), [protectedThis = Ref { *this }, request] (const auto& result) {
        protectedThis->didGetRecordOnServer(request.get(), result);
    }, [protectedThis = Ref { *this }, getRecordData = getRecordData.isolatedCopy()] (auto& operation) {
        protectedThis->getRecordOnServer(operation, getRecordData);
    }));

    return request;
}

void IDBTransaction::getRecordOnServer(IDBClient::TransactionOperation& operation, const IDBGetRecordData& getRecordData)
{
    LOG(IndexedDB, "IDBTransaction::getRecordOnServer");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    m_database->connectionProxy().getRecord(operation, getRecordData);
}

void IDBTransaction::didGetRecordOnServer(IDBRequest& request, const IDBResultData& resultData)
{
    LOG(IndexedDB, "IDBTransaction::didGetRecordOnServer");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    if (resultData.type() == IDBResultType::Error) {
        completeNoncursorRequest(request, resultData);
        return;
    }

    ASSERT(resultData.type() == IDBResultType::GetRecordSuccess);

    bool useResultKey = request.sourceIndexIdentifier() && request.requestedIndexRecordType() == IndexedDB::IndexRecordType::Key;
    if (!useResultKey)
        useResultKey = request.requestedObjectStoreRecordType() == IndexedDB::ObjectStoreRecordType::KeyOnly;

    const IDBGetResult& result = resultData.getResult();

    if (useResultKey) {
        if (!result.keyData().isNull())
            request.setResult(result.keyData());
        else
            request.setResultToUndefined();
    } else {
        if (resultData.getResult().value().data().data())
            request.setResultToStructuredClone(resultData.getResult());
        else
            request.setResultToUndefined();
    }

    completeNoncursorRequest(request, resultData);
}

Ref<IDBRequest> IDBTransaction::requestCount(IDBObjectStore& objectStore, const IDBKeyRangeData& range)
{
    LOG(IndexedDB, "IDBTransaction::requestCount (IDBObjectStore)");
    ASSERT(isActive());
    ASSERT(!range.isNull);
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    auto request = IDBRequest::create(*scriptExecutionContext(), objectStore, *this);
    addRequest(request.get());

    LOG(IndexedDBOperations, "IDB object store count operation: %s, range %s", objectStore.info().condensedLoggingString().utf8().data(), range.loggingString().utf8().data());
    scheduleOperation(IDBClient::TransactionOperationImpl::create(*this, request.get(), [protectedThis = Ref { *this }, request] (const auto& result) {
        protectedThis->didGetCountOnServer(request.get(), result);
    }, [protectedThis = Ref { *this }, range = range.isolatedCopy()] (auto& operation) {
        protectedThis->getCountOnServer(operation, range);
    }));

    return request;
}

Ref<IDBRequest> IDBTransaction::requestCount(IDBIndex& index, const IDBKeyRangeData& range)
{
    LOG(IndexedDB, "IDBTransaction::requestCount (IDBIndex)");
    ASSERT(isActive());
    ASSERT(!range.isNull);
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    auto request = IDBRequest::create(*scriptExecutionContext(), index, *this);
    addRequest(request.get());

    LOG(IndexedDBOperations, "IDB index count operation: %s, range %s", index.info().condensedLoggingString().utf8().data(), range.loggingString().utf8().data());
    scheduleOperation(IDBClient::TransactionOperationImpl::create(*this, request.get(), [protectedThis = Ref { *this }, request] (const auto& result) {
        protectedThis->didGetCountOnServer(request.get(), result);
    }, [protectedThis = Ref { *this }, range = range.isolatedCopy()] (auto& operation) {
        protectedThis->getCountOnServer(operation, range);
    }));

    return request;
}

void IDBTransaction::getCountOnServer(IDBClient::TransactionOperation& operation, const IDBKeyRangeData& keyRange)
{
    LOG(IndexedDB, "IDBTransaction::getCountOnServer");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    m_database->connectionProxy().getCount(operation, keyRange);
}

void IDBTransaction::didGetCountOnServer(IDBRequest& request, const IDBResultData& resultData)
{
    LOG(IndexedDB, "IDBTransaction::didGetCountOnServer");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    request.setResult(resultData.resultInteger());
    completeNoncursorRequest(request, resultData);
}

Ref<IDBRequest> IDBTransaction::requestDeleteRecord(IDBObjectStore& objectStore, const IDBKeyRangeData& range)
{
    LOG(IndexedDB, "IDBTransaction::requestDeleteRecord");
    ASSERT(isActive());
    ASSERT(!range.isNull);
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    auto request = IDBRequest::create(*scriptExecutionContext(), objectStore, *this);
    addRequest(request.get());

    LOG(IndexedDBOperations, "IDB delete record operation: %s, range %s", objectStore.info().condensedLoggingString().utf8().data(), range.loggingString().utf8().data());
    scheduleOperation(IDBClient::TransactionOperationImpl::create(*this, request.get(), [protectedThis = Ref { *this }, request] (const auto& result) {
        protectedThis->didDeleteRecordOnServer(request.get(), result);
    }, [protectedThis = Ref { *this }, range = range.isolatedCopy()] (auto& operation) {
        protectedThis->deleteRecordOnServer(operation, range);
    }), IsWriteOperation::Yes);
    return request;
}

void IDBTransaction::deleteRecordOnServer(IDBClient::TransactionOperation& operation, const IDBKeyRangeData& keyRange)
{
    LOG(IndexedDB, "IDBTransaction::deleteRecordOnServer");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    m_database->connectionProxy().deleteRecord(operation, keyRange);
}

void IDBTransaction::didDeleteRecordOnServer(IDBRequest& request, const IDBResultData& resultData)
{
    LOG(IndexedDB, "IDBTransaction::didDeleteRecordOnServer");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    request.setResultToUndefined();
    completeNoncursorRequest(request, resultData);
}

Ref<IDBRequest> IDBTransaction::requestClearObjectStore(IDBObjectStore& objectStore)
{
    LOG(IndexedDB, "IDBTransaction::requestClearObjectStore");
    ASSERT(isActive());
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    auto request = IDBRequest::create(*scriptExecutionContext(), objectStore, *this);
    addRequest(request.get());

    uint64_t objectStoreIdentifier = objectStore.info().identifier();

    LOG(IndexedDBOperations, "IDB clear object store operation: %s", objectStore.info().condensedLoggingString().utf8().data());
    scheduleOperation(IDBClient::TransactionOperationImpl::create(*this, request.get(), [protectedThis = Ref { *this }, request] (const auto& result) {
        protectedThis->didClearObjectStoreOnServer(request.get(), result);
    }, [protectedThis = Ref { *this }, objectStoreIdentifier] (auto& operation) {
        protectedThis->clearObjectStoreOnServer(operation, objectStoreIdentifier);
    }), IsWriteOperation::Yes);

    return request;
}

void IDBTransaction::clearObjectStoreOnServer(IDBClient::TransactionOperation& operation, const uint64_t& objectStoreIdentifier)
{
    LOG(IndexedDB, "IDBTransaction::clearObjectStoreOnServer");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    m_database->connectionProxy().clearObjectStore(operation, objectStoreIdentifier);
}

void IDBTransaction::didClearObjectStoreOnServer(IDBRequest& request, const IDBResultData& resultData)
{
    LOG(IndexedDB, "IDBTransaction::didClearObjectStoreOnServer");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    request.setResultToUndefined();
    completeNoncursorRequest(request, resultData);
}

Ref<IDBRequest> IDBTransaction::requestPutOrAdd(IDBObjectStore& objectStore, RefPtr<IDBKey>&& key, SerializedScriptValue& value, IndexedDB::ObjectStoreOverwriteMode overwriteMode)
{
    LOG(IndexedDB, "IDBTransaction::requestPutOrAdd");
    ASSERT(isActive());
    ASSERT(!isReadOnly());
    ASSERT(objectStore.info().autoIncrement() || key);
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    auto request = IDBRequest::create(*scriptExecutionContext(), objectStore, *this);
    addRequest(request.get());

    LOG(IndexedDBOperations, "IDB putOrAdd operation: %s key: %s", objectStore.info().condensedLoggingString().utf8().data(), key ? key->loggingString().utf8().data() : "<null key>");
    scheduleOperation(IDBClient::TransactionOperationImpl::create(*this, request.get(), [protectedThis = Ref { *this }, request] (const auto& result) {
        protectedThis->didPutOrAddOnServer(request.get(), result);
    }, [protectedThis = Ref { *this }, key, value = Ref { value }, overwriteMode] (auto& operation) {
        protectedThis->putOrAddOnServer(operation, key.get(), value.ptr(), overwriteMode);
    }), IsWriteOperation::Yes);

    return request;
}

void IDBTransaction::putOrAddOnServer(IDBClient::TransactionOperation& operation, RefPtr<IDBKey> key, RefPtr<SerializedScriptValue> value, const IndexedDB::ObjectStoreOverwriteMode& overwriteMode)
{
    LOG(IndexedDB, "IDBTransaction::putOrAddOnServer");
    ASSERT(canCurrentThreadAccessThreadLocalData(originThread()));
    ASSERT(!isReadOnly());
    ASSERT(value);

    if (!value->hasBlobURLs()) {
        m_database->connectionProxy().putOrAdd(operation, key.get(), *value, overwriteMode);
        return;
    }

    // Due to current limitations on our ability to post tasks back to a worker thread,
    // workers currently write blobs to disk synchronously.
    // FIXME: https://bugs.webkit.org/show_bug.cgi?id=157958 - Make this asynchronous after refactoring allows it.
    if (!isMainThread()) {
        auto idbValue = value->writeBlobsToDiskForIndexedDBSynchronously();
        if (idbValue.data().data())
            m_database->connectionProxy().putOrAdd(operation, key.get(), idbValue, overwriteMode);
        else {
            // If the IDBValue doesn't have any data, then something went wrong writing the blobs to disk.
            // In that case, we cannot successfully store this record, so we callback with an error.
            RefPtr<IDBClient::TransactionOperation> protectedOperation(&operation);
            auto result = IDBResultData::error(operation.identifier(), IDBError { UnknownError, "Error preparing Blob/File data to be stored in object store"_s });
            scriptExecutionContext()->postTask([protectedOperation = WTFMove(protectedOperation), result = WTFMove(result)](ScriptExecutionContext&) {
                protectedOperation->doComplete(result);
            });
        }
        return;
    }

    // Since this request won't actually go to the server until the blob writes are complete,
    // stop future requests from going to the server ahead of it.
    operation.setNextRequestCanGoToServer(false);

    value->writeBlobsToDiskForIndexedDB([protectedThis = Ref { *this }, this, protectedOperation = Ref<IDBClient::TransactionOperation>(operation), keyData = IDBKeyData(key.get()).isolatedCopy(), overwriteMode](IDBValue&& idbValue) mutable {
        ASSERT(canCurrentThreadAccessThreadLocalData(originThread()));
        ASSERT(isMainThread());
        if (idbValue.data().data()) {
            m_database->connectionProxy().putOrAdd(protectedOperation.get(), WTFMove(keyData), idbValue, overwriteMode);
            return;
        }

        // If the IDBValue doesn't have any data, then something went wrong writing the blobs to disk.
        // In that case, we cannot successfully store this record, so we callback with an error.
        auto result = IDBResultData::error(protectedOperation->identifier(), IDBError { UnknownError, "Error preparing Blob/File data to be stored in object store"_s });
        callOnMainThread([protectedThis = WTFMove(protectedThis), protectedOperation = WTFMove(protectedOperation), result = WTFMove(result)]() mutable {
            protectedOperation->doComplete(result);
        });
    });
}

void IDBTransaction::didPutOrAddOnServer(IDBRequest& request, const IDBResultData& resultData)
{
    LOG(IndexedDB, "IDBTransaction::didPutOrAddOnServer");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    if (auto* result = resultData.resultKey())
        request.setResult(*result);
    else
        request.setResultToUndefined();
    completeNoncursorRequest(request, resultData);
}

void IDBTransaction::deleteObjectStore(const String& objectStoreName)
{
    LOG(IndexedDB, "IDBTransaction::deleteObjectStore");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));
    ASSERT(isVersionChange());

    Locker locker { m_referencedObjectStoreLock };

    if (auto objectStore = m_referencedObjectStores.take(objectStoreName)) {
        objectStore->markAsDeleted();
        auto identifier = objectStore->info().identifier();
        m_deletedObjectStores.set(identifier, WTFMove(objectStore));
    }

    LOG(IndexedDBOperations, "IDB delete object store operation: %s", objectStoreName.utf8().data());
    scheduleOperation(IDBClient::TransactionOperationImpl::create(*this, [protectedThis = Ref { *this }] (const auto& result) {
        protectedThis->didDeleteObjectStoreOnServer(result);
    }, [protectedThis = Ref { *this }, objectStoreName = objectStoreName.isolatedCopy()] (auto& operation) {
        protectedThis->deleteObjectStoreOnServer(operation, objectStoreName);
    }), IsWriteOperation::Yes);
}

void IDBTransaction::deleteObjectStoreOnServer(IDBClient::TransactionOperation& operation, const String& objectStoreName)
{
    LOG(IndexedDB, "IDBTransaction::deleteObjectStoreOnServer");
    ASSERT(isVersionChange());
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    m_database->connectionProxy().deleteObjectStore(operation, objectStoreName);
}

void IDBTransaction::didDeleteObjectStoreOnServer(const IDBResultData& resultData)
{
    LOG(IndexedDB, "IDBTransaction::didDeleteObjectStoreOnServer");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));
    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(canCurrentThreadAccessThreadLocalData(m_database->originThread()));
    ASSERT(isVersionChange());

    LOG(IndexedDBOperations, "IDB delete index operation: %s (%" PRIu64 ")", indexName.utf8().data(), objectStoreIdentifier);
    scheduleOperation(IDBClient::TransactionOperationImpl::create(*this, [protectedThis = Ref { *this }] (const auto& result) {
        protectedThis->didDeleteIndexOnServer(result);
    }, [protectedThis = Ref { *this }, objectStoreIdentifier, indexName = indexName.isolatedCopy()] (auto& operation) {
        protectedThis->deleteIndexOnServer(operation, objectStoreIdentifier, indexName);
    }), IsWriteOperation::Yes);
}

void IDBTransaction::deleteIndexOnServer(IDBClient::TransactionOperation& operation, const uint64_t& objectStoreIdentifier, const String& indexName)
{
    LOG(IndexedDB, "IDBTransaction::deleteIndexOnServer");
    ASSERT(isVersionChange());
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    m_database->connectionProxy().deleteIndex(operation, objectStoreIdentifier, indexName);
}

void IDBTransaction::didDeleteIndexOnServer(const IDBResultData& resultData)
{
    LOG(IndexedDB, "IDBTransaction::didDeleteIndexOnServer");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));
    ASSERT_UNUSED(resultData, resultData.type() == IDBResultType::DeleteIndexSuccess || resultData.type() == IDBResultType::Error);
}

void IDBTransaction::operationCompletedOnClient(IDBClient::TransactionOperation& operation)
{
    LOG(IndexedDB, "IDBTransaction::operationCompletedOnClient");

    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));
    ASSERT(canCurrentThreadAccessThreadLocalData(operation.originThread()));
    ASSERT(m_transactionOperationMap.get(operation.identifier()) == &operation);
    ASSERT(m_transactionOperationsInProgressQueue.first() == &operation);

    m_transactionOperationMap.remove(operation.identifier());
    m_transactionOperationsInProgressQueue.removeFirst();

    if (m_commitResult && operation.identifier() == *m_lastTransactionOperationBeforeCommit) {
        didCommit(*m_commitResult);
        return;
    }

    if (m_transactionOperationsInProgressQueue.isEmpty())
        handlePendingOperations();

    autoCommit();
}

void IDBTransaction::establishOnServer()
{
    LOG(IndexedDB, "IDBTransaction::establishOnServer");
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    m_database->connectionProxy().establishTransaction(*this);
}

void IDBTransaction::activate()
{
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    if (isFinishedOrFinishing())
        return;

    m_state = IndexedDB::TransactionState::Active;
}

void IDBTransaction::deactivate()
{
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    if (m_state == IndexedDB::TransactionState::Active)
        m_state = IndexedDB::TransactionState::Inactive;

    autoCommit();
}

void IDBTransaction::connectionClosedFromServer(const IDBError& error)
{
    LOG(IndexedDB, "IDBTransaction::connectionClosedFromServer - %s", error.message().utf8().data());

    m_database->willAbortTransaction(*this);
    m_state = IndexedDB::TransactionState::Aborting;

    // Move operations out of m_pendingTransactionOperationQueue, otherwise we may start handling
    // them after we forcibly complete in-progress transactions.
    Deque<RefPtr<IDBClient::TransactionOperation>> pendingTransactionOperationQueue;
    pendingTransactionOperationQueue.swap(m_pendingTransactionOperationQueue);

    abortInProgressOperations(error);

    auto operations = copyToVector(m_transactionOperationMap.values());
    for (auto& operation : operations) {
        m_currentlyCompletingRequest = nullptr;
        m_transactionOperationsInProgressQueue.append(operation.get());
        ASSERT(m_transactionOperationsInProgressQueue.first() == operation.get());
        operation->doComplete(IDBResultData::error(operation->identifier(), error));
    }
    m_currentlyCompletingRequest = nullptr;
    m_openRequests.clear();
    pendingTransactionOperationQueue.clear();

    connectionProxy().forgetActiveOperations(operations);
    connectionProxy().forgetTransaction(*this);

    m_abortQueue.clear();
    m_transactionOperationMap.clear();

    m_idbError = error;
    m_domError = error.toDOMException();
    m_database->didAbortTransaction(*this);
    fireOnAbort();
}

template<typename Visitor>
void IDBTransaction::visitReferencedObjectStores(Visitor& visitor) const
{
    Locker locker { m_referencedObjectStoreLock };
    for (auto& objectStore : m_referencedObjectStores.values())
        visitor.addOpaqueRoot(objectStore.get());
    for (auto& objectStore : m_deletedObjectStores.values())
        visitor.addOpaqueRoot(objectStore.get());
}

template void IDBTransaction::visitReferencedObjectStores(JSC::AbstractSlotVisitor&) const;
template void IDBTransaction::visitReferencedObjectStores(JSC::SlotVisitor&) const;

void IDBTransaction::handlePendingOperations()
{
    ASSERT(canCurrentThreadAccessThreadLocalData(m_database->originThread()));

    if (!m_startedOnServer)
        return;

    if (!m_transactionOperationsInProgressQueue.isEmpty() && !m_transactionOperationsInProgressQueue.last()->nextRequestCanGoToServer())
        return;

    while (!m_pendingTransactionOperationQueue.isEmpty()) {
        auto operation = m_pendingTransactionOperationQueue.takeFirst();
        m_transactionOperationsInProgressQueue.append(operation.get());
        operation->perform();

        if (!operation->nextRequestCanGoToServer())
            break;
    }
}

void IDBTransaction::autoCommit()
{
    // If transaction is not inactive, it's active, finished or finishing.
    // If it's active, it may create new requests, so we cannot commit it.
    if (m_state != IndexedDB::TransactionState::Inactive)
        return;

    if (!m_startedOnServer)
        return;

    if (!m_transactionOperationMap.isEmpty())
        return;

    if (!m_openRequests.isEmpty())
        return;
    ASSERT(!m_currentlyCompletingRequest);

    commitInternal();
}

uint64_t IDBTransaction::generateOperationID()
{
    static std::atomic<uint64_t> currentOperationID(1);
    return currentOperationID += 1;
}

} // namespace WebCore
