IndexedDB: Snapshot metadata in front end to avoid IPC round-trips
authorjsbell@chromium.org <jsbell@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 22 Jun 2012 22:09:22 +0000 (22:09 +0000)
committerjsbell@chromium.org <jsbell@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 22 Jun 2012 22:09:22 +0000 (22:09 +0000)
https://bugs.webkit.org/show_bug.cgi?id=88467

Reviewed by Tony Chang.

Source/WebCore:

Define a new type (IDBDatabaseMetadata) that captures the "schema" of an
IDB database (name, version, properties of stores, properties of indexes).
Add a method for the front end to request this from the back end once up
front to avoid later calls (which may be slow IPC calls in ports). Implement
IDB spec logic that the metadata should be frozen for a particular IDBDatabase
connection, and only change within a version change transaction, and the spec's
funky requirement for aborted version change transactions.

Test: storage/indexeddb/metadata.html

* Modules/indexeddb/IDBDatabase.cpp:
(WebCore::IDBDatabase::IDBDatabase): Fetch metadata from back end when connection is created.
(WebCore::IDBDatabase::transactionCreated):
(WebCore::IDBDatabase::transactionFinished): Update metadata at the end of a transaction in
case it was rolled back.
(WebCore::IDBDatabase::objectStoreNames): Move implementation to front-end.
(WebCore):
(WebCore::IDBDatabase::createObjectStore): Update local copy of metadata.
(WebCore::IDBDatabase::deleteObjectStore): Update local copy of metadata.
* Modules/indexeddb/IDBDatabase.h:
(WebCore::IDBDatabase::name): Move implementation to front-end.
(WebCore::IDBDatabase::version): Move implementation to front-end.
(IDBDatabase):
(WebCore::IDBDatabase::metadata):
* Modules/indexeddb/IDBDatabaseBackendImpl.cpp:
(WebCore::IDBDatabaseBackendImpl::metadata): Construct a metadata snapshot.
(WebCore):
* Modules/indexeddb/IDBDatabaseBackendImpl.h:
(IDBDatabaseBackendImpl):
* Modules/indexeddb/IDBDatabaseBackendInterface.h:
(WebCore):
(IDBDatabaseBackendInterface):
* Modules/indexeddb/IDBIndex.cpp: Store a copy of the metadata, which will never
change during the lifetime of the index.
(WebCore::IDBIndex::IDBIndex):
* Modules/indexeddb/IDBIndex.h:
(WebCore::IDBIndex::create):
(WebCore::IDBIndex::name): Move implementation to front-end.
(WebCore::IDBIndex::objectStore): Return RefPtr (unrelated tidying).
(WebCore::IDBIndex::keyPath): Move implementation to front-end.
(WebCore::IDBIndex::unique): Move implementation to front-end.
(WebCore::IDBIndex::multiEntry): Move implementation to front-end.
(IDBIndex):
* Modules/indexeddb/IDBIndexBackendImpl.cpp:
(WebCore::IDBIndexBackendImpl::metadata): Construct a metadata snapshot.
(WebCore):
* Modules/indexeddb/IDBIndexBackendImpl.h:
(IDBIndexBackendImpl):
* Modules/indexeddb/IDBMetadata.h: Added new structs.
(WebCore):
(WebCore::IDBDatabaseMetadata::IDBDatabaseMetadata):
(IDBDatabaseMetadata):
(WebCore::IDBObjectStoreMetadata::IDBObjectStoreMetadata):
(IDBObjectStoreMetadata):
(WebCore::IDBIndexMetadata::IDBIndexMetadata):
(IDBIndexMetadata):
* Modules/indexeddb/IDBObjectStore.cpp:
(WebCore::IDBObjectStore::IDBObjectStore): Store a "live" copy of the metadata, and
and copy in case of an aborted version change transaction.
(WebCore::IDBObjectStore::indexNames): Move implementation to front-end.
(WebCore::IDBObjectStore::createIndex): Update metadata to include new index.
(WebCore::IDBObjectStore::index): Pass along metadata to instance constructor.
(WebCore::IDBObjectStore::deleteIndex): Delete index from metadata.
* Modules/indexeddb/IDBObjectStore.h:
(WebCore::IDBObjectStore::create):
(WebCore::IDBObjectStore::name): Move implementation to front-end.
(WebCore::IDBObjectStore::keyPath): Move implementation to front-end.
(WebCore::IDBObjectStore::transaction): Return RefPtr (unrelated tidying).
(WebCore::IDBObjectStore::autoIncrement): Move implementation to front-end.
(WebCore::IDBObjectStore::metadata): Allow copying the metadata, in case of abort.
(WebCore::IDBObjectStore::resetMetadata): Allow setting the metadata, in case of abort.
(IDBObjectStore):
* Modules/indexeddb/IDBObjectStoreBackendImpl.cpp:
(WebCore::IDBObjectStoreBackendImpl::metadata): Construct a metadata snapshot.
(WebCore):
* Modules/indexeddb/IDBObjectStoreBackendImpl.h:
(WebCore):
(IDBObjectStoreBackendImpl):
* Modules/indexeddb/IDBTransaction.cpp:
(WebCore::IDBTransaction::objectStore): Pass along metadata to instance constructor.
(WebCore::IDBTransaction::objectStoreCreated): Track stores changed during transaction.
(WebCore::IDBTransaction::objectStoreDeleted):Track stores changed during transaction.
(WebCore::IDBTransaction::onAbort): Revert stores metadata potentially changed during transaction.
* Modules/indexeddb/IDBTransaction.h:
(IDBTransaction):
* WebCore.gypi:

Source/WebKit/chromium:

Add conversions to/from WebCore IDB metadata type and plumbing for routing the
IDBDatabaseBackendInterface::metadata() call through the public API..

* WebKit.gyp: New file added.
* public/WebIDBMetadata.h: Conversion functions.
(WebCore):
(WebIDBMetadata):
* src/IDBDatabaseBackendProxy.cpp: Plumbing.
(WebKit::IDBDatabaseBackendProxy::metadata):
(WebKit):
* src/IDBDatabaseBackendProxy.h: Plumbing.
(IDBDatabaseBackendProxy):
* src/WebIDBDatabaseImpl.cpp: Plumbing.
(WebKit::WebIDBDatabaseImpl::metadata):
(WebKit):
* src/WebIDBDatabaseImpl.h: Plumbing.
(WebKit):
(WebIDBDatabaseImpl):
* src/WebIDBMetadata.cpp: Added - conversion functions.
(WebKit):
(WebKit::WebIDBMetadata::WebIDBMetadata):
(WebKit::WebIDBMetadata::operator IDBDatabaseMetadata):

LayoutTests:

* storage/indexeddb/metadata-expected.txt: Added.
* storage/indexeddb/metadata.html: Added.
* storage/indexeddb/resources/metadata.js: Added.
(test):
(firstOpen.request.onsuccess.request.onsuccess.trans.oncomplete):
(firstOpen.request.onsuccess.request.onsuccess):
(firstOpen.request.onsuccess):
(firstOpen):
(secondOpen.request.onsuccess.request.onsuccess.trans.oncomplete):
(secondOpen.request.onsuccess.request.onsuccess):
(secondOpen.request.onsuccess):
(secondOpen):
(thirdOpen.request.onsuccess.request.onsuccess.trans.onabort):
(thirdOpen.request.onsuccess.request.onsuccess):
(thirdOpen.request.onsuccess):
(thirdOpen):
(fourthOpen.request.onsuccess.request.onsuccess.trans.oncomplete):
(fourthOpen.request.onsuccess.request.onsuccess):
(fourthOpen.request.onsuccess):
(fourthOpen):
(checkState):

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

