Modern IDB: Add support for server side closing of open database connections.
authorbeidson@apple.com <beidson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 18 May 2016 20:42:20 +0000 (20:42 +0000)
committerbeidson@apple.com <beidson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 18 May 2016 20:42:20 +0000 (20:42 +0000)
https://bugs.webkit.org/show_bug.cgi?id=157843

Reviewed by Alex Christensen.

Source/WebCore:

Test: storage/indexeddb/modern/handle-user-delete.html

In order to support deleting IndexedDB databases, the IDB server needs the ability to
"immediately" close a currently open IDB connection.

To do so cleanly, the server has to:
- Error out all requests it knows about
- Abort all transactions it knows about
- Tell the connection that it is being closed
- Wait for the connection to acknowledge that it was closed on the server

And then the client has to:
- Error out all requests it hasn't sent to the server
- Abort all transactions that haven't already been aborted by the server
- Send acknowledgement to the server that it has been closed.

Finally, because the status of a given request might be "in flight" somewhere between the
server and the client, some design assumptions change. This requires reworking some ASSERTS,
null checks, etc.

* Modules/indexeddb/IDBDatabase.cpp:
(WebCore::IDBDatabase::didCloseFromServer): Do the heavy lifting for the immediate close on
  the client side.
* Modules/indexeddb/IDBDatabase.h:

* Modules/indexeddb/IDBDatabaseIdentifier.h:
(WebCore::IDBDatabaseIdentifier::isRelatedToOrigin):

* Modules/indexeddb/IDBTransaction.cpp:
(WebCore::IDBTransaction::connectionClosedFromServer): Error out all outstanding operations
  and fire the abort error on itself.
* Modules/indexeddb/IDBTransaction.h:

* Modules/indexeddb/client/IDBConnectionProxy.cpp:
(WebCore::IDBClient::IDBConnectionProxy::completeOperation):
(WebCore::IDBClient::IDBConnectionProxy::didCloseFromServer):
(WebCore::IDBClient::IDBConnectionProxy::confirmDidCloseFromServer):
(WebCore::IDBClient::IDBConnectionProxy::forgetActiveOperations):
* Modules/indexeddb/client/IDBConnectionProxy.h:

* Modules/indexeddb/client/IDBConnectionToServer.cpp:
(WebCore::IDBClient::IDBConnectionToServer::didCloseFromServer):
(WebCore::IDBClient::IDBConnectionToServer::confirmDidCloseFromServer):
* Modules/indexeddb/client/IDBConnectionToServer.h:
* Modules/indexeddb/client/IDBConnectionToServerDelegate.h:

* Modules/indexeddb/server/IDBConnectionToClient.cpp:
(WebCore::IDBServer::IDBConnectionToClient::didCloseFromServer):
* Modules/indexeddb/server/IDBConnectionToClient.h:
* Modules/indexeddb/server/IDBConnectionToClientDelegate.h:

* Modules/indexeddb/server/IDBServer.cpp:
(WebCore::IDBServer::IDBServer::confirmDidCloseFromServer):
(WebCore::IDBServer::generateDeleteCallbackID):
(WebCore::IDBServer::IDBServer::closeAndDeleteDatabasesModifiedSince):
(WebCore::IDBServer::IDBServer::closeAndDeleteDatabasesForOrigins):
(WebCore::IDBServer::IDBServer::performCloseAndDeleteDatabasesModifiedSince):
(WebCore::IDBServer::IDBServer::performCloseAndDeleteDatabasesForOrigins):
(WebCore::IDBServer::IDBServer::didPerformCloseAndDeleteDatabases):
* Modules/indexeddb/server/IDBServer.h:

* Modules/indexeddb/server/UniqueIDBDatabase.cpp:
(WebCore::IDBServer::UniqueIDBDatabase::~UniqueIDBDatabase):
(WebCore::IDBServer::UniqueIDBDatabase::openDatabaseConnection):
(WebCore::IDBServer::UniqueIDBDatabase::didDeleteBackingStore):
(WebCore::IDBServer::UniqueIDBDatabase::handleDatabaseOperations):
(WebCore::IDBServer::UniqueIDBDatabase::handleCurrentOperation):
(WebCore::IDBServer::UniqueIDBDatabase::handleDelete):
(WebCore::IDBServer::UniqueIDBDatabase::createObjectStore):
(WebCore::IDBServer::UniqueIDBDatabase::deleteObjectStore):
(WebCore::IDBServer::UniqueIDBDatabase::clearObjectStore):
(WebCore::IDBServer::UniqueIDBDatabase::createIndex):
(WebCore::IDBServer::UniqueIDBDatabase::deleteIndex):
(WebCore::IDBServer::UniqueIDBDatabase::putOrAdd):
(WebCore::IDBServer::UniqueIDBDatabase::getRecord):
(WebCore::IDBServer::UniqueIDBDatabase::getCount):
(WebCore::IDBServer::UniqueIDBDatabase::deleteRecord):
(WebCore::IDBServer::UniqueIDBDatabase::openCursor):
(WebCore::IDBServer::UniqueIDBDatabase::iterateCursor):
(WebCore::IDBServer::UniqueIDBDatabase::commitTransaction):
(WebCore::IDBServer::UniqueIDBDatabase::abortTransaction):
(WebCore::IDBServer::UniqueIDBDatabase::connectionClosedFromClient):
(WebCore::IDBServer::UniqueIDBDatabase::connectionClosedFromServer):
(WebCore::IDBServer::UniqueIDBDatabase::confirmDidCloseFromServer):
(WebCore::IDBServer::UniqueIDBDatabase::enqueueTransaction):
(WebCore::IDBServer::UniqueIDBDatabase::isCurrentlyInUse):
(WebCore::IDBServer::UniqueIDBDatabase::invokeOperationAndTransactionTimer):
(WebCore::IDBServer::UniqueIDBDatabase::operationAndTransactionTimerFired):
(WebCore::IDBServer::UniqueIDBDatabase::activateTransactionInBackingStore):
(WebCore::IDBServer::UniqueIDBDatabase::transactionCompleted):
(WebCore::IDBServer::UniqueIDBDatabase::postDatabaseTask):
(WebCore::IDBServer::UniqueIDBDatabase::postDatabaseTaskReply):
(WebCore::IDBServer::UniqueIDBDatabase::executeNextDatabaseTask):
(WebCore::IDBServer::UniqueIDBDatabase::executeNextDatabaseTaskReply):
(WebCore::IDBServer::UniqueIDBDatabase::doneWithHardClose):
(WebCore::IDBServer::errorOpenDBRequestForUserDelete):
(WebCore::IDBServer::UniqueIDBDatabase::immediateCloseForUserDelete): Do the heavy lifting
  for the immediate close on the server side.
(WebCore::IDBServer::UniqueIDBDatabase::performErrorCallback):
(WebCore::IDBServer::UniqueIDBDatabase::performKeyDataCallback):
(WebCore::IDBServer::UniqueIDBDatabase::performGetResultCallback):
(WebCore::IDBServer::UniqueIDBDatabase::performCountCallback):
(WebCore::IDBServer::UniqueIDBDatabase::storeCallback): Deleted.
(WebCore::IDBServer::UniqueIDBDatabase::storeCallbackOrFireError): If the database has been
  hard stopped, immediately fire and error for the callback and return a 0-identifier to
  reflect this.
* Modules/indexeddb/server/UniqueIDBDatabase.h:

* Modules/indexeddb/server/UniqueIDBDatabaseConnection.cpp:
(WebCore::IDBServer::UniqueIDBDatabaseConnection::confirmDidCloseFromServer):
* Modules/indexeddb/server/UniqueIDBDatabaseConnection.h:

* Modules/indexeddb/shared/IDBError.cpp:
(WebCore::IDBError::toDOMError):
* Modules/indexeddb/shared/IDBError.h:
(WebCore::IDBError::userDeleteError):

* Modules/indexeddb/shared/InProcessIDBServer.cpp:
(WebCore::InProcessIDBServer::didCloseFromServer):
(WebCore::InProcessIDBServer::confirmDidCloseFromServer):
* Modules/indexeddb/shared/InProcessIDBServer.h:

* platform/CrossThreadCopier.cpp:
(WebCore::std::chrono::system_clock::time_point>::copy):
* platform/CrossThreadCopier.h:

Source/WebKit2:

- Implement the required IDB delegate code.
- Make DatabaseProcess::deleteWebsiteData call the right method in IDB server.

* DatabaseProcess/DatabaseProcess.cpp:
(WebKit::DatabaseProcess::deleteWebsiteData):

* DatabaseProcess/IndexedDB/WebIDBConnectionToClient.cpp:
(WebKit::WebIDBConnectionToClient::didGetRecord):
(WebKit::WebIDBConnectionToClient::didCloseFromServer):
(WebKit::WebIDBConnectionToClient::confirmDidCloseFromServer):
* DatabaseProcess/IndexedDB/WebIDBConnectionToClient.h:
* DatabaseProcess/IndexedDB/WebIDBConnectionToClient.messages.in:

* WebProcess/Databases/IndexedDB/WebIDBConnectionToServer.cpp:
(WebKit::WebIDBConnectionToServer::confirmDidCloseFromServer):
(WebKit::WebIDBConnectionToServer::didStartTransaction):
(WebKit::WebIDBConnectionToServer::didCloseFromServer):
* WebProcess/Databases/IndexedDB/WebIDBConnectionToServer.h:
* WebProcess/Databases/IndexedDB/WebIDBConnectionToServer.messages.in:

LayoutTests:

* storage/indexeddb/modern/handle-user-delete-expected.txt: Added.
* storage/indexeddb/modern/handle-user-delete.html: Added.
* storage/indexeddb/modern/resources/handle-user-delete.js: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@201098 268f45cc-cd09-0410-ab3c-d52691b4dbfc

