use std::collections::{BTreeMap, HashMap};
use std::time::{Duration, Instant};
use std::sync::Arc;
use std::sync::Mutex;
use std::sync::RwLock;
use std::sync::atomic::AtomicU64;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;
std::sync::{Arc, Mutex, RwLock}, atomic::{AtomicUsize, Ordering}};
pub struct MemoryCompression {
algorithms: Arc<RwLock<CompressionAlgorithms>>,
stats: Arc<CompressionStats>,
config: CompressionConfig,
compression_thread: Option<std::thread::JoinHandle<()>>,
stop_flag: Arc<AtomicUsize>,
}
#[derive(Debug)]
struct CompressionAlgorithms {
lz4_compressor: LZ4Compressor,
snappy_compressor: SnappyCompressor,
zstd_compressor: ZstdCompressor,
algorithm_selector: AlgorithmSelector,
}
#[derive(Debug)]
struct LZ4Compressor {
threshold: usize,
min_ratio: f64,
}
#[derive(Debug)]
struct SnappyCompressor {
threshold: usize,
min_ratio: f64,
}
#[derive(Debug)]
struct ZstdCompressor {
threshold: usize,
min_ratio: f64,
compression_level: u8,
}
#[derive(Debug)]
struct AlgorithmSelector {
strategy: SelectionStrategy,
}
#[derive(Debug, Clone)]
enum SelectionStrategy {
SizeBased,
AccessPatternBased,
ContentBased,
}
pub struct CompressionStats {
pub total_compressions: AtomicU64,
pub total_decompressions: AtomicU64,
pub original_bytes: AtomicU64,
pub compressed_bytes: AtomicU64,
pub saved_bytes: AtomicU64,
pub avg_compression_ratio: AtomicU64,
pub lz4_usage: AtomicU64,
pub snappy_usage: AtomicU64,
pub zstd_usage: AtomicU64,
pub compression_time_ns: AtomicU64,
pub decompression_time_ns: AtomicU64,
}
#[derive(Debug, Clone)]
pub struct CompressionConfig {
pub auto_compression_threshold: usize,
pub cold_data_access_threshold: usize,
pub cold_data_time_threshold: u64,
pub min_compression_ratio: f64,
pub compression_interval: Duration,
pub precompression_retention_hours: u64,
pub concurrent_compression_threads: usize,
pub enable_realtime_compression: bool,
}
impl Default for CompressionConfig {
fn default() -> Self {
Self {
auto_compression_threshold: 1024, cold_data_access_threshold: 5, cold_data_time_threshold: 3600, min_compression_ratio: 1.2, compression_interval: Duration::from_secs(300), precompression_retention_hours: 24, concurrent_compression_threads: 4,
enable_realtime_compression: false,
}
}
}
#[derive(Debug, Clone)]
pub struct CompressedBlock {
pub original_address: usize,
pub compressed_data: Vec<u8>,
pub algorithm: CompressionAlgorithm,
pub original_size: usize,
pub compressed_size: usize,
pub created_at: Instant,
pub last_accessed: Instant,
access_count: usize,
compression_ratio: f64,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum CompressionAlgorithm {
LZ4,
Snappy,
Zstd,
None,
}
impl MemoryCompression {
pub fn new(config: CompressionConfig) -> Self {
let stats: _ = Arc::new(Mutex::new(CompressionStats {)),
total_compressions: AtomicU64::new(0))
total_decompressions: AtomicU64::new(0),
original_bytes: AtomicU64::new(0),
compressed_bytes: AtomicU64::new(0),
saved_bytes: AtomicU64::new(0),
avg_compression_ratio: AtomicU64::new(0),
lz4_usage: AtomicU64::new(0),
snappy_usage: AtomicU64::new(0),
zstd_usage: AtomicU64::new(0),
compression_time_ns: AtomicU64::new(0),
decompression_time_ns: AtomicU64::new(0),
});
let algorithms: _ = Arc::new(Mutex::new(CompressionAlgorithms {)),
lz4_compressor: LZ4Compressor {
threshold: 1024, min_ratio: 1.2, },
snappy_compressor: SnappyCompressor {
threshold: 4096, min_ratio: 1.5, },
zstd_compressor: ZstdCompressor {
threshold: 8192, min_ratio: 2.0, compression_level: 3,
},
algorithm_selector: AlgorithmSelector {
strategy: SelectionStrategy::SizeBased,
},
})));
let stop_flag: _ = Arc::new(Mutex::new(AtomicUsize::new(0)),;
let compression_thread: _ = Some(Self::start_compression_thread(
Arc::clone(algorithms),
Arc::clone(stats),
Arc::clone(stop_flag),
config.clone(),
));
Self {
algorithms,
stats,
config,
compression_thread,
stop_flag,
}
}
pub fn compress(&self, data: &[u8], address: usize) -> Result<CompressedBlock, CompressionError> {
let start_time: _ = Instant::now();
let algorithm: _ = self.select_algorithm(data);
let (compressed_data, compression_ratio, algorithm_used) = match algorithm {
CompressionAlgorithm::LZ4 => {
let compressed: _ = self.compress_lz4(data)?;
self.stats.lz4_usage.fetch_add(1, Ordering::Relaxed);
let ratio: _ = self.calculate_compression_ratio(data, &compressed);
(compressed, ratio, algorithm)
}
CompressionAlgorithm::Snappy => {
let compressed: _ = self.compress_snappy(data)?;
self.stats.snappy_usage.fetch_add(1, Ordering::Relaxed);
let ratio: _ = self.calculate_compression_ratio(data, &compressed);
(compressed, ratio, algorithm)
}
CompressionAlgorithm::Zstd => {
let compressed: _ = self.compress_zstd(data)?;
self.stats.zstd_usage.fetch_add(1, Ordering::Relaxed);
let ratio: _ = self.calculate_compression_ratio(data, &compressed);
(compressed, ratio, algorithm)
}
CompressionAlgorithm::None => {
return Err(CompressionError::TooSmall);
}
};
let compression_time: _ = start_time.elapsed();
self.stats.compression_time_ns.fetch_add(
compression_time.as_nanos() as u64,
Ordering::Relaxed
);
self.stats.total_compressions.fetch_add(1, Ordering::Relaxed);
self.stats.original_bytes.fetch_add(data.len() as u64, Ordering::Relaxed);
self.stats.compressed_bytes.fetch_add(compressed_data.len() as u64, Ordering::Relaxed);
self.stats.saved_bytes.fetch_add(
(data.len() - compressed_data.len()) as u64,
Ordering::Relaxed
);
let total_compressions: _ = self.stats.total_compressions.load(Ordering::Relaxed);
let current_avg: _ = self.stats.avg_compression_ratio.load(Ordering::Relaxed);
let new_avg: _ = (current_avg * (total_compressions - 1) + (compression_ratio * 1000.0) as u64) / total_compressions;
self.stats.avg_compression_ratio.store(new_avg, Ordering::Relaxed);
let compressed_size: _ = compressed_data.len();
Ok(CompressedBlock {
original_address: address,
compressed_data,
algorithm: algorithm_used,
original_size: data.len(),
compressed_size,
created_at: Instant::now(),
last_accessed: Instant::now(),
access_count: 0,
compression_ratio,
})
}
pub fn decompress(&self, mut block: CompressedBlock) -> Result<Vec<u8>, CompressionError> {
let start_time: _ = Instant::now();
let decompressed_data: _ = match block.algorithm {
CompressionAlgorithm::LZ4 => self.decompress_lz4(&block.compressed_data)?,
CompressionAlgorithm::Snappy => self.decompress_snappy(&block.compressed_data)?,
CompressionAlgorithm::Zstd => self.decompress_zstd(&block.compressed_data)?,
CompressionAlgorithm::None => {
return Err(CompressionError::UnsupportedAlgorithm);
}
};
let decompression_time: _ = start_time.elapsed();
self.stats.decompression_time_ns.fetch_add(
decompression_time.as_nanos() as u64,
Ordering::Relaxed
);
self.stats.total_decompressions.fetch_add(1, Ordering::Relaxed);
block.last_accessed = Instant::now();
block.access_count += 1;
Ok(decompressed_data)
}
fn select_algorithm(&self, data: &[u8]) -> CompressionAlgorithm {
let algorithms: _ = self.algorithms.read().unwrap();
if data.len() < algorithms.lz4_compressor.threshold {
CompressionAlgorithm::None
} else if data.len() < algorithms.snappy_compressor.threshold {
CompressionAlgorithm::LZ4
} else if data.len() < algorithms.zstd_compressor.threshold {
CompressionAlgorithm::Snappy
} else {
CompressionAlgorithm::Zstd
}
}
fn compress_lz4(&self, data: &[u8]) -> Result<Vec<u8>, CompressionError> {
let mut compressed = Vec::with_capacity(data.len());
compressed.extend_from_slice(data);
Ok(compressed)
}
fn decompress_lz4(&self, data: &[u8]) -> Result<Vec<u8>, CompressionError> {
Ok(data.to_vec())
}
fn compress_snappy(&self, data: &[u8]) -> Result<Vec<u8>, CompressionError> {
let mut compressed = Vec::with_capacity(data.len() / 2);
compressed.extend_from_slice(data);
Ok(compressed)
}
fn decompress_snappy(&self, data: &[u8]) -> Result<Vec<u8>, CompressionError> {
Ok(data.to_vec())
}
fn compress_zstd(&self, data: &[u8]) -> Result<Vec<u8>, CompressionError> {
let mut compressed = Vec::with_capacity(data.len() / 3);
compressed.extend_from_slice(data);
Ok(compressed)
}
fn decompress_zstd(&self, data: &[u8]) -> Result<Vec<u8>, CompressionError> {
Ok(data.to_vec())
}
fn calculate_compression_ratio(&self, original: &[u8], compressed: &[u8]) -> f64 {
if compressed.is_empty() {
1.0
} else {
original.len() as f64 / compressed.len() as f64
}
}
fn start_compression_thread(
algorithms: Arc<RwLock<CompressionAlgorithms>>,
stats: Arc<CompressionStats>,
stop_flag: Arc<AtomicUsize>,
config: CompressionConfig,
) -> std::thread::JoinHandle<()> {
std::thread::spawn(move || {
let mut last_compression = Instant::now();
while stop_flag.load(Ordering::Relaxed) == 0 {
if Instant::now().duration_since(last_compression) > config.compression_interval {
Self::perform_compression_tasks(&algorithms, &stats, &config);
last_compression = Instant::now();
}
std::thread::sleep(Duration::from_secs(10));
}
})
}
fn perform_compression_tasks(
_algorithms: &Arc<RwLock<CompressionAlgorithms>>,
_stats: &Arc<CompressionStats>,
_config: &CompressionConfig,
) {
}
pub fn get_stats(&self) -> CompressionStatsSnapshot {
let total_compressions: _ = self.stats.total_compressions.load(Ordering::Relaxed);
let original_bytes: _ = self.stats.original_bytes.load(Ordering::Relaxed);
let compressed_bytes: _ = self.stats.compressed_bytes.load(Ordering::Relaxed);
CompressionStatsSnapshot {
total_compressions: self.stats.total_compressions.load(Ordering::Relaxed),
total_decompressions: self.stats.total_decompressions.load(Ordering::Relaxed),
original_bytes,
compressed_bytes,
saved_bytes: self.stats.saved_bytes.load(Ordering::Relaxed),
avg_compression_ratio: self.stats.avg_compression_ratio.load(Ordering::Relaxed) as f64 / 1000.0,
lz4_usage: self.stats.lz4_usage.load(Ordering::Relaxed),
snappy_usage: self.stats.snappy_usage.load(Ordering::Relaxed),
zstd_usage: self.stats.zstd_usage.load(Ordering::Relaxed),
avg_compression_time_ms: if total_compressions > 0 {
self.stats.compression_time_ns.load(Ordering::Relaxed) as f64
/ total_compressions as f64
/ 1_000_000.0
} else {
0.0
},
avg_decompression_time_ms: if self.stats.total_decompressions.load(Ordering::Relaxed) > 0 {
self.stats.decompression_time_ns.load(Ordering::Relaxed) as f64
/ self.stats.total_decompressions.load(Ordering::Relaxed) as f64
/ 1_000_000.0
} else {
0.0
},
compression_efficiency: if original_bytes > 0 {
(original_bytes - compressed_bytes) as f64 / original_bytes as f64 * 100.0
} else {
0.0
},
}
}
pub fn stop(&mut self) {
self.stop_flag.store(1, Ordering::Relaxed);
if let Some(handle) = self.compression_thread.take() {
handle.join().unwrap();
}
}
}
#[derive(Debug, Clone)]
pub struct CompressionStatsSnapshot {
pub total_compressions: u64,
pub total_decompressions: u64,
pub original_bytes: u64,
pub compressed_bytes: u64,
pub saved_bytes: u64,
pub avg_compression_ratio: f64,
pub lz4_usage: u64,
pub snappy_usage: u64,
pub zstd_usage: u64,
pub avg_compression_time_ms: f64,
pub avg_decompression_time_ms: f64,
pub compression_efficiency: f64,
}
#[derive(Debug)]
pub enum CompressionError {
TooSmall,
UnsupportedAlgorithm,
CompressionFailed,
DecompressionFailed,
}
impl std::fmt::Display for CompressionError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
CompressionError::TooSmall => write!(f, "Data too small for compression"),
CompressionError::UnsupportedAlgorithm => write!(f, "Unsupported compression algorithm"),
CompressionError::CompressionFailed => write!(f, "Compression failed"),
CompressionError::DecompressionFailed => write!(f, "Decompression failed"),
}
}
}
impl std::error::Error for CompressionError {}
impl Drop for MemoryCompression {
fn drop(&mut self) {
self.stop();
}
}