Title: [192618] trunk
Revision
192618
Author
beid...@apple.com
Date
2015-11-19 00:19:56 -0800 (Thu, 19 Nov 2015)

Log Message

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.

Source/WebCore:

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:

LayoutTests:

* 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.

Modified Paths

Added Paths

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));
 }
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to