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