38 files changed:
LayoutTests/ChangeLog
LayoutTests/storage/indexeddb/modern/handle-user-delete-expected.txt [new file with mode: 0644]
LayoutTests/storage/indexeddb/modern/handle-user-delete.html [new file with mode: 0644]
LayoutTests/storage/indexeddb/modern/resources/handle-user-delete.js [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/Modules/indexeddb/IDBDatabase.cpp
Source/WebCore/Modules/indexeddb/IDBDatabase.h
Source/WebCore/Modules/indexeddb/IDBDatabaseIdentifier.h
Source/WebCore/Modules/indexeddb/IDBTransaction.cpp
Source/WebCore/Modules/indexeddb/IDBTransaction.h
Source/WebCore/Modules/indexeddb/client/IDBConnectionProxy.cpp
Source/WebCore/Modules/indexeddb/client/IDBConnectionProxy.h
Source/WebCore/Modules/indexeddb/client/IDBConnectionToServer.cpp
Source/WebCore/Modules/indexeddb/client/IDBConnectionToServer.h
Source/WebCore/Modules/indexeddb/client/IDBConnectionToServerDelegate.h
Source/WebCore/Modules/indexeddb/server/IDBConnectionToClient.cpp
Source/WebCore/Modules/indexeddb/server/IDBConnectionToClient.h
Source/WebCore/Modules/indexeddb/server/IDBConnectionToClientDelegate.h
Source/WebCore/Modules/indexeddb/server/IDBServer.cpp
Source/WebCore/Modules/indexeddb/server/IDBServer.h
Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp
Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.h
Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabaseConnection.cpp
Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabaseConnection.h
Source/WebCore/Modules/indexeddb/shared/IDBError.cpp
Source/WebCore/Modules/indexeddb/shared/IDBError.h
Source/WebCore/Modules/indexeddb/shared/InProcessIDBServer.cpp
Source/WebCore/Modules/indexeddb/shared/InProcessIDBServer.h
Source/WebCore/platform/CrossThreadCopier.cpp
Source/WebCore/platform/CrossThreadCopier.h
Source/WebKit2/ChangeLog
Source/WebKit2/DatabaseProcess/DatabaseProcess.cpp
Source/WebKit2/DatabaseProcess/IndexedDB/WebIDBConnectionToClient.cpp
Source/WebKit2/DatabaseProcess/IndexedDB/WebIDBConnectionToClient.h
Source/WebKit2/DatabaseProcess/IndexedDB/WebIDBConnectionToClient.messages.in
Source/WebKit2/WebProcess/Databases/IndexedDB/WebIDBConnectionToServer.cpp
Source/WebKit2/WebProcess/Databases/IndexedDB/WebIDBConnectionToServer.h
Source/WebKit2/WebProcess/Databases/IndexedDB/WebIDBConnectionToServer.messages.in

index e8d3bc0..d2cadc2 100644 (file)
@@ -1,3 +1,14 @@
+2016-05-18  Brady Eidson  <beidson@apple.com>
+
+        Modern IDB: Add support for server side closing of open database connections.
+        https://bugs.webkit.org/show_bug.cgi?id=157843
+
+        Reviewed by Alex Christensen.
+
+        * storage/indexeddb/modern/handle-user-delete-expected.txt: Added.
+        * storage/indexeddb/modern/handle-user-delete.html: Added.
+        * storage/indexeddb/modern/resources/handle-user-delete.js: Added.
+
 2016-05-18  Myles C. Maxfield  <mmaxfield@apple.com>
 
         [OS X] Update platform/mac/fast/text/sticky-typesetting-features.html
diff --git a/LayoutTests/storage/indexeddb/modern/handle-user-delete-expected.txt b/LayoutTests/storage/indexeddb/modern/handle-user-delete-expected.txt
new file mode 100644 (file)
index 0000000..146147b
--- /dev/null
@@ -0,0 +1,19 @@
+Tests that expected errors come back from user delete.
+
+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;
+
+indexedDB.deleteDatabase(dbname)
+indexedDB.open(dbname)
+Initial upgrade needed: Old version - 0 New version - 1
+Started two spinning requests
+Requested clearAllDatabases
+Initial upgrade versionchange transaction aborted: [object DOMError]
+[PASS] Both requests hit a failure condition (Received onerror or failed to start a new request because the transaction was aborted)
+[PASS] Database received correct error.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/storage/indexeddb/modern/handle-user-delete.html b/LayoutTests/storage/indexeddb/modern/handle-user-delete.html
new file mode 100644 (file)
index 0000000..7c03993
--- /dev/null
@@ -0,0 +1,10 @@
+<html>
+<head>
+<script src="../../../resources/js-test.js"></script>
+<script src="../resources/shared.js"></script>
+</head>
+<body>
+
+<script src="resources/handle-user-delete.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/storage/indexeddb/modern/resources/handle-user-delete.js b/LayoutTests/storage/indexeddb/modern/resources/handle-user-delete.js
new file mode 100644 (file)
index 0000000..e690966
--- /dev/null
@@ -0,0 +1,92 @@
+description("Tests that expected errors come back from user delete.");
+
+indexedDBTest(prepareDatabase);
+
+var requestErrorCount = 0;
+var databaseError = false;
+
+function done()
+{
+    if (requestErrorCount == 2)
+        log("[PASS] Both requests hit a failure condition (Received onerror or failed to start a new request because the transaction was aborted)");
+    else
+        log("[FAIL] " + requestErrorCount + " request(s) hit a failure condition.");
+
+    if (databaseError)
+        log("[PASS] Database received correct error.");
+    else
+        log("[FAIL] Database did not receive correct error.");
+        
+    finishJSTest();
+}
+
+function log(message)
+{
+    debug(message);
+}
+
+function maybeFinish()
+{
+    if (requestErrorCount == 2 && databaseError)
+        done();
+}
+
+function prepareDatabase(event)
+{
+    log("Initial upgrade needed: Old version - " + event.oldVersion + " New version - " + event.newVersion);
+
+    var versionTransaction = event.target.transaction;
+    var database = event.target.result;
+    var objectStore = database.createObjectStore("TestObjectStore");
+    objectStore.put("bar", "foo");
+    
+    database.onerror = function(event) {
+        databaseError = true;
+        maybeFinish();
+    }
+
+    var hasClearedDatabases = false;
+    var spinGet = function() { 
+        try {
+            var req = objectStore.get("foo");
+        } catch(e) {
+            ++requestErrorCount;
+            maybeFinish();
+            return;   
+        }
+        req.onsuccess = function() {
+            spinGet();
+            if (!hasClearedDatabases) {
+                if (window.testRunner) {
+                    setTimeout("testRunner.clearAllDatabases();", 0);
+                    log("Requested clearAllDatabases");
+                }
+                hasClearedDatabases = true;
+            }
+        }
+        req.onerror = function(event) {
+            ++requestErrorCount;
+            event.stopImmediatePropagation();
+            maybeFinish();
+        }
+    }
+    // Start up two get cycles so there will always be at least one request to cancel when the database is deleted.
+    spinGet();
+    spinGet();
+    
+    log("Started two spinning requests")
+
+    versionTransaction.onabort = function(event) {
+        log("Initial upgrade versionchange transaction aborted: " + versionTransaction.error);
+    }
+
+    versionTransaction.oncomplete = function() {
+        log("Initial upgrade versionchange transaction unexpected complete");
+        done();
+    }
+
+    versionTransaction.onerror = function(event) {
+        log("Initial upgrade versionchange transaction unexpected error: " + event.type + " " + versionTransaction.error.name + ", " + versionTransaction.error.message);
+        done();
+    }
+}
index 57bc8b5..4b29ccb 100644 (file)
@@ -1,3 +1,136 @@
+2016-05-18  Brady Eidson  <beidson@apple.com>
+
+        Modern IDB: Add support for server side closing of open database connections.
+        https://bugs.webkit.org/show_bug.cgi?id=157843
+
+        Reviewed by Alex Christensen.
+
+        Test: storage/indexeddb/modern/handle-user-delete.html
+
+        In order to support deleting IndexedDB databases, the IDB server needs the ability to 
+        "immediately" close a currently open IDB connection.
+        
+        To do so cleanly, the server has to:
+        - Error out all requests it knows about
+        - Abort all transactions it knows about
+        - Tell the connection that it is being closed
+        - Wait for the connection to acknowledge that it was closed on the server
+        
+        And then the client has to:
+        - Error out all requests it hasn't sent to the server
+        - Abort all transactions that haven't already been aborted by the server
+        - Send acknowledgement to the server that it has been closed.
+
+        Finally, because the status of a given request might be "in flight" somewhere between the 
+        server and the client, some design assumptions change. This requires reworking some ASSERTS,
+        null checks, etc.
+
+        * Modules/indexeddb/IDBDatabase.cpp:
+        (WebCore::IDBDatabase::didCloseFromServer): Do the heavy lifting for the immediate close on
+          the client side.
+        * Modules/indexeddb/IDBDatabase.h:
+        
+        * Modules/indexeddb/IDBDatabaseIdentifier.h:
+        (WebCore::IDBDatabaseIdentifier::isRelatedToOrigin):
+        
+        * Modules/indexeddb/IDBTransaction.cpp:
+        (WebCore::IDBTransaction::connectionClosedFromServer): Error out all outstanding operations
+          and fire the abort error on itself.
+        * Modules/indexeddb/IDBTransaction.h:
+        
+        * Modules/indexeddb/client/IDBConnectionProxy.cpp:
+        (WebCore::IDBClient::IDBConnectionProxy::completeOperation):
+        (WebCore::IDBClient::IDBConnectionProxy::didCloseFromServer):
+        (WebCore::IDBClient::IDBConnectionProxy::confirmDidCloseFromServer):
+        (WebCore::IDBClient::IDBConnectionProxy::forgetActiveOperations):
+        * Modules/indexeddb/client/IDBConnectionProxy.h:
+        
+        * Modules/indexeddb/client/IDBConnectionToServer.cpp:
+        (WebCore::IDBClient::IDBConnectionToServer::didCloseFromServer):
+        (WebCore::IDBClient::IDBConnectionToServer::confirmDidCloseFromServer):
+        * Modules/indexeddb/client/IDBConnectionToServer.h:
+        * Modules/indexeddb/client/IDBConnectionToServerDelegate.h:
+        
+        * Modules/indexeddb/server/IDBConnectionToClient.cpp:
+        (WebCore::IDBServer::IDBConnectionToClient::didCloseFromServer):
+        * Modules/indexeddb/server/IDBConnectionToClient.h:
+        * Modules/indexeddb/server/IDBConnectionToClientDelegate.h:
+        
+        * Modules/indexeddb/server/IDBServer.cpp:
+        (WebCore::IDBServer::IDBServer::confirmDidCloseFromServer):
+        (WebCore::IDBServer::generateDeleteCallbackID):
+        (WebCore::IDBServer::IDBServer::closeAndDeleteDatabasesModifiedSince):
+        (WebCore::IDBServer::IDBServer::closeAndDeleteDatabasesForOrigins):
+        (WebCore::IDBServer::IDBServer::performCloseAndDeleteDatabasesModifiedSince):
+        (WebCore::IDBServer::IDBServer::performCloseAndDeleteDatabasesForOrigins):
+        (WebCore::IDBServer::IDBServer::didPerformCloseAndDeleteDatabases):
+        * Modules/indexeddb/server/IDBServer.h:
+        
+        * Modules/indexeddb/server/UniqueIDBDatabase.cpp:
+        (WebCore::IDBServer::UniqueIDBDatabase::~UniqueIDBDatabase):
+        (WebCore::IDBServer::UniqueIDBDatabase::openDatabaseConnection):
+        (WebCore::IDBServer::UniqueIDBDatabase::didDeleteBackingStore):
+        (WebCore::IDBServer::UniqueIDBDatabase::handleDatabaseOperations):
+        (WebCore::IDBServer::UniqueIDBDatabase::handleCurrentOperation):
+        (WebCore::IDBServer::UniqueIDBDatabase::handleDelete):
+        (WebCore::IDBServer::UniqueIDBDatabase::createObjectStore):
+        (WebCore::IDBServer::UniqueIDBDatabase::deleteObjectStore):
+        (WebCore::IDBServer::UniqueIDBDatabase::clearObjectStore):
+        (WebCore::IDBServer::UniqueIDBDatabase::createIndex):
+        (WebCore::IDBServer::UniqueIDBDatabase::deleteIndex):
+        (WebCore::IDBServer::UniqueIDBDatabase::putOrAdd):
+        (WebCore::IDBServer::UniqueIDBDatabase::getRecord):
+        (WebCore::IDBServer::UniqueIDBDatabase::getCount):
+        (WebCore::IDBServer::UniqueIDBDatabase::deleteRecord):
+        (WebCore::IDBServer::UniqueIDBDatabase::openCursor):
+        (WebCore::IDBServer::UniqueIDBDatabase::iterateCursor):
+        (WebCore::IDBServer::UniqueIDBDatabase::commitTransaction):
+        (WebCore::IDBServer::UniqueIDBDatabase::abortTransaction):
+        (WebCore::IDBServer::UniqueIDBDatabase::connectionClosedFromClient):
+        (WebCore::IDBServer::UniqueIDBDatabase::connectionClosedFromServer):
+        (WebCore::IDBServer::UniqueIDBDatabase::confirmDidCloseFromServer):
+        (WebCore::IDBServer::UniqueIDBDatabase::enqueueTransaction):
+        (WebCore::IDBServer::UniqueIDBDatabase::isCurrentlyInUse):
+        (WebCore::IDBServer::UniqueIDBDatabase::invokeOperationAndTransactionTimer):
+        (WebCore::IDBServer::UniqueIDBDatabase::operationAndTransactionTimerFired):
+        (WebCore::IDBServer::UniqueIDBDatabase::activateTransactionInBackingStore):
+        (WebCore::IDBServer::UniqueIDBDatabase::transactionCompleted):
+        (WebCore::IDBServer::UniqueIDBDatabase::postDatabaseTask):
+        (WebCore::IDBServer::UniqueIDBDatabase::postDatabaseTaskReply):
+        (WebCore::IDBServer::UniqueIDBDatabase::executeNextDatabaseTask):
+        (WebCore::IDBServer::UniqueIDBDatabase::executeNextDatabaseTaskReply):
+        (WebCore::IDBServer::UniqueIDBDatabase::doneWithHardClose):
+        (WebCore::IDBServer::errorOpenDBRequestForUserDelete):
+        (WebCore::IDBServer::UniqueIDBDatabase::immediateCloseForUserDelete): Do the heavy lifting
+          for the immediate close on the server side.
+        (WebCore::IDBServer::UniqueIDBDatabase::performErrorCallback):
+        (WebCore::IDBServer::UniqueIDBDatabase::performKeyDataCallback):
+        (WebCore::IDBServer::UniqueIDBDatabase::performGetResultCallback):
+        (WebCore::IDBServer::UniqueIDBDatabase::performCountCallback):
+        (WebCore::IDBServer::UniqueIDBDatabase::storeCallback): Deleted.
+        (WebCore::IDBServer::UniqueIDBDatabase::storeCallbackOrFireError): If the database has been
+          hard stopped, immediately fire and error for the callback and return a 0-identifier to
+          reflect this.
+        * Modules/indexeddb/server/UniqueIDBDatabase.h:
+        
+        * Modules/indexeddb/server/UniqueIDBDatabaseConnection.cpp:
+        (WebCore::IDBServer::UniqueIDBDatabaseConnection::confirmDidCloseFromServer):
+        * Modules/indexeddb/server/UniqueIDBDatabaseConnection.h:
+        
+        * Modules/indexeddb/shared/IDBError.cpp:
+        (WebCore::IDBError::toDOMError):
+        * Modules/indexeddb/shared/IDBError.h:
+        (WebCore::IDBError::userDeleteError):
+        
+        * Modules/indexeddb/shared/InProcessIDBServer.cpp:
+        (WebCore::InProcessIDBServer::didCloseFromServer):
+        (WebCore::InProcessIDBServer::confirmDidCloseFromServer):
+        * Modules/indexeddb/shared/InProcessIDBServer.h:
+        
+        * platform/CrossThreadCopier.cpp:
+        (WebCore::std::chrono::system_clock::time_point>::copy):
+        * platform/CrossThreadCopier.h:
+
 2016-05-18  Simon Fraser  <simon.fraser@apple.com>
 
         REGRESSION (r200534) Command-+ no longer zooms pages 
index 29b4784..028af29 100644 (file)
@@ -245,6 +245,25 @@ void IDBDatabase::close()
     maybeCloseInServer();
 }
 
