Skip to content

Commit

Permalink
Tweak ancient packing algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
dmakarov committed Sep 30, 2024
1 parent 46f5fce commit 7e82fe9
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 2 deletions.
61 changes: 60 additions & 1 deletion accounts-db/src/accounts_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1521,6 +1521,11 @@ pub struct AccountsDb {

/// The latest full snapshot slot dictates how to handle zero lamport accounts
latest_full_snapshot_slot: SeqLock<Option<Slot>>,

/// These are the ancient storages that could be valuable to shrink.
/// sorted by largest dead bytes to smallest
/// Members are Slot and capacity. If capacity is smaller, then that means the storage was already shrunk.
pub(crate) best_ancient_slots_to_shrink: RwLock<Vec<(Slot, u64)>>,
}

#[derive(Debug, Default)]
Expand Down Expand Up @@ -2038,16 +2043,31 @@ pub struct ShrinkStats {
index_scan_returned_none: AtomicU64,
index_scan_returned_some: AtomicU64,
accounts_loaded: AtomicU64,
initial_candidates_count: AtomicU64,
purged_zero_lamports: AtomicU64,
accounts_not_found_in_index: AtomicU64,
num_ancient_slots_shrunk: AtomicU64,
ancient_slots_added_to_shrink: AtomicU64,
ancient_bytes_added_to_shrink: AtomicU64,
}

impl ShrinkStats {
fn report(&self) {
if self.last_report.should_update(1000) {
datapoint_info!(
"shrink_stats",
(
"ancient_slots_added_to_shrink",
self.ancient_slots_added_to_shrink
.swap(0, Ordering::Relaxed) as i64,
i64
),
(
"ancient_bytes_added_to_shrink",
self.ancient_bytes_added_to_shrink
.swap(0, Ordering::Relaxed) as i64,
i64
),
(
"num_slots_shrunk",
self.num_slots_shrunk.swap(0, Ordering::Relaxed) as i64,
Expand Down Expand Up @@ -2164,6 +2184,11 @@ impl ShrinkStats {
self.accounts_not_found_in_index.swap(0, Ordering::Relaxed),
i64
),
(
"initial_candidates_count",
self.initial_candidates_count.swap(0, Ordering::Relaxed),
i64
),
);
}
}
Expand Down Expand Up @@ -2491,6 +2516,7 @@ impl AccountsDb {
const ACCOUNTS_STACK_SIZE: usize = 8 * 1024 * 1024;

AccountsDb {
best_ancient_slots_to_shrink: RwLock::default(),
create_ancient_storage: CreateAncientStorage::default(),
verify_accounts_hash_in_bg: VerifyAccountsHashInBackground::default(),
active_stats: ActiveStats::default(),
Expand Down Expand Up @@ -5068,7 +5094,11 @@ impl AccountsDb {
let shrink_candidates_slots =
std::mem::take(&mut *self.shrink_candidate_slots.lock().unwrap());

let (shrink_slots, shrink_slots_next_batch) = {
self.shrink_stats
.initial_candidates_count
.store(shrink_candidates_slots.len() as u64, Ordering::Relaxed);

let (mut shrink_slots, shrink_slots_next_batch) = {
if let AccountShrinkThreshold::TotalSpace { shrink_ratio } = self.shrink_ratio {
let (shrink_slots, shrink_slots_next_batch) =
self.select_candidates_by_total_usage(&shrink_candidates_slots, shrink_ratio);
Expand All @@ -5089,6 +5119,35 @@ impl AccountsDb {
}
};

let mut ancient_slots_added = 0;
// If there are too few slots to shrink, add an ancient slot
// for shrinking.
if shrink_slots.len() < 10 {
let mut ancients = self.best_ancient_slots_to_shrink.write().unwrap();
if let Some((slot, capacity)) = ancients.first_mut() {
if let Some(store) = self.storage.get_slot_storage_entry(*slot) {
if !shrink_slots.contains(slot)
&& *capacity == store.capacity()
&& Self::is_candidate_for_shrink(self, &store)
{
*capacity = 0;
ancient_slots_added += 1;
self.shrink_stats
.ancient_bytes_added_to_shrink
.fetch_add(store.alive_bytes() as u64, Ordering::Relaxed);
shrink_slots.insert(*slot, store);
}
}
}
log::debug!(
"ancient_slots_added: {ancient_slots_added}, {}, avail: {}",
shrink_slots.len(),
ancients.len()
);
}
self.shrink_stats
.ancient_slots_added_to_shrink
.fetch_add(ancient_slots_added, Ordering::Relaxed);
if shrink_slots.is_empty()
&& shrink_slots_next_batch
.as_ref()
Expand Down
11 changes: 10 additions & 1 deletion accounts-db/src/ancient_append_vecs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ struct AncientSlotInfos {
total_alive_bytes_shrink: Saturating<u64>,
/// total alive bytes across all slots
total_alive_bytes: Saturating<u64>,
/// best_slots_to_shrink
best_slots_to_shrink: Vec<(Slot, u64)>,
}

impl AncientSlotInfos {
Expand Down Expand Up @@ -177,8 +179,10 @@ impl AncientSlotInfos {
* tuning.percent_of_alive_shrunk_data
/ 100,
);
self.best_slots_to_shrink = Vec::with_capacity(self.shrink_indexes.len());
for info_index in &self.shrink_indexes {
let info = &mut self.all_infos[*info_index];
self.best_slots_to_shrink.push((info.slot, info.capacity));
if bytes_to_shrink_due_to_ratio.0 >= threshold_bytes {
// we exceeded the amount to shrink due to alive ratio, so don't shrink this one just due to 'should_shrink'
// It MAY be shrunk based on total capacity still.
Expand Down Expand Up @@ -396,7 +400,12 @@ impl AccountsDb {
self.shrink_ancient_stats
.slots_considered
.fetch_add(sorted_slots.len() as u64, Ordering::Relaxed);
let ancient_slot_infos = self.collect_sort_filter_ancient_slots(sorted_slots, &tuning);
let mut ancient_slot_infos = self.collect_sort_filter_ancient_slots(sorted_slots, &tuning);

std::mem::swap(
&mut *self.best_ancient_slots_to_shrink.write().unwrap(),
&mut ancient_slot_infos.best_slots_to_shrink,
);

if ancient_slot_infos.all_infos.is_empty() {
return; // nothing to do
Expand Down

0 comments on commit 7e82fe9

Please sign in to comment.