#![allow(clippy::unwrap_used, clippy::expect_used)]
use chronix::prelude::*;
use chronix::{Chronix, fields, tags};
#[test]
fn decimal_metrics_reach_the_documented_compression_on_disk() {
let dir = tempfile::tempdir().unwrap();
let config = ChronixConfig::builder()
.data_dir(dir.path())
.wal_fsync_policy(chronix_core::FsyncPolicy::Periodic(
std::time::Duration::from_secs(1),
))
.build()
.unwrap();
let db = Chronix::open(config).unwrap();
const SERIES: usize = 4;
const POINTS: usize = 4_000;
let keys: Vec<SeriesKey> = (0..SERIES)
.map(|s| SeriesKey::new("power", tags! { "meter" => &format!("m{s}") }).unwrap())
.collect();
let mut batch = Vec::with_capacity(SERIES * POINTS);
for i in 0..POINTS {
let ts = i as i64 * 1_000_000_000;
for (s, key) in keys.iter().enumerate() {
let watts = 200.0 + f64::from(u32::try_from((i * 7 + s) % 5000).unwrap()) / 100.0;
batch.push(Point::new(key.clone(), fields! { "watts" => watts }, ts).unwrap());
}
}
db.insert_batch(&batch).unwrap().into_complete().unwrap();
db.flush().unwrap();
let mut segment_bytes = 0u64;
for entry in std::fs::read_dir(dir.path()).unwrap() {
let path = entry.unwrap().path();
if path.is_dir() {
for f in walk(&path) {
if f.extension().is_some_and(|e| e == "csx") {
segment_bytes += std::fs::metadata(&f).map(|m| m.len()).unwrap_or(0);
}
}
}
}
let rows = (SERIES * POINTS) as u64;
assert!(segment_bytes > 0, "no .csx segments were written");
let raw = rows * 16;
let ratio = raw as f64 / segment_bytes as f64;
println!("{rows} rows, {segment_bytes} bytes on disk, {ratio:.1}x vs {raw} raw");
assert!(
ratio >= 5.0,
"on-disk compression regressed to {ratio:.1}x ({segment_bytes} bytes for {rows} rows)"
);
let plan = db
.query()
.measurement("power")
.range(0, i64::MAX)
.build()
.unwrap();
let total: usize = db
.execute_iter(&plan)
.unwrap()
.map(|b| b.unwrap().num_rows())
.sum();
assert_eq!(total as u64, rows);
}
fn walk(dir: &std::path::Path) -> Vec<std::path::PathBuf> {
let mut out = Vec::new();
let Ok(entries) = std::fs::read_dir(dir) else {
return out;
};
for e in entries.flatten() {
let p = e.path();
if p.is_dir() {
out.extend(walk(&p));
} else {
out.push(p);
}
}
out
}