Title: [108015] trunk/Source
Revision
108015
Author
micha...@google.com
Date
2012-02-16 19:18:48 -0800 (Thu, 16 Feb 2012)

Log Message

Source/WebCore: [chromium] Fix bugs in the implementation of WebDatabase::closeDatabaseImmediately.
https://bugs.webkit.org/show_bug.cgi?id=78841

WebDatabase now delegates this function entirely to DatabaseTracker,
a new closeDatabasesImmediately() has been added for that purpose. That
method posts tasks to the appropiate context thread for each database
instance that should be closed immediately.

The DatabaseTracker getAllOpenDatabases() method has been removed from
the chromium impl because it's unsafe, refs cannot be safely taken on
AbstractDatabase instances in the tracker's collection of open databases.

Add a message to the console log when a database is forcibly closed.

Transactions initiated on a database instance that has been forcibly
closed complete with a transaction error callback.
        
This is part of resolving http://crbug.com/98939

Reviewed by David Levin.

No new layout tests, there is no common code way to closeImmediately.
We have coverage for this in py automation tests.

* platform/sql/SQLiteDatabase.cpp:
The closeImmediately code path can result in the underlying sqlite3 handle being
closed earlier than usual and trip some assertions. Updated the assertions to no
longer trigger in this early close case.
(WebCore::SQLiteDatabase::close):
(WebCore::SQLiteDatabase::setMaximumSize):
* platform/sql/SQLiteDatabase.h:
(WebCore::SQLiteDatabase::sqlite3Handle):

* storage/Database.cpp:
(WebCore::Database::closeImmediately): Modified to only be called on the context thread and to log a console message.
(WebCore::Database::changeVersion): Use the private runTransaction helper method.
(WebCore::Database::transaction): Pass a new param required by the runTransaction helper.
(WebCore::Database::readTransaction): Ditto.
(WebCore::callTransactionErrorCallback): Used to defer invocation of the error callback.
(WebCore::Database::runTransaction): Modified to detect when the database has been closed, and
to invoke the error callback in that case. This also avoids creating a reference cycle between
a newly created transaction and the database that previously existed due to a transction being
added and never removed from the Q while in this state.
* storage/Database.h:
* storage/DatabaseSync.cpp:
(WebCore::DatabaseSync::closeImmediately): Modified to only be called on the context thread and to log a console message.
* storage/DatabaseTracker.h:

* storage/chromium/DatabaseTrackerChromium.cpp:
Posts tasks to the appropiate context thread for execution without bumping AbstractDatabase refcounts.
(DatabaseTracker::CloseOneDatabaseImmediatelyTask):
(WebCore::DatabaseTracker::CloseOneDatabaseImmediatelyTask::create):
(WebCore::DatabaseTracker::CloseOneDatabaseImmediatelyTask::performTask):
(WebCore::DatabaseTracker::CloseOneDatabaseImmediatelyTask::CloseOneDatabaseImmediatelyTask):
(WebCore::DatabaseTracker::closeDatabasesImmediately): 
(WebCore::DatabaseTracker::closeOneDatabaseImmediately):

Source/WebKit/chromium: Fix bugs in the implementation of WebDatabase::closeDatabaseImmediately.
https://bugs.webkit.org/show_bug.cgi?id=78841

WebDatabase now delegates this function entirely to DatabaseTracker.
This is part of resolving http://crbug.com/98939

Reviewed by David Levin.

* src/WebDatabase.cpp:
(WebKit::WebDatabase::closeDatabaseImmediately):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (108014 => 108015)


