Modern IDB: Support IDBObjectStore.put/get support.
authorbeidson@apple.com <beidson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 27 Oct 2015 20:39:40 +0000 (20:39 +0000)
committerbeidson@apple.com <beidson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 27 Oct 2015 20:39:40 +0000 (20:39 +0000)
https://bugs.webkit.org/show_bug.cgi?id=150468

Reviewed by Alex Christensen.

Source/WebCore:

Tests: storage/indexeddb/modern/basic-put.html
       storage/indexeddb/modern/keypath-basic.html

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

* Modules/indexeddb/IDBKeyData.cpp:
(WebCore::IDBKeyData::deletedValue):
(WebCore::IDBKeyData::operator<):
(WebCore::IDBKeyData::operator==):
* Modules/indexeddb/IDBKeyData.h:
(WebCore::IDBKeyData::isValid):
(WebCore::IDBKeyData::operator!=):
(WebCore::IDBKeyData::hash):
(WebCore::IDBKeyData::isDeletedValue):
(WebCore::IDBKeyDataHash::hash):
(WebCore::IDBKeyDataHash::equal):
(WebCore::IDBKeyDataHashTraits::constructDeletedValue):
(WebCore::IDBKeyDataHashTraits::isDeletedValue):
(WebCore::IDBKeyDataHashTraits::emptyValue):
(WebCore::IDBKeyDataHashTraits::isEmptyValue):

* Modules/indexeddb/IndexedDB.h:

* Modules/indexeddb/client/IDBAnyImpl.cpp:
(WebCore::IDBClient::IDBAny::IDBAny):
(WebCore::IDBClient::IDBAny::modernIDBObjectStore):
* Modules/indexeddb/client/IDBAnyImpl.h:
(WebCore::IDBClient::IDBAny::create):

* Modules/indexeddb/client/IDBConnectionToServer.cpp:
(WebCore::IDBClient::IDBConnectionToServer::createObjectStore):
(WebCore::IDBClient::IDBConnectionToServer::didCreateObjectStore):
(WebCore::IDBClient::IDBConnectionToServer::putOrAdd):
(WebCore::IDBClient::IDBConnectionToServer::didPutOrAdd):
(WebCore::IDBClient::IDBConnectionToServer::getRecord):
(WebCore::IDBClient::IDBConnectionToServer::didGetRecord):
(WebCore::IDBClient::IDBConnectionToServer::saveOperation):
(WebCore::IDBClient::IDBConnectionToServer::completeOperation):
* Modules/indexeddb/client/IDBConnectionToServer.h:
* Modules/indexeddb/client/IDBConnectionToServerDelegate.h:

* Modules/indexeddb/client/IDBObjectStoreImpl.cpp:
(WebCore::IDBClient::IDBObjectStore::autoIncrement):
(WebCore::IDBClient::IDBObjectStore::put):
(WebCore::IDBClient::IDBObjectStore::get):
(WebCore::IDBClient::IDBObjectStore::putOrAdd):
* Modules/indexeddb/client/IDBObjectStoreImpl.h:
(WebCore::IDBClient::IDBObjectStore::info):

* Modules/indexeddb/client/IDBOpenDBRequestImpl.cpp:
(WebCore::IDBClient::IDBOpenDBRequest::IDBOpenDBRequest): Deleted.

* Modules/indexeddb/client/IDBRequestImpl.cpp:
(WebCore::IDBClient::IDBRequest::create):
(WebCore::IDBClient::IDBRequest::IDBRequest):
(WebCore::IDBClient::IDBRequest::sourceObjectStoreIdentifier):
(WebCore::IDBClient::IDBRequest::hasPendingActivity):
(WebCore::IDBClient::IDBRequest::dispatchEvent):
(WebCore::IDBClient::IDBRequest::setResult):
(WebCore::IDBClient::IDBRequest::setResultToStructuredClone):
(WebCore::IDBClient::IDBRequest::requestCompleted):
(WebCore::IDBClient::IDBRequest::onError):
(WebCore::IDBClient::IDBRequest::onSuccess):
* Modules/indexeddb/client/IDBRequestImpl.h:

* Modules/indexeddb/client/IDBTransactionImpl.cpp:
(WebCore::IDBClient::IDBTransaction::IDBTransaction):
(WebCore::IDBClient::IDBTransaction::hasPendingActivity):
(WebCore::IDBClient::IDBTransaction::isActive):
(WebCore::IDBClient::IDBTransaction::operationTimerFired):
(WebCore::IDBClient::IDBTransaction::commit):
(WebCore::IDBClient::IDBTransaction::didAbort):
(WebCore::IDBClient::IDBTransaction::createObjectStoreOnServer):
(WebCore::IDBClient::IDBTransaction::requestGetRecord):
(WebCore::IDBClient::IDBTransaction::getRecordOnServer):
(WebCore::IDBClient::IDBTransaction::didGetRecordOnServer):
(WebCore::IDBClient::IDBTransaction::requestPutOrAdd):
(WebCore::IDBClient::IDBTransaction::putOrAddOnServer):
(WebCore::IDBClient::IDBTransaction::didPutOrAddOnServer):
(WebCore::IDBClient::IDBTransaction::activate):
(WebCore::IDBClient::IDBTransaction::deactivate):
* Modules/indexeddb/client/IDBTransactionImpl.h:
(WebCore::IDBClient::IDBTransaction::isReadOnly):
(WebCore::IDBClient::TransactionActivator::TransactionActivator):
(WebCore::IDBClient::TransactionActivator::~TransactionActivator):

* Modules/indexeddb/client/TransactionOperation.cpp:
(WebCore::IDBClient::TransactionOperation::TransactionOperation):
* Modules/indexeddb/client/TransactionOperation.h:
(WebCore::IDBClient::TransactionOperation::objectStoreIdentifier):
(WebCore::IDBClient::TransactionOperation::transaction):
(WebCore::IDBClient::createTransactionOperation):

* Modules/indexeddb/server/IDBBackingStore.h:

* Modules/indexeddb/server/IDBConnectionToClient.cpp:
(WebCore::IDBServer::IDBConnectionToClient::didPutOrAdd):
(WebCore::IDBServer::IDBConnectionToClient::didGetRecord):
* Modules/indexeddb/server/IDBConnectionToClient.h:
* Modules/indexeddb/server/IDBConnectionToClientDelegate.h:

* Modules/indexeddb/server/IDBServer.cpp:
(WebCore::IDBServer::IDBServer::putOrAdd):
(WebCore::IDBServer::IDBServer::getRecord):
* Modules/indexeddb/server/IDBServer.h:

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

* Modules/indexeddb/server/MemoryIDBBackingStore.cpp:
(WebCore::IDBServer::MemoryIDBBackingStore::keyExistsInObjectStore):
(WebCore::IDBServer::MemoryIDBBackingStore::deleteRecord):
(WebCore::IDBServer::MemoryIDBBackingStore::putRecord):
(WebCore::IDBServer::MemoryIDBBackingStore::getRecord):
* Modules/indexeddb/server/MemoryIDBBackingStore.h:

* Modules/indexeddb/server/MemoryObjectStore.cpp:
(WebCore::IDBServer::MemoryObjectStore::containsRecord):
(WebCore::IDBServer::MemoryObjectStore::deleteRecord):
(WebCore::IDBServer::MemoryObjectStore::putRecord):
(WebCore::IDBServer::MemoryObjectStore::valueForKey):
* Modules/indexeddb/server/MemoryObjectStore.h:

* Modules/indexeddb/server/UniqueIDBDatabase.cpp:
(WebCore::IDBServer::UniqueIDBDatabase::storeCallback):
(WebCore::IDBServer::UniqueIDBDatabase::putOrAdd):
(WebCore::IDBServer::UniqueIDBDatabase::performPutOrAdd):
(WebCore::IDBServer::UniqueIDBDatabase::didPerformPutOrAdd):
(WebCore::IDBServer::UniqueIDBDatabase::getRecord):
(WebCore::IDBServer::UniqueIDBDatabase::performGetRecord):
(WebCore::IDBServer::UniqueIDBDatabase::didPerformGetRecord):
(WebCore::IDBServer::UniqueIDBDatabase::performKeyDataCallback):
(WebCore::IDBServer::UniqueIDBDatabase::performValueDataCallback):
* Modules/indexeddb/server/UniqueIDBDatabase.h:

* Modules/indexeddb/server/UniqueIDBDatabaseTransaction.cpp:
(WebCore::IDBServer::UniqueIDBDatabaseTransaction::isReadOnly):
(WebCore::IDBServer::UniqueIDBDatabaseTransaction::putOrAdd):
(WebCore::IDBServer::UniqueIDBDatabaseTransaction::getRecord):
* Modules/indexeddb/server/UniqueIDBDatabaseTransaction.h:

* Modules/indexeddb/shared/IDBDatabaseInfo.cpp:
(WebCore::IDBDatabaseInfo::infoForExistingObjectStore):
* Modules/indexeddb/shared/IDBDatabaseInfo.h:

* Modules/indexeddb/shared/IDBError.cpp:
(WebCore::idbErrorName):
(WebCore::idbErrorDescription):
* Modules/indexeddb/shared/IDBError.h:

* Modules/indexeddb/shared/IDBRequestData.cpp:
(WebCore::IDBRequestData::IDBRequestData):
(WebCore::IDBRequestData::serverConnectionIdentifier):
(WebCore::IDBRequestData::objectStoreIdentifier):
* Modules/indexeddb/shared/IDBRequestData.h:

* Modules/indexeddb/shared/IDBResultData.cpp:
(WebCore::IDBResultData::IDBResultData):
(WebCore::IDBResultData::putOrAddSuccess):
(WebCore::IDBResultData::getRecordSuccess):
* Modules/indexeddb/shared/IDBResultData.h:
(WebCore::IDBResultData::resultKey):
(WebCore::IDBResultData::resultData):

* Modules/indexeddb/shared/InProcessIDBServer.cpp:
(WebCore::InProcessIDBServer::didPutOrAdd):
(WebCore::InProcessIDBServer::didGetRecord):
(WebCore::InProcessIDBServer::putOrAdd):
(WebCore::InProcessIDBServer::getRecord):
* Modules/indexeddb/shared/InProcessIDBServer.h:

* bindings/js/IDBBindingUtilities.cpp:
(WebCore::idbKeyToJSValue):
(WebCore::maybeCreateIDBKeyFromScriptValueAndKeyPath):
(WebCore::canInjectIDBKeyIntoScriptValue):
(WebCore::deserializeIDBValueData):
(WebCore::scriptValueToIDBKey):
(WebCore::idbKeyDataToScriptValue):
* bindings/js/IDBBindingUtilities.h:

* platform/CrossThreadCopier.cpp:
(WebCore::ThreadSafeDataBuffer>::copy):
* platform/CrossThreadCopier.h:

* platform/ThreadSafeDataBuffer.h: Added.
(WebCore::ThreadSafeDataBufferImpl::ThreadSafeDataBufferImpl):
(WebCore::ThreadSafeDataBuffer::adoptVector):
(WebCore::ThreadSafeDataBuffer::copyVector):
(WebCore::ThreadSafeDataBuffer::ThreadSafeDataBuffer):
(WebCore::ThreadSafeDataBuffer::data):

LayoutTests:

* platform/mac-wk1/TestExpectations: Re-enable a test that can now be made reliable.

* storage/indexeddb/modern/basic-put-expected.txt: Added.
* storage/indexeddb/modern/basic-put.html: Added.
* storage/indexeddb/modern/createobjectstore-basic-expected.txt:
* storage/indexeddb/modern/createobjectstore-basic.html:
* storage/indexeddb/modern/keypath-basic-expected.txt: Added.
* storage/indexeddb/modern/keypath-basic.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@191635 268f45cc-cd09-0410-ab3c-d52691b4dbfc

59 files changed:
LayoutTests/ChangeLog
LayoutTests/platform/mac-wk1/TestExpectations
LayoutTests/storage/indexeddb/modern/basic-put-expected.txt [new file with mode: 0644]
LayoutTests/storage/indexeddb/modern/basic-put.html [new file with mode: 0644]
LayoutTests/storage/indexeddb/modern/createobjectstore-basic-expected.txt
LayoutTests/storage/indexeddb/modern/createobjectstore-basic.html
LayoutTests/storage/indexeddb/modern/keypath-basic-expected.txt [new file with mode: 0644]
LayoutTests/storage/indexeddb/modern/keypath-basic.html [new file with mode: 0644]
Source/WebCore/CMakeLists.txt
Source/WebCore/ChangeLog
Source/WebCore/Modules/indexeddb/IDBKeyData.cpp
Source/WebCore/Modules/indexeddb/IDBKeyData.h
Source/WebCore/Modules/indexeddb/IndexedDB.h
Source/WebCore/Modules/indexeddb/client/IDBAnyImpl.cpp
Source/WebCore/Modules/indexeddb/client/IDBAnyImpl.h
Source/WebCore/Modules/indexeddb/client/IDBConnectionToServer.cpp
Source/WebCore/Modules/indexeddb/client/IDBConnectionToServer.h
Source/WebCore/Modules/indexeddb/client/IDBConnectionToServerDelegate.h
Source/WebCore/Modules/indexeddb/client/IDBObjectStoreImpl.cpp
Source/WebCore/Modules/indexeddb/client/IDBObjectStoreImpl.h
Source/WebCore/Modules/indexeddb/client/IDBOpenDBRequestImpl.cpp
Source/WebCore/Modules/indexeddb/client/IDBRequestImpl.cpp
Source/WebCore/Modules/indexeddb/client/IDBRequestImpl.h
Source/WebCore/Modules/indexeddb/client/IDBTransactionImpl.cpp
Source/WebCore/Modules/indexeddb/client/IDBTransactionImpl.h
Source/WebCore/Modules/indexeddb/client/TransactionOperation.cpp [new file with mode: 0644]
Source/WebCore/Modules/indexeddb/client/TransactionOperation.h
Source/WebCore/Modules/indexeddb/server/IDBBackingStore.h
Source/WebCore/Modules/indexeddb/server/IDBConnectionToClient.cpp
Source/WebCore/Modules/indexeddb/server/IDBConnectionToClient.h
Source/WebCore/Modules/indexeddb/server/IDBConnectionToClientDelegate.h
Source/WebCore/Modules/indexeddb/server/IDBServer.cpp
Source/WebCore/Modules/indexeddb/server/IDBServer.h
Source/WebCore/Modules/indexeddb/server/MemoryBackingStoreTransaction.cpp
Source/WebCore/Modules/indexeddb/server/MemoryBackingStoreTransaction.h
Source/WebCore/Modules/indexeddb/server/MemoryIDBBackingStore.cpp
Source/WebCore/Modules/indexeddb/server/MemoryIDBBackingStore.h
Source/WebCore/Modules/indexeddb/server/MemoryObjectStore.cpp
Source/WebCore/Modules/indexeddb/server/MemoryObjectStore.h
Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp
Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.h
Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabaseTransaction.cpp
Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabaseTransaction.h
Source/WebCore/Modules/indexeddb/shared/IDBDatabaseInfo.cpp
Source/WebCore/Modules/indexeddb/shared/IDBDatabaseInfo.h
Source/WebCore/Modules/indexeddb/shared/IDBError.cpp
Source/WebCore/Modules/indexeddb/shared/IDBError.h
Source/WebCore/Modules/indexeddb/shared/IDBRequestData.cpp
Source/WebCore/Modules/indexeddb/shared/IDBRequestData.h
Source/WebCore/Modules/indexeddb/shared/IDBResultData.cpp
Source/WebCore/Modules/indexeddb/shared/IDBResultData.h
Source/WebCore/Modules/indexeddb/shared/InProcessIDBServer.cpp
Source/WebCore/Modules/indexeddb/shared/InProcessIDBServer.h
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/bindings/js/IDBBindingUtilities.cpp
Source/WebCore/bindings/js/IDBBindingUtilities.h
Source/WebCore/platform/CrossThreadCopier.cpp
Source/WebCore/platform/CrossThreadCopier.h
Source/WebCore/platform/ThreadSafeDataBuffer.h [new file with mode: 0644]

index 8b09542..94558d9 100644 (file)
@@ -1,3 +1,19 @@
+2015-10-27  Brady Eidson  <beidson@apple.com>
+
+        Modern IDB: Support IDBObjectStore.put/get support.
+        https://bugs.webkit.org/show_bug.cgi?id=150468
+
+        Reviewed by Alex Christensen.
+
+        * platform/mac-wk1/TestExpectations: Re-enable a test that can now be made reliable.
+        
+        * storage/indexeddb/modern/basic-put-expected.txt: Added.
+        * storage/indexeddb/modern/basic-put.html: Added.
+        * storage/indexeddb/modern/createobjectstore-basic-expected.txt:
+        * storage/indexeddb/modern/createobjectstore-basic.html:
+        * storage/indexeddb/modern/keypath-basic-expected.txt: Added.
+        * storage/indexeddb/modern/keypath-basic.html: Added.
+
 2015-10-27  Ryan Haddad  <ryanhaddad@apple.com>
 
         Marking newly imported W3C html/semantics/forms tests as flaky on Windows
index 5ab759d..38eeb87 100644 (file)
@@ -73,9 +73,6 @@ inspector/indexeddb
 # But Modern IndexedDB is.
 storage/indexeddb/modern [ Pass ]
 
-# Flakey, skipped until https://bugs.webkit.org/show_bug.cgi?id=150468 lets us implement a proper fix
-storage/indexeddb/modern/createobjectstore-basic.html
-
 # Fails with WebKit1 only.
 editing/secure-input/reset-state-on-navigation.html [ Failure ]
 
