uqa_storage/mvcc/session/
vector_fields.rs1use std::sync::Arc;
10
11use uqa_core::memory::{BudgetedVec, MemoryReservation};
12
13use super::VersionedKeyValueStore;
14use crate::mvcc::{CommittedRecordSnapshot, VectorFieldGuard, VersionError};
15use crate::read_control::StorageReadControl;
16use crate::{KeyValueStore, StorageBackendError, StorageBackendResult};
17
18pub struct VectorFieldGuardMaintenance {
20 writer: VersionedKeyValueStore,
21 read: Option<Arc<dyn CommittedRecordSnapshot>>,
22 prefix: BudgetedVec<u8>,
23 after: BudgetedVec<u8>,
24 current: BudgetedVec<u8>,
25 guard: Option<VectorFieldGuard>,
26 completed: Option<bool>,
27 control: StorageReadControl,
28 _memory: MemoryReservation,
29}
30
31impl VectorFieldGuardMaintenance {
32 pub fn start(
33 store: &VersionedKeyValueStore,
34 control: &StorageReadControl,
35 ) -> StorageBackendResult<Self> {
36 control.check()?;
37 let memory = control.memory().reserve(std::mem::size_of::<Self>())?;
38 let prefix = store
39 .persistence
40 .vector_field_guard_layout()
41 .prefix(control)
42 .map_err(VersionError::into_storage_error)?;
43 let read = store
44 .persistence
45 .snapshot(control)
46 .map_err(VersionError::into_storage_error)?;
47 Ok(Self {
48 writer: store.new_controlled_session(control),
49 read: Some(read),
50 prefix,
51 after: BudgetedVec::new(control.memory()),
52 current: BudgetedVec::new(control.memory()),
53 guard: None,
54 completed: None,
55 control: control.clone(),
56 _memory: memory,
57 })
58 }
59
60 pub fn step(&mut self) -> StorageBackendResult<Option<bool>> {
62 self.control.check()?;
63 if self.writer.in_transaction() {
64 return Err(VersionError::InvalidEncoding(
65 "resolve the original field-guard maintenance attempt before advancing",
66 )
67 .into_storage_error());
68 }
69 if self.current.is_empty() {
70 let Some(read) = &self.read else {
71 return Ok(None);
72 };
73 let mut selected = BudgetedVec::new(self.control.memory());
74 let mut guard = None;
75 read.visit_keys(
76 &self.prefix,
77 (!self.after.is_empty()).then_some(&*self.after),
78 1,
79 &self.control,
80 &mut |key, metadata| {
81 selected.extend_from_slice(key)?;
82 if metadata.live {
83 guard = self
84 .writer
85 .persistence
86 .vector_field_guard_layout()
87 .reference(key, &self.control)?;
88 }
89 Ok(false)
90 },
91 )
92 .map_err(VersionError::into_storage_error)?;
93 self.control.check()?;
94 self.current = selected;
95 self.guard = guard;
96 if self.current.is_empty() {
97 self.read = None;
98 return Ok(None);
99 }
100 }
101 let mut removed = false;
102 if let Some(guard) = self.guard.as_ref().filter(|_| self.completed.is_none()) {
103 let result = self.writer.with_mutation(&mut |read, batch| {
104 let mut present = false;
105 read.visit_value_budgeted(&guard.references, &self.control, &mut |value| {
106 if let Some(value) = value {
107 if value != &*guard.reference_value {
108 return Err(VersionError::InvalidEncoding(
109 "vector field reference marker payload changed",
110 )
111 .into_storage_error());
112 }
113 present = true;
114 }
115 Ok(())
116 })?;
117 if present && !read.contains_prefix_budgeted(&guard.vectors, &self.control)? {
118 read.visit_value_budgeted(&guard.lifetime, &self.control, &mut |value| {
119 if value.is_some() {
120 return Err(VersionError::InvalidEncoding(
121 "vector field lifetime guard has a live payload",
122 )
123 .into_storage_error());
124 }
125 Ok(())
126 })?;
127 batch.require_unchanged(&guard.lifetime)?;
129 batch.delete(&guard.references)?;
130 removed = true;
131 }
132 Ok(())
133 });
134 match result {
135 Err(StorageBackendError::Backend { source, .. })
136 if matches!(
137 source.downcast_ref::<VersionError>(),
138 Some(
139 VersionError::WriteConflict { .. } | VersionError::ReadConflict { .. }
140 )
141 ) =>
142 {
143 self.writer.rollback_transaction()?;
144 removed = false;
145 }
146 result => result?,
147 }
148 self.completed = Some(removed);
149 }
150 let removed = self.completed.unwrap_or(false);
151 self.after.clear();
152 self.after.extend_from_slice(&self.current)?;
153 self.current.clear();
154 self.guard = None;
155 self.completed = None;
156 Ok(Some(removed))
157 }
158
159 pub fn commit_pending(&mut self) -> StorageBackendResult<()> {
161 self.writer.commit_transaction()?;
162 self.completed = Some(true);
163 Ok(())
164 }
165
166 pub fn rollback_pending(&self) -> StorageBackendResult<()> {
167 self.writer.rollback_transaction()
168 }
169
170 pub fn run(
171 store: &VersionedKeyValueStore,
172 control: &StorageReadControl,
173 ) -> StorageBackendResult<()> {
174 let mut pass = Self::start(store, control)?;
175 while pass.step()?.is_some() {}
176 Ok(())
177 }
178}