Commit f9c19cc4 authored by hans@chromium.org's avatar hans@chromium.org

2011-05-05 Hans Wennborg <hans@chromium.org>

        Reviewed by Steve Block.

        IndexedDB: Transaction rollback prevented by open SQLite statement
        https://bugs.webkit.org/show_bug.cgi?id=60032

        Add test for veryfing that transaction roll-back works, even with a
        previously opened cursor still around.

        * storage/indexeddb/transaction-rollback-expected.txt: Added.
        * storage/indexeddb/transaction-rollback.html: Added.
2011-05-05  Hans Wennborg  <hans@chromium.org>

        Reviewed by Steve Block.

        IndexedDB: Transaction rollback prevented by open SQLite statement
        https://bugs.webkit.org/show_bug.cgi?id=60032

        Let the IDBTransactionbackendImpl keep track of all open cursors, and
        "close" them (i.e. finalizing the underlying SQLiteStatement) before
        committing or rolling back the transaction. This fixes the problem
        with opened cursors preventing transaction rollback.

        Test: storage/indexeddb/transaction-rollback.html

        * storage/IDBBackingStore.h:
        * storage/IDBCursorBackendImpl.cpp:
        (WebCore::IDBCursorBackendImpl::IDBCursorBackendImpl):
        (WebCore::IDBCursorBackendImpl::~IDBCursorBackendImpl):
        (WebCore::IDBCursorBackendImpl::close):
        * storage/IDBCursorBackendImpl.h:
        * storage/IDBLevelDBBackingStore.cpp:
        * storage/IDBSQLiteBackingStore.cpp:
        * storage/IDBTransactionBackendImpl.cpp:
        (WebCore::IDBTransactionBackendImpl::abort):
        (WebCore::IDBTransactionBackendImpl::registerOpenCursor):
        (WebCore::IDBTransactionBackendImpl::unregisterOpenCursor):
        (WebCore::IDBTransactionBackendImpl::commit):
        (WebCore::IDBTransactionBackendImpl::closeOpenCursors):
        * storage/IDBTransactionBackendImpl.h:
        * storage/IDBTransactionBackendInterface.h:
        (WebCore::IDBTransactionBackendInterface::registerOpenCursor):
        (WebCore::IDBTransactionBackendInterface::unregisterOpenCursor):
2011-05-05  Hans Wennborg  <hans@chromium.org>

        Reviewed by Steve Block.

        IndexedDB: Transaction rollback prevented by open SQLite statement
        https://bugs.webkit.org/show_bug.cgi?id=60032

        Implement two new methods in IDBTransactionBackendInterface.

        * src/IDBTransactionBackendProxy.cpp:
        (WebKit::IDBTransactionBackendProxy::registerOpenCursor):
        (WebKit::IDBTransactionBackendProxy::unregisterOpenCursor):
        * src/IDBTransactionBackendProxy.h:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@86422 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 8df6bfdc
