1use {
2 crate::{bank::Bank, installed_scheduler_pool::BankWithScheduler},
3 crossbeam_channel::{Receiver, RecvTimeoutError, Sender, bounded},
4 log::warn,
5 solana_clock::Slot,
6 solana_metrics::datapoint_info,
7 std::{
8 fmt,
9 sync::{Arc, Mutex},
10 time::{Duration, Instant},
11 },
12 thiserror::Error,
13};
14
15const CHANNEL_SIZE: usize = 16;
16
17#[derive(Debug, Error)]
18pub enum BankForksControllerError {
19 #[error("bank forks controller is disconnected")]
20 Disconnected,
21 #[error("bank to insert for slot {0} was stale, failed to insert")]
22 UnableToInsertStaleBank(Slot),
23}
24
25pub enum BankForksCommand {
26 InsertBank {
27 bank: Box<Bank>,
28 response_sender: Sender<Option<BankWithScheduler>>,
29 },
30 ClearBank {
31 slot: Slot,
32 response_sender: Sender<()>,
33 },
34}
35
36pub struct SetRootCommand {
37 pub parent_slot: Slot,
38 pub new_root: Slot,
39 pub highest_super_majority_root: Option<Slot>,
40}
41
42impl BankForksCommand {
43 fn metric_slot(&self) -> Slot {
44 match self {
45 Self::InsertBank { bank, .. } => bank.slot(),
46 Self::ClearBank { slot, .. } => *slot,
47 }
48 }
49}
50
51impl fmt::Display for BankForksCommand {
52 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53 match self {
54 Self::InsertBank { .. } => write!(f, "insert_bank"),
55 Self::ClearBank { .. } => write!(f, "clear_bank"),
56 }
57 }
58}
59
60pub trait BankForksController: Send + Sync {
61 fn insert_bank(&self, bank: Bank) -> Result<BankWithScheduler, BankForksControllerError>;
62
63 fn enqueue_set_root(
64 &self,
65 parent_slot: Slot,
66 new_root: Slot,
67 highest_super_majority_root: Option<Slot>,
68 );
69
70 fn clear_bank(&self, slot: Slot) -> Result<(), BankForksControllerError>;
71}
72
73#[derive(Clone)]
75pub struct BankForksControllerHandle {
76 sender: Sender<BankForksCommand>,
77 pending_set_root: Arc<Mutex<Option<SetRootCommand>>>,
78 set_root_signal_sender: Sender<()>,
79}
80
81impl BankForksControllerHandle {
82 pub fn new() -> (Self, BankForksCommandReceiver) {
83 let (sender, receiver) = bounded(CHANNEL_SIZE);
84 let (set_root_signal_sender, set_root_signal_receiver) = bounded(1);
85 let pending_set_root = Arc::new(Mutex::new(None));
86 (
87 Self {
88 sender,
89 pending_set_root: pending_set_root.clone(),
90 set_root_signal_sender,
91 },
92 BankForksCommandReceiver {
93 receiver,
94 pending_set_root,
95 set_root_signal_receiver,
96 },
97 )
98 }
99
100 fn send_command<T>(
101 &self,
102 command: BankForksCommand,
103 response_receiver: Receiver<T>,
104 ) -> Result<T, BankForksControllerError> {
105 let command_name = command.to_string();
106 let slot = command.metric_slot();
107 let queue_len_before_send = self.sender.len();
108 let total_start = Instant::now();
109 let send_start = Instant::now();
110 if self.sender.send(command).is_err() {
111 return Err(BankForksControllerError::Disconnected);
112 }
113 let send_us = send_start.elapsed().as_micros() as i64;
114
115 let response_wait_start = Instant::now();
116 let response = loop {
117 match response_receiver.recv_timeout(Duration::from_millis(100)) {
118 Ok(response) => break response,
119 Err(RecvTimeoutError::Disconnected) => {
120 return Err(BankForksControllerError::Disconnected);
121 }
122 Err(RecvTimeoutError::Timeout) => (),
123 }
124 warn!(
125 "Replay is stuck, waiting for {}ms no response to {command_name} for {slot}",
126 response_wait_start.elapsed().as_millis()
127 );
128 };
129
130 let response_wait_us = response_wait_start.elapsed().as_micros() as i64;
131 let total_us = total_start.elapsed().as_micros() as i64;
132 datapoint_info!(
133 "bank_forks_controller-command",
134 ("command", command_name, String),
135 ("slot", slot as i64, i64),
136 ("queue_len_before_send", queue_len_before_send as i64, i64),
137 ("send_us", send_us, i64),
138 ("response_wait_us", response_wait_us, i64),
139 ("total_us", total_us, i64),
140 );
141
142 Ok(response)
143 }
144}
145
146impl BankForksController for BankForksControllerHandle {
147 fn insert_bank(&self, bank: Bank) -> Result<BankWithScheduler, BankForksControllerError> {
148 let slot = bank.slot();
149 let (response_sender, response_receiver) = bounded(1);
150 let bank = self.send_command(
151 BankForksCommand::InsertBank {
152 bank: Box::new(bank),
153 response_sender,
154 },
155 response_receiver,
156 )?;
157 bank.ok_or(BankForksControllerError::UnableToInsertStaleBank(slot))
158 }
159
160 fn enqueue_set_root(
161 &self,
162 parent_slot: Slot,
163 new_root: Slot,
164 highest_super_majority_root: Option<Slot>,
165 ) {
166 let total_start = Instant::now();
167 let command = SetRootCommand {
168 parent_slot,
169 new_root,
170 highest_super_majority_root,
171 };
172
173 {
174 let mut pending_set_root = self.pending_set_root.lock().unwrap();
175 if pending_set_root
177 .as_ref()
178 .is_none_or(|pending| command.new_root > pending.new_root)
179 {
180 *pending_set_root = Some(command);
181 }
182 }
183 let _ = self.set_root_signal_sender.try_send(());
184
185 let total_us = total_start.elapsed().as_micros() as i64;
186
187 datapoint_info!(
188 "bank_forks_controller-command",
189 ("command", "set_root", String),
190 ("slot", new_root as i64, i64),
191 ("total_us", total_us, i64),
192 );
193 }
194
195 fn clear_bank(&self, slot: Slot) -> Result<(), BankForksControllerError> {
196 let (response_sender, response_receiver) = bounded(1);
197 self.send_command(
198 BankForksCommand::ClearBank {
199 slot,
200 response_sender,
201 },
202 response_receiver,
203 )
204 }
205}
206
207pub struct BankForksCommandReceiver {
208 receiver: Receiver<BankForksCommand>,
209 pending_set_root: Arc<Mutex<Option<SetRootCommand>>>,
210 set_root_signal_receiver: Receiver<()>,
211}
212
213impl BankForksCommandReceiver {
214 pub fn receiver(&self) -> &Receiver<BankForksCommand> {
215 &self.receiver
216 }
217
218 pub fn set_root_signal_receiver(&self) -> &Receiver<()> {
219 &self.set_root_signal_receiver
220 }
221
222 pub fn take_set_root_command(&self) -> Option<SetRootCommand> {
223 self.pending_set_root.lock().unwrap().take()
224 }
225}
226
227#[cfg(test)]
228mod tests {
229 use {
230 super::*,
231 crate::{bank::SlotLeader, bank_forks::BankForks, genesis_utils::create_genesis_config},
232 std::{thread, time::Duration},
233 };
234
235 #[test]
236 fn test_bank_forks_controller_keeps_highest_pending_set_root() {
237 let (controller, receiver) = BankForksControllerHandle::new();
238
239 controller.enqueue_set_root(5, 5, Some(5));
240 controller.enqueue_set_root(3, 3, Some(3));
241 assert_eq!(receiver.take_set_root_command().unwrap().new_root, 5);
242 assert!(receiver.take_set_root_command().is_none());
243
244 controller.enqueue_set_root(3, 3, Some(3));
245 controller.enqueue_set_root(5, 5, Some(5));
246 assert_eq!(receiver.take_set_root_command().unwrap().new_root, 5);
247 }
248
249 #[test]
250 fn test_bank_forks_controller_signals_pending_set_root() {
251 let (controller, receiver) = BankForksControllerHandle::new();
252
253 controller.enqueue_set_root(1, 1, Some(1));
254 receiver
255 .set_root_signal_receiver()
256 .recv_timeout(Duration::from_secs(1))
257 .unwrap();
258 assert_eq!(receiver.take_set_root_command().unwrap().new_root, 1);
259
260 controller.enqueue_set_root(2, 2, Some(2));
261 controller.enqueue_set_root(3, 3, Some(3));
262 receiver
263 .set_root_signal_receiver()
264 .recv_timeout(Duration::from_secs(1))
265 .unwrap();
266 assert!(receiver.set_root_signal_receiver().try_recv().is_err());
267 assert_eq!(receiver.take_set_root_command().unwrap().new_root, 3);
268 }
269
270 #[test]
271 fn test_bank_forks_controller_insert_and_set_root() {
272 let genesis = create_genesis_config(10_000);
273 let bank_forks = BankForks::new_rw_arc(Bank::new_for_tests(&genesis.genesis_config));
274 let (controller, receiver) = BankForksControllerHandle::new();
275 let replay_bank_forks = bank_forks.clone();
276 let (root_sender, root_receiver) = bounded(1);
277 let replay_thread = thread::spawn(move || {
278 loop {
279 if let Some(command) = receiver.take_set_root_command() {
280 {
281 let mut bank_forks = replay_bank_forks.write().unwrap();
282 bank_forks.set_root(command.new_root, None, None);
283 }
284 root_sender.send(command.new_root).unwrap();
285 }
286 let command = match receiver.receiver().recv_timeout(Duration::from_millis(10)) {
287 Ok(command) => command,
288 Err(RecvTimeoutError::Timeout) => continue,
289 Err(RecvTimeoutError::Disconnected) => break,
290 };
291 match command {
292 BankForksCommand::InsertBank {
293 bank,
294 response_sender,
295 } => {
296 let bank = {
297 let mut bank_forks = replay_bank_forks.write().unwrap();
298 bank_forks.insert(*bank)
299 };
300 response_sender.send(Some(bank)).unwrap();
301 }
302 BankForksCommand::ClearBank {
303 slot,
304 response_sender,
305 } => {
306 let bank_to_clear =
307 replay_bank_forks.read().unwrap().get_with_scheduler(slot);
308 if let Some(bank) = bank_to_clear {
309 let _ = bank.wait_for_completed_scheduler();
310 }
311
312 {
313 let mut bank_forks = replay_bank_forks.write().unwrap();
314 bank_forks.clear_bank(slot, false);
315 }
316 response_sender.send(()).unwrap();
317 }
318 }
319 }
320 });
321
322 let parent_bank = bank_forks.read().unwrap().root_bank();
323 let bank = Bank::new_from_parent(parent_bank, SlotLeader::default(), 1);
324 bank.freeze();
325 let inserted_bank = controller.insert_bank(bank).unwrap();
326 assert_eq!(inserted_bank.slot(), 1);
327 assert!(bank_forks.read().unwrap().get(1).is_some());
328
329 controller.enqueue_set_root(1, 1, None);
330 assert_eq!(root_receiver.recv().unwrap(), 1);
331 assert_eq!(bank_forks.read().unwrap().root(), 1);
332
333 let parent_bank = bank_forks.read().unwrap().root_bank();
334 let bank = Bank::new_from_parent(parent_bank, SlotLeader::default(), 2);
335 bank.freeze();
336 let inserted_bank = controller.insert_bank(bank).unwrap();
337 assert_eq!(inserted_bank.slot(), 2);
338 assert!(bank_forks.read().unwrap().get(2).is_some());
339
340 controller.clear_bank(2).unwrap();
341 assert!(bank_forks.read().unwrap().get(2).is_none());
342
343 drop(controller);
344 replay_thread.join().unwrap();
345 }
346}