use std::time::{Duration, Instant};
#[derive(Debug, Clone)]
pub struct PerformanceMetrics {
pub total_queries: u64,
pub successful_queries: u64,
pub failed_queries: u64,
pub consecutive_failures: u32,
pub avg_latency: Duration,
pub last_success_time: Option<Instant>,
pub last_failure_time: Option<Instant>,
pub cdn_accuracy_score: f64,
}
impl Default for PerformanceMetrics {
fn default() -> Self {
Self {
total_queries: 0,
successful_queries: 0,
failed_queries: 0,
consecutive_failures: 0,
avg_latency: Duration::from_millis(100), last_success_time: None,
last_failure_time: None,
cdn_accuracy_score: 0.8, }
}
}
impl PerformanceMetrics {
pub fn new() -> Self {
Self::default()
}
pub fn success_rate(&self) -> f64 {
if self.total_queries == 0 {
0.0
} else {
self.successful_queries as f64 / self.total_queries as f64
}
}
pub fn failure_rate(&self) -> f64 {
1.0 - self.success_rate()
}
pub fn is_available(&self) -> bool {
self.consecutive_failures < 10
}
pub fn latency_grade(&self) -> &'static str {
let ms = self.avg_latency.as_millis();
match ms {
0..=50 => "优秀",
51..=100 => "良好",
101..=200 => "一般",
201..=500 => "较差",
_ => "很差",
}
}
pub fn record_success(&mut self, latency: Duration, cdn_accurate: bool) {
self.total_queries += 1;
self.successful_queries += 1;
self.consecutive_failures = 0;
self.last_success_time = Some(Instant::now());
if self.total_queries == 1 {
self.avg_latency = latency;
} else {
let alpha = 0.1; let old_latency_ms = self.avg_latency.as_millis() as f64;
let new_latency_ms = latency.as_millis() as f64;
let smoothed_latency_ms = old_latency_ms * (1.0 - alpha) + new_latency_ms * alpha;
self.avg_latency = Duration::from_millis(smoothed_latency_ms as u64);
}
let current_score = self.cdn_accuracy_score * (self.successful_queries - 1) as f64;
let new_score = if cdn_accurate { 1.0 } else { 0.0 };
self.cdn_accuracy_score = (current_score + new_score) / self.successful_queries as f64;
}
pub fn record_failure(&mut self) {
self.total_queries += 1;
self.failed_queries += 1;
self.consecutive_failures += 1;
self.last_failure_time = Some(Instant::now());
}
pub fn reset(&mut self) {
*self = Self::default();
}
pub fn overall_score(&self) -> f64 {
let success_weight = 0.4;
let latency_weight = 0.3;
let cdn_weight = 0.2;
let availability_weight = 0.1;
let success_score = self.success_rate();
let latency_score = if self.avg_latency.as_millis() > 0 {
(1000.0 / (self.avg_latency.as_millis() as f64 + 100.0)).min(1.0)
} else {
1.0
};
let cdn_score = self.cdn_accuracy_score;
let availability_score = if self.is_available() { 1.0 } else { 0.0 };
success_score * success_weight
+ latency_score * latency_weight
+ cdn_score * cdn_weight
+ availability_score * availability_weight
}
}