hightower_kv/
replication.rs1use std::sync::Arc;
2
3use crate::command::Command;
4use crate::engine::{KvEngine, SnapshotEngine};
5use crate::error::{Error, Result};
6use crate::state::{ApplyOutcome, KvState};
7
8pub trait CommandSubmitter: Send + Sync {
10 fn submit(&self, command: Command) -> Result<ApplyOutcome>;
12
13 fn submit_batch<I>(&self, commands: I) -> Result<Vec<ApplyOutcome>>
15 where
16 I: IntoIterator<Item = Command>;
17}
18
19pub trait SnapshotProvider: Send + Sync {
21 fn snapshot_state(&self) -> Result<KvState>;
23 fn latest_version(&self) -> Result<u64>;
25}
26
27pub trait ReplicationHandle: CommandSubmitter + SnapshotProvider {}
29
30impl<T> ReplicationHandle for T where T: CommandSubmitter + SnapshotProvider {}
31
32#[derive(Debug)]
34pub struct NullReplication;
35
36impl CommandSubmitter for NullReplication {
37 fn submit(&self, _command: Command) -> Result<ApplyOutcome> {
38 Err(Error::Unimplemented("replication::submit"))
39 }
40
41 fn submit_batch<I>(&self, _commands: I) -> Result<Vec<ApplyOutcome>>
42 where
43 I: IntoIterator<Item = Command>,
44 {
45 Err(Error::Unimplemented("replication::submit_batch"))
46 }
47}
48
49impl SnapshotProvider for NullReplication {
50 fn snapshot_state(&self) -> Result<KvState> {
51 Err(Error::Unimplemented("replication::latest_snapshot"))
52 }
53
54 fn latest_version(&self) -> Result<u64> {
55 Err(Error::Unimplemented("replication::latest_version"))
56 }
57}
58
59#[derive(Debug, Clone)]
61pub struct LocalReplication<E>
62where
63 E: KvEngine + SnapshotEngine,
64{
65 engine: Arc<E>,
66}
67
68impl<E> LocalReplication<E>
69where
70 E: KvEngine + SnapshotEngine,
71{
72 pub fn new(engine: Arc<E>) -> Self {
74 Self { engine }
75 }
76}
77
78impl<E> CommandSubmitter for LocalReplication<E>
79where
80 E: KvEngine + SnapshotEngine,
81{
82 fn submit(&self, command: Command) -> Result<ApplyOutcome> {
83 self.engine.submit(command)
84 }
85
86 fn submit_batch<I>(&self, commands: I) -> Result<Vec<ApplyOutcome>>
87 where
88 I: IntoIterator<Item = Command>,
89 {
90 self.engine.submit_batch(commands)
91 }
92}
93
94impl<E> SnapshotProvider for LocalReplication<E>
95where
96 E: KvEngine + SnapshotEngine,
97{
98 fn snapshot_state(&self) -> Result<KvState> {
99 Ok(self.engine.snapshot_state())
100 }
101
102 fn latest_version(&self) -> Result<u64> {
103 Ok(self.engine.latest_version())
104 }
105}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110 use crate::config::StoreConfig;
111 use crate::engine::{SingleNodeEngine, SnapshotEngine};
112 use tempfile::tempdir;
113
114 #[test]
115 fn submit_returns_unimplemented() {
116 let repl = NullReplication;
117 let err = repl
118 .submit(Command::Delete {
119 key: b"k".to_vec(),
120 version: 0,
121 timestamp: 0,
122 })
123 .unwrap_err();
124 assert!(matches!(err, Error::Unimplemented("replication::submit")));
125 }
126
127 #[test]
128 fn local_replication_forwards_calls() {
129 let temp = tempdir().unwrap();
130 let mut cfg = StoreConfig::default();
131 cfg.data_dir = temp.path().join("repl").to_string_lossy().into_owned();
132 let engine = Arc::new(SingleNodeEngine::with_config(cfg).unwrap());
133 let repl = LocalReplication::new(Arc::clone(&engine));
134
135 repl.submit(Command::Set {
136 key: b"k".to_vec(),
137 value: b"v".to_vec(),
138 version: engine.latest_version() + 1,
139 timestamp: 1,
140 })
141 .unwrap();
142
143 let snapshot = repl.snapshot_state().unwrap();
144 assert_eq!(snapshot.get(b"k"), Some(&b"v"[..]));
145 }
146}