use dashmap::DashMap;
use once_cell::sync::Lazy;
use std::sync::Mutex;
use std::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
use std::time::Instant;
static ORIGIN: Lazy<Instant> = Lazy::new(Instant::now);
static THREAD_COUNT: AtomicUsize = AtomicUsize::new(0);
static THREAD_LAST_ACTIVITY_MS: Lazy<DashMap<usize, u64, ahash::RandomState>> =
Lazy::new(|| DashMap::with_hasher(ahash::RandomState::new()));
static THREAD_TX_COUNTS: Lazy<DashMap<usize, u64, ahash::RandomState>> =
Lazy::new(|| DashMap::with_hasher(ahash::RandomState::new()));
static LATEST_PULSE: Mutex<Option<PulseSnapshot>> = Mutex::new(None);
static RUN_SLOT_RANGE: Mutex<Option<(u64, u64)>> = Mutex::new(None);
static RESUME_COMMAND_TEMPLATE: Mutex<Option<String>> = Mutex::new(None);
static DB_RETRIES: AtomicU64 = AtomicU64::new(0);
#[derive(Clone, Debug, Default)]
pub struct PulseSnapshot {
pub progress_pct: f64,
pub eta: Option<String>,
pub tps: f64,
pub slots_processed: u64,
pub blocks_processed: u64,
pub transactions_processed: u64,
pub entries_processed: u64,
pub rewards_processed: u64,
pub total_slots: u64,
pub elapsed_secs: f64,
}
pub fn now_ms() -> u64 {
ORIGIN.elapsed().as_millis() as u64
}
pub fn init(thread_count: usize) {
Lazy::force(&ORIGIN);
THREAD_COUNT.store(thread_count, Ordering::Relaxed);
THREAD_LAST_ACTIVITY_MS.clear();
THREAD_TX_COUNTS.clear();
*LATEST_PULSE.lock().unwrap() = None;
*RUN_SLOT_RANGE.lock().unwrap() = None;
DB_RETRIES.store(0, Ordering::Relaxed);
}
pub fn note_db_retry() {
DB_RETRIES.fetch_add(1, Ordering::Relaxed);
}
pub fn db_retry_count() -> u64 {
DB_RETRIES.load(Ordering::Relaxed)
}
pub fn set_resume_command_template(template: String) {
*RESUME_COMMAND_TEMPLATE.lock().unwrap() = Some(template);
}
pub fn resume_command_template() -> Option<String> {
RESUME_COMMAND_TEMPLATE.lock().unwrap().clone()
}
pub fn set_run_slot_range(start: u64, end: u64) {
*RUN_SLOT_RANGE.lock().unwrap() = Some((start, end));
}
pub fn run_slot_range() -> Option<(u64, u64)> {
*RUN_SLOT_RANGE.lock().unwrap()
}
pub fn thread_count() -> usize {
THREAD_COUNT.load(Ordering::Relaxed)
}
pub fn note_thread_activity(thread_id: usize) {
THREAD_LAST_ACTIVITY_MS.insert(thread_id, now_ms());
}
pub fn note_thread_transaction(thread_id: usize) {
note_thread_activity(thread_id);
*THREAD_TX_COUNTS.entry(thread_id).or_insert(0) += 1;
}
pub fn thread_tx_count(thread_id: usize) -> u64 {
THREAD_TX_COUNTS
.get(&thread_id)
.map(|count| *count)
.unwrap_or(0)
}
pub fn thread_idle_ms(thread_id: usize) -> Option<u64> {
THREAD_LAST_ACTIVITY_MS
.get(&thread_id)
.map(|stamp| now_ms().saturating_sub(*stamp))
}
pub fn record_pulse(pulse: PulseSnapshot) {
*LATEST_PULSE.lock().unwrap() = Some(pulse);
}
pub fn latest_pulse() -> Option<PulseSnapshot> {
LATEST_PULSE.lock().unwrap().clone()
}