1pub mod columns;
5pub mod fingerprint;
6pub mod values;
7
8use std::{
9 fmt,
10 fmt::Debug,
11 iter,
12 ops::Deref,
13 sync::{Arc, OnceLock},
14};
15
16use reifydb_value::{
17 reifydb_assertions,
18 value::{constraint::TypeConstraint, datetime::DateTime, system_columns::SystemColumn, value_type::ValueType},
19};
20use serde::{Deserialize, Serialize};
21
22use super::bytes::{
23 CATALOG_HEADER_SIZE, EncodedRowBuilder, QUEUE_ATTEMPT_HEADER_SIZE, QUEUE_DEDUPLICATION_HEADER_SIZE,
24 QUEUE_HEADER_SIZE, RowBuilder, SHAPE_HEADER_SIZE, read_created_at, read_defined_at, read_storage_time,
25 read_updated_at, write_fingerprint,
26};
27use crate::row::{
28 catalog::EncodedCatalogRowBuilder,
29 operator::{
30 EncodedOperatorRowBuilder, OPERATOR_HEADER_SIZE, read_time as read_operator_time,
31 write_time as write_operator_time,
32 },
33 pod::{EncodedPodRowBuilder, POD_HEADER_SIZE},
34 queue::EncodedQueueRowBuilder,
35 queue_attempt::EncodedQueueAttemptRowBuilder,
36 queue_deduplication::EncodedQueueDeduplicationRowBuilder,
37 ringbuffer::EncodedRingBufferRowBuilder,
38 series::EncodedSeriesRowBuilder,
39 shape::fingerprint::{RowShapeFingerprint, compute_fingerprint},
40 table::EncodedTableRowBuilder,
41};
42
43#[repr(u8)]
44#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
45pub enum RowFamily {
46 Catalog = 0x01,
47 Pod = 0x02,
48 Table = 0x03,
49 Series = 0x04,
50 RingBuffer = 0x05,
51 Queue = 0x06,
52 Operator = 0x07,
53 QueueAttempt = 0x08,
54 QueueDeduplication = 0x09,
55}
56
57impl RowFamily {
58 pub const fn header_size(self) -> usize {
59 match self {
60 Self::Catalog => CATALOG_HEADER_SIZE,
61 Self::Pod => POD_HEADER_SIZE,
62 Self::Table => SHAPE_HEADER_SIZE,
63 Self::Series => SHAPE_HEADER_SIZE,
64 Self::RingBuffer => SHAPE_HEADER_SIZE,
65 Self::Queue => QUEUE_HEADER_SIZE,
66 Self::Operator => OPERATOR_HEADER_SIZE,
67 Self::QueueAttempt => QUEUE_ATTEMPT_HEADER_SIZE,
68 Self::QueueDeduplication => QUEUE_DEDUPLICATION_HEADER_SIZE,
69 }
70 }
71
72 pub const fn system_columns(self) -> &'static [SystemColumn] {
73 match self {
74 Self::Table
75 | Self::Series
76 | Self::RingBuffer
77 | Self::Queue
78 | Self::QueueAttempt
79 | Self::QueueDeduplication => &[SystemColumn::CreatedAt, SystemColumn::UpdatedAt, SystemColumn::Time],
80 Self::Operator => &[SystemColumn::Time],
81 Self::Pod | Self::Catalog => &[],
82 }
83 }
84
85 #[inline]
86 pub fn updated_at(self, row: &[u8]) -> DateTime {
87 match self.system_columns().contains(&SystemColumn::UpdatedAt) {
88 true => read_updated_at(row),
89 false => panic!("{self:?} rows carry no updated_at"),
90 }
91 }
92
93 pub const fn from_u8(value: u8) -> Option<Self> {
94 match value {
95 0x01 => Some(Self::Catalog),
96 0x02 => Some(Self::Pod),
97 0x03 => Some(Self::Table),
98 0x04 => Some(Self::Series),
99 0x05 => Some(Self::RingBuffer),
100 0x06 => Some(Self::Queue),
101 0x07 => Some(Self::Operator),
102 0x08 => Some(Self::QueueAttempt),
103 0x09 => Some(Self::QueueDeduplication),
104 _ => None,
105 }
106 }
107}
108
109#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
110pub struct RowShapeField {
111 pub name: String,
112
113 pub constraint: TypeConstraint,
114
115 pub offset: u32,
116
117 pub size: u32,
118}
119
120impl RowShapeField {
121 pub fn new(name: impl Into<String>, constraint: TypeConstraint) -> Self {
122 let storage_type = constraint.storage_type();
123 Self {
124 name: name.into(),
125 constraint,
126 offset: 0,
127 size: storage_type.size() as u32,
128 }
129 }
130
131 pub fn unconstrained(name: impl Into<String>, field_type: ValueType) -> Self {
132 Self::new(name, TypeConstraint::unconstrained(field_type))
133 }
134}
135
136pub struct RowShape(Arc<Inner>);
137
138#[derive(Debug, Serialize, Deserialize)]
139pub struct Inner {
140 pub fingerprint: RowShapeFingerprint,
141
142 pub family: RowFamily,
143
144 pub fields: Vec<RowShapeField>,
145
146 #[serde(skip)]
147 cached_layout: OnceLock<usize>,
148}
149
150impl PartialEq for Inner {
151 fn eq(&self, other: &Self) -> bool {
152 self.fingerprint == other.fingerprint && self.family == other.family && self.fields == other.fields
153 }
154}
155
156impl Eq for Inner {}
157
158impl Deref for RowShape {
159 type Target = Inner;
160
161 fn deref(&self) -> &Self::Target {
162 &self.0
163 }
164}
165
166impl Clone for RowShape {
167 fn clone(&self) -> Self {
168 Self(self.0.clone())
169 }
170}
171
172impl Debug for RowShape {
173 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
174 self.0.fmt(f)
175 }
176}
177
178impl PartialEq for RowShape {
179 fn eq(&self, other: &Self) -> bool {
180 self.0.as_ref() == other.0.as_ref()
181 }
182}
183
184impl Eq for RowShape {}
185
186impl RowShape {
187 pub fn new(family: RowFamily, fields: Vec<RowShapeField>) -> Self {
188 let fields = Self::compute_layout(family, fields);
189 let fingerprint = compute_fingerprint(family, &fields);
190
191 Self(Arc::new(Inner {
192 fingerprint,
193 family,
194 fields,
195 cached_layout: OnceLock::new(),
196 }))
197 }
198
199 pub fn from_parts(family: RowFamily, fingerprint: RowShapeFingerprint, fields: Vec<RowShapeField>) -> Self {
200 Self(Arc::new(Inner {
201 fingerprint,
202 family,
203 fields,
204 cached_layout: OnceLock::new(),
205 }))
206 }
207
208 pub fn family(&self) -> RowFamily {
209 self.family
210 }
211
212 pub fn header_size(&self) -> usize {
213 self.family.header_size()
214 }
215
216 pub fn fingerprint(&self) -> RowShapeFingerprint {
217 self.fingerprint
218 }
219
220 pub fn fields(&self) -> &[RowShapeField] {
221 &self.fields
222 }
223
224 pub fn field_count(&self) -> usize {
225 self.fields.len()
226 }
227
228 pub fn find_field_index(&self, name: &str) -> Option<usize> {
229 self.fields.iter().position(|f| f.name == name)
230 }
231
232 pub fn get_field(&self, index: usize) -> Option<&RowShapeField> {
233 self.fields.get(index)
234 }
235
236 pub fn field_names(&self) -> impl Iterator<Item = &str> {
237 self.fields.iter().map(|f| f.name.as_str())
238 }
239
240 fn compute_layout(family: RowFamily, mut fields: Vec<RowShapeField>) -> Vec<RowShapeField> {
241 let bitvec_size = fields.len().div_ceil(8);
242 let mut offset: u32 = (family.header_size() + bitvec_size) as u32;
243
244 for field in fields.iter_mut() {
245 field.size = field.constraint.storage_type().size() as u32;
246 field.offset = offset;
247 offset += field.size;
248 }
249
250 fields
251 }
252
253 pub fn bitvec_size(&self) -> usize {
254 self.fields.len().div_ceil(8)
255 }
256
257 pub fn data_offset(&self) -> usize {
258 self.header_size() + self.bitvec_size()
259 }
260
261 #[inline]
262 pub fn is_defined(&self, row: &[u8], index: usize) -> bool {
263 read_defined_at(row, self.header_size(), index)
264 }
265
266 #[inline]
267 pub(crate) fn set_valid(&self, row: &mut impl RowBuilder, index: usize, valid: bool) {
268 row.set_valid_at(self.header_size(), index, valid);
269 }
270
271 #[inline]
272 pub fn time(&self, row: &[u8]) -> Option<DateTime> {
273 match (self.family.system_columns().contains(&SystemColumn::Time), self.family) {
274 (false, _) => None,
275 (true, RowFamily::Operator) => read_operator_time(row),
276 (true, _) => read_storage_time(row),
277 }
278 }
279
280 #[inline]
281 pub fn created_at(&self, row: &[u8]) -> DateTime {
282 match self.family.system_columns().contains(&SystemColumn::CreatedAt) {
283 true => read_created_at(row),
284 false => panic!("{} rows carry no created_at", format!("{:?}", self.family).to_lowercase()),
285 }
286 }
287
288 #[inline]
289 pub fn updated_at(&self, row: &[u8]) -> DateTime {
290 match self.family.system_columns().contains(&SystemColumn::UpdatedAt) {
291 true => read_updated_at(row),
292 false => panic!("{} rows carry no updated_at", format!("{:?}", self.family).to_lowercase()),
293 }
294 }
295
296 fn get_cached_layout(&self) -> usize {
297 *self.cached_layout.get_or_init(|| match self.fields.last() {
298 Some(last) => last.offset as usize + last.size as usize,
299 None => self.header_size() + self.bitvec_size(),
300 })
301 }
302
303 pub fn total_static_size(&self) -> usize {
304 self.get_cached_layout()
305 }
306
307 pub fn dynamic_section_start(&self) -> usize {
308 self.total_static_size()
309 }
310
311 pub fn dynamic_section_size(&self, row: &[u8]) -> usize {
312 row.len().saturating_sub(self.total_static_size())
313 }
314
315 pub(crate) fn read_dynamic_ref(&self, row: &[u8], index: usize) -> Option<(usize, usize)> {
316 if !self.is_defined(row, index) {
317 return None;
318 }
319 let field = &self.fields()[index];
320 match field.constraint.get_type().inner_type() {
321 ValueType::Utf8
322 | ValueType::Blob
323 | ValueType::Any
324 | ValueType::Digest {
325 ..
326 } => {
327 let ref_slice = &row[field.offset as usize..field.offset as usize + 8];
328 let offset =
329 u32::from_le_bytes([ref_slice[0], ref_slice[1], ref_slice[2], ref_slice[3]])
330 as usize;
331 let length =
332 u32::from_le_bytes([ref_slice[4], ref_slice[5], ref_slice[6], ref_slice[7]])
333 as usize;
334 Some((offset, length))
335 }
336 _ => None,
337 }
338 }
339
340 pub(crate) fn write_dynamic_ref(&self, row: &mut impl RowBuilder, index: usize, offset: usize, length: usize) {
341 let field = &self.fields()[index];
342 match field.constraint.get_type().inner_type() {
343 ValueType::Utf8
344 | ValueType::Blob
345 | ValueType::Any
346 | ValueType::Digest {
347 ..
348 } => {
349 let ref_slice =
350 &mut row.as_mut_slice()[field.offset as usize..field.offset as usize + 8];
351 ref_slice[0..4].copy_from_slice(&(offset as u32).to_le_bytes());
352 ref_slice[4..8].copy_from_slice(&(length as u32).to_le_bytes());
353 }
354 _ => {}
355 }
356 }
357
358 pub(crate) fn replace_dynamic_data(&self, row: &mut impl RowBuilder, index: usize, new_data: &[u8]) {
359 if let Some((old_offset, old_length)) = self.read_dynamic_ref(row.as_slice(), index) {
360 let delta = new_data.len() as isize - old_length as isize;
361
362 let refs_to_update: Vec<(usize, usize, usize)> = if delta != 0 {
363 self.fields()
364 .iter()
365 .enumerate()
366 .filter(|(i, _)| *i != index && self.is_defined(row.as_slice(), *i))
367 .filter_map(|(i, _)| {
368 self.read_dynamic_ref(row.as_slice(), i)
369 .filter(|(off, _)| *off > old_offset)
370 .map(|(off, len)| (i, off, len))
371 })
372 .collect()
373 } else {
374 vec![]
375 };
376
377 let dynamic_start = self.dynamic_section_start();
378 let abs_start = dynamic_start + old_offset;
379 let abs_end = abs_start + old_length;
380 row.splice(abs_start..abs_end, new_data.iter().copied());
381
382 self.write_dynamic_ref(row, index, old_offset, new_data.len());
383
384 for (i, off, len) in refs_to_update {
385 let new_off = (off as isize + delta) as usize;
386 self.write_dynamic_ref(row, i, new_off, len);
387 }
388 } else {
389 let dynamic_offset = self.dynamic_section_size(row.as_slice());
390 row.extend_from_slice(new_data);
391 self.write_dynamic_ref(row, index, dynamic_offset, new_data.len());
392 }
393 self.set_valid(row, index, true);
394 }
395
396 pub(crate) fn remove_dynamic_data(&self, row: &mut impl RowBuilder, index: usize) {
397 if let Some((old_offset, old_length)) = self.read_dynamic_ref(row.as_slice(), index) {
398 let refs_to_update: Vec<(usize, usize, usize)> = self
399 .fields()
400 .iter()
401 .enumerate()
402 .filter(|(i, _)| *i != index && self.is_defined(row.as_slice(), *i))
403 .filter_map(|(i, _)| {
404 self.read_dynamic_ref(row.as_slice(), i)
405 .filter(|(off, _)| *off > old_offset)
406 .map(|(off, len)| (i, off, len))
407 })
408 .collect();
409
410 let dynamic_start = self.dynamic_section_start();
411 let abs_start = dynamic_start + old_offset;
412 let abs_end = abs_start + old_length;
413 row.splice(abs_start..abs_end, iter::empty());
414
415 for (i, off, len) in refs_to_update {
416 let new_off = off - old_length;
417 self.write_dynamic_ref(row, i, new_off, len);
418 }
419 }
420 }
421
422 fn allocate(&self) -> EncodedRowBuilder {
423 let total_size = self.get_cached_layout();
424 let mut row = EncodedRowBuilder::zeroed(total_size);
425 match self.family {
426 RowFamily::Pod => {}
427 RowFamily::Operator => write_operator_time(row.as_mut_slice(), DateTime::MAX),
428 _ => write_fingerprint(row.as_mut_slice(), self.fingerprint),
429 }
430 reifydb_assertions! {
431 assert!(
432 row.len() == total_size,
433 "allocated row length does not match the shape total_static_size, so any field accessor using pre-computed offsets will read from garbage memory (row_len={} total_size={})",
434 row.len(),
435 total_size
436 );
437 }
438 row
439 }
440
441 pub fn allocate_catalog(&self) -> EncodedCatalogRowBuilder {
442 assert_eq!(self.family, RowFamily::Catalog, "allocate_catalog on a shape of another family");
443 EncodedCatalogRowBuilder::wrap(self.allocate())
444 }
445
446 pub fn allocate_pod(&self) -> EncodedPodRowBuilder {
447 assert_eq!(self.family, RowFamily::Pod, "allocate_pod on a shape of another family");
448 EncodedPodRowBuilder::wrap(self.allocate())
449 }
450
451 pub fn allocate_operator(&self) -> EncodedOperatorRowBuilder {
452 assert_eq!(self.family, RowFamily::Operator, "allocate_operator on a shape of another family");
453 EncodedOperatorRowBuilder::wrap(self.allocate())
454 }
455
456 pub fn allocate_table(&self) -> EncodedTableRowBuilder {
457 assert_eq!(self.family, RowFamily::Table, "allocate_table on a shape of another family");
458 EncodedTableRowBuilder::wrap(self.allocate())
459 }
460
461 pub fn allocate_series(&self) -> EncodedSeriesRowBuilder {
462 assert_eq!(self.family, RowFamily::Series, "allocate_series on a shape of another family");
463 EncodedSeriesRowBuilder::wrap(self.allocate())
464 }
465
466 pub fn allocate_ringbuffer(&self) -> EncodedRingBufferRowBuilder {
467 assert_eq!(self.family, RowFamily::RingBuffer, "allocate_ringbuffer on a shape of another family");
468 EncodedRingBufferRowBuilder::wrap(self.allocate())
469 }
470
471 pub fn allocate_queue(&self) -> EncodedQueueRowBuilder {
472 assert_eq!(self.family, RowFamily::Queue, "allocate_queue on a shape of another family");
473 EncodedQueueRowBuilder::wrap(self.allocate())
474 }
475
476 pub fn allocate_queue_attempt(&self) -> EncodedQueueAttemptRowBuilder {
477 assert_eq!(self.family, RowFamily::QueueAttempt, "allocate_queue_attempt on a shape of another family");
478 EncodedQueueAttemptRowBuilder::wrap(self.allocate())
479 }
480
481 pub fn allocate_queue_deduplication(&self) -> EncodedQueueDeduplicationRowBuilder {
482 assert_eq!(
483 self.family,
484 RowFamily::QueueDeduplication,
485 "allocate_queue_deduplication on a shape of another family"
486 );
487 EncodedQueueDeduplicationRowBuilder::wrap(self.allocate())
488 }
489
490 pub fn set_none(&self, row: &mut impl RowBuilder, index: usize) {
491 self.remove_dynamic_data(row, index);
492 self.set_valid(row, index, false);
493 }
494
495 pub fn testing(family: RowFamily, types: &[ValueType]) -> Self {
496 RowShape::new(
497 family,
498 types.iter()
499 .enumerate()
500 .map(|(i, t)| RowShapeField::unconstrained(format!("f{}", i), t.clone()))
501 .collect(),
502 )
503 }
504}