Diff
Modified: trunk/LayoutTests/ChangeLog (98748 => 98749)
--- trunk/LayoutTests/ChangeLog 2011-10-28 19:15:26 UTC (rev 98748)
+++ trunk/LayoutTests/ChangeLog 2011-10-28 19:22:27 UTC (rev 98749)
@@ -1,3 +1,15 @@
+2011-10-28 Joshua Bell <[email protected]>
+
+ IndexedDB: Database metadata changes should be tied to transaction
+ https://bugs.webkit.org/show_bug.cgi?id=70974
+
+ Reviewed by Tony Chang.
+
+ * storage/indexeddb/open-during-transaction-expected.txt: Added.
+ * storage/indexeddb/open-during-transaction.html: Added.
+ * storage/indexeddb/version-change-abort-expected.txt: Added.
+ * storage/indexeddb/version-change-abort.html: Added.
+
2011-10-28 Simon Fraser <[email protected]>
Added some missing results for compositing visibilty tests.
Added: trunk/LayoutTests/storage/indexeddb/open-during-transaction-expected.txt (0 => 98749)
--- trunk/LayoutTests/storage/indexeddb/open-during-transaction-expected.txt (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/open-during-transaction-expected.txt 2011-10-28 19:22:27 UTC (rev 98749)
@@ -0,0 +1,42 @@
+Test IndexedDB opening database connections during transactions
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB;
+PASS indexedDB == null is false
+IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction;
+PASS IDBTransaction == null is false
+
+prepare database
+openreq1 = indexedDB.open('db1')
+dbc1 = openreq1.result
+setverreq = dbc1.setVersion('1.0')
+dbc1.createObjectStore('storeName')
+database preparation complete
+
+starting transaction
+state = 'starting'
+trans = dbc1.transaction('storeName', IDBTransaction.READ_WRITE)
+trans.objectStore('storeName').put('value', 'key')
+
+trying to open the same database
+openreq2 = indexedDB.open('db1')
+
+trying to open a different database
+openreq3 = indexedDB.open('db2')
+
+openreq2.onsuccess
+PASS state is "starting"
+state = 'open2complete'
+
+openreq3.onsuccess
+PASS state is "open2complete"
+state = 'open3complete'
+
+transaction complete
+PASS state is "open3complete"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/storage/indexeddb/open-during-transaction.html (0 => 98749)
--- trunk/LayoutTests/storage/indexeddb/open-during-transaction.html (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/open-during-transaction.html 2011-10-28 19:22:27 UTC (rev 98749)
@@ -0,0 +1,96 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link rel="stylesheet" href=""
+<script src=""
+<script src=""
+<script src=""
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+<script>
+
+description("Test IndexedDB opening database connections during transactions");
+if (window.layoutTestController)
+ layoutTestController.waitUntilDone();
+
+function test()
+{
+ evalAndLog("indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB;");
+ shouldBeFalse("indexedDB == null");
+ evalAndLog("IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction;");
+ shouldBeFalse("IDBTransaction == null");
+ debug("");
+ prepareDatabase();
+}
+
+function prepareDatabase()
+{
+ debug("prepare database");
+ evalAndLog("openreq1 = indexedDB.open('db1')");
+ openreq1._onerror_ = unexpectedErrorCallback;
+ openreq1._onsuccess_ = function (e) {
+ evalAndLog("dbc1 = openreq1.result");
+ evalAndLog("setverreq = dbc1.setVersion('1.0')");
+ setverreq._onerror_ = unexpectedErrorCallback;
+ setverreq._onsuccess_ = function (e) {
+ evalAndLog("dbc1.createObjectStore('storeName')");
+ setverreq.result._oncomplete_ = function (e) {
+ debug("database preparation complete");
+ debug("");
+ startTransaction();
+ };
+ };
+ };
+}
+
+function startTransaction()
+{
+ debug("starting transaction");
+ evalAndLog("state = 'starting'");
+ evalAndLog("trans = dbc1.transaction('storeName', IDBTransaction.READ_WRITE)");
+ evalAndLog("trans.objectStore('storeName').put('value', 'key')");
+ trans._onabort_ = unexpectedAbortCallback;
+ trans._onerror_ = unexpectedErrorCallback;
+ trans._oncomplete_ = function (e) {
+ debug("transaction complete");
+ shouldBeEqualToString("state", "open3complete");
+ done();
+ };
+
+ debug("");
+ tryOpens();
+}
+
+
+function tryOpens()
+{
+ debug("trying to open the same database");
+ evalAndLog("openreq2 = indexedDB.open('db1')");
+ openreq2._onerror_ = unexpectedErrorCallback;
+ openreq2._onsuccess_ = function (e) {
+ debug("openreq2.onsuccess");
+ shouldBeEqualToString("state", "starting");
+ evalAndLog("state = 'open2complete'");
+ debug("");
+ }
+ debug("");
+
+ debug("trying to open a different database");
+ evalAndLog("openreq3 = indexedDB.open('db2')");
+ openreq3._onerror_ = unexpectedErrorCallback;
+ openreq3._onsuccess_ = function (e) {
+ debug("openreq3.onsuccess");
+ shouldBeEqualToString("state", "open2complete");
+ evalAndLog("state = 'open3complete'");
+ debug("");
+ }
+ debug("");
+}
+
+test();
+
+</script>
+</body>
+</html>
Added: trunk/LayoutTests/storage/indexeddb/version-change-abort-expected.txt (0 => 98749)
--- trunk/LayoutTests/storage/indexeddb/version-change-abort-expected.txt (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/version-change-abort-expected.txt 2011-10-28 19:22:27 UTC (rev 98749)
@@ -0,0 +1,37 @@
+CONSOLE MESSAGE: line 86: Uncaught Error: This should *NOT* be caught!
+Ensure that aborted VERSION_CHANGE transactions are completely rolled back
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB;
+IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction;
+PASS indexedDB == null is false
+PASS IDBTransaction == null is false
+
+indexedDB.open('version-change-abort')
+db = event.target.result
+
+vcreq = db.setVersion('version 1')
+setVersion1() callback
+PASS vcreq.result instanceof IDBTransaction is true
+store = db.createObjectStore('store1')
+setVersion1 complete
+PASS db.version is "version 1"
+
+vcreq = db.setVersion('version 2')
+setVersion2() callback
+PASS db.version is "version 2"
+PASS vcreq.result instanceof IDBTransaction is true
+store = db.deleteObjectStore('store1')
+store = db.createObjectStore('store2')
+raising exception
+
+setVersion2Abort() callback
+PASS db.version is "version 1"
+PASS db.objectStoreNames.contains('store1') is true
+PASS db.objectStoreNames.contains('store2') is false
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/storage/indexeddb/version-change-abort.html (0 => 98749)
--- trunk/LayoutTests/storage/indexeddb/version-change-abort.html (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/version-change-abort.html 2011-10-28 19:22:27 UTC (rev 98749)
@@ -0,0 +1,108 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link rel="stylesheet" href=""
+<script src=""
+<script src=""
+<script src=""
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+<script>
+
+description("Ensure that aborted VERSION_CHANGE transactions are completely rolled back");
+if (window.layoutTestController)
+ layoutTestController.waitUntilDone();
+
+
+function test() {
+ evalAndLog("indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB;");
+ evalAndLog("IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction;");
+ shouldBeFalse("indexedDB == null");
+ shouldBeFalse("IDBTransaction == null");
+ debug("");
+ openDBConnection();
+}
+
+function openDBConnection()
+{
+ request = evalAndLog("indexedDB.open('version-change-abort')");
+ request._onsuccess_ = openSuccess;
+ request._onerror_ = unexpectedErrorCallback;
+}
+
+function openSuccess()
+{
+ window.db = evalAndLog("db = event.target.result");
+ debug("");
+
+ evalAndLog("vcreq = db.setVersion('version 1')");
+ vcreq._onsuccess_ = inSetVersion1;
+ vcreq._onerror_ = unexpectedErrorCallback;
+}
+
+function inSetVersion1()
+{
+ debug("setVersion1() callback");
+ shouldBeTrue("vcreq.result instanceof IDBTransaction");
+ trans = vcreq.result;
+ trans._onabort_ = unexpectedAbortCallback;
+ trans._onerror_ = unexpectedErrorCallback;
+ trans._oncomplete_ = setVersion1Complete;
+
+ evalAndLog("store = db.createObjectStore('store1')");
+}
+
+function setVersion1Complete()
+{
+ debug("setVersion1 complete");
+ shouldBeEqualToString("db.version", "version 1");
+ debug("");
+
+ evalAndLog("vcreq = db.setVersion('version 2')");
+ vcreq._onsuccess_ = inSetVersion2;
+ vcreq._onerror_ = unexpectedErrorCallback;
+}
+
+function inSetVersion2()
+{
+ debug("setVersion2() callback");
+ shouldBeEqualToString("db.version", "version 2");
+ shouldBeTrue("vcreq.result instanceof IDBTransaction");
+ trans = vcreq.result;
+ trans._onabort_ = setVersion2Abort;
+ trans._onerror_ = unexpectedErrorCallback;
+ trans._oncomplete_ = unexpectedCompleteCallback;
+
+ evalAndLog("store = db.deleteObjectStore('store1')");
+ evalAndLog("store = db.createObjectStore('store2')");
+
+ // Ensure the test harness error handler is not invoked.
+ window.originalWindowOnError = window.onerror;
+ window._onerror_ = null;
+
+ debug("raising exception");
+ throw new Error("This should *NOT* be caught!");
+}
+
+function setVersion2Abort()
+{
+ debug("");
+ debug("setVersion2Abort() callback");
+
+ // Restore test harness error handler.
+ window._onerror_ = window.originalWindowOnError;
+
+ shouldBeEqualToString("db.version", "version 1");
+ shouldBeTrue("db.objectStoreNames.contains('store1')");
+ shouldBeFalse("db.objectStoreNames.contains('store2')");
+
+ done();
+}
+
+test();
+
+</script>
+</body>
+</html>
Modified: trunk/Source/WebCore/ChangeLog (98748 => 98749)
--- trunk/Source/WebCore/ChangeLog 2011-10-28 19:15:26 UTC (rev 98748)
+++ trunk/Source/WebCore/ChangeLog 2011-10-28 19:22:27 UTC (rev 98749)
@@ -1,3 +1,36 @@
+2011-10-28 Joshua Bell <[email protected]>
+
+ IndexedDB: Database metadata changes should be tied to transaction
+ https://bugs.webkit.org/show_bug.cgi?id=70974
+
+ Reviewed by Tony Chang.
+
+ Database metadata (that is, the version string) was rolled back
+ on abort by an abort task. If the abort task didn't run e.g.
+ due to a crash, the metadata would not be reverted. All of the
+ other store/index/data changes were written into the transaction
+ itself, so the metadata now is too. Refactored the metadata
+ get/create/update methods for clarity as well.
+
+ Note that the new tests don't actually verify that the code handles
+ this case; that will need to be done with persistence tests
+ that span multiple runs of the browser and induce crashes.
+ The new tests do verify that these changes don't cause regressions
+ not caught by other tests.
+
+ Tests: storage/indexeddb/open-during-transaction.html
+ storage/indexeddb/version-change-abort.html
+
+ * storage/IDBBackingStore.h:
+ * storage/IDBDatabaseBackendImpl.cpp:
+ (WebCore::IDBDatabaseBackendImpl::IDBDatabaseBackendImpl):
+ (WebCore::IDBDatabaseBackendImpl::setVersionInternal):
+ * storage/IDBLevelDBBackingStore.cpp:
+ (WebCore::IDBLevelDBBackingStore::getIDBDatabaseMetaData):
+ (WebCore::IDBLevelDBBackingStore::createIDBDatabaseMetaData):
+ (WebCore::IDBLevelDBBackingStore::updateIDBDatabaseMetaData):
+ * storage/IDBLevelDBBackingStore.h:
+
2011-10-28 Luke Macpherson <[email protected]>
Use enum instead of bool to represent -webkit-column-span property.
Modified: trunk/Source/WebCore/storage/IDBBackingStore.h (98748 => 98749)
--- trunk/Source/WebCore/storage/IDBBackingStore.h 2011-10-28 19:15:26 UTC (rev 98748)
+++ trunk/Source/WebCore/storage/IDBBackingStore.h 2011-10-28 19:22:27 UTC (rev 98749)
@@ -47,8 +47,9 @@
virtual ~IDBBackingStore() {};
virtual void getDatabaseNames(Vector<String>& foundNames) = 0;
- virtual bool extractIDBDatabaseMetaData(const String& name, String& foundVersion, int64_t& foundId) = 0;
- virtual bool setIDBDatabaseMetaData(const String& name, const String& version, int64_t& rowId, bool invalidRowId) = 0;
+ virtual bool getIDBDatabaseMetaData(const String& name, String& foundVersion, int64_t& foundId) = 0;
+ virtual bool createIDBDatabaseMetaData(const String& name, const String& version, int64_t& rowId) = 0;
+ virtual bool updateIDBDatabaseMetaData(int64_t rowId, const String& version) = 0;
virtual void getObjectStores(int64_t databaseId, Vector<int64_t>& foundIds, Vector<String>& foundNames, Vector<String>& foundKeyPaths, Vector<bool>& foundAutoIncrementFlags) = 0;
virtual bool createObjectStore(int64_t databaseId, const String& name, const String& keyPath, bool autoIncrement, int64_t& assignedObjectStoreId) = 0;
Modified: trunk/Source/WebCore/storage/IDBDatabaseBackendImpl.cpp (98748 => 98749)
--- trunk/Source/WebCore/storage/IDBDatabaseBackendImpl.cpp 2011-10-28 19:15:26 UTC (rev 98748)
+++ trunk/Source/WebCore/storage/IDBDatabaseBackendImpl.cpp 2011-10-28 19:22:27 UTC (rev 98749)
@@ -88,9 +88,9 @@
{
ASSERT(!m_name.isNull());
- bool success = m_backingStore->extractIDBDatabaseMetaData(m_name, m_version, m_id);
- ASSERT_UNUSED(success, success == (m_id != InvalidId));
- if (!m_backingStore->setIDBDatabaseMetaData(m_name, m_version, m_id, m_id == InvalidId))
+ bool success = m_backingStore->getIDBDatabaseMetaData(m_name, m_version, m_id);
+ ASSERT(success == (m_id != InvalidId));
+ if (!success && !m_backingStore->createIDBDatabaseMetaData(m_name, m_version, m_id))
ASSERT_NOT_REACHED(); // FIXME: Need better error handling.
loadObjectStores();
}
@@ -218,7 +218,7 @@
{
int64_t databaseId = database->id();
database->m_version = version;
- if (!database->m_backingStore->setIDBDatabaseMetaData(database->m_name, database->m_version, databaseId, databaseId == InvalidId)) {
+ if (!database->m_backingStore->updateIDBDatabaseMetaData(databaseId, database->m_version)) {
// FIXME: The Indexed Database specification does not have an error code dedicated to I/O errors.
callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage."));
transaction->abort();
Modified: trunk/Source/WebCore/storage/IDBLevelDBBackingStore.cpp (98748 => 98749)
--- trunk/Source/WebCore/storage/IDBLevelDBBackingStore.cpp 2011-10-28 19:15:26 UTC (rev 98748)
+++ trunk/Source/WebCore/storage/IDBLevelDBBackingStore.cpp 2011-10-28 19:22:27 UTC (rev 98749)
@@ -186,7 +186,7 @@
}
}
-bool IDBLevelDBBackingStore::extractIDBDatabaseMetaData(const String& name, String& foundVersion, int64_t& foundId)
+bool IDBLevelDBBackingStore::getIDBDatabaseMetaData(const String& name, String& foundVersion, int64_t& foundId)
{
const Vector<char> key = DatabaseNameKey::encode(m_identifier, name);
@@ -216,21 +216,26 @@
return databaseId;
}
-bool IDBLevelDBBackingStore::setIDBDatabaseMetaData(const String& name, const String& version, int64_t& rowId, bool invalidRowId)
+bool IDBLevelDBBackingStore::createIDBDatabaseMetaData(const String& name, const String& version, int64_t& rowId)
{
- if (invalidRowId) {
- rowId = getNewDatabaseId(m_db.get());
- if (rowId < 0)
- return false;
+ rowId = getNewDatabaseId(m_db.get());
+ if (rowId < 0)
+ return false;
- const Vector<char> key = DatabaseNameKey::encode(m_identifier, name);
- if (!putInt(m_db.get(), key, rowId))
- return false;
- }
-
+ const Vector<char> key = DatabaseNameKey::encode(m_identifier, name);
+ if (!putInt(m_db.get(), key, rowId))
+ return false;
if (!putString(m_db.get(), DatabaseMetaDataKey::encode(rowId, DatabaseMetaDataKey::kUserVersion), version))
return false;
+ return true;
+}
+bool IDBLevelDBBackingStore::updateIDBDatabaseMetaData(int64_t rowId, const String& version)
+{
+ ASSERT(m_currentTransaction);
+ if (!putString(m_currentTransaction.get(), DatabaseMetaDataKey::encode(rowId, DatabaseMetaDataKey::kUserVersion), version))
+ return false;
+
return true;
}
Modified: trunk/Source/WebCore/storage/IDBLevelDBBackingStore.h (98748 => 98749)
--- trunk/Source/WebCore/storage/IDBLevelDBBackingStore.h 2011-10-28 19:15:26 UTC (rev 98748)
+++ trunk/Source/WebCore/storage/IDBLevelDBBackingStore.h 2011-10-28 19:22:27 UTC (rev 98749)
@@ -45,8 +45,9 @@
virtual ~IDBLevelDBBackingStore();
virtual void getDatabaseNames(Vector<String>& foundNames);
- virtual bool extractIDBDatabaseMetaData(const String& name, String& foundVersion, int64_t& foundId);
- virtual bool setIDBDatabaseMetaData(const String& name, const String& version, int64_t& rowId, bool invalidRowId);
+ virtual bool getIDBDatabaseMetaData(const String& name, String& foundVersion, int64_t& foundId);
+ virtual bool createIDBDatabaseMetaData(const String& name, const String& version, int64_t& rowId);
+ virtual bool updateIDBDatabaseMetaData(int64_t rowId, const String& version);
virtual void getObjectStores(int64_t databaseId, Vector<int64_t>& foundIds, Vector<String>& foundNames, Vector<String>& foundKeyPaths, Vector<bool>& foundAutoIncrementFlags);
virtual bool createObjectStore(int64_t databaseId, const String& name, const String& keyPath, bool autoIncrement, int64_t& assignedObjectStoreId);