<!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>[209069] 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/209069">209069</a></dd>
<dt>Author</dt> <dd>beidson@apple.com</dd>
<dt>Date</dt> <dd>2016-11-29 08:05:17 -0800 (Tue, 29 Nov 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>IndexedDB 2.0: Queue up completed requests in the client, handle them one by one.
https://bugs.webkit.org/show_bug.cgi?id=165000

Reviewed by Alex Christensen.

Source/WebCore:

No new tests (Covered extensively by every existing test).

Currently when a TransactionOperation completes on the server, it immediately completes
itself on the client side, including scheduling an event dispatch if necessary.

This patch changes it so that &quot;server completed operations&quot; instead queue up in the
IDBTransaction and are &quot;client-side completed&quot; asynchronously, 1-by-1.

Currently this is a &quot;no behavior change&quot; because only one operation is ever sent to
the server at a time.

But that will change with https://webkit.org/b/164932
And this patch is a pre-requisite for that.

* Modules/indexeddb/IDBRequest.cpp:
(WebCore::IDBRequest::dispatchEvent):
(WebCore::IDBRequest::didOpenOrIterateCursor):
(WebCore::IDBRequest::completeRequestAndDispatchEvent):
(WebCore::IDBRequest::requestCompleted): Deleted.
* Modules/indexeddb/IDBRequest.h:

* Modules/indexeddb/IDBTransaction.cpp:
(WebCore::IDBTransaction::IDBTransaction):
(WebCore::IDBTransaction::internalAbort):
(WebCore::IDBTransaction::abortOnServerAndCancelRequests):
(WebCore::IDBTransaction::scheduleOperation):
(WebCore::IDBTransaction::schedulePendingOperationTimer):
(WebCore::IDBTransaction::pendingOperationTimerFired):
(WebCore::IDBTransaction::operationCompletedOnServer):
(WebCore::IDBTransaction::scheduleCompletedOperationTimer):
(WebCore::IDBTransaction::completedOperationTimerFired):
(WebCore::IDBTransaction::completeNoncursorRequest):
(WebCore::IDBTransaction::completeCursorRequest):
(WebCore::IDBTransaction::finishedDispatchEventForRequest):
(WebCore::IDBTransaction::didStart):
(WebCore::IDBTransaction::didOpenCursorOnServer):
(WebCore::IDBTransaction::didIterateCursorOnServer):
(WebCore::IDBTransaction::didGetAllRecordsOnServer):
(WebCore::IDBTransaction::didGetRecordOnServer):
(WebCore::IDBTransaction::didGetCountOnServer):
(WebCore::IDBTransaction::didDeleteRecordOnServer):
(WebCore::IDBTransaction::didClearObjectStoreOnServer):
(WebCore::IDBTransaction::putOrAddOnServer):
(WebCore::IDBTransaction::didPutOrAddOnServer):
(WebCore::IDBTransaction::operationCompletedOnClient):
(WebCore::IDBTransaction::deactivate):
(WebCore::IDBTransaction::connectionClosedFromServer):
(WebCore::IDBTransaction::scheduleOperationTimer): Deleted.
(WebCore::IDBTransaction::operationTimerFired): Deleted.
(WebCore::IDBTransaction::operationDidComplete): Deleted.
* Modules/indexeddb/IDBTransaction.h:

* Modules/indexeddb/client/IDBConnectionProxy.cpp:
(WebCore::IDBClient::IDBConnectionProxy::completeOperation):

* Modules/indexeddb/client/TransactionOperation.cpp:
(WebCore::IDBClient::TransactionOperation::TransactionOperation):
* Modules/indexeddb/client/TransactionOperation.h:
(WebCore::IDBClient::TransactionOperation::transitionToCompleteOnThisThread):
(WebCore::IDBClient::TransactionOperation::transitionToComplete):
(WebCore::IDBClient::TransactionOperation::doComplete):
(WebCore::IDBClient::TransactionOperation::idbRequest):
(WebCore::IDBClient::TransactionOperation::performCompleteOnOriginThread): Deleted.
(WebCore::IDBClient::TransactionOperation::completed): Deleted.

LayoutTests:

* storage/indexeddb/modern/resources/transaction-scheduler-6.js: This test had a bug which was masked by previously
  synchronous behavior. Fix that bug!</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsstorageindexeddbmodernresourcestransactionscheduler6js">trunk/LayoutTests/storage/indexeddb/modern/resources/transaction-scheduler-6.js</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbIDBRequestcpp">trunk/Source/WebCore/Modules/indexeddb/IDBRequest.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbIDBRequesth">trunk/Source/WebCore/Modules/indexeddb/IDBRequest.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="#trunkSourceWebCoreModulesindexeddbclientTransactionOperationcpp">trunk/Source/WebCore/Modules/indexeddb/client/TransactionOperation.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbclientTransactionOperationh">trunk/Source/WebCore/Modules/indexeddb/client/TransactionOperation.h</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbserverSQLiteIDBBackingStorecpp">trunk/Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (209068 => 209069)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2016-11-29 16:04:41 UTC (rev 209068)
+++ trunk/LayoutTests/ChangeLog        2016-11-29 16:05:17 UTC (rev 209069)
</span><span class="lines">@@ -1,3 +1,13 @@
</span><ins>+2016-11-29  Brady Eidson  &lt;beidson@apple.com&gt;
+
+        IndexedDB 2.0: Queue up completed requests in the client, handle them one by one.
+        https://bugs.webkit.org/show_bug.cgi?id=165000
+
+        Reviewed by Alex Christensen.
+
+        * storage/indexeddb/modern/resources/transaction-scheduler-6.js: This test had a bug which was masked by previously
+          synchronous behavior. Fix that bug!
+
</ins><span class="cx"> 2016-11-29  Zalan Bujtas  &lt;zalan@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Safari (WebKit) doesn't wrap element within flex when width comes below min-width
</span></span></pre></div>
<a id="trunkLayoutTestsstorageindexeddbmodernresourcestransactionscheduler6js"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/storage/indexeddb/modern/resources/transaction-scheduler-6.js (209068 => 209069)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/storage/indexeddb/modern/resources/transaction-scheduler-6.js        2016-11-29 16:04:41 UTC (rev 209068)
+++ trunk/LayoutTests/storage/indexeddb/modern/resources/transaction-scheduler-6.js        2016-11-29 16:05:17 UTC (rev 209069)
</span><span class="lines">@@ -3,6 +3,10 @@
</span><span class="cx"> 
</span><span class="cx"> indexedDBTest(prepareDatabase);
</span><span class="cx"> 
</span><ins>+function log(msg)
+{
+        debug(msg);
+}
</ins><span class="cx"> 
</span><span class="cx"> function done()
</span><span class="cx"> {
</span><span class="lines">@@ -13,7 +17,7 @@
</span><span class="cx"> 
</span><span class="cx"> function prepareDatabase(event)
</span><span class="cx"> {
</span><del>-    debug(&quot;Upgrade needed: Old version - &quot; + event.oldVersion + &quot; New version - &quot; + event.newVersion);
</del><ins>+    log(&quot;Upgrade needed: Old version - &quot; + event.oldVersion + &quot; New version - &quot; + event.newVersion);
</ins><span class="cx"> 
</span><span class="cx">     var versionTransaction = event.target.transaction;
</span><span class="cx">     database = event.target.result;
</span><span class="lines">@@ -21,22 +25,22 @@
</span><span class="cx">     var request = objectStore.put(&quot;foo&quot;, &quot;bar&quot;);
</span><span class="cx"> 
</span><span class="cx">     request.onerror = function(event) {
</span><del>-        debug(&quot;put FAILED - &quot; + event);
</del><ins>+        log(&quot;put FAILED - &quot; + event);
</ins><span class="cx">         done();
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     versionTransaction.onabort = function(event) {
</span><del>-        debug(&quot;versionchange transaction aborted&quot;);
</del><ins>+        log(&quot;versionchange transaction aborted&quot;);
</ins><span class="cx">         done();
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     versionTransaction.oncomplete = function(event) {
</span><del>-        debug(&quot;versionchange transaction completed&quot;);
</del><ins>+        log(&quot;versionchange transaction completed&quot;);
</ins><span class="cx">         continueTest();
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     versionTransaction.onerror = function(event) {
</span><del>-        debug(&quot;versionchange transaction error'ed - &quot; + event);
</del><ins>+        log(&quot;versionchange transaction error'ed - &quot; + event);
</ins><span class="cx">         done();
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="lines">@@ -51,26 +55,26 @@
</span><span class="cx">     var request = objectStore.put(&quot;baz&quot;, &quot;foo&quot;);
</span><span class="cx"> 
</span><span class="cx">     request.onsuccess = function(event) {
</span><del>-        debug(&quot;Write in readwrite transaction succeeded&quot;);
</del><ins>+        log(&quot;Write in readwrite transaction succeeded&quot;);
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     request.onerror = function(event) {
</span><del>-        debug(&quot;Write in readwrite transaction unexpectedly failed&quot;);
</del><ins>+        log(&quot;Write in readwrite transaction unexpectedly failed&quot;);
</ins><span class="cx">         done();
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     transaction.onabort = function(event) {
</span><del>-        debug(&quot;readwrite transaction expectedly aborted&quot;);
</del><ins>+        log(&quot;readwrite transaction expectedly aborted&quot;);
</ins><span class="cx">         done();
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     transaction.oncomplete = function(event) {
</span><del>-        debug(&quot;readwrite transaction completed&quot;);
</del><ins>+        log(&quot;readwrite transaction completed&quot;);
</ins><span class="cx">         done();
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     transaction.onerror = function(event) {
</span><del>-        debug(&quot;readwrite transaction error'ed - &quot; + event);
</del><ins>+        log(&quot;readwrite transaction error'ed - &quot; + event);
</ins><span class="cx">         done();
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="lines">@@ -84,7 +88,7 @@
</span><span class="cx">     
</span><span class="cx">     request.onsuccess = function(event) {
</span><span class="cx">         if (isFirstTime) {
</span><del>-            debug(&quot;Starting a readonly transaction&quot;);
</del><ins>+            log(&quot;Starting a readonly transaction&quot;);
</ins><span class="cx">             numberOfOpenTransactions++;
</span><span class="cx">         }
</span><span class="cx">         
</span><span class="lines">@@ -95,24 +99,22 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     request.onerror = function(event) {
</span><del>-        debug(&quot;Unexpected request error - &quot; + event);
</del><ins>+        log(&quot;Unexpected request error - &quot; + event);
</ins><span class="cx">         done();
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     transaction.onerror = function(event) {
</span><del>-        debug(&quot;Unexpected transaction error - &quot; + event);
</del><ins>+        log(&quot;Unexpected transaction error - &quot; + event);
</ins><span class="cx">         done();
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     transaction.onabort = function(event) {
</span><del>-        --numberOfOpenTransactions;
-        debug(&quot;Unexpected transaction abort - &quot; + event);
</del><ins>+        log(&quot;Unexpected transaction abort - &quot; + event);
</ins><span class="cx">         done();
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     transaction.oncomplete = function(event) {
</span><del>-        --numberOfOpenTransactions;
-        debug(&quot;readonly transaction completed&quot;);
</del><ins>+        log(&quot;readonly transaction completed&quot;);
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (209068 => 209069)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2016-11-29 16:04:41 UTC (rev 209068)
+++ trunk/Source/WebCore/ChangeLog        2016-11-29 16:05:17 UTC (rev 209069)
</span><span class="lines">@@ -1,3 +1,75 @@
</span><ins>+2016-11-29  Brady Eidson  &lt;beidson@apple.com&gt;
+
+        IndexedDB 2.0: Queue up completed requests in the client, handle them one by one.
+        https://bugs.webkit.org/show_bug.cgi?id=165000
+
+        Reviewed by Alex Christensen.
+
+        No new tests (Covered extensively by every existing test).
+
+        Currently when a TransactionOperation completes on the server, it immediately completes
+        itself on the client side, including scheduling an event dispatch if necessary.
+        
+        This patch changes it so that &quot;server completed operations&quot; instead queue up in the 
+        IDBTransaction and are &quot;client-side completed&quot; asynchronously, 1-by-1.
+        
+        Currently this is a &quot;no behavior change&quot; because only one operation is ever sent to
+        the server at a time.
+        
+        But that will change with https://webkit.org/b/164932
+        And this patch is a pre-requisite for that.
+        
+        * Modules/indexeddb/IDBRequest.cpp:
+        (WebCore::IDBRequest::dispatchEvent):
+        (WebCore::IDBRequest::didOpenOrIterateCursor):
+        (WebCore::IDBRequest::completeRequestAndDispatchEvent):
+        (WebCore::IDBRequest::requestCompleted): Deleted.
+        * Modules/indexeddb/IDBRequest.h:
+        
+        * Modules/indexeddb/IDBTransaction.cpp:
+        (WebCore::IDBTransaction::IDBTransaction):
+        (WebCore::IDBTransaction::internalAbort):
+        (WebCore::IDBTransaction::abortOnServerAndCancelRequests):
+        (WebCore::IDBTransaction::scheduleOperation):
+        (WebCore::IDBTransaction::schedulePendingOperationTimer):
+        (WebCore::IDBTransaction::pendingOperationTimerFired):
+        (WebCore::IDBTransaction::operationCompletedOnServer):
+        (WebCore::IDBTransaction::scheduleCompletedOperationTimer):
+        (WebCore::IDBTransaction::completedOperationTimerFired):
+        (WebCore::IDBTransaction::completeNoncursorRequest):
+        (WebCore::IDBTransaction::completeCursorRequest):
+        (WebCore::IDBTransaction::finishedDispatchEventForRequest):
+        (WebCore::IDBTransaction::didStart):
+        (WebCore::IDBTransaction::didOpenCursorOnServer):
+        (WebCore::IDBTransaction::didIterateCursorOnServer):
+        (WebCore::IDBTransaction::didGetAllRecordsOnServer):
+        (WebCore::IDBTransaction::didGetRecordOnServer):
+        (WebCore::IDBTransaction::didGetCountOnServer):
+        (WebCore::IDBTransaction::didDeleteRecordOnServer):
+        (WebCore::IDBTransaction::didClearObjectStoreOnServer):
+        (WebCore::IDBTransaction::putOrAddOnServer):
+        (WebCore::IDBTransaction::didPutOrAddOnServer):
+        (WebCore::IDBTransaction::operationCompletedOnClient):
+        (WebCore::IDBTransaction::deactivate):
+        (WebCore::IDBTransaction::connectionClosedFromServer):
+        (WebCore::IDBTransaction::scheduleOperationTimer): Deleted.
+        (WebCore::IDBTransaction::operationTimerFired): Deleted.
+        (WebCore::IDBTransaction::operationDidComplete): Deleted.
+        * Modules/indexeddb/IDBTransaction.h:
+        
+        * Modules/indexeddb/client/IDBConnectionProxy.cpp:
+        (WebCore::IDBClient::IDBConnectionProxy::completeOperation):
+        
+        * Modules/indexeddb/client/TransactionOperation.cpp:
+        (WebCore::IDBClient::TransactionOperation::TransactionOperation):
+        * Modules/indexeddb/client/TransactionOperation.h:
+        (WebCore::IDBClient::TransactionOperation::transitionToCompleteOnThisThread):
+        (WebCore::IDBClient::TransactionOperation::transitionToComplete):
+        (WebCore::IDBClient::TransactionOperation::doComplete):
+        (WebCore::IDBClient::TransactionOperation::idbRequest):
+        (WebCore::IDBClient::TransactionOperation::performCompleteOnOriginThread): Deleted.
+        (WebCore::IDBClient::TransactionOperation::completed): Deleted.
+
</ins><span class="cx"> 2016-11-29  Zalan Bujtas  &lt;zalan@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Safari (WebKit) doesn't wrap element within flex when width comes below min-width
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbIDBRequestcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/IDBRequest.cpp (209068 => 209069)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/IDBRequest.cpp        2016-11-29 16:04:41 UTC (rev 209068)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBRequest.cpp        2016-11-29 16:05:17 UTC (rev 209069)
</span><span class="lines">@@ -304,6 +304,9 @@
</span><span class="cx">         m_transaction-&gt;abortDueToFailedRequest(*m_domError);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    if (m_transaction)
+        m_transaction-&gt;finishedDispatchEventForRequest(*this);
+
</ins><span class="cx">     return dontPreventDefault;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -465,10 +468,10 @@
</span><span class="cx">     m_cursorRequestNotifier = nullptr;
</span><span class="cx">     m_pendingCursor = nullptr;
</span><span class="cx"> 
</span><del>-    requestCompleted(resultData);
</del><ins>+    completeRequestAndDispatchEvent(resultData);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void IDBRequest::requestCompleted(const IDBResultData&amp; resultData)
</del><ins>+void IDBRequest::completeRequestAndDispatchEvent(const IDBResultData&amp; resultData)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(currentThread() == originThreadID());
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbIDBRequesth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/IDBRequest.h (209068 => 209069)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/IDBRequest.h        2016-11-29 16:04:41 UTC (rev 209068)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBRequest.h        2016-11-29 16:05:17 UTC (rev 209069)
</span><span class="lines">@@ -87,7 +87,7 @@
</span><span class="cx">     using RefCounted::ref;
</span><span class="cx">     using RefCounted::deref;
</span><span class="cx"> 
</span><del>-    void requestCompleted(const IDBResultData&amp;);
</del><ins>+    void completeRequestAndDispatchEvent(const IDBResultData&amp;);
</ins><span class="cx"> 
</span><span class="cx">     void setResult(const IDBKeyData&amp;);
</span><span class="cx">     void setResult(const Vector&lt;IDBKeyData&gt;&amp;);
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbIDBTransactioncpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.cpp (209068 => 209069)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.cpp        2016-11-29 16:04:41 UTC (rev 209068)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.cpp        2016-11-29 16:05:17 UTC (rev 209069)
</span><span class="lines">@@ -74,8 +74,10 @@
</span><span class="cx">     : IDBActiveDOMObject(database.scriptExecutionContext())
</span><span class="cx">     , m_database(database)
</span><span class="cx">     , m_info(info)
</span><del>-    , m_operationTimer(*this, &amp;IDBTransaction::operationTimerFired)
</del><ins>+    , m_pendingOperationTimer(*this, &amp;IDBTransaction::pendingOperationTimerFired)
+    , m_completedOperationTimer(*this, &amp;IDBTransaction::completedOperationTimerFired)
</ins><span class="cx">     , m_openDBRequest(request)
</span><ins>+    , m_currentlyCompletingRequest(request)
</ins><span class="cx"> 
</span><span class="cx"> {
</span><span class="cx">     LOG(IndexedDB, &quot;IDBTransaction::IDBTransaction - %s&quot;, m_info.loggingString().utf8().data());
</span><span class="lines">@@ -244,7 +246,7 @@
</span><span class="cx"> 
</span><span class="cx">     transitionedToFinishing(IndexedDB::TransactionState::Aborting);
</span><span class="cx">     
</span><del>-    m_abortQueue.swap(m_transactionOperationQueue);
</del><ins>+    m_abortQueue.swap(m_pendingTransactionOperationQueue);
</ins><span class="cx"> 
</span><span class="cx">     scheduleOperation(IDBClient::createTransactionOperation(*this, nullptr, &amp;IDBTransaction::abortOnServerAndCancelRequests));
</span><span class="cx"> }
</span><span class="lines">@@ -253,7 +255,7 @@
</span><span class="cx"> {
</span><span class="cx">     LOG(IndexedDB, &quot;IDBTransaction::abortOnServerAndCancelRequests&quot;);
</span><span class="cx">     ASSERT(currentThread() == m_database-&gt;originThreadID());
</span><del>-    ASSERT(m_transactionOperationQueue.isEmpty());
</del><ins>+    ASSERT(m_pendingTransactionOperationQueue.isEmpty());
</ins><span class="cx"> 
</span><span class="cx">     m_database-&gt;connectionProxy().abortTransaction(*this);
</span><span class="cx"> 
</span><span class="lines">@@ -260,12 +262,16 @@
</span><span class="cx">     ASSERT(m_transactionOperationMap.contains(operation.identifier()));
</span><span class="cx">     m_transactionOperationMap.remove(operation.identifier());
</span><span class="cx"> 
</span><ins>+    m_currentlyCompletingRequest = nullptr;
+    
</ins><span class="cx">     IDBError error(IDBDatabaseException::AbortError);
</span><del>-    for (auto&amp; operation : m_abortQueue)
-        operation-&gt;completed(IDBResultData::error(operation-&gt;identifier(), error));
</del><ins>+    for (auto&amp; operation : m_abortQueue) {
+        m_currentlyCompletingRequest = nullptr;
+        operation-&gt;doComplete(IDBResultData::error(operation-&gt;identifier(), error));
+    }
</ins><span class="cx"> 
</span><span class="cx">     // Since we're aborting, it should be impossible to have queued any further operations.
</span><del>-    ASSERT(m_transactionOperationQueue.isEmpty());
</del><ins>+    ASSERT(m_pendingTransactionOperationQueue.isEmpty());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> const char* IDBTransaction::activeDOMObjectName() const
</span><span class="lines">@@ -339,30 +345,30 @@
</span><span class="cx">     ASSERT(!m_transactionOperationMap.contains(operation-&gt;identifier()));
</span><span class="cx">     ASSERT(currentThread() == m_database-&gt;originThreadID());
</span><span class="cx"> 
</span><del>-    m_transactionOperationQueue.append(operation);
</del><ins>+    m_pendingTransactionOperationQueue.append(operation);
</ins><span class="cx">     m_transactionOperationMap.set(operation-&gt;identifier(), WTFMove(operation));
</span><span class="cx"> 
</span><del>-    scheduleOperationTimer();
</del><ins>+    schedulePendingOperationTimer();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void IDBTransaction::scheduleOperationTimer()
</del><ins>+void IDBTransaction::schedulePendingOperationTimer()
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(currentThread() == m_database-&gt;originThreadID());
</span><span class="cx"> 
</span><del>-    if (!m_operationTimer.isActive())
-        m_operationTimer.startOneShot(0);
</del><ins>+    if (!m_pendingOperationTimer.isActive())
+        m_pendingOperationTimer.startOneShot(0);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void IDBTransaction::operationTimerFired()
</del><ins>+void IDBTransaction::pendingOperationTimerFired()
</ins><span class="cx"> {
</span><del>-    LOG(IndexedDB, &quot;IDBTransaction::operationTimerFired (%p)&quot;, this);
</del><ins>+    LOG(IndexedDB, &quot;IDBTransaction::pendingOperationTimerFired (%p)&quot;, this);
</ins><span class="cx">     ASSERT(currentThread() == m_database-&gt;originThreadID());
</span><span class="cx"> 
</span><span class="cx">     if (!m_startedOnServer)
</span><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    if (!m_transactionOperationQueue.isEmpty()) {
-        auto operation = m_transactionOperationQueue.takeFirst();
</del><ins>+    if (!m_pendingTransactionOperationQueue.isEmpty()) {
+        auto operation = m_pendingTransactionOperationQueue.takeFirst();
</ins><span class="cx">         operation-&gt;perform();
</span><span class="cx"> 
</span><span class="cx">         return;
</span><span class="lines">@@ -375,6 +381,67 @@
</span><span class="cx">         commit();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void IDBTransaction::operationCompletedOnServer(const IDBResultData&amp; data, IDBClient::TransactionOperation&amp; operation)
+{
+    ASSERT(currentThread() == m_database-&gt;originThreadID());
+    ASSERT(currentThread() == operation.originThreadID());
+
+    m_completedOnServerQueue.append({ &amp;operation, data });
+    scheduleCompletedOperationTimer();
+}
+
+void IDBTransaction::scheduleCompletedOperationTimer()
+{
+    ASSERT(currentThread() == m_database-&gt;originThreadID());
+
+    if (!m_completedOperationTimer.isActive())
+        m_completedOperationTimer.startOneShot(0);
+}
+
+void IDBTransaction::completedOperationTimerFired()
+{
+    LOG(IndexedDB, &quot;IDBTransaction::completedOperationTimerFired (%p)&quot;, this);
+    ASSERT(currentThread() == m_database-&gt;originThreadID());
+
+    if (m_completedOnServerQueue.isEmpty() || m_currentlyCompletingRequest)
+        return;
+
+    auto iterator = m_completedOnServerQueue.takeFirst();
+    iterator.first-&gt;doComplete(iterator.second);
+
+    if (!m_completedOnServerQueue.isEmpty() &amp;&amp; !m_currentlyCompletingRequest)
+        scheduleCompletedOperationTimer();
+}
+
+void IDBTransaction::completeNoncursorRequest(IDBRequest&amp; request, const IDBResultData&amp; result)
+{
+    ASSERT(!m_currentlyCompletingRequest);
+
+    request.completeRequestAndDispatchEvent(result);
+
+    m_currentlyCompletingRequest = &amp;request;
+}
+
+void IDBTransaction::completeCursorRequest(IDBRequest&amp; request, const IDBResultData&amp; result)
+{
+    ASSERT(!m_currentlyCompletingRequest);
+
+    request.didOpenOrIterateCursor(result);
+
+    m_currentlyCompletingRequest = &amp;request;
+}
+
+void IDBTransaction::finishedDispatchEventForRequest(IDBRequest&amp; request)
+{
+    if (isFinishedOrFinishing())
+        return;
+
+    ASSERT_UNUSED(request, !m_currentlyCompletingRequest || m_currentlyCompletingRequest == &amp;request);
+
+    m_currentlyCompletingRequest = nullptr;
+    scheduleCompletedOperationTimer();
+}
+
</ins><span class="cx"> void IDBTransaction::commit()
</span><span class="cx"> {
</span><span class="cx">     LOG(IndexedDB, &quot;IDBTransaction::commit&quot;);
</span><span class="lines">@@ -422,7 +489,7 @@
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    scheduleOperationTimer();
</del><ins>+    schedulePendingOperationTimer();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void IDBTransaction::notifyDidAbort(const IDBError&amp; error)
</span><span class="lines">@@ -724,7 +791,7 @@
</span><span class="cx">     LOG(IndexedDB, &quot;IDBTransaction::didOpenCursorOnServer&quot;);
</span><span class="cx">     ASSERT(currentThread() == m_database-&gt;originThreadID());
</span><span class="cx"> 
</span><del>-    request.didOpenOrIterateCursor(resultData);
</del><ins>+    completeCursorRequest(request, resultData);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void IDBTransaction::iterateCursor(IDBCursor&amp; cursor, const IDBIterateCursorData&amp; data)
</span><span class="lines">@@ -753,7 +820,7 @@
</span><span class="cx">     LOG(IndexedDB, &quot;IDBTransaction::didIterateCursorOnServer&quot;);
</span><span class="cx">     ASSERT(currentThread() == m_database-&gt;originThreadID());
</span><span class="cx"> 
</span><del>-    request.didOpenOrIterateCursor(resultData);
</del><ins>+    completeCursorRequest(request, resultData);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> Ref&lt;IDBRequest&gt; IDBTransaction::requestGetAllObjectStoreRecords(JSC::ExecState&amp; state, IDBObjectStore&amp; objectStore, const IDBKeyRangeData&amp; keyRangeData, IndexedDB::GetAllType getAllType, std::optional&lt;uint32_t&gt; count)
</span><span class="lines">@@ -806,7 +873,7 @@
</span><span class="cx">     ASSERT(currentThread() == m_database-&gt;originThreadID());
</span><span class="cx"> 
</span><span class="cx">     if (resultData.type() == IDBResultType::Error) {
</span><del>-        request.requestCompleted(resultData);
</del><ins>+        completeNoncursorRequest(request, resultData);
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -822,7 +889,7 @@
</span><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    request.requestCompleted(resultData);
</del><ins>+    completeNoncursorRequest(request, resultData);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> Ref&lt;IDBRequest&gt; IDBTransaction::requestGetRecord(ExecState&amp; state, IDBObjectStore&amp; objectStore, const IDBGetRecordData&amp; getRecordData)
</span><span class="lines">@@ -890,7 +957,7 @@
</span><span class="cx">     ASSERT(currentThread() == m_database-&gt;originThreadID());
</span><span class="cx"> 
</span><span class="cx">     if (resultData.type() == IDBResultType::Error) {
</span><del>-        request.requestCompleted(resultData);
</del><ins>+        completeNoncursorRequest(request, resultData);
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -910,7 +977,7 @@
</span><span class="cx">             request.setResultToUndefined();
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    request.requestCompleted(resultData);
</del><ins>+    completeNoncursorRequest(request, resultData);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> Ref&lt;IDBRequest&gt; IDBTransaction::requestCount(ExecState&amp; state, IDBObjectStore&amp; objectStore, const IDBKeyRangeData&amp; range)
</span><span class="lines">@@ -961,7 +1028,7 @@
</span><span class="cx">     ASSERT(currentThread() == m_database-&gt;originThreadID());
</span><span class="cx"> 
</span><span class="cx">     request.setResult(resultData.resultInteger());
</span><del>-    request.requestCompleted(resultData);
</del><ins>+    completeNoncursorRequest(request, resultData);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> Ref&lt;IDBRequest&gt; IDBTransaction::requestDeleteRecord(ExecState&amp; state, IDBObjectStore&amp; objectStore, const IDBKeyRangeData&amp; range)
</span><span class="lines">@@ -994,7 +1061,7 @@
</span><span class="cx">     ASSERT(currentThread() == m_database-&gt;originThreadID());
</span><span class="cx"> 
</span><span class="cx">     request.setResultToUndefined();
</span><del>-    request.requestCompleted(resultData);
</del><ins>+    completeNoncursorRequest(request, resultData);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> Ref&lt;IDBRequest&gt; IDBTransaction::requestClearObjectStore(ExecState&amp; state, IDBObjectStore&amp; objectStore)
</span><span class="lines">@@ -1028,7 +1095,7 @@
</span><span class="cx">     ASSERT(currentThread() == m_database-&gt;originThreadID());
</span><span class="cx"> 
</span><span class="cx">     request.setResultToUndefined();
</span><del>-    request.requestCompleted(resultData);
</del><ins>+    completeNoncursorRequest(request, resultData);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> Ref&lt;IDBRequest&gt; IDBTransaction::requestPutOrAdd(ExecState&amp; state, IDBObjectStore&amp; objectStore, IDBKey* key, SerializedScriptValue&amp; value, IndexedDB::ObjectStoreOverwriteMode overwriteMode)
</span><span class="lines">@@ -1074,7 +1141,7 @@
</span><span class="cx">             RefPtr&lt;IDBClient::TransactionOperation&gt; protectedOperation(&amp;operation);
</span><span class="cx">             auto result = IDBResultData::error(operation.identifier(), { IDBDatabaseException::UnknownError, ASCIILiteral(&quot;Error preparing Blob/File data to be stored in object store&quot;) });
</span><span class="cx">             scriptExecutionContext()-&gt;postTask([protectedOperation = WTFMove(protectedOperation), result = WTFMove(result)](ScriptExecutionContext&amp;) {
</span><del>-                protectedOperation-&gt;completed(result);
</del><ins>+                protectedOperation-&gt;doComplete(result);
</ins><span class="cx">             });
</span><span class="cx">         }
</span><span class="cx">         return;
</span><span class="lines">@@ -1092,7 +1159,7 @@
</span><span class="cx">         // In that case, we cannot successfully store this record, so we callback with an error.
</span><span class="cx">         auto result = IDBResultData::error(protectedOperation-&gt;identifier(), { IDBDatabaseException::UnknownError, ASCIILiteral(&quot;Error preparing Blob/File data to be stored in object store&quot;) });
</span><span class="cx">         callOnMainThread([protectedThis = WTFMove(protectedThis), protectedOperation = WTFMove(protectedOperation), result = WTFMove(result)]() mutable {
</span><del>-            protectedOperation-&gt;completed(result);
</del><ins>+            protectedOperation-&gt;doComplete(result);
</ins><span class="cx">         });
</span><span class="cx">     });
</span><span class="cx"> }
</span><span class="lines">@@ -1106,7 +1173,7 @@
</span><span class="cx">         request.setResult(*result);
</span><span class="cx">     else
</span><span class="cx">         request.setResultToUndefined();
</span><del>-    request.requestCompleted(resultData);
</del><ins>+    completeNoncursorRequest(request, resultData);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void IDBTransaction::deleteObjectStore(const String&amp; objectStoreName)
</span><span class="lines">@@ -1167,8 +1234,10 @@
</span><span class="cx">     ASSERT_UNUSED(resultData, resultData.type() == IDBResultType::DeleteIndexSuccess || resultData.type() == IDBResultType::Error);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void IDBTransaction::operationDidComplete(IDBClient::TransactionOperation&amp; operation)
</del><ins>+void IDBTransaction::operationCompletedOnClient(IDBClient::TransactionOperation&amp; operation)
</ins><span class="cx"> {
</span><ins>+    LOG(IndexedDB, &quot;IDBTransaction::operationCompletedOnClient&quot;);
+
</ins><span class="cx">     ASSERT(m_transactionOperationMap.get(operation.identifier()) == &amp;operation);
</span><span class="cx">     ASSERT(currentThread() == m_database-&gt;originThreadID());
</span><span class="cx">     ASSERT(currentThread() == operation.originThreadID());
</span><span class="lines">@@ -1175,7 +1244,7 @@
</span><span class="cx"> 
</span><span class="cx">     m_transactionOperationMap.remove(operation.identifier());
</span><span class="cx"> 
</span><del>-    scheduleOperationTimer();
</del><ins>+    schedulePendingOperationTimer();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void IDBTransaction::establishOnServer()
</span><span class="lines">@@ -1203,7 +1272,7 @@
</span><span class="cx">     if (m_state == IndexedDB::TransactionState::Active)
</span><span class="cx">         m_state = IndexedDB::TransactionState::Inactive;
</span><span class="cx"> 
</span><del>-    scheduleOperationTimer();
</del><ins>+    schedulePendingOperationTimer();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void IDBTransaction::connectionClosedFromServer(const IDBError&amp; error)
</span><span class="lines">@@ -1215,12 +1284,14 @@
</span><span class="cx">     Vector&lt;RefPtr&lt;IDBClient::TransactionOperation&gt;&gt; operations;
</span><span class="cx">     copyValuesToVector(m_transactionOperationMap, operations);
</span><span class="cx"> 
</span><del>-    for (auto&amp; operation : operations)
-        operation-&gt;completed(IDBResultData::error(operation-&gt;identifier(), error));
</del><ins>+    for (auto&amp; operation : operations) {
+        m_currentlyCompletingRequest = nullptr;
+        operation-&gt;doComplete(IDBResultData::error(operation-&gt;identifier(), error));
+    }
</ins><span class="cx"> 
</span><span class="cx">     connectionProxy().forgetActiveOperations(operations);
</span><span class="cx"> 
</span><del>-    m_transactionOperationQueue.clear();
</del><ins>+    m_pendingTransactionOperationQueue.clear();
</ins><span class="cx">     m_abortQueue.clear();
</span><span class="cx">     m_transactionOperationMap.clear();
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbIDBTransactionh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.h (209068 => 209069)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.h        2016-11-29 16:04:41 UTC (rev 209068)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.h        2016-11-29 16:05:17 UTC (rev 209069)
</span><span class="lines">@@ -138,8 +138,11 @@
</span><span class="cx">     void activate();
</span><span class="cx">     void deactivate();
</span><span class="cx"> 
</span><del>-    void operationDidComplete(IDBClient::TransactionOperation&amp;);
</del><ins>+    void operationCompletedOnServer(const IDBResultData&amp;, IDBClient::TransactionOperation&amp;);
+    void operationCompletedOnClient(IDBClient::TransactionOperation&amp;);
</ins><span class="cx"> 
</span><ins>+    void finishedDispatchEventForRequest(IDBRequest&amp;);
+
</ins><span class="cx">     bool isFinishedOrFinishing() const;
</span><span class="cx">     bool isFinished() const { return m_state == IndexedDB::TransactionState::Finished; }
</span><span class="cx"> 
</span><span class="lines">@@ -159,7 +162,8 @@
</span><span class="cx">     void finishAbortOrCommit();
</span><span class="cx"> 
</span><span class="cx">     void scheduleOperation(RefPtr&lt;IDBClient::TransactionOperation&gt;&amp;&amp;);
</span><del>-    void operationTimerFired();
</del><ins>+    void pendingOperationTimerFired();
+    void completedOperationTimerFired();
</ins><span class="cx"> 
</span><span class="cx">     void fireOnComplete();
</span><span class="cx">     void fireOnAbort();
</span><span class="lines">@@ -217,8 +221,12 @@
</span><span class="cx"> 
</span><span class="cx">     void establishOnServer();
</span><span class="cx"> 
</span><del>-    void scheduleOperationTimer();
</del><ins>+    void completeNoncursorRequest(IDBRequest&amp;, const IDBResultData&amp;);
+    void completeCursorRequest(IDBRequest&amp;, const IDBResultData&amp;);
</ins><span class="cx"> 
</span><ins>+    void schedulePendingOperationTimer();
+    void scheduleCompletedOperationTimer();
+
</ins><span class="cx">     Ref&lt;IDBDatabase&gt; m_database;
</span><span class="cx">     IDBTransactionInfo m_info;
</span><span class="cx"> 
</span><span class="lines">@@ -228,12 +236,14 @@
</span><span class="cx">     IDBError m_idbError;
</span><span class="cx">     RefPtr&lt;DOMError&gt; m_domError;
</span><span class="cx"> 
</span><del>-    Timer m_operationTimer;
</del><ins>+    Timer m_pendingOperationTimer;
+    Timer m_completedOperationTimer;
</ins><span class="cx">     std::unique_ptr&lt;Timer&gt; m_activationTimer;
</span><span class="cx"> 
</span><span class="cx">     RefPtr&lt;IDBOpenDBRequest&gt; m_openDBRequest;
</span><span class="cx"> 
</span><del>-    Deque&lt;RefPtr&lt;IDBClient::TransactionOperation&gt;&gt; m_transactionOperationQueue;
</del><ins>+    Deque&lt;RefPtr&lt;IDBClient::TransactionOperation&gt;&gt; m_pendingTransactionOperationQueue;
+    Deque&lt;std::pair&lt;RefPtr&lt;IDBClient::TransactionOperation&gt;, IDBResultData&gt;&gt; m_completedOnServerQueue;
</ins><span class="cx">     Deque&lt;RefPtr&lt;IDBClient::TransactionOperation&gt;&gt; m_abortQueue;
</span><span class="cx">     HashMap&lt;IDBResourceIdentifier, RefPtr&lt;IDBClient::TransactionOperation&gt;&gt; m_transactionOperationMap;
</span><span class="cx"> 
</span><span class="lines">@@ -242,6 +252,7 @@
</span><span class="cx">     HashMap&lt;uint64_t, std::unique_ptr&lt;IDBObjectStore&gt;&gt; m_deletedObjectStores;
</span><span class="cx"> 
</span><span class="cx">     HashSet&lt;RefPtr&lt;IDBRequest&gt;&gt; m_openRequests;
</span><ins>+    RefPtr&lt;IDBRequest&gt; m_currentlyCompletingRequest;
</ins><span class="cx"> 
</span><span class="cx">     bool m_contextStopped { false };
</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 (209068 => 209069)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/client/IDBConnectionProxy.cpp        2016-11-29 16:04:41 UTC (rev 209068)
+++ trunk/Source/WebCore/Modules/indexeddb/client/IDBConnectionProxy.cpp        2016-11-29 16:05:17 UTC (rev 209069)
</span><span class="lines">@@ -249,7 +249,7 @@
</span><span class="cx">     if (!operation)
</span><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    operation-&gt;performCompleteOnOriginThread(resultData, WTFMove(operation));
</del><ins>+    operation-&gt;transitionToComplete(resultData, WTFMove(operation));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void IDBConnectionProxy::abortOpenAndUpgradeNeeded(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier&amp; transactionIdentifier)
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbclientTransactionOperationcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/client/TransactionOperation.cpp (209068 => 209069)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/client/TransactionOperation.cpp        2016-11-29 16:04:41 UTC (rev 209068)
+++ trunk/Source/WebCore/Modules/indexeddb/client/TransactionOperation.cpp        2016-11-29 16:05:17 UTC (rev 209069)
</span><span class="lines">@@ -43,6 +43,8 @@
</span><span class="cx">         m_indexRecordType = request.requestedIndexRecordType();
</span><span class="cx">     if (auto* cursor = request.pendingCursor())
</span><span class="cx">         m_cursorIdentifier = std::make_unique&lt;IDBResourceIdentifier&gt;(cursor-&gt;info().identifier());
</span><ins>+
+    m_idbRequest = &amp;request;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> } // namespace IDBClient
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbclientTransactionOperationh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/client/TransactionOperation.h (209068 => 209069)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/client/TransactionOperation.h        2016-11-29 16:04:41 UTC (rev 209068)
+++ trunk/Source/WebCore/Modules/indexeddb/client/TransactionOperation.h        2016-11-29 16:05:17 UTC (rev 209069)
</span><span class="lines">@@ -61,25 +61,31 @@
</span><span class="cx">         m_performFunction = { };
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void performCompleteOnOriginThread(const IDBResultData&amp; data, RefPtr&lt;TransactionOperation&gt;&amp;&amp; lastRef)
</del><ins>+    void transitionToCompleteOnThisThread(const IDBResultData&amp; data)
</ins><span class="cx">     {
</span><ins>+        ASSERT(m_originThreadID == currentThread());
+        m_transaction-&gt;operationCompletedOnServer(data, *this);
+    }
+
+    void transitionToComplete(const IDBResultData&amp; data, RefPtr&lt;TransactionOperation&gt;&amp;&amp; lastRef)
+    {
</ins><span class="cx">         ASSERT(isMainThread());
</span><span class="cx"> 
</span><span class="cx">         if (m_originThreadID == currentThread())
</span><del>-            completed(data);
</del><ins>+            transitionToCompleteOnThisThread(data);
</ins><span class="cx">         else {
</span><del>-            m_transaction-&gt;performCallbackOnOriginThread(*this, &amp;TransactionOperation::completed, data);
</del><ins>+            m_transaction-&gt;performCallbackOnOriginThread(*this, &amp;TransactionOperation::transitionToCompleteOnThisThread, data);
</ins><span class="cx">             m_transaction-&gt;callFunctionOnOriginThread([lastRef = WTFMove(lastRef)]() {
</span><span class="cx">             });
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void completed(const IDBResultData&amp; data)
</del><ins>+    void doComplete(const IDBResultData&amp; data)
</ins><span class="cx">     {
</span><span class="cx">         ASSERT(m_originThreadID == currentThread());
</span><span class="cx">         ASSERT(m_completeFunction);
</span><span class="cx">         m_completeFunction(data);
</span><del>-        m_transaction-&gt;operationDidComplete(*this);
</del><ins>+        m_transaction-&gt;operationCompletedOnClient(*this);
</ins><span class="cx"> 
</span><span class="cx">         // m_completeFunction might be holding the last ref to this TransactionOperation,
</span><span class="cx">         // so we need to do this trick to null it out without first destroying it.
</span><span class="lines">@@ -91,6 +97,8 @@
</span><span class="cx"> 
</span><span class="cx">     ThreadIdentifier originThreadID() const { return m_originThreadID; }
</span><span class="cx"> 
</span><ins>+    IDBRequest* idbRequest() { return m_idbRequest.get(); }
+
</ins><span class="cx"> protected:
</span><span class="cx">     TransactionOperation(IDBTransaction&amp; transaction)
</span><span class="cx">         : m_transaction(transaction)
</span><span class="lines">@@ -118,6 +126,7 @@
</span><span class="cx">     IndexedDB::IndexRecordType indexRecordType() const { return m_indexRecordType; }
</span><span class="cx"> 
</span><span class="cx">     ThreadIdentifier m_originThreadID { currentThread() };
</span><ins>+    RefPtr&lt;IDBRequest&gt; m_idbRequest;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> template &lt;typename... Arguments&gt;
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbserverSQLiteIDBBackingStorecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.cpp (209068 => 209069)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.cpp        2016-11-29 16:04:41 UTC (rev 209068)
+++ trunk/Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.cpp        2016-11-29 16:05:17 UTC (rev 209069)
</span><span class="lines">@@ -807,11 +807,8 @@
</span><span class="cx">         return { IDBDatabaseException::UnknownError, ASCIILiteral(&quot;Attempt to abort a transaction that hasn't been established&quot;) };
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-
-    if (transaction-&gt;mode() == IDBTransactionMode::Versionchange) {
-        ASSERT(m_originalDatabaseInfoBeforeVersionChange);
</del><ins>+    if (transaction-&gt;mode() == IDBTransactionMode::Versionchange &amp;&amp; m_originalDatabaseInfoBeforeVersionChange)
</ins><span class="cx">         m_databaseInfo = WTFMove(m_originalDatabaseInfoBeforeVersionChange);
</span><del>-    }
</del><span class="cx"> 
</span><span class="cx">     return transaction-&gt;abort();
</span><span class="cx"> }
</span></span></pre>
</div>
</div>

</body>
</html>