solana_core/
cost_update_service.rs

1//! this service asynchronously reports CostTracker stats
2
3use {
4    crossbeam_channel::Receiver,
5    solana_ledger::blockstore::Blockstore,
6    solana_runtime::bank::Bank,
7    std::{
8        sync::Arc,
9        thread::{self, Builder, JoinHandle},
10        time::Duration,
11    },
12};
13pub enum CostUpdate {
14    FrozenBank {
15        bank: Arc<Bank>,
16        is_leader_block: bool,
17    },
18}
19
20pub type CostUpdateReceiver = Receiver<CostUpdate>;
21
22pub struct CostUpdateService {
23    thread_hdl: JoinHandle<()>,
24}
25
26// The maximum number of retries to check if CostTracker::in_flight_transaction_count() has settled
27// to zero. Bail out after this many retries; the in-flight count is reported so this is ok
28const MAX_LOOP_COUNT: usize = 25;
29// Throttle checking the count to avoid excessive polling
30const LOOP_LIMITER: Duration = Duration::from_millis(10);
31
32impl CostUpdateService {
33    pub fn new(blockstore: Arc<Blockstore>, cost_update_receiver: CostUpdateReceiver) -> Self {
34        let thread_hdl = Builder::new()
35            .name("solCostUpdtSvc".to_string())
36            .spawn(move || {
37                Self::service_loop(blockstore, cost_update_receiver);
38            })
39            .unwrap();
40
41        Self { thread_hdl }
42    }
43
44    pub fn join(self) -> thread::Result<()> {
45        self.thread_hdl.join()
46    }
47
48    fn service_loop(_blockstore: Arc<Blockstore>, cost_update_receiver: CostUpdateReceiver) {
49        for cost_update in cost_update_receiver.iter() {
50            match cost_update {
51                CostUpdate::FrozenBank {
52                    bank,
53                    is_leader_block,
54                } => {
55                    for loop_count in 1..=MAX_LOOP_COUNT {
56                        {
57                            // Release the lock so that the thread that will
58                            // update the count is able to obtain a write lock
59                            //
60                            // Use inner scope to avoid sleeping with the lock
61                            let cost_tracker = bank.read_cost_tracker().unwrap();
62                            let in_flight_transaction_count =
63                                cost_tracker.in_flight_transaction_count();
64
65                            if in_flight_transaction_count == 0 || loop_count == MAX_LOOP_COUNT {
66                                let slot = bank.slot();
67                                trace!(
68                                    "inflight transaction count is {in_flight_transaction_count} \
69                                     for slot {slot} after {loop_count} iteration(s)"
70                                );
71                                cost_tracker.report_stats(slot, is_leader_block);
72                                break;
73                            }
74                        }
75                        std::thread::sleep(LOOP_LIMITER);
76                    }
77                }
78            }
79        }
80    }
81}