#[derive(Debug, Clone, Copy, PartialEq)]
pub struct LevelBpk {
pub level: u32,
pub bits_per_key: f32,
}
#[derive(Debug, Clone)]
pub struct BloomTuningResult {
pub levels: Vec<LevelBpk>,
}
pub struct BloomTuningPolicy {
pub base_bpk: f32,
pub min_bpk: f32,
pub max_bpk: f32,
}
impl BloomTuningPolicy {
pub fn new(base_bpk: f32, min_bpk: f32, max_bpk: f32) -> Self {
Self {
base_bpk,
min_bpk,
max_bpk,
}
}
pub fn tune(&self, level_count: u32) -> BloomTuningResult {
let mut levels = Vec::new();
for level in 0..level_count {
let decay = 1.0 / (1.0 + level as f32 * 0.5);
let mut bpk = self.base_bpk * decay;
if bpk < self.min_bpk {
bpk = self.min_bpk;
}
if bpk > self.max_bpk {
bpk = self.max_bpk;
}
levels.push(LevelBpk {
level,
bits_per_key: bpk,
});
}
BloomTuningResult { levels }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn bloom_tuning_monotonic_decay() {
let policy = BloomTuningPolicy::new(16.0, 4.0, 16.0);
let result = policy.tune(4);
assert_eq!(result.levels.len(), 4);
assert!(result.levels[0].bits_per_key >= result.levels[1].bits_per_key);
assert!(result.levels[1].bits_per_key >= result.levels[2].bits_per_key);
assert!(result.levels[2].bits_per_key >= result.levels[3].bits_per_key);
}
#[test]
fn bloom_tuning_respects_bounds() {
let policy = BloomTuningPolicy::new(12.0, 6.0, 10.0);
let result = policy.tune(6);
for level in result.levels {
assert!(level.bits_per_key >= 6.0);
assert!(level.bits_per_key <= 10.0);
}
}
}