0.34.6_repo_cleanup

This commit is contained in:
Mateusz Gruszczyński committed 2026-10-22 09:31:15 +02:00
1 parent ce1a90397c
commit 133d2f0f91
273 files changed
+5969 -6926

No files matched your search

-2
View File
@@ -411,8 +411,6 @@ impl Metrics {
}
}
/// Fixed-cardinality per-vhost counters. Retained across config updates by ID,
/// released when a vhost is removed, and finalized after complete body lifetime.
pub const DURATION_BUCKETS_US: [u64; 10] = [
5_000, 10_000, 25_000, 50_000, 100_000, 250_000, 500_000, 1_000_000, 2_500_000, 5_000_000,
];
+46 -20
View File
@@ -1,5 +1,3 @@
// Bounded pull-driven rate sampling for the JSON summary. No per-client state,
// background task, or unbounded history. A cached sample is shared by readers.
use std::sync::Mutex;
use std::time::{Duration, Instant};
@@ -34,8 +32,6 @@ impl RateSampler {
let mut state = self.0.lock().unwrap_or_else(|error| error.into_inner());
if let Some((previous_at, previous)) = state.baseline {
let elapsed = now.saturating_duration_since(previous_at);
// Do not turn rapid parallel polls into zero/spiky rates. Reuse
// the last measured rate until a useful sampling interval passes.
if elapsed < Duration::from_secs(1) {
return state.latest;
}
@@ -47,14 +43,19 @@ impl RateSampler {
if continuous {
let seconds = elapsed.as_secs_f64();
state.latest = SummaryRates {
requests_per_second: Some((counters.requests - previous.requests) as f64 / seconds),
requests_per_second: Some(
(counters.requests - previous.requests) as f64 / seconds,
),
errors_per_second: Some((counters.errors - previous.errors) as f64 / seconds),
bytes_in_per_second: Some((counters.bytes_in - previous.bytes_in) as f64 / seconds),
bytes_out_per_second: Some((counters.bytes_out - previous.bytes_out) as f64 / seconds),
bytes_in_per_second: Some(
(counters.bytes_in - previous.bytes_in) as f64 / seconds,
),
bytes_out_per_second: Some(
(counters.bytes_out - previous.bytes_out) as f64 / seconds,
),
sample_interval_seconds: Some(seconds),
};
} else {
// Long polling gaps or counter resets invalidate the baseline.
state.latest = SummaryRates::default();
}
}
@@ -65,12 +66,15 @@ impl RateSampler {
impl Metrics {
pub fn summary_rates(&self) -> SummaryRates {
self.summary_rate_sampler.sample(SummaryCounters {
requests: self.requests.load(Ordering::Relaxed),
errors: self.errors.load(Ordering::Relaxed),
bytes_in: self.bytes_in.load(Ordering::Relaxed),
bytes_out: self.bytes_out.load(Ordering::Relaxed),
}, Instant::now())
self.summary_rate_sampler.sample(
SummaryCounters {
requests: self.requests.load(Ordering::Relaxed),
errors: self.errors.load(Ordering::Relaxed),
bytes_in: self.bytes_in.load(Ordering::Relaxed),
bytes_out: self.bytes_out.load(Ordering::Relaxed),
},
Instant::now(),
)
}
}
@@ -83,18 +87,40 @@ mod summary_rate_tests {
let sampler = RateSampler::default();
let at = Instant::now();
let counts = |requests, errors, bytes_in, bytes_out| SummaryCounters {
requests, errors, bytes_in, bytes_out
requests,
errors,
bytes_in,
bytes_out,
};
assert!(sampler.sample(counts(10, 2, 100, 200), at).requests_per_second.is_none());
assert!(sampler
.sample(counts(10, 2, 100, 200), at)
.requests_per_second
.is_none());
let rate = sampler.sample(counts(20, 4, 300, 500), at + Duration::from_secs(2));
assert_eq!(rate.requests_per_second, Some(5.0));
assert_eq!(rate.errors_per_second, Some(1.0));
assert_eq!(rate.bytes_in_per_second, Some(100.0));
assert_eq!(rate.bytes_out_per_second, Some(150.0));
assert_eq!(rate.sample_interval_seconds, Some(2.0));
assert_eq!(sampler.sample(counts(21, 4, 310, 520), at + Duration::from_millis(2300)).requests_per_second, Some(5.0));
assert!(sampler.sample(counts(22, 4, 330, 550), at + Duration::from_secs(40)).requests_per_second.is_none());
assert!(sampler.sample(counts(1, 0, 0, 0), at + Duration::from_secs(42)).requests_per_second.is_none());
assert_eq!(sampler.sample(counts(5, 0, 200, 300), at + Duration::from_secs(44)).requests_per_second, Some(2.0));
assert_eq!(
sampler
.sample(counts(21, 4, 310, 520), at + Duration::from_millis(2300))
.requests_per_second,
Some(5.0)
);
assert!(sampler
.sample(counts(22, 4, 330, 550), at + Duration::from_secs(40))
.requests_per_second
.is_none());
assert!(sampler
.sample(counts(1, 0, 0, 0), at + Duration::from_secs(42))
.requests_per_second
.is_none());
assert_eq!(
sampler
.sample(counts(5, 0, 200, 300), at + Duration::from_secs(44))
.requests_per_second,
Some(2.0)
);
}
}
@@ -62,15 +62,10 @@ impl VhostMetrics {
Err(observed) => current = observed,
}
}
// Write exactly one exclusive histogram bin per exchange. Prometheus
// cumulative le=... buckets are reconstructed only when scraped.
// This removes up to 11 contended atomics for short 1 KiB responses.
let bucket = DURATION_BUCKETS_US.partition_point(|threshold| micros > *threshold);
self.buckets[bucket].fetch_add(1, Ordering::Relaxed);
}
/// A scrape-consistent cumulative representation of exclusive bins. The
/// sum of atomic snapshots is monotonic and the final count includes +Inf.
pub fn duration_histogram(&self) -> ([u64; DURATION_BUCKETS_US.len()], u64) {
let mut cumulative = [0u64; DURATION_BUCKETS_US.len()];
let mut count = 0u64;
@@ -104,4 +99,4 @@ impl VhostMetrics {
}
}
#[cfg(test)]
include!("vhost/tests.rs");
include!("tests.rs");
+8 -2
View File
@@ -5,7 +5,13 @@ mod vhost_tests {
let m = VhostMetrics::default();
m.active.store(5, Ordering::Relaxed);
for micros in [1, 5_000, 5_001, 25_000, 5_000_001] {
m.complete(200, false, std::time::Duration::from_micros(micros), 0, 1040);
m.complete(
200,
false,
std::time::Duration::from_micros(micros),
0,
1040,
);
}
let (cumulative, total) = m.duration_histogram();
assert_eq!(total, 5);
@@ -28,7 +34,7 @@ mod vhost_tests {
assert_eq!(n(&m.status[4]), 1);
assert_eq!(n(&m.buckets[1]), 0);
assert_eq!(n(&m.buckets[2]), 1);
assert_eq!(n(&m.buckets[10]), 0); // exclusive +Inf bin
assert_eq!(n(&m.buckets[10]), 0);
let (buckets, count) = m.duration_histogram();
assert_eq!(buckets[1], 0);
assert_eq!(buckets[2], 1);