38 releases (11 breaking)
new 0.16.1 | Apr 10, 2025 |
---|---|
0.15.3 | Mar 28, 2025 |
0.13.1 | Dec 4, 2024 |
0.12.2 | Oct 11, 2024 |
0.1.2 | Mar 21, 2024 |
#111 in Caching
150,876 downloads per month
Used in 6 crates
(3 directly)
270KB
5.5K
SLoC
Tutorial & Document: https://foyer.rs
foyer
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
- Hybrid Cache: Seamlessly integrates both in-memory and disk cache for optimal performance and flexibility.
- Plug-and-Play Algorithms: Empowers users with easily replaceable caching algorithms, ensuring adaptability to diverse use cases.
- Fearless Concurrency: Built to handle high concurrency with robust thread-safe mechanisms, guaranteeing reliable performance under heavy loads.
- Zero-Copy In-Memory Cache Abstraction: Leveraging Rust's robust type system, the in-memory cache in foyer achieves a better performance with zero-copy abstraction.
- User-Friendly Interface: Offers a simple and intuitive API, making cache integration effortless and accessible for developers of all levels.
- Out-of-the-Box Observability: Integrate popular observation systems such as Prometheus, Grafana, Opentelemetry, and Jaeger in just ONE line.
Projects Using foyer
Feel free to open a PR and add your projects here:
- RisingWave: SQL stream processing, analytics, and management.
- Chroma: Embedding database for LLM apps.
- SlateDB: A cloud native embedded storage engine built on object storage.
- dna: The fastest platform to build production-grade indexers that connect onchain data to web2 services.
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.16"
If your project is using the nightly rust toolchain, the nightly
feature needs to be enabled.
foyer = { version = "0.16", features = ["nightly"] }
Out-of-the-box In-memory Cache
The in-memory cache setup is extremely easy and can be setup in at least 1 line.
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
The setup of a hybrid cache is extremely easy.
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
Here is an example of a hybrid cache setup with almost all configurations to show th possibilities of tuning.
// Copyright 2025 foyer Project Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::sync::Arc;
use anyhow::Result;
use chrono::Datelike;
use foyer::{
DirectFsDeviceOptions, Engine, FifoPicker, HybridCache, HybridCacheBuilder, HybridCachePolicy, 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()
.with_name("my-hybrid-cache")
.with_policy(HybridCachePolicy::WriteOnEviction)
.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())
}
serde
Support
foyer needs to serialize/deserialize entries between memory and disk with hybrid cache. Cached keys and values need to implement the Code
trait when using hybrid cache.
The Code
trait has already been implemented for general types, such as:
- Numeric types:
u8
,u16
,u32
,u64
,u128
,usize
,i8
,i16
,i32
,i64
,i128
,isize
,f32
,f64
. - Buffer:
Vec<u8>
. - String:
String
. - Other general types:
bool
.
For more complex types, you need to implement the Code trait yourself.
To make things easier, foyer provides support for the serde
ecosystem. Types implement serde::Serialize
and serde::DeserializeOwned
, foyer will automatically implement the Code
trait. This feature requires enabling the serde
feature for foyer.
foyer = { version = "*", features = ["serde"] }
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
Dependencies
~7–18MB
~209K SLoC