<rdar://problem/
5740042> Database termination issues
Test: storage/close-during-stress-test.html
* dom/Document.cpp:
(WebCore::Document::databaseThread):
* dom/Document.h:
Don't re-create the database thread if it has been already terminated.
* storage/Database.h: (WebCore::Database::document): Changed m_database to a RefPtr to avoid
having a hanging reference.
* storage/DatabaseThread.cpp:
(WebCore::DatabaseThread::requestTermination):
* storage/SQLTransaction.cpp: (WebCore::SQLTransaction::~SQLTransaction): Removed logging.
Transactions are deleted during GC, so it's usually not importatnt to know when it happens.
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@30195
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2008-02-13 Alexey Proskuryakov <ap@webkit.org>
+
+ Reviewed by Darin.
+
+ <rdar://problem/5740042> Database termination issues
+
+ * storage/close-during-stress-test-expected.txt: Added.
+ * storage/close-during-stress-test.html: Added.
+ * storage/resources: Added.
+ * storage/resources/stress-frame.html: Added.
+
2008-02-13 Darin Adler <darin@apple.com>
- check in results for these tests
--- /dev/null
+CONSOLE MESSAGE: line 37: Can't find variable: loadNotes
+Should not crash or cause an assertion failure.
+
+A JavaScript failure on the console is expected, however, as the global object is cleared when closing a frame. It actually helps to cause database activity by throwing an exception from a callback.
+
+
--- /dev/null
+<body>
+<p>Should not crash or cause an assertion failure.</p>
+<p>A JavaScript failure on the console is expected, however, as the global object is cleared when closing a frame.
+It actually helps to cause database activity by throwing an exception from a callback.</p>
+<iframe src="resources/stress-frame.html" onload="startTest()"></iframe>
+<script>
+if (window.layoutTestController) {
+ layoutTestController.waitUntilDone();
+ layoutTestController.dumpAsText();
+}
+
+function startTest() {
+ setTimeout("document.getElementsByTagName('iframe')[0].src = 'about:blank'", 100);
+ if (window.layoutTestController)
+ setTimeout("layoutTestController.notifyDone()", 500);
+}
+</script>
+</body>
--- /dev/null
+<!doctype html>
+<html>
+<head>
+<script>
+var db;
+
+try {
+ if (window.openDatabase) {
+ db = openDatabase("StressTest2", "1.0", "Database stress test", 200000);
+ if (!db)
+ alert("Failed to open the database on disk. This is probably because the version was bad or there is not enough space left in this domain's quota");
+ } else
+ alert("Couldn't open the database. Please try with a WebKit nightly with this feature enabled");
+} catch(err) { }
+
+function loaded()
+{
+ db.transaction(function(tx) {
+ tx.executeSql("SELECT COUNT(*) FROM WebkitStickyNotes", [], function(result) {
+ loadNotes();
+ }, function(tx, error) {
+ tx.executeSql("CREATE TABLE WebKitStickyNotes (id REAL UNIQUE, note TEXT)", [], function(result) {
+ tx.executeSql("INSERT INTO WebKitStickyNotes (id, note) VALUES (?, ?)", [1, 'Text'], function(result) {
+ tx.executeSql("INSERT INTO WebKitStickyNotes (id, note) VALUES (?, ?)", [2, 'More Text'], function(result) {
+ loadNotes();
+ });
+ });
+ });
+ });
+ });
+}
+
+function loadNotes()
+{
+ db.transaction(function(tx) {
+ tx.executeSql("SELECT id, note FROM WebKitStickyNotes", [], function(tx, result) {
+ loadNotes();
+ }, function(tx, error) {
+ alert('Failed to retrieve notes from database - ' + error.message);
+ return;
+ });
+ });
+}
+
+addEventListener('load', loaded, false);
+</script>
+</head>
+<body>
+<p>This test needs to run without crashes and assertion failures for a while.<p>
+</body>
+</html>
+2008-02-13 Alexey Proskuryakov <ap@webkit.org>
+
+ Reviewed by Darin.
+
+ <rdar://problem/5740042> Database termination issues
+
+ Test: storage/close-during-stress-test.html
+
+ * dom/Document.cpp:
+ (WebCore::Document::databaseThread):
+ * dom/Document.h:
+ Don't re-create the database thread if it has been already terminated.
+
+ * storage/Database.h: (WebCore::Database::document): Changed m_database to a RefPtr to avoid
+ having a hanging reference.
+
+ * storage/DatabaseThread.cpp:
+ (WebCore::DatabaseThread::requestTermination):
+
+ * storage/SQLTransaction.cpp: (WebCore::SQLTransaction::~SQLTransaction): Removed logging.
+ Transactions are deleted during GC, so it's usually not importatnt to know when it happens.
+
2008-02-12 Bernhard Rosenkraenzer <bero@arklinux.org>
Reviewed by Darin.
#if ENABLE(DATABASE)
DatabaseThread* Document::databaseThread()
{
- if (!m_databaseThread) {
+ if (!m_databaseThread && !m_hasOpenDatabases) {
+ // Create the database thread on first request - but not if at least one database was already opened,
+ // because in that case we already had a database thread and terminated it and should not create another.
m_databaseThread = new DatabaseThread(this);
if (!m_databaseThread->start())
m_databaseThread = 0;
bool processingLoadEvent() const { return m_processingLoadEvent; }
#if ENABLE(DATABASE)
- DatabaseThread* databaseThread();
+ DatabaseThread* databaseThread(); // Creates the thread as needed, but not if it has been already terminated.
void setHasOpenDatabases() { m_hasOpenDatabases = true; }
bool hasOpenDatabases() { return m_hasOpenDatabases; }
#endif
#if ENABLE(DATABASE)
RefPtr<DatabaseThread> m_databaseThread;
- bool m_hasOpenDatabases;
+ bool m_hasOpenDatabases; // This never changes back to false, even as the database thread is closed.
#endif
#if USE(LOW_BANDWIDTH_DISPLAY)
bool m_inLowBandwidthDisplay;
Vector<String> tableNames();
- Document* document() const { return m_document; }
+ Document* document() const { return m_document.get(); }
PassRefPtr<SecurityOrigin> securityOriginCopy() const;
String stringIdentifier() const;
static void deliverPendingCallback(void*);
- Document* m_document;
+ RefPtr<Document> m_document;
RefPtr<SecurityOrigin> m_securityOrigin;
String m_name;
int m_guid;
void DatabaseThread::requestTermination()
{
- LOG(StorageAPI, "Document owning DatabaseThread %p is going away - starting thread shutdown", this);
+ LOG(StorageAPI, "DatabaseThread %p was asked to terminate\n", this);
m_queue.kill();
}
SQLTransaction::~SQLTransaction()
{
- LOG(StorageAPI, "Transaction %p destructor\n", this);
}
void SQLTransaction::executeSQL(const String& sqlStatement, const Vector<SQLValue>& arguments, PassRefPtr<SQLStatementCallback> callback, PassRefPtr<SQLStatementErrorCallback> callbackError, ExceptionCode& e)