Fix compression with 128 KiB records, use compress cache

This commit is contained in:
Jeremy Soller
2025-08-01 13:23:56 -06:00
parent b40fecf185
commit d03aa518fe
2 changed files with 33 additions and 21 deletions
+9 -1
View File
@@ -6,9 +6,14 @@ use xts_mode::{get_tweak_default, Xts128};
#[cfg(feature = "std")]
use crate::{AllocEntry, AllocList, BlockData, BlockTrait, Key, KeySlot, Node, Salt, TreeList};
use crate::{
Allocator, BlockAddr, BlockLevel, BlockMeta, Disk, Header, Transaction, BLOCK_SIZE, HEADER_RING,
Allocator, BlockAddr, BlockLevel, BlockMeta, Disk, Header, Transaction, BLOCK_SIZE,
HEADER_RING, RECORD_SIZE,
};
fn compress_cache() -> Box<[u8]> {
vec![0; lz4_flex::block::get_maximum_output_size(RECORD_SIZE as usize)].into_boxed_slice()
}
/// A file system
pub struct FileSystem<D: Disk> {
//TODO: make private
@@ -19,6 +24,7 @@ pub struct FileSystem<D: Disk> {
pub header: Header,
pub(crate) allocator: Allocator,
pub(crate) cipher_opt: Option<Xts128<Aes128>>,
pub(crate) compress_cache: Box<[u8]>,
}
impl<D: Disk> FileSystem<D> {
@@ -83,6 +89,7 @@ impl<D: Disk> FileSystem<D> {
header,
allocator: Allocator::default(),
cipher_opt,
compress_cache: compress_cache(),
};
unsafe { fs.reset_allocator()? };
@@ -162,6 +169,7 @@ impl<D: Disk> FileSystem<D> {
header,
allocator: Allocator::default(),
cipher_opt,
compress_cache: compress_cache(),
};
// Write header generation zero
+24 -20
View File
@@ -395,9 +395,8 @@ impl<'a, D: Disk> Transaction<'a, D> {
}
};
let comp_len = record.data()[0] as usize | ((record.data()[1] as usize) << 8);
if let Err(err) =
lz4_flex::decompress_into(&record.data()[2..(comp_len + 2)], &mut decomp)
{
let total_len = comp_len + 2;
if let Err(err) = lz4_flex::decompress_into(&record.data()[2..total_len], &mut decomp) {
#[cfg(feature = "log")]
log::error!("READ_RECORD: FAILED TO DECOMPRESS: {:?}", err);
return Err(Error::new(EIO));
@@ -1684,24 +1683,29 @@ impl<'a, D: Disk> Transaction<'a, D> {
// Handle record compression, if record is larger than one block
let decomp_level = record.addr().level();
if decomp_level.0 > 0 {
// Maximum compressed record size is 64 KiB
let mut comp = alloc::vec![0; 64 * 1024];
// First two bytes store compressed data length
match lz4_flex::compress_into(record.data(), &mut comp[2..]) {
match lz4_flex::compress_into(record.data(), &mut self.fs.compress_cache) {
Ok(comp_len) => {
comp[0] = comp_len as u8;
comp[1] = (comp_len >> 8) as u8;
let comp_level = BlockLevel::for_bytes((comp_len as u64) + 2);
comp.truncate(comp_level.bytes() as usize);
// Replace record with compressed record, if it saves space
if comp_level < decomp_level {
record = BlockData::new(
BlockAddr::null(BlockMeta::new_compressed(
comp_level,
decomp_level,
)),
RecordRaw(comp.into_boxed_slice()),
);
let total_len = comp_len + 2;
// Maximum compressed record size is 64 KiB
if total_len <= 64 * 1024 {
let comp_level = BlockLevel::for_bytes(total_len as u64);
// Replace record with compressed record, if it saves space
if comp_level < decomp_level {
if let Some(mut comp) = RecordRaw::empty(comp_level) {
// First two bytes store compressed data length
comp[0] = comp_len as u8;
comp[1] = (comp_len >> 8) as u8;
comp[2..total_len]
.copy_from_slice(&self.fs.compress_cache[..comp_len]);
record = BlockData::new(
BlockAddr::null(BlockMeta::new_compressed(
comp_level,
decomp_level,
)),
comp,
);
}
}
}
}
Err(_err) => {