/*
 * 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.
 */

#include "config.h"
#include "UniqueIDBDatabase.h"

#if ENABLE(INDEXED_DATABASE)

#include "IDBCursorInfo.h"
#include "IDBGetAllRecordsData.h"
#include "IDBGetAllResult.h"
#include "IDBGetRecordData.h"
#include "IDBIterateCursorData.h"
#include "IDBKeyRangeData.h"
#include "IDBResultData.h"
#include "IDBServer.h"
#include "IDBTransactionInfo.h"
#include "IDBValue.h"
#include "Logging.h"
#include "StorageQuotaManager.h"
#include "UniqueIDBDatabaseConnection.h"
#include <wtf/Scope.h>

namespace WebCore {
using namespace JSC;
namespace IDBServer {

static const uint64_t defaultWriteOperationCost = 4;

static inline uint64_t estimateSize(const IDBKeyData& keyData)
{
    uint64_t size = 4;
    switch (keyData.type()) {
    case IndexedDB::KeyType::String:
        size += keyData.string().sizeInBytes();
        break;
    case IndexedDB::KeyType::Binary: {
        size += keyData.binary().size();
        break;
    }
    case IndexedDB::KeyType::Array:
        for (auto& data : keyData.array())
            size += estimateSize(data);
        break;
    default:
        break;
    }
    return size;
}

static inline uint64_t estimateSize(const IDBValue& value)
{
    uint64_t size = 4;
    size += value.data().size();
    for (auto& url : value.blobURLs())
        size += url.sizeInBytes();
    for (auto& path : value.blobFilePaths())
        size += path.sizeInBytes();
    return size;
}

static inline uint64_t estimateSize(const IDBKeyPath& keyPath)
{
    return WTF::switchOn(keyPath, [](const String& path) {
        return static_cast<uint64_t>(path.sizeInBytes());
    }, [](const Vector<String>& paths) {
        uint64_t size = 0;
        for (auto path : paths)
            size += path.sizeInBytes();
        return size;
    });
}

static inline uint64_t estimateSize(const IDBIndexInfo& info)
{
    uint64_t size = 4;
    size += info.name().sizeInBytes();
    size += estimateSize(info.keyPath());
    return size;
}

static inline uint64_t estimateSize(const IDBObjectStoreInfo& info)
{
    uint64_t size = 4;
    size += info.name().sizeInBytes();
    if (auto keyPath = info.keyPath())
        size += estimateSize(*keyPath);
    return size;
}

UniqueIDBDatabase::UniqueIDBDatabase(IDBServer& server, const IDBDatabaseIdentifier& identifier)
    : m_server(server)
    , m_identifier(identifier)
{
    ASSERT(!isMainThread());

    LOG(IndexedDB, "UniqueIDBDatabase::UniqueIDBDatabase() (%p) %s", this, m_identifier.loggingString().utf8().data());
}

UniqueIDBDatabase::~UniqueIDBDatabase()
{
    LOG(IndexedDB, "UniqueIDBDatabase::~UniqueIDBDatabase() (%p) %s", this, m_identifier.loggingString().utf8().data());
    ASSERT(!isMainThread());
    ASSERT(m_pendingOpenDBRequests.isEmpty());
    ASSERT(!m_currentOpenDBRequest);
    ASSERT(m_inProgressTransactions.isEmpty());
    ASSERT(m_pendingTransactions.isEmpty());
    ASSERT(!hasAnyOpenConnections());
    ASSERT(!m_versionChangeTransaction);
    ASSERT(!m_versionChangeDatabaseConnection);
    RELEASE_ASSERT(!m_backingStore);
}

const IDBDatabaseInfo& UniqueIDBDatabase::info() const
{
    RELEASE_ASSERT(m_databaseInfo);
    return *m_databaseInfo;
}

void UniqueIDBDatabase::openDatabaseConnection(IDBConnectionToClient& connection, const IDBRequestData& requestData)
{
    LOG(IndexedDB, "UniqueIDBDatabase::openDatabaseConnection");
    ASSERT(!isMainThread());

    m_pendingOpenDBRequests.add(ServerOpenDBRequest::create(connection, requestData));

    handleDatabaseOperations();
}

static inline String quotaErrorMessageName(const char* taskName)
{
    return makeString("Failed to ", taskName, " in database because not enough space for domain");
}

void UniqueIDBDatabase::performCurrentOpenOperation()
{
    LOG(IndexedDB, "UniqueIDBDatabase::performCurrentOpenOperation (%p)", this);

    ASSERT(m_currentOpenDBRequest);
    ASSERT(m_currentOpenDBRequest->isOpenRequest());

    IDBError backingStoreOpenError;
    if (!m_backingStore) {
        // Quota check.
        auto decision = m_server.requestSpace(m_identifier.origin(), defaultWriteOperationCost);
        if (decision == StorageQuotaManager::Decision::Deny)
            backingStoreOpenError = IDBError { QuotaExceededError, quotaErrorMessageName("OpenBackingStore") };
        else {
            m_backingStore = m_server.createBackingStore(m_identifier);
            IDBDatabaseInfo databaseInfo;
            backingStoreOpenError = m_backingStore->getOrEstablishDatabaseInfo(databaseInfo);
            if (backingStoreOpenError.isNull())
                m_databaseInfo = makeUnique<IDBDatabaseInfo>(databaseInfo);
            else
                m_backingStore = nullptr;
        }
    }

    if (!backingStoreOpenError.isNull()) {
        auto result = IDBResultData::error(m_currentOpenDBRequest->requestData().requestIdentifier(), backingStoreOpenError);
        m_currentOpenDBRequest->connection().didOpenDatabase(result);
        m_currentOpenDBRequest = nullptr;

        return;
    }

    // If we previously started a version change operation but were blocked by having open connections,
    // we might now be unblocked.
    if (m_versionChangeDatabaseConnection) {
        if (!m_versionChangeTransaction && !hasAnyOpenConnections())
            startVersionChangeTransaction();
        return;
    }

    // 3.3.1 Opening a database
    // If requested version is undefined, then let requested version be 1 if db was created in the previous step,
    // or the current version of db otherwise.
    uint64_t requestedVersion = m_currentOpenDBRequest->requestData().requestedVersion();
    if (!requestedVersion)
        requestedVersion = m_databaseInfo->version() ? m_databaseInfo->version() : 1;

    // 3.3.1 Opening a database
    // If the database version higher than the requested version, abort these steps and return a VersionError.
    if (requestedVersion < m_databaseInfo->version()) {
        auto result = IDBResultData::error(m_currentOpenDBRequest->requestData().requestIdentifier(), IDBError(VersionError));
        m_currentOpenDBRequest->connection().didOpenDatabase(result);
        m_currentOpenDBRequest = nullptr;

        return;
    }

    Ref<UniqueIDBDatabaseConnection> connection = UniqueIDBDatabaseConnection::create(*this, *m_currentOpenDBRequest);

    if (requestedVersion == m_databaseInfo->version()) {
        auto* rawConnection = &connection.get();
        addOpenDatabaseConnection(WTFMove(connection));

        auto result = IDBResultData::openDatabaseSuccess(m_currentOpenDBRequest->requestData().requestIdentifier(), *rawConnection);
        m_currentOpenDBRequest->connection().didOpenDatabase(result);
        m_currentOpenDBRequest = nullptr;

        return;
    }

    ASSERT(!m_versionChangeDatabaseConnection);
    m_versionChangeDatabaseConnection = WTFMove(connection);

    // 3.3.7 "versionchange" transaction steps
    // If there's no other open connections to this database, the version change process can begin immediately.
    if (!hasAnyOpenConnections()) {
        startVersionChangeTransaction();
        return;
    }

    // Otherwise we have to notify all those open connections and wait for them to close.
    maybeNotifyConnectionsOfVersionChange();
}

void UniqueIDBDatabase::performCurrentDeleteOperation()
{
    LOG(IndexedDB, "UniqueIDBDatabase::performCurrentDeleteOperation - %s", m_identifier.loggingString().utf8().data());

    ASSERT(m_currentOpenDBRequest);
    ASSERT(m_currentOpenDBRequest->isDeleteRequest());

    if (hasAnyOpenConnections()) {
        maybeNotifyConnectionsOfVersionChange();
        return;
    }

    ASSERT(m_pendingTransactions.isEmpty());
    ASSERT(m_openDatabaseConnections.isEmpty());

    // It's possible to have multiple delete requests queued up in a row.
    // In that scenario only the first request will actually have to delete the database.
    // Subsequent requests can immediately notify their completion.

    if (!m_databaseInfo && m_mostRecentDeletedDatabaseInfo)
        didDeleteBackingStore(0);
    else
        deleteBackingStore();
}

void UniqueIDBDatabase::deleteBackingStore()
{
    ASSERT(!isMainThread());
    LOG(IndexedDB, "UniqueIDBDatabase::deleteBackingStore");

    uint64_t deletedVersion = 0;

    if (m_backingStore) {
        m_backingStore->deleteBackingStore();
        m_backingStore = nullptr;
    } else {
        auto backingStore = m_server.createBackingStore(m_identifier);

        IDBDatabaseInfo databaseInfo;
        auto error = backingStore->getOrEstablishDatabaseInfo(databaseInfo);
        if (!error.isNull())
            LOG_ERROR("Error getting database info from database %s that we are trying to delete", m_identifier.loggingString().utf8().data());

        deletedVersion = databaseInfo.version();
        backingStore->deleteBackingStore();
    }

    didDeleteBackingStore(deletedVersion);
}

void UniqueIDBDatabase::didDeleteBackingStore(uint64_t deletedVersion)
{
    LOG(IndexedDB, "UniqueIDBDatabase::didDeleteBackingStore");

    ASSERT(m_inProgressTransactions.isEmpty());
    ASSERT(m_pendingTransactions.isEmpty());
    ASSERT(m_openDatabaseConnections.isEmpty());
    ASSERT(!m_backingStore);

    ASSERT(m_currentOpenDBRequest->isDeleteRequest());

    if (m_databaseInfo)
        m_mostRecentDeletedDatabaseInfo = WTFMove(m_databaseInfo);

    // If this UniqueIDBDatabase was brought into existence for the purpose of deleting the file on disk,
    // we won't have a m_mostRecentDeletedDatabaseInfo. In that case, we'll manufacture one using the
    // passed in deletedVersion argument.
    if (!m_mostRecentDeletedDatabaseInfo)
        m_mostRecentDeletedDatabaseInfo = makeUnique<IDBDatabaseInfo>(m_identifier.databaseName(), deletedVersion, 0);

    if (m_currentOpenDBRequest) {
        m_currentOpenDBRequest->notifyDidDeleteDatabase(*m_mostRecentDeletedDatabaseInfo);
        m_currentOpenDBRequest = nullptr;
    }
}

void UniqueIDBDatabase::clearStalePendingOpenDBRequests()
{
    while (!m_pendingOpenDBRequests.isEmpty() && m_pendingOpenDBRequests.first()->connection().isClosed())
        m_pendingOpenDBRequests.removeFirst();
}

void UniqueIDBDatabase::handleDatabaseOperations()
{
    ASSERT(!isMainThread());
    LOG(IndexedDB, "UniqueIDBDatabase::handleDatabaseOperations - There are %u pending", m_pendingOpenDBRequests.size());

    if (m_versionChangeDatabaseConnection || m_versionChangeTransaction) {
        // We can't start any new open-database operations right now, but we might be able to start handling a delete operation.
        if (!m_currentOpenDBRequest)
            m_currentOpenDBRequest = takeNextRunnableRequest(RequestType::Delete);
    } else if (!m_currentOpenDBRequest || m_currentOpenDBRequest->connection().isClosed())
        m_currentOpenDBRequest = takeNextRunnableRequest();

    while (m_currentOpenDBRequest) {
        handleCurrentOperation();
        if (!m_currentOpenDBRequest) {
            if (m_versionChangeTransaction)
                m_currentOpenDBRequest = takeNextRunnableRequest(RequestType::Delete);
            else
                m_currentOpenDBRequest = takeNextRunnableRequest();
        } else // Request need multiple attempts to handle.
            break;
    }
    LOG(IndexedDB, "UniqueIDBDatabase::handleDatabaseOperations - There are %u pending after this round of handling", m_pendingOpenDBRequests.size());
}

void UniqueIDBDatabase::handleCurrentOperation()
{
    LOG(IndexedDB, "UniqueIDBDatabase::handleCurrentOperation");
    ASSERT(m_currentOpenDBRequest);

    if (m_currentOpenDBRequest->isOpenRequest())
        performCurrentOpenOperation();
    else if (m_currentOpenDBRequest->isDeleteRequest())
        performCurrentDeleteOperation();
    else
        ASSERT_NOT_REACHED();
}

bool UniqueIDBDatabase::hasAnyOpenConnections() const
{
    return !m_openDatabaseConnections.isEmpty();
}

bool UniqueIDBDatabase::allConnectionsAreClosedOrClosing() const
{
    for (auto& connection : m_openDatabaseConnections) {
        if (!connection->connectionIsClosing())
            return false;
    }

    return true;
}

void UniqueIDBDatabase::handleDelete(IDBConnectionToClient& connection, const IDBRequestData& requestData)
{
    LOG(IndexedDB, "UniqueIDBDatabase::handleDelete");

    m_pendingOpenDBRequests.add(ServerOpenDBRequest::create(connection, requestData));
    handleDatabaseOperations();
}

void UniqueIDBDatabase::startVersionChangeTransaction()
{
    LOG(IndexedDB, "UniqueIDBDatabase::startVersionChangeTransaction");

    ASSERT(!m_versionChangeTransaction);
    ASSERT(m_currentOpenDBRequest);
    ASSERT(m_currentOpenDBRequest->isOpenRequest());
    ASSERT(m_versionChangeDatabaseConnection);

    uint64_t requestedVersion = m_currentOpenDBRequest->requestData().requestedVersion();
    if (!requestedVersion)
        requestedVersion = m_databaseInfo->version() ? m_databaseInfo->version() : 1;

    m_versionChangeTransaction = &m_versionChangeDatabaseConnection->createVersionChangeTransaction(requestedVersion);
    auto versionChangeTransactionInfo = m_versionChangeTransaction->info();
    m_inProgressTransactions.set(versionChangeTransactionInfo.identifier(), m_versionChangeTransaction);
    
    auto error = m_backingStore->beginTransaction(versionChangeTransactionInfo);
    auto operation = WTFMove(m_currentOpenDBRequest);
    IDBResultData result;
    if (error.isNull()) {
        addOpenDatabaseConnection(*m_versionChangeDatabaseConnection);
        m_databaseInfo->setVersion(versionChangeTransactionInfo.newVersion());
        result = IDBResultData::openDatabaseUpgradeNeeded(operation->requestData().requestIdentifier(), *m_versionChangeTransaction);
        operation->connection().didOpenDatabase(result);
    } else {
        m_versionChangeDatabaseConnection->abortTransactionWithoutCallback(*m_versionChangeTransaction);
        m_versionChangeDatabaseConnection = nullptr;
        result = IDBResultData::error(operation->requestData().requestIdentifier(), error);
        operation->connection().didOpenDatabase(result);
    }
}

void UniqueIDBDatabase::maybeNotifyConnectionsOfVersionChange()
{
    ASSERT(m_currentOpenDBRequest);

    if (m_currentOpenDBRequest->hasNotifiedConnectionsOfVersionChange())
        return;

    uint64_t newVersion = m_currentOpenDBRequest->isOpenRequest() ? m_currentOpenDBRequest->requestData().requestedVersion() : 0;
    auto requestIdentifier = m_currentOpenDBRequest->requestData().requestIdentifier();

    LOG(IndexedDB, "UniqueIDBDatabase::notifyConnectionsOfVersionChange - %" PRIu64, newVersion);

    // 3.3.7 "versionchange" transaction steps
    // Fire a versionchange event at each connection in m_openDatabaseConnections that is open.
    // The event must not be fired on connections which has the closePending flag set.
    HashSet<uint64_t> connectionIdentifiers;
    for (const auto& connection : m_openDatabaseConnections) {
        if (connection->closePending())
            continue;

        connection->fireVersionChangeEvent(requestIdentifier, newVersion);
        connectionIdentifiers.add(connection->identifier());
    }

    if (!connectionIdentifiers.isEmpty())
        m_currentOpenDBRequest->notifiedConnectionsOfVersionChange(WTFMove(connectionIdentifiers));
    else
        m_currentOpenDBRequest->maybeNotifyRequestBlocked(m_databaseInfo->version());
}

void UniqueIDBDatabase::notifyCurrentRequestConnectionClosedOrFiredVersionChangeEvent(uint64_t connectionIdentifier)
{
    LOG(IndexedDB, "UniqueIDBDatabase::notifyCurrentRequestConnectionClosedOrFiredVersionChangeEvent - %" PRIu64, connectionIdentifier);

    ASSERT(m_currentOpenDBRequest);

    m_currentOpenDBRequest->connectionClosedOrFiredVersionChangeEvent(connectionIdentifier);

    if (m_currentOpenDBRequest->hasConnectionsPendingVersionChangeEvent())
        return;

    if (!hasAnyOpenConnections() || allConnectionsAreClosedOrClosing()) {
        handleDatabaseOperations();
        return;
    }

    // Since all open connections have fired their version change events but not all of them have closed,
    // this request is officially blocked.
    m_currentOpenDBRequest->maybeNotifyRequestBlocked(m_databaseInfo->version());
}

void UniqueIDBDatabase::clearTransactionsOnConnection(UniqueIDBDatabaseConnection& connection)
{
    Deque<RefPtr<UniqueIDBDatabaseTransaction>> pendingTransactions;
    while (!m_pendingTransactions.isEmpty()) {
        auto transaction = m_pendingTransactions.takeFirst();
        if (&transaction->databaseConnection() != &connection)
            pendingTransactions.append(WTFMove(transaction));
        else
            connection.deleteTransaction(*transaction);
    }
    if (!pendingTransactions.isEmpty())
        m_pendingTransactions.swap(pendingTransactions);

    Deque<RefPtr<UniqueIDBDatabaseTransaction>> transactionsToAbort;
    for (auto& transaction : m_inProgressTransactions.values()) {
        if (&transaction->databaseConnection() == &connection)
            transactionsToAbort.append(transaction);
    }
    for (auto& transaction : transactionsToAbort)
        transaction->abortWithoutCallback();
}

void UniqueIDBDatabase::didFireVersionChangeEvent(UniqueIDBDatabaseConnection& connection, const IDBResourceIdentifier& requestIdentifier, IndexedDB::ConnectionClosedOnBehalfOfServer connectionClosedOnBehalfOfServer)
{
    LOG(IndexedDB, "UniqueIDBDatabase::didFireVersionChangeEvent");

    if (!m_currentOpenDBRequest)
        return;

    ASSERT_UNUSED(requestIdentifier, m_currentOpenDBRequest->requestData().requestIdentifier() == requestIdentifier);

    if (connectionClosedOnBehalfOfServer == IndexedDB::ConnectionClosedOnBehalfOfServer::Yes) {
        if (m_openDatabaseConnections.contains(&connection)) {
            clearTransactionsOnConnection(connection);
            m_openDatabaseConnections.remove(&connection);
        }
    }

    notifyCurrentRequestConnectionClosedOrFiredVersionChangeEvent(connection.identifier());
}

void UniqueIDBDatabase::openDBRequestCancelled(const IDBResourceIdentifier& requestIdentifier)
{
    LOG(IndexedDB, "UniqueIDBDatabase::openDBRequestCancelled - %s", requestIdentifier.loggingString().utf8().data());

    if (m_currentOpenDBRequest && m_currentOpenDBRequest->requestData().requestIdentifier() == requestIdentifier)
        m_currentOpenDBRequest = nullptr;

    if (m_versionChangeDatabaseConnection && m_versionChangeDatabaseConnection->openRequestIdentifier() == requestIdentifier) {
        ASSERT(!m_versionChangeTransaction || m_versionChangeTransaction->databaseConnection().openRequestIdentifier() == requestIdentifier);
        ASSERT(!m_versionChangeTransaction || &m_versionChangeTransaction->databaseConnection() == m_versionChangeDatabaseConnection);

        connectionClosedFromClient(*m_versionChangeDatabaseConnection);
    }

    for (auto& request : m_pendingOpenDBRequests) {
        if (request->requestData().requestIdentifier() == requestIdentifier) {
            m_pendingOpenDBRequests.remove(request);
            return;
        }
    }
}

void UniqueIDBDatabase::addOpenDatabaseConnection(Ref<UniqueIDBDatabaseConnection>&& connection)
{
    ASSERT(!m_openDatabaseConnections.contains(&connection.get()));
    m_openDatabaseConnections.add(adoptRef(connection.leakRef()));
}

void UniqueIDBDatabase::createObjectStore(UniqueIDBDatabaseTransaction& transaction, const IDBObjectStoreInfo& info, ErrorCallback callback)
{
    ASSERT(!isMainThread());
    LOG(IndexedDB, "UniqueIDBDatabase::createObjectStore");

    ASSERT(m_backingStore);

    // Quota check.
    auto taskSize = defaultWriteOperationCost + estimateSize(info);
    if (m_server.requestSpace(m_identifier.origin(), taskSize) == StorageQuotaManager::Decision::Deny) {
        callback(IDBError { QuotaExceededError, quotaErrorMessageName("CreateObjectStore") });
        return;
    }

    auto error = m_backingStore->createObjectStore(transaction.info().identifier(), info);
    if (error.isNull())
        m_databaseInfo->addExistingObjectStore(info);

    callback(error);
}

void UniqueIDBDatabase::deleteObjectStore(UniqueIDBDatabaseTransaction& transaction, const String& objectStoreName, ErrorCallback callback)
{
    ASSERT(!isMainThread());
    LOG(IndexedDB, "UniqueIDBDatabase::deleteObjectStore");

    auto* info = m_databaseInfo->infoForExistingObjectStore(objectStoreName);
    if (!info) {
        callback(IDBError { UnknownError, "Attempt to delete non-existant object store"_s });
        return;
    }

    ASSERT(m_backingStore);
    auto error = m_backingStore->deleteObjectStore(transaction.info().identifier(), info->identifier());
    if (error.isNull())
        m_databaseInfo->deleteObjectStore(info->identifier());

    callback(error);
}

void UniqueIDBDatabase::renameObjectStore(UniqueIDBDatabaseTransaction& transaction, uint64_t objectStoreIdentifier, const String& newName, ErrorCallback callback)
{
    ASSERT(!isMainThread());
    LOG(IndexedDB, "UniqueIDBDatabase::renameObjectStore");

    // Quota check.
    auto taskSize = defaultWriteOperationCost + newName.sizeInBytes();
    if (m_server.requestSpace(m_identifier.origin(), taskSize) == StorageQuotaManager::Decision::Deny) {
        callback(IDBError(QuotaExceededError, quotaErrorMessageName("RenameObjectStore")));
        return;
    }

    auto* info = m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
    if (!info) {
        callback(IDBError { UnknownError, "Attempt to rename non-existant object store"_s });
        return;
    }

    ASSERT(m_backingStore);
    auto error = m_backingStore->renameObjectStore(transaction.info().identifier(), objectStoreIdentifier, newName);
    if (error.isNull())
        m_databaseInfo->renameObjectStore(objectStoreIdentifier, newName);

    callback(error);
}

void UniqueIDBDatabase::clearObjectStore(UniqueIDBDatabaseTransaction& transaction, uint64_t objectStoreIdentifier, ErrorCallback callback)
{
    ASSERT(!isMainThread());
    LOG(IndexedDB, "UniqueIDBDatabase::clearObjectStore");

    ASSERT(m_backingStore);
    auto error = m_backingStore->clearObjectStore(transaction.info().identifier(), objectStoreIdentifier);

    callback(error);
}

void UniqueIDBDatabase::createIndex(UniqueIDBDatabaseTransaction& transaction, const IDBIndexInfo& info, ErrorCallback callback)
{
    ASSERT(!isMainThread());
    LOG(IndexedDB, "UniqueIDBDatabase::createIndex");

    // Quota check.
    auto taskSize = defaultWriteOperationCost + estimateSize(info);
    if (m_server.requestSpace(m_identifier.origin(), taskSize) == StorageQuotaManager::Decision::Deny) {
        callback(IDBError { QuotaExceededError, quotaErrorMessageName("CreateIndex") });
        return;
    }

    ASSERT(m_backingStore);
    auto error = m_backingStore->createIndex(transaction.info().identifier(), info);
    if (error.isNull()) {
        ASSERT(m_databaseInfo);
        auto* objectStoreInfo = m_databaseInfo->infoForExistingObjectStore(info.objectStoreIdentifier());
        ASSERT(objectStoreInfo);
        objectStoreInfo->addExistingIndex(info);
        m_databaseInfo->setMaxIndexID(info.identifier());
    }

    callback(error);
}

void UniqueIDBDatabase::deleteIndex(UniqueIDBDatabaseTransaction& transaction, uint64_t objectStoreIdentifier, const String& indexName, ErrorCallback callback)
{
    ASSERT(!isMainThread());
    LOG(IndexedDB, "UniqueIDBDatabase::deleteIndex");

    auto* objectStoreInfo = m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
    if (!objectStoreInfo) {
        callback(IDBError { UnknownError, "Attempt to delete index from non-existant object store"_s });
        return;
    }

    auto* indexInfo = objectStoreInfo->infoForExistingIndex(indexName);
    if (!indexInfo) {
        callback(IDBError { UnknownError, "Attempt to delete non-existant index"_s });
        return;
    }
    auto indexIdentifier = indexInfo->identifier();

    ASSERT(m_backingStore);
    auto error = m_backingStore->deleteIndex(transaction.info().identifier(), objectStoreIdentifier, indexIdentifier);
    if (error.isNull())
        objectStoreInfo->deleteIndex(indexIdentifier);

    callback(error);
}

void UniqueIDBDatabase::renameIndex(UniqueIDBDatabaseTransaction& transaction, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const String& newName, ErrorCallback callback)
{
    ASSERT(!isMainThread());
    LOG(IndexedDB, "UniqueIDBDatabase::renameIndex");

    // Quota check.
    auto taskSize = defaultWriteOperationCost + newName.sizeInBytes();
    if (m_server.requestSpace(m_identifier.origin(), taskSize) == StorageQuotaManager::Decision::Deny) {
        callback(IDBError { QuotaExceededError, quotaErrorMessageName("RenameIndex") });
        return;
    }

    auto* objectStoreInfo = m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
    if (!objectStoreInfo) {
        callback(IDBError { UnknownError, "Attempt to rename index in non-existant object store"_s });
        return;
    }

    auto* indexInfo = objectStoreInfo->infoForExistingIndex(indexIdentifier);
    if (!indexInfo) {
        callback(IDBError { UnknownError, "Attempt to rename non-existant index"_s });
        return;
    }

    ASSERT(m_backingStore);
    auto error = m_backingStore->renameIndex(transaction.info().identifier(), objectStoreIdentifier, indexIdentifier, newName);
    if (error.isNull())
        indexInfo->rename(newName);

    callback(error);
}

void UniqueIDBDatabase::putOrAdd(const IDBRequestData& requestData, const IDBKeyData& keyData, const IDBValue& value, IndexedDB::ObjectStoreOverwriteMode overwriteMode, KeyDataCallback callback)
{
    ASSERT(!isMainThread());
    LOG(IndexedDB, "UniqueIDBDatabase::putOrAdd");

    ASSERT(m_databaseInfo);

    IDBKeyData usedKey;
    IDBError error;

    ASSERT(m_backingStore);
    auto objectStoreIdentifier = requestData.objectStoreIdentifier();
    auto* objectStoreInfo = m_backingStore->infoForObjectStore(objectStoreIdentifier);
    if (!objectStoreInfo) {
        callback(IDBError { InvalidStateError, "Object store cannot be found in the backing store"_s }, usedKey);
        return;
    }

    // Quota check.
    auto taskSize = defaultWriteOperationCost + estimateSize(keyData) + estimateSize(value);
    auto* objectStore = m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
    if (objectStore)
        taskSize += objectStore->indexNames().size() * taskSize;
    if (m_server.requestSpace(m_identifier.origin(), taskSize) == StorageQuotaManager::Decision::Deny) {
        callback(IDBError { QuotaExceededError, quotaErrorMessageName("PutOrAdd") }, usedKey);
        return;
    }

    bool usedKeyIsGenerated = false;
    uint64_t keyNumber;
    auto transactionIdentifier = requestData.transactionIdentifier();
    auto generatedKeyResetter = WTF::makeScopeExit([this, transactionIdentifier, objectStoreIdentifier, &keyNumber, &usedKeyIsGenerated]() {
        if (usedKeyIsGenerated)
            m_backingStore->revertGeneratedKeyNumber(transactionIdentifier, objectStoreIdentifier, keyNumber);
    });

    if (objectStoreInfo->autoIncrement() && !keyData.isValid()) {
        error = m_backingStore->generateKeyNumber(transactionIdentifier, objectStoreIdentifier, keyNumber);
        if (!error.isNull()) {
            callback(error, usedKey);
            return;
        }
        usedKey.setNumberValue(keyNumber);
        usedKeyIsGenerated = true;
    } else
        usedKey = keyData;

    if (overwriteMode == IndexedDB::ObjectStoreOverwriteMode::NoOverwrite) {
        bool keyExists;
        error = m_backingStore->keyExistsInObjectStore(transactionIdentifier, objectStoreIdentifier, usedKey, keyExists);
        if (error.isNull() && keyExists)
            error = IDBError { ConstraintError, "Key already exists in the object store"_s };

        if (!error.isNull()) {
            callback(error, usedKey);
            return;
        }
    }
    // If a record already exists in store, then remove the record from store using the steps for deleting records from an object store.
    // This is important because formally deleting it from from the object store also removes it from the appropriate indexes.
    error = m_backingStore->deleteRange(transactionIdentifier, objectStoreIdentifier, usedKey);
    if (!error.isNull()) {
        callback(error, usedKey);
        return;
    }

    error = m_backingStore->addRecord(transactionIdentifier, *objectStoreInfo, usedKey, value);
    if (!error.isNull()) {
        callback(error, usedKey);
        return;
    }

    if (overwriteMode != IndexedDB::ObjectStoreOverwriteMode::OverwriteForCursor && objectStoreInfo->autoIncrement() && keyData.type() == IndexedDB::KeyType::Number)
        error = m_backingStore->maybeUpdateKeyGeneratorNumber(transactionIdentifier, objectStoreIdentifier, keyData.number());

    generatedKeyResetter.release();
    callback(error, usedKey);
}

void UniqueIDBDatabase::getRecord(const IDBRequestData& requestData, const IDBGetRecordData& getRecordData, GetResultCallback callback)
{
    ASSERT(!isMainThread());
    LOG(IndexedDB, "UniqueIDBDatabase::getRecord");

    IDBGetResult result;
    IDBError error;

    ASSERT(m_backingStore);
    if (uint64_t indexIdentifier = requestData.indexIdentifier())
        error = m_backingStore->getIndexRecord(requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), indexIdentifier, requestData.indexRecordType(), getRecordData.keyRangeData, result);
    else
        error = m_backingStore->getRecord(requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), getRecordData.keyRangeData, getRecordData.type, result);

