use std::collections::hash_map::Iter;
use std::collections::HashMap;
use std::net::IpAddr;
use crate::stats::ClientStatEntry;
use crate::stats::ServerStats;
pub struct PerClientStats {
clients: HashMap<IpAddr, ClientStatEntry>,
num_overflows: u64,
max_clients: usize,
}
impl Default for PerClientStats {
fn default() -> Self {
Self::new()
}
}
pub const MAX_CLIENTS: usize = 100_000;
impl PerClientStats {
pub fn new() -> Self {
PerClientStats {
clients: HashMap::with_capacity(MAX_CLIENTS),
num_overflows: 0,
max_clients: MAX_CLIENTS,
}
}
#[cfg(test)]
pub fn with_limit(limit: usize) -> Self {
PerClientStats {
clients: HashMap::with_capacity(64),
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;
}
too_big
}
#[allow(dead_code)]
pub fn num_overflows(&self) -> u64 {
self.num_overflows
}
}
impl ServerStats for PerClientStats {
fn add_rfc_request(&mut self, addr: &IpAddr) {
if self.too_many_entries() {
return;
}
self.clients
.entry(*addr)
.or_insert_with(ClientStatEntry::new)
.rfc_requests += 1;
}
fn add_classic_request(&mut self, addr: &IpAddr) {
if self.too_many_entries() {
return;
}
self.clients
.entry(*addr)
.or_insert_with(ClientStatEntry::new)
.classic_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_failed_send_attempt(&mut self, addr: &IpAddr) {
if self.too_many_entries() {
return;
}
self.clients
.entry(*addr)
.or_insert_with(ClientStatEntry::new)
.failed_send_attempts += 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_rfc_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.rfc_responses_sent += 1;
entry.bytes_sent += bytes_sent;
}
fn add_classic_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.classic_responses_sent += 1;
entry.bytes_sent += bytes_sent;
}
fn total_valid_requests(&self) -> u64 {
self.clients
.values()
.map(|&v| v.rfc_requests + v.classic_requests)
.sum()
}
fn num_rfc_requests(&self) -> u64 {
self.clients.values().map(|&v| v.rfc_requests).sum()
}
fn num_classic_requests(&self) -> u64 {
self.clients.values().map(|&v| v.classic_requests).sum()
}
fn total_invalid_requests(&self) -> u64 {
self.clients.values().map(|&v| v.invalid_requests).sum()
}
fn total_health_checks(&self) -> u64 {
self.clients.values().map(|&v| v.health_checks).sum()
}
fn total_failed_send_attempts(&self) -> u64 {
self.clients.values().map(|&v| v.failed_send_attempts).sum()
}
fn total_responses_sent(&self) -> u64 {
self.clients
.values()
.map(|&v| v.rfc_responses_sent + v.classic_responses_sent)
.sum()
}
fn num_rfc_responses_sent(&self) -> u64 {
self.clients.values().map(|&v| v.rfc_responses_sent).sum()
}
fn num_classic_responses_sent(&self) -> u64 {
self.clients
.values()
.map(|&v| v.classic_responses_sent)
.sum()
}
fn total_bytes_sent(&self) -> usize {
self.clients.values().map(|&v| v.bytes_sent).sum()
}
fn total_unique_clients(&self) -> u64 {
self.clients.len() as u64
}
fn stats_for_client(&self, addr: &IpAddr) -> Option<&ClientStatEntry> {
self.clients.get(addr)
}
fn iter(&self) -> Iter<IpAddr, ClientStatEntry> {
self.clients.iter()
}
fn clear(&mut self) {
self.clients.clear();
self.num_overflows = 0;
}
}