 Chromium Code Reviews
 Chromium Code Reviews Issue 2314933005:
  Align IndexedDB metadata rollback on transaction abort to spec.  (Closed)
    
  
    Issue 2314933005:
  Align IndexedDB metadata rollback on transaction abort to spec.  (Closed) 
  | OLD | NEW | 
|---|---|
| 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 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 138 DCHECK(m_state == Finished || m_contextStopped); | 138 DCHECK(m_state == Finished || m_contextStopped); | 
| 139 DCHECK(m_requestList.isEmpty() || m_contextStopped); | 139 DCHECK(m_requestList.isEmpty() || m_contextStopped); | 
| 140 } | 140 } | 
| 141 | 141 | 
| 142 DEFINE_TRACE(IDBTransaction) { | 142 DEFINE_TRACE(IDBTransaction) { | 
| 143 visitor->trace(m_database); | 143 visitor->trace(m_database); | 
| 144 visitor->trace(m_openDBRequest); | 144 visitor->trace(m_openDBRequest); | 
| 145 visitor->trace(m_error); | 145 visitor->trace(m_error); | 
| 146 visitor->trace(m_requestList); | 146 visitor->trace(m_requestList); | 
| 147 visitor->trace(m_objectStoreMap); | 147 visitor->trace(m_objectStoreMap); | 
| 148 visitor->trace(m_createdObjectStores); | 148 visitor->trace(m_oldStoreMetadata); | 
| 149 visitor->trace(m_deletedObjectStores); | 149 visitor->trace(m_deletedIndexes); | 
| 150 visitor->trace(m_objectStoreCleanupMap); | |
| 151 EventTargetWithInlineData::trace(visitor); | 150 EventTargetWithInlineData::trace(visitor); | 
| 152 ActiveDOMObject::trace(visitor); | 151 ActiveDOMObject::trace(visitor); | 
| 153 } | 152 } | 
| 154 | 153 | 
| 155 void IDBTransaction::setError(DOMException* error) { | 154 void IDBTransaction::setError(DOMException* error) { | 
| 156 DCHECK_NE(m_state, Finished); | 155 DCHECK_NE(m_state, Finished); | 
| 157 DCHECK(error); | 156 DCHECK(error); | 
| 158 | 157 | 
| 159 // The first error to be set is the true cause of the | 158 // The first error to be set is the true cause of the | 
| 160 // transaction abort. | 159 // transaction abort. | 
| 161 if (!m_error) { | 160 if (!m_error) | 
| 162 m_error = error; | 161 m_error = error; | 
| 163 } | |
| 164 } | 162 } | 
| 165 | 163 | 
| 166 IDBObjectStore* IDBTransaction::objectStore(const String& name, | 164 IDBObjectStore* IDBTransaction::objectStore(const String& name, | 
| 167 ExceptionState& exceptionState) { | 165 ExceptionState& exceptionState) { | 
| 168 if (isFinished()) { | 166 if (isFinished()) { | 
| 169 exceptionState.throwDOMException( | 167 exceptionState.throwDOMException( | 
| 170 InvalidStateError, IDBDatabase::transactionFinishedErrorMessage); | 168 InvalidStateError, IDBDatabase::transactionFinishedErrorMessage); | 
| 171 return nullptr; | 169 return nullptr; | 
| 172 } | 170 } | 
| 173 | 171 | 
| 174 IDBObjectStoreMap::iterator it = m_objectStoreMap.find(name); | 172 IDBObjectStoreMap::iterator it = m_objectStoreMap.find(name); | 
| 175 if (it != m_objectStoreMap.end()) | 173 if (it != m_objectStoreMap.end()) | 
| 176 return it->value; | 174 return it->value; | 
| 177 | 175 | 
| 178 if (!isVersionChange() && !m_scope.contains(name)) { | 176 if (!isVersionChange() && !m_scope.contains(name)) { | 
| 179 exceptionState.throwDOMException( | 177 exceptionState.throwDOMException( | 
| 180 NotFoundError, IDBDatabase::noSuchObjectStoreErrorMessage); | 178 NotFoundError, IDBDatabase::noSuchObjectStoreErrorMessage); | 
| 181 return nullptr; | 179 return nullptr; | 
| 182 } | 180 } | 
| 183 | 181 | 
| 184 int64_t objectStoreId = m_database->findObjectStoreId(name); | 182 int64_t objectStoreId = m_database->findObjectStoreId(name); | 
| 185 if (objectStoreId == IDBObjectStoreMetadata::InvalidId) { | 183 if (objectStoreId == IDBObjectStoreMetadata::InvalidId) { | 
| 186 DCHECK(isVersionChange()); | 184 DCHECK(isVersionChange()); | 
| 187 exceptionState.throwDOMException( | 185 exceptionState.throwDOMException( | 
| 188 NotFoundError, IDBDatabase::noSuchObjectStoreErrorMessage); | 186 NotFoundError, IDBDatabase::noSuchObjectStoreErrorMessage); | 
| 189 return nullptr; | 187 return nullptr; | 
| 190 } | 188 } | 
| 191 | 189 | 
| 192 DCHECK(m_database->metadata().objectStores.contains(objectStoreId)); | 190 DCHECK(m_database->metadata().objectStores.contains(objectStoreId)); | 
| 193 const IDBObjectStoreMetadata& objectStoreMetadata = | 191 RefPtr<IDBObjectStoreMetadata> objectStoreMetadata = | 
| 194 m_database->metadata().objectStores.get(objectStoreId); | 192 m_database->metadata().objectStores.get(objectStoreId); | 
| 193 DCHECK(objectStoreMetadata.get()); | |
| 195 | 194 | 
| 196 IDBObjectStore* objectStore = | 195 IDBObjectStore* objectStore = | 
| 197 IDBObjectStore::create(objectStoreMetadata, this); | 196 IDBObjectStore::create(std::move(objectStoreMetadata), this); | 
| 198 DCHECK(!m_objectStoreMap.contains(name)); | 197 DCHECK(!m_objectStoreMap.contains(name)); | 
| 199 m_objectStoreMap.set(name, objectStore); | 198 m_objectStoreMap.set(name, objectStore); | 
| 200 m_objectStoreCleanupMap.set(objectStore, objectStore->metadata()); | 199 | 
| 200 if (isVersionChange()) { | |
| 201 DCHECK(objectStore->id() <= oldMaxObjectStoreId()) | |
| 202 << "Object store IDs are not assigned sequentially"; | |
| 203 RefPtr<IDBObjectStoreMetadata> backupMetadata = | |
| 204 objectStore->metadata().createCopy(); | |
| 205 m_oldStoreMetadata.set(objectStore, std::move(backupMetadata)); | |
| 206 } | |
| 201 return objectStore; | 207 return objectStore; | 
| 202 } | 208 } | 
| 203 | 209 | 
| 204 void IDBTransaction::objectStoreCreated(const String& name, | 210 void IDBTransaction::objectStoreCreated(const String& name, | 
| 205 IDBObjectStore* objectStore) { | 211 IDBObjectStore* objectStore) { | 
| 206 DCHECK_NE(m_state, Finished) | 212 DCHECK_NE(m_state, Finished) | 
| 207 << "A finished transaction created an object store"; | 213 << "A finished transaction created an object store"; | 
| 208 DCHECK_EQ(m_mode, WebIDBTransactionModeVersionChange) | 214 DCHECK_EQ(m_mode, WebIDBTransactionModeVersionChange) | 
| 209 << "A non-versionchange transaction created an object store"; | 215 << "A non-versionchange transaction created an object store"; | 
| 210 DCHECK(!m_objectStoreMap.contains(name)) | 216 DCHECK(!m_objectStoreMap.contains(name)) | 
| 211 << "An object store was created with the name of an existing store"; | 217 << "An object store was created with the name of an existing store"; | 
| 218 DCHECK(objectStore->id() > oldMaxObjectStoreId()) | |
| 219 << "Object store IDs are not assigned sequentially"; | |
| 212 m_objectStoreMap.set(name, objectStore); | 220 m_objectStoreMap.set(name, objectStore); | 
| 213 m_objectStoreCleanupMap.set(objectStore, objectStore->metadata()); | |
| 214 m_createdObjectStores.add(objectStore); | |
| 215 } | 221 } | 
| 216 | 222 | 
| 217 void IDBTransaction::objectStoreDeleted(const String& name) { | 223 void IDBTransaction::objectStoreDeleted(const int64_t objectStoreId, | 
| 224 const String& name) { | |
| 218 DCHECK_NE(m_state, Finished) | 225 DCHECK_NE(m_state, Finished) | 
| 219 << "A finished transaction deleted an object store"; | 226 << "A finished transaction deleted an object store"; | 
| 220 DCHECK_EQ(m_mode, WebIDBTransactionModeVersionChange) | 227 DCHECK_EQ(m_mode, WebIDBTransactionModeVersionChange) | 
| 221 << "A non-versionchange transaction deleted an object store"; | 228 << "A non-versionchange transaction deleted an object store"; | 
| 222 IDBObjectStoreMap::iterator it = m_objectStoreMap.find(name); | 229 IDBObjectStoreMap::iterator it = m_objectStoreMap.find(name); | 
| 223 if (it != m_objectStoreMap.end()) { | 230 if (it == m_objectStoreMap.end()) { | 
| 231 // No IDBObjectStore instance was created for the deleted store in this | |
| 232 // transaction. We only need to be able to revert the metadata change | |
| 233 // if the transaction aborts. | |
| 234 DCHECK(m_database->metadata().objectStores.contains(objectStoreId)); | |
| 235 RefPtr<IDBObjectStoreMetadata> metadata = | |
| 236 m_database->metadata().objectStores.get(objectStoreId); | |
| 237 DCHECK(metadata.get()); | |
| 238 DCHECK_EQ(metadata->name, name); | |
| 239 m_deletedObjectStores.append(std::move(metadata)); | |
| 240 } else { | |
| 224 IDBObjectStore* objectStore = it->value; | 241 IDBObjectStore* objectStore = it->value; | 
| 225 m_objectStoreMap.remove(name); | 242 m_objectStoreMap.remove(name); | 
| 226 objectStore->markDeleted(); | 243 objectStore->markDeleted(); | 
| 227 m_objectStoreCleanupMap.set(objectStore, objectStore->metadata()); | 244 if (objectStore->id() > m_oldDatabaseMetadata.maxObjectStoreId) { | 
| 228 m_deletedObjectStores.add(objectStore); | 245 // The store was created and deleted in this transaction, so it will | 
| 246 // not be restored even if the transaction aborts. We have just | |
| 247 // removed our last reference to it. | |
| 248 DCHECK(!m_oldStoreMetadata.contains(objectStore)); | |
| 249 objectStore->clearIndexCache(); | |
| 250 } else { | |
| 251 // The store was created before this transaction, and we created an | |
| 252 // IDBObjectStore instance for it. When that happened, we must have | |
| 253 // snapshotted the store's metadata as well. | |
| 254 DCHECK(m_oldStoreMetadata.contains(objectStore)); | |
| 255 } | |
| 229 } | 256 } | 
| 230 } | 257 } | 
| 231 | 258 | 
| 232 void IDBTransaction::objectStoreRenamed(const String& oldName, | 259 void IDBTransaction::objectStoreRenamed(const String& oldName, | 
| 233 const String& newName) { | 260 const String& newName) { | 
| 234 DCHECK_NE(m_state, Finished) | 261 DCHECK_NE(m_state, Finished) | 
| 235 << "A finished transaction renamed an object store"; | 262 << "A finished transaction renamed an object store"; | 
| 236 DCHECK_EQ(m_mode, WebIDBTransactionModeVersionChange) | 263 DCHECK_EQ(m_mode, WebIDBTransactionModeVersionChange) | 
| 237 << "A non-versionchange transaction renamed an object store"; | 264 << "A non-versionchange transaction renamed an object store"; | 
| 238 | 265 | 
| 239 DCHECK(!m_objectStoreMap.contains(newName)); | 266 DCHECK(!m_objectStoreMap.contains(newName)); | 
| 240 DCHECK(m_objectStoreMap.contains(oldName)) | 267 DCHECK(m_objectStoreMap.contains(oldName)) | 
| 241 << "The object store had to be accessed in order to be renamed."; | 268 << "The object store had to be accessed in order to be renamed."; | 
| 242 m_objectStoreMap.set(newName, m_objectStoreMap.take(oldName)); | 269 m_objectStoreMap.set(newName, m_objectStoreMap.take(oldName)); | 
| 243 } | 270 } | 
| 244 | 271 | 
| 272 void IDBTransaction::indexDeleted(IDBIndex* index) { | |
| 273 DCHECK(index); | |
| 274 DCHECK(!index->isDeleted()) << "indexDeleted called twice for the same index"; | |
| 275 | |
| 276 IDBObjectStore* objectStore = index->objectStore(); | |
| 277 DCHECK_EQ(objectStore->transaction(), this); | |
| 278 DCHECK(m_objectStoreMap.contains(objectStore->name())) | |
| 279 << "An index was deleted without accessing its object store"; | |
| 280 | |
| 281 const auto& objectStoreIterator = m_oldStoreMetadata.find(objectStore); | |
| 282 if (objectStoreIterator == m_oldStoreMetadata.end()) { | |
| 283 // The index's object store was created in this transaction, so this | |
| 284 // index was also created (and deleted) in this transaction, and will | |
| 285 // not be restored if the transaction aborts. | |
| 286 // | |
| 287 // Subtle proof for the first sentence above: Deleting an index requires | |
| 288 // calling deleteIndex() on the store's IDBObjectStore instance. | |
| 289 // Whenever we create an IDBObjectStore instance for a previously | |
| 290 // created store, we snapshot the store's metadata. So, deleting an | |
| 291 // index of an "old" store can only be done after the store's metadata | |
| 292 // is snapshotted. | |
| 293 return; | |
| 294 } | |
| 295 | |
| 296 const IDBObjectStoreMetadata* oldStoreMetadata = | |
| 297 objectStoreIterator->value.get(); | |
| 298 DCHECK(oldStoreMetadata); | |
| 299 if (!oldStoreMetadata->indexes.contains(index->id())) { | |
| 300 // The index's object store was created before this transaction, but the | |
| 301 // index was created (and deleted) in this transaction, so it will not | |
| 302 // be restored if the transaction aborts. | |
| 303 return; | |
| 304 } | |
| 305 | |
| 306 m_deletedIndexes.append(index); | |
| 307 } | |
| 308 | |
| 245 void IDBTransaction::setActive(bool active) { | 309 void IDBTransaction::setActive(bool active) { | 
| 246 DCHECK_NE(m_state, Finished) << "A finished transaction tried to setActive(" | 310 DCHECK_NE(m_state, Finished) << "A finished transaction tried to setActive(" | 
| 247 << (active ? "true" : "false") << ")"; | 311 << (active ? "true" : "false") << ")"; | 
| 248 if (m_state == Finishing) | 312 if (m_state == Finishing) | 
| 249 return; | 313 return; | 
| 250 DCHECK_NE(active, (m_state == Active)); | 314 DCHECK_NE(active, (m_state == Active)); | 
| 251 m_state = active ? Active : Inactive; | 315 m_state = active ? Active : Inactive; | 
| 252 | 316 | 
| 253 if (!active && m_requestList.isEmpty() && backendDB()) | 317 if (!active && m_requestList.isEmpty() && backendDB()) | 
| 254 backendDB()->commit(m_id); | 318 backendDB()->commit(m_id); | 
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 338 if (modeString == IndexedDBNames::readonly) | 402 if (modeString == IndexedDBNames::readonly) | 
| 339 return WebIDBTransactionModeReadOnly; | 403 return WebIDBTransactionModeReadOnly; | 
| 340 if (modeString == IndexedDBNames::readwrite) | 404 if (modeString == IndexedDBNames::readwrite) | 
| 341 return WebIDBTransactionModeReadWrite; | 405 return WebIDBTransactionModeReadWrite; | 
| 342 if (modeString == IndexedDBNames::versionchange) | 406 if (modeString == IndexedDBNames::versionchange) | 
| 343 return WebIDBTransactionModeVersionChange; | 407 return WebIDBTransactionModeVersionChange; | 
| 344 NOTREACHED(); | 408 NOTREACHED(); | 
| 345 return WebIDBTransactionModeReadOnly; | 409 return WebIDBTransactionModeReadOnly; | 
| 346 } | 410 } | 
| 347 | 411 | 
| 412 WebIDBDatabase* IDBTransaction::backendDB() const { | |
| 
cmumford
2016/10/05 21:15:27
Why move method within file?
 
pwnall
2016/10/05 23:15:45
I moved it to match the order in the header -- I'm
 
jsbell
2016/10/06 20:01:31
I'd leave it alone for this CL since it's untouche
 
cmumford
2016/10/06 20:22:55
What Josh said, plus moving it also makes it less
 | |
| 413 return m_database->backend(); | |
| 414 } | |
| 415 | |
| 348 const String& IDBTransaction::mode() const { | 416 const String& IDBTransaction::mode() const { | 
| 349 switch (m_mode) { | 417 switch (m_mode) { | 
| 350 case WebIDBTransactionModeReadOnly: | 418 case WebIDBTransactionModeReadOnly: | 
| 351 return IndexedDBNames::readonly; | 419 return IndexedDBNames::readonly; | 
| 352 | 420 | 
| 353 case WebIDBTransactionModeReadWrite: | 421 case WebIDBTransactionModeReadWrite: | 
| 354 return IndexedDBNames::readwrite; | 422 return IndexedDBNames::readwrite; | 
| 355 | 423 | 
| 356 case WebIDBTransactionModeVersionChange: | 424 case WebIDBTransactionModeVersionChange: | 
| 357 return IndexedDBNames::versionchange; | 425 return IndexedDBNames::versionchange; | 
| 358 } | 426 } | 
| 359 | 427 | 
| 360 NOTREACHED(); | 428 NOTREACHED(); | 
| 361 return IndexedDBNames::readonly; | 429 return IndexedDBNames::readonly; | 
| 362 } | 430 } | 
| 363 | 431 | 
| 364 WebIDBDatabase* IDBTransaction::backendDB() const { | |
| 365 return m_database->backend(); | |
| 366 } | |
| 367 | |
| 368 DOMStringList* IDBTransaction::objectStoreNames() const { | 432 DOMStringList* IDBTransaction::objectStoreNames() const { | 
| 369 if (isVersionChange()) | 433 if (isVersionChange()) | 
| 370 return m_database->objectStoreNames(); | 434 return m_database->objectStoreNames(); | 
| 371 | 435 | 
| 372 DOMStringList* objectStoreNames = | 436 DOMStringList* objectStoreNames = | 
| 373 DOMStringList::create(DOMStringList::IndexedDB); | 437 DOMStringList::create(DOMStringList::IndexedDB); | 
| 374 for (const String& objectStoreName : m_scope) | 438 for (const String& objectStoreName : m_scope) | 
| 375 objectStoreNames->append(objectStoreName); | 439 objectStoreNames->append(objectStoreName); | 
| 376 objectStoreNames->sort(); | 440 objectStoreNames->sort(); | 
| 377 return objectStoreNames; | 441 return objectStoreNames; | 
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 441 for (IDBRequest* request : m_requestList) | 505 for (IDBRequest* request : m_requestList) | 
| 442 request->abort(); | 506 request->abort(); | 
| 443 m_requestList.clear(); | 507 m_requestList.clear(); | 
| 444 } | 508 } | 
| 445 | 509 | 
| 446 void IDBTransaction::revertDatabaseMetadata() { | 510 void IDBTransaction::revertDatabaseMetadata() { | 
| 447 DCHECK_NE(m_state, Active); | 511 DCHECK_NE(m_state, Active); | 
| 448 if (!isVersionChange()) | 512 if (!isVersionChange()) | 
| 449 return; | 513 return; | 
| 450 | 514 | 
| 451 // Newly created stores must be marked as deleted. | 515 // Mark stores created by this transaction as deleted. | 
| 452 for (IDBObjectStore* store : m_createdObjectStores) { | 516 for (auto& it : m_objectStoreMap) { | 
| 
cmumford
2016/10/05 21:15:27
for (auto& objectStore : m_objectStoreMap.values()
 
pwnall
2016/10/05 23:15:45
Done.
Cool, thank you for teaching me this!
 | |
| 453 store->abort(); | 517 IDBObjectStore* objectStore = it.value; | 
| 454 store->markDeleted(); | 518 const int64_t objectStoreId = objectStore->id(); | 
| 519 if (objectStoreId <= oldMaxObjectStoreId()) { | |
| 520 DCHECK(m_oldStoreMetadata.contains(objectStore)); | |
| 521 continue; | |
| 522 } | |
| 523 | |
| 524 DCHECK(!m_oldStoreMetadata.contains(objectStore)); | |
| 525 m_database->revertObjectStoreCreation(objectStoreId); | |
| 526 objectStore->markDeleted(); | |
| 455 } | 527 } | 
| 456 | 528 | 
| 457 // Used stores may need to mark indexes as deleted. | 529 for (auto& it : m_oldStoreMetadata) { | 
| 
cmumford
2016/10/05 21:15:27
for (auto& objectStore : m_oldStoreMetadata.keys()
 
pwnall
2016/10/05 23:15:45
I need the value too, though -- I'm saving it as o
 
jsbell
2016/10/06 20:01:31
Seems fine to me.
 
cmumford
2016/10/06 20:22:55
Yeah, if you need both key and value then absolute
 | |
| 458 for (auto& it : m_objectStoreCleanupMap) { | 530 IDBObjectStore* objectStore = it.key; | 
| 459 it.key->abort(); | 531 RefPtr<IDBObjectStoreMetadata> oldMetadata = it.value; | 
| 460 it.key->setMetadata(it.value); | 532 | 
| 533 m_database->revertObjectStoreMetadata(oldMetadata); | |
| 534 objectStore->revertMetadata(oldMetadata); | |
| 461 } | 535 } | 
| 462 | 536 for (auto& it : m_deletedIndexes) { | 
| 
cmumford
2016/10/05 21:15:27
Why not just?
  for (auto& index : m_deletedIndex
 
pwnall
2016/10/05 23:15:45
Done.
Thank you for catching this!
 | |
| 463 m_database->setMetadata(m_oldDatabaseMetadata); | 537 IDBIndex* index = static_cast<IDBIndex*>(it); | 
| 538 index->objectStore()->revertDeletedIndexMetadata(*index); | |
| 539 } | |
| 540 for (auto& it : m_deletedObjectStores) { | |
| 541 RefPtr<IDBObjectStoreMetadata> oldMedata = | |
| 
cmumford
2016/10/05 21:15:27
Do you need oldMetadata?
 
pwnall
2016/10/05 23:15:45
Done.
Derp, I didn't.
I thought we'd have a compi
 
jsbell
2016/10/06 20:01:31
cpplint.py may be handy - not run by default; not
 | |
| 542 static_cast<RefPtr<IDBObjectStoreMetadata>>(it); | |
| 543 m_database->revertObjectStoreMetadata(std::move(it)); | |
| 544 } | |
| 545 m_database->setDatabaseMetadata(m_oldDatabaseMetadata); | |
| 464 } | 546 } | 
| 465 | 547 | 
| 466 void IDBTransaction::finished() { | 548 void IDBTransaction::finished() { | 
| 467 #if DCHECK_IS_ON() | 549 #if DCHECK_IS_ON() | 
| 468 DCHECK(!m_finishCalled); | 550 DCHECK(!m_finishCalled); | 
| 469 m_finishCalled = true; | 551 m_finishCalled = true; | 
| 470 #endif // DCHECK_IS_ON() | 552 #endif // DCHECK_IS_ON() | 
| 471 | 553 | 
| 472 m_database->transactionFinished(this); | 554 m_database->transactionFinished(this); | 
| 473 | 555 | 
| 474 // Break reference cycles. | 556 // Remove references to the IDBObjectStore and IDBIndex instances held by | 
| 475 // TODO(jsbell): This can be removed c/o Oilpan. | 557 // this transaction, so OilPan can garbage-collect the instances that aren't | 
| 476 for (auto& it : m_objectStoreMap) | 558 // used by JavaScript. | 
| 477 it.value->transactionFinished(); | 559 | 
| 560 for (auto& it : m_objectStoreMap) { | |
| 561 IDBObjectStore* objectStore = it.value; | |
| 562 if (!isVersionChange() || objectStore->id() > oldMaxObjectStoreId()) { | |
| 563 DCHECK(!m_oldStoreMetadata.contains(objectStore)); | |
| 564 objectStore->clearIndexCache(); | |
| 565 } else { | |
| 566 // We'll call clearIndexCache() on this store in the loop below. | |
| 567 DCHECK(m_oldStoreMetadata.contains(objectStore)); | |
| 568 } | |
| 569 } | |
| 478 m_objectStoreMap.clear(); | 570 m_objectStoreMap.clear(); | 
| 479 for (auto& it : m_deletedObjectStores) | 571 | 
| 480 it->transactionFinished(); | 572 for (auto& it : m_oldStoreMetadata) { | 
| 481 m_createdObjectStores.clear(); | 573 IDBObjectStore* objectStore = it.key; | 
| 574 objectStore->clearIndexCache(); | |
| 575 } | |
| 576 m_oldStoreMetadata.clear(); | |
| 577 | |
| 578 m_deletedIndexes.clear(); | |
| 482 m_deletedObjectStores.clear(); | 579 m_deletedObjectStores.clear(); | 
| 483 | |
| 484 m_objectStoreCleanupMap.clear(); | |
| 485 } | 580 } | 
| 486 | 581 | 
| 487 } // namespace blink | 582 } // namespace blink | 
| OLD | NEW |