sim_lib_journal/
memory.rs1use crate::{
2 Admission, JournalBackend, JournalError, JournalHead, JournalObject, Lease, StoredDatumRef,
3 StoredState,
4};
5use sim_kernel::{ContentId, Datum};
6use std::sync::{Mutex, PoisonError};
7
8#[derive(Default)]
9struct Inner {
10 fence: u64,
11 state: StoredState,
12}
13
14#[derive(Default)]
16pub struct MemoryBackend {
17 inner: Mutex<Inner>,
18}
19
20impl MemoryBackend {
21 pub fn new() -> Self {
22 Self::default()
23 }
24}
25
26impl JournalBackend for MemoryBackend {
27 fn acquire_lease(&self) -> Result<Lease, JournalError> {
28 let mut inner = self
29 .inner
30 .lock()
31 .map_err(|_: PoisonError<_>| JournalError::Backend("memory lock poisoned".into()))?;
32 inner.fence = inner
33 .fence
34 .checked_add(1)
35 .ok_or_else(|| JournalError::Backend("fence exhausted".into()))?;
36 Ok(Lease { fence: inner.fence })
37 }
38 fn read_state(&self) -> Result<StoredState, JournalError> {
39 Ok(self
40 .inner
41 .lock()
42 .map_err(|_: PoisonError<_>| JournalError::Backend("memory lock poisoned".into()))?
43 .state
44 .clone())
45 }
46 fn admit(&self, admission: Admission) -> Result<JournalHead, JournalError> {
47 let mut inner = self
48 .inner
49 .lock()
50 .map_err(|_: PoisonError<_>| JournalError::Backend("memory lock poisoned".into()))?;
51 if admission.fence != inner.fence {
52 return Err(JournalError::StaleLease);
53 }
54 if admission.expected != inner.state.head {
55 let exact = admission
58 .entries
59 .iter()
60 .all(|entry| inner.state.entries.get(&entry.sequence) == Some(entry))
61 && !admission.entries.is_empty();
62 if exact {
63 return inner.state.head.clone().ok_or(JournalError::WrongHead);
64 }
65 if admission
66 .entries
67 .iter()
68 .any(|entry| inner.state.entries.contains_key(&entry.sequence))
69 {
70 return Err(JournalError::ConflictingDelivery);
71 }
72 return Err(JournalError::WrongHead);
73 }
74 for object in admission.objects {
75 match inner.state.objects.get(&object.id) {
76 Some(bytes) if bytes != &object.bytes => {
77 return Err(JournalError::ConflictingObject);
78 }
79 Some(_) => {}
80 None => {
81 inner
82 .state
83 .datums
84 .insert(object.id.clone(), object.datum().clone());
85 inner.state.objects.insert(object.id, object.bytes);
86 }
87 }
88 }
89 for entry in admission.entries {
90 match inner.state.entries.get(&entry.sequence) {
91 Some(existing) if existing == &entry => {}
92 Some(_) => return Err(JournalError::ConflictingDelivery),
93 None => {
94 inner.state.entries.insert(entry.sequence, entry);
95 }
96 }
97 }
98 let entry = inner
99 .state
100 .entries
101 .last_key_value()
102 .ok_or(JournalError::EmptyBatch)?
103 .1;
104 let head = JournalHead {
105 sequence: entry.sequence,
106 entry: entry.id.clone(),
107 };
108 inner.state.head = Some(head.clone());
109 Ok(head)
110 }
111
112 fn put_datum(&self, object: JournalObject) -> Result<StoredDatumRef, JournalError> {
113 object.verify()?;
114 let storage_bytes = object.storage_bytes()?;
115 let reference = StoredDatumRef {
116 meaning: object.id.clone(),
117 storage: crate::object::storage_id(&storage_bytes),
118 };
119 let mut inner = self
120 .inner
121 .lock()
122 .map_err(|_: PoisonError<_>| JournalError::Backend("memory lock poisoned".into()))?;
123 match inner.state.datums.get(&object.id) {
124 Some(value) if value != object.datum() => return Err(JournalError::ConflictingObject),
125 _ => {
126 let datum = object.datum().clone();
127 inner.state.objects.insert(object.id.clone(), object.bytes);
128 inner.state.datums.insert(object.id, datum);
129 }
130 }
131 Ok(reference)
132 }
133
134 fn get_datum(&self, meaning: &ContentId) -> Result<Datum, JournalError> {
135 self.inner
136 .lock()
137 .map_err(|_: PoisonError<_>| JournalError::Backend("memory lock poisoned".into()))?
138 .state
139 .datums
140 .get(meaning)
141 .cloned()
142 .ok_or_else(|| JournalError::MissingSemanticObject(meaning.clone()))
143 }
144
145 fn rebuild_datum_index(&self) -> Result<Vec<StoredDatumRef>, JournalError> {
146 let inner = self
147 .inner
148 .lock()
149 .map_err(|_: PoisonError<_>| JournalError::Backend("memory lock poisoned".into()))?;
150 inner
151 .state
152 .datums
153 .iter()
154 .map(|(meaning, datum)| {
155 let object = JournalObject::from_datum(datum.clone())?;
156 let bytes = object.storage_bytes()?;
157 Ok(StoredDatumRef {
158 meaning: meaning.clone(),
159 storage: crate::object::storage_id(&bytes),
160 })
161 })
162 .collect()
163 }
164}