uqa_storage/diskann_index/query/selection/
source.rs1use crate::diskann_index::{
10 format::{
11 DiskANNCanonicalOrigin, DiskANNChangeIdentity, DiskANNGeneration, DiskANNVectorVersion,
12 },
13 DiskANNCanonicalCounts, DiskANNCanonicalRead, DiskANNCanonicalVectorVisitor, DiskANNQueryRead,
14};
15use crate::{read_control::StorageReadControl, StorageBackendResult};
16use std::sync::Arc;
17use uqa_core::{
18 memory::{Budgeted, MemoryReservation},
19 DocId,
20};
21
22#[derive(Clone)]
24pub struct DiskANNReadSnapshot {
25 canonical: Arc<dyn DiskANNQueryRead + Send + Sync>,
26 generation: DiskANNGeneration,
27 control: StorageReadControl,
28 guard: Option<Arc<Budgeted<Guard>>>,
29}
30
31struct Guard {
32 previous: Option<Arc<Budgeted<Guard>>>,
33 control: Option<StorageReadControl>,
34 _memory: Option<Arc<MemoryReservation>>,
35}
36
37impl DiskANNReadSnapshot {
38 pub(in crate::diskann_index::query) fn new(
39 canonical: Arc<dyn DiskANNQueryRead + Send + Sync>,
40 generation: DiskANNGeneration,
41 control: &StorageReadControl,
42 ) -> Self {
43 Self {
44 canonical,
45 generation,
46 control: control.clone(),
47 guard: None,
48 }
49 }
50
51 pub fn same_lineage(&self, other: &Self) -> bool {
53 self.generation.database() == other.generation.database()
54 && self.generation.table() == other.generation.table()
55 && self.generation.index() == other.generation.index()
56 }
57
58 pub(crate) fn with_guard(
59 mut self,
60 memory: Option<Arc<MemoryReservation>>,
61 control: Option<StorageReadControl>,
62 ) -> StorageBackendResult<Self> {
63 self.check_control(&self.control)?;
64 if let Some(control) = &control {
65 control.check()?;
66 }
67 if memory.is_some() || control.is_some() {
68 let guard = Guard {
69 previous: self.guard.take(),
70 control,
71 _memory: memory,
72 };
73 self.guard = Some(
74 Budgeted::new(guard, self.control.memory().empty_reservation()).into_shared()?,
75 );
76 }
77 Ok(self)
78 }
79
80 fn read<T>(
81 &self,
82 control: &StorageReadControl,
83 operation: impl FnOnce() -> StorageBackendResult<T>,
84 ) -> StorageBackendResult<T> {
85 self.check_control(control)?;
86 let result = operation()?;
87 self.check_control(control)?;
88 Ok(result)
89 }
90}
91
92impl DiskANNCanonicalRead for DiskANNReadSnapshot {
93 fn population_counts(
94 &self,
95 generation: DiskANNGeneration,
96 control: &StorageReadControl,
97 ) -> StorageBackendResult<Option<DiskANNCanonicalCounts>> {
98 self.read(control, || {
99 self.canonical.population_counts(generation, control)
100 })
101 }
102
103 fn corpus_fingerprint(
104 &self,
105 control: &StorageReadControl,
106 ) -> StorageBackendResult<Option<[u8; 32]>> {
107 self.read(control, || self.canonical.corpus_fingerprint(control))
108 }
109 fn check_control(&self, control: &StorageReadControl) -> StorageBackendResult<()> {
110 self.control.check()?;
111 control.check()?;
112 let mut guard = self.guard.as_ref();
113 while let Some(current) = guard {
114 if let Some(control) = ¤t.control {
115 control.check()?;
116 }
117 guard = current.previous.as_ref();
118 }
119 self.canonical.check_control(control)
120 }
121
122 fn dimensions(&self) -> u32 {
123 self.canonical.dimensions()
124 }
125
126 fn next_document_after(
127 &self,
128 after: Option<DocId>,
129 control: &StorageReadControl,
130 ) -> StorageBackendResult<Option<DocId>> {
131 self.read(control, || {
132 self.canonical.next_document_after(after, control)
133 })
134 }
135
136 fn origin(
137 &self,
138 document: DocId,
139 control: &StorageReadControl,
140 ) -> StorageBackendResult<Option<DiskANNVectorVersion>> {
141 self.read(control, || self.canonical.origin(document, control))
142 }
143
144 fn visit_document(
145 &self,
146 document: DocId,
147 control: &StorageReadControl,
148 visit: &mut DiskANNCanonicalVectorVisitor<'_>,
149 ) -> StorageBackendResult<Option<DiskANNVectorVersion>> {
150 self.read(control, || {
151 self.canonical.visit_document(document, control, visit)
152 })
153 }
154
155 fn read_vector(
156 &self,
157 document: DocId,
158 ordinal: u32,
159 control: &StorageReadControl,
160 ) -> StorageBackendResult<Option<uqa_core::memory::BudgetedVec<f32>>> {
161 self.read(control, || {
162 self.canonical.read_vector(document, ordinal, control)
163 })
164 }
165}
166
167impl crate::vector_index::VectorRead for DiskANNReadSnapshot {
168 fn corpus_fingerprint(
169 &self,
170 control: &StorageReadControl,
171 ) -> StorageBackendResult<Option<[u8; 32]>> {
172 DiskANNCanonicalRead::corpus_fingerprint(self, control)
173 }
174 fn check_control(&self, control: &StorageReadControl) -> StorageBackendResult<()> {
175 DiskANNCanonicalRead::check_control(self, control)
176 }
177 fn dimensions(&self) -> u32 {
178 DiskANNCanonicalRead::dimensions(self)
179 }
180 fn next_document_after(
181 &self,
182 after: Option<DocId>,
183 control: &StorageReadControl,
184 ) -> StorageBackendResult<Option<DocId>> {
185 DiskANNCanonicalRead::next_document_after(self, after, control)
186 }
187 fn document_vector_count(
188 &self,
189 document: DocId,
190 control: &StorageReadControl,
191 ) -> StorageBackendResult<u64> {
192 Ok(self
193 .document_origin(document, control)?
194 .map_or(0, DiskANNCanonicalOrigin::count))
195 }
196 fn read_vector(
197 &self,
198 document: DocId,
199 ordinal: u32,
200 control: &StorageReadControl,
201 ) -> StorageBackendResult<Option<uqa_core::memory::BudgetedVec<f32>>> {
202 DiskANNCanonicalRead::read_vector(self, document, ordinal, control)
203 }
204}
205
206impl DiskANNQueryRead for DiskANNReadSnapshot {
207 fn document_origin(
208 &self,
209 document: DocId,
210 control: &StorageReadControl,
211 ) -> StorageBackendResult<Option<DiskANNCanonicalOrigin>> {
212 self.read(control, || {
213 self.canonical.document_origin(document, control)
214 })
215 }
216
217 fn next_change_after(
218 &self,
219 after: Option<DocId>,
220 control: &StorageReadControl,
221 ) -> StorageBackendResult<Option<DiskANNChangeIdentity>> {
222 self.read(control, || self.canonical.next_change_after(after, control))
223 }
224}