<!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>[179823] trunk/Source/WebKit2</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/179823">179823</a></dd>
<dt>Author</dt> <dd>antti@apple.com</dd>
<dt>Date</dt> <dd>2015-02-09 03:03:06 -0800 (Mon, 09 Feb 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Measure cache size more accurately
https://bugs.webkit.org/show_bug.cgi?id=141378
&lt;rdar://problem/19760224&gt;

Reviewed by Chris Dumez.

Estimate the cache disk space usage from the actual entry sizes instead of the item count.
This prevents large cache items from making the cache grow beyond its bounds.

* NetworkProcess/cache/NetworkCacheStorage.h:
* NetworkProcess/cache/NetworkCacheStorageCocoa.mm:
(WebKit::NetworkCacheStorage::initialize):
(WebKit::NetworkCacheStorage::removeEntry):
(WebKit::NetworkCacheStorage::store):
(WebKit::NetworkCacheStorage::clear):
(WebKit::NetworkCacheStorage::shrinkIfNeeded):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebKit2ChangeLog">trunk/Source/WebKit2/ChangeLog</a></li>
<li><a href="#trunkSourceWebKit2NetworkProcesscacheNetworkCacheStorageh">trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStorage.h</a></li>
<li><a href="#trunkSourceWebKit2NetworkProcesscacheNetworkCacheStorageCocoamm">trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStorageCocoa.mm</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebKit2ChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/ChangeLog (179822 => 179823)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/ChangeLog        2015-02-09 08:18:20 UTC (rev 179822)
+++ trunk/Source/WebKit2/ChangeLog        2015-02-09 11:03:06 UTC (rev 179823)
</span><span class="lines">@@ -1,3 +1,22 @@
</span><ins>+2015-02-08  Antti Koivisto  &lt;antti@apple.com&gt;
+
+        Measure cache size more accurately
+        https://bugs.webkit.org/show_bug.cgi?id=141378
+        &lt;rdar://problem/19760224&gt;
+
+        Reviewed by Chris Dumez.
+
+        Estimate the cache disk space usage from the actual entry sizes instead of the item count.
+        This prevents large cache items from making the cache grow beyond its bounds.
+
+        * NetworkProcess/cache/NetworkCacheStorage.h:
+        * NetworkProcess/cache/NetworkCacheStorageCocoa.mm:
+        (WebKit::NetworkCacheStorage::initialize):
+        (WebKit::NetworkCacheStorage::removeEntry):
+        (WebKit::NetworkCacheStorage::store):
+        (WebKit::NetworkCacheStorage::clear):
+        (WebKit::NetworkCacheStorage::shrinkIfNeeded):
+
</ins><span class="cx"> 2015-02-09  Carlos Garcia Campos  &lt;cgarcia@igalia.com&gt;
</span><span class="cx"> 
</span><span class="cx">         REGRESSION(r179705): [GTK] The Web Inspector doesn't work after r179705
</span></span></pre></div>
<a id="trunkSourceWebKit2NetworkProcesscacheNetworkCacheStorageh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStorage.h (179822 => 179823)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStorage.h        2015-02-09 08:18:20 UTC (rev 179822)
+++ trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStorage.h        2015-02-09 11:03:06 UTC (rev 179823)
</span><span class="lines">@@ -29,7 +29,6 @@
</span><span class="cx"> #if ENABLE(NETWORK_CACHE)
</span><span class="cx"> 
</span><span class="cx"> #include &quot;NetworkCacheKey.h&quot;
</span><del>-#include &lt;WebCore/ResourceResponse.h&gt;
</del><span class="cx"> #include &lt;wtf/BloomFilter.h&gt;
</span><span class="cx"> #include &lt;wtf/Deque.h&gt;
</span><span class="cx"> #include &lt;wtf/HashSet.h&gt;
</span><span class="lines">@@ -46,8 +45,6 @@
</span><span class="cx"> 
</span><span class="cx"> namespace WebKit {
</span><span class="cx"> 
</span><del>-class ShareableResource;
-
</del><span class="cx"> #if PLATFORM(COCOA)
</span><span class="cx"> template &lt;typename T&gt; class DispatchPtr;
</span><span class="cx"> template &lt;typename T&gt; DispatchPtr&lt;T&gt; adoptDispatch(T dispatchObject);
</span><span class="lines">@@ -192,7 +189,7 @@
</span><span class="cx">     size_t m_maximumSize { std::numeric_limits&lt;size_t&gt;::max() };
</span><span class="cx"> 
</span><span class="cx">     BloomFilter&lt;20&gt; m_contentsFilter;
</span><del>-    std::atomic&lt;size_t&gt; m_approximateEntryCount { 0 };
</del><ins>+    std::atomic&lt;size_t&gt; m_approximateSize { 0 };
</ins><span class="cx">     std::atomic&lt;bool&gt; m_shrinkInProgress { false };
</span><span class="cx"> 
</span><span class="cx">     static const int maximumRetrievePriority = 4;
</span></span></pre></div>
<a id="trunkSourceWebKit2NetworkProcesscacheNetworkCacheStorageCocoamm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStorageCocoa.mm (179822 => 179823)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStorageCocoa.mm        2015-02-09 08:18:20 UTC (rev 179822)
+++ trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStorageCocoa.mm        2015-02-09 11:03:06 UTC (rev 179823)
</span><span class="lines">@@ -34,6 +34,7 @@
</span><span class="cx"> #include &lt;dispatch/dispatch.h&gt;
</span><span class="cx"> #include &lt;sys/mman.h&gt;
</span><span class="cx"> #include &lt;sys/stat.h&gt;
</span><ins>+#include &lt;wtf/RandomNumber.h&gt;
</ins><span class="cx"> #include &lt;wtf/RunLoop.h&gt;
</span><span class="cx"> #include &lt;wtf/text/CString.h&gt;
</span><span class="cx"> #include &lt;wtf/text/StringBuilder.h&gt;
</span><span class="lines">@@ -109,11 +110,10 @@
</span><span class="cx">     ASSERT(RunLoop::isMain());
</span><span class="cx"> 
</span><span class="cx">     StringCapture cachePathCapture(m_directoryPath);
</span><del>-    auto&amp; entryCount = m_approximateEntryCount;
</del><span class="cx"> 
</span><del>-    dispatch_async(m_backgroundIOQueue.get(), [this, cachePathCapture, &amp;entryCount] {
</del><ins>+    dispatch_async(m_backgroundIOQueue.get(), [this, cachePathCapture] {
</ins><span class="cx">         String cachePath = cachePathCapture.string();
</span><del>-        traverseCacheFiles(cachePath, [this, &amp;entryCount](const String&amp; fileName, const String&amp;) {
</del><ins>+        traverseCacheFiles(cachePath, [this](const String&amp; fileName, const String&amp; partitionPath) {
</ins><span class="cx">             NetworkCacheKey::HashType hash;
</span><span class="cx">             if (!NetworkCacheKey::stringToHash(fileName, hash))
</span><span class="cx">                 return;
</span><span class="lines">@@ -121,7 +121,10 @@
</span><span class="cx">             dispatch_async(dispatch_get_main_queue(), [this, shortHash] {
</span><span class="cx">                 m_contentsFilter.add(shortHash);
</span><span class="cx">             });
</span><del>-            ++entryCount;
</del><ins>+            auto filePath = WebCore::pathByAppendingComponent(partitionPath, fileName);
+            long long fileSize = 0;
+            WebCore::getFileSize(filePath, fileSize);
+            m_approximateSize += fileSize;
</ins><span class="cx">         });
</span><span class="cx">     });
</span><span class="cx"> }
</span><span class="lines">@@ -323,14 +326,15 @@
</span><span class="cx"> {
</span><span class="cx">     ASSERT(RunLoop::isMain());
</span><span class="cx"> 
</span><ins>+    // For simplicity we don't reduce m_approximateSize on removals caused by load or decode errors.
+    // The next cache shrink will update the size.
+
</ins><span class="cx">     if (m_contentsFilter.mayContain(key.shortHash()))
</span><span class="cx">         m_contentsFilter.remove(key.shortHash());
</span><span class="cx"> 
</span><span class="cx">     StringCapture filePathCapture(filePathForKey(key, m_directoryPath));
</span><del>-    dispatch_async(m_ioQueue.get(), [this, filePathCapture] {
</del><ins>+    dispatch_async(m_backgroundIOQueue.get(), [this, filePathCapture] {
</ins><span class="cx">         WebCore::deleteFile(filePathCapture.string());
</span><del>-        if (m_approximateEntryCount)
-            --m_approximateEntryCount;
</del><span class="cx">     });
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -429,7 +433,6 @@
</span><span class="cx">     ASSERT(RunLoop::isMain());
</span><span class="cx"> 
</span><span class="cx">     m_contentsFilter.add(key.shortHash());
</span><del>-    ++m_approximateEntryCount;
</del><span class="cx"> 
</span><span class="cx">     auto storeOperation = std::make_unique&lt;StoreOperation&gt;(StoreOperation { key, entry, WTF::move(completionHandler) });
</span><span class="cx">     auto&amp; store = *storeOperation;
</span><span class="lines">@@ -441,20 +444,21 @@
</span><span class="cx">         auto writeData = adoptDispatch(dispatch_data_create_concat(encodedHeader.get(), store.entry.body.dispatchData()));
</span><span class="cx"> 
</span><span class="cx">         size_t bodyOffset = dispatch_data_get_size(encodedHeader.get());
</span><del>-        size_t bodySize = store.entry.body.size();
</del><span class="cx"> 
</span><span class="cx">         int fd;
</span><span class="cx">         auto channel = openFileForKey(store.key, FileOpenType::Create, cachePathCapture.string(), fd);
</span><del>-        dispatch_io_write(channel.get(), 0, writeData.get(), dispatch_get_main_queue(), [this, &amp;store, fd, bodyOffset, bodySize](bool done, dispatch_data_t, int error) {
</del><ins>+        dispatch_io_write(channel.get(), 0, writeData.get(), dispatch_get_main_queue(), [this, &amp;store, fd, bodyOffset](bool done, dispatch_data_t, int error) {
</ins><span class="cx">             ASSERT_UNUSED(done, done);
</span><span class="cx">             LOG(NetworkCacheStorage, &quot;(NetworkProcess) write complete error=%d&quot;, error);
</span><span class="cx">             if (error) {
</span><span class="cx">                 if (m_contentsFilter.mayContain(store.key.shortHash()))
</span><span class="cx">                     m_contentsFilter.remove(store.key.shortHash());
</span><del>-                if (m_approximateEntryCount)
-                    --m_approximateEntryCount;
</del><span class="cx">             }
</span><ins>+            size_t bodySize = store.entry.body.size();
+            size_t totalSize = bodyOffset + bodySize;
</ins><span class="cx"> 
</span><ins>+            m_approximateSize += totalSize;
+
</ins><span class="cx">             bool shouldMapBody = !error &amp;&amp; bodySize &gt;= vm_page_size;
</span><span class="cx">             auto bodyMap = shouldMapBody ? mapFile(fd, bodyOffset, bodySize) : nullptr;
</span><span class="cx"> 
</span><span class="lines">@@ -531,7 +535,7 @@
</span><span class="cx">     LOG(NetworkCacheStorage, &quot;(NetworkProcess) clearing cache&quot;);
</span><span class="cx"> 
</span><span class="cx">     m_contentsFilter.clear();
</span><del>-    m_approximateEntryCount = 0;
</del><ins>+    m_approximateSize = 0;
</ins><span class="cx"> 
</span><span class="cx">     StringCapture directoryPathCapture(m_directoryPath);
</span><span class="cx"> 
</span><span class="lines">@@ -549,32 +553,35 @@
</span><span class="cx"> 
</span><span class="cx"> void NetworkCacheStorage::shrinkIfNeeded()
</span><span class="cx"> {
</span><del>-    const size_t assumedAverageResourceSize { 48 * 1024 };
-    const size_t everyNthResourceToDelete { 4 };
</del><ins>+    ASSERT(RunLoop::isMain());
</ins><span class="cx"> 
</span><del>-    size_t estimatedCacheSize = assumedAverageResourceSize * m_approximateEntryCount;
</del><ins>+    static const double deletionProbability { 0.25 };
</ins><span class="cx"> 
</span><del>-    if (estimatedCacheSize &lt;= m_maximumSize)
</del><ins>+    if (m_approximateSize &lt;= m_maximumSize)
</ins><span class="cx">         return;
</span><span class="cx">     if (m_shrinkInProgress)
</span><span class="cx">         return;
</span><span class="cx">     m_shrinkInProgress = true;
</span><span class="cx"> 
</span><del>-    LOG(NetworkCacheStorage, &quot;(NetworkProcess) shrinking cache m_approximateEntryCount=%d estimatedCacheSize=%d, m_maximumSize=%d&quot;, static_cast&lt;size_t&gt;(m_approximateEntryCount), estimatedCacheSize, m_maximumSize);
</del><ins>+    LOG(NetworkCacheStorage, &quot;(NetworkProcess) shrinking cache approximateSize=%d, m_maximumSize=%d&quot;, static_cast&lt;size_t&gt;(m_approximateSize), m_maximumSize);
</ins><span class="cx"> 
</span><ins>+    m_approximateSize = 0;
+
</ins><span class="cx">     StringCapture cachePathCapture(m_directoryPath);
</span><span class="cx">     dispatch_async(m_backgroundIOQueue.get(), [this, cachePathCapture] {
</span><span class="cx">         String cachePath = cachePathCapture.string();
</span><del>-        size_t foundEntryCount = 0;
-        size_t deletedCount = 0;
-        traverseCacheFiles(cachePath, [this, &amp;foundEntryCount, &amp;deletedCount](const String&amp; fileName, const String&amp; partitionPath) {
-            ++foundEntryCount;
-            if (foundEntryCount % everyNthResourceToDelete)
</del><ins>+        traverseCacheFiles(cachePath, [this](const String&amp; fileName, const String&amp; partitionPath) {
+            auto filePath = WebCore::pathByAppendingComponent(partitionPath, fileName);
+
+            bool shouldDelete = randomNumber() &lt; deletionProbability;
+            if (!shouldDelete) {
+                long long fileSize = 0;
+                WebCore::getFileSize(filePath, fileSize);
+                m_approximateSize += fileSize;
</ins><span class="cx">                 return;
</span><del>-            ++deletedCount;
</del><ins>+            }
</ins><span class="cx"> 
</span><del>-            WebCore::deleteFile(WebCore::pathByAppendingComponent(partitionPath, fileName));
-
</del><ins>+            WebCore::deleteFile(filePath);
</ins><span class="cx">             NetworkCacheKey::HashType hash;
</span><span class="cx">             if (!NetworkCacheKey::stringToHash(fileName, hash))
</span><span class="cx">                 return;
</span><span class="lines">@@ -584,10 +591,9 @@
</span><span class="cx">                     m_contentsFilter.remove(shortHash);
</span><span class="cx">             });
</span><span class="cx">         });
</span><del>-        m_approximateEntryCount = foundEntryCount - deletedCount;
</del><span class="cx">         m_shrinkInProgress = false;
</span><span class="cx"> 
</span><del>-        LOG(NetworkCacheStorage, &quot;(NetworkProcess) cache shrink completed m_approximateEntryCount=%d&quot;, static_cast&lt;size_t&gt;(m_approximateEntryCount));
</del><ins>+        LOG(NetworkCacheStorage, &quot;(NetworkProcess) cache shrink completed approximateSize=%d&quot;, static_cast&lt;size_t&gt;(m_approximateSize));
</ins><span class="cx">     });
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>