31 files changed:
LayoutTests/ChangeLog
LayoutTests/storage/indexeddb/metadata-expected.txt [new file with mode: 0644]
LayoutTests/storage/indexeddb/metadata.html [new file with mode: 0644]
LayoutTests/storage/indexeddb/resources/metadata.js [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/Modules/indexeddb/IDBDatabase.cpp
Source/WebCore/Modules/indexeddb/IDBDatabase.h
Source/WebCore/Modules/indexeddb/IDBDatabaseBackendImpl.cpp
Source/WebCore/Modules/indexeddb/IDBDatabaseBackendImpl.h
Source/WebCore/Modules/indexeddb/IDBDatabaseBackendInterface.h
Source/WebCore/Modules/indexeddb/IDBIndex.cpp
Source/WebCore/Modules/indexeddb/IDBIndex.h
Source/WebCore/Modules/indexeddb/IDBIndexBackendImpl.cpp
Source/WebCore/Modules/indexeddb/IDBIndexBackendImpl.h
Source/WebCore/Modules/indexeddb/IDBMetadata.h [new file with mode: 0644]
Source/WebCore/Modules/indexeddb/IDBObjectStore.cpp
Source/WebCore/Modules/indexeddb/IDBObjectStore.h
Source/WebCore/Modules/indexeddb/IDBObjectStoreBackendImpl.cpp
Source/WebCore/Modules/indexeddb/IDBObjectStoreBackendImpl.h
Source/WebCore/Modules/indexeddb/IDBTransaction.cpp
Source/WebCore/Modules/indexeddb/IDBTransaction.h
Source/WebCore/WebCore.gypi
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebKit/chromium/ChangeLog
Source/WebKit/chromium/WebKit.gyp
Source/WebKit/chromium/public/WebIDBMetadata.h
Source/WebKit/chromium/src/IDBDatabaseBackendProxy.cpp
Source/WebKit/chromium/src/IDBDatabaseBackendProxy.h
Source/WebKit/chromium/src/WebIDBDatabaseImpl.cpp
Source/WebKit/chromium/src/WebIDBDatabaseImpl.h
Source/WebKit/chromium/src/WebIDBMetadata.cpp [new file with mode: 0644]

index 16369cc..c15a421 100644 (file)
@@ -1,3 +1,32 @@
+2012-06-22  Joshua Bell  <jsbell@chromium.org>
+
+        IndexedDB: Snapshot metadata in front end to avoid IPC round-trips
+        https://bugs.webkit.org/show_bug.cgi?id=88467
+
+        Reviewed by Tony Chang.
+
+        * storage/indexeddb/metadata-expected.txt: Added.
+        * storage/indexeddb/metadata.html: Added.
+        * storage/indexeddb/resources/metadata.js: Added.
+        (test):
+        (firstOpen.request.onsuccess.request.onsuccess.trans.oncomplete):
+        (firstOpen.request.onsuccess.request.onsuccess):
+        (firstOpen.request.onsuccess):
+        (firstOpen):
+        (secondOpen.request.onsuccess.request.onsuccess.trans.oncomplete):
+        (secondOpen.request.onsuccess.request.onsuccess):
+        (secondOpen.request.onsuccess):
+        (secondOpen):
+        (thirdOpen.request.onsuccess.request.onsuccess.trans.onabort):
+        (thirdOpen.request.onsuccess.request.onsuccess):
+        (thirdOpen.request.onsuccess):
+        (thirdOpen):
+        (fourthOpen.request.onsuccess.request.onsuccess.trans.oncomplete):
+        (fourthOpen.request.onsuccess.request.onsuccess):
+        (fourthOpen.request.onsuccess):
+        (fourthOpen):
+        (checkState):
+
 2012-06-22  Jon Lee  <jonlee@apple.com>
 
         editing/spelling/grammar-edit-word.html fails on WK2 bots
diff --git a/LayoutTests/storage/indexeddb/metadata-expected.txt b/LayoutTests/storage/indexeddb/metadata-expected.txt
new file mode 100644 (file)
index 0000000..8436d47
--- /dev/null
@@ -0,0 +1,88 @@
+Test IndexedDB database metadata mutation/snapshotting
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+indexedDB = self.indexedDB || self.webkitIndexedDB || self.mozIndexedDB || self.msIndexedDB || self.OIndexedDB;
+
+dbname = self.location.pathname
+request = indexedDB.deleteDatabase(dbname)
+
+firstOpen():
+request = indexedDB.open(dbname)
+connection1 = request.result
+request = connection1.setVersion('1')
+trans = request.result
+connection1store1 = connection1.createObjectStore('store1')
+connection1store1.createIndex('index1', 'path')
+PASS connection1.version is "1"
+PASS connection1.objectStoreNames.length is 1
+PASS connection1store1.indexNames.length is 1
+Connection's properties should be snapshotted on close
+connection1.close()
+
+secondOpen():
+request = indexedDB.open(dbname)
+connection2 = request.result
+request = connection2.setVersion('2')
+trans = request.result
+connection2.createObjectStore('store2')
+connection2store1 = trans.objectStore('store1')
+connection2store1.createIndex('index2', 'path')
+PASS connection2.version is "2"
+PASS connection2.objectStoreNames.length is 2
+PASS connection2store1.indexNames.length is 2
+Connection's properties should be snapshotted on close
+connection2.close()
+
+thirdOpen():
+request = indexedDB.open(dbname)
+connection3 = request.result
+request = connection3.setVersion('3')
+trans = request.result
+connection3.createObjectStore('store3')
+connection3store1 = trans.objectStore('store1')
+connection3store1.createIndex('index3', 'path')
+PASS connection3.version is "3"
+PASS connection3.objectStoreNames.length is 3
+PASS connection3store1.indexNames.length is 3
+Connection's properties should be reverted on abort
+trans.abort()
+Connection's properties should be snapshotted on close
+connection3.close()
+
+fourthOpen():
+request = indexedDB.open(dbname)
+connection4 = request.result
+request = connection4.setVersion('4')
+trans = request.result
+connection4.createObjectStore('store4')
+connection4store1 = trans.objectStore('store1')
+connection4store1.createIndex('index4', 'path')
+PASS connection4.version is "4"
+PASS connection4.objectStoreNames.length is 3
+PASS connection4store1.indexNames.length is 3
+Connection's properties should be snapshotted on close
+connection4.close()
+
+checkState():
+PASS connection1.version is "1"
+PASS connection1.objectStoreNames.length is 1
+PASS connection1store1.indexNames.length is 1
+
+PASS connection2.version is "2"
+PASS connection2.objectStoreNames.length is 2
+PASS connection2store1.indexNames.length is 2
+
+PASS connection3.version is "2"
+PASS connection3.objectStoreNames.length is 2
+PASS connection3store1.indexNames.length is 2
+
+PASS connection4.version is "4"
+PASS connection4.objectStoreNames.length is 3
+PASS connection4store1.indexNames.length is 3
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/storage/indexeddb/metadata.html b/LayoutTests/storage/indexeddb/metadata.html
new file mode 100644 (file)
index 0000000..542cfe5
--- /dev/null
@@ -0,0 +1,10 @@
+<html>
+<head>
+<script src="../../fast/js/resources/js-test-pre.js"></script>
+<script src="resources/shared.js"></script>
+</head>
+<body>
+<script src="resources/metadata.js"></script>
+<script src="../../fast/js/resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/storage/indexeddb/resources/metadata.js b/LayoutTests/storage/indexeddb/resources/metadata.js
new file mode 100644 (file)
index 0000000..14c47c7
--- /dev/null
@@ -0,0 +1,166 @@
+if (this.importScripts) {
+    importScripts('../../../fast/js/resources/js-test-pre.js');
+    importScripts('shared.js');
+}
+
+description("Test IndexedDB database metadata mutation/snapshotting");
+
+function test()
+{
+    removeVendorPrefixes();
+    evalAndLog("dbname = self.location.pathname");
+    evalAndLog("request = indexedDB.deleteDatabase(dbname)");
+    request.onerror = unexpectedErrorCallback;
+    request.onsuccess = firstOpen;
+}
+
+function firstOpen()
+{
+    debug("");
+    debug("firstOpen():");
+    evalAndLog("request = indexedDB.open(dbname)");
+    request.onerror = unexpectedErrorCallback;
+    request.onsuccess = function() {
+        evalAndLog("connection1 = request.result");
+        evalAndLog("request = connection1.setVersion('1')");
+        request.onerror = unexpectedErrorCallback;
+        request.onsuccess = function() {
+            evalAndLog("trans = request.result");
+            evalAndLog("connection1store1 = connection1.createObjectStore('store1')");
+            evalAndLog("connection1store1.createIndex('index1', 'path')");
+
+            shouldBeEqualToString("connection1.version", "1");
+            shouldBe("connection1.objectStoreNames.length", "1");
+            shouldBe("connection1store1.indexNames.length", "1");
+
+            trans.onabort = unexpectedAbortCallback;
+            trans.oncomplete = function() {
+                debug("Connection's properties should be snapshotted on close");
+                evalAndLog("connection1.close()");
+                secondOpen();
+            };
+        };
+    };
+}
+
+function secondOpen()
+{
+    debug("");
+    debug("secondOpen():");
+    evalAndLog("request = indexedDB.open(dbname)");
+    request.onerror = unexpectedErrorCallback;
+    request.onsuccess = function() {
+        evalAndLog("connection2 = request.result");
+        evalAndLog("request = connection2.setVersion('2')");
+        request.onerror = unexpectedErrorCallback;
+        request.onsuccess = function() {
+            evalAndLog("trans = request.result");
+            evalAndLog("connection2.createObjectStore('store2')");
+            evalAndLog("connection2store1 = trans.objectStore('store1')");
+            evalAndLog("connection2store1.createIndex('index2', 'path')");
+
+            shouldBeEqualToString("connection2.version", "2");
+            shouldBe("connection2.objectStoreNames.length", "2");
+            shouldBe("connection2store1.indexNames.length", "2");
+
+            trans.onabort = unexpectedAbortCallback;
+            trans.oncomplete = function() {
+                debug("Connection's properties should be snapshotted on close");
+                evalAndLog("connection2.close()");
+                thirdOpen();
+            };
+        };
+    };
+}
+
+function thirdOpen()
+{
+    debug("");
+    debug("thirdOpen():");
+    evalAndLog("request = indexedDB.open(dbname)");
+    request.onerror = unexpectedErrorCallback;
+    request.onsuccess = function() {
+        evalAndLog("connection3 = request.result");
+        evalAndLog("request = connection3.setVersion('3')");
+        request.onerror = unexpectedErrorCallback;
+        request.onsuccess = function() {
+            evalAndLog("trans = request.result");
+            evalAndLog("connection3.createObjectStore('store3')");
+            evalAndLog("connection3store1 = trans.objectStore('store1')");
+            evalAndLog("connection3store1.createIndex('index3', 'path')");
+
+            shouldBeEqualToString("connection3.version", "3");
+            shouldBe("connection3.objectStoreNames.length", "3");
+            shouldBe("connection3store1.indexNames.length", "3");
+
+            trans.oncomplete = unexpectedCompleteCallback;
+            trans.onabort = function() {
+                debug("Connection's properties should be snapshotted on close");
+                evalAndLog("connection3.close()");
+                fourthOpen();
+            };
+            debug("Connection's properties should be reverted on abort");
+            evalAndLog("trans.abort()");
+        };
+    };
+}
+
+function fourthOpen()
+{
+    debug("");
+    debug("fourthOpen():");
+    evalAndLog("request = indexedDB.open(dbname)");
+    request.onerror = unexpectedErrorCallback;
+    request.onsuccess = function() {
+        evalAndLog("connection4 = request.result");
+        evalAndLog("request = connection4.setVersion('4')");
+        request.onerror = unexpectedErrorCallback;
+        request.onsuccess = function() {
+            evalAndLog("trans = request.result");
+            evalAndLog("connection4.createObjectStore('store4')");
+            evalAndLog("connection4store1 = trans.objectStore('store1')");
+            evalAndLog("connection4store1.createIndex('index4', 'path')");
+
+            shouldBeEqualToString("connection4.version", "4");
+            shouldBe("connection4.objectStoreNames.length", "3");
+            shouldBe("connection4store1.indexNames.length", "3");
+
+            trans.onabort = unexpectedAbortCallback;
+            trans.oncomplete = function() {
+                debug("Connection's properties should be snapshotted on close");
+                evalAndLog("connection4.close()");
+                checkState();
+            };
+        };
+    };
+}
+
+function checkState()
+{
+    debug("");
+    debug("checkState():");
+
+    shouldBeEqualToString("connection1.version", "1");
+    shouldBe("connection1.objectStoreNames.length", "1");
+    shouldBe("connection1store1.indexNames.length", "1");
+    debug("");
+
+    shouldBeEqualToString("connection2.version", "2");
+    shouldBe("connection2.objectStoreNames.length", "2");
+    shouldBe("connection2store1.indexNames.length", "2");
+    debug("");
+
+    shouldBeEqualToString("connection3.version", "2");
+    shouldBe("connection3.objectStoreNames.length", "2");
+    shouldBe("connection3store1.indexNames.length", "2");
+    debug("");
+
+    shouldBeEqualToString("connection4.version", "4");
+    shouldBe("connection4.objectStoreNames.length", "3");
+    shouldBe("connection4store1.indexNames.length", "3");
+    debug("");
+
+    finishJSTest();
+}
+
+test();
index 4d54631..d3cf779 100644 (file)
@@ -1,3 +1,97 @@
+2012-06-22  Joshua Bell  <jsbell@chromium.org>
+
+        IndexedDB: Snapshot metadata in front end to avoid IPC round-trips
+        https://bugs.webkit.org/show_bug.cgi?id=88467
+
+        Reviewed by Tony Chang.
+
+        Define a new type (IDBDatabaseMetadata) that captures the "schema" of an
+        IDB database (name, version, properties of stores, properties of indexes).
+        Add a method for the front end to request this from the back end once up
+        front to avoid later calls (which may be slow IPC calls in ports). Implement
+        IDB spec logic that the metadata should be frozen for a particular IDBDatabase
+        connection, and only change within a version change transaction, and the spec's
+        funky requirement for aborted version change transactions.
+
+        Test: storage/indexeddb/metadata.html
+
+        * Modules/indexeddb/IDBDatabase.cpp:
+        (WebCore::IDBDatabase::IDBDatabase): Fetch metadata from back end when connection is created.
+        (WebCore::IDBDatabase::transactionCreated):
+        (WebCore::IDBDatabase::transactionFinished): Update metadata at the end of a transaction in 
+        case it was rolled back.
+        (WebCore::IDBDatabase::objectStoreNames): Move implementation to front-end.
+        (WebCore):
+        (WebCore::IDBDatabase::createObjectStore): Update local copy of metadata.
+        (WebCore::IDBDatabase::deleteObjectStore): Update local copy of metadata.
+        * Modules/indexeddb/IDBDatabase.h:
+        (WebCore::IDBDatabase::name): Move implementation to front-end.
+        (WebCore::IDBDatabase::version): Move implementation to front-end.
+        (IDBDatabase):
+        (WebCore::IDBDatabase::metadata):
+        * Modules/indexeddb/IDBDatabaseBackendImpl.cpp:
+        (WebCore::IDBDatabaseBackendImpl::metadata): Construct a metadata snapshot.
+        (WebCore):
+        * Modules/indexeddb/IDBDatabaseBackendImpl.h:
+        (IDBDatabaseBackendImpl):
+        * Modules/indexeddb/IDBDatabaseBackendInterface.h:
+        (WebCore):
+        (IDBDatabaseBackendInterface):
+        * Modules/indexeddb/IDBIndex.cpp: Store a copy of the metadata, which will never
+        change during the lifetime of the index.
+        (WebCore::IDBIndex::IDBIndex):
+        * Modules/indexeddb/IDBIndex.h:
+        (WebCore::IDBIndex::create):
+        (WebCore::IDBIndex::name): Move implementation to front-end.
+        (WebCore::IDBIndex::objectStore): Return RefPtr (unrelated tidying).
+        (WebCore::IDBIndex::keyPath): Move implementation to front-end.
+        (WebCore::IDBIndex::unique): Move implementation to front-end.
+        (WebCore::IDBIndex::multiEntry): Move implementation to front-end.
+        (IDBIndex):
+        * Modules/indexeddb/IDBIndexBackendImpl.cpp:
+        (WebCore::IDBIndexBackendImpl::metadata): Construct a metadata snapshot.
+        (WebCore):
+        * Modules/indexeddb/IDBIndexBackendImpl.h:
+        (IDBIndexBackendImpl):
+        * Modules/indexeddb/IDBMetadata.h: Added new structs.
+        (WebCore):
+        (WebCore::IDBDatabaseMetadata::IDBDatabaseMetadata):
+        (IDBDatabaseMetadata):
+        (WebCore::IDBObjectStoreMetadata::IDBObjectStoreMetadata):
+        (IDBObjectStoreMetadata):
+        (WebCore::IDBIndexMetadata::IDBIndexMetadata):
+        (IDBIndexMetadata):
+        * Modules/indexeddb/IDBObjectStore.cpp:
+        (WebCore::IDBObjectStore::IDBObjectStore): Store a "live" copy of the metadata, and
+        and copy in case of an aborted version change transaction.
+        (WebCore::IDBObjectStore::indexNames): Move implementation to front-end.
+        (WebCore::IDBObjectStore::createIndex): Update metadata to include new index.
+        (WebCore::IDBObjectStore::index): Pass along metadata to instance constructor.
+        (WebCore::IDBObjectStore::deleteIndex): Delete index from metadata.
+        * Modules/indexeddb/IDBObjectStore.h:
+        (WebCore::IDBObjectStore::create):
+        (WebCore::IDBObjectStore::name): Move implementation to front-end.
+        (WebCore::IDBObjectStore::keyPath): Move implementation to front-end.
+        (WebCore::IDBObjectStore::transaction): Return RefPtr (unrelated tidying).
+        (WebCore::IDBObjectStore::autoIncrement): Move implementation to front-end.
+        (WebCore::IDBObjectStore::metadata): Allow copying the metadata, in case of abort.
+        (WebCore::IDBObjectStore::resetMetadata): Allow setting the metadata, in case of abort.
+        (IDBObjectStore):
+        * Modules/indexeddb/IDBObjectStoreBackendImpl.cpp:
+        (WebCore::IDBObjectStoreBackendImpl::metadata): Construct a metadata snapshot.
+        (WebCore):
+        * Modules/indexeddb/IDBObjectStoreBackendImpl.h:
+        (WebCore):
+        (IDBObjectStoreBackendImpl):
+        * Modules/indexeddb/IDBTransaction.cpp:
+        (WebCore::IDBTransaction::objectStore): Pass along metadata to instance constructor.
+        (WebCore::IDBTransaction::objectStoreCreated): Track stores changed during transaction.
+        (WebCore::IDBTransaction::objectStoreDeleted):Track stores changed during transaction.
+        (WebCore::IDBTransaction::onAbort): Revert stores metadata potentially changed during transaction.
+        * Modules/indexeddb/IDBTransaction.h:
+        (IDBTransaction):
+        * WebCore.gypi:
+
 2012-06-20  Mark Hahnenberg  <mhahnenberg@apple.com>
 
         JSLock should be per-JSGlobalData
index 2008ed8..0a49400 100644 (file)
@@ -64,6 +64,7 @@ IDBDatabase::IDBDatabase(ScriptExecutionContext* context, PassRefPtr<IDBDatabase
     // We pass a reference of this object before it can be adopted.
     relaxAdoptionRequirement();
     m_databaseCallbacks = IDBDatabaseCallbacksImpl::create(this);
+    m_metadata = m_backend->metadata();
 }
 
 IDBDatabase::~IDBDatabase()
@@ -81,6 +82,7 @@ void IDBDatabase::transactionCreated(IDBTransaction* transaction)
     if (transaction->isVersionChange()) {
         ASSERT(!m_versionChangeTransaction);
         m_versionChangeTransaction = transaction;
+        m_metadata = m_backend->metadata();
     }
 }
 
