reifydb_codec/frame/encode/
mod.rs1pub(crate) mod any;
5mod fixed;
6mod varlen;
7
8use arrow_buffer::BooleanBuffer;
9use reifydb_value::value::{
10 column_view::{ColumnView, ViewData},
11 diff_type::DiffType,
12 frame::frame::Frame,
13};
14use tracing::{Span, instrument};
15
16use crate::{
17 error::EncodeError,
18 frame::{
19 encoding::plain::{encode_bitvec, encode_plain},
20 format::{
21 COL_FLAG_HAS_NONES, Encoding, FRAME_HEADER_SIZE, MESSAGE_HEADER_SIZE, RBCF_MAGIC, RBCF_VERSION,
22 },
23 heuristics::choose_encoding,
24 options::EncodeOptions,
25 },
26 tag::TypeTag,
27 typeinfo::encode_digest_params,
28 unscaled::params,
29};
30
31pub(crate) struct EncodedColumn {
32 pub(crate) type_code: u8,
33 pub(crate) encoding: Encoding,
34 pub(crate) flags: u8,
35 pub(crate) nones: Vec<u8>,
36 pub(crate) data: Vec<u8>,
37 pub(crate) offsets: Vec<u8>,
38 pub(crate) extra: Vec<u8>,
39 pub(crate) row_count: u32,
40}
41
42#[instrument(
43 name = "wire::encode_frames",
44 level = "trace",
45 skip_all,
46 fields(
47 frame_count = frames.len(),
48 total_rows = frames.iter().map(|f| f.batch.num_rows()).sum::<usize>(),
49 bytes,
50 ),
51)]
52pub fn encode_frames(frames: &[Frame], options: &EncodeOptions) -> Result<Vec<u8>, EncodeError> {
53 let mut buf = Vec::with_capacity(4096);
54 reserve_message_header(&mut buf);
55 for frame in frames {
56 encode_frame(frame, &mut buf, options)?;
57 }
58 write_message_header(&mut buf, frames.len() as u32);
59 Span::current().record("bytes", buf.len());
60 Ok(buf)
61}
62
63#[inline]
64fn reserve_message_header(buf: &mut Vec<u8>) {
65 buf.extend_from_slice(&[0u8; MESSAGE_HEADER_SIZE]);
66}
67
68#[inline]
69fn write_message_header(buf: &mut [u8], frame_count: u32) {
70 let total_size = buf.len() as u32;
71 buf[0..4].copy_from_slice(&RBCF_MAGIC.to_le_bytes());
72 buf[4..6].copy_from_slice(&RBCF_VERSION.to_le_bytes());
73 buf[6..8].copy_from_slice(&0u16.to_le_bytes());
74 buf[8..12].copy_from_slice(&frame_count.to_le_bytes());
75 buf[12..16].copy_from_slice(&total_size.to_le_bytes());
76}
77
78fn encode_frame(frame: &Frame, buf: &mut Vec<u8>, options: &EncodeOptions) -> Result<(), EncodeError> {
79 let frame_start = buf.len();
80 let row_count = frame.batch.num_rows() as u32;
81 let column_count = frame.batch.num_columns() as u16;
82
83 reserve_frame_header(buf);
84 encode_frame_columns(frame, buf, options)?;
85
86 let frame_size = (buf.len() - frame_start) as u32;
87 let op = frame.op.map_or(0, DiffType::as_u8);
88 write_frame_header(buf, frame_start, row_count, column_count, op, frame_size);
89 Ok(())
90}
91
92#[inline]
93fn reserve_frame_header(buf: &mut Vec<u8>) {
94 buf.extend_from_slice(&[0u8; FRAME_HEADER_SIZE]);
95}
96
97#[inline]
98fn encode_frame_columns(frame: &Frame, buf: &mut Vec<u8>, options: &EncodeOptions) -> Result<(), EncodeError> {
99 let schema = frame.batch.schema_ref();
100 for (field, array) in schema.fields().iter().zip(frame.batch.columns()) {
101 let view = ColumnView::try_from((array, field.as_ref()))
102 .map_err(|error| EncodeError::UnsupportedType(error.to_string()))?;
103 encode_column(field.name(), &view, buf, options)?;
104 }
105 Ok(())
106}
107
108#[inline]
109fn write_frame_header(buf: &mut [u8], frame_start: usize, row_count: u32, column_count: u16, op: u8, frame_size: u32) {
110 let h = frame_start;
111 buf[h..h + 4].copy_from_slice(&row_count.to_le_bytes());
112 buf[h + 4..h + 6].copy_from_slice(&column_count.to_le_bytes());
113 buf[h + 6] = 0;
114 buf[h + 7] = op;
115 buf[h + 8..h + 12].copy_from_slice(&frame_size.to_le_bytes());
116}
117
118fn encode_column(
119 name: &str,
120 view: &ColumnView<'_>,
121 buf: &mut Vec<u8>,
122 options: &EncodeOptions,
123) -> Result<(), EncodeError> {
124 let desired = options.force_encoding.unwrap_or_else(|| choose_encoding(view, options.compression));
125 let enc = try_encode_with(view, desired)?;
126 write_column(name, &enc, buf);
127 Ok(())
128}
129
130fn try_encode_with(view: &ColumnView<'_>, desired: Encoding) -> Result<EncodedColumn, EncodeError> {
131 let row_count = view.len();
132 let has_nones = view.is_nullable() || view.is_none();
133 let nones = match (has_nones, view.logical_nulls()) {
134 (false, _) => Vec::new(),
135 (true, Some(nulls)) => encode_bitvec(nulls.inner()),
136 (true, None) => encode_bitvec(&BooleanBuffer::new_set(row_count)),
137 };
138
139 let row_count = row_count as u32;
140
141 let result = match desired {
142 Encoding::Dict => varlen::try_dict_varlen(view),
143 Encoding::Rle => fixed::try_rle_fixed(view),
144 Encoding::Delta => fixed::try_delta_fixed(view),
145 Encoding::DeltaRle => fixed::try_delta_rle_fixed(view),
146 _ => None,
147 };
148
149 let mut enc = match result {
150 Some(enc) => enc,
151 None => {
152 let plain = encode_plain(view)?;
153 let mut extra = Vec::new();
154 if let ViewData::Digest {
155 inner: digest_inner,
156 accuracy,
157 ..
158 } = &view.data
159 {
160 encode_digest_params(digest_inner, *accuracy, &mut extra)?;
161 }
162 EncodedColumn {
163 type_code: plain.type_code,
164 encoding: Encoding::Plain,
165 flags: 0,
166 nones: vec![],
167 data: plain.data,
168 offsets: plain.offsets,
169 extra,
170 row_count,
171 }
172 }
173 };
174
175 if let Some((precision, scale)) = params(&view.base_type()) {
176 enc.extra = vec![precision.value(), scale.value()];
177 }
178
179 if has_nones {
180 enc.type_code = TypeTag::of_type(&view.get_type())?.byte();
181 enc.nones = nones;
182 enc.flags |= COL_FLAG_HAS_NONES;
183 }
184 enc.row_count = row_count;
185 Ok(enc)
186}
187
188fn write_column(name: &str, enc: &EncodedColumn, buf: &mut Vec<u8>) {
189 let name_bytes = name.as_bytes();
190 let name_len = name_bytes.len() as u16;
191 let name_pad = (4 - (name_bytes.len() % 4)) % 4;
192
193 buf.push(enc.type_code);
194 buf.push(enc.encoding as u8);
195 buf.push(enc.flags);
196 buf.push(0);
197 buf.extend_from_slice(&name_len.to_le_bytes());
198 buf.extend_from_slice(&0u16.to_le_bytes());
199 buf.extend_from_slice(&enc.row_count.to_le_bytes());
200 buf.extend_from_slice(&(enc.nones.len() as u32).to_le_bytes());
201 buf.extend_from_slice(&(enc.data.len() as u32).to_le_bytes());
202 buf.extend_from_slice(&(enc.offsets.len() as u32).to_le_bytes());
203 buf.extend_from_slice(&(enc.extra.len() as u32).to_le_bytes());
204
205 buf.extend_from_slice(name_bytes);
206 for _ in 0..name_pad {
207 buf.push(0);
208 }
209
210 buf.extend_from_slice(&enc.nones);
211
212 buf.extend_from_slice(&enc.data);
213
214 buf.extend_from_slice(&enc.offsets);
215
216 buf.extend_from_slice(&enc.extra);
217}