diff --git a/LayoutTests/storage/indexeddb/modern/basic-put-expected.txt b/LayoutTests/storage/indexeddb/modern/basic-put-expected.txt
new file mode 100644 (file)
index 0000000..6e4a33b
--- /dev/null
@@ -0,0 +1,8 @@
+ALERT: Upgrade needed: Old version - 0 New version - 1
+ALERT: [object IDBTransaction] - versionchange
+ALERT: [object IDBDatabase]
+ALERT: put succeeded - key was 'foo'
+ALERT: get succeeded - value was 'bar'
+ALERT: version change transaction completed
+ALERT: Done
+
diff --git a/LayoutTests/storage/indexeddb/modern/basic-put.html b/LayoutTests/storage/indexeddb/modern/basic-put.html
new file mode 100644 (file)
index 0000000..2c57061
--- /dev/null
@@ -0,0 +1,64 @@
+<script>
+
+if (window.testRunner) {
+    testRunner.waitUntilDone();
+    testRunner.dumpAsText();
+}
+
+var request = window.indexedDB.open("NewDatabasePutTestDatabase");
+
+function done()
+{
+    alert("Done");
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+
+request.onupgradeneeded = function(event) {
+    alert("Upgrade needed: Old version - " + event.oldVersion + " New version - " + event.newVersion);
+    
+    var tx = request.transaction;
+    var db = event.target.result;
+
+    alert(tx + " - " + tx.mode);
+    alert(db);
+
+    var os = db.createObjectStore("TestObjectStore");
+    var putRequest = os.put("bar", "foo");
+    
+    putRequest.onsuccess = function(event) {
+        alert("put succeeded - key was '" + putRequest.result + "'");
+        
+        var getRequest = os.get("foo");
+        getRequest.onsuccess = function(event) {
+            alert("get succeeded - value was '" + getRequest.result + "'");
+        }
+
+        getRequest.onerror = function(event) {
+            alert("get unexpectedly failed - " + event);
+            done();
+        }
+    }
+
+    putRequest.onerror = function(event) {
+        alert("put unexpectedly failed - " + event);
+        done();
+    }
+    
+    tx.onabort = function(event) {
+        alert("version change transaction unexpected abort");
+        done();
+    }
+
+    tx.oncomplete = function(event) {
+        alert("version change transaction completed");
+        done();
+    }
+
+    tx.onerror = function(event) {
+        alert("version change transaction unexpected error - " + event);
+        done();
+    }
+}
+
+</script>
index 18edd8a..39cfd05 100644 (file)
@@ -1,6 +1,7 @@
 ALERT: Initial upgrade needed: Old version - 0 New version - 1
 ALERT: Object store names:
 ALERT: FirstAbortedObjectStore
+ALERT: Put succeeded
 ALERT: Initial upgrade versionchange transaction aborted
 ALERT: Object store names:
 ALERT: Second upgrade needed: Old version - 0 New version - 1
index 38df693..2104f99 100644 (file)
@@ -30,13 +30,18 @@ createRequest.onupgradeneeded = function(event) {
     var versionTransaction = createRequest.transaction;
     var database = event.target.result;
     var objectStore = database.createObjectStore("FirstAbortedObjectStore");
+    var request = objectStore.put("foo", "bar");
 
-    var f = function() {
+    request.onsuccess = function(event) {
+        alert("Put succeeded");
         versionTransaction.abort();
-    };
-
+    }
+    request.onerror = function(event) {
+        alert("Put failed - " + event);
+        done();
+    }
+    
     dumpObjectStores(database);    
-    setTimeout(f, 0);
     
     versionTransaction.onabort = function(event) {
         alert("Initial upgrade versionchange transaction aborted");
diff --git a/LayoutTests/storage/indexeddb/modern/keypath-basic-expected.txt b/LayoutTests/storage/indexeddb/modern/keypath-basic-expected.txt
new file mode 100644 (file)
index 0000000..0d6c1ce
--- /dev/null
@@ -0,0 +1,11 @@
+ALERT: Initial upgrade needed: Old version - 0 New version - 1
+ALERT: object put SUCCESS - foo1
+ALERT: array put SUCCESS - foo2
+ALERT: Second object put SUCCESS - baz1
+ALERT: Second array put SUCCESS - baz2
+ALERT: Initial upgrade versionchange transaction complete
+ALERT: Done
+This test creates some object stores with keypaths.
+It then puts some values in them.
+It makes sure the keys used are as expected.
+
diff --git a/LayoutTests/storage/indexeddb/modern/keypath-basic.html b/LayoutTests/storage/indexeddb/modern/keypath-basic.html
new file mode 100644 (file)
index 0000000..35daeb0
--- /dev/null
@@ -0,0 +1,74 @@
+This test creates some object stores with keypaths.<br>
+It then puts some values in them.<br>
+It makes sure the keys used are as expected.<br>
+<script>
+
+if (window.testRunner) {
+    testRunner.waitUntilDone();
+    testRunner.dumpAsText();
+}
+
+function done()
+{
+    alert("Done");
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+
+var createRequest = window.indexedDB.open("KeypathBasicTestDatabase", 1);
+
+createRequest.onupgradeneeded = function(event) {
+    alert("Initial upgrade needed: Old version - " + event.oldVersion + " New version - " + event.newVersion);
+
+    var versionTransaction = createRequest.transaction;
+    var database = event.target.result;    
+    var objectStore1 = database.createObjectStore("OS1", { keyPath: "foo" });
+    var objectStore2 = database.createObjectStore("OS2", { keyPath: "foo.bar" });
+
+    var object = new Object;
+    object.stuff = "bar1";
+    object.foo = "foo1";
+        
+    var request1 = objectStore1.put(object);
+    request1.onsuccess = function(event) {
+        alert("object put SUCCESS - " + request1.result);
+    }
+
+    var array = { foo: "foo2", stuff: "bar2" };
+
+    var request2 = objectStore1.put(array);
+    request2.onsuccess = function(event) {
+        alert("array put SUCCESS - " + request2.result);
+    }
+    
+    object.foo = new Object;
+    object.foo.bar = "baz1";
+    var request3 = objectStore2.put(object);
+    request3.onsuccess = function(event) {
+        alert("Second object put SUCCESS - " + request3.result);
+    }
+
+    array.foo = { bar: "baz2" };
+
+    var request4 = objectStore2.put(array);
+    request4.onsuccess = function(event) {
+        alert("Second array put SUCCESS - " + request4.result);
+    }
+
+    versionTransaction.onabort = function(event) {
+        alert("Initial upgrade versionchange transaction unexpected aborted");
+        done();
+    }
+
+    versionTransaction.oncomplete = function(event) {
+        alert("Initial upgrade versionchange transaction complete");
+        done();
+    }
+
+    versionTransaction.onerror = function(event) {
+        alert("Initial upgrade versionchange transaction unexpected error" + event);
+        done();
+    }
+}
+
+</script>
\ No newline at end of file
index dc8387d..81fea59 100644 (file)
@@ -876,6 +876,7 @@ set(WebCore_SOURCES
     Modules/indexeddb/client/IDBRequestImpl.cpp
     Modules/indexeddb/client/IDBTransactionImpl.cpp
     Modules/indexeddb/client/IDBVersionChangeEventImpl.cpp
+    Modules/indexeddb/client/TransactionOperation.cpp
 
     Modules/indexeddb/legacy/IDBCursorBackend.cpp
     Modules/indexeddb/legacy/IDBCursorBackendOperations.cpp
index 76f3368..872ca6a 100644 (file)
@@ -1,3 +1,204 @@
+2015-10-27  Brady Eidson  <beidson@apple.com>
+
+        Modern IDB: Support IDBObjectStore.put/get support.
+        https://bugs.webkit.org/show_bug.cgi?id=150468
+
+        Reviewed by Alex Christensen.
+
+        Tests: storage/indexeddb/modern/basic-put.html
+               storage/indexeddb/modern/keypath-basic.html
+
+        * CMakeLists.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+
+        * Modules/indexeddb/IDBKeyData.cpp:
+        (WebCore::IDBKeyData::deletedValue):
+        (WebCore::IDBKeyData::operator<):
+        (WebCore::IDBKeyData::operator==):
+        * Modules/indexeddb/IDBKeyData.h:
+        (WebCore::IDBKeyData::isValid):
+        (WebCore::IDBKeyData::operator!=):
+        (WebCore::IDBKeyData::hash):
+        (WebCore::IDBKeyData::isDeletedValue):
+        (WebCore::IDBKeyDataHash::hash):
+        (WebCore::IDBKeyDataHash::equal):
+        (WebCore::IDBKeyDataHashTraits::constructDeletedValue):
+        (WebCore::IDBKeyDataHashTraits::isDeletedValue):
+        (WebCore::IDBKeyDataHashTraits::emptyValue):
+        (WebCore::IDBKeyDataHashTraits::isEmptyValue):
+
+        * Modules/indexeddb/IndexedDB.h:
+
+        * Modules/indexeddb/client/IDBAnyImpl.cpp:
+        (WebCore::IDBClient::IDBAny::IDBAny):
+        (WebCore::IDBClient::IDBAny::modernIDBObjectStore):
+        * Modules/indexeddb/client/IDBAnyImpl.h:
+        (WebCore::IDBClient::IDBAny::create):
+
+        * Modules/indexeddb/client/IDBConnectionToServer.cpp:
+        (WebCore::IDBClient::IDBConnectionToServer::createObjectStore):
+        (WebCore::IDBClient::IDBConnectionToServer::didCreateObjectStore):
+        (WebCore::IDBClient::IDBConnectionToServer::putOrAdd):
+        (WebCore::IDBClient::IDBConnectionToServer::didPutOrAdd):
+        (WebCore::IDBClient::IDBConnectionToServer::getRecord):
+        (WebCore::IDBClient::IDBConnectionToServer::didGetRecord):
+        (WebCore::IDBClient::IDBConnectionToServer::saveOperation):
+        (WebCore::IDBClient::IDBConnectionToServer::completeOperation):
+        * Modules/indexeddb/client/IDBConnectionToServer.h:
+        * Modules/indexeddb/client/IDBConnectionToServerDelegate.h:
+
+        * Modules/indexeddb/client/IDBObjectStoreImpl.cpp:
+        (WebCore::IDBClient::IDBObjectStore::autoIncrement):
+        (WebCore::IDBClient::IDBObjectStore::put):
+        (WebCore::IDBClient::IDBObjectStore::get):
+        (WebCore::IDBClient::IDBObjectStore::putOrAdd):
+        * Modules/indexeddb/client/IDBObjectStoreImpl.h:
+        (WebCore::IDBClient::IDBObjectStore::info):
+
+        * Modules/indexeddb/client/IDBOpenDBRequestImpl.cpp:
+        (WebCore::IDBClient::IDBOpenDBRequest::IDBOpenDBRequest): Deleted.
+
+        * Modules/indexeddb/client/IDBRequestImpl.cpp:
+        (WebCore::IDBClient::IDBRequest::create):
+        (WebCore::IDBClient::IDBRequest::IDBRequest):
+        (WebCore::IDBClient::IDBRequest::sourceObjectStoreIdentifier):
+        (WebCore::IDBClient::IDBRequest::hasPendingActivity):
+        (WebCore::IDBClient::IDBRequest::dispatchEvent):
+        (WebCore::IDBClient::IDBRequest::setResult):
+        (WebCore::IDBClient::IDBRequest::setResultToStructuredClone):
+        (WebCore::IDBClient::IDBRequest::requestCompleted):
+        (WebCore::IDBClient::IDBRequest::onError):
+        (WebCore::IDBClient::IDBRequest::onSuccess):
+        * Modules/indexeddb/client/IDBRequestImpl.h:
+
+        * Modules/indexeddb/client/IDBTransactionImpl.cpp:
+        (WebCore::IDBClient::IDBTransaction::IDBTransaction):
+        (WebCore::IDBClient::IDBTransaction::hasPendingActivity):
+        (WebCore::IDBClient::IDBTransaction::isActive):
+        (WebCore::IDBClient::IDBTransaction::operationTimerFired):
+        (WebCore::IDBClient::IDBTransaction::commit):
+        (WebCore::IDBClient::IDBTransaction::didAbort):
+        (WebCore::IDBClient::IDBTransaction::createObjectStoreOnServer):
+        (WebCore::IDBClient::IDBTransaction::requestGetRecord):
+        (WebCore::IDBClient::IDBTransaction::getRecordOnServer):
+        (WebCore::IDBClient::IDBTransaction::didGetRecordOnServer):
+        (WebCore::IDBClient::IDBTransaction::requestPutOrAdd):
+        (WebCore::IDBClient::IDBTransaction::putOrAddOnServer):
+        (WebCore::IDBClient::IDBTransaction::didPutOrAddOnServer):
+        (WebCore::IDBClient::IDBTransaction::activate):
+        (WebCore::IDBClient::IDBTransaction::deactivate):
+        * Modules/indexeddb/client/IDBTransactionImpl.h:
+        (WebCore::IDBClient::IDBTransaction::isReadOnly):
+        (WebCore::IDBClient::TransactionActivator::TransactionActivator):
+        (WebCore::IDBClient::TransactionActivator::~TransactionActivator):
+
+        * Modules/indexeddb/client/TransactionOperation.cpp: 
+        (WebCore::IDBClient::TransactionOperation::TransactionOperation):
+        * Modules/indexeddb/client/TransactionOperation.h:
+        (WebCore::IDBClient::TransactionOperation::objectStoreIdentifier):
+        (WebCore::IDBClient::TransactionOperation::transaction):
+        (WebCore::IDBClient::createTransactionOperation):
+
+        * Modules/indexeddb/server/IDBBackingStore.h:
+        
+        * Modules/indexeddb/server/IDBConnectionToClient.cpp:
+        (WebCore::IDBServer::IDBConnectionToClient::didPutOrAdd):
+        (WebCore::IDBServer::IDBConnectionToClient::didGetRecord):
+        * Modules/indexeddb/server/IDBConnectionToClient.h:
+        * Modules/indexeddb/server/IDBConnectionToClientDelegate.h:
+
+        * Modules/indexeddb/server/IDBServer.cpp:
+        (WebCore::IDBServer::IDBServer::putOrAdd):
+        (WebCore::IDBServer::IDBServer::getRecord):
+        * Modules/indexeddb/server/IDBServer.h:
+
+        * Modules/indexeddb/server/MemoryBackingStoreTransaction.cpp:
+        (WebCore::IDBServer::MemoryBackingStoreTransaction::recordValueChanged):
+        (WebCore::IDBServer::MemoryBackingStoreTransaction::abort):
+        * Modules/indexeddb/server/MemoryBackingStoreTransaction.h:
+
+        * Modules/indexeddb/server/MemoryIDBBackingStore.cpp:
+        (WebCore::IDBServer::MemoryIDBBackingStore::keyExistsInObjectStore):
+        (WebCore::IDBServer::MemoryIDBBackingStore::deleteRecord):
+        (WebCore::IDBServer::MemoryIDBBackingStore::putRecord):
+        (WebCore::IDBServer::MemoryIDBBackingStore::getRecord):
+        * Modules/indexeddb/server/MemoryIDBBackingStore.h:
+
+        * Modules/indexeddb/server/MemoryObjectStore.cpp:
+        (WebCore::IDBServer::MemoryObjectStore::containsRecord):
+        (WebCore::IDBServer::MemoryObjectStore::deleteRecord):
+        (WebCore::IDBServer::MemoryObjectStore::putRecord):
+        (WebCore::IDBServer::MemoryObjectStore::valueForKey):
+        * Modules/indexeddb/server/MemoryObjectStore.h:
+
+        * Modules/indexeddb/server/UniqueIDBDatabase.cpp:
+        (WebCore::IDBServer::UniqueIDBDatabase::storeCallback):
+        (WebCore::IDBServer::UniqueIDBDatabase::putOrAdd):
+        (WebCore::IDBServer::UniqueIDBDatabase::performPutOrAdd):
+        (WebCore::IDBServer::UniqueIDBDatabase::didPerformPutOrAdd):
+        (WebCore::IDBServer::UniqueIDBDatabase::getRecord):
+        (WebCore::IDBServer::UniqueIDBDatabase::performGetRecord):
+        (WebCore::IDBServer::UniqueIDBDatabase::didPerformGetRecord):
+        (WebCore::IDBServer::UniqueIDBDatabase::performKeyDataCallback):
+        (WebCore::IDBServer::UniqueIDBDatabase::performValueDataCallback):
+        * Modules/indexeddb/server/UniqueIDBDatabase.h:
+
+        * Modules/indexeddb/server/UniqueIDBDatabaseTransaction.cpp:
+        (WebCore::IDBServer::UniqueIDBDatabaseTransaction::isReadOnly):
+        (WebCore::IDBServer::UniqueIDBDatabaseTransaction::putOrAdd):
+        (WebCore::IDBServer::UniqueIDBDatabaseTransaction::getRecord):
+        * Modules/indexeddb/server/UniqueIDBDatabaseTransaction.h:
+
+        * Modules/indexeddb/shared/IDBDatabaseInfo.cpp:
+        (WebCore::IDBDatabaseInfo::infoForExistingObjectStore):
+        * Modules/indexeddb/shared/IDBDatabaseInfo.h:
+
+        * Modules/indexeddb/shared/IDBError.cpp:
+        (WebCore::idbErrorName):
+        (WebCore::idbErrorDescription):
+        * Modules/indexeddb/shared/IDBError.h:
+
+        * Modules/indexeddb/shared/IDBRequestData.cpp:
+        (WebCore::IDBRequestData::IDBRequestData):
+        (WebCore::IDBRequestData::serverConnectionIdentifier):
+        (WebCore::IDBRequestData::objectStoreIdentifier):
+        * Modules/indexeddb/shared/IDBRequestData.h:
+
+        * Modules/indexeddb/shared/IDBResultData.cpp:
+        (WebCore::IDBResultData::IDBResultData):
+        (WebCore::IDBResultData::putOrAddSuccess):
+        (WebCore::IDBResultData::getRecordSuccess):
+        * Modules/indexeddb/shared/IDBResultData.h:
+        (WebCore::IDBResultData::resultKey):
+        (WebCore::IDBResultData::resultData):
+
+        * Modules/indexeddb/shared/InProcessIDBServer.cpp:
+        (WebCore::InProcessIDBServer::didPutOrAdd):
+        (WebCore::InProcessIDBServer::didGetRecord):
+        (WebCore::InProcessIDBServer::putOrAdd):
+        (WebCore::InProcessIDBServer::getRecord):
+        * Modules/indexeddb/shared/InProcessIDBServer.h:
+
+        * bindings/js/IDBBindingUtilities.cpp:
+        (WebCore::idbKeyToJSValue):
+        (WebCore::maybeCreateIDBKeyFromScriptValueAndKeyPath):
+        (WebCore::canInjectIDBKeyIntoScriptValue):
+        (WebCore::deserializeIDBValueData):
+        (WebCore::scriptValueToIDBKey):
+        (WebCore::idbKeyDataToScriptValue):
+        * bindings/js/IDBBindingUtilities.h:
+
+        * platform/CrossThreadCopier.cpp:
+        (WebCore::ThreadSafeDataBuffer>::copy):
+        * platform/CrossThreadCopier.h:
+
+        * platform/ThreadSafeDataBuffer.h: Added.
+        (WebCore::ThreadSafeDataBufferImpl::ThreadSafeDataBufferImpl):
+        (WebCore::ThreadSafeDataBuffer::adoptVector):
+        (WebCore::ThreadSafeDataBuffer::copyVector):
+        (WebCore::ThreadSafeDataBuffer::ThreadSafeDataBuffer):
+        (WebCore::ThreadSafeDataBuffer::data):
+
 2015-10-27  Tim Horton  <timothy_horton@apple.com>
 
         WKView being inside WKWebView leads to weird API issues
index 92c301f..142f248 100644 (file)
@@ -319,6 +319,45 @@ void IDBKeyData::setNumberValue(double value)
     m_isNull = false;
 }
 
+IDBKeyData IDBKeyData::deletedValue()
+{
+    IDBKeyData result;
+    result.m_isNull = false;
+    result.m_isDeletedValue = true;
+    return WTF::move(result);
+}
+
+bool IDBKeyData::operator<(const IDBKeyData& rhs) const
+{
+    return compare(rhs) < 0;
+}
+
+bool IDBKeyData::operator==(const IDBKeyData& other) const
+{
+    if (m_type != other.m_type || m_isNull != other.m_isNull || m_isDeletedValue != other.m_isDeletedValue)
+        return false;
+    switch (m_type) {
+    case KeyType::Invalid:
+    case KeyType::Max:
+    case KeyType::Min:
+        return true;
+    case KeyType::Number:
+    case KeyType::Date:
+        return m_numberValue == other.m_numberValue;
+    case KeyType::String:
+        return m_stringValue == other.m_stringValue;
+    case KeyType::Array:
+        if (m_arrayValue.size() != other.m_arrayValue.size())
+            return false;
+        for (size_t i = 0; i < m_arrayValue.size(); ++i) {
+            if (m_arrayValue[0] != other.m_arrayValue[0])
+                return false;
+        }
+        return true;
+    }
+    RELEASE_ASSERT_NOT_REACHED();
 }
 
+} // namespace WebCore
+
 #endif // ENABLE(INDEXED_DATABASE)
index 91563b2..b6aa0c6 100644 (file)
@@ -29,6 +29,7 @@
 #if ENABLE(INDEXED_DATABASE)
 
 #include "IDBKey.h"
+#include <wtf/text/StringHash.h>
 
 namespace WebCore {
 
@@ -87,14 +88,87 @@ public:
 #endif
 
     bool isNull() const { return m_isNull; }
+    bool isValid() const { return m_type != KeyType::Invalid; }
     KeyType type() const { return m_type; }
 
+    bool operator<(const IDBKeyData&) const;
+    bool operator==(const IDBKeyData& other) const;
+    bool operator!=(const IDBKeyData& other) const
+    {
+        return !(*this == other);
+    }
+
+    unsigned hash() const
+    {
+        Vector<unsigned> hashCodes;
+        hashCodes.append(static_cast<unsigned>(m_type));
+        hashCodes.append(m_isNull ? 1 : 0);
+        hashCodes.append(m_isDeletedValue ? 1 : 0);
+        switch (m_type) {
+        case KeyType::Invalid:
+        case KeyType::Max:
+        case KeyType::Min:
+            break;
+        case KeyType::Number:
+        case KeyType::Date:
+            hashCodes.append(StringHasher::hashMemory<sizeof(double)>(&m_numberValue));
+            break;
+        case KeyType::String:
+            hashCodes.append(StringHash::hash(m_stringValue));
+            break;
+        case KeyType::Array:
+            for (auto& key : m_arrayValue)
+                hashCodes.append(key.hash());
+            break;
+        }
+
+        unsigned targetSize = WTF::roundUpToPowerOfTwo(hashCodes.size());
+        hashCodes.resize(targetSize);
+
+        return StringHasher::hashMemory(hashCodes.data(), hashCodes.size() * sizeof(unsigned));
+    }
+
+    static IDBKeyData deletedValue();
+    bool isDeletedValue() const { return m_isDeletedValue; }
+
 private:
     KeyType m_type;
     Vector<IDBKeyData> m_arrayValue;
     String m_stringValue;
     double m_numberValue { 0 };
     bool m_isNull { false };
+    bool m_isDeletedValue { false };
+};
+
+struct IDBKeyDataHash {
+    static unsigned hash(const IDBKeyData& a) { return a.hash(); }
+    static bool equal(const IDBKeyData& a, const IDBKeyData& b) { return a == b; }
+    static const bool safeToCompareToEmptyOrDeleted = false;
+};
+
+struct IDBKeyDataHashTraits : public WTF::CustomHashTraits<IDBKeyData> {
+    static const bool emptyValueIsZero = false;
+    static const bool hasIsEmptyValueFunction = true;
+
+    static void constructDeletedValue(IDBKeyData& key)
+    {
+        key = IDBKeyData::deletedValue();
+    }
+
+    static bool isDeletedValue(const IDBKeyData& key)
+    {
+        return key.isDeletedValue();
+    }
+
+    static IDBKeyData emptyValue()
+    {
+        return IDBKeyData();
+    }
+
+    static bool isEmptyValue(const IDBKeyData& key)
+    {
+        return key.isNull();
+    }
 };
 
 template<class Encoder>
index 558bba7..8fef522 100644 (file)
@@ -41,7 +41,8 @@ const unsigned TransactionModeMaximum = 2;
 
 enum class TransactionState {
     Unstarted,
-    Running,
+    Active,
+    Inactive,
     Committing,
     Aborting,
     Finished,
@@ -71,7 +72,12 @@ enum class KeyPathType {
     String,
     Array,
 };
-    
+
+enum class ObjectStoreOverwriteMode {
+    Overwrite,
+    NoOverwrite,
+};
+
 // In order of the least to the highest precedent in terms of sort order.
 enum KeyType {
     Max = -1,
index 2fdab7d..7e9a137 100644 (file)
@@ -42,6 +42,18 @@ IDBAny::IDBAny(Ref<IDBDatabase>&& database)
 {
 }
 
+IDBAny::IDBAny(Ref<IDBObjectStore>&& objectStore)
+    : m_type(IDBAny::Type::IDBObjectStore)
+    , m_objectStore(adoptRef(&objectStore.leakRef()))
+{
+}
+
+IDBAny::IDBAny(const Deprecated::ScriptValue& value)
+    : m_type(IDBAny::Type::ScriptValue)
+    , m_scriptValue(value)
+{
+}
+
 IDBAny::~IDBAny()
 {
 }
@@ -82,6 +94,12 @@ RefPtr<WebCore::IDBObjectStore> IDBAny::idbObjectStore()
     return nullptr;
 }
 
+IDBObjectStore* IDBAny::modernIDBObjectStore()
+{
+    ASSERT(m_type == IDBAny::Type::IDBObjectStore);
+    return m_objectStore.get();
+}
+
 RefPtr<WebCore::IDBTransaction> IDBAny::idbTransaction()
 {
     return nullptr;
index c142656..09c42b1 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "IDBAny.h"
 #include "IDBDatabaseImpl.h"
+#include "IDBObjectStoreImpl.h"
 
 namespace WebCore {
 namespace IDBClient {
@@ -41,6 +42,16 @@ public:
         return adoptRef(new IDBAny(WTF::move(database)));
     }
 
+    static RefPtr<IDBAny> create(Ref<IDBObjectStore>&& objectStore)
+    {
+        return adoptRef(new IDBAny(WTF::move(objectStore)));
+    }
+
+    static RefPtr<IDBAny> create(const Deprecated::ScriptValue& value)
+    {
+        return adoptRef(new IDBAny(value));
+    }
+
     virtual ~IDBAny();
 
     virtual Type type() const override final { return m_type; }
@@ -57,11 +68,17 @@ public:
     virtual const String& string() override final;
     virtual const IDBKeyPath& keyPath() override final;
 
+    IDBObjectStore* modernIDBObjectStore();
+
 private:
-    IDBAny(Ref<IDBDatabase>&&);
+    explicit IDBAny(Ref<IDBDatabase>&&);
+    explicit IDBAny(Ref<IDBObjectStore>&&);
+    explicit IDBAny(const Deprecated::ScriptValue&);
+
 
     IDBAny::Type m_type { IDBAny::Type::Undefined };
     RefPtr<IDBDatabase> m_database;
+    RefPtr<IDBObjectStore> m_objectStore;
 
     const IDBKeyPath m_idbKeyPath;
     const Deprecated::ScriptValue m_scriptValue;
index 46209d8..e610325 100644 (file)
@@ -98,8 +98,7 @@ void IDBConnectionToServer::createObjectStore(TransactionOperation& operation, c
 {
     LOG(IndexedDB, "IDBConnectionToServer::createObjectStore");
 
-    ASSERT(!m_activeOperations.contains(operation.identifier()));
-    m_activeOperations.set(operation.identifier(), &operation);
+    saveOperation(operation);
 
     m_delegate->createObjectStore(IDBRequestData(operation), info);
 }
@@ -107,11 +106,37 @@ void IDBConnectionToServer::createObjectStore(TransactionOperation& operation, c
 void IDBConnectionToServer::didCreateObjectStore(const IDBResultData& resultData)
 {
     LOG(IndexedDB, "IDBConnectionToServer::didCreateObjectStore");
+    completeOperation(resultData);
+}
 
-    auto operation = m_activeOperations.take(resultData.requestIdentifier());
-    ASSERT(operation);
+void IDBConnectionToServer::putOrAdd(TransactionOperation& operation, RefPtr<IDBKey>& key, RefPtr<SerializedScriptValue>& value, const IndexedDB::ObjectStoreOverwriteMode overwriteMode)
+{
+    LOG(IndexedDB, "IDBConnectionToServer::putOrAdd");
 
-    operation->completed(resultData);
+    saveOperation(operation);
+    m_delegate->putOrAdd(IDBRequestData(operation), key.get(), *value, overwriteMode);
+}
+
+void IDBConnectionToServer::didPutOrAdd(const IDBResultData& resultData)
+{
+    LOG(IndexedDB, "IDBConnectionToServer::didPutOrAdd");
+    completeOperation(resultData);
+}
+
+void IDBConnectionToServer::getRecord(TransactionOperation& operation, RefPtr<IDBKey>& key)
+{
+    LOG(IndexedDB, "IDBConnectionToServer::getRecord");
+
+    ASSERT(key);
+
+    saveOperation(operation);
+    m_delegate->getRecord(IDBRequestData(operation), key.get());
+}
+
+void IDBConnectionToServer::didGetRecord(const IDBResultData& resultData)
+{
+    LOG(IndexedDB, "IDBConnectionToServer::didGetRecord");
+    completeOperation(resultData);
 }
 
 void IDBConnectionToServer::commitTransaction(IDBTransaction& transaction)
@@ -185,6 +210,20 @@ void IDBConnectionToServer::unregisterDatabaseConnection(IDBDatabase& database)
     m_databaseConnectionMap.remove(database.databaseConnectionIdentifier());
 }
 
+void IDBConnectionToServer::saveOperation(TransactionOperation& operation)
+{
+    ASSERT(!m_activeOperations.contains(operation.identifier()));
+    m_activeOperations.set(operation.identifier(), &operation);
+}
+
+void IDBConnectionToServer::completeOperation(const IDBResultData& resultData)
+{
+    auto operation = m_activeOperations.take(resultData.requestIdentifier());
+    ASSERT(operation);
+
+    operation->completed(resultData);
+}
+
 } // namespace IDBClient
 } // namespace WebCore
 
index 4305ea2..7e27848 100644 (file)
@@ -47,6 +47,7 @@ namespace IDBClient {
 class IDBDatabase;
 class IDBOpenDBRequest;
 class IDBTransaction;
+class TransactionOperation;
 
 class IDBConnectionToServer : public RefCounted<IDBConnectionToServer> {
 public:
@@ -63,6 +64,12 @@ public:
     void createObjectStore(TransactionOperation&, const IDBObjectStoreInfo&);
     void didCreateObjectStore(const IDBResultData&);
 
+    void putOrAdd(TransactionOperation&, RefPtr<IDBKey>&, RefPtr<SerializedScriptValue>&, const IndexedDB::ObjectStoreOverwriteMode);
+    void didPutOrAdd(const IDBResultData&);
+
+    void getRecord(TransactionOperation&, RefPtr<IDBKey>&);
+    void didGetRecord(const IDBResultData&);
+
     void commitTransaction(IDBTransaction&);
     void didCommitTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError&);
 
@@ -77,7 +84,10 @@ public:
 
 private:
     IDBConnectionToServer(IDBConnectionToServerDelegate&);
-    
+
+    void saveOperation(TransactionOperation&);
+    void completeOperation(const IDBResultData&);
+
     Ref<IDBConnectionToServerDelegate> m_delegate;
 
     HashMap<IDBResourceIdentifier, RefPtr<IDBClient::IDBOpenDBRequest>> m_openDBRequestMap;
index 09b2f01..ef268cb 100644 (file)
 
 namespace WebCore {
 
+class IDBKey;
 class IDBObjectStoreInfo;
 class IDBRequestData;
 class IDBResourceIdentifier;
+class SerializedScriptValue;
+
+namespace IndexedDB {
+enum class ObjectStoreOverwriteMode;
+}
 
 namespace IDBClient {
 
@@ -46,6 +52,9 @@ public:
     virtual void abortTransaction(IDBResourceIdentifier&) = 0;
     virtual void commitTransaction(IDBResourceIdentifier&) = 0;
     virtual void createObjectStore(const IDBRequestData&, const IDBObjectStoreInfo&) = 0;
+    virtual void putOrAdd(const IDBRequestData&, IDBKey*, SerializedScriptValue&, const IndexedDB::ObjectStoreOverwriteMode) = 0;
+    virtual void getRecord(const IDBRequestData&, IDBKey*) = 0;
+
     virtual void databaseConnectionClosed(uint64_t databaseConnectionIdentifier) = 0;
 
     virtual void ref() = 0;
index cf8cf14..4889b37 100644 (file)
 
 #if ENABLE(INDEXED_DATABASE)
 
+#include "DOMRequestState.h"
+#include "IDBBindingUtilities.h"
+#include "IDBError.h"
+#include "IDBKey.h"
+#include "IDBRequestImpl.h"
 #include "IDBTransactionImpl.h"
+#include "IndexedDB.h"
+#include "Logging.h"
+#include "SerializedScriptValue.h"
 
 namespace WebCore {
 namespace IDBClient {
@@ -80,7 +88,7 @@ RefPtr<WebCore::IDBTransaction> IDBObjectStore::transaction() const
 
 bool IDBObjectStore::autoIncrement() const
 {
-    RELEASE_ASSERT_NOT_REACHED();
+    return m_info.autoIncrement();
 }
 
 RefPtr<WebCore::IDBRequest> IDBObjectStore::add(JSC::ExecState&, Deprecated::ScriptValue&, ExceptionCode&)
@@ -88,9 +96,9 @@ RefPtr<WebCore::IDBRequest> IDBObjectStore::add(JSC::ExecState&, Deprecated::Scr
     RELEASE_ASSERT_NOT_REACHED();
 }
 
-RefPtr<WebCore::IDBRequest> IDBObjectStore::put(JSC::ExecState&, Deprecated::ScriptValue&, ExceptionCode&)
+RefPtr<WebCore::IDBRequest> IDBObjectStore::put(JSC::ExecState& state, Deprecated::ScriptValue& value, ExceptionCode& ec)
 {
-    RELEASE_ASSERT_NOT_REACHED();
+    return putOrAdd(state, value, nullptr, IndexedDB::ObjectStoreOverwriteMode::Overwrite, ec);
 }
 
 RefPtr<WebCore::IDBRequest> IDBObjectStore::openCursor(ScriptExecutionContext*, ExceptionCode&)
@@ -118,9 +126,34 @@ RefPtr<WebCore::IDBRequest> IDBObjectStore::openCursor(ScriptExecutionContext*,
     RELEASE_ASSERT_NOT_REACHED();
 }
 
-RefPtr<WebCore::IDBRequest> IDBObjectStore::get(ScriptExecutionContext*, const Deprecated::ScriptValue&, ExceptionCode&)
+RefPtr<WebCore::IDBRequest> IDBObjectStore::get(ScriptExecutionContext* context, const Deprecated::ScriptValue& key, ExceptionCode& ec)
 {
-    RELEASE_ASSERT_NOT_REACHED();
+    LOG(IndexedDB, "IDBObjectStore::get");
+
+    if (!context) {
+        ec = INVALID_STATE_ERR;
+        return nullptr;
+    }
+
+    if (!m_transaction->isActive()) {
+        ec = static_cast<ExceptionCode>(IDBExceptionCode::TransactionInactiveError);
+        return nullptr;
+    }
+
+    if (m_deleted) {
+        ec = INVALID_STATE_ERR;
+        return nullptr;
+    }
+
+    DOMRequestState requestState(context);
+    RefPtr<IDBKey> idbKey = scriptValueToIDBKey(&requestState, key);
+    if (!idbKey || idbKey->type() == KeyType::Invalid) {
+        ec = static_cast<ExceptionCode>(IDBExceptionCode::DataError);
+        return nullptr;
+    }
+
+    Ref<IDBRequest> request = m_transaction->requestGetRecord(*context, *this, *idbKey);
+    return adoptRef(request.leakRef());
 }
 
 RefPtr<WebCore::IDBRequest> IDBObjectStore::get(ScriptExecutionContext*, IDBKeyRange*, ExceptionCode&)
@@ -133,11 +166,94 @@ RefPtr<WebCore::IDBRequest> IDBObjectStore::add(JSC::ExecState&, Deprecated::Scr
     RELEASE_ASSERT_NOT_REACHED();
 }
 
-RefPtr<WebCore::IDBRequest> IDBObjectStore::put(JSC::ExecState&, Deprecated::ScriptValue&, const Deprecated::ScriptValue&, ExceptionCode&)
+RefPtr<WebCore::IDBRequest> IDBObjectStore::put(JSC::ExecState& execState, Deprecated::ScriptValue& value, const Deprecated::ScriptValue& key, ExceptionCode& ec)
 {
-    RELEASE_ASSERT_NOT_REACHED();
+    auto idbKey = scriptValueToIDBKey(execState, key);
+    return putOrAdd(execState, value, idbKey, IndexedDB::ObjectStoreOverwriteMode::NoOverwrite, ec);
 }
 
+RefPtr<WebCore::IDBRequest> IDBObjectStore::putOrAdd(JSC::ExecState& state, Deprecated::ScriptValue& value, RefPtr<IDBKey> key, IndexedDB::ObjectStoreOverwriteMode overwriteMode, ExceptionCode& ec)
+{
+    LOG(IndexedDB, "IDBObjectStore::putOrAdd");
+
+    if (m_transaction->isReadOnly()) {
+        ec = static_cast<ExceptionCode>(IDBExceptionCode::ReadOnlyError);
+        return nullptr;
+    }
+
+    if (!m_transaction->isActive()) {
+        ec = static_cast<ExceptionCode>(IDBExceptionCode::TransactionInactiveError);
+        return nullptr;
+    }
+
+    if (m_deleted) {
+        ec = INVALID_STATE_ERR;
+        return nullptr;
+    }
+
+    RefPtr<SerializedScriptValue> serializedValue = SerializedScriptValue::create(&state, value.jsValue(), nullptr, nullptr);
+    if (state.hadException()) {
+        ec = DATA_CLONE_ERR;
+        return nullptr;
+    }
+
+    if (serializedValue->hasBlobURLs()) {
+        // FIXME: Add Blob/File/FileList support
+        ec = DATA_CLONE_ERR;
+        return nullptr;
+    }
+
+    if (key && key->type() == KeyType::Invalid) {
+        ec = static_cast<ExceptionCode>(IDBExceptionCode::DataError);
+        return nullptr;
+    }
+
+    bool usesInlineKeys = !m_info.keyPath().isNull();
+    bool usesKeyGenerator = autoIncrement();
+    if (usesInlineKeys) {
+        if (key) {
+            ec = static_cast<ExceptionCode>(IDBExceptionCode::DataError);
+            return nullptr;
+        }
+
+        RefPtr<IDBKey> keyPathKey = maybeCreateIDBKeyFromScriptValueAndKeyPath(state, value, m_info.keyPath());
+        if (keyPathKey && !keyPathKey->isValid()) {
+            ec = static_cast<ExceptionCode>(IDBExceptionCode::DataError);
+            return nullptr;
+        }
+
+        if (!keyPathKey) {
+            if (usesKeyGenerator) {
+                if (!canInjectIDBKeyIntoScriptValue(state, value, m_info.keyPath())) {
+                    ec = static_cast<ExceptionCode>(IDBExceptionCode::DataError);
+                    return nullptr;
+                }
+            } else {
+                ec = static_cast<ExceptionCode>(IDBExceptionCode::DataError);
+                return nullptr;
+            }
+        }
+
+        if (keyPathKey) {
+            ASSERT(!key);
+            key = keyPathKey;
+        }
+    } else if (!usesKeyGenerator && !key) {
+        ec = static_cast<ExceptionCode>(IDBExceptionCode::DataError);
+        return nullptr;
+    }
+
+    auto context = scriptExecutionContextFromExecState(&state);
+    if (!context) {
+        ec = static_cast<ExceptionCode>(IDBExceptionCode::Unknown);
+        return nullptr;
+    }
+
+    Ref<IDBRequest> request = m_transaction->requestPutOrAdd(*context, *this, key.get(), *serializedValue, overwriteMode);
+    return adoptRef(request.leakRef());
+}
+
+
 RefPtr<WebCore::IDBRequest> IDBObjectStore::deleteFunction(ScriptExecutionContext*, IDBKeyRange*, ExceptionCode&)
 {
     RELEASE_ASSERT_NOT_REACHED();
index 5fdc986..bf82183 100644 (file)
 
 #include "IDBObjectStore.h"
 #include "IDBObjectStoreInfo.h"
+#include "IndexedDB.h"
 
 namespace WebCore {
+
+class IDBKey;
+
 namespace IDBClient {
 
 class IDBTransaction;
@@ -72,11 +76,17 @@ public:
     virtual RefPtr<WebCore::IDBRequest> count(ScriptExecutionContext*, IDBKeyRange*, ExceptionCode&) override final;
     virtual RefPtr<WebCore::IDBRequest> count(ScriptExecutionContext*, const Deprecated::ScriptValue& key, ExceptionCode&) override final;
 
+    const IDBObjectStoreInfo& info() const { return m_info; }
+
 private:
     IDBObjectStore(const IDBObjectStoreInfo&, IDBTransaction&);
 
+    RefPtr<WebCore::IDBRequest> putOrAdd(JSC::ExecState&, Deprecated::ScriptValue&, RefPtr<IDBKey>, IndexedDB::ObjectStoreOverwriteMode, ExceptionCode&);
+
     IDBObjectStoreInfo m_info;
     Ref<IDBTransaction> m_transaction;
+
+    bool m_deleted { false };
 };
 
 } // namespace IDBClient
index e012695..b6dbd3b 100644 (file)
@@ -55,7 +55,6 @@ IDBOpenDBRequest::IDBOpenDBRequest(IDBConnectionToServer& connection, ScriptExec
     , m_databaseIdentifier(databaseIdentifier)
     , m_version(version)
 {
-    suspendIfNeeded();
 }
 
 IDBOpenDBRequest::~IDBOpenDBRequest()
index b0f7947..e4c2cd4 100644 (file)
 #if ENABLE(INDEXED_DATABASE)
 
 #include "EventQueue.h"
+#include "IDBBindingUtilities.h"
+#include "IDBEventDispatcher.h"
+#include "IDBKeyData.h"
+#include "IDBResultData.h"
+#include "Logging.h"
 #include "ScriptExecutionContext.h"
+#include "ThreadSafeDataBuffer.h"
 #include <wtf/NeverDestroyed.h>
 
 namespace WebCore {
 namespace IDBClient {
 
+Ref<IDBRequest> IDBRequest::create(ScriptExecutionContext& context, IDBObjectStore& objectStore, IDBTransaction& transaction)
+{
+    return adoptRef(*new IDBRequest(context, objectStore, transaction));
+}
+
 IDBRequest::IDBRequest(IDBConnectionToServer& connection, ScriptExecutionContext* context)
     : IDBOpenDBRequest(context)
     , m_connection(connection)
     , m_resourceIdentifier(connection)
 {
+    suspendIfNeeded();
+}
+
+IDBRequest::IDBRequest(ScriptExecutionContext& context, IDBObjectStore& objectStore, IDBTransaction& transaction)
+    : IDBOpenDBRequest(&context)
+    , m_transaction(&transaction)
+    , m_connection(transaction.serverConnection())
+    , m_resourceIdentifier(transaction.serverConnection())
+    , m_source(adoptRef(*IDBAny::create(objectStore).leakRef()))
+{
+    suspendIfNeeded();
 }
 
 IDBRequest::~IDBRequest()
@@ -77,6 +99,18 @@ const String& IDBRequest::readyState() const
     return readyState;
 }
 
+uint64_t IDBRequest::sourceObjectStoreIdentifier() const
+{
+    if (!m_source)
+        return 0;
+    if (m_source->type() != IDBAny::Type::IDBObjectStore)
+        return 0;
+    if (!m_source->modernIDBObjectStore())
+        return 0;
+
+    return m_source->modernIDBObjectStore()->info().identifier();
+}
+
 EventTargetInterface IDBRequest::eventTargetInterface() const
 {
     return IDBRequestEventTargetInterfaceType;
@@ -92,6 +126,11 @@ bool IDBRequest::canSuspendForPageCache() const
     return false;
 }
 
+bool IDBRequest::hasPendingActivity() const
+{
+    return m_hasPendingActivity;
+}
+
 void IDBRequest::enqueueEvent(Ref<Event>&& event)
 {
     if (!scriptExecutionContext())
@@ -101,6 +140,82 @@ void IDBRequest::enqueueEvent(Ref<Event>&& event)
     scriptExecutionContext()->eventQueue().enqueueEvent(&event.get());
 }
 
+bool IDBRequest::dispatchEvent(PassRefPtr<Event> prpEvent)
+{
+    LOG(IndexedDB, "IDBRequest::dispatchEvent - %s", prpEvent->type().characters8());
+
+    RefPtr<Event> event = prpEvent;
+
+    if (event->type() != eventNames().blockedEvent)
+        m_readyState = IDBRequestReadyState::Done;
+
+    Vector<RefPtr<EventTarget>> targets;
+    targets.append(this);
+
+    if (m_transaction) {
+        targets.append(m_transaction);
+        targets.append(m_transaction->db());
+    }
+
+    bool dontPreventDefault;
+    {
+        TransactionActivator activator(m_transaction.get());
+        dontPreventDefault = IDBEventDispatcher::dispatch(event.get(), targets);
+    }
+
+    m_hasPendingActivity = false;
+
+    return dontPreventDefault;
+}
+
+void IDBRequest::setResult(const IDBKeyData* keyData)
+{
+    if (!keyData) {
+        m_result = nullptr;
+        return;
+    }
+
+    Deprecated::ScriptValue value = idbKeyDataToScriptValue(scriptExecutionContext(), *keyData);
+    m_result = IDBAny::create(WTF::move(value));
+}
+
+void IDBRequest::setResultToStructuredClone(const ThreadSafeDataBuffer& valueData)
+{
+    LOG(IndexedDB, "IDBRequest::setResultToStructuredClone");
+
+    auto context = scriptExecutionContext();
+    if (!context)
+        return;
+
+    Deprecated::ScriptValue value = deserializeIDBValueData(*context, valueData);
+    m_result = IDBAny::create(WTF::move(value));
+}
+
+void IDBRequest::requestCompleted(const IDBResultData& resultData)
+{
+    m_idbError = resultData.error();
+    if (!m_idbError.isNull())
+        onError();
+    else
+        onSuccess();
+}
+
+void IDBRequest::onError()
+{
+    LOG(IndexedDB, "IDBRequest::onError");
+
+    ASSERT(!m_idbError.isNull());
+    m_domError = DOMError::create(m_idbError.name());
+    enqueueEvent(Event::create(eventNames().errorEvent, true, true));
+}
+
+void IDBRequest::onSuccess()
+{
+    LOG(IndexedDB, "IDBRequest::onSuccess");
+
+    enqueueEvent(Event::create(eventNames().successEvent, false, false));
+}
+
 } // namespace IDBClient
 } // namespace WebCore
 
index d462411..1dffb12 100644 (file)
 namespace WebCore {
 
 class Event;
+class IDBKeyData;
 class IDBResultData;
+class ThreadSafeDataBuffer;
+
 
 namespace IDBClient {
 
@@ -45,6 +48,8 @@ class IDBConnectionToServer;
 
 class IDBRequest : public WebCore::IDBOpenDBRequest, public RefCounted<IDBRequest> {
 public:
+    static Ref<IDBRequest> create(ScriptExecutionContext&, IDBObjectStore&, IDBTransaction&);
+
     const IDBResourceIdentifier& resourceIdentifier() const { return m_resourceIdentifier; }
 
     virtual ~IDBRequest() override;
@@ -56,6 +61,8 @@ public:
     virtual RefPtr<WebCore::IDBTransaction> transaction() const override;
     virtual const String& readyState() const override;
 
+    uint64_t sourceObjectStoreIdentifier() const;
+
     // EventTarget
     virtual EventTargetInterface eventTargetInterface() const override;
     virtual ScriptExecutionContext* scriptExecutionContext() const override final { return ActiveDOMObject::scriptExecutionContext(); }
@@ -64,15 +71,23 @@ public:
     using RefCounted<IDBRequest>::deref;
 
     void enqueueEvent(Ref<Event>&&);
+    virtual bool dispatchEvent(PassRefPtr<Event>) override final;
 
     IDBConnectionToServer& connection() { return m_connection; }
 
+    void requestCompleted(const IDBResultData&);
+
+    void setResult(const IDBKeyData*);
+    void setResultToStructuredClone(const ThreadSafeDataBuffer&);
+
 protected:
     IDBRequest(IDBConnectionToServer&, ScriptExecutionContext*);
+    IDBRequest(ScriptExecutionContext&, IDBObjectStore&, IDBTransaction&);
 
     // ActiveDOMObject.
     virtual const char* activeDOMObjectName() const override final;
     virtual bool canSuspendForPageCache() const override final;
+    virtual bool hasPendingActivity() const override final;
     
     // EventTarget.
     virtual void refEventTarget() override final { RefCounted<IDBRequest>::ref(); }
@@ -82,10 +97,16 @@ protected:
     RefPtr<IDBAny> m_result;
     RefPtr<IDBTransaction> m_transaction;
     RefPtr<DOMError> m_domError;
+    IDBError m_idbError;
 
 private:
+    void onError();
+    void onSuccess();
+
     IDBConnectionToServer& m_connection;
     IDBResourceIdentifier m_resourceIdentifier;
+    RefPtr<IDBAny> m_source;
+    bool m_hasPendingActivity { true };
 };
 
 } // namespace IDBClient
index 82e5962..bc22b6f 100644 (file)
@@ -34,6 +34,7 @@
 #include "IDBError.h"
 #include "IDBEventDispatcher.h"
 #include "IDBObjectStore.h"
+#include "IDBRequestImpl.h"
 #include "IDBResultData.h"
 #include "Logging.h"
 #include "ScriptExecutionContext.h"
@@ -61,7 +62,7 @@ IDBTransaction::IDBTransaction(IDBDatabase& database, const IDBTransactionInfo&
         m_originalDatabaseInfo = std::make_unique<IDBDatabaseInfo>(m_database->info());
 
     suspendIfNeeded();
-    m_state = IndexedDB::TransactionState::Running;
+    m_state = IndexedDB::TransactionState::Inactive;
 }
 
 IDBTransaction::~IDBTransaction()
@@ -130,12 +131,15 @@ bool IDBTransaction::canSuspendForPageCache() const
 
 bool IDBTransaction::hasPendingActivity() const
 {
+    if (m_state == IndexedDB::TransactionState::Inactive)
+        return !m_transactionOperationQueue.isEmpty() || !m_transactionOperationMap.isEmpty();
+
     return m_state != IndexedDB::TransactionState::Finished;
 }
 
 bool IDBTransaction::isActive() const
 {
-    return m_state == IndexedDB::TransactionState::Running;
+    return m_state == IndexedDB::TransactionState::Active;
 }
 
 bool IDBTransaction::isFinishedOrFinishing() const
@@ -181,7 +185,7 @@ void IDBTransaction::operationTimerFired()
         return;
     }
 
-    if (isActive())
+    if (!isFinishedOrFinishing())
         commit();
 }
 
@@ -189,10 +193,8 @@ void IDBTransaction::commit()
 {
     LOG(IndexedDB, "IDBTransaction::commit");
 
-    if (m_state != IndexedDB::TransactionState::Running) {
-        m_state = IndexedDB::TransactionState::Finished;
+    if (isFinishedOrFinishing())
         return;
-    }
 
     m_state = IndexedDB::TransactionState::Committing;
 
@@ -211,7 +213,8 @@ void IDBTransaction::didAbort(const IDBError& error)
 {
     LOG(IndexedDB, "IDBTransaction::didAbort");
 
-    ASSERT(m_state == IndexedDB::TransactionState::Aborting || m_state == IndexedDB::TransactionState::Running);
+    if (m_state == IndexedDB::TransactionState::Finished)
+        return;
 
     m_database->didAbortTransaction(*this);
 
@@ -294,7 +297,7 @@ void IDBTransaction::createObjectStoreOnServer(TransactionOperation& operation,
 {
     LOG(IndexedDB, "IDBTransaction::createObjectStoreOnServer");
 
-    ASSERT(isActive());
+    ASSERT(!isFinishedOrFinishing());
     ASSERT(isVersionChange());
 
     m_database->serverConnection().createObjectStore(operation, info);
@@ -309,6 +312,84 @@ void IDBTransaction::didCreateObjectStoreOnServer(const IDBResultData& resultDat
     scheduleOperationTimer();
 }
 
+Ref<IDBRequest> IDBTransaction::requestGetRecord(ScriptExecutionContext& context, IDBObjectStore& objectStore, IDBKey& key)
+{
+    LOG(IndexedDB, "IDBTransaction::requestPutOrAdd");
+    ASSERT(isActive());
+    ASSERT(key.isValid());
+
+    Ref<IDBRequest> request = IDBRequest::create(context, objectStore, *this);
+
+    auto operation = createTransactionOperation(*this, request.get(), &IDBTransaction::didGetRecordOnServer, &IDBTransaction::getRecordOnServer, &key);
+    scheduleOperation(WTF::move(operation));
+
+    return WTF::move(request);
+}
+
+void IDBTransaction::getRecordOnServer(TransactionOperation& operation, RefPtr<IDBKey> key)
+{
+    LOG(IndexedDB, "IDBTransaction::getRecordOnServer");
+
+    ASSERT(!isFinishedOrFinishing());
+
+    serverConnection().getRecord(operation, key);
+}
+
+void IDBTransaction::didGetRecordOnServer(IDBRequest& request, const IDBResultData& resultData)
+{
+    LOG(IndexedDB, "IDBTransaction::didGetRecordOnServer");
+
+    request.setResultToStructuredClone(resultData.resultData());
+    request.requestCompleted(resultData);
+}
+
+Ref<IDBRequest> IDBTransaction::requestPutOrAdd(ScriptExecutionContext& context, IDBObjectStore& objectStore, IDBKey* key, SerializedScriptValue& value, IndexedDB::ObjectStoreOverwriteMode overwriteMode)
+{
+    LOG(IndexedDB, "IDBTransaction::requestPutOrAdd");
+    ASSERT(isActive());
+    ASSERT(!isReadOnly());
+    ASSERT(objectStore.info().autoIncrement() || key);
+
+    Ref<IDBRequest> request = IDBRequest::create(context, objectStore, *this);
+
+    auto operation = createTransactionOperation(*this, request.get(), &IDBTransaction::didPutOrAddOnServer, &IDBTransaction::putOrAddOnServer, key, &value, overwriteMode);
+    scheduleOperation(WTF::move(operation));
+
+    return WTF::move(request);
+}
+
+void IDBTransaction::putOrAddOnServer(TransactionOperation& operation, RefPtr<IDBKey> key, RefPtr<SerializedScriptValue> value, const IndexedDB::ObjectStoreOverwriteMode& overwriteMode)
+{
+    LOG(IndexedDB, "IDBTransaction::putOrAddOnServer");
+
+    ASSERT(!isFinishedOrFinishing());
+    ASSERT(!isReadOnly());
+
+    serverConnection().putOrAdd(operation, key, value, overwriteMode);
+}
+
+void IDBTransaction::didPutOrAddOnServer(IDBRequest& request, const IDBResultData& resultData)
+{
+    LOG(IndexedDB, "IDBTransaction::didPutOrAddOnServer");
+
+    request.setResult(resultData.resultKey());
+    request.requestCompleted(resultData);
+}
+
+void IDBTransaction::activate()
+{
+    ASSERT(m_state == IndexedDB::TransactionState::Unstarted || m_state == IndexedDB::TransactionState::Inactive);
+    m_state = IndexedDB::TransactionState::Active;
+}
+
+void IDBTransaction::deactivate()
+{
+    if (m_state == IndexedDB::TransactionState::Unstarted || m_state == IndexedDB::TransactionState::Active)
+        m_state = IndexedDB::TransactionState::Inactive;
+
+    scheduleOperationTimer();
+}
+
 } // namespace IDBClient
 } // namespace WebCore
 
index 5eb79a5..6408575 100644 (file)
@@ -81,12 +81,19 @@ public:
     void didCommit(const IDBError&);
 
     bool isVersionChange() const { return m_info.mode() == IndexedDB::TransactionMode::VersionChange; }
+    bool isReadOnly() const { return m_info.mode() == IndexedDB::TransactionMode::ReadOnly; }
     bool isActive() const;
 
     Ref<IDBObjectStore> createObjectStore(const IDBObjectStoreInfo&);
 
+    Ref<IDBRequest> requestPutOrAdd(ScriptExecutionContext&, IDBObjectStore&, IDBKey*, SerializedScriptValue&, IndexedDB::ObjectStoreOverwriteMode);
+    Ref<IDBRequest> requestGetRecord(ScriptExecutionContext&, IDBObjectStore&, IDBKey&);
+
     IDBConnectionToServer& serverConnection();
 
+    void activate();
+    void deactivate();
+
 private:
     IDBTransaction(IDBDatabase&, const IDBTransactionInfo&);
 
@@ -108,6 +115,12 @@ private:
     void createObjectStoreOnServer(TransactionOperation&, const IDBObjectStoreInfo&);
     void didCreateObjectStoreOnServer(const IDBResultData&);
 
+    void putOrAddOnServer(TransactionOperation&, RefPtr<IDBKey>, RefPtr<SerializedScriptValue>, const IndexedDB::ObjectStoreOverwriteMode&);
+    void didPutOrAddOnServer(IDBRequest&, const IDBResultData&);
+
+    void getRecordOnServer(TransactionOperation&, RefPtr<IDBKey>);
+    void didGetRecordOnServer(IDBRequest&, const IDBResultData&);
+
     Ref<IDBDatabase> m_database;
     IDBTransactionInfo m_info;
     std::unique_ptr<IDBDatabaseInfo> m_originalDatabaseInfo;
@@ -122,6 +135,26 @@ private:
     HashMap<IDBResourceIdentifier, RefPtr<TransactionOperation>> m_transactionOperationMap;
 };
 
+class TransactionActivator {
+    WTF_MAKE_NONCOPYABLE(TransactionActivator);
+public:
+    TransactionActivator(IDBTransaction* transaction)
+        : m_transaction(transaction)
+    {
+        if (m_transaction)
+            m_transaction->activate();
+    }
+
+    ~TransactionActivator()
+    {
+        if (m_transaction)
+            m_transaction->deactivate();
+    }
+
+private:
+    IDBTransaction* m_transaction;
+};
+
 } // namespace IDBClient
 } // namespace WebCore
 
diff --git a/Source/WebCore/Modules/indexeddb/client/TransactionOperation.cpp b/Source/WebCore/Modules/indexeddb/client/TransactionOperation.cpp
new file mode 100644 (file)
index 0000000..465649f
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * 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 "TransactionOperation.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+namespace IDBClient {
+
+TransactionOperation::TransactionOperation(IDBTransaction& transaction, IDBRequest& request)
+    : TransactionOperation(transaction)
+{
+    m_objectStoreIdentifier = request.sourceObjectStoreIdentifier();
+}
+
+} // namespace IDBClient
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
index 36440f6..9ddd5d7 100644 (file)
@@ -28,6 +28,7 @@
 
 #if ENABLE(INDEXED_DATABASE)
 
+#include "IDBRequestImpl.h"
 #include "IDBResourceIdentifier.h"
 #include "IDBTransactionImpl.h"
 
@@ -51,6 +52,8 @@ public:
 
     const IDBResourceIdentifier& identifier() const { return m_identifier; }
     IDBResourceIdentifier transactionIdentifier() const { return m_transaction->info().identifier(); }
+    uint64_t objectStoreIdentifier() const { return m_objectStoreIdentifier; }
+    IDBTransaction& transaction() { return m_transaction.get(); }
 
 protected:
     TransactionOperation(IDBTransaction& transaction)
@@ -59,8 +62,11 @@ protected:
     {
     }
 
+    TransactionOperation(IDBTransaction&, IDBRequest&);
+
     Ref<IDBTransaction> m_transaction;
     IDBResourceIdentifier m_identifier;
+    uint64_t m_objectStoreIdentifier { 0 };
     std::function<void ()> m_performFunction;
     std::function<void (const IDBResultData&)> m_completeFunction;
 };
@@ -81,6 +87,22 @@ public:
             (&m_transaction.get()->*completeMethod)(resultData);
         };
     }
+
+    TransactionOperationImpl(IDBTransaction& transaction, IDBRequest& request, void (IDBTransaction::*completeMethod)(IDBRequest&, const IDBResultData&), void (IDBTransaction::*performMethod)(TransactionOperation&, Arguments...), Arguments&&... arguments)
+        : TransactionOperation(transaction, request)
+    {
+        relaxAdoptionRequirement();
+
+        RefPtr<TransactionOperation> self(this);
+        m_performFunction = [self, this, performMethod, arguments...] {
+            (&m_transaction.get()->*performMethod)(*this, arguments...);
+        };
+
+        RefPtr<IDBRequest> refRequest(&request);
+        m_completeFunction = [self, this, refRequest, completeMethod](const IDBResultData& resultData) {
+            (&m_transaction.get()->*completeMethod)(*refRequest, resultData);
+        };
+    }
 };
 
 template<typename MP1, typename P1>
@@ -94,6 +116,32 @@ RefPtr<TransactionOperation> createTransactionOperation(
     return adoptRef(operation);
 }
 
+template<typename MP1, typename P1>
+RefPtr<TransactionOperation> createTransactionOperation(
+    IDBTransaction& transaction,
+    IDBRequest& request,
+    void (IDBTransaction::*complete)(IDBRequest&, const IDBResultData&),
+    void (IDBTransaction::*perform)(TransactionOperation&, MP1),
+    const P1& parameter1)
+{
+    auto operation = new TransactionOperationImpl<MP1>(transaction, request, complete, perform, parameter1);
+    return adoptRef(operation);
+}
+
+template<typename MP1, typename MP2, typename MP3, typename P1, typename P2, typename P3>
+RefPtr<TransactionOperation> createTransactionOperation(
+    IDBTransaction& transaction,
+    IDBRequest& request,
+    void (IDBTransaction::*complete)(IDBRequest&, const IDBResultData&),
+    void (IDBTransaction::*perform)(TransactionOperation&, MP1, MP2, MP3),
+    const P1& parameter1,
+    const P2& parameter2,
+    const P3& parameter3)
+{
+    auto operation = new TransactionOperationImpl<MP1, MP2, MP3>(transaction, request, complete, perform, parameter1, parameter2, parameter3);
+    return adoptRef(operation);
+}
+
 } // namespace IDBClient
 } // namespace WebCore
 
index 7e3e5c0..87c84b9 100644 (file)
 
 namespace WebCore {
 
+class IDBKeyData;
 class IDBObjectStoreInfo;
 class IDBResourceIdentifier;
 class IDBTransactionInfo;
+class ThreadSafeDataBuffer;
 
 namespace IDBServer {
 
@@ -50,6 +52,10 @@ public:
     virtual IDBError commitTransaction(const IDBResourceIdentifier& transactionIdentifier) = 0;
 
     virtual IDBError createObjectStore(const IDBResourceIdentifier& transactionIdentifier, const IDBObjectStoreInfo&) = 0;
+    virtual IDBError keyExistsInObjectStore(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyData&, bool& keyExists) = 0;
+    virtual IDBError deleteRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyData&) = 0;
+    virtual IDBError putRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyData&, const ThreadSafeDataBuffer& value) = 0;
+    virtual IDBError getRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyData&, ThreadSafeDataBuffer& outValue) = 0;
 };
 
 } // namespace IDBServer
