hitbox-feoxdb 0.2.0

FeOxDB backend for Hitbox cache with per-key TTL support
Documentation

hitbox-feoxdb

Persistent cache backend for the Hitbox caching framework.

This crate provides [FeOxDbBackend], a disk-based cache backend powered by FeOxDB, a pure Rust embedded database. It offers data persistence across restarts and native per-key TTL support.

Overview

  • Persistence: Cache data survives application restarts
  • Per-key TTL: Each entry can have its own expiration time
  • Pure Rust: No external dependencies or system libraries required
  • In-memory mode: Optional ephemeral storage for testing

Quickstart

use hitbox_feoxdb::FeOxDbBackend;

// Create a persistent backend
let backend = FeOxDbBackend::builder()
    .path("/var/cache/myapp")
    .build()
    .expect("Failed to open database");

// Or use in-memory mode for testing
let test_backend = FeOxDbBackend::in_memory()
    .expect("Failed to create in-memory backend");

Storage Modes

FeOxDbBackend supports two storage modes:

Mode Method Use case
Persistent builder().path(...) Production, data survives restarts
In-memory in_memory() Testing, temporary caching

When using persistent mode with a directory path, the database file is automatically created as cache.db within that directory.

Configuration

Option Default Description
path None (in-memory) Database file path
max_file_size 1 GB Maximum disk storage capacity
max_memory 1 GB Maximum RAM usage
key_format Bitcode Cache key serialization format
value_format JsonFormat Value serialization format
compressor PassthroughCompressor Compression strategy
label "feoxdb" Backend label for multi-tier composition

Resource Limits

FeOxDB allows configuring resource limits for both disk and memory usage:

  • max_file_size: Controls the maximum size of the database file on disk. The file is pre-allocated at this size. When full, writes fail with OutOfSpace. Only applies to persistent mode.

  • max_memory: Controls RAM usage for in-memory data structures.

    • In memory-only mode: This is the total storage capacity
    • In persistent mode: This limits the in-memory cache for disk data

    When exceeded, writes fail with OutOfMemory. FeOxDB does not automatically evict entries from the main store (unlike Moka's LRU eviction).

use hitbox_feoxdb::FeOxDbBackend;

let backend = FeOxDbBackend::builder()
    .path("/var/cache/myapp")
    .max_file_size(10 * 1024 * 1024 * 1024)  // 10 GB disk limit
    .max_memory(512 * 1024 * 1024)           // 512 MB RAM limit
    .build()
    .expect("Failed to open database");

Serialization Formats

The value_format option controls how cached data is serialized. Available formats are provided by hitbox_backend::format:

Format Speed Size Human-readable Use case
JsonFormat Slow Large Partial* Debugging, interoperability
BincodeFormat Fast Compact No General purpose (recommended)
RonFormat Medium Medium Yes Config files, debugging
RkyvFormat Fastest Compact No Zero-copy, max performance

* JSON serializes binary data as byte arrays [104, 101, ...], not readable strings.

Note: RkyvFormat requires enabling the rkyv_format feature on hitbox-backend.

Compression Strategies

The compressor option controls whether cached data is compressed. Available compressors are provided by [hitbox_backend]:

Compressor Ratio Speed Feature flag
PassthroughCompressor None Fastest
GzipCompressor Good Medium gzip
ZstdCompressor Best Fast zstd

For disk-based caches, compression is often recommended since it reduces I/O operations and disk usage, which can improve performance.

TTL Handling

FeOxDB natively supports per-key TTL. When writing a cache entry with an expiration time, the TTL is computed and passed to FeOxDB's insert_with_ttl. Expired entries are automatically cleaned up by the database.

As a safety measure, the backend also checks expiration during reads to handle edge cases where cleanup hasn't occurred yet.

When to Use This Backend

Use FeOxDbBackend when you need:

  • Persistence: Cache data must survive application restarts
  • Single-instance: Data doesn't need to be shared across processes
  • Simplicity: No external services to manage (unlike Redis)
  • Large datasets: Data that doesn't fit in memory

Consider other backends when you need:

Multi-Tier Composition

FeOxDbBackend works well as an L2 cache behind a fast in-memory cache:

use hitbox_backend::composition::Compose;
use hitbox_moka::MokaBackend;
use hitbox_feoxdb::FeOxDbBackend;

// Fast in-memory cache (L1) backed by disk (L2)
let l1 = MokaBackend::builder(10_000).build();
let l2 = FeOxDbBackend::builder()
    .path("/var/cache/myapp")
    .build()?;

let backend = l1.compose(l2, offload_manager);

Thread Safety

FeOxDbBackend is Clone, Send, and Sync. Cloned instances share the same underlying database connection via Arc<FeoxStore>. All database operations are performed in blocking tasks to avoid blocking the async runtime.