Make clear_unconfirmed_slot() update parent's next_slots list (#26085)
A slot may be purged from the blockstore with clear_unconfirmed_slot(). If the slot is added back, the slot should only exist once in its' parent SlotMeta::next_slots Vec. Prior to this change, repeated clearing and re-adding of a slot could result in the slot existing in parent's next_slots multiple times. The result is that if the next time the parent slot is processed (node restart or ledger-tool-replay), slot could be added to the queue of slots to play multiple times. Added test that failed before change and works now as well
This commit is contained in:
parent
d5dbfb67fd
commit
1165a7f3fc
|
@ -994,8 +994,9 @@ impl Blockstore {
|
||||||
self.completed_slots_senders.lock().unwrap().clear();
|
self.completed_slots_senders.lock().unwrap().clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Range-delete all entries which prefix matches the specified `slot` and
|
/// Range-delete all entries which prefix matches the specified `slot`,
|
||||||
/// clear all the related `SlotMeta` except its next_slots.
|
/// remove `slot` its' parents SlotMeta next_slots list, and
|
||||||
|
/// clear `slot`'s SlotMeta (except for next_slots).
|
||||||
///
|
///
|
||||||
/// This function currently requires `insert_shreds_lock`, as both
|
/// This function currently requires `insert_shreds_lock`, as both
|
||||||
/// `clear_unconfirmed_slot()` and `insert_shreds_handle_duplicate()`
|
/// `clear_unconfirmed_slot()` and `insert_shreds_handle_duplicate()`
|
||||||
|
@ -1011,6 +1012,21 @@ impl Blockstore {
|
||||||
self.run_purge(slot, slot, PurgeType::PrimaryIndex)
|
self.run_purge(slot, slot, PurgeType::PrimaryIndex)
|
||||||
.expect("Purge database operations failed");
|
.expect("Purge database operations failed");
|
||||||
|
|
||||||
|
// Clear this slot as a next slot from parent
|
||||||
|
if let Some(parent_slot) = slot_meta.parent_slot {
|
||||||
|
let mut parent_slot_meta = self
|
||||||
|
.meta(parent_slot)
|
||||||
|
.expect("Couldn't fetch from SlotMeta column family")
|
||||||
|
.expect("Unconfirmed slot should have had parent slot set");
|
||||||
|
// .retain() is a linear scan; however, next_slots should
|
||||||
|
// only contain several elements so this isn't so bad
|
||||||
|
parent_slot_meta
|
||||||
|
.next_slots
|
||||||
|
.retain(|&next_slot| next_slot != slot);
|
||||||
|
self.meta_cf
|
||||||
|
.put(parent_slot, &parent_slot_meta)
|
||||||
|
.expect("Couldn't insert into SlotMeta column family");
|
||||||
|
}
|
||||||
// Reinsert parts of `slot_meta` that are important to retain, like the `next_slots`
|
// Reinsert parts of `slot_meta` that are important to retain, like the `next_slots`
|
||||||
// field.
|
// field.
|
||||||
slot_meta.clear_unconfirmed_slot();
|
slot_meta.clear_unconfirmed_slot();
|
||||||
|
@ -8582,6 +8598,47 @@ pub mod tests {
|
||||||
.is_none());
|
.is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_clear_unconfirmed_slot_and_insert_again() {
|
||||||
|
let ledger_path = get_tmp_ledger_path_auto_delete!();
|
||||||
|
let blockstore = Blockstore::open(ledger_path.path()).unwrap();
|
||||||
|
|
||||||
|
let confirmed_slot = 7;
|
||||||
|
let unconfirmed_slot = 8;
|
||||||
|
let slots = vec![confirmed_slot, unconfirmed_slot];
|
||||||
|
|
||||||
|
let shreds: Vec<_> = make_chaining_slot_entries(&slots, 1)
|
||||||
|
.into_iter()
|
||||||
|
.flat_map(|x| x.0)
|
||||||
|
.collect();
|
||||||
|
assert_eq!(shreds.len(), 2);
|
||||||
|
|
||||||
|
// Save off unconfirmed_slot for later, just one shred at shreds[1]
|
||||||
|
let unconfirmed_slot_shreds = vec![shreds[1].clone()];
|
||||||
|
assert_eq!(unconfirmed_slot_shreds[0].slot(), unconfirmed_slot);
|
||||||
|
|
||||||
|
// Insert into slot 9
|
||||||
|
blockstore.insert_shreds(shreds, None, false).unwrap();
|
||||||
|
|
||||||
|
// Purge the slot
|
||||||
|
blockstore.clear_unconfirmed_slot(unconfirmed_slot);
|
||||||
|
assert!(!blockstore.is_dead(unconfirmed_slot));
|
||||||
|
assert!(blockstore
|
||||||
|
.get_data_shred(unconfirmed_slot, 0)
|
||||||
|
.unwrap()
|
||||||
|
.is_none());
|
||||||
|
|
||||||
|
// Re-add unconfirmed_slot and confirm that confirmed_slot only has
|
||||||
|
// unconfirmed_slot in next_slots once
|
||||||
|
blockstore
|
||||||
|
.insert_shreds(unconfirmed_slot_shreds, None, false)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
blockstore.meta(confirmed_slot).unwrap().unwrap().next_slots,
|
||||||
|
vec![unconfirmed_slot]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_update_completed_data_indexes() {
|
fn test_update_completed_data_indexes() {
|
||||||
let mut completed_data_indexes = BTreeSet::default();
|
let mut completed_data_indexes = BTreeSet::default();
|
||||||
|
|
Loading…
Reference in New Issue