karlseguin / ccache

A golang LRU Cache for high concurrency
MIT License
1.27k stars 118 forks source link

ability to set an item that never expires #57

Closed eli-darkly closed 3 years ago

eli-darkly commented 3 years ago

Unless I'm missing something, the current implementation requires that all items have a finite TTL. That's fine for many use cases, but if I'm caching the results of some expensive computation that won't change over time for any given key, then I really wouldn't ever want values to be evicted (or recomputed by Fetch) simply because they're old— I would only want LRU entries to be evicted due to the cache being too full. I'd like to be able to specify a zero or negative time.Duration to mean "this doesn't expire."

karlseguin commented 3 years ago

fetch doesn't do anything fancy (e.g., there's no singleflight mechanism), so it isn't too burdensome to re-implement it in your app to behave how you want.

Essentially, fetch is currently:

    item := c.Get(key)
    if item != nil && !item.Expired() {
        return item, nil
    }
    value, err := fetch()
    if err != nil {
        return nil, err
    }
    return c.set(key, value, duration, false), nil

You could simply remove the item.Expired() check:

    item := c.Get(key)
    if item != nil {
        return item, nil
    }
    value, err := fetch()
    if err != nil {
        return nil, err
    }
    return c.set(key, value, duration, false), nil

As-is, items are only evicted when the cache is full. Alternative, I'd recommend just using a very large ttl:

const MAX_TTL = time.Duration(1<<63 - 1)
eli-darkly commented 3 years ago

Fair enough. As I mentioned in my comment on the other issue, I'd recommend updating the doc comment on Fetch to clarify that it's not doing anything you can't do exactly as well with Get and Set (I wasn't 100% sure at first because it's calling the private set rather than the exported Set—that's also the case above, so your example code wouldn't actually compile if implemented outside the package—but when I followed through to the implementation of set I could see that there's nothing special there).