store.rs
Overview
This file defines an abstraction layer for key-value storage systems using the KeyValueStore trait, designed to facilitate interaction with Aerospike databases or any other key-value stores implementing the same interface. It provides asynchronous-safe methods for retrieving and storing data in the form of Aerospike Bins and Values. The file also includes default batch processing implementations for get and put operations, enabling efficient bulk access patterns.
Types and Traits
ValueMap
pub type ValueMap = HashMap<String, Value>;
Description: Alias for a hash map where keys are strings representing bin names and values are Aerospike
Valueobjects.Usage: Represents a collection of bin values retrieved from or to be stored in a key-value store record.
KeyValueStore Trait
pub trait KeyValueStore: Send + Sync {
fn get(
&self,
key: &Key,
values: &Bins,
label: &'static str,
) -> anyhow::Result<Option<ValueMap>>;
fn batch_get(
&self,
gets: Vec<(Key, Bins)>,
label: &'static str,
) -> anyhow::Result<Vec<Option<ValueMap>>>;
fn put(
&self,
key: &Key,
bins: &[Bin],
until_success: bool,
label: &'static str,
) -> anyhow::Result<()>;
fn batch_put(
&self,
puts: Vec<(Key, Vec<Bin>)>,
until_success: bool,
label: &'static str,
) -> anyhow::Result<()>;
#[cfg(debug_assertions)]
fn db_reads(&self) -> usize;
#[cfg(debug_assertions)]
fn db_writes(&self) -> usize;
}
Purpose
Defines the interface for any key-value store implementation, ensuring thread safety (Send + Sync) and providing methods to:
Retrieve values (
getandbatch_get)Store values (
putandbatch_put)Optionally track the number of database reads and writes in debug mode
Methods
get
fn get(
&self,
key: &Key,
values: &Bins,
label: &'static str,
) -> anyhow::Result<Option<ValueMap>>;
Parameters:
key: AerospikeKeyidentifying the record to fetch.values: AerospikeBinsspecifying which bins (fields) to retrieve.label: Static string label used for logging, tracing, or metrics tagging.
Returns:
Ok(Some(ValueMap))if the record exists, mapping bin names to their values.Ok(None)if the record does not exist.Errif an error occurs during retrieval.
Usage Example:
let key = Key::new("test", "users", "user123");
let bins = Bins::All;
let label = "fetch-user";
let result = store.get(&key, &bins, label)?;
if let Some(values) = result {
// Process values
}
batch_get
fn batch_get(
&self,
gets: Vec<(Key, Bins)>,
label: &'static str,
) -> anyhow::Result<Vec<Option<ValueMap>>>;
Parameters:
gets: Vector of tuples, each containing aKeyandBinsto fetch.label: Static string label for logging or monitoring.
Returns: Vector of optional
ValueMaps corresponding to each requested key.Implementation Details:
Default implementation calls
getfor each key sequentially.Can be overridden for optimized batch retrieval.
Usage Example:
let requests = vec![
(Key::new("test", "users", "user123"), Bins::All),
(Key::new("test", "users", "user456"), Bins::All),
];
let results = store.batch_get(requests, "batch-fetch")?;
put
fn put(
&self,
key: &Key,
bins: &[Bin],
until_success: bool,
label: &'static str,
) -> anyhow::Result<()>;
Parameters:
key: AerospikeKeyspecifying where to store data.bins: Slice of AerospikeBinobjects representing the data to store.until_success: Boolean indicating if the operation should retry until successful.label: Static string label for logging/tracing.
Returns:
Ok(())on success or an error on failure.Usage Example:
let bins = vec![Bin::new("name", "Alice"), Bin::new("age", 30)];
store.put(&key, &bins, false, "store-user")?;
batch_put
fn batch_put(
&self,
puts: Vec<(Key, Vec<Bin>)>,
until_success: bool,
label: &'static str,
) -> anyhow::Result<()>;
Parameters:
puts: Vector of tuples where each contains aKeyand vector ofBins to store.until_success: If true, retries until put succeeds.label: Static string label for logging or metrics.
Returns:
Ok(())on success, error otherwise.Implementation Details:
Default implementation calls
putsequentially for each key-value pair.Can be overridden for optimized batch writes.
Usage Example:
let batch_data = vec![
(Key::new("test", "users", "user123"), vec![Bin::new("name", "Alice")]),
(Key::new("test", "users", "user456"), vec![Bin::new("name", "Bob")]),
];
store.batch_put(batch_data, false, "batch-store")?;
db_reads and db_writes
Purpose: Provide counters for the number of database read and write operations performed.
Availability: Only compiled in debug builds (
#[cfg(debug_assertions)]).Returns:
usizecount of reads or writes.Usage: Useful for profiling and debugging performance or usage patterns.
Implementation Details
The trait uses the
anyhow::Resulttype for error handling, enabling flexible error propagation.Batch operations have default implementations that perform sequential calls to their single-operation counterparts, simplifying implementation for basic stores.
The
labelparameter in all methods is designed for observability purposes, allowing instrumentation such as logging, tracing, or metrics tagging without impacting core logic.The trait is
Send + Syncto ensure thread safety in concurrent environments.
Interaction with Other System Components
This trait abstracts the storage backend. Implementations likely interact with the Aerospike client library (
aerospikecrate), managing network communication and serialization.Components requiring persistent storage of key-value pairs use this interface for data manipulation without coupling to Aerospike or any other specific key-value store.
The
Key,Bin,Bins, andValuetypes come from the Aerospike client library, linking this abstraction closely with Aerospike's data model.Higher-level application logic can use this trait to perform atomic get/put operations or batch operations, integrating with caching, indexing, or business logic layers.
Mermaid Diagram
classDiagram
class KeyValueStore {
<<trait>>
+get()
+batch_get()
+put()
+batch_put()
+db_reads()
+db_writes()
}
class ValueMap {
<<type alias>>
}
KeyValueStore ..> ValueMap : uses
This diagram shows the KeyValueStore trait with its main methods and the ValueMap type alias used in method signatures.