Skip to content

Commit

Permalink
Implement cache size limit
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=140844

Reviewed by Andreas Kling.

Prevent the cache from growing without bounds. The simple scheme implemented here
estimates the cache size from number of entries. When the estimated size exceeds
the maximum size we randomly clear 1/4 of the entries.

* NetworkProcess/cache/NetworkCacheStorage.h:
* NetworkProcess/cache/NetworkCacheStorageCocoa.mm:
(WebKit::NetworkCacheStorage::NetworkCacheStorage):
(WebKit::NetworkCacheStorage::initialize):
(WebKit::NetworkCacheStorage::removeEntry):
(WebKit::NetworkCacheStorage::store):
(WebKit::NetworkCacheStorage::setMaximumSize):
(WebKit::NetworkCacheStorage::clear):
(WebKit::NetworkCacheStorage::shrinkIfNeeded):
(WebKit::NetworkCacheStorage::initializeKeyFilter): Deleted.



Canonical link: https://commits.webkit.org/158835@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@179052 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
anttijk committed Jan 24, 2015
1 parent 4fc82fc commit 5a15d2a
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 12 deletions.
22 changes: 22 additions & 0 deletions Source/WebKit2/ChangeLog
@@ -1,3 +1,25 @@
2015-01-23 Antti Koivisto <antti@apple.com>

Implement cache size limit
https://bugs.webkit.org/show_bug.cgi?id=140844

Reviewed by Andreas Kling.

Prevent the cache from growing without bounds. The simple scheme implemented here
estimates the cache size from number of entries. When the estimated size exceeds
the maximum size we randomly clear 1/4 of the entries.

* NetworkProcess/cache/NetworkCacheStorage.h:
* NetworkProcess/cache/NetworkCacheStorageCocoa.mm:
(WebKit::NetworkCacheStorage::NetworkCacheStorage):
(WebKit::NetworkCacheStorage::initialize):
(WebKit::NetworkCacheStorage::removeEntry):
(WebKit::NetworkCacheStorage::store):
(WebKit::NetworkCacheStorage::setMaximumSize):
(WebKit::NetworkCacheStorage::clear):
(WebKit::NetworkCacheStorage::shrinkIfNeeded):
(WebKit::NetworkCacheStorage::initializeKeyFilter): Deleted.

2015-01-23 Timothy Horton <timothy_horton@apple.com>

