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

Commit 8bd62d7

Browse files
authored
Fix race in remove_unrooted_slot (#10607)
* Fix race * clippy fixes * Rename and add comment Co-authored-by: Carl <carl@solana.com>
1 parent f76bd9c commit 8bd62d7

File tree

2 files changed

+28
-18
lines changed

2 files changed

+28
-18
lines changed

runtime/src/accounts_db.rs

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ use std::{
4242
ops::RangeBounds,
4343
path::{Path, PathBuf},
4444
sync::atomic::{AtomicBool, AtomicU64, AtomicUsize, Ordering},
45-
sync::{Arc, Mutex, RwLock, RwLockReadGuard},
45+
sync::{Arc, Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard},
4646
time::Instant,
4747
};
4848
use tempfile::TempDir;
@@ -535,7 +535,7 @@ impl AccountsDB {
535535
inc_new_counter_info!("clean-old-root-par-clean-ms", clean_rooted.as_ms() as usize);
536536

537537
let mut measure = Measure::start("clean_old_root_reclaims");
538-
self.handle_reclaims(&reclaims);
538+
self.handle_reclaims_maybe_cleanup(&reclaims);
539539
measure.stop();
540540
debug!("{} {}", clean_rooted, measure);
541541
inc_new_counter_info!("clean-old-root-reclaim-ms", measure.as_ms() as usize);
@@ -726,15 +726,15 @@ impl AccountsDB {
726726
}
727727
}
728728

729-
self.handle_reclaims(&reclaims);
729+
self.handle_reclaims_maybe_cleanup(&reclaims);
730730
reclaims_time.stop();
731731
debug!(
732732
"clean_accounts: {} {} {} {}",
733733
accounts_scan, store_counts_time, purge_filter, reclaims_time
734734
);
735735
}
736736

737-
fn handle_reclaims(&self, reclaims: SlotSlice<AccountInfo>) {
737+
fn handle_reclaims_maybe_cleanup(&self, reclaims: SlotSlice<AccountInfo>) {
738738
let mut dead_accounts = Measure::start("reclaims::remove_dead_accounts");
739739
let dead_slots = self.remove_dead_accounts(reclaims);
740740
dead_accounts.stop();
@@ -744,13 +744,27 @@ impl AccountsDB {
744744
dead_slots_w.len()
745745
};
746746
if dead_slots_len > 5000 {
747-
self.process_dead_slots();
747+
self.process_dead_slots(None);
748748
}
749749
}
750750

751-
pub fn process_dead_slots(&self) {
752-
let empty = HashSet::new();
751+
// Atomicallly process reclaims and new dead_slots in this thread, gauranteeing
752+
// complete data removal for slots in reclaims.
753+
fn handle_reclaims_ensure_cleanup(&self, reclaims: SlotSlice<AccountInfo>) {
754+
let mut dead_accounts = Measure::start("reclaims::remove_dead_accounts");
755+
let dead_slots = self.remove_dead_accounts(reclaims);
756+
dead_accounts.stop();
753757
let mut dead_slots_w = self.dead_slots.write().unwrap();
758+
dead_slots_w.extend(dead_slots);
759+
self.process_dead_slots(Some(dead_slots_w));
760+
}
761+
762+
pub fn process_dead_slots<'a>(
763+
&'a self,
764+
dead_slots_w: Option<RwLockWriteGuard<'a, HashSet<Slot>>>,
765+
) {
766+
let empty = HashSet::new();
767+
let mut dead_slots_w = dead_slots_w.unwrap_or_else(|| self.dead_slots.write().unwrap());
754768
let dead_slots = std::mem::replace(&mut *dead_slots_w, empty);
755769
drop(dead_slots_w);
756770

@@ -887,7 +901,7 @@ impl AccountsDB {
887901
);
888902
let reclaims = self.update_index(slot, infos, &accounts);
889903

890-
self.handle_reclaims(&reclaims);
904+
self.handle_reclaims_maybe_cleanup(&reclaims);
891905

892906
let mut storage = self.storage.write().unwrap();
893907
if let Some(slot_storage) = storage.0.get_mut(&slot) {
@@ -1192,13 +1206,9 @@ impl AccountsDB {
11921206
}
11931207
}
11941208

1195-
self.handle_reclaims(&reclaims);
1196-
11971209
// 1) Remove old bank hash from self.bank_hashes
11981210
// 2) Purge this slot's storage entries from self.storage
1199-
self.process_dead_slots();
1200-
1201-
// Sanity check storage entries are removed from the index
1211+
self.handle_reclaims_ensure_cleanup(&reclaims);
12021212
assert!(self.storage.read().unwrap().0.get(&remove_slot).is_none());
12031213
}
12041214

@@ -1810,7 +1820,7 @@ impl AccountsDB {
18101820
update_index.stop();
18111821
trace!("reclaim: {}", reclaims.len());
18121822

1813-
self.handle_reclaims(&reclaims);
1823+
self.handle_reclaims_maybe_cleanup(&reclaims);
18141824
}
18151825

18161826
pub fn add_root(&self, slot: Slot) {
@@ -2521,7 +2531,7 @@ pub mod tests {
25212531
//slot is gone
25222532
print_accounts("pre-clean", &accounts);
25232533
accounts.clean_accounts();
2524-
accounts.process_dead_slots();
2534+
accounts.process_dead_slots(None);
25252535
assert!(accounts.storage.read().unwrap().0.get(&0).is_none());
25262536

25272537
//new value is there
@@ -2959,7 +2969,7 @@ pub mod tests {
29592969
let hash = accounts.update_accounts_hash(current_slot, &ancestors);
29602970

29612971
accounts.clean_accounts();
2962-
accounts.process_dead_slots();
2972+
accounts.process_dead_slots(None);
29632973

29642974
assert_eq!(
29652975
accounts.update_accounts_hash(current_slot, &ancestors),
@@ -3761,7 +3771,7 @@ pub mod tests {
37613771
current_slot += 1;
37623772
assert_eq!(4, accounts.ref_count_for_pubkey(&pubkey1));
37633773
accounts.store(current_slot, &[(&pubkey1, &zero_lamport_account)]);
3764-
accounts.process_dead_slots();
3774+
accounts.process_dead_slots(None);
37653775
assert_eq!(
37663776
3, /* == 4 - 2 + 1 */
37673777
accounts.ref_count_for_pubkey(&pubkey1)

runtime/src/bank.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2569,7 +2569,7 @@ impl Bank {
25692569
}
25702570

25712571
pub fn process_dead_slots(&self) {
2572-
self.rc.accounts.accounts_db.process_dead_slots();
2572+
self.rc.accounts.accounts_db.process_dead_slots(None);
25732573
}
25742574

25752575
pub fn shrink_all_slots(&self) {

0 commit comments

Comments
 (0)