EGL Multifile Blobcache: Clean up key reuse
This CL contains multiple fixes that allow key reuse.
* set() now checks whether an entry is already present, and if so
removes it from hotcache and tracking before adding them.
* trackEntry and removeEntry now update the total cache size.
* applyLRU now correctly removes entries from all tracking.
Additional tests:
* SameKeyDifferentValues
* SameKeyLargeValues
Based on work by: Igor Nazarov <i.nazarov@samsung.com>
Test: libEGL_test, EGL_test, ANGLE trace tests, apps
Bug: b/351867582, b/380483358
Flag: com.android.graphics.egl.flags.multifile_blobcache_advanced_usage
Change-Id: I66fe9cde18e468e541a80296c80f2234ac61acb0
diff --git a/opengl/libs/EGL/MultifileBlobCache.cpp b/opengl/libs/EGL/MultifileBlobCache.cpp
index ebbb8c4..917671d 100644
--- a/opengl/libs/EGL/MultifileBlobCache.cpp
+++ b/opengl/libs/EGL/MultifileBlobCache.cpp
@@ -246,12 +246,9 @@
ALOGV("INIT: Entry %u is good, tracking it now.", entryHash);
- // Track details for rapid lookup later
+ // Track details for rapid lookup later and update total size
trackEntry(entryHash, header.valueSize, fileSize, st.st_atime);
- // Track the total size
- increaseTotalCacheSize(fileSize);
-
// Preload the entry for fast retrieval
if ((mHotCacheSize + fileSize) < mHotCacheLimit) {
ALOGV("INIT: Populating hot cache with fd = %i, cacheEntry = %p for "
@@ -326,6 +323,15 @@
// Generate a hash of the key and use it to track this entry
uint32_t entryHash = android::JenkinsHashMixBytes(0, static_cast<const uint8_t*>(key), keySize);
+ // See if we already have this file
+ if (flags::multifile_blobcache_advanced_usage() && contains(entryHash)) {
+ // Remove previous entry from hot cache
+ removeFromHotCache(entryHash);
+
+ // Remove previous entry and update the overall cache size
+ removeEntry(entryHash);
+ }
+
size_t fileSize = sizeof(MultifileHeader) + keySize + valueSize;
// If we're going to be over the cache limit, kick off a trim to clear space
@@ -350,12 +356,9 @@
std::string fullPath = mMultifileDirName + "/" + std::to_string(entryHash);
- // Track the size and access time for quick recall
+ // Track the size and access time for quick recall and update the overall cache size
trackEntry(entryHash, valueSize, fileSize, time(0));
- // Update the overall cache size
- increaseTotalCacheSize(fileSize);
-
// Keep the entry in hot cache for quick retrieval
ALOGV("SET: Adding %u to hot cache.", entryHash);
@@ -638,6 +641,27 @@
time_t accessTime) {
mEntries.insert(entryHash);
mEntryStats[entryHash] = {valueSize, fileSize, accessTime};
+
+ increaseTotalCacheSize(fileSize);
+}
+
+bool MultifileBlobCache::removeEntry(uint32_t entryHash) {
+ auto entryIter = mEntries.find(entryHash);
+ if (entryIter == mEntries.end()) {
+ return false;
+ }
+
+ auto entryStatsIter = mEntryStats.find(entryHash);
+ if (entryStatsIter == mEntryStats.end()) {
+ ALOGE("Failed to remove entryHash (%u) from mEntryStats", entryHash);
+ return false;
+ }
+ decreaseTotalCacheSize(entryStatsIter->second.fileSize);
+
+ mEntryStats.erase(entryStatsIter);
+ mEntries.erase(entryIter);
+
+ return true;
}
bool MultifileBlobCache::contains(uint32_t hashEntry) const {
@@ -728,13 +752,10 @@
// Walk through our map of sorted last access times and remove files until under the limit
for (auto cacheEntryIter = mEntryStats.begin(); cacheEntryIter != mEntryStats.end();) {
uint32_t entryHash = cacheEntryIter->first;
+ const MultifileEntryStats& entryStats = cacheEntryIter->second;
ALOGV("LRU: Removing entryHash %u", entryHash);
- // Track the overall size
- MultifileEntryStats entryStats = getEntryStats(entryHash);
- decreaseTotalCacheSize(entryStats.fileSize);
-
// Remove it from hot cache if present
removeFromHotCache(entryHash);
@@ -748,10 +769,9 @@
// Increment the iterator before clearing the entry
cacheEntryIter++;
- // Delete the entry from our tracking
- size_t count = mEntryStats.erase(entryHash);
- if (count != 1) {
- ALOGE("LRU: Failed to remove entryHash (%u) from mEntryStats", entryHash);
+ // Delete the entry from our tracking and update the overall cache size
+ if (!removeEntry(entryHash)) {
+ ALOGE("LRU: Failed to remove entryHash %u", entryHash);
return false;
}