1use std::borrow::Borrow;
10use std::collections::BTreeMap;
11use std::sync::Arc;
12
13use parking_lot::Mutex;
14use uqa_core::memory::{BudgetedVec, MemoryBudget, MemoryReservation};
15
16use crate::read_control::StorageReadControl;
17
18use super::key::RecordKey;
19use super::{
20 CommitSequence, CommittedRecordSnapshot, PreparedRecordCommit, RecordHistory, RecordVersion,
21 RecordWrite, ScannedRecord, SharedRecordValue, VersionResult,
22};
23
24type History = RecordHistory<SharedRecordValue>;
25
26struct RecordEntry {
27 history: History,
28 _memory: MemoryReservation,
29}
30
31#[derive(Default)]
32struct State {
33 sequence: CommitSequence,
34 records: BTreeMap<RecordKey, RecordEntry>,
35 snapshots: BTreeMap<CommitSequence, usize>,
36}
37
38struct Database {
39 state: Mutex<State>,
40 memory: MemoryBudget,
41}
42
43#[derive(Clone)]
47pub struct MemoryVersionStore {
48 database: Arc<Database>,
49}
50
51impl MemoryVersionStore {
52 pub fn new(memory: &MemoryBudget) -> Self {
53 Self {
54 database: Arc::new(Database {
55 state: Mutex::new(State::default()),
56 memory: memory.clone(),
57 }),
58 }
59 }
60
61 pub fn snapshot(&self) -> VersionResult<MemoryRecordSnapshot> {
62 let memory = self
63 .database
64 .memory
65 .reserve(std::mem::size_of::<MemoryRecordSnapshot>())?;
66 let mut state = self.database.state.lock();
67 let sequence = state.sequence;
68 let count = state.snapshots.entry(sequence).or_default();
69 *count = count
70 .checked_add(1)
71 .ok_or(uqa_core::memory::MemoryError::SizeOverflow)?;
72 Ok(MemoryRecordSnapshot {
73 database: Arc::clone(&self.database),
74 sequence,
75 _memory: memory,
76 })
77 }
78
79 pub fn commit(
83 &self,
84 writes: &[RecordWrite<'_>],
85 control: &StorageReadControl,
86 ) -> VersionResult<CommitSequence> {
87 let preparation = StorageReadControl::new(&self.database.memory, control.cancellation());
88 let prepared = PreparedRecordCommit::new(writes, &preparation)?;
89 self.commit_prepared(&prepared, control)
90 }
91
92 pub fn commit_prepared(
93 &self,
94 commit: &PreparedRecordCommit,
95 control: &StorageReadControl,
96 ) -> VersionResult<CommitSequence> {
97 control.cancellation().check()?;
98 let values = self.retain_values(commit, control)?;
99 let mut state = self.database.state.lock();
100 commit.validate_snapshot(state.sequence)?;
101 let writes = commit.records();
102 let validate = || {
103 commit.validate(control.cancellation(), |key| {
104 Ok(state
105 .records
106 .get(key)
107 .and_then(|entry| entry.history.head())
108 .map(RecordVersion::sequence))
109 })
110 };
111 if writes.is_empty() {
112 validate()?;
113 return Ok(state.sequence);
114 }
115 let sequence = state.sequence.successor()?;
116 validate()?;
117 let mut prepared = BudgetedVec::new(&self.database.memory);
118 prepared.reserve(writes.len())?;
119 for (write, value) in writes.iter().zip(values.iter()) {
120 control.cancellation().check()?;
121 let key = RecordKey::new(write.key(), &self.database.memory)?;
122 let value = value.clone();
123 let history = if let Some(entry) = state.records.get(write.key()) {
124 entry.history.fork_appending(sequence, value)?
125 } else {
126 let mut history = History::new(&self.database.memory);
127 history.append(sequence, value)?;
128 history
129 };
130 let memory = self
131 .database
132 .memory
133 .reserve(std::mem::size_of::<(RecordKey, RecordEntry)>())?;
134 prepared.push((
135 key,
136 RecordEntry {
137 history,
138 _memory: memory,
139 },
140 ))?;
141 }
142 control.cancellation().check()?;
143 while let Some((key, entry)) = prepared.pop() {
146 state.records.insert(key, entry);
147 }
148 state.sequence = sequence;
149 Ok(sequence)
150 }
151
152 fn retain_values(
153 &self,
154 commit: &PreparedRecordCommit,
155 control: &StorageReadControl,
156 ) -> VersionResult<BudgetedVec<Option<SharedRecordValue>>> {
157 let mut values = BudgetedVec::new(&self.database.memory);
158 values.reserve(commit.records().len())?;
159 for write in commit.records() {
160 control.cancellation().check()?;
161 let mut value = write.shared_value();
162 if let Some(source) = value
163 .as_ref()
164 .filter(|value| !value.budget().shares_allowance(&self.database.memory))
165 {
166 let mut owned = BudgetedVec::new(&self.database.memory);
167 owned.reserve(source.len())?;
168 for chunk in source.chunks(65536) {
169 control.cancellation().check()?;
170 owned.extend_from_slice(chunk)?;
171 }
172 value = Some(Arc::new(owned));
173 }
174 values.push(value)?;
175 }
176 Ok(values)
177 }
178
179 pub fn reclaim(&self) -> VersionResult<usize> {
181 let mut state = self.database.state.lock();
182 let horizon = state
183 .snapshots
184 .first_key_value()
185 .map_or(state.sequence, |(sequence, _)| *sequence);
186 state.records.values_mut().try_fold(0, |removed, entry| {
187 Ok(removed + entry.history.reclaim_before(horizon)?)
188 })
189 }
190}
191
192pub struct MemoryRecordSnapshot {
194 database: Arc<Database>,
195 sequence: CommitSequence,
196 _memory: MemoryReservation,
197}
198
199impl MemoryRecordSnapshot {
200 pub fn sequence(&self) -> CommitSequence {
201 self.sequence
202 }
203
204 pub fn get(&self, key: &[u8]) -> Option<RecordVersion<SharedRecordValue>> {
206 self.database
207 .state
208 .lock()
209 .records
210 .get(key)
211 .and_then(|entry| entry.history.visible_at(self.sequence))
212 .cloned()
213 }
214
215 pub fn scan(
217 &self,
218 prefix: &[u8],
219 after: Option<&[u8]>,
220 limit: usize,
221 control: &StorageReadControl,
222 ) -> VersionResult<BudgetedVec<ScannedRecord>> {
223 control.cancellation().check()?;
224 let mut result = BudgetedVec::new(control.memory());
225 if limit == 0 {
226 return Ok(result);
227 }
228 let state = self.database.state.lock();
229 let start = after.filter(|after| *after >= prefix).unwrap_or(prefix);
230 for (key, entry) in state
231 .records
232 .range::<[u8], _>((std::ops::Bound::Included(start), std::ops::Bound::Unbounded))
233 {
234 control.cancellation().check()?;
235 let bytes: &[u8] = key.borrow();
236 if !bytes.starts_with(prefix) {
237 break;
238 }
239 if after.is_some_and(|after| bytes <= after) {
240 continue;
241 }
242 let Some(version) = entry.history.visible_at(self.sequence) else {
243 continue;
244 };
245 result.push(ScannedRecord {
246 key: copy_bytes(bytes, control.memory())?,
247 version: version.clone(),
248 })?;
249 if result.len() == limit {
250 break;
251 }
252 }
253 Ok(result)
254 }
255}
256
257impl CommittedRecordSnapshot for MemoryRecordSnapshot {
258 fn sequence(&self) -> CommitSequence {
259 Self::sequence(self)
260 }
261
262 fn get(
263 &self,
264 key: &[u8],
265 control: &StorageReadControl,
266 ) -> VersionResult<Option<RecordVersion<SharedRecordValue>>> {
267 control.cancellation().check()?;
268 Ok(Self::get(self, key))
269 }
270
271 fn scan(
272 &self,
273 prefix: &[u8],
274 after: Option<&[u8]>,
275 limit: usize,
276 control: &StorageReadControl,
277 ) -> VersionResult<BudgetedVec<ScannedRecord>> {
278 Self::scan(self, prefix, after, limit, control)
279 }
280
281 fn visit_prefix(
282 &self,
283 prefix: &[u8],
284 after: Option<&[u8]>,
285 limit: usize,
286 control: &StorageReadControl,
287 visit: &mut super::RecordScanVisitor<'_>,
288 ) -> VersionResult<()> {
289 control.cancellation().check()?;
290 if limit == 0 {
291 return Ok(());
292 }
293 let state = self.database.state.lock();
294 let start = after.filter(|after| *after >= prefix).unwrap_or(prefix);
295 let mut count = 0;
296 for (key, history) in state
297 .records
298 .range::<[u8], _>((std::ops::Bound::Included(start), std::ops::Bound::Unbounded))
299 {
300 control.cancellation().check()?;
301 let key = key.bytes();
302 if !key.starts_with(prefix) {
303 break;
304 }
305 if after.is_some_and(|after| key <= after) {
306 continue;
307 }
308 if let Some(record) = history.history.visible_at(self.sequence) {
309 let more = visit(
310 key,
311 super::BorrowedRecord {
312 revision: Some(record.sequence()),
313 value: record.value().map(|value| &***value),
314 },
315 )?;
316 control.cancellation().check()?;
317 count += 1;
318 if !more || count == limit {
319 break;
320 }
321 }
322 }
323 Ok(())
324 }
325}
326
327impl Drop for MemoryRecordSnapshot {
328 fn drop(&mut self) {
329 let mut state = self.database.state.lock();
330 let count = state
331 .snapshots
332 .get_mut(&self.sequence)
333 .expect("snapshot owns its lease");
334 *count -= 1;
335 if *count == 0 {
336 state.snapshots.remove(&self.sequence);
337 }
338 }
339}
340
341fn copy_bytes(value: &[u8], memory: &MemoryBudget) -> VersionResult<BudgetedVec<u8>> {
342 let mut owned = BudgetedVec::new(memory);
343 owned.extend_from_slice(value)?;
344 Ok(owned)
345}