Skip to content

Commit

Permalink
Implement zstd_seekable with 4KB frame size
Browse files Browse the repository at this point in the history
Fixes #117

Signed-off-by: Ariel Miculas <amiculas@cisco.com>
  • Loading branch information
ariel-miculas committed Dec 14, 2023
1 parent 2e43a0e commit 9df93f1
Show file tree
Hide file tree
Showing 8 changed files with 248 additions and 28 deletions.
53 changes: 52 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions puzzlefs-lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ fuser = {version = "0.11.1", default-features = false}
os_pipe = "1.1.2"
tempfile = "3.8.0"
openat = "0.1.21"
zstd-seekable = "0.1.23"


[dev-dependencies]
tempfile = "3.8.0"
Expand Down
10 changes: 5 additions & 5 deletions puzzlefs-lib/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ fn serialize_metadata(inodes: Vec<Inode>) -> Result<Vec<u8>> {
Ok(buf)
}

fn process_chunks<C: for<'a> Compression<'a> + Any>(
fn process_chunks<C: Compression + Any>(
oci: &Image,
mut chunker: StreamCDC,
files: &mut [File],
Expand Down Expand Up @@ -178,7 +178,7 @@ fn process_chunks<C: for<'a> Compression<'a> + Any>(
Ok(())
}

fn build_delta<C: for<'a> Compression<'a> + Any>(
fn build_delta<C: Compression + Any>(
rootfs: &Path,
oci: &Image,
mut existing: Option<PuzzleFS>,
Expand Down Expand Up @@ -414,7 +414,7 @@ fn build_delta<C: for<'a> Compression<'a> + Any>(
Ok(desc)
}

pub fn build_initial_rootfs<C: for<'a> Compression<'a> + Any>(
pub fn build_initial_rootfs<C: Compression + Any>(
rootfs: &Path,
oci: &Image,
) -> Result<Descriptor> {
Expand All @@ -440,7 +440,7 @@ pub fn build_initial_rootfs<C: for<'a> Compression<'a> + Any>(

// add_rootfs_delta adds whatever the delta between the current rootfs and the puzzlefs
// representation from the tag is.
pub fn add_rootfs_delta<C: for<'a> Compression<'a> + Any>(
pub fn add_rootfs_delta<C: Compression + Any>(
rootfs_path: &Path,
oci: Image,
tag: &str,
Expand Down Expand Up @@ -554,7 +554,7 @@ pub mod tests {
// there should be a blob that matches the hash of the test data, since it all gets input
// as one chunk and there's only one file
const FILE_DIGEST: &str =
"a7b1fbc3c77f9ffc40c051e3608d607d63eebcd23c559958043eccb64bdab7ff";
"3eee1082ab3babf6c1595f1069d11ebc2a60135890a11e402e017ddd831a220d";

let md = fs::symlink_metadata(image.blob_path().join(FILE_DIGEST)).unwrap();
assert!(md.is_file());
Expand Down
16 changes: 8 additions & 8 deletions puzzlefs-lib/src/compression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,21 @@ use std::io::Seek;
mod noop;
pub use noop::Noop;

mod zstd_wrapper;
pub use zstd_wrapper::*;
mod zstd_seekable_wrapper;
pub use zstd_seekable_wrapper::*;

pub trait Compressor: io::Write {
// https://users.rust-lang.org/t/how-to-move-self-when-using-dyn-trait/50123
fn end(self: Box<Self>) -> io::Result<()>;
}

pub trait Decompressor: io::Read + io::Seek + Send {
pub trait Decompressor: io::Read + io::Seek {
fn get_uncompressed_length(&mut self) -> io::Result<u64>;
}

pub trait Compression<'a> {
fn compress<W: std::io::Write + 'a>(dest: W) -> io::Result<Box<dyn Compressor + 'a>>;
fn decompress<R: std::io::Read + Seek + Send + 'a>(
pub trait Compression {
fn compress<'a, W: std::io::Write + 'a>(dest: W) -> io::Result<Box<dyn Compressor + 'a>>;
fn decompress<'a, R: std::io::Read + Seek + 'a>(
source: R,
) -> io::Result<Box<dyn Decompressor + 'a>>;
fn append_extension(media_type: &str) -> String;
Expand All @@ -31,7 +31,7 @@ mod tests {

pub const TRUTH: &str = "meshuggah rocks";

pub fn compress_decompress<C: for<'a> Compression<'a>>() -> anyhow::Result<()> {
pub fn compress_decompress<C: Compression>() -> anyhow::Result<()> {
let f = NamedTempFile::new()?;
let mut compressed = C::compress(f.reopen()?)?;
compressed.write_all(TRUTH.as_bytes())?;
Expand All @@ -45,7 +45,7 @@ mod tests {
Ok(())
}

pub fn compression_is_seekable<C: for<'a> Compression<'a>>() -> anyhow::Result<()> {
pub fn compression_is_seekable<C: Compression>() -> anyhow::Result<()> {
let f = NamedTempFile::new()?;
let mut compressed = C::compress(f.reopen()?)?;
compressed.write_all(TRUTH.as_bytes())?;
Expand Down
14 changes: 7 additions & 7 deletions puzzlefs-lib/src/compression/noop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,36 +24,36 @@ impl<W: Write> Compressor for NoopCompressor<W> {
}
}

pub struct NoopDecompressor<R: Read + Seek + Send> {
pub struct NoopDecompressor<R: Read + Seek> {
decoder: Box<R>,
}

impl<R: Read + io::Seek + Send> Seek for NoopDecompressor<R> {
impl<R: Read + io::Seek> Seek for NoopDecompressor<R> {
fn seek(&mut self, offset: io::SeekFrom) -> io::Result<u64> {
self.decoder.seek(offset)
}
}

impl<R: Read + Seek + Send> Read for NoopDecompressor<R> {
impl<R: Read + Seek> Read for NoopDecompressor<R> {
fn read(&mut self, out: &mut [u8]) -> io::Result<usize> {
self.decoder.read(out)
}
}

impl<R: Read + Seek + Send> Decompressor for NoopDecompressor<R> {
impl<R: Read + Seek> Decompressor for NoopDecompressor<R> {
fn get_uncompressed_length(&mut self) -> io::Result<u64> {
self.decoder.stream_len()
}
}

impl<'a> Compression<'a> for Noop {
fn compress<W: std::io::Write + 'a>(dest: W) -> io::Result<Box<dyn Compressor + 'a>> {
impl Compression for Noop {
fn compress<'a, W: std::io::Write + 'a>(dest: W) -> io::Result<Box<dyn Compressor + 'a>> {
Ok(Box::new(NoopCompressor {
encoder: Box::new(dest),
}))
}

fn decompress<R: std::io::Read + Seek + Send + 'a>(
fn decompress<'a, R: std::io::Read + Seek + 'a>(
source: R,
) -> io::Result<Box<dyn Decompressor + 'a>> {
Ok(Box::new(NoopDecompressor {
Expand Down
Loading

0 comments on commit 9df93f1

Please sign in to comment.