Skip to main content

ClientApi

Trait ClientApi 

Source
pub trait ClientApi: Send + Sync {
    // Required methods
    fn put<'life0, 'async_trait>(
        &'life0 self,
        key: impl AsRef<[u8]> + Send + 'async_trait,
        value: impl AsRef<[u8]> + Send + 'async_trait,
    ) -> Pin<Box<dyn Future<Output = Result<(), ClientApiError>> + Send + 'async_trait>>
       where 'life0: 'async_trait,
             Self: 'async_trait;
    fn put_with_ttl<'life0, 'async_trait>(
        &'life0 self,
        key: impl AsRef<[u8]> + Send + 'async_trait,
        value: impl AsRef<[u8]> + Send + 'async_trait,
        ttl_secs: u64,
    ) -> Pin<Box<dyn Future<Output = Result<(), ClientApiError>> + Send + 'async_trait>>
       where 'life0: 'async_trait,
             Self: 'async_trait;
    fn get<'life0, 'async_trait>(
        &'life0 self,
        key: impl AsRef<[u8]> + Send + 'async_trait,
    ) -> Pin<Box<dyn Future<Output = Result<Option<Bytes>, ClientApiError>> + Send + 'async_trait>>
       where 'life0: 'async_trait,
             Self: 'async_trait;
    fn get_multi<'life0, 'life1, 'async_trait>(
        &'life0 self,
        keys: &'life1 [Bytes],
    ) -> Pin<Box<dyn Future<Output = Result<Vec<Option<Bytes>>, ClientApiError>> + Send + 'async_trait>>
       where 'life0: 'async_trait,
             'life1: 'async_trait,
             Self: 'async_trait;
    fn delete<'life0, 'async_trait>(
        &'life0 self,
        key: impl AsRef<[u8]> + Send + 'async_trait,
    ) -> Pin<Box<dyn Future<Output = Result<(), ClientApiError>> + Send + 'async_trait>>
       where 'life0: 'async_trait,
             Self: 'async_trait;
    fn compare_and_swap<'life0, 'async_trait>(
        &'life0 self,
        key: impl AsRef<[u8]> + Send + 'async_trait,
        expected_value: Option<impl AsRef<[u8]> + Send + 'async_trait>,
        new_value: impl AsRef<[u8]> + Send + 'async_trait,
    ) -> Pin<Box<dyn Future<Output = Result<bool, ClientApiError>> + Send + 'async_trait>>
       where 'life0: 'async_trait,
             Self: 'async_trait;
    fn list_members<'life0, 'async_trait>(
        &'life0 self,
    ) -> Pin<Box<dyn Future<Output = Result<Vec<NodeMeta>, ClientApiError>> + Send + 'async_trait>>
       where 'life0: 'async_trait,
             Self: 'async_trait;
    fn get_leader_id<'life0, 'async_trait>(
        &'life0 self,
    ) -> Pin<Box<dyn Future<Output = Result<Option<u32>, ClientApiError>> + Send + 'async_trait>>
       where 'life0: 'async_trait,
             Self: '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 = Result<Vec<Option<Bytes>>, ClientApiError>> + Send + 'async_trait>>
       where 'life0: 'async_trait,
             'life1: 'async_trait,
             Self: 'async_trait;
    fn get_linearizable<'life0, 'async_trait>(
        &'life0 self,
        key: impl AsRef<[u8]> + Send + 'async_trait,
    ) -> Pin<Box<dyn Future<Output = Result<Option<Bytes>, ClientApiError>> + Send + 'async_trait>>
       where 'life0: 'async_trait,
             Self: 'async_trait;
    fn get_lease<'life0, 'async_trait>(
        &'life0 self,
        key: impl AsRef<[u8]> + Send + 'async_trait,
    ) -> Pin<Box<dyn Future<Output = Result<Option<Bytes>, ClientApiError>> + Send + 'async_trait>>
       where 'life0: 'async_trait,
             Self: 'async_trait;
    fn get_eventual<'life0, 'async_trait>(
        &'life0 self,
        key: impl AsRef<[u8]> + Send + 'async_trait,
    ) -> Pin<Box<dyn Future<Output = Result<Option<Bytes>, ClientApiError>> + Send + 'async_trait>>
       where 'life0: 'async_trait,
             Self: '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§