Fix the pre-Yosemite build.
Expand Down
9 changes: 6 additions & 3 deletions Source/WebKit2/NetworkProcess/cache/NetworkCacheStorage.h
Expand Up @@ -96,7 +96,8 @@ class NetworkCacheStorage {
private:
NetworkCacheStorage(const String& directoryPath);

void initializeKeyFilter();
void initialize();
void shrinkIfNeeded();

void removeEntry(const NetworkCacheKey&);

Expand All @@ -109,12 +110,14 @@ class NetworkCacheStorage {

const String m_directoryPath;

size_t m_maximumSize;
size_t m_maximumSize { std::numeric_limits<size_t>::max() };

BloomFilter<20> m_keyFilter;
std::atomic<size_t> m_approximateEntryCount { 0 };
std::atomic<bool> m_shrinkInProgress { false };

Vector<Deque<RetrieveOperation>> m_pendingRetrieveOperationsByPriority;
unsigned m_activeRetrieveOperationCount;
unsigned m_activeRetrieveOperationCount { 0 };

#if PLATFORM(COCOA)
mutable OSObjectPtr<dispatch_queue_t> m_ioQueue;
Expand Down
70 changes: 61 additions & 9 deletions Source/WebKit2/NetworkProcess/cache/NetworkCacheStorageCocoa.mm
Expand Up @@ -122,30 +122,30 @@ static void traverseCacheFiles(const String& cachePath, std::function<void (cons

NetworkCacheStorage::NetworkCacheStorage(const String& directoryPath)
: m_directoryPath(directoryPath)
, m_maximumSize(std::numeric_limits<size_t>::max())
, m_activeRetrieveOperationCount(0)
, m_ioQueue(adoptOSObject(dispatch_queue_create("com.apple.WebKit.Cache.Storage", DISPATCH_QUEUE_CONCURRENT)))
, m_backgroundIOQueue(adoptOSObject(dispatch_queue_create("com.apple.WebKit.Cache.Storage.Background", DISPATCH_QUEUE_CONCURRENT)))
{
dispatch_set_target_queue(m_backgroundIOQueue.get(), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0));

initializeKeyFilter();
initialize();
}

void NetworkCacheStorage::initializeKeyFilter()
void NetworkCacheStorage::initialize()
{
ASSERT(RunLoop::isMain());

StringCapture cachePathCapture(m_directoryPath);
auto& keyFilter = m_keyFilter;
auto& entryCount = m_approximateEntryCount;

dispatch_async(m_backgroundIOQueue.get(), [cachePathCapture, &keyFilter] {
dispatch_async(m_backgroundIOQueue.get(), [cachePathCapture, &keyFilter, &entryCount] {
String cachePath = cachePathCapture.string();
traverseCacheFiles(cachePath, [&keyFilter](const String& fileName, const String&) {
traverseCacheFiles(cachePath, [&keyFilter, &entryCount](const String& fileName, const String&) {
NetworkCacheKey::HashType hash;
if (!NetworkCacheKey::stringToHash(fileName, hash))
return;
keyFilter.add(hash);
++entryCount;
});
});
}
Expand Down Expand Up @@ -343,9 +343,11 @@ static bool decodeEntryMetaData(EntryMetaData& metaData, dispatch_data_t fileDat
m_keyFilter.remove(key.hash());

StringCapture filePathCapture(filePathForKey(key, m_directoryPath));
dispatch_async(m_ioQueue.get(), [filePathCapture] {
dispatch_async(m_ioQueue.get(), [this, filePathCapture] {
CString path = WebCore::fileSystemRepresentation(filePathCapture.string());
unlink(path.data());
if (m_approximateEntryCount)
--m_approximateEntryCount;
});
}

Expand Down Expand Up @@ -427,8 +429,11 @@ static bool decodeEntryMetaData(EntryMetaData& metaData, dispatch_data_t fileDat
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)
if (!error) {
m_keyFilter.add(key.hash());
++m_approximateEntryCount;
shrinkIfNeeded();
}
completionHandler(!error);
});
});
Expand All @@ -437,8 +442,9 @@ static bool decodeEntryMetaData(EntryMetaData& metaData, dispatch_data_t fileDat
void NetworkCacheStorage::setMaximumSize(size_t size)
{
ASSERT(RunLoop::isMain());
// FIXME: Implement.
m_maximumSize = size;

shrinkIfNeeded();
}

void NetworkCacheStorage::clear()
Expand All @@ -447,6 +453,7 @@ static bool decodeEntryMetaData(EntryMetaData& metaData, dispatch_data_t fileDat
LOG(NetworkCacheStorage, "(NetworkProcess) clearing cache");

m_keyFilter.clear();
m_approximateEntryCount = 0;

StringCapture directoryPathCapture(m_directoryPath);

Expand All @@ -463,6 +470,51 @@ static bool decodeEntryMetaData(EntryMetaData& metaData, dispatch_data_t fileDat
});
}

void NetworkCacheStorage::shrinkIfNeeded()
{
const size_t assumedAverageResourceSize { 48 * 1024 };
const size_t everyNthResourceToDelete { 4 };

size_t estimatedCacheSize = assumedAverageResourceSize * m_approximateEntryCount;

if (estimatedCacheSize <= m_maximumSize)
return;
if (m_shrinkInProgress)
return;
m_shrinkInProgress = true;

LOG(NetworkCacheStorage, "(NetworkProcess) shrinking cache m_approximateEntryCount=%d estimatedCacheSize=%d, m_maximumSize=%d", static_cast<size_t>(m_approximateEntryCount), estimatedCacheSize, m_maximumSize);

StringCapture cachePathCapture(m_directoryPath);
dispatch_async(m_backgroundIOQueue.get(), [this, cachePathCapture] {
String cachePath = cachePathCapture.string();
size_t foundEntryCount = 0;
size_t deletedCount = 0;
traverseCacheFiles(cachePath, [this, &foundEntryCount, &deletedCount](const String& fileName, const String& directory) {
String partitionPath = WebCore::pathByAppendingComponent(directory, fileName);
CString path = WebCore::fileSystemRepresentation(partitionPath);
++foundEntryCount;
if (foundEntryCount % everyNthResourceToDelete)
return;
++deletedCount;

unlink(path.data());

NetworkCacheKey::HashType hash;
if (!NetworkCacheKey::stringToHash(fileName, hash))
return;
dispatch_async(dispatch_get_main_queue(), [this, hash] {
if (m_keyFilter.mayContain(hash))
m_keyFilter.remove(hash);
});
});
m_approximateEntryCount = foundEntryCount - deletedCount;
m_shrinkInProgress = false;

LOG(NetworkCacheStorage, "(NetworkProcess) cache shrink completed m_approximateEntryCount=%d", static_cast<size_t>(m_approximateEntryCount));
});
}

}

#endif

0 comments on commit 5a15d2a

Please sign in to comment.