use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc;
use rocksdb::{
compaction_filter::Decision, BlockBasedOptions, ColumnFamilyDescriptor, DBCompactionStyle,
DBCompressionType, Options,
};
use crate::config::BlockStoreConfig;
use crate::constants::{
ALL_COLUMN_FAMILIES, CF_ATTESTED, CF_BLOCKS, CF_CANONICAL, CF_CHECKPOINTS, CF_HEADERS,
CF_METADATA, DEFAULT_BLOOM_BITS_PER_KEY,
};
pub const BLOCKS_BLOB_MIN_SIZE: u64 = 512;
pub const CHECKPOINTS_TARGET_FILE_SIZE_BASE: u64 = 256 * 1024 * 1024;
pub fn column_family_descriptors(
config: &BlockStoreConfig,
prune_threshold: Option<Arc<AtomicU64>>,
) -> Vec<ColumnFamilyDescriptor> {
ALL_COLUMN_FAMILIES
.iter()
.map(|&name| {
let opts = match name {
CF_BLOCKS => blocks_cf_options(config, prune_threshold.clone()),
CF_HEADERS => headers_cf_options(prune_threshold.clone()),
CF_ATTESTED => attested_cf_options(prune_threshold.clone()),
CF_CANONICAL => canonical_cf_options(),
CF_CHECKPOINTS => checkpoints_cf_options(),
CF_METADATA => metadata_cf_options(),
_ => unreachable!("ALL_COLUMN_FAMILIES drifted from TYP-001 names: {name}"),
};
ColumnFamilyDescriptor::new(name, opts)
})
.collect()
}
pub fn blocks_cf_options(
config: &BlockStoreConfig,
prune_threshold: Option<Arc<AtomicU64>>,
) -> Options {
let mut opts = Options::default();
opts.set_compaction_style(DBCompactionStyle::Universal);
if config.enable_blob_db {
opts.set_enable_blob_files(true);
opts.set_min_blob_size(BLOCKS_BLOB_MIN_SIZE);
opts.set_blob_compression_type(DBCompressionType::Zstd);
}
if let Some(threshold) = prune_threshold {
opts.set_compaction_filter("prn003_block_height_filter", move |_level, _key, value| {
let min_height = threshold.load(Ordering::Acquire);
if min_height == 0 {
return Decision::Keep;
}
let raw = match zstd::decode_all(value) {
Ok(r) => r,
Err(_) => return Decision::Keep, };
match bincode::deserialize::<dig_block::L2Block>(&raw) {
Ok(block) => {
if block.height() < min_height {
Decision::Remove
} else {
Decision::Keep
}
}
Err(_) => Decision::Keep,
}
});
}
opts
}
pub fn headers_cf_options(prune_threshold: Option<Arc<AtomicU64>>) -> Options {
let mut block = BlockBasedOptions::default();
block.set_bloom_filter(f64::from(DEFAULT_BLOOM_BITS_PER_KEY), false);
let mut opts = Options::default();
opts.set_compaction_style(DBCompactionStyle::Level);
opts.set_block_based_table_factory(&block);
opts.set_compression_type(DBCompressionType::None);
if let Some(threshold) = prune_threshold {
opts.set_compaction_filter("prn003_header_height_filter", move |_level, _key, value| {
let min_height = threshold.load(Ordering::Acquire);
if min_height == 0 {
return Decision::Keep;
}
match bincode::deserialize::<dig_block::L2BlockHeader>(value) {
Ok(header) => {
if header.height < min_height {
Decision::Remove
} else {
Decision::Keep
}
}
Err(_) => Decision::Keep,
}
});
}
opts
}
pub fn attested_cf_options(prune_threshold: Option<Arc<AtomicU64>>) -> Options {
let mut block = BlockBasedOptions::default();
block.set_bloom_filter(f64::from(DEFAULT_BLOOM_BITS_PER_KEY), false);
let mut opts = Options::default();
opts.set_compaction_style(DBCompactionStyle::Level);
opts.set_block_based_table_factory(&block);
if let Some(threshold) = prune_threshold {
opts.set_compaction_filter(
"prn003_attested_height_filter",
move |_level, _key, value| {
let min_height = threshold.load(Ordering::Acquire);
if min_height == 0 {
return Decision::Keep;
}
match bincode::deserialize::<dig_block::AttestedBlock>(value) {
Ok(ab) => {
if ab.block.height() < min_height {
Decision::Remove
} else {
Decision::Keep
}
}
Err(_) => Decision::Keep,
}
},
);
}
opts
}
pub fn canonical_cf_options() -> Options {
let mut opts = Options::default();
opts.set_compaction_style(DBCompactionStyle::Level);
opts.set_compression_type(DBCompressionType::None);
opts
}
pub fn checkpoints_cf_options() -> Options {
let mut opts = Options::default();
opts.set_compaction_style(DBCompactionStyle::Level);
opts.set_target_file_size_base(CHECKPOINTS_TARGET_FILE_SIZE_BASE);
opts
}
pub fn metadata_cf_options() -> Options {
let mut opts = Options::default();
opts.set_compaction_style(DBCompactionStyle::Level);
opts
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn column_family_descriptors_matches_all_families_count() {
let cfg = BlockStoreConfig::default();
assert_eq!(
column_family_descriptors(&cfg, None).len(),
ALL_COLUMN_FAMILIES.len()
);
}
}