<!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>[242599] trunk/Source</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/242599">242599</a></dd>
<dt>Author</dt> <dd>youenn@apple.com</dd>
<dt>Date</dt> <dd>2019-03-07 09:40:40 -0800 (Thu, 07 Mar 2019)</dd>
</dl>

<h3>Log Message</h3>
<pre>Introduce a quota manager for Cache API/Service Worker/IDB storage
https://bugs.webkit.org/show_bug.cgi?id=195283

Reviewed by Chris Dumez.

Source/WebCore:

Introduce a generic quota manager and quota users to be used in Network Process.
Quota manager/users are scoped by client origin.
Quota manager is used to check for quota by an entity wanting to execute a storage task of a given taskSize.
Quota manager will check the current space used by all its quota users.
If the size + taskSize is above quota, it will call a function to try extend the quota.
In the meantime, the task (and all tasks that may be added) are queued.

Once the new quota is received, the quota manager will either allow or disallow the first task in the queue.
The quota manager will try to execute as many tasks as possible with the provided quota.
If some tasks are remaining and quota limit is hit, the quota manager will compute the space needed for all remaining requests
and do another quota extension request.

* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* page/ClientOrigin.h:
* storage/StorageQuotaManager.cpp: Added.
(WebCore::StorageQuotaManager::~StorageQuotaManager):
(WebCore::StorageQuotaManager::spaceUsage const):
(WebCore::StorageQuotaManager::requestSpace):
(WebCore::StorageQuotaManager::askForMoreSpace):
(WebCore::StorageQuotaManager::processPendingRequests):
* storage/StorageQuotaManager.h: Added.
(WebCore::StorageQuotaManager::StorageQuotaManager):
(WebCore::StorageQuotaManager::addUser):
(WebCore::StorageQuotaManager::removeUser):
* storage/StorageQuotaUser.h: Added.

Source/WebKit:

Remove quota handling from Cache API storage and use StorageQuotaManager/StorageQuotaUser.
CacheStorage::Caches becomes a quota user and has a StorageQuotaManager to check for space for any cache API write task.
NetworkProcess is responsible to manage the quota managers.
Quota managers will go through network process to ask UIProcess for quota extension.

Remove pending callback handling from CacheStorage since they are queued in QuotaManager now.

