Skip to content

bug: touch() appears to leak refs #1284

Description

@leiysky

Summary

Cache::touch() seems to increment the internal record refcount on every hit, but does not decrement it afterwards.
contains() does not change refs, and get() returns refs to the original value after drop, but repeated touch() calls make refs grow monotonically.

Observed behavior:
Starting from a single inserted entry under FifoConfig, repeated touch() calls increase refs() linearly:

baseline refs=1
after contains #1 hit=true refs=1
after contains #2 hit=true refs=1
after contains #3 hit=true refs=1
after get #1 observed=1 refs=1
after get #2 observed=1 refs=1
after get #3 observed=1 refs=1
after touch #1 touched=true refs=2
after touch #2 touched=true refs=3
after touch #3 touched=true refs=4
after touch #4 touched=true refs=5
after touch #5 touched=true refs=6

Expected behavior:
touch() should not permanently increase refs for a hit. After touch(), the entry refcount should return to its prior value, similar to get() after the returned entry is dropped.

Minimal repro:

use std::sync::Arc;
use foyer::{Cache, CacheProperties, DefaultHasher, FifoConfig};

fn print_refs(cache: &Cache<u64, Arc<[u8]>, DefaultHasher, CacheProperties>, label: &str) {
    let entry = cache.get(&1).unwrap();
    println!("{label} refs={}", entry.refs());
    drop(entry);
}

fn main() {
    let cache = Cache::<u64, Arc<[u8]>, DefaultHasher, CacheProperties>::builder(16)
        .with_shards(1)
        .with_eviction_config(FifoConfig::default())
        .with_hash_builder(DefaultHasher::default())
        .build::<CacheProperties>();

    cache.insert(1, Arc::<[u8]>::from(vec![1u8; 8]));

    print_refs(&cache, "baseline");

    for i in 1..=3 {
        let hit = cache.contains(&1);
        print_refs(&cache, &format!("after contains #{i} hit={hit}"));
    }

    for i in 1..=3 {
        let entry = cache.get(&1).unwrap();
        let refs = entry.refs();
        drop(entry);
        print_refs(&cache, &format!("after get #{i} observed={refs}"));
    }

    for i in 1..=5 {
        let touched = cache.touch(&1);
        print_refs(&cache, &format!("after touch #{i} touched={touched}"));
    }
}

Version

  • foyer = 0.22.3

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    Projects

    Status
    No status

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions