<!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>[182090] 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/182090">182090</a></dd>
<dt>Author</dt> <dd>cdumez@apple.com</dd>
<dt>Date</dt> <dd>2015-03-27 16:49:15 -0700 (Fri, 27 Mar 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>[WK2][NetworkCache] Use WTF::WorkQueue abstraction inside NetworkCacheStatistics
https://bugs.webkit.org/show_bug.cgi?id=143154

Reviewed by Antti Koivisto.

Use WTF::WorkQueue abstraction inside NetworkCacheStatistics, like we
already do in NetworkCacheStorage.

* NetworkProcess/cache/NetworkCacheStatistics.cpp: Renamed from Source/WebKit2/NetworkProcess/cache/NetworkCacheStatisticsCocoa.mm.
(WebKit::NetworkCache::executeSQLCommand):
(WebKit::NetworkCache::executeSQLStatement):
(WebKit::NetworkCache::Statistics::open):
(WebKit::NetworkCache::Statistics::Statistics):
(WebKit::NetworkCache::Statistics::initialize):
(WebKit::NetworkCache::Statistics::bootstrapFromNetworkCache):
(WebKit::NetworkCache::Statistics::shrinkIfNeeded):
(WebKit::NetworkCache::Statistics::recordRetrievalRequest):
(WebKit::NetworkCache::Statistics::recordNotCachingResponse):
(WebKit::NetworkCache::retrieveDecisionToDiagnosticKey):
(WebKit::NetworkCache::Statistics::recordNotUsingCacheForRequest):
(WebKit::NetworkCache::storeDecisionToDiagnosticKey):
(WebKit::NetworkCache::Statistics::recordRetrievalFailure):
(WebKit::NetworkCache::cachedEntryReuseFailureToDiagnosticKey):
(WebKit::NetworkCache::Statistics::recordRetrievedCachedEntry):
(WebKit::NetworkCache::Statistics::markAsRequested):
(WebKit::NetworkCache::Statistics::writeTimerFired):
(WebKit::NetworkCache::Statistics::queryWasEverRequested):
(WebKit::NetworkCache::Statistics::clear):
(WebKit::NetworkCache::Statistics::addHashesToDatabase):
(WebKit::NetworkCache::Statistics::addStoreDecisionsToDatabase):
* NetworkProcess/cache/NetworkCacheStatistics.h:
(WebKit::NetworkCache::Statistics::serialBackgroundIOQueue):
* WebKit2.xcodeproj/project.pbxproj:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebKit2ChangeLog">trunk/Source/WebKit2/ChangeLog</a></li>
<li><a href="#trunkSourceWebKit2NetworkProcesscacheNetworkCacheStatisticsh">trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStatistics.h</a></li>
<li><a href="#trunkSourceWebKit2WebKit2xcodeprojprojectpbxproj">trunk/Source/WebKit2/WebKit2.xcodeproj/project.pbxproj</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceWebKit2NetworkProcesscacheNetworkCacheStatisticscpp">trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStatistics.cpp</a></li>
</ul>

<h3>Removed Paths</h3>
<ul>
<li><a href="#trunkSourceWebKit2NetworkProcesscacheNetworkCacheStatisticsCocoamm">trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStatisticsCocoa.mm</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebKit2ChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/ChangeLog (182089 => 182090)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/ChangeLog        2015-03-27 23:08:01 UTC (rev 182089)
+++ trunk/Source/WebKit2/ChangeLog        2015-03-27 23:49:15 UTC (rev 182090)
</span><span class="lines">@@ -1,3 +1,39 @@
</span><ins>+2015-03-27  Chris Dumez  &lt;cdumez@apple.com&gt;
+
+        [WK2][NetworkCache] Use WTF::WorkQueue abstraction inside NetworkCacheStatistics
+        https://bugs.webkit.org/show_bug.cgi?id=143154
+
+        Reviewed by Antti Koivisto.
+
+        Use WTF::WorkQueue abstraction inside NetworkCacheStatistics, like we
+        already do in NetworkCacheStorage.
+
+        * NetworkProcess/cache/NetworkCacheStatistics.cpp: Renamed from Source/WebKit2/NetworkProcess/cache/NetworkCacheStatisticsCocoa.mm.
+        (WebKit::NetworkCache::executeSQLCommand):
+        (WebKit::NetworkCache::executeSQLStatement):
+        (WebKit::NetworkCache::Statistics::open):
+        (WebKit::NetworkCache::Statistics::Statistics):
+        (WebKit::NetworkCache::Statistics::initialize):
+        (WebKit::NetworkCache::Statistics::bootstrapFromNetworkCache):
+        (WebKit::NetworkCache::Statistics::shrinkIfNeeded):
+        (WebKit::NetworkCache::Statistics::recordRetrievalRequest):
+        (WebKit::NetworkCache::Statistics::recordNotCachingResponse):
+        (WebKit::NetworkCache::retrieveDecisionToDiagnosticKey):
+        (WebKit::NetworkCache::Statistics::recordNotUsingCacheForRequest):
+        (WebKit::NetworkCache::storeDecisionToDiagnosticKey):
+        (WebKit::NetworkCache::Statistics::recordRetrievalFailure):
+        (WebKit::NetworkCache::cachedEntryReuseFailureToDiagnosticKey):
+        (WebKit::NetworkCache::Statistics::recordRetrievedCachedEntry):
+        (WebKit::NetworkCache::Statistics::markAsRequested):
+        (WebKit::NetworkCache::Statistics::writeTimerFired):
+        (WebKit::NetworkCache::Statistics::queryWasEverRequested):
+        (WebKit::NetworkCache::Statistics::clear):
+        (WebKit::NetworkCache::Statistics::addHashesToDatabase):
+        (WebKit::NetworkCache::Statistics::addStoreDecisionsToDatabase):
+        * NetworkProcess/cache/NetworkCacheStatistics.h:
+        (WebKit::NetworkCache::Statistics::serialBackgroundIOQueue):
+        * WebKit2.xcodeproj/project.pbxproj:
+
</ins><span class="cx"> 2015-03-27  Ryosuke Niwa  &lt;rniwa@webkit.org&gt;
</span><span class="cx"> 
</span><span class="cx">         Safari clears selection when its window gets activated via mouse down
</span></span></pre></div>
<a id="trunkSourceWebKit2NetworkProcesscacheNetworkCacheStatisticscppfromrev182089trunkSourceWebKit2NetworkProcesscacheNetworkCacheStatisticsCocoamm"></a>
<div class="copfile"><h4>Copied: trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStatistics.cpp (from rev 182089, trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStatisticsCocoa.mm) (0 => 182090)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStatistics.cpp                                (rev 0)
+++ trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStatistics.cpp        2015-03-27 23:49:15 UTC (rev 182090)
</span><span class="lines">@@ -0,0 +1,436 @@
</span><ins>+/*
+ * Copyright (C) 2015 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. AND ITS CONTRIBUTORS ``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 ITS 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 &quot;config.h&quot;
+
+#if ENABLE(NETWORK_CACHE)
+#include &quot;NetworkCacheStatistics.h&quot;
+
+#include &quot;Logging.h&quot;
+#include &quot;NetworkCache.h&quot;
+#include &quot;NetworkCacheFileSystemPosix.h&quot;
+#include &quot;NetworkProcess.h&quot;
+#include &lt;WebCore/DiagnosticLoggingKeys.h&gt;
+#include &lt;WebCore/DiagnosticLoggingResultType.h&gt;
+#include &lt;WebCore/ResourceRequest.h&gt;
+#include &lt;WebCore/SQLiteDatabaseTracker.h&gt;
+#include &lt;WebCore/SQLiteStatement.h&gt;
+#include &lt;WebCore/SQLiteTransaction.h&gt;
+#include &lt;wtf/RunLoop.h&gt;
+
+namespace WebKit {
+namespace NetworkCache {
+
+static const char* StatisticsDatabaseName = &quot;WebKitCacheStatistics.db&quot;;
+static const std::chrono::milliseconds mininumWriteInterval = std::chrono::milliseconds(10000);
+
+static bool executeSQLCommand(WebCore::SQLiteDatabase&amp; database, const String&amp; sql)
+{
+    ASSERT(!RunLoop::isMain());
+    ASSERT(WebCore::SQLiteDatabaseTracker::hasTransactionInProgress());
+    ASSERT(database.isOpen());
+
+    bool result = database.executeCommand(sql);
+    if (!result)
+        LOG_ERROR(&quot;Network cache statistics: failed to execute statement \&quot;%s\&quot; error \&quot;%s\&quot;&quot;, sql.utf8().data(), database.lastErrorMsg());
+
+    return result;
+}
+
+static bool executeSQLStatement(WebCore::SQLiteStatement&amp; statement)
+{
+    ASSERT(!RunLoop::isMain());
+    ASSERT(WebCore::SQLiteDatabaseTracker::hasTransactionInProgress());
+    ASSERT(statement.database().isOpen());
+
+    if (statement.step() != WebCore::SQLResultDone) {
+        LOG_ERROR(&quot;Network cache statistics: failed to execute statement \&quot;%s\&quot; error \&quot;%s\&quot;&quot;, statement.query().utf8().data(), statement.database().lastErrorMsg());
+        return false;
+    }
+
+    return true;
+}
+
+std::unique_ptr&lt;Statistics&gt; Statistics::open(const String&amp; cachePath)
+{
+    ASSERT(RunLoop::isMain());
+
+    String databasePath = WebCore::pathByAppendingComponent(cachePath, StatisticsDatabaseName);
+    return std::unique_ptr&lt;Statistics&gt;(new Statistics(databasePath));
+}
+
+Statistics::Statistics(const String&amp; databasePath)
+    : m_serialBackgroundIOQueue(WorkQueue::create(&quot;com.apple.WebKit.Cache.Statistics.Background&quot;, WorkQueue::Type::Serial, WorkQueue::QOS::Background))
+    , m_writeTimer(*this, &amp;Statistics::writeTimerFired)
+{
+    initialize(databasePath);
+}
+
+void Statistics::initialize(const String&amp; databasePath)
+{
+    ASSERT(RunLoop::isMain());
+
+    auto startTime = std::chrono::system_clock::now();
+
+    StringCapture databasePathCapture(databasePath);
+    StringCapture networkCachePathCapture(singleton().storagePath());
+    serialBackgroundIOQueue().dispatch([this, databasePathCapture, networkCachePathCapture, startTime] {
+        WebCore::SQLiteTransactionInProgressAutoCounter transactionCounter;
+
+        String databasePath = databasePathCapture.string();
+        if (!WebCore::makeAllDirectories(WebCore::directoryName(databasePath)))
+            return;
+
+        LOG(NetworkCache, &quot;(NetworkProcess) Opening network cache statistics database at %s...&quot;, databasePath.utf8().data());
+        m_database.open(databasePath);
+        m_database.disableThreadingChecks();
+        if (!m_database.isOpen()) {
+            LOG_ERROR(&quot;Network cache statistics: Failed to open / create the network cache statistics database&quot;);
+            return;
+        }
+
+        executeSQLCommand(m_database, ASCIILiteral(&quot;CREATE TABLE IF NOT EXISTS AlreadyRequested (hash TEXT PRIMARY KEY)&quot;));
+        executeSQLCommand(m_database, ASCIILiteral(&quot;CREATE TABLE IF NOT EXISTS UncachedReason (hash TEXT PRIMARY KEY, reason INTEGER)&quot;));
+
+        WebCore::SQLiteStatement statement(m_database, ASCIILiteral(&quot;SELECT count(*) FROM AlreadyRequested&quot;));
+        if (statement.prepareAndStep() != WebCore::SQLResultRow) {
+            LOG_ERROR(&quot;Network cache statistics: Failed to count the number of rows in AlreadyRequested table&quot;);
+            return;
+        }
+
+        m_approximateEntryCount = statement.getColumnInt(0);
+
+#if !LOG_DISABLED
+        auto elapsedMS = std::chrono::duration_cast&lt;std::chrono::milliseconds&gt;(std::chrono::system_clock::now() - startTime).count();
+#endif
+        LOG(NetworkCache, &quot;(NetworkProcess) Network cache statistics database load complete, entries=%lu time=%lldms&quot;, static_cast&lt;size_t&gt;(m_approximateEntryCount), elapsedMS);
+
+        if (!m_approximateEntryCount) {
+            bootstrapFromNetworkCache(networkCachePathCapture.string());
+#if !LOG_DISABLED
+            elapsedMS = std::chrono::duration_cast&lt;std::chrono::milliseconds&gt;(std::chrono::system_clock::now() - startTime).count();
+#endif
+            LOG(NetworkCache, &quot;(NetworkProcess) Network cache statistics database bootstrapping complete, entries=%lu time=%lldms&quot;, static_cast&lt;size_t&gt;(m_approximateEntryCount), elapsedMS);
+        }
+    });
+}
+
+void Statistics::bootstrapFromNetworkCache(const String&amp; networkCachePath)
+{
+    ASSERT(!RunLoop::isMain());
+
+    LOG(NetworkCache, &quot;(NetworkProcess) Bootstrapping the network cache statistics database from the network cache...&quot;);
+
+    Vector&lt;StringCapture&gt; hashes;
+    traverseCacheFiles(networkCachePath, [&amp;hashes](const String&amp; hash, const String&amp;) {
+        hashes.append(hash);
+    });
+
+    WebCore::SQLiteTransactionInProgressAutoCounter transactionCounter;
+    WebCore::SQLiteTransaction writeTransaction(m_database);
+    writeTransaction.begin();
+
+    addHashesToDatabase(hashes);
+
+    writeTransaction.commit();
+}
+
+void Statistics::shrinkIfNeeded()
+{
+    ASSERT(RunLoop::isMain());
+    const size_t maxEntries = 100000;
+
+    if (m_approximateEntryCount &lt; maxEntries)
+        return;
+
+    LOG(NetworkCache, &quot;(NetworkProcess) shrinking statistics cache m_approximateEntryCount=%lu, maxEntries=%lu&quot;, static_cast&lt;size_t&gt;(m_approximateEntryCount), maxEntries);
+
+    clear();
+
+    StringCapture networkCachePathCapture(singleton().storagePath());
+    serialBackgroundIOQueue().dispatch([this, networkCachePathCapture] {
+        bootstrapFromNetworkCache(networkCachePathCapture.string());
+        LOG(NetworkCache, &quot;(NetworkProcess) statistics cache shrink completed m_approximateEntryCount=%lu&quot;, static_cast&lt;size_t&gt;(m_approximateEntryCount));
+    });
+}
+
+void Statistics::recordRetrievalRequest(uint64_t webPageID)
+{
+    NetworkProcess::singleton().logDiagnosticMessage(webPageID, WebCore::DiagnosticLoggingKeys::networkCacheKey(), WebCore::DiagnosticLoggingKeys::retrievalRequestKey(), WebCore::ShouldSample::Yes);
+}
+
+void Statistics::recordNotCachingResponse(const Key&amp; key, StoreDecision storeDecision)
+{
+    ASSERT(storeDecision != StoreDecision::Yes);
+
+    m_storeDecisionsToAdd.set(key.hashAsString(), storeDecision);
+    if (!m_writeTimer.isActive())
+        m_writeTimer.startOneShot(mininumWriteInterval);
+}
+
+static String retrieveDecisionToDiagnosticKey(RetrieveDecision retrieveDecision)
+{
+    switch (retrieveDecision) {
+    case RetrieveDecision::NoDueToHTTPMethod:
+        return WebCore::DiagnosticLoggingKeys::unsupportedHTTPMethodKey();
+    case RetrieveDecision::NoDueToConditionalRequest:
+        return WebCore::DiagnosticLoggingKeys::isConditionalRequestKey();
+    case RetrieveDecision::NoDueToReloadIgnoringCache:
+        return WebCore::DiagnosticLoggingKeys::isReloadIgnoringCacheDataKey();
+    case RetrieveDecision::Yes:
+        ASSERT_NOT_REACHED();
+        break;
+    }
+    return emptyString();
+}
+
+void Statistics::recordNotUsingCacheForRequest(uint64_t webPageID, const Key&amp; key, const WebCore::ResourceRequest&amp; request, RetrieveDecision retrieveDecision)
+{
+    ASSERT(retrieveDecision != RetrieveDecision::Yes);
+
+    String hash = key.hashAsString();
+    WebCore::URL requestURL = request.url();
+    queryWasEverRequested(hash, NeedUncachedReason::No, [this, hash, requestURL, webPageID, retrieveDecision](bool wasEverRequested, const Optional&lt;StoreDecision&gt;&amp;) {
+        if (wasEverRequested) {
+            String diagnosticKey = retrieveDecisionToDiagnosticKey(retrieveDecision);
+            LOG(NetworkCache, &quot;(NetworkProcess) webPageID %llu: %s was previously requested but we are not using the cache, reason: %s&quot;, webPageID, requestURL.string().ascii().data(), diagnosticKey.utf8().data());
+            NetworkProcess::singleton().logDiagnosticMessageWithValue(webPageID, WebCore::DiagnosticLoggingKeys::networkCacheKey(), WebCore::DiagnosticLoggingKeys::unusedKey(), diagnosticKey, WebCore::ShouldSample::Yes);
+        } else {
+            NetworkProcess::singleton().logDiagnosticMessageWithValue(webPageID, WebCore::DiagnosticLoggingKeys::networkCacheKey(), WebCore::DiagnosticLoggingKeys::requestKey(), WebCore::DiagnosticLoggingKeys::neverSeenBeforeKey(), WebCore::ShouldSample::Yes);
+            markAsRequested(hash);
+        }
+    });
+}
+
+static String storeDecisionToDiagnosticKey(StoreDecision storeDecision)
+{
+    switch (storeDecision) {
+    case StoreDecision::NoDueToProtocol:
+        return WebCore::DiagnosticLoggingKeys::notHTTPFamilyKey();
+    case StoreDecision::NoDueToHTTPMethod:
+        return WebCore::DiagnosticLoggingKeys::unsupportedHTTPMethodKey();
+    case StoreDecision::NoDueToAttachmentResponse:
+        return WebCore::DiagnosticLoggingKeys::isAttachmentKey();
+    case StoreDecision::NoDueToNoStoreResponse:
+    case StoreDecision::NoDueToNoStoreRequest:
+        return WebCore::DiagnosticLoggingKeys::cacheControlNoStoreKey();
+    case StoreDecision::NoDueToHTTPStatusCode:
+        return WebCore::DiagnosticLoggingKeys::uncacheableStatusCodeKey();
+    case StoreDecision::Yes:
+        // It was stored but could not be retrieved so it must have been pruned from the cache.
+        return WebCore::DiagnosticLoggingKeys::noLongerInCacheKey();
+    }
+    return String();
+}
+
+void Statistics::recordRetrievalFailure(uint64_t webPageID, const Key&amp; key, const WebCore::ResourceRequest&amp; request)
+{
+    String hash = key.hashAsString();
+    WebCore::URL requestURL = request.url();
+    queryWasEverRequested(hash, NeedUncachedReason::Yes, [this, hash, requestURL, webPageID](bool wasPreviouslyRequested, const Optional&lt;StoreDecision&gt;&amp; storeDecision) {
+        if (wasPreviouslyRequested) {
+            String diagnosticKey = storeDecisionToDiagnosticKey(storeDecision.value());
+            LOG(NetworkCache, &quot;(NetworkProcess) webPageID %llu: %s was previously request but is not in the cache, reason: %s&quot;, webPageID, requestURL.string().ascii().data(), diagnosticKey.utf8().data());
+            NetworkProcess::singleton().logDiagnosticMessageWithValue(webPageID, WebCore::DiagnosticLoggingKeys::networkCacheKey(), WebCore::DiagnosticLoggingKeys::notInCacheKey(), diagnosticKey, WebCore::ShouldSample::Yes);
+        } else {
+            NetworkProcess::singleton().logDiagnosticMessageWithValue(webPageID, WebCore::DiagnosticLoggingKeys::networkCacheKey(), WebCore::DiagnosticLoggingKeys::requestKey(), WebCore::DiagnosticLoggingKeys::neverSeenBeforeKey(), WebCore::ShouldSample::Yes);
+            markAsRequested(hash);
+        }
+    });
+}
+
+static String cachedEntryReuseFailureToDiagnosticKey(UseDecision decision)
+{
+    switch (decision) {
+    case UseDecision::NoDueToVaryingHeaderMismatch:
+        return WebCore::DiagnosticLoggingKeys::varyingHeaderMismatchKey();
+    case UseDecision::NoDueToMissingValidatorFields:
+        return WebCore::DiagnosticLoggingKeys::missingValidatorFieldsKey();
+    case UseDecision::NoDueToDecodeFailure:
+        return WebCore::DiagnosticLoggingKeys::otherKey();
+    case UseDecision::Use:
+    case UseDecision::Validate:
+        ASSERT_NOT_REACHED();
+        break;
+    }
+    return emptyString();
+}
+
+void Statistics::recordRetrievedCachedEntry(uint64_t webPageID, const Key&amp; key, const WebCore::ResourceRequest&amp; request, UseDecision decision)
+{
+    WebCore::URL requestURL = request.url();
+    if (decision == UseDecision::Use || decision == UseDecision::Validate) {
+        LOG(NetworkCache, &quot;(NetworkProcess) webPageID %llu: %s is in the cache and is used&quot;, webPageID, requestURL.string().ascii().data());
+        NetworkProcess::singleton().logDiagnosticMessageWithResult(webPageID, WebCore::DiagnosticLoggingKeys::networkCacheKey(), WebCore::DiagnosticLoggingKeys::retrievalKey(), WebCore::DiagnosticLoggingResultPass, WebCore::ShouldSample::Yes);
+        return;
+    }
+
+    String diagnosticKey = cachedEntryReuseFailureToDiagnosticKey(decision);
+    LOG(NetworkCache, &quot;(NetworkProcess) webPageID %llu: %s is in the cache but wasn't used, reason: %s&quot;, webPageID, requestURL.string().ascii().data(), diagnosticKey.utf8().data());
+    NetworkProcess::singleton().logDiagnosticMessageWithValue(webPageID, WebCore::DiagnosticLoggingKeys::networkCacheKey(), WebCore::DiagnosticLoggingKeys::unusableCachedEntryKey(), diagnosticKey, WebCore::ShouldSample::Yes);
+}
+
+void Statistics::markAsRequested(const String&amp; hash)
+{
+    ASSERT(RunLoop::isMain());
+
+    m_hashesToAdd.add(hash);
+    if (!m_writeTimer.isActive())
+        m_writeTimer.startOneShot(mininumWriteInterval);
+}
+
+void Statistics::writeTimerFired()
+{
+    ASSERT(RunLoop::isMain());
+
+    Vector&lt;StringCapture&gt; hashesToAdd;
+    copyToVector(m_hashesToAdd, hashesToAdd);
+    m_hashesToAdd.clear();
+
+    Vector&lt;std::pair&lt;StringCapture, StoreDecision&gt;&gt; storeDecisionsToAdd;
+    copyToVector(m_storeDecisionsToAdd, storeDecisionsToAdd);
+    m_storeDecisionsToAdd.clear();
+
+    shrinkIfNeeded();
+
+    serialBackgroundIOQueue().dispatch([this, hashesToAdd, storeDecisionsToAdd] {
+        if (!m_database.isOpen())
+            return;
+
+        WebCore::SQLiteTransactionInProgressAutoCounter transactionCounter;
+        WebCore::SQLiteTransaction writeTransaction(m_database);
+        writeTransaction.begin();
+
+        addHashesToDatabase(hashesToAdd);
+        addStoreDecisionsToDatabase(storeDecisionsToAdd);
+
+        writeTransaction.commit();
+    });
+}
+
+void Statistics::queryWasEverRequested(const String&amp; hash, NeedUncachedReason needUncachedReason, const RequestedCompletionHandler&amp; completionHandler)
+{
+    ASSERT(RunLoop::isMain());
+
+    // Query pending writes first.
+    bool wasAlreadyRequested = m_hashesToAdd.contains(hash);
+    if (wasAlreadyRequested &amp;&amp; needUncachedReason == NeedUncachedReason::No) {
+        completionHandler(true, Nullopt);
+        return;
+    }
+    if (needUncachedReason == NeedUncachedReason::Yes &amp;&amp; m_storeDecisionsToAdd.contains(hash)) {
+        completionHandler(true, m_storeDecisionsToAdd.get(hash));
+        return;
+    }
+
+    // Query the database.
+    auto everRequestedQuery = std::make_unique&lt;EverRequestedQuery&gt;(EverRequestedQuery { hash, needUncachedReason == NeedUncachedReason::Yes, completionHandler });
+    auto&amp; query = *everRequestedQuery;
+    m_activeQueries.add(WTF::move(everRequestedQuery));
+    serialBackgroundIOQueue().dispatch([this, wasAlreadyRequested, &amp;query] () mutable {
+        WebCore::SQLiteTransactionInProgressAutoCounter transactionCounter;
+        Optional&lt;StoreDecision&gt; storeDecision;
+        if (m_database.isOpen()) {
+            if (!wasAlreadyRequested) {
+                WebCore::SQLiteStatement statement(m_database, ASCIILiteral(&quot;SELECT hash FROM AlreadyRequested WHERE hash=?&quot;));
+                if (statement.prepare() == WebCore::SQLResultOk) {
+                    statement.bindText(1, query.hash);
+                    wasAlreadyRequested = (statement.step() == WebCore::SQLResultRow);
+                }
+            }
+            if (wasAlreadyRequested &amp;&amp; query.needUncachedReason) {
+                WebCore::SQLiteStatement statement(m_database, ASCIILiteral(&quot;SELECT reason FROM UncachedReason WHERE hash=?&quot;));
+                storeDecision = StoreDecision::Yes;
+                if (statement.prepare() == WebCore::SQLResultOk) {
+                    statement.bindText(1, query.hash);
+                    if (statement.step() == WebCore::SQLResultRow)
+                        storeDecision = static_cast&lt;StoreDecision&gt;(statement.getColumnInt(0));
+                }
+            }
+        }
+        RunLoop::main().dispatch([this, &amp;query, wasAlreadyRequested, storeDecision] {
+            query.completionHandler(wasAlreadyRequested, storeDecision);
+            m_activeQueries.remove(&amp;query);
+        });
+    });
+}
+
+void Statistics::clear()
+{
+    ASSERT(RunLoop::isMain());
+
+    serialBackgroundIOQueue().dispatch([this] {
+        if (m_database.isOpen()) {
+            WebCore::SQLiteTransactionInProgressAutoCounter transactionCounter;
+            WebCore::SQLiteTransaction deleteTransaction(m_database);
+            deleteTransaction.begin();
+            executeSQLCommand(m_database, ASCIILiteral(&quot;DELETE FROM AlreadyRequested&quot;));
+            executeSQLCommand(m_database, ASCIILiteral(&quot;DELETE FROM UncachedReason&quot;));
+            deleteTransaction.commit();
+            m_approximateEntryCount = 0;
+        }
+    });
+}
+
+void Statistics::addHashesToDatabase(const Vector&lt;StringCapture&gt;&amp; hashes)
+{
+    ASSERT(!RunLoop::isMain());
+    ASSERT(WebCore::SQLiteDatabaseTracker::hasTransactionInProgress());
+    ASSERT(m_database.isOpen());
+
+    WebCore::SQLiteStatement statement(m_database, ASCIILiteral(&quot;INSERT OR IGNORE INTO AlreadyRequested (hash) VALUES (?)&quot;));
+    if (statement.prepare() != WebCore::SQLResultOk)
+        return;
+
+    for (auto&amp; hash : hashes) {
+        statement.bindText(1, hash.string());
+        if (executeSQLStatement(statement))
+            ++m_approximateEntryCount;
+        statement.reset();
+    }
+}
+
+void Statistics::addStoreDecisionsToDatabase(const Vector&lt;std::pair&lt;StringCapture, StoreDecision&gt;&gt;&amp; storeDecisions)
+{
+    ASSERT(!RunLoop::isMain());
+    ASSERT(WebCore::SQLiteDatabaseTracker::hasTransactionInProgress());
+    ASSERT(m_database.isOpen());
+
+    WebCore::SQLiteStatement statement(m_database, ASCIILiteral(&quot;INSERT OR REPLACE INTO UncachedReason (hash, reason) VALUES (?, ?)&quot;));
+    if (statement.prepare() != WebCore::SQLResultOk)
+        return;
+
+    for (auto&amp; pair : storeDecisions) {
+        statement.bindText(1, pair.first.string());
+        statement.bindInt(2, static_cast&lt;int&gt;(pair.second));
+        executeSQLStatement(statement);
+        statement.reset();
+    }
+}
+
+}
+}
+
+#endif // ENABLE(NETWORK_CACHE)
</ins></span></pre></div>
<a id="trunkSourceWebKit2NetworkProcesscacheNetworkCacheStatisticsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStatistics.h (182089 => 182090)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStatistics.h        2015-03-27 23:08:01 UTC (rev 182089)
+++ trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStatistics.h        2015-03-27 23:49:15 UTC (rev 182090)
</span><span class="lines">@@ -30,9 +30,9 @@
</span><span class="cx"> 
</span><span class="cx"> #include &quot;NetworkCache.h&quot;
</span><span class="cx"> #include &quot;NetworkCacheKey.h&quot;
</span><del>-#include &quot;NetworkCacheStorage.h&quot;
</del><span class="cx"> #include &lt;WebCore/SQLiteDatabase.h&gt;
</span><span class="cx"> #include &lt;WebCore/Timer.h&gt;
</span><ins>+#include &lt;wtf/WorkQueue.h&gt;
</ins><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> class ResourceRequest;
</span><span class="lines">@@ -56,6 +56,8 @@
</span><span class="cx"> private:
</span><span class="cx">     explicit Statistics(const String&amp; databasePath);
</span><span class="cx"> 
</span><ins>+    WorkQueue&amp; serialBackgroundIOQueue() { return m_serialBackgroundIOQueue.get(); }
+
</ins><span class="cx">     void initialize(const String&amp; databasePath);
</span><span class="cx">     void bootstrapFromNetworkCache(const String&amp; networkCachePath);
</span><span class="cx">     void shrinkIfNeeded();
</span><span class="lines">@@ -77,9 +79,7 @@
</span><span class="cx"> 
</span><span class="cx">     std::atomic&lt;size_t&gt; m_approximateEntryCount { 0 };
</span><span class="cx"> 
</span><del>-#if PLATFORM(COCOA)
-    mutable DispatchPtr&lt;dispatch_queue_t&gt; m_backgroundIOQueue;
-#endif
</del><ins>+    mutable Ref&lt;WorkQueue&gt; m_serialBackgroundIOQueue;
</ins><span class="cx">     mutable HashSet&lt;std::unique_ptr&lt;const EverRequestedQuery&gt;&gt; m_activeQueries;
</span><span class="cx">     WebCore::SQLiteDatabase m_database;
</span><span class="cx">     HashSet&lt;String&gt; m_hashesToAdd;
</span></span></pre></div>
<a id="trunkSourceWebKit2NetworkProcesscacheNetworkCacheStatisticsCocoamm"></a>
<div class="delfile"><h4>Deleted: trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStatisticsCocoa.mm (182089 => 182090)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStatisticsCocoa.mm        2015-03-27 23:08:01 UTC (rev 182089)
+++ trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStatisticsCocoa.mm        2015-03-27 23:49:15 UTC (rev 182090)
</span><span class="lines">@@ -1,438 +0,0 @@
</span><del>-/*
- * Copyright (C) 2015 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. AND ITS CONTRIBUTORS ``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 ITS 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 &quot;config.h&quot;
-
-#if ENABLE(NETWORK_CACHE)
-#include &quot;NetworkCacheStatistics.h&quot;
-
-#include &quot;Logging.h&quot;
-#include &quot;NetworkCache.h&quot;
-#include &quot;NetworkCacheFileSystemPosix.h&quot;
-#include &quot;NetworkProcess.h&quot;
-#include &lt;WebCore/DiagnosticLoggingKeys.h&gt;
-#include &lt;WebCore/DiagnosticLoggingResultType.h&gt;
-#include &lt;WebCore/ResourceRequest.h&gt;
-#include &lt;WebCore/SQLiteDatabaseTracker.h&gt;
-#include &lt;WebCore/SQLiteStatement.h&gt;
-#include &lt;WebCore/SQLiteTransaction.h&gt;
-#include &lt;wtf/RunLoop.h&gt;
-
-namespace WebKit {
-namespace NetworkCache {
-
-static const char* StatisticsDatabaseName = &quot;WebKitCacheStatistics.db&quot;;
-static const std::chrono::milliseconds mininumWriteInterval = std::chrono::milliseconds(10000);
-
-static bool executeSQLCommand(WebCore::SQLiteDatabase&amp; database, const String&amp; sql)
-{
-    ASSERT(!RunLoop::isMain());
-    ASSERT(WebCore::SQLiteDatabaseTracker::hasTransactionInProgress());
-    ASSERT(database.isOpen());
-
-    bool result = database.executeCommand(sql);
-    if (!result)
-        LOG_ERROR(&quot;Network cache statistics: failed to execute statement \&quot;%s\&quot; error \&quot;%s\&quot;&quot;, sql.utf8().data(), database.lastErrorMsg());
-
-    return result;
-}
-
-static bool executeSQLStatement(WebCore::SQLiteStatement&amp; statement)
-{
-    ASSERT(!RunLoop::isMain());
-    ASSERT(WebCore::SQLiteDatabaseTracker::hasTransactionInProgress());
-    ASSERT(statement.database().isOpen());
-
-    if (statement.step() != WebCore::SQLResultDone) {
-        LOG_ERROR(&quot;Network cache statistics: failed to execute statement \&quot;%s\&quot; error \&quot;%s\&quot;&quot;, statement.query().utf8().data(), statement.database().lastErrorMsg());
-        return false;
-    }
-
-    return true;
-}
-
-std::unique_ptr&lt;Statistics&gt; Statistics::open(const String&amp; cachePath)
-{
-    ASSERT(RunLoop::isMain());
-
-    String databasePath = WebCore::pathByAppendingComponent(cachePath, StatisticsDatabaseName);
-    return std::unique_ptr&lt;Statistics&gt;(new Statistics(databasePath));
-}
-
-Statistics::Statistics(const String&amp; databasePath)
-    : m_backgroundIOQueue(adoptDispatch(dispatch_queue_create(&quot;com.apple.WebKit.Cache.Statistics.Background&quot;, DISPATCH_QUEUE_SERIAL)))
-    , m_writeTimer(*this, &amp;Statistics::writeTimerFired)
-{
-    dispatch_set_target_queue(m_backgroundIOQueue.get(), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0));
-
-    initialize(databasePath);
-}
-
-void Statistics::initialize(const String&amp; databasePath)
-{
-    ASSERT(RunLoop::isMain());
-
-    auto startTime = std::chrono::system_clock::now();
-
-    StringCapture databasePathCapture(databasePath);
-    StringCapture networkCachePathCapture(singleton().storagePath());
-    dispatch_async(m_backgroundIOQueue.get(), [this, databasePathCapture, networkCachePathCapture, startTime] {
-        WebCore::SQLiteTransactionInProgressAutoCounter transactionCounter;
-
-        String databasePath = databasePathCapture.string();
-        if (!WebCore::makeAllDirectories(WebCore::directoryName(databasePath)))
-            return;
-
-        LOG(NetworkCache, &quot;(NetworkProcess) Opening network cache statistics database at %s...&quot;, databasePath.utf8().data());
-        m_database.open(databasePath);
-        m_database.disableThreadingChecks();
-        if (!m_database.isOpen()) {
-            LOG_ERROR(&quot;Network cache statistics: Failed to open / create the network cache statistics database&quot;);
-            return;
-        }
-
-        executeSQLCommand(m_database, ASCIILiteral(&quot;CREATE TABLE IF NOT EXISTS AlreadyRequested (hash TEXT PRIMARY KEY)&quot;));
-        executeSQLCommand(m_database, ASCIILiteral(&quot;CREATE TABLE IF NOT EXISTS UncachedReason (hash TEXT PRIMARY KEY, reason INTEGER)&quot;));
-
-        WebCore::SQLiteStatement statement(m_database, ASCIILiteral(&quot;SELECT count(*) FROM AlreadyRequested&quot;));
-        if (statement.prepareAndStep() != WebCore::SQLResultRow) {
-            LOG_ERROR(&quot;Network cache statistics: Failed to count the number of rows in AlreadyRequested table&quot;);
-            return;
-        }
-
-        m_approximateEntryCount = statement.getColumnInt(0);
-
-#if !LOG_DISABLED
-        auto elapsedMS = std::chrono::duration_cast&lt;std::chrono::milliseconds&gt;(std::chrono::system_clock::now() - startTime).count();
-#endif
-        LOG(NetworkCache, &quot;(NetworkProcess) Network cache statistics database load complete, entries=%lu time=%lldms&quot;, static_cast&lt;size_t&gt;(m_approximateEntryCount), elapsedMS);
-
-        if (!m_approximateEntryCount) {
-            bootstrapFromNetworkCache(networkCachePathCapture.string());
-#if !LOG_DISABLED
-            elapsedMS = std::chrono::duration_cast&lt;std::chrono::milliseconds&gt;(std::chrono::system_clock::now() - startTime).count();
-#endif
-            LOG(NetworkCache, &quot;(NetworkProcess) Network cache statistics database bootstrapping complete, entries=%lu time=%lldms&quot;, static_cast&lt;size_t&gt;(m_approximateEntryCount), elapsedMS);
-        }
-    });
-}
-
-void Statistics::bootstrapFromNetworkCache(const String&amp; networkCachePath)
-{
-    ASSERT(!RunLoop::isMain());
-
-    LOG(NetworkCache, &quot;(NetworkProcess) Bootstrapping the network cache statistics database from the network cache...&quot;);
-
-    Vector&lt;StringCapture&gt; hashes;
-    traverseCacheFiles(networkCachePath, [&amp;hashes](const String&amp; hash, const String&amp;) {
-        hashes.append(hash);
-    });
-
-    WebCore::SQLiteTransactionInProgressAutoCounter transactionCounter;
-    WebCore::SQLiteTransaction writeTransaction(m_database);
-    writeTransaction.begin();
-
-    addHashesToDatabase(hashes);
-
-    writeTransaction.commit();
-}
-
-void Statistics::shrinkIfNeeded()
-{
-    ASSERT(RunLoop::isMain());
-    const size_t maxEntries = 100000;
-
-    if (m_approximateEntryCount &lt; maxEntries)
-        return;
-
-    LOG(NetworkCache, &quot;(NetworkProcess) shrinking statistics cache m_approximateEntryCount=%lu, maxEntries=%lu&quot;, static_cast&lt;size_t&gt;(m_approximateEntryCount), maxEntries);
-
-    clear();
-
-    StringCapture networkCachePathCapture(singleton().storagePath());
-    dispatch_async(m_backgroundIOQueue.get(), [this, networkCachePathCapture] {
-        bootstrapFromNetworkCache(networkCachePathCapture.string());
-        LOG(NetworkCache, &quot;(NetworkProcess) statistics cache shrink completed m_approximateEntryCount=%lu&quot;, static_cast&lt;size_t&gt;(m_approximateEntryCount));
-    });
-}
-
-void Statistics::recordRetrievalRequest(uint64_t webPageID)
-{
-    NetworkProcess::singleton().logDiagnosticMessage(webPageID, WebCore::DiagnosticLoggingKeys::networkCacheKey(), WebCore::DiagnosticLoggingKeys::retrievalRequestKey(), WebCore::ShouldSample::Yes);
-}
-
-void Statistics::recordNotCachingResponse(const Key&amp; key, StoreDecision storeDecision)
-{
-    ASSERT(storeDecision != StoreDecision::Yes);
-
-    m_storeDecisionsToAdd.set(key.hashAsString(), storeDecision);
-    if (!m_writeTimer.isActive())
-        m_writeTimer.startOneShot(mininumWriteInterval);
-}
-
-static String retrieveDecisionToDiagnosticKey(RetrieveDecision retrieveDecision)
-{
-    switch (retrieveDecision) {
-    case RetrieveDecision::NoDueToHTTPMethod:
-        return WebCore::DiagnosticLoggingKeys::unsupportedHTTPMethodKey();
-    case RetrieveDecision::NoDueToConditionalRequest:
-        return WebCore::DiagnosticLoggingKeys::isConditionalRequestKey();
-    case RetrieveDecision::NoDueToReloadIgnoringCache:
-        return WebCore::DiagnosticLoggingKeys::isReloadIgnoringCacheDataKey();
-    case RetrieveDecision::Yes:
-        ASSERT_NOT_REACHED();
-        break;
-    }
-    return emptyString();
-}
-
-void Statistics::recordNotUsingCacheForRequest(uint64_t webPageID, const Key&amp; key, const WebCore::ResourceRequest&amp; request, RetrieveDecision retrieveDecision)
-{
-    ASSERT(retrieveDecision != RetrieveDecision::Yes);
-
-    String hash = key.hashAsString();
-    WebCore::URL requestURL = request.url();
-    queryWasEverRequested(hash, NeedUncachedReason::No, [this, hash, requestURL, webPageID, retrieveDecision](bool wasEverRequested, const Optional&lt;StoreDecision&gt;&amp;) {
-        if (wasEverRequested) {
-            String diagnosticKey = retrieveDecisionToDiagnosticKey(retrieveDecision);
-            LOG(NetworkCache, &quot;(NetworkProcess) webPageID %llu: %s was previously requested but we are not using the cache, reason: %s&quot;, webPageID, requestURL.string().ascii().data(), diagnosticKey.utf8().data());
-            NetworkProcess::singleton().logDiagnosticMessageWithValue(webPageID, WebCore::DiagnosticLoggingKeys::networkCacheKey(), WebCore::DiagnosticLoggingKeys::unusedKey(), diagnosticKey, WebCore::ShouldSample::Yes);
-        } else {
-            NetworkProcess::singleton().logDiagnosticMessageWithValue(webPageID, WebCore::DiagnosticLoggingKeys::networkCacheKey(), WebCore::DiagnosticLoggingKeys::requestKey(), WebCore::DiagnosticLoggingKeys::neverSeenBeforeKey(), WebCore::ShouldSample::Yes);
-            markAsRequested(hash);
-        }
-    });
-}
-
-static String storeDecisionToDiagnosticKey(StoreDecision storeDecision)
-{
-    switch (storeDecision) {
-    case StoreDecision::NoDueToProtocol:
-        return WebCore::DiagnosticLoggingKeys::notHTTPFamilyKey();
-    case StoreDecision::NoDueToHTTPMethod:
-        return WebCore::DiagnosticLoggingKeys::unsupportedHTTPMethodKey();
-    case StoreDecision::NoDueToAttachmentResponse:
-        return WebCore::DiagnosticLoggingKeys::isAttachmentKey();
-    case StoreDecision::NoDueToNoStoreResponse:
-    case StoreDecision::NoDueToNoStoreRequest:
-        return WebCore::DiagnosticLoggingKeys::cacheControlNoStoreKey();
-    case StoreDecision::NoDueToHTTPStatusCode:
-        return WebCore::DiagnosticLoggingKeys::uncacheableStatusCodeKey();
-    case StoreDecision::Yes:
-        // It was stored but could not be retrieved so it must have been pruned from the cache.
-        return WebCore::DiagnosticLoggingKeys::noLongerInCacheKey();
-    }
-    return String();
-}
-
-void Statistics::recordRetrievalFailure(uint64_t webPageID, const Key&amp; key, const WebCore::ResourceRequest&amp; request)
-{
-    String hash = key.hashAsString();
-    WebCore::URL requestURL = request.url();
-    queryWasEverRequested(hash, NeedUncachedReason::Yes, [this, hash, requestURL, webPageID](bool wasPreviouslyRequested, const Optional&lt;StoreDecision&gt;&amp; storeDecision) {
-        if (wasPreviouslyRequested) {
-            String diagnosticKey = storeDecisionToDiagnosticKey(storeDecision.value());
-            LOG(NetworkCache, &quot;(NetworkProcess) webPageID %llu: %s was previously request but is not in the cache, reason: %s&quot;, webPageID, requestURL.string().ascii().data(), diagnosticKey.utf8().data());
-            NetworkProcess::singleton().logDiagnosticMessageWithValue(webPageID, WebCore::DiagnosticLoggingKeys::networkCacheKey(), WebCore::DiagnosticLoggingKeys::notInCacheKey(), diagnosticKey, WebCore::ShouldSample::Yes);
-        } else {
-            NetworkProcess::singleton().logDiagnosticMessageWithValue(webPageID, WebCore::DiagnosticLoggingKeys::networkCacheKey(), WebCore::DiagnosticLoggingKeys::requestKey(), WebCore::DiagnosticLoggingKeys::neverSeenBeforeKey(), WebCore::ShouldSample::Yes);
-            markAsRequested(hash);
-        }
-    });
-}
-
-static String cachedEntryReuseFailureToDiagnosticKey(UseDecision decision)
-{
-    switch (decision) {
-    case UseDecision::NoDueToVaryingHeaderMismatch:
-        return WebCore::DiagnosticLoggingKeys::varyingHeaderMismatchKey();
-    case UseDecision::NoDueToMissingValidatorFields:
-        return WebCore::DiagnosticLoggingKeys::missingValidatorFieldsKey();
-    case UseDecision::NoDueToDecodeFailure:
-        return WebCore::DiagnosticLoggingKeys::otherKey();
-    case UseDecision::Use:
-    case UseDecision::Validate:
-        ASSERT_NOT_REACHED();
-        break;
-    }
-    return emptyString();
-}
-
-void Statistics::recordRetrievedCachedEntry(uint64_t webPageID, const Key&amp; key, const WebCore::ResourceRequest&amp; request, UseDecision decision)
-{
-    WebCore::URL requestURL = request.url();
-    if (decision == UseDecision::Use || decision == UseDecision::Validate) {
-        LOG(NetworkCache, &quot;(NetworkProcess) webPageID %llu: %s is in the cache and is used&quot;, webPageID, requestURL.string().ascii().data());
-        NetworkProcess::singleton().logDiagnosticMessageWithResult(webPageID, WebCore::DiagnosticLoggingKeys::networkCacheKey(), WebCore::DiagnosticLoggingKeys::retrievalKey(), WebCore::DiagnosticLoggingResultPass, WebCore::ShouldSample::Yes);
-        return;
-    }
-
-    String diagnosticKey = cachedEntryReuseFailureToDiagnosticKey(decision);
-    LOG(NetworkCache, &quot;(NetworkProcess) webPageID %llu: %s is in the cache but wasn't used, reason: %s&quot;, webPageID, requestURL.string().ascii().data(), diagnosticKey.utf8().data());
-    NetworkProcess::singleton().logDiagnosticMessageWithValue(webPageID, WebCore::DiagnosticLoggingKeys::networkCacheKey(), WebCore::DiagnosticLoggingKeys::unusableCachedEntryKey(), diagnosticKey, WebCore::ShouldSample::Yes);
-}
-
-void Statistics::markAsRequested(const String&amp; hash)
-{
-    ASSERT(RunLoop::isMain());
-
-    m_hashesToAdd.add(hash);
-    if (!m_writeTimer.isActive())
-        m_writeTimer.startOneShot(mininumWriteInterval);
-}
-
-void Statistics::writeTimerFired()
-{
-    ASSERT(RunLoop::isMain());
-
-    Vector&lt;StringCapture&gt; hashesToAdd;
-    copyToVector(m_hashesToAdd, hashesToAdd);
-    m_hashesToAdd.clear();
-
-    Vector&lt;std::pair&lt;StringCapture, StoreDecision&gt;&gt; storeDecisionsToAdd;
-    copyToVector(m_storeDecisionsToAdd, storeDecisionsToAdd);
-    m_storeDecisionsToAdd.clear();
-
-    shrinkIfNeeded();
-
-    dispatch_async(m_backgroundIOQueue.get(), [this, hashesToAdd, storeDecisionsToAdd] {
-        if (!m_database.isOpen())
-            return;
-
-        WebCore::SQLiteTransactionInProgressAutoCounter transactionCounter;
-        WebCore::SQLiteTransaction writeTransaction(m_database);
-        writeTransaction.begin();
-
-        addHashesToDatabase(hashesToAdd);
-        addStoreDecisionsToDatabase(storeDecisionsToAdd);
-
-        writeTransaction.commit();
-    });
-}
-
-void Statistics::queryWasEverRequested(const String&amp; hash, NeedUncachedReason needUncachedReason, const RequestedCompletionHandler&amp; completionHandler)
-{
-    ASSERT(RunLoop::isMain());
-
-    // Query pending writes first.
-    bool wasAlreadyRequested = m_hashesToAdd.contains(hash);
-    if (wasAlreadyRequested &amp;&amp; needUncachedReason == NeedUncachedReason::No) {
-        completionHandler(true, Nullopt);
-        return;
-    }
-    if (needUncachedReason == NeedUncachedReason::Yes &amp;&amp; m_storeDecisionsToAdd.contains(hash)) {
-        completionHandler(true, m_storeDecisionsToAdd.get(hash));
-        return;
-    }
-
-    // Query the database.
-    auto everRequestedQuery = std::make_unique&lt;EverRequestedQuery&gt;(EverRequestedQuery { hash, needUncachedReason == NeedUncachedReason::Yes, completionHandler });
-    auto&amp; query = *everRequestedQuery;
-    m_activeQueries.add(WTF::move(everRequestedQuery));
-    dispatch_async(m_backgroundIOQueue.get(), [this, wasAlreadyRequested, &amp;query] () mutable {
-        WebCore::SQLiteTransactionInProgressAutoCounter transactionCounter;
-        Optional&lt;StoreDecision&gt; storeDecision;
-        if (m_database.isOpen()) {
-            if (!wasAlreadyRequested) {
-                WebCore::SQLiteStatement statement(m_database, ASCIILiteral(&quot;SELECT hash FROM AlreadyRequested WHERE hash=?&quot;));
-                if (statement.prepare() == WebCore::SQLResultOk) {
-                    statement.bindText(1, query.hash);
-                    wasAlreadyRequested = (statement.step() == WebCore::SQLResultRow);
-                }
-            }
-            if (wasAlreadyRequested &amp;&amp; query.needUncachedReason) {
-                WebCore::SQLiteStatement statement(m_database, ASCIILiteral(&quot;SELECT reason FROM UncachedReason WHERE hash=?&quot;));
-                storeDecision = StoreDecision::Yes;
-                if (statement.prepare() == WebCore::SQLResultOk) {
-                    statement.bindText(1, query.hash);
-                    if (statement.step() == WebCore::SQLResultRow)
-                        storeDecision = static_cast&lt;StoreDecision&gt;(statement.getColumnInt(0));
-                }
-            }
-        }
-        dispatch_async(dispatch_get_main_queue(), [this, &amp;query, wasAlreadyRequested, storeDecision] {
-            query.completionHandler(wasAlreadyRequested, storeDecision);
-            m_activeQueries.remove(&amp;query);
-        });
-    });
-}
-
-void Statistics::clear()
-{
-    ASSERT(RunLoop::isMain());
-
-    dispatch_async(m_backgroundIOQueue.get(), [this] {
-        if (m_database.isOpen()) {
-            WebCore::SQLiteTransactionInProgressAutoCounter transactionCounter;
-            WebCore::SQLiteTransaction deleteTransaction(m_database);
-            deleteTransaction.begin();
-            executeSQLCommand(m_database, ASCIILiteral(&quot;DELETE FROM AlreadyRequested&quot;));
-            executeSQLCommand(m_database, ASCIILiteral(&quot;DELETE FROM UncachedReason&quot;));
-            deleteTransaction.commit();
-            m_approximateEntryCount = 0;
-        }
-    });
-}
-
-void Statistics::addHashesToDatabase(const Vector&lt;StringCapture&gt;&amp; hashes)
-{
-    ASSERT(!RunLoop::isMain());
-    ASSERT(WebCore::SQLiteDatabaseTracker::hasTransactionInProgress());
-    ASSERT(m_database.isOpen());
-
-    WebCore::SQLiteStatement statement(m_database, ASCIILiteral(&quot;INSERT OR IGNORE INTO AlreadyRequested (hash) VALUES (?)&quot;));
-    if (statement.prepare() != WebCore::SQLResultOk)
-        return;
-
-    for (auto&amp; hash : hashes) {
-        statement.bindText(1, hash.string());
-        if (executeSQLStatement(statement))
-            ++m_approximateEntryCount;
-        statement.reset();
-    }
-}
-
-void Statistics::addStoreDecisionsToDatabase(const Vector&lt;std::pair&lt;StringCapture, StoreDecision&gt;&gt;&amp; storeDecisions)
-{
-    ASSERT(!RunLoop::isMain());
-    ASSERT(WebCore::SQLiteDatabaseTracker::hasTransactionInProgress());
-    ASSERT(m_database.isOpen());
-
-    WebCore::SQLiteStatement statement(m_database, ASCIILiteral(&quot;INSERT OR REPLACE INTO UncachedReason (hash, reason) VALUES (?, ?)&quot;));
-    if (statement.prepare() != WebCore::SQLResultOk)
-        return;
-
-    for (auto&amp; pair : storeDecisions) {
-        statement.bindText(1, pair.first.string());
-        statement.bindInt(2, static_cast&lt;int&gt;(pair.second));
-        executeSQLStatement(statement);
-        statement.reset();
-    }
-}
-
-}
-}
-
-#endif // ENABLE(NETWORK_CACHE)
</del></span></pre></div>
<a id="trunkSourceWebKit2WebKit2xcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/WebKit2.xcodeproj/project.pbxproj (182089 => 182090)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/WebKit2.xcodeproj/project.pbxproj        2015-03-27 23:08:01 UTC (rev 182089)
+++ trunk/Source/WebKit2/WebKit2.xcodeproj/project.pbxproj        2015-03-27 23:49:15 UTC (rev 182090)
</span><span class="lines">@@ -1177,7 +1177,6 @@
</span><span class="cx">                 7EC4F0FB18E4ACBB008056AF /* NetworkProcessCocoa.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7EC4F0F918E4A945008056AF /* NetworkProcessCocoa.mm */; };
</span><span class="cx">                 834B250F1A831A8D00CFB150 /* NetworkCacheFileSystemPosix.h in Headers */ = {isa = PBXBuildFile; fileRef = 834B250E1A831A8D00CFB150 /* NetworkCacheFileSystemPosix.h */; };
</span><span class="cx">                 834B25121A842C8700CFB150 /* NetworkCacheStatistics.h in Headers */ = {isa = PBXBuildFile; fileRef = 834B25101A842C8700CFB150 /* NetworkCacheStatistics.h */; };
</span><del>-                834B25131A842C8700CFB150 /* NetworkCacheStatisticsCocoa.mm in Sources */ = {isa = PBXBuildFile; fileRef = 834B25111A842C8700CFB150 /* NetworkCacheStatisticsCocoa.mm */; };
</del><span class="cx">                 8372DB251A674C8F00C697C5 /* WKPageDiagnosticLoggingClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 8372DB241A674C8F00C697C5 /* WKPageDiagnosticLoggingClient.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 8372DB281A67562800C697C5 /* WebPageDiagnosticLoggingClient.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8372DB261A67562800C697C5 /* WebPageDiagnosticLoggingClient.cpp */; };
</span><span class="cx">                 8372DB291A67562800C697C5 /* WebPageDiagnosticLoggingClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 8372DB271A67562800C697C5 /* WebPageDiagnosticLoggingClient.h */; };
</span><span class="lines">@@ -1186,6 +1185,7 @@
</span><span class="cx">                 83891B691A68BEBC0030F386 /* _WKDiagnosticLoggingDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 83891B681A68BEBC0030F386 /* _WKDiagnosticLoggingDelegate.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 83891B6C1A68C30B0030F386 /* DiagnosticLoggingClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 83891B6A1A68C30B0030F386 /* DiagnosticLoggingClient.h */; };
</span><span class="cx">                 83891B6D1A68C30B0030F386 /* DiagnosticLoggingClient.mm in Sources */ = {isa = PBXBuildFile; fileRef = 83891B6B1A68C30B0030F386 /* DiagnosticLoggingClient.mm */; };
</span><ins>+                83BDCCB91AC5FDB6003F6441 /* NetworkCacheStatistics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83BDCCB81AC5FDB6003F6441 /* NetworkCacheStatistics.cpp */; };
</ins><span class="cx">                 84477853176FCC0800CDC7BB /* InjectedBundleHitTestResultMediaType.h in Headers */ = {isa = PBXBuildFile; fileRef = 84477851176FCAC100CDC7BB /* InjectedBundleHitTestResultMediaType.h */; };
</span><span class="cx">                 868160D0187645570021E79D /* WindowServerConnection.mm in Sources */ = {isa = PBXBuildFile; fileRef = 868160CF187645370021E79D /* WindowServerConnection.mm */; };
</span><span class="cx">                 86E67A251910B9D100004AB7 /* ProcessThrottler.h in Headers */ = {isa = PBXBuildFile; fileRef = 86E67A21190F411800004AB7 /* ProcessThrottler.h */; };
</span><span class="lines">@@ -3385,7 +3385,6 @@
</span><span class="cx">                 7EC4F0F918E4A945008056AF /* NetworkProcessCocoa.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = NetworkProcessCocoa.mm; path = NetworkProcess/cocoa/NetworkProcessCocoa.mm; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 834B250E1A831A8D00CFB150 /* NetworkCacheFileSystemPosix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkCacheFileSystemPosix.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 834B25101A842C8700CFB150 /* NetworkCacheStatistics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkCacheStatistics.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><del>-                834B25111A842C8700CFB150 /* NetworkCacheStatisticsCocoa.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = NetworkCacheStatisticsCocoa.mm; sourceTree = &quot;&lt;group&gt;&quot;; };
</del><span class="cx">                 8372DB241A674C8F00C697C5 /* WKPageDiagnosticLoggingClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKPageDiagnosticLoggingClient.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 8372DB261A67562800C697C5 /* WebPageDiagnosticLoggingClient.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebPageDiagnosticLoggingClient.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 8372DB271A67562800C697C5 /* WebPageDiagnosticLoggingClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebPageDiagnosticLoggingClient.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -3394,6 +3393,7 @@
</span><span class="cx">                 83891B681A68BEBC0030F386 /* _WKDiagnosticLoggingDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _WKDiagnosticLoggingDelegate.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 83891B6A1A68C30B0030F386 /* DiagnosticLoggingClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DiagnosticLoggingClient.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 83891B6B1A68C30B0030F386 /* DiagnosticLoggingClient.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DiagnosticLoggingClient.mm; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                83BDCCB81AC5FDB6003F6441 /* NetworkCacheStatistics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NetworkCacheStatistics.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 84477851176FCAC100CDC7BB /* InjectedBundleHitTestResultMediaType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InjectedBundleHitTestResultMediaType.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 868160CD18763D4B0021E79D /* WindowServerConnection.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WindowServerConnection.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 868160CF187645370021E79D /* WindowServerConnection.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = WindowServerConnection.mm; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -7484,8 +7484,8 @@
</span><span class="cx">                                 E42E060D1AA750E500B11699 /* NetworkCacheIOChannelCocoa.mm */,
</span><span class="cx">                                 E4436EC01A0CFDB200EAD204 /* NetworkCacheKey.cpp */,
</span><span class="cx">                                 E4436EC11A0CFDB200EAD204 /* NetworkCacheKey.h */,
</span><ins>+                                83BDCCB81AC5FDB6003F6441 /* NetworkCacheStatistics.cpp */,
</ins><span class="cx">                                 834B25101A842C8700CFB150 /* NetworkCacheStatistics.h */,
</span><del>-                                834B25111A842C8700CFB150 /* NetworkCacheStatisticsCocoa.mm */,
</del><span class="cx">                                 E4436EC31A0CFDB200EAD204 /* NetworkCacheStorage.cpp */,
</span><span class="cx">                                 E4436EC21A0CFDB200EAD204 /* NetworkCacheStorage.h */,
</span><span class="cx">                         );
</span><span class="lines">@@ -9712,6 +9712,7 @@
</span><span class="cx">                                 512E352E130B55AF00ABD19A /* WebApplicationCacheManager.cpp in Sources */,
</span><span class="cx">                                 512E356A130B57F000ABD19A /* WebApplicationCacheManagerMessageReceiver.cpp in Sources */,
</span><span class="cx">                                 512E3524130B550600ABD19A /* WebApplicationCacheManagerProxy.cpp in Sources */,
</span><ins>+                                83BDCCB91AC5FDB6003F6441 /* NetworkCacheStatistics.cpp in Sources */,
</ins><span class="cx">                                 512E35F8130B642E00ABD19A /* WebApplicationCacheManagerProxyMessageReceiver.cpp in Sources */,
</span><span class="cx">                                 BC72BA1D11E64907001EB4EA /* WebBackForwardList.cpp in Sources */,
</span><span class="cx">                                 518D2CAD12D5153B003BB93B /* WebBackForwardListItem.cpp in Sources */,
</span><span class="lines">@@ -10019,7 +10020,6 @@
</span><span class="cx">                                 1C8E293A12761E5B00BC7BD0 /* WKInspector.cpp in Sources */,
</span><span class="cx">                                 0F3C725C196F605200AEDD0C /* WKInspectorHighlightView.mm in Sources */,
</span><span class="cx">                                 A54293A5195A43DD002782C7 /* WKInspectorNodeSearchGestureRecognizer.mm in Sources */,
</span><del>-                                834B25131A842C8700CFB150 /* NetworkCacheStatisticsCocoa.mm in Sources */,
</del><span class="cx">                                 51A9E10A1315CD18009E7031 /* WKKeyValueStorageManager.cpp in Sources */,
</span><span class="cx">                                 33D3A3B51339600B00709BE4 /* WKMediaCacheManager.cpp in Sources */,
</span><span class="cx">                                 BC4075FD124FF0270068F20A /* WKMutableArray.cpp in Sources */,
</span></span></pre>
</div>
</div>

</body>
</html>