<!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>[244112] 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/244112">244112</a></dd>
<dt>Author</dt> <dd>youenn@apple.com</dd>
<dt>Date</dt> <dd>2019-04-10 09:30:58 -0700 (Wed, 10 Apr 2019)</dd>
</dl>

<h3>Log Message</h3>
<pre>Delay initialization of quota users until the first quota request
https://bugs.webkit.org/show_bug.cgi?id=196467

Reviewed by Chris Dumez.

Source/WebCore:

Instead of triggering initialization of each user when being added,
delay initialization until the first call to requestSpace with a non zero task size.
This will make sure we do not load Cache API information in memory or check for
IDB space until actually necessary.

To implement that, move from a HashSet of being initialized users to a HashMap where the key is user and
the value is the user initialization state.

When removing a user, delay the call to processPendingRequest so that a synchronous call to addUser
can be taken into consideration.

This unflakes some Cache API tests as these tests do clear the Cache API and check for the clearing result.
Clearing the caches triggers a removeUser/addUser dance which then triggers initialization of the Caches structure.

Covered by existing tests.

* storage/StorageQuotaManager.cpp:
(WebCore::StorageQuotaManager::initializeUsersIfNeeded):
(WebCore::StorageQuotaManager::askUserToInitialize):
(WebCore::StorageQuotaManager::addUser):
(WebCore::StorageQuotaManager::requestSpace):
* storage/StorageQuotaManager.h:

LayoutTests:

Unflake cache storage tests.

