Title: [192294] trunk
Revision
192294
Author
beid...@apple.com
Date
2015-11-10 22:07:03 -0800 (Tue, 10 Nov 2015)

Log Message

Modern IDB: Make indexes actually index.
https://bugs.webkit.org/show_bug.cgi?id=150939

Reviewed by Alex Christensen.

Source/WebCore:

Tests: storage/indexeddb/modern/index-1.html
       storage/indexeddb/modern/index-2.html
       storage/indexeddb/modern/index-3.html

* CMakeLists.txt:
* WebCore.xcodeproj/project.pbxproj:

* Modules/indexeddb/IDBKeyData.h:
(WebCore::IDBKeyData::hash): Deleted.

* Modules/indexeddb/IDBKeyRangeData.cpp:
(WebCore::IDBKeyRangeData::isExactlyOneKey):

* Modules/indexeddb/client/IDBTransactionImpl.cpp:
(WebCore::IDBClient::IDBTransaction::didGetRecordOnServer):

* Modules/indexeddb/server/IndexValueEntry.cpp: Copied from Source/WebCore/Modules/indexeddb/server/MemoryIndex.cpp.
(WebCore::IDBServer::IndexValueEntry::IndexValueEntry):
(WebCore::IDBServer::IndexValueEntry::~IndexValueEntry):
(WebCore::IDBServer::IndexValueEntry::addKey):
(WebCore::IDBServer::IndexValueEntry::removeKey):
(WebCore::IDBServer::IndexValueEntry::getLowest):
(WebCore::IDBServer::IndexValueEntry::getCount):
* Modules/indexeddb/server/IndexValueEntry.h: Copied from Source/WebCore/Modules/indexeddb/server/MemoryIndex.h.

* Modules/indexeddb/server/IndexValueStore.cpp: Added.
(WebCore::IDBServer::IndexValueStore::IndexValueStore):
(WebCore::IDBServer::IndexValueStore::lowestValueForKey):
(WebCore::IDBServer::IndexValueStore::countForKey):
(WebCore::IDBServer::IndexValueStore::contains):
(WebCore::IDBServer::IndexValueStore::addRecord):
(WebCore::IDBServer::IndexValueStore::removeRecord):
(WebCore::IDBServer::IndexValueStore::removeEntriesWithValueKey):
(WebCore::IDBServer::IndexValueStore::lowestKeyWithRecordInRange):
* Modules/indexeddb/server/IndexValueStore.h: Copied from Source/WebCore/Modules/indexeddb/server/MemoryIndex.h.

* Modules/indexeddb/server/MemoryBackingStoreTransaction.cpp:
(WebCore::IDBServer::MemoryBackingStoreTransaction::objectStoreCleared):
(WebCore::IDBServer::MemoryBackingStoreTransaction::indexCleared):
(WebCore::IDBServer::MemoryBackingStoreTransaction::abort):
* Modules/indexeddb/server/MemoryBackingStoreTransaction.h:

* Modules/indexeddb/server/MemoryIDBBackingStore.cpp:
(WebCore::IDBServer::MemoryIDBBackingStore::addRecord):

* Modules/indexeddb/server/MemoryIndex.cpp:
(WebCore::IDBServer::MemoryIndex::create):
(WebCore::IDBServer::MemoryIndex::MemoryIndex):
(WebCore::IDBServer::MemoryIndex::objectStoreCleared):
(WebCore::IDBServer::MemoryIndex::replaceIndexValueStore):
(WebCore::IDBServer::MemoryIndex::getResultForKeyRange):
(WebCore::IDBServer::MemoryIndex::countForKeyRange):
(WebCore::IDBServer::MemoryIndex::putIndexKey):
(WebCore::IDBServer::MemoryIndex::removeRecord):
(WebCore::IDBServer::MemoryIndex::removeEntriesWithValueKey):
(WebCore::IDBServer::MemoryIndex::valueForKeyRange): Deleted.
* Modules/indexeddb/server/MemoryIndex.h:

* Modules/indexeddb/server/MemoryObjectStore.cpp:
(WebCore::IDBServer::MemoryObjectStore::createIndex):
(WebCore::IDBServer::MemoryObjectStore::clear):
(WebCore::IDBServer::MemoryObjectStore::deleteRecord):
(WebCore::IDBServer::MemoryObjectStore::addRecord):
(WebCore::IDBServer::indexVM):
(WebCore::IDBServer::indexGlobalExec):
(WebCore::IDBServer::MemoryObjectStore::updateIndexesForDeleteRecord):
(WebCore::IDBServer::MemoryObjectStore::updateIndexesForPutRecord):
(WebCore::IDBServer::MemoryObjectStore::indexValueForKeyRange):
* Modules/indexeddb/server/MemoryObjectStore.h:
(WebCore::IDBServer::MemoryObjectStore::writeTransaction):

* Modules/indexeddb/shared/IndexKey.cpp: Copied from Source/WebCore/Modules/indexeddb/IDBKeyRangeData.cpp.
(WebCore::IndexKey::IndexKey):
(WebCore::IndexKey::isolatedCopy):
(WebCore::IndexKey::asOneKey):
(WebCore::IndexKey::multiEntry):
* Modules/indexeddb/shared/IndexKey.h: Added.
(WebCore::IndexKey::isNull):

* bindings/js/IDBBindingUtilities.cpp:
(WebCore::idbValueDataToJSValue):
(WebCore::deserializeIDBValueBuffer):
(WebCore::idbKeyDataToScriptValue):
(WebCore::createKeyPathArray):
(WebCore::generateIndexKeyForValue):
* bindings/js/IDBBindingUtilities.h:

LayoutTests:

* storage/indexeddb/modern/index-1-expected.txt: Added.
* storage/indexeddb/modern/index-1.html: Added.
* storage/indexeddb/modern/index-2-expected.txt: Added.
* storage/indexeddb/modern/index-2.html: Added.
* storage/indexeddb/modern/index-3-expected.txt: Added.
* storage/indexeddb/modern/index-3.html: Added.
* storage/indexeddb/modern/index-get-count-basic-expected.txt:
* storage/indexeddb/modern/index-get-count-basic.html:

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (192293 => 192294)


--- trunk/LayoutTests/ChangeLog	2015-11-11 05:19:56 UTC (rev 192293)
+++ trunk/LayoutTests/ChangeLog	2015-11-11 06:07:03 UTC (rev 192294)
@@ -1,3 +1,19 @@
+2015-11-10  Brady Eidson  <beid...@apple.com>
+
+        Modern IDB: Make indexes actually index.
+        https://bugs.webkit.org/show_bug.cgi?id=150939
+
+        Reviewed by Alex Christensen.
+
+        * storage/indexeddb/modern/index-1-expected.txt: Added.
+        * storage/indexeddb/modern/index-1.html: Added.
+        * storage/indexeddb/modern/index-2-expected.txt: Added.
+        * storage/indexeddb/modern/index-2.html: Added.
+        * storage/indexeddb/modern/index-3-expected.txt: Added.
+        * storage/indexeddb/modern/index-3.html: Added.
+        * storage/indexeddb/modern/index-get-count-basic-expected.txt:
+        * storage/indexeddb/modern/index-get-count-basic.html:
+
 2015-11-10  Myles C. Maxfield  <mmaxfi...@apple.com>
 
         Updating test expected results after r192269

Added: trunk/LayoutTests/storage/indexeddb/modern/index-1-expected.txt (0 => 192294)


--- trunk/LayoutTests/storage/indexeddb/modern/index-1-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/modern/index-1-expected.txt	2015-11-11 06:07:03 UTC (rev 192294)
@@ -0,0 +1,136 @@
+This tests the expected values from some more complex index situations.
+Initial upgrade needed: Old version - 0 New version - 1
+get "good" result is: [object Object]
+bar is good
+baz is bad
+getKey "good" result is: 1
+get "bad" result is: undefined
+getKey "bad" result is: undefined
+get "ok" result is: [object Object]
+bar is ok
+baz is meh
+getKey "ok" result is: 4
+get "meh" result is: undefined
+getKey "meh" result is: undefined
+get "super" result is: [object Object]
+bar is super
+baz is thanksForAsking
+getKey "super" result is: 7
+get "thanksForAsking" result is: undefined
+getKey "thanksForAsking" result is: undefined
+get "good,bad" result is: undefined
+getKey "good,bad" result is: undefined
+get "ok,meh" result is: undefined
+getKey "ok,meh" result is: undefined
+get "super,thanksForAsking" result is: undefined
+getKey "super,thanksForAsking" result is: undefined
+get "This is to test" result is: undefined
+getKey "This is to test" result is: undefined
+get "multiEntry indexes" result is: undefined
+getKey "multiEntry indexes" result is: undefined
+get "This is to test,multiEntry indexes" result is: [object Object]
+bar is This is to test,multiEntry indexes
+getKey "This is to test,multiEntry indexes" result is: 10
+count result is: 10
+
+get "good" result is: undefined
+getKey "good" result is: undefined
+get "bad" result is: [object Object]
+bar is good
+baz is bad
+getKey "bad" result is: 1
+get "ok" result is: undefined
+getKey "ok" result is: undefined
+get "meh" result is: [object Object]
+bar is ok
+baz is meh
+getKey "meh" result is: 4
+get "super" result is: undefined
+getKey "super" result is: undefined
+get "thanksForAsking" result is: [object Object]
+bar is super
+baz is thanksForAsking
+getKey "thanksForAsking" result is: 7
+get "good,bad" result is: undefined
+getKey "good,bad" result is: undefined
+get "ok,meh" result is: undefined
+getKey "ok,meh" result is: undefined
+get "super,thanksForAsking" result is: undefined
+getKey "super,thanksForAsking" result is: undefined
+get "This is to test" result is: undefined
+getKey "This is to test" result is: undefined
+get "multiEntry indexes" result is: undefined
+getKey "multiEntry indexes" result is: undefined
+get "This is to test,multiEntry indexes" result is: undefined
+getKey "This is to test,multiEntry indexes" result is: undefined
+count result is: 9
+
+get "good" result is: undefined
+getKey "good" result is: undefined
+get "bad" result is: undefined
+getKey "bad" result is: undefined
+get "ok" result is: undefined
+getKey "ok" result is: undefined
+get "meh" result is: undefined
+getKey "meh" result is: undefined
+get "super" result is: undefined
+getKey "super" result is: undefined
+get "thanksForAsking" result is: undefined
+getKey "thanksForAsking" result is: undefined
+get "good,bad" result is: [object Object]
+bar is good
+baz is bad
+getKey "good,bad" result is: 1
+get "ok,meh" result is: [object Object]
+bar is ok
+baz is meh
+getKey "ok,meh" result is: 4
+get "super,thanksForAsking" result is: [object Object]
+bar is super
+baz is thanksForAsking
+getKey "super,thanksForAsking" result is: 7
+get "This is to test" result is: undefined
+getKey "This is to test" result is: undefined
+get "multiEntry indexes" result is: undefined
+getKey "multiEntry indexes" result is: undefined
+get "This is to test,multiEntry indexes" result is: undefined
+getKey "This is to test,multiEntry indexes" result is: undefined
+count result is: 9
+
+get "good" result is: [object Object]
+bar is good
+baz is bad
+getKey "good" result is: 1
+get "bad" result is: undefined
+getKey "bad" result is: undefined
+get "ok" result is: [object Object]
+bar is ok
+baz is meh
+getKey "ok" result is: 4
+get "meh" result is: undefined
+getKey "meh" result is: undefined
+get "super" result is: [object Object]
+bar is super
+baz is thanksForAsking
+getKey "super" result is: 7
+get "thanksForAsking" result is: undefined
+getKey "thanksForAsking" result is: undefined
+get "good,bad" result is: undefined
+getKey "good,bad" result is: undefined
+get "ok,meh" result is: undefined
+getKey "ok,meh" result is: undefined
+get "super,thanksForAsking" result is: undefined
+getKey "super,thanksForAsking" result is: undefined
+get "This is to test" result is: [object Object]
+bar is This is to test,multiEntry indexes
+getKey "This is to test" result is: 10
+get "multiEntry indexes" result is: [object Object]
+bar is This is to test,multiEntry indexes
+getKey "multiEntry indexes" result is: 10
+get "This is to test,multiEntry indexes" result is: undefined
+getKey "This is to test,multiEntry indexes" result is: undefined
+count result is: 11
+
+Initial upgrade versionchange transaction complete
+Done
+

