use crate::metrics::DIEM_STORAGE_LEDGER;
use num_derive::ToPrimitive;
use num_traits::ToPrimitive;
use num_variants::NumVariants;
#[cfg(test)]
use proptest::{collection::hash_map, prelude::*};
#[cfg(test)]
use proptest_derive::Arbitrary;
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, ToPrimitive, NumVariants)]
#[cfg_attr(test, derive(Arbitrary))]
pub(crate) enum LedgerCounter {
EventsCreated = 101,
NewStateLeaves = 201,
StaleStateLeaves = 202,
NewStateNodes = 301,
StaleStateNodes = 302,
}
impl LedgerCounter {
const STR_EVENTS_CREATED: &'static str = "events_created";
const STR_NEW_STATE_LEAVES: &'static str = "new_state_leaves";
const STR_NEW_STATE_NODES: &'static str = "new_state_nodes";
const STR_STALE_STATE_LEAVES: &'static str = "stale_state_leaves";
const STR_STALE_STATE_NODES: &'static str = "stale_state_nodes";
const VARIANTS: [LedgerCounter; LedgerCounter::NUM_VARIANTS] = [
LedgerCounter::EventsCreated,
LedgerCounter::NewStateLeaves,
LedgerCounter::StaleStateLeaves,
LedgerCounter::NewStateNodes,
LedgerCounter::StaleStateNodes,
];
pub fn name(self) -> &'static str {
match self {
Self::EventsCreated => Self::STR_EVENTS_CREATED,
Self::NewStateLeaves => Self::STR_NEW_STATE_LEAVES,
Self::StaleStateLeaves => Self::STR_STALE_STATE_LEAVES,
Self::NewStateNodes => Self::STR_NEW_STATE_NODES,
Self::StaleStateNodes => Self::STR_STALE_STATE_NODES,
}
}
}
#[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)]
struct InnerLedgerCounters {
counters: BTreeMap<u16, usize>,
}
impl InnerLedgerCounters {
pub fn new() -> Self {
Self {
counters: BTreeMap::new(),
}
}
fn raw_key(counter: LedgerCounter) -> u16 {
counter
.to_u16()
.expect("LedgerCounter should convert to u16.")
}
fn get(&self, counter: LedgerCounter) -> usize {
self.counters
.get(&Self::raw_key(counter))
.cloned()
.unwrap_or(0)
}
fn inc(&mut self, counter: LedgerCounter, by: usize) -> &mut Self {
self.raw_inc(Self::raw_key(counter), by)
}
fn raw_inc(&mut self, key: u16, by: usize) -> &mut Self {
let value = self.counters.entry(key).or_insert(0);
*value += by;
self
}
}
pub(crate) struct LedgerCounterBumps {
bumps: InnerLedgerCounters,
}
impl LedgerCounterBumps {
pub fn new() -> Self {
Self {
bumps: InnerLedgerCounters::new(),
}
}
pub fn bump(&mut self, counter: LedgerCounter, by: usize) -> &mut Self {
self.bumps.inc(counter, by);
self
}
#[cfg(test)]
pub fn get(&self, counter: LedgerCounter) -> usize {
self.bumps.get(counter)
}
}
#[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)]
pub(crate) struct LedgerCounters {
counters: InnerLedgerCounters,
}
impl LedgerCounters {
pub fn new() -> Self {
Self {
counters: InnerLedgerCounters::new(),
}
}
pub fn bump(&mut self, bumps: &LedgerCounterBumps) -> &mut Self {
for (key, value) in bumps.bumps.counters.iter() {
self.counters.raw_inc(*key, *value);
}
self
}
pub fn bump_op_counters(&self) {
for counter in &LedgerCounter::VARIANTS {
DIEM_STORAGE_LEDGER
.with_label_values(&[counter.name()])
.set(self.get(*counter) as i64);
}
}
pub fn get(&self, counter: LedgerCounter) -> usize {
self.counters.get(counter)
}
}
#[cfg(test)]
prop_compose! {
pub(crate) fn ledger_counters_strategy()(
counters_map in hash_map(any::<LedgerCounter>(), any::<usize>(), 0..3)
) -> LedgerCounters {
let mut counters = InnerLedgerCounters::new();
for (counter, value) in counters_map {
counters.inc(counter, value);
}
LedgerCounters { counters }
}
}
#[cfg(test)]
impl Arbitrary for LedgerCounters {
type Parameters = ();
type Strategy = BoxedStrategy<Self>;
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
ledger_counters_strategy().boxed()
}
}
#[cfg(test)]
mod test;