1use std::collections::BTreeMap;
8use std::sync::Arc;
9
10use uqa_analysis::Analyzer;
11use uqa_core::memory::Budgeted;
12use uqa_core::{DocId, FieldName, IndexStats, PostingEntry, PostingList, TokenOccurrence};
13
14use crate::block_max_index::BlockMaxScorer;
15use crate::clustered_postings::{BudgetedPostingReadCursor, OccurrencePosting, PostingCursor};
16use crate::inverted_index::{AnalyzerPhase, IndexedFieldMetadata, InvertedIndexChangeVisitor};
17use crate::read_control::StorageReadControl;
18use crate::{InvertedIndex, StorageBackendResult, TokenTermKey};
19
20use super::{read_only_error, ReadOnlySnapshot};
21
22impl ReadOnlySnapshot<dyn InvertedIndex> {
23 pub fn from_budgeted_inverted<T: InvertedIndex + 'static>(
25 snapshot: Budgeted<T>,
26 ) -> StorageBackendResult<Self> {
27 let snapshot = ReadOnlySnapshot::from_budgeted(snapshot)?;
28 Ok(Self(snapshot.0, snapshot.1, snapshot.2, None))
29 }
30}
31
32impl<T: InvertedIndex + ?Sized> ReadOnlySnapshot<T> {
33 pub fn with_inverted_read_control(
35 mut self,
36 control: &StorageReadControl,
37 ) -> StorageBackendResult<Self> {
38 control.check()?;
39 if self.2.is_none() {
40 self.2 = Some(control.clone());
41 }
42 self.check_inverted_read()?;
43 Ok(self)
44 }
45
46 fn check_inverted_read(&self) -> StorageBackendResult<()> {
47 self.2.as_ref().map_or(Ok(()), StorageReadControl::check)
48 }
49
50 fn inverted_control<'a>(
51 &'a self,
52 requested: &'a StorageReadControl,
53 ) -> StorageBackendResult<&'a StorageReadControl> {
54 requested.check()?;
55 self.check_inverted_read()?;
56 Ok(requested)
58 }
59}
60
61impl InvertedIndex for ReadOnlySnapshot<dyn InvertedIndex> {
62 fn source_rebuild_required(&self) -> StorageBackendResult<bool> {
63 self.check_inverted_read()?;
64 self.0.source_rebuild_required()
65 }
66
67 fn analyzer(&self) -> &Analyzer {
68 self.0.analyzer()
69 }
70
71 fn default_analyzer_binding(
72 &self,
73 ) -> StorageBackendResult<crate::inverted_index::AnalyzerDefault> {
74 self.check_inverted_read()?;
75 self.0.default_analyzer_binding()
76 }
77
78 fn add_document(
79 &mut self,
80 _doc_id: DocId,
81 _fields: BTreeMap<FieldName, String>,
82 ) -> StorageBackendResult<()> {
83 Err(read_only_error())
84 }
85
86 fn try_add_document(
87 &mut self,
88 _doc_id: DocId,
89 _fields: BTreeMap<FieldName, String>,
90 ) -> StorageBackendResult<()> {
91 Err(read_only_error())
92 }
93
94 fn try_add_documents(
95 &mut self,
96 _documents: Vec<(DocId, BTreeMap<FieldName, String>)>,
97 ) -> StorageBackendResult<()> {
98 Err(read_only_error())
99 }
100
101 fn try_add_documents_observed(
102 &mut self,
103 _documents: Vec<(DocId, BTreeMap<FieldName, String>)>,
104 _visit: &mut InvertedIndexChangeVisitor<'_>,
105 ) -> StorageBackendResult<()> {
106 Err(read_only_error())
107 }
108
109 fn try_remove_document_observed(
110 &mut self,
111 _doc_id: DocId,
112 _visit: &mut InvertedIndexChangeVisitor<'_>,
113 ) -> StorageBackendResult<()> {
114 Err(read_only_error())
115 }
116
117 fn remove_document(&mut self, _doc_id: DocId) -> StorageBackendResult<()> {
118 Err(read_only_error())
119 }
120
121 fn try_remove_document(&mut self, _doc_id: DocId) -> StorageBackendResult<()> {
122 Err(read_only_error())
123 }
124
125 fn clear(&mut self) -> StorageBackendResult<()> {
126 Err(read_only_error())
127 }
128
129 fn try_clear(&mut self) -> StorageBackendResult<()> {
130 Err(read_only_error())
131 }
132
133 fn try_rebuild_documents(
134 &mut self,
135 _documents: Vec<(DocId, BTreeMap<FieldName, String>)>,
136 ) -> StorageBackendResult<()> {
137 Err(read_only_error())
138 }
139
140 fn get_posting_list(&self, field: &str, term: &str) -> StorageBackendResult<PostingList> {
141 self.check_inverted_read()?;
142 self.0.get_posting_list(field, term)
143 }
144
145 fn get_posting_list_key(
146 &self,
147 field: &str,
148 term: &TokenTermKey,
149 ) -> StorageBackendResult<PostingList> {
150 self.check_inverted_read()?;
151 self.0.get_posting_list_key(field, term)
152 }
153
154 fn posting_cursor_key(
155 &self,
156 field: &str,
157 term: &TokenTermKey,
158 ) -> StorageBackendResult<Box<dyn PostingCursor>> {
159 self.check_inverted_read()?;
160 self.0.posting_cursor_key(field, term)
161 }
162
163 fn posting_read_cursor_key<'a>(
164 &'a self,
165 field: &'a str,
166 term: &TokenTermKey,
167 ) -> StorageBackendResult<Box<dyn crate::clustered_postings::PostingReadCursor + 'a>> {
168 self.0.posting_read_cursor_key(field, term)
169 }
170
171 fn posting_read_cursor_key_budgeted<'a>(
172 &'a self,
173 field: &'a str,
174 term: &'a TokenTermKey,
175 control: &StorageReadControl,
176 ) -> StorageBackendResult<BudgetedPostingReadCursor<'a>> {
177 self.0
178 .posting_read_cursor_key_budgeted(field, term, self.inverted_control(control)?)
179 }
180
181 fn visit_score_clusters(
182 &self,
183 field: &str,
184 term: &TokenTermKey,
185 after: Option<u64>,
186 limit: usize,
187 control: &StorageReadControl,
188 visit: &mut crate::clustered_postings::ScoreClusterVisitor<'_>,
189 ) -> StorageBackendResult<()> {
190 self.0.visit_score_clusters(
191 field,
192 term,
193 after,
194 limit,
195 self.inverted_control(control)?,
196 visit,
197 )
198 }
199
200 fn get_occurrences_budgeted(
201 &self,
202 doc_id: DocId,
203 field: &str,
204 term: &TokenTermKey,
205 control: &StorageReadControl,
206 ) -> StorageBackendResult<Budgeted<Vec<TokenOccurrence>>> {
207 self.0
208 .get_occurrences_budgeted(doc_id, field, term, self.inverted_control(control)?)
209 }
210
211 fn get_occurrence_postings(
212 &self,
213 field: &str,
214 term: &TokenTermKey,
215 ) -> StorageBackendResult<Vec<OccurrencePosting>> {
216 self.check_inverted_read()?;
217 self.0.get_occurrence_postings(field, term)
218 }
219
220 fn get_occurrences(
221 &self,
222 doc_id: DocId,
223 field: &str,
224 term: &TokenTermKey,
225 ) -> StorageBackendResult<Vec<TokenOccurrence>> {
226 self.check_inverted_read()?;
227 self.0.get_occurrences(doc_id, field, term)
228 }
229
230 fn indexed_field_metadata(
231 &self,
232 doc_id: DocId,
233 field: &str,
234 ) -> StorageBackendResult<Option<IndexedFieldMetadata>> {
235 self.check_inverted_read()?;
236 self.0.indexed_field_metadata(doc_id, field)
237 }
238
239 fn doc_freq_key(&self, field: &str, term: &TokenTermKey) -> StorageBackendResult<u64> {
240 self.check_inverted_read()?;
241 self.0.doc_freq_key(field, term)
242 }
243
244 fn get_term_freq_key(
245 &self,
246 doc_id: DocId,
247 field: &str,
248 term: &TokenTermKey,
249 ) -> StorageBackendResult<u64> {
250 self.check_inverted_read()?;
251 self.0.get_term_freq_key(doc_id, field, term)
252 }
253
254 fn vocabulary_keys(&self, field: &str) -> StorageBackendResult<Vec<TokenTermKey>> {
255 self.check_inverted_read()?;
256 self.0.vocabulary_keys(field)
257 }
258
259 fn get_posting_lists_bulk(
260 &self,
261 field: &str,
262 terms: &[String],
263 ) -> StorageBackendResult<Vec<PostingList>> {
264 self.check_inverted_read()?;
265 self.0.get_posting_lists_bulk(field, terms)
266 }
267
268 fn posting_cursor(
269 &self,
270 field: &str,
271 term: &str,
272 ) -> StorageBackendResult<Box<dyn PostingCursor>> {
273 self.check_inverted_read()?;
274 self.0.posting_cursor(field, term)
275 }
276
277 fn posting_cursors_bulk(
278 &self,
279 field: &str,
280 terms: &[String],
281 ) -> StorageBackendResult<Vec<Box<dyn PostingCursor>>> {
282 self.check_inverted_read()?;
283 self.0.posting_cursors_bulk(field, terms)
284 }
285
286 fn posting_cursors_keys_bulk(
287 &self,
288 field: &str,
289 terms: &[TokenTermKey],
290 ) -> StorageBackendResult<Vec<Box<dyn PostingCursor>>> {
291 self.check_inverted_read()?;
292 self.0.posting_cursors_keys_bulk(field, terms)
293 }
294
295 fn get_posting_lists_keys_bulk(
296 &self,
297 field: &str,
298 terms: &[TokenTermKey],
299 ) -> StorageBackendResult<Vec<PostingList>> {
300 self.check_inverted_read()?;
301 self.0.get_posting_lists_keys_bulk(field, terms)
302 }
303
304 fn persisted_block_max_scores_keys_bulk(
305 &self,
306 field: &str,
307 terms: &[TokenTermKey],
308 scorer_fingerprint: &str,
309 ) -> StorageBackendResult<Vec<Option<Vec<f64>>>> {
310 self.check_inverted_read()?;
311 self.0
312 .persisted_block_max_scores_keys_bulk(field, terms, scorer_fingerprint)
313 }
314
315 fn get_scoring_inputs_keys_bulk(
316 &self,
317 doc_ids: &[DocId],
318 field: &str,
319 terms: &[TokenTermKey],
320 ) -> StorageBackendResult<Vec<(u64, Vec<u64>)>> {
321 self.check_inverted_read()?;
322 self.0.get_scoring_inputs_keys_bulk(doc_ids, field, terms)
323 }
324
325 fn rebuild_persisted_block_max(
326 &mut self,
327 _field: &str,
328 _scorer: &dyn BlockMaxScorer,
329 _scorer_fingerprint: &str,
330 ) -> StorageBackendResult<bool> {
331 Err(read_only_error())
332 }
333
334 fn persisted_block_max_scores(
335 &self,
336 field: &str,
337 term: &str,
338 scorer_fingerprint: &str,
339 ) -> StorageBackendResult<Option<Vec<f64>>> {
340 self.check_inverted_read()?;
341 self.0
342 .persisted_block_max_scores(field, term, scorer_fingerprint)
343 }
344
345 fn persisted_block_max_scores_bulk(
346 &self,
347 field: &str,
348 terms: &[String],
349 scorer_fingerprint: &str,
350 ) -> StorageBackendResult<Vec<Option<Vec<f64>>>> {
351 self.check_inverted_read()?;
352 self.0
353 .persisted_block_max_scores_bulk(field, terms, scorer_fingerprint)
354 }
355
356 fn for_each_posting(
357 &self,
358 field: &str,
359 term: &str,
360 visit: &mut dyn FnMut(&PostingEntry),
361 ) -> StorageBackendResult<()> {
362 self.check_inverted_read()?;
363 self.0.for_each_posting(field, term, visit)
364 }
365
366 fn for_each_term_freq(
367 &self,
368 field: &str,
369 term: &str,
370 visit: &mut dyn FnMut(DocId, u64),
371 ) -> StorageBackendResult<()> {
372 self.check_inverted_read()?;
373 self.0.for_each_term_freq(field, term, visit)
374 }
375
376 fn doc_freq(&self, field: &str, term: &str) -> StorageBackendResult<u64> {
377 self.check_inverted_read()?;
378 self.0.doc_freq(field, term)
379 }
380
381 fn get_doc_length(&self, doc_id: DocId, field: &str) -> StorageBackendResult<u64> {
382 self.check_inverted_read()?;
383 self.0.get_doc_length(doc_id, field)
384 }
385
386 fn get_term_freq(&self, doc_id: DocId, field: &str, term: &str) -> StorageBackendResult<u64> {
387 self.check_inverted_read()?;
388 self.0.get_term_freq(doc_id, field, term)
389 }
390
391 fn doc_count(&self) -> StorageBackendResult<u64> {
392 self.check_inverted_read()?;
393 self.0.doc_count()
394 }
395
396 fn total_field_length(&self, field: &str) -> StorageBackendResult<u64> {
397 self.check_inverted_read()?;
398 self.0.total_field_length(field)
399 }
400
401 fn field_doc_count(&self, field: &str) -> StorageBackendResult<u64> {
402 self.check_inverted_read()?;
403 self.0.field_doc_count(field)
404 }
405
406 fn field_stats(&self, field: &str) -> StorageBackendResult<IndexStats> {
407 self.check_inverted_read()?;
408 self.0.field_stats(field)
409 }
410
411 fn field_stats_scalar(&self, field: &str) -> StorageBackendResult<IndexStats> {
412 self.check_inverted_read()?;
413 self.0.field_stats_scalar(field)
414 }
415
416 fn field_stats_scalar_budgeted(
417 &self,
418 field: &str,
419 control: &StorageReadControl,
420 ) -> StorageBackendResult<IndexStats> {
421 self.0
422 .field_stats_scalar_budgeted(field, self.inverted_control(control)?)
423 }
424
425 fn vocabulary_terms(&self, field: &str) -> StorageBackendResult<Vec<String>> {
426 self.check_inverted_read()?;
427 self.0.vocabulary_terms(field)
428 }
429
430 fn stats(&self) -> StorageBackendResult<IndexStats> {
431 self.check_inverted_read()?;
432 self.0.stats()
433 }
434
435 fn posting_count(&self, field: Option<&str>) -> StorageBackendResult<u64> {
436 self.check_inverted_read()?;
437 self.0.posting_count(field)
438 }
439
440 fn doc_length_count(&self, field: Option<&str>) -> StorageBackendResult<u64> {
441 self.check_inverted_read()?;
442 self.0.doc_length_count(field)
443 }
444
445 fn term_count(&self, field: Option<&str>) -> StorageBackendResult<u64> {
446 self.check_inverted_read()?;
447 self.0.term_count(field)
448 }
449
450 fn snapshot(&self) -> StorageBackendResult<Arc<dyn InvertedIndex>> {
451 self.check_inverted_read()?;
452 Ok(Arc::new(self.clone()))
453 }
454
455 fn snapshot_with_control(
456 &self,
457 control: &StorageReadControl,
458 ) -> StorageBackendResult<Arc<dyn InvertedIndex>> {
459 control.check()?;
460 if self.1.is_some() || self.2.is_some() {
461 return self.clone().with_inverted_read_control(control)?.snapshot();
462 }
463 Ok(Arc::new(ReadOnlySnapshot::new(
464 self.0.snapshot_with_control(control)?,
465 )))
466 }
467
468 fn field_names(&self) -> StorageBackendResult<Vec<FieldName>> {
469 self.check_inverted_read()?;
470 self.0.field_names()
471 }
472
473 fn get_posting_list_any_field(&self, term: &str) -> StorageBackendResult<PostingList> {
474 self.check_inverted_read()?;
475 self.0.get_posting_list_any_field(term)
476 }
477
478 fn doc_freq_any_field(&self, term: &str) -> StorageBackendResult<u64> {
479 self.check_inverted_read()?;
480 self.0.doc_freq_any_field(term)
481 }
482
483 fn get_total_doc_length(&self, doc_id: DocId) -> StorageBackendResult<u64> {
484 self.check_inverted_read()?;
485 self.0.get_total_doc_length(doc_id)
486 }
487
488 fn get_doc_lengths_bulk(
489 &self,
490 doc_ids: &[DocId],
491 field: &str,
492 ) -> StorageBackendResult<BTreeMap<DocId, u64>> {
493 self.check_inverted_read()?;
494 self.0.get_doc_lengths_bulk(doc_ids, field)
495 }
496
497 fn get_term_freqs_bulk(
498 &self,
499 doc_ids: &[DocId],
500 field: &str,
501 term: &str,
502 ) -> StorageBackendResult<BTreeMap<DocId, u64>> {
503 self.check_inverted_read()?;
504 self.0.get_term_freqs_bulk(doc_ids, field, term)
505 }
506
507 fn get_scoring_inputs_bulk(
508 &self,
509 doc_ids: &[DocId],
510 field: &str,
511 terms: &[String],
512 ) -> StorageBackendResult<Vec<(u64, Vec<u64>)>> {
513 self.check_inverted_read()?;
514 self.0.get_scoring_inputs_bulk(doc_ids, field, terms)
515 }
516
517 fn get_total_term_freq(&self, doc_id: DocId, term: &str) -> StorageBackendResult<u64> {
518 self.check_inverted_read()?;
519 self.0.get_total_term_freq(doc_id, term)
520 }
521
522 fn set_field_analyzer(
523 &mut self,
524 _field: &str,
525 _analyzer: Analyzer,
526 _phase: AnalyzerPhase,
527 ) -> Result<(), String> {
528 Err(read_only_error().to_string())
529 }
530
531 fn remove_field_analyzers(&mut self, _field: &str) -> Result<(), String> {
532 Err(read_only_error().to_string())
533 }
534
535 fn get_field_analyzer(&self, field: &str) -> Analyzer {
536 self.0.get_field_analyzer(field)
537 }
538
539 fn get_search_analyzer(&self, field: &str) -> Analyzer {
540 self.0.get_search_analyzer(field)
541 }
542
543 fn index_analyzer_revision(
544 &self,
545 field: &str,
546 ) -> StorageBackendResult<Arc<uqa_analysis::CompiledAnalyzer>> {
547 self.check_inverted_read()?;
548 self.0.index_analyzer_revision(field)
549 }
550
551 fn search_analyzer_revision(
552 &self,
553 field: &str,
554 ) -> StorageBackendResult<Arc<uqa_analysis::CompiledAnalyzer>> {
555 self.check_inverted_read()?;
556 self.0.search_analyzer_revision(field)
557 }
558
559 fn set_field_analyzer_revision(
560 &mut self,
561 _field: &str,
562 _revision: Arc<uqa_analysis::CompiledAnalyzer>,
563 _phase: AnalyzerPhase,
564 ) -> Result<(), String> {
565 Err(read_only_error().to_string())
566 }
567
568 fn set_field_analyzer_revisions(
569 &mut self,
570 _field: &str,
571 _index: Arc<uqa_analysis::CompiledAnalyzer>,
572 _search: Arc<uqa_analysis::CompiledAnalyzer>,
573 ) -> Result<(), String> {
574 Err(read_only_error().to_string())
575 }
576
577 fn rebuild_with_analyzer_revision(
578 &mut self,
579 _field: &str,
580 _revision: Arc<uqa_analysis::CompiledAnalyzer>,
581 _phase: AnalyzerPhase,
582 _documents: Vec<(DocId, BTreeMap<FieldName, String>)>,
583 ) -> StorageBackendResult<()> {
584 Err(read_only_error())
585 }
586
587 fn try_rebuild_documents_cancellable(
588 &mut self,
589 _documents: Vec<(DocId, BTreeMap<FieldName, String>)>,
590 _cancellation: &uqa_core::CancellationToken,
591 ) -> StorageBackendResult<()> {
592 Err(read_only_error())
593 }
594
595 fn rebuild_with_analyzer_revision_cancellable(
596 &mut self,
597 _field: &str,
598 _revision: Arc<uqa_analysis::CompiledAnalyzer>,
599 _phase: AnalyzerPhase,
600 _documents: Vec<(DocId, BTreeMap<FieldName, String>)>,
601 _cancellation: &uqa_core::CancellationToken,
602 ) -> StorageBackendResult<()> {
603 Err(read_only_error())
604 }
605}