iris_chat_protocol/protocol_engine/
group_retry_pacing.rs1use super::*;
2
3#[derive(Default)]
6pub(super) struct GroupRetryPacing {
7 pub(super) enabled: bool,
8 pub(super) not_before: Option<std::time::Instant>,
9 pub(super) fresh_not_before: Option<std::time::Instant>,
10 #[cfg(test)]
11 pub(super) clock: Option<std::time::Instant>,
12 #[cfg(test)]
13 pub(super) key_trials: usize,
14 #[cfg(test)]
15 pub(super) work_calls: usize,
16 #[cfg(test)]
17 pub(super) fresh_key_trials: usize,
18 #[cfg(test)]
19 pub(super) fresh_work_calls: usize,
20}
21
22impl GroupRetryPacing {
23 pub(super) fn now(&self) -> std::time::Instant {
24 #[cfg(test)]
25 if let Some(now) = self.clock {
26 return now;
27 }
28 std::time::Instant::now()
29 }
30
31 pub(super) fn delay(&self) -> std::time::Duration {
32 if !self.enabled {
33 return std::time::Duration::ZERO;
34 }
35 self.not_before
36 .map_or(std::time::Duration::ZERO, |deadline| {
37 deadline.saturating_duration_since(self.now())
38 })
39 }
40
41 pub(super) fn record_work(&mut self, elapsed: std::time::Duration) {
42 if self.enabled {
43 #[cfg(test)]
44 if let Some(now) = self.clock {
45 self.clock = now.checked_add(elapsed);
48 }
49 self.not_before = self
53 .not_before
54 .unwrap_or_else(|| self.now())
55 .max(self.now())
56 .checked_add(elapsed.saturating_mul(49));
57 }
58 }
59
60 pub(super) fn fresh_delay(&self) -> std::time::Duration {
61 self.fresh_not_before
62 .map_or(std::time::Duration::ZERO, |deadline| {
63 deadline.saturating_duration_since(self.now())
64 })
65 }
66
67 pub(super) fn record_fresh_work(&mut self, elapsed: std::time::Duration) {
68 self.record_work(elapsed);
72 self.fresh_not_before = self.now().checked_add(elapsed.saturating_mul(49));
73 }
74}
75
76impl ProtocolEngine {
77 pub fn enable_background_history_recovery_pacing(&self) {
82 self.group_retry_pacing.borrow_mut().enabled = true;
83 }
84
85 pub fn group_sender_key_retry_delay(&self) -> std::time::Duration {
88 let retry = self.group_sender_key_retry.borrow();
89 if retry.prepared.is_some() {
90 return std::time::Duration::ZERO;
91 }
92 let pacing = self.group_retry_pacing.borrow();
93 if retry.fresh.is_empty() {
94 pacing.delay()
95 } else {
96 pacing.delay().min(pacing.fresh_delay())
97 }
98 }
99}