    callback(error, result);
}

void UniqueIDBDatabase::getAllRecords(const IDBRequestData& requestData, const IDBGetAllRecordsData& getAllRecordsData, GetAllResultsCallback callback)
{
    ASSERT(!isMainThread());
    LOG(IndexedDB, "UniqueIDBDatabase::getAllRecords");

    ASSERT(m_backingStore);
    IDBGetAllResult result;
    auto error = m_backingStore->getAllRecords(requestData.transactionIdentifier(), getAllRecordsData, result);

    callback(error, result);
}

void UniqueIDBDatabase::getCount(const IDBRequestData& requestData, const IDBKeyRangeData& range, CountCallback callback)
{
    ASSERT(!isMainThread());
    LOG(IndexedDB, "UniqueIDBDatabase::getCount");

    ASSERT(m_backingStore);
    uint64_t count = 0;
    auto error = m_backingStore->getCount(requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), requestData.indexIdentifier(), range, count);

    callback(error, count);
}

void UniqueIDBDatabase::deleteRecord(const IDBRequestData& requestData, const IDBKeyRangeData& keyRangeData, ErrorCallback callback)
{
    ASSERT(!isMainThread());
    LOG(IndexedDB, "UniqueIDBDatabase::deleteRecord");

    ASSERT(m_backingStore);
    auto error = m_backingStore->deleteRange(requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), keyRangeData);

    callback(error);
}

