Title: [179547] trunk/Source/WebKit2
Revision
179547
Author
an...@apple.com
Date
2015-02-03 06:17:12 -0800 (Tue, 03 Feb 2015)

Log Message

Memory cache for resources pending disk write
https://bugs.webkit.org/show_bug.cgi?id=141159

Reviewed by Andreas Kling.

If a resource was requested from the disk cache before it has been written we ended up
loading it again. Add a short lived memory cache to avoid this.

* NetworkProcess/cache/NetworkCache.cpp:
(WebKit::decodeStorageEntry):
* NetworkProcess/cache/NetworkCacheStorage.h:
(WebKit::NetworkCacheStorage::Data::isMap):

    Add a way to know whether a Data is backed by map or not. SharedMemory does not work correctly
    if it is not a map.

* NetworkProcess/cache/NetworkCacheStorageCocoa.mm:
(WebKit::NetworkCacheStorage::Data::Data):
(WebKit::NetworkCacheStorage::initialize):

    Also do some renaming.

(WebKit::decodeEntry):
(WebKit::NetworkCacheStorage::removeEntry):
(WebKit::NetworkCacheStorage::retrieve):
(WebKit::NetworkCacheStorage::store):
(WebKit::NetworkCacheStorage::clear):
(WebKit::NetworkCacheStorage::shrinkIfNeeded):

Modified Paths

Diff

Modified: trunk/Source/WebKit2/ChangeLog (179546 => 179547)


--- trunk/Source/WebKit2/ChangeLog	2015-02-03 12:41:52 UTC (rev 179546)
+++ trunk/Source/WebKit2/ChangeLog	2015-02-03 14:17:12 UTC (rev 179547)
@@ -1,3 +1,34 @@
+2015-02-03  Antti Koivisto  <an...@apple.com>
+
+        Memory cache for resources pending disk write
+        https://bugs.webkit.org/show_bug.cgi?id=141159
+
+        Reviewed by Andreas Kling.
+
+        If a resource was requested from the disk cache before it has been written we ended up
+        loading it again. Add a short lived memory cache to avoid this.
+
+        * NetworkProcess/cache/NetworkCache.cpp:
+        (WebKit::decodeStorageEntry):
+        * NetworkProcess/cache/NetworkCacheStorage.h:
+        (WebKit::NetworkCacheStorage::Data::isMap):
+
+            Add a way to know whether a Data is backed by map or not. SharedMemory does not work correctly
+            if it is not a map.
+
+        * NetworkProcess/cache/NetworkCacheStorageCocoa.mm:
+        (WebKit::NetworkCacheStorage::Data::Data):
+        (WebKit::NetworkCacheStorage::initialize):
+
+            Also do some renaming.
+
+        (WebKit::decodeEntry):
+        (WebKit::NetworkCacheStorage::removeEntry):
+        (WebKit::NetworkCacheStorage::retrieve):
+        (WebKit::NetworkCacheStorage::store):
+        (WebKit::NetworkCacheStorage::clear):
+        (WebKit::NetworkCacheStorage::shrinkIfNeeded):
+
 2015-02-02  Antti Koivisto  <an...@apple.com>
 
         Update cache header after revalidation without rewriting the body data

Modified: trunk/Source/WebKit2/NetworkProcess/cache/NetworkCache.cpp (179546 => 179547)


--- trunk/Source/WebKit2/NetworkProcess/cache/NetworkCache.cpp	2015-02-03 12:41:52 UTC (rev 179546)
+++ trunk/Source/WebKit2/NetworkProcess/cache/NetworkCache.cpp	2015-02-03 14:17:12 UTC (rev 179547)
@@ -174,7 +174,7 @@
     entry->response = cachedResponse;
 
 #if ENABLE(SHAREABLE_RESOURCE)
-    RefPtr<SharedMemory> sharedMemory = storageEntry.body.size() ? SharedMemory::createFromVMBuffer(const_cast<uint8_t*>(storageEntry.body.data()), storageEntry.body.size()) : nullptr;
+    RefPtr<SharedMemory> sharedMemory = storageEntry.body.isMap() ? SharedMemory::createFromVMBuffer(const_cast<uint8_t*>(storageEntry.body.data()), storageEntry.body.size()) : nullptr;
     RefPtr<ShareableResource> shareableResource = sharedMemory ? ShareableResource::create(sharedMemory.release(), 0, storageEntry.body.size()) : nullptr;
 
     if (shareableResource && shareableResource->createHandle(entry->shareableResourceHandle))

Modified: trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStorage.h (179546 => 179547)


--- trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStorage.h	2015-02-03 12:41:52 UTC (rev 179546)
+++ trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStorage.h	2015-02-03 14:17:12 UTC (rev 179547)
@@ -105,15 +105,18 @@
 
     class Data {
     public:
-        Data();
+        Data() { }
         Data(const uint8_t*, size_t);
+
+        enum class Backing { Buffer, Map };
 #if PLATFORM(COCOA)
-        explicit Data(DispatchPtr<dispatch_data_t>);
+        explicit Data(DispatchPtr<dispatch_data_t>, Backing = Backing::Buffer);
 #endif
         bool isNull() const;
 
         const uint8_t* data() const;
         size_t size() const { return m_size; }
+        bool isMap() const { return m_isMap; }
 
 #if PLATFORM(COCOA)
         dispatch_data_t dispatchData() const { return m_dispatchData.get(); }
@@ -122,8 +125,9 @@
 #if PLATFORM(COCOA)
         mutable DispatchPtr<dispatch_data_t> m_dispatchData;
 #endif
-        mutable const uint8_t* m_data;
-        size_t m_size;
+        mutable const uint8_t* m_data { nullptr };
+        size_t m_size { 0 };
+        bool m_isMap { false };
     };
 
     struct Entry {
@@ -160,13 +164,16 @@
 
     size_t m_maximumSize { std::numeric_limits<size_t>::max() };
 
-    BloomFilter<20> m_keyFilter;
+    BloomFilter<20> m_contentsFilter;
     std::atomic<size_t> m_approximateEntryCount { 0 };
     std::atomic<bool> m_shrinkInProgress { false };
 
     Vector<Deque<RetrieveOperation>> m_pendingRetrieveOperationsByPriority;
     unsigned m_activeRetrieveOperationCount { 0 };
 
+    typedef std::pair<NetworkCacheKey, Entry> KeyEntryPair;
+    HashMap<NetworkCacheKey::HashType, std::shared_ptr<KeyEntryPair>, AlreadyHashed> m_writeCache;
+
 #if PLATFORM(COCOA)
     mutable DispatchPtr<dispatch_queue_t> m_ioQueue;
     mutable DispatchPtr<dispatch_queue_t> m_backgroundIOQueue;

Modified: trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStorageCocoa.mm (179546 => 179547)


--- trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStorageCocoa.mm	2015-02-03 12:41:52 UTC (rev 179546)
+++ trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStorageCocoa.mm	2015-02-03 14:17:12 UTC (rev 179547)
@@ -73,24 +73,18 @@
     });
 }
 
-NetworkCacheStorage::Data::Data()
-    : m_data(nullptr)
-    , m_size(0)
-{
-}
-
 NetworkCacheStorage::Data::Data(const uint8_t* data, size_t size)
     : m_dispatchData(adoptDispatch(dispatch_data_create(data, size, nullptr, DISPATCH_DATA_DESTRUCTOR_DEFAULT)))
-    , m_data(nullptr)
     , m_size(size)
 {
 }
 
-NetworkCacheStorage::Data::Data(DispatchPtr<dispatch_data_t> dispatchData)
+NetworkCacheStorage::Data::Data(DispatchPtr<dispatch_data_t> dispatchData, Backing backing)
 {
     const void* data;
     m_dispatchData = adoptDispatch(dispatch_data_create_map(dispatchData.get(), &data, &m_size));
     m_data = static_cast<const uint8_t*>(data);
+    m_isMap = m_size && backing == Backing::Map;
 }
 
 const uint8_t* NetworkCacheStorage::Data::data() const
@@ -135,16 +129,16 @@
     ASSERT(RunLoop::isMain());
 
     StringCapture cachePathCapture(m_directoryPath);
-    auto& keyFilter = m_keyFilter;
+    auto& diskContentsFilter = m_contentsFilter;
     auto& entryCount = m_approximateEntryCount;
 
