use crate::types::RespCommand;
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct CommandStatsEntry {
pub calls: u64,
pub failed_calls: u64,
pub rejected_calls: u64,
}
pub struct CommandStats {
pub entries: Vec<CommandStatsEntry>,
}
impl CommandStats {
pub const ENTRY_COUNT: usize = RespCommand::Quit as u16 as usize + 1;
pub fn new() -> Self {
Self {
entries: vec![CommandStatsEntry::default(); Self::ENTRY_COUNT],
}
}
#[inline]
pub fn increment_calls(&mut self, cmd: RespCommand) {
if let Some(entry) = self.entries.get_mut(cmd as u16 as usize) {
entry.calls += 1;
}
}
#[inline]
pub fn increment_failed(&mut self, cmd: RespCommand) {
if let Some(entry) = self.entries.get_mut(cmd as u16 as usize) {
entry.failed_calls += 1;
}
}
#[inline]
pub fn increment_rejected(&mut self, cmd: RespCommand) {
if let Some(entry) = self.entries.get_mut(cmd as u16 as usize) {
entry.rejected_calls += 1;
}
}
#[inline]
pub fn get_entry(&self, cmd: RespCommand) -> CommandStatsEntry {
self
.entries
.get(cmd as u16 as usize)
.copied()
.unwrap_or_default()
}
pub fn add(&mut self, other: &CommandStats) {
let len = self.entries.len().min(other.entries.len());
for (dst, src) in self.entries[..len]
.iter_mut()
.zip(other.entries[..len].iter())
{
dst.calls += src.calls;
dst.failed_calls += src.failed_calls;
dst.rejected_calls += src.rejected_calls;
}
}
pub fn reset(&mut self) {
self.entries.fill(CommandStatsEntry::default());
}
}
impl Default for CommandStats {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::CommandStats;
use crate::types::RespCommand;
#[test]
fn counters_per_command() {
let mut stats = CommandStats::new();
assert_eq!(stats.entries.len(), RespCommand::Quit as u16 as usize + 1);
stats.increment_calls(RespCommand::Get);
stats.increment_calls(RespCommand::Get);
stats.increment_failed(RespCommand::Get);
stats.increment_rejected(RespCommand::Set);
let get = stats.get_entry(RespCommand::Get);
assert_eq!((get.calls, get.failed_calls, get.rejected_calls), (2, 1, 0));
let set = stats.get_entry(RespCommand::Set);
assert_eq!((set.calls, set.failed_calls, set.rejected_calls), (0, 0, 1));
assert_eq!(
stats.get_entry(RespCommand::Ping),
super::CommandStatsEntry::default()
);
}
#[test]
fn add_and_reset() {
let mut a = CommandStats::new();
let mut b = CommandStats::new();
a.increment_calls(RespCommand::Incr);
b.increment_calls(RespCommand::Incr);
b.increment_calls(RespCommand::Incr);
b.increment_failed(RespCommand::Decr);
a.add(&b);
assert_eq!(a.get_entry(RespCommand::Incr).calls, 3);
assert_eq!(a.get_entry(RespCommand::Decr).failed_calls, 1);
a.reset();
assert_eq!(a.get_entry(RespCommand::Incr).calls, 0);
}
}