mod.rs
Overview
This file defines caching abstractions and implementations for a key-value storage system, providing an intermediary cache layer that wraps around a lower-level KeyValueStore. It includes a generic Cache trait, a Least Recently Used (LRU) sized cache implementation (LruSizedCache), and a composite store (CachedStore) that combines a cache and an underlying database store to improve read efficiency and reduce direct database hits.
Traits and Structs
Cache Trait
The Cache trait abstracts the behavior of a thread-safe cache for key-value pairs, where keys are Aerospike Key instances and values are ValueMaps (a map representation of bins and their values).
Methods
fn get(&self, key: &Key) -> Option<ValueMap>;
Retrieves the cached value for the specified key if present. Returns None if the key is not cached.fn put(&self, key: &Key, bins: ValueMap);
Inserts or updates the cache entry for the specified key with the given value map.fn invalidate(&self, key: &Key);
Removes the cache entry for the specified key, if present.
Usage Example
fn example(cache: &impl Cache, key: &Key, value: ValueMap) {
cache.put(key, value.clone());
if let Some(cached_value) = cache.get(key) {
// Use cached_value
}
cache.invalidate(key);
}
LruSizedCache Struct
A thread-safe, fixed-size LRU cache implementation of the Cache trait. It internally uses cached::SizedCache wrapped in a parking_lot::Mutex for synchronization, and Arc for shared ownership.
Fields
cache: Arc<Mutex<SizedCache<String, ValueMap>>>
The underlying LRU cache storing keys as strings and values asValueMap.
Methods
pub fn new(size: usize) -> Self
Creates a newLruSizedCachewith a maximum capacity ofsizeentries.
Trait Implementation: Cache
get
Converts the Aerospike key to a string and retrieves the associatedValueMapfrom the LRU cache.put
Inserts or updates the entry for the stringified key.invalidate
Removes the entry for the stringified key.
Implementation Details
The cache keys are string representations of Aerospike keys (
key.to_string()).The use of
parking_lot::Mutexprovides efficient locking semantics for concurrent access.Cloning the
LruSizedCacheresults in a shared reference to the same underlying cache due toArc.
CachedStore<B, C> Struct
A generic, composable key-value store that integrates an underlying database store (B: KeyValueStore) with a cache layer (C: Cache). This store attempts to serve reads from the cache before falling back to the database, and writes update both layers.
Fields
db: B
The underlying database store implementing theKeyValueStoretrait.cache: C
The cache implementing theCachetrait.
Methods
pub fn new(db: B, cache: C) -> Self
Constructs a newCachedStoreby composing the database and cache.fn bins_to_map(bins: &[Bin<'_>]) -> ValueMap(private helper)
Converts a slice of AerospikeBinreferences to aValueMap(mapping bin names to their values).
Trait Implementation: KeyValueStore
Implements the core key-value operations with caching logic.
fn get(&self, key: &Key, values: &Bins, label: &'static str) -> anyhow::Result<Option<ValueMap>>
Checks the cache first for the key; on miss, queries the underlying database and caches the result if found.fn put(&self, key: &Key, bins: &[Bin], until_success: bool, label: &'static str) -> anyhow::Result<()>
Writes the bins to the database first, then updates the cache with the new bin values.fn batch_get(&self, reads: Vec<(Key, Bins)>, label: &'static str) -> anyhow::Result<Vec<Option<ValueMap>>>
Performs batched retrieval of multiple keys:Attempts to fulfill each key from the cache.
Collects cache misses and fetches them in batch from the database.
Updates the cache with the batch results.
Returns a vector of results maintaining input order.
fn db_reads(&self) -> usizeandfn db_writes(&self) -> usize(debug builds only)
Delegates calls to the underlying database store to retrieve internal statistics about the number of reads and writes.
Implementation Details
The cache is always updated after a successful database read or write to maintain consistency.
The batch_get method optimizes database calls by only querying missing keys.
Uses
anyhow::Resultto propagate errors from the underlying store.The label parameter is passed downstream to the database for logging or telemetry purposes.
Clones are performed where necessary to avoid lifetime issues with values stored in the cache.
Interaction with Other Modules
Utilizes Aerospike types:
Key,Bin, andBinsto represent data keys and values.Depends on the
KeyValueStoretrait andValueMaptype from thecrate::storagemodule to abstract database interactions.Uses
cached::SizedCachefor the LRU cache implementation.Employs
parking_lot::Mutexfor efficient concurrency control.Wraps the lower-level store (
db) and adds caching transparently, making it composable and reusable in higher-level components.
Visual Diagram
classDiagram
class Cache {
<<trait>>
+get()
+put()
+invalidate()
}
class LruSizedCache {
-cache: Arc<Mutex<SizedCache>>
+new()
+get()
+put()
+invalidate()
}
class KeyValueStore {
<<trait>>
+get()
+put()
+batch_get()
+db_reads() [debug only]
+db_writes() [debug only]
}
class CachedStore {
-db: KeyValueStore
-cache: Cache
+new()
+get()
+put()
+batch_get()
+db_reads() [debug only]
+db_writes() [debug only]
}
Cache <|.. LruSizedCache
KeyValueStore <|.. CachedStore
CachedStore --> Cache : uses
CachedStore --> KeyValueStore : uses
Key Algorithms and Implementation Notes
LRU Caching:
LruSizedCacheuses a size-limited cache that evicts least recently used entries once capacity is reached, maintaining recent data for fast retrieval.Batch Get Optimization: CachedStore::batch_get minimizes database reads by first querying the cache for each key and only requesting missing keys in a single batch call.
Thread Safety: The cache implementations are designed to be thread-safe, allowing concurrent access and mutation without data races.
Cache Consistency: On writes, the cache is updated immediately after the database write to ensure read-after-write consistency.
Key Serialization: Aerospike keys are serialized to strings for use as cache keys, simplifying cache lookups.
Usage Context
This module is intended to be used wherever key-value data retrieval and storage occurs, enhancing performance by avoiding repeated database access for frequently requested keys. It can be integrated into larger systems requiring fast data access and reliability with consistent caching semantics. The generic design allows it to wrap any KeyValueStore implementation and use any cache conforming to the Cache trait, promoting modularity and testability.
For further exploration of Aerospike key management and bin structures, see Aerospike Key Handling and Bin Data Structures. For details on caching strategies and concurrency, refer to Caching Strategies and Concurrency Primitives.