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