* TestExpectations:
* platform/mac-wk2/TestExpectations:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsTestExpectations">trunk/LayoutTests/TestExpectations</a></li>
<li><a href="#trunkLayoutTestsplatformmacwk2TestExpectations">trunk/LayoutTests/platform/mac-wk2/TestExpectations</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorestorageStorageQuotaManagercpp">trunk/Source/WebCore/storage/StorageQuotaManager.cpp</a></li>
<li><a href="#trunkSourceWebCorestorageStorageQuotaManagerh">trunk/Source/WebCore/storage/StorageQuotaManager.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (244111 => 244112)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog      2019-04-10 13:46:01 UTC (rev 244111)
+++ trunk/LayoutTests/ChangeLog 2019-04-10 16:30:58 UTC (rev 244112)
</span><span class="lines">@@ -1,3 +1,15 @@
</span><ins>+2019-04-10  Youenn Fablet  <youenn@apple.com>
+
+        Delay initialization of quota users until the first quota request
+        https://bugs.webkit.org/show_bug.cgi?id=196467
+
+        Reviewed by Chris Dumez.
+
+        Unflake cache storage tests.
+
+        * TestExpectations:
+        * platform/mac-wk2/TestExpectations:
+
</ins><span class="cx"> 2019-04-10  Philippe Normand  <pnormand@igalia.com>
</span><span class="cx"> 
</span><span class="cx">         there is no vp8 support in youtube.com/html5 page with libwebkit2gtk 2.24 (MSE enabled)
</span></span></pre></div>
<a id="trunkLayoutTestsTestExpectations"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/TestExpectations (244111 => 244112)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/TestExpectations       2019-04-10 13:46:01 UTC (rev 244111)
+++ trunk/LayoutTests/TestExpectations  2019-04-10 16:30:58 UTC (rev 244112)
</span><span class="lines">@@ -2229,7 +2229,6 @@
</span><span class="cx"> webkit.org/b/90980 fast/forms/textarea/textarea-state-restore.html [ Pass Timeout ]
</span><span class="cx"> 
</span><span class="cx"> webkit.org/b/182928 http/tests/cache-storage/cache-representation.https.html [ Pass Failure ]
</span><del>-webkit.org/b/193976 http/tests/cache-storage/cache-clearing-origin.https.html [ Pass Failure ]
</del><span class="cx"> 
</span><span class="cx"> webkit.org/b/116621 fast/replaced/preferred-widths.html [ Pass Failure ]
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkLayoutTestsplatformmacwk2TestExpectations"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/platform/mac-wk2/TestExpectations (244111 => 244112)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/platform/mac-wk2/TestExpectations      2019-04-10 13:46:01 UTC (rev 244111)
+++ trunk/LayoutTests/platform/mac-wk2/TestExpectations 2019-04-10 16:30:58 UTC (rev 244112)
</span><span class="lines">@@ -854,8 +854,6 @@
</span><span class="cx"> 
</span><span class="cx"> webkit.org/b/184245 http/tests/workers/service/service-worker-cache-api.https.html [ Pass Failure ]
</span><span class="cx"> 
</span><del>-webkit.org/b/177380 http/tests/cache-storage/cache-records-persistency.https.html [ Pass Failure ]
-
</del><span class="cx"> webkit.org/b/184937 transitions/opacity-transition-zindex.html [ Skip ]
</span><span class="cx"> 
</span><span class="cx"> webkit.org/b/186362 [ Release ] http/tests/resourceLoadStatistics/prevalent-resource-with-user-interaction.html [ Skip ]
</span><span class="lines">@@ -925,8 +923,6 @@
</span><span class="cx"> 
</span><span class="cx"> webkit.org/b/194916 fast/mediastream/MediaStream-video-element.html [ Pass Failure ]
</span><span class="cx"> 
</span><del>-webkit.org/b/196228 http/tests/cache-storage/cache-clearing-origin.https.html [ Pass Failure ]
-
</del><span class="cx"> webkit.org/b/195719 fast/events/wheel-event-destroys-overflow.html [ Pass Timeout ]
</span><span class="cx"> webkit.org/b/195719 fast/events/wheelevent-mousewheel-interaction.html  [ Pass Timeout ]
</span><span class="cx"> webkit.org/b/195719 fast/events/wheel-event-destroys-frame.html  [ Pass Timeout ]
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (244111 => 244112)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog   2019-04-10 13:46:01 UTC (rev 244111)
+++ trunk/Source/WebCore/ChangeLog      2019-04-10 16:30:58 UTC (rev 244112)
</span><span class="lines">@@ -1,3 +1,33 @@
</span><ins>+2019-04-10  Youenn Fablet  <youenn@apple.com>
+
+        Delay initialization of quota users until the first quota request
+        https://bugs.webkit.org/show_bug.cgi?id=196467
+
+        Reviewed by Chris Dumez.
+
+        Instead of triggering initialization of each user when being added,
+        delay initialization until the first call to requestSpace with a non zero task size.
+        This will make sure we do not load Cache API information in memory or check for
+        IDB space until actually necessary.
+
+        To implement that, move from a HashSet of being initialized users to a HashMap where the key is user and
+        the value is the user initialization state.
+
+        When removing a user, delay the call to processPendingRequest so that a synchronous call to addUser
+        can be taken into consideration.
+
+        This unflakes some Cache API tests as these tests do clear the Cache API and check for the clearing result.
+        Clearing the caches triggers a removeUser/addUser dance which then triggers initialization of the Caches structure.
+
+        Covered by existing tests.
+
+        * storage/StorageQuotaManager.cpp:
+        (WebCore::StorageQuotaManager::initializeUsersIfNeeded):
+        (WebCore::StorageQuotaManager::askUserToInitialize):
+        (WebCore::StorageQuotaManager::addUser):
+        (WebCore::StorageQuotaManager::requestSpace):
+        * storage/StorageQuotaManager.h:
+
</ins><span class="cx"> 2019-04-10  Philippe Normand  <pnormand@igalia.com>
</span><span class="cx"> 
</span><span class="cx">         there is no vp8 support in youtube.com/html5 page with libwebkit2gtk 2.24 (MSE enabled)
</span></span></pre></div>
<a id="trunkSourceWebCorestorageStorageQuotaManagercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/storage/StorageQuotaManager.cpp (244111 => 244112)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/storage/StorageQuotaManager.cpp     2019-04-10 13:46:01 UTC (rev 244111)
+++ trunk/Source/WebCore/storage/StorageQuotaManager.cpp        2019-04-10 16:30:58 UTC (rev 244112)
</span><span class="lines">@@ -53,11 +53,26 @@
</span><span class="cx">     m_quota = std::max(m_quota, defaultQuotaStep * ((spaceUsage() / defaultQuotaStep) + 1));
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void StorageQuotaManager::addUser(StorageQuotaUser& user)
</del><ins>+void StorageQuotaManager::initializeUsersIfNeeded()
</ins><span class="cx"> {
</span><del>-    ASSERT(!m_pendingInitializationUsers.contains(&user));
-    ASSERT(!m_users.contains(&user));
-    m_pendingInitializationUsers.add(&user);
</del><ins>+    if (m_pendingInitializationUsers.isEmpty())
+        return;
+
+    Vector<StorageQuotaUser*> usersToInitialize;
+    for (auto& keyValue : m_pendingInitializationUsers) {
+        if (keyValue.value == WhenInitializedCalled::No) {
+            keyValue.value = WhenInitializedCalled::Yes;
+            usersToInitialize.append(keyValue.key);
+        }
+    }
+    for (auto* user : usersToInitialize) {
+        if (m_pendingInitializationUsers.contains(user))
+            askUserToInitialize(*user);
+    }
+}
+
+void StorageQuotaManager::askUserToInitialize(StorageQuotaUser& user)
+{
</ins><span class="cx">     user.whenInitialized([this, &user, weakThis = makeWeakPtr(this)]() {
</span><span class="cx">         if (!weakThis)
</span><span class="cx">             return;
</span><span class="lines">@@ -73,6 +88,16 @@
</span><span class="cx">     });
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void StorageQuotaManager::addUser(StorageQuotaUser& user)
+{
+    ASSERT(!m_pendingInitializationUsers.contains(&user));
+    ASSERT(!m_users.contains(&user));
+    m_pendingInitializationUsers.add(&user, WhenInitializedCalled::No);
+
+    if (!m_pendingRequests.isEmpty())
+        askUserToInitialize(user);
+}
+
</ins><span class="cx"> bool StorageQuotaManager::shouldAskForMoreSpace(uint64_t spaceIncrease) const
</span><span class="cx"> {
</span><span class="cx">     if (!spaceIncrease)
</span><span class="lines">@@ -85,22 +110,44 @@
</span><span class="cx"> {
</span><span class="cx">     ASSERT(m_users.contains(&user) || m_pendingInitializationUsers.contains(&user));
</span><span class="cx">     m_users.remove(&user);
</span><del>-    if (m_pendingInitializationUsers.remove(&user) && m_pendingInitializationUsers.isEmpty())
-        processPendingRequests({ }, ShouldDequeueFirstPendingRequest::No);
</del><ins>+    if (m_pendingInitializationUsers.remove(&user) && m_pendingInitializationUsers.isEmpty()) {
+        // When being cleared, quota users may remove themselves and add themselves to trigger reinitialization.
+        // Let's wait for addUser to be called before processing pending requests.
+        callOnMainThread([this, weakThis = makeWeakPtr(this)] {
+            if (!weakThis)
+                return;
+
+            if (m_pendingInitializationUsers.isEmpty())
+                this->processPendingRequests({ }, ShouldDequeueFirstPendingRequest::No);
+        });
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void StorageQuotaManager::requestSpace(uint64_t spaceIncrease, RequestCallback&& callback)
</span><span class="cx"> {
</span><del>-    if (!m_pendingRequests.isEmpty() || !m_pendingInitializationUsers.isEmpty()) {
</del><ins>+    if (!m_pendingRequests.isEmpty()) {
</ins><span class="cx">         m_pendingRequests.append({ spaceIncrease, WTFMove(callback) });
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    if (!spaceIncrease) {
+        callback(Decision::Grant);
+        return;
+    }
+
+    initializeUsersIfNeeded();
+
+    if (!m_pendingInitializationUsers.isEmpty()) {
+        m_pendingRequests.append({ spaceIncrease, WTFMove(callback) });
+        return;
+    }
+
</ins><span class="cx">     if (shouldAskForMoreSpace(spaceIncrease)) {
</span><span class="cx">         m_pendingRequests.append({ spaceIncrease, WTFMove(callback) });
</span><span class="cx">         askForMoreSpace(spaceIncrease);
</span><span class="cx">         return;
</span><span class="cx">     }
</span><ins>+
</ins><span class="cx">     callback(Decision::Grant);
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCorestorageStorageQuotaManagerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/storage/StorageQuotaManager.h (244111 => 244112)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/storage/StorageQuotaManager.h       2019-04-10 13:46:01 UTC (rev 244111)
+++ trunk/Source/WebCore/storage/StorageQuotaManager.h  2019-04-10 16:30:58 UTC (rev 244112)
</span><span class="lines">@@ -28,6 +28,7 @@
</span><span class="cx"> #include "ClientOrigin.h"
</span><span class="cx"> #include <wtf/CompletionHandler.h>
</span><span class="cx"> #include <wtf/Deque.h>
</span><ins>+#include <wtf/HashMap.h>
</ins><span class="cx"> #include <wtf/HashSet.h>
</span><span class="cx"> #include <wtf/WeakPtr.h>
</span><span class="cx"> 
</span><span class="lines">@@ -66,6 +67,9 @@
</span><span class="cx">     bool shouldAskForMoreSpace(uint64_t spaceIncrease) const;
</span><span class="cx">     void askForMoreSpace(uint64_t spaceIncrease);
</span><span class="cx"> 
</span><ins>+    void initializeUsersIfNeeded();
+    void askUserToInitialize(StorageQuotaUser&);
+
</ins><span class="cx">     enum class ShouldDequeueFirstPendingRequest { No, Yes };
</span><span class="cx">     void processPendingRequests(Optional<uint64_t>, ShouldDequeueFirstPendingRequest);
</span><span class="cx"> 
</span><span class="lines">@@ -73,7 +77,9 @@
</span><span class="cx"> 
</span><span class="cx">     bool m_isWaitingForSpaceIncreaseResponse { false };
</span><span class="cx">     SpaceIncreaseRequester m_spaceIncreaseRequester;
</span><del>-    HashSet<const StorageQuotaUser*> m_pendingInitializationUsers;
</del><ins>+
+    enum class WhenInitializedCalled { No, Yes };
+    HashMap<StorageQuotaUser*, WhenInitializedCalled> m_pendingInitializationUsers;
</ins><span class="cx">     HashSet<const StorageQuotaUser*> m_users;
</span><span class="cx"> 
</span><span class="cx">     struct PendingRequest {
</span></span></pre>
</div>
</div>

</body>
</html>