diff --git a/core/src/validator.rs b/core/src/validator.rs index f35211fd62..1558222685 100644 --- a/core/src/validator.rs +++ b/core/src/validator.rs @@ -1418,7 +1418,9 @@ fn load_blockstore( let blockstore = Arc::new(blockstore); let blockstore_root_scan = BlockstoreRootScan::new(config, &blockstore, exit); - let halt_at_slot = config.halt_at_slot.or_else(|| highest_slot(&blockstore)); + let halt_at_slot = config + .halt_at_slot + .or_else(|| blockstore.highest_slot().unwrap_or(None)); let process_options = blockstore_processor::ProcessOptions { poh_verify: config.poh_verify, @@ -1517,29 +1519,6 @@ fn load_blockstore( )) } -fn highest_slot(blockstore: &Blockstore) -> Option { - let mut start = Measure::start("Blockstore search for highest slot"); - let highest_slot = blockstore - .slot_meta_iterator(0) - .map(|metas| { - let slots: Vec<_> = metas.map(|(slot, _)| slot).collect(); - if slots.is_empty() { - info!("Ledger is empty"); - None - } else { - let first = slots.first().unwrap(); - Some(*slots.last().unwrap_or(first)) - } - }) - .unwrap_or_else(|err| { - warn!("Failed to ledger slot meta: {}", err); - None - }); - start.stop(); - info!("{}. Found slot {:?}", start, highest_slot); - highest_slot -} - pub struct ProcessBlockStore<'a> { id: &'a Pubkey, vote_account: &'a Pubkey, @@ -1598,7 +1577,7 @@ impl<'a> ProcessBlockStore<'a> { *self.start_progress.write().unwrap() = ValidatorStartProgress::LoadingLedger; let exit = Arc::new(AtomicBool::new(false)); - if let Some(max_slot) = highest_slot(self.blockstore) { + if let Ok(Some(max_slot)) = self.blockstore.highest_slot() { let bank_forks = self.bank_forks.clone(); let exit = exit.clone(); let start_progress = self.start_progress.clone(); diff --git a/ledger/src/blockstore.rs b/ledger/src/blockstore.rs index 261bc7439d..e8360a1616 100644 --- a/ledger/src/blockstore.rs +++ b/ledger/src/blockstore.rs @@ -3226,6 +3226,16 @@ impl Blockstore { self.last_root() } + /// Returns the highest available slot in the blockstore + pub fn highest_slot(&self) -> Result> { + let highest_slot = self + .db + .iter::(IteratorMode::End)? + .next() + .map(|(slot, _)| slot); + Ok(highest_slot) + } + pub fn lowest_cleanup_slot(&self) -> Slot { *self.lowest_cleanup_slot.read().unwrap() } @@ -8433,6 +8443,27 @@ pub mod tests { assert_eq!(blockstore.lowest_slot(), 6); } + #[test] + fn test_highest_slot() { + let ledger_path = get_tmp_ledger_path_auto_delete!(); + let blockstore = Blockstore::open(ledger_path.path()).unwrap(); + + assert_eq!(blockstore.highest_slot().unwrap(), None); + + for slot in 0..10 { + let (shreds, _) = make_slot_entries(slot, 0, 1); + blockstore.insert_shreds(shreds, None, false).unwrap(); + assert_eq!(blockstore.highest_slot().unwrap(), Some(slot)); + } + blockstore + .run_purge(5, 10, PurgeType::PrimaryIndex) + .unwrap(); + assert_eq!(blockstore.highest_slot().unwrap(), Some(4)); + + blockstore.run_purge(0, 4, PurgeType::PrimaryIndex).unwrap(); + assert_eq!(blockstore.highest_slot().unwrap(), None); + } + #[test] fn test_recovery() { let ledger_path = get_tmp_ledger_path_auto_delete!(); diff --git a/ledger/src/blockstore_processor.rs b/ledger/src/blockstore_processor.rs index a827bd3d7b..2fb88269be 100644 --- a/ledger/src/blockstore_processor.rs +++ b/ledger/src/blockstore_processor.rs @@ -820,10 +820,8 @@ pub fn process_blockstore_from_root( ); } - if let Ok(metas) = blockstore.slot_meta_iterator(start_slot) { - if let Some((slot, _meta)) = metas.last() { - info!("ledger holds data through slot {}", slot); - } + if let Ok(Some(highest_slot)) = blockstore.highest_slot() { + info!("ledger holds data through slot {}", highest_slot); } let mut timing = ExecuteTimings::default();