Title: [211480] trunk/Source/WebKit2
Revision
211480
Author
an...@apple.com
Date
2017-02-01 05:38:49 -0800 (Wed, 01 Feb 2017)

Log Message

Load resources speculatively
https://bugs.webkit.org/show_bug.cgi?id=167660

Reviewed by Andreas Kling.

* NetworkProcess/cache/NetworkCache.cpp:
(WebKit::NetworkCache::Cache::makeEntry):

    Factor to a function.

(WebKit::NetworkCache::Cache::store):
* NetworkProcess/cache/NetworkCache.h:
* NetworkProcess/cache/NetworkCacheSpeculativeLoad.cpp:
(WebKit::NetworkCache::SpeculativeLoad::SpeculativeLoad):

    Support loads where we don't have existing cache entry to validate.

(WebKit::NetworkCache::SpeculativeLoad::didReceiveBuffer):

    Synthesize a NetworkCache::Entry if we can't store it.

(WebKit::NetworkCache::SpeculativeLoad::didFinishLoading):
(WebKit::NetworkCache::SpeculativeLoad::didFailLoading):
(WebKit::NetworkCache::SpeculativeLoad::abort):
(WebKit::NetworkCache::SpeculativeLoad::didComplete):
* NetworkProcess/cache/NetworkCacheSpeculativeLoad.h:
* NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.cpp:
(WebKit::NetworkCache::constructRevalidationRequest):

    Make having existing cache entry optional.

(WebKit::NetworkCache::SpeculativeLoadManager::retrieveEntryFromStorage):

    Allow validation without validation headers (that is, normal load).

(WebKit::NetworkCache::SpeculativeLoadManager::revalidateSubresource):

    Make having existing cache entry optional.

(WebKit::NetworkCache::canRevalidate):

    Allow speculative loads without validation headers if we have high confidence that the
    page is going to request this resource again. This is based on the time span we have
    seen this resource being loaded on a given page and how much time has elapsed since we
    last loaded it.

    For example if we have seen the resource over the last 10 days we'll speculate that it will
    be required for the next 5 days.

(WebKit::NetworkCache::SpeculativeLoadManager::preloadEntry):
(WebKit::NetworkCache::SpeculativeLoadManager::revalidateEntry): Deleted.
* NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.h:
* NetworkProcess/cache/NetworkCacheSubresourcesEntry.cpp:
(WebKit::NetworkCache::SubresourceInfo::encode):
(WebKit::NetworkCache::SubresourceInfo::decode):

    Encode the firstSeen and lastSeen time stamps.

(WebKit::NetworkCache::SubresourceInfo::SubresourceInfo):
(WebKit::NetworkCache::makeSubresourceInfoVector):
(WebKit::NetworkCache::SubresourcesEntry::SubresourcesEntry):
(WebKit::NetworkCache::SubresourcesEntry::updateSubresourceLoads):
* NetworkProcess/cache/NetworkCacheSubresourcesEntry.h:
(WebKit::NetworkCache::SubresourceInfo::lastSeen):
(WebKit::NetworkCache::SubresourceInfo::firstSeen):
(WebKit::NetworkCache::SubresourceInfo::setNonTransient):
(WebKit::NetworkCache::SubresourceInfo::SubresourceInfo): Deleted.
(WebKit::NetworkCache::SubresourceInfo::setTransient): Deleted.

Modified Paths

Diff

Modified: trunk/Source/WebKit2/ChangeLog (211479 => 211480)