index f98537e..431a4fd 100644 (file)
@@ -68,6 +68,16 @@ void IDBConnectionToClient::didCreateObjectStore(const IDBResultData& result)
     m_delegate->didCreateObjectStore(result);
 }
 
+void IDBConnectionToClient::didPutOrAdd(const IDBResultData& result)
+{
+    m_delegate->didPutOrAdd(result);
+}
+
+void IDBConnectionToClient::didGetRecord(const IDBResultData& result)
+{
+    m_delegate->didGetRecord(result);
+}
+
 void IDBConnectionToClient::didCommitTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError& error)
 {
     m_delegate->didCommitTransaction(transactionIdentifier, error);
index 25ce512..bff856e 100644 (file)
@@ -53,6 +53,8 @@ public:
     void didAbortTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError&);
     void didCommitTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError&);
     void didCreateObjectStore(const IDBResultData&);
+    void didPutOrAdd(const IDBResultData&);
+    void didGetRecord(const IDBResultData&);
 
     void fireVersionChangeEvent(UniqueIDBDatabaseConnection&, uint64_t requestedVersion);
 
index ca7887c..1027f4f 100644 (file)
@@ -49,6 +49,8 @@ public:
     virtual void didAbortTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError&) = 0;
     virtual void didCommitTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError&) = 0;
     virtual void didCreateObjectStore(const IDBResultData&) = 0;