--- trunk/Source/WebCore/ChangeLog	2012-02-17 02:41:11 UTC (rev 108014)
+++ trunk/Source/WebCore/ChangeLog	2012-02-17 03:18:48 UTC (rev 108015)
@@ -1,3 +1,62 @@
+2012-02-15  Michael Nordman  <micha...@google.com>
+
+        [chromium] Fix bugs in the implementation of WebDatabase::closeDatabaseImmediately.
+        https://bugs.webkit.org/show_bug.cgi?id=78841
+
+        WebDatabase now delegates this function entirely to DatabaseTracker,
+        a new closeDatabasesImmediately() has been added for that purpose. That
+        method posts tasks to the appropiate context thread for each database
+        instance that should be closed immediately.
+
+        The DatabaseTracker getAllOpenDatabases() method has been removed from
+        the chromium impl because it's unsafe, refs cannot be safely taken on
+        AbstractDatabase instances in the tracker's collection of open databases.
+
+        Add a message to the console log when a database is forcibly closed.
+
+        Transactions initiated on a database instance that has been forcibly
+        closed complete with a transaction error callback.
+        
+        This is part of resolving http://crbug.com/98939
+
+        Reviewed by David Levin.
+
+        No new layout tests, there is no common code way to closeImmediately.
+        We have coverage for this in py automation tests.
+
+        * platform/sql/SQLiteDatabase.cpp:
+        The closeImmediately code path can result in the underlying sqlite3 handle being
+        closed earlier than usual and trip some assertions. Updated the assertions to no
+        longer trigger in this early close case.
+        (WebCore::SQLiteDatabase::close):
+        (WebCore::SQLiteDatabase::setMaximumSize):
+        * platform/sql/SQLiteDatabase.h:
+        (WebCore::SQLiteDatabase::sqlite3Handle):
+
+        * storage/Database.cpp:
+        (WebCore::Database::closeImmediately): Modified to only be called on the context thread and to log a console message.
+        (WebCore::Database::changeVersion): Use the private runTransaction helper method.
+        (WebCore::Database::transaction): Pass a new param required by the runTransaction helper.
+        (WebCore::Database::readTransaction): Ditto.
+        (WebCore::callTransactionErrorCallback): Used to defer invocation of the error callback.
+        (WebCore::Database::runTransaction): Modified to detect when the database has been closed, and
+        to invoke the error callback in that case. This also avoids creating a reference cycle between
+        a newly created transaction and the database that previously existed due to a transction being
+        added and never removed from the Q while in this state.
+        * storage/Database.h:
+        * storage/DatabaseSync.cpp:
+        (WebCore::DatabaseSync::closeImmediately): Modified to only be called on the context thread and to log a console message.
+        * storage/DatabaseTracker.h:
+
+        * storage/chromium/DatabaseTrackerChromium.cpp:
+        Posts tasks to the appropiate context thread for execution without bumping AbstractDatabase refcounts.
+        (DatabaseTracker::CloseOneDatabaseImmediatelyTask):
+        (WebCore::DatabaseTracker::CloseOneDatabaseImmediatelyTask::create):
+        (WebCore::DatabaseTracker::CloseOneDatabaseImmediatelyTask::performTask):
+        (WebCore::DatabaseTracker::CloseOneDatabaseImmediatelyTask::CloseOneDatabaseImmediatelyTask):
+        (WebCore::DatabaseTracker::closeDatabasesImmediately): 
+        (WebCore::DatabaseTracker::closeOneDatabaseImmediately):
+
 2012-02-16  Dana Jansens  <dan...@chromium.org>
 
         [Chromium] Occlusion tracking with CSS filters

Modified: trunk/Source/WebCore/platform/sql/SQLiteDatabase.cpp (108014 => 108015)