@@ -93,12 +95,22 @@ void IDBDatabase::transactionFinished(IDBTransaction* transaction)
     if (transaction->isVersionChange()) {
         ASSERT(m_versionChangeTransaction == transaction);
         m_versionChangeTransaction = 0;
+        m_metadata = m_backend->metadata();
     }
 
     if (m_closePending && m_transactions.isEmpty())
         closeConnection();
 }
 
+PassRefPtr<DOMStringList> IDBDatabase::objectStoreNames() const
+{
+    RefPtr<DOMStringList> objectStoreNames = DOMStringList::create();
+    for (IDBDatabaseMetadata::ObjectStoreMap::const_iterator it = m_metadata.objectStores.begin(); it != m_metadata.objectStores.end(); ++it)
+        objectStoreNames->append(it->first);
+    objectStoreNames->sort();
+    return objectStoreNames.release();
+}
+
 PassRefPtr<IDBObjectStore> IDBDatabase::createObjectStore(const String& name, const Dictionary& options, ExceptionCode& ec)
 {
     if (!m_versionChangeTransaction) {
@@ -136,7 +148,10 @@ PassRefPtr<IDBObjectStore> IDBDatabase::createObjectStore(const String& name, co
         return 0;
     }
 
-    RefPtr<IDBObjectStore> objectStore = IDBObjectStore::create(objectStoreBackend.release(), m_versionChangeTransaction.get());
+    IDBObjectStoreMetadata metadata(name, keyPath, autoIncrement);
+    RefPtr<IDBObjectStore> objectStore = IDBObjectStore::create(metadata, objectStoreBackend.release(), m_versionChangeTransaction.get());
+    m_metadata.objectStores.set(name, metadata);
+
     m_versionChangeTransaction->objectStoreCreated(name, objectStore);
     return objectStore.release();
 }
@@ -149,8 +164,10 @@ void IDBDatabase::deleteObjectStore(const String& name, ExceptionCode& ec)
     }
 
     m_backend->deleteObjectStore(name, m_versionChangeTransaction->backend(), ec);
