rabia_kvstore_example/
smr_impl.rs1use crate::operations::{KVOperation, KVResult, StoreError};
7use crate::store::{KVStore, KVStoreConfig, ValueEntry};
8use async_trait::async_trait;
9use rabia_core::smr::StateMachine;
10use serde::{Deserialize, Serialize};
11use std::collections::HashMap;
12
13#[derive(Debug, Clone, Serialize, Deserialize, Default)]
15pub struct KVStoreState {
16 pub data: HashMap<String, ValueEntry>,
17 pub version: u64,
18}
19
20pub struct KVStoreSMR {
22 store: KVStore,
23}
24
25impl Clone for KVStoreSMR {
26 fn clone(&self) -> Self {
27 let config = self.store.config.clone();
30
31 let new_store = tokio::task::block_in_place(|| {
33 tokio::runtime::Handle::current().block_on(async { KVStore::new(config).await })
34 })
35 .expect("Failed to create new KVStore instance");
36
37 let current_data = self.store.get_all_data();
39 let current_version = self.store.current_version();
40
41 new_store.set_all_data(current_data);
42 new_store.set_version(current_version);
43
44 Self { store: new_store }
45 }
46}
47
48impl KVStoreSMR {
49 pub async fn new(config: KVStoreConfig) -> Result<Self, StoreError> {
51 let store = KVStore::new(config).await?;
52 Ok(Self { store })
53 }
54
55 pub async fn new_default() -> Result<Self, StoreError> {
57 Self::new(KVStoreConfig::default()).await
58 }
59
60 pub fn store(&self) -> &KVStore {
62 &self.store
63 }
64}
65
66#[async_trait]
67impl StateMachine for KVStoreSMR {
68 type Command = KVOperation;
69 type Response = KVResult;
70 type State = KVStoreState;
71
72 async fn apply_command(&mut self, command: Self::Command) -> Self::Response {
73 match command {
74 KVOperation::Set { key, value } => match self.store.set(&key, &value).await {
75 Ok(result) => result,
76 Err(e) => KVResult::Error(e.to_string()),
77 },
78 KVOperation::Get { key } => match self.store.get(&key).await {
79 Ok(Some(_)) => KVResult::Success,
80 Ok(None) => KVResult::NotFound,
81 Err(e) => KVResult::Error(e.to_string()),
82 },
83 KVOperation::Delete { key } => match self.store.delete(&key).await {
84 Ok(result) => result,
85 Err(e) => KVResult::Error(e.to_string()),
86 },
87 KVOperation::Exists { key } => match self.store.exists(&key).await {
88 Ok(true) => KVResult::Success,
89 Ok(false) => KVResult::NotFound,
90 Err(e) => KVResult::Error(e.to_string()),
91 },
92 }
93 }
94
95 fn get_state(&self) -> Self::State {
96 let data = self.store.get_all_data();
98 let version = self.store.current_version();
99
100 KVStoreState { data, version }
101 }
102
103 fn set_state(&mut self, state: Self::State) {
104 self.store.set_all_data(state.data);
106 self.store.set_version(state.version);
107 }
108
109 fn serialize_state(&self) -> Vec<u8> {
110 let state = self.get_state();
111 bincode::serialize(&state).unwrap_or_default()
112 }
113
114 fn deserialize_state(&mut self, data: &[u8]) -> Result<(), Box<dyn std::error::Error>> {
115 let state: KVStoreState = bincode::deserialize(data)?;
116 self.set_state(state);
117 Ok(())
118 }
119
120 async fn apply_commands(&mut self, commands: Vec<Self::Command>) -> Vec<Self::Response> {
121 let mut responses = Vec::with_capacity(commands.len());
122 for command in commands {
123 responses.push(self.apply_command(command).await);
124 }
125 responses
126 }
127
128 fn is_deterministic(&self) -> bool {
129 true
130 }
131}
132
133#[cfg(test)]
134mod tests {
135 use super::*;
136
137 #[tokio::test]
138 async fn test_kvstore_smr_basic_operations() {
139 let mut smr = KVStoreSMR::new_default().await.unwrap();
140
141 let set_cmd = KVOperation::Set {
143 key: "test_key".to_string(),
144 value: "test_value".to_string(),
145 };
146 let result = smr.apply_command(set_cmd).await;
147 assert!(result.is_success());
148
149 let get_cmd = KVOperation::Get {
151 key: "test_key".to_string(),
152 };
153 let result = smr.apply_command(get_cmd).await;
154 assert!(result.is_success());
155
156 let exists_cmd = KVOperation::Exists {
158 key: "test_key".to_string(),
159 };
160 let result = smr.apply_command(exists_cmd).await;
161 assert!(result.is_success());
162
163 let delete_cmd = KVOperation::Delete {
165 key: "test_key".to_string(),
166 };
167 let result = smr.apply_command(delete_cmd).await;
168 assert!(result.is_success());
169
170 let get_cmd = KVOperation::Get {
172 key: "test_key".to_string(),
173 };
174 let result = smr.apply_command(get_cmd).await;
175 assert!(result.is_not_found());
176 }
177
178 #[tokio::test]
179 async fn test_kvstore_smr_state_serialization() {
180 let mut smr = KVStoreSMR::new_default().await.unwrap();
181
182 let set_cmd1 = KVOperation::Set {
184 key: "key1".to_string(),
185 value: "value1".to_string(),
186 };
187 let set_cmd2 = KVOperation::Set {
188 key: "key2".to_string(),
189 value: "value2".to_string(),
190 };
191 smr.apply_command(set_cmd1).await;
192 smr.apply_command(set_cmd2).await;
193
194 let serialized = smr.serialize_state();
196 assert!(!serialized.is_empty());
197
198 let mut new_smr = KVStoreSMR::new_default().await.unwrap();
200 new_smr.deserialize_state(&serialized).unwrap();
201
202 let state = new_smr.get_state();
204 assert_eq!(state.data.len(), 2);
205 assert!(state.data.contains_key("key1"));
206 assert!(state.data.contains_key("key2"));
207 assert_eq!(state.data["key1"].value, "value1");
208 assert_eq!(state.data["key2"].value, "value2");
209 }
210
211 #[tokio::test]
212 async fn test_kvstore_smr_multiple_commands() {
213 let mut smr = KVStoreSMR::new_default().await.unwrap();
214
215 let commands = vec![
216 KVOperation::Set {
217 key: "key1".to_string(),
218 value: "value1".to_string(),
219 },
220 KVOperation::Set {
221 key: "key2".to_string(),
222 value: "value2".to_string(),
223 },
224 KVOperation::Get {
225 key: "key1".to_string(),
226 },
227 KVOperation::Delete {
228 key: "key2".to_string(),
229 },
230 KVOperation::Get {
231 key: "key2".to_string(),
232 },
233 ];
234
235 let responses = smr.apply_commands(commands).await;
236 assert_eq!(responses.len(), 5);
237 assert!(responses[0].is_success()); assert!(responses[1].is_success()); assert!(responses[2].is_success()); assert!(responses[3].is_success()); assert!(responses[4].is_not_found()); }
243}