trust_dns_resolver/name_server/
name_server_stats.rs1use std::cmp::Ordering;
9
10use std::collections::VecDeque;
11use std::sync::Mutex;
12use std::sync::atomic::{self, AtomicUsize};
13
14use crate::error::ResolveErrorKind;
15
16#[derive(Debug, Clone)]
18pub struct NameServerStats {
19 pub addr: std::net::SocketAddr,
21 pub proto: crate::config::Protocol,
23 pub failures: usize,
25 pub successes: usize,
27 pub success_streak: usize,
29 pub recent_errors: Vec<ResolveErrorKind>,
32}
33
34#[derive(Clone)]
35pub(crate) struct InternalNameServerStats {
36 successes: usize,
37 failures: usize,
38 success_streak: usize,
39 retained_errors: usize,
40 recent_errors: VecDeque<ResolveErrorKind>,
41 }
43
44impl InternalNameServerStats {
45 pub(crate) fn new(retained_errors: usize) -> Self {
46 Self::new_internal(0, 0, 0, retained_errors)
47 }
48
49 fn new_internal(successes: usize, failures: usize, success_streak: usize, retained_errors: usize) -> Self {
50 Self {
51 successes: successes,
52 failures: failures,
53 success_streak: success_streak,
54 retained_errors: retained_errors,
55 recent_errors: VecDeque::with_capacity(retained_errors),
56 }
57 }
58
59 pub(crate) fn next_success(&mut self) {
60 self.successes += 1;
61 self.success_streak += 1;
62 }
63
64 pub(crate) fn next_failure(&mut self, error: ResolveErrorKind) {
65 self.failures += 1;
66 self.success_streak = 0;
67
68 if self.retained_errors > 0 {
69 if self.recent_errors.len() >= self.retained_errors {
71 self.recent_errors.pop_front().unwrap();
72 }
73 self.recent_errors.push_back(error);
74 }
75 }
76
77 pub(crate) fn export(
78 &self,
79 addr: std::net::SocketAddr,
80 proto: crate::config::Protocol,
81 ) -> NameServerStats {
82 let Self { successes, failures, success_streak, retained_errors, recent_errors } = self;
83
84 NameServerStats {
85 addr,
86 proto,
87 failures: *failures,
88 successes: *successes,
89 success_streak: *success_streak,
90 recent_errors: self.recent_errors.iter().cloned().collect(),
91 }
92 }
93}
94
95impl PartialEq for InternalNameServerStats {
96 fn eq(&self, other: &Self) -> bool {
97 self.successes == other.successes && self.failures == other.failures
98 }
99}
100
101impl Eq for InternalNameServerStats {}
102
103impl Ord for InternalNameServerStats {
104 fn cmp(&self, other: &Self) -> Ordering {
106 if self == other {
108 return Ordering::Equal;
109 }
110
111 if self.failures <= other.failures {
115 return Ordering::Greater;
116 }
117
118 self.successes.cmp(&other.successes)
120 }
121}
122
123impl PartialOrd for InternalNameServerStats {
124 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
125 Some(self.cmp(other))
126 }
127}
128
129#[cfg(test)]
130mod tests {
131 use super::*;
132
133 fn is_send_sync<S: Sync + Send>() -> bool {
134 true
135 }
136
137 #[test]
138 fn stats_are_sync() {
139 assert!(is_send_sync::<InternalNameServerStats>());
140 }
141
142 #[test]
143 fn test_state_cmp() {
144 let nil = InternalNameServerStats::new_internal(0, 0, 0, 0);
145 let successes = InternalNameServerStats::new_internal(1, 0, 0, 0);
146 let failures = InternalNameServerStats::new_internal(0, 1, 0, 0);
147
148 assert_eq!(nil.cmp(&nil), Ordering::Equal);
149 assert_eq!(nil.cmp(&successes), Ordering::Greater);
150 assert_eq!(successes.cmp(&failures), Ordering::Greater);
151 }
152}