- Revision
- 129038
- Author
- [email protected]
- Date
- 2012-09-19 13:35:19 -0700 (Wed, 19 Sep 2012)
Log Message
IndexedDB: Free up resources used by completed cursors earlier
https://bugs.webkit.org/show_bug.cgi?id=97023
Reviewed by Tony Chang.
Source/WebCore:
Prior to this patch, IDBCursor objects are kept around by their parent
IDBTransaction until the transaction finishes. It's possible to release
references to them earlier, when the cursor has been "run to the end",
as no further events will fire and all calls to continue() etc should fail.
This change tells the cursor it's done when "null" finally comes through in
the IDBRequest, and the cursor then lets transaction know it can be
forgotten.
The added test doesn't distinguish the new behavior, but does exercise
"finished" cursors and apparently we didn't have tests for these before.
Test: storage/indexeddb/cursor-finished.html
* Modules/indexeddb/IDBCursor.cpp:
(WebCore::IDBCursor::close): Make idempotent; notify transaction.
* Modules/indexeddb/IDBRequest.cpp:
(WebCore::IDBRequest::onSuccess): Tell cursor it's finished before releasing.
* Modules/indexeddb/IDBTransaction.cpp:
(WebCore::IDBTransaction::OpenCursorNotifier::~OpenCursorNotifier):
(WebCore):
(WebCore::IDBTransaction::OpenCursorNotifier::cursorFinished): New method for explicit notification.
* Modules/indexeddb/IDBTransaction.h:
(OpenCursorNotifier):
LayoutTests:
Test to exercise cursor methods after the cursor has been run to the end.
* storage/indexeddb/cursor-finished-expected.txt: Added.
* storage/indexeddb/cursor-finished.html: Added.
* storage/indexeddb/resources/cursor-finished.js: Added.
(test):
(prepareDatabase):
(onDeleteSuccess):
(onUpgradeNeeded):
(onOpenSuccess):
(onCursorSuccess):
Modified Paths
Added Paths
Diff
Modified: trunk/LayoutTests/ChangeLog (129037 => 129038)
--- trunk/LayoutTests/ChangeLog 2012-09-19 20:28:35 UTC (rev 129037)
+++ trunk/LayoutTests/ChangeLog 2012-09-19 20:35:19 UTC (rev 129038)
@@ -1,3 +1,22 @@
+2012-09-19 Joshua Bell <[email protected]>
+
+ IndexedDB: Free up resources used by completed cursors earlier
+ https://bugs.webkit.org/show_bug.cgi?id=97023
+
+ Reviewed by Tony Chang.
+
+ Test to exercise cursor methods after the cursor has been run to the end.
+
+ * storage/indexeddb/cursor-finished-expected.txt: Added.
+ * storage/indexeddb/cursor-finished.html: Added.
+ * storage/indexeddb/resources/cursor-finished.js: Added.
+ (test):
+ (prepareDatabase):
+ (onDeleteSuccess):
+ (onUpgradeNeeded):
+ (onOpenSuccess):
+ (onCursorSuccess):
+
2012-09-19 David Grogan <[email protected]>
IndexedDB: fire upgradeneeded even without an explicit integer version
Added: trunk/LayoutTests/storage/indexeddb/cursor-finished-expected.txt (0 => 129038)
--- trunk/LayoutTests/storage/indexeddb/cursor-finished-expected.txt (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/cursor-finished-expected.txt 2012-09-19 20:35:19 UTC (rev 129038)
@@ -0,0 +1,72 @@
+Ensure cursor calls behave as expected after cursor has run to the end.
+
+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 = "cursor-finished.html"
+
+prepareDatabase():
+indexedDB.deleteDatabase(dbname)
+
+onDeleteSuccess():
+indexedDB.open(dbname, 1)
+
+onUpgradeNeeded():
+db = event.target.result
+store = db.createObjectStore('store')
+store.put(1, 1)
+store.put(2, 2)
+
+onOpenSuccess():
+db = event.target.result
+transaction = db.transaction('store', 'readwrite')
+store = transaction.objectStore('store')
+count = 0
+cursorRequest = store.openCursor()
+
+onCursorSuccess():
+cursor = event.target.result
+PASS cursor is non-null.
+count++
+savedCursor = cursor
+cursor.continue()
+
+onCursorSuccess():
+cursor = event.target.result
+PASS cursor is non-null.
+count++
+savedCursor = cursor
+cursor.continue()
+
+onCursorSuccess():
+cursor = event.target.result
+PASS cursor is null
+PASS savedCursor is non-null.
+
+Expecting exception from savedCursor.update('value')
+PASS Exception was thrown.
+PASS code is DOMException.INVALID_STATE_ERR
+PASS ename is 'InvalidStateError'
+Expecting exception from savedCursor.advance(1)
+PASS Exception was thrown.
+PASS code is DOMException.INVALID_STATE_ERR
+PASS ename is 'InvalidStateError'
+Expecting exception from savedCursor.continue()
+PASS Exception was thrown.
+PASS code is DOMException.INVALID_STATE_ERR
+PASS ename is 'InvalidStateError'
+Expecting exception from savedCursor.continue('key')
+PASS Exception was thrown.
+PASS code is DOMException.INVALID_STATE_ERR
+PASS ename is 'InvalidStateError'
+Expecting exception from savedCursor.delete()
+PASS Exception was thrown.
+PASS code is DOMException.INVALID_STATE_ERR
+PASS ename is 'InvalidStateError'
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/storage/indexeddb/cursor-finished.html (0 => 129038)
--- trunk/LayoutTests/storage/indexeddb/cursor-finished.html (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/cursor-finished.html 2012-09-19 20:35:19 UTC (rev 129038)
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<script src=""
+</head>
+<body>
+<script src=""
+<script src=""
+</body>
+</html>
+
+
Added: trunk/LayoutTests/storage/indexeddb/resources/cursor-finished.js (0 => 129038)
--- trunk/LayoutTests/storage/indexeddb/resources/cursor-finished.js (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/resources/cursor-finished.js 2012-09-19 20:35:19 UTC (rev 129038)
@@ -0,0 +1,76 @@
+description("Ensure cursor calls behave as expected after cursor has run to the end.");
+setTimeout(finishJSTest,1000);
+
+function test()
+{
+ removeVendorPrefixes();
+ setDBNameFromPath();
+ prepareDatabase();
+}
+
+function prepareDatabase()
+{
+ preamble();
+ request = evalAndLog("indexedDB.deleteDatabase(dbname)");
+ request._onerror_ = unexpectedErrorCallback;
+ request._onblocked_ = unexpectedBlockedCallback;
+ request._onsuccess_ = onDeleteSuccess;
+}
+
+function onDeleteSuccess(evt)
+{
+ preamble(evt);
+ request = evalAndLog("indexedDB.open(dbname, 1)");
+ request._onerror_ = unexpectedErrorCallback;
+ request._onblocked_ = unexpectedBlockedCallback;
+ request._onupgradeneeded_ = onUpgradeNeeded;
+ request._onsuccess_ = onOpenSuccess;
+}
+
+function onUpgradeNeeded(evt)
+{
+ preamble(evt);
+ evalAndLog("db = event.target.result");
+ evalAndLog("store = db.createObjectStore('store')");
+ evalAndLog("store.put(1, 1)");
+ evalAndLog("store.put(2, 2)");
+}
+
+function onOpenSuccess(evt)
+{
+ preamble(evt);
+ evalAndLog("db = event.target.result");
+ evalAndLog("transaction = db.transaction('store', 'readwrite')");
+ evalAndLog("store = transaction.objectStore('store')");
+ evalAndLog("count = 0");
+ evalAndLog("cursorRequest = store.openCursor()");
+ cursorRequest._onerror_ = unexpectedErrorCallback;
+ cursorRequest._onsuccess_ = onCursorSuccess;
+}
+
+function onCursorSuccess(evt)
+{
+ preamble(evt);
+ evalAndLog("cursor = event.target.result");
+ if (count < 2) {
+ shouldBeNonNull("cursor");
+ evalAndLog("count++");
+ evalAndLog("savedCursor = cursor");
+ evalAndLog("cursor.continue()");
+ } else {
+ shouldBeNull("cursor");
+ shouldBeNonNull("savedCursor");
+
+ debug("");
+ evalAndExpectException("savedCursor.update('value')", "DOMException.INVALID_STATE_ERR", "'InvalidStateError'");
+ evalAndExpectException("savedCursor.advance(1)", "DOMException.INVALID_STATE_ERR", "'InvalidStateError'");
+ evalAndExpectException("savedCursor.continue()", "DOMException.INVALID_STATE_ERR", "'InvalidStateError'");
+ evalAndExpectException("savedCursor.continue('key')", "DOMException.INVALID_STATE_ERR", "'InvalidStateError'");
+ evalAndExpectException("savedCursor.delete()", "DOMException.INVALID_STATE_ERR", "'InvalidStateError'");
+
+ debug("");
+ finishJSTest();
+ }
+}
+
+test();
Modified: trunk/Source/WebCore/ChangeLog (129037 => 129038)
--- trunk/Source/WebCore/ChangeLog 2012-09-19 20:28:35 UTC (rev 129037)
+++ trunk/Source/WebCore/ChangeLog 2012-09-19 20:35:19 UTC (rev 129038)
@@ -1,3 +1,35 @@
+2012-09-19 Joshua Bell <[email protected]>
+
+ IndexedDB: Free up resources used by completed cursors earlier
+ https://bugs.webkit.org/show_bug.cgi?id=97023
+
+ Reviewed by Tony Chang.
+
+ Prior to this patch, IDBCursor objects are kept around by their parent
+ IDBTransaction until the transaction finishes. It's possible to release
+ references to them earlier, when the cursor has been "run to the end",
+ as no further events will fire and all calls to continue() etc should fail.
+
+ This change tells the cursor it's done when "null" finally comes through in
+ the IDBRequest, and the cursor then lets transaction know it can be
+ forgotten.
+
+ The added test doesn't distinguish the new behavior, but does exercise
+ "finished" cursors and apparently we didn't have tests for these before.
+
+ Test: storage/indexeddb/cursor-finished.html
+
+ * Modules/indexeddb/IDBCursor.cpp:
+ (WebCore::IDBCursor::close): Make idempotent; notify transaction.
+ * Modules/indexeddb/IDBRequest.cpp:
+ (WebCore::IDBRequest::onSuccess): Tell cursor it's finished before releasing.
+ * Modules/indexeddb/IDBTransaction.cpp:
+ (WebCore::IDBTransaction::OpenCursorNotifier::~OpenCursorNotifier):
+ (WebCore):
+ (WebCore::IDBTransaction::OpenCursorNotifier::cursorFinished): New method for explicit notification.
+ * Modules/indexeddb/IDBTransaction.h:
+ (OpenCursorNotifier):
+
2012-09-19 David Grogan <[email protected]>
IndexedDB: fire upgradeneeded even without an explicit integer version
Modified: trunk/Source/WebCore/Modules/indexeddb/IDBCursor.cpp (129037 => 129038)
--- trunk/Source/WebCore/Modules/indexeddb/IDBCursor.cpp 2012-09-19 20:28:35 UTC (rev 129037)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBCursor.cpp 2012-09-19 20:35:19 UTC (rev 129038)
@@ -254,9 +254,11 @@
void IDBCursor::close()
{
- ASSERT(m_request);
- m_request->finishCursor();
- m_request.clear();
+ m_transactionNotifier.cursorFinished();
+ if (m_request) {
+ m_request->finishCursor();
+ m_request.clear();
+ }
}
void IDBCursor::setValueReady(PassRefPtr<IDBKey> key, PassRefPtr<IDBKey> primaryKey, ScriptValue& value)
Modified: trunk/Source/WebCore/Modules/indexeddb/IDBRequest.cpp (129037 => 129038)
--- trunk/Source/WebCore/Modules/indexeddb/IDBRequest.cpp 2012-09-19 20:28:35 UTC (rev 129037)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBRequest.cpp 2012-09-19 20:35:19 UTC (rev 129038)
@@ -379,7 +379,10 @@
void IDBRequest::onSuccessInternal(const ScriptValue& value)
{
m_result = IDBAny::create(value);
- m_pendingCursor.clear();
+ if (m_pendingCursor) {
+ m_pendingCursor->close();
+ m_pendingCursor.clear();
+ }
enqueueEvent(createSuccessEvent());
}
Modified: trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.cpp (129037 => 129038)
--- trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.cpp 2012-09-19 20:28:35 UTC (rev 129037)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.cpp 2012-09-19 20:35:19 UTC (rev 129038)
@@ -232,9 +232,19 @@
IDBTransaction::OpenCursorNotifier::~OpenCursorNotifier()
{
- m_transaction->unregisterOpenCursor(m_cursor);
+ if (m_cursor)
+ m_transaction->unregisterOpenCursor(m_cursor);
}
+void IDBTransaction::OpenCursorNotifier::cursorFinished()
+{
+ if (m_cursor) {
+ m_transaction->unregisterOpenCursor(m_cursor);
+ m_cursor = 0;
+ m_transaction.clear();
+ }
+}
+
void IDBTransaction::registerOpenCursor(IDBCursor* cursor)
{
m_openCursors.add(cursor);
Modified: trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.h (129037 => 129038)
--- trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.h 2012-09-19 20:28:35 UTC (rev 129037)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.h 2012-09-19 20:35:19 UTC (rev 129038)
@@ -86,6 +86,7 @@
public:
OpenCursorNotifier(PassRefPtr<IDBTransaction>, IDBCursor*);
~OpenCursorNotifier();
+ void cursorFinished();
private:
RefPtr<IDBTransaction> m_transaction;
IDBCursor* m_cursor;