Repair alternate versions of dead slots (#9805)
Co-authored-by: Carl <carl@solana.com>
This commit is contained in:
@ -178,6 +178,10 @@ impl BankForks {
|
||||
bank
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, slot: Slot) -> Option<Arc<Bank>> {
|
||||
self.banks.remove(&slot)
|
||||
}
|
||||
|
||||
pub fn working_bank(&self) -> Arc<Bank> {
|
||||
self.working_bank.clone()
|
||||
}
|
||||
|
@ -836,6 +836,30 @@ impl Blockstore {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn clear_unconfirmed_slot(&self, slot: Slot) {
|
||||
let _lock = self.insert_shreds_lock.lock().unwrap();
|
||||
if let Some(mut slot_meta) = self
|
||||
.meta(slot)
|
||||
.expect("Couldn't fetch from SlotMeta column family")
|
||||
{
|
||||
// Clear all slot related information
|
||||
self.run_purge(slot, slot)
|
||||
.expect("Purge database operations failed");
|
||||
|
||||
// Reinsert parts of `slot_meta` that are important to retain, like the `next_slots`
|
||||
// field.
|
||||
slot_meta.clear_unconfirmed_slot();
|
||||
self.meta_cf
|
||||
.put(slot, &slot_meta)
|
||||
.expect("Couldn't insert into SlotMeta column family");
|
||||
} else {
|
||||
error!(
|
||||
"clear_unconfirmed_slot() called on slot {} with no SlotMeta",
|
||||
slot
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert_shreds(
|
||||
&self,
|
||||
shreds: Vec<Shred>,
|
||||
@ -2139,6 +2163,16 @@ impl Blockstore {
|
||||
Ok(orphans_iter.map(|(slot, _)| slot))
|
||||
}
|
||||
|
||||
pub fn dead_slots_iterator<'a>(
|
||||
&'a self,
|
||||
slot: Slot,
|
||||
) -> Result<impl Iterator<Item = Slot> + 'a> {
|
||||
let dead_slots_iterator = self
|
||||
.db
|
||||
.iter::<cf::DeadSlots>(IteratorMode::From(slot, IteratorDirection::Forward))?;
|
||||
Ok(dead_slots_iterator.map(|(slot, _)| slot))
|
||||
}
|
||||
|
||||
/// Prune blockstore such that slots higher than `target_slot` are deleted and all references to
|
||||
/// higher slots are removed
|
||||
pub fn prune(&self, target_slot: Slot) {
|
||||
@ -2397,10 +2431,7 @@ fn find_slot_meta_in_db_else_create<'a>(
|
||||
// If this slot doesn't exist, make a orphan slot. This way we
|
||||
// remember which slots chained to this one when we eventually get a real shred
|
||||
// for this slot
|
||||
insert_map.insert(
|
||||
slot,
|
||||
Rc::new(RefCell::new(SlotMeta::new(slot, std::u64::MAX))),
|
||||
);
|
||||
insert_map.insert(slot, Rc::new(RefCell::new(SlotMeta::new_orphan(slot))));
|
||||
Ok(insert_map.get(&slot).unwrap().clone())
|
||||
}
|
||||
}
|
||||
@ -6695,4 +6726,49 @@ pub mod tests {
|
||||
|
||||
Blockstore::destroy(&blockstore_path).expect("Expected successful database destruction");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_clear_unconfirmed_slot() {
|
||||
let blockstore_path = get_tmp_ledger_path!();
|
||||
{
|
||||
let blockstore = Blockstore::open(&blockstore_path).unwrap();
|
||||
let unconfirmed_slot = 9;
|
||||
let unconfirmed_child_slot = 10;
|
||||
let slots = vec![2, unconfirmed_slot, unconfirmed_child_slot];
|
||||
|
||||
// Insert into slot 9, mark it as dead
|
||||
let shreds: Vec<_> = make_chaining_slot_entries(&slots, 1)
|
||||
.into_iter()
|
||||
.flat_map(|x| x.0)
|
||||
.collect();
|
||||
blockstore.insert_shreds(shreds, None, false).unwrap();
|
||||
// Should only be one shred in slot 9
|
||||
assert!(blockstore
|
||||
.get_data_shred(unconfirmed_slot, 0)
|
||||
.unwrap()
|
||||
.is_some());
|
||||
assert!(blockstore
|
||||
.get_data_shred(unconfirmed_slot, 1)
|
||||
.unwrap()
|
||||
.is_none());
|
||||
blockstore.set_dead_slot(unconfirmed_slot).unwrap();
|
||||
|
||||
// Purge the slot
|
||||
blockstore.clear_unconfirmed_slot(unconfirmed_slot);
|
||||
assert!(!blockstore.is_dead(unconfirmed_slot));
|
||||
assert_eq!(
|
||||
blockstore
|
||||
.meta(unconfirmed_slot)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.next_slots,
|
||||
vec![unconfirmed_child_slot]
|
||||
);
|
||||
assert!(blockstore
|
||||
.get_data_shred(unconfirmed_slot, 0)
|
||||
.unwrap()
|
||||
.is_none());
|
||||
}
|
||||
Blockstore::destroy(&blockstore_path).expect("Expected successful database destruction");
|
||||
}
|
||||
}
|
||||
|
@ -158,6 +158,12 @@ impl SlotMeta {
|
||||
self.parent_slot != std::u64::MAX
|
||||
}
|
||||
|
||||
pub fn clear_unconfirmed_slot(&mut self) {
|
||||
let mut new_self = SlotMeta::new_orphan(self.slot);
|
||||
std::mem::swap(&mut new_self.next_slots, &mut self.next_slots);
|
||||
std::mem::swap(self, &mut new_self);
|
||||
}
|
||||
|
||||
pub(crate) fn new(slot: Slot, parent_slot: Slot) -> Self {
|
||||
SlotMeta {
|
||||
slot,
|
||||
@ -171,6 +177,10 @@ impl SlotMeta {
|
||||
completed_data_indexes: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new_orphan(slot: Slot) -> Self {
|
||||
Self::new(slot, std::u64::MAX)
|
||||
}
|
||||
}
|
||||
|
||||
impl ErasureMeta {
|
||||
@ -289,4 +299,17 @@ mod test {
|
||||
assert_eq!(e_meta.status(&index), DataFull);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_clear_unconfirmed_slot() {
|
||||
let mut slot_meta = SlotMeta::new_orphan(5);
|
||||
slot_meta.consumed = 5;
|
||||
slot_meta.received = 5;
|
||||
slot_meta.next_slots = vec![6, 7];
|
||||
slot_meta.clear_unconfirmed_slot();
|
||||
|
||||
let mut expected = SlotMeta::new_orphan(5);
|
||||
expected.next_slots = vec![6, 7];
|
||||
assert_eq!(slot_meta, expected);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user