Skip to main content

turbo_persistence/
compression.rs

1use std::{mem::MaybeUninit, sync::Arc};
2
3use anyhow::{Context, Result};
4use lzzzz::lz4::{self, decompress};
5
6/// Decompresses a block into an Arc allocation.
7///
8/// The caller must ensure `uncompressed_length > 0` (i.e., the block is actually compressed).
9/// Uncompressed blocks should be handled via zero-copy mmap slices before calling this.
10pub fn decompress_into_arc(uncompressed_length: u32, block: &[u8]) -> Result<Arc<[u8]>> {
11    debug_assert!(
12        uncompressed_length > 0,
13        "decompress_into_arc called with uncompressed_length=0; uncompressed blocks should use \
14         zero-copy mmap path"
15    );
16
17    // Allocate directly into an Arc to avoid a copy. The buffer is uninitialized;
18    // decompression will overwrite it completely (verified by the assert below).
19    let buffer: Arc<[MaybeUninit<u8>]> = Arc::new_uninit_slice(uncompressed_length as usize);
20    // Safety: decompression will fully initialize the buffer we verify with an assert
21    let mut buffer = unsafe { buffer.assume_init() };
22    // We just created this Arc so refcount is 1; get_mut always succeeds.
23    let decompressed = Arc::get_mut(&mut buffer).expect("Arc refcount should be 1");
24    let bytes_written = decompress(block, decompressed).with_context(|| {
25        format!(
26            "Failed to decompress block ({} bytes compressed, {} bytes uncompressed)",
27            block.len(),
28            uncompressed_length
29        )
30    })?;
31    assert_eq!(
32        bytes_written, uncompressed_length as usize,
33        "Decompressed length does not match expected length"
34    );
35    Ok(buffer)
36}
37
38/// Computes a CRC32 checksum of a byte slice.
39pub fn checksum_block(data: &[u8]) -> u32 {
40    crc32fast::hash(data)
41}
42
43#[tracing::instrument(level = "trace", skip_all)]
44pub fn compress_into_buffer(block: &[u8], buffer: &mut Vec<u8>) -> Result<()> {
45    lz4::compress_to_vec(block, buffer, lz4::ACC_LEVEL_DEFAULT).context("Compression failed")?;
46    Ok(())
47}