+    virtual void didPutOrAdd(const IDBResultData&) = 0;
+    virtual void didGetRecord(const IDBResultData&) = 0;
 
     virtual void fireVersionChangeEvent(UniqueIDBDatabaseConnection&, uint64_t requestedVersion) = 0;
 
index 49302f9..1c40184 100644 (file)
@@ -168,6 +168,28 @@ void IDBServer::createObjectStore(const IDBRequestData& requestData, const IDBOb
     transaction->createObjectStore(requestData, info);
 }
 
+void IDBServer::putOrAdd(const IDBRequestData& requestData, const IDBKeyData& keyData, const ThreadSafeDataBuffer& valueData, IndexedDB::ObjectStoreOverwriteMode overwriteMode)
+{
+    LOG(IndexedDB, "IDBServer::putOrAdd");
+
+    auto transaction = m_transactions.get(requestData.transactionIdentifier());
+    if (!transaction)
+        return;
+
+    transaction->putOrAdd(requestData, keyData, valueData, overwriteMode);
+}
+
+void IDBServer::getRecord(const IDBRequestData& requestData, const IDBKeyData& keyData)
+{
+    LOG(IndexedDB, "IDBServer::getRecord");
+
+    auto transaction = m_transactions.get(requestData.transactionIdentifier());
+    if (!transaction)
+        return;
+
+    transaction->getRecord(requestData, keyData);
+}
+
 void IDBServer::commitTransaction(const IDBResourceIdentifier& transactionIdentifier)
 {
     LOG(IndexedDB, "IDBServer::commitTransaction");
index 4d2a83c..ff2696c 100644 (file)
@@ -60,6 +60,8 @@ public:
     void abortTransaction(const IDBResourceIdentifier&);
     void commitTransaction(const IDBResourceIdentifier&);
     void createObjectStore(const IDBRequestData&, const IDBObjectStoreInfo&);
+    void putOrAdd(const IDBRequestData&, const IDBKeyData&, const ThreadSafeDataBuffer& valueData, IndexedDB::ObjectStoreOverwriteMode);
+    void getRecord(const IDBRequestData&, const IDBKeyData&);
     void databaseConnectionClosed(uint64_t databaseConnectionIdentifier);
 
     void postDatabaseTask(std::unique_ptr<CrossThreadTask>&&);
index 5c4477f..c564ad6 100644 (file)
@@ -32,6 +32,7 @@
 #include "Logging.h"
 #include "MemoryIDBBackingStore.h"
 #include "MemoryObjectStore.h"
+#include <wtf/TemporaryChange.h>
 
 namespace WebCore {
 namespace IDBServer {
@@ -67,15 +68,51 @@ void MemoryBackingStoreTransaction::addNewObjectStore(MemoryObjectStore& objectS
     objectStore.writeTransactionStarted(*this);
 }
 
+void MemoryBackingStoreTransaction::recordValueChanged(MemoryObjectStore& objectStore, const IDBKeyData& key)
+{
+    ASSERT(m_objectStores.contains(&objectStore));
+
+    if (m_isAborting)
+        return;
+
+    auto originalAddResult = m_originalValues.add(&objectStore, nullptr);
+    if (originalAddResult.isNewEntry)
+        originalAddResult.iterator->value = std::make_unique<KeyValueMap>();
+
+    auto* map = originalAddResult.iterator->value.get();
+
+    auto addResult = map->add(key, ThreadSafeDataBuffer());
+    if (!addResult.isNewEntry)
+        return;
+
+    addResult.iterator->value = objectStore.valueForKey(key);
+}
+
 void MemoryBackingStoreTransaction::abort()
 {
     LOG(IndexedDB, "MemoryBackingStoreTransaction::abort()");
 
+    TemporaryChange<bool> change(m_isAborting, true);
+
     if (m_originalDatabaseInfo) {
         ASSERT(m_info.mode() == IndexedDB::TransactionMode::VersionChange);
         m_backingStore.setDatabaseInfo(*m_originalDatabaseInfo);
     }
 
+    for (auto objectStore : m_objectStores) {
+        auto keyValueMap = m_originalValues.get(objectStore);
+        if (!keyValueMap)
+            continue;
+
+        for (auto entry : *keyValueMap) {
+            objectStore->deleteRecord(entry.key);
+            objectStore->setKeyValue(entry.key, entry.value);
+        }
+
+        m_originalValues.remove(objectStore);
+    }
+
+
     finish();
 
     for (auto objectStore : m_versionChangeAddedObjectStores)
index aa8aa60..295bbca 100644 (file)
 #if ENABLE(INDEXED_DATABASE)
 
 #include "IDBDatabaseInfo.h"
+#include "IDBKeyData.h"
 #include "IDBTransactionInfo.h"
+#include "ThreadSafeDataBuffer.h"
+#include <wtf/HashMap.h>
 #include <wtf/HashSet.h>
 
 namespace WebCore {
@@ -38,6 +41,8 @@ namespace IDBServer {
 class MemoryIDBBackingStore;
 class MemoryObjectStore;
 
+typedef HashMap<IDBKeyData, ThreadSafeDataBuffer, IDBKeyDataHash, IDBKeyDataHashTraits> KeyValueMap;
+
 class MemoryBackingStoreTransaction {
     friend std::unique_ptr<MemoryBackingStoreTransaction> std::make_unique<MemoryBackingStoreTransaction>(WebCore::IDBServer::MemoryIDBBackingStore&, const WebCore::IDBTransactionInfo&);
 public:
@@ -51,6 +56,7 @@ public:
     const IDBDatabaseInfo& originalDatabaseInfo() const;
 
     void addNewObjectStore(MemoryObjectStore&);
+    void recordValueChanged(MemoryObjectStore&, const IDBKeyData&);
 
     void abort();
     void commit();
@@ -66,10 +72,13 @@ private:
     std::unique_ptr<IDBDatabaseInfo> m_originalDatabaseInfo;
 
     bool m_inProgress { true };
+    bool m_isAborting { false };
 
     HashSet<MemoryObjectStore*> m_objectStores;
     HashSet<MemoryObjectStore*> m_versionChangeAddedObjectStores;
 
+    HashMap<MemoryObjectStore*, std::unique_ptr<KeyValueMap>> m_originalValues;
+
 };
 
 } // namespace IDBServer
index 8572bd3..fe2fa18 100644 (file)
@@ -136,6 +136,69 @@ void MemoryIDBBackingStore::removeObjectStoreForVersionChangeAbort(MemoryObjectS
     m_objectStores.remove(objectStore.info().identifier());
 }
 
+
+IDBError MemoryIDBBackingStore::keyExistsInObjectStore(const IDBResourceIdentifier&, uint64_t objectStoreIdentifier, const IDBKeyData& keyData, bool& keyExists)
+{
+    LOG(IndexedDB, "MemoryIDBBackingStore::keyExistsInObjectStore");
+
+    ASSERT(objectStoreIdentifier);
+
+    MemoryObjectStore* objectStore = m_objectStores.get(objectStoreIdentifier);
+    RELEASE_ASSERT(objectStore);
+
+    keyExists = objectStore->containsRecord(keyData);
+    return IDBError();
+}
+
+IDBError MemoryIDBBackingStore::deleteRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyData& keyData)
+{
+    LOG(IndexedDB, "MemoryIDBBackingStore::deleteRecord");
+
+    ASSERT(objectStoreIdentifier);
+
+    MemoryObjectStore* objectStore = m_objectStores.get(objectStoreIdentifier);
+    RELEASE_ASSERT(objectStore);
+    RELEASE_ASSERT(m_transactions.contains(transactionIdentifier));
+
+    objectStore->deleteRecord(keyData);
+    return IDBError();
+}
+
+IDBError MemoryIDBBackingStore::putRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyData& keyData, const ThreadSafeDataBuffer& value)
+{
+    LOG(IndexedDB, "MemoryIDBBackingStore::putRecord");
+
+    ASSERT(objectStoreIdentifier);
+
+    auto transaction = m_transactions.get(transactionIdentifier);
+    if (!transaction)
+        return IDBError(IDBExceptionCode::Unknown, WTF::ASCIILiteral("No backing store transaction found to get record"));
+
+    MemoryObjectStore* objectStore = m_objectStores.get(objectStoreIdentifier);
+    if (!objectStore)
+        return IDBError(IDBExceptionCode::Unknown, WTF::ASCIILiteral("No backing store object store found to put record"));
+
+    objectStore->putRecord(*transaction, keyData, value);
+    return IDBError();
+}
+
+IDBError MemoryIDBBackingStore::getRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyData& keyData, ThreadSafeDataBuffer& outValue)
+{
+    LOG(IndexedDB, "MemoryIDBBackingStore::getRecord");
+
+    ASSERT(objectStoreIdentifier);
+
+    if (!m_transactions.contains(transactionIdentifier))
+        return IDBError(IDBExceptionCode::Unknown, WTF::ASCIILiteral("No backing store transaction found to get record"));
+
+    MemoryObjectStore* objectStore = m_objectStores.get(objectStoreIdentifier);
+    if (!objectStore)
+        return IDBError(IDBExceptionCode::Unknown, WTF::ASCIILiteral("No backing store object store found"));
+
+    outValue = objectStore->valueForKey(keyData);
+    return IDBError();
+}
+
 } // namespace IDBServer
 } // namespace WebCore
 
