Skip to content
This repository was archived by the owner on Jan 22, 2025. It is now read-only.

Commit 136ab21

Browse files
authored
Define InstalledScheduler::wait_for_termination() (#33922)
* Define InstalledScheduler::wait_for_termination() * Rename to wait_for_scheduler_termination * Comment wait_for_termination and WaitReason better
1 parent b2cec5a commit 136ab21

File tree

8 files changed

+401
-16
lines changed

8 files changed

+401
-16
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/src/replay_stage.rs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ use {
4242
block_error::BlockError,
4343
blockstore::Blockstore,
4444
blockstore_processor::{
45-
self, BlockstoreProcessorError, ConfirmationProgress, TransactionStatusSender,
45+
self, BlockstoreProcessorError, ConfirmationProgress, ExecuteBatchesInternalMetrics,
46+
TransactionStatusSender,
4647
},
4748
entry_notifier_service::EntryNotifierSender,
4849
leader_schedule_cache::LeaderScheduleCache,
@@ -2815,6 +2816,40 @@ impl ReplayStage {
28152816
.expect("Bank fork progress entry missing for completed bank");
28162817

28172818
let replay_stats = bank_progress.replay_stats.clone();
2819+
2820+
if let Some((result, completed_execute_timings)) =
2821+
bank.wait_for_completed_scheduler()
2822+
{
2823+
let metrics = ExecuteBatchesInternalMetrics::new_with_timings_from_all_threads(
2824+
completed_execute_timings,
2825+
);
2826+
replay_stats
2827+
.write()
2828+
.unwrap()
2829+
.batch_execute
2830+
.accumulate(metrics);
2831+
2832+
if let Err(err) = result {
2833+
Self::mark_dead_slot(
2834+
blockstore,
2835+
bank,
2836+
bank_forks.read().unwrap().root(),
2837+
&BlockstoreProcessorError::InvalidTransaction(err),
2838+
rpc_subscriptions,
2839+
duplicate_slots_tracker,
2840+
gossip_duplicate_confirmed_slots,
2841+
epoch_slots_frozen_slots,
2842+
progress,
2843+
heaviest_subtree_fork_choice,
2844+
duplicate_slots_to_repair,
2845+
ancestor_hashes_replay_update_sender,
2846+
purge_repair_slot_counter,
2847+
);
2848+
// don't try to run the remaining normal processing for the completed bank
2849+
continue;
2850+
}
2851+
}
2852+
28182853
let r_replay_stats = replay_stats.read().unwrap();
28192854
let replay_progress = bank_progress.replay_progress.clone();
28202855
let r_replay_progress = replay_progress.read().unwrap();

ledger/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ lazy_static = { workspace = true }
2525
libc = { workspace = true }
2626
log = { workspace = true }
2727
lru = { workspace = true }
28+
mockall = { workspace = true }
2829
num_cpus = { workspace = true }
2930
num_enum = { workspace = true }
3031
prost = { workspace = true }

ledger/src/blockstore_processor.rs

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -216,12 +216,27 @@ fn execute_batch(
216216
}
217217

218218
#[derive(Default)]
219-
struct ExecuteBatchesInternalMetrics {
219+
pub struct ExecuteBatchesInternalMetrics {
220220
execution_timings_per_thread: HashMap<usize, ThreadExecuteTimings>,
221221
total_batches_len: u64,
222222
execute_batches_us: u64,
223223
}
224224

225+
impl ExecuteBatchesInternalMetrics {
226+
pub fn new_with_timings_from_all_threads(execute_timings: ExecuteTimings) -> Self {
227+
const DUMMY_THREAD_INDEX: usize = 999;
228+
let mut new = Self::default();
229+
new.execution_timings_per_thread.insert(
230+
DUMMY_THREAD_INDEX,
231+
ThreadExecuteTimings {
232+
execute_timings,
233+
..ThreadExecuteTimings::default()
234+
},
235+
);
236+
new
237+
}
238+
}
239+
225240
fn execute_batches_internal(
226241
bank: &Arc<Bank>,
227242
batches: &[TransactionBatchWithIndexes],
@@ -1068,7 +1083,7 @@ pub struct BatchExecutionTiming {
10681083
}
10691084

10701085
impl BatchExecutionTiming {
1071-
fn accumulate(&mut self, new_batch: ExecuteBatchesInternalMetrics) {
1086+
pub fn accumulate(&mut self, new_batch: ExecuteBatchesInternalMetrics) {
10721087
let Self {
10731088
totals,
10741089
wall_clock_us,
@@ -1382,6 +1397,9 @@ fn process_bank_0(
13821397
&mut ExecuteTimings::default(),
13831398
)
13841399
.expect("Failed to process bank 0 from ledger. Did you forget to provide a snapshot?");
1400+
if let Some((result, _timings)) = bank0.wait_for_completed_scheduler() {
1401+
result.unwrap();
1402+
}
13851403
bank0.freeze();
13861404
if blockstore.is_primary_access() {
13871405
blockstore.insert_bank_hash(bank0.slot(), bank0.hash(), false);
@@ -1784,6 +1802,9 @@ fn process_single_slot(
17841802
err
17851803
})?;
17861804

1805+
if let Some((result, _timings)) = bank.wait_for_completed_scheduler() {
1806+
result?
1807+
}
17871808
bank.freeze(); // all banks handled by this routine are created from complete slots
17881809
if blockstore.is_primary_access() {
17891810
blockstore.insert_bank_hash(bank.slot(), bank.hash(), false);
@@ -1924,7 +1945,7 @@ pub mod tests {
19241945
genesis_utils::{
19251946
self, create_genesis_config_with_vote_accounts, ValidatorVoteKeypairs,
19261947
},
1927-
installed_scheduler_pool::MockInstalledScheduler,
1948+
installed_scheduler_pool::{MockInstalledScheduler, WaitReason},
19281949
},
19291950
solana_sdk::{
19301951
account::{AccountSharedData, WritableAccount},
@@ -4510,10 +4531,17 @@ pub mod tests {
45104531
let txs = create_test_transactions(&mint_keypair, &genesis_config.hash());
45114532

45124533
let mut mocked_scheduler = MockInstalledScheduler::new();
4534+
let mut seq = mockall::Sequence::new();
45134535
mocked_scheduler
45144536
.expect_schedule_execution()
45154537
.times(txs.len())
45164538
.returning(|_| ());
4539+
mocked_scheduler
4540+
.expect_wait_for_termination()
4541+
.with(mockall::predicate::eq(WaitReason::DroppedFromBankForks))
4542+
.times(1)
4543+
.in_sequence(&mut seq)
4544+
.returning(|_| None);
45174545
let bank = BankWithScheduler::new(bank, Some(Box::new(mocked_scheduler)));
45184546

45194547
let batch = bank.prepare_sanitized_batch(&txs);

programs/sbf/Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

runtime/src/bank.rs

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ use {
4343
builtins::{BuiltinPrototype, BUILTINS},
4444
epoch_rewards_hasher::hash_rewards_into_partitions,
4545
epoch_stakes::{EpochStakes, NodeVoteAccounts},
46+
installed_scheduler_pool::{BankWithScheduler, InstalledSchedulerRwLock},
4647
runtime_config::RuntimeConfig,
4748
serde_snapshot::BankIncrementalSnapshotPersistence,
4849
snapshot_hash::SnapshotHash,
@@ -220,7 +221,7 @@ mod metrics;
220221
mod serde_snapshot;
221222
mod sysvar_cache;
222223
#[cfg(test)]
223-
mod tests;
224+
pub(crate) mod tests;
224225
mod transaction_account_state_info;
225226

226227
pub const SECONDS_PER_YEAR: f64 = 365.25 * 24.0 * 60.0 * 60.0;
@@ -4185,7 +4186,11 @@ impl Bank {
41854186
/// Register a new recent blockhash in the bank's recent blockhash queue. Called when a bank
41864187
/// reaches its max tick height. Can be called by tests to get new blockhashes for transaction
41874188
/// processing without advancing to a new bank slot.
4188-
pub fn register_recent_blockhash(&self, blockhash: &Hash) {
4189+
fn register_recent_blockhash(&self, blockhash: &Hash, scheduler: &InstalledSchedulerRwLock) {
4190+
// This is needed because recent_blockhash updates necessitate synchronizations for
4191+
// consistent tx check_age handling.
4192+
BankWithScheduler::wait_for_paused_scheduler(self, scheduler);
4193+
41894194
// Only acquire the write lock for the blockhash queue on block boundaries because
41904195
// readers can starve this write lock acquisition and ticks would be slowed down too
41914196
// much if the write lock is acquired for each tick.
@@ -4197,7 +4202,10 @@ impl Bank {
41974202
// gating this under #[cfg(feature = "dev-context-only-utils")] isn't easy due to
41984203
// solana-program-test's usage...
41994204
pub fn register_unique_recent_blockhash_for_test(&self) {
4200-
self.register_recent_blockhash(&Hash::new_unique())
4205+
self.register_recent_blockhash(
4206+
&Hash::new_unique(),
4207+
&BankWithScheduler::no_scheduler_available(),
4208+
)
42014209
}
42024210

42034211
/// Tell the bank which Entry IDs exist on the ledger. This function assumes subsequent calls
@@ -4206,14 +4214,14 @@ impl Bank {
42064214
///
42074215
/// This is NOT thread safe because if tick height is updated by two different threads, the
42084216
/// block boundary condition could be missed.
4209-
pub fn register_tick(&self, hash: &Hash) {
4217+
pub fn register_tick(&self, hash: &Hash, scheduler: &InstalledSchedulerRwLock) {
42104218
assert!(
42114219
!self.freeze_started(),
42124220
"register_tick() working on a bank that is already frozen or is undergoing freezing!"
42134221
);
42144222

42154223
if self.is_block_boundary(self.tick_height.load(Relaxed) + 1) {
4216-
self.register_recent_blockhash(hash);
4224+
self.register_recent_blockhash(hash, scheduler);
42174225
}
42184226

42194227
// ReplayStage will start computing the accounts delta hash when it
@@ -4226,18 +4234,17 @@ impl Bank {
42264234

42274235
#[cfg(feature = "dev-context-only-utils")]
42284236
pub fn register_tick_for_test(&self, hash: &Hash) {
4229-
// currently meaningless wrapper; upcoming pr will make it an actual helper...
4230-
self.register_tick(hash)
4237+
self.register_tick(hash, &BankWithScheduler::no_scheduler_available())
42314238
}
42324239

42334240
#[cfg(feature = "dev-context-only-utils")]
42344241
pub fn register_default_tick_for_test(&self) {
4235-
self.register_tick(&Hash::default())
4242+
self.register_tick_for_test(&Hash::default())
42364243
}
42374244

42384245
#[cfg(feature = "dev-context-only-utils")]
42394246
pub fn register_unique_tick(&self) {
4240-
self.register_tick(&Hash::new_unique())
4247+
self.register_tick_for_test(&Hash::new_unique())
42414248
}
42424249

42434250
pub fn is_complete(&self) -> bool {
@@ -8008,10 +8015,14 @@ impl Bank {
80088015
}
80098016

80108017
pub fn fill_bank_with_ticks_for_tests(&self) {
8018+
self.do_fill_bank_with_ticks_for_tests(&BankWithScheduler::no_scheduler_available())
8019+
}
8020+
8021+
pub(crate) fn do_fill_bank_with_ticks_for_tests(&self, scheduler: &InstalledSchedulerRwLock) {
80118022
if self.tick_height.load(Relaxed) < self.max_tick_height {
80128023
let last_blockhash = self.last_blockhash();
80138024
while self.last_blockhash() == last_blockhash {
8014-
self.register_tick(&Hash::new_unique())
8025+
self.register_tick(&Hash::new_unique(), scheduler)
80158026
}
80168027
} else {
80178028
warn!("Bank already reached max tick height, cannot fill it with more ticks");

runtime/src/bank/tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ fn test_bank_new() {
274274
assert_eq!(rent.lamports_per_byte_year, 5);
275275
}
276276

277-
fn create_simple_test_bank(lamports: u64) -> Bank {
277+
pub(crate) fn create_simple_test_bank(lamports: u64) -> Bank {
278278
let (genesis_config, _mint_keypair) = create_genesis_config(lamports);
279279
Bank::new_for_tests(&genesis_config)
280280
}

0 commit comments

Comments
 (0)