Source

fn put<'life0, 'async_trait>( &'life0 self, key: impl AsRef<[u8]> + Send + 'async_trait, value: impl AsRef<[u8]> + Send + 'async_trait, ) -> Pin<Box<dyn Future<Output = Result<(), ClientApiError>> + Send + 'async_trait>>
where 'life0: 'async_trait, Self: '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?;
Source

fn put_with_ttl<'life0, 'async_trait>( &'life0 self, key: impl AsRef<[u8]> + Send + 'async_trait, value: impl AsRef<[u8]> + Send + 'async_trait, ttl_secs: u64, ) -> Pin<Box<dyn Future<Output = Result<(), ClientApiError>> + Send + 'async_trait>>
where 'life0: 'async_trait, Self: '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 store
  • value - The value to store
  • ttl_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?;
Source

fn get<'life0, 'async_trait>( &'life0 self, key: impl AsRef<[u8]> + Send + 'async_trait, ) -> Pin<Box<dyn Future<Output = Result<Option<Bytes>, ClientApiError>> + Send + 'async_trait>>
where 'life0: 'async_trait, Self: '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 exists
  • Ok(None) if key does not exist or has expired
  • Err(_) 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"),
}
Source

fn get_multi<'life0, 'life1, 'async_trait>( &'life0 self, keys: &'life1 [Bytes], ) -> Pin<Box<dyn Future<Output = Result<Vec<Option<Bytes>>, ClientApiError>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, Self: '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?;
Source

fn delete<'life0, 'async_trait>( &'life0 self, key: impl AsRef<[u8]> + Send + 'async_trait, ) -> Pin<Box<dyn Future<Output = Result<(), ClientApiError>> + Send + 'async_trait>>
where 'life0: 'async_trait, Self: '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?;
Source

fn compare_and_swap<'life0, 'async_trait>( &'life0 self, key: impl AsRef<[u8]> + Send + 'async_trait, expected_value: Option<impl AsRef<[u8]> + Send + 'async_trait>, new_value: impl AsRef<[u8]> + Send + 'async_trait, ) -> Pin<Box<dyn Future<Output = Result<bool, ClientApiError>> + Send + 'async_trait>>
where 'life0: 'async_trait, Self: '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.)
Source

fn list_members<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<Vec<NodeMeta>, ClientApiError>> + Send + 'async_trait>>
where 'life0: 'async_trait, Self: '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

Source

fn get_leader_id<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<Option<u32>, ClientApiError>> + Send + 'async_trait>>
where 'life0: 'async_trait, Self: '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

Source

fn get_multi_with_policy<'life0, 'life1, 'async_trait>( &'life0 self, keys: &'life1 [Bytes], consistency_policy: Option<ReadConsistencyPolicy>, ) -> Pin<Box<dyn Future<Output = Result<Vec<Option<Bytes>>, ClientApiError>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, Self: '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 retrieve
  • consistency_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?;
Source

fn get_linearizable<'life0, 'async_trait>( &'life0 self, key: impl AsRef<[u8]> + Send + 'async_trait, ) -> Pin<Box<dyn Future<Output = Result<Option<Bytes>, ClientApiError>> + Send + 'async_trait>>
where 'life0: 'async_trait, Self: '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 exists
  • Ok(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?;
Source

fn get_lease<'life0, 'async_trait>( &'life0 self, key: impl AsRef<[u8]> + Send + 'async_trait, ) -> Pin<Box<dyn Future<Output = Result<Option<Bytes>, ClientApiError>> + Send + 'async_trait>>
where 'life0: 'async_trait, Self: '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 exists
  • Ok(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?;
Source

fn get_eventual<'life0, 'async_trait>( &'life0 self, key: impl AsRef<[u8]> + Send + 'async_trait, ) -> Pin<Box<dyn Future<Output = Result<Option<Bytes>, ClientApiError>> + Send + 'async_trait>>
where 'life0: 'async_trait, Self: '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.

Implementors§