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 |