Switch to file backed buffer when resource is cached to disk
authorantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 5 Feb 2015 22:17:22 +0000 (22:17 +0000)
committerantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 5 Feb 2015 22:17:22 +0000 (22:17 +0000)
https://bugs.webkit.org/show_bug.cgi?id=141295

Reviewed by Chris Dumez.

Wire the DidCacheResource mechanism to the new disk cache.

* NetworkProcess/NetworkResourceLoader.cpp:
(WebKit::NetworkResourceLoader::didFinishLoading):

    Send DidCacheResource message to the web process so it can switch the resource to file backing.

* NetworkProcess/cache/NetworkCache.cpp:
(WebKit::NetworkCache::store):
(WebKit::NetworkCache::update):
* NetworkProcess/cache/NetworkCache.h:
* NetworkProcess/cache/NetworkCacheStorage.h:
(WebKit::DispatchPtr::DispatchPtr):
* NetworkProcess/cache/NetworkCacheStorageCocoa.mm:
(WebKit::NetworkCacheStorage::Data::Data):
(WebKit::mapFile):
(WebKit::decodeEntry):
(WebKit::retrieveActive):
(WebKit::NetworkCacheStorage::retrieve):
(WebKit::NetworkCacheStorage::store):

    Map files larger than a memory page after a successful store.

(WebKit::NetworkCacheStorage::update):
(WebKit::encodeEntry): Deleted.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@179708 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebKit2/ChangeLog
Source/WebKit2/NetworkProcess/NetworkResourceLoader.cpp
Source/WebKit2/NetworkProcess/cache/NetworkCache.cpp
Source/WebKit2/NetworkProcess/cache/NetworkCache.h
Source/WebKit2/NetworkProcess/cache/NetworkCacheStorage.h
Source/WebKit2/NetworkProcess/cache/NetworkCacheStorageCocoa.mm

index 57e5347..20cccc6 100644 (file)
@@ -1,3 +1,36 @@
+2015-02-05  Antti Koivisto  <antti@apple.com>
+
+        Switch to file backed buffer when resource is cached to disk
+        https://bugs.webkit.org/show_bug.cgi?id=141295
+
+        Reviewed by Chris Dumez.
+
+        Wire the DidCacheResource mechanism to the new disk cache.
+
+        * NetworkProcess/NetworkResourceLoader.cpp:
+        (WebKit::NetworkResourceLoader::didFinishLoading):
+
+            Send DidCacheResource message to the web process so it can switch the resource to file backing.
+
+        * NetworkProcess/cache/NetworkCache.cpp:
+        (WebKit::NetworkCache::store):
+        (WebKit::NetworkCache::update):
+        * NetworkProcess/cache/NetworkCache.h:
+        * NetworkProcess/cache/NetworkCacheStorage.h:
+        (WebKit::DispatchPtr::DispatchPtr):
+        * NetworkProcess/cache/NetworkCacheStorageCocoa.mm:
+        (WebKit::NetworkCacheStorage::Data::Data):
+        (WebKit::mapFile):
+        (WebKit::decodeEntry):
+        (WebKit::retrieveActive):
+        (WebKit::NetworkCacheStorage::retrieve):
+        (WebKit::NetworkCacheStorage::store):
+
+            Map files larger than a memory page after a successful store.
+
+        (WebKit::NetworkCacheStorage::update):
+        (WebKit::encodeEntry): Deleted.
+
 2015-02-05  Chris Dumez  <cdumez@apple.com>
 
         [WK2] Properly check for mmap() error case
index cf7a470..01ac936 100644 (file)
@@ -336,8 +336,19 @@ void NetworkResourceLoader::didFinishLoading(ResourceHandle* handle, double fini
         }
 
         bool isPrivate = sessionID().isEphemeral();