void UniqueIDBDatabase::openCursor(const IDBRequestData& requestData, const IDBCursorInfo& info, GetResultCallback callback)
{
    ASSERT(!isMainThread());
    LOG(IndexedDB, "UniqueIDBDatabase::openCursor");

    ASSERT(m_backingStore);

    IDBGetResult result;
    auto error = m_backingStore->openCursor(requestData.transactionIdentifier(), info, result);

    callback(error, result);
}

void UniqueIDBDatabase::iterateCursor(const IDBRequestData& requestData, const IDBIterateCursorData& data, GetResultCallback callback)
{
    ASSERT(!isMainThread());
    LOG(IndexedDB, "UniqueIDBDatabase::iterateCursor");

    ASSERT(m_backingStore);

    IDBGetResult result;
    auto transactionIdentifier = requestData.transactionIdentifier();
    auto cursorIdentifier = requestData.cursorIdentifier();
    auto error = m_backingStore->iterateCursor(transactionIdentifier, cursorIdentifier, data, result);

    callback(error, result);
}

void UniqueIDBDatabase::commitTransaction(UniqueIDBDatabaseTransaction& transaction, ErrorCallback callback)
{
    ASSERT(!isMainThread());
    LOG(IndexedDB, "UniqueIDBDatabase::commitTransaction - %s", transaction.info().identifier().loggingString().utf8().data());

    ASSERT(transaction.databaseConnection().database() == this);
    ASSERT(m_backingStore);
    auto takenTransaction = m_inProgressTransactions.take(transaction.info().identifier());
    if (!takenTransaction) {
        if (!m_openDatabaseConnections.contains(&transaction.databaseConnection()))
            return;

        callback(IDBError { UnknownError, "Attempt to commit transaction that is not running"_s });
        return;
    }

    auto error = m_backingStore->commitTransaction(transaction.info().identifier());

    callback(error);
    transactionCompleted(WTFMove(takenTransaction));
}

