Skip to main content

uqa_storage/mvcc/
ivf.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! Evaluated IVF document changes and provider-owned record codecs.
8
9mod resolve;
10
11use super::VersionResult;
12use crate::{
13    ivf_index::{IVFMetadataSnapshot, IVFState},
14    read_control::StorageReadControl,
15    IVFIndexParams,
16};
17use uqa_core::{memory::BudgetedVec, DocId};
18
19#[derive(Clone, Copy)]
20pub struct IVFRecordHeader {
21    pub dimensions: u32,
22    pub params: IVFIndexParams,
23    pub state: IVFState,
24    pub trained_size: usize,
25    pub deletes_since_train: usize,
26    pub vector_count: usize,
27    /// Optional persisted mutation counter; native layouts without that column rely on record revisions and input validation.
28    pub revision: Option<u64>,
29}
30
31#[derive(Clone, Copy)]
32pub enum IVFRecordKey {
33    Structure,
34    Document(DocId),
35    Vectors,
36    Centroids,
37    Assignments,
38    Centroid(usize),
39    Assignment(DocId, u32),
40}
41
42pub enum IVFRecordValue<'a> {
43    Header {
44        snapshot: &'a IVFMetadataSnapshot,
45        revision: Option<u64>,
46    },
47    Centroid(&'a [f32]),
48    Assignment(usize),
49}
50
51/// Only physical addressing and row codecs. Common storage owns reconstruction, ordered mutation replay, conflicts and publication.
52pub trait IVFRecordLayout: Send + Sync {
53    /// Return the owning metadata key for a header, centroid or assignment; unrelated records return `None`.
54    fn metadata_key(
55        &self,
56        key: &[u8],
57        control: &StorageReadControl,
58    ) -> VersionResult<Option<BudgetedVec<u8>>>;
59    fn key(
60        &self,
61        metadata: &[u8],
62        address: IVFRecordKey,
63        control: &StorageReadControl,
64    ) -> VersionResult<BudgetedVec<u8>>;
65    fn header(
66        &self,
67        key: &[u8],
68        value: &[u8],
69        control: &StorageReadControl,
70    ) -> VersionResult<IVFRecordHeader>;
71    /// Decode a canonical vector identity without hydrating its payload.
72    fn vector_id(&self, key: &[u8], control: &StorageReadControl) -> VersionResult<(DocId, u32)>;
73    fn vector(
74        &self,
75        key: &[u8],
76        value: &[u8],
77        control: &StorageReadControl,
78    ) -> VersionResult<(DocId, u32, BudgetedVec<f32>)>;
79    fn centroid(
80        &self,
81        key: &[u8],
82        value: &[u8],
83        control: &StorageReadControl,
84    ) -> VersionResult<(usize, BudgetedVec<f32>)>;
85    fn assignment(
86        &self,
87        key: &[u8],
88        value: &[u8],
89        control: &StorageReadControl,
90    ) -> VersionResult<(DocId, u32, usize)>;
91    fn encode(
92        &self,
93        key: &[u8],
94        metadata_template: &[u8],
95        value: IVFRecordValue<'_>,
96        control: &StorageReadControl,
97    ) -> VersionResult<BudgetedVec<u8>>;
98}
99
100pub(super) use resolve::merge;