--- trunk/Source/WebKit2/ChangeLog	2017-02-01 11:29:25 UTC (rev 211479)
+++ trunk/Source/WebKit2/ChangeLog	2017-02-01 13:38:49 UTC (rev 211480)
@@ -1,3 +1,74 @@
+2017-02-01  Antti Koivisto  <an...@apple.com>
+
+        Load resources speculatively
+        https://bugs.webkit.org/show_bug.cgi?id=167660
+
+        Reviewed by Andreas Kling.
+
+        * NetworkProcess/cache/NetworkCache.cpp:
+        (WebKit::NetworkCache::Cache::makeEntry):
+
+            Factor to a function.
+
+        (WebKit::NetworkCache::Cache::store):
+        * NetworkProcess/cache/NetworkCache.h:
+        * NetworkProcess/cache/NetworkCacheSpeculativeLoad.cpp:
+        (WebKit::NetworkCache::SpeculativeLoad::SpeculativeLoad):
+
+            Support loads where we don't have existing cache entry to validate.
+
+        (WebKit::NetworkCache::SpeculativeLoad::didReceiveBuffer):
+
+            Synthesize a NetworkCache::Entry if we can't store it.
+
+        (WebKit::NetworkCache::SpeculativeLoad::didFinishLoading):
+        (WebKit::NetworkCache::SpeculativeLoad::didFailLoading):
+        (WebKit::NetworkCache::SpeculativeLoad::abort):
+        (WebKit::NetworkCache::SpeculativeLoad::didComplete):
+        * NetworkProcess/cache/NetworkCacheSpeculativeLoad.h:
+        * NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.cpp:
+        (WebKit::NetworkCache::constructRevalidationRequest):
+
+            Make having existing cache entry optional.
+
+        (WebKit::NetworkCache::SpeculativeLoadManager::retrieveEntryFromStorage):
+
+            Allow validation without validation headers (that is, normal load).
+
+        (WebKit::NetworkCache::SpeculativeLoadManager::revalidateSubresource):
+
+            Make having existing cache entry optional.
+
+        (WebKit::NetworkCache::canRevalidate):
+
+            Allow speculative loads without validation headers if we have high confidence that the
+            page is going to request this resource again. This is based on the time span we have
+            seen this resource being loaded on a given page and how much time has elapsed since we
+            last loaded it.
+
+            For example if we have seen the resource over the last 10 days we'll speculate that it will
+            be required for the next 5 days.
+
+        (WebKit::NetworkCache::SpeculativeLoadManager::preloadEntry):
+        (WebKit::NetworkCache::SpeculativeLoadManager::revalidateEntry): Deleted.
+        * NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.h:
+        * NetworkProcess/cache/NetworkCacheSubresourcesEntry.cpp:
+        (WebKit::NetworkCache::SubresourceInfo::encode):
+        (WebKit::NetworkCache::SubresourceInfo::decode):
+
+            Encode the firstSeen and lastSeen time stamps.
+
+        (WebKit::NetworkCache::SubresourceInfo::SubresourceInfo):
+        (WebKit::NetworkCache::makeSubresourceInfoVector):
+        (WebKit::NetworkCache::SubresourcesEntry::SubresourcesEntry):
+        (WebKit::NetworkCache::SubresourcesEntry::updateSubresourceLoads):
+        * NetworkProcess/cache/NetworkCacheSubresourcesEntry.h:
+        (WebKit::NetworkCache::SubresourceInfo::lastSeen):
+        (WebKit::NetworkCache::SubresourceInfo::firstSeen):
+        (WebKit::NetworkCache::SubresourceInfo::setNonTransient):
+        (WebKit::NetworkCache::SubresourceInfo::SubresourceInfo): Deleted.
+        (WebKit::NetworkCache::SubresourceInfo::setTransient): Deleted.
+
 2017-02-01  Csaba Osztrogonác  <o...@webkit.org>
 
         [Mac][cmake] Unreviewed speculative buildfix after r211403.

Modified: trunk/Source/WebKit2/NetworkProcess/cache/NetworkCache.cpp (211479 => 211480)


--- trunk/Source/WebKit2/NetworkProcess/cache/NetworkCache.cpp	2017-02-01 11:29:25 UTC (rev 211479)
+++ trunk/Source/WebKit2/NetworkProcess/cache/NetworkCache.cpp	2017-02-01 13:38:49 UTC (rev 211480)
@@ -389,6 +389,12 @@
     });
 }
 