index 26958fd..4318715 100644 (file)
@@ -53,6 +53,10 @@ public:
     virtual IDBError abortTransaction(const IDBResourceIdentifier& transactionIdentifier) override final;
     virtual IDBError commitTransaction(const IDBResourceIdentifier& transactionIdentifier) override final;
     virtual IDBError createObjectStore(const IDBResourceIdentifier& transactionIdentifier, const IDBObjectStoreInfo&) override final;
+    virtual IDBError keyExistsInObjectStore(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyData&, bool& keyExists) override final;
+    virtual IDBError deleteRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyData&) override final;
+    virtual IDBError putRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyData&, const ThreadSafeDataBuffer& value) override final;
+    virtual IDBError getRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyData&, ThreadSafeDataBuffer& outValue) override final;
 
     void removeObjectStoreForVersionChangeAbort(MemoryObjectStore&);
 
index dfac780..145c89e 100644 (file)
@@ -29,6 +29,7 @@
 #if ENABLE(INDEXED_DATABASE)
 
 #include "Logging.h"
+#include "MemoryBackingStoreTransaction.h"
 
 namespace WebCore {
 namespace IDBServer {
@@ -64,6 +65,61 @@ void MemoryObjectStore::writeTransactionFinished(MemoryBackingStoreTransaction&
     m_writeTransaction = nullptr;
 }
 
+bool MemoryObjectStore::containsRecord(const IDBKeyData& key)
+{
+    if (!m_keyValueStore)
+        return false;
+
+    return m_keyValueStore->contains(key);
+}
+
+void MemoryObjectStore::deleteRecord(const IDBKeyData& key)
+{
+    LOG(IndexedDB, "MemoryObjectStore::deleteRecord");
+
+    ASSERT(m_writeTransaction);
+    m_writeTransaction->recordValueChanged(*this, key);
+
+    if (!m_keyValueStore)
+        return;
+
+    m_keyValueStore->remove(key);
+    if (m_orderedKeys)
+        m_orderedKeys->erase(key);
+}
+
+void MemoryObjectStore::putRecord(MemoryBackingStoreTransaction& transaction, const IDBKeyData& keyData, const ThreadSafeDataBuffer& value)
+{
+    LOG(IndexedDB, "MemoryObjectStore::putRecord");
+
+    ASSERT(m_writeTransaction);
+    ASSERT_UNUSED(transaction, m_writeTransaction == &transaction);
+
+    m_writeTransaction->recordValueChanged(*this, keyData);
+
+    setKeyValue(keyData, value);
+}
+
+void MemoryObjectStore::setKeyValue(const IDBKeyData& keyData, const ThreadSafeDataBuffer& value)
+{
+    if (!m_keyValueStore)
+        m_keyValueStore = std::make_unique<KeyValueMap>();
+
+    auto result = m_keyValueStore->set(keyData, value);
+    if (result.isNewEntry && m_orderedKeys)
+        m_orderedKeys->insert(keyData);
+}
+
+ThreadSafeDataBuffer MemoryObjectStore::valueForKey(const IDBKeyData& keyData) const
+{
+    LOG(IndexedDB, "MemoryObjectStore::valueForKey");
+
+    if (!m_keyValueStore)
+        return ThreadSafeDataBuffer();
+
+    return m_keyValueStore->get(keyData);
+}
+
 } // namespace IDBServer
 } // namespace WebCore
 
