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