mod memtable;
mod unified_memtable; mod sstable;
mod compaction;
mod engine;
mod bloom;
mod blobstore;
mod merging_iterator;
pub use memtable::MemTable;
pub use unified_memtable::{UnifiedMemTable, UnifiedEntry, DataEntry};
pub use sstable::{SSTable, SSTableBuilder, BlockIndex};
pub use compaction::{CompactionWorker, CompactionConfig, Level, SSTableMeta, CompactionStats};
pub use engine::{LSMEngine, LSMBatchedIterator}; pub use bloom::BloomFilter;
pub use blobstore::BlobStore;
pub use merging_iterator::MergingIterator;
pub type Key = u64;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct BlobRef {
pub file_id: u32,
pub offset: u64,
pub size: u32,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ValueData {
Inline(Vec<u8>),
Blob(BlobRef),
}
impl ValueData {
pub fn len(&self) -> usize {
match self {
ValueData::Inline(data) => data.len(),
ValueData::Blob(_) => 16, }
}
pub fn is_empty(&self) -> bool {
match self {
ValueData::Inline(data) => data.is_empty(),
ValueData::Blob(_) => false,
}
}
}
#[derive(Clone, Debug)]
pub struct Value {
pub data: ValueData,
pub timestamp: u64,
pub deleted: bool,
}
impl Value {
pub fn new(data: Vec<u8>, timestamp: u64) -> Self {
Self {
data: ValueData::Inline(data),
timestamp,
deleted: false,
}
}
pub fn new_blob(blob_ref: BlobRef, timestamp: u64) -> Self {
Self {
data: ValueData::Blob(blob_ref),
timestamp,
deleted: false,
}
}
pub fn tombstone(timestamp: u64) -> Self {
Self {
data: ValueData::Inline(Vec::new()),
timestamp,
deleted: true,
}
}
pub fn as_inline(&self) -> Option<&[u8]> {
match &self.data {
ValueData::Inline(data) => Some(data),
ValueData::Blob(_) => None,
}
}
pub fn is_blob(&self) -> bool {
matches!(self.data, ValueData::Blob(_))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum CompressionAlgorithm {
#[default]
Zstd,
Snappy,
None,
}
#[derive(Debug, Clone)]
pub struct LSMConfig {
pub memtable_size: usize,
pub block_size: usize,
pub num_levels: usize,
pub level_multiplier: usize,
pub l0_compaction_trigger: usize,
pub bloom_bits_per_key: usize,
pub enable_compression: bool,
pub compression_algorithm: CompressionAlgorithm,
pub zstd_compression_level: i32,
pub blob_threshold: usize,
pub blob_file_size: usize,
pub sstable_cache_size: usize,
pub sstable_cache_memory_limit_mb: Option<usize>,
pub compaction_rate_limit: Option<u64>,
pub compaction_max_open_sstables: usize,
pub compaction_yield_every_n_blocks: usize,
pub compaction_idle_only: bool,
}
impl Default for LSMConfig {
fn default() -> Self {
Self {
memtable_size: 512 * 1024,
block_size: 64 * 1024,
num_levels: 7,
level_multiplier: 10,
l0_compaction_trigger: 4,
bloom_bits_per_key: 12,
enable_compression: true,
compression_algorithm: CompressionAlgorithm::Zstd,
zstd_compression_level: 1,
blob_threshold: 32 * 1024,
blob_file_size: 256 * 1024 * 1024,
sstable_cache_size: 32,
sstable_cache_memory_limit_mb: Some(200),
compaction_rate_limit: Some(4 * 1024 * 1024), compaction_max_open_sstables: 4,
compaction_yield_every_n_blocks: 4,
compaction_idle_only: false,
}
}
}
impl LSMConfig {
pub fn from_db_config(db_config: &crate::config::LSMConfig) -> Self {
let defaults = Self::default();
Self {
memtable_size: db_config.memtable_size_limit,
l0_compaction_trigger: db_config.level0_compaction_threshold,
bloom_bits_per_key: db_config.bloom_filter_false_positive_rate as usize,
sstable_cache_size: db_config.sstable_cache_size.unwrap_or(defaults.sstable_cache_size),
sstable_cache_memory_limit_mb: db_config.sstable_cache_memory_limit_mb.or(defaults.sstable_cache_memory_limit_mb),
block_size: db_config.block_size.unwrap_or(defaults.block_size),
..defaults
}
}
pub fn read_optimized() -> Self {
Self {
memtable_size: 4 * 1024 * 1024,
block_size: 32 * 1024,
num_levels: 7,
level_multiplier: 10,
l0_compaction_trigger: 2,
bloom_bits_per_key: 16,
enable_compression: true,
blob_threshold: 32 * 1024,
blob_file_size: 256 * 1024 * 1024,
sstable_cache_size: 256,
sstable_cache_memory_limit_mb: Some(400),
..Self::default()
}
}
pub fn write_optimized() -> Self {
Self {
memtable_size: 16 * 1024 * 1024,
block_size: 128 * 1024,
num_levels: 6,
level_multiplier: 8,
l0_compaction_trigger: 8,
bloom_bits_per_key: 8,
enable_compression: true,
blob_threshold: 32 * 1024,
blob_file_size: 256 * 1024 * 1024,
sstable_cache_size: 64,
sstable_cache_memory_limit_mb: Some(200),
..Self::default()
}
}
pub fn embedded() -> Self {
Self {
memtable_size: 2 * 1024 * 1024,
block_size: 32 * 1024,
num_levels: 6,
level_multiplier: 8,
l0_compaction_trigger: 2,
bloom_bits_per_key: 8,
enable_compression: true,
blob_threshold: 16 * 1024,
blob_file_size: 128 * 1024 * 1024,
sstable_cache_size: 32,
sstable_cache_memory_limit_mb: Some(40),
..Self::default()
}
}
pub fn tiny() -> Self {
Self {
memtable_size: 1024 * 1024,
block_size: 16 * 1024,
num_levels: 5,
level_multiplier: 4,
l0_compaction_trigger: 2,
bloom_bits_per_key: 6,
enable_compression: true,
blob_threshold: 8 * 1024,
blob_file_size: 64 * 1024 * 1024,
sstable_cache_size: 8,
sstable_cache_memory_limit_mb: Some(20),
..Self::default()
}
}
pub fn memory_optimized() -> Self {
Self {
memtable_size: 2 * 1024 * 1024,
block_size: 32 * 1024,
num_levels: 7,
level_multiplier: 10,
l0_compaction_trigger: 2,
bloom_bits_per_key: 10,
enable_compression: true,
blob_threshold: 16 * 1024,
blob_file_size: 128 * 1024 * 1024,
sstable_cache_size: 4,
sstable_cache_memory_limit_mb: Some(100),
..Self::default()
}
}
pub fn balanced() -> Self {
Self::default()
}
}