Added: trunk/LayoutTests/storage/indexeddb/modern/index-1.html (0 => 192294)


--- trunk/LayoutTests/storage/indexeddb/modern/index-1.html	                        (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/modern/index-1.html	2015-11-11 06:07:03 UTC (rev 192294)
@@ -0,0 +1,106 @@
+This tests the expected values from some more complex index situations.<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 createRequest = window.indexedDB.open("Index1Database", 1);
+
+function checkKey(index, key)
+{
+    var request1 = index.get(key);
+    var request2 = index.getKey(key);
+
+    request1._onsuccess_ = function() {
+        log("get \"" + key + "\" result is: " + request1.result);
+        for (n in request1.result)
+            log(n + " is " + request1.result[n]);
+    }
+    request2._onsuccess_ = function() {
+        log("getKey \"" + key + "\" result is: " + request2.result);
+        for (n in request2.result)
+            log(n + " is " + request2.result[n]);
+    } 
+}
+
+function checkIndex(index)
+{
+    checkKey(index, "good");
+    checkKey(index, "bad");
+    checkKey(index, "ok");
+    checkKey(index, "meh");
+    checkKey(index, "super");
+    checkKey(index, "thanksForAsking");
+    checkKey(index, [ "good", "bad" ]);
+    checkKey(index, [ "ok", "meh" ]);
+    checkKey(index, [ "super", "thanksForAsking" ]);
+    checkKey(index, "This is to test");
+    checkKey(index, "multiEntry indexes");
+    checkKey(index, ["This is to test", "multiEntry indexes" ]);
+    
+    var request = index.count();
+    request._onsuccess_ = function() {
+        log("count result is: " + request.result);
+        log(" ");
+    }
+}
+
+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;
+    var objectStore = database.createObjectStore("TestObjectStore");
+    var index1 = objectStore.createIndex("TestIndex1", "bar");
+    var index2 = objectStore.createIndex("TestIndex2", "baz");
+    var index3 = objectStore.createIndex("TestIndex3", [ "bar", "baz" ]);
+    var index4 = objectStore.createIndex("TestIndex4", "bar", { multiEntry: true });
+
+    objectStore.put({ bar: "good", baz: "bad" }, 1);
+    objectStore.put({ bar: "good", baz: "bad" }, 2);
+    objectStore.put({ bar: "good", baz: "bad" }, 3);
+    objectStore.put({ bar: "ok", baz: "meh" }, 4);
+    objectStore.put({ bar: "ok", baz: "meh" }, 5);
+    objectStore.put({ bar: "ok", baz: "meh" }, 6);
+    objectStore.put({ bar: "super", baz: "thanksForAsking" }, 7);
+    objectStore.put({ bar: "super", baz: "thanksForAsking" }, 8);
+    objectStore.put({ bar: "super", baz: "thanksForAsking" }, 9);
+    objectStore.put({ bar: [ "This is to test", "multiEntry indexes" ]}, 10);
+    
+    checkIndex(index1);
+    checkIndex(index2);
+    checkIndex(index3);
+    checkIndex(index4);
+  
+    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-2-expected.txt (0 => 192294)


--- trunk/LayoutTests/storage/indexeddb/modern/index-2-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/modern/index-2-expected.txt	2015-11-11 06:07:03 UTC (rev 192294)
@@ -0,0 +1,150 @@
+This tests indexes are left in appropriate states after aborted transactions.
+Initial upgrade needed: Old version - 0 New version - 1
+get "good" result is: [object Object]
+bar is good
+baz is bad
+getKey "good" result is: 1
+get "bad" result is: undefined
+getKey "bad" result is: undefined
+get "multiEntry" result is: undefined
+getKey "multiEntry" result is: undefined
+get "test" result is: undefined
+getKey "test" result is: undefined
+count result is: 2
+
+get "good" result is: undefined
+getKey "good" result is: undefined
+get "bad" result is: [object Object]
+bar is good
+baz is bad
+getKey "bad" result is: 1
+get "multiEntry" result is: undefined
+getKey "multiEntry" result is: undefined
+get "test" result is: undefined
+getKey "test" result is: undefined
+count result is: 1
+
+get "good" result is: [object Object]
+bar is good
+baz is bad
+getKey "good" result is: 1
+get "bad" result is: undefined
+getKey "bad" result is: undefined
+get "multiEntry" result is: [object Object]
+bar is multiEntry,test
+getKey "multiEntry" result is: 2
+get "test" result is: [object Object]
+bar is multiEntry,test
+getKey "test" result is: 2
+count result is: 3
+
+Initial upgrade versionchange transaction complete
+Deleted key 1 from objectstore
+
+get "good" result is: undefined
+getKey "good" result is: undefined
+get "bad" result is: undefined
+getKey "bad" result is: undefined
+get "multiEntry" result is: undefined
+getKey "multiEntry" result is: undefined
+get "test" result is: undefined
+getKey "test" result is: undefined
+count result is: 1
+
+get "good" result is: undefined
+getKey "good" result is: undefined
+get "bad" result is: undefined
+getKey "bad" result is: undefined
+get "multiEntry" result is: undefined
+getKey "multiEntry" result is: undefined
+get "test" result is: undefined
+getKey "test" result is: undefined
+count result is: 0
+
+get "good" result is: undefined
+getKey "good" result is: undefined
+get "bad" result is: undefined
+getKey "bad" result is: undefined
+get "multiEntry" result is: [object Object]
+bar is multiEntry,test
+getKey "multiEntry" result is: 2
+get "test" result is: [object Object]
+bar is multiEntry,test
+getKey "test" result is: 2
+count result is: 2
+
+Cleared objectstore
+
+get "good" result is: undefined
+getKey "good" result is: undefined
+get "bad" result is: undefined
+getKey "bad" result is: undefined
+get "multiEntry" result is: undefined
+getKey "multiEntry" result is: undefined
+get "test" result is: undefined
+getKey "test" result is: undefined
+count result is: 0
+
+get "good" result is: undefined
+getKey "good" result is: undefined
+get "bad" result is: undefined
+getKey "bad" result is: undefined
+get "multiEntry" result is: undefined
+getKey "multiEntry" result is: undefined
+get "test" result is: undefined
+getKey "test" result is: undefined
+count result is: 0
+
+get "good" result is: undefined
+getKey "good" result is: undefined
+get "bad" result is: undefined
+getKey "bad" result is: undefined
+get "multiEntry" result is: undefined
+getKey "multiEntry" result is: undefined
+get "test" result is: undefined
+getKey "test" result is: undefined
+count result is: 0
+
+All done. Moving on to final part
+readwrite transaction aborted
+get "good" result is: [object Object]
+bar is good
+baz is bad
+getKey "good" result is: 1
+get "bad" result is: undefined
+getKey "bad" result is: undefined
+get "multiEntry" result is: undefined
+getKey "multiEntry" result is: undefined
+get "test" result is: undefined
+getKey "test" result is: undefined
+count result is: 2
+
+get "good" result is: undefined
+getKey "good" result is: undefined
+get "bad" result is: [object Object]
+bar is good
+baz is bad
+getKey "bad" result is: 1
+get "multiEntry" result is: undefined
+getKey "multiEntry" result is: undefined
+get "test" result is: undefined
+getKey "test" result is: undefined
+count result is: 1
+
+get "good" result is: [object Object]
+bar is good
+baz is bad
+getKey "good" result is: 1
+get "bad" result is: undefined
+getKey "bad" result is: undefined
+get "multiEntry" result is: [object Object]
+bar is multiEntry,test
+getKey "multiEntry" result is: 2
+get "test" result is: [object Object]
+bar is multiEntry,test
+getKey "test" result is: 2
+count result is: 3
+
+readwrite transaction complete
+Done
+

Added: trunk/LayoutTests/storage/indexeddb/modern/index-2.html (0 => 192294)


--- trunk/LayoutTests/storage/indexeddb/modern/index-2.html	                        (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/modern/index-2.html	2015-11-11 06:07:03 UTC (rev 192294)
@@ -0,0 +1,165 @@
+This tests indexes are left in appropriate states after aborted transactions.<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 createRequest = window.indexedDB.open("Index2Database", 1);
+
+function checkKey(index, key)
+{
+    var request1 = index.get(key);
+    var request2 = index.getKey(key);
+
+    request1._onsuccess_ = function() {
+        log("get \"" + key + "\" result is: " + request1.result);
+        for (n in request1.result)
+            log(n + " is " + request1.result[n]);
+    }
+    request2._onsuccess_ = function() {
+        log("getKey \"" + key + "\" result is: " + request2.result);
+        for (n in request2.result)
+            log(n + " is " + request2.result[n]);
+    } 
+}
+
+function checkIndex(index)
+{
+    checkKey(index, "good");
+    checkKey(index, "bad");
+    checkKey(index, "multiEntry");
+    checkKey(index, "test");
+    
+    var request = index.count();
+    request._onsuccess_ = function() {
+        log("count result is: " + request.result);
+        log(" ");
+    }
+}
+
+var database;
+
+createRequest._onupgradeneeded_ = function(event) {
+    log("Initial upgrade needed: Old version - " + event.oldVersion + " New version - " + event.newVersion);
+
+    var versionTransaction = createRequest.transaction;
+    database = event.target.result;
+    var objectStore = database.createObjectStore("TestObjectStore");
+    var index1 = objectStore.createIndex("TestIndex1", "bar");
+    var index2 = objectStore.createIndex("TestIndex2", "baz");
+    var index3 = objectStore.createIndex("TestIndex3", "bar", { multiEntry: true });
+
+    objectStore.put({ bar: "good", baz: "bad" }, 1);
+    objectStore.put({ bar: [ "multiEntry", "test" ]}, 2);
+    
+    checkIndex(index1);
+    checkIndex(index2);
+    checkIndex(index3);
+
+    versionTransaction._onabort_ = function(event) {
+        log("Initial upgrade versionchange transaction unexpected abort");
+        done();
+    }
+
+    versionTransaction._oncomplete_ = function(event) {
+        log("Initial upgrade versionchange transaction complete");
+        continueTest1();
+    }
+
+    versionTransaction._onerror_ = function(event) {
+        log("Initial upgrade versionchange transaction unexpected error" + event);
+        done();
+    }
+}
+
+function continueTest1()
+{   
+    var transaction = database.transaction("TestObjectStore", "readwrite");
+    var objectStore = transaction.objectStore("TestObjectStore");
+    var index1 = objectStore.index("TestIndex1");
+    var index2 = objectStore.index("TestIndex2");
+    var index3 = objectStore.index("TestIndex3");
+    
+    objectStore.delete(1)._onsuccess_ = function() {
+       log("Deleted key 1 from objectstore");
+       log("");
+    }
+
+    checkIndex(index1);
+    checkIndex(index2);
+    checkIndex(index3);
+
+    objectStore.clear()._onsuccess_ = function() {
+       log("Cleared objectstore");
+       log("");
+    }
+    
+    checkIndex(index1);
+    checkIndex(index2);
+    checkIndex(index3);
+    
+    objectStore.get(0)._onsuccess_ = function() {
+        log("All done. Moving on to final part");
+        transaction.abort();
+    }
+    
+    transaction._onabort_ = function(event) {
+        log("readwrite transaction aborted");
+        continueTest2();
+    }
+
+    transaction._oncomplete_ = function(event) {
+        log("readwrite transaction unexpected complete");
+        done();
+    }
+
+    transaction._onerror_ = function(event) {
+        log("readwrite transaction unexpected error");
+        done();
+    }
+}
+
+function continueTest2()
+{   
+    var transaction = database.transaction("TestObjectStore", "readonly");
+    var objectStore = transaction.objectStore("TestObjectStore");
+    var index1 = objectStore.index("TestIndex1");
+    var index2 = objectStore.index("TestIndex2");
+    var index3 = objectStore.index("TestIndex3");
+    
+    checkIndex(index1);
+    checkIndex(index2);
+    checkIndex(index3);
+    
+    transaction._onabort_ = function(event) {
+        log("readwrite transaction unexpected abort");
+        done();
+    }
+
+    transaction._oncomplete_ = function(event) {
+        log("readwrite transaction complete");
+        done();
+    }
+
+    transaction._onerror_ = function(event) {
+        log("readwrite transaction unexpected error");
+        done();
+    }
+}
+
+</script>

Added: trunk/LayoutTests/storage/indexeddb/modern/index-3-expected.txt (0 => 192294)


--- trunk/LayoutTests/storage/indexeddb/modern/index-3-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/modern/index-3-expected.txt	2015-11-11 06:07:03 UTC (rev 192294)
@@ -0,0 +1,23 @@
+This test exercises the "unique" constraint of indexes.
+Initial upgrade needed: Old version - 0 New version - 1
+First put success
+Value of 1 is: [object Object]
+Value of 2 is: undefined
+Value of 3 is: undefined
+Count in index 1 is: 1
+Count in index 2 is: 1
+Second put failure
+Value of 1 is: [object Object]
+Value of 2 is: undefined
+Value of 3 is: undefined
+Count in index 1 is: 1
+Count in index 2 is: 1
+Third put failure
+Value of 1 is: [object Object]
+Value of 2 is: undefined
+Value of 3 is: undefined
+Count in index 1 is: 1
+Count in index 2 is: 1
+Initial upgrade versionchange transaction complete
+Done
+

Added: trunk/LayoutTests/storage/indexeddb/modern/index-3.html (0 => 192294)


--- trunk/LayoutTests/storage/indexeddb/modern/index-3.html	                        (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/modern/index-3.html	2015-11-11 06:07:03 UTC (rev 192294)
@@ -0,0 +1,115 @@
+This test exercises the "unique" constraint of indexes.<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 createRequest = window.indexedDB.open("Index3Database", 1);
+var objectStore;
+
+function checkObjectStore()
+{
+    var req1 = objectStore.get(1);
+    req1._onsuccess_ = function() {
+        log("Value of 1 is: " + req1.result);
+    }
+    var req2 = objectStore.get(2);
+    req2._onsuccess_ = function() {
+        log("Value of 2 is: " + req2.result);
+    }
+    var req3 = objectStore.get(3);
+    req3._onsuccess_ = function() {
+        log("Value of 3 is: " + req3.result);
+    }
+}
+
+function checkIndex(index, name)
+{
+    var req = index.count();
+    req._onsuccess_ = function() {
+        log("Count in index " + name + " is: " + req.result);
+    }
+}
+
+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");
+    var i1 = objectStore.createIndex("TestIndex1", "bar", { unique: true });
+    var i2 = objectStore.createIndex("TestIndex2", "bar", { multiEntry: true, unique: true });
+
+    var request1 = objectStore.put({ bar: "good", baz: "bad" }, 1);
+    request1._onsuccess_ = function() {
+        log("First put success");
+    }
+    request1._onerror_ = function() {
+        log("First put unexpected failure");
+        done();
+    }
+    
+    checkObjectStore();
+    checkIndex(i1, 1);
+    checkIndex(i2, 2);
+    
+    var request2 = objectStore.put({ bar: "good", baz: "bad" }, 2);
+    request2._onsuccess_ = function() {
+        log("Second put unexpected success");
+        done();
+    }
+    request2._onerror_ = function(e) {
+        log("Second put failure");
+        e.stopPropagation();
+    }
+    
+    checkObjectStore();
+    checkIndex(i1, 1);
+    checkIndex(i2, 2);
+    
+    var request3 = objectStore.put({ bar: [ "gnarly", "great", "good" ]}, 3);
+    request3._onsuccess_ = function() {
+        log("Third put unexpected success");
+        done();
+    }
+    request3._onerror_ = function(e) {
+        log("Third put failure");
+        e.stopPropagation();
+    }
+    
+    checkObjectStore();
+    checkIndex(i1, 1);
+    checkIndex(i2, 2);
+    
+    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>

Modified: trunk/LayoutTests/storage/indexeddb/modern/index-get-count-basic-expected.txt (192293 => 192294)


--- trunk/LayoutTests/storage/indexeddb/modern/index-get-count-basic-expected.txt	2015-11-11 05:19:56 UTC (rev 192293)
+++ trunk/LayoutTests/storage/indexeddb/modern/index-get-count-basic-expected.txt	2015-11-11 06:07:03 UTC (rev 192294)
@@ -1,9 +1,10 @@
-ALERT: Initial upgrade needed: Old version - 0 New version - 1
-ALERT: get result is: undefined
-ALERT: getKey result is: undefined
-ALERT: count result is: 0
-ALERT: Initial upgrade versionchange transaction complete
-ALERT: Done
 This tests the most basic operation of the IDBIndex methods get(), getKey(), and count().
-It doesn't actually do anything other than exercise the requests themselves because we don't actually index yet.
+Initial upgrade needed: Old version - 0 New version - 1
+get result is: [object Object]
+bar is good
+baz is bad
+getKey result is: foo
+count result is: 1
+Initial upgrade versionchange transaction complete
+Done
 

Modified: trunk/LayoutTests/storage/indexeddb/modern/index-get-count-basic.html (192293 => 192294)


--- trunk/LayoutTests/storage/indexeddb/modern/index-get-count-basic.html	2015-11-11 05:19:56 UTC (rev 192293)
+++ trunk/LayoutTests/storage/indexeddb/modern/index-get-count-basic.html	2015-11-11 06:07:03 UTC (rev 192294)
@@ -1,5 +1,4 @@
 This tests the most basic operation of the IDBIndex methods get(), getKey(), and count().<br>
-It doesn't actually do anything other than exercise the requests themselves because we don't actually index yet.<br>
 <div id="logger"></div>
 <script>
 
@@ -10,12 +9,12 @@
 
 function done()
 {
-    alert("Done");
+    log("Done");
     if (window.testRunner)
         testRunner.notifyDone();
 }
 
-function gol(message)
+function log(message)
 {
     document.getElementById("logger").innerHTML += message + "<br>";
 }
@@ -23,42 +22,44 @@
 var createRequest = window.indexedDB.open("IndexGetCountBasicDatabase", 1);
 
 createRequest._onupgradeneeded_ = function(event) {
-    alert("Initial upgrade needed: Old version - " + event.oldVersion + " New version - " + event.newVersion);
+    log("Initial upgrade needed: Old version - " + event.oldVersion + " New version - " + event.newVersion);
 
     var versionTransaction = createRequest.transaction;
     var database = event.target.result;
     var objectStore = database.createObjectStore("TestObjectStore");
-    var index = objectStore.createIndex("TestIndex", "foo");
+    var index = objectStore.createIndex("TestIndex", "bar");
 
-    objectStore.put("bar", "foo");
+    objectStore.put({ bar: "good", baz: "bad" }, "foo");
     
-    var request1 = index.get("bar");
+    var request1 = index.get("good");
     request1._onsuccess_ = function() {
-        alert("get result is: " + request1.result);
+        log("get result is: " + request1.result);
+        for (n in request1.result)
+            log(n + " is " + request1.result[n]);
     }
 
-    request2 = index.getKey("bar");
+    request2 = index.getKey("good");
     request2._onsuccess_ = function() {
-        alert("getKey result is: " + request2.result);
+        log("getKey result is: " + request2.result);
     }
     
     var request3 = index.count();
     request3._onsuccess_ = function() {
-        alert("count result is: " + request3.result);
+        log("count result is: " + request3.result);
     }
         
     versionTransaction._onabort_ = function(event) {
-        alert("Initial upgrade versionchange transaction unexpected aborted");
+        log("Initial upgrade versionchange transaction unexpected aborted");
         done();
     }
 
     versionTransaction._oncomplete_ = function(event) {
-        alert("Initial upgrade versionchange transaction complete");
+        log("Initial upgrade versionchange transaction complete");
         done();
     }
 
     versionTransaction._onerror_ = function(event) {
-        alert("Initial upgrade versionchange transaction unexpected error" + event);
+        log("Initial upgrade versionchange transaction unexpected error" + event);
         done();
     }
 }

Modified: trunk/Source/WebCore/CMakeLists.txt (192293 => 192294)


--- trunk/Source/WebCore/CMakeLists.txt	2015-11-11 05:19:56 UTC (rev 192293)
+++ trunk/Source/WebCore/CMakeLists.txt	2015-11-11 06:07:03 UTC (rev 192294)
@@ -902,6 +902,8 @@
     Modules/indexeddb/server/IDBConnectionToClient.cpp
     Modules/indexeddb/server/IDBServer.cpp
     Modules/indexeddb/server/IDBServerOperation.cpp
+    Modules/indexeddb/server/IndexValueEntry.cpp
+    Modules/indexeddb/server/IndexValueStore.cpp
     Modules/indexeddb/server/MemoryBackingStoreTransaction.cpp
     Modules/indexeddb/server/MemoryIDBBackingStore.cpp
     Modules/indexeddb/server/MemoryIndex.cpp
@@ -919,6 +921,7 @@
     Modules/indexeddb/shared/IDBResultData.cpp
     Modules/indexeddb/shared/IDBTransactionInfo.cpp
     Modules/indexeddb/shared/InProcessIDBServer.cpp
+    Modules/indexeddb/shared/IndexKey.cpp
 
     Modules/mediacontrols/MediaControlsHost.cpp
 

Modified: trunk/Source/WebCore/ChangeLog (192293 => 192294)


--- trunk/Source/WebCore/ChangeLog	2015-11-11 05:19:56 UTC (rev 192293)
+++ trunk/Source/WebCore/ChangeLog	2015-11-11 06:07:03 UTC (rev 192294)
@@ -1,3 +1,97 @@
+2015-11-10  Brady Eidson  <beid...@apple.com>
+
+        Modern IDB: Make indexes actually index.
+        https://bugs.webkit.org/show_bug.cgi?id=150939
+
+        Reviewed by Alex Christensen.
+
+        Tests: storage/indexeddb/modern/index-1.html
+               storage/indexeddb/modern/index-2.html
+               storage/indexeddb/modern/index-3.html
+
+        * CMakeLists.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+
+        * Modules/indexeddb/IDBKeyData.h:
+        (WebCore::IDBKeyData::hash): Deleted.
+
+        * Modules/indexeddb/IDBKeyRangeData.cpp:
+        (WebCore::IDBKeyRangeData::isExactlyOneKey):
+
+        * Modules/indexeddb/client/IDBTransactionImpl.cpp:
+        (WebCore::IDBClient::IDBTransaction::didGetRecordOnServer):
+
+        * Modules/indexeddb/server/IndexValueEntry.cpp: Copied from Source/WebCore/Modules/indexeddb/server/MemoryIndex.cpp.
+        (WebCore::IDBServer::IndexValueEntry::IndexValueEntry):
+        (WebCore::IDBServer::IndexValueEntry::~IndexValueEntry):
+        (WebCore::IDBServer::IndexValueEntry::addKey):
+        (WebCore::IDBServer::IndexValueEntry::removeKey):
+        (WebCore::IDBServer::IndexValueEntry::getLowest):
+        (WebCore::IDBServer::IndexValueEntry::getCount):
+        * Modules/indexeddb/server/IndexValueEntry.h: Copied from Source/WebCore/Modules/indexeddb/server/MemoryIndex.h.
+
+        * Modules/indexeddb/server/IndexValueStore.cpp: Added.
+        (WebCore::IDBServer::IndexValueStore::IndexValueStore):
+        (WebCore::IDBServer::IndexValueStore::lowestValueForKey):
+        (WebCore::IDBServer::IndexValueStore::countForKey):
+        (WebCore::IDBServer::IndexValueStore::contains):
+        (WebCore::IDBServer::IndexValueStore::addRecord):
+        (WebCore::IDBServer::IndexValueStore::removeRecord):
+        (WebCore::IDBServer::IndexValueStore::removeEntriesWithValueKey):
+        (WebCore::IDBServer::IndexValueStore::lowestKeyWithRecordInRange):
+        * Modules/indexeddb/server/IndexValueStore.h: Copied from Source/WebCore/Modules/indexeddb/server/MemoryIndex.h.
+
+        * Modules/indexeddb/server/MemoryBackingStoreTransaction.cpp:
+        (WebCore::IDBServer::MemoryBackingStoreTransaction::objectStoreCleared):
+        (WebCore::IDBServer::MemoryBackingStoreTransaction::indexCleared):
+        (WebCore::IDBServer::MemoryBackingStoreTransaction::abort):
+        * Modules/indexeddb/server/MemoryBackingStoreTransaction.h:
+
+        * Modules/indexeddb/server/MemoryIDBBackingStore.cpp:
+        (WebCore::IDBServer::MemoryIDBBackingStore::addRecord):
+
+        * Modules/indexeddb/server/MemoryIndex.cpp:
+        (WebCore::IDBServer::MemoryIndex::create):
+        (WebCore::IDBServer::MemoryIndex::MemoryIndex):
+        (WebCore::IDBServer::MemoryIndex::objectStoreCleared):
+        (WebCore::IDBServer::MemoryIndex::replaceIndexValueStore):
+        (WebCore::IDBServer::MemoryIndex::getResultForKeyRange):
+        (WebCore::IDBServer::MemoryIndex::countForKeyRange):
+        (WebCore::IDBServer::MemoryIndex::putIndexKey):
+        (WebCore::IDBServer::MemoryIndex::removeRecord):
+        (WebCore::IDBServer::MemoryIndex::removeEntriesWithValueKey):
+        (WebCore::IDBServer::MemoryIndex::valueForKeyRange): Deleted.
+        * Modules/indexeddb/server/MemoryIndex.h:
+
+        * Modules/indexeddb/server/MemoryObjectStore.cpp:
+        (WebCore::IDBServer::MemoryObjectStore::createIndex):
+        (WebCore::IDBServer::MemoryObjectStore::clear):
+        (WebCore::IDBServer::MemoryObjectStore::deleteRecord):
+        (WebCore::IDBServer::MemoryObjectStore::addRecord):
+        (WebCore::IDBServer::indexVM):
+        (WebCore::IDBServer::indexGlobalExec):
+        (WebCore::IDBServer::MemoryObjectStore::updateIndexesForDeleteRecord):
+        (WebCore::IDBServer::MemoryObjectStore::updateIndexesForPutRecord):
+        (WebCore::IDBServer::MemoryObjectStore::indexValueForKeyRange):
+        * Modules/indexeddb/server/MemoryObjectStore.h:
+        (WebCore::IDBServer::MemoryObjectStore::writeTransaction):
+
+        * Modules/indexeddb/shared/IndexKey.cpp: Copied from Source/WebCore/Modules/indexeddb/IDBKeyRangeData.cpp.
+        (WebCore::IndexKey::IndexKey):
+        (WebCore::IndexKey::isolatedCopy):
+        (WebCore::IndexKey::asOneKey):
+        (WebCore::IndexKey::multiEntry):
+        * Modules/indexeddb/shared/IndexKey.h: Added.
+        (WebCore::IndexKey::isNull):
+
+        * bindings/js/IDBBindingUtilities.cpp:
+        (WebCore::idbValueDataToJSValue):
+        (WebCore::deserializeIDBValueBuffer):
+        (WebCore::idbKeyDataToScriptValue):
+        (WebCore::createKeyPathArray):
+        (WebCore::generateIndexKeyForValue):
+        * bindings/js/IDBBindingUtilities.h:
+
 2015-11-10  Myles C. Maxfield  <mmaxfi...@apple.com>
 
         Move locale information into FontDescription

Modified: trunk/Source/WebCore/Modules/indexeddb/IDBKeyData.h (192293 => 192294)


--- trunk/Source/WebCore/Modules/indexeddb/IDBKeyData.h	2015-11-11 05:19:56 UTC (rev 192293)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBKeyData.h	2015-11-11 06:07:03 UTC (rev 192294)
@@ -122,9 +122,6 @@
             break;
         }
 
-        unsigned targetSize = WTF::roundUpToPowerOfTwo(hashCodes.size());
-        hashCodes.resize(targetSize);
-
         return StringHasher::hashMemory(hashCodes.data(), hashCodes.size() * sizeof(unsigned));
     }
 

Modified: trunk/Source/WebCore/Modules/indexeddb/IDBKeyRangeData.cpp (192293 => 192294)


--- trunk/Source/WebCore/Modules/indexeddb/IDBKeyRangeData.cpp	2015-11-11 05:19:56 UTC (rev 192293)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBKeyRangeData.cpp	2015-11-11 06:07:03 UTC (rev 192294)
@@ -73,7 +73,7 @@
 
 bool IDBKeyRangeData::isExactlyOneKey() const
 {
-    if (isNull || lowerOpen || upperOpen)
+    if (isNull || lowerOpen || upperOpen || !upperKey.isValid() || !lowerKey.isValid())
         return false;
 
     return !lowerKey.compare(upperKey);

Modified: trunk/Source/WebCore/Modules/indexeddb/client/IDBTransactionImpl.cpp (192293 => 192294)


--- trunk/Source/WebCore/Modules/indexeddb/client/IDBTransactionImpl.cpp	2015-11-11 05:19:56 UTC (rev 192293)
+++ trunk/Source/WebCore/Modules/indexeddb/client/IDBTransactionImpl.cpp	2015-11-11 06:07:03 UTC (rev 192294)
@@ -484,9 +484,11 @@
 {
     LOG(IndexedDB, "IDBTransaction::didGetRecordOnServer");
 
+    const IDBGetResult& result = resultData.getResult();
+
     if (request.sourceIndexIdentifier() && request.requestedIndexRecordType() == IndexedDB::IndexRecordType::Key) {
-        if (resultData.resultKey())
-            request.setResult(resultData.resultKey());
+        if (!result.keyData.isNull())
+            request.setResult(&result.keyData);
         else
             request.setResultToUndefined();
     } else {

Copied: trunk/Source/WebCore/Modules/indexeddb/server/IndexValueEntry.cpp (from rev 192293, trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndex.cpp) (0 => 192294)


--- trunk/Source/WebCore/Modules/indexeddb/server/IndexValueEntry.cpp	                        (rev 0)
+++ trunk/Source/WebCore/Modules/indexeddb/server/IndexValueEntry.cpp	2015-11-11 06:07:03 UTC (rev 192294)
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "IndexValueEntry.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+namespace IDBServer {
+
+IndexValueEntry::IndexValueEntry(bool unique)
+    : m_unique(unique)
+{
+    if (m_unique)
+        m_key = nullptr;
+    else
+        m_orderedKeys = new std::set<IDBKeyData>;
+}
+
+IndexValueEntry::~IndexValueEntry()
+{
+    if (m_unique)
+        delete m_key;
+    else
+        delete m_orderedKeys;
+}
+
+void IndexValueEntry::addKey(const IDBKeyData& key)
+{
+    if (m_unique) {
+        delete m_key;
+        m_key = new IDBKeyData(key);
+        return;
+    }
+
+    m_orderedKeys->insert(key);
+}
+
+bool IndexValueEntry::removeKey(const IDBKeyData& key)
+{
+    if (m_unique && m_key && *m_key == key) {
+        delete m_key;
+        m_key = nullptr;
+        return true;
+    }
+
+    m_orderedKeys->erase(key);
+    return m_orderedKeys->empty();
+}
+
+const IDBKeyData* IndexValueEntry::getLowest() const
+{
+    if (m_unique)
+        return m_key;
+
+    if (m_orderedKeys->empty())
+        return nullptr;
+
+    return &(*m_orderedKeys->begin());
+}
+
+uint64_t IndexValueEntry::getCount() const
+{
+    if (m_unique)
+        return m_key ? 1 : 0;
+
+    return m_orderedKeys->size();
+}
+
+} // namespace IDBServer
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)

Copied: trunk/Source/WebCore/Modules/indexeddb/server/IndexValueEntry.h (from rev 192293, trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndex.h) (0 => 192294)


--- trunk/Source/WebCore/Modules/indexeddb/server/IndexValueEntry.h	                        (rev 0)
+++ trunk/Source/WebCore/Modules/indexeddb/server/IndexValueEntry.h	2015-11-11 06:07:03 UTC (rev 192294)
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef IndexValueEntry_h
+#define IndexValueEntry_h
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "IDBKeyData.h"
+#include <set>
+
+namespace WebCore {
+namespace IDBServer {
+
+class IndexValueEntry {
+public:
+    IndexValueEntry(bool unique);
+    ~IndexValueEntry();
+
+    void addKey(const IDBKeyData&);
+
+    // Returns true if the IndexValueEntry is empty after removing the key;
+    bool removeKey(const IDBKeyData&);
+
+    const IDBKeyData* getLowest() const;
+
+    uint64_t getCount() const;
+
+private:
+    union {
+        std::set<IDBKeyData>* m_orderedKeys;
+        IDBKeyData* m_key;
+    };
+
+    bool m_unique;
+};
+
+} // namespace IDBServer
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
+#endif // IndexValueEntry_h

Added: trunk/Source/WebCore/Modules/indexeddb/server/IndexValueStore.cpp (0 => 192294)


--- trunk/Source/WebCore/Modules/indexeddb/server/IndexValueStore.cpp	                        (rev 0)
+++ trunk/Source/WebCore/Modules/indexeddb/server/IndexValueStore.cpp	2015-11-11 06:07:03 UTC (rev 192294)
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "IndexValueStore.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "IDBError.h"
+#include "IDBKeyRangeData.h"
+
+namespace WebCore {
+namespace IDBServer {
+
+IndexValueStore::IndexValueStore(bool unique)
+    : m_unique(unique)
+{
+}
+
+const IDBKeyData* IndexValueStore::lowestValueForKey(const IDBKeyData& key) const
+{
+    const auto& entry = m_records.get(key);
+    if (!entry)
+        return nullptr;
+
+    return entry->getLowest();
+}
+
+uint64_t IndexValueStore::countForKey(const IDBKeyData& key) const
+{
+    const auto& entry = m_records.get(key);
+    if (!entry)
+        return 0;
+
+    return entry->getCount();
+}
+
+bool IndexValueStore::contains(const IDBKeyData& key) const
+{
+    const auto& entry = m_records.get(key);
+    if (!entry)
+        return false;
+
+    ASSERT(entry->getCount());
+
+    return true;
+}
+
+IDBError IndexValueStore::addRecord(const IDBKeyData& indexKey, const IDBKeyData& valueKey)
+{
+    auto result = m_records.add(indexKey, nullptr);
+
+    if (!result.isNewEntry && m_unique)
+        return IDBError(IDBExceptionCode::ConstraintError);
+
+    if (result.isNewEntry)
+        result.iterator->value = std::make_unique<IndexValueEntry>(m_unique);
+
+    result.iterator->value->addKey(valueKey);
+    m_orderedKeys.insert(indexKey);
+
+    return { };
+}
+
+void IndexValueStore::removeRecord(const IDBKeyData& indexKey, const IDBKeyData& valueKey)
+{
+    auto iterator = m_records.find(indexKey);
+    if (!iterator->value)
+        return;
+
+    if (iterator->value->removeKey(valueKey))
+        m_records.remove(iterator);
+}
+
+void IndexValueStore::removeEntriesWithValueKey(const IDBKeyData& valueKey)
+{
+    HashSet<IDBKeyData*> entryKeysToRemove;
+
+    for (auto& entry : m_records) {
+        if (entry.value->removeKey(valueKey))
+            entryKeysToRemove.add(&entry.key);
+    }
+
+    for (auto* entry : entryKeysToRemove) {
+        m_orderedKeys.erase(*entry);
+        m_records.remove(*entry);
+    }
+}
+
+IDBKeyData IndexValueStore::lowestKeyWithRecordInRange(const IDBKeyRangeData& range) const
+{
+    if (range.isExactlyOneKey())
+        return m_records.contains(range.lowerKey) ? range.lowerKey : IDBKeyData();
+
+    auto lowestInRange = m_orderedKeys.lower_bound(range.lowerKey);
+
+    if (lowestInRange == m_orderedKeys.end())
+        return { };
+
+    if (range.lowerOpen && *lowestInRange == range.lowerKey)
+        ++lowestInRange;
+
+    if (lowestInRange == m_orderedKeys.end())
+        return { };
+
+    if (!range.upperKey.isNull()) {
+        if (lowestInRange->compare(range.upperKey) > 0)
+            return { };
+        if (range.upperOpen && *lowestInRange == range.upperKey)
+            return { };
+    }
+
+    return *lowestInRange;
+}
+
+} // namespace IDBServer
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)

Copied: trunk/Source/WebCore/Modules/indexeddb/server/IndexValueStore.h (from rev 192293, trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndex.h) (0 => 192294)


--- trunk/Source/WebCore/Modules/indexeddb/server/IndexValueStore.h	                        (rev 0)
+++ trunk/Source/WebCore/Modules/indexeddb/server/IndexValueStore.h	2015-11-11 06:07:03 UTC (rev 192294)
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef IndexValueStore_h
+#define IndexValueStore_h
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "IDBKeyData.h"
+#include "IndexValueEntry.h"
+#include <set>
+#include <wtf/HashMap.h>
+
+namespace WebCore {
+
+class IDBError;
+
+struct IDBKeyRangeData;
+
+namespace IDBServer {
+
+typedef HashMap<IDBKeyData, std::unique_ptr<IndexValueEntry>, IDBKeyDataHash, IDBKeyDataHashTraits> IndexKeyValueMap;
+
+class IndexValueStore {
+public:
+    IndexValueStore(bool unique);
+
+    const IDBKeyData* lowestValueForKey(const IDBKeyData&) const;
+    uint64_t countForKey(const IDBKeyData&) const;
+    IDBKeyData lowestKeyWithRecordInRange(const IDBKeyRangeData&) const;
+    bool contains(const IDBKeyData&) const;
+
+    IDBError addRecord(const IDBKeyData& indexKey, const IDBKeyData& valueKey);
+    void removeRecord(const IDBKeyData& indexKey, const IDBKeyData& valueKey);
+
+    void removeEntriesWithValueKey(const IDBKeyData& valueKey);
+
+private:
+    IndexKeyValueMap m_records;
+    std::set<IDBKeyData> m_orderedKeys;
+    
+    bool m_unique;
+};
+
+} // namespace IDBServer
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
+#endif // IndexValueStore_h

Modified: trunk/Source/WebCore/Modules/indexeddb/server/MemoryBackingStoreTransaction.cpp (192293 => 192294)


--- trunk/Source/WebCore/Modules/indexeddb/server/MemoryBackingStoreTransaction.cpp	2015-11-11 05:19:56 UTC (rev 192293)
+++ trunk/Source/WebCore/Modules/indexeddb/server/MemoryBackingStoreTransaction.cpp	2015-11-11 06:07:03 UTC (rev 192294)
@@ -117,21 +117,24 @@
 
     auto addResult = m_clearedKeyValueMaps.add(&objectStore, nullptr);
 
-    // If this object store has already been cleared during this transaction, we don't need to remember this clearing.
+    // If this object store has already been cleared during this transaction, we shouldn't remember this clearing.
     if (!addResult.isNewEntry)
         return;
 
-    // If values had previously been changed during this transaction, fold those changes back into the
-    // cleared key-value map now, so we have exactly the map that will need to be restored if the transaction is aborted.
-    auto originalValues = m_originalValues.take(&objectStore);
-    if (originalValues) {
-        for (auto iterator : *originalValues)
-            keyValueMap->set(iterator.key, iterator.value);
-    }
-
     addResult.iterator->value = WTF::move(keyValueMap);
 }
 
+void MemoryBackingStoreTransaction::indexCleared(MemoryIndex& index, std::unique_ptr<IndexValueStore>&& valueStore)
+{
+    auto addResult = m_clearedIndexValueStores.add(&index, nullptr);
+
+    // If this index has already been cleared during this transaction, we shouldn't remember this clearing.
+    if (!addResult.isNewEntry)
+        return;
+
+    addResult.iterator->value = WTF::move(valueStore);
+}
+
 void MemoryBackingStoreTransaction::recordValueChanged(MemoryObjectStore& objectStore, const IDBKeyData& key, ThreadSafeDataBuffer* value)
 {
     ASSERT(m_objectStores.contains(&objectStore));
@@ -182,15 +185,19 @@
         m_backingStore.setDatabaseInfo(*m_originalDatabaseInfo);
     }
 
+    // Restore cleared index value stores before we re-insert values into object stores
+    // because inserting those values will regenerate the appropriate index values.
+    for (auto& iterator : m_clearedIndexValueStores)
+        iterator.key->replaceIndexValueStore(WTF::move(iterator.value));
+    m_clearedIndexValueStores.clear();
+    
     for (auto objectStore : m_objectStores) {
         ASSERT(m_originalKeyGenerators.contains(objectStore));
         objectStore->setKeyGeneratorValue(m_originalKeyGenerators.get(objectStore));
 
         auto clearedKeyValueMap = m_clearedKeyValueMaps.take(objectStore);
-        if (clearedKeyValueMap) {
+        if (clearedKeyValueMap)
             objectStore->replaceKeyValueStore(WTF::move(clearedKeyValueMap));
-            continue;
-        }
 
         auto keyValueMap = m_originalValues.take(objectStore);
         if (!keyValueMap)

Modified: trunk/Source/WebCore/Modules/indexeddb/server/MemoryBackingStoreTransaction.h (192293 => 192294)


--- trunk/Source/WebCore/Modules/indexeddb/server/MemoryBackingStoreTransaction.h	2015-11-11 05:19:56 UTC (rev 192293)
+++ trunk/Source/WebCore/Modules/indexeddb/server/MemoryBackingStoreTransaction.h	2015-11-11 06:07:03 UTC (rev 192294)
@@ -31,6 +31,7 @@
 #include "IDBDatabaseInfo.h"
 #include "IDBKeyData.h"
 #include "IDBTransactionInfo.h"
+#include "IndexValueStore.h"
 #include "ThreadSafeDataBuffer.h"
 #include <wtf/HashMap.h>
 #include <wtf/HashSet.h>
@@ -63,6 +64,7 @@
     void recordValueChanged(MemoryObjectStore&, const IDBKeyData&, ThreadSafeDataBuffer*);
     void objectStoreDeleted(std::unique_ptr<MemoryObjectStore>);
     void objectStoreCleared(MemoryObjectStore&, std::unique_ptr<KeyValueMap>&&);
+    void indexCleared(MemoryIndex&, std::unique_ptr<IndexValueStore>&&);
 
     void addNewIndex(MemoryIndex&);
     void addExistingIndex(MemoryIndex&);
@@ -90,8 +92,10 @@
 
     HashMap<MemoryObjectStore*, uint64_t> m_originalKeyGenerators;
     HashMap<String, std::unique_ptr<MemoryObjectStore>> m_deletedObjectStores;
+    HashMap<String, std::unique_ptr<MemoryIndex>> m_deletedIndexes;
     HashMap<MemoryObjectStore*, std::unique_ptr<KeyValueMap>> m_originalValues;
     HashMap<MemoryObjectStore*, std::unique_ptr<KeyValueMap>> m_clearedKeyValueMaps;
+    HashMap<MemoryIndex*, std::unique_ptr<IndexValueStore>> m_clearedIndexValueStores;
 };
 
 } // namespace IDBServer

Modified: trunk/Source/WebCore/Modules/indexeddb/server/MemoryIDBBackingStore.cpp (192293 => 192294)


--- trunk/Source/WebCore/Modules/indexeddb/server/MemoryIDBBackingStore.cpp	2015-11-11 05:19:56 UTC (rev 192293)
+++ trunk/Source/WebCore/Modules/indexeddb/server/MemoryIDBBackingStore.cpp	2015-11-11 06:07:03 UTC (rev 192294)
@@ -258,8 +258,7 @@
     if (!objectStore)
         return IDBError(IDBExceptionCode::Unknown, WTF::ASCIILiteral("No backing store object store found to put record"));
 
-    objectStore->addRecord(*transaction, keyData, value);
-    return IDBError();
+    return objectStore->addRecord(*transaction, keyData, value);
 }
 
 IDBError MemoryIDBBackingStore::getRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyRangeData& range, ThreadSafeDataBuffer& outValue)

