use std::sync::Arc;
use fjall::{
CompressionType, Database, Keyspace as FjallKeyspace, KeyspaceCreateOptions, KvSeparationOptions,
config::{
BlockSizePolicy, CompressionPolicy, HashRatioPolicy, PinningPolicy, RestartIntervalPolicy,
},
};
use crate::{
conf::{Conf, DbConfig},
error::{Error, Result},
};
pub const DATA: &str = "data";
pub const META: &str = "meta";
pub const DATA_NS: &str = "data_ns";
pub const META_NS: &str = "meta_ns";
#[derive(Clone)]
pub struct Keyspace {
pub data: FjallKeyspace,
pub meta: FjallKeyspace,
pub data_ns: FjallKeyspace,
pub meta_ns: FjallKeyspace,
}
impl Keyspace {
#[inline]
fn make_options(
comp_policy: CompressionPolicy,
manual_persist: bool,
memtable_size: u64,
kv_separation: Option<usize>,
block_size: u32,
hash_ratio: f32,
expect_point_hits: bool,
) -> KeyspaceCreateOptions {
let mut opts = KeyspaceCreateOptions::default()
.data_block_size_policy(BlockSizePolicy::all(block_size))
.data_block_compression_policy(comp_policy)
.data_block_hash_ratio_policy(HashRatioPolicy::all(hash_ratio))
.data_block_restart_interval_policy(RestartIntervalPolicy::new([8, 16]))
.index_block_pinning_policy(PinningPolicy::all(true))
.filter_block_pinning_policy(PinningPolicy::all(true))
.expect_point_read_hits(expect_point_hits)
.max_memtable_size(memtable_size)
.manual_journal_persist(manual_persist);
if let Some(threshold) = kv_separation {
opts = opts.with_kv_separation(Some(
KvSeparationOptions::default()
.separation_threshold(threshold as u32)
.compression(CompressionType::Lz4),
));
}
opts
}
pub fn open<I>(db: &Arc<Database>, conf_li: I) -> Result<Self>
where
I: IntoIterator<Item = Conf>,
{
let cfg = DbConfig::from_conf_li(conf_li);
Self::open_with_cfg(db, &cfg)
}
pub fn open_with_cfg(db: &Arc<Database>, cfg: &DbConfig) -> Result<Self> {
let comp_type: CompressionType = cfg.compression.into();
let data_comp_policy = match comp_type {
CompressionType::None => CompressionPolicy::disabled(),
CompressionType::Lz4 => CompressionPolicy::new([
CompressionType::None,
CompressionType::None,
CompressionType::Lz4,
]),
};
let manual_persist = cfg.manual_journal_persist;
let data_block_size = cfg.data_block_size as u32;
let meta_block_size = cfg.meta_block_size as u32;
let data_memtable_size = cfg.data_memtable_size as u64;
let meta_memtable_size = cfg.meta_memtable_size as u64;
let data_kv_sep = cfg.kv_separation_threshold;
let data_hash_ratio = cfg.data_hash_ratio;
let expect_point_hits = cfg.expect_point_read_hits;
let p1 = data_comp_policy.clone();
let data = db
.keyspace(DATA, move || {
Self::make_options(
p1,
manual_persist,
data_memtable_size,
data_kv_sep,
data_block_size,
data_hash_ratio,
expect_point_hits,
)
})
.map_err(|e| Error::internal_with_source("Failed to open data keyspace", e))?;
let p2 = data_comp_policy.clone();
let meta = db
.keyspace(META, move || {
Self::make_options(
p2,
manual_persist,
meta_memtable_size,
None,
meta_block_size,
0.0,
expect_point_hits,
)
})
.map_err(|e| Error::internal_with_source("Failed to open meta keyspace", e))?;
let p3 = data_comp_policy.clone();
let data_ns = db
.keyspace(DATA_NS, move || {
Self::make_options(
p3,
manual_persist,
data_memtable_size,
data_kv_sep,
data_block_size,
data_hash_ratio,
expect_point_hits,
)
})
.map_err(|e| Error::internal_with_source("Failed to open data_ns keyspace", e))?;
let meta_ns = db
.keyspace(META_NS, move || {
Self::make_options(
data_comp_policy,
manual_persist,
meta_memtable_size,
None,
meta_block_size,
0.0,
expect_point_hits,
)
})
.map_err(|e| Error::internal_with_source("Failed to open meta_ns keyspace", e))?;
Ok(Self {
data,
meta,
data_ns,
meta_ns,
})
}
}