v3.9.0 Codeberg

Getting started

Installation

ferncache requires Rust 1.75+. Add it to your project:

cargo add ferncache

Quick start

Here is a complete program that uses ferncache.

use std::time::Duration;
use ferncache::{Store, Error};

#[tokio::main]
async fn main() -> Result<(), Error> {
    let store = Store::builder()
        .max_entries(10_000)
        .default_ttl(Duration::from_secs(300))
        .build()?;

    store.set("user:42", b"Ada").await?;

    let v = store.get("user:42").await?;
    println!("{v:?}");
    Ok(())
}

Choosing a capacity

Every store has a capacity, expressed either as a number of entries or as a total cost. When an insert would exceed it, ferncache evicts entries until the new one fits.

Cost is whatever you want it to be: bytes, rows, or a constant 1. Start with the number of entries and switch to cost only when your values vary a lot in size.

Expiration

Entries can expire after a fixed time-to-live. The default TTL applies to every insert; pass an explicit TTL to override it for a single key.

Expired entries are removed lazily, when they are read or when their shard needs room. There is no background thread or timer per entry.

Loading on a miss

Use the loader form of a read to fill the store from a slower source. If several callers miss the same key at the same time, only the first one runs the loader; the others wait for its result.

Errors returned by the loader are not cached. The next caller will try again.

Sharding

Keys are hashed into a fixed number of shards. More shards mean less lock contention but slightly more memory overhead; the default works well up to dozens of cores.

The shard count must be a power of two and cannot be changed after the store is created.

Testing

Inject a fake clock to test expiration without sleeping. All time-dependent behaviour in ferncache goes through it.

Call clear() between tests instead of creating a new store if construction is expensive in your setup.