Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 96fa0e77 authored by Cody Northrop's avatar Cody Northrop
Browse files

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
parent b7f342a0
Loading
Loading
Loading
Loading
+13 −2
Original line number Diff line number Diff line
@@ -330,6 +330,8 @@ void MultifileBlobCache::set(const void* key, EGLsizeiANDROID keySize, const voi
    // 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);

    std::string fullPath = mMultifileDirName + "/" + std::to_string(entryHash);

    // See if we already have this file
    if (flags::multifile_blobcache_advanced_usage() && contains(entryHash)) {
        // Remove previous entry from hot cache
@@ -337,6 +339,17 @@ void MultifileBlobCache::set(const void* key, EGLsizeiANDROID keySize, const voi

        // Remove previous entry and update the overall cache size
        removeEntry(entryHash);

        // If valueSize is zero, this is an indication that the user wants to remove the entry from
        // cache It has already been removed from tracking, now remove it from disk It is safe to do
        // this immediately because we drained the write queue in removeFromHotCache
        if (valueSize == 0) {
            ALOGV("SET: Zero size detected for existing entry, removing %u from cache", entryHash);
            if (remove(fullPath.c_str()) != 0) {
                ALOGW("SET: Error removing %s: %s", fullPath.c_str(), std::strerror(errno));
            }
            return;
        }
    }

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

    std::string fullPath = mMultifileDirName + "/" + std::to_string(entryHash);

    // Track the size and access time for quick recall and update the overall cache size
    struct timespec time = {0, 0};
    if (flags::multifile_blobcache_advanced_usage()) {
+57 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include <fcntl.h>
#include <gtest/gtest.h>
#include <stdio.h>
#include <utils/JenkinsHash.h>

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

// Remove from cache when size is zero
TEST_F(MultifileBlobCacheTest, ZeroSizeRemovesEntry) {
    if (!flags::multifile_blobcache_advanced_usage()) {
        GTEST_SKIP() << "Skipping test that requires multifile_blobcache_advanced_usage flag";
    }

    // Put some entries in
    int entry = 0;
    int result = 0;

    uint32_t kEntryCount = 20;

    // Add some entries
    for (entry = 0; entry < kEntryCount; entry++) {
        mMBC->set(&entry, sizeof(entry), &entry, sizeof(entry));
        ASSERT_EQ(sizeof(entry), mMBC->get(&entry, sizeof(entry), &result, sizeof(result)));
        ASSERT_EQ(entry, result);
    }

    // Send some of them again with size zero
    std::vector<int> removedEntries = {5, 10, 18};
    for (int i = 0; i < removedEntries.size(); i++) {
        entry = removedEntries[i];
        mMBC->set(&entry, sizeof(entry), nullptr, 0);
    }

    // Ensure they do not get a hit
    for (int i = 0; i < removedEntries.size(); i++) {
        entry = removedEntries[i];
        ASSERT_EQ(size_t(0), mMBC->get(&entry, sizeof(entry), &result, sizeof(result)));
    }

    // And have been removed from disk
    std::vector<std::string> diskEntries = getCacheEntries();
    ASSERT_EQ(diskEntries.size(), kEntryCount - removedEntries.size());
    for (int i = 0; i < removedEntries.size(); i++) {
        entry = removedEntries[i];
        // Generate a hash for our removed entries and ensure they are not contained
        // Note our entry and key and the same here, so we're hashing the key just like
        // the multifile blobcache does.
        uint32_t entryHash =
                android::JenkinsHashMixBytes(0, reinterpret_cast<uint8_t*>(&entry), sizeof(entry));
        ASSERT_EQ(std::find(diskEntries.begin(), diskEntries.end(), std::to_string(entryHash)),
                  diskEntries.end());
    }

    // Ensure the others are still present
    for (entry = 0; entry < kEntryCount; entry++) {
        if (std::find(removedEntries.begin(), removedEntries.end(), entry) ==
            removedEntries.end()) {
            ASSERT_EQ(sizeof(entry), mMBC->get(&entry, sizeof(entry), &result, sizeof(result)));
            ASSERT_EQ(result, entry);
        }
    }
}

} // namespace android