Skip to content

Commit

Permalink
ProgramCache: remove SecondLevel structure
Browse files Browse the repository at this point in the history
  • Loading branch information
alessandrod committed May 6, 2024
1 parent 027a7cd commit fd8436b
Showing 1 changed file with 14 additions and 28 deletions.
42 changes: 14 additions & 28 deletions program-runtime/src/loaded_programs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ pub struct ProgramCacheStats {
pub prunes_orphan: AtomicU64,
/// a program got pruned because it was not recompiled for the next epoch
pub prunes_environment: AtomicU64,
/// the [SecondLevel] was empty because all slot versions got pruned
/// a program had no entries because all slot versions got pruned
pub empty_entries: AtomicU64,
}

Expand Down Expand Up @@ -578,13 +578,6 @@ impl LoadingTaskWaiter {
}
}

/// Contains all the program versions at a specific address.
#[derive(Debug, Default)]
struct SecondLevel {
/// List of all versions (across all forks) of a program sorted by the slot in which they were modified
slot_versions: Vec<Arc<ProgramCacheEntry>>,
}

/// This structure is the global cache of loaded, verified and compiled programs.
///
/// It ...
Expand All @@ -603,8 +596,9 @@ struct SecondLevel {
pub struct ProgramCache<FG: ForkGraph> {
/// A two level index:
///
/// The first level is for the address at which programs are deployed and the second level for the slot (and thus also fork).
entries: HashMap<Pubkey, SecondLevel>,
/// - the first level is for the address at which programs are deployed
/// - the second level for the slot (and thus also fork), sorted by slot number.
entries: HashMap<Pubkey, Vec<Arc<ProgramCacheEntry>>>,
/// The entries that are getting loaded and have not yet finished loading.
///
/// The key is the program address, the value is a tuple of the slot in which the program is
Expand Down Expand Up @@ -824,7 +818,7 @@ impl<FG: ForkGraph> ProgramCache<FG> {
&entry.program,
ProgramCacheEntryType::DelayVisibility
));
let slot_versions = &mut self.entries.entry(key).or_default().slot_versions;
let slot_versions = &mut self.entries.entry(key).or_default();
match slot_versions.binary_search_by(|at| {
at.effective_slot
.cmp(&entry.effective_slot)
Expand Down Expand Up @@ -865,9 +859,7 @@ impl<FG: ForkGraph> ProgramCache<FG> {

pub fn prune_by_deployment_slot(&mut self, slot: Slot) {
for second_level in self.entries.values_mut() {
second_level
.slot_versions
.retain(|entry| entry.deployment_slot != slot);
second_level.retain(|entry| entry.deployment_slot != slot);
}
self.remove_programs_with_no_entries();
}
Expand Down Expand Up @@ -895,8 +887,7 @@ impl<FG: ForkGraph> ProgramCache<FG> {
// Remove entries un/re/deployed on orphan forks
let mut first_ancestor_found = false;
let mut first_ancestor_env = None;
second_level.slot_versions = second_level
.slot_versions
*second_level = second_level
.iter()
.rev()
.filter(|entry| {
Expand Down Expand Up @@ -945,7 +936,7 @@ impl<FG: ForkGraph> ProgramCache<FG> {
})
.cloned()
.collect();
second_level.slot_versions.reverse();
second_level.reverse();
}
self.remove_programs_with_no_entries();
debug_assert!(self.latest_root_slot <= new_root_slot);
Expand Down Expand Up @@ -989,7 +980,7 @@ impl<FG: ForkGraph> ProgramCache<FG> {
let mut cooperative_loading_task = None;
search_for.retain(|(key, (match_criteria, usage_count))| {
if let Some(second_level) = self.entries.get(key) {
for entry in second_level.slot_versions.iter().rev() {
for entry in second_level.iter().rev() {
if entry.deployment_slot <= self.latest_root_slot
|| matches!(
locked_fork_graph.relationship(
Expand Down Expand Up @@ -1107,7 +1098,6 @@ impl<FG: ForkGraph> ProgramCache<FG> {
.iter()
.flat_map(|(id, second_level)| {
second_level
.slot_versions
.iter()
.filter_map(move |program| match program.program {
ProgramCacheEntryType::Loaded(_) => {
Expand All @@ -1132,19 +1122,16 @@ impl<FG: ForkGraph> ProgramCache<FG> {
self.entries
.iter()
.flat_map(|(id, second_level)| {
second_level
.slot_versions
.iter()
.map(|program| (*id, program.clone()))
second_level.iter().map(|program| (*id, program.clone()))
})
.collect()
}

/// Returns the `slot_versions` of the second level for the given program id.
/// Returns the slot versions for the given program id.
pub fn get_slot_versions_for_tests(&self, key: &Pubkey) -> &[Arc<ProgramCacheEntry>] {
self.entries
.get(key)
.map(|second_level| second_level.slot_versions.as_ref())
.map(|second_level| second_level.as_ref())
.unwrap_or(&[])
}

Expand Down Expand Up @@ -1205,7 +1192,6 @@ impl<FG: ForkGraph> ProgramCache<FG> {
fn unload_program_entry(&mut self, program: &Pubkey, remove_entry: &Arc<ProgramCacheEntry>) {
let second_level = self.entries.get_mut(program).expect("Cache lookup failed");
let candidate = second_level
.slot_versions
.iter_mut()
.find(|entry| entry == &remove_entry)
.expect("Program entry not found");
Expand Down Expand Up @@ -1238,7 +1224,7 @@ impl<FG: ForkGraph> ProgramCache<FG> {
fn remove_programs_with_no_entries(&mut self) {
let num_programs_before_removal = self.entries.len();
self.entries
.retain(|_key, second_level| !second_level.slot_versions.is_empty());
.retain(|_key, second_level| !second_level.is_empty());
if self.entries.len() < num_programs_before_removal {
self.stats.empty_entries.fetch_add(
num_programs_before_removal.saturating_sub(self.entries.len()) as u64,
Expand Down Expand Up @@ -2070,7 +2056,7 @@ mod tests {
keys.iter()
.filter_map(|key| {
let visible_entry = cache.entries.get(key).and_then(|second_level| {
second_level.slot_versions.iter().rev().find(|entry| {
second_level.iter().rev().find(|entry| {
matches!(
locked_fork_graph.relationship(entry.deployment_slot, loading_slot),
BlockRelation::Equal | BlockRelation::Ancestor,
Expand Down

0 comments on commit fd8436b

Please sign in to comment.