Diff
Modified: trunk/LayoutTests/ChangeLog (192617 => 192618)
--- trunk/LayoutTests/ChangeLog 2015-11-19 08:17:44 UTC (rev 192617)
+++ trunk/LayoutTests/ChangeLog 2015-11-19 08:19:56 UTC (rev 192618)
@@ -1,3 +1,15 @@
+2015-11-19 Brady Eidson <beid...@apple.com>
+
+ Modern IDB: Populate indexes created in object stores that already have records.
+ https://bugs.webkit.org/show_bug.cgi?id=151421
+
+ Reviewed by Alex Christensen.
+
+ * storage/indexeddb/modern/index-4-expected.txt: Added.
+ * storage/indexeddb/modern/index-4.html: Added.
+ * storage/indexeddb/modern/index-5-expected.txt: Added.
+ * storage/indexeddb/modern/index-5.html: Added.
+
2015-11-18 Brian Burg <bb...@apple.com>
Web Inspector: Storage tab shouldn't hide cookies for .example.com when inspected page is foo.bar.example.com
Added: trunk/LayoutTests/storage/indexeddb/modern/index-4-expected.txt (0 => 192618)
--- trunk/LayoutTests/storage/indexeddb/modern/index-4-expected.txt (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/modern/index-4-expected.txt 2015-11-19 08:19:56 UTC (rev 192618)
@@ -0,0 +1,24 @@
+This tests that indexes added to an object store with existing records are populated upon their creation.
+Initial upgrade needed: Old version - 0 New version - 1
+Count is: 18
+Cursor at record: A / 1
+Cursor at record: A / 2
+Cursor at record: B / 3
+Cursor at record: B / 4
+Cursor at record: C / 5
+Cursor at record: C / 6
+Cursor at record: D / 7
+Cursor at record: D / 8
+Cursor at record: E / 9
+Cursor at record: E / 10
+Cursor at record: F / 11
+Cursor at record: F / 12
+Cursor at record: G / 13
+Cursor at record: G / 14
+Cursor at record: H / 15
+Cursor at record: H / 16
+Cursor at record: I / 17
+Cursor at record: I / 18
+Cursor at record: undefined / undefined
+Done
+
Added: trunk/LayoutTests/storage/indexeddb/modern/index-4.html (0 => 192618)
--- trunk/LayoutTests/storage/indexeddb/modern/index-4.html (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/modern/index-4.html 2015-11-19 08:19:56 UTC (rev 192618)
@@ -0,0 +1,96 @@
+This tests that indexes added to an object store with existing records are populated upon their creation.<br>
+<div id="logger"></div>
+<script>
+
+if (window.testRunner) {
+ testRunner.waitUntilDone();
+ testRunner.dumpAsText();
+}
+
+function done()
+{
+ log("Done");
+ if (window.testRunner)
+ testRunner.notifyDone();
+}
+
+function log(message)
+{
+ document.getElementById("logger").innerHTML += message + "<br>";
+}
+
+var index;
+var objectStore;
+
+function checkIndexValues()
+{
+ var countRequest = index.count();
+ countRequest._onsuccess_ = function() {
+ log("Count is: " + countRequest.result);
+ }
+
+ var cursorRequest = index.openCursor();
+ cursorRequest._onsuccess_ = function() {
+ var cursor = cursorRequest.result;
+ log("Cursor at record: " + cursor.key + " / " + cursor.primaryKey);
+
+ if (cursor.key != undefined)
+ cursor.continue();
+ else
+ done();
+ }
+ cursorRequest._onerror_ = function(e) {
+ log("Unexpected error opening or iterating cursor");
+ logCursor(cursorRequest.result);
+ done();
+ }
+}
+
+var createRequest = window.indexedDB.open("Index4Database", 1);
+createRequest._onupgradeneeded_ = function(event) {
+ log("Initial upgrade needed: Old version - " + event.oldVersion + " New version - " + event.newVersion);
+
+ var versionTransaction = createRequest.transaction;
+ var database = event.target.result;
+ objectStore = database.createObjectStore("TestObjectStore");
+ objectStore.put({ bar: "A" }, 1);
+ objectStore.put({ bar: "A" }, 2);
+ objectStore.put({ bar: "B" }, 3);
+ objectStore.put({ bar: "B" }, 4);
+ objectStore.put({ bar: "C" }, 5);
+ objectStore.put({ bar: "C" }, 6);
+ objectStore.put({ bar: "D" }, 7);
+ objectStore.put({ bar: "D" }, 8);
+ objectStore.put({ bar: "E" }, 9);
+ objectStore.put({ bar: "E" }, 10);
+ objectStore.put({ bar: "F" }, 11);
+ objectStore.put({ bar: "F" }, 12);
+ objectStore.put({ bar: "G" }, 13);
+ objectStore.put({ bar: "G" }, 14);
+ objectStore.put({ bar: "H" }, 15);
+ objectStore.put({ bar: "H" }, 16);
+ objectStore.put({ bar: "I" }, 17);
+ objectStore.put({ bar: "I" }, 18);
+
+ // This index should be populated with the above values upon its creation.
+ index = objectStore.createIndex("TestIndex1", "bar");
+
+ checkIndexValues();
+
+ versionTransaction._onabort_ = function(event) {
+ log("Initial upgrade versionchange transaction unexpected aborted");
+ done();
+ }
+
+ versionTransaction._oncomplete_ = function(event) {
+ log("Initial upgrade versionchange transaction complete");
+ done();
+ }
+
+ versionTransaction._onerror_ = function(event) {
+ log("Initial upgrade versionchange transaction unexpected error" + event);
+ done();
+ }
+}
+
+</script>
Added: trunk/LayoutTests/storage/indexeddb/modern/index-5-expected.txt (0 => 192618)
--- trunk/LayoutTests/storage/indexeddb/modern/index-5-expected.txt (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/modern/index-5-expected.txt 2015-11-19 08:19:56 UTC (rev 192618)
@@ -0,0 +1,6 @@
+This tests creating an index on an object store that already has records, and those records would violate the unique constraint of the index.
+(The index creation should fail).
+Initial upgrade needed: Old version - 0 New version - 1
+Initial upgrade versionchange transaction aborted (expected because index creation failed, and that should've caused transaction abort)
+Done
+
Added: trunk/LayoutTests/storage/indexeddb/modern/index-5.html (0 => 192618)
--- trunk/LayoutTests/storage/indexeddb/modern/index-5.html (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/modern/index-5.html 2015-11-19 08:19:56 UTC (rev 192618)
@@ -0,0 +1,82 @@
+This tests creating an index on an object store that already has records, and those records would violate the unique constraint of the index.<br>
+(The index creation should fail).<br>
+<div id="logger"></div>
+<script>
+
+if (window.testRunner) {
+ testRunner.waitUntilDone();
+ testRunner.dumpAsText();
+}
+
+function done()
+{
+ log("Done");
+ if (window.testRunner)
+ testRunner.notifyDone();
+}
+
+function log(message)
+{
+ document.getElementById("logger").innerHTML += message + "<br>";
+}
+
+var index;
+var objectStore;
+
+function checkIndexValues()
+{
+ var countRequest = index.count();
+ countRequest._onsuccess_ = function() {
+ log("Count is: " + countRequest.result);
+ }
+
+ var cursorRequest = index.openCursor();
+ cursorRequest._onsuccess_ = function() {
+ var cursor = cursorRequest.result;
+ log("Cursor at record: " + cursor.key + " / " + cursor.primaryKey);
+
+ if (cursor.key != undefined)
+ cursor.continue();
+ else
+ done();
+ }
+ cursorRequest._onerror_ = function(e) {
+ log("Unexpected error opening or iterating cursor");
+ logCursor(cursorRequest.result);
+ done();
+ }
+}
+
+var createRequest = window.indexedDB.open("Index5Database", 1);
+createRequest._onupgradeneeded_ = function(event) {
+ log("Initial upgrade needed: Old version - " + event.oldVersion + " New version - " + event.newVersion);
+
+ var versionTransaction = createRequest.transaction;
+ var database = event.target.result;
+ objectStore = database.createObjectStore("TestObjectStore");
+ objectStore.put({ bar: "A" }, 1);
+ objectStore.put({ bar: "A" }, 2);
+
+ // This index should be populated with the above values upon its creation, but that should fail because
+ // of constraint violations.
+ index = objectStore.createIndex("TestIndex1", "bar", { unique: true });
+
+ checkIndexValues();
+
+ versionTransaction._onabort_ = function(event) {
+ log("Initial upgrade versionchange transaction aborted (expected because index creation failed, and that should've caused transaction abort)");
+ done();
+ }
+
+ versionTransaction._oncomplete_ = function(event) {
+ log("Initial upgrade versionchange transaction unexpected complete");
+ done();
+ }
+
+ versionTransaction._onerror_ = function(event) {
+ log("Initial upgrade versionchange transaction unexpected error" + event);
+ done();
+ }
+}
+
+</script>
Modified: trunk/Source/WebCore/ChangeLog (192617 => 192618)
--- trunk/Source/WebCore/ChangeLog 2015-11-19 08:17:44 UTC (rev 192617)
+++ trunk/Source/WebCore/ChangeLog 2015-11-19 08:19:56 UTC (rev 192618)
@@ -1,3 +1,18 @@
+2015-11-19 Brady Eidson <beid...@apple.com>
+
+ Modern IDB: Populate indexes created in object stores that already have records.
+ https://bugs.webkit.org/show_bug.cgi?id=151421
+
+ Reviewed by Alex Christensen.
+
+ Test: storage/indexeddb/modern/index-4.html
+ storage/indexeddb/modern/index-5.html
+
+ * Modules/indexeddb/server/MemoryObjectStore.cpp:
+ (WebCore::IDBServer::MemoryObjectStore::createIndex):
+ (WebCore::IDBServer::MemoryObjectStore::populateIndexWithExistingRecords):
+ * Modules/indexeddb/server/MemoryObjectStore.h:
+
2015-11-18 Brady Eidson <beid...@apple.com>
Modern IDB:Make in-memory Index cursors work.
Modified: trunk/Source/WebCore/Modules/indexeddb/client/IDBTransactionImpl.cpp (192617 => 192618)
--- trunk/Source/WebCore/Modules/indexeddb/client/IDBTransactionImpl.cpp 2015-11-19 08:17:44 UTC (rev 192617)
+++ trunk/Source/WebCore/Modules/indexeddb/client/IDBTransactionImpl.cpp 2015-11-19 08:19:56 UTC (rev 192618)
@@ -157,6 +157,20 @@
return adoptRef(&objectStore.leakRef());
}
+void IDBTransaction::immediateAbort()
+{
+ LOG(IndexedDB, "IDBTransaction::immediateAbort");
+
+ if (isFinishedOrFinishing())
+ return;
+
+ m_state = IndexedDB::TransactionState::Aborting;
+ m_database->willAbortTransaction(*this);
+
+ auto operation = createTransactionOperation(*this, nullptr, &IDBTransaction::abortOnServer);
+ abortOnServer(*operation);
+}
+
void IDBTransaction::abort(ExceptionCode& ec)
{
LOG(IndexedDB, "IDBTransaction::abort");
@@ -429,7 +443,11 @@
{
LOG(IndexedDB, "IDBTransaction::didCreateIndexOnServer");
- ASSERT_UNUSED(resultData, resultData.type() == IDBResultType::CreateIndexSuccess);
+ if (resultData.type() == IDBResultType::CreateIndexSuccess)
+ return;
+
+ // If index creation failed, the transaction is aborted.
+ immediateAbort();
}
Ref<IDBRequest> IDBTransaction::requestOpenCursor(ScriptExecutionContext& context, IDBObjectStore& objectStore, const IDBCursorInfo& info)
Modified: trunk/Source/WebCore/Modules/indexeddb/client/IDBTransactionImpl.h (192617 => 192618)
--- trunk/Source/WebCore/Modules/indexeddb/client/IDBTransactionImpl.h 2015-11-19 08:17:44 UTC (rev 192617)
+++ trunk/Source/WebCore/Modules/indexeddb/client/IDBTransactionImpl.h 2015-11-19 08:19:56 UTC (rev 192618)
@@ -176,6 +176,8 @@
void scheduleOperationTimer();
+ void immediateAbort();
+
Ref<IDBDatabase> m_database;
IDBTransactionInfo m_info;
std::unique_ptr<IDBDatabaseInfo> m_originalDatabaseInfo;
Modified: trunk/Source/WebCore/Modules/indexeddb/server/MemoryObjectStore.cpp (192617 => 192618)
--- trunk/Source/WebCore/Modules/indexeddb/server/MemoryObjectStore.cpp 2015-11-19 08:17:44 UTC (rev 192617)
+++ trunk/Source/WebCore/Modules/indexeddb/server/MemoryObjectStore.cpp 2015-11-19 08:19:56 UTC (rev 192618)
@@ -90,8 +90,12 @@
ASSERT(!m_indexesByIdentifier.contains(info.identifier()));
auto index = MemoryIndex::create(info, *this);
+ // If there was an error populating the new index, then the current records in the object store violate its contraints
+ auto error = populateIndexWithExistingRecords(*index);
+ if (!error.isNull())
+ return error;
+
m_info.addExistingIndex(info);
-
transaction.addNewIndex(*index);
registerIndex(WTF::move(index));
@@ -283,6 +287,33 @@
return error;
}
+
+IDBError MemoryObjectStore::populateIndexWithExistingRecords(MemoryIndex& index)
+{
+ if (!m_keyValueStore)
+ return { };
+
+ JSLockHolder locker(indexVM());
+
+ for (auto iterator : *m_keyValueStore) {
+ auto jsValue = idbValueDataToJSValue(indexGlobalExec(), iterator.value);
+ if (jsValue.isUndefinedOrNull())
+ return { };
+
+ IndexKey indexKey;
+ generateIndexKeyForValue(indexGlobalExec(), index.info(), jsValue, indexKey);
+
+ if (indexKey.isNull())
+ continue;
+
+ IDBError error = index.putIndexKey(iterator.key, indexKey);
+ if (!error.isNull())
+ return error;
+ }
+
+ return { };
+}
+
uint64_t MemoryObjectStore::countForKeyRange(uint64_t indexIdentifier, const IDBKeyRangeData& inRange) const
{
LOG(IndexedDB, "MemoryObjectStore::countForKeyRange");
Modified: trunk/Source/WebCore/Modules/indexeddb/server/MemoryObjectStore.h (192617 => 192618)
--- trunk/Source/WebCore/Modules/indexeddb/server/MemoryObjectStore.h 2015-11-19 08:17:44 UTC (rev 192617)
+++ trunk/Source/WebCore/Modules/indexeddb/server/MemoryObjectStore.h 2015-11-19 08:19:56 UTC (rev 192618)
@@ -97,6 +97,7 @@
IDBKeyData lowestKeyWithRecordInRange(const IDBKeyRangeData&) const;
std::set<IDBKeyData>::iterator lowestIteratorInRange(const IDBKeyRangeData&, bool reverse) const;
+ IDBError populateIndexWithExistingRecords(MemoryIndex&);
IDBError updateIndexesForPutRecord(const IDBKeyData&, const ThreadSafeDataBuffer& value);
void updateIndexesForDeleteRecord(const IDBKeyData& value);
void updateCursorsForPutRecord(std::set<IDBKeyData>::iterator);
Modified: trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp (192617 => 192618)
--- trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp 2015-11-19 08:17:44 UTC (rev 192617)
+++ trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp 2015-11-19 08:19:56 UTC (rev 192618)
@@ -353,9 +353,8 @@
LOG(IndexedDB, "(db) UniqueIDBDatabase::performCreateIndex");
ASSERT(m_backingStore);
- m_backingStore->createIndex(transactionIdentifier, info);
+ IDBError error = m_backingStore->createIndex(transactionIdentifier, info);
- IDBError error;
m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformCreateIndex, callbackIdentifier, error, info));
}