<!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>[194649] 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/194649">194649</a></dd>
<dt>Author</dt> <dd>beidson@apple.com</dd>
<dt>Date</dt> <dd>2016-01-06 11:24:57 -0800 (Wed, 06 Jan 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>Modern IDB: storage/indexeddb/transaction-scope-sequencing.html fails
https://bugs.webkit.org/show_bug.cgi?id=152775

Reviewed by Alex Christensen.

Source/WebCore:

No new tests (At least one failing test now passes, plus changes to another existing test).

Any transaction enqueued after a read-write transaction whose scope overlaps with
that read-write transaction cannot run until after that read-write transaction runs.

Additionally, read-only transactions were actually sometimes running even though their scopes
overlapped with a running read-write transaction.

This patch fixes both of those issues.

* Modules/indexeddb/server/UniqueIDBDatabase.cpp:
(WebCore::IDBServer::UniqueIDBDatabase::operationAndTransactionTimerFired):
(WebCore::IDBServer::UniqueIDBDatabase::takeNextRunnableTransaction):
(WebCore::IDBServer::UniqueIDBDatabase::inProgressTransactionCompleted):
* Modules/indexeddb/server/UniqueIDBDatabase.h:

LayoutTests:

In addition to enabling the previously skipped test, this also completely rewrites transaction-scheduler-4,
which covered incorrect behavior, to cover newly implemented correct behavior.

* platform/mac-wk1/TestExpectations:
* storage/indexeddb/modern/resources/transaction-scheduler-4.js: Added.
* storage/indexeddb/modern/transaction-scheduler-4-expected.txt:
* storage/indexeddb/modern/transaction-scheduler-4.html:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsplatformmacwk1TestExpectations">trunk/LayoutTests/platform/mac-wk1/TestExpectations</a></li>
<li><a href="#trunkLayoutTestsstorageindexeddbmoderntransactionscheduler4expectedtxt">trunk/LayoutTests/storage/indexeddb/modern/transaction-scheduler-4-expected.txt</a></li>
<li><a href="#trunkLayoutTestsstorageindexeddbmoderntransactionscheduler4html">trunk/LayoutTests/storage/indexeddb/modern/transaction-scheduler-4.html</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</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>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsstorageindexeddbmodernresourcestransactionscheduler4js">trunk/LayoutTests/storage/indexeddb/modern/resources/transaction-scheduler-4.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (194648 => 194649)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2016-01-06 19:17:55 UTC (rev 194648)
+++ trunk/LayoutTests/ChangeLog        2016-01-06 19:24:57 UTC (rev 194649)
</span><span class="lines">@@ -1,3 +1,18 @@
</span><ins>+2016-01-06  Brady Eidson  &lt;beidson@apple.com&gt;
+
+        Modern IDB: storage/indexeddb/transaction-scope-sequencing.html fails
+        https://bugs.webkit.org/show_bug.cgi?id=152775
+
+        Reviewed by Alex Christensen.
+
+        In addition to enabling the previously skipped test, this also completely rewrites transaction-scheduler-4, 
+        which covered incorrect behavior, to cover newly implemented correct behavior.
+
+        * platform/mac-wk1/TestExpectations:
+        * storage/indexeddb/modern/resources/transaction-scheduler-4.js: Added.
+        * storage/indexeddb/modern/transaction-scheduler-4-expected.txt:
+        * storage/indexeddb/modern/transaction-scheduler-4.html:
+
</ins><span class="cx"> 2016-01-06  Zalan Bujtas  &lt;zalan@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Float with media query positioned incorrectly after window resize.
</span></span></pre></div>
<a id="trunkLayoutTestsplatformmacwk1TestExpectations"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/platform/mac-wk1/TestExpectations (194648 => 194649)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/platform/mac-wk1/TestExpectations        2016-01-06 19:17:55 UTC (rev 194648)
+++ trunk/LayoutTests/platform/mac-wk1/TestExpectations        2016-01-06 19:24:57 UTC (rev 194649)
</span><span class="lines">@@ -89,7 +89,6 @@
</span><span class="cx"> storage/indexeddb/open-db-private-browsing.html [ Failure ]
</span><span class="cx"> storage/indexeddb/properties-disabled-at-runtime.html [ Failure ]
</span><span class="cx"> storage/indexeddb/setversion-blocked-by-versionchange-close.html [ Failure ]
</span><del>-storage/indexeddb/transaction-scope-sequencing.html [ Failure ]
</del><span class="cx"> 
</span><span class="cx"> # Relies on internals.observeGC
</span><span class="cx"> storage/indexeddb/connection-leak.html [ Skip ]
</span></span></pre></div>
<a id="trunkLayoutTestsstorageindexeddbmodernresourcestransactionscheduler4js"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/storage/indexeddb/modern/resources/transaction-scheduler-4.js (0 => 194649)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/storage/indexeddb/modern/resources/transaction-scheduler-4.js                                (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/modern/resources/transaction-scheduler-4.js        2016-01-06 19:24:57 UTC (rev 194649)
</span><span class="lines">@@ -0,0 +1,57 @@
</span><ins>+description(&quot;Makes sure that a read-only transaction scheduled after a read-write transaction with overlapping scope does not start until the read-write transaction completes&quot;);
+
+indexedDBTest(prepareDatabase, versionChangeSuccessCallback);
+
+function prepareDatabase()
+{
+    evalAndLog(&quot;connection = event.target.result;&quot;);
+    evalAndLog(&quot;objectStore = connection.createObjectStore('store');&quot;);
+}
+
+function versionChangeSuccessCallback()
+{
+    evalAndLog(&quot;transaction1 = connection.transaction('store', 'readwrite');&quot;);
+    evalAndLog(&quot;transaction2 = connection.transaction('store', 'readonly');&quot;);
+    evalAndLog(&quot;getRequest = transaction2.objectStore('store').get('foo');&quot;);
+
+    debug(&quot;Starting a series of 20 puts in the readwrite transaction to make sure the readonly transaction is deferred for some time&quot;);
+    evalAndLog(&quot;putCount = 0;&quot;);
+    evalAndLog(&quot;readWriteTransactionDone = false;&quot;);
+    evalAndLog(&quot;getRequestDone = false;&quot;);
+    var putSuccess = function() {
+        if (++putCount == 20) {
+            debug(&quot;20th put complete&quot;);
+            return;
+        }
+        
+        var newRequest = transaction1.objectStore('store').put('bar', 'foo');
+        newRequest.onsuccess = putSuccess;
+    };
+
+    var request = transaction1.objectStore('store').put('bar', 'foo');
+    request.onsuccess = putSuccess;
+
+
+
+    transaction1.oncomplete = function() {
+        debug(&quot;Transaction 1 (readwrite) completed with &quot; + putCount + &quot; puts completed.&quot;);
+        shouldBeFalse(&quot;getRequestDone&quot;);
+        shouldBe(&quot;putCount&quot;, &quot;20&quot;);
+        readWriteTransactionDone = true;
+    }
+
+    getRequest.onsuccess = function() {
+        debug(&quot;Getting the value of 'foo' completed - This means the readonly transaction started. At this point &quot; + putCount + &quot; puts completed in the readwrite transaction.&quot;);
+        shouldBeTrue(&quot;readWriteTransactionDone&quot;);
+        shouldBe(&quot;putCount&quot;, &quot;20&quot;);
+        getRequestDone = true;
+    }
+
+    transaction2.oncomplete = function() {
+        debug(&quot;Transaction 1 (readonly) completed&quot;);
+        shouldBeTrue(&quot;readWriteTransactionDone&quot;);
+        shouldBeTrue(&quot;getRequestDone&quot;);
+        shouldBe(&quot;putCount&quot;, &quot;20&quot;);
+        finishJSTest();
+    }
+}
</ins></span></pre></div>
<a id="trunkLayoutTestsstorageindexeddbmoderntransactionscheduler4expectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/storage/indexeddb/modern/transaction-scheduler-4-expected.txt (194648 => 194649)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/storage/indexeddb/modern/transaction-scheduler-4-expected.txt        2016-01-06 19:17:55 UTC (rev 194648)
+++ trunk/LayoutTests/storage/indexeddb/modern/transaction-scheduler-4-expected.txt        2016-01-06 19:24:57 UTC (rev 194649)
</span><span class="lines">@@ -1,20 +1,34 @@
</span><del>-ALERT: Upgrade needed: Old version - 0 New version - 1
-ALERT: versionchange transaction completed
-ALERT: Success opening database connection - Starting readonly transaction
-ALERT: Other objectstore read transaction get success - [object Event]
-ALERT: Other objectstore read transaction complete - [object Event]
-ALERT: Read transaction complete - [object Event]
-ALERT: Write transaction first put success
-ALERT: Second read-only transaction get success - [object Event]
-ALERT: Write transaction complete - [object Event]
-ALERT: Second read-only transaction complete - [object Event]
-ALERT: Done
-This test opens a long running read-only transaction to an object store, and then a read-write transaction to the same object store.
-The read-write transaction should be blocked while the long running read-only transaction is in progress.
-It also queues up a second read-only transaction to that same object store behind the blocked read-write transaction.
-Even though that second read-only transaction could start while the first is in progress and the read-write transaction is blocked,
-it should *not* start because doing so would risk continuing to block the read-write transaction.
-It also queues up a read-only to a different object store behind those first three transactions.
-That last read-only transaction *should* start while the read-write transaction is still blocked,
-as doing so won't risk blocking the read-write transaction further.
</del><ins>+Makes sure that a read-only transaction scheduled after a read-write transaction with overlapping scope does not start until the read-write transaction completes
</ins><span class="cx"> 
</span><ins>+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;
+
+dbname = &quot;transaction-scheduler-4.html&quot;
+indexedDB.deleteDatabase(dbname)
+indexedDB.open(dbname)
+connection = event.target.result;
+objectStore = connection.createObjectStore('store');
+transaction1 = connection.transaction('store', 'readwrite');
+transaction2 = connection.transaction('store', 'readonly');
+getRequest = transaction2.objectStore('store').get('foo');
+Starting a series of 20 puts in the readwrite transaction to make sure the readonly transaction is deferred for some time
+putCount = 0;
+readWriteTransactionDone = false;
+getRequestDone = false;
+20th put complete
+Transaction 1 (readwrite) completed with 20 puts completed.
+PASS getRequestDone is false
+PASS putCount is 20
+Getting the value of 'foo' completed - This means the readonly transaction started. At this point 20 puts completed in the readwrite transaction.
+PASS readWriteTransactionDone is true
+PASS putCount is 20
+Transaction 1 (readonly) completed
+PASS readWriteTransactionDone is true
+PASS getRequestDone is true
+PASS putCount is 20
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsstorageindexeddbmoderntransactionscheduler4html"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/storage/indexeddb/modern/transaction-scheduler-4.html (194648 => 194649)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/storage/indexeddb/modern/transaction-scheduler-4.html        2016-01-06 19:17:55 UTC (rev 194648)
+++ trunk/LayoutTests/storage/indexeddb/modern/transaction-scheduler-4.html        2016-01-06 19:24:57 UTC (rev 194649)
</span><span class="lines">@@ -1,233 +1,9 @@
</span><del>-This test opens a long running read-only transaction to an object store, and then a read-write transaction to the same object store.&lt;br&gt;
-The read-write transaction should be blocked while the long running read-only transaction is in progress.&lt;br&gt;
-It also queues up a second read-only transaction to that same object store behind the blocked read-write transaction.&lt;br&gt;
-Even though that second read-only transaction could start while the first is in progress and the read-write transaction is blocked,&lt;br&gt;
-it should *not* start because doing so would risk continuing to block the read-write transaction.&lt;br&gt;
-It also queues up a read-only to a different object store behind those first three transactions.&lt;br&gt;
-That last read-only transaction *should* start while the read-write transaction is still blocked,&lt;br&gt;
-as doing so won't risk blocking the read-write transaction further.&lt;br&gt;
-&lt;script&gt;
-
-if (window.testRunner) {
-    testRunner.waitUntilDone();
-    testRunner.dumpAsText();
-}
-
-function done()
-{
-    alert(&quot;Done&quot;);
-    if (window.testRunner)
-        testRunner.notifyDone();
-}
-
-var createRequest = window.indexedDB.open(&quot;TransactionScheduler4Database&quot;);
-
-createRequest.onupgradeneeded = function(event) {
-    alert(&quot;Upgrade needed: Old version - &quot; + event.oldVersion + &quot; New version - &quot; + event.newVersion);
-
-    var versionTransaction = createRequest.transaction;
-    var database = event.target.result;
-    var objectStore = database.createObjectStore(&quot;OS&quot;);
-    var request = objectStore.put(&quot;bar&quot;, &quot;foo&quot;);
-
-    request.onerror = function(event) {
-        alert(&quot;first put FAILED - &quot; + event);
-        done();
-    }
-
-    objectStore = database.createObjectStore(&quot;OtherOS&quot;);
-    request = objectStore.put(&quot;bar&quot;, &quot;foo&quot;);
-    
-    request.onerror = function(event) {
-        alert(&quot;second put FAILED - &quot; + event);
-        done();
-    }
-    
-    versionTransaction.onabort = function(event) {
-        alert(&quot;versionchange transaction aborted&quot;);
-        done();
-    }
-
-    versionTransaction.oncomplete = function(event) {
-        alert(&quot;versionchange transaction completed&quot;);
-        continueTest();
-        database.close();
-    }
-
-    versionTransaction.onerror = function(event) {
-        alert(&quot;versionchange transaction error'ed - &quot; + event);
-        done();
-    }
-}
-
-var secondDatabaseConnection;
-function continueTest()
-{
-    var longRunningReadRequest = window.indexedDB.open(&quot;TransactionScheduler4Database&quot;, 1);
-    longRunningReadRequest.onsuccess = function(event) {
-        alert(&quot;Success opening database connection - Starting readonly transaction&quot;);
-        secondDatabaseConnection = event.target.result;
-        
-        var transaction = secondDatabaseConnection.transaction(&quot;OS&quot;, &quot;readonly&quot;);
-        
-        transaction.onerror = function(event) {
-            alert(&quot;Unexpected transaction error - &quot; + event);
-            done();
-        }
-
-        transaction.onabort = function(event) {
-            alert(&quot;Unexpected transaction abort - &quot; + event);
-            done();
-        }
-
-        transaction.oncomplete = function(event) {
-            alert(&quot;Read transaction complete - &quot; + event);
-        }
-        
-        firstReadTransactionLoop(transaction, true);
-    }
-    longRunningReadRequest.onerror = function(event) {
-        alert(&quot;Long running read request unexpected error - &quot; + event);
-        done();
-    }
-    longRunningReadRequest.onblocked = function(event) {
-        alert(&quot;Long running read request unexpected blocked - &quot; + event);
-        done();
-    }
-    longRunningReadRequest.onupgradeneeded = function(event) {
-        alert(&quot;Long running read request unexpected upgradeneeded - &quot; + event);
-        done();
-    } 
-}
-
-var shouldEndReadTransaction = false;
-
-function firstReadTransactionLoop(transaction, isFirstTime)
-{
-    var objectStore = transaction.objectStore(&quot;OS&quot;);
-    var request = objectStore.get(&quot;foo&quot;);
-    
-    request.onsuccess = function(event) {
-        if (shouldEndReadTransaction)
-            return;
-            
-        firstReadTransactionLoop(event.target.transaction, false);
-        
-        // Now that the read transaction is open, the other transactions can be queued up.
-        if (isFirstTime)
-             startOtherTransactions()
-    }
-
-    request.onerror = function(event) {
-        alert(&quot;Unexpected request error - &quot; + event);
-        done();
-    }
-}
-
-var shouldEndReadTransaction = false;
-var loggedWritePutSuccessOnce = false;
-function writeTransactionLoop(transaction)
-{
-    var objectStore = transaction.objectStore(&quot;OS&quot;);
-    var request = objectStore.put(&quot;baz&quot;, &quot;foo&quot;);
-
-    request.onsuccess = function(event) {
-        if (!loggedWritePutSuccessOnce) {
-            alert(&quot;Write transaction first put success&quot;);
-            loggedWritePutSuccessOnce = true;
-        }
-        if (shouldEndReadTransaction)
-            return;
-        
-        writeTransactionLoop(transaction);
-    }
-    
-    request.onerror = function(event) {
-        alert(&quot;Write transaction put unexpected error - &quot; + event);
-        done();
-    }
-}
-
-function startOtherTransactions()
-{
-    var transaction = secondDatabaseConnection.transaction(&quot;OS&quot;, &quot;readwrite&quot;);
-
-    transaction.onerror = function(event) {
-        alert(&quot;Write transaction unexpected error - &quot; + event);
-        done();
-    }
-
-    transaction.onabort = function(event) {
-        alert(&quot;Write transaction unexpected abort - &quot; + event);
-        done();
-    }
-
-    transaction.oncomplete = function(event) {
-        alert(&quot;Write transaction complete - &quot; + event);
-    }
-    
-    writeTransactionLoop(transaction);
-
-    // This read-only transaction should be blocked behind the read-write transaction above, 
-    // and should not start until it finishes.
-    transaction = secondDatabaseConnection.transaction(&quot;OS&quot;, &quot;readonly&quot;);
-    transaction.onerror = function(event) {
-        alert(&quot;Second read-only transaction unexpected error - &quot; + event);
-        done();
-    }
-
-    transaction.onabort = function(event) {
-        alert(&quot;Second read-only transaction unexpected abort - &quot; + event);
-        done();
-    }
-
-    transaction.oncomplete = function(event) {
-        alert(&quot;Second read-only transaction complete - &quot; + event);
-        done();
-    }
-    
-    var objectStore = transaction.objectStore(&quot;OS&quot;);
-    var request = objectStore.get(&quot;foo&quot;);
-
-    request.onsuccess = function(event) {
-        alert(&quot;Second read-only transaction get success - &quot; + event);
-    }
-    
-    request.onerror = function(event) {
-        alert(&quot;Second read-only transaction put unexpected error - &quot; + event);
-        done();
-    }
-
-    // This read-only transaction is queued behind the 3 previous transactions, but should not
-    // be blocked because its scope doesn't overlap the read-write transaction.
-    transaction = secondDatabaseConnection.transaction(&quot;OtherOS&quot;, &quot;readonly&quot;);
-
-    transaction.onerror = function(event) {
-        alert(&quot;Other objectstore read transaction unexpected error - &quot; + event);
-        done();
-    }
-
-    transaction.onabort = function(event) {
-        alert(&quot;Other objectstore read transaction unexpected abort - &quot; + event);
-        done();
-    }
-
-    transaction.oncomplete = function(event) {
-        alert(&quot;Other objectstore read transaction complete - &quot; + event);
-        shouldEndReadTransaction = true;
-    }
-
-    objectStore = transaction.objectStore(&quot;OtherOS&quot;);
-    request = objectStore.get(&quot;foo&quot;);
-
-    request.onsuccess = function(event) {
-        alert(&quot;Other objectstore read transaction get success - &quot; + event);
-    }
-    
-    request.onerror = function(event) {
-        alert(&quot;Other objectstore read transaction get unexpected error - &quot; + event);
-        done();
-    }
-}
-
-&lt;/script&gt;
</del><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/transaction-scheduler-4.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (194648 => 194649)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2016-01-06 19:17:55 UTC (rev 194648)
+++ trunk/Source/WebCore/ChangeLog        2016-01-06 19:24:57 UTC (rev 194649)
</span><span class="lines">@@ -1,3 +1,26 @@
</span><ins>+2016-01-06  Brady Eidson  &lt;beidson@apple.com&gt;
+
+        Modern IDB: storage/indexeddb/transaction-scope-sequencing.html fails
+        https://bugs.webkit.org/show_bug.cgi?id=152775
+
+        Reviewed by Alex Christensen.
+
+        No new tests (At least one failing test now passes, plus changes to another existing test).
+        
+        Any transaction enqueued after a read-write transaction whose scope overlaps with
+        that read-write transaction cannot run until after that read-write transaction runs.
+        
+        Additionally, read-only transactions were actually sometimes running even though their scopes
+        overlapped with a running read-write transaction.
+        
+        This patch fixes both of those issues.
+    
+        * Modules/indexeddb/server/UniqueIDBDatabase.cpp:
+        (WebCore::IDBServer::UniqueIDBDatabase::operationAndTransactionTimerFired):
+        (WebCore::IDBServer::UniqueIDBDatabase::takeNextRunnableTransaction):
+        (WebCore::IDBServer::UniqueIDBDatabase::inProgressTransactionCompleted):
+        * Modules/indexeddb/server/UniqueIDBDatabase.h:
+
</ins><span class="cx"> 2016-01-06  Zalan Bujtas  &lt;zalan@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Float with media query positioned incorrectly after window resize.
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbserverUniqueIDBDatabasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp (194648 => 194649)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp        2016-01-06 19:17:55 UTC (rev 194648)
+++ trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp        2016-01-06 19:24:57 UTC (rev 194649)
</span><span class="lines">@@ -1067,8 +1067,13 @@
</span><span class="cx"> 
</span><span class="cx">     if (transaction) {
</span><span class="cx">         m_inProgressTransactions.set(transaction-&gt;info().identifier(), transaction);
</span><del>-        for (auto objectStore : transaction-&gt;objectStoreIdentifiers())
</del><ins>+        for (auto objectStore : transaction-&gt;objectStoreIdentifiers()) {
</ins><span class="cx">             m_objectStoreTransactionCounts.add(objectStore);
</span><ins>+            if (!transaction-&gt;isReadOnly()) {
+                m_objectStoreWriteTransactions.add(objectStore);
+                ASSERT(m_objectStoreTransactionCounts.count(objectStore) == 1);
+            }
+        }
</ins><span class="cx"> 
</span><span class="cx">         activateTransactionInBackingStore(*transaction);
</span><span class="cx"> 
</span><span class="lines">@@ -1125,26 +1130,33 @@
</span><span class="cx">     Deque&lt;RefPtr&lt;UniqueIDBDatabaseTransaction&gt;&gt; deferredTransactions;
</span><span class="cx">     RefPtr&lt;UniqueIDBDatabaseTransaction&gt; currentTransaction;
</span><span class="cx"> 
</span><ins>+    HashSet&lt;uint64_t&gt; deferredReadWriteScopes;
+
</ins><span class="cx">     while (!m_pendingTransactions.isEmpty()) {
</span><span class="cx">         currentTransaction = m_pendingTransactions.takeFirst();
</span><span class="cx"> 
</span><span class="cx">         switch (currentTransaction-&gt;info().mode()) {
</span><del>-        case IndexedDB::TransactionMode::ReadOnly:
-            // If there are any deferred transactions, the first one is a read-write transaction we need to unblock.
-            // Therefore, skip this read-only transaction if its scope overlaps with that read-write transaction.
-            if (!deferredTransactions.isEmpty()) {
-                ASSERT(deferredTransactions.first()-&gt;info().mode() == IndexedDB::TransactionMode::ReadWrite);
-                if (scopesOverlap(deferredTransactions.first()-&gt;objectStoreIdentifiers(), currentTransaction-&gt;objectStoreIdentifiers()))
-                    deferredTransactions.append(WTFMove(currentTransaction));
-            }
</del><ins>+        case IndexedDB::TransactionMode::ReadOnly: {
+            bool hasOverlappingScopes = scopesOverlap(deferredReadWriteScopes, currentTransaction-&gt;objectStoreIdentifiers());
+            hasOverlappingScopes |= scopesOverlap(m_objectStoreWriteTransactions, currentTransaction-&gt;objectStoreIdentifiers());
</ins><span class="cx"> 
</span><ins>+            if (hasOverlappingScopes)
+                deferredTransactions.append(WTFMove(currentTransaction));
+
</ins><span class="cx">             break;
</span><del>-        case IndexedDB::TransactionMode::ReadWrite:
-            // If this read-write transaction's scope overlaps with running transactions, it must be deferred.
-            if (scopesOverlap(m_objectStoreTransactionCounts, currentTransaction-&gt;objectStoreIdentifiers()))
</del><ins>+        }
+        case IndexedDB::TransactionMode::ReadWrite: {
+            bool hasOverlappingScopes = scopesOverlap(m_objectStoreTransactionCounts, currentTransaction-&gt;objectStoreIdentifiers());
+            hasOverlappingScopes |= scopesOverlap(deferredReadWriteScopes, currentTransaction-&gt;objectStoreIdentifiers());
+
+            if (hasOverlappingScopes) {
+                for (auto objectStore : currentTransaction-&gt;objectStoreIdentifiers())
+                    deferredReadWriteScopes.add(objectStore);
</ins><span class="cx">                 deferredTransactions.append(WTFMove(currentTransaction));
</span><ins>+            }
</ins><span class="cx"> 
</span><span class="cx">             break;
</span><ins>+        }
</ins><span class="cx">         case IndexedDB::TransactionMode::VersionChange:
</span><span class="cx">             // Version change transactions should never be scheduled in the traditional manner.
</span><span class="cx">             RELEASE_ASSERT_NOT_REACHED();
</span><span class="lines">@@ -1171,8 +1183,13 @@
</span><span class="cx">     auto transaction = m_inProgressTransactions.take(transactionIdentifier);
</span><span class="cx">     ASSERT(transaction);
</span><span class="cx"> 
</span><del>-    for (auto objectStore : transaction-&gt;objectStoreIdentifiers())
</del><ins>+    for (auto objectStore : transaction-&gt;objectStoreIdentifiers()) {
+        if (!transaction-&gt;isReadOnly()) {
+            m_objectStoreWriteTransactions.remove(objectStore);
+            ASSERT(m_objectStoreTransactionCounts.count(objectStore) == 1);
+        }
</ins><span class="cx">         m_objectStoreTransactionCounts.remove(objectStore);
</span><ins>+    }
</ins><span class="cx"> 
</span><span class="cx">     if (!transaction-&gt;databaseConnection().hasNonFinishedTransactions())
</span><span class="cx">         m_closePendingDatabaseConnections.remove(&amp;transaction-&gt;databaseConnection());
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbserverUniqueIDBDatabaseh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.h (194648 => 194649)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.h        2016-01-06 19:17:55 UTC (rev 194648)
+++ trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.h        2016-01-06 19:24:57 UTC (rev 194649)
</span><span class="lines">@@ -203,11 +203,10 @@
</span><span class="cx">     Deque&lt;RefPtr&lt;UniqueIDBDatabaseTransaction&gt;&gt; m_pendingTransactions;
</span><span class="cx">     HashMap&lt;IDBResourceIdentifier, RefPtr&lt;UniqueIDBDatabaseTransaction&gt;&gt; m_inProgressTransactions;
</span><span class="cx"> 
</span><del>-    // The key into this set is the object store ID.
-    // The set counts how many transactions are open to the given object store.
-    // This helps make sure opening narrowly scoped transactions (one or two object stores)
-    // doesn't continuously block widely scoped write transactions.
</del><ins>+    // The keys into these sets are the object store ID.
+    // These sets help to decide which transactions can be started and which must be deferred.
</ins><span class="cx">     HashCountedSet&lt;uint64_t&gt; m_objectStoreTransactionCounts;
</span><ins>+    HashSet&lt;uint64_t&gt; m_objectStoreWriteTransactions;
</ins><span class="cx"> 
</span><span class="cx">     bool m_deletePending { false };
</span><span class="cx">     bool m_deleteBackingStoreInProgress { false };
</span></span></pre>
</div>
</div>

</body>
</html>