+void IDBDatabase::didCloseFromServer(const IDBError& error)
+{
+    LOG(IndexedDB, "IDBDatabase::didCloseFromServer - %" PRIu64, m_databaseConnectionIdentifier);
+
+    ASSERT(currentThread() == m_originThreadID);
+
+    m_closePending = true;
+    m_closedInServer = true;
+
+    for (auto& transaction : m_activeTransactions.values())
+        transaction->connectionClosedFromServer(error);
+
+    Ref<Event> event = Event::create(eventNames().errorEvent, true, false);
+    event->setTarget(this);
+    scriptExecutionContext()->eventQueue().enqueueEvent(WTFMove(event));
+
+    m_connectionProxy->confirmDidCloseFromServer(*this);
+}
+
 void IDBDatabase::maybeCloseInServer()
 {
     LOG(IndexedDB, "IDBDatabase::maybeCloseInServer - %" PRIu64, m_databaseConnectionIdentifier);
index 3cf6d47..3629353 100644 (file)
@@ -86,6 +86,7 @@ public:
     void didAbortTransaction(IDBTransaction&);
 
     void fireVersionChangeEvent(const IDBResourceIdentifier& requestIdentifier, uint64_t requestedVersion);
+    void didCloseFromServer(const IDBError&);
 
     IDBClient::IDBConnectionProxy& connectionProxy() { return m_connectionProxy.get(); }
 
index 31e41aa..ea1efe1 100644 (file)
@@ -102,6 +102,11 @@ public:
     String debugString() const;
 #endif
 
+    bool isRelatedToOrigin(const SecurityOriginData& other) const
+    {
+        return m_openingOrigin == other || m_mainFrameOrigin == other;
+    }
+
 private:
     String m_databaseName;
     SecurityOriginData m_openingOrigin;
index 112b764..ef4ced0 100644 (file)
@@ -1075,6 +1075,29 @@ ThreadIdentifier IDBTransaction::originThreadID() const
     return m_database->originThreadID();
 }
 
+void IDBTransaction::connectionClosedFromServer(const IDBError& error)
+{
+    LOG(IndexedDB, "IDBTransaction::connectionClosedFromServer - %s", error.message().utf8().data());
+
+    m_state = IndexedDB::TransactionState::Aborting;
+
+    Vector<RefPtr<IDBClient::TransactionOperation>> operations;
+    copyValuesToVector(m_transactionOperationMap, operations);
+
+    for (auto& operation : operations)
+        operation->completed(IDBResultData::error(operation->identifier(), error));
+
+    connectionProxy().forgetActiveOperations(operations);
+
+    m_transactionOperationQueue.clear();
+    m_abortQueue.clear();
+    m_transactionOperationMap.clear();
+
+    m_idbError = error;
+    m_domError = error.toDOMError();
+    fireOnAbort();
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(INDEXED_DATABASE)
index ca21547..191ccf7 100644 (file)
@@ -145,6 +145,8 @@ public:
 
     ThreadIdentifier originThreadID() const;
 
+    void connectionClosedFromServer(const IDBError&);
+
 private:
     IDBTransaction(IDBDatabase&, const IDBTransactionInfo&, IDBOpenDBRequest*);
 
index ce8c8b0..a1b47d8 100644 (file)
@@ -249,7 +249,8 @@ void IDBConnectionProxy::completeOperation(const IDBResultData& resultData)
         operation = m_activeOperations.take(resultData.requestIdentifier());
     }
 
-    ASSERT(operation);
+    if (!operation)
+        return;
 
     performCallbackOnCorrectThread(*operation, &TransactionOperation::completed, resultData);
 }
@@ -388,6 +389,29 @@ void IDBConnectionProxy::databaseConnectionClosed(IDBDatabase& database)
     callConnectionOnMainThread(&IDBConnectionToServer::databaseConnectionClosed, database.databaseConnectionIdentifier());
 }
 
+void IDBConnectionProxy::didCloseFromServer(uint64_t databaseConnectionIdentifier, const IDBError& error)
+{
+    RefPtr<IDBDatabase> database;
+    {
+        Locker<Lock> locker(m_databaseConnectionMapLock);
+        database = m_databaseConnectionMap.get(databaseConnectionIdentifier);
+    }
+
+    // If the IDBDatabase object is gone, message back to the server so it doesn't hang
+    // waiting for a reply that will never come.
+    if (!database) {
+        m_connectionToServer.confirmDidCloseFromServer(databaseConnectionIdentifier);
+        return;
+    }
+
+    performCallbackOnCorrectThread(*database, &IDBDatabase::didCloseFromServer, error);
+}
+
+void IDBConnectionProxy::confirmDidCloseFromServer(IDBDatabase& database)
+{
+    callConnectionOnMainThread(&IDBConnectionToServer::confirmDidCloseFromServer, database.databaseConnectionIdentifier());
+}
+
 void IDBConnectionProxy::scheduleMainThreadTasks()
 {
     Locker<Lock> locker(m_mainThreadTaskLock);
@@ -438,6 +462,14 @@ void IDBConnectionProxy::unregisterDatabaseConnection(IDBDatabase& database)
     m_databaseConnectionMap.remove(database.databaseConnectionIdentifier());
 }
 
+void IDBConnectionProxy::forgetActiveOperations(const Vector<RefPtr<TransactionOperation>>& operations)
+{
+    Locker<Lock> locker(m_transactionOperationLock);
+
+    for (auto& operation : operations)
+        m_activeOperations.remove(operation->identifier());
+}
+
 } // namesapce IDBClient
 } // namespace WebCore
 
index 387d7d0..c84a8bc 100644 (file)
@@ -93,6 +93,9 @@ public:
     void didFinishHandlingVersionChangeTransaction(uint64_t databaseConnectionIdentifier, IDBTransaction&);
     void databaseConnectionClosed(IDBDatabase&);
 
+    void didCloseFromServer(uint64_t databaseConnectionIdentifier, const IDBError&);
+    void confirmDidCloseFromServer(IDBDatabase&);
+
     void abortOpenAndUpgradeNeeded(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& transactionIdentifier);
 
     void completeOperation(const IDBResultData&);
@@ -109,6 +112,8 @@ public:
 
     RefPtr<IDBOpenDBRequest> takeIDBOpenDBRequest(IDBOpenDBRequest&);
 
+    void forgetActiveOperations(const Vector<RefPtr<TransactionOperation>>&);
+
 private:
     void completeOpenDBRequest(const IDBResultData&);
     bool hasRecordOfTransaction(const IDBTransaction&) const;
index fbe7f41..662ac4b 100644 (file)
@@ -316,6 +316,22 @@ void IDBConnectionToServer::didStartTransaction(const IDBResourceIdentifier& tra
     m_proxy->didStartTransaction(transactionIdentifier, error);
 }
 
+void IDBConnectionToServer::didCloseFromServer(uint64_t databaseConnectionIdentifier, const IDBError& error)
+{
+    LOG(IndexedDB, "IDBConnectionToServer::didCloseFromServer");
+    ASSERT(isMainThread());
+
+    m_proxy->didCloseFromServer(databaseConnectionIdentifier, error);
+}
+
+void IDBConnectionToServer::confirmDidCloseFromServer(uint64_t databaseConnectionIdentifier)
+{
+    LOG(IndexedDB, "IDBConnectionToServer::confirmDidCloseFromServer");
+    ASSERT(isMainThread());
+
+    m_delegate->confirmDidCloseFromServer(databaseConnectionIdentifier);
+}
+
 void IDBConnectionToServer::notifyOpenDBRequestBlocked(const IDBResourceIdentifier& requestIdentifier, uint64_t oldVersion, uint64_t newVersion)
 {
     LOG(IndexedDB, "IDBConnectionToServer::didStartTransaction");
index d0ce068..c7933c8 100644 (file)
@@ -106,6 +106,10 @@ public:
     void didFireVersionChangeEvent(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& requestIdentifier);
 
     WEBCORE_EXPORT void didStartTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError&);
+
+    WEBCORE_EXPORT void didCloseFromServer(uint64_t databaseConnectionIdentifier, const IDBError&);
+    void confirmDidCloseFromServer(uint64_t databaseConnectionIdentifier);
+
     WEBCORE_EXPORT void notifyOpenDBRequestBlocked(const IDBResourceIdentifier& requestIdentifier, uint64_t oldVersion, uint64_t newVersion);
     void openDBRequestCancelled(const IDBRequestData&);
 
index 2c03d4e..cb4e5cd 100644 (file)
@@ -77,6 +77,7 @@ public:
     virtual void abortOpenAndUpgradeNeeded(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& transactionIdentifier) = 0;
     virtual void didFireVersionChangeEvent(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& requestIdentifier) = 0;
     virtual void openDBRequestCancelled(const IDBRequestData&) = 0;
+    virtual void confirmDidCloseFromServer(uint64_t databaseConnectionIdentifier) = 0;
 
     virtual void getAllDatabaseNames(const SecurityOriginData& mainFrameOrigin, const SecurityOriginData& openingOrigin, uint64_t callbackID) = 0;
 
index 4bf41e0..ec9312f 100644 (file)
@@ -133,6 +133,11 @@ void IDBConnectionToClient::didStartTransaction(const IDBResourceIdentifier& tra
     m_delegate->didStartTransaction(transactionIdentifier, error);
 }
 
+void IDBConnectionToClient::didCloseFromServer(UniqueIDBDatabaseConnection& connection, const IDBError& error)
+{
+    m_delegate->didCloseFromServer(connection, error);
+}
+
 void IDBConnectionToClient::notifyOpenDBRequestBlocked(const IDBResourceIdentifier& requestIdentifier, uint64_t oldVersion, uint64_t newVersion)
 {
     m_delegate->notifyOpenDBRequestBlocked(requestIdentifier, oldVersion, newVersion);
index 7e24647..f21f917 100644 (file)
@@ -66,6 +66,7 @@ public:
 
     void fireVersionChangeEvent(UniqueIDBDatabaseConnection&, const IDBResourceIdentifier& requestIdentifier, uint64_t requestedVersion);
     void didStartTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError&);
+    void didCloseFromServer(UniqueIDBDatabaseConnection&, const IDBError&);
 
     void notifyOpenDBRequestBlocked(const IDBResourceIdentifier& requestIdentifier, uint64_t oldVersion, uint64_t newVersion);
 
index 42c54ab..62caf46 100644 (file)
@@ -65,6 +65,7 @@ public:
 
     virtual void fireVersionChangeEvent(UniqueIDBDatabaseConnection&, const IDBResourceIdentifier& requestIdentifier, uint64_t requestedVersion) = 0;
     virtual void didStartTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError&) = 0;
+    virtual void didCloseFromServer(UniqueIDBDatabaseConnection&, const IDBError&) = 0;
     virtual void notifyOpenDBRequestBlocked(const IDBResourceIdentifier& requestIdentifier, uint64_t oldVersion, uint64_t newVersion) = 0;
 
     virtual void didGetAllDatabaseNames(uint64_t callbackID, const Vector<String>& databaseNames) = 0;
index 21ba755..41c0d06 100644 (file)
@@ -33,7 +33,9 @@
 #include "IDBResultData.h"
 #include "Logging.h"
 #include "MemoryIDBBackingStore.h"
+#include "SQLiteFileSystem.h"
 #include "SQLiteIDBBackingStore.h"
+#include "SecurityOrigin.h"
 #include <wtf/Locker.h>
 #include <wtf/MainThread.h>
 
@@ -388,6 +390,14 @@ void IDBServer::openDBRequestCancelled(const IDBRequestData& requestData)
     uniqueIDBDatabase->openDBRequestCancelled(requestData.requestIdentifier());
 }
 
+void IDBServer::confirmDidCloseFromServer(uint64_t databaseConnectionIdentifier)
+{
+    LOG(IndexedDB, "IDBServer::confirmDidCloseFromServer");
+
+    if (auto databaseConnection = m_databaseConnections.get(databaseConnectionIdentifier))
+        databaseConnection->confirmDidCloseFromServer();
+}
+
 void IDBServer::getAllDatabaseNames(uint64_t serverConnectionIdentifier, const SecurityOriginData& mainFrameOrigin, const SecurityOriginData& openingOrigin, uint64_t callbackID)
 {
     postDatabaseTask(createCrossThreadTask(*this, &IDBServer::performGetAllDatabaseNames, serverConnectionIdentifier, mainFrameOrigin, openingOrigin, callbackID));
@@ -468,10 +478,75 @@ void IDBServer::handleTaskRepliesOnMainThread()
         task->performTask();
 }
 
-void IDBServer::closeAndDeleteDatabasesModifiedSince(std::chrono::system_clock::time_point, std::function<void ()> completionHandler)
+static uint64_t generateDeleteCallbackID()
+{
+    ASSERT(isMainThread());
+    static uint64_t currentID = 0;
+    return ++currentID;
+}
+
+void IDBServer::closeAndDeleteDatabasesModifiedSince(std::chrono::system_clock::time_point modificationTime, std::function<void ()> completionHandler)
+{
+    uint64_t callbackID = generateDeleteCallbackID();
+    auto addResult = m_deleteDatabaseCompletionHandlers.add(callbackID, WTFMove(completionHandler));
+    ASSERT_UNUSED(addResult, addResult.isNewEntry);
+
+    // If the modification time is in the future, don't both doing anything.
+    if (modificationTime > std::chrono::system_clock::now()) {
+        postDatabaseTaskReply(createCrossThreadTask(*this, &IDBServer::didPerformCloseAndDeleteDatabases, callbackID));
+        return;
+    }
+
+    HashSet<UniqueIDBDatabase*> openDatabases;
+    for (auto* connection : m_databaseConnections.values())
+        openDatabases.add(&connection->database());
+
+    for (auto* database : openDatabases)
+        database->immediateCloseForUserDelete();
+
+    postDatabaseTask(createCrossThreadTask(*this, &IDBServer::performCloseAndDeleteDatabasesModifiedSince, modificationTime, callbackID));
+}
+
+void IDBServer::closeAndDeleteDatabasesForOrigins(const Vector<SecurityOriginData>& origins, std::function<void ()> completionHandler)
+{
+    uint64_t callbackID = generateDeleteCallbackID();
+    auto addResult = m_deleteDatabaseCompletionHandlers.add(callbackID, WTFMove(completionHandler));
+    ASSERT_UNUSED(addResult, addResult.isNewEntry);
+
+    HashSet<UniqueIDBDatabase*> openDatabases;
+    for (auto* connection : m_databaseConnections.values()) {
+        const auto& identifier = connection->database().identifier();
+        for (auto& origin : origins) {
+            if (identifier.isRelatedToOrigin(origin)) {
+                openDatabases.add(&connection->database());
+                break;
+            }
+        }
+    }
+
+    for (auto* database : openDatabases)
+        database->immediateCloseForUserDelete();
+
+    postDatabaseTask(createCrossThreadTask(*this, &IDBServer::performCloseAndDeleteDatabasesForOrigins, origins, callbackID));
+}
+
+void IDBServer::performCloseAndDeleteDatabasesModifiedSince(std::chrono::system_clock::time_point, uint64_t callbackID)
+{
+    // FIXME: Implement deleting the files.
+    postDatabaseTaskReply(createCrossThreadTask(*this, &IDBServer::didPerformCloseAndDeleteDatabases, callbackID));
+}
+
+void IDBServer::performCloseAndDeleteDatabasesForOrigins(const Vector<SecurityOriginData>&, uint64_t callbackID)
+{
+    // FIXME: Implement deleting the files.
+    postDatabaseTaskReply(createCrossThreadTask(*this, &IDBServer::didPerformCloseAndDeleteDatabases, callbackID));
+}
+
+void IDBServer::didPerformCloseAndDeleteDatabases(uint64_t callbackID)
 {
-    // FIXME: Implement (https://bugs.webkit.org/show_bug.cgi?id=157626)
-    completionHandler();
+    auto callback = m_deleteDatabaseCompletionHandlers.take(callbackID);
+    ASSERT(callback);
+    callback();
 }
 
 } // namespace IDBServer
index 8cee38f..83209e4 100644 (file)
@@ -81,6 +81,7 @@ public:
     WEBCORE_EXPORT void abortOpenAndUpgradeNeeded(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& transactionIdentifier);
     WEBCORE_EXPORT void didFireVersionChangeEvent(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& requestIdentifier);
     WEBCORE_EXPORT void openDBRequestCancelled(const IDBRequestData&);
+    WEBCORE_EXPORT void confirmDidCloseFromServer(uint64_t databaseConnectionIdentifier);
 
     WEBCORE_EXPORT void getAllDatabaseNames(uint64_t serverConnectionIdentifier, const SecurityOriginData& mainFrameOrigin, const SecurityOriginData& openingOrigin, uint64_t callbackID);
 
@@ -97,6 +98,7 @@ public:
     std::unique_ptr<IDBBackingStore> createBackingStore(const IDBDatabaseIdentifier&);
 
     WEBCORE_EXPORT void closeAndDeleteDatabasesModifiedSince(std::chrono::system_clock::time_point, std::function<void ()> completionHandler);
+    WEBCORE_EXPORT void closeAndDeleteDatabasesForOrigins(const Vector<SecurityOriginData>&, std::function<void ()> completionHandler);
 
 private:
     IDBServer(IDBBackingStoreTemporaryFileHandler&);
@@ -107,6 +109,10 @@ private:
     void performGetAllDatabaseNames(uint64_t serverConnectionIdentifier, const SecurityOriginData& mainFrameOrigin, const SecurityOriginData& openingOrigin, uint64_t callbackID);
     void didGetAllDatabaseNames(uint64_t serverConnectionIdentifier, uint64_t callbackID, const Vector<String>& databaseNames);
 
+    void performCloseAndDeleteDatabasesModifiedSince(std::chrono::system_clock::time_point, uint64_t callbackID);
+    void performCloseAndDeleteDatabasesForOrigins(const Vector<SecurityOriginData>&, uint64_t callbackID);
+    void didPerformCloseAndDeleteDatabases(uint64_t callbackID);
+
     static void databaseThreadEntry(void*);
     void databaseRunLoop();
     void handleTaskRepliesOnMainThread();
@@ -125,6 +131,8 @@ private:
     HashMap<uint64_t, UniqueIDBDatabaseConnection*> m_databaseConnections;
     HashMap<IDBResourceIdentifier, UniqueIDBDatabaseTransaction*> m_transactions;
 
+    HashMap<uint64_t, std::function<void ()>> m_deleteDatabaseCompletionHandlers;
+
     String m_databaseDirectoryPath;
     IDBBackingStoreTemporaryFileHandler& m_backingStoreTemporaryFileHandler;
 };
index eda8db9..d4bd65d 100644 (file)
@@ -47,7 +47,7 @@ using namespace JSC;
 
 namespace WebCore {
 namespace IDBServer {
-    
+
 UniqueIDBDatabase::UniqueIDBDatabase(IDBServer& server, const IDBDatabaseIdentifier& identifier)
     : m_server(server)
     , m_identifier(identifier)
@@ -63,7 +63,8 @@ UniqueIDBDatabase::~UniqueIDBDatabase()
     ASSERT(!hasUnfinishedTransactions());
     ASSERT(m_pendingTransactions.isEmpty());
     ASSERT(m_openDatabaseConnections.isEmpty());
-    ASSERT(m_closePendingDatabaseConnections.isEmpty());
+    ASSERT(m_clientClosePendingDatabaseConnections.isEmpty());
+    ASSERT(m_serverClosePendingDatabaseConnections.isEmpty());
 }
 
 const IDBDatabaseInfo& UniqueIDBDatabase::info() const
@@ -74,6 +75,9 @@ const IDBDatabaseInfo& UniqueIDBDatabase::info() const
 
 void UniqueIDBDatabase::openDatabaseConnection(IDBConnectionToClient& connection, const IDBRequestData& requestData)
 {
+    LOG(IndexedDB, "UniqueIDBDatabase::openDatabaseConnection");
+    ASSERT(!m_hardClosedForUserDelete);
+
     m_pendingOpenDBRequests.add(ServerOpenDBRequest::create(connection, requestData));
 
     // An open operation is already in progress, so we can't possibly handle this one yet.
@@ -271,7 +275,7 @@ void UniqueIDBDatabase::didDeleteBackingStore(uint64_t deletedVersion)
 
     m_deleteBackingStoreInProgress = false;
 
-    if (m_closePendingDatabaseConnections.isEmpty() && m_pendingOpenDBRequests.isEmpty()) {
+    if (m_clientClosePendingDatabaseConnections.isEmpty() && m_pendingOpenDBRequests.isEmpty()) {
         m_server.closeUniqueIDBDatabase(*this);
         return;
     }
@@ -283,6 +287,7 @@ void UniqueIDBDatabase::handleDatabaseOperations()
 {
     ASSERT(isMainThread());
     LOG(IndexedDB, "(main) UniqueIDBDatabase::handleDatabaseOperations - There are %u pending", m_pendingOpenDBRequests.size());
+    ASSERT(!m_hardClosedForUserDelete);
 
     if (m_deleteBackingStoreInProgress)
         return;
@@ -311,7 +316,7 @@ void UniqueIDBDatabase::handleDatabaseOperations()
 void UniqueIDBDatabase::handleCurrentOperation()
 {
     LOG(IndexedDB, "(main) UniqueIDBDatabase::handleCurrentOperation");
-
+    ASSERT(!m_hardClosedForUserDelete);
     ASSERT(m_currentOpenDBRequest);
 
     RefPtr<UniqueIDBDatabase> protectedThis(this);
@@ -339,32 +344,52 @@ static uint64_t generateUniqueCallbackIdentifier()
     return ++currentID;
 }
 
-uint64_t UniqueIDBDatabase::storeCallback(ErrorCallback callback)
+uint64_t UniqueIDBDatabase::storeCallbackOrFireError(ErrorCallback callback)
 {
+    if (m_hardClosedForUserDelete) {
+        callback(IDBError::userDeleteError());
+        return 0;
+    }
+
     uint64_t identifier = generateUniqueCallbackIdentifier();
     ASSERT(!m_errorCallbacks.contains(identifier));
     m_errorCallbacks.add(identifier, callback);
     return identifier;
 }
 
-uint64_t UniqueIDBDatabase::storeCallback(KeyDataCallback callback)
+uint64_t UniqueIDBDatabase::storeCallbackOrFireError(KeyDataCallback callback)
 {
+    if (m_hardClosedForUserDelete) {
+        callback(IDBError::userDeleteError(), { });
+        return 0;
+    }
+
     uint64_t identifier = generateUniqueCallbackIdentifier();
     ASSERT(!m_keyDataCallbacks.contains(identifier));
     m_keyDataCallbacks.add(identifier, callback);
     return identifier;
 }
 
-uint64_t UniqueIDBDatabase::storeCallback(GetResultCallback callback)
+uint64_t UniqueIDBDatabase::storeCallbackOrFireError(GetResultCallback callback)
 {
+    if (m_hardClosedForUserDelete) {
+        callback(IDBError::userDeleteError(), { });
+        return 0;
+    }
+
     uint64_t identifier = generateUniqueCallbackIdentifier();
     ASSERT(!m_getResultCallbacks.contains(identifier));
     m_getResultCallbacks.add(identifier, callback);
     return identifier;
 }
 
-uint64_t UniqueIDBDatabase::storeCallback(CountCallback callback)
+uint64_t UniqueIDBDatabase::storeCallbackOrFireError(CountCallback callback)
 {
+    if (m_hardClosedForUserDelete) {
+        callback(IDBError::userDeleteError(), 0);
+        return 0;
+    }
+
     uint64_t identifier = generateUniqueCallbackIdentifier();
     ASSERT(!m_countCallbacks.contains(identifier));
     m_countCallbacks.add(identifier, callback);
@@ -374,6 +399,7 @@ uint64_t UniqueIDBDatabase::storeCallback(CountCallback callback)
 void UniqueIDBDatabase::handleDelete(IDBConnectionToClient& connection, const IDBRequestData& requestData)
 {
     LOG(IndexedDB, "(main) UniqueIDBDatabase::handleDelete");
+    ASSERT(!m_hardClosedForUserDelete);
 
     m_pendingOpenDBRequests.add(ServerOpenDBRequest::create(connection, requestData));
     handleDatabaseOperations();
@@ -538,7 +564,10 @@ void UniqueIDBDatabase::createObjectStore(UniqueIDBDatabaseTransaction& transact
     ASSERT(isMainThread());
     LOG(IndexedDB, "(main) UniqueIDBDatabase::createObjectStore");
 
-    uint64_t callbackID = storeCallback(callback);
+    uint64_t callbackID = storeCallbackOrFireError(callback);
+    if (!callbackID)
+        return;
+
     postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performCreateObjectStore, callbackID, transaction.info().identifier(), info));
 }
 
@@ -570,7 +599,9 @@ void UniqueIDBDatabase::deleteObjectStore(UniqueIDBDatabaseTransaction& transact
     ASSERT(isMainThread());
     LOG(IndexedDB, "(main) UniqueIDBDatabase::deleteObjectStore");
 
-    uint64_t callbackID = storeCallback(callback);
+    uint64_t callbackID = storeCallbackOrFireError(callback);
+    if (!callbackID)
+        return;
 
     auto* info = m_databaseInfo->infoForExistingObjectStore(objectStoreName);
     if (!info) {
@@ -609,7 +640,9 @@ void UniqueIDBDatabase::clearObjectStore(UniqueIDBDatabaseTransaction& transacti
     ASSERT(isMainThread());
     LOG(IndexedDB, "(main) UniqueIDBDatabase::clearObjectStore");
 
-    uint64_t callbackID = storeCallback(callback);
+    uint64_t callbackID = storeCallbackOrFireError(callback);
+    if (!callbackID)
+        return;
     postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performClearObjectStore, callbackID, transaction.info().identifier(), objectStoreIdentifier));
 }
 
@@ -638,7 +671,9 @@ void UniqueIDBDatabase::createIndex(UniqueIDBDatabaseTransaction& transaction, c
     ASSERT(isMainThread());
     LOG(IndexedDB, "(main) UniqueIDBDatabase::createIndex");
 
-    uint64_t callbackID = storeCallback(callback);
+    uint64_t callbackID = storeCallbackOrFireError(callback);
+    if (!callbackID)
+        return;
     postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performCreateIndex, callbackID, transaction.info().identifier(), info));
 }
 
@@ -673,7 +708,9 @@ void UniqueIDBDatabase::deleteIndex(UniqueIDBDatabaseTransaction& transaction, u
     ASSERT(isMainThread());
     LOG(IndexedDB, "(main) UniqueIDBDatabase::deleteIndex");
 
-    uint64_t callbackID = storeCallback(callback);
+    uint64_t callbackID = storeCallbackOrFireError(callback);
+    if (!callbackID)
+        return;
 
     auto* objectStoreInfo = m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
     if (!objectStoreInfo) {
@@ -721,7 +758,9 @@ void UniqueIDBDatabase::putOrAdd(const IDBRequestData& requestData, const IDBKey
     ASSERT(isMainThread());
     LOG(IndexedDB, "(main) UniqueIDBDatabase::putOrAdd");
 
-    uint64_t callbackID = storeCallback(callback);
+    uint64_t callbackID = storeCallbackOrFireError(callback);
+    if (!callbackID)
+        return;
     postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performPutOrAdd, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), keyData, value, overwriteMode));
 }
 
@@ -857,7 +896,9 @@ void UniqueIDBDatabase::getRecord(const IDBRequestData& requestData, const IDBKe
     ASSERT(isMainThread());
     LOG(IndexedDB, "(main) UniqueIDBDatabase::getRecord");
 
-    uint64_t callbackID = storeCallback(callback);
+    uint64_t callbackID = storeCallbackOrFireError(callback);
+    if (!callbackID)
+        return;
 
     if (uint64_t indexIdentifier = requestData.indexIdentifier())
         postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performGetIndexRecord, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), indexIdentifier, requestData.indexRecordType(), range));
@@ -904,7 +945,9 @@ void UniqueIDBDatabase::getCount(const IDBRequestData& requestData, const IDBKey
     ASSERT(isMainThread());
     LOG(IndexedDB, "(main) UniqueIDBDatabase::getCount");
 
-    uint64_t callbackID = storeCallback(callback);
+    uint64_t callbackID = storeCallbackOrFireError(callback);
+    if (!callbackID)
+        return;
     postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performGetCount, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), requestData.indexIdentifier(), range));
 }
 
@@ -935,7 +978,9 @@ void UniqueIDBDatabase::deleteRecord(const IDBRequestData& requestData, const ID
     ASSERT(isMainThread());
     LOG(IndexedDB, "(main) UniqueIDBDatabase::deleteRecord");
 
-    uint64_t callbackID = storeCallback(callback);
+    uint64_t callbackID = storeCallbackOrFireError(callback);
+    if (!callbackID)
+        return;
     postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performDeleteRecord, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), keyRangeData));
 }
 
@@ -962,7 +1007,9 @@ void UniqueIDBDatabase::openCursor(const IDBRequestData& requestData, const IDBC
     ASSERT(isMainThread());
     LOG(IndexedDB, "(main) UniqueIDBDatabase::openCursor");
 
-    uint64_t callbackID = storeCallback(callback);
+    uint64_t callbackID = storeCallbackOrFireError(callback);
+    if (!callbackID)
+        return;
     postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performOpenCursor, callbackID, requestData.transactionIdentifier(), info));
 }
 
@@ -990,7 +1037,9 @@ void UniqueIDBDatabase::iterateCursor(const IDBRequestData& requestData, const I
     ASSERT(isMainThread());
     LOG(IndexedDB, "(main) UniqueIDBDatabase::iterateCursor");
 
-    uint64_t callbackID = storeCallback(callback);
+    uint64_t callbackID = storeCallbackOrFireError(callback);
+    if (!callbackID)
+        return;
     postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performIterateCursor, callbackID, requestData.transactionIdentifier(), requestData.cursorIdentifier(), key, count));
 }
 
