MCPcopy Create free account
hub / github.com/NodeDB-Lab/nodedb / write_packed

Function write_packed

nodedb/src/engine/timeseries/packed_partition.rs:196–258  ·  view source on GitHub ↗

Write a packed partition file from individual column files. When `kek` is `Some`, the columns + sparse index payload region is wrapped in a `SEGT` AES-256-GCM envelope. The NDPK footer remains in plaintext to allow footer-only range requests without decryption. The `column_ranges` in the footer record offsets within the *decrypted payload blob, not the on-disk ciphertext, so `read_column` can pa

(
    output_path: &Path,
    columns: &[(String, Vec<u8>)], // (column_name, compressed_bytes)
    sparse_index: Option<&[u8]>,
    schema: &[PackedColumnSchema],
    meta: &PartitionMeta,
    kek: O

Source from the content-addressed store, hash-verified

194/// payload blob, not the on-disk ciphertext, so `read_column` can pass them
195/// through after decryption.
196pub fn write_packed(
197 output_path: &Path,
198 columns: &[(String, Vec<u8>)], // (column_name, compressed_bytes)
199 sparse_index: Option<&[u8]>,
200 schema: &[PackedColumnSchema],
201 meta: &PartitionMeta,
202 kek: Option<&WalEncryptionKey>,
203) -> Result<u64, PackedError> {
204 let mut payload = Vec::new();
205 let mut column_ranges = HashMap::new();
206
207 // Build the payload (columns + sparse index).
208 for (name, data) in columns {
209 let offset = payload.len() as u64;
210 payload.extend_from_slice(data);
211 column_ranges.insert(name.clone(), (offset, data.len() as u64));
212 }
213
214 let sparse_index_range = sparse_index.map(|idx_data| {
215 let offset = payload.len() as u64;
216 payload.extend_from_slice(idx_data);
217 (offset, idx_data.len() as u64)
218 });
219
220 // Optionally encrypt the payload.
221 let payload_encrypted = kek.is_some();
222 let payload_on_disk: Vec<u8> = if let Some(key) = kek {
223 encrypt_file(key, &payload).map_err(PackedError::from)?
224 } else {
225 payload
226 };
227
228 // Build footer (plaintext).
229 let footer = PackedFooter {
230 column_ranges,
231 sparse_index_range,
232 schema: schema.to_vec(),
233 meta: meta.clone(),
234 payload_encrypted,
235 };
236 let footer_body = zerompk::to_msgpack_vec(&footer)
237 .map_err(|e| PackedError::Io(format!("footer encode: {e}")))?;
238
239 // Compose the final file.
240 let mut buf = Vec::with_capacity(payload_on_disk.len() + footer_body.len() + PACKED_TAIL_SIZE);
241 buf.extend_from_slice(&payload_on_disk);
242 buf.extend_from_slice(&footer_body);
243
244 let footer_len = footer_body.len() as u32;
245 let crc = crc32c::crc32c(&footer_body);
246
247 // Tail: footer_len (4B) | crc (4B) | version (2B) | magic (4B)
248 buf.extend_from_slice(&footer_len.to_le_bytes());
249 buf.extend_from_slice(&crc.to_le_bytes());
250 buf.extend_from_slice(&PACKED_VERSION.to_le_bytes());
251 buf.extend_from_slice(&PACKED_MAGIC);
252
253 let total_size = buf.len() as u64;

Calls 6

encrypt_fileFunction · 0.85
writeFunction · 0.50
lenMethod · 0.45
insertMethod · 0.45
cloneMethod · 0.45
to_vecMethod · 0.45