-        if (hasCacheableRedirect && !isPrivate)
-            NetworkCache::singleton().store(originalRequest(), m_response, m_bufferedDataForCache.release());
+        if (hasCacheableRedirect && !isPrivate) {
+            // Keep the connection alive.
+            RefPtr<NetworkConnectionToWebProcess> connection(connectionToWebProcess());
+            RefPtr<NetworkResourceLoader> loader(this);
+            NetworkCache::singleton().store(originalRequest(), m_response, WTF::move(m_bufferedDataForCache), [loader, connection](NetworkCache::MappedBody& mappedBody) {
+#if ENABLE(SHAREABLE_RESOURCE)
+                if (mappedBody.shareableResourceHandle.isNull())
+                    return;
+                LOG(NetworkCache, "(NetworkProcess) sending DidCacheResource");
+                loader->send(Messages::NetworkProcessConnection::DidCacheResource(loader->originalRequest(), mappedBody.shareableResourceHandle, loader->sessionID()));
+#endif
+            });
+        }
     }
 #endif
 
index ecdab1b..66b6479 100644 (file)
@@ -281,7 +281,7 @@ static bool canStore(const WebCore::ResourceRequest& originalRequest, const WebC
     return false;
 }
 
-void NetworkCache::store(const WebCore::ResourceRequest& originalRequest, const WebCore::ResourceResponse& response, PassRefPtr<WebCore::SharedBuffer> responseData)
+void NetworkCache::store(const WebCore::ResourceRequest& originalRequest, const WebCore::ResourceResponse& response, RefPtr<WebCore::SharedBuffer>&& responseData, std::function<void (MappedBody&)> completionHandler)
 {
     ASSERT(isEnabled());
     ASSERT(responseData);
@@ -294,9 +294,19 @@ void NetworkCache::store(const WebCore::ResourceRequest& originalRequest, const
     }
 
     auto key = makeCacheKey(originalRequest);
-    auto storageEntry = encodeStorageEntry(originalRequest, response, responseData);
+    auto storageEntry = encodeStorageEntry(originalRequest, response, WTF::move(responseData));
 
-    m_storage->store(key, storageEntry, [](bool success) {
+    m_storage->store(key, storageEntry, [completionHandler](bool success, const NetworkCacheStorage::Data& bodyData) {
+        MappedBody mappedBody;
+#if ENABLE(SHAREABLE_RESOURCE)
+        if (bodyData.isMap()) {
+            RefPtr<SharedMemory> sharedMemory = SharedMemory::createFromVMBuffer(const_cast<uint8_t*>(bodyData.data()), bodyData.size());
+            mappedBody.shareableResource = sharedMemory ? ShareableResource::create(WTF::move(sharedMemory), 0, bodyData.size()) : nullptr;
+            if (mappedBody.shareableResource)
+                mappedBody.shareableResource->createHandle(mappedBody.shareableResourceHandle);
+        }
+#endif
+        completionHandler(mappedBody);
         LOG(NetworkCache, "(NetworkProcess) store success=%d", success);
     });
 }
@@ -311,7 +321,7 @@ void NetworkCache::update(const WebCore::ResourceRequest& originalRequest, const
     auto key = makeCacheKey(originalRequest);
     auto updateEntry = encodeStorageEntry(originalRequest, response, entry.buffer);
 
-    m_storage->update(key, updateEntry, entry.storageEntry, [](bool success) {
+    m_storage->update(key, updateEntry, entry.storageEntry, [](bool success, const NetworkCacheStorage::Data&) {
         LOG(NetworkCache, "(NetworkProcess) updated, success=%d", success);
     });
 }
index a705751..b287969 100644 (file)
@@ -63,7 +63,14 @@ public:
     };
     // Completion handler may get called back synchronously on failure.
     void retrieve(const WebCore::ResourceRequest&, std::function<void (std::unique_ptr<Entry>)>);
-    void store(const WebCore::ResourceRequest&, const WebCore::ResourceResponse&, PassRefPtr<WebCore::SharedBuffer>);
+
+    struct MappedBody {
+#if ENABLE(SHAREABLE_RESOURCE)
+        RefPtr<ShareableResource> shareableResource;
+        ShareableResource::Handle shareableResourceHandle;
+#endif
+    };
+    void store(const WebCore::ResourceRequest&, const WebCore::ResourceResponse&, RefPtr<WebCore::SharedBuffer>&&, std::function<void (MappedBody&)>);
     void update(const WebCore::ResourceRequest&, const Entry&, const WebCore::ResourceResponse& validatingResponse);
 
     void clear();
index 063457c..a91c6eb 100644 (file)
@@ -59,6 +59,12 @@ public:
         : m_ptr(nullptr)
     {
     }
+    DispatchPtr(T ptr)
+        : m_ptr(ptr)
+    {
+        if (m_ptr)
+            dispatch_retain(m_ptr);
+    }
     DispatchPtr(const DispatchPtr& other)
         : m_ptr(other.m_ptr)
     {
@@ -137,9 +143,12 @@ public:
         Data body;
     };
     // This may call completion handler synchronously on failure.
-    void retrieve(const NetworkCacheKey&, unsigned priority, std::function<bool (std::unique_ptr<Entry>)>);
-    void store(const NetworkCacheKey&, const Entry&, std::function<void (bool success)>);
-    void update(const NetworkCacheKey&, const Entry& updateEntry, const Entry& existingEntry, std::function<void (bool success)>);
+    typedef std::function<bool (std::unique_ptr<Entry>)> RetrieveCompletionHandler;
+    void retrieve(const NetworkCacheKey&, unsigned priority, RetrieveCompletionHandler&&);
+
+    typedef std::function<void (bool success, const Data& mappedBody)> StoreCompletionHandler;
+    void store(const NetworkCacheKey&, const Entry&, StoreCompletionHandler&&);
+    void update(const NetworkCacheKey&, const Entry& updateEntry, const Entry& existingEntry, StoreCompletionHandler&&);
 
     void setMaximumSize(size_t);
     void clear();
@@ -156,7 +165,7 @@ private:
 
     struct RetrieveOperation {
         NetworkCacheKey key;
-        std::function<bool (std::unique_ptr<Entry>)> completionHandler;
+        RetrieveCompletionHandler completionHandler;
     };
     void dispatchRetrieveOperation(std::unique_ptr<const RetrieveOperation>);
     void dispatchPendingRetrieveOperations();
@@ -164,14 +173,14 @@ private:
     struct StoreOperation {
         NetworkCacheKey key;
         Entry entry;
-        std::function<void (bool success)> completionHandler;
+        StoreCompletionHandler completionHandler;
     };
 
     struct UpdateOperation {
         NetworkCacheKey key;
         Entry entry;
         Entry existingEntry;
-        std::function<void (bool success)> completionHandler;
+        StoreCompletionHandler completionHandler;
     };
 
     const String m_directoryPath;
index dbf03ca..674d581 100644 (file)
@@ -81,6 +81,8 @@ NetworkCacheStorage::Data::Data(const uint8_t* data, size_t size)
 
 NetworkCacheStorage::Data::Data(DispatchPtr<dispatch_data_t> dispatchData, Backing backing)
 {
+    if (!dispatchData)
+        return;
     const void* data;
     m_dispatchData = adoptDispatch(dispatch_data_create_map(dispatchData.get(), &data, &m_size));
     m_data = static_cast<const uint8_t*>(data);
@@ -164,7 +166,7 @@ static DispatchPtr<dispatch_io_t> openFileForKey(const NetworkCacheKey& key, Fil
 
     switch (type) {
     case FileOpenType::Create:
-        oflag = O_WRONLY | O_CREAT | O_TRUNC | O_NONBLOCK;
+        oflag = O_RDWR | O_CREAT | O_TRUNC | O_NONBLOCK;
         mode = S_IRUSR | S_IWUSR;
         WebCore::makeAllDirectories(directoryPathForKey(key, cachePath));
         break;
@@ -250,6 +252,17 @@ static bool decodeEntryMetaData(EntryMetaData& metaData, dispatch_data_t fileDat
     return success;
 }
 
+static DispatchPtr<dispatch_data_t> mapFile(int fd, size_t offset, size_t size)
+{
+    void* map = mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd, offset);
+    if (map == MAP_FAILED)
+        return nullptr;
+    auto bodyMap = adoptDispatch(dispatch_data_create(map, size, dispatch_get_main_queue(), [map, size] {
+        munmap(map, size);
+    }));
+    return bodyMap;
+}
+
 static std::unique_ptr<NetworkCacheStorage::Entry> decodeEntry(dispatch_data_t fileData, int fd, const NetworkCacheKey& key)
 {
     EntryMetaData metaData;
@@ -270,17 +283,13 @@ static std::unique_ptr<NetworkCacheStorage::Entry> decodeEntry(dispatch_data_t f
         LOG(NetworkCacheStorage, "(NetworkProcess) header checksum mismatch");
         return nullptr;
     }
-    size_t mapSize = metaData.bodySize;
-    void* map = mmap(nullptr, mapSize, PROT_READ, MAP_PRIVATE, fd, metaData.bodyOffset);
-    if (!map) {
+
+    auto bodyData = mapFile(fd, metaData.bodyOffset, metaData.bodySize);
+    if (!bodyData) {
         LOG(NetworkCacheStorage, "(NetworkProcess) map failed");
         return nullptr;
     }
 
-    auto bodyData = adoptDispatch(dispatch_data_create(map, metaData.bodySize, dispatch_get_main_queue(), [map, mapSize] {
-        munmap(map, mapSize);
-    }));
-
     if (metaData.bodyChecksum != hashData(bodyData.get())) {
         LOG(NetworkCacheStorage, "(NetworkProcess) data checksum mismatch");
         return nullptr;
@@ -331,12 +340,6 @@ static DispatchPtr<dispatch_data_t> encodeEntryHeader(const NetworkCacheKey& key
     return adoptDispatch(dispatch_data_create_concat(headerData.get(), alignmentData.get()));
 }
 
-static DispatchPtr<dispatch_data_t> encodeEntry(const NetworkCacheKey& key, const NetworkCacheStorage::Entry& entry)
-{
-    auto encodedHeader = encodeEntryHeader(key, entry);
-    return adoptDispatch(dispatch_data_create_concat(encodedHeader.get(), entry.body.dispatchData()));
-}
-
 void NetworkCacheStorage::removeEntry(const NetworkCacheKey& key)
 {
     ASSERT(RunLoop::isMain());
@@ -407,7 +410,7 @@ void NetworkCacheStorage::dispatchPendingRetrieveOperations()
     }
 }
 
-template <class T> bool retrieveActive(const T& operations, const NetworkCacheKey& key, std::function<bool (std::unique_ptr<NetworkCacheStorage::Entry>)>& completionHandler)
+template <class T> bool retrieveActive(const T& operations, const NetworkCacheKey& key, NetworkCacheStorage::RetrieveCompletionHandler& completionHandler)
 {
     for (auto& operation : operations) {
         if (operation->key == key) {
@@ -422,7 +425,7 @@ template <class T> bool retrieveActive(const T& operations, const NetworkCacheKe
     return false;
 }
 
-void NetworkCacheStorage::retrieve(const NetworkCacheKey& key, unsigned priority, std::function<bool (std::unique_ptr<Entry>)> completionHandler)
+void NetworkCacheStorage::retrieve(const NetworkCacheKey& key, unsigned priority, RetrieveCompletionHandler&& completionHandler)
 {
     ASSERT(RunLoop::isMain());
     ASSERT(priority <= maximumRetrievePriority);
@@ -438,28 +441,32 @@ void NetworkCacheStorage::retrieve(const NetworkCacheKey& key, unsigned priority
         return;
 
     // Fetch from disk.
-    m_pendingRetrieveOperationsByPriority[priority].append(std::make_unique<RetrieveOperation>(RetrieveOperation { key, completionHandler }));
+    m_pendingRetrieveOperationsByPriority[priority].append(std::make_unique<RetrieveOperation>(RetrieveOperation { key, WTF::move(completionHandler) }));
     dispatchPendingRetrieveOperations();
 }
 
-void NetworkCacheStorage::store(const NetworkCacheKey& key, const Entry& entry, std::function<void (bool success)> completionHandler)
+void NetworkCacheStorage::store(const NetworkCacheKey& key, const Entry& entry, StoreCompletionHandler&& completionHandler)
 {
     ASSERT(RunLoop::isMain());
 
     m_contentsFilter.add(key.hash());
     ++m_approximateEntryCount;
 
-    auto storeOperation = std::make_unique<StoreOperation>(StoreOperation { key, entry, completionHandler });
+    auto storeOperation = std::make_unique<StoreOperation>(StoreOperation { key, entry, WTF::move(completionHandler) });
     auto& store = *storeOperation;
     m_activeStoreOperations.add(WTF::move(storeOperation));
 
     StringCapture cachePathCapture(m_directoryPath);
     dispatch_async(m_backgroundIOQueue.get(), [this, &store, cachePathCapture] {
-        auto data = encodeEntry(store.key, store.entry);
+        auto encodedHeader = encodeEntryHeader(store.key, store.entry);
+        auto writeData = adoptDispatch(dispatch_data_create_concat(encodedHeader.get(), store.entry.body.dispatchData()));
+
+        size_t bodyOffset = dispatch_data_get_size(encodedHeader.get());
+        size_t bodySize = store.entry.body.size();
 
         int fd;
         auto channel = openFileForKey(store.key, FileOpenType::Create, cachePathCapture.string(), fd);
-        dispatch_io_write(channel.get(), 0, data.get(), dispatch_get_main_queue(), [this, &store](bool done, dispatch_data_t, int error) {
+        dispatch_io_write(channel.get(), 0, writeData.get(), dispatch_get_main_queue(), [this, &store, fd, bodyOffset, bodySize](bool done, dispatch_data_t, int error) {
             ASSERT_UNUSED(done, done);
             LOG(NetworkCacheStorage, "(NetworkProcess) write complete error=%d", error);
             if (error) {
@@ -469,7 +476,11 @@ void NetworkCacheStorage::store(const NetworkCacheKey& key, const Entry& entry,
                     --m_approximateEntryCount;
             }
 
-            store.completionHandler(!error);
+            bool shouldMapBody = !error && bodySize >= vm_page_size;
+            auto bodyMap = shouldMapBody ? mapFile(fd, bodyOffset, bodySize) : nullptr;
+
+            Data bodyData(bodyMap, Data::Backing::Map);
+            store.completionHandler(!error, bodyData);
 
             m_activeStoreOperations.remove(&store);
         });
@@ -478,17 +489,17 @@ void NetworkCacheStorage::store(const NetworkCacheKey& key, const Entry& entry,
     shrinkIfNeeded();
 }
 
-void NetworkCacheStorage::update(const NetworkCacheKey& key, const Entry& updateEntry, const Entry& existingEntry, std::function<void (bool success)> completionHandler)
+void NetworkCacheStorage::update(const NetworkCacheKey& key, const Entry& updateEntry, const Entry& existingEntry, StoreCompletionHandler&& completionHandler)
 {
     ASSERT(RunLoop::isMain());
 
     if (!m_contentsFilter.mayContain(key.hash())) {
         LOG(NetworkCacheStorage, "(NetworkProcess) existing entry not found, storing full entry");
-        store(key, updateEntry, completionHandler);
+        store(key, updateEntry, WTF::move(completionHandler));
         return;
     }
 
-    auto updateOperation = std::make_unique<UpdateOperation>(UpdateOperation { key, updateEntry, existingEntry, completionHandler });
+    auto updateOperation = std::make_unique<UpdateOperation>(UpdateOperation { key, updateEntry, existingEntry, WTF::move(completionHandler) });
     auto& update = *updateOperation;
     m_activeUpdateOperations.add(WTF::move(updateOperation));
 
@@ -502,7 +513,7 @@ void NetworkCacheStorage::update(const NetworkCacheKey& key, const Entry& update
         if (pageRoundedHeaderSizeChanged) {
             LOG(NetworkCacheStorage, "(NetworkProcess) page-rounded header size changed, storing full entry");
             dispatch_async(dispatch_get_main_queue(), [this, &update] {
-                store(update.key, update.entry, update.completionHandler);
+                store(update.key, update.entry, WTF::move(update.completionHandler));
 
                 ASSERT(m_activeUpdateOperations.contains(&update));
                 m_activeUpdateOperations.remove(&update);
@@ -519,7 +530,7 @@ void NetworkCacheStorage::update(const NetworkCacheKey& key, const Entry& update
             if (error)
                 removeEntry(update.key);
 
-            update.completionHandler(!error);
+            update.completionHandler(!error, Data());
 
             ASSERT(m_activeUpdateOperations.contains(&update));
             m_activeUpdateOperations.remove(&update);