-    if (!ec)
+    if (!ec) {
         m_versionChangeTransaction->objectStoreDeleted(name);
+        m_metadata.objectStores.remove(name);
+    }
 }
 
 PassRefPtr<IDBVersionChangeRequest> IDBDatabase::setVersion(ScriptExecutionContext* context, const String& version, ExceptionCode& ec)
index adad32d..a248cd8 100644 (file)
@@ -33,6 +33,7 @@
 #include "EventTarget.h"
 #include "IDBDatabaseBackendInterface.h"
 #include "IDBDatabaseCallbacksImpl.h"
+#include "IDBMetadata.h"
 #include "IDBObjectStore.h"
 #include "IDBTransaction.h"
 #include <wtf/PassRefPtr.h>
@@ -57,9 +58,9 @@ public:
     void transactionFinished(IDBTransaction*);
 
     // Implement the IDL
-    String name() const { return m_backend->name(); }
-    String version() const { return m_backend->version(); }
-    PassRefPtr<DOMStringList> objectStoreNames() const { return m_backend->objectStoreNames(); }
+    const String name() const { return m_metadata.name; }
+    const String version() const { return m_metadata.version; }
+    PassRefPtr<DOMStringList> objectStoreNames() const;
 
     // FIXME: Try to modify the code generator so this is unneeded.
     PassRefPtr<IDBObjectStore> createObjectStore(const String& name, ExceptionCode& ec) { return createObjectStore(name, Dictionary(), ec); }
@@ -87,6 +88,7 @@ public:
     virtual ScriptExecutionContext* scriptExecutionContext() const;
 
     void registerFrontendCallbacks();
+    const IDBDatabaseMetadata metadata() const { return m_metadata; }
     void enqueueEvent(PassRefPtr<Event>);
     bool dispatchEvent(PassRefPtr<Event> event, ExceptionCode& ec) { return EventTarget::dispatchEvent(event, ec); }
     virtual bool dispatchEvent(PassRefPtr<Event>);
@@ -105,6 +107,7 @@ private:
 
     void closeConnection();
 
+    IDBDatabaseMetadata m_metadata;
     RefPtr<IDBDatabaseBackendInterface> m_backend;
     RefPtr<IDBTransaction> m_versionChangeTransaction;
     HashSet<IDBTransaction*> m_transactions;
