use super::{RepeatBucket, WindowSummary};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum WindowSource {
Field,
Synthetic,
}
pub const MIN_ACCESSES: u64 = 10_000;
pub const RECOMMENDED_GO_THRESHOLD: f64 = 0.50;
pub const ASSUMED_DECODE_MULTIPLIER: f64 = 3.5;
#[derive(Clone, Debug, PartialEq)]
pub enum Refusal {
UnpriceableFraction {
fraction: f64,
partitions: u64,
},
SamplingFloor {
sample_denominator: u64,
},
NonCensusSample {
sample_denominator: u64,
},
DroppedAccesses {
dropped: u64,
recorded: u64,
},
TooFewAccesses {
accesses: u64,
minimum: u64,
},
SyntheticWorkload,
NoPricedBytes,
InvalidInput {
detail: &'static str,
value: f64,
},
}
impl std::fmt::Display for Refusal {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Refusal::UnpriceableFraction {
fraction,
partitions,
} => write!(
f,
"REFUSED: {partitions} distinct partitions ({:.1}% of the window) have \
size_source=unavailable, so the on-disk byte total is incomplete by an \
unknown amount; a hit-ratio computed from a partial byte total would \
overstate what fits in the budget",
fraction * 100.0
),
Refusal::SamplingFloor { sample_denominator } => write!(
f,
"REFUSED: the recorder reached its sampling floor (denominator \
{sample_denominator}); the surviving sample is statistically worthless"
),
Refusal::NonCensusSample { sample_denominator } => write!(
f,
"REFUSED: this window is a 1-in-{sample_denominator} SAMPLE, not a \
census. Its per-bucket bytes are sample-domain totals, so filling a \
real cache budget against them would price the whole budget against \
1/{sample_denominator} of the working set and OVERSTATE what fits. \
Remedy: shorten the measurement window so the distinct set fits the \
counting table — set CQLITE_PARTITION_ACCESS_WINDOW_SECS (or \
CQLITE_PARTITION_ACCESS_WINDOW_ACCESSES) and re-measure"
),
Refusal::DroppedAccesses { dropped, recorded } => write!(
f,
"REFUSED: {dropped} of {recorded} accesses could not be seated in the \
counting table, so the histogram is missing input. Only NEW keys are \
ever dropped, which suppresses the singleton bucket and overstates \
concentration — the direction that flatters the cache"
),
Refusal::TooFewAccesses { accesses, minimum } => write!(
f,
"REFUSED: {accesses} accesses is below the stated minimum of {minimum}; \
this window is not a workload"
),
Refusal::SyntheticWorkload => write!(
f,
"REFUSED: the window came from synthetic or self-generated load. Its output \
may be recorded as an instrument self-check and may NEVER be cited as the \
decoded-partition-cache go/no-go — the answer would be a function of a \
distribution we chose"
),
Refusal::NoPricedBytes => write!(
f,
"REFUSED: no partition in the window carried authoritative on-disk bytes, \
so no budget can be filled"
),
Refusal::InvalidInput { detail, value } => write!(
f,
"REFUSED: {detail} (got {value}). This is rejected rather than computed \
because the arithmetic would still produce a verdict — a zero decode \
multiplier makes the on-disk budget infinite, every bucket fits, and \
the result is a maximal hit ratio that clears any threshold: a FALSE GO"
),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Ceiling {
pub budget_bytes: u64,
pub on_disk_budget_bytes: f64,
pub h_max: f64,
pub clears_threshold: bool,
pub threshold: f64,
}
#[derive(Clone, Debug, PartialEq)]
pub enum Verdict {
Refused(Refusal),
Priced(Ceiling),
}
impl Verdict {
pub fn is_refusal(&self) -> bool {
matches!(self, Verdict::Refused(_))
}
}
pub fn evaluate(
summary: &WindowSummary,
source: WindowSource,
budget_bytes: u64,
decode_multiplier: f64,
) -> Verdict {
evaluate_with_threshold(
summary,
source,
budget_bytes,
decode_multiplier,
RECOMMENDED_GO_THRESHOLD,
)
}
pub fn evaluate_with_threshold(
summary: &WindowSummary,
source: WindowSource,
budget_bytes: u64,
decode_multiplier: f64,
threshold: f64,
) -> Verdict {
if !decode_multiplier.is_finite() || decode_multiplier <= 0.0 {
return Verdict::Refused(Refusal::InvalidInput {
detail: "the decode multiplier must be a finite number greater than zero",
value: decode_multiplier,
});
}
if !threshold.is_finite() || !(0.0..=1.0).contains(&threshold) {
return Verdict::Refused(Refusal::InvalidInput {
detail: "the go threshold must be a finite hit ratio in [0.0, 1.0]",
value: threshold,
});
}
let unavailable = summary.unavailable_partitions();
if unavailable > 0 {
return Verdict::Refused(Refusal::UnpriceableFraction {
fraction: summary.unavailable_fraction(),
partitions: unavailable,
});
}
if summary.dropped_accesses > 0 {
return Verdict::Refused(Refusal::DroppedAccesses {
dropped: summary.dropped_accesses,
recorded: summary.recorded_accesses,
});
}
if summary.at_sampling_floor {
return Verdict::Refused(Refusal::SamplingFloor {
sample_denominator: summary.sample_denominator,
});
}
if !summary.is_census() {
return Verdict::Refused(Refusal::NonCensusSample {
sample_denominator: summary.sample_denominator,
});
}
let total_accesses = summary.total_accesses();
if total_accesses < MIN_ACCESSES {
return Verdict::Refused(Refusal::TooFewAccesses {
accesses: total_accesses,
minimum: MIN_ACCESSES,
});
}
if source == WindowSource::Synthetic {
return Verdict::Refused(Refusal::SyntheticWorkload);
}
if summary.total_bytes() == 0 {
return Verdict::Refused(Refusal::NoPricedBytes);
}
let mut ordered: Vec<(RepeatBucket, f64, u64, u64, u64)> = RepeatBucket::ALL
.iter()
.filter_map(|b| {
let s = summary.bucket(*b);
let priced = s.distinct_priced();
if s.bytes == 0 || priced == 0 {
return None;
}
let density = s.accesses as f64 / s.bytes as f64;
Some((*b, density, s.accesses, priced, s.bytes))
})
.collect();
ordered.sort_by(|a, b| {
b.1.partial_cmp(&a.1).unwrap_or(std::cmp::Ordering::Equal)
});
let on_disk_budget = budget_bytes as f64 / decode_multiplier;
let mut remaining = on_disk_budget;
let mut served = 0f64;
for (_, _, accesses, distinct, bytes) in ordered {
if remaining <= 0.0 {
break;
}
let hittable = accesses.saturating_sub(distinct) as f64;
let bytes_f = bytes as f64;
if bytes_f <= remaining {
served += hittable;
remaining -= bytes_f;
} else {
let f = remaining / bytes_f;
served += f * hittable;
remaining = 0.0;
}
}
let h_max = served / total_accesses as f64;
Verdict::Priced(Ceiling {
budget_bytes,
on_disk_budget_bytes: on_disk_budget,
h_max,
clears_threshold: h_max >= threshold,
threshold,
})
}
#[cfg(test)]
mod tests {
use super::*;
use crate::observability::partition_access::{
AccessWeight, PartitionAccessRecorder, TableScope, WindowConfig,
};
use std::time::Duration;
fn recorder() -> PartitionAccessRecorder {
PartitionAccessRecorder::new(WindowConfig {
duration: Duration::from_secs(86_400),
max_accesses: u64::MAX,
..WindowConfig::default()
})
}
fn window(spec: &[(u64, u32, u64)]) -> WindowSummary {
let r = recorder();
let mut key = 0u64;
for (n, times, bytes) in spec {
for _ in 0..*n {
key += 1;
for _ in 0..*times {
r.record(
TableScope::new("ks", "t"),
&key.to_le_bytes(),
AccessWeight::SuccessorGap(*bytes),
);
}
}
}
r.close_window().expect("window recorded accesses")
}
#[test]
fn a_window_with_unpriceable_partitions_is_refused_by_name() {
let r = recorder();
for i in 0..12_000u64 {
r.record(
TableScope::new("ks", "t"),
&i.to_le_bytes(),
AccessWeight::SuccessorGap(1_024),
);
}
r.record(
TableScope::new("ks", "t"),
b"bti-resolved",
AccessWeight::Unavailable,
);
let s = r.close_window().expect("accesses recorded");
let v = evaluate(
&s,
WindowSource::Field,
128 * 1024 * 1024,
ASSUMED_DECODE_MULTIPLIER,
);
match v {
Verdict::Refused(Refusal::UnpriceableFraction {
partitions,
fraction,
}) => {
assert_eq!(partitions, 1);
assert!(fraction > 0.0);
}
other => panic!("expected an unpriceable-fraction refusal, got {other:?}"),
}
}
#[test]
fn an_out_of_domain_input_is_refused_rather_than_priced() {
let s = window(&[(600, 20, 1_024), (10_000, 1, 1_024)]);
assert!(
s.total_accesses() >= MIN_ACCESSES,
"so only the input is at issue"
);
for bad_multiplier in [0.0, -1.0, f64::NAN, f64::INFINITY, f64::NEG_INFINITY] {
match evaluate(&s, WindowSource::Field, 128 * 1024 * 1024, bad_multiplier) {
Verdict::Refused(Refusal::InvalidInput { value, .. }) => {
assert!(
value.is_nan() == bad_multiplier.is_nan()
&& (value.is_nan() || value == bad_multiplier),
"the refusal must name the offending value"
);
}
other => panic!("multiplier {bad_multiplier} must be refused: {other:?}"),
}
}
for bad_threshold in [-0.1, 1.5, f64::NAN, f64::INFINITY] {
let v = evaluate_with_threshold(
&s,
WindowSource::Field,
128 * 1024 * 1024,
ASSUMED_DECODE_MULTIPLIER,
bad_threshold,
);
assert!(
matches!(v, Verdict::Refused(Refusal::InvalidInput { .. })),
"threshold {bad_threshold} must be refused: {v:?}"
);
}
for ok_threshold in [0.0, 1.0, RECOMMENDED_GO_THRESHOLD] {
let v = evaluate_with_threshold(
&s,
WindowSource::Field,
128 * 1024 * 1024,
ASSUMED_DECODE_MULTIPLIER,
ok_threshold,
);
assert!(
matches!(v, Verdict::Priced(_)),
"threshold {ok_threshold} is in domain and must price: {v:?}"
);
}
assert!(matches!(
evaluate(
&s,
WindowSource::Field,
128 * 1024 * 1024,
f64::MIN_POSITIVE
),
Verdict::Priced(_)
));
}
#[test]
fn a_synthetic_window_is_refused_however_good_it_looks() {
let s = window(&[(1_000, 20, 1_024)]);
let v = evaluate(
&s,
WindowSource::Synthetic,
128 * 1024 * 1024,
ASSUMED_DECODE_MULTIPLIER,
);
assert_eq!(v, Verdict::Refused(Refusal::SyntheticWorkload));
}
#[test]
fn a_window_below_the_minimum_access_count_is_refused() {
let s = window(&[(10, 5, 1_024)]);
let v = evaluate(
&s,
WindowSource::Field,
128 * 1024 * 1024,
ASSUMED_DECODE_MULTIPLIER,
);
assert_eq!(
v,
Verdict::Refused(Refusal::TooFewAccesses {
accesses: 50,
minimum: MIN_ACCESSES
})
);
}
#[test]
fn a_complete_census_window_is_priced_and_the_estimate_is_hand_checkable() {
let s = window(&[(500, 20, 1_024), (10_000, 1, 1_024)]);
assert!(s.is_census());
assert_eq!(s.total_accesses(), 20_000);
let v = evaluate(
&s,
WindowSource::Field,
128 * 1024 * 1024,
ASSUMED_DECODE_MULTIPLIER,
);
match v {
Verdict::Priced(c) => {
assert!(
(c.h_max - 0.475).abs() < 1e-9,
"expected the hand-computed 0.475, got {}",
c.h_max
);
assert!(!c.clears_threshold, "0.475 is below the 0.50 threshold");
}
other => panic!("expected a priced verdict, got {other:?}"),
}
}
#[test]
fn a_tight_budget_takes_the_densest_bucket_first() {
let s = window(&[(500, 20, 1_024), (10_000, 1, 1_024)]);
let v = evaluate(
&s,
WindowSource::Field,
1_792_000,
ASSUMED_DECODE_MULTIPLIER,
);
match v {
Verdict::Priced(c) => {
assert!(
(c.h_max - 0.475).abs() < 1e-6,
"the cold bucket contributes no hits, so the estimate is unchanged: {}",
c.h_max
);
}
other => panic!("expected a priced verdict, got {other:?}"),
}
}
}