--- trunk/Source/WebCore/platform/sql/SQLiteDatabase.cpp	2012-02-17 02:41:11 UTC (rev 108014)
+++ trunk/Source/WebCore/platform/sql/SQLiteDatabase.cpp	2012-02-17 03:18:48 UTC (rev 108015)
@@ -102,7 +102,7 @@
 void SQLiteDatabase::close()
 {
     if (m_db) {
-        // FIXME: This is being called on themain thread during JS GC. <rdar://problem/5739818>
+        // FIXME: This is being called on the main thread during JS GC. <rdar://problem/5739818>
         // ASSERT(currentThread() == m_openingThread);
         sqlite3* db = m_db;
         {
@@ -167,7 +167,7 @@
     
     int currentPageSize = pageSize();
 
-    ASSERT(currentPageSize);
+    ASSERT(currentPageSize || !m_db);
     int64_t newMaxPageCount = currentPageSize ? size / currentPageSize : 0;
     
     MutexLocker locker(m_authorizerLock);

Modified: trunk/Source/WebCore/platform/sql/SQLiteDatabase.h (108014 => 108015)


--- trunk/Source/WebCore/platform/sql/SQLiteDatabase.h	2012-02-17 02:41:11 UTC (rev 108014)
+++ trunk/Source/WebCore/platform/sql/SQLiteDatabase.h	2012-02-17 03:18:48 UTC (rev 108015)
@@ -104,7 +104,7 @@
     const char* lastErrorMsg();
     
     sqlite3* sqlite3Handle() const {
-        ASSERT(m_sharable || currentThread() == m_openingThread);
+        ASSERT(m_sharable || currentThread() == m_openingThread || !m_db);
         return m_db;
     }
     

Modified: trunk/Source/WebCore/storage/Database.cpp (108014 => 108015)


--- trunk/Source/WebCore/storage/Database.cpp	2012-02-17 02:41:11 UTC (rev 108014)
+++ trunk/Source/WebCore/storage/Database.cpp	2012-02-17 03:18:48 UTC (rev 108015)
@@ -32,6 +32,7 @@
 #if ENABLE(SQL_DATABASE)
 
 #include "ChangeVersionWrapper.h"
+#include "CrossThreadTask.h"
 #include "DatabaseCallback.h"
 #include "DatabaseTask.h"
 #include "DatabaseThread.h"
@@ -41,6 +42,7 @@
 #include "Logging.h"
 #include "NotImplemented.h"
 #include "Page.h"
+#include "SQLError.h"
 #include "SQLTransactionCallback.h"
 #include "SQLTransactionClient.h"
 #include "SQLTransactionCoordinator.h"
@@ -230,9 +232,12 @@
 
 void Database::closeImmediately()
 {
+    ASSERT(m_scriptExecutionContext->isContextThread());
     DatabaseThread* databaseThread = scriptExecutionContext()->databaseThread();
-    if (databaseThread && !databaseThread->terminationRequested() && opened())
+    if (databaseThread && !databaseThread->terminationRequested() && opened()) {
+        logErrorMessage("forcibly closing database");
         databaseThread->scheduleImmediateTask(DatabaseCloseTask::create(this, 0));
+    }
 }
 
 unsigned long long Database::maximumSize() const
@@ -256,30 +261,36 @@
                              PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback,
                              PassRefPtr<VoidCallback> successCallback)
 {
-    RefPtr<SQLTransaction> transaction =
-        SQLTransaction::create(this, callback, errorCallback, successCallback, ChangeVersionWrapper::create(oldVersion, newVersion));
-    MutexLocker locker(m_transactionInProgressMutex);
-    m_transactionQueue.append(transaction.release());
-    if (!m_transactionInProgress)
-        scheduleTransaction();
+    runTransaction(callback, errorCallback, successCallback, ChangeVersionWrapper::create(oldVersion, newVersion), false);
 }
 
 void Database::transaction(PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback, PassRefPtr<VoidCallback> successCallback)
 {
-    runTransaction(callback, errorCallback, successCallback, false);
+    runTransaction(callback, errorCallback, successCallback, 0, false);
 }
 
 void Database::readTransaction(PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback, PassRefPtr<VoidCallback> successCallback)
 {
-    runTransaction(callback, errorCallback, successCallback, true);
+    runTransaction(callback, errorCallback, successCallback, 0, true);
 }
 
+static void callTransactionErrorCallback(ScriptExecutionContext*, PassRefPtr<SQLTransactionErrorCallback> callback, PassRefPtr<SQLError> error)
+{
+    callback->handleEvent(error.get());
+}
+
 void Database::runTransaction(PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback,
-                              PassRefPtr<VoidCallback> successCallback, bool readOnly)
+                              PassRefPtr<VoidCallback> successCallback, PassRefPtr<SQLTransactionWrapper> wrapper, bool readOnly)
 {
-    RefPtr<SQLTransaction> transaction =
-        SQLTransaction::create(this, callback, errorCallback, successCallback, 0, readOnly);
     MutexLocker locker(m_transactionInProgressMutex);
+    if (!m_isTransactionQueueEnabled) {
+        if (errorCallback) {
+            RefPtr<SQLError> error = SQLError::create(SQLError::UNKNOWN_ERR, "database has been closed");
+            scriptExecutionContext()->postTask(createCallbackTask(&callTransactionErrorCallback, errorCallback, error.release()));
+        }
+        return;
+    }
+    RefPtr<SQLTransaction> transaction = SQLTransaction::create(this, callback, errorCallback, successCallback, wrapper, readOnly);
     m_transactionQueue.append(transaction.release());
     if (!m_transactionInProgress)
         scheduleTransaction();
@@ -297,9 +308,8 @@
     ASSERT(!m_transactionInProgressMutex.tryLock()); // Locked by caller.
     RefPtr<SQLTransaction> transaction;
 
-    if (m_isTransactionQueueEnabled && !m_transactionQueue.isEmpty()) {
+    if (m_isTransactionQueueEnabled && !m_transactionQueue.isEmpty())
         transaction = m_transactionQueue.takeFirst();
-    }
 
     if (transaction && m_scriptExecutionContext->databaseThread()) {
         OwnPtr<DatabaseTransactionTask> task = DatabaseTransactionTask::create(transaction);

Modified: trunk/Source/WebCore/storage/Database.h (108014 => 108015)


--- trunk/Source/WebCore/storage/Database.h	2012-02-17 02:41:11 UTC (rev 108014)
+++ trunk/Source/WebCore/storage/Database.h	2012-02-17 03:18:48 UTC (rev 108015)
@@ -47,6 +47,7 @@
 class SQLTransactionClient;
 class SQLTransactionCoordinator;
 class SQLTransactionErrorCallback;
+class SQLTransactionWrapper;
 class VoidCallback;
 
 typedef int ExceptionCode;
@@ -93,7 +94,7 @@
     Database(ScriptExecutionContext*, const String& name, const String& expectedVersion,
              const String& displayName, unsigned long estimatedSize);
     void runTransaction(PassRefPtr<SQLTransactionCallback>, PassRefPtr<SQLTransactionErrorCallback>,
-                        PassRefPtr<VoidCallback> successCallback, bool readOnly);
+                        PassRefPtr<VoidCallback> successCallback, PassRefPtr<SQLTransactionWrapper>, bool readOnly);
 
     bool openAndVerifyVersion(bool setVersionInNewDatabase, ExceptionCode&, String& errorMessage);
     virtual bool performOpenAndVerify(bool setVersionInNewDatabase, ExceptionCode&, String& errorMessage);

Modified: trunk/Source/WebCore/storage/DatabaseSync.cpp (108014 => 108015)


--- trunk/Source/WebCore/storage/DatabaseSync.cpp	2012-02-17 02:41:11 UTC (rev 108014)
+++ trunk/Source/WebCore/storage/DatabaseSync.cpp	2012-02-17 03:18:48 UTC (rev 108015)
@@ -205,16 +205,13 @@
 
 void DatabaseSync::closeImmediately()
 {
-    if (!m_scriptExecutionContext->isContextThread()) {
-        m_scriptExecutionContext->postTask(CloseSyncDatabaseOnContextThreadTask::create(this));
-        return;
-    }
+    ASSERT(m_scriptExecutionContext->isContextThread());
 
     if (!opened())
         return;
 
+    logErrorMessage("forcibly closing database");
     DatabaseTracker::tracker().removeOpenDatabase(this);
-
     closeDatabase();
 }
 

Modified: trunk/Source/WebCore/storage/DatabaseTracker.h (108014 => 108015)


--- trunk/Source/WebCore/storage/DatabaseTracker.h	2012-02-17 02:41:11 UTC (rev 108014)
+++ trunk/Source/WebCore/storage/DatabaseTracker.h	2012-02-17 03:18:48 UTC (rev 108015)
@@ -173,13 +173,16 @@
     static void notifyDatabasesChanged(void*);
 #else
 public:
-    void getOpenDatabases(const String& originIdentifier, const String& name, HashSet<RefPtr<AbstractDatabase> >* databases);
+    void closeDatabasesImmediately(const String& originIdentifier, const String& name);
 
 private:
     typedef HashSet<AbstractDatabase*> DatabaseSet;
     typedef HashMap<String, DatabaseSet*> DatabaseNameMap;
     typedef HashMap<String, DatabaseNameMap*> DatabaseOriginMap;
+    class CloseOneDatabaseImmediatelyTask;
 
+    void closeOneDatabaseImmediately(const String& originIdentifier, const String& name, AbstractDatabase* database);
+
     Mutex m_openDatabaseMapGuard;
     mutable OwnPtr<DatabaseOriginMap> m_openDatabaseMap;
 #endif // !PLATFORM(CHROMIUM)

Modified: trunk/Source/WebCore/storage/chromium/DatabaseTrackerChromium.cpp (108014 => 108015)


--- trunk/Source/WebCore/storage/chromium/DatabaseTrackerChromium.cpp	2012-02-17 02:41:11 UTC (rev 108014)
+++ trunk/Source/WebCore/storage/chromium/DatabaseTrackerChromium.cpp	2012-02-17 03:18:48 UTC (rev 108015)
@@ -157,29 +157,6 @@
         DatabaseObserver::databaseClosed(database);
 }
 
-void DatabaseTracker::getOpenDatabases(SecurityOrigin* origin, const String& name, HashSet<RefPtr<AbstractDatabase> >* databases)
-{
-    getOpenDatabases(origin->databaseIdentifier(), name, databases);
-}
-
-void DatabaseTracker::getOpenDatabases(const String& originIdentifier, const String& name, HashSet<RefPtr<AbstractDatabase> >* databases)
-{
-    MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
-    if (!m_openDatabaseMap)
-        return;
-
-    DatabaseNameMap* nameMap = m_openDatabaseMap->get(originIdentifier);
-    if (!nameMap)
-        return;
-
-    DatabaseSet* databaseSet = nameMap->get(name);
-    if (!databaseSet)
-        return;
-
-    for (DatabaseSet::iterator it = databaseSet->begin(); it != databaseSet->end(); ++it)
-        databases->add(*it);
-}
-
 unsigned long long DatabaseTracker::getMaxSizeForDatabase(const AbstractDatabase* database)
 {
     unsigned long long spaceAvailable = 0;
@@ -212,6 +189,76 @@
     }
 }
 
