uqa_storage/key_value/diskann/
pruning.rs1use super::{identity::validate_mapping, invalid, publication, KeyValueDiskANNSource};
8use crate::diskann_index::{
9 catalog::DiskANNIndexScope,
10 changes::{DiskANNChangeJournal, DiskANNChangeRead, DiskANNPruneRequest, DiskANNPruneResult},
11 maintenance::{DiskANNStatisticsPage, DiskANNStatisticsRequest},
12 pages::DiskANNOriginReader,
13};
14use crate::key_value::KeyValueRead;
15use crate::{read_control::StorageReadControl, KeyValueBatch, StorageBackendResult};
16use std::sync::Arc;
17
18pub struct KeyValueDiskANNPruner {
20 source: Arc<KeyValueDiskANNSource>,
21 origins: DiskANNOriginReader,
22 control: StorageReadControl,
23}
24
25impl KeyValueDiskANNPruner {
26 pub fn statistics(
28 &self,
29 journal: &dyn DiskANNChangeRead,
30 request: DiskANNStatisticsRequest,
31 control: &StorageReadControl,
32 ) -> StorageBackendResult<DiskANNStatisticsPage> {
33 self.control.check()?;
34 let page =
35 crate::diskann_index::maintenance::measure(&self.origins, journal, request, control)?;
36 self.control.check()?;
37 Ok(page)
38 }
39
40 pub fn open(
41 source: Arc<KeyValueDiskANNSource>,
42 maximum: usize,
43 control: &StorageReadControl,
44 ) -> StorageBackendResult<Self> {
45 let origins = DiskANNOriginReader::open(source.clone(), maximum, control)?;
46 Ok(Self {
47 source,
48 origins,
49 control: control.clone(),
50 })
51 }
52
53 pub fn require_selected(
55 &self,
56 scope: &DiskANNIndexScope,
57 dimensions: u32,
58 parameters: crate::vector_index::DiskANNIndexParams,
59 read: &dyn KeyValueRead,
60 batch: &mut dyn KeyValueBatch,
61 control: &StorageReadControl,
62 ) -> StorageBackendResult<()> {
63 self.control.check()?;
64 control.check()?;
65 let input = self.origins.manifest().input();
66 if input.dimensions != dimensions || input.parameters != parameters {
67 return Err(invalid(
68 "selected generation differs from the current index configuration",
69 ));
70 }
71 let generation = input.generation;
72 self.source.check(control)?;
73 validate_mapping(scope, generation, &*self.source.read, control)?;
74 if publication::selected_generation(scope, read, control)? != Some(generation) {
75 return Err(invalid("journal pruning requires the selected generation"));
76 }
77 let key = publication::head_key(scope);
78 if read
79 .record_revision(&key)?
80 .is_none_or(|revision| revision.has_private_changes())
81 {
82 return Err(invalid("journal pruning requires a committed head"));
83 }
84 batch.require_unchanged(&key)?;
85 self.control.check()?;
86 control.check()
87 }
88
89 pub fn prune(
91 &self,
92 journal: &mut dyn DiskANNChangeJournal,
93 request: DiskANNPruneRequest,
94 control: &StorageReadControl,
95 ) -> StorageBackendResult<DiskANNPruneResult> {
96 self.control.check()?;
97 let result =
98 crate::diskann_index::changes::prune(&self.origins, journal, request, control)?;
99 self.control.check()?;
100 Ok(result)
101 }
102}