index 31e2e4d..c246ab4 100644 (file)
 
 #if ENABLE(INDEXED_DATABASE)
 
+#include "IDBKeyData.h"
 #include "IDBObjectStoreInfo.h"
+#include "ThreadSafeDataBuffer.h"
+#include <set>
+#include <wtf/HashMap.h>
 
 namespace WebCore {
+
+class IDBKeyData;
+
 namespace IDBServer {
 
 class MemoryBackingStoreTransaction;
 
+typedef HashMap<IDBKeyData, ThreadSafeDataBuffer, IDBKeyDataHash, IDBKeyDataHashTraits> KeyValueMap;
+
 class MemoryObjectStore {
     friend std::unique_ptr<MemoryObjectStore> std::make_unique<MemoryObjectStore>(const WebCore::IDBObjectStoreInfo&);
 public:
@@ -45,6 +54,14 @@ public:
     void writeTransactionStarted(MemoryBackingStoreTransaction&);
     void writeTransactionFinished(MemoryBackingStoreTransaction&);
 
+    bool containsRecord(const IDBKeyData&);
+    void deleteRecord(const IDBKeyData&);
+    void putRecord(MemoryBackingStoreTransaction&, const IDBKeyData&, const ThreadSafeDataBuffer& value);
+
+    void setKeyValue(const IDBKeyData&, const ThreadSafeDataBuffer& value);
+
+    ThreadSafeDataBuffer valueForKey(const IDBKeyData&) const;
+
     const IDBObjectStoreInfo& info() const { return m_info; }
 
 private:
@@ -53,6 +70,9 @@ private:
     IDBObjectStoreInfo m_info;
 
     MemoryBackingStoreTransaction* m_writeTransaction { nullptr };
+
+    std::unique_ptr<KeyValueMap> m_keyValueStore;
+    std::unique_ptr<std::set<IDBKeyData>> m_orderedKeys;
 };
 
 } // namespace IDBServer
index 56236d0..68ff5f1 100644 (file)
@@ -139,6 +139,20 @@ uint64_t UniqueIDBDatabase::storeCallback(ErrorCallback callback)
     return identifier;
 }
 
+uint64_t UniqueIDBDatabase::storeCallback(KeyDataCallback callback)
+{
+    uint64_t identifier = generateUniqueCallbackIdentifier();
+    m_keyDataCallbacks.set(identifier, callback);
+    return identifier;
+}
+
+uint64_t UniqueIDBDatabase::storeCallback(ValueDataCallback callback)
+{
+    uint64_t identifier = generateUniqueCallbackIdentifier();
+    m_valueDataCallbacks.set(identifier, callback);
+    return identifier;
+}
+
 void UniqueIDBDatabase::startVersionChangeTransaction()
 {
     LOG(IndexedDB, "(main) UniqueIDBDatabase::startVersionChangeTransaction");
@@ -251,6 +265,108 @@ void UniqueIDBDatabase::didPerformCreateObjectStore(uint64_t callbackIdentifier,
     performErrorCallback(callbackIdentifier, error);
 }
 
+void UniqueIDBDatabase::putOrAdd(const IDBRequestData& requestData, const IDBKeyData& keyData, const ThreadSafeDataBuffer& valueData, IndexedDB::ObjectStoreOverwriteMode overwriteMode, KeyDataCallback callback)
+{
+    ASSERT(isMainThread());
+    LOG(IndexedDB, "(main) UniqueIDBDatabase::putOrAdd");
+
+    uint64_t callbackID = storeCallback(callback);
+    m_server.postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performPutOrAdd, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), keyData, valueData, overwriteMode));
+}
+
+void UniqueIDBDatabase::performPutOrAdd(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyData& keyData, const ThreadSafeDataBuffer& valueData, IndexedDB::ObjectStoreOverwriteMode overwriteMode)
+{
+    ASSERT(!isMainThread());
+    LOG(IndexedDB, "(db) UniqueIDBDatabase::performPutOrAdd");
+
+    ASSERT(m_backingStore);
+    ASSERT(objectStoreIdentifier);
+
+    IDBKeyData usedKey;
+    IDBError error;
+
+    auto objectStoreInfo = m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
+    if (!objectStoreInfo) {
+        error = IDBError(IDBExceptionCode::InvalidStateError, ASCIILiteral("Object store cannot be found in the backing store"));
+        m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));
+        return;
+    }
+
+    if (objectStoreInfo->autoIncrement() && !keyData.isValid()) {
+        // FIXME: This is where generated key support goes
+        error = IDBError(IDBExceptionCode::Unknown, ASCIILiteral("Key generators not supported yet"));
+        m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));
+        return;
+    }
+
+    usedKey = keyData;
+
+    if (overwriteMode == IndexedDB::ObjectStoreOverwriteMode::NoOverwrite) {
+        bool keyExists;
+        error = m_backingStore->keyExistsInObjectStore(transactionIdentifier, objectStoreIdentifier, usedKey, keyExists);
+        if (error.isNull() && keyExists)
+            error = IDBError(IDBExceptionCode::ConstraintError, ASCIILiteral("Key already exists in the object store"));
+
+        if (!error.isNull()) {
+            m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));
+            return;
+        }
+    }
+
+    // 3.4.1 Object Store Storage Operation
+    // ...If a record already exists in store ...
+    // then remove the record from store using the steps for deleting records from an object store...
+    // This is important because formally deleting it from from the object store also removes it from the appropriate indexes.
+    error = m_backingStore->deleteRecord(transactionIdentifier, objectStoreIdentifier, usedKey);
+    if (!error.isNull()) {
+        m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));
+        return;
+    }
+
+    error = m_backingStore->putRecord(transactionIdentifier, objectStoreIdentifier, usedKey, valueData);
+
+    m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));
+}
+
+void UniqueIDBDatabase::didPerformPutOrAdd(uint64_t callbackIdentifier, const IDBError& error, const IDBKeyData& resultKey)
+{
+    ASSERT(isMainThread());
+    LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformPutOrAdd");
+
+    performKeyDataCallback(callbackIdentifier, error, resultKey);
+}
+
+void UniqueIDBDatabase::getRecord(const IDBRequestData& requestData, const IDBKeyData& keyData, ValueDataCallback callback)
+{
+    ASSERT(isMainThread());
+    LOG(IndexedDB, "(main) UniqueIDBDatabase::getRecord");
+
+    uint64_t callbackID = storeCallback(callback);
+    m_server.postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performGetRecord, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), keyData));
+}
+
+void UniqueIDBDatabase::performGetRecord(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyData& keyData)
+{
+    ASSERT(!isMainThread());
+    LOG(IndexedDB, "(db) UniqueIDBDatabase::performGetRecord");
+
+    ASSERT(m_backingStore);
+    ASSERT(objectStoreIdentifier);
+
+    ThreadSafeDataBuffer valueData;
+    IDBError error = m_backingStore->getRecord(transactionIdentifier, objectStoreIdentifier, keyData, valueData);
+
+    m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformGetRecord, callbackIdentifier, error, valueData));
+}
+
+void UniqueIDBDatabase::didPerformGetRecord(uint64_t callbackIdentifier, const IDBError& error, const ThreadSafeDataBuffer& resultData)
+{
+    ASSERT(isMainThread());
+    LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformGetRecord");
+
+    performValueDataCallback(callbackIdentifier, error, resultData);
+}
+
 void UniqueIDBDatabase::commitTransaction(UniqueIDBDatabaseTransaction& transaction, ErrorCallback callback)
 {
     ASSERT(isMainThread());
@@ -380,6 +496,20 @@ void UniqueIDBDatabase::performErrorCallback(uint64_t callbackIdentifier, const
     callback(error);
 }
 
+void UniqueIDBDatabase::performKeyDataCallback(uint64_t callbackIdentifier, const IDBError& error, const IDBKeyData& resultKey)
+{
+    auto callback = m_keyDataCallbacks.take(callbackIdentifier);
+    ASSERT(callback);
+    callback(error, resultKey);
+}
+
+void UniqueIDBDatabase::performValueDataCallback(uint64_t callbackIdentifier, const IDBError& error, const ThreadSafeDataBuffer& resultData)
+{
+    auto callback = m_valueDataCallbacks.take(callbackIdentifier);
+    ASSERT(callback);
+    callback(error, resultData);
+}
+
 } // namespace IDBServer
 } // namespace WebCore
 
index 790db1e..2b390f0 100644 (file)
@@ -32,6 +32,7 @@
 #include "IDBDatabaseIdentifier.h"
 #include "IDBDatabaseInfo.h"
 #include "IDBServerOperation.h"
+#include "ThreadSafeDataBuffer.h"
 #include "Timer.h"
 #include "UniqueIDBDatabaseConnection.h"
 #include "UniqueIDBDatabaseTransaction.h"
@@ -52,6 +53,8 @@ class IDBConnectionToClient;
 class IDBServer;
 
 typedef std::function<void(const IDBError&)> ErrorCallback;
+typedef std::function<void(const IDBError&, const IDBKeyData&)> KeyDataCallback;
+typedef std::function<void(const IDBError&, const ThreadSafeDataBuffer&)> ValueDataCallback;
 
 class UniqueIDBDatabase : public ThreadSafeRefCounted<UniqueIDBDatabase> {
 public:
@@ -66,6 +69,8 @@ public:
     IDBServer& server() { return m_server; }
 
     void createObjectStore(UniqueIDBDatabaseTransaction&, const IDBObjectStoreInfo&, ErrorCallback);
+    void putOrAdd(const IDBRequestData&, const IDBKeyData&, const ThreadSafeDataBuffer& valueData, IndexedDB::ObjectStoreOverwriteMode, KeyDataCallback);
+    void getRecord(const IDBRequestData&, const IDBKeyData&, ValueDataCallback);
     void commitTransaction(UniqueIDBDatabaseTransaction&, ErrorCallback);
     void abortTransaction(UniqueIDBDatabaseTransaction&, ErrorCallback);
     void transactionDestroyed(UniqueIDBDatabaseTransaction&);
@@ -81,22 +86,30 @@ private:
     void startVersionChangeTransaction();
     void notifyConnectionsOfVersionChange();
 
-    uint64_t storeCallback(ErrorCallback);
-    
     // Database thread operations
     void openBackingStore(const IDBDatabaseIdentifier&);
     void performCommitTransaction(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier);
     void performAbortTransaction(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier);
     void beginTransactionInBackingStore(const IDBTransactionInfo&);
     void performCreateObjectStore(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, const IDBObjectStoreInfo&);
+    void performPutOrAdd(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyData&, const ThreadSafeDataBuffer& valueData, IndexedDB::ObjectStoreOverwriteMode);
+    void performGetRecord(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyData&);
 
     // Main thread callbacks
     void didOpenBackingStore(const IDBDatabaseInfo&);
     void didPerformCreateObjectStore(uint64_t callbackIdentifier, const IDBError&, const IDBObjectStoreInfo&);
+    void didPerformPutOrAdd(uint64_t callbackIdentifier, const IDBError&, const IDBKeyData&);
+    void didPerformGetRecord(uint64_t callbackIdentifier, const IDBError&, const ThreadSafeDataBuffer&);
     void didPerformCommitTransaction(uint64_t callbackIdentifier, const IDBError&);
     void didPerformAbortTransaction(uint64_t callbackIdentifier, const IDBError&, const IDBResourceIdentifier& transactionIdentifier);
 
+    uint64_t storeCallback(ErrorCallback);
+    uint64_t storeCallback(KeyDataCallback);
+    uint64_t storeCallback(ValueDataCallback);
+
     void performErrorCallback(uint64_t callbackIdentifier, const IDBError&);
+    void performKeyDataCallback(uint64_t callbackIdentifier, const IDBError&, const IDBKeyData&);
+    void performValueDataCallback(uint64_t callbackIdentifier, const IDBError&, const ThreadSafeDataBuffer&);
 
     void invokeTransactionScheduler();
     void transactionSchedulingTimerFired();
@@ -117,6 +130,8 @@ private:
     std::unique_ptr<IDBDatabaseInfo> m_databaseInfo;
 
     HashMap<uint64_t, ErrorCallback> m_errorCallbacks;
+    HashMap<uint64_t, KeyDataCallback> m_keyDataCallbacks;
+    HashMap<uint64_t, ValueDataCallback> m_valueDataCallbacks;
 
     Timer m_transactionSchedulingTimer;
 };
index 89c2a6c..cbf6a6e 100644 (file)
@@ -80,6 +80,11 @@ bool UniqueIDBDatabaseTransaction::isVersionChange() const
     return m_transactionInfo.mode() == IndexedDB::TransactionMode::VersionChange;
 }
 
+bool UniqueIDBDatabaseTransaction::isReadOnly() const
+{
+    return m_transactionInfo.mode() == IndexedDB::TransactionMode::ReadOnly;
+}   
+
 void UniqueIDBDatabaseTransaction::commit()
 {
     LOG(IndexedDB, "UniqueIDBDatabaseTransaction::commit");
@@ -108,6 +113,41 @@ void UniqueIDBDatabaseTransaction::createObjectStore(const IDBRequestData& reque
     });
 }
 