void UniqueIDBDatabase::abortTransaction(UniqueIDBDatabaseTransaction& transaction, ErrorCallback callback)
{
    ASSERT(!isMainThread());
    LOG(IndexedDB, "UniqueIDBDatabase::abortTransaction - %s", transaction.info().identifier().loggingString().utf8().data());

    ASSERT(transaction.databaseConnection().database() == this);

    auto takenTransaction = m_inProgressTransactions.take(transaction.info().identifier());
    if (!takenTransaction) {
        if (!m_openDatabaseConnections.contains(&transaction.databaseConnection()))
            return;

        callback(IDBError { UnknownError, "Attempt to abort transaction that is not running"_s });
        return;
    }

    // If transaction is already aborted on the main thread for suspension,
    // return the result of that abort.
    if (auto existingAbortResult = takenTransaction->mainThreadAbortResult()) {
        callback(*existingAbortResult);
        transactionCompleted(WTFMove(takenTransaction));
        return;
    }

    auto transactionIdentifier = transaction.info().identifier();
    if (m_versionChangeTransaction && m_versionChangeTransaction->info().identifier() == transactionIdentifier) {
        ASSERT(m_versionChangeTransaction == &transaction);
        ASSERT(!m_versionChangeDatabaseConnection || &m_versionChangeTransaction->databaseConnection() == m_versionChangeDatabaseConnection);
        ASSERT(m_versionChangeTransaction->originalDatabaseInfo());
        m_databaseInfo = makeUnique<IDBDatabaseInfo>(*m_versionChangeTransaction->originalDatabaseInfo());
    }

    auto error = m_backingStore->abortTransaction(transactionIdentifier);

    callback(error);
    transactionCompleted(WTFMove(takenTransaction));
}