+class DatabaseTracker::CloseOneDatabaseImmediatelyTask : public ScriptExecutionContext::Task {
+public:
+    static PassOwnPtr<CloseOneDatabaseImmediatelyTask> create(const String& originIdentifier, const String& name, AbstractDatabase* database)
+    {
+        return adoptPtr(new CloseOneDatabaseImmediatelyTask(originIdentifier, name, database));
+    }
+
+    virtual void performTask(ScriptExecutionContext* context)
+    {
+        DatabaseTracker::tracker().closeOneDatabaseImmediately(m_originIdentifier, m_name, m_database);
+    }
+
+private:
+    CloseOneDatabaseImmediatelyTask(const String& originIdentifier, const String& name, AbstractDatabase* database)
+        : m_originIdentifier(originIdentifier.isolatedCopy())
+        , m_name(name.isolatedCopy())
+        , m_database(database)
+    {
+    }
+
+    String m_originIdentifier;
+    String m_name;
+    AbstractDatabase* m_database;  // Intentionally a raw pointer.
+};
+
+void DatabaseTracker::closeDatabasesImmediately(const String& originIdentifier, const String& name) {
+    MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
+    if (!m_openDatabaseMap)
+        return;
+
+    DatabaseNameMap* nameMap = m_openDatabaseMap->get(originIdentifier);
+    if (!nameMap)
+        return;
+
+    DatabaseSet* databaseSet = nameMap->get(name);
+    if (!databaseSet)
+        return;
+
+    // We have to call closeImmediately() on the context thread and we cannot safely add a reference to
+    // the database in our collection when not on the context thread (which is always the case given
+    // current usage).
+    for (DatabaseSet::iterator it = databaseSet->begin(); it != databaseSet->end(); ++it)
+        (*it)->scriptExecutionContext()->postTask(CloseOneDatabaseImmediatelyTask::create(originIdentifier, name, *it));
 }
 