Modified: trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndex.cpp (192293 => 192294)


--- trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndex.cpp	2015-11-11 05:19:56 UTC (rev 192293)
+++ trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndex.cpp	2015-11-11 06:07:03 UTC (rev 192294)
@@ -28,18 +28,26 @@
 
 #if ENABLE(INDEXED_DATABASE)
 
+#include "IDBError.h"
 #include "IDBGetResult.h"
+#include "IDBKeyRangeData.h"
+#include "IndexKey.h"
+#include "Logging.h"
+#include "MemoryBackingStoreTransaction.h"
+#include "MemoryObjectStore.h"
+#include "ThreadSafeDataBuffer.h"
 
 namespace WebCore {
 namespace IDBServer {
 
-std::unique_ptr<MemoryIndex> MemoryIndex::create(const IDBIndexInfo& info)
+std::unique_ptr<MemoryIndex> MemoryIndex::create(const IDBIndexInfo& info, MemoryObjectStore& objectStore)
 {
-    return std::make_unique<MemoryIndex>(info);
+    return std::make_unique<MemoryIndex>(info, objectStore);
 }
 
-MemoryIndex::MemoryIndex(const IDBIndexInfo& info)
+MemoryIndex::MemoryIndex(const IDBIndexInfo& info, MemoryObjectStore& objectStore)
     : m_info(info)
+    , m_objectStore(objectStore)
 {
 }
 
@@ -47,20 +55,125 @@
 {
 }
 
-IDBGetResult MemoryIndex::valueForKeyRange(IndexedDB::IndexRecordType, const IDBKeyRangeData&) const
+void MemoryIndex::objectStoreCleared()
 {
-    // FIXME: Once indexes actually index, we'll return something real.
-    // https://bugs.webkit.org/show_bug.cgi?id=150939
+    auto transaction = m_objectStore.writeTransaction();
+    ASSERT(transaction);
+
+    transaction->indexCleared(*this, WTF::move(m_records));
+}
+
+void MemoryIndex::replaceIndexValueStore(std::unique_ptr<IndexValueStore>&& valueStore)
+{
+    ASSERT(m_objectStore.writeTransaction());
+    ASSERT(m_objectStore.writeTransaction()->isAborting());
+
+    m_records = WTF::move(valueStore);
+}
+
+IDBGetResult MemoryIndex::getResultForKeyRange(IndexedDB::IndexRecordType type, const IDBKeyRangeData& range) const
+{
+    LOG(IndexedDB, "MemoryIndex::getResultForKeyRange");
+
+    if (!m_records)
+        return { };
+
+    IDBKeyData keyToLookFor;
+    if (range.isExactlyOneKey())
+        keyToLookFor = range.lowerKey;
+    else
+        keyToLookFor = m_records->lowestKeyWithRecordInRange(range);
+
+    if (keyToLookFor.isNull())
+        return { };
+
+    const IDBKeyData* keyValue = m_records->lowestValueForKey(keyToLookFor);
+
+    if (!keyValue)
+        return { };
+
+    return type == IndexedDB::IndexRecordType::Key ? IDBGetResult(*keyValue) : IDBGetResult(m_objectStore.valueForKeyRange(*keyValue));
+}
+
+uint64_t MemoryIndex::countForKeyRange(const IDBKeyRangeData& inRange)
+{
+    LOG(IndexedDB, "MemoryIndex::countForKeyRange");
+
+    if (!m_records)
+        return 0;
+
+    uint64_t count = 0;
+    IDBKeyRangeData range = inRange;
+    while (true) {
+        auto key = m_records->lowestKeyWithRecordInRange(range);
+        if (key.isNull())
+            break;
+
+        count += m_records->countForKey(key);
+
+        range.lowerKey = key;
+        range.lowerOpen = true;
+    }
+
+    return count;
+}
+
+IDBError MemoryIndex::putIndexKey(const IDBKeyData& valueKey, const IndexKey& indexKey)
+{
+    LOG(IndexedDB, "MemoryIndex::provisionalPutIndexKey");
+
+    if (!m_records)
+        m_records = std::make_unique<IndexValueStore>(m_info.unique());
+
+    if (!m_info.multiEntry()) {
+        IDBKeyData key = indexKey.asOneKey();
+        return m_records->addRecord(key, valueKey);
+    }
+
+    Vector<IDBKeyData> keys = indexKey.multiEntry();
+
+    if (m_info.unique()) {
+        for (auto& key : keys) {
+            if (m_records->contains(key))
+                return IDBError(IDBExceptionCode::ConstraintError);
+        }
+    }
+
+    for (auto& key : keys) {
+        auto error = m_records->addRecord(key, valueKey);
+        ASSERT_UNUSED(error, error.isNull());
+    }
+
     return { };
 }
 
-uint64_t MemoryIndex::countForKeyRange(const IDBKeyRangeData&)
+void MemoryIndex::removeRecord(const IDBKeyData& valueKey, const IndexKey& indexKey)
 {
-    // FIXME: Once indexes actually index, we'll return something real.
-    // https://bugs.webkit.org/show_bug.cgi?id=150939
-    return 0;
+    LOG(IndexedDB, "MemoryIndex::removeRecord");
+
+    ASSERT(m_records);
+
+    if (!m_info.multiEntry()) {
+        IDBKeyData key = indexKey.asOneKey();
+        m_records->removeRecord(key, valueKey);
+        return;
+    }
+
+    Vector<IDBKeyData> keys = indexKey.multiEntry();
+    for (auto& key : keys)
+        m_records->removeRecord(key, valueKey);
 }
 
+void MemoryIndex::removeEntriesWithValueKey(const IDBKeyData& valueKey)
+{
+    LOG(IndexedDB, "MemoryIndex::removeEntriesWithValueKey");
+
+    if (!m_records)
+        return;
+
+    m_records->removeEntriesWithValueKey(valueKey);
+}
+
 } // namespace IDBServer
 } // namespace WebCore
 

