Chromium Code Reviews| 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 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |