<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[201098] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/201098">201098</a></dd>
<dt>Author</dt> <dd>beidson@apple.com</dd>
<dt>Date</dt> <dd>2016-05-18 13:42:20 -0700 (Wed, 18 May 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>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.

Source/WebCore:

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

In order to support deleting IndexedDB databases, the IDB server needs the ability to
&quot;immediately&quot; 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 &quot;in flight&quot; 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&gt;::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.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbIDBDatabasecpp">trunk/Source/WebCore/Modules/indexeddb/IDBDatabase.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbIDBDatabaseh">trunk/Source/WebCore/Modules/indexeddb/IDBDatabase.h</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbIDBDatabaseIdentifierh">trunk/Source/WebCore/Modules/indexeddb/IDBDatabaseIdentifier.h</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbIDBTransactioncpp">trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbIDBTransactionh">trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.h</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbclientIDBConnectionProxycpp">trunk/Source/WebCore/Modules/indexeddb/client/IDBConnectionProxy.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbclientIDBConnectionProxyh">trunk/Source/WebCore/Modules/indexeddb/client/IDBConnectionProxy.h</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbclientIDBConnectionToServercpp">trunk/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServer.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbclientIDBConnectionToServerh">trunk/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServer.h</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbclientIDBConnectionToServerDelegateh">trunk/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServerDelegate.h</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbserverIDBConnectionToClientcpp">trunk/Source/WebCore/Modules/indexeddb/server/IDBConnectionToClient.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbserverIDBConnectionToClienth">trunk/Source/WebCore/Modules/indexeddb/server/IDBConnectionToClient.h</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbserverIDBConnectionToClientDelegateh">trunk/Source/WebCore/Modules/indexeddb/server/IDBConnectionToClientDelegate.h</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbserverIDBServercpp">trunk/Source/WebCore/Modules/indexeddb/server/IDBServer.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbserverIDBServerh">trunk/Source/WebCore/Modules/indexeddb/server/IDBServer.h</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbserverUniqueIDBDatabasecpp">trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbserverUniqueIDBDatabaseh">trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.h</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbserverUniqueIDBDatabaseConnectioncpp">trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabaseConnection.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbserverUniqueIDBDatabaseConnectionh">trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabaseConnection.h</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbsharedIDBErrorcpp">trunk/Source/WebCore/Modules/indexeddb/shared/IDBError.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbsharedIDBErrorh">trunk/Source/WebCore/Modules/indexeddb/shared/IDBError.h</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbsharedInProcessIDBServercpp">trunk/Source/WebCore/Modules/indexeddb/shared/InProcessIDBServer.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbsharedInProcessIDBServerh">trunk/Source/WebCore/Modules/indexeddb/shared/InProcessIDBServer.h</a></li>
<li><a href="#trunkSourceWebCoreplatformCrossThreadCopiercpp">trunk/Source/WebCore/platform/CrossThreadCopier.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformCrossThreadCopierh">trunk/Source/WebCore/platform/CrossThreadCopier.h</a></li>
<li><a href="#trunkSourceWebKit2ChangeLog">trunk/Source/WebKit2/ChangeLog</a></li>
<li><a href="#trunkSourceWebKit2DatabaseProcessDatabaseProcesscpp">trunk/Source/WebKit2/DatabaseProcess/DatabaseProcess.cpp</a></li>
<li><a href="#trunkSourceWebKit2DatabaseProcessIndexedDBWebIDBConnectionToClientcpp">trunk/Source/WebKit2/DatabaseProcess/IndexedDB/WebIDBConnectionToClient.cpp</a></li>
<li><a href="#trunkSourceWebKit2DatabaseProcessIndexedDBWebIDBConnectionToClienth">trunk/Source/WebKit2/DatabaseProcess/IndexedDB/WebIDBConnectionToClient.h</a></li>
<li><a href="#trunkSourceWebKit2DatabaseProcessIndexedDBWebIDBConnectionToClientmessagesin">trunk/Source/WebKit2/DatabaseProcess/IndexedDB/WebIDBConnectionToClient.messages.in</a></li>
<li><a href="#trunkSourceWebKit2WebProcessDatabasesIndexedDBWebIDBConnectionToServercpp">trunk/Source/WebKit2/WebProcess/Databases/IndexedDB/WebIDBConnectionToServer.cpp</a></li>
<li><a href="#trunkSourceWebKit2WebProcessDatabasesIndexedDBWebIDBConnectionToServerh">trunk/Source/WebKit2/WebProcess/Databases/IndexedDB/WebIDBConnectionToServer.h</a></li>
<li><a href="#trunkSourceWebKit2WebProcessDatabasesIndexedDBWebIDBConnectionToServermessagesin">trunk/Source/WebKit2/WebProcess/Databases/IndexedDB/WebIDBConnectionToServer.messages.in</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsstorageindexeddbmodernhandleuserdeleteexpectedtxt">trunk/LayoutTests/storage/indexeddb/modern/handle-user-delete-expected.txt</a></li>
<li><a href="#trunkLayoutTestsstorageindexeddbmodernhandleuserdeletehtml">trunk/LayoutTests/storage/indexeddb/modern/handle-user-delete.html</a></li>
<li><a href="#trunkLayoutTestsstorageindexeddbmodernresourceshandleuserdeletejs">trunk/LayoutTests/storage/indexeddb/modern/resources/handle-user-delete.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (201097 => 201098)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2016-05-18 20:21:31 UTC (rev 201097)
+++ trunk/LayoutTests/ChangeLog        2016-05-18 20:42:20 UTC (rev 201098)
</span><span class="lines">@@ -1,3 +1,14 @@
</span><ins>+2016-05-18  Brady Eidson  &lt;beidson@apple.com&gt;
+
+        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.
+
</ins><span class="cx"> 2016-05-18  Myles C. Maxfield  &lt;mmaxfield@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [OS X] Update platform/mac/fast/text/sticky-typesetting-features.html
</span></span></pre></div>
<a id="trunkLayoutTestsstorageindexeddbmodernhandleuserdeleteexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/storage/indexeddb/modern/handle-user-delete-expected.txt (0 => 201098)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/storage/indexeddb/modern/handle-user-delete-expected.txt                                (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/modern/handle-user-delete-expected.txt        2016-05-18 20:42:20 UTC (rev 201098)
</span><span class="lines">@@ -0,0 +1,19 @@
</span><ins>+Tests that expected errors come back from user delete.
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+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
+
</ins></span></pre></div>
<a id="trunkLayoutTestsstorageindexeddbmodernhandleuserdeletehtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/storage/indexeddb/modern/handle-user-delete.html (0 => 201098)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/storage/indexeddb/modern/handle-user-delete.html                                (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/modern/handle-user-delete.html        2016-05-18 20:42:20 UTC (rev 201098)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../../../resources/js-test.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../resources/shared.js&quot;&gt;&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+
+&lt;script src=&quot;resources/handle-user-delete.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsstorageindexeddbmodernresourceshandleuserdeletejs"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/storage/indexeddb/modern/resources/handle-user-delete.js (0 => 201098)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/storage/indexeddb/modern/resources/handle-user-delete.js                                (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/modern/resources/handle-user-delete.js        2016-05-18 20:42:20 UTC (rev 201098)
</span><span class="lines">@@ -0,0 +1,92 @@
</span><ins>+description(&quot;Tests that expected errors come back from user delete.&quot;);
+
+indexedDBTest(prepareDatabase);
+
+var requestErrorCount = 0;
+var databaseError = false;
+
+function done()
+{
+    if (requestErrorCount == 2)
+        log(&quot;[PASS] Both requests hit a failure condition (Received onerror or failed to start a new request because the transaction was aborted)&quot;);
+    else
+        log(&quot;[FAIL] &quot; + requestErrorCount + &quot; request(s) hit a failure condition.&quot;);
+
+    if (databaseError)
+        log(&quot;[PASS] Database received correct error.&quot;);
+    else
+        log(&quot;[FAIL] Database did not receive correct error.&quot;);
+        
+    finishJSTest();
+}
+
+function log(message)
+{
+    debug(message);
+}
+
+function maybeFinish()
+{
+    if (requestErrorCount == 2 &amp;&amp; databaseError)
+        done();
+}
+
+function prepareDatabase(event)
+{
+    log(&quot;Initial upgrade needed: Old version - &quot; + event.oldVersion + &quot; New version - &quot; + event.newVersion);
+
+    var versionTransaction = event.target.transaction;
+    var database = event.target.result;
+    var objectStore = database.createObjectStore(&quot;TestObjectStore&quot;);
+    objectStore.put(&quot;bar&quot;, &quot;foo&quot;);
+    
+    database.onerror = function(event) {
+        databaseError = true;
+        maybeFinish();
+    }
+
+    var hasClearedDatabases = false;
+    var spinGet = function() { 
+        try {
+            var req = objectStore.get(&quot;foo&quot;);
+        } catch(e) {
+            ++requestErrorCount;
+            maybeFinish();
+            return;   
+        }
+        req.onsuccess = function() {
+            spinGet();
+            if (!hasClearedDatabases) {
+                if (window.testRunner) {
+                    setTimeout(&quot;testRunner.clearAllDatabases();&quot;, 0);
+                    log(&quot;Requested clearAllDatabases&quot;);
+                }
+                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(&quot;Started two spinning requests&quot;)
+
+    versionTransaction.onabort = function(event) {
+        log(&quot;Initial upgrade versionchange transaction aborted: &quot; + versionTransaction.error);
+    }
+
+    versionTransaction.oncomplete = function() {
+        log(&quot;Initial upgrade versionchange transaction unexpected complete&quot;);
+        done();
+    }
+
+    versionTransaction.onerror = function(event) {
+        log(&quot;Initial upgrade versionchange transaction unexpected error: &quot; + event.type + &quot; &quot; + versionTransaction.error.name + &quot;, &quot; + versionTransaction.error.message);
+        done();
+    }
+}
</ins></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (201097 => 201098)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2016-05-18 20:21:31 UTC (rev 201097)
+++ trunk/Source/WebCore/ChangeLog        2016-05-18 20:42:20 UTC (rev 201098)
</span><span class="lines">@@ -1,3 +1,136 @@
</span><ins>+2016-05-18  Brady Eidson  &lt;beidson@apple.com&gt;
+
+        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 
+        &quot;immediately&quot; 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 &quot;in flight&quot; 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&gt;::copy):
+        * platform/CrossThreadCopier.h:
+
</ins><span class="cx"> 2016-05-18  Simon Fraser  &lt;simon.fraser@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         REGRESSION (r200534) Command-+ no longer zooms pages 
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbIDBDatabasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/IDBDatabase.cpp (201097 => 201098)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/IDBDatabase.cpp        2016-05-18 20:21:31 UTC (rev 201097)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBDatabase.cpp        2016-05-18 20:42:20 UTC (rev 201098)
</span><span class="lines">@@ -245,6 +245,25 @@
</span><span class="cx">     maybeCloseInServer();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void IDBDatabase::didCloseFromServer(const IDBError&amp; error)
+{
+    LOG(IndexedDB, &quot;IDBDatabase::didCloseFromServer - %&quot; PRIu64, m_databaseConnectionIdentifier);
+
+    ASSERT(currentThread() == m_originThreadID);
+
+    m_closePending = true;
+    m_closedInServer = true;
+
+    for (auto&amp; transaction : m_activeTransactions.values())
+        transaction-&gt;connectionClosedFromServer(error);
+
+    Ref&lt;Event&gt; event = Event::create(eventNames().errorEvent, true, false);
+    event-&gt;setTarget(this);
+    scriptExecutionContext()-&gt;eventQueue().enqueueEvent(WTFMove(event));
+
+    m_connectionProxy-&gt;confirmDidCloseFromServer(*this);
+}
+
</ins><span class="cx"> void IDBDatabase::maybeCloseInServer()
</span><span class="cx"> {
</span><span class="cx">     LOG(IndexedDB, &quot;IDBDatabase::maybeCloseInServer - %&quot; PRIu64, m_databaseConnectionIdentifier);
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbIDBDatabaseh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/IDBDatabase.h (201097 => 201098)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/IDBDatabase.h        2016-05-18 20:21:31 UTC (rev 201097)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBDatabase.h        2016-05-18 20:42:20 UTC (rev 201098)
</span><span class="lines">@@ -86,6 +86,7 @@
</span><span class="cx">     void didAbortTransaction(IDBTransaction&amp;);
</span><span class="cx"> 
</span><span class="cx">     void fireVersionChangeEvent(const IDBResourceIdentifier&amp; requestIdentifier, uint64_t requestedVersion);
</span><ins>+    void didCloseFromServer(const IDBError&amp;);
</ins><span class="cx"> 
</span><span class="cx">     IDBClient::IDBConnectionProxy&amp; connectionProxy() { return m_connectionProxy.get(); }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbIDBDatabaseIdentifierh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/IDBDatabaseIdentifier.h (201097 => 201098)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/IDBDatabaseIdentifier.h        2016-05-18 20:21:31 UTC (rev 201097)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBDatabaseIdentifier.h        2016-05-18 20:42:20 UTC (rev 201098)
</span><span class="lines">@@ -102,6 +102,11 @@
</span><span class="cx">     String debugString() const;
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+    bool isRelatedToOrigin(const SecurityOriginData&amp; other) const
+    {
+        return m_openingOrigin == other || m_mainFrameOrigin == other;
+    }
+
</ins><span class="cx"> private:
</span><span class="cx">     String m_databaseName;
</span><span class="cx">     SecurityOriginData m_openingOrigin;
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbIDBTransactioncpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.cpp (201097 => 201098)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.cpp        2016-05-18 20:21:31 UTC (rev 201097)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.cpp        2016-05-18 20:42:20 UTC (rev 201098)
</span><span class="lines">@@ -1075,6 +1075,29 @@
</span><span class="cx">     return m_database-&gt;originThreadID();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void IDBTransaction::connectionClosedFromServer(const IDBError&amp; error)
+{
+    LOG(IndexedDB, &quot;IDBTransaction::connectionClosedFromServer - %s&quot;, error.message().utf8().data());
+
+    m_state = IndexedDB::TransactionState::Aborting;
+
+    Vector&lt;RefPtr&lt;IDBClient::TransactionOperation&gt;&gt; operations;
+    copyValuesToVector(m_transactionOperationMap, operations);
+
+    for (auto&amp; operation : operations)
+        operation-&gt;completed(IDBResultData::error(operation-&gt;identifier(), error));
+
+    connectionProxy().forgetActiveOperations(operations);
+
+    m_transactionOperationQueue.clear();
+    m_abortQueue.clear();
+    m_transactionOperationMap.clear();
+
+    m_idbError = error;
+    m_domError = error.toDOMError();
+    fireOnAbort();
+}
+
</ins><span class="cx"> } // namespace WebCore
</span><span class="cx"> 
</span><span class="cx"> #endif // ENABLE(INDEXED_DATABASE)
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbIDBTransactionh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.h (201097 => 201098)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.h        2016-05-18 20:21:31 UTC (rev 201097)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.h        2016-05-18 20:42:20 UTC (rev 201098)
</span><span class="lines">@@ -145,6 +145,8 @@
</span><span class="cx"> 
</span><span class="cx">     ThreadIdentifier originThreadID() const;
</span><span class="cx"> 
</span><ins>+    void connectionClosedFromServer(const IDBError&amp;);
+
</ins><span class="cx"> private:
</span><span class="cx">     IDBTransaction(IDBDatabase&amp;, const IDBTransactionInfo&amp;, IDBOpenDBRequest*);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbclientIDBConnectionProxycpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/client/IDBConnectionProxy.cpp (201097 => 201098)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/client/IDBConnectionProxy.cpp        2016-05-18 20:21:31 UTC (rev 201097)
+++ trunk/Source/WebCore/Modules/indexeddb/client/IDBConnectionProxy.cpp        2016-05-18 20:42:20 UTC (rev 201098)
</span><span class="lines">@@ -249,7 +249,8 @@
</span><span class="cx">         operation = m_activeOperations.take(resultData.requestIdentifier());
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    ASSERT(operation);
</del><ins>+    if (!operation)
+        return;
</ins><span class="cx"> 
</span><span class="cx">     performCallbackOnCorrectThread(*operation, &amp;TransactionOperation::completed, resultData);
</span><span class="cx"> }
</span><span class="lines">@@ -388,6 +389,29 @@
</span><span class="cx">     callConnectionOnMainThread(&amp;IDBConnectionToServer::databaseConnectionClosed, database.databaseConnectionIdentifier());
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void IDBConnectionProxy::didCloseFromServer(uint64_t databaseConnectionIdentifier, const IDBError&amp; error)
+{
+    RefPtr&lt;IDBDatabase&gt; database;
+    {
+        Locker&lt;Lock&gt; 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, &amp;IDBDatabase::didCloseFromServer, error);
+}
+
+void IDBConnectionProxy::confirmDidCloseFromServer(IDBDatabase&amp; database)
+{
+    callConnectionOnMainThread(&amp;IDBConnectionToServer::confirmDidCloseFromServer, database.databaseConnectionIdentifier());
+}
+
</ins><span class="cx"> void IDBConnectionProxy::scheduleMainThreadTasks()
</span><span class="cx"> {
</span><span class="cx">     Locker&lt;Lock&gt; locker(m_mainThreadTaskLock);
</span><span class="lines">@@ -438,6 +462,14 @@
</span><span class="cx">     m_databaseConnectionMap.remove(database.databaseConnectionIdentifier());
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void IDBConnectionProxy::forgetActiveOperations(const Vector&lt;RefPtr&lt;TransactionOperation&gt;&gt;&amp; operations)
+{
+    Locker&lt;Lock&gt; locker(m_transactionOperationLock);
+
+    for (auto&amp; operation : operations)
+        m_activeOperations.remove(operation-&gt;identifier());
+}
+
</ins><span class="cx"> } // namesapce IDBClient
</span><span class="cx"> } // namespace WebCore
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbclientIDBConnectionProxyh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/client/IDBConnectionProxy.h (201097 => 201098)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/client/IDBConnectionProxy.h        2016-05-18 20:21:31 UTC (rev 201097)
+++ trunk/Source/WebCore/Modules/indexeddb/client/IDBConnectionProxy.h        2016-05-18 20:42:20 UTC (rev 201098)
</span><span class="lines">@@ -93,6 +93,9 @@
</span><span class="cx">     void didFinishHandlingVersionChangeTransaction(uint64_t databaseConnectionIdentifier, IDBTransaction&amp;);
</span><span class="cx">     void databaseConnectionClosed(IDBDatabase&amp;);
</span><span class="cx"> 
</span><ins>+    void didCloseFromServer(uint64_t databaseConnectionIdentifier, const IDBError&amp;);
+    void confirmDidCloseFromServer(IDBDatabase&amp;);
+
</ins><span class="cx">     void abortOpenAndUpgradeNeeded(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier&amp; transactionIdentifier);
</span><span class="cx"> 
</span><span class="cx">     void completeOperation(const IDBResultData&amp;);
</span><span class="lines">@@ -109,6 +112,8 @@
</span><span class="cx"> 
</span><span class="cx">     RefPtr&lt;IDBOpenDBRequest&gt; takeIDBOpenDBRequest(IDBOpenDBRequest&amp;);
</span><span class="cx"> 
</span><ins>+    void forgetActiveOperations(const Vector&lt;RefPtr&lt;TransactionOperation&gt;&gt;&amp;);
+
</ins><span class="cx"> private:
</span><span class="cx">     void completeOpenDBRequest(const IDBResultData&amp;);
</span><span class="cx">     bool hasRecordOfTransaction(const IDBTransaction&amp;) const;
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbclientIDBConnectionToServercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServer.cpp (201097 => 201098)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServer.cpp        2016-05-18 20:21:31 UTC (rev 201097)
+++ trunk/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServer.cpp        2016-05-18 20:42:20 UTC (rev 201098)
</span><span class="lines">@@ -316,6 +316,22 @@
</span><span class="cx">     m_proxy-&gt;didStartTransaction(transactionIdentifier, error);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void IDBConnectionToServer::didCloseFromServer(uint64_t databaseConnectionIdentifier, const IDBError&amp; error)
+{
+    LOG(IndexedDB, &quot;IDBConnectionToServer::didCloseFromServer&quot;);
+    ASSERT(isMainThread());
+
+    m_proxy-&gt;didCloseFromServer(databaseConnectionIdentifier, error);
+}
+
+void IDBConnectionToServer::confirmDidCloseFromServer(uint64_t databaseConnectionIdentifier)
+{
+    LOG(IndexedDB, &quot;IDBConnectionToServer::confirmDidCloseFromServer&quot;);
+    ASSERT(isMainThread());
+
+    m_delegate-&gt;confirmDidCloseFromServer(databaseConnectionIdentifier);
+}
+
</ins><span class="cx"> void IDBConnectionToServer::notifyOpenDBRequestBlocked(const IDBResourceIdentifier&amp; requestIdentifier, uint64_t oldVersion, uint64_t newVersion)
</span><span class="cx"> {
</span><span class="cx">     LOG(IndexedDB, &quot;IDBConnectionToServer::didStartTransaction&quot;);
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbclientIDBConnectionToServerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServer.h (201097 => 201098)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServer.h        2016-05-18 20:21:31 UTC (rev 201097)
+++ trunk/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServer.h        2016-05-18 20:42:20 UTC (rev 201098)
</span><span class="lines">@@ -106,6 +106,10 @@
</span><span class="cx">     void didFireVersionChangeEvent(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier&amp; requestIdentifier);
</span><span class="cx"> 
</span><span class="cx">     WEBCORE_EXPORT void didStartTransaction(const IDBResourceIdentifier&amp; transactionIdentifier, const IDBError&amp;);
</span><ins>+
+    WEBCORE_EXPORT void didCloseFromServer(uint64_t databaseConnectionIdentifier, const IDBError&amp;);
+    void confirmDidCloseFromServer(uint64_t databaseConnectionIdentifier);
+
</ins><span class="cx">     WEBCORE_EXPORT void notifyOpenDBRequestBlocked(const IDBResourceIdentifier&amp; requestIdentifier, uint64_t oldVersion, uint64_t newVersion);
</span><span class="cx">     void openDBRequestCancelled(const IDBRequestData&amp;);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbclientIDBConnectionToServerDelegateh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServerDelegate.h (201097 => 201098)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServerDelegate.h        2016-05-18 20:21:31 UTC (rev 201097)
+++ trunk/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServerDelegate.h        2016-05-18 20:42:20 UTC (rev 201098)
</span><span class="lines">@@ -77,6 +77,7 @@
</span><span class="cx">     virtual void abortOpenAndUpgradeNeeded(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier&amp; transactionIdentifier) = 0;
</span><span class="cx">     virtual void didFireVersionChangeEvent(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier&amp; requestIdentifier) = 0;
</span><span class="cx">     virtual void openDBRequestCancelled(const IDBRequestData&amp;) = 0;
</span><ins>+    virtual void confirmDidCloseFromServer(uint64_t databaseConnectionIdentifier) = 0;
</ins><span class="cx"> 
</span><span class="cx">     virtual void getAllDatabaseNames(const SecurityOriginData&amp; mainFrameOrigin, const SecurityOriginData&amp; openingOrigin, uint64_t callbackID) = 0;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbserverIDBConnectionToClientcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/server/IDBConnectionToClient.cpp (201097 => 201098)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/server/IDBConnectionToClient.cpp        2016-05-18 20:21:31 UTC (rev 201097)
+++ trunk/Source/WebCore/Modules/indexeddb/server/IDBConnectionToClient.cpp        2016-05-18 20:42:20 UTC (rev 201098)
</span><span class="lines">@@ -133,6 +133,11 @@
</span><span class="cx">     m_delegate-&gt;didStartTransaction(transactionIdentifier, error);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void IDBConnectionToClient::didCloseFromServer(UniqueIDBDatabaseConnection&amp; connection, const IDBError&amp; error)
+{
+    m_delegate-&gt;didCloseFromServer(connection, error);
+}
+
</ins><span class="cx"> void IDBConnectionToClient::notifyOpenDBRequestBlocked(const IDBResourceIdentifier&amp; requestIdentifier, uint64_t oldVersion, uint64_t newVersion)
</span><span class="cx"> {
</span><span class="cx">     m_delegate-&gt;notifyOpenDBRequestBlocked(requestIdentifier, oldVersion, newVersion);
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbserverIDBConnectionToClienth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/server/IDBConnectionToClient.h (201097 => 201098)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/server/IDBConnectionToClient.h        2016-05-18 20:21:31 UTC (rev 201097)
+++ trunk/Source/WebCore/Modules/indexeddb/server/IDBConnectionToClient.h        2016-05-18 20:42:20 UTC (rev 201098)
</span><span class="lines">@@ -66,6 +66,7 @@
</span><span class="cx"> 
</span><span class="cx">     void fireVersionChangeEvent(UniqueIDBDatabaseConnection&amp;, const IDBResourceIdentifier&amp; requestIdentifier, uint64_t requestedVersion);
</span><span class="cx">     void didStartTransaction(const IDBResourceIdentifier&amp; transactionIdentifier, const IDBError&amp;);
</span><ins>+    void didCloseFromServer(UniqueIDBDatabaseConnection&amp;, const IDBError&amp;);
</ins><span class="cx"> 
</span><span class="cx">     void notifyOpenDBRequestBlocked(const IDBResourceIdentifier&amp; requestIdentifier, uint64_t oldVersion, uint64_t newVersion);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbserverIDBConnectionToClientDelegateh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/server/IDBConnectionToClientDelegate.h (201097 => 201098)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/server/IDBConnectionToClientDelegate.h        2016-05-18 20:21:31 UTC (rev 201097)
+++ trunk/Source/WebCore/Modules/indexeddb/server/IDBConnectionToClientDelegate.h        2016-05-18 20:42:20 UTC (rev 201098)
</span><span class="lines">@@ -65,6 +65,7 @@
</span><span class="cx"> 
</span><span class="cx">     virtual void fireVersionChangeEvent(UniqueIDBDatabaseConnection&amp;, const IDBResourceIdentifier&amp; requestIdentifier, uint64_t requestedVersion) = 0;
</span><span class="cx">     virtual void didStartTransaction(const IDBResourceIdentifier&amp; transactionIdentifier, const IDBError&amp;) = 0;
</span><ins>+    virtual void didCloseFromServer(UniqueIDBDatabaseConnection&amp;, const IDBError&amp;) = 0;
</ins><span class="cx">     virtual void notifyOpenDBRequestBlocked(const IDBResourceIdentifier&amp; requestIdentifier, uint64_t oldVersion, uint64_t newVersion) = 0;
</span><span class="cx"> 
</span><span class="cx">     virtual void didGetAllDatabaseNames(uint64_t callbackID, const Vector&lt;String&gt;&amp; databaseNames) = 0;
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbserverIDBServercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/server/IDBServer.cpp (201097 => 201098)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/server/IDBServer.cpp        2016-05-18 20:21:31 UTC (rev 201097)
+++ trunk/Source/WebCore/Modules/indexeddb/server/IDBServer.cpp        2016-05-18 20:42:20 UTC (rev 201098)
</span><span class="lines">@@ -33,7 +33,9 @@
</span><span class="cx"> #include &quot;IDBResultData.h&quot;
</span><span class="cx"> #include &quot;Logging.h&quot;
</span><span class="cx"> #include &quot;MemoryIDBBackingStore.h&quot;
</span><ins>+#include &quot;SQLiteFileSystem.h&quot;
</ins><span class="cx"> #include &quot;SQLiteIDBBackingStore.h&quot;
</span><ins>+#include &quot;SecurityOrigin.h&quot;
</ins><span class="cx"> #include &lt;wtf/Locker.h&gt;
</span><span class="cx"> #include &lt;wtf/MainThread.h&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -388,6 +390,14 @@
</span><span class="cx">     uniqueIDBDatabase-&gt;openDBRequestCancelled(requestData.requestIdentifier());
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void IDBServer::confirmDidCloseFromServer(uint64_t databaseConnectionIdentifier)
+{
+    LOG(IndexedDB, &quot;IDBServer::confirmDidCloseFromServer&quot;);
+
+    if (auto databaseConnection = m_databaseConnections.get(databaseConnectionIdentifier))
+        databaseConnection-&gt;confirmDidCloseFromServer();
+}
+
</ins><span class="cx"> void IDBServer::getAllDatabaseNames(uint64_t serverConnectionIdentifier, const SecurityOriginData&amp; mainFrameOrigin, const SecurityOriginData&amp; openingOrigin, uint64_t callbackID)
</span><span class="cx"> {
</span><span class="cx">     postDatabaseTask(createCrossThreadTask(*this, &amp;IDBServer::performGetAllDatabaseNames, serverConnectionIdentifier, mainFrameOrigin, openingOrigin, callbackID));
</span><span class="lines">@@ -468,12 +478,77 @@
</span><span class="cx">         task-&gt;performTask();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void IDBServer::closeAndDeleteDatabasesModifiedSince(std::chrono::system_clock::time_point, std::function&lt;void ()&gt; completionHandler)
</del><ins>+static uint64_t generateDeleteCallbackID()
</ins><span class="cx"> {
</span><del>-    // FIXME: Implement (https://bugs.webkit.org/show_bug.cgi?id=157626)
-    completionHandler();
</del><ins>+    ASSERT(isMainThread());
+    static uint64_t currentID = 0;
+    return ++currentID;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void IDBServer::closeAndDeleteDatabasesModifiedSince(std::chrono::system_clock::time_point modificationTime, std::function&lt;void ()&gt; 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 &gt; std::chrono::system_clock::now()) {
+        postDatabaseTaskReply(createCrossThreadTask(*this, &amp;IDBServer::didPerformCloseAndDeleteDatabases, callbackID));
+        return;
+    }
+
+    HashSet&lt;UniqueIDBDatabase*&gt; openDatabases;
+    for (auto* connection : m_databaseConnections.values())
+        openDatabases.add(&amp;connection-&gt;database());
+
+    for (auto* database : openDatabases)
+        database-&gt;immediateCloseForUserDelete();
+
+    postDatabaseTask(createCrossThreadTask(*this, &amp;IDBServer::performCloseAndDeleteDatabasesModifiedSince, modificationTime, callbackID));
+}
+
+void IDBServer::closeAndDeleteDatabasesForOrigins(const Vector&lt;SecurityOriginData&gt;&amp; origins, std::function&lt;void ()&gt; completionHandler)
+{
+    uint64_t callbackID = generateDeleteCallbackID();
+    auto addResult = m_deleteDatabaseCompletionHandlers.add(callbackID, WTFMove(completionHandler));
+    ASSERT_UNUSED(addResult, addResult.isNewEntry);
+
+    HashSet&lt;UniqueIDBDatabase*&gt; openDatabases;
+    for (auto* connection : m_databaseConnections.values()) {
+        const auto&amp; identifier = connection-&gt;database().identifier();
+        for (auto&amp; origin : origins) {
+            if (identifier.isRelatedToOrigin(origin)) {
+                openDatabases.add(&amp;connection-&gt;database());
+                break;
+            }
+        }
+    }
+
+    for (auto* database : openDatabases)
+        database-&gt;immediateCloseForUserDelete();
+
+    postDatabaseTask(createCrossThreadTask(*this, &amp;IDBServer::performCloseAndDeleteDatabasesForOrigins, origins, callbackID));
+}
+
+void IDBServer::performCloseAndDeleteDatabasesModifiedSince(std::chrono::system_clock::time_point, uint64_t callbackID)
+{
+    // FIXME: Implement deleting the files.
+    postDatabaseTaskReply(createCrossThreadTask(*this, &amp;IDBServer::didPerformCloseAndDeleteDatabases, callbackID));
+}
+
+void IDBServer::performCloseAndDeleteDatabasesForOrigins(const Vector&lt;SecurityOriginData&gt;&amp;, uint64_t callbackID)
+{
+    // FIXME: Implement deleting the files.
+    postDatabaseTaskReply(createCrossThreadTask(*this, &amp;IDBServer::didPerformCloseAndDeleteDatabases, callbackID));
+}
+
+void IDBServer::didPerformCloseAndDeleteDatabases(uint64_t callbackID)
+{
+    auto callback = m_deleteDatabaseCompletionHandlers.take(callbackID);
+    ASSERT(callback);
+    callback();
+}
+
</ins><span class="cx"> } // namespace IDBServer
</span><span class="cx"> } // namespace WebCore
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbserverIDBServerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/server/IDBServer.h (201097 => 201098)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/server/IDBServer.h        2016-05-18 20:21:31 UTC (rev 201097)
+++ trunk/Source/WebCore/Modules/indexeddb/server/IDBServer.h        2016-05-18 20:42:20 UTC (rev 201098)
</span><span class="lines">@@ -81,6 +81,7 @@
</span><span class="cx">     WEBCORE_EXPORT void abortOpenAndUpgradeNeeded(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier&amp; transactionIdentifier);
</span><span class="cx">     WEBCORE_EXPORT void didFireVersionChangeEvent(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier&amp; requestIdentifier);
</span><span class="cx">     WEBCORE_EXPORT void openDBRequestCancelled(const IDBRequestData&amp;);
</span><ins>+    WEBCORE_EXPORT void confirmDidCloseFromServer(uint64_t databaseConnectionIdentifier);
</ins><span class="cx"> 
</span><span class="cx">     WEBCORE_EXPORT void getAllDatabaseNames(uint64_t serverConnectionIdentifier, const SecurityOriginData&amp; mainFrameOrigin, const SecurityOriginData&amp; openingOrigin, uint64_t callbackID);
</span><span class="cx"> 
</span><span class="lines">@@ -97,6 +98,7 @@
</span><span class="cx">     std::unique_ptr&lt;IDBBackingStore&gt; createBackingStore(const IDBDatabaseIdentifier&amp;);
</span><span class="cx"> 
</span><span class="cx">     WEBCORE_EXPORT void closeAndDeleteDatabasesModifiedSince(std::chrono::system_clock::time_point, std::function&lt;void ()&gt; completionHandler);
</span><ins>+    WEBCORE_EXPORT void closeAndDeleteDatabasesForOrigins(const Vector&lt;SecurityOriginData&gt;&amp;, std::function&lt;void ()&gt; completionHandler);
</ins><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     IDBServer(IDBBackingStoreTemporaryFileHandler&amp;);
</span><span class="lines">@@ -107,6 +109,10 @@
</span><span class="cx">     void performGetAllDatabaseNames(uint64_t serverConnectionIdentifier, const SecurityOriginData&amp; mainFrameOrigin, const SecurityOriginData&amp; openingOrigin, uint64_t callbackID);
</span><span class="cx">     void didGetAllDatabaseNames(uint64_t serverConnectionIdentifier, uint64_t callbackID, const Vector&lt;String&gt;&amp; databaseNames);
</span><span class="cx"> 
</span><ins>+    void performCloseAndDeleteDatabasesModifiedSince(std::chrono::system_clock::time_point, uint64_t callbackID);
+    void performCloseAndDeleteDatabasesForOrigins(const Vector&lt;SecurityOriginData&gt;&amp;, uint64_t callbackID);
+    void didPerformCloseAndDeleteDatabases(uint64_t callbackID);
+
</ins><span class="cx">     static void databaseThreadEntry(void*);
</span><span class="cx">     void databaseRunLoop();
</span><span class="cx">     void handleTaskRepliesOnMainThread();
</span><span class="lines">@@ -125,6 +131,8 @@
</span><span class="cx">     HashMap&lt;uint64_t, UniqueIDBDatabaseConnection*&gt; m_databaseConnections;
</span><span class="cx">     HashMap&lt;IDBResourceIdentifier, UniqueIDBDatabaseTransaction*&gt; m_transactions;
</span><span class="cx"> 
</span><ins>+    HashMap&lt;uint64_t, std::function&lt;void ()&gt;&gt; m_deleteDatabaseCompletionHandlers;
+
</ins><span class="cx">     String m_databaseDirectoryPath;
</span><span class="cx">     IDBBackingStoreTemporaryFileHandler&amp; m_backingStoreTemporaryFileHandler;
</span><span class="cx"> };
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbserverUniqueIDBDatabasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp (201097 => 201098)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp        2016-05-18 20:21:31 UTC (rev 201097)
+++ trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp        2016-05-18 20:42:20 UTC (rev 201098)
</span><span class="lines">@@ -47,7 +47,7 @@
</span><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> namespace IDBServer {
</span><del>-    
</del><ins>+
</ins><span class="cx"> UniqueIDBDatabase::UniqueIDBDatabase(IDBServer&amp; server, const IDBDatabaseIdentifier&amp; identifier)
</span><span class="cx">     : m_server(server)
</span><span class="cx">     , m_identifier(identifier)
</span><span class="lines">@@ -63,7 +63,8 @@
</span><span class="cx">     ASSERT(!hasUnfinishedTransactions());
</span><span class="cx">     ASSERT(m_pendingTransactions.isEmpty());
</span><span class="cx">     ASSERT(m_openDatabaseConnections.isEmpty());
</span><del>-    ASSERT(m_closePendingDatabaseConnections.isEmpty());
</del><ins>+    ASSERT(m_clientClosePendingDatabaseConnections.isEmpty());
+    ASSERT(m_serverClosePendingDatabaseConnections.isEmpty());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> const IDBDatabaseInfo&amp; UniqueIDBDatabase::info() const
</span><span class="lines">@@ -74,6 +75,9 @@
</span><span class="cx"> 
</span><span class="cx"> void UniqueIDBDatabase::openDatabaseConnection(IDBConnectionToClient&amp; connection, const IDBRequestData&amp; requestData)
</span><span class="cx"> {
</span><ins>+    LOG(IndexedDB, &quot;UniqueIDBDatabase::openDatabaseConnection&quot;);
+    ASSERT(!m_hardClosedForUserDelete);
+
</ins><span class="cx">     m_pendingOpenDBRequests.add(ServerOpenDBRequest::create(connection, requestData));
</span><span class="cx"> 
</span><span class="cx">     // An open operation is already in progress, so we can't possibly handle this one yet.
</span><span class="lines">@@ -271,7 +275,7 @@
</span><span class="cx"> 
</span><span class="cx">     m_deleteBackingStoreInProgress = false;
</span><span class="cx"> 
</span><del>-    if (m_closePendingDatabaseConnections.isEmpty() &amp;&amp; m_pendingOpenDBRequests.isEmpty()) {
</del><ins>+    if (m_clientClosePendingDatabaseConnections.isEmpty() &amp;&amp; m_pendingOpenDBRequests.isEmpty()) {
</ins><span class="cx">         m_server.closeUniqueIDBDatabase(*this);
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="lines">@@ -283,6 +287,7 @@
</span><span class="cx"> {
</span><span class="cx">     ASSERT(isMainThread());
</span><span class="cx">     LOG(IndexedDB, &quot;(main) UniqueIDBDatabase::handleDatabaseOperations - There are %u pending&quot;, m_pendingOpenDBRequests.size());
</span><ins>+    ASSERT(!m_hardClosedForUserDelete);
</ins><span class="cx"> 
</span><span class="cx">     if (m_deleteBackingStoreInProgress)
</span><span class="cx">         return;
</span><span class="lines">@@ -311,7 +316,7 @@
</span><span class="cx"> void UniqueIDBDatabase::handleCurrentOperation()
</span><span class="cx"> {
</span><span class="cx">     LOG(IndexedDB, &quot;(main) UniqueIDBDatabase::handleCurrentOperation&quot;);
</span><del>-
</del><ins>+    ASSERT(!m_hardClosedForUserDelete);
</ins><span class="cx">     ASSERT(m_currentOpenDBRequest);
</span><span class="cx"> 
</span><span class="cx">     RefPtr&lt;UniqueIDBDatabase&gt; protectedThis(this);
</span><span class="lines">@@ -339,32 +344,52 @@
</span><span class="cx">     return ++currentID;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-uint64_t UniqueIDBDatabase::storeCallback(ErrorCallback callback)
</del><ins>+uint64_t UniqueIDBDatabase::storeCallbackOrFireError(ErrorCallback callback)
</ins><span class="cx"> {
</span><ins>+    if (m_hardClosedForUserDelete) {
+        callback(IDBError::userDeleteError());
+        return 0;
+    }
+
</ins><span class="cx">     uint64_t identifier = generateUniqueCallbackIdentifier();
</span><span class="cx">     ASSERT(!m_errorCallbacks.contains(identifier));
</span><span class="cx">     m_errorCallbacks.add(identifier, callback);
</span><span class="cx">     return identifier;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-uint64_t UniqueIDBDatabase::storeCallback(KeyDataCallback callback)
</del><ins>+uint64_t UniqueIDBDatabase::storeCallbackOrFireError(KeyDataCallback callback)
</ins><span class="cx"> {
</span><ins>+    if (m_hardClosedForUserDelete) {
+        callback(IDBError::userDeleteError(), { });
+        return 0;
+    }
+
</ins><span class="cx">     uint64_t identifier = generateUniqueCallbackIdentifier();
</span><span class="cx">     ASSERT(!m_keyDataCallbacks.contains(identifier));
</span><span class="cx">     m_keyDataCallbacks.add(identifier, callback);
</span><span class="cx">     return identifier;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-uint64_t UniqueIDBDatabase::storeCallback(GetResultCallback callback)
</del><ins>+uint64_t UniqueIDBDatabase::storeCallbackOrFireError(GetResultCallback callback)
</ins><span class="cx"> {
</span><ins>+    if (m_hardClosedForUserDelete) {
+        callback(IDBError::userDeleteError(), { });
+        return 0;
+    }
+
</ins><span class="cx">     uint64_t identifier = generateUniqueCallbackIdentifier();
</span><span class="cx">     ASSERT(!m_getResultCallbacks.contains(identifier));
</span><span class="cx">     m_getResultCallbacks.add(identifier, callback);
</span><span class="cx">     return identifier;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-uint64_t UniqueIDBDatabase::storeCallback(CountCallback callback)
</del><ins>+uint64_t UniqueIDBDatabase::storeCallbackOrFireError(CountCallback callback)
</ins><span class="cx"> {
</span><ins>+    if (m_hardClosedForUserDelete) {
+        callback(IDBError::userDeleteError(), 0);
+        return 0;
+    }
+
</ins><span class="cx">     uint64_t identifier = generateUniqueCallbackIdentifier();
</span><span class="cx">     ASSERT(!m_countCallbacks.contains(identifier));
</span><span class="cx">     m_countCallbacks.add(identifier, callback);
</span><span class="lines">@@ -374,6 +399,7 @@
</span><span class="cx"> void UniqueIDBDatabase::handleDelete(IDBConnectionToClient&amp; connection, const IDBRequestData&amp; requestData)
</span><span class="cx"> {
</span><span class="cx">     LOG(IndexedDB, &quot;(main) UniqueIDBDatabase::handleDelete&quot;);
</span><ins>+    ASSERT(!m_hardClosedForUserDelete);
</ins><span class="cx"> 
</span><span class="cx">     m_pendingOpenDBRequests.add(ServerOpenDBRequest::create(connection, requestData));
</span><span class="cx">     handleDatabaseOperations();
</span><span class="lines">@@ -538,7 +564,10 @@
</span><span class="cx">     ASSERT(isMainThread());
</span><span class="cx">     LOG(IndexedDB, &quot;(main) UniqueIDBDatabase::createObjectStore&quot;);
</span><span class="cx"> 
</span><del>-    uint64_t callbackID = storeCallback(callback);
</del><ins>+    uint64_t callbackID = storeCallbackOrFireError(callback);
+    if (!callbackID)
+        return;
+
</ins><span class="cx">     postDatabaseTask(createCrossThreadTask(*this, &amp;UniqueIDBDatabase::performCreateObjectStore, callbackID, transaction.info().identifier(), info));
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -570,7 +599,9 @@
</span><span class="cx">     ASSERT(isMainThread());
</span><span class="cx">     LOG(IndexedDB, &quot;(main) UniqueIDBDatabase::deleteObjectStore&quot;);
</span><span class="cx"> 
</span><del>-    uint64_t callbackID = storeCallback(callback);
</del><ins>+    uint64_t callbackID = storeCallbackOrFireError(callback);
+    if (!callbackID)
+        return;
</ins><span class="cx"> 
</span><span class="cx">     auto* info = m_databaseInfo-&gt;infoForExistingObjectStore(objectStoreName);
</span><span class="cx">     if (!info) {
</span><span class="lines">@@ -609,7 +640,9 @@
</span><span class="cx">     ASSERT(isMainThread());
</span><span class="cx">     LOG(IndexedDB, &quot;(main) UniqueIDBDatabase::clearObjectStore&quot;);
</span><span class="cx"> 
</span><del>-    uint64_t callbackID = storeCallback(callback);
</del><ins>+    uint64_t callbackID = storeCallbackOrFireError(callback);
+    if (!callbackID)
+        return;
</ins><span class="cx">     postDatabaseTask(createCrossThreadTask(*this, &amp;UniqueIDBDatabase::performClearObjectStore, callbackID, transaction.info().identifier(), objectStoreIdentifier));
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -638,7 +671,9 @@
</span><span class="cx">     ASSERT(isMainThread());
</span><span class="cx">     LOG(IndexedDB, &quot;(main) UniqueIDBDatabase::createIndex&quot;);
</span><span class="cx"> 
</span><del>-    uint64_t callbackID = storeCallback(callback);
</del><ins>+    uint64_t callbackID = storeCallbackOrFireError(callback);
+    if (!callbackID)
+        return;
</ins><span class="cx">     postDatabaseTask(createCrossThreadTask(*this, &amp;UniqueIDBDatabase::performCreateIndex, callbackID, transaction.info().identifier(), info));
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -673,7 +708,9 @@
</span><span class="cx">     ASSERT(isMainThread());
</span><span class="cx">     LOG(IndexedDB, &quot;(main) UniqueIDBDatabase::deleteIndex&quot;);
</span><span class="cx"> 
</span><del>-    uint64_t callbackID = storeCallback(callback);
</del><ins>+    uint64_t callbackID = storeCallbackOrFireError(callback);
+    if (!callbackID)
+        return;
</ins><span class="cx"> 
</span><span class="cx">     auto* objectStoreInfo = m_databaseInfo-&gt;infoForExistingObjectStore(objectStoreIdentifier);
</span><span class="cx">     if (!objectStoreInfo) {
</span><span class="lines">@@ -721,7 +758,9 @@
</span><span class="cx">     ASSERT(isMainThread());
</span><span class="cx">     LOG(IndexedDB, &quot;(main) UniqueIDBDatabase::putOrAdd&quot;);
</span><span class="cx"> 
</span><del>-    uint64_t callbackID = storeCallback(callback);
</del><ins>+    uint64_t callbackID = storeCallbackOrFireError(callback);
+    if (!callbackID)
+        return;
</ins><span class="cx">     postDatabaseTask(createCrossThreadTask(*this, &amp;UniqueIDBDatabase::performPutOrAdd, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), keyData, value, overwriteMode));
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -857,7 +896,9 @@
</span><span class="cx">     ASSERT(isMainThread());
</span><span class="cx">     LOG(IndexedDB, &quot;(main) UniqueIDBDatabase::getRecord&quot;);
</span><span class="cx"> 
</span><del>-    uint64_t callbackID = storeCallback(callback);
</del><ins>+    uint64_t callbackID = storeCallbackOrFireError(callback);
+    if (!callbackID)
+        return;
</ins><span class="cx"> 
</span><span class="cx">     if (uint64_t indexIdentifier = requestData.indexIdentifier())
</span><span class="cx">         postDatabaseTask(createCrossThreadTask(*this, &amp;UniqueIDBDatabase::performGetIndexRecord, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), indexIdentifier, requestData.indexRecordType(), range));
</span><span class="lines">@@ -904,7 +945,9 @@
</span><span class="cx">     ASSERT(isMainThread());
</span><span class="cx">     LOG(IndexedDB, &quot;(main) UniqueIDBDatabase::getCount&quot;);
</span><span class="cx"> 
</span><del>-    uint64_t callbackID = storeCallback(callback);
</del><ins>+    uint64_t callbackID = storeCallbackOrFireError(callback);
+    if (!callbackID)
+        return;
</ins><span class="cx">     postDatabaseTask(createCrossThreadTask(*this, &amp;UniqueIDBDatabase::performGetCount, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), requestData.indexIdentifier(), range));
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -935,7 +978,9 @@
</span><span class="cx">     ASSERT(isMainThread());
</span><span class="cx">     LOG(IndexedDB, &quot;(main) UniqueIDBDatabase::deleteRecord&quot;);
</span><span class="cx"> 
</span><del>-    uint64_t callbackID = storeCallback(callback);
</del><ins>+    uint64_t callbackID = storeCallbackOrFireError(callback);
+    if (!callbackID)
+        return;
</ins><span class="cx">     postDatabaseTask(createCrossThreadTask(*this, &amp;UniqueIDBDatabase::performDeleteRecord, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), keyRangeData));
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -962,7 +1007,9 @@
</span><span class="cx">     ASSERT(isMainThread());
</span><span class="cx">     LOG(IndexedDB, &quot;(main) UniqueIDBDatabase::openCursor&quot;);
</span><span class="cx"> 
</span><del>-    uint64_t callbackID = storeCallback(callback);
</del><ins>+    uint64_t callbackID = storeCallbackOrFireError(callback);
+    if (!callbackID)
+        return;
</ins><span class="cx">     postDatabaseTask(createCrossThreadTask(*this, &amp;UniqueIDBDatabase::performOpenCursor, callbackID, requestData.transactionIdentifier(), info));
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -990,7 +1037,9 @@
</span><span class="cx">     ASSERT(isMainThread());
</span><span class="cx">     LOG(IndexedDB, &quot;(main) UniqueIDBDatabase::iterateCursor&quot;);
</span><span class="cx"> 
</span><del>-    uint64_t callbackID = storeCallback(callback);
</del><ins>+    uint64_t callbackID = storeCallbackOrFireError(callback);
+    if (!callbackID)
+        return;
</ins><span class="cx">     postDatabaseTask(createCrossThreadTask(*this, &amp;UniqueIDBDatabase::performIterateCursor, callbackID, requestData.transactionIdentifier(), requestData.cursorIdentifier(), key, count));
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -1032,7 +1081,9 @@
</span><span class="cx"> 
</span><span class="cx">     ASSERT(&amp;transaction.databaseConnection().database() == this);
</span><span class="cx"> 
</span><del>-    uint64_t callbackID = storeCallback(callback);
</del><ins>+    uint64_t callbackID = storeCallbackOrFireError(callback);
+    if (!callbackID)
+        return;
</ins><span class="cx"> 
</span><span class="cx">     if (!prepareToFinishTransaction(transaction)) {
</span><span class="cx">         if (!m_openDatabaseConnections.contains(&amp;transaction.databaseConnection())) {
</span><span class="lines">@@ -1074,7 +1125,9 @@
</span><span class="cx"> 
</span><span class="cx">     ASSERT(&amp;transaction.databaseConnection().database() == this);
</span><span class="cx"> 
</span><del>-    uint64_t callbackID = storeCallback(callback);
</del><ins>+    uint64_t callbackID = storeCallbackOrFireError(callback);
+    if (!callbackID)
+        return;
</ins><span class="cx"> 
</span><span class="cx">     if (!prepareToFinishTransaction(transaction)) {
</span><span class="cx">         if (!m_openDatabaseConnections.contains(&amp;transaction.databaseConnection())) {
</span><span class="lines">@@ -1149,7 +1202,7 @@
</span><span class="cx"> 
</span><span class="cx">     if (m_versionChangeDatabaseConnection == &amp;connection) {
</span><span class="cx">         if (m_versionChangeTransaction) {
</span><del>-            m_closePendingDatabaseConnections.add(WTFMove(m_versionChangeDatabaseConnection));
</del><ins>+            m_clientClosePendingDatabaseConnections.add(WTFMove(m_versionChangeDatabaseConnection));
</ins><span class="cx"> 
</span><span class="cx">             auto transactionIdentifier = m_versionChangeTransaction-&gt;info().identifier();
</span><span class="cx">             if (m_inProgressTransactions.contains(transactionIdentifier)) {
</span><span class="lines">@@ -1177,7 +1230,7 @@
</span><span class="cx">         notifyCurrentRequestConnectionClosedOrFiredVersionChangeEvent(connection.identifier());
</span><span class="cx"> 
</span><span class="cx">     if (connection.hasNonFinishedTransactions()) {
</span><del>-        m_closePendingDatabaseConnections.add(WTFMove(protectedConnection));
</del><ins>+        m_clientClosePendingDatabaseConnections.add(WTFMove(protectedConnection));
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -1185,9 +1238,38 @@
</span><span class="cx">     invokeOperationAndTransactionTimer();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void UniqueIDBDatabase::connectionClosedFromServer(UniqueIDBDatabaseConnection&amp; connection)
+{
+    ASSERT(isMainThread());
+    LOG(IndexedDB, &quot;UniqueIDBDatabase::connectionClosedFromServer - %s (%&quot; PRIu64 &quot;)&quot;, connection.openRequestIdentifier().loggingString().utf8().data(), connection.identifier());
+
+    if (m_clientClosePendingDatabaseConnections.contains(&amp;connection)) {
+        ASSERT(!m_openDatabaseConnections.contains(&amp;connection));
+        ASSERT(!m_serverClosePendingDatabaseConnections.contains(&amp;connection));
+        return;
+    }
+
+    Ref&lt;UniqueIDBDatabaseConnection&gt; protectedConnection(connection);
+    m_openDatabaseConnections.remove(&amp;connection);
+
+    connection.connectionToClient().didCloseFromServer(connection, IDBError::userDeleteError());
+
+    m_serverClosePendingDatabaseConnections.add(WTFMove(protectedConnection));
+}
+
+void UniqueIDBDatabase::confirmDidCloseFromServer(UniqueIDBDatabaseConnection&amp; connection)
+{
+    ASSERT(isMainThread());
+    LOG(IndexedDB, &quot;UniqueIDBDatabase::confirmDidCloseFromServer - %s (%&quot; PRIu64 &quot;)&quot;, connection.openRequestIdentifier().loggingString().utf8().data(), connection.identifier());
+
+    ASSERT(m_serverClosePendingDatabaseConnections.contains(&amp;connection));
+    m_serverClosePendingDatabaseConnections.remove(&amp;connection);
+}
+
</ins><span class="cx"> void UniqueIDBDatabase::enqueueTransaction(Ref&lt;UniqueIDBDatabaseTransaction&gt;&amp;&amp; transaction)
</span><span class="cx"> {
</span><span class="cx">     LOG(IndexedDB, &quot;UniqueIDBDatabase::enqueueTransaction - %s&quot;, transaction-&gt;info().loggingString().utf8().data());
</span><ins>+    ASSERT(!m_hardClosedForUserDelete);
</ins><span class="cx"> 
</span><span class="cx">     ASSERT(transaction-&gt;info().mode() != IndexedDB::TransactionMode::VersionChange);
</span><span class="cx"> 
</span><span class="lines">@@ -1198,7 +1280,7 @@
</span><span class="cx"> 
</span><span class="cx"> bool UniqueIDBDatabase::isCurrentlyInUse() const
</span><span class="cx"> {
</span><del>-    return !m_openDatabaseConnections.isEmpty() || !m_closePendingDatabaseConnections.isEmpty() || !m_pendingOpenDBRequests.isEmpty() || m_currentOpenDBRequest || m_versionChangeDatabaseConnection || m_versionChangeTransaction || m_isOpeningBackingStore || m_deleteBackingStoreInProgress;
</del><ins>+    return !m_openDatabaseConnections.isEmpty() || !m_clientClosePendingDatabaseConnections.isEmpty() || !m_pendingOpenDBRequests.isEmpty() || m_currentOpenDBRequest || m_versionChangeDatabaseConnection || m_versionChangeTransaction || m_isOpeningBackingStore || m_deleteBackingStoreInProgress;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool UniqueIDBDatabase::hasUnfinishedTransactions() const
</span><span class="lines">@@ -1209,6 +1291,8 @@
</span><span class="cx"> void UniqueIDBDatabase::invokeOperationAndTransactionTimer()
</span><span class="cx"> {
</span><span class="cx">     LOG(IndexedDB, &quot;UniqueIDBDatabase::invokeOperationAndTransactionTimer()&quot;);
</span><ins>+    ASSERT(!m_hardClosedForUserDelete);
+
</ins><span class="cx">     if (!m_operationAndTransactionTimer.isActive())
</span><span class="cx">         m_operationAndTransactionTimer.startOneShot(0);
</span><span class="cx"> }
</span><span class="lines">@@ -1216,6 +1300,7 @@
</span><span class="cx"> void UniqueIDBDatabase::operationAndTransactionTimerFired()
</span><span class="cx"> {
</span><span class="cx">     LOG(IndexedDB, &quot;(main) UniqueIDBDatabase::operationAndTransactionTimerFired&quot;);
</span><ins>+    ASSERT(!m_hardClosedForUserDelete);
</ins><span class="cx"> 
</span><span class="cx">     RefPtr&lt;UniqueIDBDatabase&gt; protectedThis(this);
</span><span class="cx"> 
</span><span class="lines">@@ -1268,7 +1353,9 @@
</span><span class="cx">         refTransaction-&gt;didActivateInBackingStore(error);
</span><span class="cx">     };
</span><span class="cx"> 
</span><del>-    uint64_t callbackID = storeCallback(callback);
</del><ins>+    uint64_t callbackID = storeCallbackOrFireError(callback);
+    if (!callbackID)
+        return;
</ins><span class="cx">     postDatabaseTask(createCrossThreadTask(*this, &amp;UniqueIDBDatabase::performActivateTransactionInBackingStore, callbackID, transaction.info()));
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -1373,26 +1460,28 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (!transaction-&gt;databaseConnection().hasNonFinishedTransactions())
</span><del>-        m_closePendingDatabaseConnections.remove(&amp;transaction-&gt;databaseConnection());
</del><ins>+        m_clientClosePendingDatabaseConnections.remove(&amp;transaction-&gt;databaseConnection());
</ins><span class="cx"> 
</span><span class="cx">     if (m_versionChangeTransaction == transaction)
</span><span class="cx">         m_versionChangeTransaction = nullptr;
</span><span class="cx"> 
</span><span class="cx">     // It's possible that this database had its backing store deleted but there were a few outstanding asynchronous operations.
</span><span class="cx">     // If this transaction completing was the last of those operations, we can finally delete this UniqueIDBDatabase.
</span><del>-    if (m_closePendingDatabaseConnections.isEmpty() &amp;&amp; m_pendingOpenDBRequests.isEmpty() &amp;&amp; !m_databaseInfo) {
</del><ins>+    if (m_clientClosePendingDatabaseConnections.isEmpty() &amp;&amp; m_pendingOpenDBRequests.isEmpty() &amp;&amp; !m_databaseInfo) {
</ins><span class="cx">         m_server.closeUniqueIDBDatabase(*this);
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // Previously blocked operations might be runnable.
</span><del>-    invokeOperationAndTransactionTimer();
</del><ins>+    if (!m_hardClosedForUserDelete)
+        invokeOperationAndTransactionTimer();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void UniqueIDBDatabase::postDatabaseTask(std::unique_ptr&lt;CrossThreadTask&gt;&amp;&amp; task)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(isMainThread());
</span><span class="cx">     m_databaseQueue.append(WTFMove(task));
</span><ins>+    ++m_queuedTaskCount;
</ins><span class="cx"> 
</span><span class="cx">     m_server.postDatabaseTask(createCrossThreadTask(*this, &amp;UniqueIDBDatabase::executeNextDatabaseTask));
</span><span class="cx"> }
</span><span class="lines">@@ -1401,6 +1490,7 @@
</span><span class="cx"> {
</span><span class="cx">     ASSERT(!isMainThread());
</span><span class="cx">     m_databaseReplyQueue.append(WTFMove(task));
</span><ins>+    ++m_queuedTaskCount;
</ins><span class="cx"> 
</span><span class="cx">     m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &amp;UniqueIDBDatabase::executeNextDatabaseTaskReply));
</span><span class="cx"> }
</span><span class="lines">@@ -1408,49 +1498,147 @@
</span><span class="cx"> void UniqueIDBDatabase::executeNextDatabaseTask()
</span><span class="cx"> {
</span><span class="cx">     ASSERT(!isMainThread());
</span><ins>+    ASSERT(m_queuedTaskCount);
</ins><span class="cx"> 
</span><span class="cx">     auto task = m_databaseQueue.tryGetMessage();
</span><span class="cx">     ASSERT(task);
</span><span class="cx"> 
</span><span class="cx">     task-&gt;performTask();
</span><ins>+    --m_queuedTaskCount;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void UniqueIDBDatabase::executeNextDatabaseTaskReply()
</span><span class="cx"> {
</span><span class="cx">     ASSERT(isMainThread());
</span><ins>+    ASSERT(m_queuedTaskCount);
</ins><span class="cx"> 
</span><span class="cx">     auto task = m_databaseReplyQueue.tryGetMessage();
</span><span class="cx">     ASSERT(task);
</span><span class="cx"> 
</span><span class="cx">     task-&gt;performTask();
</span><ins>+    --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 &amp;&amp; doneWithHardClose())
+        m_hardCloseProtector = nullptr;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool UniqueIDBDatabase::doneWithHardClose()
+{
+    return (!m_queuedTaskCount &amp;&amp; m_serverClosePendingDatabaseConnections.isEmpty());
+}
+
+static void errorOpenDBRequestForUserDelete(ServerOpenDBRequest&amp; 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, &quot;UniqueIDBDatabase::immediateCloseForUserDelete - Cancelling (%i, %i, %i, %i) callbacks&quot;, m_errorCallbacks.size(), m_keyDataCallbacks.size(), m_getResultCallbacks.size(), m_countCallbacks.size());
+
+    // Error out all transactions
+    Vector&lt;IDBResourceIdentifier&gt; inProgressIdentifiers;
+    copyKeysToVector(m_inProgressTransactions, inProgressIdentifiers);
+    for (auto&amp; identifier : inProgressIdentifiers)
+        m_inProgressTransactions.get(identifier)-&gt;abortWithoutCallback();
+
+    ASSERT(m_inProgressTransactions.isEmpty());
+
+    m_pendingTransactions.clear();
+    m_objectStoreTransactionCounts.clear();
+    m_objectStoreWriteTransactions.clear();
+
+    // Error out all pending callbacks
+    Vector&lt;uint64_t&gt; 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&amp; request : m_pendingOpenDBRequests)
+        errorOpenDBRequestForUserDelete(*request);
+
+    m_pendingOpenDBRequests.clear();
+
+    // Close all open connections
+    ListHashSet&lt;RefPtr&lt;UniqueIDBDatabaseConnection&gt;&gt; openDatabaseConnections = m_openDatabaseConnections;
+    for (auto&amp; 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);
+}
+
</ins><span class="cx"> void UniqueIDBDatabase::performErrorCallback(uint64_t callbackIdentifier, const IDBError&amp; error)
</span><span class="cx"> {
</span><span class="cx">     auto callback = m_errorCallbacks.take(callbackIdentifier);
</span><del>-    ASSERT(callback);
-    callback(error);
</del><ins>+    ASSERT(callback || m_hardClosedForUserDelete);
+    if (callback)
+        callback(error);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void UniqueIDBDatabase::performKeyDataCallback(uint64_t callbackIdentifier, const IDBError&amp; error, const IDBKeyData&amp; resultKey)
</span><span class="cx"> {
</span><span class="cx">     auto callback = m_keyDataCallbacks.take(callbackIdentifier);
</span><del>-    ASSERT(callback);
-    callback(error, resultKey);
</del><ins>+    ASSERT(callback || m_hardClosedForUserDelete);
+    if (callback)
+        callback(error, resultKey);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void UniqueIDBDatabase::performGetResultCallback(uint64_t callbackIdentifier, const IDBError&amp; error, const IDBGetResult&amp; resultData)
</span><span class="cx"> {
</span><span class="cx">     auto callback = m_getResultCallbacks.take(callbackIdentifier);
</span><del>-    ASSERT(callback);
-    callback(error, resultData);
</del><ins>+    ASSERT(callback || m_hardClosedForUserDelete);
+    if (callback)
+        callback(error, resultData);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void UniqueIDBDatabase::performCountCallback(uint64_t callbackIdentifier, const IDBError&amp; error, uint64_t count)
</span><span class="cx"> {
</span><span class="cx">     auto callback = m_countCallbacks.take(callbackIdentifier);
</span><del>-    ASSERT(callback);
-    callback(error, count);
</del><ins>+    ASSERT(callback || m_hardClosedForUserDelete);
+    if (callback)
+        callback(error, count);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void UniqueIDBDatabase::forgetErrorCallback(uint64_t callbackIdentifier)
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbserverUniqueIDBDatabaseh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.h (201097 => 201098)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.h        2016-05-18 20:21:31 UTC (rev 201097)
+++ trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.h        2016-05-18 20:42:20 UTC (rev 201098)
</span><span class="lines">@@ -101,12 +101,15 @@
</span><span class="cx">     void didFinishHandlingVersionChange(UniqueIDBDatabaseConnection&amp;, const IDBResourceIdentifier&amp; transactionIdentifier);
</span><span class="cx">     void transactionDestroyed(UniqueIDBDatabaseTransaction&amp;);
</span><span class="cx">     void connectionClosedFromClient(UniqueIDBDatabaseConnection&amp;);
</span><ins>+    void confirmConnectionClosedOnServer(UniqueIDBDatabaseConnection&amp;);
</ins><span class="cx">     void didFireVersionChangeEvent(UniqueIDBDatabaseConnection&amp;, const IDBResourceIdentifier&amp; requestIdentifier);
</span><span class="cx">     void openDBRequestCancelled(const IDBResourceIdentifier&amp; requestIdentifier);
</span><ins>+    void confirmDidCloseFromServer(UniqueIDBDatabaseConnection&amp;);
</ins><span class="cx"> 
</span><span class="cx">     void enqueueTransaction(Ref&lt;UniqueIDBDatabaseTransaction&gt;&amp;&amp;);
</span><span class="cx"> 
</span><span class="cx">     void handleDelete(IDBConnectionToClient&amp;, const IDBRequestData&amp;);
</span><ins>+    void immediateCloseForUserDelete();
</ins><span class="cx"> 
</span><span class="cx">     static JSC::VM&amp; databaseThreadVM();
</span><span class="cx">     static JSC::ExecState&amp; databaseThreadExecState();
</span><span class="lines">@@ -129,6 +132,8 @@
</span><span class="cx">     void activateTransactionInBackingStore(UniqueIDBDatabaseTransaction&amp;);
</span><span class="cx">     void transactionCompleted(RefPtr&lt;UniqueIDBDatabaseTransaction&gt;&amp;&amp;);
</span><span class="cx"> 
</span><ins>+    void connectionClosedFromServer(UniqueIDBDatabaseConnection&amp;);
+
</ins><span class="cx">     // Database thread operations
</span><span class="cx">     void deleteBackingStore(const IDBDatabaseIdentifier&amp;);
</span><span class="cx">     void openBackingStore(const IDBDatabaseIdentifier&amp;);
</span><span class="lines">@@ -167,10 +172,10 @@
</span><span class="cx">     void didPerformAbortTransaction(uint64_t callbackIdentifier, const IDBError&amp;, const IDBResourceIdentifier&amp; transactionIdentifier);
</span><span class="cx">     void didPerformActivateTransactionInBackingStore(uint64_t callbackIdentifier, const IDBError&amp;);
</span><span class="cx"> 
</span><del>-    uint64_t storeCallback(ErrorCallback);
-    uint64_t storeCallback(KeyDataCallback);
-    uint64_t storeCallback(GetResultCallback);
-    uint64_t storeCallback(CountCallback);
</del><ins>+    uint64_t storeCallbackOrFireError(ErrorCallback);
+    uint64_t storeCallbackOrFireError(KeyDataCallback);
+    uint64_t storeCallbackOrFireError(GetResultCallback);
+    uint64_t storeCallbackOrFireError(CountCallback);
</ins><span class="cx"> 
</span><span class="cx">     void performErrorCallback(uint64_t callbackIdentifier, const IDBError&amp;);
</span><span class="cx">     void performKeyDataCallback(uint64_t callbackIdentifier, const IDBError&amp;, const IDBKeyData&amp;);
</span><span class="lines">@@ -194,6 +199,8 @@
</span><span class="cx">     void executeNextDatabaseTask();
</span><span class="cx">     void executeNextDatabaseTaskReply();
</span><span class="cx"> 
</span><ins>+    bool doneWithHardClose();
+
</ins><span class="cx">     IDBServer&amp; m_server;
</span><span class="cx">     IDBDatabaseIdentifier m_identifier;
</span><span class="cx">     
</span><span class="lines">@@ -201,7 +208,8 @@
</span><span class="cx">     RefPtr&lt;ServerOpenDBRequest&gt; m_currentOpenDBRequest;
</span><span class="cx"> 
</span><span class="cx">     ListHashSet&lt;RefPtr&lt;UniqueIDBDatabaseConnection&gt;&gt; m_openDatabaseConnections;
</span><del>-    HashSet&lt;RefPtr&lt;UniqueIDBDatabaseConnection&gt;&gt; m_closePendingDatabaseConnections;
</del><ins>+    HashSet&lt;RefPtr&lt;UniqueIDBDatabaseConnection&gt;&gt; m_clientClosePendingDatabaseConnections;
+    HashSet&lt;RefPtr&lt;UniqueIDBDatabaseConnection&gt;&gt; m_serverClosePendingDatabaseConnections;
</ins><span class="cx"> 
</span><span class="cx">     RefPtr&lt;UniqueIDBDatabaseConnection&gt; m_versionChangeDatabaseConnection;
</span><span class="cx">     RefPtr&lt;UniqueIDBDatabaseTransaction&gt; m_versionChangeTransaction;
</span><span class="lines">@@ -235,6 +243,10 @@
</span><span class="cx"> 
</span><span class="cx">     MessageQueue&lt;CrossThreadTask&gt; m_databaseQueue;
</span><span class="cx">     MessageQueue&lt;CrossThreadTask&gt; m_databaseReplyQueue;
</span><ins>+    std::atomic&lt;uint64_t&gt; m_queuedTaskCount { 0 };
+
+    bool m_hardClosedForUserDelete { false };
+    RefPtr&lt;UniqueIDBDatabase&gt; m_hardCloseProtector;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace IDBServer
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbserverUniqueIDBDatabaseConnectioncpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabaseConnection.cpp (201097 => 201098)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabaseConnection.cpp        2016-05-18 20:21:31 UTC (rev 201097)
+++ trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabaseConnection.cpp        2016-05-18 20:42:20 UTC (rev 201098)
</span><span class="lines">@@ -89,6 +89,13 @@
</span><span class="cx">     m_database.connectionClosedFromClient(*this);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void UniqueIDBDatabaseConnection::confirmDidCloseFromServer()
+{
+    LOG(IndexedDB, &quot;UniqueIDBDatabaseConnection::confirmDidCloseFromServer - %s - %&quot; PRIu64, m_openRequestIdentifier.loggingString().utf8().data(), m_identifier);
+
+    m_database.confirmDidCloseFromServer(*this);
+}
+
</ins><span class="cx"> void UniqueIDBDatabaseConnection::didFireVersionChangeEvent(const IDBResourceIdentifier&amp; requestIdentifier)
</span><span class="cx"> {
</span><span class="cx">     LOG(IndexedDB, &quot;UniqueIDBDatabaseConnection::didFireVersionChangeEvent - %s - %&quot; PRIu64, m_openRequestIdentifier.loggingString().utf8().data(), m_identifier);
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbserverUniqueIDBDatabaseConnectionh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabaseConnection.h (201097 => 201098)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabaseConnection.h        2016-05-18 20:21:31 UTC (rev 201097)
+++ trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabaseConnection.h        2016-05-18 20:42:20 UTC (rev 201098)
</span><span class="lines">@@ -74,6 +74,7 @@
</span><span class="cx">     void didDeleteIndex(const IDBResultData&amp;);
</span><span class="cx">     void didFireVersionChangeEvent(const IDBResourceIdentifier&amp; requestIdentifier);
</span><span class="cx">     void didFinishHandlingVersionChange(const IDBResourceIdentifier&amp; transactionIdentifier);
</span><ins>+    void confirmDidCloseFromServer();
</ins><span class="cx"> 
</span><span class="cx">     void abortTransactionWithoutCallback(UniqueIDBDatabaseTransaction&amp;);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbsharedIDBErrorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/shared/IDBError.cpp (201097 => 201098)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/shared/IDBError.cpp        2016-05-18 20:21:31 UTC (rev 201097)
+++ trunk/Source/WebCore/Modules/indexeddb/shared/IDBError.cpp        2016-05-18 20:42:20 UTC (rev 201098)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2015 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2015, 2016 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -65,6 +65,11 @@
</span><span class="cx">     return IDBDatabaseException::getErrorDescription(m_code);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+RefPtr&lt;DOMError&gt; IDBError::toDOMError() const
+{
+    return DOMError::create(IDBDatabaseException::getErrorName(m_code), m_message);
+}
+
</ins><span class="cx"> } // namespace WebCore
</span><span class="cx"> 
</span><span class="cx"> #endif // ENABLE(INDEXED_DATABASE)
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbsharedIDBErrorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/shared/IDBError.h (201097 => 201098)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/shared/IDBError.h        2016-05-18 20:21:31 UTC (rev 201097)
+++ trunk/Source/WebCore/Modules/indexeddb/shared/IDBError.h        2016-05-18 20:42:20 UTC (rev 201098)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2015 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2015, 2016 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -23,11 +23,11 @@
</span><span class="cx">  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
</span><span class="cx">  */
</span><span class="cx"> 
</span><del>-#ifndef IDBError_h
-#define IDBError_h
</del><ins>+#pragma once
</ins><span class="cx"> 
</span><span class="cx"> #if ENABLE(INDEXED_DATABASE)
</span><span class="cx"> 
</span><ins>+#include &quot;DOMError.h&quot;
</ins><span class="cx"> #include &quot;IDBDatabaseException.h&quot;
</span><span class="cx"> #include &lt;wtf/text/WTFString.h&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -39,8 +39,15 @@
</span><span class="cx">     IDBError(ExceptionCode);
</span><span class="cx">     IDBError(ExceptionCode, const String&amp; message);
</span><span class="cx"> 
</span><ins>+    static IDBError userDeleteError()
+    {
+        return { IDBDatabaseException::UnknownError, ASCIILiteral(&quot;Database deleted by request of the user&quot;) };
+    }
+
</ins><span class="cx">     IDBError&amp; operator=(const IDBError&amp;);
</span><span class="cx"> 
</span><ins>+    RefPtr&lt;DOMError&gt; toDOMError() const;
+
</ins><span class="cx">     ExceptionCode code() const { return m_code; }
</span><span class="cx">     String name() const;
</span><span class="cx">     String message() const;
</span><span class="lines">@@ -78,4 +85,3 @@
</span><span class="cx"> } // namespace WebCore
</span><span class="cx"> 
</span><span class="cx"> #endif // ENABLE(INDEXED_DATABASE)
</span><del>-#endif // IDBError_h
</del></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbsharedInProcessIDBServercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/shared/InProcessIDBServer.cpp (201097 => 201098)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/shared/InProcessIDBServer.cpp        2016-05-18 20:21:31 UTC (rev 201097)
+++ trunk/Source/WebCore/Modules/indexeddb/shared/InProcessIDBServer.cpp        2016-05-18 20:42:20 UTC (rev 201098)
</span><span class="lines">@@ -367,6 +367,15 @@
</span><span class="cx">     });
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void InProcessIDBServer::didCloseFromServer(IDBServer::UniqueIDBDatabaseConnection&amp; connection, const IDBError&amp; error)
+{
+    RefPtr&lt;InProcessIDBServer&gt; protectedThis(this);
+    uint64_t databaseConnectionIdentifier = connection.identifier();
+    RunLoop::current().dispatch([this, protectedThis, databaseConnectionIdentifier, error] {
+        m_connectionToServer-&gt;didCloseFromServer(databaseConnectionIdentifier, error);
+    });
+}
+
</ins><span class="cx"> void InProcessIDBServer::notifyOpenDBRequestBlocked(const IDBResourceIdentifier&amp; requestIdentifier, uint64_t oldVersion, uint64_t newVersion)
</span><span class="cx"> {
</span><span class="cx">     RefPtr&lt;InProcessIDBServer&gt; protectedThis(this);
</span><span class="lines">@@ -407,6 +416,14 @@
</span><span class="cx">     });
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void InProcessIDBServer::confirmDidCloseFromServer(uint64_t databaseConnectionIdentifier)
+{
+    RefPtr&lt;InProcessIDBServer&gt; protectedThis(this);
+    RunLoop::current().dispatch([this, protectedThis, databaseConnectionIdentifier] {
+        m_server-&gt;confirmDidCloseFromServer(databaseConnectionIdentifier);
+    });
+}
+
</ins><span class="cx"> void InProcessIDBServer::getAllDatabaseNames(const SecurityOriginData&amp; mainFrameOrigin, const SecurityOriginData&amp; openingOrigin, uint64_t callbackID)
</span><span class="cx"> {
</span><span class="cx">     RefPtr&lt;InProcessIDBServer&gt; protectedThis(this);
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbsharedInProcessIDBServerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/shared/InProcessIDBServer.h (201097 => 201098)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/shared/InProcessIDBServer.h        2016-05-18 20:21:31 UTC (rev 201097)
+++ trunk/Source/WebCore/Modules/indexeddb/shared/InProcessIDBServer.h        2016-05-18 20:42:20 UTC (rev 201098)
</span><span class="lines">@@ -52,6 +52,7 @@
</span><span class="cx"> 
</span><span class="cx">     WEBCORE_EXPORT IDBClient::IDBConnectionToServer&amp; connectionToServer() const;
</span><span class="cx">     IDBServer::IDBConnectionToClient&amp; connectionToClient() const;
</span><ins>+    IDBServer::IDBServer&amp; server() { return m_server.get(); }
</ins><span class="cx"> 
</span><span class="cx">     IDBServer::IDBServer&amp; idbServer() { return m_server.get(); }
</span><span class="cx"> 
</span><span class="lines">@@ -77,6 +78,7 @@
</span><span class="cx">     void abortOpenAndUpgradeNeeded(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier&amp; transactionIdentifier) final;
</span><span class="cx">     void didFireVersionChangeEvent(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier&amp; requestIdentifier) final;
</span><span class="cx">     void openDBRequestCancelled(const IDBRequestData&amp;) final;
</span><ins>+    void confirmDidCloseFromServer(uint64_t databaseConnectionIdentifier) final;
</ins><span class="cx">     void getAllDatabaseNames(const SecurityOriginData&amp; mainFrameOrigin, const SecurityOriginData&amp; openingOrigin, uint64_t callbackID) final;
</span><span class="cx"> 
</span><span class="cx">     // IDBConnectionToClient
</span><span class="lines">@@ -98,6 +100,7 @@
</span><span class="cx">     void didIterateCursor(const IDBResultData&amp;) final;
</span><span class="cx">     void fireVersionChangeEvent(IDBServer::UniqueIDBDatabaseConnection&amp;, const IDBResourceIdentifier&amp; requestIdentifier, uint64_t requestedVersion) final;
</span><span class="cx">     void didStartTransaction(const IDBResourceIdentifier&amp; transactionIdentifier, const IDBError&amp;) final;
</span><ins>+    void didCloseFromServer(IDBServer::UniqueIDBDatabaseConnection&amp;, const IDBError&amp;) final;
</ins><span class="cx">     void notifyOpenDBRequestBlocked(const IDBResourceIdentifier&amp; requestIdentifier, uint64_t oldVersion, uint64_t newVersion) final;
</span><span class="cx">     void didGetAllDatabaseNames(uint64_t callbackID, const Vector&lt;String&gt;&amp; databaseNames) final;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformCrossThreadCopiercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/CrossThreadCopier.cpp (201097 => 201098)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/CrossThreadCopier.cpp        2016-05-18 20:21:31 UTC (rev 201097)
+++ trunk/Source/WebCore/platform/CrossThreadCopier.cpp        2016-05-18 20:42:20 UTC (rev 201098)
</span><span class="lines">@@ -85,6 +85,11 @@
</span><span class="cx">     return ThreadSafeDataBuffer(buffer);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+CrossThreadCopierBase&lt;false, false, std::chrono::system_clock::time_point&gt;::Type CrossThreadCopierBase&lt;false, false, std::chrono::system_clock::time_point&gt;::copy(const std::chrono::system_clock::time_point&amp; timePoint)
+{
+    return timePoint;
+}
+
</ins><span class="cx"> // Test CrossThreadCopier using COMPILE_ASSERT.
</span><span class="cx"> 
</span><span class="cx"> // Verify that ThreadSafeRefCounted objects get handled correctly.
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformCrossThreadCopierh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/CrossThreadCopier.h (201097 => 201098)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/CrossThreadCopier.h        2016-05-18 20:21:31 UTC (rev 201097)
+++ trunk/Source/WebCore/platform/CrossThreadCopier.h        2016-05-18 20:42:20 UTC (rev 201098)
</span><span class="lines">@@ -160,6 +160,11 @@
</span><span class="cx">     static Type copy(const ThreadSafeDataBuffer&amp;);
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+template&lt;&gt; struct CrossThreadCopierBase&lt;false, false, std::chrono::system_clock::time_point&gt; {
+    typedef std::chrono::system_clock::time_point Type;
+    static Type copy(const Type&amp; source);
+};
+
</ins><span class="cx"> template&lt;typename T&gt;
</span><span class="cx"> struct CrossThreadCopier : public CrossThreadCopierBase&lt;CrossThreadCopierBaseHelper::IsEnumOrConvertibleToInteger&lt;T&gt;::value, CrossThreadCopierBaseHelper::IsThreadSafeRefCountedPointer&lt;T&gt;::value, T&gt; {
</span><span class="cx"> };
</span></span></pre></div>
<a id="trunkSourceWebKit2ChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/ChangeLog (201097 => 201098)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/ChangeLog        2016-05-18 20:21:31 UTC (rev 201097)
+++ trunk/Source/WebKit2/ChangeLog        2016-05-18 20:42:20 UTC (rev 201098)
</span><span class="lines">@@ -1,5 +1,32 @@
</span><span class="cx"> 2016-05-18  Brady Eidson  &lt;beidson@apple.com&gt;
</span><span class="cx"> 
</span><ins>+        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  &lt;beidson@apple.com&gt;
+
</ins><span class="cx">         Modern IDB: Make TestRunner.clearAllDatabases also delete IndexedDB databases (once doing so is supported).
</span><span class="cx">         https://bugs.webkit.org/show_bug.cgi?id=157823
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebKit2DatabaseProcessDatabaseProcesscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/DatabaseProcess/DatabaseProcess.cpp (201097 => 201098)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/DatabaseProcess/DatabaseProcess.cpp        2016-05-18 20:21:31 UTC (rev 201097)
+++ trunk/Source/WebKit2/DatabaseProcess/DatabaseProcess.cpp        2016-05-18 20:42:20 UTC (rev 201098)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013, 2014, 2015, 2016 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -259,13 +259,8 @@
</span><span class="cx">     }));
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(INDEXED_DATABASE)
</span><del>-    if (websiteDataTypes.contains(WebsiteDataType::IndexedDBDatabases)) {
-        postDatabaseTask(std::make_unique&lt;CrossThreadTask&gt;([this, callbackAggregator, modifiedSince] {
-
-            deleteIndexedDatabaseEntriesModifiedSince(modifiedSince);
-            RunLoop::main().dispatch([callbackAggregator] { });
-        }));
-    }
</del><ins>+    if (websiteDataTypes.contains(WebsiteDataType::IndexedDBDatabases))
+        m_idbServer-&gt;closeAndDeleteDatabasesModifiedSince(modifiedSince, [callbackAggregator] { });
</ins><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebKit2DatabaseProcessIndexedDBWebIDBConnectionToClientcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/DatabaseProcess/IndexedDB/WebIDBConnectionToClient.cpp (201097 => 201098)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/DatabaseProcess/IndexedDB/WebIDBConnectionToClient.cpp        2016-05-18 20:21:31 UTC (rev 201097)
+++ trunk/Source/WebKit2/DatabaseProcess/IndexedDB/WebIDBConnectionToClient.cpp        2016-05-18 20:42:20 UTC (rev 201098)
</span><span class="lines">@@ -127,6 +127,11 @@
</span><span class="cx"> 
</span><span class="cx"> void WebIDBConnectionToClient::didGetRecord(const WebCore::IDBResultData&amp; resultData)
</span><span class="cx"> {
</span><ins>+    if (resultData.type() == IDBResultType::Error) {
+        send(Messages::WebIDBConnectionToServer::DidGetRecord(resultData));
+        return;
+    }
+
</ins><span class="cx">     auto&amp; blobFilePaths = resultData.getResult().value().blobFilePaths();
</span><span class="cx">     if (blobFilePaths.isEmpty()) {
</span><span class="cx">         send(Messages::WebIDBConnectionToServer::DidGetRecord(resultData));
</span><span class="lines">@@ -169,6 +174,11 @@
</span><span class="cx">     send(Messages::WebIDBConnectionToServer::DidStartTransaction(transactionIdentifier, error));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void WebIDBConnectionToClient::didCloseFromServer(WebCore::IDBServer::UniqueIDBDatabaseConnection&amp; connection, const WebCore::IDBError&amp; error)
+{
+    send(Messages::WebIDBConnectionToServer::DidCloseFromServer(connection.identifier(), error));
+}
+
</ins><span class="cx"> void WebIDBConnectionToClient::notifyOpenDBRequestBlocked(const WebCore::IDBResourceIdentifier&amp; requestIdentifier, uint64_t oldVersion, uint64_t newVersion)
</span><span class="cx"> {
</span><span class="cx">     send(Messages::WebIDBConnectionToServer::NotifyOpenDBRequestBlocked(requestIdentifier, oldVersion, newVersion));
</span><span class="lines">@@ -294,6 +304,11 @@
</span><span class="cx">     DatabaseProcess::singleton().idbServer().openDBRequestCancelled(requestData);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void WebIDBConnectionToClient::confirmDidCloseFromServer(uint64_t databaseConnectionIdentifier)
+{
+    DatabaseProcess::singleton().idbServer().confirmDidCloseFromServer(databaseConnectionIdentifier);
+}
+
</ins><span class="cx"> void WebIDBConnectionToClient::getAllDatabaseNames(uint64_t serverConnectionIdentifier, const WebCore::SecurityOriginData&amp; topOrigin, const WebCore::SecurityOriginData&amp; openingOrigin, uint64_t callbackID)
</span><span class="cx"> {
</span><span class="cx">     DatabaseProcess::singleton().idbServer().getAllDatabaseNames(serverConnectionIdentifier, topOrigin, openingOrigin, callbackID);
</span></span></pre></div>
<a id="trunkSourceWebKit2DatabaseProcessIndexedDBWebIDBConnectionToClienth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/DatabaseProcess/IndexedDB/WebIDBConnectionToClient.h (201097 => 201098)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/DatabaseProcess/IndexedDB/WebIDBConnectionToClient.h        2016-05-18 20:21:31 UTC (rev 201097)
+++ trunk/Source/WebKit2/DatabaseProcess/IndexedDB/WebIDBConnectionToClient.h        2016-05-18 20:42:20 UTC (rev 201098)
</span><span class="lines">@@ -23,8 +23,7 @@
</span><span class="cx">  * THE POSSIBILITY OF SUCH DAMAGE.
</span><span class="cx">  */
</span><span class="cx"> 
</span><del>-#ifndef WebIDBConnectionToClient_h
-#define WebIDBConnectionToClient_h
</del><ins>+#pragma once
</ins><span class="cx"> 
</span><span class="cx"> #if ENABLE(INDEXED_DATABASE)
</span><span class="cx"> 
</span><span class="lines">@@ -76,6 +75,7 @@
</span><span class="cx"> 
</span><span class="cx">     void fireVersionChangeEvent(WebCore::IDBServer::UniqueIDBDatabaseConnection&amp;, const WebCore::IDBResourceIdentifier&amp; requestIdentifier, uint64_t requestedVersion) final;
</span><span class="cx">     void didStartTransaction(const WebCore::IDBResourceIdentifier&amp; transactionIdentifier, const WebCore::IDBError&amp;) final;
</span><ins>+    void didCloseFromServer(WebCore::IDBServer::UniqueIDBDatabaseConnection&amp;, const WebCore::IDBError&amp;) final;
</ins><span class="cx">     void notifyOpenDBRequestBlocked(const WebCore::IDBResourceIdentifier&amp; requestIdentifier, uint64_t oldVersion, uint64_t newVersion) final;
</span><span class="cx"> 
</span><span class="cx">     void didGetAllDatabaseNames(uint64_t callbackID, const Vector&lt;String&gt;&amp; databaseNames) final;
</span><span class="lines">@@ -106,6 +106,7 @@
</span><span class="cx">     void abortOpenAndUpgradeNeeded(uint64_t databaseConnectionIdentifier, const WebCore::IDBResourceIdentifier&amp; transactionIdentifier);
</span><span class="cx">     void didFireVersionChangeEvent(uint64_t databaseConnectionIdentifier, const WebCore::IDBResourceIdentifier&amp; requestIdentifier);
</span><span class="cx">     void openDBRequestCancelled(const WebCore::IDBRequestData&amp;);
</span><ins>+    void confirmDidCloseFromServer(uint64_t databaseConnectionIdentifier);
</ins><span class="cx"> 
</span><span class="cx">     void getAllDatabaseNames(uint64_t serverConnectionIdentifier, const WebCore::SecurityOriginData&amp; topOrigin, const WebCore::SecurityOriginData&amp; openingOrigin, uint64_t callbackID);
</span><span class="cx"> 
</span><span class="lines">@@ -127,4 +128,3 @@
</span><span class="cx"> } // namespace WebKit
</span><span class="cx"> 
</span><span class="cx"> #endif // ENABLE(INDEXED_DATABASE)
</span><del>-#endif // WebIDBConnectionToClient_h
</del></span></pre></div>
<a id="trunkSourceWebKit2DatabaseProcessIndexedDBWebIDBConnectionToClientmessagesin"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/DatabaseProcess/IndexedDB/WebIDBConnectionToClient.messages.in (201097 => 201098)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/DatabaseProcess/IndexedDB/WebIDBConnectionToClient.messages.in        2016-05-18 20:21:31 UTC (rev 201097)
+++ trunk/Source/WebKit2/DatabaseProcess/IndexedDB/WebIDBConnectionToClient.messages.in        2016-05-18 20:42:20 UTC (rev 201098)
</span><span class="lines">@@ -45,6 +45,7 @@
</span><span class="cx">     AbortOpenAndUpgradeNeeded(uint64_t databaseConnectionIdentifier, WebCore::IDBResourceIdentifier transactionIdentifier);
</span><span class="cx">     DidFireVersionChangeEvent(uint64_t databaseConnectionIdentifier, WebCore::IDBResourceIdentifier requestIdentifier);
</span><span class="cx">     OpenDBRequestCancelled(WebCore::IDBRequestData requestData);
</span><ins>+    ConfirmDidCloseFromServer(uint64_t databaseConnectionIdentifier);
</ins><span class="cx"> 
</span><span class="cx">     GetAllDatabaseNames(uint64_t serverConnectionIdentifier, struct WebCore::SecurityOriginData topOrigin, struct WebCore::SecurityOriginData openingOrigin, uint64_t callbackID);
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebKit2WebProcessDatabasesIndexedDBWebIDBConnectionToServercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/WebProcess/Databases/IndexedDB/WebIDBConnectionToServer.cpp (201097 => 201098)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/WebProcess/Databases/IndexedDB/WebIDBConnectionToServer.cpp        2016-05-18 20:21:31 UTC (rev 201097)
+++ trunk/Source/WebKit2/WebProcess/Databases/IndexedDB/WebIDBConnectionToServer.cpp        2016-05-18 20:42:20 UTC (rev 201098)
</span><span class="lines">@@ -186,6 +186,11 @@
</span><span class="cx">     send(Messages::WebIDBConnectionToClient::OpenDBRequestCancelled(requestData));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void WebIDBConnectionToServer::confirmDidCloseFromServer(uint64_t databaseConnectionIdentifier)
+{
+    send(Messages::WebIDBConnectionToClient::ConfirmDidCloseFromServer(databaseConnectionIdentifier));
+}
+
</ins><span class="cx"> void WebIDBConnectionToServer::getAllDatabaseNames(const WebCore::SecurityOriginData&amp; topOrigin, const WebCore::SecurityOriginData&amp; openingOrigin, uint64_t callbackID)
</span><span class="cx"> {
</span><span class="cx">     send(Messages::WebIDBConnectionToClient::GetAllDatabaseNames(m_identifier, topOrigin, openingOrigin, callbackID));
</span><span class="lines">@@ -282,11 +287,16 @@
</span><span class="cx">     m_connectionToServer-&gt;fireVersionChangeEvent(uniqueDatabaseConnectionIdentifier, requestIdentifier, requestedVersion);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void WebIDBConnectionToServer::didStartTransaction(const IDBResourceIdentifier&amp; transactionIdentifier, const WebCore::IDBError&amp; error)
</del><ins>+void WebIDBConnectionToServer::didStartTransaction(const IDBResourceIdentifier&amp; transactionIdentifier, const IDBError&amp; error)
</ins><span class="cx"> {
</span><span class="cx">     m_connectionToServer-&gt;didStartTransaction(transactionIdentifier, error);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void WebIDBConnectionToServer::didCloseFromServer(uint64_t databaseConnectionIdentifier, const IDBError&amp; error)
+{
+    m_connectionToServer-&gt;didCloseFromServer(databaseConnectionIdentifier, error);
+}
+
</ins><span class="cx"> void WebIDBConnectionToServer::notifyOpenDBRequestBlocked(const IDBResourceIdentifier&amp; requestIdentifier, uint64_t oldVersion, uint64_t newVersion)
</span><span class="cx"> {
</span><span class="cx">     m_connectionToServer-&gt;notifyOpenDBRequestBlocked(requestIdentifier, oldVersion, newVersion);
</span></span></pre></div>
<a id="trunkSourceWebKit2WebProcessDatabasesIndexedDBWebIDBConnectionToServerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/WebProcess/Databases/IndexedDB/WebIDBConnectionToServer.h (201097 => 201098)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/WebProcess/Databases/IndexedDB/WebIDBConnectionToServer.h        2016-05-18 20:21:31 UTC (rev 201097)
+++ trunk/Source/WebKit2/WebProcess/Databases/IndexedDB/WebIDBConnectionToServer.h        2016-05-18 20:42:20 UTC (rev 201098)
</span><span class="lines">@@ -23,8 +23,7 @@
</span><span class="cx">  * THE POSSIBILITY OF SUCH DAMAGE.
</span><span class="cx">  */
</span><span class="cx"> 
</span><del>-#ifndef WebIDBConnectionToServer_h
-#define WebIDBConnectionToServer_h
</del><ins>+#pragma once
</ins><span class="cx"> 
</span><span class="cx"> #if ENABLE(INDEXED_DATABASE)
</span><span class="cx"> 
</span><span class="lines">@@ -66,6 +65,7 @@
</span><span class="cx">     void abortOpenAndUpgradeNeeded(uint64_t databaseConnectionIdentifier, const WebCore::IDBResourceIdentifier&amp; transactionIdentifier) final;
</span><span class="cx">     void didFireVersionChangeEvent(uint64_t databaseConnectionIdentifier, const WebCore::IDBResourceIdentifier&amp; requestIdentifier) final;
</span><span class="cx">     void openDBRequestCancelled(const WebCore::IDBRequestData&amp;) final;
</span><ins>+    void confirmDidCloseFromServer(uint64_t databaseConnectionIdentifier) final;
</ins><span class="cx"> 
</span><span class="cx">     void getAllDatabaseNames(const WebCore::SecurityOriginData&amp; topOrigin, const WebCore::SecurityOriginData&amp; openingOrigin, uint64_t callbackID) final;
</span><span class="cx"> 
</span><span class="lines">@@ -91,6 +91,7 @@
</span><span class="cx">     void didIterateCursor(const WebCore::IDBResultData&amp;);
</span><span class="cx">     void fireVersionChangeEvent(uint64_t uniqueDatabaseConnectionIdentifier, const WebCore::IDBResourceIdentifier&amp; requestIdentifier, uint64_t requestedVersion);
</span><span class="cx">     void didStartTransaction(const WebCore::IDBResourceIdentifier&amp; transactionIdentifier, const WebCore::IDBError&amp;);
</span><ins>+    void didCloseFromServer(uint64_t databaseConnectionIdentifier, const WebCore::IDBError&amp;);
</ins><span class="cx">     void notifyOpenDBRequestBlocked(const WebCore::IDBResourceIdentifier&amp; requestIdentifier, uint64_t oldVersion, uint64_t newVersion);
</span><span class="cx">     void didGetAllDatabaseNames(uint64_t callbackID, const Vector&lt;String&gt;&amp; databaseNames);
</span><span class="cx"> 
</span><span class="lines">@@ -109,4 +110,3 @@
</span><span class="cx"> } // namespace WebKit
</span><span class="cx"> 
</span><span class="cx"> #endif // ENABLE(INDEXED_DATABASE)
</span><del>-#endif // WebIDBConnectionToServer_h
</del></span></pre></div>
<a id="trunkSourceWebKit2WebProcessDatabasesIndexedDBWebIDBConnectionToServermessagesin"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/WebProcess/Databases/IndexedDB/WebIDBConnectionToServer.messages.in (201097 => 201098)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/WebProcess/Databases/IndexedDB/WebIDBConnectionToServer.messages.in        2016-05-18 20:21:31 UTC (rev 201097)
+++ trunk/Source/WebKit2/WebProcess/Databases/IndexedDB/WebIDBConnectionToServer.messages.in        2016-05-18 20:42:20 UTC (rev 201098)
</span><span class="lines">@@ -42,6 +42,7 @@
</span><span class="cx"> 
</span><span class="cx">     FireVersionChangeEvent(uint64_t databaseConnectionIdentifier, WebCore::IDBResourceIdentifier requestIdentifier, uint64_t requestedVersion)
</span><span class="cx">     DidStartTransaction(WebCore::IDBResourceIdentifier transactionIdentifier, WebCore::IDBError error)
</span><ins>+    DidCloseFromServer(uint64_t databaseConnectionIdentifier, WebCore::IDBError error) final;
</ins><span class="cx">     NotifyOpenDBRequestBlocked(WebCore::IDBResourceIdentifier requestIdentifier, uint64_t oldVersion, uint64_t newVersion)
</span><span class="cx"> 
</span><span class="cx">     DidGetAllDatabaseNames(uint64_t callbackID, Vector&lt;String&gt; databaseNames)
</span></span></pre>
</div>
</div>

</body>
</html>