Modified: trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndex.h (192293 => 192294)


--- trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndex.h	2015-11-11 05:19:56 UTC (rev 192293)
+++ trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndex.h	2015-11-11 06:07:03 UTC (rev 192294)
@@ -30,9 +30,15 @@
 
 #include "IDBGetResult.h"
 #include "IDBIndexInfo.h"
+#include "IDBKeyData.h"
+#include "IndexValueStore.h"
+#include <set>
+#include <wtf/HashMap.h>
 
 namespace WebCore {
 
+class IDBError;
+class IndexKey;
 class ThreadSafeDataBuffer;
 
 struct IDBKeyRangeData;
@@ -43,22 +49,38 @@
 
 namespace IDBServer {
 
+class MemoryBackingStoreTransaction;
+class MemoryObjectStore;
+
 class MemoryIndex {
-    friend std::unique_ptr<MemoryIndex> std::make_unique<MemoryIndex>(const WebCore::IDBIndexInfo&);
+    friend std::unique_ptr<MemoryIndex> std::make_unique<MemoryIndex>(const WebCore::IDBIndexInfo&, WebCore::IDBServer::MemoryObjectStore&);
 public:
-    static std::unique_ptr<MemoryIndex> create(const IDBIndexInfo&);
+    static std::unique_ptr<MemoryIndex> create(const IDBIndexInfo&, MemoryObjectStore&);
 
     ~MemoryIndex();
 
     const IDBIndexInfo& info() const { return m_info; }
 
-    IDBGetResult valueForKeyRange(IndexedDB::IndexRecordType, const IDBKeyRangeData&) const;
+    IDBGetResult getResultForKeyRange(IndexedDB::IndexRecordType, const IDBKeyRangeData&) const;
     uint64_t countForKeyRange(const IDBKeyRangeData&);
-    
+
+    IDBError putIndexKey(const IDBKeyData&, const IndexKey&);
+
+    void removeEntriesWithValueKey(const IDBKeyData&);
+    void removeRecord(const IDBKeyData&, const IndexKey&);
+
+    void objectStoreCleared();
+    void replaceIndexValueStore(std::unique_ptr<IndexValueStore>&&);
+
 private:
-    MemoryIndex(const IDBIndexInfo&);
+    MemoryIndex(const IDBIndexInfo&, MemoryObjectStore&);
 
+    uint64_t recordCountForKey(const IDBKeyData&) const;
+    
     IDBIndexInfo m_info;
+    MemoryObjectStore& m_objectStore;
+
+    std::unique_ptr<IndexValueStore> m_records;
 };
 
 } // namespace IDBServer

Modified: trunk/Source/WebCore/Modules/indexeddb/server/MemoryObjectStore.cpp (192293 => 192294)


--- trunk/Source/WebCore/Modules/indexeddb/server/MemoryObjectStore.cpp	2015-11-11 05:19:56 UTC (rev 192293)
+++ trunk/Source/WebCore/Modules/indexeddb/server/MemoryObjectStore.cpp	2015-11-11 06:07:03 UTC (rev 192294)
@@ -28,12 +28,18 @@
 
 #if ENABLE(INDEXED_DATABASE)
 
+#include "IDBBindingUtilities.h"
 #include "IDBDatabaseException.h"
 #include "IDBError.h"
 #include "IDBKeyRangeData.h"
+#include "IndexKey.h"
 #include "Logging.h"
 #include "MemoryBackingStoreTransaction.h"
 
+#include <wtf/NeverDestroyed.h>
+
+using namespace JSC;
+
 namespace WebCore {
 namespace IDBServer {
 
@@ -76,7 +82,7 @@
         return IDBError(IDBExceptionCode::ConstraintError);
 
     ASSERT(!m_indexesByIdentifier.contains(info.identifier()));
-    auto index = MemoryIndex::create(info);
+    auto index = MemoryIndex::create(info, *this);
 
     m_info.addExistingIndex(info);
 
@@ -100,6 +106,8 @@
     ASSERT(m_writeTransaction);
 
     m_writeTransaction->objectStoreCleared(*this, WTF::move(m_keyValueStore));
+    for (auto& index : m_indexesByIdentifier.values())
+        index->objectStoreCleared();
 }
 
 void MemoryObjectStore::replaceKeyValueStore(std::unique_ptr<KeyValueMap>&& store)
@@ -132,6 +140,8 @@
     m_writeTransaction->recordValueChanged(*this, key, &iterator->value);
     m_keyValueStore->remove(iterator);
     m_orderedKeys->erase(key);
+
+    updateIndexesForDeleteRecord(key);
 }
 
 void MemoryObjectStore::deleteRange(const IDBKeyRangeData& inputRange)
@@ -158,7 +168,7 @@
     }
 }
 
