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

Commit 1165a7f

Browse files
author
steviez
authored
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
1 parent d5dbfb6 commit 1165a7f

File tree

1 file changed

+59
-2
lines changed

1 file changed

+59
-2
lines changed

ledger/src/blockstore.rs

+59-2
Original file line numberDiff line numberDiff line change
@@ -994,8 +994,9 @@ impl Blockstore {
994994
self.completed_slots_senders.lock().unwrap().clear();
995995
}
996996

997-
/// Range-delete all entries which prefix matches the specified `slot` and
998-
/// clear all the related `SlotMeta` except its next_slots.
997+
/// Range-delete all entries which prefix matches the specified `slot`,
998+
/// remove `slot` its' parents SlotMeta next_slots list, and
999+
/// clear `slot`'s SlotMeta (except for next_slots).
9991000
///
10001001
/// This function currently requires `insert_shreds_lock`, as both
10011002
/// `clear_unconfirmed_slot()` and `insert_shreds_handle_duplicate()`
@@ -1011,6 +1012,21 @@ impl Blockstore {
10111012
self.run_purge(slot, slot, PurgeType::PrimaryIndex)
10121013
.expect("Purge database operations failed");
10131014

1015+
// Clear this slot as a next slot from parent
1016+
if let Some(parent_slot) = slot_meta.parent_slot {
1017+
let mut parent_slot_meta = self
1018+
.meta(parent_slot)
1019+
.expect("Couldn't fetch from SlotMeta column family")
1020+
.expect("Unconfirmed slot should have had parent slot set");
1021+
// .retain() is a linear scan; however, next_slots should
1022+
// only contain several elements so this isn't so bad
1023+
parent_slot_meta
1024+
.next_slots
1025+
.retain(|&next_slot| next_slot != slot);
1026+
self.meta_cf
1027+
.put(parent_slot, &parent_slot_meta)
1028+
.expect("Couldn't insert into SlotMeta column family");
1029+
}
10141030
// Reinsert parts of `slot_meta` that are important to retain, like the `next_slots`
10151031
// field.
10161032
slot_meta.clear_unconfirmed_slot();
@@ -8582,6 +8598,47 @@ pub mod tests {
85828598
.is_none());
85838599
}
85848600

8601+
#[test]
8602+
fn test_clear_unconfirmed_slot_and_insert_again() {
8603+
let ledger_path = get_tmp_ledger_path_auto_delete!();
8604+
let blockstore = Blockstore::open(ledger_path.path()).unwrap();
8605+
8606+
let confirmed_slot = 7;
8607+
let unconfirmed_slot = 8;
8608+
let slots = vec![confirmed_slot, unconfirmed_slot];
8609+
8610+
let shreds: Vec<_> = make_chaining_slot_entries(&slots, 1)
8611+
.into_iter()
8612+
.flat_map(|x| x.0)
8613+
.collect();
8614+
assert_eq!(shreds.len(), 2);
8615+
8616+
// Save off unconfirmed_slot for later, just one shred at shreds[1]
8617+
let unconfirmed_slot_shreds = vec![shreds[1].clone()];
8618+
assert_eq!(unconfirmed_slot_shreds[0].slot(), unconfirmed_slot);
8619+
8620+
// Insert into slot 9
8621+
blockstore.insert_shreds(shreds, None, false).unwrap();
8622+
8623+
// Purge the slot
8624+
blockstore.clear_unconfirmed_slot(unconfirmed_slot);
8625+
assert!(!blockstore.is_dead(unconfirmed_slot));
8626+
assert!(blockstore
8627+
.get_data_shred(unconfirmed_slot, 0)
8628+
.unwrap()
8629+
.is_none());
8630+
8631+
// Re-add unconfirmed_slot and confirm that confirmed_slot only has
8632+
// unconfirmed_slot in next_slots once
8633+
blockstore
8634+
.insert_shreds(unconfirmed_slot_shreds, None, false)
8635+
.unwrap();
8636+
assert_eq!(
8637+
blockstore.meta(confirmed_slot).unwrap().unwrap().next_slots,
8638+
vec![unconfirmed_slot]
8639+
);
8640+
}
8641+
85858642
#[test]
85868643
fn test_update_completed_data_indexes() {
85878644
let mut completed_data_indexes = BTreeSet::default();

0 commit comments

Comments
 (0)