-    dispatch_async(m_backgroundIOQueue.get(), [cachePathCapture, &keyFilter, &entryCount] {
+    dispatch_async(m_backgroundIOQueue.get(), [cachePathCapture, &diskContentsFilter, &entryCount] {
         String cachePath = cachePathCapture.string();
-        traverseCacheFiles(cachePath, [&keyFilter, &entryCount](const String& fileName, const String&) {
+        traverseCacheFiles(cachePath, [&diskContentsFilter, &entryCount](const String& fileName, const String&) {
             NetworkCacheKey::HashType hash;
             if (!NetworkCacheKey::stringToHash(fileName, hash))
                 return;
-            keyFilter.add(hash);
+            diskContentsFilter.add(hash);
             ++entryCount;
         });
     });
@@ -293,8 +287,8 @@
 
     return std::make_unique<NetworkCacheStorage::Entry>(NetworkCacheStorage::Entry {
         metaData.timeStamp,
-        NetworkCacheStorage::Data(headerData),
-        NetworkCacheStorage::Data(bodyData)
+        NetworkCacheStorage::Data { headerData },
+        NetworkCacheStorage::Data { bodyData, NetworkCacheStorage::Data::Backing::Map }
     });
 }
 
@@ -346,8 +340,8 @@
 {
     ASSERT(RunLoop::isMain());
 
-    if (m_keyFilter.mayContain(key.hash()))
-        m_keyFilter.remove(key.hash());
+    if (m_contentsFilter.mayContain(key.hash()))
+        m_contentsFilter.remove(key.hash());
 
     StringCapture filePathCapture(filePathForKey(key, m_directoryPath));
     dispatch_async(m_ioQueue.get(), [this, filePathCapture] {
@@ -416,11 +410,22 @@
 {
     ASSERT(RunLoop::isMain());
 
-    if (!m_keyFilter.mayContain(key.hash())) {
+    if (!m_contentsFilter.mayContain(key.hash())) {
         completionHandler(nullptr);
         return;
     }
 
+    // Write cache is a temporary memory cache used to respond to requests while a write is pending.
+    if (auto keyEntryPair = m_writeCache.get(key.hash())) {
+        if (keyEntryPair->first == key) {
+            LOG(NetworkCacheStorage, "(NetworkProcess) found from the write cache");
+            dispatch_async(dispatch_get_main_queue(), [keyEntryPair, completionHandler] {
+                completionHandler(std::make_unique<Entry>(keyEntryPair->second));
+            });
+            return;
+        }
+    }
+
     if (m_pendingRetrieveOperationsByPriority.size() < priority + 1)
         m_pendingRetrieveOperationsByPriority.grow(priority + 1);
     m_pendingRetrieveOperationsByPriority[priority].append(RetrieveOperation { key, completionHandler });
@@ -432,6 +437,11 @@
 {
     ASSERT(RunLoop::isMain());
 
+    m_contentsFilter.add(key.hash());
+    ++m_approximateEntryCount;
+
+    m_writeCache.set(key.hash(), std::make_shared<KeyEntryPair>(key, entry));
+
     StringCapture cachePathCapture(m_directoryPath);
     dispatch_async(m_backgroundIOQueue.get(), [this, key, entry, cachePathCapture, completionHandler] {
         auto data = "" entry);
@@ -441,26 +451,33 @@
         dispatch_io_write(channel.get(), 0, data.get(), dispatch_get_main_queue(), [this, key, completionHandler](bool done, dispatch_data_t, int error) {
             ASSERT_UNUSED(done, done);
             LOG(NetworkCacheStorage, "(NetworkProcess) write complete error=%d", error);
-            if (!error) {
-                m_keyFilter.add(key.hash());
-                ++m_approximateEntryCount;
-                shrinkIfNeeded();
+            if (error) {
+                if (m_contentsFilter.mayContain(key.hash()))
+                    m_contentsFilter.remove(key.hash());
+                if (m_approximateEntryCount)
+                    --m_approximateEntryCount;
             }
+            m_writeCache.remove(key.hash());
+
             completionHandler(!error);
         });
     });
+
+    shrinkIfNeeded();
 }
 
 void NetworkCacheStorage::update(const NetworkCacheKey& key, const Entry& updateEntry, const Entry& existingEntry, std::function<void (bool success)> completionHandler)
 {
     ASSERT(RunLoop::isMain());
 
-    if (!m_keyFilter.mayContain(key.hash())) {
+    if (!m_contentsFilter.mayContain(key.hash())) {
         LOG(NetworkCacheStorage, "(NetworkProcess) existing entry not found, storing full entry");
         store(key, updateEntry, completionHandler);
         return;
     }
 
+    m_writeCache.set(key.hash(), std::make_shared<KeyEntryPair>(key, updateEntry));
+
     // Try to update the header of an existing entry.
     StringCapture cachePathCapture(m_directoryPath);
     dispatch_async(m_backgroundIOQueue.get(), [this, key, updateEntry, existingEntry, cachePathCapture, completionHandler] {
@@ -484,6 +501,7 @@
 
             if (error)
                 removeEntry(key);
+            m_writeCache.remove(key.hash());
 
             completionHandler(!error);
         });
@@ -503,7 +521,8 @@
     ASSERT(RunLoop::isMain());
     LOG(NetworkCacheStorage, "(NetworkProcess) clearing cache");
 
-    m_keyFilter.clear();
+    m_writeCache.clear();
+    m_contentsFilter.clear();
     m_approximateEntryCount = 0;
 
     StringCapture directoryPathCapture(m_directoryPath);
@@ -555,8 +574,8 @@
             if (!NetworkCacheKey::stringToHash(fileName, hash))
                 return;
             dispatch_async(dispatch_get_main_queue(), [this, hash] {
-                if (m_keyFilter.mayContain(hash))
-                    m_keyFilter.remove(hash);
+                if (m_contentsFilter.mayContain(hash))
+                    m_contentsFilter.remove(hash);
             });
         });
         m_approximateEntryCount = foundEntryCount - deletedCount;
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to