cherenkov/server/
pacer.rs1pub(super) struct ChunkPacer {
4 floor: usize,
5 ceiling: usize,
6 target_seconds: f64,
8 tokens: usize,
9 contended: bool,
10}
11
12impl ChunkPacer {
13 pub(super) fn new(ceiling: usize, target_seconds: f64) -> Self {
14 let floor = ceiling.min(128);
15
16 Self {
17 floor,
18 ceiling,
19 target_seconds,
20 tokens: if target_seconds == 0.0 {
21 ceiling
22 } else {
23 floor
24 },
25 contended: false,
26 }
27 }
28
29 pub(super) fn quantum(&mut self, contended: bool) -> usize {
32 if self.target_seconds == 0.0 {
33 return self.ceiling;
34 }
35
36 if contended && !self.contended {
37 self.tokens = self.floor;
38 }
39
40 self.contended = contended;
41
42 if contended { self.tokens } else { self.ceiling }
43 }
44
45 pub(super) fn observe(&mut self, tokens: usize, seconds: f64) {
48 if !self.contended || tokens == 0 || !seconds.is_finite() || seconds <= 0.0 {
49 return;
50 }
51
52 let scaled = tokens as f64 * self.target_seconds / seconds;
53 let damped = scaled.clamp(self.tokens as f64 * 0.5, self.tokens as f64 * 2.0);
54
55 self.tokens = (damped as usize).clamp(self.floor, self.ceiling);
56 }
57
58 pub(super) fn tokens(&self) -> usize {
60 self.tokens
61 }
62}
63
64#[cfg(test)]
65#[path = "../../tests/unit/server/pacer.rs"]
66mod tests;