use serde::Deserialize;
#[derive(Debug, Clone, Deserialize)]
pub struct GenerationStats {
pub generation: u64,
pub bytes: u64,
#[serde(default)]
pub rows: Option<u64>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct MemtableStats {
pub generation: u64,
pub rows: u64,
pub bytes: u64,
pub batches: u64,
pub indexes: Vec<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct BucketStats {
pub shard_id: String,
pub status: String,
pub writer_epoch: u64,
pub manifest_version: u64,
pub current_generation: u64,
pub replay_after_wal_entry_position: u64,
pub wal_entry_position_last_seen: u64,
pub generations: Vec<GenerationStats>,
pub compacting: bool,
#[serde(default)]
pub memtables: Option<Vec<MemtableStats>>,
}
impl BucketStats {
pub(crate) fn newest_generation(&self) -> Option<u64> {
self.generations.iter().map(|g| g.generation).max()
}
pub(crate) fn outstanding_generations(&self, target: u64) -> usize {
self.generations
.iter()
.filter(|g| g.generation <= target)
.count()
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct LsmStats {
pub buckets: Vec<BucketStats>,
}
#[derive(Debug, Deserialize)]
pub(crate) struct GetLsmStatsResponse {
#[serde(default)]
pub lsm_stats: Option<LsmStats>,
}
#[cfg(test)]
mod tests {
use super::*;
fn bucket(shard: &str, generations: &[u64], compacting: bool) -> BucketStats {
BucketStats {
shard_id: shard.into(),
status: "Active".into(),
writer_epoch: 1,
manifest_version: 1,
current_generation: generations.iter().max().copied().unwrap_or(0) + 1,
replay_after_wal_entry_position: 0,
wal_entry_position_last_seen: 0,
generations: generations
.iter()
.map(|g| GenerationStats {
generation: *g,
bytes: 1,
rows: None,
})
.collect(),
compacting,
memtables: None,
}
}
#[test]
fn newer_generations_do_not_extend_the_target() {
let start = bucket("b0", &[7, 8], false);
let target = start.newest_generation().expect("L0 is non-empty");
assert_eq!(target, 8);
let later = bucket("b0", &[9, 10], false);
assert_eq!(
later.outstanding_generations(target),
0,
"generations above the target are somebody else's problem"
);
assert_eq!(
bucket("b0", &[8, 9], false).outstanding_generations(target),
1
);
}
#[test]
fn progress_is_measured_in_generations() {
let target = 3;
let counts: Vec<usize> = [&[1u64, 2, 3][..], &[2, 3][..], &[3][..], &[][..]]
.iter()
.map(|gens| bucket("b0", gens, false).outstanding_generations(target))
.collect();
assert_eq!(counts, vec![3, 2, 1, 0]);
}
#[test]
fn empty_l0_has_no_target() {
assert!(bucket("b0", &[], false).newest_generation().is_none());
}
}