diff --git a/program-runtime/src/loaded_programs.rs b/program-runtime/src/loaded_programs.rs index a92da7bd001bbe..813133e2ddf089 100644 --- a/program-runtime/src/loaded_programs.rs +++ b/program-runtime/src/loaded_programs.rs @@ -137,8 +137,6 @@ pub struct LoadedProgram { pub deployment_slot: Slot, /// Slot in which this entry will become active (can be in the future) pub effective_slot: Slot, - /// Optional expiration slot for this entry, after which it is treated as non-existent - pub maybe_expiration_slot: Option, /// How often this entry was used by a transaction pub tx_usage_counter: AtomicU64, /// How often this entry was used by an instruction @@ -164,8 +162,6 @@ pub struct Stats { pub one_hit_wonders: AtomicU64, /// a program became unreachable in the fork graph because of rerooting pub prunes_orphan: AtomicU64, - /// a program got pruned because its expiration slot passed - pub prunes_expired: 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 @@ -182,7 +178,6 @@ impl Stats { let one_hit_wonders = self.one_hit_wonders.load(Ordering::Relaxed); let evictions: u64 = self.evictions.values().sum(); let prunes_orphan = self.prunes_orphan.load(Ordering::Relaxed); - let prunes_expired = self.prunes_expired.load(Ordering::Relaxed); let prunes_environment = self.prunes_environment.load(Ordering::Relaxed); let empty_entries = self.empty_entries.load(Ordering::Relaxed); datapoint_info!( @@ -195,13 +190,12 @@ impl Stats { ("replacements", replacements, i64), ("one_hit_wonders", one_hit_wonders, i64), ("prunes_orphan", prunes_orphan, i64), - ("prunes_expired", prunes_expired, i64), ("prunes_environment", prunes_environment, i64), ("empty_entries", empty_entries, i64), ); debug!( - "Loaded Programs Cache Stats -- Hits: {}, Misses: {}, Evictions: {}, Insertions: {}, Replacements: {}, One-Hit-Wonders: {}, Prunes-Orphan: {}, Prunes-Expired: {}, Prunes-Environment: {}, Empty: {}", - hits, misses, evictions, insertions, replacements, one_hit_wonders, prunes_orphan, prunes_expired, prunes_environment, empty_entries + "Loaded Programs Cache Stats -- Hits: {}, Misses: {}, Evictions: {}, Insertions: {}, Replacements: {}, One-Hit-Wonders: {}, Prunes-Orphan: {}, Prunes-Environment: {}, Empty: {}", + hits, misses, evictions, insertions, replacements, one_hit_wonders, prunes_orphan, prunes_environment, empty_entries ); if log_enabled!(log::Level::Trace) && !self.evictions.is_empty() { let mut evictions = self.evictions.iter().collect::>(); @@ -278,7 +272,6 @@ impl LoadedProgram { program_runtime_environment: ProgramRuntimeEnvironment, deployment_slot: Slot, effective_slot: Slot, - maybe_expiration_slot: Option, elf_bytes: &[u8], account_size: usize, metrics: &mut LoadProgramMetrics, @@ -288,7 +281,6 @@ impl LoadedProgram { program_runtime_environment, deployment_slot, effective_slot, - maybe_expiration_slot, elf_bytes, account_size, metrics, @@ -309,7 +301,6 @@ impl LoadedProgram { program_runtime_environment: Arc>>, deployment_slot: Slot, effective_slot: Slot, - maybe_expiration_slot: Option, elf_bytes: &[u8], account_size: usize, metrics: &mut LoadProgramMetrics, @@ -319,7 +310,6 @@ impl LoadedProgram { program_runtime_environment, deployment_slot, effective_slot, - maybe_expiration_slot, elf_bytes, account_size, metrics, @@ -332,7 +322,6 @@ impl LoadedProgram { program_runtime_environment: Arc>>, deployment_slot: Slot, effective_slot: Slot, - maybe_expiration_slot: Option, elf_bytes: &[u8], account_size: usize, metrics: &mut LoadProgramMetrics, @@ -377,7 +366,6 @@ impl LoadedProgram { deployment_slot, account_size, effective_slot, - maybe_expiration_slot, tx_usage_counter: AtomicU64::new(0), program, ix_usage_counter: AtomicU64::new(0), @@ -391,7 +379,6 @@ impl LoadedProgram { account_size: self.account_size, deployment_slot: self.deployment_slot, effective_slot: self.effective_slot, - maybe_expiration_slot: self.maybe_expiration_slot, tx_usage_counter: AtomicU64::new(self.tx_usage_counter.load(Ordering::Relaxed)), ix_usage_counter: AtomicU64::new(self.ix_usage_counter.load(Ordering::Relaxed)), latest_access_slot: AtomicU64::new(self.latest_access_slot.load(Ordering::Relaxed)), @@ -412,7 +399,6 @@ impl LoadedProgram { deployment_slot, account_size, effective_slot: deployment_slot, - maybe_expiration_slot: None, tx_usage_counter: AtomicU64::new(0), program: LoadedProgramType::Builtin(BuiltinProgram::new_builtin(function_registry)), ix_usage_counter: AtomicU64::new(0), @@ -421,14 +407,11 @@ impl LoadedProgram { } pub fn new_tombstone(slot: Slot, reason: LoadedProgramType) -> Self { - let maybe_expiration_slot = matches!(reason, LoadedProgramType::DelayVisibility) - .then_some(slot.saturating_add(DELAY_VISIBILITY_SLOT_OFFSET)); let tombstone = Self { program: reason, account_size: 0, deployment_slot: slot, effective_slot: slot, - maybe_expiration_slot, tx_usage_counter: AtomicU64::default(), ix_usage_counter: AtomicU64::default(), latest_access_slot: AtomicU64::new(0), @@ -830,13 +813,6 @@ impl LoadedPrograms { } }) .filter(|entry| { - // Remove expired - if let Some(expiration) = entry.maybe_expiration_slot { - if expiration <= new_root_slot { - self.stats.prunes_expired.fetch_add(1, Ordering::Relaxed); - return false; - } - } // Remove outdated environment of previous feature set if recompilation_phase_ends && !Self::matches_environment(entry, &self.environments) @@ -881,25 +857,6 @@ impl LoadedPrograms { } } - fn is_entry_usable( - entry: &Arc, - current_slot: Slot, - match_criteria: &LoadedProgramMatchCriteria, - ) -> bool { - if entry - .maybe_expiration_slot - .map(|expiration_slot| expiration_slot <= current_slot) - .unwrap_or(false) - { - // Found an entry that's already expired. Any further entries in the list - // are older than the current one. So treat the program as missing in the - // cache and return early. - return false; - } - - Self::matches_loaded_program_criteria(entry, match_criteria) - } - /// Extracts a subset of the programs relevant to a transaction batch /// and returns which program accounts the accounts DB needs to load. pub fn extract( @@ -929,14 +886,9 @@ impl LoadedPrograms { entry, &loaded_programs_for_tx_batch.environments, ) { - if !Self::is_entry_usable( - entry, - loaded_programs_for_tx_batch.slot, - match_criteria, - ) { + if !Self::matches_loaded_program_criteria(entry, match_criteria) { break; } - if let LoadedProgramType::Unloaded(_environment) = &entry.program { break; } @@ -1226,27 +1178,12 @@ mod tests { deployment_slot: Slot, effective_slot: Slot, usage_counter: AtomicU64, - ) -> Arc { - new_test_loaded_program_with_usage_and_expiry( - deployment_slot, - effective_slot, - usage_counter, - None, - ) - } - - fn new_test_loaded_program_with_usage_and_expiry( - deployment_slot: Slot, - effective_slot: Slot, - usage_counter: AtomicU64, - expiry: Option, ) -> Arc { Arc::new(LoadedProgram { program: LoadedProgramType::TestLoaded(MOCK_ENVIRONMENT.get().unwrap().clone()), account_size: 0, deployment_slot, effective_slot, - maybe_expiration_slot: expiry, tx_usage_counter: usage_counter, ix_usage_counter: AtomicU64::default(), latest_access_slot: AtomicU64::new(deployment_slot), @@ -1259,7 +1196,6 @@ mod tests { account_size: 0, deployment_slot, effective_slot, - maybe_expiration_slot: None, tx_usage_counter: AtomicU64::default(), ix_usage_counter: AtomicU64::default(), latest_access_slot: AtomicU64::default(), @@ -1288,7 +1224,6 @@ mod tests { account_size: 0, deployment_slot: slot, effective_slot: slot.saturating_add(1), - maybe_expiration_slot: None, tx_usage_counter: AtomicU64::default(), ix_usage_counter: AtomicU64::default(), latest_access_slot: AtomicU64::default(), @@ -1881,7 +1816,6 @@ mod tests { account_size: 0, deployment_slot: 20, effective_slot: 20, - maybe_expiration_slot: None, tx_usage_counter: AtomicU64::default(), ix_usage_counter: AtomicU64::default(), latest_access_slot: AtomicU64::default(), @@ -2168,58 +2102,6 @@ mod tests { assert!(match_missing(&missing, &program3, false)); - // The following is a special case, where there's an expiration slot - let test_program = Arc::new(LoadedProgram { - program: LoadedProgramType::DelayVisibility, - account_size: 0, - deployment_slot: 19, - effective_slot: 19, - maybe_expiration_slot: Some(21), - tx_usage_counter: AtomicU64::default(), - ix_usage_counter: AtomicU64::default(), - latest_access_slot: AtomicU64::default(), - }); - assert!(!cache.replenish(program4, test_program).0); - - // Testing fork 0 - 5 - 11 - 15 - 16 - 19 - 21 - 23 with current slot at 19 - let mut missing = vec![ - (program1, (LoadedProgramMatchCriteria::NoCriteria, 1)), - (program2, (LoadedProgramMatchCriteria::NoCriteria, 1)), - (program3, (LoadedProgramMatchCriteria::NoCriteria, 1)), - (program4, (LoadedProgramMatchCriteria::NoCriteria, 1)), - ]; - let mut extracted = LoadedProgramsForTxBatch::new(19, cache.environments.clone()); - cache.extract(&mut missing, &mut extracted); - - assert!(match_slot(&extracted, &program1, 0, 19)); - assert!(match_slot(&extracted, &program2, 11, 19)); - // Program4 deployed at slot 19 should not be expired yet - assert!(match_slot(&extracted, &program4, 19, 19)); - - assert!(match_missing(&missing, &program3, false)); - - // Testing fork 0 - 5 - 11 - 15 - 16 - 19 - 21 - 23 with current slot at 21 - // This would cause program4 deployed at slot 19 to be expired. - let mut missing = vec![ - (program1, (LoadedProgramMatchCriteria::NoCriteria, 1)), - (program2, (LoadedProgramMatchCriteria::NoCriteria, 1)), - (program3, (LoadedProgramMatchCriteria::NoCriteria, 1)), - (program4, (LoadedProgramMatchCriteria::NoCriteria, 1)), - ]; - let mut extracted = LoadedProgramsForTxBatch::new(21, cache.environments.clone()); - cache.extract(&mut missing, &mut extracted); - - assert!(match_slot(&extracted, &program1, 0, 21)); - assert!(match_slot(&extracted, &program2, 11, 21)); - - assert!(match_missing(&missing, &program3, false)); - assert!(match_missing(&missing, &program4, false)); - - // Remove the expired entry to let the rest of the test continue - if let Some(second_level) = cache.entries.get_mut(&program4) { - second_level.slot_versions.pop(); - } - cache.prune(5, 0); // Fork graph after pruning @@ -2475,117 +2357,6 @@ mod tests { assert!(match_missing(&missing, &program3, true)); } - #[test] - fn test_prune_expired() { - let mut cache = new_mock_cache::(); - - // Fork graph created for the test - // 0 - // / \ - // 10 5 - // | | - // 20 11 - // | | \ - // 22 15 25 - // | | - // 16 27 - // | - // 19 - // | - // 23 - - let mut fork_graph = TestForkGraphSpecific::default(); - fork_graph.insert_fork(&[0, 10, 20, 22]); - fork_graph.insert_fork(&[0, 5, 11, 12, 15, 16, 18, 19, 21, 23]); - fork_graph.insert_fork(&[0, 5, 11, 25, 27]); - let fork_graph = Arc::new(RwLock::new(fork_graph)); - cache.set_fork_graph(fork_graph); - - let program1 = Pubkey::new_unique(); - assert!(!cache.replenish(program1, new_test_loaded_program(10, 11)).0); - assert!(!cache.replenish(program1, new_test_loaded_program(20, 21)).0); - - let program2 = Pubkey::new_unique(); - assert!(!cache.replenish(program2, new_test_loaded_program(5, 6)).0); - assert!(!cache.replenish(program2, new_test_loaded_program(11, 12)).0); - - let program3 = Pubkey::new_unique(); - assert!(!cache.replenish(program3, new_test_loaded_program(25, 26)).0); - - // The following is a special case, where there's an expiration slot - let test_program = Arc::new(LoadedProgram { - program: LoadedProgramType::DelayVisibility, - account_size: 0, - deployment_slot: 11, - effective_slot: 11, - maybe_expiration_slot: Some(15), - tx_usage_counter: AtomicU64::default(), - ix_usage_counter: AtomicU64::default(), - latest_access_slot: AtomicU64::default(), - }); - assert!(!cache.replenish(program1, test_program).0); - - // Testing fork 0 - 5 - 11 - 15 - 16 - 19 - 21 - 23 with current slot at 19 - let mut missing = vec![ - (program1, (LoadedProgramMatchCriteria::NoCriteria, 1)), - (program2, (LoadedProgramMatchCriteria::NoCriteria, 1)), - (program3, (LoadedProgramMatchCriteria::NoCriteria, 1)), - ]; - let mut extracted = LoadedProgramsForTxBatch::new(12, cache.environments.clone()); - cache.extract(&mut missing, &mut extracted); - - // Program1 deployed at slot 11 should not be expired yet - assert!(match_slot(&extracted, &program1, 11, 12)); - assert!(match_slot(&extracted, &program2, 11, 12)); - - assert!(match_missing(&missing, &program3, false)); - - // Testing fork 0 - 5 - 11 - 12 - 15 - 16 - 19 - 21 - 23 with current slot at 15 - // This would cause program4 deployed at slot 15 to be expired. - let mut missing = vec![ - (program1, (LoadedProgramMatchCriteria::NoCriteria, 1)), - (program2, (LoadedProgramMatchCriteria::NoCriteria, 1)), - (program3, (LoadedProgramMatchCriteria::NoCriteria, 1)), - ]; - let mut extracted = LoadedProgramsForTxBatch::new(15, cache.environments.clone()); - cache.extract(&mut missing, &mut extracted); - - assert!(match_slot(&extracted, &program2, 11, 15)); - - assert!(match_missing(&missing, &program1, false)); - assert!(match_missing(&missing, &program3, false)); - - // Test that the program still exists in the cache, even though it is expired. - assert_eq!( - cache - .entries - .get(&program1) - .expect("Didn't find program1") - .slot_versions - .len(), - 3 - ); - - // New root 5 should not evict the expired entry for program1 - cache.prune(5, 0); - assert_eq!( - cache - .entries - .get(&program1) - .expect("Didn't find program1") - .slot_versions - .len(), - 1 - ); - - // Unlock the cooperative loading lock so that the subsequent prune can do its job - cache.finish_cooperative_loading_task(15, program1, new_test_loaded_program(0, 1)); - - // New root 15 should evict the expired entry for program1 - cache.prune(15, 0); - assert!(cache.entries.get(&program1).is_none()); - } - #[test] fn test_fork_prune_find_first_ancestor() { let mut cache = new_mock_cache::(); @@ -2717,109 +2488,96 @@ mod tests { new_mock_cache::(); let tombstone = Arc::new(LoadedProgram::new_tombstone(0, LoadedProgramType::Closed)); - assert!(LoadedPrograms::::is_entry_usable( - &tombstone, - 0, - &LoadedProgramMatchCriteria::NoCriteria - )); - - assert!(LoadedPrograms::::is_entry_usable( - &tombstone, - 1, - &LoadedProgramMatchCriteria::Tombstone - )); + assert!( + LoadedPrograms::::matches_loaded_program_criteria( + &tombstone, + &LoadedProgramMatchCriteria::NoCriteria + ) + ); - assert!(LoadedPrograms::::is_entry_usable( - &tombstone, - 1, - &LoadedProgramMatchCriteria::NoCriteria - )); + assert!( + LoadedPrograms::::matches_loaded_program_criteria( + &tombstone, + &LoadedProgramMatchCriteria::Tombstone + ) + ); - assert!(LoadedPrograms::::is_entry_usable( - &tombstone, - 1, - &LoadedProgramMatchCriteria::DeployedOnOrAfterSlot(0) - )); + assert!( + LoadedPrograms::::matches_loaded_program_criteria( + &tombstone, + &LoadedProgramMatchCriteria::DeployedOnOrAfterSlot(0) + ) + ); - assert!(!LoadedPrograms::::is_entry_usable( - &tombstone, - 1, - &LoadedProgramMatchCriteria::DeployedOnOrAfterSlot(1) - )); + assert!( + !LoadedPrograms::::matches_loaded_program_criteria( + &tombstone, + &LoadedProgramMatchCriteria::DeployedOnOrAfterSlot(1) + ) + ); let program = new_test_loaded_program(0, 1); - assert!(LoadedPrograms::::is_entry_usable( - &program, - 0, - &LoadedProgramMatchCriteria::NoCriteria - )); - - assert!(!LoadedPrograms::::is_entry_usable( - &program, - 1, - &LoadedProgramMatchCriteria::Tombstone - )); + assert!( + LoadedPrograms::::matches_loaded_program_criteria( + &program, + &LoadedProgramMatchCriteria::NoCriteria + ) + ); - assert!(LoadedPrograms::::is_entry_usable( - &program, - 1, - &LoadedProgramMatchCriteria::NoCriteria - )); + assert!( + !LoadedPrograms::::matches_loaded_program_criteria( + &program, + &LoadedProgramMatchCriteria::Tombstone + ) + ); - assert!(LoadedPrograms::::is_entry_usable( - &program, - 1, - &LoadedProgramMatchCriteria::DeployedOnOrAfterSlot(0) - )); + assert!( + LoadedPrograms::::matches_loaded_program_criteria( + &program, + &LoadedProgramMatchCriteria::DeployedOnOrAfterSlot(0) + ) + ); - assert!(!LoadedPrograms::::is_entry_usable( - &program, - 1, - &LoadedProgramMatchCriteria::DeployedOnOrAfterSlot(1) - )); + assert!( + !LoadedPrograms::::matches_loaded_program_criteria( + &program, + &LoadedProgramMatchCriteria::DeployedOnOrAfterSlot(1) + ) + ); - let program = Arc::new(new_test_loaded_program_with_usage_and_expiry( + let program = Arc::new(new_test_loaded_program_with_usage( 0, 1, AtomicU64::default(), - Some(2), - )); - - assert!(LoadedPrograms::::is_entry_usable( - &program, - 0, - &LoadedProgramMatchCriteria::NoCriteria - )); - - assert!(LoadedPrograms::::is_entry_usable( - &program, - 1, - &LoadedProgramMatchCriteria::NoCriteria )); - assert!(!LoadedPrograms::::is_entry_usable( - &program, - 1, - &LoadedProgramMatchCriteria::Tombstone - )); + assert!( + LoadedPrograms::::matches_loaded_program_criteria( + &program, + &LoadedProgramMatchCriteria::NoCriteria + ) + ); - assert!(!LoadedPrograms::::is_entry_usable( - &program, - 2, - &LoadedProgramMatchCriteria::NoCriteria - )); + assert!( + !LoadedPrograms::::matches_loaded_program_criteria( + &program, + &LoadedProgramMatchCriteria::Tombstone + ) + ); - assert!(LoadedPrograms::::is_entry_usable( - &program, - 1, - &LoadedProgramMatchCriteria::DeployedOnOrAfterSlot(0) - )); + assert!( + LoadedPrograms::::matches_loaded_program_criteria( + &program, + &LoadedProgramMatchCriteria::DeployedOnOrAfterSlot(0) + ) + ); - assert!(!LoadedPrograms::::is_entry_usable( - &program, - 1, - &LoadedProgramMatchCriteria::DeployedOnOrAfterSlot(1) - )); + assert!( + !LoadedPrograms::::matches_loaded_program_criteria( + &program, + &LoadedProgramMatchCriteria::DeployedOnOrAfterSlot(1) + ) + ); } } diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index 48d44b7187a658..21a7b5fed77257 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -81,7 +81,6 @@ pub fn load_program_from_bytes( program_runtime_environment, deployment_slot, effective_slot, - None, programdata, account_size, load_program_metrics, @@ -93,7 +92,6 @@ pub fn load_program_from_bytes( program_runtime_environment, deployment_slot, effective_slot, - None, programdata, account_size, load_program_metrics, @@ -4004,7 +4002,6 @@ mod tests { account_size: 0, deployment_slot: 0, effective_slot: 0, - maybe_expiration_slot: None, tx_usage_counter: AtomicU64::new(100), ix_usage_counter: AtomicU64::new(100), latest_access_slot: AtomicU64::new(0), @@ -4045,7 +4042,6 @@ mod tests { account_size: 0, deployment_slot: 0, effective_slot: 0, - maybe_expiration_slot: None, tx_usage_counter: AtomicU64::new(100), ix_usage_counter: AtomicU64::new(100), latest_access_slot: AtomicU64::new(0), diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 6f5cd9a07f607b..8129ecd3b0dc77 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -4694,7 +4694,6 @@ impl Bank { program_runtime_environment.clone(), deployment_slot, deployment_slot.saturating_add(DELAY_VISIBILITY_SLOT_OFFSET), - None, programdata, account_size, load_program_metrics, @@ -4706,7 +4705,6 @@ impl Bank { program_runtime_environment.clone(), deployment_slot, deployment_slot.saturating_add(DELAY_VISIBILITY_SLOT_OFFSET), - None, programdata, account_size, load_program_metrics,