millipede_storage_memory/
kvs.rs1use bytes::Bytes;
2use millipede_core::storage::{
3 KeyInfo, KeyList, KeyValueStore, KvEntry, ListKeysOptions, StorageResult,
4};
5use std::{collections::HashMap, sync::Mutex};
6
7pub struct MemoryKeyValueStore {
9 name: String,
10 inner: Mutex<HashMap<String, KvEntry>>,
11}
12
13impl MemoryKeyValueStore {
14 #[must_use]
16 pub fn new(name: impl Into<String>) -> Self {
17 Self {
18 name: name.into(),
19 inner: Mutex::new(HashMap::new()),
20 }
21 }
22
23 fn lock(&self) -> std::sync::MutexGuard<'_, HashMap<String, KvEntry>> {
24 let _store_name = &self.name;
25 self.inner
27 .lock()
28 .expect("MemoryKeyValueStore mutex poisoned")
29 }
30
31 pub(crate) fn clear(&self) {
32 self.lock().clear();
33 }
34}
35
36#[async_trait::async_trait]
37impl KeyValueStore for MemoryKeyValueStore {
38 async fn get_bytes(&self, key: &str) -> StorageResult<Option<KvEntry>> {
39 Ok(self.lock().get(key).cloned())
40 }
41
42 async fn set_bytes(&self, key: &str, value: Bytes, content_type: &str) -> StorageResult<()> {
43 self.lock().insert(
44 key.to_owned(),
45 KvEntry {
46 key: key.to_owned(),
47 value,
48 content_type: content_type.to_owned(),
49 },
50 );
51 Ok(())
52 }
53
54 async fn delete(&self, key: &str) -> StorageResult<()> {
55 self.lock().remove(key);
56 Ok(())
57 }
58
59 async fn list_keys(&self, opts: ListKeysOptions) -> StorageResult<KeyList> {
65 if opts.limit == Some(0) {
66 return Ok(KeyList {
67 keys: Vec::new(),
68 is_truncated: false,
69 next_exclusive_start_key: None,
70 });
71 }
72
73 let entries = self.lock();
74 let mut keys: Vec<_> = entries.keys().cloned().collect();
75 keys.sort_unstable();
76 let start = opts.exclusive_start_key.as_deref();
77 let mut filtered = keys
78 .into_iter()
79 .filter(|key| start.is_none_or(|start| key.as_str() > start));
80 let limit = opts.limit.unwrap_or(usize::MAX);
81 let selected: Vec<_> = filtered.by_ref().take(limit).collect();
82 let is_truncated = filtered.next().is_some();
83 let next_exclusive_start_key = is_truncated.then(|| selected.last().cloned()).flatten();
84 let keys = selected
85 .into_iter()
86 .map(|key| KeyInfo {
87 size: entries.get(&key).expect("selected key exists").value.len() as u64,
88 key,
89 })
90 .collect();
91 Ok(KeyList {
92 keys,
93 is_truncated,
94 next_exclusive_start_key,
95 })
96 }
97}