+void UniqueIDBDatabaseTransaction::putOrAdd(const IDBRequestData& requestData, const IDBKeyData& keyData, const ThreadSafeDataBuffer& valueData, IndexedDB::ObjectStoreOverwriteMode overwriteMode)
+{
+    LOG(IndexedDB, "UniqueIDBDatabaseTransaction::putOrAdd");
+
+    ASSERT(!isReadOnly());
+    ASSERT(m_transactionInfo.identifier() == requestData.transactionIdentifier());
+
+    RefPtr<UniqueIDBDatabaseTransaction> self(this);
+    m_databaseConnection->database().putOrAdd(requestData, keyData, valueData, overwriteMode, [this, self, requestData](const IDBError& error, const IDBKeyData& key) {
+        LOG(IndexedDB, "UniqueIDBDatabaseTransaction::putOrAdd (callback)");
+
+        if (error.isNull())
+            m_databaseConnection->connectionToClient().didPutOrAdd(IDBResultData::putOrAddSuccess(requestData.requestIdentifier(), key));
+        else
+            m_databaseConnection->connectionToClient().didPutOrAdd(IDBResultData::error(requestData.requestIdentifier(), error));
+    });
+}
+
+void UniqueIDBDatabaseTransaction::getRecord(const IDBRequestData& requestData, const IDBKeyData& keyData)
+{
+    LOG(IndexedDB, "UniqueIDBDatabaseTransaction::getRecord");
+
+    ASSERT(m_transactionInfo.identifier() == requestData.transactionIdentifier());
+
+    RefPtr<UniqueIDBDatabaseTransaction> self(this);
+    m_databaseConnection->database().getRecord(requestData, keyData, [this, self, requestData](const IDBError& error, const ThreadSafeDataBuffer& valueData) {
+        LOG(IndexedDB, "UniqueIDBDatabaseTransaction::getRecord (callback)");
+
+        if (error.isNull())
+            m_databaseConnection->connectionToClient().didGetRecord(IDBResultData::getRecordSuccess(requestData.requestIdentifier(), valueData));
+        else
+            m_databaseConnection->connectionToClient().didGetRecord(IDBResultData::error(requestData.requestIdentifier(), error));
+    });
+}
+
 } // namespace IDBServer
 } // namespace WebCore
 
index 1f3383d..a8e643d 100644 (file)
 namespace WebCore {
 
 class IDBDatabaseInfo;
+class IDBKeyData;
 class IDBObjectStoreInfo;
 class IDBRequestData;
+class ThreadSafeDataBuffer;
 
 namespace IDBServer {
 
@@ -52,6 +54,7 @@ public:
     UniqueIDBDatabaseConnection& databaseConnection() { return m_databaseConnection.get(); }
     const IDBTransactionInfo& info() const { return m_transactionInfo; }
     bool isVersionChange() const;
+    bool isReadOnly() const;
 
     IDBDatabaseInfo* originalDatabaseInfo() const;
 
@@ -59,6 +62,8 @@ public:
     void commit();
 
     void createObjectStore(const IDBRequestData&, const IDBObjectStoreInfo&);
+    void putOrAdd(const IDBRequestData&, const IDBKeyData&, const ThreadSafeDataBuffer& valueData, IndexedDB::ObjectStoreOverwriteMode);
+    void getRecord(const IDBRequestData&, const IDBKeyData&);
 
 private:
     UniqueIDBDatabaseTransaction(UniqueIDBDatabaseConnection&, IDBTransactionInfo&);
index 638817e..5ddb2a2 100644 (file)
@@ -77,6 +77,15 @@ void IDBDatabaseInfo::addExistingObjectStore(const IDBObjectStoreInfo& info)
     m_objectStoreMap.set(info.identifier(), info);
 }
 
+const IDBObjectStoreInfo* IDBDatabaseInfo::infoForExistingObjectStore(uint64_t objectStoreIdentifier) const
+{
+    auto iterator = m_objectStoreMap.find(objectStoreIdentifier);
+    if (iterator == m_objectStoreMap.end())
+        return nullptr;
+
+    return &iterator->value;
+}
+
 Vector<String> IDBDatabaseInfo::objectStoreNames() const
 {
     Vector<String> names;
index 40f5394..0df9e16 100644 (file)
@@ -49,6 +49,7 @@ public:
     bool hasObjectStore(const String& name) const;
     IDBObjectStoreInfo createNewObjectStore(const String& name, const IDBKeyPath&, bool autoIncrement);
     void addExistingObjectStore(const IDBObjectStoreInfo&);
+    const IDBObjectStoreInfo* infoForExistingObjectStore(uint64_t objectStoreIdentifier) const;
 
     Vector<String> objectStoreNames() const;
 
index 2288ce8..452a470 100644 (file)
@@ -51,6 +51,22 @@ static const String& idbErrorName(IDBExceptionCode code)
         static NeverDestroyed<String> entry = ASCIILiteral("InvalidStateError");
         return entry;
     }
+    case IDBExceptionCode::DataError: {
+        static NeverDestroyed<String> entry = ASCIILiteral("DataError");
+        return entry;
+    }
+    case IDBExceptionCode::TransactionInactiveError: {
+        static NeverDestroyed<String> entry = ASCIILiteral("TransactionInactiveError");
+        return entry;
+    }
+    case IDBExceptionCode::ReadOnlyError: {
+        static NeverDestroyed<String> entry = ASCIILiteral("ReadOnlyError");
+        return entry;
+    }
+    case IDBExceptionCode::DataCloneError: {
+        static NeverDestroyed<String> entry = ASCIILiteral("DataCloneError");
+        return entry;
+    }
     case IDBExceptionCode::None:
         RELEASE_ASSERT_NOT_REACHED();
     }
@@ -77,6 +93,22 @@ static const String& idbErrorDescription(IDBExceptionCode code)
         static NeverDestroyed<String> entry = ASCIILiteral("Operation was called on an object on which it is not allowed or at a time when it is not allowed.");
         return entry;
     }
+    case IDBExceptionCode::DataError: {
+        static NeverDestroyed<String> entry = ASCIILiteral("Data provided to an operation does not meet requirements.");
+        return entry;
+    }
+    case IDBExceptionCode::TransactionInactiveError: {
+        static NeverDestroyed<String> entry = ASCIILiteral("Request was placed against a transaction which is currently not active, or which is finished.");
+        return entry;
+    }
+    case IDBExceptionCode::ReadOnlyError: {
+        static NeverDestroyed<String> entry = ASCIILiteral("A mutating operation was attempted in a \"readonly\" transaction.");
+        return entry;
+    }
+    case IDBExceptionCode::DataCloneError: {
+        static NeverDestroyed<String> entry = ASCIILiteral("Data being stored could not be cloned by the structured cloning algorithm.");
+        return entry;
+    }
     case IDBExceptionCode::None:
         RELEASE_ASSERT_NOT_REACHED();
     }
index b919636..2e74f4e 100644 (file)
@@ -36,10 +36,14 @@ enum class IDBExceptionCode {
     None = 0,
     Unknown,
     ConstraintError,
+    DataError,
+    TransactionInactiveError,
+    ReadOnlyError,
     VersionError,
 
     // Indexed DB existing exception codes with IDB-specific error messages:
     InvalidStateError,
+    DataCloneError,
 };
 
 class IDBError {
index 93252cb..5a3d9e5 100644 (file)
 namespace WebCore {
 
 IDBRequestData::IDBRequestData(const IDBClient::IDBConnectionToServer& connection, const IDBClient::IDBOpenDBRequest& request)
-    : m_requestIdentifier(std::make_unique<IDBResourceIdentifier>(connection, request))
+    : m_serverConnectionIdentifier(connection.identifier())
+    , m_requestIdentifier(std::make_unique<IDBResourceIdentifier>(connection, request))
     , m_databaseIdentifier(request.databaseIdentifier())
     , m_requestedVersion(request.version())
 {
 }
 
 IDBRequestData::IDBRequestData(IDBClient::TransactionOperation& operation)
-    : m_requestIdentifier(std::make_unique<IDBResourceIdentifier>(operation.identifier()))
+    : m_serverConnectionIdentifier(operation.transaction().database().serverConnection().identifier())
+    , m_requestIdentifier(std::make_unique<IDBResourceIdentifier>(operation.identifier()))
     , m_transactionIdentifier(std::make_unique<IDBResourceIdentifier>(operation.transactionIdentifier()))
+    , m_objectStoreIdentifier(operation.objectStoreIdentifier())
 {
 }
 
 IDBRequestData::IDBRequestData(const IDBRequestData& other)
-    : m_databaseIdentifier(other.m_databaseIdentifier)
+    : m_serverConnectionIdentifier(other.m_serverConnectionIdentifier)
+    , m_objectStoreIdentifier(other.m_objectStoreIdentifier)
+    , m_databaseIdentifier(other.m_databaseIdentifier)
     , m_requestedVersion(other.m_requestedVersion)
 {
     if (other.m_requestIdentifier)
@@ -56,6 +61,12 @@ IDBRequestData::IDBRequestData(const IDBRequestData& other)
         m_transactionIdentifier = std::make_unique<IDBResourceIdentifier>(*other.m_transactionIdentifier);
 }
 
+uint64_t IDBRequestData::serverConnectionIdentifier() const
+{
+    ASSERT(m_serverConnectionIdentifier);
+    return m_serverConnectionIdentifier;
+}
+
 IDBResourceIdentifier IDBRequestData::requestIdentifier() const
 {
     RELEASE_ASSERT(m_requestIdentifier);
@@ -68,6 +79,12 @@ IDBResourceIdentifier IDBRequestData::transactionIdentifier() const
     return *m_transactionIdentifier;
 }
 
+uint64_t IDBRequestData::objectStoreIdentifier() const
+{
+    RELEASE_ASSERT(m_objectStoreIdentifier);
+    return m_objectStoreIdentifier;
+}
+
 uint64_t IDBRequestData::requestedVersion() const
 {
     return m_requestedVersion;
index 416fd5d..b8b4a28 100644 (file)
@@ -46,8 +46,10 @@ public:
     explicit IDBRequestData(IDBClient::TransactionOperation&);
     IDBRequestData(const IDBRequestData&);
 
+    uint64_t serverConnectionIdentifier() const;
     IDBResourceIdentifier requestIdentifier() const;
     IDBResourceIdentifier transactionIdentifier() const;
+    uint64_t objectStoreIdentifier() const;
 
     const IDBDatabaseIdentifier& databaseIdentifier() const { return m_databaseIdentifier; }
     uint64_t requestedVersion() const;
@@ -55,8 +57,10 @@ public:
     IDBRequestData isolatedCopy();
 
 private:
+    uint64_t m_serverConnectionIdentifier { 0 };
     std::unique_ptr<IDBResourceIdentifier> m_requestIdentifier;
     std::unique_ptr<IDBResourceIdentifier> m_transactionIdentifier;
+    uint64_t m_objectStoreIdentifier { 0 };
 
     IDBDatabaseIdentifier m_databaseIdentifier;
     uint64_t m_requestedVersion { 0 };
index 65071d8..8dcb746 100644 (file)
@@ -50,11 +50,14 @@ IDBResultData::IDBResultData(const IDBResultData& other)
     , m_requestIdentifier(other.m_requestIdentifier)
     , m_error(other.m_error)
     , m_databaseConnectionIdentifier(other.m_databaseConnectionIdentifier)
+    , m_resultData(other.m_resultData)
 {
     if (other.m_databaseInfo)
         m_databaseInfo = std::make_unique<IDBDatabaseInfo>(*other.m_databaseInfo);
     if (other.m_transactionInfo)
         m_transactionInfo = std::make_unique<IDBTransactionInfo>(*other.m_transactionInfo);
+    if (other.m_resultKey)
+        m_resultKey = std::make_unique<IDBKeyData>(*other.m_resultKey);
 }
 
 IDBResultData IDBResultData::error(const IDBResourceIdentifier& requestIdentifier, const IDBError& error)
@@ -90,6 +93,20 @@ IDBResultData IDBResultData::createObjectStoreSuccess(const IDBResourceIdentifie
     return { IDBResultType::CreateObjectStoreSuccess, requestIdentifier };
 }
 
+IDBResultData IDBResultData::putOrAddSuccess(const IDBResourceIdentifier& requestIdentifier, const IDBKeyData& resultKey)
+{
+    IDBResultData result(IDBResultType::PutOrAddSuccess, requestIdentifier);
+    result.m_resultKey = std::make_unique<IDBKeyData>(resultKey);
+    return result;
+}
+
+IDBResultData IDBResultData::getRecordSuccess(const IDBResourceIdentifier& requestIdentifier, const ThreadSafeDataBuffer& valueData)
+{
+    IDBResultData result(IDBResultType::GetRecordSuccess, requestIdentifier);
+    result.m_resultData = valueData;
+    return result;
+}
+
 const IDBDatabaseInfo& IDBResultData::databaseInfo() const
 {
     RELEASE_ASSERT(m_databaseInfo);
index 2ae71d3..8f293c9 100644 (file)
 
 #include "IDBDatabaseInfo.h"
 #include "IDBError.h"
+#include "IDBKeyData.h"
 #include "IDBResourceIdentifier.h"
 #include "IDBTransactionInfo.h"
+#include "ThreadSafeDataBuffer.h"
 
 namespace WebCore {
 
 class IDBResourceIdentifier;
-
-namespace IDBServer {
-class UniqueIDBDatabaseConnection;
-class UniqueIDBDatabaseTransaction;
-}
+class ThreadSafeDataBuffer;
 
 enum class IDBResultType {
     Error,
     OpenDatabaseSuccess,
     OpenDatabaseUpgradeNeeded,
     CreateObjectStoreSuccess,
+    PutOrAddSuccess,
+    GetRecordSuccess,
 };
 
+namespace IDBServer {
+class UniqueIDBDatabaseConnection;
+class UniqueIDBDatabaseTransaction;
+}
+
 class IDBResultData {
 public:
     static IDBResultData error(const IDBResourceIdentifier&, const IDBError&);
     static IDBResultData openDatabaseSuccess(const IDBResourceIdentifier&, IDBServer::UniqueIDBDatabaseConnection&);
     static IDBResultData openDatabaseUpgradeNeeded(const IDBResourceIdentifier&, IDBServer::UniqueIDBDatabaseTransaction&);
     static IDBResultData createObjectStoreSuccess(const IDBResourceIdentifier&);
+    static IDBResultData putOrAddSuccess(const IDBResourceIdentifier&, const IDBKeyData&);
+    static IDBResultData getRecordSuccess(const IDBResourceIdentifier&, const ThreadSafeDataBuffer& valueData);
 
     IDBResultData(const IDBResultData&);
 
@@ -67,6 +74,9 @@ public:
     const IDBDatabaseInfo& databaseInfo() const;
     const IDBTransactionInfo& transactionInfo() const;
 
+    const IDBKeyData* resultKey() const { return m_resultKey.get(); }
+    const ThreadSafeDataBuffer& resultData() const { return m_resultData; }
+
 private:
     IDBResultData(const IDBResourceIdentifier&);
     IDBResultData(IDBResultType, const IDBResourceIdentifier&);
@@ -78,6 +88,8 @@ private:
     uint64_t m_databaseConnectionIdentifier { 0 };
     std::unique_ptr<IDBDatabaseInfo> m_databaseInfo;
     std::unique_ptr<IDBTransactionInfo> m_transactionInfo;
+    std::unique_ptr<IDBKeyData> m_resultKey;
+    ThreadSafeDataBuffer m_resultData;
 };
 
 } // namespace WebCore
index ba3b60c..8b606b9 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "IDBConnectionToClient.h"
 #include "IDBConnectionToServer.h"
+#include "IDBKeyData.h"
 #include "IDBOpenDBRequestImpl.h"
 #include "IDBRequestData.h"
 #include "IDBResultData.h"
@@ -126,6 +127,22 @@ void InProcessIDBServer::didCreateObjectStore(const IDBResultData& resultData)
     });
 }
 
+void InProcessIDBServer::didPutOrAdd(const IDBResultData& resultData)
+{
+    RefPtr<InProcessIDBServer> self(this);
+    RunLoop::current().dispatch([this, self, resultData] {
+        m_connectionToServer->didPutOrAdd(resultData);
+    });
+}
+
+void InProcessIDBServer::didGetRecord(const IDBResultData& resultData)
+{
+    RefPtr<InProcessIDBServer> self(this);
+    RunLoop::current().dispatch([this, self, resultData] {
+        m_connectionToServer->didGetRecord(resultData);
+    });
+}
+
 void InProcessIDBServer::abortTransaction(IDBResourceIdentifier& resourceIdentifier)
 {
     RefPtr<InProcessIDBServer> self(this);
@@ -150,6 +167,27 @@ void InProcessIDBServer::createObjectStore(const IDBRequestData& resultData, con
     });
 }
 
+void InProcessIDBServer::putOrAdd(const IDBRequestData& requestData, IDBKey* key, SerializedScriptValue& value, const IndexedDB::ObjectStoreOverwriteMode overwriteMode)
+{
+    RefPtr<InProcessIDBServer> self(this);
+    IDBKeyData keyData(key);
+    auto valueData = ThreadSafeDataBuffer::copyVector(value.data());
+
+    RunLoop::current().dispatch([this, self, requestData, keyData, valueData, overwriteMode] {
+        m_server->putOrAdd(requestData, keyData, valueData, overwriteMode);
+    });
+}
+
+void InProcessIDBServer::getRecord(const IDBRequestData& requestData, IDBKey* key)
+{
+    RefPtr<InProcessIDBServer> self(this);
+    IDBKeyData keyData(key);
+
+    RunLoop::current().dispatch([this, self, requestData, keyData] {
+        m_server->getRecord(requestData, keyData);
+    });
+}
+
 void InProcessIDBServer::fireVersionChangeEvent(IDBServer::UniqueIDBDatabaseConnection& connection, uint64_t requestedVersion)
 {
     RefPtr<InProcessIDBServer> self(this);
index 8736557..efc31a0 100644 (file)
@@ -59,6 +59,8 @@ public:
     virtual void abortTransaction(IDBResourceIdentifier&) override final;
     virtual void commitTransaction(IDBResourceIdentifier&) override final;
     virtual void createObjectStore(const IDBRequestData&, const IDBObjectStoreInfo&) override final;
+    virtual void putOrAdd(const IDBRequestData&, IDBKey*, SerializedScriptValue&, const IndexedDB::ObjectStoreOverwriteMode) override final;
+    virtual void getRecord(const IDBRequestData&, IDBKey*) override final;
     virtual void databaseConnectionClosed(uint64_t databaseConnectionIdentifier) override final;
 
     // IDBConnectionToClient
@@ -68,6 +70,8 @@ public:
     virtual void didAbortTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError&) override final;
     virtual void didCommitTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError&) override final;
     virtual void didCreateObjectStore(const IDBResultData&) override final;
+    virtual void didPutOrAdd(const IDBResultData&) override final;
+    virtual void didGetRecord(const IDBResultData&) override final;
     virtual void fireVersionChangeEvent(IDBServer::UniqueIDBDatabaseConnection&, uint64_t requestedVersion) override final;
 
     virtual void ref() override { RefCounted<InProcessIDBServer>::ref(); }
