Skip to main content

mito_codec/row_converter/
sparse.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15mod checked;
16
17use std::collections::{HashMap, HashSet};
18use std::sync::Arc;
19
20use bytes::BufMut;
21use common_recordbatch::filter::SimpleFilterEvaluator;
22use datatypes::prelude::ConcreteDataType;
23use datatypes::value::{Value, ValueRef};
24use memcomparable::{Deserializer, Serializer};
25use serde::{Deserialize, Serialize};
26use snafu::{OptionExt, ResultExt, ensure};
27use store_api::codec::PrimaryKeyEncoding;
28use store_api::metadata::RegionMetadataRef;
29use store_api::storage::ColumnId;
30use store_api::storage::consts::ReservedColumnId;
31
32use crate::error::{
33    DeserializeFieldSnafu, InvalidSparsePrimaryKeySnafu, Result, SerializeFieldSnafu,
34    UnsupportedOperationSnafu,
35};
36use crate::key_values::KeyValue;
37use crate::primary_key_filter::SparsePrimaryKeyFilter;
38use crate::row_converter::dense::SortField;
39pub use crate::row_converter::sparse::checked::SparsePrimaryKeyView;
40use crate::row_converter::{CompositeValues, PrimaryKeyCodec, PrimaryKeyFilter};
41
42/// A codec for sparse keys with reserved table ID and TSID columns.
43///
44/// ## Encoding format
45/// Each primary key is encoded as a sequence of `(column_id, value)` pairs:
46/// - Keys start with reserved `table_id` (uint32) and `tsid` (uint64).
47/// - String tags follow the reserved prefix; null tags are omitted.
48///
49/// The `column_id` is encoded as a 4-byte big-endian integer, and the value is encoded
50/// using memcomparable serialization.
51///
52/// `decode_leftmost` returns the reserved `table_id` value.
53///
54/// ## Requirements
55/// Encoders supply columns in the layout's order using stable physical-region IDs.
56#[derive(Clone, Debug)]
57pub struct SparsePrimaryKeyCodec {
58    inner: Arc<SparsePrimaryKeyCodecInner>,
59}
60
61#[derive(Debug, Clone)]
62struct SparsePrimaryKeyCodecInner {
63    fields: Option<Vec<(ColumnId, SortField)>>,
64    // Internal fields
65    table_id_field: SortField,
66    // Internal fields
67    tsid_field: SortField,
68    // User defined label field
69    label_field: SortField,
70    // Columns in primary key
71    //
72    // None means all unknown columns is primary key(`Self::label_field`).
73    columns: Option<HashSet<ColumnId>>,
74}
75
76/// Sparse values representation.
77///
78/// Callers must not insert a column id that is already present; otherwise
79/// the existing entry will shadow the newly inserted value on lookup.
80#[derive(Debug, Clone, PartialEq, Eq, Default)]
81pub struct SparseValues {
82    values: Vec<(ColumnId, Value)>,
83}
84
85impl SparseValues {
86    /// Creates an empty [`SparseValues`].
87    pub fn new() -> Self {
88        Self { values: Vec::new() }
89    }
90
91    /// Creates an empty [`SparseValues`] with space reserved for `cap` entries.
92    pub fn with_capacity(cap: usize) -> Self {
93        Self {
94            values: Vec::with_capacity(cap),
95        }
96    }
97
98    /// Returns the value of the given column, or [`Value::Null`] if the column is not present.
99    pub fn get_or_null(&self, column_id: ColumnId) -> &Value {
100        for (id, value) in &self.values {
101            if *id == column_id {
102                return value;
103            }
104        }
105        &Value::Null
106    }
107
108    /// Returns the value of the given column, or [`None`] if the column is not present.
109    pub fn get(&self, column_id: &ColumnId) -> Option<&Value> {
110        for (id, value) in &self.values {
111            if id == column_id {
112                return Some(value);
113            }
114        }
115        None
116    }
117
118    /// Appends a new `(column_id, value)` pair.
119    ///
120    /// Append-only: the caller must ensure `column_id` is not already present.
121    pub fn insert(&mut self, column_id: ColumnId, value: Value) {
122        self.values.push((column_id, value));
123    }
124
125    /// Returns an iterator over all stored column id/value pairs.
126    pub fn iter(&self) -> impl Iterator<Item = (&ColumnId, &Value)> {
127        self.values.iter().map(|(id, value)| (id, value))
128    }
129}
130
131/// The column id of the tsid.
132pub const RESERVED_COLUMN_ID_TSID: ColumnId = ReservedColumnId::tsid();
133/// The column id of the table id.
134pub const RESERVED_COLUMN_ID_TABLE_ID: ColumnId = ReservedColumnId::table_id();
135/// The size of the column id in the encoded sparse row.
136pub const COLUMN_ID_ENCODE_SIZE: usize = 4;
137
138// Fixed byte offsets for reserved columns in the sparse encoding.
139// Layout: [table_id_col_id: 4B][marker: 1B][table_id: 4B][tsid_col_id: 4B][marker: 1B][tsid: 8B]
140/// Byte offset to the table_id value (after its 4-byte column id).
141const TABLE_ID_VALUE_OFFSET: usize = COLUMN_ID_ENCODE_SIZE;
142/// Byte offset to the tsid value (after 9-byte table_id entry + 4-byte tsid column id).
143const TSID_VALUE_OFFSET: usize = COLUMN_ID_ENCODE_SIZE + 5 + COLUMN_ID_ENCODE_SIZE;
144/// Byte offset where tag columns start (after 9-byte table_id + 13-byte tsid entries).
145const TAGS_START_OFFSET: usize = COLUMN_ID_ENCODE_SIZE + 5 + COLUMN_ID_ENCODE_SIZE + 9;
146
147/// Validates complete sparse keys without materializing their values.
148///
149/// Scratch buffers retain capacity between keys; validation does not depend on region metadata.
150#[derive(Default)]
151pub struct SparsePrimaryKeyValidator {
152    column_ids: Vec<ColumnId>,
153    label_buf: Vec<u8>,
154}
155
156impl SparsePrimaryKeyValidator {
157    /// Checks the prefix, all label framing and UTF-8, and rejects duplicate or reserved labels.
158    pub fn validate(&mut self, bytes: &[u8]) -> Result<()> {
159        self.column_ids.clear();
160        validate_prefix(bytes)?;
161        let mut remaining = &bytes[TAGS_START_OFFSET..];
162        while !remaining.is_empty() {
163            let id = remaining.first_chunk::<COLUMN_ID_ENCODE_SIZE>().context(
164                InvalidSparsePrimaryKeySnafu {
165                    reason: "truncated label column id",
166                },
167            )?;
168            let column_id = u32::from_be_bytes(*id);
169            ensure!(
170                !ReservedColumnId::is_reserved(column_id),
171                InvalidSparsePrimaryKeySnafu {
172                    reason: "reserved column id in sparse labels",
173                }
174            );
175            self.column_ids.push(column_id);
176            let encoded = &remaining[COLUMN_ID_ENCODE_SIZE..];
177            let (length, ascii) = crate::row_converter::encoded_string_info::<true>(encoded)
178                .context(DeserializeFieldSnafu)?;
179            let encoded = &encoded[..length];
180            // Framing is already checked; ASCII needs no unchunking to establish valid UTF-8.
181            if !ascii {
182                self.label_buf.clear();
183                self.label_buf.reserve(length);
184                Deserializer::new(&encoded[1..])
185                    .read_bytes_into(&mut self.label_buf)
186                    .context(DeserializeFieldSnafu)?;
187                std::str::from_utf8(&self.label_buf).map_err(|_| {
188                    InvalidSparsePrimaryKeySnafu {
189                        reason: "label is not valid UTF-8",
190                    }
191                    .build()
192                })?;
193            }
194            remaining = &remaining[COLUMN_ID_ENCODE_SIZE + length..];
195        }
196        self.column_ids.sort_unstable();
197        ensure!(
198            !self.column_ids.windows(2).any(|pair| pair[0] == pair[1]),
199            InvalidSparsePrimaryKeySnafu {
200                reason: "duplicate column id in sparse key",
201            }
202        );
203        Ok(())
204    }
205}
206
207/// Inline capacity for the small-vec fast path of [`SparseOffsetsCache`].
208///
209/// Most sparse primary keys carry only a handful of tags, so a linear scan
210/// over a short `Vec` beats a `HashMap` lookup. Tags beyond this capacity
211/// spill into the overflow `HashMap`.
212const SPARSE_OFFSETS_INLINE_CAP: usize = 32;
213
214/// A lazily populated cache of tag column offsets inside a sparse primary key.
215#[derive(Debug, Clone)]
216pub struct SparseOffsetsCache {
217    /// Small-vec fast path. Reserves [`SPARSE_OFFSETS_INLINE_CAP`] slots on
218    /// the first insert.
219    inline: Vec<(ColumnId, usize)>,
220    /// Overflow for columns beyond the inline capacity. Lazily allocated.
221    overflow: HashMap<ColumnId, usize>,
222    /// Next byte position in the pk to resume parsing from.
223    cursor: usize,
224    /// True once the decoder has walked past the last tag column (or stopped
225    /// on an unknown column id); no further offsets can be discovered.
226    finished: bool,
227}
228
229impl Default for SparseOffsetsCache {
230    fn default() -> Self {
231        Self::new()
232    }
233}
234
235impl SparseOffsetsCache {
236    pub fn new() -> Self {
237        Self {
238            inline: Vec::new(),
239            overflow: HashMap::new(),
240            cursor: TAGS_START_OFFSET,
241            finished: false,
242        }
243    }
244
245    pub fn clear(&mut self) {
246        self.inline.clear();
247        self.overflow.clear();
248        self.cursor = TAGS_START_OFFSET;
249        self.finished = false;
250    }
251
252    /// Returns the cached offset for `column_id`, if any.
253    fn get(&self, column_id: ColumnId) -> Option<usize> {
254        for entry in &self.inline {
255            if entry.0 == column_id {
256                return Some(entry.1);
257            }
258        }
259        self.overflow.get(&column_id).copied()
260    }
261
262    /// Records a new `(column_id, offset)` entry.
263    fn insert(&mut self, column_id: ColumnId, offset: usize) {
264        if self.inline.len() < SPARSE_OFFSETS_INLINE_CAP {
265            if self.inline.capacity() == 0 {
266                self.inline.reserve_exact(SPARSE_OFFSETS_INLINE_CAP);
267            }
268            self.inline.push((column_id, offset));
269        } else {
270            self.overflow.insert(column_id, offset);
271        }
272    }
273
274    #[cfg(test)]
275    fn contains(&self, column_id: ColumnId) -> bool {
276        self.get(column_id).is_some()
277    }
278}
279
280impl SparsePrimaryKeyCodec {
281    /// Creates a new [`SparsePrimaryKeyCodec`] instance.
282    pub fn from_columns(columns_ids: impl Iterator<Item = ColumnId>) -> Self {
283        let columns = columns_ids.collect();
284        Self {
285            inner: Arc::new(SparsePrimaryKeyCodecInner {
286                fields: None,
287                table_id_field: SortField::new(ConcreteDataType::uint32_datatype()),
288                tsid_field: SortField::new(ConcreteDataType::uint64_datatype()),
289                label_field: SortField::new(ConcreteDataType::string_datatype()),
290                columns: Some(columns),
291            }),
292        }
293    }
294
295    /// Creates a new [`SparsePrimaryKeyCodec`] instance.
296    pub fn new(region_metadata: &RegionMetadataRef) -> Self {
297        let fields = region_metadata
298            .primary_key_columns()
299            .map(|c| {
300                (
301                    c.column_id,
302                    SortField::new(c.column_schema.data_type.clone()),
303                )
304            })
305            .collect();
306        Self::with_fields(fields)
307    }
308
309    /// Returns a new [`SparsePrimaryKeyCodec`] instance.
310    ///
311    /// It treats all unknown columns as primary key(label field).
312    pub fn schemaless() -> Self {
313        Self {
314            inner: Arc::new(SparsePrimaryKeyCodecInner {
315                fields: None,
316                table_id_field: SortField::new(ConcreteDataType::uint32_datatype()),
317                tsid_field: SortField::new(ConcreteDataType::uint64_datatype()),
318                label_field: SortField::new(ConcreteDataType::string_datatype()),
319                columns: None,
320            }),
321        }
322    }
323
324    /// Creates a schema-aware sparse codec.
325    pub fn with_fields(fields: Vec<(ColumnId, SortField)>) -> Self {
326        let mut codec = Self::from_columns(fields.iter().map(|f| f.0));
327        Arc::make_mut(&mut codec.inner).fields = Some(fields);
328        codec
329    }
330
331    /// Returns the field of the given column id.
332    fn get_field(&self, column_id: ColumnId) -> Option<&SortField> {
333        if let Some(columns) = &self.inner.columns
334            && !columns.contains(&column_id)
335        {
336            return None;
337        }
338        match column_id {
339            RESERVED_COLUMN_ID_TABLE_ID => Some(&self.inner.table_id_field),
340            RESERVED_COLUMN_ID_TSID => Some(&self.inner.tsid_field),
341            _ => Some(&self.inner.label_field),
342        }
343    }
344
345    /// Encodes the given bytes into a [`SparseValues`].
346    pub fn encode_to_vec<'a, I>(&self, row: I, buffer: &mut Vec<u8>) -> Result<()>
347    where
348        I: Iterator<Item = (ColumnId, ValueRef<'a>)>,
349    {
350        let mut serializer = Serializer::new(buffer);
351        for (column_id, value) in row {
352            if value.is_null() {
353                continue;
354            }
355
356            if let Some(field) = self.get_field(column_id) {
357                column_id
358                    .serialize(&mut serializer)
359                    .context(SerializeFieldSnafu)?;
360                field.serialize(&mut serializer, &value)?;
361            } else {
362                // TODO(weny): handle the error.
363                common_telemetry::warn!("Column {} is not in primary key, skipping", column_id);
364            }
365        }
366        Ok(())
367    }
368
369    pub fn encode_raw_tag_value<'a, I>(&self, row: I, buffer: &mut Vec<u8>) -> Result<()>
370    where
371        I: Iterator<Item = (ColumnId, &'a [u8])>,
372    {
373        for (tag_column_id, tag_value) in row {
374            let value_len = tag_value.len();
375            buffer.reserve(6 + value_len.div_ceil(8) * 9);
376            buffer.put_u32(tag_column_id);
377            buffer.put_u8(1);
378            buffer.put_u8(!tag_value.is_empty() as u8);
379
380            // Manual implementation of memcomparable::ser::Serializer::serialize_bytes
381            // to avoid byte-by-byte put.
382            let mut len = 0;
383            let num_chucks = value_len / 8;
384            let remainder = value_len % 8;
385
386            for idx in 0..num_chucks {
387                buffer.extend_from_slice(&tag_value[idx * 8..idx * 8 + 8]);
388                len += 8;
389                // append an extra byte that signals the number of significant bytes in this chunk
390                // 1-8: many bytes were significant and this group is the last group
391                // 9: all 8 bytes were significant and there is more data to come
392                let extra = if len == value_len { 8 } else { 9 };
393                buffer.put_u8(extra);
394            }
395
396            if remainder != 0 {
397                buffer.extend_from_slice(&tag_value[len..value_len]);
398                buffer.put_bytes(0, 8 - remainder);
399                buffer.put_u8(remainder as u8);
400            }
401        }
402        Ok(())
403    }
404
405    /// Encodes the given bytes into a [`SparseValues`].
406    pub fn encode_internal(&self, table_id: u32, tsid: u64, buffer: &mut Vec<u8>) -> Result<()> {
407        buffer.reserve_exact(22);
408        buffer.put_u32(RESERVED_COLUMN_ID_TABLE_ID);
409        buffer.put_u8(1);
410        buffer.put_u32(table_id);
411        buffer.put_u32(RESERVED_COLUMN_ID_TSID);
412        buffer.put_u8(1);
413        buffer.put_u64(tsid);
414        Ok(())
415    }
416
417    /// Decodes the reserved `(table_id, tsid)` prefix from a sparse primary key.
418    pub fn decode_ids(&self, bytes: &[u8]) -> Result<(u32, u64)> {
419        // Two column IDs, two non-null markers, a u32 table ID, and a u64 TSID.
420        const INTERNAL_PREFIX_LEN: usize = 4 + 1 + 4 + 4 + 1 + 8;
421        ensure!(
422            bytes.len() >= INTERNAL_PREFIX_LEN,
423            InvalidSparsePrimaryKeySnafu {
424                reason: format!(
425                    "internal prefix requires at least {INTERNAL_PREFIX_LEN} bytes, got {}",
426                    bytes.len()
427                ),
428            }
429        );
430
431        let mut deserializer = Deserializer::new(bytes);
432
433        let table_id_column = u32::deserialize(&mut deserializer).context(DeserializeFieldSnafu)?;
434        ensure!(
435            table_id_column == RESERVED_COLUMN_ID_TABLE_ID,
436            InvalidSparsePrimaryKeySnafu {
437                reason: format!(
438                    "expected table id column {}, got {}",
439                    RESERVED_COLUMN_ID_TABLE_ID, table_id_column
440                ),
441            }
442        );
443        let table_id = self.inner.table_id_field.deserialize(&mut deserializer)?;
444
445        let tsid_column = u32::deserialize(&mut deserializer).context(DeserializeFieldSnafu)?;
446        ensure!(
447            tsid_column == RESERVED_COLUMN_ID_TSID,
448            InvalidSparsePrimaryKeySnafu {
449                reason: format!(
450                    "expected tsid column {}, got {}",
451                    RESERVED_COLUMN_ID_TSID, tsid_column
452                ),
453            }
454        );
455        let tsid = self.inner.tsid_field.deserialize(&mut deserializer)?;
456
457        match (table_id, tsid) {
458            (Value::UInt32(table_id), Value::UInt64(tsid)) => Ok((table_id, tsid)),
459            (table_id, tsid) => InvalidSparsePrimaryKeySnafu {
460                reason: format!(
461                    "expected UInt32 table id and UInt64 tsid, got {table_id:?} and {tsid:?}"
462                ),
463            }
464            .fail(),
465        }
466    }
467
468    /// Decodes the given bytes into a [`SparseValues`].
469    fn decode_sparse(&self, bytes: &[u8]) -> Result<SparseValues> {
470        let mut values = SparseValues::with_capacity(16);
471        let (table_id, tsid) = self.decode_ids(bytes)?;
472        values.insert(RESERVED_COLUMN_ID_TABLE_ID, Value::UInt32(table_id));
473        values.insert(RESERVED_COLUMN_ID_TSID, Value::UInt64(tsid));
474        let mut remaining = &bytes[TAGS_START_OFFSET..];
475        while !remaining.is_empty() {
476            let id = remaining.first_chunk::<COLUMN_ID_ENCODE_SIZE>().context(
477                InvalidSparsePrimaryKeySnafu {
478                    reason: "truncated label column id",
479                },
480            )?;
481            let column_id = u32::from_be_bytes(*id);
482            ensure!(
483                !ReservedColumnId::is_reserved(column_id),
484                InvalidSparsePrimaryKeySnafu {
485                    reason: "reserved column id in sparse labels"
486                }
487            );
488            let encoded = &remaining[COLUMN_ID_ENCODE_SIZE..];
489            let length =
490                crate::row_converter::encoded_string_len(encoded).context(DeserializeFieldSnafu)?;
491            let value = self
492                .inner
493                .label_field
494                .deserialize(&mut Deserializer::new(&encoded[..length]))?;
495            ensure!(
496                values.get(&column_id).is_none(),
497                InvalidSparsePrimaryKeySnafu {
498                    reason: "duplicate column id in sparse key",
499                }
500            );
501            values.insert(column_id, value);
502            remaining = &encoded[length..];
503        }
504        Ok(values)
505    }
506
507    /// Decodes the reserved table ID from the key prefix.
508    fn decode_leftmost(&self, bytes: &[u8]) -> Result<Option<Value>> {
509        if bytes.is_empty() {
510            return Ok(None);
511        }
512        self.decode_ids(bytes)
513            .map(|(table_id, _)| Some(Value::UInt32(table_id)))
514    }
515
516    /// Returns the offset of the given column id in the given primary key.
517    ///
518    /// The pk must start with the table_id + tsid prefix written by
519    /// `encode_internal`.
520    ///
521    /// # Panics
522    ///
523    /// Panics if `pk` is not a well-formed sparse primary key produced by
524    /// this codec (e.g. truncated or otherwise malformed bytes).
525    pub fn has_column(
526        &self,
527        pk: &[u8],
528        cache: &mut SparseOffsetsCache,
529        column_id: ColumnId,
530    ) -> Option<usize> {
531        // Decoding is lazy: on each call we only advance the cache's cursor as
532        // far as needed to answer the query. A column that has already been
533        // seen returns immediately; a column we haven't reached yet causes the
534        // parser to resume from `cache.cursor` and stop as soon as the column
535        // is located. Once the cursor walks off the end (or hits an unknown
536        // column id) the cache is marked finished, so subsequent misses are
537        // O(1).
538        // table_id and tsid are at fixed offsets.
539        match column_id {
540            RESERVED_COLUMN_ID_TABLE_ID => return Some(TABLE_ID_VALUE_OFFSET),
541            RESERVED_COLUMN_ID_TSID => return Some(TSID_VALUE_OFFSET),
542            _ => {}
543        }
544
545        if let Some(offset) = cache.get(column_id) {
546            return Some(offset);
547        }
548        if cache.finished {
549            return None;
550        }
551
552        let mut deserializer = Deserializer::new(pk);
553        deserializer.advance(cache.cursor);
554        let mut offset = cache.cursor;
555        while deserializer.has_remaining() {
556            let col = u32::deserialize(&mut deserializer).unwrap();
557            offset += COLUMN_ID_ENCODE_SIZE;
558            let value_offset = offset;
559            cache.insert(col, value_offset);
560            let Some(field) = self.get_field(col) else {
561                cache.finished = true;
562                cache.cursor = offset;
563                return None;
564            };
565
566            let skip = field.skip_deserialize(pk, &mut deserializer).unwrap();
567            offset += skip;
568            cache.cursor = offset;
569            if col == column_id {
570                return Some(value_offset);
571            }
572        }
573
574        cache.finished = true;
575        None
576    }
577
578    /// Decode value at `offset` in `pk`.
579    pub fn decode_value_at(&self, pk: &[u8], offset: usize, column_id: ColumnId) -> Result<Value> {
580        let mut deserializer = Deserializer::new(pk);
581        deserializer.advance(offset);
582        // Safety: checked by `has_column`
583        let field = self.get_field(column_id).unwrap();
584        field.deserialize(&mut deserializer)
585    }
586
587    /// Returns the encoded bytes of the given `column_id` in `pk`.
588    ///
589    /// Returns `Ok(None)` if the `column_id` is missing in `pk`.
590    pub fn encoded_value_for_column<'a>(
591        &self,
592        pk: &'a [u8],
593        cache: &mut SparseOffsetsCache,
594        column_id: ColumnId,
595    ) -> Result<Option<&'a [u8]>> {
596        let Some(offset) = self.has_column(pk, cache, column_id) else {
597            return Ok(None);
598        };
599
600        let Some(field) = self.get_field(column_id) else {
601            return Ok(None);
602        };
603
604        let mut deserializer = Deserializer::new(pk);
605        deserializer.advance(offset);
606        let len = field.skip_deserialize(pk, &mut deserializer)?;
607        Ok(Some(&pk[offset..offset + len]))
608    }
609}
610
611impl PrimaryKeyCodec for SparsePrimaryKeyCodec {
612    fn encode_key_value(&self, key_value: &KeyValue, buffer: &mut Vec<u8>) -> Result<()> {
613        let fields = self
614            .inner
615            .fields
616            .as_ref()
617            .context(UnsupportedOperationSnafu {
618                err_msg: "raw row encoding requires primary key metadata",
619            })?;
620        self.encode_to_vec(
621            fields.iter().map(|f| f.0).zip(key_value.primary_keys()),
622            buffer,
623        )
624    }
625
626    fn encode_values(&self, values: &[(ColumnId, Value)], buffer: &mut Vec<u8>) -> Result<()> {
627        self.encode_to_vec(values.iter().map(|v| (v.0, v.1.as_value_ref())), buffer)
628    }
629
630    fn encode_value_refs(
631        &self,
632        values: &[(ColumnId, ValueRef)],
633        buffer: &mut Vec<u8>,
634    ) -> Result<()> {
635        self.encode_to_vec(values.iter().map(|v| (v.0, v.1.clone())), buffer)
636    }
637
638    fn estimated_size(&self) -> Option<usize> {
639        None
640    }
641
642    fn num_fields(&self) -> Option<usize> {
643        None
644    }
645
646    fn encoding(&self) -> PrimaryKeyEncoding {
647        PrimaryKeyEncoding::Sparse
648    }
649
650    fn primary_key_filter(
651        &self,
652        metadata: &RegionMetadataRef,
653        filters: Arc<Vec<SimpleFilterEvaluator>>,
654    ) -> Box<dyn PrimaryKeyFilter> {
655        Box::new(SparsePrimaryKeyFilter::new(
656            metadata.clone(),
657            filters,
658            self.clone(),
659        ))
660    }
661
662    fn decode(&self, bytes: &[u8]) -> Result<CompositeValues> {
663        Ok(CompositeValues::Sparse(self.decode_sparse(bytes)?))
664    }
665
666    fn decode_leftmost(&self, bytes: &[u8]) -> Result<Option<Value>> {
667        self.decode_leftmost(bytes)
668    }
669}
670
671fn validate_prefix(pk: &[u8]) -> Result<()> {
672    ensure!(
673        pk.len() >= TAGS_START_OFFSET
674            && pk[..COLUMN_ID_ENCODE_SIZE] == RESERVED_COLUMN_ID_TABLE_ID.to_be_bytes()
675            && pk[TSID_VALUE_OFFSET - COLUMN_ID_ENCODE_SIZE..TSID_VALUE_OFFSET]
676                == RESERVED_COLUMN_ID_TSID.to_be_bytes()
677            && pk[TABLE_ID_VALUE_OFFSET] == 1
678            && pk[TSID_VALUE_OFFSET] == 1,
679        InvalidSparsePrimaryKeySnafu {
680            reason: "invalid table_id/tsid prefix"
681        }
682    );
683    Ok(())
684}
685
686#[cfg(test)]
687mod tests {
688    use std::sync::Arc;
689
690    use api::v1::SemanticType;
691    use common_query::prelude::{greptime_timestamp, greptime_value};
692    use common_time::Timestamp;
693    use common_time::timestamp::TimeUnit;
694    use datatypes::schema::ColumnSchema;
695    use datatypes::value::{OrderedFloat, Value};
696    use store_api::metadata::{ColumnMetadata, RegionMetadataBuilder};
697    use store_api::metric_engine_consts::{
698        DATA_SCHEMA_TABLE_ID_COLUMN_NAME, DATA_SCHEMA_TSID_COLUMN_NAME,
699    };
700    use store_api::storage::{ColumnId, RegionId};
701
702    use super::*;
703
704    fn test_region_metadata() -> RegionMetadataRef {
705        let mut builder = RegionMetadataBuilder::new(RegionId::new(1, 1));
706        builder
707            .push_column_metadata(ColumnMetadata {
708                column_schema: ColumnSchema::new(
709                    DATA_SCHEMA_TABLE_ID_COLUMN_NAME,
710                    ConcreteDataType::uint32_datatype(),
711                    false,
712                ),
713                semantic_type: SemanticType::Tag,
714                column_id: ReservedColumnId::table_id(),
715            })
716            .push_column_metadata(ColumnMetadata {
717                column_schema: ColumnSchema::new(
718                    DATA_SCHEMA_TSID_COLUMN_NAME,
719                    ConcreteDataType::uint64_datatype(),
720                    false,
721                ),
722                semantic_type: SemanticType::Tag,
723                column_id: ReservedColumnId::tsid(),
724            })
725            .push_column_metadata(ColumnMetadata {
726                column_schema: ColumnSchema::new("pod", ConcreteDataType::string_datatype(), true),
727                semantic_type: SemanticType::Tag,
728                column_id: 1,
729            })
730            .push_column_metadata(ColumnMetadata {
731                column_schema: ColumnSchema::new(
732                    "namespace",
733                    ConcreteDataType::string_datatype(),
734                    true,
735                ),
736                semantic_type: SemanticType::Tag,
737                column_id: 2,
738            })
739            .push_column_metadata(ColumnMetadata {
740                column_schema: ColumnSchema::new(
741                    "container",
742                    ConcreteDataType::string_datatype(),
743                    true,
744                ),
745                semantic_type: SemanticType::Tag,
746                column_id: 3,
747            })
748            .push_column_metadata(ColumnMetadata {
749                column_schema: ColumnSchema::new(
750                    "pod_name",
751                    ConcreteDataType::string_datatype(),
752                    true,
753                ),
754                semantic_type: SemanticType::Tag,
755                column_id: 4,
756            })
757            .push_column_metadata(ColumnMetadata {
758                column_schema: ColumnSchema::new(
759                    "pod_ip",
760                    ConcreteDataType::string_datatype(),
761                    true,
762                ),
763                semantic_type: SemanticType::Tag,
764                column_id: 5,
765            })
766            .push_column_metadata(ColumnMetadata {
767                column_schema: ColumnSchema::new(
768                    greptime_value(),
769                    ConcreteDataType::float64_datatype(),
770                    false,
771                ),
772                semantic_type: SemanticType::Field,
773                column_id: 6,
774            })
775            .push_column_metadata(ColumnMetadata {
776                column_schema: ColumnSchema::new(
777                    greptime_timestamp(),
778                    ConcreteDataType::timestamp_nanosecond_datatype(),
779                    false,
780                ),
781                semantic_type: SemanticType::Timestamp,
782                column_id: 7,
783            })
784            .primary_key(vec![
785                ReservedColumnId::table_id(),
786                ReservedColumnId::tsid(),
787                1,
788                2,
789                3,
790                4,
791                5,
792            ]);
793        let metadata = builder.build().unwrap();
794        Arc::new(metadata)
795    }
796
797    #[test]
798    fn test_sparse_value_new_and_get_or_null() {
799        let mut sparse_value = SparseValues::new();
800        sparse_value.insert(1, Value::Int32(42));
801
802        assert_eq!(sparse_value.get_or_null(1), &Value::Int32(42));
803        assert_eq!(sparse_value.get_or_null(2), &Value::Null);
804    }
805
806    #[test]
807    fn test_sparse_value_insert() {
808        let mut sparse_value = SparseValues::new();
809        sparse_value.insert(1, Value::Int32(42));
810
811        assert_eq!(sparse_value.get_or_null(1), &Value::Int32(42));
812    }
813
814    fn test_row() -> Vec<(ColumnId, ValueRef<'static>)> {
815        vec![
816            (RESERVED_COLUMN_ID_TABLE_ID, ValueRef::UInt32(42)),
817            (
818                RESERVED_COLUMN_ID_TSID,
819                ValueRef::UInt64(123843349035232323),
820            ),
821            // label: pod
822            (1, ValueRef::String("greptime-frontend-6989d9899-22222")),
823            // label: namespace
824            (2, ValueRef::String("greptime-cluster")),
825            // label: container
826            (3, ValueRef::String("greptime-frontend-6989d9899-22222")),
827            // label: pod_name
828            (4, ValueRef::String("greptime-frontend-6989d9899-22222")),
829            // label: pod_ip
830            (5, ValueRef::String("10.10.10.10")),
831            // field: greptime_value
832            (6, ValueRef::Float64(OrderedFloat(1.0))),
833            // field: greptime_timestamp
834            (
835                7,
836                ValueRef::Timestamp(Timestamp::new(1618876800000000000, TimeUnit::Nanosecond)),
837            ),
838        ]
839    }
840
841    #[test]
842    fn test_encode_by_short_cuts() {
843        let region_metadata = test_region_metadata();
844        let codec = SparsePrimaryKeyCodec::new(&region_metadata);
845        let mut buffer = Vec::new();
846        let internal_columns = [
847            (RESERVED_COLUMN_ID_TABLE_ID, ValueRef::UInt32(1024)),
848            (RESERVED_COLUMN_ID_TSID, ValueRef::UInt64(42)),
849        ];
850        let tags = [
851            (1, "greptime-frontend-6989d9899-22222"),
852            (2, "greptime-cluster"),
853            (3, "greptime-frontend-6989d9899-22222"),
854            (4, "greptime-frontend-6989d9899-22222"),
855            (5, "10.10.10.10"),
856        ];
857        codec
858            .encode_to_vec(internal_columns.into_iter(), &mut buffer)
859            .unwrap();
860        codec
861            .encode_to_vec(
862                tags.iter()
863                    .map(|(col_id, tag_value)| (*col_id, ValueRef::String(tag_value))),
864                &mut buffer,
865            )
866            .unwrap();
867
868        let mut buffer_by_raw_encoding = Vec::new();
869        codec
870            .encode_internal(1024, 42, &mut buffer_by_raw_encoding)
871            .unwrap();
872        let tags: Vec<_> = tags
873            .into_iter()
874            .map(|(col_id, tag_value)| (col_id, tag_value.as_bytes()))
875            .collect();
876        codec
877            .encode_raw_tag_value(
878                tags.iter().map(|(c, b)| (*c, *b)),
879                &mut buffer_by_raw_encoding,
880            )
881            .unwrap();
882        assert_eq!(buffer, buffer_by_raw_encoding);
883    }
884
885    #[test]
886    fn raw_encoding_matches_serde_at_chunk_boundaries() {
887        let codec = SparsePrimaryKeyCodec::schemaless();
888        let mut actual = Vec::new();
889        for len in [0, 7, 8, 9, 15, 16, 17, 1024] {
890            let label = "x".repeat(len);
891            let mut expected = Vec::new();
892            codec.encode_internal(42, 7, &mut expected).unwrap();
893            codec
894                .encode_to_vec([(1, ValueRef::String(&label))].into_iter(), &mut expected)
895                .unwrap();
896            actual.clear();
897            codec.encode_internal(42, 7, &mut actual).unwrap();
898            codec
899                .encode_raw_tag_value([(1, label.as_bytes())].into_iter(), &mut actual)
900                .unwrap();
901            assert_eq!(actual, expected, "label length {len}");
902        }
903    }
904
905    #[test]
906    fn test_encode_to_vec() {
907        let region_metadata = test_region_metadata();
908        let codec = SparsePrimaryKeyCodec::new(&region_metadata);
909        let mut buffer = Vec::new();
910
911        let row = test_row();
912        codec.encode_to_vec(row.into_iter(), &mut buffer).unwrap();
913        assert!(!buffer.is_empty());
914        let sparse_value = codec.decode_sparse(&buffer).unwrap();
915        assert_eq!(
916            sparse_value.get_or_null(RESERVED_COLUMN_ID_TABLE_ID),
917            &Value::UInt32(42)
918        );
919        assert_eq!(
920            sparse_value.get_or_null(1),
921            &Value::String("greptime-frontend-6989d9899-22222".into())
922        );
923        assert_eq!(
924            sparse_value.get_or_null(2),
925            &Value::String("greptime-cluster".into())
926        );
927        assert_eq!(
928            sparse_value.get_or_null(3),
929            &Value::String("greptime-frontend-6989d9899-22222".into())
930        );
931        assert_eq!(
932            sparse_value.get_or_null(4),
933            &Value::String("greptime-frontend-6989d9899-22222".into())
934        );
935        assert_eq!(
936            sparse_value.get_or_null(5),
937            &Value::String("10.10.10.10".into())
938        );
939    }
940
941    #[test]
942    fn test_decode_leftmost() {
943        let region_metadata = test_region_metadata();
944        let codec = SparsePrimaryKeyCodec::new(&region_metadata);
945        let mut buffer = Vec::new();
946        let row = test_row();
947        codec.encode_to_vec(row.into_iter(), &mut buffer).unwrap();
948        assert!(!buffer.is_empty());
949        let result = codec.decode_leftmost(&buffer).unwrap().unwrap();
950        assert_eq!(result, Value::UInt32(42));
951        assert_eq!(codec.decode_leftmost(&[]).unwrap(), None);
952        assert!(
953            codec
954                .decode_leftmost(&buffer[..TAGS_START_OFFSET - 1])
955                .is_err()
956        );
957    }
958
959    #[test]
960    fn test_decode_ids() {
961        let region_metadata = test_region_metadata();
962        let codec = SparsePrimaryKeyCodec::new(&region_metadata);
963        let mut buffer = Vec::new();
964        codec.encode_internal(42, 100, &mut buffer).unwrap();
965
966        assert_eq!((42, 100), codec.decode_ids(&buffer).unwrap());
967
968        let mut invalid = buffer.clone();
969        invalid[0..4].copy_from_slice(&1_u32.to_be_bytes());
970        assert!(codec.decode_ids(&invalid).is_err());
971        assert!(codec.decode_ids(&buffer[..buffer.len() - 1]).is_err());
972    }
973
974    #[test]
975    fn test_sparse_validator_matches_decoder() {
976        let codec = SparsePrimaryKeyCodec::schemaless();
977        let mut validator = SparsePrimaryKeyValidator::default();
978        let mut prefix = Vec::new();
979        codec.encode_internal(0, 0, &mut prefix).unwrap();
980        let mut cases = vec![prefix.clone()];
981        let mut max_prefix = Vec::new();
982        codec
983            .encode_internal(u32::MAX, u64::MAX, &mut max_prefix)
984            .unwrap();
985        cases.push(max_prefix);
986
987        for label in ["", "a", "12345678", "123456789", "1234567🦀末尾", "日本語"]
988            .into_iter()
989            .map(String::from)
990            .chain([
991                "a".repeat(128),
992                format!("{}🦀", "a".repeat(127)),
993                format!("🦀{}", "a".repeat(127)),
994            ])
995        {
996            let mut key = prefix.clone();
997            codec
998                .encode_raw_tag_value([(37, label.as_bytes())].into_iter(), &mut key)
999                .unwrap();
1000            assert!(validator.validate(&key).is_ok());
1001            cases.push(key);
1002        }
1003
1004        // Null labels, unknown IDs and arbitrary label order are accepted by the decoder.
1005        let mut labels = prefix.clone();
1006        labels.extend_from_slice(&12_u32.to_be_bytes());
1007        labels.push(0);
1008        codec
1009            .encode_raw_tag_value(
1010                [(999, b"unknown".as_slice()), (0, b"first".as_slice())].into_iter(),
1011                &mut labels,
1012            )
1013            .unwrap();
1014        assert!(validator.validate(&labels).is_ok());
1015        cases.push(labels.clone());
1016
1017        // Padding outside the significant bytes has never been required to be zero.
1018        let mut padded = cases[3].clone();
1019        let padding_offset = padded.len() - 2;
1020        padded[padding_offset] = 0xff;
1021        assert!(codec.decode(&padded).is_ok());
1022        assert!(validator.validate(&padded).is_ok());
1023        cases.push(padded);
1024
1025        for id in [
1026            12,
1027            RESERVED_COLUMN_ID_TABLE_ID,
1028            RESERVED_COLUMN_ID_TSID,
1029            u32::MAX,
1030        ] {
1031            let mut invalid = labels.clone();
1032            invalid.extend_from_slice(&id.to_be_bytes());
1033            invalid.push(0);
1034            assert!(codec.decode(&invalid).is_err());
1035            assert!(validator.validate(&invalid).is_err());
1036            cases.push(invalid);
1037        }
1038        for label in [
1039            b"\xff".as_slice(),
1040            b"\xc0\xaf",
1041            b"\xed\xa0\x80",
1042            b"1234567\xf4\x90\x80\x80",
1043        ] {
1044            let mut invalid = prefix.clone();
1045            codec
1046                .encode_raw_tag_value([(37, label)].into_iter(), &mut invalid)
1047                .unwrap();
1048            assert!(codec.decode(&invalid).is_err());
1049            assert!(validator.validate(&invalid).is_err());
1050            cases.push(invalid);
1051        }
1052
1053        // Reuse the same scratch state across successes and failures, including every
1054        // truncation and byte substitution in this corpus of framing and UTF-8 boundaries.
1055        let mut compare = |bytes: &[u8]| {
1056            assert_eq!(
1057                validator.validate(bytes).is_ok(),
1058                codec.decode(bytes).is_ok(),
1059                "{bytes:02x?}"
1060            );
1061        };
1062        for key in cases {
1063            compare(&key);
1064            for end in 0..key.len() {
1065                compare(&key[..end]);
1066            }
1067            for offset in 0..key.len() {
1068                let mut mutated = key.clone();
1069                for byte in 0..=u8::MAX {
1070                    mutated[offset] = byte;
1071                    compare(&mutated);
1072                }
1073            }
1074        }
1075    }
1076
1077    #[test]
1078    fn test_sparse_validator_reuses_state_for_unordered_columns() {
1079        let codec = SparsePrimaryKeyCodec::schemaless();
1080        let mut validator = SparsePrimaryKeyValidator::default();
1081        for num_tags in [512, 32, 1] {
1082            let mut key = Vec::new();
1083            codec.encode_internal(0, 0, &mut key).unwrap();
1084            codec
1085                .encode_raw_tag_value(
1086                    (0..num_tags).map(|index| (index * 17 % num_tags, "1234567🦀".as_bytes())),
1087                    &mut key,
1088                )
1089                .unwrap();
1090            assert!(validator.validate(&key).is_ok());
1091
1092            let mut duplicate = key.clone();
1093            duplicate.extend_from_slice(&0_u32.to_be_bytes());
1094            duplicate.push(0);
1095            assert!(validator.validate(&duplicate).is_err());
1096            assert!(validator.validate(&key).is_ok());
1097        }
1098    }
1099
1100    #[test]
1101    fn test_has_column() {
1102        let region_metadata = test_region_metadata();
1103        let codec = SparsePrimaryKeyCodec::new(&region_metadata);
1104        let mut buffer = Vec::new();
1105        let row = test_row();
1106        codec.encode_to_vec(row.into_iter(), &mut buffer).unwrap();
1107        assert!(!buffer.is_empty());
1108
1109        let mut offsets_map = SparseOffsetsCache::new();
1110        for column_id in [
1111            RESERVED_COLUMN_ID_TABLE_ID,
1112            RESERVED_COLUMN_ID_TSID,
1113            1,
1114            2,
1115            3,
1116            4,
1117            5,
1118        ] {
1119            let offset = codec.has_column(&buffer, &mut offsets_map, column_id);
1120            assert!(offset.is_some());
1121        }
1122
1123        let offset = codec.has_column(&buffer, &mut offsets_map, 6);
1124        assert!(offset.is_none());
1125    }
1126
1127    #[test]
1128    fn test_has_column_lazy_resume() {
1129        let region_metadata = test_region_metadata();
1130        let codec = SparsePrimaryKeyCodec::new(&region_metadata);
1131        let mut buffer = Vec::new();
1132        codec
1133            .encode_to_vec(test_row().into_iter(), &mut buffer)
1134            .unwrap();
1135
1136        let mut cache = SparseOffsetsCache::new();
1137        // Look up an early column: only a prefix of tags is decoded.
1138        assert!(codec.has_column(&buffer, &mut cache, 1).is_some());
1139        assert!(!cache.finished);
1140        assert!(cache.contains(1));
1141        assert!(!cache.contains(5));
1142
1143        // A later column resumes from the cursor.
1144        assert!(codec.has_column(&buffer, &mut cache, 5).is_some());
1145        assert!(cache.contains(5));
1146
1147        // An earlier column that was already cached still resolves.
1148        assert!(codec.has_column(&buffer, &mut cache, 2).is_some());
1149
1150        // A non-existent column walks off the end and marks the cache finished.
1151        assert!(codec.has_column(&buffer, &mut cache, 999).is_none());
1152        assert!(cache.finished);
1153        // Further misses are O(1).
1154        assert!(codec.has_column(&buffer, &mut cache, 998).is_none());
1155    }
1156
1157    #[test]
1158    fn test_decode_value_at() {
1159        let region_metadata = test_region_metadata();
1160        let codec = SparsePrimaryKeyCodec::new(&region_metadata);
1161        let mut buffer = Vec::new();
1162        let row = test_row();
1163        codec.encode_to_vec(row.into_iter(), &mut buffer).unwrap();
1164        assert!(!buffer.is_empty());
1165
1166        let row = test_row();
1167        let mut offsets_map = SparseOffsetsCache::new();
1168        for column_id in [
1169            RESERVED_COLUMN_ID_TABLE_ID,
1170            RESERVED_COLUMN_ID_TSID,
1171            1,
1172            2,
1173            3,
1174            4,
1175            5,
1176        ] {
1177            let offset = codec
1178                .has_column(&buffer, &mut offsets_map, column_id)
1179                .unwrap();
1180            let value = codec.decode_value_at(&buffer, offset, column_id).unwrap();
1181            let expected_value = row
1182                .iter()
1183                .find(|(id, _)| *id == column_id)
1184                .unwrap()
1185                .1
1186                .clone();
1187            assert_eq!(value.as_value_ref(), expected_value);
1188        }
1189    }
1190
1191    #[test]
1192    fn test_encoded_value_for_column() {
1193        let region_metadata = test_region_metadata();
1194        let codec = SparsePrimaryKeyCodec::new(&region_metadata);
1195        let mut buffer = Vec::new();
1196        let row = test_row();
1197        codec
1198            .encode_to_vec(row.clone().into_iter(), &mut buffer)
1199            .unwrap();
1200        assert!(!buffer.is_empty());
1201
1202        let mut offsets_map = SparseOffsetsCache::new();
1203        for column_id in [
1204            RESERVED_COLUMN_ID_TABLE_ID,
1205            RESERVED_COLUMN_ID_TSID,
1206            1,
1207            2,
1208            3,
1209            4,
1210            5,
1211        ] {
1212            let encoded_value = codec
1213                .encoded_value_for_column(&buffer, &mut offsets_map, column_id)
1214                .unwrap()
1215                .unwrap();
1216            let expected_value = row
1217                .iter()
1218                .find(|(id, _)| *id == column_id)
1219                .unwrap()
1220                .1
1221                .clone();
1222            let data_type = match column_id {
1223                RESERVED_COLUMN_ID_TABLE_ID => ConcreteDataType::uint32_datatype(),
1224                RESERVED_COLUMN_ID_TSID => ConcreteDataType::uint64_datatype(),
1225                _ => ConcreteDataType::string_datatype(),
1226            };
1227            let field = SortField::new(data_type);
1228            let mut expected_encoded = Vec::new();
1229            let mut serializer = Serializer::new(&mut expected_encoded);
1230            field.serialize(&mut serializer, &expected_value).unwrap();
1231            assert_eq!(encoded_value, expected_encoded.as_slice());
1232        }
1233
1234        for column_id in [6_u32, 7_u32, 999_u32] {
1235            let encoded_value = codec
1236                .encoded_value_for_column(&buffer, &mut offsets_map, column_id)
1237                .unwrap();
1238            assert!(encoded_value.is_none());
1239        }
1240    }
1241}