@@ -1032,7 +1081,9 @@ void UniqueIDBDatabase::commitTransaction(UniqueIDBDatabaseTransaction& transact
 
     ASSERT(&transaction.databaseConnection().database() == this);
 
-    uint64_t callbackID = storeCallback(callback);
+    uint64_t callbackID = storeCallbackOrFireError(callback);
+    if (!callbackID)
+        return;
 
     if (!prepareToFinishTransaction(transaction)) {
         if (!m_openDatabaseConnections.contains(&transaction.databaseConnection())) {
@@ -1074,7 +1125,9 @@ void UniqueIDBDatabase::abortTransaction(UniqueIDBDatabaseTransaction& transacti
 
     ASSERT(&transaction.databaseConnection().database() == this);
 
-    uint64_t callbackID = storeCallback(callback);
+    uint64_t callbackID = storeCallbackOrFireError(callback);
+    if (!callbackID)
+        return;
 
     if (!prepareToFinishTransaction(transaction)) {
         if (!m_openDatabaseConnections.contains(&transaction.databaseConnection())) {
@@ -1149,7 +1202,7 @@ void UniqueIDBDatabase::connectionClosedFromClient(UniqueIDBDatabaseConnection&
 
     if (m_versionChangeDatabaseConnection == &connection) {
         if (m_versionChangeTransaction) {
-            m_closePendingDatabaseConnections.add(WTFMove(m_versionChangeDatabaseConnection));
+            m_clientClosePendingDatabaseConnections.add(WTFMove(m_versionChangeDatabaseConnection));
 
             auto transactionIdentifier = m_versionChangeTransaction->info().identifier();
             if (m_inProgressTransactions.contains(transactionIdentifier)) {
@@ -1177,7 +1230,7 @@ void UniqueIDBDatabase::connectionClosedFromClient(UniqueIDBDatabaseConnection&
         notifyCurrentRequestConnectionClosedOrFiredVersionChangeEvent(connection.identifier());
 
     if (connection.hasNonFinishedTransactions()) {
-        m_closePendingDatabaseConnections.add(WTFMove(protectedConnection));
+        m_clientClosePendingDatabaseConnections.add(WTFMove(protectedConnection));
         return;
     }
 
@@ -1185,9 +1238,38 @@ void UniqueIDBDatabase::connectionClosedFromClient(UniqueIDBDatabaseConnection&
     invokeOperationAndTransactionTimer();
 }
 
+void UniqueIDBDatabase::connectionClosedFromServer(UniqueIDBDatabaseConnection& connection)
+{
+    ASSERT(isMainThread());
+    LOG(IndexedDB, "UniqueIDBDatabase::connectionClosedFromServer - %s (%" PRIu64 ")", connection.openRequestIdentifier().loggingString().utf8().data(), connection.identifier());
+
+    if (m_clientClosePendingDatabaseConnections.contains(&connection)) {
+        ASSERT(!m_openDatabaseConnections.contains(&connection));
+        ASSERT(!m_serverClosePendingDatabaseConnections.contains(&connection));
+        return;
+    }
+
+    Ref<UniqueIDBDatabaseConnection> protectedConnection(connection);
+    m_openDatabaseConnections.remove(&connection);
+
+    connection.connectionToClient().didCloseFromServer(connection, IDBError::userDeleteError());
+
+    m_serverClosePendingDatabaseConnections.add(WTFMove(protectedConnection));
+}
+
+void UniqueIDBDatabase::confirmDidCloseFromServer(UniqueIDBDatabaseConnection& connection)
+{
+    ASSERT(isMainThread());
+    LOG(IndexedDB, "UniqueIDBDatabase::confirmDidCloseFromServer - %s (%" PRIu64 ")", connection.openRequestIdentifier().loggingString().utf8().data(), connection.identifier());
+
+    ASSERT(m_serverClosePendingDatabaseConnections.contains(&connection));
+    m_serverClosePendingDatabaseConnections.remove(&connection);
+}
+
 void UniqueIDBDatabase::enqueueTransaction(Ref<UniqueIDBDatabaseTransaction>&& transaction)
 {
     LOG(IndexedDB, "UniqueIDBDatabase::enqueueTransaction - %s", transaction->info().loggingString().utf8().data());
+    ASSERT(!m_hardClosedForUserDelete);
 
     ASSERT(transaction->info().mode() != IndexedDB::TransactionMode::VersionChange);
 
@@ -1198,7 +1280,7 @@ void UniqueIDBDatabase::enqueueTransaction(Ref<UniqueIDBDatabaseTransaction>&& t
 
 bool UniqueIDBDatabase::isCurrentlyInUse() const
 {
-    return !m_openDatabaseConnections.isEmpty() || !m_closePendingDatabaseConnections.isEmpty() || !m_pendingOpenDBRequests.isEmpty() || m_currentOpenDBRequest || m_versionChangeDatabaseConnection || m_versionChangeTransaction || m_isOpeningBackingStore || m_deleteBackingStoreInProgress;
+    return !m_openDatabaseConnections.isEmpty() || !m_clientClosePendingDatabaseConnections.isEmpty() || !m_pendingOpenDBRequests.isEmpty() || m_currentOpenDBRequest || m_versionChangeDatabaseConnection || m_versionChangeTransaction || m_isOpeningBackingStore || m_deleteBackingStoreInProgress;
 }
 
 bool UniqueIDBDatabase::hasUnfinishedTransactions() const
@@ -1209,6 +1291,8 @@ bool UniqueIDBDatabase::hasUnfinishedTransactions() const
 void UniqueIDBDatabase::invokeOperationAndTransactionTimer()
 {
     LOG(IndexedDB, "UniqueIDBDatabase::invokeOperationAndTransactionTimer()");
+    ASSERT(!m_hardClosedForUserDelete);
+
     if (!m_operationAndTransactionTimer.isActive())
         m_operationAndTransactionTimer.startOneShot(0);
 }
@@ -1216,6 +1300,7 @@ void UniqueIDBDatabase::invokeOperationAndTransactionTimer()
 void UniqueIDBDatabase::operationAndTransactionTimerFired()
 {
     LOG(IndexedDB, "(main) UniqueIDBDatabase::operationAndTransactionTimerFired");
+    ASSERT(!m_hardClosedForUserDelete);
 
     RefPtr<UniqueIDBDatabase> protectedThis(this);
 
@@ -1268,7 +1353,9 @@ void UniqueIDBDatabase::activateTransactionInBackingStore(UniqueIDBDatabaseTrans
         refTransaction->didActivateInBackingStore(error);
     };
 
-    uint64_t callbackID = storeCallback(callback);
+    uint64_t callbackID = storeCallbackOrFireError(callback);
+    if (!callbackID)
+        return;
     postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performActivateTransactionInBackingStore, callbackID, transaction.info()));
 }
 
@@ -1373,26 +1460,28 @@ void UniqueIDBDatabase::transactionCompleted(RefPtr<UniqueIDBDatabaseTransaction
     }
 
     if (!transaction->databaseConnection().hasNonFinishedTransactions())
-        m_closePendingDatabaseConnections.remove(&transaction->databaseConnection());
+        m_clientClosePendingDatabaseConnections.remove(&transaction->databaseConnection());
 
     if (m_versionChangeTransaction == transaction)
         m_versionChangeTransaction = nullptr;
 
     // It's possible that this database had its backing store deleted but there were a few outstanding asynchronous operations.
     // If this transaction completing was the last of those operations, we can finally delete this UniqueIDBDatabase.
-    if (m_closePendingDatabaseConnections.isEmpty() && m_pendingOpenDBRequests.isEmpty() && !m_databaseInfo) {
+    if (m_clientClosePendingDatabaseConnections.isEmpty() && m_pendingOpenDBRequests.isEmpty() && !m_databaseInfo) {
         m_server.closeUniqueIDBDatabase(*this);
         return;
     }
 
     // Previously blocked operations might be runnable.
-    invokeOperationAndTransactionTimer();
+    if (!m_hardClosedForUserDelete)
+        invokeOperationAndTransactionTimer();
 }
 
 void UniqueIDBDatabase::postDatabaseTask(std::unique_ptr<CrossThreadTask>&& task)
 {
     ASSERT(isMainThread());
     m_databaseQueue.append(WTFMove(task));
+    ++m_queuedTaskCount;
 
     m_server.postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::executeNextDatabaseTask));
 }
@@ -1401,6 +1490,7 @@ void UniqueIDBDatabase::postDatabaseTaskReply(std::unique_ptr<CrossThreadTask>&&
 {
     ASSERT(!isMainThread());
     m_databaseReplyQueue.append(WTFMove(task));
+    ++m_queuedTaskCount;
 
     m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::executeNextDatabaseTaskReply));
 }
@@ -1408,49 +1498,147 @@ void UniqueIDBDatabase::postDatabaseTaskReply(std::unique_ptr<CrossThreadTask>&&
 void UniqueIDBDatabase::executeNextDatabaseTask()
 {
     ASSERT(!isMainThread());
+    ASSERT(m_queuedTaskCount);
 
     auto task = m_databaseQueue.tryGetMessage();
     ASSERT(task);
 
     task->performTask();
+    --m_queuedTaskCount;
 }
 
 void UniqueIDBDatabase::executeNextDatabaseTaskReply()
 {
     ASSERT(isMainThread());
+    ASSERT(m_queuedTaskCount);
 
     auto task = m_databaseReplyQueue.tryGetMessage();
     ASSERT(task);
 
     task->performTask();
+    --m_queuedTaskCount;
+
+    // If this database was force closed (e.g. for a user delete) and there are no more
+    // queued tasks left, delete this.
+    if (m_hardCloseProtector && doneWithHardClose())
+        m_hardCloseProtector = nullptr;
+}
+
+bool UniqueIDBDatabase::doneWithHardClose()
+{
+    return (!m_queuedTaskCount && m_serverClosePendingDatabaseConnections.isEmpty());
+}
+
+static void errorOpenDBRequestForUserDelete(ServerOpenDBRequest& request)
+{
+    auto result = IDBResultData::error(request.requestData().requestIdentifier(), IDBError::userDeleteError());
+    if (request.isOpenRequest())
+        request.connection().didOpenDatabase(result);
+    else
+        request.connection().didDeleteDatabase(result);
+}
+
+void UniqueIDBDatabase::immediateCloseForUserDelete()
+{
+    LOG(IndexedDB, "UniqueIDBDatabase::immediateCloseForUserDelete - Cancelling (%i, %i, %i, %i) callbacks", m_errorCallbacks.size(), m_keyDataCallbacks.size(), m_getResultCallbacks.size(), m_countCallbacks.size());
+
+    // Error out all transactions
+    Vector<IDBResourceIdentifier> inProgressIdentifiers;
+    copyKeysToVector(m_inProgressTransactions, inProgressIdentifiers);
+    for (auto& identifier : inProgressIdentifiers)
+        m_inProgressTransactions.get(identifier)->abortWithoutCallback();
+
+    ASSERT(m_inProgressTransactions.isEmpty());
+
+    m_pendingTransactions.clear();
+    m_objectStoreTransactionCounts.clear();
+    m_objectStoreWriteTransactions.clear();
+
+    // Error out all pending callbacks
+    Vector<uint64_t> callbackIdentifiers;
+    IDBError error = IDBError::userDeleteError();
+    IDBKeyData keyData;
+    IDBGetResult getResult;
+
+    copyKeysToVector(m_errorCallbacks, callbackIdentifiers);
+    for (auto identifier : callbackIdentifiers)
+        performErrorCallback(identifier, error);
+
+    callbackIdentifiers.clear();
+    copyKeysToVector(m_keyDataCallbacks, callbackIdentifiers);
+    for (auto identifier : callbackIdentifiers)
+        performKeyDataCallback(identifier, error, keyData);
+
+    callbackIdentifiers.clear();
+    copyKeysToVector(m_getResultCallbacks, callbackIdentifiers);
+    for (auto identifier : callbackIdentifiers)
+        performGetResultCallback(identifier, error, getResult);
+
+    callbackIdentifiers.clear();
+    copyKeysToVector(m_countCallbacks, callbackIdentifiers);
+    for (auto identifier : callbackIdentifiers)
+        performCountCallback(identifier, error, 0);
+
+    // Error out all IDBOpenDBRequests
+    if (m_currentOpenDBRequest) {
+        errorOpenDBRequestForUserDelete(*m_currentOpenDBRequest);
+        m_currentOpenDBRequest = nullptr;
+    }
+
+    for (auto& request : m_pendingOpenDBRequests)
+        errorOpenDBRequestForUserDelete(*request);
+
+    m_pendingOpenDBRequests.clear();
+
+    // Close all open connections
+    ListHashSet<RefPtr<UniqueIDBDatabaseConnection>> openDatabaseConnections = m_openDatabaseConnections;
+    for (auto& connection : openDatabaseConnections)
+        connectionClosedFromServer(*connection);
+
+    // Cancel the operation timer
+    m_operationAndTransactionTimer.stop();
+
+    // Set up the database to remain alive-but-inert until all of its background activity finishes and all
+    // database connections confirm that they have closed.
+    m_hardClosedForUserDelete = true;
+    if (!doneWithHardClose())
+        m_hardCloseProtector = this;
+
+    // Remove the database from the IDBServer's set of open databases.
+    // If there is no in-progress background thread activity for this database, it will be deleted here.
+    m_server.closeUniqueIDBDatabase(*this);
 }
 
 void UniqueIDBDatabase::performErrorCallback(uint64_t callbackIdentifier, const IDBError& error)
 {
     auto callback = m_errorCallbacks.take(callbackIdentifier);
-    ASSERT(callback);
-    callback(error);
+    ASSERT(callback || m_hardClosedForUserDelete);
+    if (callback)
+        callback(error);
 }
 
 void UniqueIDBDatabase::performKeyDataCallback(uint64_t callbackIdentifier, const IDBError& error, const IDBKeyData& resultKey)
 {
     auto callback = m_keyDataCallbacks.take(callbackIdentifier);
-    ASSERT(callback);
-    callback(error, resultKey);
+    ASSERT(callback || m_hardClosedForUserDelete);
+    if (callback)
+        callback(error, resultKey);
 }
 
 void UniqueIDBDatabase::performGetResultCallback(uint64_t callbackIdentifier, const IDBError& error, const IDBGetResult& resultData)
 {
     auto callback = m_getResultCallbacks.take(callbackIdentifier);
-    ASSERT(callback);
-    callback(error, resultData);
+    ASSERT(callback || m_hardClosedForUserDelete);
+    if (callback)
+        callback(error, resultData);
 }
 
 void UniqueIDBDatabase::performCountCallback(uint64_t callbackIdentifier, const IDBError& error, uint64_t count)
 {
     auto callback = m_countCallbacks.take(callbackIdentifier);
-    ASSERT(callback);
-    callback(error, count);
+    ASSERT(callback || m_hardClosedForUserDelete);
+    if (callback)
+        callback(error, count);
 }
 
 void UniqueIDBDatabase::forgetErrorCallback(uint64_t callbackIdentifier)
index ac84625..ae504d6 100644 (file)
@@ -101,12 +101,15 @@ public:
     void didFinishHandlingVersionChange(UniqueIDBDatabaseConnection&, const IDBResourceIdentifier& transactionIdentifier);
     void transactionDestroyed(UniqueIDBDatabaseTransaction&);
     void connectionClosedFromClient(UniqueIDBDatabaseConnection&);
+    void confirmConnectionClosedOnServer(UniqueIDBDatabaseConnection&);
     void didFireVersionChangeEvent(UniqueIDBDatabaseConnection&, const IDBResourceIdentifier& requestIdentifier);
     void openDBRequestCancelled(const IDBResourceIdentifier& requestIdentifier);
+    void confirmDidCloseFromServer(UniqueIDBDatabaseConnection&);
 
     void enqueueTransaction(Ref<UniqueIDBDatabaseTransaction>&&);
 
     void handleDelete(IDBConnectionToClient&, const IDBRequestData&);
+    void immediateCloseForUserDelete();
 
     static JSC::VM& databaseThreadVM();
     static JSC::ExecState& databaseThreadExecState();
@@ -129,6 +132,8 @@ private:
     void activateTransactionInBackingStore(UniqueIDBDatabaseTransaction&);
     void transactionCompleted(RefPtr<UniqueIDBDatabaseTransaction>&&);
 
+    void connectionClosedFromServer(UniqueIDBDatabaseConnection&);
+
     // Database thread operations
     void deleteBackingStore(const IDBDatabaseIdentifier&);
     void openBackingStore(const IDBDatabaseIdentifier&);
@@ -167,10 +172,10 @@ private:
     void didPerformAbortTransaction(uint64_t callbackIdentifier, const IDBError&, const IDBResourceIdentifier& transactionIdentifier);
     void didPerformActivateTransactionInBackingStore(uint64_t callbackIdentifier, const IDBError&);
 
-    uint64_t storeCallback(ErrorCallback);
-    uint64_t storeCallback(KeyDataCallback);
-    uint64_t storeCallback(GetResultCallback);
-    uint64_t storeCallback(CountCallback);
+    uint64_t storeCallbackOrFireError(ErrorCallback);
+    uint64_t storeCallbackOrFireError(KeyDataCallback);
+    uint64_t storeCallbackOrFireError(GetResultCallback);
+    uint64_t storeCallbackOrFireError(CountCallback);
 
     void performErrorCallback(uint64_t callbackIdentifier, const IDBError&);
     void performKeyDataCallback(uint64_t callbackIdentifier, const IDBError&, const IDBKeyData&);
@@ -194,6 +199,8 @@ private:
     void executeNextDatabaseTask();
     void executeNextDatabaseTaskReply();
 
+    bool doneWithHardClose();
+
     IDBServer& m_server;
     IDBDatabaseIdentifier m_identifier;
     
@@ -201,7 +208,8 @@ private:
     RefPtr<ServerOpenDBRequest> m_currentOpenDBRequest;
 
     ListHashSet<RefPtr<UniqueIDBDatabaseConnection>> m_openDatabaseConnections;
-    HashSet<RefPtr<UniqueIDBDatabaseConnection>> m_closePendingDatabaseConnections;
+    HashSet<RefPtr<UniqueIDBDatabaseConnection>> m_clientClosePendingDatabaseConnections;
+    HashSet<RefPtr<UniqueIDBDatabaseConnection>> m_serverClosePendingDatabaseConnections;
 
     RefPtr<UniqueIDBDatabaseConnection> m_versionChangeDatabaseConnection;
     RefPtr<UniqueIDBDatabaseTransaction> m_versionChangeTransaction;
@@ -235,6 +243,10 @@ private:
 
     MessageQueue<CrossThreadTask> m_databaseQueue;
     MessageQueue<CrossThreadTask> m_databaseReplyQueue;
+    std::atomic<uint64_t> m_queuedTaskCount { 0 };
+
+    bool m_hardClosedForUserDelete { false };
+    RefPtr<UniqueIDBDatabase> m_hardCloseProtector;
 };
 
 } // namespace IDBServer
index 62e0fa5..9b847a4 100644 (file)
@@ -89,6 +89,13 @@ void UniqueIDBDatabaseConnection::connectionClosedFromClient()
     m_database.connectionClosedFromClient(*this);
 }
 
+void UniqueIDBDatabaseConnection::confirmDidCloseFromServer()
+{
+    LOG(IndexedDB, "UniqueIDBDatabaseConnection::confirmDidCloseFromServer - %s - %" PRIu64, m_openRequestIdentifier.loggingString().utf8().data(), m_identifier);
+
+    m_database.confirmDidCloseFromServer(*this);
+}
+
 void UniqueIDBDatabaseConnection::didFireVersionChangeEvent(const IDBResourceIdentifier& requestIdentifier)
 {
     LOG(IndexedDB, "UniqueIDBDatabaseConnection::didFireVersionChangeEvent - %s - %" PRIu64, m_openRequestIdentifier.loggingString().utf8().data(), m_identifier);
index ed12349..5aa0287 100644 (file)
@@ -74,6 +74,7 @@ public:
     void didDeleteIndex(const IDBResultData&);
     void didFireVersionChangeEvent(const IDBResourceIdentifier& requestIdentifier);
     void didFinishHandlingVersionChange(const IDBResourceIdentifier& transactionIdentifier);
+    void confirmDidCloseFromServer();
 
     void abortTransactionWithoutCallback(UniqueIDBDatabaseTransaction&);
 
index af510b1..89b120f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015, 2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -65,6 +65,11 @@ String IDBError::message() const
     return IDBDatabaseException::getErrorDescription(m_code);
 }
 
+RefPtr<DOMError> IDBError::toDOMError() const
+{
+    return DOMError::create(IDBDatabaseException::getErrorName(m_code), m_message);
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(INDEXED_DATABASE)
index 1ee9b5d..2ca5bc1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015, 2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef IDBError_h
-#define IDBError_h
+#pragma once
 
 #if ENABLE(INDEXED_DATABASE)
 
+#include "DOMError.h"
 #include "IDBDatabaseException.h"
 #include <wtf/text/WTFString.h>
 
@@ -39,8 +39,15 @@ public:
     IDBError(ExceptionCode);
     IDBError(ExceptionCode, const String& message);
 
+    static IDBError userDeleteError()
+    {
+        return { IDBDatabaseException::UnknownError, ASCIILiteral("Database deleted by request of the user") };
+    }
+
     IDBError& operator=(const IDBError&);
 
+    RefPtr<DOMError> toDOMError() const;
+
     ExceptionCode code() const { return m_code; }
     String name() const;
     String message() const;
@@ -78,4 +85,3 @@ bool IDBError::decode(Decoder& decoder, IDBError& error)
 } // namespace WebCore
 
 #endif // ENABLE(INDEXED_DATABASE)
-#endif // IDBError_h
index eda8783..8ea2976 100644 (file)
@@ -367,6 +367,15 @@ void InProcessIDBServer::didStartTransaction(const IDBResourceIdentifier& transa
     });
 }
 
+void InProcessIDBServer::didCloseFromServer(IDBServer::UniqueIDBDatabaseConnection& connection, const IDBError& error)
+{
+    RefPtr<InProcessIDBServer> protectedThis(this);
+    uint64_t databaseConnectionIdentifier = connection.identifier();
+    RunLoop::current().dispatch([this, protectedThis, databaseConnectionIdentifier, error] {
+        m_connectionToServer->didCloseFromServer(databaseConnectionIdentifier, error);
+    });
+}
+
 void InProcessIDBServer::notifyOpenDBRequestBlocked(const IDBResourceIdentifier& requestIdentifier, uint64_t oldVersion, uint64_t newVersion)
 {
     RefPtr<InProcessIDBServer> protectedThis(this);
@@ -407,6 +416,14 @@ void InProcessIDBServer::openDBRequestCancelled(const IDBRequestData& requestDat
     });
 }
 
+void InProcessIDBServer::confirmDidCloseFromServer(uint64_t databaseConnectionIdentifier)
+{
+    RefPtr<InProcessIDBServer> protectedThis(this);
+    RunLoop::current().dispatch([this, protectedThis, databaseConnectionIdentifier] {
+        m_server->confirmDidCloseFromServer(databaseConnectionIdentifier);
+    });
+}
+
 void InProcessIDBServer::getAllDatabaseNames(const SecurityOriginData& mainFrameOrigin, const SecurityOriginData& openingOrigin, uint64_t callbackID)
 {
     RefPtr<InProcessIDBServer> protectedThis(this);
index 1aced3f..ee5ed73 100644 (file)
@@ -52,6 +52,7 @@ public:
 
     WEBCORE_EXPORT IDBClient::IDBConnectionToServer& connectionToServer() const;
     IDBServer::IDBConnectionToClient& connectionToClient() const;
+    IDBServer::IDBServer& server() { return m_server.get(); }
 
     IDBServer::IDBServer& idbServer() { return m_server.get(); }
 
@@ -77,6 +78,7 @@ public:
     void abortOpenAndUpgradeNeeded(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& transactionIdentifier) final;
     void didFireVersionChangeEvent(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& requestIdentifier) final;
     void openDBRequestCancelled(const IDBRequestData&) final;
+    void confirmDidCloseFromServer(uint64_t databaseConnectionIdentifier) final;
     void getAllDatabaseNames(const SecurityOriginData& mainFrameOrigin, const SecurityOriginData& openingOrigin, uint64_t callbackID) final;
 
     // IDBConnectionToClient
@@ -98,6 +100,7 @@ public:
     void didIterateCursor(const IDBResultData&) final;
     void fireVersionChangeEvent(IDBServer::UniqueIDBDatabaseConnection&, const IDBResourceIdentifier& requestIdentifier, uint64_t requestedVersion) final;
     void didStartTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError&) final;
+    void didCloseFromServer(IDBServer::UniqueIDBDatabaseConnection&, const IDBError&) final;
     void notifyOpenDBRequestBlocked(const IDBResourceIdentifier& requestIdentifier, uint64_t oldVersion, uint64_t newVersion) final;
     void didGetAllDatabaseNames(uint64_t callbackID, const Vector<String>& databaseNames) final;
 
index 4ff334d..a0d739c 100644 (file)
@@ -85,6 +85,11 @@ CrossThreadCopierBase<false, false, ThreadSafeDataBuffer>::Type CrossThreadCopie
     return ThreadSafeDataBuffer(buffer);
 }
 
+CrossThreadCopierBase<false, false, std::chrono::system_clock::time_point>::Type CrossThreadCopierBase<false, false, std::chrono::system_clock::time_point>::copy(const std::chrono::system_clock::time_point& timePoint)
+{
+    return timePoint;
+}
+
 // Test CrossThreadCopier using COMPILE_ASSERT.
 
 // Verify that ThreadSafeRefCounted objects get handled correctly.
index 8494bf5..fa83c67 100644 (file)
@@ -160,6 +160,11 @@ template<> struct CrossThreadCopierBase<false, false, ThreadSafeDataBuffer> {
     static Type copy(const ThreadSafeDataBuffer&);
 };
 
+template<> struct CrossThreadCopierBase<false, false, std::chrono::system_clock::time_point> {
+    typedef std::chrono::system_clock::time_point Type;
+    static Type copy(const Type& source);
+};
+
 template<typename T>
 struct CrossThreadCopier : public CrossThreadCopierBase<CrossThreadCopierBaseHelper::IsEnumOrConvertibleToInteger<T>::value, CrossThreadCopierBaseHelper::IsThreadSafeRefCountedPointer<T>::value, T> {
 };
index c1ea944..698c96c 100644 (file)
@@ -1,5 +1,32 @@
 2016-05-18  Brady Eidson  <beidson@apple.com>
 
+        Modern IDB: Add support for server side closing of open database connections.
+        https://bugs.webkit.org/show_bug.cgi?id=157843
+
+        Reviewed by Alex Christensen.
+
+        - Implement the required IDB delegate code.
+        - Make DatabaseProcess::deleteWebsiteData call the right method in IDB server.
+
+        * DatabaseProcess/DatabaseProcess.cpp:
+        (WebKit::DatabaseProcess::deleteWebsiteData):
+
+        * DatabaseProcess/IndexedDB/WebIDBConnectionToClient.cpp:
+        (WebKit::WebIDBConnectionToClient::didGetRecord):
+        (WebKit::WebIDBConnectionToClient::didCloseFromServer):
+        (WebKit::WebIDBConnectionToClient::confirmDidCloseFromServer):
+        * DatabaseProcess/IndexedDB/WebIDBConnectionToClient.h:
+        * DatabaseProcess/IndexedDB/WebIDBConnectionToClient.messages.in:
+
+        * WebProcess/Databases/IndexedDB/WebIDBConnectionToServer.cpp:
+        (WebKit::WebIDBConnectionToServer::confirmDidCloseFromServer):
+        (WebKit::WebIDBConnectionToServer::didStartTransaction):
+        (WebKit::WebIDBConnectionToServer::didCloseFromServer):
+        * WebProcess/Databases/IndexedDB/WebIDBConnectionToServer.h:
+        * WebProcess/Databases/IndexedDB/WebIDBConnectionToServer.messages.in:
+
+2016-05-18  Brady Eidson  <beidson@apple.com>
+
         Modern IDB: Make TestRunner.clearAllDatabases also delete IndexedDB databases (once doing so is supported).
         https://bugs.webkit.org/show_bug.cgi?id=157823
 
index d0cbb46..118efbf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2014, 2015, 2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -259,13 +259,8 @@ void DatabaseProcess::deleteWebsiteData(WebCore::SessionID, OptionSet<WebsiteDat
     }));
 
 #if ENABLE(INDEXED_DATABASE)
