use rudb::Database;
use rudb_common::Value;
fn scratch(tag: &str) -> std::path::PathBuf {
let path =
std::env::temp_dir().join(format!("rudb-loadprofile-{tag}-{}.rudb", std::process::id()));
let _ = std::fs::remove_file(&path);
path
}
fn number(value: &Value) -> i64 {
value.to_string().parse().expect("an integer column")
}
fn stages(database: &Database, target: &str, column: &str) -> Vec<(String, i64)> {
let result = database
.query(&format!(
"SELECT stage, {column} FROM rudb_write_metrics() WHERE target = '{target}' \
AND load = (SELECT max(load) FROM rudb_write_metrics() WHERE target = '{target}')"
))
.expect("the load profile reads");
result.rows().map(|row| (row[0].to_string(), number(&row[1]))).collect()
}
#[test]
fn a_create_table_as_leaves_a_profile_that_adds_up_to_the_file() {
let path = scratch("ctas");
let name = path.to_str().expect("a UTF-8 temporary path").to_owned();
let database = Database::open(&name).expect("a file name starts a native database");
database
.execute(
"CREATE TABLE profiled AS SELECT range AS a, 'v' || (range % 7) AS b \
FROM range(300000)",
)
.expect("loads");
let rows = stages(&database, "profiled", "rows");
let named: Vec<&str> = rows.iter().map(|(stage, _)| stage.as_str()).collect();
assert_eq!(named, ["convert", "page builder", "dictionary", "write", "publish", "total"]);
let rows_of = |stage: &str| rows.iter().find(|(name, _)| name == stage).map(|(_, n)| *n);
assert_eq!(rows_of("convert"), Some(300_000));
assert_eq!(rows_of("page builder"), Some(300_000));
assert_eq!(rows_of("write"), Some(300_000));
assert_eq!(rows_of("total"), Some(300_000));
let written = stages(&database, "profiled", "bytes_out");
let total = written.iter().find(|(stage, _)| stage == "total").map(|(_, n)| *n).unwrap();
let file = i64::try_from(std::fs::metadata(&path).expect("the file is there").len()).unwrap();
assert!(total > 0 && total <= file, "{total} bytes charged to a file of {file}");
assert!(file - total < 4096, "{} bytes of the file nobody charged", file - total);
let running = database
.value(
"SELECT count(*) FROM rudb_write_metrics() WHERE target = 'profiled' AND NOT finished",
)
.expect("reads");
assert_eq!(running.to_string(), "0");
drop(database);
std::fs::remove_file(path).expect("removes the temporary database");
}
#[test]
fn a_statement_that_never_loaded_leaves_no_profile() {
let database = Database::new();
database
.execute("CREATE TABLE in_memory AS SELECT range AS a FROM range(10)")
.expect("creates");
let count = database
.value("SELECT count(*) FROM rudb_write_metrics() WHERE target = 'in_memory'")
.expect("reads");
assert_eq!(count.to_string(), "0");
}