1use crate::error::{HematiteError, Result};
4
5use super::record::StoredRow;
6use super::serialization::RowCodec;
7
8pub const INVALID_PAGE_ID: u32 = u32::MAX;
9
10#[derive(Debug, Clone, PartialEq, Eq)]
11pub struct RowidLeafCell {
12 pub rowid: u64,
13 pub payload: Vec<u8>,
14}
15
16pub const ROWID_LEAF_FIXED_HEADER_SIZE: usize = 20;
17
18#[derive(Debug, Clone, PartialEq, Eq)]
19pub struct RowidLeafCellLayout {
20 pub rowid: u64,
21 pub total_payload_len: u32,
22 pub local_payload: Vec<u8>,
23 pub overflow_first_page: u32,
24}
25
26impl RowidLeafCellLayout {
27 pub fn local_payload_len_for(total_payload_len: usize, max_local_payload: usize) -> usize {
28 total_payload_len.min(max_local_payload)
29 }
30
31 pub fn encode(&self) -> Result<Vec<u8>> {
32 if self.local_payload.len() > self.total_payload_len as usize {
33 return Err(HematiteError::StorageError(
34 "Local payload cannot exceed total payload length".to_string(),
35 ));
36 }
37
38 let local_len = self.local_payload.len() as u32;
39 let mut out = Vec::with_capacity(ROWID_LEAF_FIXED_HEADER_SIZE + self.local_payload.len());
40 out.extend_from_slice(&self.rowid.to_le_bytes());
41 out.extend_from_slice(&self.total_payload_len.to_le_bytes());
42 out.extend_from_slice(&local_len.to_le_bytes());
43 out.extend_from_slice(&self.overflow_first_page.to_le_bytes());
44 out.extend_from_slice(&self.local_payload);
45 Ok(out)
46 }
47
48 pub fn decode(data: &[u8]) -> Result<Self> {
49 if data.len() < ROWID_LEAF_FIXED_HEADER_SIZE {
50 return Err(HematiteError::CorruptedData(
51 "Rowid fixed leaf cell header is truncated".to_string(),
52 ));
53 }
54
55 let rowid = u64::from_le_bytes([
56 data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
57 ]);
58 let total_payload_len = u32::from_le_bytes([data[8], data[9], data[10], data[11]]);
59 let local_len = u32::from_le_bytes([data[12], data[13], data[14], data[15]]) as usize;
60 let overflow_first_page = u32::from_le_bytes([data[16], data[17], data[18], data[19]]);
61
62 if ROWID_LEAF_FIXED_HEADER_SIZE + local_len != data.len() {
63 return Err(HematiteError::CorruptedData(
64 "Rowid fixed leaf local payload length mismatch".to_string(),
65 ));
66 }
67 if local_len > total_payload_len as usize {
68 return Err(HematiteError::CorruptedData(
69 "Rowid fixed leaf local payload exceeds total payload length".to_string(),
70 ));
71 }
72
73 Ok(Self {
74 rowid,
75 total_payload_len,
76 local_payload: data[ROWID_LEAF_FIXED_HEADER_SIZE..].to_vec(),
77 overflow_first_page,
78 })
79 }
80}
81
82#[derive(Debug, Clone, PartialEq, Eq)]
83pub struct EncodedRowidRecord {
84 pub cell: RowidLeafCellLayout,
85 pub overflow_payload: Vec<u8>,
86}
87
88pub fn encode_stored_row_record(
89 row: &StoredRow,
90 max_local_payload: usize,
91) -> Result<EncodedRowidRecord> {
92 let mut payload = RowCodec::encode_stored_row(&StoredRow {
93 row_id: 0,
94 values: row.values.clone(),
95 })?;
96 if payload.len() < 4 {
97 return Err(HematiteError::CorruptedData(
98 "Stored row payload is truncated".to_string(),
99 ));
100 }
101 payload.drain(0..4);
102 let local_len = RowidLeafCellLayout::local_payload_len_for(payload.len(), max_local_payload);
103 let local_payload = payload[0..local_len].to_vec();
104 let overflow_payload = payload[local_len..].to_vec();
105
106 Ok(EncodedRowidRecord {
107 cell: RowidLeafCellLayout {
108 rowid: row.row_id,
109 total_payload_len: payload.len() as u32,
110 local_payload,
111 overflow_first_page: INVALID_PAGE_ID,
112 },
113 overflow_payload,
114 })
115}
116
117pub fn decode_stored_row_record(rowid: u64, payload: &[u8]) -> Result<StoredRow> {
118 let mut serialized = Vec::with_capacity(payload.len() + 4);
119 serialized.extend_from_slice(&(payload.len() as u32).to_le_bytes());
120 serialized.extend_from_slice(payload);
121 let mut row = RowCodec::decode_stored_row(&serialized)?;
122 row.row_id = rowid;
123 Ok(row)
124}
125
126pub fn materialize_row_record_cell<F>(
127 row: &StoredRow,
128 max_local_payload: usize,
129 mut write_overflow_chain: F,
130) -> Result<Vec<u8>>
131where
132 F: FnMut(&[u8]) -> Result<Option<u32>>,
133{
134 let mut encoded = encode_stored_row_record(row, max_local_payload)?;
135 let overflow_first = write_overflow_chain(&encoded.overflow_payload)?;
136 encoded.cell.overflow_first_page = overflow_first.unwrap_or(INVALID_PAGE_ID);
137 encoded.cell.encode()
138}
139
140pub fn hydrate_row_record_cell<F>(
141 cell_bytes: &[u8],
142 mut read_overflow_chain: F,
143) -> Result<StoredRow>
144where
145 F: FnMut(Option<u32>, usize) -> Result<Vec<u8>>,
146{
147 let cell = RowidLeafCellLayout::decode(cell_bytes)?;
148 let local_len = cell.local_payload.len();
149 let total_len = cell.total_payload_len as usize;
150 if local_len > total_len {
151 return Err(HematiteError::CorruptedData(
152 "Cell local payload exceeds total payload length".to_string(),
153 ));
154 }
155
156 let overflow_len = total_len - local_len;
157 let overflow_first = if cell.overflow_first_page == INVALID_PAGE_ID {
158 None
159 } else {
160 Some(cell.overflow_first_page)
161 };
162 let overflow_payload = read_overflow_chain(overflow_first, overflow_len)?;
163
164 let mut payload = cell.local_payload;
165 payload.extend_from_slice(&overflow_payload);
166 decode_stored_row_record(cell.rowid, &payload)
167}
168
169pub fn free_row_record_overflow<F>(cell_bytes: &[u8], mut free_overflow_chain: F) -> Result<()>
170where
171 F: FnMut(Option<u32>) -> Result<()>,
172{
173 let cell = RowidLeafCellLayout::decode(cell_bytes)?;
174 let overflow_first = if cell.overflow_first_page == INVALID_PAGE_ID {
175 None
176 } else {
177 Some(cell.overflow_first_page)
178 };
179 free_overflow_chain(overflow_first)
180}
181
182impl RowidLeafCell {
183 pub const HEADER_SIZE: usize = 12;
184
185 pub fn encode(&self) -> Vec<u8> {
186 let mut out = Vec::with_capacity(Self::HEADER_SIZE + self.payload.len());
187 out.extend_from_slice(&self.rowid.to_le_bytes());
188 out.extend_from_slice(&(self.payload.len() as u32).to_le_bytes());
189 out.extend_from_slice(&self.payload);
190 out
191 }
192
193 pub fn decode(data: &[u8]) -> Result<Self> {
194 if data.len() < Self::HEADER_SIZE {
195 return Err(HematiteError::CorruptedData(
196 "Rowid leaf cell header is truncated".to_string(),
197 ));
198 }
199
200 let rowid = u64::from_le_bytes([
201 data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
202 ]);
203 let payload_len = u32::from_le_bytes([data[8], data[9], data[10], data[11]]) as usize;
204 if Self::HEADER_SIZE + payload_len != data.len() {
205 return Err(HematiteError::CorruptedData(
206 "Rowid leaf cell payload length mismatch".to_string(),
207 ));
208 }
209
210 Ok(Self {
211 rowid,
212 payload: data[Self::HEADER_SIZE..].to_vec(),
213 })
214 }
215}
216
217#[derive(Debug, Clone, PartialEq, Eq)]
218pub struct RowidInternalCell {
219 pub separator_rowid: u64,
220 pub child_page_id: u32,
221}
222
223impl RowidInternalCell {
224 pub const SIZE: usize = 12;
225
226 pub fn encode(&self) -> [u8; Self::SIZE] {
227 let mut out = [0u8; Self::SIZE];
228 out[0..8].copy_from_slice(&self.separator_rowid.to_le_bytes());
229 out[8..12].copy_from_slice(&self.child_page_id.to_le_bytes());
230 out
231 }
232
233 pub fn decode(data: &[u8]) -> Result<Self> {
234 if data.len() != Self::SIZE {
235 return Err(HematiteError::CorruptedData(
236 "Rowid internal cell size mismatch".to_string(),
237 ));
238 }
239
240 let separator_rowid = u64::from_le_bytes([
241 data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
242 ]);
243 let child_page_id = u32::from_le_bytes([data[8], data[9], data[10], data[11]]);
244
245 Ok(Self {
246 separator_rowid,
247 child_page_id,
248 })
249 }
250}