d_engine_client/
kv_client.rs

1//! KV client trait - unified interface for key-value operations.
2//!
3//! Provides a common abstraction for both remote (gRPC) and embedded (local) access
4//! to d-engine's key-value store.
5//!
6//! # Implementations
7//!
8//! - `GrpcKvClient` (d-engine-client): Remote access via gRPC protocol
9//! - `LocalKvClient` (d-engine-server): Zero-overhead embedded access
10//!
11//! # Design Principles
12//!
13//! - **Unified Interface**: Same API for remote and embedded modes
14//! - **Async-first**: All operations are async for non-blocking I/O
15//! - **Type Safety**: Strong typing with clear error handling
16//! - **Performance**: Zero-cost abstractions, no runtime overhead
17//!
18//! # Example
19//!
20//! ```rust,ignore
21//! async fn store_config<C: KvClient>(client: &C) -> Result<()> {
22//!     client.put(b"config:timeout", b"30s").await?;
23//!     let value = client.get(b"config:timeout").await?;
24//!     Ok(())
25//! }
26//! ```
27
28use bytes::Bytes;
29
30use crate::kv_error::KvResult;
31
32/// Unified key-value store interface.
33///
34/// This trait abstracts over different client implementations, allowing applications
35/// to write generic code that works with both remote (gRPC) and embedded (local) access.
36///
37/// # Consistency Guarantees
38///
39/// - **put()**: Strong consistency, linearizable writes
40/// - **get()**: Linearizable reads by default
41/// - **delete()**: Strong consistency, linearizable deletes
42///
43/// # Thread Safety
44///
45/// All implementations must be `Send + Sync`, safe for concurrent access.
46///
47/// # Performance Characteristics
48///
49/// - `GrpcKvClient`: 1-2ms latency (network + serialization)
50/// - `LocalKvClient`: <0.1ms latency (direct function call)
51#[async_trait::async_trait]
52pub trait KvClient: Send + Sync {
53    /// Stores a key-value pair with strong consistency.
54    ///
55    /// The write is replicated to a quorum of nodes before returning,
56    /// ensuring durability and linearizability.
57    ///
58    /// # Arguments
59    ///
60    /// * `key` - The key to store (arbitrary bytes)
61    /// * `value` - The value to store (arbitrary bytes)
62    ///
63    /// # Errors
64    ///
65    /// - [`crate::kv_error::KvClientError::ChannelClosed`] if node is shutting down
66    /// - [`crate::kv_error::KvClientError::Timeout`] if operation exceeds timeout
67    /// - [`crate::kv_error::KvClientError::ServerError`] for server-side errors (e.g., not leader)
68    ///
69    /// # Example
70    ///
71    /// ```rust,ignore
72    /// client.put(b"user:1001", b"Alice").await?;
73    /// ```
74    async fn put(
75        &self,
76        key: impl AsRef<[u8]> + Send,
77        value: impl AsRef<[u8]> + Send,
78    ) -> KvResult<()>;
79
80    /// Stores a key-value pair with time-to-live (TTL).
81    ///
82    /// The key will automatically expire after `ttl_secs` seconds.
83    ///
84    /// # Arguments
85    ///
86    /// * `key` - The key to store
87    /// * `value` - The value to store
88    /// * `ttl_secs` - Time-to-live in seconds
89    ///
90    /// # Errors
91    ///
92    /// Same as [`put()`](Self::put)
93    ///
94    /// # Example
95    ///
96    /// ```rust,ignore
97    /// // Session expires after 1 hour
98    /// client.put_with_ttl(b"session:abc", b"user_data", 3600).await?;
99    /// ```
100    async fn put_with_ttl(
101        &self,
102        key: impl AsRef<[u8]> + Send,
103        value: impl AsRef<[u8]> + Send,
104        ttl_secs: u64,
105    ) -> KvResult<()>;
106
107    /// Retrieves the value associated with a key.
108    ///
109    /// Uses linearizable reads by default, ensuring the returned value
110    /// reflects all previously committed writes.
111    ///
112    /// # Arguments
113    ///
114    /// * `key` - The key to retrieve
115    ///
116    /// # Returns
117    ///
118    /// * `Ok(Some(value))` if key exists
119    /// * `Ok(None)` if key does not exist or has expired
120    /// * `Err(_)` if operation failed
121    ///
122    /// # Errors
123    ///
124    /// - [`crate::kv_error::KvClientError::ChannelClosed`] if node is shutting down
125    /// - [`crate::kv_error::KvClientError::Timeout`] if operation exceeds timeout
126    /// - [`crate::kv_error::KvClientError::ServerError`] for server-side errors
127    ///
128    /// # Example
129    ///
130    /// ```rust,ignore
131    /// match client.get(b"user:1001").await? {
132    ///     Some(value) => println!("User: {:?}", value),
133    ///     None => println!("User not found"),
134    /// }
135    /// ```
136    async fn get(
137        &self,
138        key: impl AsRef<[u8]> + Send,
139    ) -> KvResult<Option<Bytes>>;
140
141    /// Retrieves multiple keys in a single request.
142    ///
143    /// More efficient than multiple individual `get()` calls when fetching
144    /// multiple keys, as it batches the requests.
145    ///
146    /// # Arguments
147    ///
148    /// * `keys` - Slice of keys to retrieve
149    ///
150    /// # Returns
151    ///
152    /// Vector of results in the same order as input keys.
153    /// `None` for keys that don't exist.
154    ///
155    /// # Errors
156    ///
157    /// Same as [`get()`](Self::get)
158    ///
159    /// # Example
160    ///
161    /// ```rust,ignore
162    /// let keys = vec![
163    ///     Bytes::from("user:1001"),
164    ///     Bytes::from("user:1002"),
165    /// ];
166    /// let results = client.get_multi(&keys).await?;
167    /// ```
168    async fn get_multi(
169        &self,
170        keys: &[Bytes],
171    ) -> KvResult<Vec<Option<Bytes>>>;
172
173    /// Deletes a key-value pair with strong consistency.
174    ///
175    /// The deletion is replicated to a quorum before returning.
176    /// Returns successfully even if the key does not exist (idempotent).
177    ///
178    /// # Arguments
179    ///
180    /// * `key` - The key to delete
181    ///
182    /// # Errors
183    ///
184    /// - [`crate::kv_error::KvClientError::ChannelClosed`] if node is shutting down
185    /// - [`crate::kv_error::KvClientError::Timeout`] if operation exceeds timeout
186    /// - [`crate::kv_error::KvClientError::ServerError`] for server-side errors
187    ///
188    /// # Example
189    ///
190    /// ```rust,ignore
191    /// client.delete(b"temp:session_123").await?;
192    /// ```
193    async fn delete(
194        &self,
195        key: impl AsRef<[u8]> + Send,
196    ) -> KvResult<()>;
197}