void UniqueIDBDatabase::didFinishHandlingVersionChange(UniqueIDBDatabaseConnection& connection, const IDBResourceIdentifier& transactionIdentifier)
{
    ASSERT(!isMainThread());
    LOG(IndexedDB, "UniqueIDBDatabase::didFinishHandlingVersionChange");

    ASSERT_UNUSED(transactionIdentifier, !m_versionChangeTransaction || m_versionChangeTransaction->info().identifier() == transactionIdentifier);
    ASSERT_UNUSED(connection, !m_versionChangeDatabaseConnection || m_versionChangeDatabaseConnection.get() == &connection);

    m_versionChangeTransaction = nullptr;
    m_versionChangeDatabaseConnection = nullptr;

    handleDatabaseOperations();
    handleTransactions();
}

void UniqueIDBDatabase::connectionClosedFromClient(UniqueIDBDatabaseConnection& connection)
{
    ASSERT(!isMainThread());
    LOG(IndexedDB, "UniqueIDBDatabase::connectionClosedFromClient - %s (%" PRIu64 ")", connection.openRequestIdentifier().loggingString().utf8().data(), connection.identifier());

    Ref<UniqueIDBDatabaseConnection> protectedConnection(connection);
    m_openDatabaseConnections.remove(&connection);

    if (m_versionChangeDatabaseConnection == &connection) {
        m_versionChangeDatabaseConnection = nullptr;
        if (m_versionChangeTransaction) {
            connection.abortTransactionWithoutCallback(*m_versionChangeTransaction);
            ASSERT(!connection.hasNonFinishedTransactions());

            // Previous blocked operations or transactions may be runnable.
            handleDatabaseOperations();
            handleTransactions();

            return;
        }
    }

    // Remove all pending transactions on the connection.
    clearTransactionsOnConnection(connection);

    if (m_currentOpenDBRequest)
        notifyCurrentRequestConnectionClosedOrFiredVersionChangeEvent(connection.identifier());

    ASSERT(!connection.hasNonFinishedTransactions());

    // Now that a database connection has closed, previously blocked operations might be runnable.
    handleDatabaseOperations();
    handleTransactions();
}

