blob: 5e71449784a0da0767789a8dedc522689f4d8dcc [file] [log] [blame]
/*
* Copyright (C) 2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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
* 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 "MemoryBackingStoreTransaction.h"
#if ENABLE(INDEXED_DATABASE)
#include "IDBKeyRangeData.h"
#include "IDBValue.h"
#include "IndexedDB.h"
#include "Logging.h"
#include "MemoryIDBBackingStore.h"
#include "MemoryObjectStore.h"
#include <wtf/SetForScope.h>
namespace WebCore {
namespace IDBServer {
std::unique_ptr<MemoryBackingStoreTransaction> MemoryBackingStoreTransaction::create(MemoryIDBBackingStore& backingStore, const IDBTransactionInfo& info)
{
return makeUnique<MemoryBackingStoreTransaction>(backingStore, info);
}
MemoryBackingStoreTransaction::MemoryBackingStoreTransaction(MemoryIDBBackingStore& backingStore, const IDBTransactionInfo& info)
: m_backingStore(backingStore)
, m_info(info)
{
if (m_info.mode() == IDBTransactionMode::Versionchange) {
IDBDatabaseInfo info;
auto error = m_backingStore.getOrEstablishDatabaseInfo(info);
if (error.isNull())
m_originalDatabaseInfo = makeUnique<IDBDatabaseInfo>(info);
}
}
MemoryBackingStoreTransaction::~MemoryBackingStoreTransaction()
{
ASSERT(!m_inProgress);
}
void MemoryBackingStoreTransaction::addNewObjectStore(MemoryObjectStore& objectStore)
{
LOG(IndexedDB, "MemoryBackingStoreTransaction::addNewObjectStore()");
ASSERT(isVersionChange());
m_versionChangeAddedObjectStores.add(&objectStore);
addExistingObjectStore(objectStore);
}
void MemoryBackingStoreTransaction::addNewIndex(MemoryIndex& index)
{
LOG(IndexedDB, "MemoryBackingStoreTransaction::addNewIndex()");
ASSERT(isVersionChange());
m_versionChangeAddedIndexes.add(&index);
addExistingIndex(index);
}
void MemoryBackingStoreTransaction::addExistingIndex(MemoryIndex& index)
{
LOG(IndexedDB, "MemoryBackingStoreTransaction::addExistingIndex");
ASSERT(isWriting());
ASSERT(!m_indexes.contains(&index));
m_indexes.add(&index);
}
void MemoryBackingStoreTransaction::indexDeleted(Ref<MemoryIndex>&& index)
{
m_indexes.remove(&index.get());
// If this MemoryIndex belongs to an object store that will not get restored if this transaction aborts,
// then we can forget about it altogether.
auto& objectStore = index->objectStore();
if (auto deletedObjectStore = m_deletedObjectStores.get(objectStore.info().name())) {
if (deletedObjectStore != &objectStore)
return;
}
auto addResult = m_deletedIndexes.add(index->info().name(), nullptr);
if (addResult.isNewEntry)
addResult.iterator->value = WTFMove(index);
}
void MemoryBackingStoreTransaction::addExistingObjectStore(MemoryObjectStore& objectStore)
{
LOG(IndexedDB, "MemoryBackingStoreTransaction::addExistingObjectStore");
ASSERT(isWriting());
ASSERT(!m_objectStores.contains(&objectStore));
m_objectStores.add(&objectStore);
objectStore.writeTransactionStarted(*this);
m_originalKeyGenerators.add(&objectStore, objectStore.currentKeyGeneratorValue());
}
void MemoryBackingStoreTransaction::objectStoreDeleted(Ref<MemoryObjectStore>&& objectStore)
{
ASSERT(m_objectStores.contains(&objectStore.get()));
m_objectStores.remove(&objectStore.get());
objectStore->deleteAllIndexes(*this);
auto addResult = m_deletedObjectStores.add(objectStore->info().name(), nullptr);
if (addResult.isNewEntry)
addResult.iterator->value = WTFMove(objectStore);
}
void MemoryBackingStoreTransaction::objectStoreCleared(MemoryObjectStore& objectStore, std::unique_ptr<KeyValueMap>&& keyValueMap, std::unique_ptr<IDBKeyDataSet>&& orderedKeys)
{
ASSERT(m_objectStores.contains(&objectStore));
auto addResult = m_clearedKeyValueMaps.add(&objectStore, nullptr);
// If this object store has already been cleared during this transaction, we shouldn't remember this clearing.
if (!addResult.isNewEntry)
return;
addResult.iterator->value = WTFMove(keyValueMap);
ASSERT(!m_clearedOrderedKeys.contains(&objectStore));
m_clearedOrderedKeys.add(&objectStore, WTFMove(orderedKeys));
}
void MemoryBackingStoreTransaction::objectStoreRenamed(MemoryObjectStore& objectStore, const String& oldName)
{
ASSERT(m_objectStores.contains(&objectStore));
ASSERT(m_info.mode() == IDBTransactionMode::Versionchange);
// We only care about the first rename in a given transaction, because if the transaction is aborted we want
// to go back to the first 'oldName'
m_originalObjectStoreNames.add(&objectStore, oldName);
}
void MemoryBackingStoreTransaction::indexRenamed(MemoryIndex& index, const String& oldName)
{
ASSERT(m_objectStores.contains(&index.objectStore()));
ASSERT(m_info.mode() == IDBTransactionMode::Versionchange);
// We only care about the first rename in a given transaction, because if the transaction is aborted we want
// to go back to the first 'oldName'
m_originalIndexNames.add(&index, oldName);
}
void MemoryBackingStoreTransaction::indexCleared(MemoryIndex& index, std::unique_ptr<IndexValueStore>&& valueStore)
{
auto addResult = m_clearedIndexValueStores.add(&index, nullptr);
// If this index has already been cleared during this transaction, we shouldn't remember this clearing.
if (!addResult.isNewEntry)
return;
addResult.iterator->value = WTFMove(valueStore);
}
void MemoryBackingStoreTransaction::recordValueChanged(MemoryObjectStore& objectStore, const IDBKeyData& key, ThreadSafeDataBuffer* value)
{
ASSERT(m_objectStores.contains(&objectStore));
if (m_isAborting)
return;
// If this object store had been cleared during the transaction, no point in recording this
// individual key/value change as its entire key/value map will be restored upon abort.
if (m_clearedKeyValueMaps.contains(&objectStore))
return;
auto originalAddResult = m_originalValues.add(&objectStore, nullptr);
if (originalAddResult.isNewEntry)
originalAddResult.iterator->value = makeUnique<KeyValueMap>();
auto* map = originalAddResult.iterator->value.get();
auto addResult = map->add(key, ThreadSafeDataBuffer());
if (!addResult.isNewEntry)
return;
if (value)
addResult.iterator->value = *value;
}
void MemoryBackingStoreTransaction::abort()
{
LOG(IndexedDB, "MemoryBackingStoreTransaction::abort()");
SetForScope<bool> change(m_isAborting, true);
for (const auto& iterator : m_originalIndexNames)
iterator.key->rename(iterator.value);
m_originalIndexNames.clear();
for (const auto& iterator : m_originalObjectStoreNames)
iterator.key->rename(iterator.value);
m_originalObjectStoreNames.clear();
for (const auto& objectStore : m_versionChangeAddedObjectStores)
m_backingStore.removeObjectStoreForVersionChangeAbort(*objectStore);
m_versionChangeAddedObjectStores.clear();
for (auto& objectStore : m_deletedObjectStores.values()) {
m_backingStore.restoreObjectStoreForVersionChangeAbort(*objectStore);
ASSERT(!m_objectStores.contains(objectStore.get()));
m_objectStores.add(objectStore);
}
m_deletedObjectStores.clear();
if (m_originalDatabaseInfo) {
ASSERT(m_info.mode() == IDBTransactionMode::Versionchange);
m_backingStore.setDatabaseInfo(*m_originalDatabaseInfo);
}
// Restore cleared index value stores before we re-insert values into object stores
// because inserting those values will regenerate the appropriate index values.
for (auto& iterator : m_clearedIndexValueStores)
iterator.key->replaceIndexValueStore(WTFMove(iterator.value));
m_clearedIndexValueStores.clear();
for (auto& objectStore : m_objectStores) {
ASSERT(m_originalKeyGenerators.contains(objectStore.get()));
objectStore->setKeyGeneratorValue(m_originalKeyGenerators.get(objectStore.get()));
auto clearedKeyValueMap = m_clearedKeyValueMaps.take(objectStore.get());
if (clearedKeyValueMap) {
ASSERT(m_clearedOrderedKeys.contains(objectStore.get()));
objectStore->replaceKeyValueStore(WTFMove(clearedKeyValueMap), m_clearedOrderedKeys.take(objectStore.get()));
}
auto keyValueMap = m_originalValues.take(objectStore.get());
if (!keyValueMap)
continue;
for (const auto& entry : *keyValueMap) {
objectStore->deleteRecord(entry.key);
objectStore->addRecord(*this, entry.key, { entry.value });
}
}
for (auto& index : m_deletedIndexes.values())
index->objectStore().maybeRestoreDeletedIndex(*index);
m_deletedIndexes.clear();
finish();
}
void MemoryBackingStoreTransaction::commit()
{
LOG(IndexedDB, "MemoryBackingStoreTransaction::commit()");
finish();
}
void MemoryBackingStoreTransaction::finish()
{
m_inProgress = false;
if (!isWriting())
return;
for (auto& objectStore : m_objectStores)
objectStore->writeTransactionFinished(*this);
for (auto& objectStore : m_deletedObjectStores.values())
objectStore->writeTransactionFinished(*this);
}
} // namespace IDBServer
} // namespace WebCore
#endif // ENABLE(INDEXED_DATABASE)