docs.rs crates.io docs.rs

Tutorial & Document: https://foyer.rs

foyer

GitHub License Crates.io MSRV CI License Checker codecov

foyer aims to be an efficient and user-friendly hybrid cache lib in Rust.

foyer draws inspiration from Facebook/CacheLib, a highly-regarded hybrid cache library written in C++, and ben-manes/caffeine, a popular Java caching library, among other projects.

However, foyer is more than just a rewrite in Rust effort; it introduces a variety of new and optimized features.

For more details, please visit foyer's website: https://foyer.rs 🥰

Website | Tutorial | API Docs | Crate

Features

Projects Using foyer

Feel free to open a PR and add your projects here:

Quick Start

This section only shows briefs. Please visit https://foyer.rs for more details.

To use foyer in your project, add this line to the dependencies section of Cargo.toml.

foyer = "0.14"

If your project is using the nightly rust toolchain, the nightly feature needs to be enabled.

foyer = { version = "0.14", features = ["nightly"] }

Out-of-the-box In-memory Cache

use foyer::{Cache, CacheBuilder};

fn main() {
    let cache: Cache<String, String> = CacheBuilder::new(16).build();

    let entry = cache.insert("hello".to_string(), "world".to_string());
    let e = cache.get("hello").unwrap();

    assert_eq!(entry.value(), e.value());
}

Easy-to-use Hybrid Cache

use foyer::{DirectFsDeviceOptions, Engine, HybridCache, HybridCacheBuilder};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let dir = tempfile::tempdir()?;

    let hybrid: HybridCache<u64, String> = HybridCacheBuilder::new()
        .memory(64 * 1024 * 1024)
        .storage(Engine::Large) // use large object disk cache engine only
        .with_device_options(DirectFsDeviceOptions::new(dir.path()).with_capacity(256 * 1024 * 1024))
        .build()
        .await?;

    hybrid.insert(42, "The answer to life, the universe, and everything.".to_string());
    assert_eq!(
        hybrid.get(&42).await?.unwrap().value(),
        "The answer to life, the universe, and everything."
    );

    Ok(())
}

Fully Configured Hybrid Cache

use std::sync::Arc;

use anyhow::Result;
use chrono::Datelike;
use foyer::{
    DirectFsDeviceOptions, Engine, FifoPicker, HybridCache, HybridCacheBuilder, LargeEngineOptions, LruConfig,
    RateLimitPicker, RecoverMode, RuntimeOptions, SmallEngineOptions, TokioRuntimeOptions, TombstoneLogConfigBuilder,
};
use tempfile::tempdir;

#[tokio::main]
async fn main() -> Result<()> {
    let dir = tempdir()?;

    let hybrid: HybridCache<u64, String> = HybridCacheBuilder::new()
        .memory(1024)
        .with_shards(4)
        .with_eviction_config(LruConfig {
            high_priority_pool_ratio: 0.1,
        })
        .with_hash_builder(ahash::RandomState::default())
        .with_weighter(|_key, value: &String| value.len())
        .storage(Engine::Mixed(0.1))
        .with_device_options(
            DirectFsDeviceOptions::new(dir.path())
                .with_capacity(64 * 1024 * 1024)
                .with_file_size(4 * 1024 * 1024),
        )
        .with_flush(true)
        .with_recover_mode(RecoverMode::Quiet)
        .with_admission_picker(Arc::new(RateLimitPicker::new(100 * 1024 * 1024)))
        .with_compression(foyer::Compression::Lz4)
        .with_runtime_options(RuntimeOptions::Separated {
            read_runtime_options: TokioRuntimeOptions {
                worker_threads: 4,
                max_blocking_threads: 8,
            },
            write_runtime_options: TokioRuntimeOptions {
                worker_threads: 4,
                max_blocking_threads: 8,
            },
        })
        .with_large_object_disk_cache_options(
            LargeEngineOptions::new()
                .with_indexer_shards(64)
                .with_recover_concurrency(8)
                .with_flushers(2)
                .with_reclaimers(2)
                .with_buffer_pool_size(256 * 1024 * 1024)
                .with_clean_region_threshold(4)
                .with_eviction_pickers(vec![Box::<FifoPicker>::default()])
                .with_reinsertion_picker(Arc::new(RateLimitPicker::new(10 * 1024 * 1024)))
                .with_tombstone_log_config(
                    TombstoneLogConfigBuilder::new(dir.path().join("tombstone-log-file"))
                        .with_flush(true)
                        .build(),
                ),
        )
        .with_small_object_disk_cache_options(
            SmallEngineOptions::new()
                .with_set_size(16 * 1024)
                .with_set_cache_capacity(64)
                .with_flushers(2),
        )
        .build()
        .await?;

    hybrid.insert(42, "The answer to life, the universe, and everything.".to_string());
    assert_eq!(
        hybrid.get(&42).await?.unwrap().value(),
        "The answer to life, the universe, and everything."
    );

    let e = hybrid
        .fetch(20230512, || async {
            let value = mock().await?;
            Ok(value)
        })
        .await?;
    assert_eq!(e.key(), &20230512);
    assert_eq!(e.value(), "Hello, foyer.");

    hybrid.close().await.unwrap();

    Ok(())
}

async fn mock() -> Result<String> {
    let now = chrono::Utc::now();
    if format!("{}{}{}", now.year(), now.month(), now.day()) == "20230512" {
        return Err(anyhow::anyhow!("Hi, time traveler!"));
    }
    Ok("Hello, foyer.".to_string())
}

Other Examples

More examples and details can be found here.

Supported Rust Versions

foyer is built against the recent stable release. The minimum supported version is 1.81.0. The current foyer version is not guaranteed to build on Rust versions earlier than the minimum supported version.

Supported Platforms

foyer is designed to serve on Linux OS, but can still be built on other OS for development.

However, other components may not support non-Linux OS.

Component Linux MacOS Windows
foyer ✓ ✓ ✓
foyer-bench ✓ ✗ ✗

Development State & Roadmap

Currently, foyer is still under heavy development.

The development state and the roadmap can be found in foyer - Development Roadmap.

Contributing

Contributions for foyer are warmly welcomed! 🥰

Don't forget to pass make fast (which means fast check & test) locally before submitting a PR. 🚀

If you want to run a broader range of checks locally, run make full. 🙌

Thank you for your contribution~

Star History

Star History Chart

Join libs.tech

...and unlock some superpowers

GitHub

We won't share your data with anyone else.