jetstreamer_plugin/
metrics.rs1use dashmap::DashMap;
8use once_cell::sync::Lazy;
9use std::sync::Mutex;
10use std::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
11use std::time::Instant;
12
13static ORIGIN: Lazy<Instant> = Lazy::new(Instant::now);
14static THREAD_COUNT: AtomicUsize = AtomicUsize::new(0);
15static THREAD_LAST_ACTIVITY_MS: Lazy<DashMap<usize, u64, ahash::RandomState>> =
16 Lazy::new(|| DashMap::with_hasher(ahash::RandomState::new()));
17static THREAD_TX_COUNTS: Lazy<DashMap<usize, u64, ahash::RandomState>> =
18 Lazy::new(|| DashMap::with_hasher(ahash::RandomState::new()));
19static LATEST_PULSE: Mutex<Option<PulseSnapshot>> = Mutex::new(None);
20static RUN_SLOT_RANGE: Mutex<Option<(u64, u64)>> = Mutex::new(None);
21static RESUME_COMMAND_TEMPLATE: Mutex<Option<String>> = Mutex::new(None);
22static DB_RETRIES: AtomicU64 = AtomicU64::new(0);
23
24#[derive(Clone, Debug, Default)]
26pub struct PulseSnapshot {
27 pub progress_pct: f64,
29 pub eta: Option<String>,
31 pub tps: f64,
33 pub slots_processed: u64,
35 pub blocks_processed: u64,
37 pub transactions_processed: u64,
39 pub entries_processed: u64,
41 pub rewards_processed: u64,
43 pub total_slots: u64,
45 pub elapsed_secs: f64,
47}
48
49pub fn now_ms() -> u64 {
51 ORIGIN.elapsed().as_millis() as u64
52}
53
54pub fn init(thread_count: usize) {
56 Lazy::force(&ORIGIN);
57 THREAD_COUNT.store(thread_count, Ordering::Relaxed);
58 THREAD_LAST_ACTIVITY_MS.clear();
59 THREAD_TX_COUNTS.clear();
60 *LATEST_PULSE.lock().unwrap() = None;
61 *RUN_SLOT_RANGE.lock().unwrap() = None;
62 DB_RETRIES.store(0, Ordering::Relaxed);
63}
64
65pub fn note_db_retry() {
67 DB_RETRIES.fetch_add(1, Ordering::Relaxed);
68}
69
70pub fn db_retry_count() -> u64 {
72 DB_RETRIES.load(Ordering::Relaxed)
73}
74
75pub fn set_resume_command_template(template: String) {
79 *RESUME_COMMAND_TEMPLATE.lock().unwrap() = Some(template);
80}
81
82pub fn resume_command_template() -> Option<String> {
84 RESUME_COMMAND_TEMPLATE.lock().unwrap().clone()
85}
86
87pub fn set_run_slot_range(start: u64, end: u64) {
89 *RUN_SLOT_RANGE.lock().unwrap() = Some((start, end));
90}
91
92pub fn run_slot_range() -> Option<(u64, u64)> {
94 *RUN_SLOT_RANGE.lock().unwrap()
95}
96
97pub fn thread_count() -> usize {
99 THREAD_COUNT.load(Ordering::Relaxed)
100}
101
102pub fn note_thread_activity(thread_id: usize) {
104 THREAD_LAST_ACTIVITY_MS.insert(thread_id, now_ms());
105}
106
107pub fn note_thread_transaction(thread_id: usize) {
109 note_thread_activity(thread_id);
110 *THREAD_TX_COUNTS.entry(thread_id).or_insert(0) += 1;
111}
112
113pub fn thread_tx_count(thread_id: usize) -> u64 {
115 THREAD_TX_COUNTS
116 .get(&thread_id)
117 .map(|count| *count)
118 .unwrap_or(0)
119}
120
121pub fn thread_idle_ms(thread_id: usize) -> Option<u64> {
124 THREAD_LAST_ACTIVITY_MS
125 .get(&thread_id)
126 .map(|stamp| now_ms().saturating_sub(*stamp))
127}
128
129pub fn record_pulse(pulse: PulseSnapshot) {
131 *LATEST_PULSE.lock().unwrap() = Some(pulse);
132}
133
134pub fn latest_pulse() -> Option<PulseSnapshot> {
136 LATEST_PULSE.lock().unwrap().clone()
137}