Chromium Code Reviews| Index: third_party/WebKit/Source/modules/indexeddb/IDBTransaction.cpp |
| diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBTransaction.cpp b/third_party/WebKit/Source/modules/indexeddb/IDBTransaction.cpp |
| index 71ccf3d4f7fa6e7cf935eddf98135f78e28983c8..8c02b44c87fbf4d242d00558d3c52c54386d3d5a 100644 |
| --- a/third_party/WebKit/Source/modules/indexeddb/IDBTransaction.cpp |
| +++ b/third_party/WebKit/Source/modules/indexeddb/IDBTransaction.cpp |
| @@ -46,17 +46,19 @@ using blink::WebIDBDatabase; |
| namespace blink { |
| -IDBTransaction* IDBTransaction::create(ScriptState* scriptState, int64_t id, const HashSet<String>& objectStoreNames, WebIDBTransactionMode mode, IDBDatabase* db) |
| +IDBTransaction* IDBTransaction::createNonVersionChange(ScriptState* scriptState, int64_t id, const HashSet<String>& objectStoreNames, WebIDBTransactionMode mode, IDBDatabase* db) |
| { |
| + DCHECK_NE(mode, WebIDBTransactionModeVersionChange); |
| + DCHECK(!objectStoreNames.isEmpty()) << "Non-version transactions should operate on a well-defined set of stores"; |
|
cmumford
2016/09/19 23:26:48
Add a space before 'Non'
pwnall
2016/09/20 09:11:14
I apologize in advance for being clueless, but can
|
| IDBOpenDBRequest* openDBRequest = nullptr; |
| IDBTransaction* transaction = new IDBTransaction(scriptState, id, objectStoreNames, mode, db, openDBRequest, IDBDatabaseMetadata()); |
| transaction->suspendIfNeeded(); |
| return transaction; |
| } |
| -IDBTransaction* IDBTransaction::create(ScriptState* scriptState, int64_t id, IDBDatabase* db, IDBOpenDBRequest* openDBRequest, const IDBDatabaseMetadata& previousMetadata) |
| +IDBTransaction* IDBTransaction::createVersionChange(ScriptState* scriptState, int64_t id, IDBDatabase* db, IDBOpenDBRequest* openDBRequest, const IDBDatabaseMetadata& oldMetadata) |
| { |
| - IDBTransaction* transaction = new IDBTransaction(scriptState, id, HashSet<String>(), WebIDBTransactionModeVersionChange, db, openDBRequest, previousMetadata); |
| + IDBTransaction* transaction = new IDBTransaction(scriptState, id, HashSet<String>(), WebIDBTransactionModeVersionChange, db, openDBRequest, oldMetadata); |
| transaction->suspendIfNeeded(); |
| return transaction; |
| } |
| @@ -85,19 +87,23 @@ private: |
| } // namespace |
| -IDBTransaction::IDBTransaction(ScriptState* scriptState, int64_t id, const HashSet<String>& objectStoreNames, WebIDBTransactionMode mode, IDBDatabase* db, IDBOpenDBRequest* openDBRequest, const IDBDatabaseMetadata& previousMetadata) |
| +IDBTransaction::IDBTransaction(ScriptState* scriptState, int64_t id, const HashSet<String>& objectStoreNames, WebIDBTransactionMode mode, IDBDatabase* db, IDBOpenDBRequest* openDBRequest, const IDBDatabaseMetadata& oldMetadata) |
| : ActiveScriptWrappable(this) |
| , ActiveDOMObject(scriptState->getExecutionContext()) |
| , m_id(id) |
| , m_database(db) |
| - , m_objectStoreNames(objectStoreNames) |
| + , m_scope(objectStoreNames) |
|
cmumford
2016/09/19 23:26:48
Nit: It does seem a bit odd to have a public name
pwnall
2016/09/20 09:11:14
I agree that it does seem weird. Here is my ration
|
| , m_openDBRequest(openDBRequest) |
| , m_mode(mode) |
| - , m_previousMetadata(previousMetadata) |
| + , m_oldDatabaseMetadata(oldMetadata) |
| { |
| - if (mode == WebIDBTransactionModeVersionChange) { |
| + if (isVersionChange()) { |
|
cmumford
2016/09/19 23:26:48
Is there a need to DCHECK mode?
pwnall
2016/09/20 09:11:14
We got by without it, but it seems like a good ide
|
| + DCHECK(objectStoreNames.isEmpty()); |
| + |
| // Not active until the callback. |
| m_state = Inactive; |
| + } else { |
| + DCHECK(!objectStoreNames.isEmpty()) << "Non-versionchange transactions must operate on a well-defined set of stores"; |
|
cmumford
2016/09/19 23:26:48
Space before 'Non'
pwnall
2016/09/20 09:11:14
The same question as above applies. After I unders
|
| } |
| if (m_state == Active) |
| @@ -127,8 +133,8 @@ DEFINE_TRACE(IDBTransaction) |
| void IDBTransaction::setError(DOMException* error) |
| { |
| - ASSERT(m_state != Finished); |
| - ASSERT(error); |
| + DCHECK_NE(m_state, Finished); |
| + DCHECK(error); |
| // The first error to be set is the true cause of the |
| // transaction abort. |
| @@ -139,7 +145,7 @@ void IDBTransaction::setError(DOMException* error) |
| IDBObjectStore* IDBTransaction::objectStore(const String& name, ExceptionState& exceptionState) |
| { |
| - if (m_state == Finished) { |
| + if (isFinished()) { |
| exceptionState.throwDOMException(InvalidStateError, IDBDatabase::transactionFinishedErrorMessage); |
| return nullptr; |
| } |
| @@ -148,7 +154,7 @@ IDBObjectStore* IDBTransaction::objectStore(const String& name, ExceptionState& |
| if (it != m_objectStoreMap.end()) |
| return it->value; |
| - if (!isVersionChange() && !m_objectStoreNames.contains(name)) { |
| + if (!isVersionChange() && !m_scope.contains(name)) { |
| exceptionState.throwDOMException(NotFoundError, IDBDatabase::noSuchObjectStoreErrorMessage); |
| return nullptr; |
| } |
| @@ -160,9 +166,11 @@ IDBObjectStore* IDBTransaction::objectStore(const String& name, ExceptionState& |
| return nullptr; |
| } |
| - const IDBDatabaseMetadata& metadata = m_database->metadata(); |
| + DCHECK(m_database->metadata().objectStores.contains(objectStoreId)); |
| + const IDBObjectStoreMetadata& objectStoreMetadata = m_database->metadata().objectStores.get(objectStoreId); |
| - IDBObjectStore* objectStore = IDBObjectStore::create(metadata.objectStores.get(objectStoreId), this); |
| + IDBObjectStore* objectStore = IDBObjectStore::create(objectStoreMetadata, this); |
| + DCHECK(!m_objectStoreMap.contains(name)); |
| m_objectStoreMap.set(name, objectStore); |
| m_objectStoreCleanupMap.set(objectStore, objectStore->metadata()); |
| return objectStore; |
| @@ -170,8 +178,9 @@ IDBObjectStore* IDBTransaction::objectStore(const String& name, ExceptionState& |
| void IDBTransaction::objectStoreCreated(const String& name, IDBObjectStore* objectStore) |
| { |
| - ASSERT(m_state != Finished); |
| - ASSERT(isVersionChange()); |
| + DCHECK_NE(m_state, Finished) << "A finished transaction created an object store"; |
|
cmumford
2016/09/19 23:26:48
spaces before these (and all) strings, so:
DCHE
pwnall
2016/09/20 09:11:14
The same question as above applies. After I unders
|
| + DCHECK_EQ(m_mode, WebIDBTransactionModeVersionChange) << "A non-versionchange transaction created an object store"; |
| + DCHECK(!m_objectStoreMap.contains(name)) << "An object store was created with the name of an existing store"; |
| m_objectStoreMap.set(name, objectStore); |
| m_objectStoreCleanupMap.set(objectStore, objectStore->metadata()); |
| m_createdObjectStores.add(objectStore); |
| @@ -179,8 +188,8 @@ void IDBTransaction::objectStoreCreated(const String& name, IDBObjectStore* obje |
| void IDBTransaction::objectStoreDeleted(const String& name) |
| { |
| - ASSERT(m_state != Finished); |
| - ASSERT(isVersionChange()); |
| + DCHECK_NE(m_state, Finished) << "A finished transaction deleted an object store"; |
| + DCHECK_EQ(m_mode, WebIDBTransactionModeVersionChange) << "A non-versionchange transaction deleted an object store"; |
| IDBObjectStoreMap::iterator it = m_objectStoreMap.find(name); |
| if (it != m_objectStoreMap.end()) { |
| IDBObjectStore* objectStore = it->value; |
| @@ -193,15 +202,13 @@ void IDBTransaction::objectStoreDeleted(const String& name) |
| void IDBTransaction::objectStoreRenamed(const String& oldName, const String& newName) |
| { |
| - DCHECK(m_state != Finished); |
| - DCHECK(isVersionChange()); |
| + DCHECK_NE(m_state, Finished) << "A finished transaction renamed an object store"; |
| + DCHECK_EQ(m_mode, WebIDBTransactionModeVersionChange) << "A non-versionchange transaction renamed an object store"; |
| DCHECK(!m_objectStoreMap.contains(newName)); |
| DCHECK(m_objectStoreMap.contains(oldName)) << "The object store had to be accessed in order to be renamed."; |
| - |
| - IDBObjectStoreMap::iterator it = m_objectStoreMap.find(oldName); |
| - m_objectStoreMap.set(newName, it->value); |
| - m_objectStoreMap.remove(oldName); |
| + IDBObjectStore* objectStore = m_objectStoreMap.take(oldName); |
| + m_objectStoreMap.set(newName, objectStore); |
| } |
| void IDBTransaction::setActive(bool active) |
| @@ -228,14 +235,8 @@ void IDBTransaction::abort(ExceptionState& exceptionState) |
| if (m_contextStopped) |
| return; |
| - for (IDBRequest* request : m_requestList) |
| - request->abort(); |
| - m_requestList.clear(); |
| - |
| - for (IDBObjectStore* store : m_createdObjectStores) { |
| - store->abort(); |
| - store->markDeleted(); |
| - } |
| + abortOutstandingRequests(); |
| + revertDatabaseMetadata(); |
| if (backendDB()) |
| backendDB()->abort(m_id); |
| @@ -259,62 +260,44 @@ void IDBTransaction::onAbort(DOMException* error) |
| { |
| IDB_TRACE("IDBTransaction::onAbort"); |
| if (m_contextStopped) { |
| - m_database->transactionFinished(this); |
| + finish(); |
| return; |
| } |
| ASSERT(m_state != Finished); |
| if (m_state != Finishing) { |
| // Abort was not triggered by front-end. |
| - ASSERT(error); |
| + DCHECK(error); |
| setError(error); |
| - // Outstanding requests must be aborted. |
| - for (IDBRequest* request : m_requestList) |
| - request->abort(); |
| - m_requestList.clear(); |
| - |
| - // Newly created stores must be marked as deleted. |
| - for (IDBObjectStore* store : m_createdObjectStores) |
| - store->markDeleted(); |
| - |
| - // Used stores may need to mark indexes as deleted. |
| - for (auto& it : m_objectStoreCleanupMap) |
| - it.key->abort(); |
| + abortOutstandingRequests(); |
| + revertDatabaseMetadata(); |
| m_state = Finishing; |
| } |
| - if (isVersionChange()) { |
| - for (auto& it : m_objectStoreCleanupMap) |
| - it.key->setMetadata(it.value); |
| - m_database->setMetadata(m_previousMetadata); |
| + if (isVersionChange()) |
| m_database->close(); |
| - } |
| - m_objectStoreCleanupMap.clear(); |
| // Enqueue events before notifying database, as database may close which enqueues more events and order matters. |
| enqueueEvent(Event::createBubble(EventTypeNames::abort)); |
| - |
| - m_database->transactionFinished(this); |
| + finish(); |
| } |
| void IDBTransaction::onComplete() |
| { |
| IDB_TRACE("IDBTransaction::onComplete"); |
| if (m_contextStopped) { |
| - m_database->transactionFinished(this); |
| + finish(); |
| return; |
| } |
| ASSERT(m_state != Finished); |
| m_state = Finishing; |
| - m_objectStoreCleanupMap.clear(); |
| // Enqueue events before notifying database, as database may close which enqueues more events and order matters. |
| enqueueEvent(Event::create(EventTypeNames::complete)); |
| - |
| - m_database->transactionFinished(this); |
| + finish(); |
| } |
| bool IDBTransaction::hasPendingActivity() const |
| @@ -354,14 +337,19 @@ const String& IDBTransaction::mode() const |
| return IndexedDBNames::readonly; |
| } |
| +WebIDBDatabase* IDBTransaction::backendDB() const |
| +{ |
| + return m_database->backend(); |
| +} |
| + |
| DOMStringList* IDBTransaction::objectStoreNames() const |
| { |
| - if (m_mode == WebIDBTransactionModeVersionChange) |
| + if (isVersionChange()) |
| return m_database->objectStoreNames(); |
| DOMStringList* objectStoreNames = DOMStringList::create(DOMStringList::IndexedDB); |
| - for (const String& name : m_objectStoreNames) |
| - objectStoreNames->append(name); |
| + for (const String& objectStoreName : m_scope) |
| + objectStoreNames->append(objectStoreName); |
| objectStoreNames->sort(); |
| return objectStoreNames; |
| } |
| @@ -383,33 +371,23 @@ DispatchEventResult IDBTransaction::dispatchEventInternal(Event* event) |
| m_state = Finished; |
| return DispatchEventResult::CanceledBeforeDispatch; |
| } |
| - ASSERT(m_state != Finished); |
| - ASSERT(m_hasPendingActivity); |
| - ASSERT(getExecutionContext()); |
| - ASSERT(event->target() == this); |
| + DCHECK_NE(m_state, Finished); |
| + DCHECK(m_hasPendingActivity); |
| + DCHECK(getExecutionContext()); |
| + DCHECK_EQ(event->target(), this); |
| m_state = Finished; |
| - // Break reference cycles. |
| - // TODO(jsbell): This can be removed c/o Oilpan. |
| - for (auto& it : m_objectStoreMap) |
| - it.value->transactionFinished(); |
| - m_objectStoreMap.clear(); |
| - for (auto& it : m_deletedObjectStores) |
| - it->transactionFinished(); |
| - m_createdObjectStores.clear(); |
| - m_deletedObjectStores.clear(); |
| - |
| HeapVector<Member<EventTarget>> targets; |
| targets.append(this); |
| targets.append(db()); |
| // FIXME: When we allow custom event dispatching, this will probably need to change. |
| - ASSERT(event->type() == EventTypeNames::complete || event->type() == EventTypeNames::abort); |
| + DCHECK(event->type() == EventTypeNames::complete || event->type() == EventTypeNames::abort); |
| DispatchEventResult dispatchResult = IDBEventDispatcher::dispatch(event, targets); |
| // FIXME: Try to construct a test where |this| outlives openDBRequest and we |
| // get a crash. |
| if (m_openDBRequest) { |
| - ASSERT(isVersionChange()); |
| + DCHECK(isVersionChange()); |
| m_openDBRequest->transactionDidFinishAndDispatch(); |
| } |
| m_hasPendingActivity = false; |
| @@ -437,9 +415,54 @@ void IDBTransaction::enqueueEvent(Event* event) |
| eventQueue->enqueueEvent(event); |
| } |
| -WebIDBDatabase* IDBTransaction::backendDB() const |
| +void IDBTransaction::abortOutstandingRequests() |
| { |
| - return m_database->backend(); |
| + for (IDBRequest* request : m_requestList) |
| + request->abort(); |
| + m_requestList.clear(); |
| +} |
| + |
| +void IDBTransaction::revertDatabaseMetadata() |
| +{ |
| + DCHECK_NE(m_state, Active); |
| + if (!isVersionChange()) |
| + return; |
| + |
| + // Newly created stores must be marked as deleted. |
| + for (IDBObjectStore* store : m_createdObjectStores) { |
| + store->abort(); |
| + store->markDeleted(); |
| + } |
| + |
| + // Used stores may need to mark indexes as deleted. |
| + for (auto& it : m_objectStoreCleanupMap) { |
| + it.key->abort(); |
| + it.key->setMetadata(it.value); |
| + } |
| + |
| + m_database->setMetadata(m_oldDatabaseMetadata); |
| +} |
| + |
| +void IDBTransaction::finish() |
| +{ |
| +#if DCHECK_IS_ON() |
| + DCHECK(!m_finishCalled); |
| + m_finishCalled = true; |
| +#endif // DCHECK_IS_ON() |
| + |
| + m_database->transactionFinished(this); |
| + |
| + // Break reference cycles. |
| + // TODO(jsbell): This can be removed c/o Oilpan. |
| + for (auto& it : m_objectStoreMap) |
| + it.value->transactionFinished(); |
| + m_objectStoreMap.clear(); |
| + for (auto& it : m_deletedObjectStores) |
| + it->transactionFinished(); |
| + m_createdObjectStores.clear(); |
| + m_deletedObjectStores.clear(); |
| + |
| + m_objectStoreCleanupMap.clear(); |
| } |
| } // namespace blink |