Skip to content

Commit

Permalink
feat(objectarium): implement Snappy compression algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
ccamel committed May 2, 2023
1 parent a634a96 commit 2958730
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 44 deletions.
54 changes: 32 additions & 22 deletions contracts/okp4-objectarium/src/compress.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use std::io;

use enum_iterator::Sequence;
use lz4_flex;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use snap;
use thiserror::Error;

/// CompressionAlgorithm is an enumeration that defines the different compression algorithms
Expand All @@ -10,16 +12,16 @@ use thiserror::Error;
pub enum CompressionAlgorithm {
/// Represents the "No compression" algorithm.
Passthrough,
/// Represents the LZ4 algorithm.
Lz4,
/// Represents the Snappy algorithm.
Snappy,
}

impl CompressionAlgorithm {
/// compress returns the compressed data using the given algorithm.
pub fn compress(&self, data: &[u8]) -> Result<Vec<u8>, CompressionError> {
let compressor = match self {
CompressionAlgorithm::Passthrough => passthrough,
CompressionAlgorithm::Lz4 => lz4_compress,
CompressionAlgorithm::Snappy => snappy_compress,
};
compressor(data)
}
Expand All @@ -29,7 +31,7 @@ impl CompressionAlgorithm {
pub fn decompress(&self, data: &[u8]) -> Result<Vec<u8>, CompressionError> {
let decompressor = match self {
CompressionAlgorithm::Passthrough => passthrough,
CompressionAlgorithm::Lz4 => lz4_decompress,
CompressionAlgorithm::Snappy => snappy_decompress,
};
decompressor(data)
}
Expand All @@ -41,8 +43,8 @@ pub enum CompressionError {
Error(String),
}

impl From<lz4_flex::block::DecompressError> for CompressionError {
fn from(err: lz4_flex::block::DecompressError) -> Self {
impl From<std::io::Error> for CompressionError {
fn from(err: std::io::Error) -> Self {
CompressionError::Error(err.to_string())
}
}
Expand All @@ -53,37 +55,45 @@ fn passthrough(data: &[u8]) -> Result<Vec<u8>, CompressionError> {
Ok(data.to_vec())
}

// lz4_compress returns the LZ4 compressed data.
// snappy_compress returns the Snappy compressed data.
#[inline]
fn lz4_compress(data: &[u8]) -> Result<Vec<u8>, CompressionError> {
Ok(lz4_flex::compress_prepend_size(data))
fn snappy_compress(data: &[u8]) -> Result<Vec<u8>, CompressionError> {
let mut reader = io::Cursor::new(data);
let mut writer = Vec::new();
{
let mut snappy_writer = snap::write::FrameEncoder::new(&mut writer);
io::copy(&mut reader, &mut snappy_writer)?;
}
Ok(writer)
}

// lz4_decompress returns the LZ4 decompressed data.
// snappy_decompress returns the Snappy decompressed data.
#[inline]
fn lz4_decompress(data: &[u8]) -> Result<Vec<u8>, CompressionError> {
Ok(lz4_flex::decompress_size_prepended(data)?)
fn snappy_decompress(data: &[u8]) -> Result<Vec<u8>, CompressionError> {
let reader = io::Cursor::new(data);
let mut snappy_reader = snap::read::FrameDecoder::new(reader);
let mut writer = Vec::new();
io::copy(&mut snappy_reader, &mut writer)?;
Ok(writer)
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_from_lz4_flex_decompress_error() {
// Define test cases as tuples of input DecompressError and expected CompressionError
let test_cases = vec![(
lz4_flex::block::DecompressError::UncompressedSizeDiffers {
expected: 1000,
actual: 998,
},
fn test_from_io_decompress_error() {
let cases = vec![(
std::io::Error::new(
std::io::ErrorKind::InvalidData,
"the expected decompressed size differs, actual 998, expected 1000",
),
CompressionError::Error(
"the expected decompressed size differs, actual 998, expected 1000".to_string(),
),
)];

// Iterate over test cases using a for loop
for (error, expected_error) in test_cases {
for (error, expected_error) in cases {
let compression_err = CompressionError::from(error);

assert_eq!(compression_err, expected_error);
Expand Down
20 changes: 10 additions & 10 deletions contracts/okp4-objectarium/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ mod tests {
BucketLimits {
accepted_compression_algorithms: Some(vec![
CompressionAlgorithm::Passthrough,
CompressionAlgorithm::Lz4,
CompressionAlgorithm::Snappy,
]),
..Default::default()
}
Expand Down Expand Up @@ -989,10 +989,10 @@ mod tests {
},
TC {
accepted_compression_algorithms: None,
compression_algorithm: Some(CompressionAlgorithm::Lz4),
compression_algorithm: Some(CompressionAlgorithm::Snappy),
expected_result: Either::Right(ExpectedCompressionResult {
compression_algorithm: CompressionAlgorithm::Lz4,
compressed_size: 415,
compression_algorithm: CompressionAlgorithm::Snappy,
compressed_size: 414,
}),
},
TC {
Expand All @@ -1006,21 +1006,21 @@ mod tests {
TC {
accepted_compression_algorithms: Some(vec![
CompressionAlgorithm::Passthrough,
CompressionAlgorithm::Lz4,
CompressionAlgorithm::Snappy,
]),
compression_algorithm: Some(CompressionAlgorithm::Lz4),
compression_algorithm: Some(CompressionAlgorithm::Snappy),
expected_result: Either::Right(ExpectedCompressionResult {
compression_algorithm: CompressionAlgorithm::Lz4,
compressed_size: 415,
compression_algorithm: CompressionAlgorithm::Snappy,
compressed_size: 414,
}),
},
TC {
accepted_compression_algorithms: Some(vec![CompressionAlgorithm::Lz4]),
accepted_compression_algorithms: Some(vec![CompressionAlgorithm::Snappy]),
compression_algorithm: Some(CompressionAlgorithm::Passthrough),
expected_result: Either::Left(ContractError::Bucket(
BucketError::CompressionAlgorithmNotAccepted(
CompressionAlgorithm::Passthrough,
vec![CompressionAlgorithm::Lz4],
vec![CompressionAlgorithm::Snappy],
),
)),
},
Expand Down
4 changes: 2 additions & 2 deletions contracts/okp4-objectarium/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,10 @@ fn test_bucket_error_messages() {
),
(
ContractError::Bucket(BucketError::CompressionAlgorithmNotAccepted(
CompressionAlgorithm::Lz4,
CompressionAlgorithm::Snappy,
vec![CompressionAlgorithm::Passthrough],
)),
"Compression algorithm is not accepted: Lz4 (accepted: \"[Passthrough]\")",
"Compression algorithm is not accepted: Snappy (accepted: \"[Passthrough]\")",
),
(ContractError::ObjectAlreadyPinned {}, "Object is already pinned"),
(
Expand Down
14 changes: 6 additions & 8 deletions contracts/okp4-objectarium/src/msg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,15 +160,13 @@ pub enum CompressionAlgorithm {
/// Represents no compression algorithm.
/// The object is stored as is without any compression.
Passthrough,
/// # LZ4
/// Represents the LZ4 algorithm.
/// LZ4 is a lossless compression algorithm that is used to compress objects.
/// It is extremely fast to compress and decompress, and is suitable for real-time compression.
/// The compression ratio is relatively low, but the computational cost is also low, so it is a good choice
/// for compressing data that is already highly compressible.
/// # Snappy
/// Represents the Snappy algorithm.
/// Snappy is a compression/decompression algorithm that does not aim for maximum compression. Instead, it aims for very high speeds and reasonable
/// compression.
///
/// See [the LZ4 Wikipedia page](https://en.wikipedia.org/wiki/LZ4_(compression_algorithm)) for more information.
Lz4,
/// See [the snappy web page](https://google.github.io/snappy/) for more information.
Snappy,
}

/// HashAlgorithm is an enumeration that defines the different hash algorithms
Expand Down
4 changes: 2 additions & 2 deletions contracts/okp4-objectarium/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ impl From<msg::CompressionAlgorithm> for CompressionAlgorithm {
fn from(algorithm: msg::CompressionAlgorithm) -> Self {
match algorithm {
msg::CompressionAlgorithm::Passthrough => CompressionAlgorithm::Passthrough,
msg::CompressionAlgorithm::Lz4 => CompressionAlgorithm::Lz4,
msg::CompressionAlgorithm::Snappy => CompressionAlgorithm::Snappy,
}
}
}
Expand All @@ -124,7 +124,7 @@ impl From<CompressionAlgorithm> for msg::CompressionAlgorithm {
fn from(algorithm: CompressionAlgorithm) -> Self {
match algorithm {
CompressionAlgorithm::Passthrough => msg::CompressionAlgorithm::Passthrough,
CompressionAlgorithm::Lz4 => msg::CompressionAlgorithm::Lz4,
CompressionAlgorithm::Snappy => msg::CompressionAlgorithm::Snappy,
}
}
}
Expand Down

0 comments on commit 2958730

Please sign in to comment.