-void MemoryObjectStore::addRecord(MemoryBackingStoreTransaction& transaction, const IDBKeyData& keyData, const ThreadSafeDataBuffer& value)
+IDBError MemoryObjectStore::addRecord(MemoryBackingStoreTransaction& transaction, const IDBKeyData& keyData, const ThreadSafeDataBuffer& value)
 {
     LOG(IndexedDB, "MemoryObjectStore::addRecord");
 
@@ -173,11 +183,82 @@
         m_orderedKeys = std::make_unique<std::set<IDBKeyData>>();
     }
 
-    auto result = m_keyValueStore->set(keyData, value);
-    if (result.isNewEntry)
-        m_orderedKeys->insert(keyData);
+    auto mapResult = m_keyValueStore->set(keyData, value);
+    ASSERT(mapResult.isNewEntry);
+    auto listResult = m_orderedKeys->insert(keyData);
+    ASSERT(listResult.second);
+
+    // If there was an error indexing this addition, then revert it.
+    auto error = updateIndexesForPutRecord(keyData, value);
+    if (!error.isNull()) {
+        m_keyValueStore->remove(mapResult.iterator);
+        m_orderedKeys->erase(listResult.first);
+    }
+
+    return error;
 }
 
+static VM& indexVM()
+{
+    ASSERT(!isMainThread());
+    static NeverDestroyed<RefPtr<VM>> vm = VM::create();
+    return *vm.get();
+}
+
+static ExecState& indexGlobalExec()
+{
+    ASSERT(!isMainThread());
+    static NeverDestroyed<Strong<JSGlobalObject>> globalObject;
+    static bool initialized = false;
+    if (!initialized) {
+        globalObject.get().set(indexVM(), JSGlobalObject::create(indexVM(), JSGlobalObject::createStructure(indexVM(), jsNull())));
+        initialized = true;
+    }
+
+    RELEASE_ASSERT(globalObject.get()->globalExec());
+    return *globalObject.get()->globalExec();
+}
+
+void MemoryObjectStore::updateIndexesForDeleteRecord(const IDBKeyData& value)
+{
+    for (auto* index : m_indexesByName.values())
+        index->removeEntriesWithValueKey(value);
+}
+
+IDBError MemoryObjectStore::updateIndexesForPutRecord(const IDBKeyData& key, const ThreadSafeDataBuffer& value)
+{
+    JSLockHolder locker(indexVM());
+
+    auto jsValue = idbValueDataToJSValue(indexGlobalExec(), value);
+    if (jsValue.isUndefinedOrNull())
+        return { };
+
+    IDBError error;
+    Vector<std::pair<MemoryIndex*, IndexKey>> changedIndexRecords;
+
+    for (auto* index : m_indexesByName.values()) {
+        IndexKey indexKey;
+        generateIndexKeyForValue(indexGlobalExec(), index->info(), jsValue, indexKey);
+
+        if (indexKey.isNull())
+            continue;
+
+        error = index->putIndexKey(key, indexKey);
+        if (!error.isNull())
+            break;
+
+        changedIndexRecords.append(std::make_pair(index, indexKey));
+    }
+
+    // If any of the index puts failed, revert all of the ones that went through.
+    if (!error.isNull()) {
+        for (auto& record : changedIndexRecords)
+            record.first->removeRecord(key, record.second);
+    }
+
+    return error;
+}
+
 uint64_t MemoryObjectStore::countForKeyRange(uint64_t indexIdentifier, const IDBKeyRangeData& inRange) const
 {
     LOG(IndexedDB, "MemoryObjectStore::countForKeyRange");
@@ -224,7 +305,7 @@
 
     auto* index = m_indexesByIdentifier.get(indexIdentifier);
     ASSERT(index);
-    return index->valueForKeyRange(recordType, range);
+    return index->getResultForKeyRange(recordType, range);
 }
 
 IDBKeyData MemoryObjectStore::lowestKeyWithRecordInRange(const IDBKeyRangeData& keyRangeData) const