+    
+std::unique_ptr<Entry> Cache::makeEntry(const WebCore::ResourceRequest& request, const WebCore::ResourceResponse& response, RefPtr<WebCore::SharedBuffer>&& responseData)
+{
+    return std::make_unique<Entry>(makeCacheKey(request), response, WTFMove(responseData), WebCore::collectVaryingRequestHeaders(request, response));
+}
+
 std::unique_ptr<Entry> Cache::store(const WebCore::ResourceRequest& request, const WebCore::ResourceResponse& response, RefPtr<WebCore::SharedBuffer>&& responseData, Function<void (MappedBody&)>&& completionHandler)
 {
     ASSERT(isEnabled());
@@ -413,7 +419,7 @@
         return nullptr;
     }
 
-    auto cacheEntry = std::make_unique<Entry>(makeCacheKey(request), response, WTFMove(responseData), WebCore::collectVaryingRequestHeaders(request, response));
+    auto cacheEntry = makeEntry(request, response, WTFMove(responseData));
     auto record = cacheEntry->encodeAsStorageRecord();
 
     m_storage->store(record, [completionHandler = WTFMove(completionHandler)](const Data& bodyData) {

Modified: trunk/Source/WebKit2/NetworkProcess/cache/NetworkCache.h (211479 => 211480)


--- trunk/Source/WebKit2/NetworkProcess/cache/NetworkCache.h	2017-02-01 11:29:25 UTC (rev 211479)
+++ trunk/Source/WebKit2/NetworkProcess/cache/NetworkCache.h	2017-02-01 13:38:49 UTC (rev 211480)
@@ -123,6 +123,8 @@
 
     void retrieveData(const DataKey&, Function<void (const uint8_t* data, size_t size)>);
     void storeData(const DataKey&,  const uint8_t* data, size_t);
+    
+    std::unique_ptr<Entry> makeEntry(const WebCore::ResourceRequest&, const WebCore::ResourceResponse&, RefPtr<WebCore::SharedBuffer>&&);
 
     void dumpContentsToFile();
 

Modified: trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoad.cpp (211479 => 211480)


--- trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoad.cpp	2017-02-01 11:29:25 UTC (rev 211479)
+++ trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoad.cpp	2017-02-01 13:38:49 UTC (rev 211480)
@@ -46,10 +46,9 @@
     , m_completionHandler(WTFMove(completionHandler))
     , m_originalRequest(request)
     , m_bufferedDataForCache(SharedBuffer::create())
-    , m_cacheEntryForValidation(WTFMove(cacheEntryForValidation))
+    , m_cacheEntry(WTFMove(cacheEntryForValidation))
 {
-    ASSERT(m_cacheEntryForValidation);
-    ASSERT(m_cacheEntryForValidation->needsValidation());
+    ASSERT(!m_cacheEntry || m_cacheEntry->needsValidation());
 
     NetworkLoadParameters parameters;
     parameters.sessionID = SessionID::defaultSessionID();
@@ -82,13 +81,11 @@
     if (m_response.isMultipart())
         m_bufferedDataForCache = nullptr;
 
-    ASSERT(m_cacheEntryForValidation);
-
     bool validationSucceeded = m_response.httpStatusCode() == 304; // 304 Not Modified
-    if (validationSucceeded)
-        m_cacheEntryForValidation = NetworkCache::singleton().update(m_originalRequest, m_frameID, *m_cacheEntryForValidation, m_response);
+    if (validationSucceeded && m_cacheEntry)
+        m_cacheEntry = NetworkCache::singleton().update(m_originalRequest, m_frameID, *m_cacheEntry, m_response);
     else
-        m_cacheEntryForValidation = nullptr;
+        m_cacheEntry = nullptr;
 
     return ShouldContinueDidReceiveResponse::Yes;
 }
@@ -95,7 +92,7 @@
 
 void SpeculativeLoad::didReceiveBuffer(Ref<SharedBuffer>&& buffer, int reportedEncodedDataLength)
 {
-    ASSERT(!m_cacheEntryForValidation);
+    ASSERT(!m_cacheEntry);
 
     if (m_bufferedDataForCache) {
         // Prevent memory growth in case of streaming data.
@@ -109,8 +106,12 @@
 
 void SpeculativeLoad::didFinishLoading(double finishTime)
 {
-    if (!m_cacheEntryForValidation && m_bufferedDataForCache)
-        m_cacheEntryForValidation = NetworkCache::singleton().store(m_originalRequest, m_response, WTFMove(m_bufferedDataForCache), [](auto& mappedBody) { });
+    if (!m_cacheEntry && m_bufferedDataForCache) {
+        m_cacheEntry = NetworkCache::singleton().store(m_originalRequest, m_response, WTFMove(m_bufferedDataForCache), [](auto& mappedBody) { });
+        // Create a synthetic cache entry if we can't store.
+        if (!m_cacheEntry && m_response.httpStatusCode() == 200)
+            m_cacheEntry = NetworkCache::singleton().makeEntry(m_originalRequest, m_response, WTFMove(m_bufferedDataForCache));
+    }
 
     didComplete();
 }
@@ -124,7 +125,7 @@
 
 void SpeculativeLoad::didFailLoading(const ResourceError&)
 {
-    m_cacheEntryForValidation = nullptr;
+    m_cacheEntry = nullptr;
 
     didComplete();
 }
@@ -134,7 +135,7 @@
     if (m_networkLoad)
         m_networkLoad->cancel();
 
-    m_cacheEntryForValidation = nullptr;
+    m_cacheEntry = nullptr;
     didComplete();
 }
 
@@ -145,10 +146,10 @@
     m_networkLoad = nullptr;
 
     // Make sure speculatively revalidated resources do not get validated by the NetworkResourceLoader again.
-    if (m_cacheEntryForValidation)
-        m_cacheEntryForValidation->setNeedsValidation(false);
+    if (m_cacheEntry)
+        m_cacheEntry->setNeedsValidation(false);
 
-    m_completionHandler(WTFMove(m_cacheEntryForValidation));
+    m_completionHandler(WTFMove(m_cacheEntry));
 }
 
 } // namespace NetworkCache

Modified: trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoad.h (211479 => 211480)


--- trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoad.h	2017-02-01 11:29:25 UTC (rev 211479)
+++ trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoad.h	2017-02-01 13:38:49 UTC (rev 211480)
@@ -76,7 +76,7 @@
     WebCore::ResourceResponse m_response;
 
     RefPtr<WebCore::SharedBuffer> m_bufferedDataForCache;
-    std::unique_ptr<NetworkCache::Entry> m_cacheEntryForValidation;
+    std::unique_ptr<NetworkCache::Entry> m_cacheEntry;
 };
 
 } // namespace NetworkCache

