Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(132)

Side by Side Diff: third_party/WebKit/Source/modules/indexeddb/IDBTransaction.cpp

Issue 2314933005: Align IndexedDB metadata rollback on transaction abort to spec. (Closed)
Patch Set: Rebased. Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2010 Google Inc. All rights reserved. 2 * Copyright (C) 2010 Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions 5 * modification, are permitted provided that the following conditions
6 * are met: 6 * are met:
7 * 7 *
8 * 1. Redistributions of source code must retain the above copyright 8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright 10 * 2. Redistributions in binary form must reproduce the above copyright
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
120 DCHECK(m_requestList.isEmpty() || m_contextStopped); 120 DCHECK(m_requestList.isEmpty() || m_contextStopped);
121 } 121 }
122 122
123 DEFINE_TRACE(IDBTransaction) 123 DEFINE_TRACE(IDBTransaction)
124 { 124 {
125 visitor->trace(m_database); 125 visitor->trace(m_database);
126 visitor->trace(m_openDBRequest); 126 visitor->trace(m_openDBRequest);
127 visitor->trace(m_error); 127 visitor->trace(m_error);
128 visitor->trace(m_requestList); 128 visitor->trace(m_requestList);
129 visitor->trace(m_objectStoreMap); 129 visitor->trace(m_objectStoreMap);
130 visitor->trace(m_createdObjectStores); 130 visitor->trace(m_oldStoreMetadata);
131 visitor->trace(m_deletedObjectStores); 131 visitor->trace(m_deletedIndexes);
132 visitor->trace(m_objectStoreCleanupMap);
133 EventTargetWithInlineData::trace(visitor); 132 EventTargetWithInlineData::trace(visitor);
134 ActiveDOMObject::trace(visitor); 133 ActiveDOMObject::trace(visitor);
135 } 134 }
136 135
137 void IDBTransaction::setError(DOMException* error) 136 void IDBTransaction::setError(DOMException* error)
138 { 137 {
139 DCHECK_NE(m_state, Finished); 138 DCHECK_NE(m_state, Finished);
140 DCHECK(error); 139 DCHECK(error);
141 140
142 // The first error to be set is the true cause of the 141 // The first error to be set is the true cause of the
143 // transaction abort. 142 // transaction abort.
144 if (!m_error) { 143 if (!m_error)
145 m_error = error; 144 m_error = error;
146 }
147 } 145 }
148 146
149 IDBObjectStore* IDBTransaction::objectStore(const String& name, ExceptionState& exceptionState) 147 IDBObjectStore* IDBTransaction::objectStore(const String& name, ExceptionState& exceptionState)
150 { 148 {
151 if (isFinished()) { 149 if (isFinished()) {
152 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::transac tionFinishedErrorMessage); 150 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::transac tionFinishedErrorMessage);
153 return nullptr; 151 return nullptr;
154 } 152 }
155 153
156 IDBObjectStoreMap::iterator it = m_objectStoreMap.find(name); 154 IDBObjectStoreMap::iterator it = m_objectStoreMap.find(name);
157 if (it != m_objectStoreMap.end()) 155 if (it != m_objectStoreMap.end())
158 return it->value; 156 return it->value;
159 157
160 if (!isVersionChange() && !m_scope.contains(name)) { 158 if (!isVersionChange() && !m_scope.contains(name)) {
161 exceptionState.throwDOMException(NotFoundError, IDBDatabase::noSuchObjec tStoreErrorMessage); 159 exceptionState.throwDOMException(NotFoundError, IDBDatabase::noSuchObjec tStoreErrorMessage);
162 return nullptr; 160 return nullptr;
163 } 161 }
164 162
165 int64_t objectStoreId = m_database->findObjectStoreId(name); 163 int64_t objectStoreId = m_database->findObjectStoreId(name);
166 if (objectStoreId == IDBObjectStoreMetadata::InvalidId) { 164 if (objectStoreId == IDBObjectStoreMetadata::InvalidId) {
167 DCHECK(isVersionChange()); 165 DCHECK(isVersionChange());
168 exceptionState.throwDOMException(NotFoundError, IDBDatabase::noSuchObjec tStoreErrorMessage); 166 exceptionState.throwDOMException(NotFoundError, IDBDatabase::noSuchObjec tStoreErrorMessage);
169 return nullptr; 167 return nullptr;
170 } 168 }
171 169
172 DCHECK(m_database->metadata().objectStores.contains(objectStoreId)); 170 DCHECK(m_database->metadata().objectStores.contains(objectStoreId));
173 const IDBObjectStoreMetadata& objectStoreMetadata = m_database->metadata().o bjectStores.get(objectStoreId); 171 RefPtr<IDBObjectStoreMetadata> objectStoreMetadata = m_database->metadata(). objectStores.get(objectStoreId);
172 DCHECK(objectStoreMetadata.get());
174 173
175 IDBObjectStore* objectStore = IDBObjectStore::create(objectStoreMetadata, th is); 174 IDBObjectStore* objectStore = IDBObjectStore::create(std::move(objectStoreMe tadata), this);
176 DCHECK(!m_objectStoreMap.contains(name)); 175 DCHECK(!m_objectStoreMap.contains(name));
177 m_objectStoreMap.set(name, objectStore); 176 m_objectStoreMap.set(name, objectStore);
178 m_objectStoreCleanupMap.set(objectStore, objectStore->metadata()); 177
178 if (isVersionChange()) {
179 DCHECK(objectStore->id() <= oldMaxObjectStoreId()) << "Object store IDs are not assigned sequentially";
180 RefPtr<IDBObjectStoreMetadata> backupMetadata = objectStore->metadata(). createCopy();
181 m_oldStoreMetadata.set(objectStore, std::move(backupMetadata));
182 }
179 return objectStore; 183 return objectStore;
180 } 184 }
181 185
182 void IDBTransaction::objectStoreCreated(const String& name, IDBObjectStore* obje ctStore) 186 void IDBTransaction::objectStoreCreated(const String& name, IDBObjectStore* obje ctStore)
183 { 187 {
184 DCHECK_NE(m_state, Finished) << "A finished transaction created an object st ore"; 188 DCHECK_NE(m_state, Finished) << "A finished transaction created an object st ore";
185 DCHECK_EQ(m_mode, WebIDBTransactionModeVersionChange) << "A non-versionchang e transaction created an object store"; 189 DCHECK_EQ(m_mode, WebIDBTransactionModeVersionChange) << "A non-versionchang e transaction created an object store";
186 DCHECK(!m_objectStoreMap.contains(name)) << "An object store was created wit h the name of an existing store"; 190 DCHECK(!m_objectStoreMap.contains(name)) << "An object store was created wit h the name of an existing store";
191 DCHECK(objectStore->id() > oldMaxObjectStoreId()) << "Object store IDs are n ot assigned sequentially";
187 m_objectStoreMap.set(name, objectStore); 192 m_objectStoreMap.set(name, objectStore);
188 m_objectStoreCleanupMap.set(objectStore, objectStore->metadata());
189 m_createdObjectStores.add(objectStore);
190 } 193 }
191 194
192 void IDBTransaction::objectStoreDeleted(const String& name) 195 void IDBTransaction::objectStoreDeleted(const int64_t objectStoreId, const Strin g& name)
193 { 196 {
194 DCHECK_NE(m_state, Finished) << "A finished transaction deleted an object st ore"; 197 DCHECK_NE(m_state, Finished) << "A finished transaction deleted an object st ore";
195 DCHECK_EQ(m_mode, WebIDBTransactionModeVersionChange) << "A non-versionchang e transaction deleted an object store"; 198 DCHECK_EQ(m_mode, WebIDBTransactionModeVersionChange) << "A non-versionchang e transaction deleted an object store";
196 IDBObjectStoreMap::iterator it = m_objectStoreMap.find(name); 199 IDBObjectStoreMap::iterator it = m_objectStoreMap.find(name);
197 if (it != m_objectStoreMap.end()) { 200 if (it == m_objectStoreMap.end()) {
201 DCHECK(m_database->metadata().objectStores.contains(objectStoreId));
jsbell 2016/09/26 22:23:40 Can you add a comment about what it means when the
pwnall 2016/09/27 00:12:19 Done. Thank you! I think future me will be really
202 RefPtr<IDBObjectStoreMetadata> metadata = m_database->metadata().objectS tores.get(objectStoreId);
203 DCHECK(metadata.get());
204 DCHECK_EQ(metadata->name, name);
205 m_deletedObjectStores.append(std::move(metadata));
206 } else {
198 IDBObjectStore* objectStore = it->value; 207 IDBObjectStore* objectStore = it->value;
199 m_objectStoreMap.remove(name); 208 m_objectStoreMap.remove(name);
200 objectStore->markDeleted(); 209 objectStore->markDeleted();
201 m_objectStoreCleanupMap.set(objectStore, objectStore->metadata()); 210 if (objectStore->id() > m_oldDatabaseMetadata.maxObjectStoreId) {
202 m_deletedObjectStores.add(objectStore); 211 // This store was created and deleted in the same transaction, so it
212 // will not be restored even if the transaction aborts. We have just
213 // removed our last reference to it.
214 DCHECK(!m_oldStoreMetadata.contains(objectStore));
215 objectStore->clearIndexCache();
216 } else {
217 DCHECK(m_oldStoreMetadata.contains(objectStore));
218 }
203 } 219 }
204 } 220 }
205 221
206 void IDBTransaction::objectStoreRenamed(const String& oldName, const String& new Name) 222 void IDBTransaction::objectStoreRenamed(const String& oldName, const String& new Name)
207 { 223 {
208 DCHECK_NE(m_state, Finished) << "A finished transaction renamed an object st ore"; 224 DCHECK_NE(m_state, Finished) << "A finished transaction renamed an object st ore";
209 DCHECK_EQ(m_mode, WebIDBTransactionModeVersionChange) << "A non-versionchang e transaction renamed an object store"; 225 DCHECK_EQ(m_mode, WebIDBTransactionModeVersionChange) << "A non-versionchang e transaction renamed an object store";
210 226
211 DCHECK(!m_objectStoreMap.contains(newName)); 227 DCHECK(!m_objectStoreMap.contains(newName));
212 DCHECK(m_objectStoreMap.contains(oldName)) << "The object store had to be ac cessed in order to be renamed."; 228 DCHECK(m_objectStoreMap.contains(oldName)) << "The object store had to be ac cessed in order to be renamed.";
213 m_objectStoreMap.set(newName, m_objectStoreMap.take(oldName)); 229 m_objectStoreMap.set(newName, m_objectStoreMap.take(oldName));
214 } 230 }
215 231
232 void IDBTransaction::indexDeleted(IDBIndex* index)
233 {
234 DCHECK(index);
235 DCHECK(!index->isDeleted()) << "indexDeleted called twice for the same index ";
236
237 IDBObjectStore* objectStore = index->objectStore();
238 DCHECK_EQ(objectStore->transaction(), this);
239 DCHECK(m_objectStoreMap.contains(objectStore->name())) << "An index was dele ted without accessing its object store";
240
241 const auto& objectStoreIterator = m_oldStoreMetadata.find(objectStore);
jsbell 2016/09/26 22:23:40 Can you add a comment about what this case means?
pwnall 2016/09/27 00:12:19 Done. Future me thanks you!
242 if (objectStoreIterator == m_oldStoreMetadata.end())
243 return;
244
245 const IDBObjectStoreMetadata* oldStoreMetadata = objectStoreIterator->value. get();
246 DCHECK(oldStoreMetadata);
jsbell 2016/09/26 22:23:40 Can you add a comment about what this case means?
pwnall 2016/09/27 00:12:19 Done. Once again, future me thanks you!
247 if (!oldStoreMetadata->indexes.contains(index->id()))
248 return;
249
250 m_deletedIndexes.append(index);
251 }
252
216 void IDBTransaction::setActive(bool active) 253 void IDBTransaction::setActive(bool active)
217 { 254 {
218 DCHECK_NE(m_state, Finished) << "A finished transaction tried to setActive(" << (active ? "true" : "false") << ")"; 255 DCHECK_NE(m_state, Finished) << "A finished transaction tried to setActive(" << (active ? "true" : "false") << ")";
219 if (m_state == Finishing) 256 if (m_state == Finishing)
220 return; 257 return;
221 DCHECK_NE(active, (m_state == Active)); 258 DCHECK_NE(active, (m_state == Active));
222 m_state = active ? Active : Inactive; 259 m_state = active ? Active : Inactive;
223 260
224 if (!active && m_requestList.isEmpty() && backendDB()) 261 if (!active && m_requestList.isEmpty() && backendDB())
225 backendDB()->commit(m_id); 262 backendDB()->commit(m_id);
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
315 if (modeString == IndexedDBNames::readonly) 352 if (modeString == IndexedDBNames::readonly)
316 return WebIDBTransactionModeReadOnly; 353 return WebIDBTransactionModeReadOnly;
317 if (modeString == IndexedDBNames::readwrite) 354 if (modeString == IndexedDBNames::readwrite)
318 return WebIDBTransactionModeReadWrite; 355 return WebIDBTransactionModeReadWrite;
319 if (modeString == IndexedDBNames::versionchange) 356 if (modeString == IndexedDBNames::versionchange)
320 return WebIDBTransactionModeVersionChange; 357 return WebIDBTransactionModeVersionChange;
321 NOTREACHED(); 358 NOTREACHED();
322 return WebIDBTransactionModeReadOnly; 359 return WebIDBTransactionModeReadOnly;
323 } 360 }
324 361
362 WebIDBDatabase* IDBTransaction::backendDB() const
363 {
364 return m_database->backend();
365 }
366
325 const String& IDBTransaction::mode() const 367 const String& IDBTransaction::mode() const
326 { 368 {
327 switch (m_mode) { 369 switch (m_mode) {
328 case WebIDBTransactionModeReadOnly: 370 case WebIDBTransactionModeReadOnly:
329 return IndexedDBNames::readonly; 371 return IndexedDBNames::readonly;
330 372
331 case WebIDBTransactionModeReadWrite: 373 case WebIDBTransactionModeReadWrite:
332 return IndexedDBNames::readwrite; 374 return IndexedDBNames::readwrite;
333 375
334 case WebIDBTransactionModeVersionChange: 376 case WebIDBTransactionModeVersionChange:
335 return IndexedDBNames::versionchange; 377 return IndexedDBNames::versionchange;
336 } 378 }
337 379
338 NOTREACHED(); 380 NOTREACHED();
339 return IndexedDBNames::readonly; 381 return IndexedDBNames::readonly;
340 } 382 }
341 383
342 WebIDBDatabase* IDBTransaction::backendDB() const
343 {
344 return m_database->backend();
345 }
346
347 DOMStringList* IDBTransaction::objectStoreNames() const 384 DOMStringList* IDBTransaction::objectStoreNames() const
348 { 385 {
349 if (isVersionChange()) 386 if (isVersionChange())
350 return m_database->objectStoreNames(); 387 return m_database->objectStoreNames();
351 388
352 DOMStringList* objectStoreNames = DOMStringList::create(DOMStringList::Index edDB); 389 DOMStringList* objectStoreNames = DOMStringList::create(DOMStringList::Index edDB);
353 for (const String& objectStoreName : m_scope) 390 for (const String& objectStoreName : m_scope)
354 objectStoreNames->append(objectStoreName); 391 objectStoreNames->append(objectStoreName);
355 objectStoreNames->sort(); 392 objectStoreNames->sort();
356 return objectStoreNames; 393 return objectStoreNames;
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
423 request->abort(); 460 request->abort();
424 m_requestList.clear(); 461 m_requestList.clear();
425 } 462 }
426 463
427 void IDBTransaction::revertDatabaseMetadata() 464 void IDBTransaction::revertDatabaseMetadata()
428 { 465 {
429 DCHECK_NE(m_state, Active); 466 DCHECK_NE(m_state, Active);
430 if (!isVersionChange()) 467 if (!isVersionChange())
431 return; 468 return;
432 469
433 // Newly created stores must be marked as deleted. 470 // Mark stores created by this transaction as deleted.
434 for (IDBObjectStore* store : m_createdObjectStores) { 471 for (auto& it : m_objectStoreMap) {
435 store->abort(); 472 IDBObjectStore* objectStore = it.value;
436 store->markDeleted(); 473 const int64_t objectStoreId = objectStore->id();
474 if (objectStoreId <= oldMaxObjectStoreId()) {
475 DCHECK(m_oldStoreMetadata.contains(objectStore));
476 continue;
477 }
478
479 DCHECK(!m_oldStoreMetadata.contains(objectStore));
480 m_database->revertObjectStoreCreation(objectStoreId);
481 objectStore->markDeleted();
437 } 482 }
438 483
439 // Used stores may need to mark indexes as deleted. 484 for (auto& it : m_oldStoreMetadata) {
440 for (auto& it : m_objectStoreCleanupMap) { 485 IDBObjectStore* objectStore = it.key;
441 it.key->abort(); 486 RefPtr<IDBObjectStoreMetadata> oldMetadata = it.value;
442 it.key->setMetadata(it.value); 487
488 m_database->revertObjectStoreMetadata(oldMetadata);
489 objectStore->revertMetadata(oldMetadata);
443 } 490 }
444 491 for (auto& it : m_deletedIndexes) {
445 m_database->setMetadata(m_oldDatabaseMetadata); 492 IDBIndex* index = static_cast<IDBIndex*>(it);
493 index->objectStore()->revertDeletedIndexMetadata(*index);
494 }
495 for (auto& it: m_deletedObjectStores) {
496 RefPtr<IDBObjectStoreMetadata> oldMedata = static_cast<RefPtr<IDBObjectS toreMetadata>>(it);
497 m_database->revertObjectStoreMetadata(std::move(it));
498 }
499 m_database->setDatabaseMetadata(m_oldDatabaseMetadata);
446 } 500 }
447 501
448 void IDBTransaction::finished() 502 void IDBTransaction::finished()
449 { 503 {
450 #if DCHECK_IS_ON() 504 #if DCHECK_IS_ON()
451 DCHECK(!m_finishCalled); 505 DCHECK(!m_finishCalled);
452 m_finishCalled = true; 506 m_finishCalled = true;
453 #endif // DCHECK_IS_ON() 507 #endif // DCHECK_IS_ON()
454 508
455 m_database->transactionFinished(this); 509 m_database->transactionFinished(this);
456 510
457 // Break reference cycles. 511 // Remove references to the IDBObjectStore and IDBIndex instances held by
jsbell 2016/09/26 22:23:40 This comment is misleading; they types can be GC'd
pwnall 2016/09/27 00:12:19 Gah, sorry for the poor explanation. I was thinki
458 // TODO(jsbell): This can be removed c/o Oilpan. 512 // this transaction, so OilPan can garbage-collect the instances that aren't
459 for (auto& it : m_objectStoreMap) 513 // used by JavaScript.
460 it.value->transactionFinished(); 514
515 for (auto& it : m_objectStoreMap) {
516 IDBObjectStore* objectStore = it.value;
517 if (!isVersionChange() || objectStore->id() > oldMaxObjectStoreId()) {
518 DCHECK(!m_oldStoreMetadata.contains(objectStore));
519 objectStore->clearIndexCache();
520 } else {
521 // We'll call clearIndexCache() on this store in the loop below.
522 DCHECK(m_oldStoreMetadata.contains(objectStore));
523 }
524 }
461 m_objectStoreMap.clear(); 525 m_objectStoreMap.clear();
462 for (auto& it : m_deletedObjectStores) 526
463 it->transactionFinished(); 527 for (auto& it : m_oldStoreMetadata) {
464 m_createdObjectStores.clear(); 528 IDBObjectStore* objectStore = it.key;
529 objectStore->clearIndexCache();
530 }
531 m_oldStoreMetadata.clear();
532
533 m_deletedIndexes.clear();
465 m_deletedObjectStores.clear(); 534 m_deletedObjectStores.clear();
466
467 m_objectStoreCleanupMap.clear();
468 } 535 }
469 536
470 } // namespace blink 537 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698