Skip to main content

linkrs_storage/edge/csr_variant/
persistence.rs

1use linkrs_core::StorageResult;
2
3use super::super::csr_trait::CsrBase;
4use super::super::{ImmutableCsr, MutableCsr, PureTopologyCsr, SingleMutableCsr};
5use super::CsrVariant;
6
7impl CsrBase for CsrVariant {
8    fn vertex_capacity(&self) -> usize {
9        match self {
10            CsrVariant::None { vertex_capacity } => *vertex_capacity,
11            CsrVariant::Multiple(csr) => csr.vertex_capacity(),
12            CsrVariant::Single(csr) => csr.vertex_capacity(),
13            CsrVariant::Pure(csr) => csr.vertex_capacity(),
14            CsrVariant::Bundled(csr) => csr.vertex_capacity(),
15            CsrVariant::Frozen(csr) => csr.vertex_capacity(),
16        }
17    }
18
19    fn edge_count(&self) -> u64 {
20        dispatch!(self, edge_count() -> 0)
21    }
22
23    fn dump(&self) -> Vec<u8> {
24        // Tag 3 holds the authoritative frozen heap bytes. Snapshot mappings
25        // are a derived serving cache and never persist through this payload;
26        // checkpoint snapshot files own the mapped fast path, never this tag.
27        match self {
28            CsrVariant::None { vertex_capacity } => {
29                let mut result = vec![0u8];
30                result.extend((*vertex_capacity as u64).to_le_bytes());
31                result
32            }
33            CsrVariant::Multiple(csr) => {
34                let mut result = vec![1u8];
35                result.extend(csr.dump());
36                result
37            }
38            CsrVariant::Single(csr) => {
39                let mut result = vec![2u8];
40                result.extend(csr.dump());
41                result
42            }
43            CsrVariant::Frozen(csr) => {
44                let mut result = vec![3u8];
45                result.extend(csr.dump());
46                result
47            }
48            CsrVariant::Pure(csr) => {
49                let mut result = vec![4u8];
50                result.extend(csr.dump());
51                result
52            }
53            CsrVariant::Bundled(csr) => {
54                let mut result = vec![5u8];
55                result.extend(csr.dump());
56                result
57            }
58        }
59    }
60
61    fn dump_into(&self, out: &mut Vec<u8>) {
62        // Same tag contract as `dump`: tag 3 always carries heap frozen bytes.
63        match self {
64            CsrVariant::None { vertex_capacity } => {
65                out.push(0u8);
66                out.extend((*vertex_capacity as u64).to_le_bytes());
67            }
68            CsrVariant::Multiple(csr) => {
69                out.push(1u8);
70                csr.dump_into(out);
71            }
72            CsrVariant::Single(csr) => {
73                out.push(2u8);
74                csr.dump_into(out);
75            }
76            CsrVariant::Frozen(csr) => {
77                out.push(3u8);
78                csr.dump_into(out);
79            }
80            CsrVariant::Pure(csr) => {
81                out.push(4u8);
82                csr.dump_into(out);
83            }
84            CsrVariant::Bundled(csr) => {
85                out.push(5u8);
86                csr.dump_into(out);
87            }
88        }
89    }
90
91    fn load(&mut self, data: &[u8]) -> StorageResult<()> {
92        // Tag 3 always loads the heap frozen form. Mappings only open from
93        // snapshot files through the group container, never from this payload.
94        if data.is_empty() {
95            return Err(linkrs_core::StorageError::deserialize_error(
96                "Cannot load CSR variant: empty data",
97            ));
98        }
99
100        match data[0] {
101            0 => {
102                if data.len() < 9 {
103                    return Err(linkrs_core::StorageError::deserialize_error(
104                        "Cannot load None CSR variant: data too short",
105                    ));
106                }
107                let vertex_capacity = u64::from_le_bytes([
108                    data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8],
109                ]) as usize;
110                *self = CsrVariant::None { vertex_capacity };
111                Ok(())
112            }
113            1 => {
114                let mut csr = MutableCsr::new();
115                csr.load(&data[1..])?;
116                *self = CsrVariant::Multiple(Box::new(csr));
117                Ok(())
118            }
119            2 => {
120                let mut csr = SingleMutableCsr::new();
121                csr.load(&data[1..])?;
122                *self = CsrVariant::Single(csr);
123                Ok(())
124            }
125            3 => {
126                let mut csr = ImmutableCsr::new();
127                csr.load(&data[1..])?;
128                *self = CsrVariant::Frozen(Box::new(csr));
129                Ok(())
130            }
131            4 => {
132                let mut csr = PureTopologyCsr::default();
133                csr.load(&data[1..])?;
134                *self = CsrVariant::Pure(Box::new(csr));
135                Ok(())
136            }
137            5 => {
138                let mut csr = super::super::BundledCsr::default();
139                csr.load(&data[1..])?;
140                *self = CsrVariant::Bundled(Box::new(csr));
141                Ok(())
142            }
143            _ => Err(linkrs_core::StorageError::deserialize_error(
144                "Invalid CSR variant tag in serialized data",
145            )),
146        }
147    }
148}
149
150impl CsrVariant {
151    /// Borrow-based dump reusing caller-owned column buffers.
152    ///
153    /// Same bytes as `dump_into` through the base trait. A checkpoint over
154    /// many groups pays one allocation per column instead of one per group.
155    pub fn dump_into_with_scratch(
156        &self,
157        out: &mut Vec<u8>,
158        scratch: &mut super::super::mutable_csr::persistence::CsrDumpScratch,
159    ) {
160        match self {
161            CsrVariant::None { vertex_capacity } => {
162                out.push(0u8);
163                out.extend((*vertex_capacity as u64).to_le_bytes());
164            }
165            CsrVariant::Multiple(csr) => {
166                out.push(1u8);
167                csr.dump_into_with_scratch(out, scratch);
168            }
169            CsrVariant::Single(csr) => {
170                out.push(2u8);
171                csr.dump_into(out);
172            }
173            CsrVariant::Frozen(csr) => {
174                out.push(3u8);
175                csr.dump_into(out);
176            }
177            CsrVariant::Pure(csr) => {
178                out.push(4u8);
179                csr.dump_into(out);
180            }
181            CsrVariant::Bundled(csr) => {
182                out.push(5u8);
183                csr.dump_into(out);
184            }
185        }
186    }
187}