index 78e0ee0..b636d80 100644 (file)
@@ -134,6 +134,14 @@ PassRefPtr<IDBBackingStore> IDBDatabaseBackendImpl::backingStore() const
     return m_backingStore;
 }
 
+IDBDatabaseMetadata IDBDatabaseBackendImpl::metadata() const
+{
+    IDBDatabaseMetadata metadata(m_name, m_version);
+    for (ObjectStoreMap::const_iterator it = m_objectStores.begin(); it != m_objectStores.end(); ++it)
+        metadata.objectStores.set(it->first, it->second->metadata());
+    return metadata;
+}
+
 PassRefPtr<DOMStringList> IDBDatabaseBackendImpl::objectStoreNames() const
 {
     RefPtr<DOMStringList> objectStoreNames = DOMStringList::create();
index 15571a8..36eb241 100644 (file)
@@ -58,6 +58,7 @@ public:
     void openConnection(PassRefPtr<IDBCallbacks>);
     void deleteDatabase(PassRefPtr<IDBCallbacks>);
 
+    virtual IDBDatabaseMetadata metadata() const;
     virtual String name() const { return m_name; }
     virtual String version() const { return m_version; }
     virtual PassRefPtr<DOMStringList> objectStoreNames() const;
index 4248074..d581777 100644 (file)
@@ -41,6 +41,7 @@ class IDBDatabaseCallbacks;
 class IDBKeyPath;
 class IDBObjectStoreBackendInterface;
 class IDBTransactionBackendInterface;
+struct IDBDatabaseMetadata;
 
 typedef int ExceptionCode;
 
@@ -52,6 +53,7 @@ class IDBDatabaseBackendInterface : public ThreadSafeRefCounted<IDBDatabaseBacke
 public:
     virtual ~IDBDatabaseBackendInterface() { }
 
+    virtual IDBDatabaseMetadata metadata() const = 0;
     virtual String name() const = 0;
     virtual String version() const = 0;
     virtual PassRefPtr<DOMStringList> objectStoreNames() const = 0;
index 34df189..31e7f5d 100644 (file)
@@ -42,8 +42,9 @@ namespace WebCore {
 
 static const unsigned short defaultDirection = IDBCursor::NEXT;
 
-IDBIndex::IDBIndex(PassRefPtr<IDBIndexBackendInterface> backend, IDBObjectStore* objectStore, IDBTransaction* transaction)
-    : m_backend(backend)
+IDBIndex::IDBIndex(const IDBIndexMetadata& metadata, PassRefPtr<IDBIndexBackendInterface> backend, IDBObjectStore* objectStore, IDBTransaction* transaction)
+    : m_metadata(metadata)
+    , m_backend(backend)
     , m_objectStore(objectStore)
     , m_transaction(transaction)
     , m_deleted(false)
index c7e5f78..8201d5d 100644 (file)
@@ -30,6 +30,8 @@
 #include "IDBIndexBackendInterface.h"
 #include "IDBKeyPath.h"
 #include "IDBKeyRange.h"
+#include "IDBMetadata.h"
+#include "IDBObjectStore.h"
 #include "IDBRequest.h"
 #include "PlatformString.h"
 #include <wtf/Forward.h>
@@ -42,18 +44,18 @@ class IDBObjectStore;
 
 class IDBIndex : public RefCounted<IDBIndex> {
 public:
-    static PassRefPtr<IDBIndex> create(PassRefPtr<IDBIndexBackendInterface> backend, IDBObjectStore* objectStore, IDBTransaction* transaction)
+    static PassRefPtr<IDBIndex> create(const IDBIndexMetadata& metadata, PassRefPtr<IDBIndexBackendInterface> backend, IDBObjectStore* objectStore, IDBTransaction* transaction)
     {
-        return adoptRef(new IDBIndex(backend, objectStore, transaction));
+        return adoptRef(new IDBIndex(metadata, backend, objectStore, transaction));
     }
     ~IDBIndex();
 
     // Implement the IDL
-    String name() const { return m_backend->name(); }
-    IDBObjectStore* objectStore() const { return m_objectStore.get(); }
-    PassRefPtr<IDBAny> keyPath() const { return m_backend->keyPath(); }
-    bool unique() const { return m_backend->unique(); }
-    bool multiEntry() const { return m_backend->multiEntry(); }
+    const String name() const { return m_metadata.name; }
+    PassRefPtr<IDBObjectStore> objectStore() const { return m_objectStore; }
+    PassRefPtr<IDBAny> keyPath() const { return m_metadata.keyPath; }
+    bool unique() const { return m_metadata.unique; }
+    bool multiEntry() const { return m_metadata.multiEntry; }
 
     // FIXME: Try to modify the code generator so this is unneeded.
     PassRefPtr<IDBRequest> openCursor(ScriptExecutionContext* context, ExceptionCode& ec) { return openCursor(context, static_cast<IDBKeyRange*>(0), ec); }
@@ -83,8 +85,9 @@ public:
     void markDeleted() { m_deleted = true; }
 
 private:
-    IDBIndex(PassRefPtr<IDBIndexBackendInterface>, IDBObjectStore*, IDBTransaction*);
+    IDBIndex(const IDBIndexMetadata&, PassRefPtr<IDBIndexBackendInterface>, IDBObjectStore*, IDBTransaction*);
 
+    IDBIndexMetadata m_metadata;
     RefPtr<IDBIndexBackendInterface> m_backend;
     RefPtr<IDBObjectStore> m_objectStore;
     RefPtr<IDBTransaction> m_transaction;
index 98614df..a087e6a 100644 (file)
@@ -36,6 +36,7 @@
 #include "IDBDatabaseException.h"
 #include "IDBKey.h"
 #include "IDBKeyRange.h"
+#include "IDBMetadata.h"
 #include "IDBObjectStoreBackendImpl.h"
 #include "IDBTracing.h"
 
@@ -67,6 +68,11 @@ IDBIndexBackendImpl::~IDBIndexBackendImpl()
 {
 }
 
+IDBIndexMetadata IDBIndexBackendImpl::metadata() const
+{
+    return IDBIndexMetadata(m_name, m_keyPath, m_unique, m_multiEntry);
+}
+
 void IDBIndexBackendImpl::openCursorInternal(ScriptExecutionContext*, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBKeyRange> range, unsigned short untypedDirection, IDBCursorBackendInterface::CursorType cursorType, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface> transaction)
 {
     IDB_TRACE("IDBIndexBackendImpl::openCursorInternal");
index d8b197d..6410cba 100644 (file)
@@ -32,6 +32,7 @@
 #include "IDBDatabaseBackendImpl.h"
 #include "IDBIndexBackendInterface.h"
 #include "IDBKeyPath.h"
+#include "IDBMetadata.h"
 
 namespace WebCore {
 
@@ -63,6 +64,7 @@ public:
     bool addingKeyAllowed(const IDBKey* indexKey, const IDBKey* primaryKey = 0);
 
     // Implements IDBIndexBackendInterface.
+    virtual IDBIndexMetadata metadata() const;
     virtual String name() { return m_name; }
     virtual IDBKeyPath keyPath() { return m_keyPath; }
     virtual bool unique() { return m_unique; }
diff --git a/Source/WebCore/Modules/indexeddb/IDBMetadata.h b/Source/WebCore/Modules/indexeddb/IDBMetadata.h
new file mode 100644 (file)
index 0000000..247e84d
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2012 Google 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.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GOOGLE 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 OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef IDBMetadata_h
+#define IDBMetadata_h
+
+#include "IDBKeyPath.h"
+#include "PlatformString.h"
+#include <wtf/HashMap.h>
+#include <wtf/text/StringHash.h>
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+struct IDBObjectStoreMetadata;
+struct IDBIndexMetadata;
+
+struct IDBDatabaseMetadata {
+    IDBDatabaseMetadata() { }
+    IDBDatabaseMetadata(const String& name, const String& version)
+        : name(name)
+        , version(version) { }
+    String name;
+    String version;
+
+    typedef HashMap<String, IDBObjectStoreMetadata> ObjectStoreMap;
+    ObjectStoreMap objectStores;
+};
+
+struct IDBObjectStoreMetadata {
+    IDBObjectStoreMetadata() { }
+    IDBObjectStoreMetadata(const String& name, const IDBKeyPath& keyPath, bool autoIncrement)
+        : name(name)
+        , keyPath(keyPath)
+        , autoIncrement(autoIncrement) { }
+    String name;
+    IDBKeyPath keyPath;
+    bool autoIncrement;
+
+    typedef HashMap<String, IDBIndexMetadata> IndexMap;
+    IndexMap indexes;
+};
+
+struct IDBIndexMetadata {
+    IDBIndexMetadata() { }
+    IDBIndexMetadata(const String& name, const IDBKeyPath& keyPath, bool unique, bool multiEntry)
+        : name(name)
+        , keyPath(keyPath)
+        , unique(unique)
+        , multiEntry(multiEntry) { }
+    String name;
+    IDBKeyPath keyPath;
+    bool unique;
+    bool multiEntry;
+};
+
+}
+
+#endif // ENABLE(INDEXED_DATABASE)
+
+#endif // IDBMetadata_h
index b0fae85..68bc171 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "DOMStringList.h"
 #include "IDBAny.h"
+#include "IDBDatabase.h"
 #include "IDBDatabaseException.h"
 #include "IDBIndex.h"
 #include "IDBKey.h"
@@ -44,8 +45,9 @@ namespace WebCore {
 
 static const unsigned short defaultDirection = IDBCursor::NEXT;
 
-IDBObjectStore::IDBObjectStore(PassRefPtr<IDBObjectStoreBackendInterface> idbObjectStore, IDBTransaction* transaction)
-    : m_backend(idbObjectStore)
+IDBObjectStore::IDBObjectStore(const IDBObjectStoreMetadata& metadata, PassRefPtr<IDBObjectStoreBackendInterface> idbObjectStore, IDBTransaction* transaction)
+    : m_metadata(metadata)
+    , m_backend(idbObjectStore)
     , m_transaction(transaction)
     , m_deleted(false)
 {
@@ -55,34 +57,14 @@ IDBObjectStore::IDBObjectStore(PassRefPtr<IDBObjectStoreBackendInterface> idbObj
     relaxAdoptionRequirement();
 }
 
-String IDBObjectStore::name() const
-{
-    IDB_TRACE("IDBObjectStore::name");
-    return m_backend->name();
-}
-
-PassRefPtr<IDBAny> IDBObjectStore::keyPath() const
-{
-    IDB_TRACE("IDBObjectStore::keyPath");
-    return m_backend->keyPath();
-}
-
 PassRefPtr<DOMStringList> IDBObjectStore::indexNames() const
 {
     IDB_TRACE("IDBObjectStore::indexNames");
-    return m_backend->indexNames();
-}
-
-IDBTransaction* IDBObjectStore::transaction() const
-{
-    IDB_TRACE("IDBObjectStore::transaction");
-    return m_transaction.get();
-}
-
-bool IDBObjectStore::autoIncrement() const
-{
-    IDB_TRACE("IDBObjectStore::autoIncrement");
-    return m_backend->autoIncrement();
+    RefPtr<DOMStringList> indexNames = DOMStringList::create();
+    for (IDBObjectStoreMetadata::IndexMap::const_iterator it = m_metadata.indexes.begin(); it != m_metadata.indexes.end(); ++it)
+        indexNames->append(it->first);
+    indexNames->sort();
+    return indexNames.release();
 }
 
 PassRefPtr<IDBRequest> IDBObjectStore::get(ScriptExecutionContext* context, PassRefPtr<IDBKeyRange> keyRange, ExceptionCode& ec)
@@ -279,8 +261,10 @@ PassRefPtr<IDBIndex> IDBObjectStore::createIndex(const String& name, const IDBKe
     if (ec)
         return 0;
 
-    RefPtr<IDBIndex> index = IDBIndex::create(indexBackend.release(), this, m_transaction.get());
+    IDBIndexMetadata metadata(name, keyPath, unique, multiEntry);
+    RefPtr<IDBIndex> index = IDBIndex::create(metadata, indexBackend.release(), this, m_transaction.get());
     m_indexMap.set(name, index);
+    m_metadata.indexes.set(name, metadata);
 
     return index.release();
 }
@@ -306,7 +290,10 @@ PassRefPtr<IDBIndex> IDBObjectStore::index(const String& name, ExceptionCode& ec
     if (ec)
         return 0;
 
-    RefPtr<IDBIndex> index = IDBIndex::create(indexBackend.release(), this, m_transaction.get());
+    IDBObjectStoreMetadata::IndexMap::const_iterator mdit = m_metadata.indexes.find(name);
+    ASSERT(mdit != m_metadata.indexes.end());
+
+    RefPtr<IDBIndex> index = IDBIndex::create(mdit->second, indexBackend.release(), this, m_transaction.get());
     m_indexMap.set(name, index);
     return index.release();
 }
@@ -325,6 +312,9 @@ void IDBObjectStore::deleteIndex(const String& name, ExceptionCode& ec)
             it->second->markDeleted();
             m_indexMap.remove(name);
         }
+
+        ASSERT(m_metadata.indexes.contains(name));
+        m_metadata.indexes.remove(name);
     }
 }
 
index 834bd50..8181eb9 100644 (file)
@@ -31,6 +31,7 @@
 #include "IDBIndex.h"
 #include "IDBKey.h"
 #include "IDBKeyRange.h"
+#include "IDBMetadata.h"
 #include "IDBObjectStoreBackendInterface.h"
 #include "IDBRequest.h"
 #include "IDBTransaction.h"
@@ -49,18 +50,18 @@ class IDBAny;
 
 class IDBObjectStore : public RefCounted<IDBObjectStore> {
 public:
-    static PassRefPtr<IDBObjectStore> create(PassRefPtr<IDBObjectStoreBackendInterface> idbObjectStore, IDBTransaction* transaction)
+    static PassRefPtr<IDBObjectStore> create(const IDBObjectStoreMetadata& metadata, PassRefPtr<IDBObjectStoreBackendInterface> backend, IDBTransaction* transaction)
     {
-        return adoptRef(new IDBObjectStore(idbObjectStore, transaction));
+        return adoptRef(new IDBObjectStore(metadata, backend, transaction));
     }
     ~IDBObjectStore() { }
 
     // Implement the IDBObjectStore IDL
-    String name() const;
-    PassRefPtr<IDBAny> keyPath() const;
+    const String name() const { return m_metadata.name; }
+    PassRefPtr<IDBAny> keyPath() const { return m_metadata.keyPath; }
     PassRefPtr<DOMStringList> indexNames() const;
-    IDBTransaction* transaction() const;
-    bool autoIncrement() const;
+    PassRefPtr<IDBTransaction> transaction() const { return m_transaction; }
+    bool autoIncrement() const { return m_metadata.autoIncrement; }
 
     PassRefPtr<IDBRequest> add(ScriptExecutionContext* context, PassRefPtr<SerializedScriptValue> value, ExceptionCode& ec) { return add(context, value, 0, ec);  }
     PassRefPtr<IDBRequest> put(ScriptExecutionContext* context, PassRefPtr<SerializedScriptValue> value, ExceptionCode& ec) { return put(context, value, 0, ec);  }
@@ -97,10 +98,14 @@ public:
     void markDeleted() { m_deleted = true; }
     void transactionFinished();
 
+    IDBObjectStoreMetadata metadata() const { return m_metadata; }
+    void setMetadata(const IDBObjectStoreMetadata& metadata) { m_metadata = metadata; }
+
 private:
-    IDBObjectStore(PassRefPtr<IDBObjectStoreBackendInterface>, IDBTransaction*);
+    IDBObjectStore(const IDBObjectStoreMetadata&, PassRefPtr<IDBObjectStoreBackendInterface>, IDBTransaction*);
     void removeTransactionFromPendingList();
 
+    IDBObjectStoreMetadata m_metadata;
     RefPtr<IDBObjectStoreBackendInterface> m_backend;
     RefPtr<IDBTransaction> m_transaction;
     bool m_deleted;
index fecf880..7854497 100644 (file)
@@ -72,6 +72,14 @@ IDBObjectStoreBackendImpl::IDBObjectStoreBackendImpl(const IDBDatabaseBackendImp
 {
 }
 
+IDBObjectStoreMetadata IDBObjectStoreBackendImpl::metadata() const
+{
+    IDBObjectStoreMetadata metadata(m_name, m_keyPath, m_autoIncrement);
+    for (IndexMap::const_iterator it = m_indexes.begin(); it != m_indexes.end(); ++it)
+        metadata.indexes.set(it->first, it->second->metadata());
+    return metadata;
+}
+
 PassRefPtr<DOMStringList> IDBObjectStoreBackendImpl::indexNames() const
 {
     RefPtr<DOMStringList> indexNames = DOMStringList::create();
index bacd9df..07ab9fc 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "IDBDatabaseBackendImpl.h"
 #include "IDBKeyPath.h"
+#include "IDBMetadata.h"
 #include "IDBObjectStoreBackendInterface.h"
 #include <wtf/HashMap.h>
 #include <wtf/text/StringHash.h>
@@ -40,6 +41,7 @@ class IDBDatabaseBackendImpl;
 class IDBIndexBackendImpl;
 class IDBTransactionBackendInterface;
 class ScriptExecutionContext;
+struct IDBObjectStoreMetadata;
 
 class IDBObjectStoreBackendImpl : public IDBObjectStoreBackendInterface {
 public:
@@ -61,6 +63,7 @@ public:
     }
     void setId(int64_t id) { m_id = id; }
 
+    virtual IDBObjectStoreMetadata metadata() const;
     virtual String name() const { return m_name; }
     virtual IDBKeyPath keyPath() const { return m_keyPath; }
     virtual PassRefPtr<DOMStringList> indexNames() const;
index 641e576..7087c65 100644 (file)
@@ -158,25 +158,34 @@ PassRefPtr<IDBObjectStore> IDBTransaction::objectStore(const String& name, Excep
     if (ec)
         return 0;
 
-    RefPtr<IDBObjectStore> objectStore = IDBObjectStore::create(objectStoreBackend, this);
+    const IDBDatabaseMetadata& metadata = m_database->metadata();
+    IDBDatabaseMetadata::ObjectStoreMap::const_iterator mdit = metadata.objectStores.find(name);
+    ASSERT(mdit != metadata.objectStores.end());
+
+    RefPtr<IDBObjectStore> objectStore = IDBObjectStore::create(mdit->second, objectStoreBackend, this);
     objectStoreCreated(name, objectStore);
     return objectStore.release();
 }
 
-void IDBTransaction::objectStoreCreated(const String& name, PassRefPtr<IDBObjectStore> objectStore)
+void IDBTransaction::objectStoreCreated(const String& name, PassRefPtr<IDBObjectStore> prpObjectStore)
 {
     ASSERT(!m_transactionFinished);
+    RefPtr<IDBObjectStore> objectStore = prpObjectStore;
     m_objectStoreMap.set(name, objectStore);
+    if (isVersionChange())
+        m_objectStoreCleanupMap.set(objectStore, objectStore->metadata());
 }
 
 void IDBTransaction::objectStoreDeleted(const String& name)
 {
     ASSERT(!m_transactionFinished);
+    ASSERT(isVersionChange());
     IDBObjectStoreMap::iterator it = m_objectStoreMap.find(name);
     if (it != m_objectStoreMap.end()) {
         RefPtr<IDBObjectStore> objectStore = it->second;
         m_objectStoreMap.remove(name);
         objectStore->markDeleted();
+        m_objectStoreCleanupMap.set(objectStore, objectStore->metadata());
     }
 }
 
@@ -239,6 +248,11 @@ void IDBTransaction::onAbort()
         request->abort();
     }
 
+    if (isVersionChange()) {
+        for (IDBObjectStoreMetadataMap::iterator it = m_objectStoreCleanupMap.begin(); it != m_objectStoreCleanupMap.end(); ++it)
+            it->first->setMetadata(it->second);
+    }
+    m_objectStoreCleanupMap.clear();
     closeOpenCursors();
     m_database->transactionFinished(this);
 
@@ -251,6 +265,7 @@ void IDBTransaction::onAbort()
 void IDBTransaction::onComplete()
 {
     ASSERT(!m_transactionFinished);
+    m_objectStoreCleanupMap.clear();
     closeOpenCursors();
     m_database->transactionFinished(this);
 
index 4f95f5b..0b2dec6 100644 (file)
@@ -35,6 +35,7 @@
 #include "EventListener.h"
 #include "EventNames.h"
 #include "EventTarget.h"
+#include "IDBMetadata.h"
 #include "IDBTransactionBackendInterface.h"
 #include "IDBTransactionCallbacks.h"
 #include <wtf/HashSet.h>
@@ -143,6 +144,9 @@ private:
     typedef HashMap<String, RefPtr<IDBObjectStore> > IDBObjectStoreMap;
     IDBObjectStoreMap m_objectStoreMap;
 
+    typedef HashMap<RefPtr<IDBObjectStore>, IDBObjectStoreMetadata> IDBObjectStoreMetadataMap;
+    IDBObjectStoreMetadataMap m_objectStoreCleanupMap;
+
     HashSet<IDBCursor*> m_openCursors;
 
     EventTargetData m_eventTargetData;
index 5a03f9c..b3da70b 100644 (file)
             'Modules/indexeddb/IDBLevelDBCoding.h',
             'Modules/indexeddb/IDBLevelDBBackingStore.cpp',
             'Modules/indexeddb/IDBLevelDBBackingStore.h',
+            'Modules/indexeddb/IDBMetadata.h',
             'Modules/indexeddb/IDBObjectStore.cpp',
             'Modules/indexeddb/IDBObjectStore.h',
             'Modules/indexeddb/IDBObjectStoreBackendImpl.cpp',
index db6d8ac..c5ad8e7 100644 (file)
                BCC5BDFE0C0E93110011C2DB /* JSCSSStyleSheet.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = JSCSSStyleSheet.cpp; sourceTree = "<group>"; };
                BCC5BDFF0C0E93110011C2DB /* JSCSSStyleSheet.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = JSCSSStyleSheet.h; sourceTree = "<group>"; };
                BCC64F600DCFB84E0081EF3B /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = sourcecode.javascript; name = English; path = English.lproj/localizedStrings.js; sourceTree = SOURCE_ROOT; };
+               BCC65145159294C300ACC9E4 /* IDBMetadata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IDBMetadata.h; path = Modules/indexeddb/IDBMetadata.h; sourceTree = "<group>"; };
                BCC8CFCA0986CD2400140BF2 /* ColorData.gperf */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = ColorData.gperf; sourceTree = "<group>"; };
                BCCBAD3A0C18BFF800CE890F /* JSHTMLCollectionCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSHTMLCollectionCustom.cpp; sourceTree = "<group>"; };
                BCCBAD3E0C18C14200CE890F /* JSHTMLCollection.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = JSHTMLCollection.cpp; sourceTree = "<group>"; };
                                9712A58D15004EDA0048AF10 /* IDBLevelDBBackingStore.h */,
                                9712A58E15004EDA0048AF10 /* IDBLevelDBCoding.cpp */,
                                9712A58F15004EDA0048AF10 /* IDBLevelDBCoding.h */,
+                               BCC65145159294C300ACC9E4 /* IDBMetadata.h */,
                                9712A59015004EDA0048AF10 /* IDBObjectStore.cpp */,
                                9712A59115004EDA0048AF10 /* IDBObjectStore.h */,
                                9712A59215004EDA0048AF10 /* IDBObjectStore.idl */,
index 17c788b..fe13721 100644 (file)
@@ -1,3 +1,33 @@
+2012-06-22  Joshua Bell  <jsbell@chromium.org>
+
+        IndexedDB: Snapshot metadata in front end to avoid IPC round-trips
+        https://bugs.webkit.org/show_bug.cgi?id=88467
+
+        Reviewed by Tony Chang.
+
+        Add conversions to/from WebCore IDB metadata type and plumbing for routing the
+        IDBDatabaseBackendInterface::metadata() call through the public API..
+
+        * WebKit.gyp: New file added.
+        * public/WebIDBMetadata.h: Conversion functions.
+        (WebCore):
+        (WebIDBMetadata):
+        * src/IDBDatabaseBackendProxy.cpp: Plumbing.
+        (WebKit::IDBDatabaseBackendProxy::metadata):
+        (WebKit):
+        * src/IDBDatabaseBackendProxy.h: Plumbing.
+        (IDBDatabaseBackendProxy):
+        * src/WebIDBDatabaseImpl.cpp: Plumbing.
+        (WebKit::WebIDBDatabaseImpl::metadata):
+        (WebKit):
+        * src/WebIDBDatabaseImpl.h: Plumbing.
+        (WebKit):
+        (WebIDBDatabaseImpl):
+        * src/WebIDBMetadata.cpp: Added - conversion functions.
+        (WebKit):
+        (WebKit::WebIDBMetadata::WebIDBMetadata):
+        (WebKit::WebIDBMetadata::operator IDBDatabaseMetadata):
+
 2012-06-22  Fady Samuel  <fsamuel@chromium.org>
 
         [Chromium] Browser Plugin: Expose advanceFocus to WebKit API so that guests can advance focus of theirs embedders
index 65e8679..bcbb913 100644 (file)
                 'src/WebIDBKey.cpp',
                 'src/WebIDBKeyPath.cpp',
                 'src/WebIDBKeyRange.cpp',
+                'src/WebIDBMetadata.cpp',
                 'src/WebIDBObjectStoreImpl.cpp',
                 'src/WebIDBObjectStoreImpl.h',
                 'src/WebIDBTransactionImpl.cpp',
index 410d9fa..1c33d1b 100644 (file)
 #include "platform/WebString.h"
 #include "platform/WebVector.h"
 
+namespace WebCore {
+struct IDBDatabaseMetadata;
+}
+
 namespace WebKit {
 
 struct WebIDBMetadata {
@@ -62,6 +66,11 @@ struct WebIDBMetadata {
             , unique(false)
             , multiEntry(false) { }
     };
+
+#if WEBKIT_IMPLEMENTATION
+    WebIDBMetadata(const WebCore::IDBDatabaseMetadata&);
+    operator WebCore::IDBDatabaseMetadata() const;
+#endif
 };
 
 
index 58661eb..107ec63 100644 (file)
@@ -31,6 +31,7 @@
 #include "DOMStringList.h"
 #include "IDBCallbacks.h"
 #include "IDBDatabaseCallbacks.h"
+#include "IDBMetadata.h"
 #include "IDBObjectStoreBackendProxy.h"
 #include "IDBTransactionBackendProxy.h"
 #include "WebDOMStringList.h"
@@ -60,6 +61,11 @@ IDBDatabaseBackendProxy::~IDBDatabaseBackendProxy()
 {
 }
 
+IDBDatabaseMetadata IDBDatabaseBackendProxy::metadata() const
+{
+    return m_webIDBDatabase->metadata();
+}
+
 String IDBDatabaseBackendProxy::name() const
 {
     return m_webIDBDatabase->name();
index e817edf..b05552c 100644 (file)
@@ -42,6 +42,7 @@ public:
     static PassRefPtr<WebCore::IDBDatabaseBackendInterface> create(PassOwnPtr<WebIDBDatabase>);
     virtual ~IDBDatabaseBackendProxy();
 
+    virtual WebCore::IDBDatabaseMetadata metadata() const;
     virtual String name() const;
     virtual String version() const;
     virtual PassRefPtr<WebCore::DOMStringList> objectStoreNames() const;
index 2662f80..39803e1 100644 (file)
 #include "IDBCallbacksProxy.h"
 #include "IDBDatabaseBackendInterface.h"
 #include "IDBDatabaseCallbacksProxy.h"
+#include "IDBMetadata.h"
 #include "IDBTransactionBackendInterface.h"
 #include "WebIDBCallbacks.h"
 #include "WebIDBDatabaseCallbacks.h"
+#include "WebIDBMetadata.h"
 #include "WebIDBObjectStoreImpl.h"
 #include "WebIDBTransactionImpl.h"
 
@@ -51,6 +53,11 @@ WebIDBDatabaseImpl::~WebIDBDatabaseImpl()
 {
 }
 
+WebIDBMetadata WebIDBDatabaseImpl::metadata() const
+{
+    return m_databaseBackend->metadata();
+}
+
 WebString WebIDBDatabaseImpl::name() const
 {
     return m_databaseBackend->name();
index 190d7e2..5e989e0 100644 (file)
@@ -40,6 +40,7 @@ namespace WebKit {
 
 class IDBDatabaseCallbacksProxy;
 class WebIDBDatabaseCallbacks;
+class WebIDBDatabaseMetadata;
 class WebIDBObjectStore;
 class WebIDBTransaction;
 
@@ -49,6 +50,7 @@ public:
     WebIDBDatabaseImpl(WTF::PassRefPtr<WebCore::IDBDatabaseBackendInterface>);
     virtual ~WebIDBDatabaseImpl();
 
+    virtual WebIDBMetadata metadata() const;
     virtual WebString name() const;
     virtual WebString version() const;
     virtual WebDOMStringList objectStoreNames() const;
diff --git a/Source/WebKit/chromium/src/WebIDBMetadata.cpp b/Source/WebKit/chromium/src/WebIDBMetadata.cpp
new file mode 100644 (file)
index 0000000..735063e
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2012 Google 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 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 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 "WebIDBMetadata.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "IDBMetadata.h"
+#include "WebIDBKeyPath.h"
+#include "platform/WebString.h"
+#include "platform/WebVector.h"
+
+using namespace WebCore;
+
+namespace WebKit {
+
+WebIDBMetadata::WebIDBMetadata(const WebCore::IDBDatabaseMetadata& metadata)
+{
+    name = metadata.name;
+    version = metadata.version;
+    objectStores = WebVector<ObjectStore>(static_cast<size_t>(metadata.objectStores.size()));
+
+    size_t i = 0;
+    for (IDBDatabaseMetadata::ObjectStoreMap::const_iterator storeIterator = metadata.objectStores.begin(); storeIterator != metadata.objectStores.end(); ++storeIterator) {
+        const IDBObjectStoreMetadata& objectStore = storeIterator->second;
+        ObjectStore webObjectStore;
+        webObjectStore.name = objectStore.name;
+        webObjectStore.keyPath = objectStore.keyPath;
+        webObjectStore.autoIncrement = objectStore.autoIncrement;
+        webObjectStore.indexes = WebVector<Index>(static_cast<size_t>(objectStore.indexes.size()));
+
+        size_t j = 0;
+        for (IDBObjectStoreMetadata::IndexMap::const_iterator indexIterator = objectStore.indexes.begin(); indexIterator != objectStore.indexes.end(); ++indexIterator) {
+            const IDBIndexMetadata& index = indexIterator->second;
+            Index webIndex;
+            webIndex.name = index.name;
+            webIndex.keyPath = index.keyPath;
+            webIndex.unique = index.unique;
+            webIndex.multiEntry = index.multiEntry;
+            webObjectStore.indexes[j++] = webIndex;
+        }
+        objectStores[i++] = webObjectStore;
+    }
+}
+
+WebIDBMetadata::operator IDBDatabaseMetadata() const
+{
+    IDBDatabaseMetadata db(name, version);
+    for (size_t i = 0; i < objectStores.size(); ++i) {
+        const ObjectStore webObjectStore = objectStores[i];
+        IDBObjectStoreMetadata objectStore(webObjectStore.name, webObjectStore.keyPath, webObjectStore.autoIncrement);
+
+        for (size_t j = 0; j < webObjectStore.indexes.size(); ++j) {
+            const Index webIndex = webObjectStore.indexes[j];
+            IDBIndexMetadata index(webIndex.name, webIndex.keyPath, webIndex.unique, webIndex.multiEntry);
+            objectStore.indexes.set(index.name, index);
+        }
+        db.objectStores.set(objectStore.name, objectStore);
+    }
+    return db;
+}
+
+} // namespace WebKit
+
+#endif // ENABLE(INDEXED_DATABASE)