Modified: trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.cpp (211479 => 211480)


--- trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.cpp	2017-02-01 11:29:25 UTC (rev 211479)
+++ trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.cpp	2017-02-01 13:38:49 UTC (rev 211480)
@@ -84,25 +84,27 @@
     return Key(resourceKey.partition(), subresourcesType(), resourceKey.range(), resourceKey.identifier(), salt);
 }
 
-static inline ResourceRequest constructRevalidationRequest(const Entry& entry, const SubresourceInfo& subResourceInfo)
+static inline ResourceRequest constructRevalidationRequest(const Key& key, const SubresourceInfo& subResourceInfo, const Entry* entry)
 {
-    ResourceRequest revalidationRequest(entry.key().identifier());
+    ResourceRequest revalidationRequest(key.identifier());
     revalidationRequest.setHTTPHeaderFields(subResourceInfo.requestHeaders());
     revalidationRequest.setFirstPartyForCookies(subResourceInfo.firstPartyForCookies());
 #if ENABLE(CACHE_PARTITIONING)
-    if (!entry.key().partition().isEmpty())
-        revalidationRequest.setCachePartition(entry.key().partition());
+    if (!key.partition().isEmpty())
+        revalidationRequest.setCachePartition(key.partition());
 #endif
-    ASSERT_WITH_MESSAGE(entry.key().range().isEmpty(), "range is not supported");
+    ASSERT_WITH_MESSAGE(key.range().isEmpty(), "range is not supported");
 
     revalidationRequest.makeUnconditional();
-    String eTag = entry.response().httpHeaderField(HTTPHeaderName::ETag);
-    if (!eTag.isEmpty())
-        revalidationRequest.setHTTPHeaderField(HTTPHeaderName::IfNoneMatch, eTag);
+    if (entry) {
+        String eTag = entry->response().httpHeaderField(HTTPHeaderName::ETag);
+        if (!eTag.isEmpty())
+            revalidationRequest.setHTTPHeaderField(HTTPHeaderName::IfNoneMatch, eTag);
 
-    String lastModified = entry.response().httpHeaderField(HTTPHeaderName::LastModified);
-    if (!lastModified.isEmpty())
-        revalidationRequest.setHTTPHeaderField(HTTPHeaderName::IfModifiedSince, lastModified);
+        String lastModified = entry->response().httpHeaderField(HTTPHeaderName::LastModified);
+        if (!lastModified.isEmpty())
+            revalidationRequest.setHTTPHeaderField(HTTPHeaderName::IfModifiedSince, lastModified);
+    }
     
     revalidationRequest.setPriority(subResourceInfo.priority());
 
@@ -406,9 +408,9 @@
     }));
 }
 