index 900b154..c11c562 100644 (file)
                51D0C5160DAA90B7003B3831 /* JSStorageCustom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 51D0C5150DAA90B7003B3831 /* JSStorageCustom.cpp */; };
                51D7236C1BB6174900478CA3 /* IDBResultData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 51D7236A1BB60BFE00478CA3 /* IDBResultData.cpp */; };
                51D7236D1BB6174900478CA3 /* IDBResultData.h in Headers */ = {isa = PBXBuildFile; fileRef = 51D7236B1BB60BFE00478CA3 /* IDBResultData.h */; };
+               51D7EFEA1BDE8F8C00E93E10 /* ThreadSafeDataBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 511FAEA91BDC989A00B4AFE4 /* ThreadSafeDataBuffer.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               51D7EFEC1BDEFA5100E93E10 /* TransactionOperation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 51D7EFEB1BDEFA4700E93E10 /* TransactionOperation.cpp */; };
                51DCE8020CAC9F1C00488358 /* JSSQLResultSetRowListCustom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 51DCE8010CAC9F1C00488358 /* JSSQLResultSetRowListCustom.cpp */; };
                51DF6D7E0B92A16D00C2DC85 /* ThreadCheck.h in Headers */ = {isa = PBXBuildFile; fileRef = 51DF6D7D0B92A16D00C2DC85 /* ThreadCheck.h */; settings = {ATTRIBUTES = (Private, ); }; };
                51DF6D800B92A18E00C2DC85 /* ThreadCheck.mm in Sources */ = {isa = PBXBuildFile; fileRef = 51DF6D7F0B92A18E00C2DC85 /* ThreadCheck.mm */; };
                511EF2CC17F0FDF100E4FA16 /* JSIDBAnyCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSIDBAnyCustom.cpp; sourceTree = "<group>"; };
                511EF2CD17F0FDF100E4FA16 /* JSIDBDatabaseCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSIDBDatabaseCustom.cpp; sourceTree = "<group>"; };
                511EF2CE17F0FDF100E4FA16 /* JSIDBObjectStoreCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSIDBObjectStoreCustom.cpp; sourceTree = "<group>"; };
+               511FAEA91BDC989A00B4AFE4 /* ThreadSafeDataBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThreadSafeDataBuffer.h; sourceTree = "<group>"; };
                5123AF161890A4CA0031CDC9 /* IDBKeyRangeData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IDBKeyRangeData.cpp; sourceTree = "<group>"; };
                5123AF171890A4CA0031CDC9 /* IDBKeyRangeData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IDBKeyRangeData.h; sourceTree = "<group>"; };
                5123AF1C18918AE40031CDC9 /* IDBGetResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IDBGetResult.h; sourceTree = "<group>"; };
                51D719B3181106E00016DC51 /* WorkerGlobalScopeIndexedDatabase.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WorkerGlobalScopeIndexedDatabase.idl; sourceTree = "<group>"; };
                51D7236A1BB60BFE00478CA3 /* IDBResultData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IDBResultData.cpp; sourceTree = "<group>"; };
                51D7236B1BB60BFE00478CA3 /* IDBResultData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IDBResultData.h; sourceTree = "<group>"; };
+               51D7EFEB1BDEFA4700E93E10 /* TransactionOperation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TransactionOperation.cpp; sourceTree = "<group>"; };
                51DCE8010CAC9F1C00488358 /* JSSQLResultSetRowListCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSSQLResultSetRowListCustom.cpp; sourceTree = "<group>"; };
                51DF6D7D0B92A16D00C2DC85 /* ThreadCheck.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThreadCheck.h; sourceTree = "<group>"; };
                51DF6D7F0B92A18E00C2DC85 /* ThreadCheck.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ThreadCheck.mm; sourceTree = "<group>"; };
                                5198F7B31BBE001D00E2CC5F /* IDBTransactionImpl.h */,
                                5198F7B61BC3141700E2CC5F /* IDBVersionChangeEventImpl.cpp */,
                                5198F7B71BC3141700E2CC5F /* IDBVersionChangeEventImpl.h */,
+                               51D7EFEB1BDEFA4700E93E10 /* TransactionOperation.cpp */,
                                5160712B1BD8305300DBC4F2 /* TransactionOperation.h */,
                        );
                        path = client;
                                51DF6D7D0B92A16D00C2DC85 /* ThreadCheck.h */,
                                E1FF57A50F01256B00891EBB /* ThreadGlobalData.cpp */,
                                E1FF57A20F01255B00891EBB /* ThreadGlobalData.h */,
+                               511FAEA91BDC989A00B4AFE4 /* ThreadSafeDataBuffer.h */,
                                185BCF260F3279CE000EA262 /* ThreadTimers.cpp */,
                                185BCF270F3279CE000EA262 /* ThreadTimers.h */,
                                93309EA1099EB78C0056E581 /* Timer.cpp */,
                                B2FA3DAF0AB75A6F000E5AC4 /* JSSVGMetadataElement.h in Headers */,
                                B27B282A0CEF0C0700D39D54 /* JSSVGMissingGlyphElement.h in Headers */,
                                4496E3A0139813A5003EE32A /* JSSVGMPathElement.h in Headers */,
+                               51D7EFEA1BDE8F8C00E93E10 /* ThreadSafeDataBuffer.h in Headers */,
                                8542A7970AE5C94300DF58DF /* JSSVGNumber.h in Headers */,
                                B2FA3DB10AB75A6F000E5AC4 /* JSSVGNumberList.h in Headers */,
                                B2FA3DB30AB75A6F000E5AC4 /* JSSVGPaint.h in Headers */,
                                2D4F96F51A1ECC240098BF88 /* TextIndicator.cpp in Sources */,
                                2D4F96F81A1ECC240098BF88 /* TextIndicatorWindow.mm in Sources */,
                                F55B3DD91251F12D003EF269 /* TextInputType.cpp in Sources */,
+                               51D7EFEC1BDEFA5100E93E10 /* TransactionOperation.cpp in Sources */,
                                CECADFCD1537791D00E37068 /* TextInsertionBaseCommand.cpp in Sources */,
                                93309E1B099E64920056E581 /* TextIterator.cpp in Sources */,
                                E4D988B617BFEB210084FB88 /* TextNodeTraversal.cpp in Sources */,
index a7cbd78..3bf4b29 100644 (file)
@@ -37,6 +37,7 @@
 #include "JSDOMBinding.h"
 #include "Logging.h"
 #include "SharedBuffer.h"
+#include "ThreadSafeDataBuffer.h"
 
 #include <runtime/DateInstance.h>
 #include <runtime/ObjectConstructor.h>
@@ -77,12 +78,14 @@ static bool set(ExecState* exec, JSValue& object, const String& keyPathElement,
 
 static JSValue idbKeyToJSValue(ExecState* exec, JSDOMGlobalObject* globalObject, IDBKey* key)
 {
-    if (!key) {
+    if (!key || !exec) {
         // This should be undefined, not null.
         // Spec: http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBKeyRange
         return jsUndefined();
     }
 
+    Locker<JSLock> locker(exec->vm().apiLock());
+
     switch (key->type()) {
     case KeyType::Array:
         {
@@ -279,10 +282,41 @@ RefPtr<IDBKey> createIDBKeyFromScriptValueAndKeyPath(ExecState* exec, const Depr
     return internalCreateIDBKeyFromScriptValueAndKeyPath(exec, value, keyPath.string());
 }
 
+RefPtr<IDBKey> maybeCreateIDBKeyFromScriptValueAndKeyPath(ExecState& exec, const Deprecated::ScriptValue& value, const IDBKeyPath& keyPath)
+{
+    ASSERT(!keyPath.isNull());
+
+    if (keyPath.type() == IndexedDB::KeyPathType::Array) {
+        Vector<RefPtr<IDBKey>> result;
+        const Vector<String>& array = keyPath.array();
+        for (size_t i = 0; i < array.size(); i++) {
+            RefPtr<IDBKey> key = internalCreateIDBKeyFromScriptValueAndKeyPath(&exec, value, array[i]);
+            if (!key)
+                return nullptr;
+            result.append(key);
+        }
+        return IDBKey::createArray(result);
+    }
+
+    ASSERT(keyPath.type() == IndexedDB::KeyPathType::String);
+    return internalCreateIDBKeyFromScriptValueAndKeyPath(&exec, value, keyPath.string());
+}
+
 bool canInjectIDBKeyIntoScriptValue(DOMRequestState* requestState, const Deprecated::ScriptValue& scriptValue, const IDBKeyPath& keyPath)
 {
     LOG(StorageAPI, "canInjectIDBKeyIntoScriptValue");
 
+    JSC::ExecState* exec = requestState->exec();
+    if (!exec)
+        return false;
+
+    return canInjectIDBKeyIntoScriptValue(*exec, scriptValue, keyPath);
+}
+
+bool canInjectIDBKeyIntoScriptValue(JSC::ExecState& execState, const Deprecated::ScriptValue& scriptValue, const IDBKeyPath& keyPath)
+{
+    LOG(StorageAPI, "canInjectIDBKeyIntoScriptValue");
+
     ASSERT(keyPath.type() == IndexedDB::KeyPathType::String);
     Vector<String> keyPathElements;
     IDBKeyPathParseError error;
@@ -292,8 +326,7 @@ bool canInjectIDBKeyIntoScriptValue(DOMRequestState* requestState, const Depreca
     if (!keyPathElements.size())
         return false;
 
-    JSC::ExecState* exec = requestState->exec();
-    return canInjectNthValueOnKeyPath(exec, scriptValue.jsValue(), keyPathElements, keyPathElements.size() - 1);
+    return canInjectNthValueOnKeyPath(&execState, scriptValue.jsValue(), keyPathElements, keyPathElements.size() - 1);
 }
 
 Deprecated::ScriptValue deserializeIDBValue(DOMRequestState* requestState, PassRefPtr<SerializedScriptValue> prpValue)
@@ -308,6 +341,28 @@ Deprecated::ScriptValue deserializeIDBValue(DOMRequestState* requestState, PassR
     return Deprecated::ScriptValue(exec->vm(), result);
 }
 
+Deprecated::ScriptValue deserializeIDBValueData(ScriptExecutionContext& context, const ThreadSafeDataBuffer& valueData)
+{
+    DOMRequestState state(&context);
+    auto* execState = state.exec();
+
+    if (!valueData.data())
+        return Deprecated::ScriptValue(execState->vm(), jsUndefined());
+
+    const Vector<uint8_t>& data = *valueData.data();
+    JSValue result;
+    if (data.size()) {
+        RefPtr<SerializedScriptValue> serializedValue = SerializedScriptValue::createFromWireBytes(data);
+
+        execState->vm().apiLock().lock();
+        result = serializedValue->deserialize(execState, execState->lexicalGlobalObject(), 0, NonThrowing);
+        execState->vm().apiLock().unlock();
+    } else
+        result = jsNull();
+
+    return Deprecated::ScriptValue(execState->vm(), result);
+}
+
 Deprecated::ScriptValue deserializeIDBValueBuffer(DOMRequestState* requestState, PassRefPtr<SharedBuffer> prpBuffer, bool keyIsDefined)
 {
     if (prpBuffer) {
@@ -350,6 +405,11 @@ RefPtr<IDBKey> scriptValueToIDBKey(DOMRequestState* requestState, const Deprecat
     return createIDBKeyFromValue(exec, scriptValue.jsValue());
 }
 
+RefPtr<IDBKey> scriptValueToIDBKey(ExecState& exec, const Deprecated::ScriptValue& scriptValue)
+{
+    return createIDBKeyFromValue(&exec, scriptValue.jsValue());
+}
+
 void generateIndexKeysForValue(ExecState* exec, const IDBIndexMetadata& indexMetadata, const Deprecated::ScriptValue& objectValue, Vector<IDBKeyData>& indexKeys)
 {
     RefPtr<IDBKey> indexKey = createIDBKeyFromScriptValueAndKeyPath(exec, objectValue, indexMetadata.keyPath);
@@ -375,6 +435,13 @@ void generateIndexKeysForValue(ExecState* exec, const IDBIndexMetadata& indexMet
     }
 }
 
+Deprecated::ScriptValue idbKeyDataToScriptValue(ScriptExecutionContext* context, const IDBKeyData& keyData)
+{
+    RefPtr<IDBKey> key = keyData.maybeCreateIDBKey();
+    DOMRequestState requestState(context);
+    return idbKeyToScriptValue(&requestState, key.get());
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(INDEXED_DATABASE)
index bbd1066..42b7b39 100644 (file)
@@ -38,6 +38,7 @@ class DOMRequestState;
 class IDBKey;
 class IDBKeyPath;
 class SharedBuffer;
+class ThreadSafeDataBuffer;
 
 struct IDBIndexMetadata;
 class IDBKeyData;
@@ -45,15 +46,23 @@ class IDBKeyData;
 IDBKeyPath idbKeyPathFromValue(JSC::ExecState*, JSC::JSValue);
 
 bool injectIDBKeyIntoScriptValue(DOMRequestState*, PassRefPtr<IDBKey>, Deprecated::ScriptValue&, const IDBKeyPath&);
+
 RefPtr<IDBKey> createIDBKeyFromScriptValueAndKeyPath(JSC::ExecState*, const Deprecated::ScriptValue&, const IDBKeyPath&);
+RefPtr<IDBKey> maybeCreateIDBKeyFromScriptValueAndKeyPath(JSC::ExecState&, const Deprecated::ScriptValue&, const IDBKeyPath&);
+
 bool canInjectIDBKeyIntoScriptValue(DOMRequestState*, const Deprecated::ScriptValue&, const IDBKeyPath&);
+bool canInjectIDBKeyIntoScriptValue(JSC::ExecState&, const Deprecated::ScriptValue&, const IDBKeyPath&);
+
 Deprecated::ScriptValue deserializeIDBValue(DOMRequestState*, PassRefPtr<SerializedScriptValue>);
+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 Deprecated::ScriptValue&);
+RefPtr<IDBKey> scriptValueToIDBKey(JSC::ExecState&, const Deprecated::ScriptValue&);
 WEBCORE_EXPORT void generateIndexKeysForValue(JSC::ExecState*, const IDBIndexMetadata&, const Deprecated::ScriptValue& objectValue, Vector<IDBKeyData>& indexKeys);
 
+Deprecated::ScriptValue idbKeyDataToScriptValue(ScriptExecutionContext*, const IDBKeyData&);
 }
 
 #endif // ENABLE(INDEXED_DATABASE)
index f8e3fcb..1d8cf31 100644 (file)
@@ -38,6 +38,7 @@
 #include "ResourceResponse.h"
 #include "SerializedScriptValue.h"
 #include "SessionID.h"
+#include "ThreadSafeDataBuffer.h"
 #include <wtf/Assertions.h>
 #include <wtf/text/WTFString.h>
 
@@ -86,6 +87,11 @@ CrossThreadCopierBase<false, false, SessionID>::Type CrossThreadCopierBase<false
     return sessionID;
 }
 
+CrossThreadCopierBase<false, false, ThreadSafeDataBuffer>::Type CrossThreadCopierBase<false, false, ThreadSafeDataBuffer>::copy(const ThreadSafeDataBuffer& buffer)
+{
+    return ThreadSafeDataBuffer(buffer);
+}
+
 #if ENABLE(INDEXED_DATABASE)
 
 IndexedDB::TransactionMode CrossThreadCopierBase<false, false, IndexedDB::TransactionMode>::copy(const IndexedDB::TransactionMode& mode)
index abf906b..1605885 100644 (file)
@@ -46,6 +46,7 @@ namespace WebCore {
     class ResourceRequest;
     class ResourceResponse;
     class SessionID;
+    class ThreadSafeDataBuffer;
     struct CrossThreadResourceResponseData;
     struct CrossThreadResourceRequestData;
     struct ThreadableLoaderOptions;
@@ -139,6 +140,11 @@ namespace WebCore {
         static Type copy(const SessionID&);
     };
 
+    template<> struct CrossThreadCopierBase<false, false, ThreadSafeDataBuffer> {
+        typedef ThreadSafeDataBuffer Type;
+        static Type copy(const ThreadSafeDataBuffer&);
+    };
+
 #if ENABLE(INDEXED_DATABASE)
     namespace IndexedDB {
         enum class TransactionMode;
diff --git a/Source/WebCore/platform/ThreadSafeDataBuffer.h b/Source/WebCore/platform/ThreadSafeDataBuffer.h
new file mode 100644 (file)
index 0000000..ee4c95d
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * 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 ThreadSafeDataBuffer_h
+#define ThreadSafeDataBuffer_h
+
+#include <wtf/ThreadSafeRefCounted.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class ThreadSafeDataBuffer;
+
+class ThreadSafeDataBufferImpl : public ThreadSafeRefCounted<ThreadSafeDataBufferImpl> {
+friend class ThreadSafeDataBuffer;
+private:
+    enum AdoptVectorTag { AdoptVector };
+    ThreadSafeDataBufferImpl(Vector<uint8_t>& data, AdoptVectorTag)
+    {
+        m_data.swap(data);
+    }
+
+    ThreadSafeDataBufferImpl(const Vector<uint8_t>& data)
+        : m_data(data)
+    {
+    }
+
+    Vector<uint8_t> m_data;
+};
+
+class ThreadSafeDataBuffer {
+public:
+    static ThreadSafeDataBuffer adoptVector(Vector<uint8_t>& data)
+    {
+        return ThreadSafeDataBuffer(data, ThreadSafeDataBufferImpl::AdoptVector);
+    }
+    
+    static ThreadSafeDataBuffer copyVector(const Vector<uint8_t>& data)
+    {
+        return ThreadSafeDataBuffer(data);
+    }
+
+    ThreadSafeDataBuffer()
+    {
+    }
+    
+    const Vector<uint8_t>* data() const
+    {
+        return m_impl ? &m_impl->m_data : nullptr;
+    }
+
+private:
+    explicit ThreadSafeDataBuffer(Vector<uint8_t>& data, ThreadSafeDataBufferImpl::AdoptVectorTag tag)
+    {
+        m_impl = adoptRef(new ThreadSafeDataBufferImpl(data, tag));
+    }
+
+    explicit ThreadSafeDataBuffer(const Vector<uint8_t>& data)
+    {
+        m_impl = adoptRef(new ThreadSafeDataBufferImpl(data));
+    }
+
+    RefPtr<ThreadSafeDataBufferImpl> m_impl;
+};
+
+} // namespace WebCore
+
+#endif // ThreadSafeDataBuffer_h