void UniqueIDBDatabase::connectionClosedFromServer(UniqueIDBDatabaseConnection& connection)
{
    ASSERT(!isMainThread());
    LOG(IndexedDB, "UniqueIDBDatabase::connectionClosedFromServer - %s (%" PRIu64 ")", connection.openRequestIdentifier().loggingString().utf8().data(), connection.identifier());

    connection.connectionToClient().didCloseFromServer(connection, IDBError::userDeleteError());

    m_openDatabaseConnections.remove(&connection);
}

void UniqueIDBDatabase::enqueueTransaction(Ref<UniqueIDBDatabaseTransaction>&& transaction)
{
    LOG(IndexedDB, "UniqueIDBDatabase::enqueueTransaction - %s", transaction->info().loggingString().utf8().data());

    ASSERT(transaction->info().mode() != IDBTransactionMode::Versionchange);

    m_pendingTransactions.append(WTFMove(transaction));

    handleTransactions();
}

void UniqueIDBDatabase::handleTransactions()
{
    LOG(IndexedDB, "UniqueIDBDatabase::handleTransactions - There are %zu pending", m_pendingTransactions.size());

    bool hadDeferredTransactions = false;
    auto transaction = takeNextRunnableTransaction(hadDeferredTransactions);

    while (transaction) {
        m_inProgressTransactions.set(transaction->info().identifier(), transaction);
        for (auto objectStore : transaction->objectStoreIdentifiers()) {
            m_objectStoreTransactionCounts.add(objectStore);
            if (!transaction->isReadOnly()) {
                m_objectStoreWriteTransactions.add(objectStore);
                ASSERT(m_objectStoreTransactionCounts.count(objectStore) == 1);
            }
        }

        activateTransactionInBackingStore(*transaction);
        if (hadDeferredTransactions)
            break;
        transaction = takeNextRunnableTransaction(hadDeferredTransactions);
    }
    LOG(IndexedDB, "UniqueIDBDatabase::handleTransactions - There are %zu pending after this round of handling", m_pendingTransactions.size());
}