* NetworkProcess/NetworkProcess.cpp:
(WebKit::NetworkProcess::~NetworkProcess):
(WebKit::NetworkProcess::destroySession):
(WebKit::NetworkProcess::cacheStorageRootPath):
(WebKit::NetworkProcess::setCacheStorageParameters):
(WebKit::NetworkProcess::storageQuotaManager):
* NetworkProcess/NetworkProcess.h:
* NetworkProcess/cache/CacheStorageEngine.cpp:
(WebKit::CacheStorage::Engine::from):
(WebKit::CacheStorage::Engine::Engine):
(WebKit::CacheStorage::Engine::readCachesFromDisk):
* NetworkProcess/cache/CacheStorageEngine.h:
* NetworkProcess/cache/CacheStorageEngineCache.cpp:
(WebKit::CacheStorage::Cache::put):
* NetworkProcess/cache/CacheStorageEngineCache.h:
* NetworkProcess/cache/CacheStorageEngineCaches.cpp:
(WebKit::CacheStorage::Caches::Caches):
(WebKit::CacheStorage::Caches::~Caches):
(WebKit::CacheStorage::Caches::requestSpace):
(WebKit::CacheStorage::Caches::writeRecord):
* NetworkProcess/cache/CacheStorageEngineCaches.h:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreSourcestxt">trunk/Source/WebCore/Sources.txt</a></li>
<li><a href="#trunkSourceWebCoreWebCorexcodeprojprojectpbxproj">trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkSourceWebCorepageClientOriginh">trunk/Source/WebCore/page/ClientOrigin.h</a></li>
<li><a href="#trunkSourceWebKitChangeLog">trunk/Source/WebKit/ChangeLog</a></li>
<li><a href="#trunkSourceWebKitNetworkProcessNetworkProcesscpp">trunk/Source/WebKit/NetworkProcess/NetworkProcess.cpp</a></li>
<li><a href="#trunkSourceWebKitNetworkProcessNetworkProcessh">trunk/Source/WebKit/NetworkProcess/NetworkProcess.h</a></li>
<li><a href="#trunkSourceWebKitNetworkProcesscacheCacheStorageEnginecpp">trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngine.cpp</a></li>
<li><a href="#trunkSourceWebKitNetworkProcesscacheCacheStorageEngineh">trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngine.h</a></li>
<li><a href="#trunkSourceWebKitNetworkProcesscacheCacheStorageEngineCachecpp">trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngineCache.cpp</a></li>
<li><a href="#trunkSourceWebKitNetworkProcesscacheCacheStorageEngineCacheh">trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngineCache.h</a></li>
<li><a href="#trunkSourceWebKitNetworkProcesscacheCacheStorageEngineCachescpp">trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngineCaches.cpp</a></li>
<li><a href="#trunkSourceWebKitNetworkProcesscacheCacheStorageEngineCachesh">trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngineCaches.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceWebCorestorageStorageQuotaManagercpp">trunk/Source/WebCore/storage/StorageQuotaManager.cpp</a></li>
<li><a href="#trunkSourceWebCorestorageStorageQuotaManagerh">trunk/Source/WebCore/storage/StorageQuotaManager.h</a></li>
<li><a href="#trunkSourceWebCorestorageStorageQuotaUserh">trunk/Source/WebCore/storage/StorageQuotaUser.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (242598 => 242599)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog   2019-03-07 17:22:27 UTC (rev 242598)
+++ trunk/Source/WebCore/ChangeLog      2019-03-07 17:40:40 UTC (rev 242599)
</span><span class="lines">@@ -1,3 +1,37 @@
</span><ins>+2019-03-07  Youenn Fablet  <youenn@apple.com>
+
+        Introduce a quota manager for Cache API/Service Worker/IDB storage
+        https://bugs.webkit.org/show_bug.cgi?id=195283
+
+        Reviewed by Chris Dumez.
+
+        Introduce a generic quota manager and quota users to be used in Network Process.
+        Quota manager/users are scoped by client origin.
+        Quota manager is used to check for quota by an entity wanting to execute a storage task of a given taskSize.
+        Quota manager will check the current space used by all its quota users.
+        If the size + taskSize is above quota, it will call a function to try extend the quota.
+        In the meantime, the task (and all tasks that may be added) are queued.
+
+        Once the new quota is received, the quota manager will either allow or disallow the first task in the queue.
+        The quota manager will try to execute as many tasks as possible with the provided quota.
+        If some tasks are remaining and quota limit is hit, the quota manager will compute the space needed for all remaining requests
+        and do another quota extension request.
+
+        * Sources.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * page/ClientOrigin.h:
+        * storage/StorageQuotaManager.cpp: Added.
+        (WebCore::StorageQuotaManager::~StorageQuotaManager):
+        (WebCore::StorageQuotaManager::spaceUsage const):
+        (WebCore::StorageQuotaManager::requestSpace):
+        (WebCore::StorageQuotaManager::askForMoreSpace):
+        (WebCore::StorageQuotaManager::processPendingRequests):
+        * storage/StorageQuotaManager.h: Added.
+        (WebCore::StorageQuotaManager::StorageQuotaManager):
+        (WebCore::StorageQuotaManager::addUser):
+        (WebCore::StorageQuotaManager::removeUser):
+        * storage/StorageQuotaUser.h: Added.
+
</ins><span class="cx"> 2019-03-07  John Wilander  <wilander@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Resource Load Statistics: Make it possible to purge only script-accessible cookies
</span></span></pre></div>
<a id="trunkSourceWebCoreSourcestxt"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Sources.txt (242598 => 242599)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Sources.txt 2019-03-07 17:22:27 UTC (rev 242598)
+++ trunk/Source/WebCore/Sources.txt    2019-03-07 17:40:40 UTC (rev 242599)
</span><span class="lines">@@ -2231,6 +2231,7 @@
</span><span class="cx"> 
</span><span class="cx"> replay/UserInputBridge.cpp
</span><span class="cx"> 
</span><ins>+storage/StorageQuotaManager.cpp
</ins><span class="cx"> storage/Storage.cpp
</span><span class="cx"> storage/StorageEvent.cpp
</span><span class="cx"> storage/StorageEventDispatcher.cpp
</span></span></pre></div>
<a id="trunkSourceWebCoreWebCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (242598 => 242599)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj   2019-03-07 17:22:27 UTC (rev 242598)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj      2019-03-07 17:40:40 UTC (rev 242599)
</span><span class="lines">@@ -1168,6 +1168,8 @@
</span><span class="cx">          41D129D51F3D0F6900D15E47 /* CacheStorageProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = 41D129D41F3D0F6600D15E47 /* CacheStorageProvider.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">          41D129DB1F3D143800D15E47 /* FetchHeaders.h in Headers */ = {isa = PBXBuildFile; fileRef = 41F54F831C50C4F600338488 /* FetchHeaders.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">          41D28D0D2139E05800F4206F /* LibWebRTCStatsCollector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41D28D0B2139E01D00F4206F /* LibWebRTCStatsCollector.cpp */; };
</span><ins>+               41DE7C7C222DA14300532B65 /* StorageQuotaManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 41DE7C7B222DA13E00532B65 /* StorageQuotaManager.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               41DE7C7D222DA14800532B65 /* StorageQuotaUser.h in Headers */ = {isa = PBXBuildFile; fileRef = 41DE7C78222DA13C00532B65 /* StorageQuotaUser.h */; settings = {ATTRIBUTES = (Private, ); }; };
</ins><span class="cx">           41DEFCB61E56C1BD000D9E5F /* JSDOMMapLike.h in Headers */ = {isa = PBXBuildFile; fileRef = 41DEFCB41E56C1B9000D9E5F /* JSDOMMapLike.h */; };
</span><span class="cx">          41E1B1D10FF5986900576B3B /* AbstractWorker.h in Headers */ = {isa = PBXBuildFile; fileRef = 41E1B1CB0FF5986900576B3B /* AbstractWorker.h */; };
</span><span class="cx">          41F062140F5F192600A07EAC /* InspectorDatabaseResource.h in Headers */ = {isa = PBXBuildFile; fileRef = 41F062120F5F192600A07EAC /* InspectorDatabaseResource.h */; };
</span><span class="lines">@@ -7511,6 +7513,9 @@
</span><span class="cx">          41D28D0B2139E01D00F4206F /* LibWebRTCStatsCollector.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LibWebRTCStatsCollector.cpp; path = libwebrtc/LibWebRTCStatsCollector.cpp; sourceTree = "<group>"; };
</span><span class="cx">          41D28D0C2139E01E00F4206F /* LibWebRTCStatsCollector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LibWebRTCStatsCollector.h; path = libwebrtc/LibWebRTCStatsCollector.h; sourceTree = "<group>"; };
</span><span class="cx">          41D51BB21E4E2E8100131A5B /* LibWebRTCAudioFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LibWebRTCAudioFormat.h; path = libwebrtc/LibWebRTCAudioFormat.h; sourceTree = "<group>"; };
</span><ins>+               41DE7C78222DA13C00532B65 /* StorageQuotaUser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StorageQuotaUser.h; sourceTree = "<group>"; };
+               41DE7C7A222DA13D00532B65 /* StorageQuotaManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StorageQuotaManager.cpp; sourceTree = "<group>"; };
+               41DE7C7B222DA13E00532B65 /* StorageQuotaManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StorageQuotaManager.h; sourceTree = "<group>"; };
</ins><span class="cx">           41DEFCB21E56C1B9000D9E5F /* JSDOMBindingInternals.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = JSDOMBindingInternals.js; sourceTree = "<group>"; };
</span><span class="cx">          41DEFCB31E56C1B9000D9E5F /* JSDOMMapLike.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSDOMMapLike.cpp; sourceTree = "<group>"; };
</span><span class="cx">          41DEFCB41E56C1B9000D9E5F /* JSDOMMapLike.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSDOMMapLike.h; sourceTree = "<group>"; };
</span><span class="lines">@@ -16862,6 +16867,9 @@
</span><span class="cx">                          C50D0E810FF4272900AC2644 /* StorageNamespace.h */,
</span><span class="cx">                          1A3763691A2E68BB009A7EE2 /* StorageNamespaceProvider.cpp */,
</span><span class="cx">                          1A37636A1A2E68BB009A7EE2 /* StorageNamespaceProvider.h */,
</span><ins>+                               41DE7C7A222DA13D00532B65 /* StorageQuotaManager.cpp */,
+                               41DE7C7B222DA13E00532B65 /* StorageQuotaManager.h */,
+                               41DE7C78222DA13C00532B65 /* StorageQuotaUser.h */,
</ins><span class="cx">                           5166D3CC1E8ED41100AD62E3 /* StorageType.h */,
</span><span class="cx">                  );
</span><span class="cx">                  indentWidth = 4;
</span><span class="lines">@@ -31689,6 +31697,8 @@
</span><span class="cx">                          51E0BB380DA5ACB600A9E417 /* StorageMap.h in Headers */,
</span><span class="cx">                          C50D0E830FF4272900AC2644 /* StorageNamespace.h in Headers */,
</span><span class="cx">                          1A37636C1A2E68BB009A7EE2 /* StorageNamespaceProvider.h in Headers */,
</span><ins>+                               41DE7C7C222DA14300532B65 /* StorageQuotaManager.h in Headers */,
+                               41DE7C7D222DA14800532B65 /* StorageQuotaUser.h in Headers */,
</ins><span class="cx">                           5C9EF2F321F06190003BDC56 /* StorageSessionProvider.h in Headers */,
</span><span class="cx">                          5166D3CD1E8ED48F00AD62E3 /* StorageType.h in Headers */,
</span><span class="cx">                          4682D2001F79783000C863DB /* StoredCredentialsPolicy.h in Headers */,
</span></span></pre></div>
<a id="trunkSourceWebCorepageClientOriginh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/page/ClientOrigin.h (242598 => 242599)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/page/ClientOrigin.h 2019-03-07 17:22:27 UTC (rev 242598)
+++ trunk/Source/WebCore/page/ClientOrigin.h    2019-03-07 17:40:40 UTC (rev 242599)
</span><span class="lines">@@ -26,6 +26,7 @@
</span><span class="cx"> #pragma once
</span><span class="cx"> 
</span><span class="cx"> #include "SecurityOriginData.h"
</span><ins>+#include <wtf/HashTraits.h>
</ins><span class="cx"> #include <wtf/URL.h>
</span><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span></span></pre></div>
<a id="trunkSourceWebCorestorageStorageQuotaManagercpp"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/storage/StorageQuotaManager.cpp (0 => 242599)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/storage/StorageQuotaManager.cpp                             (rev 0)
+++ trunk/Source/WebCore/storage/StorageQuotaManager.cpp        2019-03-07 17:40:40 UTC (rev 242599)
</span><span class="lines">@@ -0,0 +1,101 @@
</span><ins>+/*
+ * Copyright (C) 2019 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "StorageQuotaManager.h"
+
+#include "StorageQuotaUser.h"
+
+namespace WebCore {
+
+StorageQuotaManager::~StorageQuotaManager()
+{
+    while (!m_pendingRequests.isEmpty())
+        m_pendingRequests.takeFirst().callback(Decision::Deny);
+}
+
+uint64_t StorageQuotaManager::spaceUsage() const
+{
+    uint64_t usage = 0;
+    for (auto& user : m_users)
+        usage += user->spaceUsed();
+    return usage;
+}
+
+void StorageQuotaManager::requestSpace(uint64_t spaceIncrease, RequestCallback&& callback)
+{
+    if (!m_pendingRequests.isEmpty()) {
+        m_pendingRequests.append({ spaceIncrease, WTFMove(callback) });
+        return;
+    }
+
+    auto spaceUsage = this->spaceUsage();
+    if (spaceUsage + spaceIncrease > m_quota) {
+        m_pendingRequests.append({ spaceIncrease, WTFMove(callback) });
+        askForMoreSpace(spaceUsage, spaceIncrease);
+        return;
+    }
+    callback(Decision::Grant);
+}
+
+void StorageQuotaManager::askForMoreSpace(uint64_t spaceUsage, uint64_t spaceIncrease)
+{
+    ASSERT(spaceUsage + spaceIncrease > m_quota);
+    m_spaceIncreaseRequester(m_quota, spaceUsage, spaceIncrease, [this, weakThis = makeWeakPtr(*this)](Optional<uint64_t> newQuota) {
+        if (!weakThis)
+            return;
+        processPendingRequests(newQuota);
+    });
+}
+
+void StorageQuotaManager::processPendingRequests(Optional<uint64_t> newQuota)
+{
+    if (m_pendingRequests.isEmpty())
+        return;
+
+    if (newQuota)
+        m_quota = *newQuota;
+
+    auto request = m_pendingRequests.takeFirst();
+    auto decision = m_quota >= (spaceUsage() + request.spaceIncrease) ? Decision::Grant : Decision::Deny;
+    request.callback(decision);
+
+    while (!m_pendingRequests.isEmpty()) {
+        auto& request = m_pendingRequests.first();
+
+        auto spaceUsage = this->spaceUsage();
+        if (m_quota < spaceUsage + request.spaceIncrease) {
+            uint64_t spaceIncrease = 0;
+            for (auto& request : m_pendingRequests)
+                spaceIncrease += request.spaceIncrease;
+            askForMoreSpace(spaceUsage, spaceIncrease);
+            return;
+        }
+
+        m_pendingRequests.takeFirst().callback(Decision::Grant);
+    }
+}
+
+} // namespace WebCore
</ins></span></pre></div>
<a id="trunkSourceWebCorestorageStorageQuotaManagerh"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/storage/StorageQuotaManager.h (0 => 242599)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/storage/StorageQuotaManager.h                               (rev 0)
+++ trunk/Source/WebCore/storage/StorageQuotaManager.h  2019-03-07 17:40:40 UTC (rev 242599)
</span><span class="lines">@@ -0,0 +1,81 @@
</span><ins>+/*
+ * Copyright (C) 2019 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "ClientOrigin.h"
+#include <wtf/CompletionHandler.h>
+#include <wtf/Deque.h>
+#include <wtf/HashSet.h>
+#include <wtf/WeakPtr.h>
+
+namespace WebCore {
+
+class StorageQuotaUser;
+
+class StorageQuotaManager : public CanMakeWeakPtr<StorageQuotaManager> {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    using SpaceIncreaseRequester = WTF::Function<void(uint64_t quota, uint64_t currentSpace, uint64_t spaceIncrease, CompletionHandler<void(Optional<uint64_t>)>&&)>;
+    StorageQuotaManager(uint64_t quota, SpaceIncreaseRequester&& spaceIncreaseRequester)
+        : m_quota(quota)
+        , m_spaceIncreaseRequester(WTFMove(spaceIncreaseRequester))
+    {
+    }
+    WEBCORE_EXPORT ~StorageQuotaManager();
+
+    void addUser(StorageQuotaUser& user)
+    {
+        ASSERT(!m_users.contains(&user));
+        m_users.add(&user);
+    }
+
+    void removeUser(StorageQuotaUser& user)
+    {
+        ASSERT(m_users.contains(&user));
+        m_users.remove(&user);
+    }
+
+    enum class Decision { Deny, Grant };
+    using RequestCallback = CompletionHandler<void(Decision)>;
+    WEBCORE_EXPORT void requestSpace(uint64_t, RequestCallback&&);
+
+private:
+    uint64_t spaceUsage() const;
+    void askForMoreSpace(uint64_t spaceUsage, uint64_t spaceIncrease);
+    void processPendingRequests(Optional<uint64_t>);
+
+    uint64_t m_quota { 0 };
+    SpaceIncreaseRequester m_spaceIncreaseRequester;
+    HashSet<const StorageQuotaUser*> m_users;
+
+    struct PendingRequest {
+        uint64_t spaceIncrease;
+        RequestCallback callback;
+    };
+    Deque<PendingRequest> m_pendingRequests;
+};
+
+} // namespace WebCore
</ins></span></pre></div>
<a id="trunkSourceWebCorestorageStorageQuotaUserh"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/storage/StorageQuotaUser.h (0 => 242599)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/storage/StorageQuotaUser.h                          (rev 0)
+++ trunk/Source/WebCore/storage/StorageQuotaUser.h     2019-03-07 17:40:40 UTC (rev 242599)
</span><span class="lines">@@ -0,0 +1,37 @@
</span><ins>+/*
+ * Copyright (C) 2019 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+namespace WebCore {
+
+class StorageQuotaUser {
+public:
+    virtual ~StorageQuotaUser() = default;
+
+    virtual uint64_t spaceUsed() const = 0;
+};
+
+} // namespace WebCore
</ins></span></pre></div>
<a id="trunkSourceWebKitChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/ChangeLog (242598 => 242599)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/ChangeLog    2019-03-07 17:22:27 UTC (rev 242598)
+++ trunk/Source/WebKit/ChangeLog       2019-03-07 17:40:40 UTC (rev 242599)
</span><span class="lines">@@ -1,3 +1,39 @@
</span><ins>+2019-03-07  Youenn Fablet  <youenn@apple.com>
+
+        Introduce a quota manager for Cache API/Service Worker/IDB storage
+        https://bugs.webkit.org/show_bug.cgi?id=195283
+
+        Reviewed by Chris Dumez.
+
+        Remove quota handling from Cache API storage and use StorageQuotaManager/StorageQuotaUser.
+        CacheStorage::Caches becomes a quota user and has a StorageQuotaManager to check for space for any cache API write task.
+        NetworkProcess is responsible to manage the quota managers.
+        Quota managers will go through network process to ask UIProcess for quota extension.
+
+        Remove pending callback handling from CacheStorage since they are queued in QuotaManager now.
+
+        * NetworkProcess/NetworkProcess.cpp:
+        (WebKit::NetworkProcess::~NetworkProcess):
+        (WebKit::NetworkProcess::destroySession):
+        (WebKit::NetworkProcess::cacheStorageRootPath):
+        (WebKit::NetworkProcess::setCacheStorageParameters):
+        (WebKit::NetworkProcess::storageQuotaManager):
+        * NetworkProcess/NetworkProcess.h:
+        * NetworkProcess/cache/CacheStorageEngine.cpp:
+        (WebKit::CacheStorage::Engine::from):
+        (WebKit::CacheStorage::Engine::Engine):
+        (WebKit::CacheStorage::Engine::readCachesFromDisk):
+        * NetworkProcess/cache/CacheStorageEngine.h:
+        * NetworkProcess/cache/CacheStorageEngineCache.cpp:
+        (WebKit::CacheStorage::Cache::put):
+        * NetworkProcess/cache/CacheStorageEngineCache.h:
+        * NetworkProcess/cache/CacheStorageEngineCaches.cpp:
+        (WebKit::CacheStorage::Caches::Caches):
+        (WebKit::CacheStorage::Caches::~Caches):
+        (WebKit::CacheStorage::Caches::requestSpace):
+        (WebKit::CacheStorage::Caches::writeRecord):
+        * NetworkProcess/cache/CacheStorageEngineCaches.h:
+
</ins><span class="cx"> 2019-03-07  John Wilander  <wilander@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Resource Load Statistics: Make it possible to purge only script-accessible cookies
</span></span></pre></div>
<a id="trunkSourceWebKitNetworkProcessNetworkProcesscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/NetworkProcess/NetworkProcess.cpp (242598 => 242599)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/NetworkProcess/NetworkProcess.cpp    2019-03-07 17:22:27 UTC (rev 242598)
+++ trunk/Source/WebKit/NetworkProcess/NetworkProcess.cpp       2019-03-07 17:40:40 UTC (rev 242599)
</span><span class="lines">@@ -76,6 +76,7 @@
</span><span class="cx"> #include <WebCore/RuntimeEnabledFeatures.h>
</span><span class="cx"> #include <WebCore/SchemeRegistry.h>
</span><span class="cx"> #include <WebCore/SecurityOriginData.h>
</span><ins>+#include <WebCore/StorageQuotaManager.h>
</ins><span class="cx"> #include <wtf/Algorithms.h>
</span><span class="cx"> #include <wtf/CallbackAggregator.h>
</span><span class="cx"> #include <wtf/OptionSet.h>
</span><span class="lines">@@ -168,7 +169,7 @@
</span><span class="cx"> {
</span><span class="cx">     for (auto& callbacks : m_cacheStorageParametersCallbacks.values()) {
</span><span class="cx">         for (auto& callback : callbacks)
</span><del>-            callback(String { }, 0);
</del><ins>+            callback(String { });
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -568,6 +569,8 @@
</span><span class="cx">     m_swServers.remove(sessionID);
</span><span class="cx">     m_swDatabasePaths.remove(sessionID);
</span><span class="cx"> #endif
</span><ins>+
+    m_storageQuotaManagers.remove(sessionID);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(RESOURCE_LOAD_STATISTICS)
</span><span class="lines">@@ -1927,16 +1930,20 @@
</span><span class="cx">     WebCore::prefetchDNS(hostname);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void NetworkProcess::cacheStorageParameters(PAL::SessionID sessionID, CacheStorageParametersCallback&& callback)
</del><ins>+void NetworkProcess::cacheStorageRootPath(PAL::SessionID sessionID, CacheStorageRootPathCallback&& callback)
</ins><span class="cx"> {
</span><span class="cx">     m_cacheStorageParametersCallbacks.ensure(sessionID, [&] {
</span><span class="cx">         parentProcessConnection()->send(Messages::NetworkProcessProxy::RetrieveCacheStorageParameters { sessionID }, 0);
</span><del>-        return Vector<CacheStorageParametersCallback> { };
</del><ins>+        return Vector<CacheStorageRootPathCallback> { };
</ins><span class="cx">     }).iterator->value.append(WTFMove(callback));
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void NetworkProcess::setCacheStorageParameters(PAL::SessionID sessionID, uint64_t quota, String&& cacheStorageDirectory, SandboxExtension::Handle&& handle)
</span><span class="cx"> {
</span><ins>+    m_storageQuotaManagers.ensure(sessionID, [] {
+        return StorageQuotaManagers { };
+    }).iterator->value.defaultQuota = quota;
+
</ins><span class="cx">     auto iterator = m_cacheStorageParametersCallbacks.find(sessionID);
</span><span class="cx">     if (iterator == m_cacheStorageParametersCallbacks.end())
</span><span class="cx">         return;
</span><span class="lines">@@ -1945,7 +1952,7 @@
</span><span class="cx">     auto callbacks = WTFMove(iterator->value);
</span><span class="cx">     m_cacheStorageParametersCallbacks.remove(iterator);
</span><span class="cx">     for (auto& callback : callbacks)
</span><del>-        callback(String { cacheStorageDirectory }, quota);
</del><ins>+        callback(String { cacheStorageDirectory });
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void NetworkProcess::preconnectTo(const URL& url, WebCore::StoredCredentialsPolicy storedCredentialsPolicy)
</span><span class="lines">@@ -2270,6 +2277,18 @@
</span><span class="cx">     parentProcessConnection()->sendWithAsyncReply(Messages::NetworkProcessProxy::RequestStorageSpace { sessionID, origin, quota, currentSize, spaceRequired }, WTFMove(callback), 0);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+StorageQuotaManager& NetworkProcess::storageQuotaManager(PAL::SessionID sessionID, const ClientOrigin& origin)
+{
+    auto& storageQuotaManagers = m_storageQuotaManagers.ensure(sessionID, [] {
+        return StorageQuotaManagers { };
+    }).iterator->value;
+    return *storageQuotaManagers.managersPerOrigin.ensure(origin, [this, &storageQuotaManagers, sessionID, &origin] {
+        return std::make_unique<StorageQuotaManager>(storageQuotaManagers.defaultQuota, [this, sessionID, origin](uint64_t quota, uint64_t currentSpace, uint64_t spaceIncrease, auto callback) {
+            this->requestStorageSpace(sessionID, origin, quota, currentSpace, spaceIncrease, WTFMove(callback));
+        });
+    }).iterator->value;
+}
+
</ins><span class="cx"> #if !PLATFORM(COCOA)
</span><span class="cx"> void NetworkProcess::initializeProcess(const AuxiliaryProcessInitializationParameters&)
</span><span class="cx"> {
</span></span></pre></div>
<a id="trunkSourceWebKitNetworkProcessNetworkProcessh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/NetworkProcess/NetworkProcess.h (242598 => 242599)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/NetworkProcess/NetworkProcess.h      2019-03-07 17:22:27 UTC (rev 242598)
+++ trunk/Source/WebKit/NetworkProcess/NetworkProcess.h 2019-03-07 17:40:40 UTC (rev 242599)
</span><span class="lines">@@ -33,6 +33,7 @@
</span><span class="cx"> #include "NetworkHTTPSUpgradeChecker.h"
</span><span class="cx"> #include "SandboxExtension.h"
</span><span class="cx"> #include <WebCore/AdClickAttribution.h>
</span><ins>+#include <WebCore/ClientOrigin.h>
</ins><span class="cx"> #include <WebCore/DiagnosticLoggingClient.h>
</span><span class="cx"> #include <WebCore/FetchIdentifier.h>
</span><span class="cx"> #include <WebCore/IDBKeyData.h>
</span><span class="lines">@@ -69,6 +70,7 @@
</span><span class="cx"> class CertificateInfo;
</span><span class="cx"> class CurlProxySettings;
</span><span class="cx"> class DownloadID;
</span><ins>+class StorageQuotaManager;
</ins><span class="cx"> class NetworkStorageSession;
</span><span class="cx"> class ResourceError;
</span><span class="cx"> class SWServer;
</span><span class="lines">@@ -258,8 +260,8 @@
</span><span class="cx">     void resetCrossSiteLoadsWithLinkDecorationForTesting(PAL::SessionID, CompletionHandler<void()>&&);
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-    using CacheStorageParametersCallback = CompletionHandler<void(const String&, uint64_t quota)>;
-    void cacheStorageParameters(PAL::SessionID, CacheStorageParametersCallback&&);
</del><ins>+    using CacheStorageRootPathCallback = CompletionHandler<void(String&&)>;
+    void cacheStorageRootPath(PAL::SessionID, CacheStorageRootPathCallback&&);
</ins><span class="cx"> 
</span><span class="cx">     void preconnectTo(const URL&, WebCore::StoredCredentialsPolicy);
</span><span class="cx"> 
</span><span class="lines">@@ -323,6 +325,8 @@
</span><span class="cx">     void dumpAdClickAttribution(PAL::SessionID, CompletionHandler<void(String)>&&);
</span><span class="cx">     void clearAdClickAttribution(PAL::SessionID, CompletionHandler<void()>&&);
</span><span class="cx"> 
</span><ins>+    WebCore::StorageQuotaManager& storageQuotaManager(PAL::SessionID, const WebCore::ClientOrigin&);
+
</ins><span class="cx"> private:
</span><span class="cx">     void platformInitializeNetworkProcess(const NetworkProcessCreationParameters&);
</span><span class="cx">     std::unique_ptr<WebCore::NetworkStorageSession> platformCreateDefaultStorageSession() const;
</span><span class="lines">@@ -467,7 +471,8 @@
</span><span class="cx">     NetworkProcessSupplementMap m_supplements;
</span><span class="cx"> 
</span><span class="cx">     HashSet<PAL::SessionID> m_sessionsControlledByAutomation;
</span><del>-    HashMap<PAL::SessionID, Vector<CacheStorageParametersCallback>> m_cacheStorageParametersCallbacks;
</del><ins>+    HashMap<PAL::SessionID, Vector<CacheStorageRootPathCallback>> m_cacheStorageParametersCallbacks;
+
</ins><span class="cx">     HashMap<PAL::SessionID, Ref<NetworkSession>> m_networkSessions;
</span><span class="cx">     HashMap<PAL::SessionID, std::unique_ptr<WebCore::NetworkStorageSession>> m_networkStorageSessions;
</span><span class="cx">     mutable std::unique_ptr<WebCore::NetworkStorageSession> m_defaultNetworkStorageSession;
</span><span class="lines">@@ -516,6 +521,12 @@
</span><span class="cx"> #if PLATFORM(COCOA)
</span><span class="cx">     NetworkHTTPSUpgradeChecker m_networkHTTPSUpgradeChecker;
</span><span class="cx"> #endif
</span><ins>+
+    struct StorageQuotaManagers {
+        uint64_t defaultQuota { 0 };
+        HashMap<WebCore::ClientOrigin, std::unique_ptr<WebCore::StorageQuotaManager>> managersPerOrigin;
+    };
+    HashMap<PAL::SessionID, StorageQuotaManagers> m_storageQuotaManagers;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebKit
</span></span></pre></div>
<a id="trunkSourceWebKitNetworkProcesscacheCacheStorageEnginecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngine.cpp (242598 => 242599)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngine.cpp  2019-03-07 17:22:27 UTC (rev 242598)
+++ trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngine.cpp     2019-03-07 17:40:40 UTC (rev 242599)
</span><span class="lines">@@ -80,9 +80,9 @@
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    networkProcess.cacheStorageParameters(sessionID, [networkProcess = makeRef(networkProcess), sessionID, callback = WTFMove(callback)] (auto&& rootPath, auto quota) mutable {
</del><ins>+    networkProcess.cacheStorageRootPath(sessionID, [networkProcess = makeRef(networkProcess), sessionID, callback = WTFMove(callback)] (auto&& rootPath) mutable {
</ins><span class="cx">         callback(networkProcess->ensureCacheEngine(sessionID, [&] {
</span><del>-            return adoptRef(*new Engine { sessionID, networkProcess.get(), String { rootPath }, quota });
</del><ins>+            return adoptRef(*new Engine { sessionID, networkProcess.get(), WTFMove(rootPath) });
</ins><span class="cx">         }));
</span><span class="cx">     });
</span><span class="cx"> }
</span><span class="lines">@@ -185,11 +185,10 @@
</span><span class="cx">     });
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-Engine::Engine(PAL::SessionID sessionID, NetworkProcess& process, String&& rootPath, uint64_t quota)
</del><ins>+Engine::Engine(PAL::SessionID sessionID, NetworkProcess& process, String&& rootPath)
</ins><span class="cx">     : m_sessionID(sessionID)
</span><span class="cx">     , m_networkProcess(makeWeakPtr(process))
</span><span class="cx">     , m_rootPath(WTFMove(rootPath))
</span><del>-    , m_quota(quota)
</del><span class="cx"> {
</span><span class="cx">     if (!m_rootPath.isNull())
</span><span class="cx">         m_ioQueue = WorkQueue::create("com.apple.WebKit.CacheStorageEngine.serialBackground", WorkQueue::Type::Serial, WorkQueue::QOS::Background);
</span><span class="lines">@@ -317,7 +316,7 @@
</span><span class="cx"> 
</span><span class="cx">         auto& caches = m_caches.ensure(origin, [&origin, this] {
</span><span class="cx">             auto path = cachesRootPath(origin);
</span><del>-            return Caches::create(*this, WebCore::ClientOrigin { origin }, WTFMove(path), m_quota);
</del><ins>+            return Caches::create(*this, WebCore::ClientOrigin { origin }, WTFMove(path), m_networkProcess->storageQuotaManager(m_sessionID, origin));
</ins><span class="cx">         }).iterator->value;
</span><span class="cx"> 
</span><span class="cx">         if (caches->isInitialized()) {
</span><span class="lines">@@ -650,15 +649,6 @@
</span><span class="cx">     return builder.toString();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void Engine::requestSpace(const WebCore::ClientOrigin& origin, uint64_t quota, uint64_t currentSize, uint64_t spaceRequired, RequestSpaceCallback&& callback)
-{
-    if (!m_networkProcess) {
-        callback({ });
-        return;
-    }
-    m_networkProcess->requestStorageSpace(m_sessionID, origin, quota, currentSize, spaceRequired, WTFMove(callback));
-}
-
</del><span class="cx"> } // namespace CacheStorage
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebKit
</span></span></pre></div>
<a id="trunkSourceWebKitNetworkProcesscacheCacheStorageEngineh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngine.h (242598 => 242599)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngine.h    2019-03-07 17:22:27 UTC (rev 242598)
+++ trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngine.h       2019-03-07 17:40:40 UTC (rev 242599)
</span><span class="lines">@@ -90,11 +90,8 @@
</span><span class="cx">     const NetworkCache::Salt& salt() const { return m_salt.value(); }
</span><span class="cx">     uint64_t nextCacheIdentifier() { return ++m_nextCacheIdentifier; }
</span><span class="cx"> 
</span><del>-    using RequestSpaceCallback = CompletionHandler<void(Optional<uint64_t>)>;
-    void requestSpace(const WebCore::ClientOrigin&, uint64_t quota, uint64_t currentSize, uint64_t spaceRequired, RequestSpaceCallback&&);
-
</del><span class="cx"> private:
</span><del>-    Engine(PAL::SessionID, NetworkProcess&, String&& rootPath, uint64_t quota);
</del><ins>+    Engine(PAL::SessionID, NetworkProcess&, String&& rootPath);
</ins><span class="cx"> 
</span><span class="cx">     void open(const WebCore::ClientOrigin&, const String& cacheName, WebCore::DOMCacheEngine::CacheIdentifierCallback&&);
</span><span class="cx">     void remove(uint64_t cacheIdentifier, WebCore::DOMCacheEngine::CacheIdentifierCallback&&);
</span><span class="lines">@@ -137,7 +134,6 @@
</span><span class="cx">     HashMap<WebCore::ClientOrigin, RefPtr<Caches>> m_caches;
</span><span class="cx">     uint64_t m_nextCacheIdentifier { 0 };
</span><span class="cx">     String m_rootPath;
</span><del>-    uint64_t m_quota { 0 };
</del><span class="cx">     RefPtr<WorkQueue> m_ioQueue;
</span><span class="cx">     Optional<NetworkCache::Salt> m_salt;
</span><span class="cx">     HashMap<CacheIdentifier, LockCount> m_cacheLocks;
</span></span></pre></div>
<a id="trunkSourceWebKitNetworkProcesscacheCacheStorageEngineCachecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngineCache.cpp (242598 => 242599)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngineCache.cpp     2019-03-07 17:22:27 UTC (rev 242598)
+++ trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngineCache.cpp        2019-03-07 17:40:40 UTC (rev 242599)
</span><span class="lines">@@ -400,15 +400,10 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void Cache::put(Vector<Record>&& records, RecordIdentifiersCallback&& callback, CanRequestMoreSpace canRequestMoreSpace)
</del><ins>+void Cache::put(Vector<Record>&& records, RecordIdentifiersCallback&& callback)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(m_state == State::Open);
</span><span class="cx"> 
</span><del>-    if (m_caches.isRequestingSpace()) {
-        m_pendingPutRequests.append({ WTFMove(records), WTFMove(callback) });
-        return;
-    }
-
</del><span class="cx">     WebCore::CacheQueryOptions options;
</span><span class="cx">     uint64_t spaceRequired = 0;
</span><span class="cx"> 
</span><span class="lines">@@ -423,16 +418,6 @@
</span><span class="cx">             spaceRequired -= sameURLRecords->at(position).size;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (m_caches.hasEnoughSpace(spaceRequired)) {
-        storeRecords(WTFMove(records), WTFMove(callback));
-        return;
-    }
-
-    if (canRequestMoreSpace == CanRequestMoreSpace::No) {
-        callback(makeUnexpected(DOMCacheEngine::Error::QuotaExceeded));
-        return;
-    }
-
</del><span class="cx">     m_caches.requestSpace(spaceRequired, [caches = makeRef(m_caches), identifier = m_identifier, records = WTFMove(records), callback = WTFMove(callback)](Optional<DOMCacheEngine::Error>&& error) mutable {
</span><span class="cx">         if (error) {
</span><span class="cx">             callback(makeUnexpected(error.value()));
</span><span class="lines">@@ -443,18 +428,10 @@
</span><span class="cx">             callback(makeUnexpected(DOMCacheEngine::Error::Internal));
</span><span class="cx">             return;
</span><span class="cx">         }
</span><del>-
-        cache->put(WTFMove(records), WTFMove(callback), CanRequestMoreSpace::No);
</del><ins>+        cache->storeRecords(WTFMove(records), WTFMove(callback));
</ins><span class="cx">     });
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void Cache::retryPuttingPendingRecords()
-{
-    auto pendingPutRequests = WTFMove(m_pendingPutRequests);
-    for (auto& request : pendingPutRequests)
-        put(WTFMove(request.records), WTFMove(request.callback));
-}
-
</del><span class="cx"> void Cache::remove(WebCore::ResourceRequest&& request, WebCore::CacheQueryOptions&& options, RecordIdentifiersCallback&& callback)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(m_state == State::Open);
</span></span></pre></div>
<a id="trunkSourceWebKitNetworkProcesscacheCacheStorageEngineCacheh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngineCache.h (242598 => 242599)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngineCache.h       2019-03-07 17:22:27 UTC (rev 242598)
+++ trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngineCache.h  2019-03-07 17:40:40 UTC (rev 242599)
</span><span class="lines">@@ -69,8 +69,7 @@
</span><span class="cx">     void retrieveRecords(const URL&, WebCore::DOMCacheEngine::RecordsCallback&&);
</span><span class="cx">     WebCore::DOMCacheEngine::CacheInfo info() const { return { m_identifier, m_name }; }
</span><span class="cx"> 
</span><del>-    enum class CanRequestMoreSpace { No, Yes };
-    void put(Vector<WebCore::DOMCacheEngine::Record>&&, WebCore::DOMCacheEngine::RecordIdentifiersCallback&&, CanRequestMoreSpace = CanRequestMoreSpace::Yes);
</del><ins>+    void put(Vector<WebCore::DOMCacheEngine::Record>&&, WebCore::DOMCacheEngine::RecordIdentifiersCallback&&);
</ins><span class="cx">     void remove(WebCore::ResourceRequest&&, WebCore::CacheQueryOptions&&, WebCore::DOMCacheEngine::RecordIdentifiersCallback&&);
</span><span class="cx"> 
</span><span class="cx">     Vector<NetworkCache::Key> keys() const;
</span><span class="lines">@@ -78,8 +77,6 @@
</span><span class="cx">     void dispose();
</span><span class="cx">     void clearMemoryRepresentation();
</span><span class="cx"> 
</span><del>-    void retryPuttingPendingRecords();
-
</del><span class="cx">     static Optional<WebCore::DOMCacheEngine::Record> decode(const NetworkCache::Storage::Record&);
</span><span class="cx">     static NetworkCache::Storage::Record encode(const RecordInformation&, const WebCore::DOMCacheEngine::Record&);
</span><span class="cx"> 
</span><span class="lines">@@ -123,12 +120,6 @@
</span><span class="cx">     HashMap<String, Vector<RecordInformation>> m_records;
</span><span class="cx">     uint64_t m_nextRecordIdentifier { 0 };
</span><span class="cx">     Vector<WebCore::DOMCacheEngine::CompletionCallback> m_pendingOpeningCallbacks;
</span><del>-
-    struct PendingPutRequest {
-        Vector<WebCore::DOMCacheEngine::Record> records;
-        WebCore::DOMCacheEngine::RecordIdentifiersCallback callback;
-    };
-    Vector<PendingPutRequest> m_pendingPutRequests;
</del><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace CacheStorage
</span></span></pre></div>
<a id="trunkSourceWebKitNetworkProcesscacheCacheStorageEngineCachescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngineCaches.cpp (242598 => 242599)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngineCaches.cpp    2019-03-07 17:22:27 UTC (rev 242598)
+++ trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngineCaches.cpp       2019-03-07 17:40:40 UTC (rev 242599)
</span><span class="lines">@@ -30,6 +30,7 @@
</span><span class="cx"> #include "NetworkCacheCoders.h"
</span><span class="cx"> #include "NetworkCacheIOChannel.h"
</span><span class="cx"> #include <WebCore/SecurityOrigin.h>
</span><ins>+#include <WebCore/StorageQuotaManager.h>
</ins><span class="cx"> #include <wtf/RunLoop.h>
</span><span class="cx"> #include <wtf/UUID.h>
</span><span class="cx"> #include <wtf/text/StringBuilder.h>
</span><span class="lines">@@ -50,9 +51,21 @@
</span><span class="cx">     return FileSystem::pathByAppendingComponent(cachesRootPath, "origin"_s);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+Caches::Caches(Engine& engine, WebCore::ClientOrigin&& origin, String&& rootPath, StorageQuotaManager& quotaManager)
+    : m_engine(&engine)
+    , m_origin(WTFMove(origin))
+    , m_rootPath(WTFMove(rootPath))
+    , m_quotaManager(makeWeakPtr(quotaManager))
+{
+    quotaManager.addUser(*this);
+}
+
</ins><span class="cx"> Caches::~Caches()
</span><span class="cx"> {
</span><span class="cx">     ASSERT(m_pendingWritingCachesToDiskCallbacks.isEmpty());
</span><ins>+
+    if (m_quotaManager)
+        m_quotaManager->removeUser(*this);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void Caches::retrieveOriginFromDirectory(const String& folderPath, WorkQueue& queue, WTF::CompletionHandler<void(Optional<WebCore::ClientOrigin>&&)>&& completionHandler)
</span><span class="lines">@@ -78,14 +91,6 @@
</span><span class="cx">     });
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-Caches::Caches(Engine& engine, WebCore::ClientOrigin&& origin, String&& rootPath, uint64_t quota)
-    : m_engine(&engine)
-    , m_origin(WTFMove(origin))
-    , m_rootPath(WTFMove(rootPath))
-    , m_quota(quota)
-{
-}
-
</del><span class="cx"> void Caches::storeOrigin(CompletionCallback&& completionHandler)
</span><span class="cx"> {
</span><span class="cx">     WTF::Persistence::Encoder encoder;
</span><span class="lines">@@ -488,37 +493,22 @@
</span><span class="cx"> 
</span><span class="cx"> void Caches::requestSpace(uint64_t spaceRequired, WebCore::DOMCacheEngine::CompletionCallback&& callback)
</span><span class="cx"> {
</span><del>-    ASSERT(!m_isRequestingSpace);
-
-    ASSERT(m_quota < m_size + spaceRequired);
-
-    if (!m_engine) {
</del><ins>+    if (!m_quotaManager) {
</ins><span class="cx">         callback(Error::QuotaExceeded);
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    m_isRequestingSpace = true;
-    m_engine->requestSpace(m_origin, m_quota, m_size, spaceRequired, [this, protectedThis = makeRef(*this), callback = WTFMove(callback)] (Optional<uint64_t> newQuota) {
-        m_isRequestingSpace = false;
-        if (!newQuota) {
</del><ins>+    m_quotaManager->requestSpace(spaceRequired, [callback = WTFMove(callback)](auto decision) {
+        switch (decision) {
+        case StorageQuotaManager::Decision::Deny:
</ins><span class="cx">             callback(Error::QuotaExceeded);
</span><del>-            notifyCachesOfRequestSpaceEnd();
</del><span class="cx">             return;
</span><del>-        }
-        m_quota = *newQuota;
-        callback({ });
-        notifyCachesOfRequestSpaceEnd();
</del><ins>+        case StorageQuotaManager::Decision::Grant:
+            callback({ });
+        };
</ins><span class="cx">     });
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void Caches::notifyCachesOfRequestSpaceEnd()
-{
-    for (auto& cache : m_caches)
-        cache.retryPuttingPendingRecords();
-    for (auto& cache : m_removedCaches)
-        cache.retryPuttingPendingRecords();
-}
-
</del><span class="cx"> void Caches::writeRecord(const Cache& cache, const RecordInformation& recordInformation, Record&& record, uint64_t previousRecordSize, CompletionCallback&& callback)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(m_isInitialized);
</span><span class="lines">@@ -527,8 +517,6 @@
</span><span class="cx">     m_size += recordInformation.size;
</span><span class="cx">     m_size -= previousRecordSize;
</span><span class="cx"> 
</span><del>-    ASSERT(m_size <= m_quota);
-
</del><span class="cx">     if (!shouldPersist()) {
</span><span class="cx">         m_volatileStorage.set(recordInformation.key, WTFMove(record));
</span><span class="cx">         callback(WTF::nullopt);
</span></span></pre></div>
<a id="trunkSourceWebKitNetworkProcesscacheCacheStorageEngineCachesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngineCaches.h (242598 => 242599)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngineCaches.h      2019-03-07 17:22:27 UTC (rev 242598)
+++ trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngineCaches.h 2019-03-07 17:40:40 UTC (rev 242599)
</span><span class="lines">@@ -28,9 +28,14 @@
</span><span class="cx"> #include "CacheStorageEngineCache.h"
</span><span class="cx"> #include "NetworkCacheStorage.h"
</span><span class="cx"> #include <WebCore/ClientOrigin.h>
</span><ins>+#include <WebCore/StorageQuotaUser.h>
</ins><span class="cx"> #include <wtf/CompletionHandler.h>
</span><span class="cx"> #include <wtf/Deque.h>
</span><span class="cx"> 
</span><ins>+namespace WebCore {
+class StorageQuotaManager;
+}
+
</ins><span class="cx"> namespace WebKit {
</span><span class="cx"> 
</span><span class="cx"> namespace CacheStorage {
</span><span class="lines">@@ -37,9 +42,9 @@
</span><span class="cx"> 
</span><span class="cx"> class Engine;
</span><span class="cx"> 
</span><del>-class Caches : public RefCounted<Caches> {
</del><ins>+class Caches final : public RefCounted<Caches>, private WebCore::StorageQuotaUser {
</ins><span class="cx"> public:
</span><del>-    static Ref<Caches> create(Engine& engine, WebCore::ClientOrigin&& origin, String&& rootPath, uint64_t quota) { return adoptRef(*new Caches { engine, WTFMove(origin), WTFMove(rootPath), quota }); }
</del><ins>+    static Ref<Caches> create(Engine& engine, WebCore::ClientOrigin&& origin, String&& rootPath, WebCore::StorageQuotaManager& quotaManager) { return adoptRef(*new Caches { engine, WTFMove(origin), WTFMove(rootPath), quotaManager }); }
</ins><span class="cx">     ~Caches();
</span><span class="cx"> 
</span><span class="cx">     static void retrieveOriginFromDirectory(const String& folderPath, WorkQueue&, WTF::CompletionHandler<void(Optional<WebCore::ClientOrigin>&&)>&&);
</span><span class="lines">@@ -60,8 +65,6 @@
</span><span class="cx">     void readRecordsList(Cache&, NetworkCache::Storage::TraverseHandler&&);
</span><span class="cx">     void readRecord(const NetworkCache::Key&, WTF::Function<void(Expected<WebCore::DOMCacheEngine::Record, WebCore::DOMCacheEngine::Error>&&)>&&);
</span><span class="cx"> 
</span><del>-    bool hasEnoughSpace(uint64_t spaceRequired) const { return m_quota >= m_size + spaceRequired; }
-    bool isRequestingSpace() const { return m_isRequestingSpace; }
</del><span class="cx">     void requestSpace(uint64_t spaceRequired, WebCore::DOMCacheEngine::CompletionCallback&&);
</span><span class="cx">     void writeRecord(const Cache&, const RecordInformation&, WebCore::DOMCacheEngine::Record&&, uint64_t previousRecordSize, WebCore::DOMCacheEngine::CompletionCallback&&);
</span><span class="cx"> 
</span><span class="lines">@@ -79,8 +82,11 @@
</span><span class="cx">     uint64_t storageSize() const;
</span><span class="cx"> 
</span><span class="cx"> private:
</span><del>-    Caches(Engine&, WebCore::ClientOrigin&&, String&& rootPath, uint64_t quota);
</del><ins>+    Caches(Engine&, WebCore::ClientOrigin&&, String&& rootPath, WebCore::StorageQuotaManager&);
</ins><span class="cx"> 
</span><ins>+    // StorageQuotaUser API.
+    uint64_t spaceUsed() const final { return m_size; }
+
</ins><span class="cx">     void initializeSize();
</span><span class="cx">     void readCachesFromDisk(WTF::Function<void(Expected<Vector<Cache>, WebCore::DOMCacheEngine::Error>&&)>&&);
</span><span class="cx">     void writeCachesToDisk(WebCore::DOMCacheEngine::CompletionCallback&&);
</span><span class="lines">@@ -94,17 +100,13 @@
</span><span class="cx">     void makeDirty() { ++m_updateCounter; }
</span><span class="cx">     bool isDirty(uint64_t updateCounter) const;
</span><span class="cx"> 
</span><del>-    void notifyCachesOfRequestSpaceEnd();
-
</del><span class="cx">     bool hasActiveCache() const;
</span><span class="cx"> 
</span><span class="cx">     bool m_isInitialized { false };
</span><del>-    bool m_isRequestingSpace { false };
</del><span class="cx">     Engine* m_engine { nullptr };
</span><span class="cx">     uint64_t m_updateCounter { 0 };
</span><span class="cx">     WebCore::ClientOrigin m_origin;
</span><span class="cx">     String m_rootPath;
</span><del>-    uint64_t m_quota { 0 };
</del><span class="cx">     uint64_t m_size { 0 };
</span><span class="cx">     Vector<Cache> m_caches;
</span><span class="cx">     Vector<Cache> m_removedCaches;
</span><span class="lines">@@ -114,6 +116,7 @@
</span><span class="cx">     Vector<WebCore::DOMCacheEngine::CompletionCallback> m_pendingInitializationCallbacks;
</span><span class="cx">     bool m_isWritingCachesToDisk { false };
</span><span class="cx">     Deque<CompletionHandler<void(Optional<WebCore::DOMCacheEngine::Error>)>> m_pendingWritingCachesToDiskCallbacks;
</span><ins>+    WeakPtr<WebCore::StorageQuotaManager> m_quotaManager;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace CacheStorage
</span></span></pre>
</div>
</div>

</body>
</html>