Index: third_party/WebKit/Source/modules/indexeddb/IDBObjectStore.cpp |
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBObjectStore.cpp b/third_party/WebKit/Source/modules/indexeddb/IDBObjectStore.cpp |
index 7c80f4cc645bc75ffc457d6978f6289ef672e18f..01e6d6466b08741c7e1f3116fef21dfa84fd8186 100644 |
--- a/third_party/WebKit/Source/modules/indexeddb/IDBObjectStore.cpp |
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBObjectStore.cpp |
@@ -55,23 +55,28 @@ using blink::WebIDBCursor; |
using blink::WebIDBDatabase; |
using blink::WebVector; |
+ |
namespace blink { |
-IDBObjectStore::IDBObjectStore(const IDBObjectStoreMetadata& metadata, IDBTransaction* transaction) |
- : m_metadata(metadata) |
+namespace { |
+using IndexKeys = HeapVector<Member<IDBKey>>; |
+} |
+ |
+IDBObjectStore::IDBObjectStore(RefPtr<IDBObjectStoreMetadata> metadata, IDBTransaction* transaction) |
+ : m_metadata(std::move(metadata)) |
, m_transaction(transaction) |
{ |
- ASSERT(m_transaction); |
+ DCHECK(m_transaction); |
+ DCHECK(m_metadata.get()); |
} |
DEFINE_TRACE(IDBObjectStore) |
{ |
visitor->trace(m_transaction); |
visitor->trace(m_indexMap); |
- visitor->trace(m_createdIndexes); |
} |
-void IDBObjectStore::setName(const String& name, ExceptionState& exceptionState) |
+void IDBObjectStore::setName(const String& newName, ExceptionState& exceptionState) |
{ |
if (!RuntimeEnabledFeatures::indexedDBExperimentalEnabled()) |
return; |
@@ -94,9 +99,9 @@ void IDBObjectStore::setName(const String& name, ExceptionState& exceptionState) |
return; |
} |
- if (m_metadata.name == name) |
+ if (name() == newName) |
return; |
- if (m_transaction->db()->containsObjectStore(name)) { |
+ if (m_transaction->db()->containsObjectStore(newName)) { |
exceptionState.throwDOMException(ConstraintError, IDBDatabase::objectStoreNameTakenErrorMessage); |
return; |
} |
@@ -105,26 +110,20 @@ void IDBObjectStore::setName(const String& name, ExceptionState& exceptionState) |
return; |
} |
- backendDB()->renameObjectStore(m_transaction->id(), id(), name); |
- m_transaction->objectStoreRenamed(m_metadata.name, name); |
- m_metadata.name = name; |
- |
- // The name inside the database's version of the object store metadata is used by IDBDatabase.objectStoreNames(). |
- // If the transaction is aborted, this name will be reverted when the metadata is overwritten with the previousMetadata in IDBTransaction. |
- m_transaction->db()->objectStoreRenamed(id(), name); |
+ m_transaction->db()->renameObjectStore(id(), newName); |
} |
ScriptValue IDBObjectStore::keyPath(ScriptState* scriptState) const |
{ |
- return ScriptValue::from(scriptState, m_metadata.keyPath); |
+ return ScriptValue::from(scriptState, metadata().own.keyPath); |
} |
DOMStringList* IDBObjectStore::indexNames() const |
{ |
IDB_TRACE("IDBObjectStore::indexNames"); |
DOMStringList* indexNames = DOMStringList::create(DOMStringList::IndexedDB); |
- for (const auto& it : m_metadata.indexes) |
- indexNames->append(it.value.name); |
+ for (const auto& it : metadata().indexes) |
+ indexNames->append(it.value->name); |
indexNames->sort(); |
return indexNames; |
} |
@@ -265,7 +264,7 @@ IDBRequest* IDBObjectStore::getAllKeys(ScriptState* scriptState, const ScriptVal |
return request; |
} |
-static void generateIndexKeysForValue(v8::Isolate* isolate, const IDBIndexMetadata& indexMetadata, const ScriptValue& objectValue, IDBObjectStore::IndexKeys* indexKeys) |
+static void generateIndexKeysForValue(v8::Isolate* isolate, const IDBIndexMetadata& indexMetadata, const ScriptValue& objectValue, IndexKeys* indexKeys) |
{ |
ASSERT(indexKeys); |
NonThrowableExceptionState exceptionState; |
@@ -340,7 +339,7 @@ IDBRequest* IDBObjectStore::put(ScriptState* scriptState, WebIDBPutMode putMode, |
// clone lazily since the operation may be expensive. |
ScriptValue clone; |
- const IDBKeyPath& keyPath = m_metadata.keyPath; |
+ const IDBKeyPath& keyPath = metadata().own.keyPath; |
const bool usesInLineKeys = !keyPath.isNull(); |
const bool hasKeyGenerator = autoIncrement(); |
@@ -402,11 +401,11 @@ IDBRequest* IDBObjectStore::put(ScriptState* scriptState, WebIDBPutMode putMode, |
Vector<int64_t> indexIds; |
HeapVector<IndexKeys> indexKeys; |
- for (const auto& it : m_metadata.indexes) { |
+ for (const auto& it : metadata().indexes) { |
if (clone.isEmpty()) |
clone = deserializeScriptValue(scriptState, serializedValue.get(), &blobInfo); |
IndexKeys keys; |
- generateIndexKeysForValue(scriptState->isolate(), it.value, clone, &keys); |
+ generateIndexKeysForValue(scriptState->isolate(), *it.value, clone, &keys); |
indexIds.append(it.key); |
indexKeys.append(keys); |
} |
@@ -494,9 +493,9 @@ namespace { |
// cursor success handlers are kept alive. |
class IndexPopulator final : public EventListener { |
public: |
- static IndexPopulator* create(ScriptState* scriptState, IDBDatabase* database, int64_t transactionId, int64_t objectStoreId, const IDBIndexMetadata& indexMetadata) |
+ static IndexPopulator* create(ScriptState* scriptState, IDBDatabase* database, int64_t transactionId, int64_t objectStoreId, RefPtr<const IDBIndexMetadata> indexMetadata) |
{ |
- return new IndexPopulator(scriptState, database, transactionId, objectStoreId, indexMetadata); |
+ return new IndexPopulator(scriptState, database, transactionId, objectStoreId, std::move(indexMetadata)); |
} |
bool operator==(const EventListener& other) const override |
@@ -511,16 +510,19 @@ public: |
} |
private: |
- IndexPopulator(ScriptState* scriptState, IDBDatabase* database, int64_t transactionId, int64_t objectStoreId, const IDBIndexMetadata& indexMetadata) |
+ IndexPopulator(ScriptState* scriptState, IDBDatabase* database, int64_t transactionId, int64_t objectStoreId, RefPtr<const IDBIndexMetadata> indexMetadata) |
: EventListener(CPPEventListenerType) |
, m_scriptState(scriptState) |
, m_database(database) |
, m_transactionId(transactionId) |
, m_objectStoreId(objectStoreId) |
- , m_indexMetadata(indexMetadata) |
+ , m_indexMetadata(std::move(indexMetadata)) |
{ |
+ DCHECK(m_indexMetadata.get()); |
} |
+ const IDBIndexMetadata& indexMetadata() { return *m_indexMetadata; } |
+ |
void handleEvent(ExecutionContext* executionContext, Event* event) override |
{ |
ASSERT(m_scriptState->getExecutionContext() == executionContext); |
@@ -537,17 +539,17 @@ private: |
cursor = cursorAny->idbCursorWithValue(); |
Vector<int64_t> indexIds; |
- indexIds.append(m_indexMetadata.id); |
+ indexIds.append(indexMetadata().id); |
if (cursor && !cursor->isDeleted()) { |
cursor->continueFunction(nullptr, nullptr, ASSERT_NO_EXCEPTION); |
IDBKey* primaryKey = cursor->idbPrimaryKey(); |
ScriptValue value = cursor->value(m_scriptState.get()); |
- IDBObjectStore::IndexKeys indexKeys; |
- generateIndexKeysForValue(m_scriptState->isolate(), m_indexMetadata, value, &indexKeys); |
+ IndexKeys indexKeys; |
+ generateIndexKeysForValue(m_scriptState->isolate(), indexMetadata(), value, &indexKeys); |
- HeapVector<IDBObjectStore::IndexKeys> indexKeysList; |
+ HeapVector<IndexKeys> indexKeysList; |
indexKeysList.append(indexKeys); |
m_database->backend()->setIndexKeys(m_transactionId, m_objectStoreId, primaryKey, indexIds, indexKeysList); |
@@ -564,7 +566,7 @@ private: |
Member<IDBDatabase> m_database; |
const int64_t m_transactionId; |
const int64_t m_objectStoreId; |
- const IDBIndexMetadata m_indexMetadata; |
+ RefPtr<const IDBIndexMetadata> m_indexMetadata; |
}; |
} // namespace |
@@ -604,17 +606,17 @@ IDBIndex* IDBObjectStore::createIndex(ScriptState* scriptState, const String& na |
return nullptr; |
} |
- int64_t indexId = m_metadata.maxIndexId + 1; |
+ int64_t indexId = m_metadata->own.maxIndexId + 1; |
+ DCHECK(indexId != IDBIndexMetadata::InvalidId); |
backendDB()->createIndex(m_transaction->id(), id(), indexId, name, keyPath, options.unique(), options.multiEntry()); |
- ++m_metadata.maxIndexId; |
+ ++m_metadata->own.maxIndexId; |
- IDBIndexMetadata metadata(name, indexId, keyPath, options.unique(), options.multiEntry()); |
- IDBIndex* index = IDBIndex::create(metadata, this, m_transaction.get()); |
+ RefPtr<IDBIndexMetadata> indexMetadata = adoptRef(new IDBIndexMetadata( |
+ name, indexId, keyPath, options.unique(), options.multiEntry())); |
+ IDBIndex* index = IDBIndex::create(indexMetadata, this, m_transaction.get()); |
m_indexMap.set(name, index); |
- m_createdIndexes.add(index); |
- m_metadata.indexes.set(indexId, metadata); |
- m_transaction->db()->indexCreated(id(), metadata); |
+ m_metadata->indexes.set(indexId, indexMetadata); |
ASSERT(!exceptionState.hadException()); |
if (exceptionState.hadException()) |
@@ -624,7 +626,7 @@ IDBIndex* IDBObjectStore::createIndex(ScriptState* scriptState, const String& na |
indexRequest->preventPropagation(); |
// This is kept alive by being the success handler of the request, which is in turn kept alive by the owning transaction. |
- IndexPopulator* indexPopulator = IndexPopulator::create(scriptState, transaction()->db(), m_transaction->id(), id(), metadata); |
+ IndexPopulator* indexPopulator = IndexPopulator::create(scriptState, transaction()->db(), m_transaction->id(), id(), std::move(indexMetadata)); |
indexRequest->setOnsuccess(indexPopulator); |
return index; |
} |
@@ -641,7 +643,7 @@ IDBIndex* IDBObjectStore::index(const String& name, ExceptionState& exceptionSta |
return nullptr; |
} |
- IDBIndexMap::iterator it = m_indexMap.find(name); |
+ IndexMap::iterator it = m_indexMap.find(name); |
if (it != m_indexMap.end()) |
return it->value; |
@@ -651,17 +653,10 @@ IDBIndex* IDBObjectStore::index(const String& name, ExceptionState& exceptionSta |
return nullptr; |
} |
- const IDBIndexMetadata* indexMetadata(nullptr); |
- for (const auto& it : m_metadata.indexes) { |
- if (it.value.name == name) { |
- indexMetadata = &it.value; |
- break; |
- } |
- } |
- ASSERT(indexMetadata); |
- ASSERT(indexMetadata->id != IDBIndexMetadata::InvalidId); |
- |
- IDBIndex* index = IDBIndex::create(*indexMetadata, this, m_transaction.get()); |
+ DCHECK(metadata().indexes.contains(indexId)); |
+ RefPtr<IDBIndexMetadata> indexMetadata = metadata().indexes.get(indexId); |
+ DCHECK(indexMetadata.get()); |
+ IDBIndex* index = IDBIndex::create(std::move(indexMetadata), this, m_transaction.get()); |
m_indexMap.set(name, index); |
return index; |
} |
@@ -697,10 +692,10 @@ void IDBObjectStore::deleteIndex(const String& name, ExceptionState& exceptionSt |
backendDB()->deleteIndex(m_transaction->id(), id(), indexId); |
- m_metadata.indexes.remove(indexId); |
- m_transaction->db()->indexDeleted(id(), indexId); |
- IDBIndexMap::iterator it = m_indexMap.find(name); |
+ m_metadata->indexes.remove(indexId); |
+ IndexMap::iterator it = m_indexMap.find(name); |
if (it != m_indexMap.end()) { |
+ m_transaction->indexDeleted(it->value); |
it->value->markDeleted(); |
m_indexMap.remove(name); |
} |
@@ -807,44 +802,100 @@ IDBRequest* IDBObjectStore::count(ScriptState* scriptState, const ScriptValue& r |
return request; |
} |
-void IDBObjectStore::abort() |
+void IDBObjectStore::markDeleted() |
{ |
- for (auto& index : m_createdIndexes) |
+ m_deleted = true; |
+ m_metadata->indexes.clear(); |
+ |
+ for (auto& it : m_indexMap) { |
+ IDBIndex* index = it.value; |
index->markDeleted(); |
+ } |
} |
void IDBObjectStore::transactionFinished() |
{ |
- ASSERT(m_transaction->isFinished()); |
+ DCHECK(m_transaction->isFinished()); |
- // Break reference cycles. |
- // TODO(jsbell): This can be removed c/o Oilpan. |
+ // Remove our references to IDBIndex instances, so Oilpan can |
+ // garbage-collect the instances that are not referenced in JavaScript. |
m_indexMap.clear(); |
- m_createdIndexes.clear(); |
} |
-void IDBObjectStore::indexRenamed(int64_t indexId, const String& newName) |
+void IDBObjectStore::revertMetadata(RefPtr<IDBObjectStoreMetadata> oldMetadata) |
+{ |
+ DCHECK(m_transaction->isVersionChange()); |
+ DCHECK(!m_transaction->isActive()); |
+ DCHECK(oldMetadata.get()); |
+ DCHECK(id() == oldMetadata->own.id); |
+ |
+ // Index IDs are allocated sequentially, so we can tell if an index was |
+ // created in this transaction by comparing its ID with the object store's |
+ // maximum index ID at the time when the transaction was started. |
+ const int64_t oldMaxIndexId = oldMetadata->own.maxIndexId; |
+ for (auto& it : m_indexMap) { |
+ IDBIndex* index = it.value; |
+ const int64_t indexId = index->id(); |
+ |
+ if (indexId >= oldMaxIndexId) { |
+ // The index was created by this transaction. According to the spec, |
+ // its metadata will remain as-is. We just need to look up the |
+ // index's IDBIndex instance, and mark it as deleted. |
+ DCHECK(!oldMetadata->indexes.contains(indexId)); |
+ index->markDeleted(); |
+ continue; |
+ } |
+ |
+ // The index was created in a previous transaction. We need to revert |
+ // its metadata. The index might have been deleted, so we |
+ // unconditionally reset the deletion marker. We could find out if the |
+ // index was deleted by looking up the index ID in the store's metadata, |
+ // but that would be more work than the unconditional reset. |
+ DCHECK(oldMetadata->indexes.contains(indexId)); |
+ RefPtr<IDBIndexMetadata> oldIndexMetadata = oldMetadata->indexes.get(indexId); |
+ index->revertMetadata(std::move(oldIndexMetadata)); |
+ } |
+ m_metadata = std::move(oldMetadata); |
+ |
+ // An object store's metadata will only get reverted if the index was in the |
+ // database when the versionchange transaction started. |
+ m_deleted = false; |
+} |
+ |
+void IDBObjectStore::revertDeletedIndexMetadata(IDBIndex& deletedIndex) |
+{ |
+ DCHECK(m_transaction->isVersionChange()); |
+ DCHECK(!m_transaction->isActive()); |
+ DCHECK(deletedIndex.objectStore() == this); |
+ DCHECK(deletedIndex.isDeleted()); |
+ |
+ const int64_t indexId = deletedIndex.id(); |
+ DCHECK(m_metadata->indexes.contains(indexId)) << "The object store's metadata was not correctly reverted"; |
+ RefPtr<IDBIndexMetadata> oldIndexMetadata = m_metadata->indexes.get(indexId); |
+ deletedIndex.revertMetadata(std::move(oldIndexMetadata)); |
+} |
+ |
+void IDBObjectStore::renameIndex(int64_t indexId, const String& newName) |
{ |
DCHECK(m_transaction->isVersionChange()); |
DCHECK(m_transaction->isActive()); |
- IDBObjectStoreMetadata::IndexMap::iterator metadataIterator = m_metadata.indexes.find(indexId); |
- DCHECK(metadataIterator != m_metadata.indexes.end()) << "Invalid indexId"; |
- const String& oldName = metadataIterator->value.name; |
+ auto metadataIterator = m_metadata->indexes.find(indexId); |
+ DCHECK(metadataIterator != m_metadata->indexes.end()) << "Invalid indexId"; |
+ const String& oldName = metadataIterator->value->name; |
DCHECK(m_indexMap.contains(oldName)) << "The index had to be accessed in order to be renamed."; |
DCHECK(!m_indexMap.contains(newName)); |
- IDBIndexMap::iterator it = m_indexMap.find(oldName); |
- m_indexMap.set(newName, it->value); |
- m_indexMap.remove(oldName); |
+ IDBIndex* index = m_indexMap.take(oldName); |
+ m_indexMap.set(newName, index); |
- metadataIterator->value.name = newName; |
+ metadataIterator->value->name = newName; |
} |
int64_t IDBObjectStore::findIndexId(const String& name) const |
{ |
- for (const auto& it : m_metadata.indexes) { |
- if (it.value.name == name) { |
+ for (const auto& it : metadata().indexes) { |
+ if (it.value->name == name) { |
ASSERT(it.key != IDBIndexMetadata::InvalidId); |
return it.key; |
} |