1use crate::Result;
2use async_trait::async_trait;
3use std::time::Duration;
4
5#[async_trait]
16pub trait StateManager: Send + Sync {
17 async fn get(&self, key: &str) -> Result<Option<Vec<u8>>>;
19
20 async fn set(&self, key: &str, value: Vec<u8>, ttl: Option<Duration>) -> Result<()>;
22
23 async fn delete(&self, key: &str) -> Result<()>;
25
26 async fn exists(&self, key: &str) -> Result<bool>;
28}
29
30struct StateEntry {
32 value: Vec<u8>,
33 expires_at: Option<tokio::time::Instant>,
34}
35
36pub struct MemoryStateManager {
41 store: dashmap::DashMap<String, StateEntry>,
42}
43
44impl MemoryStateManager {
45 #[must_use]
47 pub fn new() -> Self {
48 Self {
49 store: dashmap::DashMap::new(),
50 }
51 }
52}
53
54impl Default for MemoryStateManager {
55 fn default() -> Self {
56 Self::new()
57 }
58}
59
60#[async_trait]
61impl StateManager for MemoryStateManager {
62 async fn get(&self, key: &str) -> Result<Option<Vec<u8>>> {
63 if let Some(entry) = self.store.get(key) {
64 if let Some(expires_at) = entry.expires_at {
66 if tokio::time::Instant::now() >= expires_at {
67 drop(entry); self.store.remove(key);
70 return Ok(None);
71 }
72 }
73 Ok(Some(entry.value.clone()))
74 } else {
75 Ok(None)
76 }
77 }
78
79 async fn set(&self, key: &str, value: Vec<u8>, ttl: Option<Duration>) -> Result<()> {
80 let expires_at = ttl.map(|d| tokio::time::Instant::now() + d);
81 self.store
82 .insert(key.to_string(), StateEntry { value, expires_at });
83 Ok(())
84 }
85
86 async fn delete(&self, key: &str) -> Result<()> {
87 self.store.remove(key);
88 Ok(())
89 }
90
91 async fn exists(&self, key: &str) -> Result<bool> {
92 if let Some(entry) = self.store.get(key) {
93 if let Some(expires_at) = entry.expires_at {
95 if tokio::time::Instant::now() >= expires_at {
96 drop(entry);
97 self.store.remove(key);
98 return Ok(false);
99 }
100 }
101 Ok(true)
102 } else {
103 Ok(false)
104 }
105 }
106}
107
108#[cfg(feature = "persistence")]
110pub use trueno_kv::TruenoKvStateManager;
111
112#[cfg(feature = "persistence")]
113mod trueno_kv {
114 use super::*;
115 use crate::Error;
116 use tokio::time::Instant;
117 use trueno_db::kv::{KvStore, MemoryKvStore};
122
123 pub struct TruenoKvStateManager {
131 store: MemoryKvStore,
132 expirations: dashmap::DashMap<String, Instant>,
134 }
135
136 impl TruenoKvStateManager {
137 #[must_use]
139 pub fn new() -> Self {
140 Self {
141 store: MemoryKvStore::new(),
142 expirations: dashmap::DashMap::new(),
143 }
144 }
145
146 #[must_use]
148 pub fn with_capacity(capacity: usize) -> Self {
149 Self {
150 store: MemoryKvStore::with_capacity(capacity),
151 expirations: dashmap::DashMap::new(),
152 }
153 }
154
155 fn is_expired(&self, key: &str) -> bool {
157 let expired = if let Some(expires_at) = self.expirations.get(key) {
159 Instant::now() >= *expires_at
160 } else {
161 return false;
162 };
163 if expired {
165 self.expirations.remove(key);
166 }
167 expired
168 }
169
170 #[must_use]
172 pub fn len(&self) -> usize {
173 self.store.len()
174 }
175
176 #[must_use]
178 pub fn is_empty(&self) -> bool {
179 self.store.is_empty()
180 }
181
182 pub fn clear(&self) {
184 self.store.clear();
185 }
186
187 #[cfg(test)]
190 pub(crate) fn set_expiration_for_test(&self, key: &str, expires_at: Instant) {
191 self.expirations.insert(key.to_string(), expires_at);
192 }
193 }
194
195 impl Default for TruenoKvStateManager {
196 fn default() -> Self {
197 Self::new()
198 }
199 }
200
201 #[async_trait]
202 impl StateManager for TruenoKvStateManager {
203 async fn get(&self, key: &str) -> Result<Option<Vec<u8>>> {
204 if self.is_expired(key) {
206 return Ok(None);
209 }
210
211 self.store
212 .get(key)
213 .await
214 .map_err(|e| Error::StateError(e.to_string()))
215 }
216
217 async fn set(&self, key: &str, value: Vec<u8>, ttl: Option<Duration>) -> Result<()> {
218 if let Some(duration) = ttl {
220 let expires_at = Instant::now() + duration;
221 self.expirations.insert(key.to_string(), expires_at);
222 } else {
223 self.expirations.remove(key);
225 }
226
227 self.store
228 .set(key, value)
229 .await
230 .map_err(|e| Error::StateError(e.to_string()))
231 }
232
233 async fn delete(&self, key: &str) -> Result<()> {
234 self.expirations.remove(key);
236
237 self.store
238 .delete(key)
239 .await
240 .map_err(|e| Error::StateError(e.to_string()))
241 }
242
243 async fn exists(&self, key: &str) -> Result<bool> {
244 if self.is_expired(key) {
246 return Ok(false);
249 }
250
251 self.store
252 .exists(key)
253 .await
254 .map_err(|e| Error::StateError(e.to_string()))
255 }
256 }
257}
258
259#[cfg(test)]
260mod tests {
261 use super::*;
262
263 #[tokio::test]
264 async fn test_memory_state_basic() {
265 let state = MemoryStateManager::new();
266
267 state.set("key1", b"value1".to_vec(), None).await.unwrap();
269 let value = state.get("key1").await.unwrap();
270 assert_eq!(value, Some(b"value1".to_vec()));
271
272 assert!(state.exists("key1").await.unwrap());
274 assert!(!state.exists("key2").await.unwrap());
275
276 state.delete("key1").await.unwrap();
278 assert!(!state.exists("key1").await.unwrap());
279 }
280
281 #[tokio::test]
282 async fn test_memory_state_overwrite() {
283 let state = MemoryStateManager::new();
284
285 state.set("key", b"value1".to_vec(), None).await.unwrap();
286 state.set("key", b"value2".to_vec(), None).await.unwrap();
287
288 let value = state.get("key").await.unwrap();
289 assert_eq!(value, Some(b"value2".to_vec()));
290 }
291
292 #[tokio::test]
293 async fn test_memory_state_concurrent() {
294 use std::sync::Arc;
295
296 let state = Arc::new(MemoryStateManager::new());
297 let mut handles = vec![];
298
299 for i in 0..10 {
300 let state = Arc::clone(&state);
301 handles.push(tokio::spawn(async move {
302 let key = format!("key{i}");
303 let value = format!("value{i}").into_bytes();
304 state.set(&key, value, None).await.unwrap();
305 }));
306 }
307
308 for handle in handles {
309 handle.await.unwrap();
310 }
311
312 for i in 0..10 {
313 let key = format!("key{i}");
314 assert!(state.exists(&key).await.unwrap());
315 }
316 }
317
318 #[tokio::test(start_paused = true)]
319 async fn test_memory_state_ttl_expiration() {
320 let state = MemoryStateManager::new();
321
322 state
324 .set(
325 "ttl_key",
326 b"value".to_vec(),
327 Some(Duration::from_millis(50)),
328 )
329 .await
330 .unwrap();
331
332 assert!(state.exists("ttl_key").await.unwrap());
334 assert_eq!(state.get("ttl_key").await.unwrap(), Some(b"value".to_vec()));
335
336 tokio::time::advance(Duration::from_millis(60)).await;
338
339 assert!(!state.exists("ttl_key").await.unwrap());
341 assert_eq!(state.get("ttl_key").await.unwrap(), None);
342 }
343
344 #[tokio::test(start_paused = true)]
345 async fn test_memory_state_ttl_no_expiration() {
346 let state = MemoryStateManager::new();
347
348 state.set("no_ttl", b"value".to_vec(), None).await.unwrap();
350
351 tokio::time::advance(Duration::from_millis(10)).await;
353
354 assert!(state.exists("no_ttl").await.unwrap());
356 assert_eq!(state.get("no_ttl").await.unwrap(), Some(b"value".to_vec()));
357 }
358
359 #[tokio::test(start_paused = true)]
360 async fn test_memory_state_ttl_overwrite_extends() {
361 let state = MemoryStateManager::new();
362
363 state
365 .set("key", b"v1".to_vec(), Some(Duration::from_millis(30)))
366 .await
367 .unwrap();
368
369 tokio::time::advance(Duration::from_millis(20)).await;
371
372 state
374 .set("key", b"v2".to_vec(), Some(Duration::from_millis(100)))
375 .await
376 .unwrap();
377
378 tokio::time::advance(Duration::from_millis(20)).await;
380
381 assert_eq!(state.get("key").await.unwrap(), Some(b"v2".to_vec()));
383 }
384
385 #[cfg(feature = "persistence")]
387 mod trueno_kv_tests {
388 use super::*;
389 use crate::state::TruenoKvStateManager;
390
391 #[tokio::test]
392 async fn test_trueno_kv_basic() {
393 let state = TruenoKvStateManager::new();
394
395 state.set("key1", b"value1".to_vec(), None).await.unwrap();
397 let value = state.get("key1").await.unwrap();
398 assert_eq!(value, Some(b"value1".to_vec()));
399
400 assert!(state.exists("key1").await.unwrap());
402 assert!(!state.exists("key2").await.unwrap());
403
404 state.delete("key1").await.unwrap();
406 assert!(!state.exists("key1").await.unwrap());
407 }
408
409 #[tokio::test]
410 async fn test_trueno_kv_overwrite() {
411 let state = TruenoKvStateManager::new();
412
413 state.set("key", b"value1".to_vec(), None).await.unwrap();
414 state.set("key", b"value2".to_vec(), None).await.unwrap();
415
416 let value = state.get("key").await.unwrap();
417 assert_eq!(value, Some(b"value2".to_vec()));
418 }
419
420 #[tokio::test]
421 async fn test_trueno_kv_with_capacity() {
422 let state = TruenoKvStateManager::with_capacity(100);
423 state.set("key", b"value".to_vec(), None).await.unwrap();
424 assert_eq!(state.get("key").await.unwrap(), Some(b"value".to_vec()));
425 }
426
427 #[tokio::test]
428 async fn test_trueno_kv_len_and_clear() {
429 let state = TruenoKvStateManager::new();
430
431 assert!(state.is_empty());
432 assert_eq!(state.len(), 0);
433
434 state.set("key1", b"value1".to_vec(), None).await.unwrap();
435 assert!(!state.is_empty());
436 assert_eq!(state.len(), 1);
437
438 state.set("key2", b"value2".to_vec(), None).await.unwrap();
439 assert_eq!(state.len(), 2);
440
441 state.clear();
442 assert!(state.is_empty());
443 }
444
445 #[test]
446 fn test_trueno_kv_default() {
447 let state: TruenoKvStateManager = Default::default();
448 assert!(state.is_empty());
449 }
450
451 #[tokio::test]
452 async fn test_trueno_kv_ttl_expiration() {
453 use tokio::time::Instant;
454
455 let state = TruenoKvStateManager::new();
456
457 state
459 .set("ttl_key", b"value".to_vec(), None)
460 .await
461 .expect("set should succeed");
462
463 assert!(state
465 .exists("ttl_key")
466 .await
467 .expect("exists check should succeed"));
468
469 state.set_expiration_for_test("ttl_key", Instant::now());
472
473 tokio::task::yield_now().await;
475
476 assert!(!state
479 .exists("ttl_key")
480 .await
481 .expect("exists check should succeed"));
482 }
483
484 #[tokio::test]
485 async fn test_trueno_kv_ttl_no_expiration() {
486 use tokio::time::Instant;
487
488 let state = TruenoKvStateManager::new();
489
490 state
492 .set("no_ttl", b"value".to_vec(), None)
493 .await
494 .expect("set should succeed");
495
496 let future = Instant::now() + Duration::from_secs(3600);
498 state.set_expiration_for_test("no_ttl", future);
499
500 assert!(state
502 .exists("no_ttl")
503 .await
504 .expect("exists check should succeed"));
505 assert_eq!(
506 state.get("no_ttl").await.expect("get should succeed"),
507 Some(b"value".to_vec())
508 );
509 }
510 }
511}