mirror of
https://github.com/aaru-dps/libaaruformat.git
synced 2026-09-21 22:34:19 +00:00
Replace the existing value when caching a key that is already present
add_to_cache_uint64() called HASH_ADD without first looking the key up. uthash keeps both entries in that case, but HASH_FIND only ever reaches the newer one, so the older entry becomes unreachable and its value stays alive until free_cache() tears the whole cache down. It also counted twice against the cache budget. ec_recover_data_block() reaches this: it caches the recovered BlockHeader for a block offset that may already be in block_header_cache, because a header read from the file is cached before the corruption check that sends the read into erasure recovery. Look the key up first, and on a hit free the old value and reuse the entry.
This commit is contained in:
26
src/lru.c
26
src/lru.c
@@ -55,8 +55,9 @@ void *find_in_cache_uint64(struct CacheHeader *cache, const uint64_t key)
|
||||
/**
|
||||
* @brief Adds a value to the cache with a uint64_t key, evicting LRU entries if over budget.
|
||||
*
|
||||
* Adds a new entry to the cache. If the cache exceeds its memory budget, the least recently
|
||||
* used entries are evicted until it fits again. The entry just inserted is never evicted, so the
|
||||
* Adds a new entry to the cache. If an entry with the same key is already present, its value
|
||||
* is freed and replaced. If the cache exceeds its memory budget, the least recently used
|
||||
* entries are evicted until it fits again. The entry just inserted is never evicted, so the
|
||||
* caller may keep using the pointer it handed over for the remainder of the call.
|
||||
*
|
||||
* @param cache Pointer to the cache header.
|
||||
@@ -66,8 +67,25 @@ void *find_in_cache_uint64(struct CacheHeader *cache, const uint64_t key)
|
||||
*/
|
||||
void add_to_cache_uint64(struct CacheHeader *cache, const uint64_t key, void *value, const size_t size)
|
||||
{
|
||||
struct CacheEntry *entry = malloc(sizeof(struct CacheEntry));
|
||||
if(!entry) return;
|
||||
struct CacheEntry *entry = NULL;
|
||||
|
||||
// Replace an existing entry for this key. A blind HASH_ADD would leave the old entry in the
|
||||
// table unreachable by HASH_FIND, and its value alive until the whole cache is freed.
|
||||
HASH_FIND(hh, cache->cache, &key, sizeof(uint64_t), entry);
|
||||
|
||||
if(entry)
|
||||
{
|
||||
cache->cur_bytes -= entry->size;
|
||||
|
||||
if(cache->free_func && entry->value && entry->value != value) cache->free_func(entry->value);
|
||||
|
||||
HASH_DELETE(hh, cache->cache, entry);
|
||||
}
|
||||
else
|
||||
{
|
||||
entry = malloc(sizeof(struct CacheEntry));
|
||||
if(!entry) return;
|
||||
}
|
||||
|
||||
entry->key = key;
|
||||
entry->value = value;
|
||||
|
||||
Reference in New Issue
Block a user