Modified: trunk/Source/WebCore/Modules/indexeddb/server/MemoryObjectStore.h (192293 => 192294)


--- trunk/Source/WebCore/Modules/indexeddb/server/MemoryObjectStore.h	2015-11-11 05:19:56 UTC (rev 192293)
+++ trunk/Source/WebCore/Modules/indexeddb/server/MemoryObjectStore.h	2015-11-11 06:07:03 UTC (rev 192294)
@@ -61,13 +61,14 @@
 
     void writeTransactionStarted(MemoryBackingStoreTransaction&);
     void writeTransactionFinished(MemoryBackingStoreTransaction&);
+    MemoryBackingStoreTransaction* writeTransaction() { return m_writeTransaction; }
 
     IDBError createIndex(MemoryBackingStoreTransaction&, const IDBIndexInfo&);
 
     bool containsRecord(const IDBKeyData&);
     void deleteRecord(const IDBKeyData&);
     void deleteRange(const IDBKeyRangeData&);
-    void addRecord(MemoryBackingStoreTransaction&, const IDBKeyData&, const ThreadSafeDataBuffer& value);
+    IDBError addRecord(MemoryBackingStoreTransaction&, const IDBKeyData&, const ThreadSafeDataBuffer& value);
 
     uint64_t currentKeyGeneratorValue() const { return m_keyGeneratorValue; }
     void setKeyGeneratorValue(uint64_t value) { m_keyGeneratorValue = value; }