-    if (websiteDataTypes.contains(WebsiteDataType::IndexedDBDatabases)) {
-        postDatabaseTask(std::make_unique<CrossThreadTask>([this, callbackAggregator, modifiedSince] {
-
-            deleteIndexedDatabaseEntriesModifiedSince(modifiedSince);
-            RunLoop::main().dispatch([callbackAggregator] { });
-        }));
-    }
+    if (websiteDataTypes.contains(WebsiteDataType::IndexedDBDatabases))
+        m_idbServer->closeAndDeleteDatabasesModifiedSince(modifiedSince, [callbackAggregator] { });
 #endif
 }
 
index d1c1b3d..750e46f 100644 (file)
@@ -127,6 +127,11 @@ void WebIDBConnectionToClient::didPutOrAdd(const WebCore::IDBResultData& resultD
 
 void WebIDBConnectionToClient::didGetRecord(const WebCore::IDBResultData& resultData)
 {
+    if (resultData.type() == IDBResultType::Error) {
+        send(Messages::WebIDBConnectionToServer::DidGetRecord(resultData));
+        return;
+    }
+
     auto& blobFilePaths = resultData.getResult().value().blobFilePaths();
     if (blobFilePaths.isEmpty()) {
         send(Messages::WebIDBConnectionToServer::DidGetRecord(resultData));
@@ -169,6 +174,11 @@ void WebIDBConnectionToClient::didStartTransaction(const WebCore::IDBResourceIde
     send(Messages::WebIDBConnectionToServer::DidStartTransaction(transactionIdentifier, error));
 }
 
+void WebIDBConnectionToClient::didCloseFromServer(WebCore::IDBServer::UniqueIDBDatabaseConnection& connection, const WebCore::IDBError& error)
+{
+    send(Messages::WebIDBConnectionToServer::DidCloseFromServer(connection.identifier(), error));
+}
+
 void WebIDBConnectionToClient::notifyOpenDBRequestBlocked(const WebCore::IDBResourceIdentifier& requestIdentifier, uint64_t oldVersion, uint64_t newVersion)
 {
     send(Messages::WebIDBConnectionToServer::NotifyOpenDBRequestBlocked(requestIdentifier, oldVersion, newVersion));
@@ -294,6 +304,11 @@ void WebIDBConnectionToClient::openDBRequestCancelled(const IDBRequestData& requ
     DatabaseProcess::singleton().idbServer().openDBRequestCancelled(requestData);
 }
 
+void WebIDBConnectionToClient::confirmDidCloseFromServer(uint64_t databaseConnectionIdentifier)
+{
+    DatabaseProcess::singleton().idbServer().confirmDidCloseFromServer(databaseConnectionIdentifier);
+}
+
 void WebIDBConnectionToClient::getAllDatabaseNames(uint64_t serverConnectionIdentifier, const WebCore::SecurityOriginData& topOrigin, const WebCore::SecurityOriginData& openingOrigin, uint64_t callbackID)
 {
     DatabaseProcess::singleton().idbServer().getAllDatabaseNames(serverConnectionIdentifier, topOrigin, openingOrigin, callbackID);
index ffb8096..9496c7d 100644 (file)
@@ -23,8 +23,7 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef WebIDBConnectionToClient_h
-#define WebIDBConnectionToClient_h
+#pragma once
 
 #if ENABLE(INDEXED_DATABASE)
 
@@ -76,6 +75,7 @@ public:
 
     void fireVersionChangeEvent(WebCore::IDBServer::UniqueIDBDatabaseConnection&, const WebCore::IDBResourceIdentifier& requestIdentifier, uint64_t requestedVersion) final;
     void didStartTransaction(const WebCore::IDBResourceIdentifier& transactionIdentifier, const WebCore::IDBError&) final;
+    void didCloseFromServer(WebCore::IDBServer::UniqueIDBDatabaseConnection&, const WebCore::IDBError&) final;
     void notifyOpenDBRequestBlocked(const WebCore::IDBResourceIdentifier& requestIdentifier, uint64_t oldVersion, uint64_t newVersion) final;
 
     void didGetAllDatabaseNames(uint64_t callbackID, const Vector<String>& databaseNames) final;
@@ -106,6 +106,7 @@ public:
     void abortOpenAndUpgradeNeeded(uint64_t databaseConnectionIdentifier, const WebCore::IDBResourceIdentifier& transactionIdentifier);
     void didFireVersionChangeEvent(uint64_t databaseConnectionIdentifier, const WebCore::IDBResourceIdentifier& requestIdentifier);
     void openDBRequestCancelled(const WebCore::IDBRequestData&);
+    void confirmDidCloseFromServer(uint64_t databaseConnectionIdentifier);
 
     void getAllDatabaseNames(uint64_t serverConnectionIdentifier, const WebCore::SecurityOriginData& topOrigin, const WebCore::SecurityOriginData& openingOrigin, uint64_t callbackID);
 
@@ -127,4 +128,3 @@ private:
 } // namespace WebKit
 
 #endif // ENABLE(INDEXED_DATABASE)
-#endif // WebIDBConnectionToClient_h
index ff92808..cc38538 100644 (file)
@@ -45,6 +45,7 @@ messages -> WebIDBConnectionToClient {
     AbortOpenAndUpgradeNeeded(uint64_t databaseConnectionIdentifier, WebCore::IDBResourceIdentifier transactionIdentifier);
     DidFireVersionChangeEvent(uint64_t databaseConnectionIdentifier, WebCore::IDBResourceIdentifier requestIdentifier);
     OpenDBRequestCancelled(WebCore::IDBRequestData requestData);
+    ConfirmDidCloseFromServer(uint64_t databaseConnectionIdentifier);
 
     GetAllDatabaseNames(uint64_t serverConnectionIdentifier, struct WebCore::SecurityOriginData topOrigin, struct WebCore::SecurityOriginData openingOrigin, uint64_t callbackID);
 }
index 507f266..8f9dcc5 100644 (file)
@@ -186,6 +186,11 @@ void WebIDBConnectionToServer::openDBRequestCancelled(const IDBRequestData& requ
     send(Messages::WebIDBConnectionToClient::OpenDBRequestCancelled(requestData));
 }
 
+void WebIDBConnectionToServer::confirmDidCloseFromServer(uint64_t databaseConnectionIdentifier)
+{
+    send(Messages::WebIDBConnectionToClient::ConfirmDidCloseFromServer(databaseConnectionIdentifier));
+}
+
 void WebIDBConnectionToServer::getAllDatabaseNames(const WebCore::SecurityOriginData& topOrigin, const WebCore::SecurityOriginData& openingOrigin, uint64_t callbackID)
 {
     send(Messages::WebIDBConnectionToClient::GetAllDatabaseNames(m_identifier, topOrigin, openingOrigin, callbackID));
@@ -282,11 +287,16 @@ void WebIDBConnectionToServer::fireVersionChangeEvent(uint64_t uniqueDatabaseCon
     m_connectionToServer->fireVersionChangeEvent(uniqueDatabaseConnectionIdentifier, requestIdentifier, requestedVersion);
 }
 
-void WebIDBConnectionToServer::didStartTransaction(const IDBResourceIdentifier& transactionIdentifier, const WebCore::IDBError& error)
+void WebIDBConnectionToServer::didStartTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError& error)
 {
     m_connectionToServer->didStartTransaction(transactionIdentifier, error);
 }
 
+void WebIDBConnectionToServer::didCloseFromServer(uint64_t databaseConnectionIdentifier, const IDBError& error)
+{
+    m_connectionToServer->didCloseFromServer(databaseConnectionIdentifier, error);
+}
+
 void WebIDBConnectionToServer::notifyOpenDBRequestBlocked(const IDBResourceIdentifier& requestIdentifier, uint64_t oldVersion, uint64_t newVersion)
 {
     m_connectionToServer->notifyOpenDBRequestBlocked(requestIdentifier, oldVersion, newVersion);
index 1164b56..05f396a 100644 (file)
@@ -23,8 +23,7 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef WebIDBConnectionToServer_h
-#define WebIDBConnectionToServer_h
+#pragma once
 
 #if ENABLE(INDEXED_DATABASE)
 
@@ -66,6 +65,7 @@ public:
     void abortOpenAndUpgradeNeeded(uint64_t databaseConnectionIdentifier, const WebCore::IDBResourceIdentifier& transactionIdentifier) final;
     void didFireVersionChangeEvent(uint64_t databaseConnectionIdentifier, const WebCore::IDBResourceIdentifier& requestIdentifier) final;
     void openDBRequestCancelled(const WebCore::IDBRequestData&) final;
+    void confirmDidCloseFromServer(uint64_t databaseConnectionIdentifier) final;
 
     void getAllDatabaseNames(const WebCore::SecurityOriginData& topOrigin, const WebCore::SecurityOriginData& openingOrigin, uint64_t callbackID) final;
 
@@ -91,6 +91,7 @@ public:
     void didIterateCursor(const WebCore::IDBResultData&);
     void fireVersionChangeEvent(uint64_t uniqueDatabaseConnectionIdentifier, const WebCore::IDBResourceIdentifier& requestIdentifier, uint64_t requestedVersion);
     void didStartTransaction(const WebCore::IDBResourceIdentifier& transactionIdentifier, const WebCore::IDBError&);
+    void didCloseFromServer(uint64_t databaseConnectionIdentifier, const WebCore::IDBError&);
     void notifyOpenDBRequestBlocked(const WebCore::IDBResourceIdentifier& requestIdentifier, uint64_t oldVersion, uint64_t newVersion);
     void didGetAllDatabaseNames(uint64_t callbackID, const Vector<String>& databaseNames);
 
@@ -109,4 +110,3 @@ private:
 } // namespace WebKit
 
 #endif // ENABLE(INDEXED_DATABASE)
-#endif // WebIDBConnectionToServer_h
index 65ec103..2d5be28 100644 (file)
@@ -42,6 +42,7 @@ messages -> WebIDBConnectionToServer {
 
     FireVersionChangeEvent(uint64_t databaseConnectionIdentifier, WebCore::IDBResourceIdentifier requestIdentifier, uint64_t requestedVersion)
     DidStartTransaction(WebCore::IDBResourceIdentifier transactionIdentifier, WebCore::IDBError error)
+    DidCloseFromServer(uint64_t databaseConnectionIdentifier, WebCore::IDBError error) final;
     NotifyOpenDBRequestBlocked(WebCore::IDBResourceIdentifier requestIdentifier, uint64_t oldVersion, uint64_t newVersion)
 
     DidGetAllDatabaseNames(uint64_t callbackID, Vector<String> databaseNames)