pub trait ClientApi: Send + Sync {
// Required methods
fn put<'life0, 'async_trait>(
&'life0 self,
key: impl 'async_trait + AsRef<[u8]> + Send,
value: impl 'async_trait + AsRef<[u8]> + Send,
) -> Pin<Box<dyn Future<Output = ClientApiResult<()>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn put_with_ttl<'life0, 'async_trait>(
&'life0 self,
key: impl 'async_trait + AsRef<[u8]> + Send,
value: impl 'async_trait + AsRef<[u8]> + Send,
ttl_secs: u64,
) -> Pin<Box<dyn Future<Output = ClientApiResult<()>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn get<'life0, 'async_trait>(
&'life0 self,
key: impl 'async_trait + AsRef<[u8]> + Send,
) -> Pin<Box<dyn Future<Output = ClientApiResult<Option<Bytes>>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn get_multi<'life0, 'life1, 'async_trait>(
&'life0 self,
keys: &'life1 [Bytes],
) -> Pin<Box<dyn Future<Output = ClientApiResult<Vec<Option<Bytes>>>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn delete<'life0, 'async_trait>(
&'life0 self,
key: impl 'async_trait + AsRef<[u8]> + Send,
) -> Pin<Box<dyn Future<Output = ClientApiResult<()>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn compare_and_swap<'life0, 'async_trait>(
&'life0 self,
key: impl 'async_trait + AsRef<[u8]> + Send,
expected_value: Option<impl 'async_trait + AsRef<[u8]> + Send>,
new_value: impl 'async_trait + AsRef<[u8]> + Send,
) -> Pin<Box<dyn Future<Output = ClientApiResult<bool>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn list_members<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = ClientApiResult<Vec<NodeMeta>>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn get_leader_id<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = ClientApiResult<Option<u32>>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn get_multi_with_policy<'life0, 'life1, 'async_trait>(
&'life0 self,
keys: &'life1 [Bytes],
consistency_policy: Option<ReadConsistencyPolicy>,
) -> Pin<Box<dyn Future<Output = ClientApiResult<Vec<Option<Bytes>>>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn get_linearizable<'life0, 'async_trait>(
&'life0 self,
key: impl 'async_trait + AsRef<[u8]> + Send,
) -> Pin<Box<dyn Future<Output = ClientApiResult<Option<Bytes>>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn get_lease<'life0, 'async_trait>(
&'life0 self,
key: impl 'async_trait + AsRef<[u8]> + Send,
) -> Pin<Box<dyn Future<Output = ClientApiResult<Option<Bytes>>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn get_eventual<'life0, 'async_trait>(
&'life0 self,
key: impl 'async_trait + AsRef<[u8]> + Send,
) -> Pin<Box<dyn Future<Output = ClientApiResult<Option<Bytes>>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
}Expand description
Unified key-value store interface.
This trait abstracts over different client implementations, allowing applications to write generic code that works with both remote (gRPC) and embedded (local) access.
§Consistency Guarantees
- put(): Strong consistency, linearizable writes
- get(): Linearizable reads by default
- delete(): Strong consistency, linearizable deletes
§Thread Safety
All implementations must be Send + Sync, safe for concurrent access.
§Performance Characteristics
GrpcClient: 1-2ms latency (network + serialization)EmbeddedClient: <0.1ms latency (direct function call)
Required Methods§
Sourcefn put<'life0, 'async_trait>(
&'life0 self,
key: impl 'async_trait + AsRef<[u8]> + Send,
value: impl 'async_trait + AsRef<[u8]> + Send,
) -> Pin<Box<dyn Future<Output = ClientApiResult<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn put<'life0, 'async_trait>(
&'life0 self,
key: impl 'async_trait + AsRef<[u8]> + Send,
value: impl 'async_trait + AsRef<[u8]> + Send,
) -> Pin<Box<dyn Future<Output = ClientApiResult<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Stores a key-value pair with strong consistency.
The write is replicated to a quorum of nodes before returning, ensuring durability and linearizability.
§Arguments
key- The key to store (arbitrary bytes)value- The value to store (arbitrary bytes)
§Errors
- [
ClientApiError::Network] if node is shutting down or timeout occurs - [
ClientApiError::Business] for server-side errors (e.g., not leader)
§Example
client.put(b"user:1001", b"Alice").await?;Sourcefn put_with_ttl<'life0, 'async_trait>(
&'life0 self,
key: impl 'async_trait + AsRef<[u8]> + Send,
value: impl 'async_trait + AsRef<[u8]> + Send,
ttl_secs: u64,
) -> Pin<Box<dyn Future<Output = ClientApiResult<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn put_with_ttl<'life0, 'async_trait>(
&'life0 self,
key: impl 'async_trait + AsRef<[u8]> + Send,
value: impl 'async_trait + AsRef<[u8]> + Send,
ttl_secs: u64,
) -> Pin<Box<dyn Future<Output = ClientApiResult<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Stores a key-value pair with time-to-live (TTL).
The key will automatically expire after ttl_secs seconds.
§Arguments
key- The key to storevalue- The value to storettl_secs- Time-to-live in seconds
§Errors
Same as put()
§Example
// Session expires after 1 hour
client.put_with_ttl(b"session:abc", b"user_data", 3600).await?;Sourcefn get<'life0, 'async_trait>(
&'life0 self,
key: impl 'async_trait + AsRef<[u8]> + Send,
) -> Pin<Box<dyn Future<Output = ClientApiResult<Option<Bytes>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn get<'life0, 'async_trait>(
&'life0 self,
key: impl 'async_trait + AsRef<[u8]> + Send,
) -> Pin<Box<dyn Future<Output = ClientApiResult<Option<Bytes>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Retrieves the value associated with a key.
Uses linearizable reads by default, ensuring the returned value reflects all previously committed writes.
§Arguments
key- The key to retrieve
§Returns
Ok(Some(value))if key existsOk(None)if key does not exist or has expiredErr(_)if operation failed
§Errors
- [
ClientApiError::Network] if node is shutting down or timeout occurs - [
ClientApiError::Business] for server-side errors
§Example
match client.get(b"user:1001").await? {
Some(value) => println!("User: {:?}", value),
None => println!("User not found"),
}Sourcefn get_multi<'life0, 'life1, 'async_trait>(
&'life0 self,
keys: &'life1 [Bytes],
) -> Pin<Box<dyn Future<Output = ClientApiResult<Vec<Option<Bytes>>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn get_multi<'life0, 'life1, 'async_trait>(
&'life0 self,
keys: &'life1 [Bytes],
) -> Pin<Box<dyn Future<Output = ClientApiResult<Vec<Option<Bytes>>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Retrieves multiple keys in a single request.
More efficient than multiple individual get() calls when fetching
multiple keys, as it batches the requests.
§Arguments
keys- Slice of keys to retrieve
§Returns
Vector of results in the same order as input keys.
None for keys that don’t exist.
§Errors
Same as get()
§Example
let keys = vec![
Bytes::from("user:1001"),
Bytes::from("user:1002"),
];
let results = client.get_multi(&keys).await?;Sourcefn delete<'life0, 'async_trait>(
&'life0 self,
key: impl 'async_trait + AsRef<[u8]> + Send,
) -> Pin<Box<dyn Future<Output = ClientApiResult<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn delete<'life0, 'async_trait>(
&'life0 self,
key: impl 'async_trait + AsRef<[u8]> + Send,
) -> Pin<Box<dyn Future<Output = ClientApiResult<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Deletes a key-value pair with strong consistency.
The deletion is replicated to a quorum before returning. Returns successfully even if the key does not exist (idempotent).
§Arguments
key- The key to delete
§Errors
- [
ClientApiError::Network] if node is shutting down or timeout occurs - [
ClientApiError::Business] for server-side errors
§Example
client.delete(b"temp:session_123").await?;Sourcefn compare_and_swap<'life0, 'async_trait>(
&'life0 self,
key: impl 'async_trait + AsRef<[u8]> + Send,
expected_value: Option<impl 'async_trait + AsRef<[u8]> + Send>,
new_value: impl 'async_trait + AsRef<[u8]> + Send,
) -> Pin<Box<dyn Future<Output = ClientApiResult<bool>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn compare_and_swap<'life0, 'async_trait>(
&'life0 self,
key: impl 'async_trait + AsRef<[u8]> + Send,
expected_value: Option<impl 'async_trait + AsRef<[u8]> + Send>,
new_value: impl 'async_trait + AsRef<[u8]> + Send,
) -> Pin<Box<dyn Future<Output = ClientApiResult<bool>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Atomically compare and swap a key’s value
Returns:
- Ok(true): CAS succeeded, value was updated
- Ok(false): CAS failed, current value != expected_value
- Err(e): Operation error (timeout, cluster unavailable, etc.)
Sourcefn list_members<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = ClientApiResult<Vec<NodeMeta>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn list_members<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = ClientApiResult<Vec<NodeMeta>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Lists all cluster members with metadata
Returns node information including:
- Node ID
- Address
- Role (Leader/Follower/Learner)
- Status
§Errors
Returns error if unable to retrieve cluster metadata
Sourcefn get_leader_id<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = ClientApiResult<Option<u32>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn get_leader_id<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = ClientApiResult<Option<u32>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Get the current leader ID
Returns the leader node ID if known, or None if no leader is currently elected.
§Errors
Returns error if unable to determine leader status
Sourcefn get_multi_with_policy<'life0, 'life1, 'async_trait>(
&'life0 self,
keys: &'life1 [Bytes],
consistency_policy: Option<ReadConsistencyPolicy>,
) -> Pin<Box<dyn Future<Output = ClientApiResult<Vec<Option<Bytes>>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn get_multi_with_policy<'life0, 'life1, 'async_trait>(
&'life0 self,
keys: &'life1 [Bytes],
consistency_policy: Option<ReadConsistencyPolicy>,
) -> Pin<Box<dyn Future<Output = ClientApiResult<Vec<Option<Bytes>>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Retrieves multiple keys with explicit consistency policy
Batch retrieval with explicit consistency control. More efficient than multiple individual calls when fetching multiple keys.
§Arguments
keys- Slice of keys to retrieveconsistency_policy- Explicit consistency policy for this batch request
§Returns
Vector of results in the same order as input keys.
None for keys that don’t exist.
§Errors
Same as get()
§Example
use d_engine_proto::client::ReadConsistencyPolicy;
let keys = vec![
Bytes::from("key1"),
Bytes::from("key2"),
];
let values = client.get_multi_with_policy(
&keys,
Some(ReadConsistencyPolicy::EventualConsistency)
).await?;Sourcefn get_linearizable<'life0, 'async_trait>(
&'life0 self,
key: impl 'async_trait + AsRef<[u8]> + Send,
) -> Pin<Box<dyn Future<Output = ClientApiResult<Option<Bytes>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn get_linearizable<'life0, 'async_trait>(
&'life0 self,
key: impl 'async_trait + AsRef<[u8]> + Send,
) -> Pin<Box<dyn Future<Output = ClientApiResult<Option<Bytes>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Retrieves a key with linearizable (strong) consistency
Convenience method for get_multi_with_policy() with
LinearizableRead policy. Guarantees reading the latest committed value.
§Arguments
key- The key to retrieve
§Returns
Ok(Some(value))if key existsOk(None)if key does not exist or has expired
§Errors
Same as get()
§Example
// Guaranteed to read latest value
let value = client.get_linearizable(b"critical-config").await?;Sourcefn get_lease<'life0, 'async_trait>(
&'life0 self,
key: impl 'async_trait + AsRef<[u8]> + Send,
) -> Pin<Box<dyn Future<Output = ClientApiResult<Option<Bytes>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn get_lease<'life0, 'async_trait>(
&'life0 self,
key: impl 'async_trait + AsRef<[u8]> + Send,
) -> Pin<Box<dyn Future<Output = ClientApiResult<Option<Bytes>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Retrieves a key with lease-based consistency
Convenience method for get_multi_with_policy() with
LeaseRead policy. Optimized linearizable read using Leader lease mechanism.
§Arguments
key- The key to retrieve
§Returns
Ok(Some(value))if key existsOk(None)if key does not exist or has expired
§Errors
Same as get()
§Example
// Lease-based read (faster than linearizable, still strong consistency)
let value = client.get_lease(b"config").await?;Sourcefn get_eventual<'life0, 'async_trait>(
&'life0 self,
key: impl 'async_trait + AsRef<[u8]> + Send,
) -> Pin<Box<dyn Future<Output = ClientApiResult<Option<Bytes>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn get_eventual<'life0, 'async_trait>(
&'life0 self,
key: impl 'async_trait + AsRef<[u8]> + Send,
) -> Pin<Box<dyn Future<Output = ClientApiResult<Option<Bytes>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Retrieves a key with eventual consistency
Convenience method for get_multi_with_policy() with
EventualConsistency policy. Fast but may return stale data if replication is lagging.
§Arguments
key- The key to retrieve
§Returns
Ok(Some(value))if key exists (may be stale)Ok(None)if key does not exist or has expired
§Errors
Same as get()
§Use Cases
- Read-heavy workloads with acceptable staleness
- Analytics/reporting (staleness acceptable)
- Caching scenarios
§Example
// Fast stale read
let cached_value = client.get_eventual(b"user-preference").await?;Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.