bank.initial_blockstore_processing_complete to avoid concurrent hash calculations (#27776)

* bank.initial_blockstore_processing_complete to avoid concurrent hash calculations

* Update runtime/src/bank.rs

Co-authored-by: Brooks Prumo <brooks@prumo.org>

* Update runtime/src/bank.rs

Co-authored-by: Brooks Prumo <brooks@prumo.org>

* Rename TestValidator::set_startup_verification_complete()

* Initialize with `AtomicBool::new(false)` instead of `default()`

* snapshot tests: move where `initial_blockstore_processing_completed()` is called

* fixup bank_forks.rs calling `is_initial_blockstore_processing_complete()`

* only call initial_blockstore_processing_completed() in blockstore_processor

Co-authored-by: Brooks Prumo <brooks@prumo.org>
Co-authored-by: Brooks Prumo <brooks@solana.com>
This commit is contained in:
Jeff Washington (jwash) 2022-09-19 13:00:21 -07:00 committed by GitHub
parent abfb996135
commit f2d6a7ecea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 43 additions and 12 deletions

View File

@ -103,6 +103,8 @@ impl SnapshotTestConfig {
accounts_db::AccountShrinkThreshold::default(), accounts_db::AccountShrinkThreshold::default(),
); );
bank0.freeze(); bank0.freeze();
bank0.set_startup_verification_complete();
bank0.initial_blockstore_processing_completed();
let mut bank_forks = BankForks::new(bank0); let mut bank_forks = BankForks::new(bank0);
bank_forks.accounts_hash_interval_slots = accounts_hash_interval_slots; bank_forks.accounts_hash_interval_slots = accounts_hash_interval_slots;
@ -208,7 +210,6 @@ fn run_bank_forks_snapshot_n<F>(
); );
let bank_forks = &mut snapshot_test_config.bank_forks; let bank_forks = &mut snapshot_test_config.bank_forks;
bank_forks.root_bank().set_startup_verification_complete();
let mint_keypair = &snapshot_test_config.genesis_config_info.mint_keypair; let mint_keypair = &snapshot_test_config.genesis_config_info.mint_keypair;
let (snapshot_request_sender, snapshot_request_receiver) = unbounded(); let (snapshot_request_sender, snapshot_request_receiver) = unbounded();
@ -675,7 +676,6 @@ fn test_bank_forks_incremental_snapshot(
snapshot_test_config.accounts_dir.path().display(), snapshot_test_config.bank_snapshots_dir.path().display(), snapshot_test_config.full_snapshot_archives_dir.path().display(), snapshot_test_config.incremental_snapshot_archives_dir.path().display()); snapshot_test_config.accounts_dir.path().display(), snapshot_test_config.bank_snapshots_dir.path().display(), snapshot_test_config.full_snapshot_archives_dir.path().display(), snapshot_test_config.incremental_snapshot_archives_dir.path().display());
let bank_forks = &mut snapshot_test_config.bank_forks; let bank_forks = &mut snapshot_test_config.bank_forks;
bank_forks.root_bank().set_startup_verification_complete();
let mint_keypair = &snapshot_test_config.genesis_config_info.mint_keypair; let mint_keypair = &snapshot_test_config.genesis_config_info.mint_keypair;
let (snapshot_request_sender, snapshot_request_receiver) = unbounded(); let (snapshot_request_sender, snapshot_request_receiver) = unbounded();

View File

@ -874,6 +874,8 @@ pub fn process_blockstore_from_root(
} }
time_cap.stop(); time_cap.stop();
bank.initial_blockstore_processing_completed();
datapoint_info!( datapoint_info!(
"process_blockstore_from_root", "process_blockstore_from_root",
("total_time_us", processing_time.as_micros(), i64), ("total_time_us", processing_time.as_micros(), i64),

View File

@ -1204,6 +1204,9 @@ pub struct AccountsDb {
/// debug feature to scan every append vec and verify refcounts are equal /// debug feature to scan every append vec and verify refcounts are equal
exhaustively_verify_refcounts: bool, exhaustively_verify_refcounts: bool,
/// true once all accounts hash calculations that may take place at startup have been requested
pub initial_blockstore_processing_complete: AtomicBool,
/// the full accounts hash calculation as of a predetermined block height 'N' /// the full accounts hash calculation as of a predetermined block height 'N'
/// to be included in the bank hash at a predetermined block height 'M' /// to be included in the bank hash at a predetermined block height 'M'
/// The cadence is once per epoch, all nodes calculate a full accounts hash as of a known slot calculated using 'N' /// The cadence is once per epoch, all nodes calculate a full accounts hash as of a known slot calculated using 'N'
@ -2020,6 +2023,7 @@ impl AccountsDb {
num_hash_scan_passes, num_hash_scan_passes,
log_dead_slots: AtomicBool::new(true), log_dead_slots: AtomicBool::new(true),
exhaustively_verify_refcounts: false, exhaustively_verify_refcounts: false,
initial_blockstore_processing_complete: AtomicBool::new(false),
epoch_accounts_hash: Mutex::new(None), epoch_accounts_hash: Mutex::new(None),
} }
} }

View File