+void DatabaseTracker::closeOneDatabaseImmediately(const String& originIdentifier, const String& name, AbstractDatabase* database)
+{
+    // First we have to confirm the 'database' is still in our collection.
+    {
+        MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
+        if (!m_openDatabaseMap)
+            return;
+
+        DatabaseNameMap* nameMap = m_openDatabaseMap->get(originIdentifier);
+        if (!nameMap)
+            return;
+
+        DatabaseSet* databaseSet = nameMap->get(name);
+        if (!databaseSet)
+            return;
+
+        DatabaseSet::iterator found = databaseSet->find(database);
+        if (found == databaseSet->end())
+            return;
+    }
+
+    // And we have to call closeImmediately() without our collection lock being held.
+    database->closeImmediately();
+}
+
+}
+
 #endif // ENABLE(SQL_DATABASE)

Modified: trunk/Source/WebKit/chromium/ChangeLog (108014 => 108015)


--- trunk/Source/WebKit/chromium/ChangeLog	2012-02-17 02:41:11 UTC (rev 108014)
+++ trunk/Source/WebKit/chromium/ChangeLog	2012-02-17 03:18:48 UTC (rev 108015)
@@ -1,3 +1,16 @@
+2012-02-15  Michael Nordman  <micha...@google.com>
+
+        Fix bugs in the implementation of WebDatabase::closeDatabaseImmediately.
+        https://bugs.webkit.org/show_bug.cgi?id=78841
+
+        WebDatabase now delegates this function entirely to DatabaseTracker.
+        This is part of resolving http://crbug.com/98939
+
+        Reviewed by David Levin.
+
+        * src/WebDatabase.cpp:
+        (WebKit::WebDatabase::closeDatabaseImmediately):
+
 2012-02-16  Dana Jansens  <dan...@chromium.org>
 
         [Chromium] Occlusion tracking with CSS filters

Modified: trunk/Source/WebKit/chromium/src/WebDatabase.cpp (108014 => 108015)


--- trunk/Source/WebKit/chromium/src/WebDatabase.cpp	2012-02-17 02:41:11 UTC (rev 108014)
+++ trunk/Source/WebKit/chromium/src/WebDatabase.cpp	2012-02-17 03:18:48 UTC (rev 108015)
@@ -122,10 +122,7 @@
 void WebDatabase::closeDatabaseImmediately(const WebString& originIdentifier, const WebString& databaseName)
 {
 #if ENABLE(SQL_DATABASE)
-    HashSet<RefPtr<AbstractDatabase> > databaseHandles;
-    DatabaseTracker::tracker().getOpenDatabases(originIdentifier, databaseName, &databaseHandles);
-    for (HashSet<RefPtr<AbstractDatabase> >::iterator it = databaseHandles.begin(); it != databaseHandles.end(); ++it)
-        it->get()->closeImmediately();
+    DatabaseTracker::tracker().closeDatabasesImmediately(originIdentifier, databaseName);
 #endif
 }
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to