@@ -86,6 +87,9 @@
 
     IDBKeyData lowestKeyWithRecordInRange(const IDBKeyRangeData&) const;
 
+    IDBError updateIndexesForPutRecord(const IDBKeyData&, const ThreadSafeDataBuffer& value);
+    void updateIndexesForDeleteRecord(const IDBKeyData& value);
+
     IDBObjectStoreInfo m_info;
 
     MemoryBackingStoreTransaction* m_writeTransaction { nullptr };

Copied: trunk/Source/WebCore/Modules/indexeddb/shared/IndexKey.cpp (from rev 192293, trunk/Source/WebCore/Modules/indexeddb/IDBKeyRangeData.cpp) (0 => 192294)


--- trunk/Source/WebCore/Modules/indexeddb/shared/IndexKey.cpp	                        (rev 0)
+++ trunk/Source/WebCore/Modules/indexeddb/shared/IndexKey.cpp	2015-11-11 06:07:03 UTC (rev 192294)
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "IndexKey.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+IndexKey::IndexKey()
+{
+}
+
+IndexKey::IndexKey(Vector<IDBKeyData>&& keys)
+{
+    m_keys.swap(keys);
+}
+
+IndexKey IndexKey::isolatedCopy() const
+{
+    Vector<IDBKeyData> keys;
+    keys.reserveInitialCapacity(m_keys.size());
+    for (auto& key : m_keys)
+        keys.uncheckedAppend(key.isolatedCopy());
+
+    return { WTF::move(keys) };
+}
+
+IDBKeyData IndexKey::asOneKey() const
+{
+    if (m_keys.isEmpty())
+        return { };
+
+    if (m_keys.size() == 1)
+        return m_keys[0];
+
+    IDBKeyData result;
+    result.setArrayValue(m_keys);
+    return result;
+}
+
+Vector<IDBKeyData> IndexKey::multiEntry() const
+{
+    Vector<IDBKeyData> multiEntry;
+    for (auto& key : m_keys) {
+        if (!key.isValid())
+            continue;
+
+        bool skip = false;
+        for (auto& otherKey : multiEntry) {
+            if (key == otherKey) {
+                skip = true;
+                break;
+            }
+        }
+
+        if (!skip)
+            multiEntry.append(key);
+    }
+
+    return multiEntry;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)

Added: trunk/Source/WebCore/Modules/indexeddb/shared/IndexKey.h (0 => 192294)


--- trunk/Source/WebCore/Modules/indexeddb/shared/IndexKey.h	                        (rev 0)
+++ trunk/Source/WebCore/Modules/indexeddb/shared/IndexKey.h	2015-11-11 06:07:03 UTC (rev 192294)
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef IndexKey_h
+#define IndexKey_h
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "IDBKeyData.h"
+#include <wtf/HashMap.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class IndexKey {
+public:
+    IndexKey();
+    IndexKey(Vector<IDBKeyData>&&);
+
+    IndexKey isolatedCopy() const;
+
+    IDBKeyData asOneKey() const;
+    Vector<IDBKeyData> multiEntry() const;
+
+    bool isNull() const { return m_keys.isEmpty(); }
+
+private:
+    Vector<IDBKeyData> m_keys;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
+#endif // IndexKey_h

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (192293 => 192294)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2015-11-11 05:19:56 UTC (rev 192293)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2015-11-11 06:07:03 UTC (rev 192294)
@@ -2047,6 +2047,10 @@
 		516D7D701BB5F0BD00AF7C77 /* IDBConnectionToServerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 5185FCBD1BB5CB770012898F /* IDBConnectionToServerDelegate.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		516D7D711BB5F0BD00AF7C77 /* IDBConnectionToClient.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 516D7D6D1BB5F06500AF7C77 /* IDBConnectionToClient.cpp */; };
 		516D7D721BB5F0BD00AF7C77 /* IDBConnectionToClientDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 516D7D6E1BB5F06500AF7C77 /* IDBConnectionToClientDelegate.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		517138EF1BED1D1A000D5F01 /* IndexKey.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 517138ED1BED1D17000D5F01 /* IndexKey.cpp */; };
+		517138F01BED1D1A000D5F01 /* IndexKey.h in Headers */ = {isa = PBXBuildFile; fileRef = 517138EE1BED1D17000D5F01 /* IndexKey.h */; };
+		517138F71BF128BB000D5F01 /* IndexValueStore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 517138F51BF12262000D5F01 /* IndexValueStore.cpp */; };
+		517138F81BF128BB000D5F01 /* IndexValueStore.h in Headers */ = {isa = PBXBuildFile; fileRef = 517138F61BF12262000D5F01 /* IndexValueStore.h */; };
 		51741D0F0B07259A00ED442C /* BackForwardClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 51741D0B0B07259A00ED442C /* BackForwardClient.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		51741D110B07259A00ED442C /* HistoryItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 51741D0D0B07259A00ED442C /* HistoryItem.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		51741D120B07259A00ED442C /* HistoryItem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 51741D0E0B07259A00ED442C /* HistoryItem.cpp */; };
@@ -2211,6 +2215,8 @@
 		51EC92650CE90DD400F90308 /* JSCustomSQLStatementErrorCallback.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 51EC925D0CE90DD400F90308 /* JSCustomSQLStatementErrorCallback.cpp */; };
 		51EE7B381AA50B0500F92B21 /* ResourceLoadInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 51EE7B371AA50B0500F92B21 /* ResourceLoadInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		51EE7B3A1AA5123100F92B21 /* ResourceLoadInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 51EE7B391AA5123100F92B21 /* ResourceLoadInfo.cpp */; };
+		51EEAA731BEFFAB100218008 /* IndexValueEntry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 51EEAA711BEFFA7900218008 /* IndexValueEntry.cpp */; };
+		51EEAA741BEFFAB100218008 /* IndexValueEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = 51EEAA721BEFFA7900218008 /* IndexValueEntry.h */; };
 		51F41A681BA73B5B002E053B /* IDBCallbacks.h in Headers */ = {isa = PBXBuildFile; fileRef = 51F41A481BA73B2C002E053B /* IDBCallbacks.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		51F41A691BA73B5B002E053B /* IDBCursorBackend.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 51F41A491BA73B2C002E053B /* IDBCursorBackend.cpp */; };
 		51F41A6A1BA73B5B002E053B /* IDBCursorBackend.h in Headers */ = {isa = PBXBuildFile; fileRef = 51F41A4A1BA73B2C002E053B /* IDBCursorBackend.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -9497,6 +9503,10 @@
 		516C62241950E2B900337E75 /* JSGamepadEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSGamepadEvent.h; sourceTree = "<group>"; };
 		516D7D6D1BB5F06500AF7C77 /* IDBConnectionToClient.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IDBConnectionToClient.cpp; sourceTree = "<group>"; };
 		516D7D6E1BB5F06500AF7C77 /* IDBConnectionToClientDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IDBConnectionToClientDelegate.h; sourceTree = "<group>"; };
+		517138ED1BED1D17000D5F01 /* IndexKey.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IndexKey.cpp; sourceTree = "<group>"; };
+		517138EE1BED1D17000D5F01 /* IndexKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IndexKey.h; sourceTree = "<group>"; };
+		517138F51BF12262000D5F01 /* IndexValueStore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IndexValueStore.cpp; sourceTree = "<group>"; };
+		517138F61BF12262000D5F01 /* IndexValueStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IndexValueStore.h; sourceTree = "<group>"; };
 		51741D0B0B07259A00ED442C /* BackForwardClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BackForwardClient.h; sourceTree = "<group>"; };
 		51741D0D0B07259A00ED442C /* HistoryItem.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = HistoryItem.h; sourceTree = "<group>"; };
 		51741D0E0B07259A00ED442C /* HistoryItem.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = HistoryItem.cpp; sourceTree = "<group>"; };
@@ -9654,6 +9664,8 @@
 		51EC925D0CE90DD400F90308 /* JSCustomSQLStatementErrorCallback.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSCustomSQLStatementErrorCallback.cpp; sourceTree = "<group>"; };
 		51EE7B371AA50B0500F92B21 /* ResourceLoadInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ResourceLoadInfo.h; sourceTree = "<group>"; };
 		51EE7B391AA5123100F92B21 /* ResourceLoadInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ResourceLoadInfo.cpp; sourceTree = "<group>"; };
+		51EEAA711BEFFA7900218008 /* IndexValueEntry.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IndexValueEntry.cpp; sourceTree = "<group>"; };
+		51EEAA721BEFFA7900218008 /* IndexValueEntry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IndexValueEntry.h; sourceTree = "<group>"; };
 		51F41A481BA73B2C002E053B /* IDBCallbacks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IDBCallbacks.h; sourceTree = "<group>"; };
 		51F41A491BA73B2C002E053B /* IDBCursorBackend.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IDBCursorBackend.cpp; sourceTree = "<group>"; };
 		51F41A4A1BA73B2C002E053B /* IDBCursorBackend.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IDBCursorBackend.h; sourceTree = "<group>"; };
@@ -16878,6 +16890,8 @@
 				5198F7AB1BBDD3E300E2CC5F /* IDBTransactionInfo.h */,
 				510A58E21BAA40AE00C19282 /* InProcessIDBServer.cpp */,
 				510A58E31BAA40AE00C19282 /* InProcessIDBServer.h */,
+				517138ED1BED1D17000D5F01 /* IndexKey.cpp */,
+				517138EE1BED1D17000D5F01 /* IndexKey.h */,
 			);
 			path = shared;
 			sourceTree = "<group>";
@@ -16893,6 +16907,10 @@
 				510A58F01BAB720F00C19282 /* IDBServer.h */,
 				518864E41BBB4B7E00E540C9 /* IDBServerOperation.cpp */,
 				518864E51BBB4B7E00E540C9 /* IDBServerOperation.h */,
+				51EEAA711BEFFA7900218008 /* IndexValueEntry.cpp */,
+				51EEAA721BEFFA7900218008 /* IndexValueEntry.h */,
+				517138F51BF12262000D5F01 /* IndexValueStore.cpp */,
+				517138F61BF12262000D5F01 /* IndexValueStore.h */,
 				51E1BAC01BD806470055D81F /* MemoryBackingStoreTransaction.cpp */,
 				51E1BAC11BD806470055D81F /* MemoryBackingStoreTransaction.h */,
 				51BA4AC81BBC5B9E00DF3D6D /* MemoryIDBBackingStore.cpp */,
@@ -25682,6 +25700,7 @@
 				A871DE2D0A152AC800B12A68 /* HTMLHeadElement.h in Headers */,
 				A8EA7CB80A192B9C00A8EF5F /* HTMLHeadingElement.h in Headers */,
 				A8EA7CAF0A192B9C00A8EF5F /* HTMLHRElement.h in Headers */,
