| 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 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 48 #include "public/platform/modules/indexeddb/WebIDBKeyRange.h" | 48 #include "public/platform/modules/indexeddb/WebIDBKeyRange.h" |
| 49 #include <memory> | 49 #include <memory> |
| 50 #include <v8.h> | 50 #include <v8.h> |
| 51 | 51 |
| 52 using blink::WebBlobInfo; | 52 using blink::WebBlobInfo; |
| 53 using blink::WebIDBCallbacks; | 53 using blink::WebIDBCallbacks; |
| 54 using blink::WebIDBCursor; | 54 using blink::WebIDBCursor; |
| 55 using blink::WebIDBDatabase; | 55 using blink::WebIDBDatabase; |
| 56 using blink::WebVector; | 56 using blink::WebVector; |
| 57 | 57 |
| 58 |
| 58 namespace blink { | 59 namespace blink { |
| 59 | 60 |
| 60 IDBObjectStore::IDBObjectStore(const IDBObjectStoreMetadata& metadata, IDBTransa
ction* transaction) | 61 namespace { |
| 61 : m_metadata(metadata) | 62 using IndexKeys = HeapVector<Member<IDBKey>>; |
| 63 } |
| 64 |
| 65 IDBObjectStore::IDBObjectStore(RefPtr<IDBObjectStoreMetadata> metadata, IDBTrans
action* transaction) |
| 66 : m_metadata(std::move(metadata)) |
| 62 , m_transaction(transaction) | 67 , m_transaction(transaction) |
| 63 { | 68 { |
| 64 ASSERT(m_transaction); | 69 DCHECK(m_transaction); |
| 70 DCHECK(m_metadata.get()); |
| 65 } | 71 } |
| 66 | 72 |
| 67 DEFINE_TRACE(IDBObjectStore) | 73 DEFINE_TRACE(IDBObjectStore) |
| 68 { | 74 { |
| 69 visitor->trace(m_transaction); | 75 visitor->trace(m_transaction); |
| 70 visitor->trace(m_indexMap); | 76 visitor->trace(m_indexMap); |
| 71 visitor->trace(m_createdIndexes); | |
| 72 } | 77 } |
| 73 | 78 |
| 74 void IDBObjectStore::setName(const String& name, ExceptionState& exceptionState) | 79 void IDBObjectStore::setName(const String& newName, ExceptionState& exceptionSta
te) |
| 75 { | 80 { |
| 76 if (!RuntimeEnabledFeatures::indexedDBExperimentalEnabled()) | 81 if (!RuntimeEnabledFeatures::indexedDBExperimentalEnabled()) |
| 77 return; | 82 return; |
| 78 | 83 |
| 79 IDB_TRACE("IDBObjectStore::setName"); | 84 IDB_TRACE("IDBObjectStore::setName"); |
| 80 if (!m_transaction->isVersionChange()) { | 85 if (!m_transaction->isVersionChange()) { |
| 81 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::notVers
ionChangeTransactionErrorMessage); | 86 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::notVers
ionChangeTransactionErrorMessage); |
| 82 return; | 87 return; |
| 83 } | 88 } |
| 84 if (isDeleted()) { | 89 if (isDeleted()) { |
| 85 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectS
toreDeletedErrorMessage); | 90 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectS
toreDeletedErrorMessage); |
| 86 return; | 91 return; |
| 87 } | 92 } |
| 88 if (m_transaction->isFinished() || m_transaction->isFinishing()) { | 93 if (m_transaction->isFinished() || m_transaction->isFinishing()) { |
| 89 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::
transactionFinishedErrorMessage); | 94 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::
transactionFinishedErrorMessage); |
| 90 return; | 95 return; |
| 91 } | 96 } |
| 92 if (!m_transaction->isActive()) { | 97 if (!m_transaction->isActive()) { |
| 93 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::
transactionInactiveErrorMessage); | 98 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::
transactionInactiveErrorMessage); |
| 94 return; | 99 return; |
| 95 } | 100 } |
| 96 | 101 |
| 97 if (m_metadata.name == name) | 102 if (name() == newName) |
| 98 return; | 103 return; |
| 99 if (m_transaction->db()->containsObjectStore(name)) { | 104 if (m_transaction->db()->containsObjectStore(newName)) { |
| 100 exceptionState.throwDOMException(ConstraintError, IDBDatabase::objectSto
reNameTakenErrorMessage); | 105 exceptionState.throwDOMException(ConstraintError, IDBDatabase::objectSto
reNameTakenErrorMessage); |
| 101 return; | 106 return; |
| 102 } | 107 } |
| 103 if (!backendDB()) { | 108 if (!backendDB()) { |
| 104 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databas
eClosedErrorMessage); | 109 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databas
eClosedErrorMessage); |
| 105 return; | 110 return; |
| 106 } | 111 } |
| 107 | 112 |
| 108 backendDB()->renameObjectStore(m_transaction->id(), id(), name); | 113 m_transaction->db()->renameObjectStore(id(), newName); |
| 109 m_transaction->objectStoreRenamed(m_metadata.name, name); | |
| 110 m_metadata.name = name; | |
| 111 | |
| 112 // The name inside the database's version of the object store metadata is us
ed by IDBDatabase.objectStoreNames(). | |
| 113 // If the transaction is aborted, this name will be reverted when the metada
ta is overwritten with the previousMetadata in IDBTransaction. | |
| 114 m_transaction->db()->objectStoreRenamed(id(), name); | |
| 115 } | 114 } |
| 116 | 115 |
| 117 ScriptValue IDBObjectStore::keyPath(ScriptState* scriptState) const | 116 ScriptValue IDBObjectStore::keyPath(ScriptState* scriptState) const |
| 118 { | 117 { |
| 119 return ScriptValue::from(scriptState, m_metadata.keyPath); | 118 return ScriptValue::from(scriptState, metadata().own.keyPath); |
| 120 } | 119 } |
| 121 | 120 |
| 122 DOMStringList* IDBObjectStore::indexNames() const | 121 DOMStringList* IDBObjectStore::indexNames() const |
| 123 { | 122 { |
| 124 IDB_TRACE("IDBObjectStore::indexNames"); | 123 IDB_TRACE("IDBObjectStore::indexNames"); |
| 125 DOMStringList* indexNames = DOMStringList::create(DOMStringList::IndexedDB); | 124 DOMStringList* indexNames = DOMStringList::create(DOMStringList::IndexedDB); |
| 126 for (const auto& it : m_metadata.indexes) | 125 for (const auto& it : metadata().indexes) |
| 127 indexNames->append(it.value.name); | 126 indexNames->append(it.value->name); |
| 128 indexNames->sort(); | 127 indexNames->sort(); |
| 129 return indexNames; | 128 return indexNames; |
| 130 } | 129 } |
| 131 | 130 |
| 132 IDBRequest* IDBObjectStore::get(ScriptState* scriptState, const ScriptValue& key
, ExceptionState& exceptionState) | 131 IDBRequest* IDBObjectStore::get(ScriptState* scriptState, const ScriptValue& key
, ExceptionState& exceptionState) |
| 133 { | 132 { |
| 134 IDB_TRACE("IDBObjectStore::get"); | 133 IDB_TRACE("IDBObjectStore::get"); |
| 135 if (isDeleted()) { | 134 if (isDeleted()) { |
| 136 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectS
toreDeletedErrorMessage); | 135 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectS
toreDeletedErrorMessage); |
| 137 return nullptr; | 136 return nullptr; |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 258 if (!backendDB()) { | 257 if (!backendDB()) { |
| 259 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databas
eClosedErrorMessage); | 258 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databas
eClosedErrorMessage); |
| 260 return nullptr; | 259 return nullptr; |
| 261 } | 260 } |
| 262 | 261 |
| 263 IDBRequest* request = IDBRequest::create(scriptState, IDBAny::create(this),
m_transaction.get()); | 262 IDBRequest* request = IDBRequest::create(scriptState, IDBAny::create(this),
m_transaction.get()); |
| 264 backendDB()->getAll(m_transaction->id(), id(), IDBIndexMetadata::InvalidId,
range, maxCount, true, WebIDBCallbacksImpl::create(request).release()); | 263 backendDB()->getAll(m_transaction->id(), id(), IDBIndexMetadata::InvalidId,
range, maxCount, true, WebIDBCallbacksImpl::create(request).release()); |
| 265 return request; | 264 return request; |
| 266 } | 265 } |
| 267 | 266 |
| 268 static void generateIndexKeysForValue(v8::Isolate* isolate, const IDBIndexMetada
ta& indexMetadata, const ScriptValue& objectValue, IDBObjectStore::IndexKeys* in
dexKeys) | 267 static void generateIndexKeysForValue(v8::Isolate* isolate, const IDBIndexMetada
ta& indexMetadata, const ScriptValue& objectValue, IndexKeys* indexKeys) |
| 269 { | 268 { |
| 270 ASSERT(indexKeys); | 269 ASSERT(indexKeys); |
| 271 NonThrowableExceptionState exceptionState; | 270 NonThrowableExceptionState exceptionState; |
| 272 IDBKey* indexKey = ScriptValue::to<IDBKey*>(isolate, objectValue, exceptionS
tate, indexMetadata.keyPath); | 271 IDBKey* indexKey = ScriptValue::to<IDBKey*>(isolate, objectValue, exceptionS
tate, indexMetadata.keyPath); |
| 273 | 272 |
| 274 if (!indexKey) | 273 if (!indexKey) |
| 275 return; | 274 return; |
| 276 | 275 |
| 277 if (!indexMetadata.multiEntry || indexKey->getType() != IDBKey::ArrayType) { | 276 if (!indexMetadata.multiEntry || indexKey->getType() != IDBKey::ArrayType) { |
| 278 if (!indexKey->isValid()) | 277 if (!indexKey->isValid()) |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 333 Vector<WebBlobInfo> blobInfo; | 332 Vector<WebBlobInfo> blobInfo; |
| 334 RefPtr<SerializedScriptValue> serializedValue = SerializedScriptValue::seria
lize(isolate, value.v8Value(), nullptr, &blobInfo, exceptionState); | 333 RefPtr<SerializedScriptValue> serializedValue = SerializedScriptValue::seria
lize(isolate, value.v8Value(), nullptr, &blobInfo, exceptionState); |
| 335 if (exceptionState.hadException()) | 334 if (exceptionState.hadException()) |
| 336 return nullptr; | 335 return nullptr; |
| 337 | 336 |
| 338 // Keys that need to be extracted must be taken from a clone so that | 337 // Keys that need to be extracted must be taken from a clone so that |
| 339 // side effects (i.e. getters) are not triggered. Construct the | 338 // side effects (i.e. getters) are not triggered. Construct the |
| 340 // clone lazily since the operation may be expensive. | 339 // clone lazily since the operation may be expensive. |
| 341 ScriptValue clone; | 340 ScriptValue clone; |
| 342 | 341 |
| 343 const IDBKeyPath& keyPath = m_metadata.keyPath; | 342 const IDBKeyPath& keyPath = metadata().own.keyPath; |
| 344 const bool usesInLineKeys = !keyPath.isNull(); | 343 const bool usesInLineKeys = !keyPath.isNull(); |
| 345 const bool hasKeyGenerator = autoIncrement(); | 344 const bool hasKeyGenerator = autoIncrement(); |
| 346 | 345 |
| 347 if (putMode != WebIDBPutModeCursorUpdate && usesInLineKeys && key) { | 346 if (putMode != WebIDBPutModeCursorUpdate && usesInLineKeys && key) { |
| 348 exceptionState.throwDOMException(DataError, "The object store uses in-li
ne keys and the key parameter was provided."); | 347 exceptionState.throwDOMException(DataError, "The object store uses in-li
ne keys and the key parameter was provided."); |
| 349 return nullptr; | 348 return nullptr; |
| 350 } | 349 } |
| 351 | 350 |
| 352 // This test logically belongs in IDBCursor, but must operate on the cloned
value. | 351 // This test logically belongs in IDBCursor, but must operate on the cloned
value. |
| 353 if (putMode == WebIDBPutModeCursorUpdate && usesInLineKeys) { | 352 if (putMode == WebIDBPutModeCursorUpdate && usesInLineKeys) { |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 395 return nullptr; | 394 return nullptr; |
| 396 } | 395 } |
| 397 | 396 |
| 398 if (!backendDB()) { | 397 if (!backendDB()) { |
| 399 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databas
eClosedErrorMessage); | 398 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databas
eClosedErrorMessage); |
| 400 return nullptr; | 399 return nullptr; |
| 401 } | 400 } |
| 402 | 401 |
| 403 Vector<int64_t> indexIds; | 402 Vector<int64_t> indexIds; |
| 404 HeapVector<IndexKeys> indexKeys; | 403 HeapVector<IndexKeys> indexKeys; |
| 405 for (const auto& it : m_metadata.indexes) { | 404 for (const auto& it : metadata().indexes) { |
| 406 if (clone.isEmpty()) | 405 if (clone.isEmpty()) |
| 407 clone = deserializeScriptValue(scriptState, serializedValue.get(), &
blobInfo); | 406 clone = deserializeScriptValue(scriptState, serializedValue.get(), &
blobInfo); |
| 408 IndexKeys keys; | 407 IndexKeys keys; |
| 409 generateIndexKeysForValue(scriptState->isolate(), it.value, clone, &keys
); | 408 generateIndexKeysForValue(scriptState->isolate(), *it.value, clone, &key
s); |
| 410 indexIds.append(it.key); | 409 indexIds.append(it.key); |
| 411 indexKeys.append(keys); | 410 indexKeys.append(keys); |
| 412 } | 411 } |
| 413 | 412 |
| 414 IDBRequest* request = IDBRequest::create(scriptState, source, m_transaction.
get()); | 413 IDBRequest* request = IDBRequest::create(scriptState, source, m_transaction.
get()); |
| 415 Vector<char> wireBytes; | 414 Vector<char> wireBytes; |
| 416 serializedValue->toWireBytes(wireBytes); | 415 serializedValue->toWireBytes(wireBytes); |
| 417 RefPtr<SharedBuffer> valueBuffer = SharedBuffer::adoptVector(wireBytes); | 416 RefPtr<SharedBuffer> valueBuffer = SharedBuffer::adoptVector(wireBytes); |
| 418 | 417 |
| 419 backendDB()->put(m_transaction->id(), id(), WebData(valueBuffer), blobInfo,
key, static_cast<WebIDBPutMode>(putMode), WebIDBCallbacksImpl::create(request).r
elease(), indexIds, indexKeys); | 418 backendDB()->put(m_transaction->id(), id(), WebData(valueBuffer), blobInfo,
key, static_cast<WebIDBPutMode>(putMode), WebIDBCallbacksImpl::create(request).r
elease(), indexIds, indexKeys); |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 487 } | 486 } |
| 488 | 487 |
| 489 namespace { | 488 namespace { |
| 490 // This class creates the index keys for a given index by extracting | 489 // This class creates the index keys for a given index by extracting |
| 491 // them from the SerializedScriptValue, for all the existing values in | 490 // them from the SerializedScriptValue, for all the existing values in |
| 492 // the objectStore. It only needs to be kept alive by virtue of being | 491 // the objectStore. It only needs to be kept alive by virtue of being |
| 493 // a listener on an IDBRequest object, in the same way that JavaScript | 492 // a listener on an IDBRequest object, in the same way that JavaScript |
| 494 // cursor success handlers are kept alive. | 493 // cursor success handlers are kept alive. |
| 495 class IndexPopulator final : public EventListener { | 494 class IndexPopulator final : public EventListener { |
| 496 public: | 495 public: |
| 497 static IndexPopulator* create(ScriptState* scriptState, IDBDatabase* databas
e, int64_t transactionId, int64_t objectStoreId, const IDBIndexMetadata& indexMe
tadata) | 496 static IndexPopulator* create(ScriptState* scriptState, IDBDatabase* databas
e, int64_t transactionId, int64_t objectStoreId, RefPtr<const IDBIndexMetadata>
indexMetadata) |
| 498 { | 497 { |
| 499 return new IndexPopulator(scriptState, database, transactionId, objectSt
oreId, indexMetadata); | 498 return new IndexPopulator(scriptState, database, transactionId, objectSt
oreId, std::move(indexMetadata)); |
| 500 } | 499 } |
| 501 | 500 |
| 502 bool operator==(const EventListener& other) const override | 501 bool operator==(const EventListener& other) const override |
| 503 { | 502 { |
| 504 return this == &other; | 503 return this == &other; |
| 505 } | 504 } |
| 506 | 505 |
| 507 DEFINE_INLINE_VIRTUAL_TRACE() | 506 DEFINE_INLINE_VIRTUAL_TRACE() |
| 508 { | 507 { |
| 509 visitor->trace(m_database); | 508 visitor->trace(m_database); |
| 510 EventListener::trace(visitor); | 509 EventListener::trace(visitor); |
| 511 } | 510 } |
| 512 | 511 |
| 513 private: | 512 private: |
| 514 IndexPopulator(ScriptState* scriptState, IDBDatabase* database, int64_t tran
sactionId, int64_t objectStoreId, const IDBIndexMetadata& indexMetadata) | 513 IndexPopulator(ScriptState* scriptState, IDBDatabase* database, int64_t tran
sactionId, int64_t objectStoreId, RefPtr<const IDBIndexMetadata> indexMetadata) |
| 515 : EventListener(CPPEventListenerType) | 514 : EventListener(CPPEventListenerType) |
| 516 , m_scriptState(scriptState) | 515 , m_scriptState(scriptState) |
| 517 , m_database(database) | 516 , m_database(database) |
| 518 , m_transactionId(transactionId) | 517 , m_transactionId(transactionId) |
| 519 , m_objectStoreId(objectStoreId) | 518 , m_objectStoreId(objectStoreId) |
| 520 , m_indexMetadata(indexMetadata) | 519 , m_indexMetadata(std::move(indexMetadata)) |
| 521 { | 520 { |
| 521 DCHECK(m_indexMetadata.get()); |
| 522 } | 522 } |
| 523 | 523 |
| 524 const IDBIndexMetadata& indexMetadata() { return *m_indexMetadata; } |
| 525 |
| 524 void handleEvent(ExecutionContext* executionContext, Event* event) override | 526 void handleEvent(ExecutionContext* executionContext, Event* event) override |
| 525 { | 527 { |
| 526 ASSERT(m_scriptState->getExecutionContext() == executionContext); | 528 ASSERT(m_scriptState->getExecutionContext() == executionContext); |
| 527 ASSERT(event->type() == EventTypeNames::success); | 529 ASSERT(event->type() == EventTypeNames::success); |
| 528 EventTarget* target = event->target(); | 530 EventTarget* target = event->target(); |
| 529 IDBRequest* request = static_cast<IDBRequest*>(target); | 531 IDBRequest* request = static_cast<IDBRequest*>(target); |
| 530 | 532 |
| 531 if (!m_database->backend()) // If database is stopped? | 533 if (!m_database->backend()) // If database is stopped? |
| 532 return; | 534 return; |
| 533 | 535 |
| 534 IDBAny* cursorAny = request->resultAsAny(); | 536 IDBAny* cursorAny = request->resultAsAny(); |
| 535 IDBCursorWithValue* cursor = nullptr; | 537 IDBCursorWithValue* cursor = nullptr; |
| 536 if (cursorAny->getType() == IDBAny::IDBCursorWithValueType) | 538 if (cursorAny->getType() == IDBAny::IDBCursorWithValueType) |
| 537 cursor = cursorAny->idbCursorWithValue(); | 539 cursor = cursorAny->idbCursorWithValue(); |
| 538 | 540 |
| 539 Vector<int64_t> indexIds; | 541 Vector<int64_t> indexIds; |
| 540 indexIds.append(m_indexMetadata.id); | 542 indexIds.append(indexMetadata().id); |
| 541 if (cursor && !cursor->isDeleted()) { | 543 if (cursor && !cursor->isDeleted()) { |
| 542 cursor->continueFunction(nullptr, nullptr, ASSERT_NO_EXCEPTION); | 544 cursor->continueFunction(nullptr, nullptr, ASSERT_NO_EXCEPTION); |
| 543 | 545 |
| 544 IDBKey* primaryKey = cursor->idbPrimaryKey(); | 546 IDBKey* primaryKey = cursor->idbPrimaryKey(); |
| 545 ScriptValue value = cursor->value(m_scriptState.get()); | 547 ScriptValue value = cursor->value(m_scriptState.get()); |
| 546 | 548 |
| 547 IDBObjectStore::IndexKeys indexKeys; | 549 IndexKeys indexKeys; |
| 548 generateIndexKeysForValue(m_scriptState->isolate(), m_indexMetadata,
value, &indexKeys); | 550 generateIndexKeysForValue(m_scriptState->isolate(), indexMetadata(),
value, &indexKeys); |
| 549 | 551 |
| 550 HeapVector<IDBObjectStore::IndexKeys> indexKeysList; | 552 HeapVector<IndexKeys> indexKeysList; |
| 551 indexKeysList.append(indexKeys); | 553 indexKeysList.append(indexKeys); |
| 552 | 554 |
| 553 m_database->backend()->setIndexKeys(m_transactionId, m_objectStoreId
, primaryKey, indexIds, indexKeysList); | 555 m_database->backend()->setIndexKeys(m_transactionId, m_objectStoreId
, primaryKey, indexIds, indexKeysList); |
| 554 } else { | 556 } else { |
| 555 // Now that we are done indexing, tell the backend to go | 557 // Now that we are done indexing, tell the backend to go |
| 556 // back to processing tasks of type NormalTask. | 558 // back to processing tasks of type NormalTask. |
| 557 m_database->backend()->setIndexesReady(m_transactionId, m_objectStor
eId, indexIds); | 559 m_database->backend()->setIndexesReady(m_transactionId, m_objectStor
eId, indexIds); |
| 558 m_database.clear(); | 560 m_database.clear(); |
| 559 } | 561 } |
| 560 | 562 |
| 561 } | 563 } |
| 562 | 564 |
| 563 RefPtr<ScriptState> m_scriptState; | 565 RefPtr<ScriptState> m_scriptState; |
| 564 Member<IDBDatabase> m_database; | 566 Member<IDBDatabase> m_database; |
| 565 const int64_t m_transactionId; | 567 const int64_t m_transactionId; |
| 566 const int64_t m_objectStoreId; | 568 const int64_t m_objectStoreId; |
| 567 const IDBIndexMetadata m_indexMetadata; | 569 RefPtr<const IDBIndexMetadata> m_indexMetadata; |
| 568 }; | 570 }; |
| 569 } // namespace | 571 } // namespace |
| 570 | 572 |
| 571 IDBIndex* IDBObjectStore::createIndex(ScriptState* scriptState, const String& na
me, const IDBKeyPath& keyPath, const IDBIndexParameters& options, ExceptionState
& exceptionState) | 573 IDBIndex* IDBObjectStore::createIndex(ScriptState* scriptState, const String& na
me, const IDBKeyPath& keyPath, const IDBIndexParameters& options, ExceptionState
& exceptionState) |
| 572 { | 574 { |
| 573 IDB_TRACE("IDBObjectStore::createIndex"); | 575 IDB_TRACE("IDBObjectStore::createIndex"); |
| 574 if (!m_transaction->isVersionChange()) { | 576 if (!m_transaction->isVersionChange()) { |
| 575 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::notVers
ionChangeTransactionErrorMessage); | 577 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::notVers
ionChangeTransactionErrorMessage); |
| 576 return nullptr; | 578 return nullptr; |
| 577 } | 579 } |
| (...skipping 19 matching lines...) Expand all Loading... |
| 597 } | 599 } |
| 598 if (keyPath.getType() == IDBKeyPath::ArrayType && options.multiEntry()) { | 600 if (keyPath.getType() == IDBKeyPath::ArrayType && options.multiEntry()) { |
| 599 exceptionState.throwDOMException(InvalidAccessError, "The keyPath argume
nt was an array and the multiEntry option is true."); | 601 exceptionState.throwDOMException(InvalidAccessError, "The keyPath argume
nt was an array and the multiEntry option is true."); |
| 600 return nullptr; | 602 return nullptr; |
| 601 } | 603 } |
| 602 if (!backendDB()) { | 604 if (!backendDB()) { |
| 603 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databas
eClosedErrorMessage); | 605 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databas
eClosedErrorMessage); |
| 604 return nullptr; | 606 return nullptr; |
| 605 } | 607 } |
| 606 | 608 |
| 607 int64_t indexId = m_metadata.maxIndexId + 1; | 609 int64_t indexId = m_metadata->own.maxIndexId + 1; |
| 610 DCHECK(indexId != IDBIndexMetadata::InvalidId); |
| 608 backendDB()->createIndex(m_transaction->id(), id(), indexId, name, keyPath,
options.unique(), options.multiEntry()); | 611 backendDB()->createIndex(m_transaction->id(), id(), indexId, name, keyPath,
options.unique(), options.multiEntry()); |
| 609 | 612 |
| 610 ++m_metadata.maxIndexId; | 613 ++m_metadata->own.maxIndexId; |
| 611 | 614 |
| 612 IDBIndexMetadata metadata(name, indexId, keyPath, options.unique(), options.
multiEntry()); | 615 RefPtr<IDBIndexMetadata> indexMetadata = adoptRef(new IDBIndexMetadata( |
| 613 IDBIndex* index = IDBIndex::create(metadata, this, m_transaction.get()); | 616 name, indexId, keyPath, options.unique(), options.multiEntry())); |
| 617 IDBIndex* index = IDBIndex::create(indexMetadata, this, m_transaction.get())
; |
| 614 m_indexMap.set(name, index); | 618 m_indexMap.set(name, index); |
| 615 m_createdIndexes.add(index); | 619 m_metadata->indexes.set(indexId, indexMetadata); |
| 616 m_metadata.indexes.set(indexId, metadata); | |
| 617 m_transaction->db()->indexCreated(id(), metadata); | |
| 618 | 620 |
| 619 ASSERT(!exceptionState.hadException()); | 621 ASSERT(!exceptionState.hadException()); |
| 620 if (exceptionState.hadException()) | 622 if (exceptionState.hadException()) |
| 621 return nullptr; | 623 return nullptr; |
| 622 | 624 |
| 623 IDBRequest* indexRequest = openCursor(scriptState, nullptr, WebIDBCursorDire
ctionNext, WebIDBTaskTypePreemptive); | 625 IDBRequest* indexRequest = openCursor(scriptState, nullptr, WebIDBCursorDire
ctionNext, WebIDBTaskTypePreemptive); |
| 624 indexRequest->preventPropagation(); | 626 indexRequest->preventPropagation(); |
| 625 | 627 |
| 626 // This is kept alive by being the success handler of the request, which is
in turn kept alive by the owning transaction. | 628 // This is kept alive by being the success handler of the request, which is
in turn kept alive by the owning transaction. |
| 627 IndexPopulator* indexPopulator = IndexPopulator::create(scriptState, transac
tion()->db(), m_transaction->id(), id(), metadata); | 629 IndexPopulator* indexPopulator = IndexPopulator::create(scriptState, transac
tion()->db(), m_transaction->id(), id(), std::move(indexMetadata)); |
| 628 indexRequest->setOnsuccess(indexPopulator); | 630 indexRequest->setOnsuccess(indexPopulator); |
| 629 return index; | 631 return index; |
| 630 } | 632 } |
| 631 | 633 |
| 632 IDBIndex* IDBObjectStore::index(const String& name, ExceptionState& exceptionSta
te) | 634 IDBIndex* IDBObjectStore::index(const String& name, ExceptionState& exceptionSta
te) |
| 633 { | 635 { |
| 634 IDB_TRACE("IDBObjectStore::index"); | 636 IDB_TRACE("IDBObjectStore::index"); |
| 635 if (isDeleted()) { | 637 if (isDeleted()) { |
| 636 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectS
toreDeletedErrorMessage); | 638 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectS
toreDeletedErrorMessage); |
| 637 return nullptr; | 639 return nullptr; |
| 638 } | 640 } |
| 639 if (m_transaction->isFinished() || m_transaction->isFinishing()) { | 641 if (m_transaction->isFinished() || m_transaction->isFinishing()) { |
| 640 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::transac
tionFinishedErrorMessage); | 642 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::transac
tionFinishedErrorMessage); |
| 641 return nullptr; | 643 return nullptr; |
| 642 } | 644 } |
| 643 | 645 |
| 644 IDBIndexMap::iterator it = m_indexMap.find(name); | 646 IndexMap::iterator it = m_indexMap.find(name); |
| 645 if (it != m_indexMap.end()) | 647 if (it != m_indexMap.end()) |
| 646 return it->value; | 648 return it->value; |
| 647 | 649 |
| 648 int64_t indexId = findIndexId(name); | 650 int64_t indexId = findIndexId(name); |
| 649 if (indexId == IDBIndexMetadata::InvalidId) { | 651 if (indexId == IDBIndexMetadata::InvalidId) { |
| 650 exceptionState.throwDOMException(NotFoundError, IDBDatabase::noSuchIndex
ErrorMessage); | 652 exceptionState.throwDOMException(NotFoundError, IDBDatabase::noSuchIndex
ErrorMessage); |
| 651 return nullptr; | 653 return nullptr; |
| 652 } | 654 } |
| 653 | 655 |
| 654 const IDBIndexMetadata* indexMetadata(nullptr); | 656 DCHECK(metadata().indexes.contains(indexId)); |
| 655 for (const auto& it : m_metadata.indexes) { | 657 RefPtr<IDBIndexMetadata> indexMetadata = metadata().indexes.get(indexId); |
| 656 if (it.value.name == name) { | 658 DCHECK(indexMetadata.get()); |
| 657 indexMetadata = &it.value; | 659 IDBIndex* index = IDBIndex::create(std::move(indexMetadata), this, m_transac
tion.get()); |
| 658 break; | |
| 659 } | |
| 660 } | |
| 661 ASSERT(indexMetadata); | |
| 662 ASSERT(indexMetadata->id != IDBIndexMetadata::InvalidId); | |
| 663 | |
| 664 IDBIndex* index = IDBIndex::create(*indexMetadata, this, m_transaction.get()
); | |
| 665 m_indexMap.set(name, index); | 660 m_indexMap.set(name, index); |
| 666 return index; | 661 return index; |
| 667 } | 662 } |
| 668 | 663 |
| 669 void IDBObjectStore::deleteIndex(const String& name, ExceptionState& exceptionSt
ate) | 664 void IDBObjectStore::deleteIndex(const String& name, ExceptionState& exceptionSt
ate) |
| 670 { | 665 { |
| 671 IDB_TRACE("IDBObjectStore::deleteIndex"); | 666 IDB_TRACE("IDBObjectStore::deleteIndex"); |
| 672 if (!m_transaction->isVersionChange()) { | 667 if (!m_transaction->isVersionChange()) { |
| 673 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::notVers
ionChangeTransactionErrorMessage); | 668 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::notVers
ionChangeTransactionErrorMessage); |
| 674 return; | 669 return; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 690 exceptionState.throwDOMException(NotFoundError, IDBDatabase::noSuchIndex
ErrorMessage); | 685 exceptionState.throwDOMException(NotFoundError, IDBDatabase::noSuchIndex
ErrorMessage); |
| 691 return; | 686 return; |
| 692 } | 687 } |
| 693 if (!backendDB()) { | 688 if (!backendDB()) { |
| 694 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databas
eClosedErrorMessage); | 689 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databas
eClosedErrorMessage); |
| 695 return; | 690 return; |
| 696 } | 691 } |
| 697 | 692 |
| 698 backendDB()->deleteIndex(m_transaction->id(), id(), indexId); | 693 backendDB()->deleteIndex(m_transaction->id(), id(), indexId); |
| 699 | 694 |
| 700 m_metadata.indexes.remove(indexId); | 695 m_metadata->indexes.remove(indexId); |
| 701 m_transaction->db()->indexDeleted(id(), indexId); | 696 IndexMap::iterator it = m_indexMap.find(name); |
| 702 IDBIndexMap::iterator it = m_indexMap.find(name); | |
| 703 if (it != m_indexMap.end()) { | 697 if (it != m_indexMap.end()) { |
| 698 m_transaction->indexDeleted(it->value); |
| 704 it->value->markDeleted(); | 699 it->value->markDeleted(); |
| 705 m_indexMap.remove(name); | 700 m_indexMap.remove(name); |
| 706 } | 701 } |
| 707 } | 702 } |
| 708 | 703 |
| 709 IDBRequest* IDBObjectStore::openCursor(ScriptState* scriptState, const ScriptVal
ue& range, const String& directionString, ExceptionState& exceptionState) | 704 IDBRequest* IDBObjectStore::openCursor(ScriptState* scriptState, const ScriptVal
ue& range, const String& directionString, ExceptionState& exceptionState) |
| 710 { | 705 { |
| 711 IDB_TRACE("IDBObjectStore::openCursor"); | 706 IDB_TRACE("IDBObjectStore::openCursor"); |
| 712 if (isDeleted()) { | 707 if (isDeleted()) { |
| 713 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectS
toreDeletedErrorMessage); | 708 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectS
toreDeletedErrorMessage); |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 800 if (!backendDB()) { | 795 if (!backendDB()) { |
| 801 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databas
eClosedErrorMessage); | 796 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databas
eClosedErrorMessage); |
| 802 return nullptr; | 797 return nullptr; |
| 803 } | 798 } |
| 804 | 799 |
| 805 IDBRequest* request = IDBRequest::create(scriptState, IDBAny::create(this),
m_transaction.get()); | 800 IDBRequest* request = IDBRequest::create(scriptState, IDBAny::create(this),
m_transaction.get()); |
| 806 backendDB()->count(m_transaction->id(), id(), IDBIndexMetadata::InvalidId, k
eyRange, WebIDBCallbacksImpl::create(request).release()); | 801 backendDB()->count(m_transaction->id(), id(), IDBIndexMetadata::InvalidId, k
eyRange, WebIDBCallbacksImpl::create(request).release()); |
| 807 return request; | 802 return request; |
| 808 } | 803 } |
| 809 | 804 |
| 810 void IDBObjectStore::abort() | 805 void IDBObjectStore::markDeleted() |
| 811 { | 806 { |
| 812 for (auto& index : m_createdIndexes) | 807 m_deleted = true; |
| 808 m_metadata->indexes.clear(); |
| 809 |
| 810 for (auto& it : m_indexMap) { |
| 811 IDBIndex* index = it.value; |
| 813 index->markDeleted(); | 812 index->markDeleted(); |
| 813 } |
| 814 } | 814 } |
| 815 | 815 |
| 816 void IDBObjectStore::transactionFinished() | 816 void IDBObjectStore::transactionFinished() |
| 817 { | 817 { |
| 818 ASSERT(m_transaction->isFinished()); | 818 DCHECK(m_transaction->isFinished()); |
| 819 | 819 |
| 820 // Break reference cycles. | 820 // Remove our references to IDBIndex instances, so Oilpan can |
| 821 // TODO(jsbell): This can be removed c/o Oilpan. | 821 // garbage-collect the instances that are not referenced in JavaScript. |
| 822 m_indexMap.clear(); | 822 m_indexMap.clear(); |
| 823 m_createdIndexes.clear(); | |
| 824 } | 823 } |
| 825 | 824 |
| 826 void IDBObjectStore::indexRenamed(int64_t indexId, const String& newName) | 825 void IDBObjectStore::revertMetadata(RefPtr<IDBObjectStoreMetadata> oldMetadata) |
| 826 { |
| 827 DCHECK(m_transaction->isVersionChange()); |
| 828 DCHECK(!m_transaction->isActive()); |
| 829 DCHECK(oldMetadata.get()); |
| 830 DCHECK(id() == oldMetadata->own.id); |
| 831 |
| 832 // Index IDs are allocated sequentially, so we can tell if an index was |
| 833 // created in this transaction by comparing its ID with the object store's |
| 834 // maximum index ID at the time when the transaction was started. |
| 835 const int64_t oldMaxIndexId = oldMetadata->own.maxIndexId; |
| 836 for (auto& it : m_indexMap) { |
| 837 IDBIndex* index = it.value; |
| 838 const int64_t indexId = index->id(); |
| 839 |
| 840 if (indexId >= oldMaxIndexId) { |
| 841 // The index was created by this transaction. According to the spec, |
| 842 // its metadata will remain as-is. We just need to look up the |
| 843 // index's IDBIndex instance, and mark it as deleted. |
| 844 DCHECK(!oldMetadata->indexes.contains(indexId)); |
| 845 index->markDeleted(); |
| 846 continue; |
| 847 } |
| 848 |
| 849 // The index was created in a previous transaction. We need to revert |
| 850 // its metadata. The index might have been deleted, so we |
| 851 // unconditionally reset the deletion marker. We could find out if the |
| 852 // index was deleted by looking up the index ID in the store's metadata, |
| 853 // but that would be more work than the unconditional reset. |
| 854 DCHECK(oldMetadata->indexes.contains(indexId)); |
| 855 RefPtr<IDBIndexMetadata> oldIndexMetadata = oldMetadata->indexes.get(ind
exId); |
| 856 index->revertMetadata(std::move(oldIndexMetadata)); |
| 857 } |
| 858 m_metadata = std::move(oldMetadata); |
| 859 |
| 860 // An object store's metadata will only get reverted if the index was in the |
| 861 // database when the versionchange transaction started. |
| 862 m_deleted = false; |
| 863 } |
| 864 |
| 865 void IDBObjectStore::revertDeletedIndexMetadata(IDBIndex& deletedIndex) |
| 866 { |
| 867 DCHECK(m_transaction->isVersionChange()); |
| 868 DCHECK(!m_transaction->isActive()); |
| 869 DCHECK(deletedIndex.objectStore() == this); |
| 870 DCHECK(deletedIndex.isDeleted()); |
| 871 |
| 872 const int64_t indexId = deletedIndex.id(); |
| 873 DCHECK(m_metadata->indexes.contains(indexId)) << "The object store's metadat
a was not correctly reverted"; |
| 874 RefPtr<IDBIndexMetadata> oldIndexMetadata = m_metadata->indexes.get(indexId)
; |
| 875 deletedIndex.revertMetadata(std::move(oldIndexMetadata)); |
| 876 } |
| 877 |
| 878 void IDBObjectStore::renameIndex(int64_t indexId, const String& newName) |
| 827 { | 879 { |
| 828 DCHECK(m_transaction->isVersionChange()); | 880 DCHECK(m_transaction->isVersionChange()); |
| 829 DCHECK(m_transaction->isActive()); | 881 DCHECK(m_transaction->isActive()); |
| 830 | 882 |
| 831 IDBObjectStoreMetadata::IndexMap::iterator metadataIterator = m_metadata.ind
exes.find(indexId); | 883 auto metadataIterator = m_metadata->indexes.find(indexId); |
| 832 DCHECK(metadataIterator != m_metadata.indexes.end()) << "Invalid indexId"; | 884 DCHECK(metadataIterator != m_metadata->indexes.end()) << "Invalid indexId"; |
| 833 const String& oldName = metadataIterator->value.name; | 885 const String& oldName = metadataIterator->value->name; |
| 834 | 886 |
| 835 DCHECK(m_indexMap.contains(oldName)) << "The index had to be accessed in ord
er to be renamed."; | 887 DCHECK(m_indexMap.contains(oldName)) << "The index had to be accessed in ord
er to be renamed."; |
| 836 DCHECK(!m_indexMap.contains(newName)); | 888 DCHECK(!m_indexMap.contains(newName)); |
| 837 IDBIndexMap::iterator it = m_indexMap.find(oldName); | 889 IDBIndex* index = m_indexMap.take(oldName); |
| 838 m_indexMap.set(newName, it->value); | 890 m_indexMap.set(newName, index); |
| 839 m_indexMap.remove(oldName); | |
| 840 | 891 |
| 841 metadataIterator->value.name = newName; | 892 metadataIterator->value->name = newName; |
| 842 } | 893 } |
| 843 | 894 |
| 844 int64_t IDBObjectStore::findIndexId(const String& name) const | 895 int64_t IDBObjectStore::findIndexId(const String& name) const |
| 845 { | 896 { |
| 846 for (const auto& it : m_metadata.indexes) { | 897 for (const auto& it : metadata().indexes) { |
| 847 if (it.value.name == name) { | 898 if (it.value->name == name) { |
| 848 ASSERT(it.key != IDBIndexMetadata::InvalidId); | 899 ASSERT(it.key != IDBIndexMetadata::InvalidId); |
| 849 return it.key; | 900 return it.key; |
| 850 } | 901 } |
| 851 } | 902 } |
| 852 return IDBIndexMetadata::InvalidId; | 903 return IDBIndexMetadata::InvalidId; |
| 853 } | 904 } |
| 854 | 905 |
| 855 WebIDBDatabase* IDBObjectStore::backendDB() const | 906 WebIDBDatabase* IDBObjectStore::backendDB() const |
| 856 { | 907 { |
| 857 return m_transaction->backendDB(); | 908 return m_transaction->backendDB(); |
| 858 } | 909 } |
| 859 | 910 |
| 860 } // namespace blink | 911 } // namespace blink |
| OLD | NEW |