void UniqueIDBDatabase::activateTransactionInBackingStore(UniqueIDBDatabaseTransaction& transaction)
{
    LOG(IndexedDB, "UniqueIDBDatabase::activateTransactionInBackingStore");

    ASSERT(m_backingStore);

    auto error = m_backingStore->beginTransaction(transaction.info());

    transaction.didActivateInBackingStore(error);
}

template<typename T> bool scopesOverlap(const T& aScopes, const Vector<uint64_t>& bScopes)
{
    for (auto scope : bScopes) {
        if (aScopes.contains(scope))
            return true;
    }

    return false;
}

RefPtr<UniqueIDBDatabaseTransaction> UniqueIDBDatabase::takeNextRunnableTransaction(bool& hadDeferredTransactions)
{
    hadDeferredTransactions = false;

    if (m_pendingTransactions.isEmpty())
        return nullptr;

    if (!m_backingStore->supportsSimultaneousTransactions() && !m_inProgressTransactions.isEmpty()) {
        LOG(IndexedDB, "UniqueIDBDatabase::takeNextRunnableTransaction - Backing store only supports 1 transaction, and we already have 1");
        return nullptr;
    }

    Deque<RefPtr<UniqueIDBDatabaseTransaction>> deferredTransactions;
    RefPtr<UniqueIDBDatabaseTransaction> currentTransaction;

    HashSet<uint64_t> deferredReadWriteScopes;

    while (!m_pendingTransactions.isEmpty()) {
        currentTransaction = m_pendingTransactions.takeFirst();

        switch (currentTransaction->info().mode()) {
        case IDBTransactionMode::Readonly: {
            bool hasOverlappingScopes = scopesOverlap(deferredReadWriteScopes, currentTransaction->objectStoreIdentifiers());
            hasOverlappingScopes |= scopesOverlap(m_objectStoreWriteTransactions, currentTransaction->objectStoreIdentifiers());

            if (hasOverlappingScopes)
                deferredTransactions.append(WTFMove(currentTransaction));

            break;
        }
        case IDBTransactionMode::Readwrite: {
            bool hasOverlappingScopes = scopesOverlap(m_objectStoreTransactionCounts, currentTransaction->objectStoreIdentifiers());
            hasOverlappingScopes |= scopesOverlap(deferredReadWriteScopes, currentTransaction->objectStoreIdentifiers());

            if (hasOverlappingScopes) {
                for (auto objectStore : currentTransaction->objectStoreIdentifiers())
                    deferredReadWriteScopes.add(objectStore);
                deferredTransactions.append(WTFMove(currentTransaction));
            }

            break;
        }
        case IDBTransactionMode::Versionchange:
            // Version change transactions should never be scheduled in the traditional manner.
            RELEASE_ASSERT_NOT_REACHED();
        }

        // If we didn't defer the currentTransaction above, it can be run now.
        if (currentTransaction)
            break;
    }

    hadDeferredTransactions = !deferredTransactions.isEmpty();
    if (!hadDeferredTransactions)
        return currentTransaction;

    // Prepend the deferred transactions back on the beginning of the deque for future scheduling passes.
    while (!deferredTransactions.isEmpty())
        m_pendingTransactions.prepend(deferredTransactions.takeLast());

    return currentTransaction;
}