+				517138F81BF128BB000D5F01 /* IndexValueStore.h in Headers */,
 				A871DE270A152AC800B12A68 /* HTMLHtmlElement.h in Headers */,
 				A871DE2A0A152AC800B12A68 /* HTMLIFrameElement.h in Headers */,
 				A8EA7D2D0A19385500A8EF5F /* HTMLImageElement.h in Headers */,
@@ -26960,6 +26979,7 @@
 				CE12523D1A1676CD00864480 /* QuartzCoreSPI.h in Headers */,
 				442AF7A9102CDDEA008FD4D3 /* QuickLook.h in Headers */,
 				A10DBF4718F92317000D70C6 /* QuickLookHandleClient.h in Headers */,
+				51EEAA741BEFFAB100218008 /* IndexValueEntry.h in Headers */,
 				937F4CCC1A2D48C100BB39F5 /* QuickLookMacSPI.h in Headers */,
 				443918001A91B2F8006E04F2 /* QuickLookSoftLink.h in Headers */,
 				CE1252391A166FA000864480 /* QuickLookSPI.h in Headers */,
@@ -27321,6 +27341,7 @@
 				93309E10099E64920056E581 /* SetNodeAttributeCommand.h in Headers */,
 				B8DBDB4C130B0F8A00F5CDB1 /* SetSelectionCommand.h in Headers */,
 				93F1994F08245E59001E9ABC /* Settings.h in Headers */,
+				517138F01BED1D1A000D5F01 /* IndexKey.h in Headers */,
 				53EF766B16530A61004CBE49 /* SettingsMacros.h in Headers */,
 				0F3DD45012F5EA1B000D9190 /* ShadowBlur.h in Headers */,
 				BC5EB8C40E82031B00B25965 /* ShadowData.h in Headers */,
@@ -28718,6 +28739,7 @@
 				31BC742D1AAFF45C006B4340 /* CSSAnimationTriggerScrollValue.cpp in Sources */,
 				CAE9F90F146441F000C245B0 /* CSSAspectRatioValue.cpp in Sources */,
 				FBD6AF8B15EF25E5008B7110 /* CSSBasicShapes.cpp in Sources */,
+				51EEAA731BEFFAB100218008 /* IndexValueEntry.cpp in Sources */,
 				E16A84F914C85CCC002977DF /* CSSBorderImage.cpp in Sources */,
 				BC274B31140EBED800EADFA6 /* CSSBorderImageSliceValue.cpp in Sources */,
 				49AE2D8E134EE50C0072920A /* CSSCalculationValue.cpp in Sources */,
@@ -29789,6 +29811,7 @@
 				9752D38D1413104B003305BD /* JSHTMLSpanElement.cpp in Sources */,
 				A80E7B0F0A19D606007FB8C5 /* JSHTMLStyleElement.cpp in Sources */,
 				BCA169A20BFD55B40019CA76 /* JSHTMLTableCaptionElement.cpp in Sources */,
+				517138F71BF128BB000D5F01 /* IndexValueStore.cpp in Sources */,
 				BC06EDE30BFD6D0D00856E9D /* JSHTMLTableCellElement.cpp in Sources */,
 				BC06ED9D0BFD660600856E9D /* JSHTMLTableColElement.cpp in Sources */,
 				836CB1F91BD1E41800AF1591 /* JSHTMLTableDataCellElement.cpp in Sources */,
@@ -29961,6 +29984,7 @@
 				AA7FEEA416A4E6F3004C0C33 /* JSSpeechSynthesis.cpp in Sources */,
 				AA2A5AD316A4860D00976A25 /* JSSpeechSynthesisEvent.cpp in Sources */,
 				AA7FEEA616A4E6F3004C0C33 /* JSSpeechSynthesisUtterance.cpp in Sources */,
+				517138EF1BED1D1A000D5F01 /* IndexKey.cpp in Sources */,
 				AA7FEEA816A4E6F3004C0C33 /* JSSpeechSynthesisVoice.cpp in Sources */,
 				514C76370CE9225E007EF3CD /* JSSQLError.cpp in Sources */,
 				B525A96611CA2340003A23A8 /* JSSQLException.cpp in Sources */,

Modified: trunk/Source/WebCore/bindings/js/IDBBindingUtilities.cpp (192293 => 192294)


--- trunk/Source/WebCore/bindings/js/IDBBindingUtilities.cpp	2015-11-11 05:19:56 UTC (rev 192293)
+++ trunk/Source/WebCore/bindings/js/IDBBindingUtilities.cpp	2015-11-11 06:07:03 UTC (rev 192294)
@@ -30,10 +30,12 @@
 #include "IDBBindingUtilities.h"
 
 #include "DOMRequestState.h"
+#include "IDBIndexInfo.h"
 #include "IDBIndexMetadata.h"
 #include "IDBKey.h"
 #include "IDBKeyData.h"
 #include "IDBKeyPath.h"
+#include "IndexKey.h"
 #include "JSDOMBinding.h"
 #include "Logging.h"
 #include "SharedBuffer.h"
@@ -398,8 +400,19 @@
     return Deprecated::ScriptValue(requestState->exec()->vm(), jsNull());
 }
 
+static JSValue idbValueDataToJSValue(JSC::ExecState& exec, const Vector<uint8_t>& buffer)
+{
+    if (buffer.isEmpty())
+        return jsNull();
+
+    RefPtr<SerializedScriptValue> serializedValue = SerializedScriptValue::createFromWireBytes(buffer);
+    return serializedValue->deserialize(&exec, exec.lexicalGlobalObject(), 0, NonThrowing);
+}
+
 Deprecated::ScriptValue deserializeIDBValueBuffer(JSC::ExecState* exec, const Vector<uint8_t>& buffer, bool keyIsDefined)
 {
+    ASSERT(exec);
+
     // If the key doesn't exist, then the value must be undefined (as opposed to null).
     if (!keyIsDefined) {
         // We either shouldn't have a buffer or it should be of size 0.
@@ -407,16 +420,18 @@
         return Deprecated::ScriptValue(exec->vm(), jsUndefined());
     }
 
-    JSValue result;
-    if (buffer.size()) {
-        RefPtr<SerializedScriptValue> serializedValue = SerializedScriptValue::createFromWireBytes(buffer);
-        result = serializedValue->deserialize(exec, exec->lexicalGlobalObject(), 0, NonThrowing);
-    } else
-        result = jsNull();
-
+    JSValue result = idbValueDataToJSValue(*exec, buffer);
     return Deprecated::ScriptValue(exec->vm(), result);
 }
 
+JSValue idbValueDataToJSValue(JSC::ExecState& exec, const ThreadSafeDataBuffer& valueData)
+{
+    if (!valueData.data())
+        return jsUndefined();
+
+    return idbValueDataToJSValue(exec, *valueData.data());
+}
+
 Deprecated::ScriptValue idbKeyToScriptValue(DOMRequestState* requestState, PassRefPtr<IDBKey> key)
 {
     ExecState* exec = requestState->exec();
@@ -434,6 +449,13 @@
     return createIDBKeyFromValue(&exec, scriptValue);
 }
 
+Deprecated::ScriptValue idbKeyDataToScriptValue(ScriptExecutionContext* context, const IDBKeyData& keyData)
+{
+    RefPtr<IDBKey> key = keyData.maybeCreateIDBKey();
+    DOMRequestState requestState(context);
+    return idbKeyToScriptValue(&requestState, key.get());
+}
+
 void generateIndexKeysForValue(ExecState* exec, const IDBIndexMetadata& indexMetadata, const Deprecated::ScriptValue& objectValue, Vector<IDBKeyData>& indexKeys)
 {
     RefPtr<IDBKey> indexKey = createIDBKeyFromScriptValueAndKeyPath(exec, objectValue, indexMetadata.keyPath);
@@ -459,13 +481,49 @@
     }
 }
 
-Deprecated::ScriptValue idbKeyDataToScriptValue(ScriptExecutionContext* context, const IDBKeyData& keyData)
+static Vector<IDBKeyData> createKeyPathArray(ExecState& exec, JSValue value, const IDBIndexInfo& info)
 {
-    RefPtr<IDBKey> key = keyData.maybeCreateIDBKey();
-    DOMRequestState requestState(context);
-    return idbKeyToScriptValue(&requestState, key.get());
+    Vector<IDBKeyData> keys;
+
+    switch (info.keyPath().type()) {
+    case IndexedDB::KeyPathType::Array:
+        for (auto& entry : info.keyPath().array()) {
+            auto key = internalCreateIDBKeyFromScriptValueAndKeyPath(&exec, value, entry);
+            if (!key)
+                return { };
+            keys.append(key.get());
+        }
+        break;
+    case IndexedDB::KeyPathType::String: {
+        auto idbKey = internalCreateIDBKeyFromScriptValueAndKeyPath(&exec, value, info.keyPath().string());
+        if (!idbKey)
+            return { };
+
+        if (info.multiEntry() && idbKey->type() == IndexedDB::Array) {
+            for (auto& key : idbKey->array())
+                keys.append(key.get());
+        } else
+            keys.append(idbKey.get());
+
+        break;
+    }
+    case IndexedDB::KeyPathType::Null:
+        RELEASE_ASSERT_NOT_REACHED();
+    }
+
+    return keys;
 }
 
+void generateIndexKeyForValue(ExecState& exec, const IDBIndexInfo& info, JSValue value, IndexKey& outKey)
+{
+    auto keyDatas = createKeyPathArray(exec, value, info);
+
+    if (keyDatas.isEmpty())
+        return;
+
+    outKey = IndexKey(WTF::move(keyDatas));
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(INDEXED_DATABASE)

Modified: trunk/Source/WebCore/bindings/js/IDBBindingUtilities.h (192293 => 192294)


--- trunk/Source/WebCore/bindings/js/IDBBindingUtilities.h	2015-11-11 05:19:56 UTC (rev 192293)
+++ trunk/Source/WebCore/bindings/js/IDBBindingUtilities.h	2015-11-11 06:07:03 UTC (rev 192294)
@@ -35,8 +35,10 @@
 namespace WebCore {
 
 class DOMRequestState;
+class IDBIndexInfo;
 class IDBKey;
 class IDBKeyPath;
+class IndexKey;
 class SharedBuffer;
 class ThreadSafeDataBuffer;
 
@@ -58,12 +60,17 @@
 Deprecated::ScriptValue deserializeIDBValueData(ScriptExecutionContext&, const ThreadSafeDataBuffer& valueData);
 Deprecated::ScriptValue deserializeIDBValueBuffer(DOMRequestState*, PassRefPtr<SharedBuffer>, bool keyIsDefined);
 WEBCORE_EXPORT Deprecated::ScriptValue deserializeIDBValueBuffer(JSC::ExecState*, const Vector<uint8_t>&, bool keyIsDefined);
+
 Deprecated::ScriptValue idbKeyToScriptValue(DOMRequestState*, PassRefPtr<IDBKey>);
 RefPtr<IDBKey> scriptValueToIDBKey(DOMRequestState*, const JSC::JSValue&);
 RefPtr<IDBKey> scriptValueToIDBKey(JSC::ExecState&, const JSC::JSValue&);
 WEBCORE_EXPORT void generateIndexKeysForValue(JSC::ExecState*, const IDBIndexMetadata&, const Deprecated::ScriptValue& objectValue, Vector<IDBKeyData>& indexKeys);
 
 Deprecated::ScriptValue idbKeyDataToScriptValue(ScriptExecutionContext*, const IDBKeyData&);
+
+JSC::JSValue idbValueDataToJSValue(JSC::ExecState&, const ThreadSafeDataBuffer& valueData);
+void generateIndexKeyForValue(JSC::ExecState&, const IDBIndexInfo&, JSC::JSValue, IndexKey& outKey);
+
 }
 
 #endif // ENABLE(INDEXED_DATABASE)
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to