2011-05-05 Hans Wennborg <hans@chromium.org>
Reviewed by Steve Block.
IndexedDB: Transaction rollback prevented by open SQLite statement
https://bugs.webkit.org/show_bug.cgi?id=60032
Add test for veryfing that transaction roll-back works, even with a
previously opened cursor still around.
* storage/indexeddb/transaction-rollback-expected.txt: Added.
* storage/indexeddb/transaction-rollback.html: Added.
2011-05-13 Sergio Villar Senin <svillar@igalia.com>
Unreviewed, new GTK+ test expectations after r86352.
Test IndexedDB transaction rollback.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS 'webkitIndexedDB' in window is true
PASS webkitIndexedDB == null is false
webkitIndexedDB.open('transaction-rollback')
openSuccess():
db = event.target.result
request = db.setVersion('version 1')
cleanDatabase():
transaction = event.target.result
Deleted all object stores.
db.createObjectStore('myObjectStore')
PASS db.objectStoreNames.length is 1
setVersionComplete():
transaction = db.transaction(['myObjectStore'], webkitIDBTransaction.READ_WRITE)
store = transaction.objectStore('myObjectStore')
store.add('rollbackValue', 'rollbackKey123')
addSuccess():
PASS event.target.result is 'rollbackKey123'
store.openCursor()
openCursorSuccess():
cursor = event.target.result
abortCallback():
Transaction was aborted.
transaction = db.transaction(['myObjectStore'], webkitIDBTransaction.READ)
store = transaction.objectStore('myObjectStore')
store.get('rollbackKey123')
getSuccess():
PASS event.target.result is undefined
PASS cursor.value is 'rollbackValue'
PASS successfullyParsed is true
TEST COMPLETE
<html>
<head>
<link rel="stylesheet" href="../../fast/js/resources/js-test-style.css">
<script src="../../fast/js/resources/js-test-pre.js"></script>
<script src="../../fast/js/resources/js-test-post-function.js"></script>
<script src="resources/shared.js"></script>
</head>
<body>
<p id="description"></p>
<div id="console"></div>
<script>
description("Test IndexedDB transaction rollback.");
if (window.layoutTestController)
layoutTestController.waitUntilDone();
function test()
{
shouldBeTrue("'webkitIndexedDB' in window");
shouldBeFalse("webkitIndexedDB == null");
request = evalAndLog("webkitIndexedDB.open('transaction-rollback')");
request.onsuccess = openSuccess;
request.onerror = unexpectedErrorCallback;
}
function openSuccess()
{
debug("openSuccess():");
window.db = evalAndLog("db = event.target.result");
request = evalAndLog("request = db.setVersion('version 1')");
request.onsuccess = cleanDatabase;
request.onerror = unexpectedErrorCallback;
}
function cleanDatabase()
{
debug("cleanDatabase():");
window.transaction = evalAndLog("transaction = event.target.result");
transaction.onabort = unexpectedErrorCallback;
transaction.oncomplete = setVersionComplete;
deleteAllObjectStores(db);
evalAndLog("db.createObjectStore('myObjectStore')");
shouldBe("db.objectStoreNames.length", "1");
}
function setVersionComplete()
{
debug("setVersionComplete():");
window.transaction = evalAndLog("transaction = db.transaction(['myObjectStore'], webkitIDBTransaction.READ_WRITE)");
transaction.onabort = abortCallback;
transaction.oncomplete = unexpectedCompleteCallback;
window.store = evalAndLog("store = transaction.objectStore('myObjectStore')");
request = evalAndLog("store.add('rollbackValue', 'rollbackKey123')");
request.onsuccess = addSuccess;
request.onerror = unexpectedErrorCallback;
}
function addSuccess()
{
debug("addSuccess():");
shouldBe("event.target.result", "'rollbackKey123'");
request = evalAndLog("store.openCursor()");
request.onsuccess = openCursorSuccess;
request.onerror = unexpectedErrorCallback;
}
function openCursorSuccess()
{
debug("openCursorSuccess():");
window.cursor = evalAndLog("cursor = event.target.result");
transaction.abort();
}
function abortCallback()
{
debug("abortCallback():");
debug('Transaction was aborted.');
window.transaction = evalAndLog("transaction = db.transaction(['myObjectStore'], webkitIDBTransaction.READ)");
window.store = evalAndLog("store = transaction.objectStore('myObjectStore')");
request = evalAndLog("store.get('rollbackKey123')");
request.onerror = unexpectedErrorCallback;
request.onsuccess = getSuccess;
}
function getSuccess()
{
debug("getSuccess():");
shouldBe("event.target.result", "undefined");
shouldBe("cursor.value", "'rollbackValue'");
done();
}
var successfullyParsed = true;
test();
</script>
</body>
</html>
2011-05-05 Hans Wennborg <hans@chromium.org>
Reviewed by Steve Block.
IndexedDB: Transaction rollback prevented by open SQLite statement
https://bugs.webkit.org/show_bug.cgi?id=60032
Let the IDBTransactionbackendImpl keep track of all open cursors, and
"close" them (i.e. finalizing the underlying SQLiteStatement) before
committing or rolling back the transaction. This fixes the problem
with opened cursors preventing transaction rollback.
Test: storage/indexeddb/transaction-rollback.html
* storage/IDBBackingStore.h:
* storage/IDBCursorBackendImpl.cpp:
(WebCore::IDBCursorBackendImpl::IDBCursorBackendImpl):
(WebCore::IDBCursorBackendImpl::~IDBCursorBackendImpl):
(WebCore::IDBCursorBackendImpl::close):
* storage/IDBCursorBackendImpl.h:
* storage/IDBLevelDBBackingStore.cpp:
* storage/IDBSQLiteBackingStore.cpp:
* storage/IDBTransactionBackendImpl.cpp:
(WebCore::IDBTransactionBackendImpl::abort):
(WebCore::IDBTransactionBackendImpl::registerOpenCursor):
(WebCore::IDBTransactionBackendImpl::unregisterOpenCursor):
(WebCore::IDBTransactionBackendImpl::commit):
(WebCore::IDBTransactionBackendImpl::closeOpenCursors):
* storage/IDBTransactionBackendImpl.h:
* storage/IDBTransactionBackendInterface.h:
(WebCore::IDBTransactionBackendInterface::registerOpenCursor):
(WebCore::IDBTransactionBackendInterface::unregisterOpenCursor):
2011-05-13 Patrick Gansterer <paroga@webkit.org>
Reviewed by Adam Barth.
......@@ -91,7 +91,8 @@ public:
virtual String value() = 0;
virtual PassRefPtr<ObjectStoreRecordIdentifier> objectStoreRecordIdentifier() = 0;
virtual int64_t indexDataId() = 0;
virtual ~Cursor() {};
virtual void close() = 0;
virtual ~Cursor() { };
};
virtual PassRefPtr<Cursor> openObjectStoreCursor(int64_t databaseId, int64_t objectStoreId, const IDBKeyRange*, IDBCursor::Direction) = 0;
......
......@@ -48,10 +48,12 @@ IDBCursorBackendImpl::IDBCursorBackendImpl(PassRefPtr<IDBBackingStore::Cursor> c
, m_transaction(transaction)
, m_objectStore(objectStore)
{
m_transaction->registerOpenCursor(this);
}
IDBCursorBackendImpl::~IDBCursorBackendImpl()
{
m_transaction->unregisterOpenCursor(this);
}
unsigned short IDBCursorBackendImpl::direction() const
......@@ -120,6 +122,12 @@ void IDBCursorBackendImpl::deleteFunction(PassRefPtr<IDBCallbacks> prpCallbacks,
m_objectStore->deleteFunction(m_cursor->primaryKey(), prpCallbacks, m_transaction.get(), ec);
}
void IDBCursorBackendImpl::close()
{
if (m_cursor)
m_cursor->close();
}
} // namespace WebCore
#endif // ENABLE(INDEXED_DATABASE)
......@@ -61,6 +61,7 @@ public:
virtual void update(PassRefPtr<SerializedScriptValue>, PassRefPtr<IDBCallbacks>, ExceptionCode&);
virtual void continueFunction(PassRefPtr<IDBKey>, PassRefPtr<IDBCallbacks>, ExceptionCode&);
virtual void deleteFunction(PassRefPtr<IDBCallbacks>, ExceptionCode&);
void close();
private:
IDBCursorBackendImpl(PassRefPtr<IDBBackingStore::Cursor>, IDBCursor::Direction, CursorType, IDBTransactionBackendInterface*, IDBObjectStoreBackendInterface*);
......
......@@ -812,6 +812,7 @@ public:
virtual String value() = 0;
virtual PassRefPtr<IDBBackingStore::ObjectStoreRecordIdentifier> objectStoreRecordIdentifier() = 0; // FIXME: I don't think this is actually used, so drop it.
virtual int64_t indexDataId() = 0;
virtual void close() { }
virtual bool loadCurrentRow() = 0;
bool firstSeek();
......
......@@ -708,6 +708,7 @@ public:
virtual String value() = 0;
virtual PassRefPtr<IDBBackingStore::ObjectStoreRecordIdentifier> objectStoreRecordIdentifier() = 0;
virtual int64_t indexDataId() = 0;
virtual void close() { m_query.finalize(); }
virtual void loadCurrentRow() = 0;
virtual bool currentRowExists() = 0;
......
......@@ -29,6 +29,7 @@
#if ENABLE(INDEXED_DATABASE)
#include "IDBBackingStore.h"
#include "IDBCursorBackendImpl.h"
#include "IDBDatabaseBackendImpl.h"
#include "IDBDatabaseException.h"
#include "IDBTransactionCoordinator.h"
......@@ -113,6 +114,8 @@ void IDBTransactionBackendImpl::abort()
m_state = Finished;
m_taskTimer.stop();
m_taskEventTimer.stop();
closeOpenCursors();
m_transaction->rollback();
// Run the abort tasks, if any.
......@@ -128,6 +131,16 @@ void IDBTransactionBackendImpl::abort()
m_database = 0;
}
void IDBTransactionBackendImpl::registerOpenCursor(IDBCursorBackendImpl* cursor)
{
m_openCursors.add(cursor);
}
void IDBTransactionBackendImpl::unregisterOpenCursor(IDBCursorBackendImpl* cursor)
{
m_openCursors.remove(cursor);
}
void IDBTransactionBackendImpl::didCompleteTaskEvents()
{
if (m_state == Finished)
......@@ -166,6 +179,7 @@ void IDBTransactionBackendImpl::commit()
ASSERT(m_state == Running);
m_state = Finished;
closeOpenCursors();
m_transaction->commit();
m_callbacks->onComplete();
m_database->transactionCoordinator()->didFinishTransaction(this);
......@@ -210,6 +224,13 @@ void IDBTransactionBackendImpl::taskEventTimerFired(Timer<IDBTransactionBackendI
m_taskTimer.startOneShot(0);
}
void IDBTransactionBackendImpl::closeOpenCursors()
{
for (HashSet<IDBCursorBackendImpl*>::iterator i = m_openCursors.begin(); i != m_openCursors.end(); ++i)
(*i)->close();
m_openCursors.clear();
}
};
#endif // ENABLE(INDEXED_DATABASE)
......@@ -34,6 +34,7 @@
#include "IDBTransactionCallbacks.h"
#include "Timer.h"
#include <wtf/Deque.h>
#include <wtf/HashSet.h>
#include <wtf/RefPtr.h>
namespace WebCore {
......@@ -51,6 +52,8 @@ public:
virtual void didCompleteTaskEvents();
virtual void abort();
virtual void setCallbacks(IDBTransactionCallbacks* callbacks) { m_callbacks = callbacks; }
virtual void registerOpenCursor(IDBCursorBackendImpl*);
virtual void unregisterOpenCursor(IDBCursorBackendImpl*);
void run();
......@@ -69,6 +72,7 @@ private:
void taskTimerFired(Timer<IDBTransactionBackendImpl>*);
void taskEventTimerFired(Timer<IDBTransactionBackendImpl>*);
void closeOpenCursors();
RefPtr<DOMStringList> m_objectStoreNames;
unsigned short m_mode;
......@@ -87,6 +91,8 @@ private:
Timer<IDBTransactionBackendImpl> m_taskTimer;
Timer<IDBTransactionBackendImpl> m_taskEventTimer;
int m_pendingEvents;
HashSet<IDBCursorBackendImpl*> m_openCursors;
};
} // namespace WebCore
......
......@@ -36,6 +36,7 @@
namespace WebCore {
class IDBCursorBackendImpl;
class IDBObjectStoreBackendInterface;
class IDBTransactionCallbacks;
......@@ -53,6 +54,8 @@ public:
virtual void didCompleteTaskEvents() = 0;
virtual void abort() = 0;
virtual void setCallbacks(IDBTransactionCallbacks*) = 0;
virtual void registerOpenCursor(IDBCursorBackendImpl*) = 0;
virtual void unregisterOpenCursor(IDBCursorBackendImpl*) = 0;
};
} // namespace WebCore
......
2011-05-05 Hans Wennborg <hans@chromium.org>
Reviewed by Steve Block.
IndexedDB: Transaction rollback prevented by open SQLite statement
https://bugs.webkit.org/show_bug.cgi?id=60032
Implement two new methods in IDBTransactionBackendInterface.
* src/IDBTransactionBackendProxy.cpp:
(WebKit::IDBTransactionBackendProxy::registerOpenCursor):
(WebKit::IDBTransactionBackendProxy::unregisterOpenCursor):
* src/IDBTransactionBackendProxy.h:
2011-05-13 Patrick Gansterer <paroga@webkit.org>
Reviewed by Adam Barth.
......
......@@ -72,6 +72,16 @@ void IDBTransactionBackendProxy::abort()
m_webIDBTransaction->abort();
}
void IDBTransactionBackendProxy::registerOpenCursor(WebCore::IDBCursorBackendImpl*)
{
ASSERT_NOT_REACHED();
}
void IDBTransactionBackendProxy::unregisterOpenCursor(WebCore::IDBCursorBackendImpl*)
{
ASSERT_NOT_REACHED();
}
bool IDBTransactionBackendProxy::scheduleTask(PassOwnPtr<ScriptExecutionContext::Task>, PassOwnPtr<ScriptExecutionContext::Task>)
{
// This should never be reached as it's the impl objects who get to
......
......@@ -47,6 +47,8 @@ public:
virtual bool scheduleTask(PassOwnPtr<WebCore::ScriptExecutionContext::Task>, PassOwnPtr<WebCore::ScriptExecutionContext::Task>);
virtual void didCompleteTaskEvents();
virtual void setCallbacks(WebCore::IDBTransactionCallbacks*);
virtual void registerOpenCursor(WebCore::IDBCursorBackendImpl*);
virtual void unregisterOpenCursor(WebCore::IDBCursorBackendImpl*);
WebIDBTransaction* getWebIDBTransaction() const { return m_webIDBTransaction.get(); }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment