1use crate::key::check_prefix;
12use crate::{clip, Bytes, Cond, Error, Key, Meta, Object, ObjectStore, Result};
13use std::collections::{BTreeMap, VecDeque};
14use std::future::{ready, Ready};
15use std::ops::Range;
16use std::sync::Mutex;
17
18#[derive(Debug)]
20#[non_exhaustive]
21pub enum Fault {
22 Pass,
25 Fail(Error),
27 LostResponse(Error),
29}
30
31#[derive(Debug, Default)]
32struct Inner {
33 objects: BTreeMap<String, Object>,
34 next_generation: u64,
35 faults: VecDeque<Fault>,
36 ops: u64,
37}
38
39#[derive(Debug, Default)]
42pub struct Mem {
43 inner: Mutex<Inner>,
44}
45
46impl Mem {
47 pub fn inject(&self, fault: Fault) {
49 self.lock().faults.push_back(fault);
50 }
51
52 pub fn inject_after(&self, skip: u64, fault: Fault) {
55 let mut g = self.lock();
56 for _ in 0..skip {
57 g.faults.push_back(Fault::Pass);
58 }
59 g.faults.push_back(fault);
60 }
61
62 pub fn clear_faults(&self) {
64 self.lock().faults.clear();
65 }
66
67 #[must_use]
69 pub fn ops(&self) -> u64 {
70 self.lock().ops
71 }
72
73 #[must_use]
75 pub fn keys(&self) -> Vec<String> {
76 self.lock().objects.keys().cloned().collect()
77 }
78
79 fn lock(&self) -> std::sync::MutexGuard<'_, Inner> {
80 self.inner.lock().unwrap_or_else(std::sync::PoisonError::into_inner)
84 }
85
86 fn run<T>(&self, op: impl FnOnce(&mut Inner) -> Result<T>) -> Result<T> {
87 let mut g = self.lock();
88 g.ops += 1;
89 match g.faults.pop_front() {
90 Some(Fault::Fail(e)) => Err(e),
91 Some(Fault::LostResponse(e)) => {
92 let _ = op(&mut g);
93 Err(e)
94 }
95 Some(Fault::Pass) | None => op(&mut g),
96 }
97 }
98}
99
100impl ObjectStore for Mem {
101 type Get<'a> = Ready<Result<Option<Object>>>;
102 type GetRange<'a> = Ready<Result<Bytes>>;
103 type Head<'a> = Ready<Result<Option<Meta>>>;
104 type Put<'a> = Ready<Result<u64>>;
105 type List<'a> = Ready<Result<Vec<Meta>>>;
106 type Delete<'a> = Ready<Result<()>>;
107
108 fn get<'a>(&'a self, key: &'a str) -> Self::Get<'a> {
109 ready(Key::parse(key).and_then(|k| self.run(|g| Ok(g.objects.get(k.as_str()).cloned()))))
110 }
111
112 fn get_range<'a>(&'a self, key: &'a str, range: Range<u64>) -> Self::GetRange<'a> {
113 ready(Key::parse(key).and_then(|k| {
114 self.run(|g| {
115 let o = g.objects.get(k.as_str()).ok_or(Error::NotFound)?;
116 Ok(o.bytes.slice(clip(&range, o.bytes.len() as u64)))
117 })
118 }))
119 }
120
121 fn head<'a>(&'a self, key: &'a str) -> Self::Head<'a> {
122 ready(Key::parse(key).and_then(|k| {
123 self.run(|g| {
124 Ok(g.objects.get(k.as_str()).map(|o| Meta {
125 key: k.as_str().to_owned(),
126 size: o.bytes.len() as u64,
127 generation: o.generation,
128 }))
129 })
130 }))
131 }
132
133 fn put<'a>(&'a self, key: &'a str, body: Bytes, cond: Cond) -> Self::Put<'a> {
134 ready(Key::parse(key).and_then(|k| {
135 self.run(|g| {
136 let current = g.objects.get(k.as_str()).map(|o| o.generation);
137 match (cond, current) {
138 (Cond::CreateOnly, Some(_)) => return Err(Error::Conflict),
139 (Cond::IfGeneration(want), cur) if cur != Some(want) => {
140 return Err(Error::PreconditionFailed)
141 }
142 _ => {}
143 }
144 g.next_generation += 1;
145 let generation = g.next_generation;
146 g.objects.insert(k.as_str().to_owned(), Object { bytes: body, generation });
147 Ok(generation)
148 })
149 }))
150 }
151
152 fn list<'a>(&'a self, prefix: &'a str) -> Self::List<'a> {
153 ready(check_prefix(prefix).and_then(|()| {
154 self.run(|g| {
155 Ok(g.objects
156 .range(prefix.to_owned()..)
157 .take_while(|(k, _)| k.starts_with(prefix))
158 .map(|(k, o)| Meta {
159 key: k.clone(),
160 size: o.bytes.len() as u64,
161 generation: o.generation,
162 })
163 .collect())
164 })
165 }))
166 }
167
168 fn delete<'a>(&'a self, key: &'a str) -> Self::Delete<'a> {
169 ready(Key::parse(key).and_then(|k| {
170 self.run(|g| {
171 g.objects.remove(k.as_str());
172 Ok(())
173 })
174 }))
175 }
176}
177
178#[cfg(test)]
179mod tests {
180 use super::*;
181
182 #[test]
183 fn inject_after_targets_the_nth_operation() {
184 let m = Mem::default();
185 m.inject_after(2, Fault::Fail(Error::unavailable("boom", true)));
186 let put = |k| futures::executor::block_on(m.put(k, Bytes::new(), Cond::None));
187 assert!(put("a").is_ok());
188 assert!(put("b").is_ok());
189 assert!(put("c").is_err());
190 assert!(put("d").is_ok());
191 }
192 use futures::executor::block_on;
193
194 #[test]
195 fn faults_apply_in_order() {
196 let m = Mem::default();
197 m.inject(Fault::LostResponse(Error::unavailable("lost", true)));
198 m.inject(Fault::Fail(Error::unavailable("down", true)));
199 assert!(block_on(m.put("a", Bytes::from_static(b"1"), Cond::CreateOnly)).is_err());
200 assert_eq!(block_on(m.get("a")).unwrap_err().to_string(), "store unavailable: down");
201 assert!(block_on(m.get("a")).unwrap().is_some(), "the lost-response write was applied");
202 assert!(matches!(
203 block_on(m.put("a", Bytes::new(), Cond::CreateOnly)),
204 Err(Error::Conflict)
205 ));
206 assert_eq!(m.ops(), 4);
207 }
208}