-void SpeculativeLoadManager::retrieveEntryFromStorage(const Key& key, ResourceLoadPriority priority, RetrieveCompletionHandler&& completionHandler)
+void SpeculativeLoadManager::retrieveEntryFromStorage(const SubresourceInfo& info, RetrieveCompletionHandler&& completionHandler)
 {
-    m_storage.retrieve(key, static_cast<unsigned>(priority), [completionHandler = WTFMove(completionHandler)](auto record) {
+    m_storage.retrieve(info.key(), static_cast<unsigned>(info.priority()), [completionHandler = WTFMove(completionHandler)](auto record) {
         if (!record) {
             completionHandler(nullptr);
             return false;
@@ -420,11 +422,6 @@
         }
 
         auto& response = entry->response();
-        if (!response.hasCacheValidatorFields()) {
-            completionHandler(nullptr);
-            return true;
-        }
-
         if (responseNeedsRevalidation(response, entry->timeStamp())) {
             // Do not use cached redirects that have expired.
             if (entry->redirectRequest()) {
@@ -451,18 +448,17 @@
     return true;
 }
 
-void SpeculativeLoadManager::revalidateEntry(std::unique_ptr<Entry> entry, const SubresourceInfo& subresourceInfo, const GlobalFrameID& frameID)
+void SpeculativeLoadManager::revalidateSubresource(const SubresourceInfo& subresourceInfo, std::unique_ptr<Entry> entry, const GlobalFrameID& frameID)
 {
-    ASSERT(entry);
-    ASSERT(entry->needsValidation());
+    ASSERT(!entry || entry->needsValidation());
 
-    auto key = entry->key();
+    auto& key = subresourceInfo.key();
 
     // Range is not supported.
     if (!key.range().isEmpty())
         return;
 
-    ResourceRequest revalidationRequest = constructRevalidationRequest(*entry, subresourceInfo);
+    ResourceRequest revalidationRequest = constructRevalidationRequest(key, subresourceInfo, entry.get());
 
     LOG(NetworkCacheSpeculativePreloading, "(NetworkProcess) Speculatively revalidating '%s':", key.identifier().utf8().data());
 
@@ -484,14 +480,51 @@
     });
     m_pendingPreloads.add(key, WTFMove(revalidator));
 }
+    
+static bool canRevalidate(const SubresourceInfo& subresourceInfo, const Entry* entry)
+{
+    ASSERT(!subresourceInfo.isTransient());
+    ASSERT(!entry || entry->needsValidation());
+    
+    if (entry && entry->response().hasCacheValidatorFields())
+        return true;
+    
+    auto seenAge = subresourceInfo.lastSeen() - subresourceInfo.firstSeen();
+    if (seenAge == 0ms) {
+        LOG(NetworkCacheSpeculativePreloading, "Speculative load: Seen only once");
+        return false;
+    }
+    
+    auto now = std::chrono::system_clock::now();
+    auto firstSeenAge = now - subresourceInfo.firstSeen();
+    auto lastSeenAge = now - subresourceInfo.lastSeen();
+    // Sanity check.
+    if (seenAge <= 0ms || firstSeenAge <= 0ms || lastSeenAge <= 0ms)
+        return false;
+    
+    // Load full resources speculatively if they seem to stay the same.
+    const auto minimumAgeRatioToLoad = 2. / 3;
+    const auto recentMinimumAgeRatioToLoad = 1. / 3;
+    const auto recentThreshold = 5min;
+    
+    auto ageRatio = std::chrono::duration_cast<std::chrono::duration<double>>(seenAge) / firstSeenAge;
+    auto minimumAgeRatio = lastSeenAge > recentThreshold ? minimumAgeRatioToLoad : recentMinimumAgeRatioToLoad;
+    
+    LOG(NetworkCacheSpeculativePreloading, "Speculative load: ok=%d ageRatio=%f entry=%d", ageRatio > minimumAgeRatio, ageRatio, !!entry);
+    
+    if (ageRatio > minimumAgeRatio)
+        return true;
+    
+    return false;
+}
 
-void SpeculativeLoadManager::preloadEntry(const Key& key, const SubresourceInfo& subResourceInfo, const GlobalFrameID& frameID)
+void SpeculativeLoadManager::preloadEntry(const Key& key, const SubresourceInfo& subresourceInfo, const GlobalFrameID& frameID)
 {
     if (m_pendingPreloads.contains(key))
         return;
+    m_pendingPreloads.add(key, nullptr);
     
-    m_pendingPreloads.add(key, nullptr);
-    retrieveEntryFromStorage(key, subResourceInfo.priority(), [this, key, subResourceInfo, frameID](std::unique_ptr<Entry> entry) {
+    retrieveEntryFromStorage(subresourceInfo, [this, key, subresourceInfo, frameID](std::unique_ptr<Entry> entry) {
         ASSERT(!m_pendingPreloads.get(key));
         bool removed = m_pendingPreloads.remove(key);
         ASSERT_UNUSED(removed, removed);
@@ -501,14 +534,14 @@
                 logSpeculativeLoadingDiagnosticMessage(frameID, DiagnosticLoggingKeys::successfulSpeculativeWarmupWithoutRevalidationKey());
             return;
         }
-
-        if (!entry)
+        
+        if (!entry || entry->needsValidation()) {
+            if (canRevalidate(subresourceInfo, entry.get()))
+                revalidateSubresource(subresourceInfo, WTFMove(entry), frameID);
             return;
-
-        if (entry->needsValidation())
-            revalidateEntry(WTFMove(entry), subResourceInfo, frameID);
-        else
-            addPreloadedEntry(WTFMove(entry), frameID);
+        }
+        
+        addPreloadedEntry(WTFMove(entry), frameID);
     });
 }
 

Modified: trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.h (211479 => 211480)


--- trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.h	2017-02-01 11:29:25 UTC (rev 211479)
+++ trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.h	2017-02-01 13:38:49 UTC (rev 211480)
@@ -61,8 +61,8 @@
 
     void addPreloadedEntry(std::unique_ptr<Entry>, const GlobalFrameID&, std::optional<WebCore::ResourceRequest>&& revalidationRequest = std::nullopt);
     void preloadEntry(const Key&, const SubresourceInfo&, const GlobalFrameID&);
-    void retrieveEntryFromStorage(const Key&, WebCore::ResourceLoadPriority, RetrieveCompletionHandler&&);
-    void revalidateEntry(std::unique_ptr<Entry>, const SubresourceInfo&, const GlobalFrameID&);
+    void retrieveEntryFromStorage(const SubresourceInfo&, RetrieveCompletionHandler&&);
+    void revalidateSubresource(const SubresourceInfo&, std::unique_ptr<Entry>, const GlobalFrameID&);
     bool satisfyPendingRequests(const Key&, Entry*);
     void retrieveSubresourcesEntry(const Key& storageKey, std::function<void (std::unique_ptr<SubresourcesEntry>)>&&);
     void startSpeculativeRevalidation(const GlobalFrameID&, SubresourcesEntry&);

Modified: trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheSubresourcesEntry.cpp (211479 => 211480)


--- trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheSubresourcesEntry.cpp	2017-02-01 11:29:25 UTC (rev 211479)
+++ trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheSubresourcesEntry.cpp	2017-02-01 13:38:49 UTC (rev 211480)
@@ -31,6 +31,8 @@
 #include "Logging.h"
 #include "NetworkCacheCoders.h"
 
+using namespace std::chrono;
+
 namespace WebKit {
 namespace NetworkCache {
 
@@ -37,6 +39,8 @@
 void SubresourceInfo::encode(WTF::Persistence::Encoder& encoder) const
 {
     encoder << m_key;
+    encoder << m_lastSeen;
+    encoder << m_firstSeen;
     encoder << m_isTransient;
 
     // Do not bother serializing other data members of transient resources as they are empty.
@@ -52,13 +56,17 @@
 {
     if (!decoder.decode(info.m_key))
         return false;
-
+    if (!decoder.decode(info.m_lastSeen))
+        return false;
+    if (!decoder.decode(info.m_firstSeen))
+        return false;
+    
     if (!decoder.decode(info.m_isTransient))
         return false;
-
+    
     if (info.m_isTransient)
         return true;
-
+    
     if (!decoder.decode(info.m_firstPartyForCookies))
         return false;
 
@@ -103,17 +111,46 @@
 {
     ASSERT(m_key.type() == "SubResources");
 }
-    
-static Vector<SubresourceInfo> makeSubresourceInfoVector(const Vector<std::unique_ptr<SubresourceLoad>>& subresourceLoads)
+
+SubresourceInfo::SubresourceInfo(const Key& key, const WebCore::ResourceRequest& request, const SubresourceInfo* previousInfo)
+    : m_key(key)
+    , m_lastSeen(std::chrono::system_clock::now())
+    , m_firstSeen(previousInfo ? previousInfo->firstSeen() : m_lastSeen)
+    , m_isTransient(!previousInfo)
+    , m_firstPartyForCookies(request.firstPartyForCookies())
+    , m_requestHeaders(request.httpHeaderFields())
+    , m_priority(request.priority())
 {
+}
+
+static Vector<SubresourceInfo> makeSubresourceInfoVector(const Vector<std::unique_ptr<SubresourceLoad>>& subresourceLoads, Vector<SubresourceInfo>* previousSubresources)
+{
     Vector<SubresourceInfo> result;
     result.reserveInitialCapacity(subresourceLoads.size());
     
-    HashSet<Key> seenKeys;
+    HashMap<Key, unsigned> previousMap;
+    if (previousSubresources) {
+        for (unsigned i = 0; i < previousSubresources->size(); ++i)
+            previousMap.add(previousSubresources->at(i).key(), i);
+    }
+
+    HashSet<Key> deduplicationSet;
     for (auto& load : subresourceLoads) {
-        if (!seenKeys.add(load->key).isNewEntry)
+        if (!deduplicationSet.add(load->key).isNewEntry)
             continue;
-        result.uncheckedAppend({ load->key, load->request });
+        
+        SubresourceInfo* previousInfo = nullptr;
+        if (previousSubresources) {
+            auto it = previousMap.find(load->key);
+            if (it != previousMap.end())
+                previousInfo = &(*previousSubresources)[it->value];
+        }
+        
+        result.uncheckedAppend({ load->key, load->request, previousInfo });
+        
+        // FIXME: We should really consider all resources seen for the first time transient.
+        if (!previousSubresources)
+            result.last().setNonTransient();
     }
 
     return result;
@@ -122,24 +159,14 @@
 SubresourcesEntry::SubresourcesEntry(Key&& key, const Vector<std::unique_ptr<SubresourceLoad>>& subresourceLoads)
     : m_key(WTFMove(key))
     , m_timeStamp(std::chrono::system_clock::now())
-    , m_subresources(makeSubresourceInfoVector(subresourceLoads))
+    , m_subresources(makeSubresourceInfoVector(subresourceLoads, nullptr))
 {
     ASSERT(m_key.type() == "SubResources");
 }
-
+    
 void SubresourcesEntry::updateSubresourceLoads(const Vector<std::unique_ptr<SubresourceLoad>>& subresourceLoads)
 {
-    HashSet<Key> previousKeys;
-    for (auto& info : m_subresources)
-        previousKeys.add(info.key());
-    
-    m_subresources = makeSubresourceInfoVector(subresourceLoads);
-
-    // Mark keys that are not common with the last load as transient.
-    for (auto& subresourceInfo : m_subresources) {
-        if (!previousKeys.contains(subresourceInfo.key()))
-            subresourceInfo.setTransient();
-    }
+    m_subresources = makeSubresourceInfoVector(subresourceLoads, &m_subresources);
 }
 
 } // namespace WebKit

Modified: trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheSubresourcesEntry.h (211479 => 211480)


--- trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheSubresourcesEntry.h	2017-02-01 11:29:25 UTC (rev 211479)
+++ trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheSubresourcesEntry.h	2017-02-01 13:38:49 UTC (rev 211480)
@@ -43,24 +43,23 @@
     static bool decode(WTF::Persistence::Decoder&, SubresourceInfo&);
 
     SubresourceInfo() = default;
-    SubresourceInfo(const Key& key, const WebCore::ResourceRequest& request)
-        : m_key(key)
-        , m_firstPartyForCookies(request.firstPartyForCookies())
-        , m_requestHeaders(request.httpHeaderFields())
-        , m_priority(request.priority())
-    {
-    }
+    SubresourceInfo(const Key&, const WebCore::ResourceRequest&, const SubresourceInfo* previousInfo);
 
     const Key& key() const { return m_key; }
+    std::chrono::system_clock::time_point lastSeen() const { return m_lastSeen; }
+    std::chrono::system_clock::time_point firstSeen() const { return m_firstSeen; }
+
     bool isTransient() const { return m_isTransient; }
     const WebCore::URL& firstPartyForCookies() const { ASSERT(!m_isTransient); return m_firstPartyForCookies; }
     const WebCore::HTTPHeaderMap& requestHeaders() const { ASSERT(!m_isTransient); return m_requestHeaders; }
     WebCore::ResourceLoadPriority priority() const { ASSERT(!m_isTransient); return m_priority; }
     
-    void setTransient() { m_isTransient = true; }
+    void setNonTransient() { m_isTransient = false; }
 
 private:
     Key m_key;
+    std::chrono::system_clock::time_point m_lastSeen;
+    std::chrono::system_clock::time_point m_firstSeen;
     bool m_isTransient { false };
     WebCore::URL m_firstPartyForCookies;
     WebCore::HTTPHeaderMap m_requestHeaders;
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to