diff options
author | Stuart Stock <stuart@int08h.com> | 2019-02-09 08:04:28 -0600 |
---|---|---|
committer | Stuart Stock <stuart@int08h.com> | 2019-02-09 08:04:28 -0600 |
commit | a5fc96c00d6edc23811933e73b0175e8bab1ccb1 (patch) | |
tree | 32a5e9058407151f7f639b555c7bd3b5b114df56 /src/stats/mod.rs | |
parent | 194808137ffe18f33bb804b82475a64117d5b247 (diff) | |
download | roughenough-a5fc96c00d6edc23811933e73b0175e8bab1ccb1.zip |
Refactor stats to distinct mod and separate impls
Diffstat (limited to 'src/stats/mod.rs')
-rw-r--r-- | src/stats/mod.rs | 268 |
1 files changed, 22 insertions, 246 deletions
diff --git a/src/stats/mod.rs b/src/stats/mod.rs index 013b7ea..29e7ad8 100644 --- a/src/stats/mod.rs +++ b/src/stats/mod.rs @@ -16,41 +16,15 @@ //! Facilities for tracking client requests to the server //! -use hashbrown::HashMap; -use hashbrown::hash_map::Iter; - -use std::net::IpAddr; - -/// -/// Implementations of this trait record client activity -/// -pub trait ServerStats { - fn add_valid_request(&mut self, addr: &IpAddr); - - fn add_invalid_request(&mut self, addr: &IpAddr); - - fn add_health_check(&mut self, addr: &IpAddr); - - fn add_response(&mut self, addr: &IpAddr, bytes_sent: usize); +mod aggregated; +mod per_client; - fn total_valid_requests(&self) -> u64; +pub use crate::stats::aggregated::AggregatedStats; +pub use crate::stats::per_client::PerClientStats; - fn total_invalid_requests(&self) -> u64; - - fn total_health_checks(&self) -> u64; - - fn total_responses_sent(&self) -> u64; - - fn total_bytes_sent(&self) -> usize; - - fn total_unique_clients(&self) -> u64; - - fn get_client_stats(&self, addr: &IpAddr) -> Option<&ClientStatEntry>; - - fn iter(&self) -> Iter<IpAddr, ClientStatEntry>; +use hashbrown::hash_map::Iter; - fn clear(&mut self); -} +use std::net::IpAddr; /// /// Specific metrics tracked per each client @@ -77,234 +51,36 @@ impl ClientStatEntry { } /// -/// Implementation of `ServerStats` that provides granular per-client request/response counts. -/// -/// Maintains a maximum of `MAX_CLIENTS` unique entries to bound memory use. Excess -/// entries beyond `MAX_CLIENTS` are ignored and `num_overflows` is incremented. +/// Implementations of this trait record client activity /// -pub struct PerClientStats { - clients: HashMap<IpAddr, ClientStatEntry>, - num_overflows: u64, - max_clients: usize, -} - -impl PerClientStats { - - /// Maximum number of stats entries to maintain to prevent - /// unbounded memory growth. - pub const MAX_CLIENTS: usize = 1_000_000; - - pub fn new() -> Self { - PerClientStats { - clients: HashMap::with_capacity(128), - num_overflows: 0, - max_clients: PerClientStats::MAX_CLIENTS, - } - } - - // visible for testing - #[cfg(test)] - fn with_limit(limit: usize) -> Self { - PerClientStats { - clients: HashMap::with_capacity(128), - num_overflows: 0, - max_clients: limit, - } - } - - #[inline] - fn too_many_entries(&mut self) -> bool { - let too_big = self.clients.len() >= self.max_clients; - - if too_big { - self.num_overflows += 1; - } - - return too_big; - } - - #[allow(dead_code)] - pub fn num_overflows(&self) -> u64 { - self.num_overflows - } -} - -impl ServerStats for PerClientStats { - fn add_valid_request(&mut self, addr: &IpAddr) { - if self.too_many_entries() { - return; - } - self.clients - .entry(*addr) - .or_insert_with(ClientStatEntry::new) - .valid_requests += 1; - } - - fn add_invalid_request(&mut self, addr: &IpAddr) { - if self.too_many_entries() { - return; - } - self.clients - .entry(*addr) - .or_insert_with(ClientStatEntry::new) - .invalid_requests += 1; - } - - fn add_health_check(&mut self, addr: &IpAddr) { - if self.too_many_entries() { - return; - } - self.clients - .entry(*addr) - .or_insert_with(ClientStatEntry::new) - .health_checks += 1; - } - - fn add_response(&mut self, addr: &IpAddr, bytes_sent: usize) { - if self.too_many_entries() { - return; - } - let entry = self.clients - .entry(*addr) - .or_insert_with(ClientStatEntry::new); - - entry.responses_sent += 1; - entry.bytes_sent += bytes_sent; - } +pub trait ServerStats { + fn add_valid_request(&mut self, addr: &IpAddr); - fn total_valid_requests(&self) -> u64 { - self.clients - .values() - .map(|&v| v.valid_requests) - .sum() - } + fn add_invalid_request(&mut self, addr: &IpAddr); - fn total_invalid_requests(&self) -> u64 { - self.clients - .values() - .map(|&v| v.invalid_requests) - .sum() - } + fn add_health_check(&mut self, addr: &IpAddr); - fn total_health_checks(&self) -> u64 { - self.clients - .values() - .map(|&v| v.health_checks) - .sum() - } + fn add_response(&mut self, addr: &IpAddr, bytes_sent: usize); - fn total_responses_sent(&self) -> u64 { - self.clients - .values() - .map(|&v| v.responses_sent) - .sum() - } + fn total_valid_requests(&self) -> u64; - fn total_bytes_sent(&self) -> usize { - self.clients - .values() - .map(|&v| v.bytes_sent) - .sum() - } + fn total_invalid_requests(&self) -> u64; - fn total_unique_clients(&self) -> u64 { - self.clients.len() as u64 - } + fn total_health_checks(&self) -> u64; - fn get_client_stats(&self, addr: &IpAddr) -> Option<&ClientStatEntry> { - self.clients.get(addr) - } + fn total_responses_sent(&self) -> u64; - fn iter(&self) -> Iter<IpAddr, ClientStatEntry> { - self.clients.iter() - } + fn total_bytes_sent(&self) -> usize; - fn clear(&mut self) { - self.clients.clear(); - self.num_overflows = 0; - } -} + fn total_unique_clients(&self) -> u64; -/// -/// Implementation of `ServerStats` that provides high-level aggregated server statistics. -/// -#[allow(dead_code)] -pub struct AggregatedStats { - valid_requests: u64, - invalid_requests: u64, - health_checks: u64, - responses_sent: u64, - bytes_sent: usize, - empty_map: HashMap<IpAddr, ClientStatEntry>, -} + fn get_client_stats(&self, addr: &IpAddr) -> Option<&ClientStatEntry>; -impl AggregatedStats { + fn iter(&self) -> Iter<IpAddr, ClientStatEntry>; - #[allow(dead_code)] - pub fn new() -> Self { - AggregatedStats { - valid_requests: 0, - invalid_requests: 0, - health_checks: 0, - responses_sent: 0, - bytes_sent: 0, - empty_map: HashMap::new() - } - } + fn clear(&mut self); } -impl ServerStats for AggregatedStats { - fn add_valid_request(&mut self, _: &IpAddr) { - self.valid_requests += 1 - } - - fn add_invalid_request(&mut self, _: &IpAddr) { - self.invalid_requests += 1 - } - - fn add_health_check(&mut self, _: &IpAddr) { - self.health_checks += 1 - } - - fn add_response(&mut self, _: &IpAddr, bytes_sent: usize) { - self.bytes_sent += bytes_sent; - self.responses_sent += 1; - } - - fn total_valid_requests(&self) -> u64 { - self.valid_requests - } - - fn total_invalid_requests(&self) -> u64 { - self.invalid_requests - } - - fn total_health_checks(&self) -> u64 { - self.health_checks - } - - fn total_responses_sent(&self) -> u64 { - self.responses_sent - } - - fn total_bytes_sent(&self) -> usize { - self.bytes_sent - } - - fn total_unique_clients(&self) -> u64 { - 0 - } - - fn get_client_stats(&self, _addr: &IpAddr) -> Option<&ClientStatEntry> { - None - } - - fn iter(&self) -> Iter<IpAddr, ClientStatEntry> { - self.empty_map.iter() - } - - fn clear(&mut self) {} -} #[cfg(test)] mod test { @@ -355,7 +131,7 @@ mod test { stats.add_response(&ip, 2048); stats.add_response(&ip, 1024); - let entry = stats.get_stats(&ip).unwrap(); + let entry = stats.get_client_stats(&ip).unwrap(); assert_eq!(entry.valid_requests, 1); assert_eq!(entry.invalid_requests, 0); assert_eq!(entry.responses_sent, 2); |