Skip to content

Commit 96fa0e7

Browse files
committed
EGL Multifile Blobcache: Remove entries when valueSize is zero
When set is called with a value size of zero, the cache will simply remove the entry from disk and return. Any pending writes will complete before the entry is removed. Additional tests: * ZeroSizeRemovesEntry Based on work by: Igor Nazarov <i.nazarov@samsung.com> Test: libEGL_test, EGL_test, ANGLE trace tests, apps Bug: b/355259618, b/380483358 Flag: com.android.graphics.egl.flags.multifile_blobcache_advanced_usage Change-Id: I092a0e41c587ac036311b5e08e8b6ffa59588bca
1 parent b7f342a commit 96fa0e7

2 files changed

Lines changed: 70 additions & 2 deletions

File tree

opengl/libs/EGL/MultifileBlobCache.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -330,13 +330,26 @@ void MultifileBlobCache::set(const void* key, EGLsizeiANDROID keySize, const voi
330330
// Generate a hash of the key and use it to track this entry
331331
uint32_t entryHash = android::JenkinsHashMixBytes(0, static_cast<const uint8_t*>(key), keySize);
332332

333+
std::string fullPath = mMultifileDirName + "/" + std::to_string(entryHash);
334+
333335
// See if we already have this file
334336
if (flags::multifile_blobcache_advanced_usage() && contains(entryHash)) {
335337
// Remove previous entry from hot cache
336338
removeFromHotCache(entryHash);
337339

338340
// Remove previous entry and update the overall cache size
339341
removeEntry(entryHash);
342+
343+
// If valueSize is zero, this is an indication that the user wants to remove the entry from
344+
// cache It has already been removed from tracking, now remove it from disk It is safe to do
345+
// this immediately because we drained the write queue in removeFromHotCache
346+
if (valueSize == 0) {
347+
ALOGV("SET: Zero size detected for existing entry, removing %u from cache", entryHash);
348+
if (remove(fullPath.c_str()) != 0) {
349+
ALOGW("SET: Error removing %s: %s", fullPath.c_str(), std::strerror(errno));
350+
}
351+
return;
352+
}
340353
}
341354

342355
size_t fileSize = sizeof(MultifileHeader) + keySize + valueSize;
@@ -361,8 +374,6 @@ void MultifileBlobCache::set(const void* key, EGLsizeiANDROID keySize, const voi
361374
memcpy(static_cast<void*>(buffer + sizeof(MultifileHeader) + keySize),
362375
static_cast<const void*>(value), valueSize);
363376

364-
std::string fullPath = mMultifileDirName + "/" + std::to_string(entryHash);
365-
366377
// Track the size and access time for quick recall and update the overall cache size
367378
struct timespec time = {0, 0};
368379
if (flags::multifile_blobcache_advanced_usage()) {

opengl/libs/EGL/MultifileBlobCache_test.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <fcntl.h>
2222
#include <gtest/gtest.h>
2323
#include <stdio.h>
24+
#include <utils/JenkinsHash.h>
2425

2526
#include <fstream>
2627
#include <memory>
@@ -855,4 +856,60 @@ TEST_F(MultifileBlobCacheTest, EvictAfterLostCache) {
855856
ASSERT_LE(getCacheEntries().size(), kMaxTotalEntries);
856857
}
857858

859+
// Remove from cache when size is zero
860+
TEST_F(MultifileBlobCacheTest, ZeroSizeRemovesEntry) {
861+
if (!flags::multifile_blobcache_advanced_usage()) {
862+
GTEST_SKIP() << "Skipping test that requires multifile_blobcache_advanced_usage flag";
863+
}
864+
865+
// Put some entries in
866+
int entry = 0;
867+
int result = 0;
868+
869+
uint32_t kEntryCount = 20;
870+
871+
// Add some entries
872+
for (entry = 0; entry < kEntryCount; entry++) {
873+
mMBC->set(&entry, sizeof(entry), &entry, sizeof(entry));
874+
ASSERT_EQ(sizeof(entry), mMBC->get(&entry, sizeof(entry), &result, sizeof(result)));
875+
ASSERT_EQ(entry, result);
876+
}
877+
878+
// Send some of them again with size zero
879+
std::vector<int> removedEntries = {5, 10, 18};
880+
for (int i = 0; i < removedEntries.size(); i++) {
881+
entry = removedEntries[i];
882+
mMBC->set(&entry, sizeof(entry), nullptr, 0);
883+
}
884+
885+
// Ensure they do not get a hit
886+
for (int i = 0; i < removedEntries.size(); i++) {
887+
entry = removedEntries[i];
888+
ASSERT_EQ(size_t(0), mMBC->get(&entry, sizeof(entry), &result, sizeof(result)));
889+
}
890+
891+
// And have been removed from disk
892+
std::vector<std::string> diskEntries = getCacheEntries();
893+
ASSERT_EQ(diskEntries.size(), kEntryCount - removedEntries.size());
894+
for (int i = 0; i < removedEntries.size(); i++) {
895+
entry = removedEntries[i];
896+
// Generate a hash for our removed entries and ensure they are not contained
897+
// Note our entry and key and the same here, so we're hashing the key just like
898+
// the multifile blobcache does.
899+
uint32_t entryHash =
900+
android::JenkinsHashMixBytes(0, reinterpret_cast<uint8_t*>(&entry), sizeof(entry));
901+
ASSERT_EQ(std::find(diskEntries.begin(), diskEntries.end(), std::to_string(entryHash)),
902+
diskEntries.end());
903+
}
904+
905+
// Ensure the others are still present
906+
for (entry = 0; entry < kEntryCount; entry++) {
907+
if (std::find(removedEntries.begin(), removedEntries.end(), entry) ==
908+
removedEntries.end()) {
909+
ASSERT_EQ(sizeof(entry), mMBC->get(&entry, sizeof(entry), &result, sizeof(result)));
910+
ASSERT_EQ(result, entry);
911+
}
912+
}
913+
}
914+
858915
} // namespace android

0 commit comments

Comments
 (0)