@ -163,7 +163,7 @@ use {
sync::{ sync::{
atomic::{ atomic::{
AtomicBool, AtomicI64, AtomicU64, AtomicUsize, AtomicBool, AtomicI64, AtomicU64, AtomicUsize,
Ordering::{AcqRel, Acquire, Relaxed}, Ordering::{AcqRel, Acquire, Relaxed, Release},
}, },
Arc, LockResult, RwLock, RwLockReadGuard, RwLockWriteGuard, Arc, LockResult, RwLock, RwLockReadGuard, RwLockWriteGuard,
}, },
@ -7231,6 +7231,28 @@ impl Bank {
self.update_accounts_hash_with_index_option(true, false, false) self.update_accounts_hash_with_index_option(true, false, false)
} }
/// When the validator starts up, there is an initial hash calculation verification of the snapshot.
/// Then, in some conditions, there are additional slots replayed and a second hash calculation verification occurs.
/// This function is called when all initial hash calculations have been requested or completed.
pub fn initial_blockstore_processing_completed(&self) {
self.rc
.accounts
.accounts_db
.initial_blockstore_processing_complete
.store(true, Release);
}
/// until this occurs, no additional accounts hash calculations can be started
/// There will be 0..=2 of these requests.
pub fn is_initial_blockstore_processing_complete(&self) -> bool {
self.rc
.accounts
.accounts_db
.initial_blockstore_processing_complete
.load(Acquire)
&& self.is_startup_verification_complete()
}
/// A snapshot bank should be purged of 0 lamport accounts which are not part of the hash /// A snapshot bank should be purged of 0 lamport accounts which are not part of the hash
/// calculation and could shield other real accounts. /// calculation and could shield other real accounts.
pub fn verify_snapshot_bank( pub fn verify_snapshot_bank(
@ -8152,9 +8174,7 @@ pub(crate) mod tests {
MAX_LOCKOUT_HISTORY, MAX_LOCKOUT_HISTORY,
}, },
}, },
std::{ std::{result, str::FromStr, thread::Builder, time::Duration},
result, str::FromStr, sync::atomic::Ordering::Release, thread::Builder, time::Duration,
},
test_utils::goto_end_of_slot, test_utils::goto_end_of_slot,
}; };

View File

@ -276,7 +276,7 @@ impl BankForks {
if self.snapshot_config.is_some() if self.snapshot_config.is_some()
&& accounts_background_request_sender.is_snapshot_creation_enabled() && accounts_background_request_sender.is_snapshot_creation_enabled()
{ {
if bank.is_startup_verification_complete() { if bank.is_initial_blockstore_processing_complete() {
// Save off the status cache because these may get pruned if another // Save off the status cache because these may get pruned if another
// `set_root()` is called before the snapshots package can be generated // `set_root()` is called before the snapshots package can be generated
let status_cache_slot_deltas = let status_cache_slot_deltas =

View File

@ -600,12 +600,17 @@ impl TestValidator {
} }
/// allow tests to indicate that validator has completed initialization /// allow tests to indicate that validator has completed initialization
pub fn set_startup_verification_complete(&self) { pub fn set_startup_verification_complete_for_tests(&self) {
self.bank_forks() self.bank_forks()
.read() .read()
.unwrap() .unwrap()
.root_bank() .root_bank()
.set_startup_verification_complete(); .set_startup_verification_complete();
self.bank_forks()
.read()
.unwrap()
.root_bank()
.initial_blockstore_processing_completed();
} }
/// Initialize the ledger directory /// Initialize the ledger directory
@ -1003,7 +1008,7 @@ mod test {
#[test] #[test]
fn get_health() { fn get_health() {
let (test_validator, _payer) = TestValidatorGenesis::default().start(); let (test_validator, _payer) = TestValidatorGenesis::default().start();
test_validator.set_startup_verification_complete(); test_validator.set_startup_verification_complete_for_tests();
let rpc_client = test_validator.get_rpc_client(); let rpc_client = test_validator.get_rpc_client();
rpc_client.get_health().expect("health"); rpc_client.get_health().expect("health");
} }
@ -1011,7 +1016,7 @@ mod test {
#[tokio::test] #[tokio::test]
async fn nonblocking_get_health() { async fn nonblocking_get_health() {
let (test_validator, _payer) = TestValidatorGenesis::default().start_async().await; let (test_validator, _payer) = TestValidatorGenesis::default().start_async().await;
test_validator.set_startup_verification_complete(); test_validator.set_startup_verification_complete_for_tests();
let rpc_client = test_validator.get_async_rpc_client(); let rpc_client = test_validator.get_async_rpc_client();
rpc_client.get_health().await.expect("health"); rpc_client.get_health().await.expect("health");
} }

View File

@ -1279,7 +1279,7 @@ mod tests {
fn simple_test_validator_no_fees(pubkey: Pubkey) -> TestValidator { fn simple_test_validator_no_fees(pubkey: Pubkey) -> TestValidator {
let test_validator = let test_validator =
TestValidator::with_no_fees(pubkey, None, SocketAddrSpace::Unspecified); TestValidator::with_no_fees(pubkey, None, SocketAddrSpace::Unspecified);
test_validator.set_startup_verification_complete(); test_validator.set_startup_verification_complete_for_tests();
test_validator test_validator
} }
@ -1826,7 +1826,7 @@ mod tests {
fn simple_test_validator(alice: Pubkey) -> TestValidator { fn simple_test_validator(alice: Pubkey) -> TestValidator {
let test_validator = let test_validator =
TestValidator::with_custom_fees(alice, 10_000, None, SocketAddrSpace::Unspecified); TestValidator::with_custom_fees(alice, 10_000, None, SocketAddrSpace::Unspecified);
test_validator.set_startup_verification_complete(); test_validator.set_startup_verification_complete_for_tests();
test_validator test_validator
} }