void UniqueIDBDatabase::transactionCompleted(RefPtr<UniqueIDBDatabaseTransaction>&& transaction)
{
    ASSERT(transaction);
    ASSERT(!m_inProgressTransactions.contains(transaction->info().identifier()));
    ASSERT(!isMainThread());

    for (auto objectStore : transaction->objectStoreIdentifiers()) {
        if (!transaction->isReadOnly()) {
            m_objectStoreWriteTransactions.remove(objectStore);
            ASSERT(m_objectStoreTransactionCounts.count(objectStore) == 1);
        }
        m_objectStoreTransactionCounts.remove(objectStore);
    }

    if (m_versionChangeTransaction == transaction)
        m_versionChangeTransaction = nullptr;

    // Previously blocked operations might be runnable.
    handleDatabaseOperations();
    handleTransactions();
}

static void errorOpenDBRequestForUserDelete(ServerOpenDBRequest& request)
{
    auto result = IDBResultData::error(request.requestData().requestIdentifier(), IDBError::userDeleteError());
    if (request.isOpenRequest())
        request.connection().didOpenDatabase(result);
    else
        request.connection().didDeleteDatabase(result);
}

void UniqueIDBDatabase::immediateClose()
{
    LOG(IndexedDB, "UniqueIDBDatabase::immediateClose");

    // Error out all transactions.
    // Pending transactions must be cleared before in-progress transactions,
    // or they may get started right away after aborting in-progress transactions.
    for (auto& transaction : m_pendingTransactions)
        transaction->databaseConnection().deleteTransaction(*transaction);
    m_pendingTransactions.clear();

    for (auto& identifier : copyToVector(m_inProgressTransactions.keys()))
        m_inProgressTransactions.get(identifier)->abortWithoutCallback();

    ASSERT(m_inProgressTransactions.isEmpty());

    m_objectStoreTransactionCounts.clear();
    m_objectStoreWriteTransactions.clear();

    // Error out all IDBOpenDBRequests
    if (m_currentOpenDBRequest) {
        errorOpenDBRequestForUserDelete(*m_currentOpenDBRequest);
        m_currentOpenDBRequest = nullptr;
    }

    for (auto& request : m_pendingOpenDBRequests)
        errorOpenDBRequestForUserDelete(*request);

    m_pendingOpenDBRequests.clear();

    // Close all open connections
    auto openDatabaseConnections = m_openDatabaseConnections;
    for (auto& connection : openDatabaseConnections)
        connectionClosedFromServer(*connection);

    if (m_versionChangeDatabaseConnection) {
        connectionClosedFromServer(*m_versionChangeDatabaseConnection);
        m_versionChangeDatabaseConnection = nullptr;
    }

    ASSERT(!hasAnyOpenConnections());

    close();
}

void UniqueIDBDatabase::abortActiveTransactions()
{
    ASSERT(isMainThread());
    ASSERT(m_server.lock().isHeld());

    for (auto& identifier : copyToVector(m_inProgressTransactions.keys())) {
        auto transaction = m_inProgressTransactions.get(identifier);
        transaction->setMainThreadAbortResult(m_backingStore->abortTransaction(transaction->info().identifier()));
    }
}

void UniqueIDBDatabase::close()
{
    LOG(IndexedDB, "UniqueIDBDatabase::close");

    if (m_backingStore) {
        m_backingStore->close();
        m_backingStore = nullptr;
    }
}

bool UniqueIDBDatabase::tryClose()
{
    if (m_backingStore && m_backingStore->isEphemeral())
        return false;

    if (hasAnyOpenConnections() || m_versionChangeDatabaseConnection)
        return false;

    close();
    return true;
}

RefPtr<ServerOpenDBRequest> UniqueIDBDatabase::takeNextRunnableRequest(RequestType requestType)
{
    // Connection of request may be closed or lost.
    clearStalePendingOpenDBRequests();

    if (!m_pendingOpenDBRequests.isEmpty()) {
        if (requestType == RequestType::Delete && !m_pendingOpenDBRequests.first()->isDeleteRequest())
            return nullptr;
        return m_pendingOpenDBRequests.takeFirst();
    }

    return nullptr;
}

} // namespace IDBServer
} // namespace WebCore

#endif // ENABLE(INDEXED_DATABASE)
