Set a global fork graph in program cache (#33776)
* Set a global fork graph in program cache * fix deadlock * review feedback
This commit is contained in:
parent
c98c24bd6d
commit
59cb3b57ee
|
@ -3859,6 +3859,7 @@ impl ReplayStage {
|
||||||
epoch_slots_frozen_slots: &mut EpochSlotsFrozenSlots,
|
epoch_slots_frozen_slots: &mut EpochSlotsFrozenSlots,
|
||||||
drop_bank_sender: &Sender<Vec<Arc<Bank>>>,
|
drop_bank_sender: &Sender<Vec<Arc<Bank>>>,
|
||||||
) {
|
) {
|
||||||
|
bank_forks.read().unwrap().prune_program_cache(new_root);
|
||||||
let removed_banks = bank_forks.write().unwrap().set_root(
|
let removed_banks = bank_forks.write().unwrap().set_root(
|
||||||
new_root,
|
new_root,
|
||||||
accounts_background_request_sender,
|
accounts_background_request_sender,
|
||||||
|
|
|
@ -189,6 +189,15 @@ pub fn load_bank_forks(
|
||||||
(bank_forks, None)
|
(bank_forks, None)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bank_forks
|
||||||
|
.read()
|
||||||
|
.expect("Failed to read lock the bank forks")
|
||||||
|
.root_bank()
|
||||||
|
.loaded_programs_cache
|
||||||
|
.write()
|
||||||
|
.expect("Failed to write lock the program cache")
|
||||||
|
.set_fork_graph(bank_forks.clone());
|
||||||
|
|
||||||
let mut leader_schedule_cache =
|
let mut leader_schedule_cache =
|
||||||
LeaderScheduleCache::new_from_bank(&bank_forks.read().unwrap().root_bank());
|
LeaderScheduleCache::new_from_bank(&bank_forks.read().unwrap().root_bank());
|
||||||
if process_options.full_leader_cache {
|
if process_options.full_leader_cache {
|
||||||
|
|
|
@ -1555,6 +1555,11 @@ fn load_frozen_forks(
|
||||||
root = new_root_bank.slot();
|
root = new_root_bank.slot();
|
||||||
|
|
||||||
leader_schedule_cache.set_root(new_root_bank);
|
leader_schedule_cache.set_root(new_root_bank);
|
||||||
|
new_root_bank
|
||||||
|
.loaded_programs_cache
|
||||||
|
.write()
|
||||||
|
.unwrap()
|
||||||
|
.prune(root, new_root_bank.epoch());
|
||||||
let _ = bank_forks.write().unwrap().set_root(
|
let _ = bank_forks.write().unwrap().set_root(
|
||||||
root,
|
root,
|
||||||
accounts_background_request_sender,
|
accounts_background_request_sender,
|
||||||
|
|
|
@ -4,7 +4,7 @@ use {
|
||||||
timings::ExecuteDetailsTimings,
|
timings::ExecuteDetailsTimings,
|
||||||
},
|
},
|
||||||
itertools::Itertools,
|
itertools::Itertools,
|
||||||
log::{debug, log_enabled, trace},
|
log::{debug, error, log_enabled, trace},
|
||||||
percentage::PercentageInteger,
|
percentage::PercentageInteger,
|
||||||
solana_measure::measure::Measure,
|
solana_measure::measure::Measure,
|
||||||
solana_rbpf::{
|
solana_rbpf::{
|
||||||
|
@ -24,7 +24,7 @@ use {
|
||||||
fmt::{Debug, Formatter},
|
fmt::{Debug, Formatter},
|
||||||
sync::{
|
sync::{
|
||||||
atomic::{AtomicU64, Ordering},
|
atomic::{AtomicU64, Ordering},
|
||||||
Arc,
|
Arc, RwLock,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -442,8 +442,8 @@ impl Default for ProgramRuntimeEnvironments {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug)]
|
||||||
pub struct LoadedPrograms {
|
pub struct LoadedPrograms<FG: ForkGraph> {
|
||||||
/// A two level index:
|
/// A two level index:
|
||||||
///
|
///
|
||||||
/// Pubkey is the address of a program, multiple versions can coexists simultaneously under the same address (in different slots).
|
/// Pubkey is the address of a program, multiple versions can coexists simultaneously under the same address (in different slots).
|
||||||
|
@ -455,6 +455,20 @@ pub struct LoadedPrograms {
|
||||||
/// Environments of the current epoch
|
/// Environments of the current epoch
|
||||||
pub environments: ProgramRuntimeEnvironments,
|
pub environments: ProgramRuntimeEnvironments,
|
||||||
pub stats: Stats,
|
pub stats: Stats,
|
||||||
|
fork_graph: Option<Arc<RwLock<FG>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<FG: ForkGraph> Default for LoadedPrograms<FG> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
entries: HashMap::new(),
|
||||||
|
latest_root_slot: 0,
|
||||||
|
latest_root_epoch: 0,
|
||||||
|
environments: ProgramRuntimeEnvironments::default(),
|
||||||
|
stats: Stats::default(),
|
||||||
|
fork_graph: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
|
@ -531,7 +545,11 @@ pub enum LoadedProgramMatchCriteria {
|
||||||
NoCriteria,
|
NoCriteria,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LoadedPrograms {
|
impl<FG: ForkGraph> LoadedPrograms<FG> {
|
||||||
|
pub fn set_fork_graph(&mut self, fork_graph: Arc<RwLock<FG>>) {
|
||||||
|
self.fork_graph = Some(fork_graph);
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the current environments depending on the given epoch
|
/// Returns the current environments depending on the given epoch
|
||||||
pub fn get_environments_for_epoch(&self, _epoch: Epoch) -> &ProgramRuntimeEnvironments {
|
pub fn get_environments_for_epoch(&self, _epoch: Epoch) -> &ProgramRuntimeEnvironments {
|
||||||
&self.environments
|
&self.environments
|
||||||
|
@ -625,12 +643,15 @@ impl LoadedPrograms {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Before rerooting the blockstore this removes all superfluous entries
|
/// Before rerooting the blockstore this removes all superfluous entries
|
||||||
pub fn prune<F: ForkGraph>(
|
pub fn prune(&mut self, new_root_slot: Slot, new_root_epoch: Epoch) {
|
||||||
&mut self,
|
let Some(fork_graph) = self.fork_graph.clone() else {
|
||||||
fork_graph: &F,
|
error!("Program cache doesn't have fork graph.");
|
||||||
new_root_slot: Slot,
|
return;
|
||||||
new_root_epoch: Epoch,
|
};
|
||||||
) {
|
let Ok(fork_graph) = fork_graph.read() else {
|
||||||
|
error!("Failed to lock fork graph for reading.");
|
||||||
|
return;
|
||||||
|
};
|
||||||
for second_level in self.entries.values_mut() {
|
for second_level in self.entries.values_mut() {
|
||||||
// Remove entries un/re/deployed on orphan forks
|
// Remove entries un/re/deployed on orphan forks
|
||||||
let mut first_ancestor_found = false;
|
let mut first_ancestor_found = false;
|
||||||
|
@ -911,7 +932,7 @@ impl solana_frozen_abi::abi_example::AbiExample for LoadedProgram {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(RUSTC_WITH_SPECIALIZATION)]
|
#[cfg(RUSTC_WITH_SPECIALIZATION)]
|
||||||
impl solana_frozen_abi::abi_example::AbiExample for LoadedPrograms {
|
impl<FG: ForkGraph> solana_frozen_abi::abi_example::AbiExample for LoadedPrograms<FG> {
|
||||||
fn example() -> Self {
|
fn example() -> Self {
|
||||||
// LoadedPrograms isn't serializable by definition.
|
// LoadedPrograms isn't serializable by definition.
|
||||||
Self::default()
|
Self::default()
|
||||||
|
@ -937,7 +958,7 @@ mod tests {
|
||||||
ops::ControlFlow,
|
ops::ControlFlow,
|
||||||
sync::{
|
sync::{
|
||||||
atomic::{AtomicU64, Ordering},
|
atomic::{AtomicU64, Ordering},
|
||||||
Arc,
|
Arc, RwLock,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -945,7 +966,7 @@ mod tests {
|
||||||
static MOCK_ENVIRONMENT: std::sync::OnceLock<ProgramRuntimeEnvironment> =
|
static MOCK_ENVIRONMENT: std::sync::OnceLock<ProgramRuntimeEnvironment> =
|
||||||
std::sync::OnceLock::<ProgramRuntimeEnvironment>::new();
|
std::sync::OnceLock::<ProgramRuntimeEnvironment>::new();
|
||||||
|
|
||||||
fn new_mock_cache() -> LoadedPrograms {
|
fn new_mock_cache<FG: ForkGraph>() -> LoadedPrograms<FG> {
|
||||||
let mut cache = LoadedPrograms::default();
|
let mut cache = LoadedPrograms::default();
|
||||||
cache.environments.program_runtime_v1 = MOCK_ENVIRONMENT
|
cache.environments.program_runtime_v1 = MOCK_ENVIRONMENT
|
||||||
.get_or_init(|| Arc::new(BuiltinProgram::new_mock()))
|
.get_or_init(|| Arc::new(BuiltinProgram::new_mock()))
|
||||||
|
@ -999,8 +1020,8 @@ mod tests {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_tombstone(
|
fn set_tombstone<FG: ForkGraph>(
|
||||||
cache: &mut LoadedPrograms,
|
cache: &mut LoadedPrograms<FG>,
|
||||||
key: Pubkey,
|
key: Pubkey,
|
||||||
slot: Slot,
|
slot: Slot,
|
||||||
reason: LoadedProgramType,
|
reason: LoadedProgramType,
|
||||||
|
@ -1008,8 +1029,8 @@ mod tests {
|
||||||
cache.assign_program(key, Arc::new(LoadedProgram::new_tombstone(slot, reason)))
|
cache.assign_program(key, Arc::new(LoadedProgram::new_tombstone(slot, reason)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_unloaded_program(
|
fn insert_unloaded_program<FG: ForkGraph>(
|
||||||
cache: &mut LoadedPrograms,
|
cache: &mut LoadedPrograms<FG>,
|
||||||
key: Pubkey,
|
key: Pubkey,
|
||||||
slot: Slot,
|
slot: Slot,
|
||||||
) -> Arc<LoadedProgram> {
|
) -> Arc<LoadedProgram> {
|
||||||
|
@ -1031,9 +1052,10 @@ mod tests {
|
||||||
cache.replenish(key, unloaded).1
|
cache.replenish(key, unloaded).1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn num_matching_entries<P>(cache: &LoadedPrograms, predicate: P) -> usize
|
fn num_matching_entries<P, FG>(cache: &LoadedPrograms<FG>, predicate: P) -> usize
|
||||||
where
|
where
|
||||||
P: Fn(&LoadedProgramType) -> bool,
|
P: Fn(&LoadedProgramType) -> bool,
|
||||||
|
FG: ForkGraph,
|
||||||
{
|
{
|
||||||
cache
|
cache
|
||||||
.entries
|
.entries
|
||||||
|
@ -1052,7 +1074,7 @@ mod tests {
|
||||||
let mut programs = vec![];
|
let mut programs = vec![];
|
||||||
let mut num_total_programs: usize = 0;
|
let mut num_total_programs: usize = 0;
|
||||||
|
|
||||||
let mut cache = new_mock_cache();
|
let mut cache = new_mock_cache::<TestForkGraph>();
|
||||||
|
|
||||||
let program1 = Pubkey::new_unique();
|
let program1 = Pubkey::new_unique();
|
||||||
let program1_deployment_slots = [0, 10, 20];
|
let program1_deployment_slots = [0, 10, 20];
|
||||||
|
@ -1218,7 +1240,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_usage_count_of_unloaded_program() {
|
fn test_usage_count_of_unloaded_program() {
|
||||||
let mut cache = new_mock_cache();
|
let mut cache = new_mock_cache::<TestForkGraph>();
|
||||||
|
|
||||||
let program = Pubkey::new_unique();
|
let program = Pubkey::new_unique();
|
||||||
let num_total_programs = 6;
|
let num_total_programs = 6;
|
||||||
|
@ -1270,7 +1292,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_replace_tombstones() {
|
fn test_replace_tombstones() {
|
||||||
let mut cache = new_mock_cache();
|
let mut cache = new_mock_cache::<TestForkGraph>();
|
||||||
let program1 = Pubkey::new_unique();
|
let program1 = Pubkey::new_unique();
|
||||||
let env = Arc::new(BuiltinProgram::new_mock());
|
let env = Arc::new(BuiltinProgram::new_mock());
|
||||||
set_tombstone(
|
set_tombstone(
|
||||||
|
@ -1302,7 +1324,7 @@ mod tests {
|
||||||
assert_eq!(tombstone.deployment_slot, 100);
|
assert_eq!(tombstone.deployment_slot, 100);
|
||||||
assert_eq!(tombstone.effective_slot, 100);
|
assert_eq!(tombstone.effective_slot, 100);
|
||||||
|
|
||||||
let mut cache = new_mock_cache();
|
let mut cache = new_mock_cache::<TestForkGraph>();
|
||||||
let program1 = Pubkey::new_unique();
|
let program1 = Pubkey::new_unique();
|
||||||
let tombstone = set_tombstone(
|
let tombstone = set_tombstone(
|
||||||
&mut cache,
|
&mut cache,
|
||||||
|
@ -1362,48 +1384,55 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_prune_empty() {
|
fn test_prune_empty() {
|
||||||
let mut cache = new_mock_cache();
|
let mut cache = new_mock_cache::<TestForkGraph>();
|
||||||
let fork_graph = TestForkGraph {
|
let fork_graph = Arc::new(RwLock::new(TestForkGraph {
|
||||||
relation: BlockRelation::Unrelated,
|
relation: BlockRelation::Unrelated,
|
||||||
};
|
}));
|
||||||
|
|
||||||
cache.prune(&fork_graph, 0, 0);
|
cache.set_fork_graph(fork_graph);
|
||||||
|
|
||||||
|
cache.prune(0, 0);
|
||||||
assert!(cache.entries.is_empty());
|
assert!(cache.entries.is_empty());
|
||||||
|
|
||||||
cache.prune(&fork_graph, 10, 0);
|
cache.prune(10, 0);
|
||||||
assert!(cache.entries.is_empty());
|
assert!(cache.entries.is_empty());
|
||||||
|
|
||||||
let mut cache = new_mock_cache();
|
let mut cache = new_mock_cache::<TestForkGraph>();
|
||||||
let fork_graph = TestForkGraph {
|
let fork_graph = Arc::new(RwLock::new(TestForkGraph {
|
||||||
relation: BlockRelation::Ancestor,
|
relation: BlockRelation::Ancestor,
|
||||||
};
|
}));
|
||||||
|
|
||||||
cache.prune(&fork_graph, 0, 0);
|
cache.set_fork_graph(fork_graph);
|
||||||
|
|
||||||
|
cache.prune(0, 0);
|
||||||
assert!(cache.entries.is_empty());
|
assert!(cache.entries.is_empty());
|
||||||
|
|
||||||
cache.prune(&fork_graph, 10, 0);
|
cache.prune(10, 0);
|
||||||
assert!(cache.entries.is_empty());
|
assert!(cache.entries.is_empty());
|
||||||
|
|
||||||
let mut cache = new_mock_cache();
|
let mut cache = new_mock_cache::<TestForkGraph>();
|
||||||
let fork_graph = TestForkGraph {
|
let fork_graph = Arc::new(RwLock::new(TestForkGraph {
|
||||||
relation: BlockRelation::Descendant,
|
relation: BlockRelation::Descendant,
|
||||||
};
|
}));
|
||||||
|
|
||||||
cache.prune(&fork_graph, 0, 0);
|
cache.set_fork_graph(fork_graph);
|
||||||
|
|
||||||
|
cache.prune(0, 0);
|
||||||
assert!(cache.entries.is_empty());
|
assert!(cache.entries.is_empty());
|
||||||
|
|
||||||
cache.prune(&fork_graph, 10, 0);
|
cache.prune(10, 0);
|
||||||
assert!(cache.entries.is_empty());
|
assert!(cache.entries.is_empty());
|
||||||
|
|
||||||
let mut cache = new_mock_cache();
|
let mut cache = new_mock_cache::<TestForkGraph>();
|
||||||
let fork_graph = TestForkGraph {
|
let fork_graph = Arc::new(RwLock::new(TestForkGraph {
|
||||||
relation: BlockRelation::Unknown,
|
relation: BlockRelation::Unknown,
|
||||||
};
|
}));
|
||||||
|
cache.set_fork_graph(fork_graph);
|
||||||
|
|
||||||
cache.prune(&fork_graph, 0, 0);
|
cache.prune(0, 0);
|
||||||
assert!(cache.entries.is_empty());
|
assert!(cache.entries.is_empty());
|
||||||
|
|
||||||
cache.prune(&fork_graph, 10, 0);
|
cache.prune(10, 0);
|
||||||
assert!(cache.entries.is_empty());
|
assert!(cache.entries.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1512,7 +1541,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_fork_extract_and_prune() {
|
fn test_fork_extract_and_prune() {
|
||||||
let mut cache = new_mock_cache();
|
let mut cache = new_mock_cache::<TestForkGraphSpecific>();
|
||||||
|
|
||||||
// Fork graph created for the test
|
// Fork graph created for the test
|
||||||
// 0
|
// 0
|
||||||
|
@ -1534,6 +1563,9 @@ mod tests {
|
||||||
fork_graph.insert_fork(&[0, 5, 11, 15, 16, 19, 21, 23]);
|
fork_graph.insert_fork(&[0, 5, 11, 15, 16, 19, 21, 23]);
|
||||||
fork_graph.insert_fork(&[0, 5, 11, 25, 27]);
|
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();
|
let program1 = Pubkey::new_unique();
|
||||||
assert!(!cache.replenish(program1, new_test_loaded_program(0, 1)).0);
|
assert!(!cache.replenish(program1, new_test_loaded_program(0, 1)).0);
|
||||||
assert!(!cache.replenish(program1, new_test_loaded_program(10, 11)).0);
|
assert!(!cache.replenish(program1, new_test_loaded_program(10, 11)).0);
|
||||||
|
@ -1783,7 +1815,7 @@ mod tests {
|
||||||
programs.pop();
|
programs.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
cache.prune(&fork_graph, 5, 0);
|
cache.prune(5, 0);
|
||||||
|
|
||||||
// Fork graph after pruning
|
// Fork graph after pruning
|
||||||
// 0
|
// 0
|
||||||
|
@ -1848,7 +1880,7 @@ mod tests {
|
||||||
assert!(match_slot(&found, &program3, 25, 27));
|
assert!(match_slot(&found, &program3, 25, 27));
|
||||||
assert!(match_slot(&found, &program4, 5, 27));
|
assert!(match_slot(&found, &program4, 5, 27));
|
||||||
|
|
||||||
cache.prune(&fork_graph, 15, 0);
|
cache.prune(15, 0);
|
||||||
|
|
||||||
// Fork graph after pruning
|
// Fork graph after pruning
|
||||||
// 0
|
// 0
|
||||||
|
@ -1893,7 +1925,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_extract_using_deployment_slot() {
|
fn test_extract_using_deployment_slot() {
|
||||||
let mut cache = new_mock_cache();
|
let mut cache = new_mock_cache::<TestForkGraphSpecific>();
|
||||||
|
|
||||||
// Fork graph created for the test
|
// Fork graph created for the test
|
||||||
// 0
|
// 0
|
||||||
|
@ -1915,6 +1947,9 @@ mod tests {
|
||||||
fork_graph.insert_fork(&[0, 5, 11, 15, 16, 19, 21, 23]);
|
fork_graph.insert_fork(&[0, 5, 11, 15, 16, 19, 21, 23]);
|
||||||
fork_graph.insert_fork(&[0, 5, 11, 25, 27]);
|
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();
|
let program1 = Pubkey::new_unique();
|
||||||
assert!(!cache.replenish(program1, new_test_loaded_program(0, 1)).0);
|
assert!(!cache.replenish(program1, new_test_loaded_program(0, 1)).0);
|
||||||
assert!(!cache.replenish(program1, new_test_loaded_program(20, 21)).0);
|
assert!(!cache.replenish(program1, new_test_loaded_program(20, 21)).0);
|
||||||
|
@ -1978,7 +2013,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_extract_unloaded() {
|
fn test_extract_unloaded() {
|
||||||
let mut cache = new_mock_cache();
|
let mut cache = new_mock_cache::<TestForkGraphSpecific>();
|
||||||
|
|
||||||
// Fork graph created for the test
|
// Fork graph created for the test
|
||||||
// 0
|
// 0
|
||||||
|
@ -2000,6 +2035,9 @@ mod tests {
|
||||||
fork_graph.insert_fork(&[0, 5, 11, 15, 16, 19, 21, 23]);
|
fork_graph.insert_fork(&[0, 5, 11, 15, 16, 19, 21, 23]);
|
||||||
fork_graph.insert_fork(&[0, 5, 11, 25, 27]);
|
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();
|
let program1 = Pubkey::new_unique();
|
||||||
assert!(!cache.replenish(program1, new_test_loaded_program(0, 1)).0);
|
assert!(!cache.replenish(program1, new_test_loaded_program(0, 1)).0);
|
||||||
assert!(!cache.replenish(program1, new_test_loaded_program(20, 21)).0);
|
assert!(!cache.replenish(program1, new_test_loaded_program(20, 21)).0);
|
||||||
|
@ -2096,7 +2134,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_prune_expired() {
|
fn test_prune_expired() {
|
||||||
let mut cache = new_mock_cache();
|
let mut cache = new_mock_cache::<TestForkGraphSpecific>();
|
||||||
|
|
||||||
// Fork graph created for the test
|
// Fork graph created for the test
|
||||||
// 0
|
// 0
|
||||||
|
@ -2117,6 +2155,8 @@ mod tests {
|
||||||
fork_graph.insert_fork(&[0, 10, 20, 22]);
|
fork_graph.insert_fork(&[0, 10, 20, 22]);
|
||||||
fork_graph.insert_fork(&[0, 5, 11, 15, 16, 19, 21, 23]);
|
fork_graph.insert_fork(&[0, 5, 11, 15, 16, 19, 21, 23]);
|
||||||
fork_graph.insert_fork(&[0, 5, 11, 25, 27]);
|
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();
|
let program1 = Pubkey::new_unique();
|
||||||
assert!(!cache.replenish(program1, new_test_loaded_program(10, 11)).0);
|
assert!(!cache.replenish(program1, new_test_loaded_program(10, 11)).0);
|
||||||
|
@ -2198,7 +2238,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
|
|
||||||
// New root 5 should not evict the expired entry for program1
|
// New root 5 should not evict the expired entry for program1
|
||||||
cache.prune(&fork_graph, 5, 0);
|
cache.prune(5, 0);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cache
|
cache
|
||||||
.entries
|
.entries
|
||||||
|
@ -2209,13 +2249,13 @@ mod tests {
|
||||||
);
|
);
|
||||||
|
|
||||||
// New root 15 should evict the expired entry for program1
|
// New root 15 should evict the expired entry for program1
|
||||||
cache.prune(&fork_graph, 15, 0);
|
cache.prune(15, 0);
|
||||||
assert!(cache.entries.get(&program1).is_none());
|
assert!(cache.entries.get(&program1).is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_fork_prune_find_first_ancestor() {
|
fn test_fork_prune_find_first_ancestor() {
|
||||||
let mut cache = new_mock_cache();
|
let mut cache = new_mock_cache::<TestForkGraphSpecific>();
|
||||||
|
|
||||||
// Fork graph created for the test
|
// Fork graph created for the test
|
||||||
// 0
|
// 0
|
||||||
|
@ -2230,12 +2270,14 @@ mod tests {
|
||||||
let mut fork_graph = TestForkGraphSpecific::default();
|
let mut fork_graph = TestForkGraphSpecific::default();
|
||||||
fork_graph.insert_fork(&[0, 10, 20]);
|
fork_graph.insert_fork(&[0, 10, 20]);
|
||||||
fork_graph.insert_fork(&[0, 5]);
|
fork_graph.insert_fork(&[0, 5]);
|
||||||
|
let fork_graph = Arc::new(RwLock::new(fork_graph));
|
||||||
|
cache.set_fork_graph(fork_graph);
|
||||||
|
|
||||||
let program1 = Pubkey::new_unique();
|
let program1 = Pubkey::new_unique();
|
||||||
assert!(!cache.replenish(program1, new_test_loaded_program(0, 1)).0);
|
assert!(!cache.replenish(program1, new_test_loaded_program(0, 1)).0);
|
||||||
assert!(!cache.replenish(program1, new_test_loaded_program(5, 6)).0);
|
assert!(!cache.replenish(program1, new_test_loaded_program(5, 6)).0);
|
||||||
|
|
||||||
cache.prune(&fork_graph, 10, 0);
|
cache.prune(10, 0);
|
||||||
|
|
||||||
let working_slot = TestWorkingSlot::new(20, &[0, 10, 20]);
|
let working_slot = TestWorkingSlot::new(20, &[0, 10, 20]);
|
||||||
let ExtractedPrograms {
|
let ExtractedPrograms {
|
||||||
|
@ -2261,7 +2303,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_prune_by_deployment_slot() {
|
fn test_prune_by_deployment_slot() {
|
||||||
let mut cache = new_mock_cache();
|
let mut cache = new_mock_cache::<TestForkGraphSpecific>();
|
||||||
|
|
||||||
// Fork graph created for the test
|
// Fork graph created for the test
|
||||||
// 0
|
// 0
|
||||||
|
@ -2276,6 +2318,8 @@ mod tests {
|
||||||
let mut fork_graph = TestForkGraphSpecific::default();
|
let mut fork_graph = TestForkGraphSpecific::default();
|
||||||
fork_graph.insert_fork(&[0, 10, 20]);
|
fork_graph.insert_fork(&[0, 10, 20]);
|
||||||
fork_graph.insert_fork(&[0, 5]);
|
fork_graph.insert_fork(&[0, 5]);
|
||||||
|
let fork_graph = Arc::new(RwLock::new(fork_graph));
|
||||||
|
cache.set_fork_graph(fork_graph);
|
||||||
|
|
||||||
let program1 = Pubkey::new_unique();
|
let program1 = Pubkey::new_unique();
|
||||||
assert!(!cache.replenish(program1, new_test_loaded_program(0, 1)).0);
|
assert!(!cache.replenish(program1, new_test_loaded_program(0, 1)).0);
|
||||||
|
@ -2380,34 +2424,34 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_usable_entries_for_slot() {
|
fn test_usable_entries_for_slot() {
|
||||||
new_mock_cache();
|
new_mock_cache::<TestForkGraph>();
|
||||||
let tombstone = Arc::new(LoadedProgram::new_tombstone(0, LoadedProgramType::Closed));
|
let tombstone = Arc::new(LoadedProgram::new_tombstone(0, LoadedProgramType::Closed));
|
||||||
|
|
||||||
assert!(LoadedPrograms::is_entry_usable(
|
assert!(LoadedPrograms::<TestForkGraph>::is_entry_usable(
|
||||||
&tombstone,
|
&tombstone,
|
||||||
0,
|
0,
|
||||||
&LoadedProgramMatchCriteria::NoCriteria
|
&LoadedProgramMatchCriteria::NoCriteria
|
||||||
));
|
));
|
||||||
|
|
||||||
assert!(LoadedPrograms::is_entry_usable(
|
assert!(LoadedPrograms::<TestForkGraph>::is_entry_usable(
|
||||||
&tombstone,
|
&tombstone,
|
||||||
1,
|
1,
|
||||||
&LoadedProgramMatchCriteria::Tombstone
|
&LoadedProgramMatchCriteria::Tombstone
|
||||||
));
|
));
|
||||||
|
|
||||||
assert!(LoadedPrograms::is_entry_usable(
|
assert!(LoadedPrograms::<TestForkGraph>::is_entry_usable(
|
||||||
&tombstone,
|
&tombstone,
|
||||||
1,
|
1,
|
||||||
&LoadedProgramMatchCriteria::NoCriteria
|
&LoadedProgramMatchCriteria::NoCriteria
|
||||||
));
|
));
|
||||||
|
|
||||||
assert!(LoadedPrograms::is_entry_usable(
|
assert!(LoadedPrograms::<TestForkGraph>::is_entry_usable(
|
||||||
&tombstone,
|
&tombstone,
|
||||||
1,
|
1,
|
||||||
&LoadedProgramMatchCriteria::DeployedOnOrAfterSlot(0)
|
&LoadedProgramMatchCriteria::DeployedOnOrAfterSlot(0)
|
||||||
));
|
));
|
||||||
|
|
||||||
assert!(!LoadedPrograms::is_entry_usable(
|
assert!(!LoadedPrograms::<TestForkGraph>::is_entry_usable(
|
||||||
&tombstone,
|
&tombstone,
|
||||||
1,
|
1,
|
||||||
&LoadedProgramMatchCriteria::DeployedOnOrAfterSlot(1)
|
&LoadedProgramMatchCriteria::DeployedOnOrAfterSlot(1)
|
||||||
|
@ -2415,31 +2459,31 @@ mod tests {
|
||||||
|
|
||||||
let program = new_test_loaded_program(0, 1);
|
let program = new_test_loaded_program(0, 1);
|
||||||
|
|
||||||
assert!(LoadedPrograms::is_entry_usable(
|
assert!(LoadedPrograms::<TestForkGraph>::is_entry_usable(
|
||||||
&program,
|
&program,
|
||||||
0,
|
0,
|
||||||
&LoadedProgramMatchCriteria::NoCriteria
|
&LoadedProgramMatchCriteria::NoCriteria
|
||||||
));
|
));
|
||||||
|
|
||||||
assert!(!LoadedPrograms::is_entry_usable(
|
assert!(!LoadedPrograms::<TestForkGraph>::is_entry_usable(
|
||||||
&program,
|
&program,
|
||||||
1,
|
1,
|
||||||
&LoadedProgramMatchCriteria::Tombstone
|
&LoadedProgramMatchCriteria::Tombstone
|
||||||
));
|
));
|
||||||
|
|
||||||
assert!(LoadedPrograms::is_entry_usable(
|
assert!(LoadedPrograms::<TestForkGraph>::is_entry_usable(
|
||||||
&program,
|
&program,
|
||||||
1,
|
1,
|
||||||
&LoadedProgramMatchCriteria::NoCriteria
|
&LoadedProgramMatchCriteria::NoCriteria
|
||||||
));
|
));
|
||||||
|
|
||||||
assert!(LoadedPrograms::is_entry_usable(
|
assert!(LoadedPrograms::<TestForkGraph>::is_entry_usable(
|
||||||
&program,
|
&program,
|
||||||
1,
|
1,
|
||||||
&LoadedProgramMatchCriteria::DeployedOnOrAfterSlot(0)
|
&LoadedProgramMatchCriteria::DeployedOnOrAfterSlot(0)
|
||||||
));
|
));
|
||||||
|
|
||||||
assert!(!LoadedPrograms::is_entry_usable(
|
assert!(!LoadedPrograms::<TestForkGraph>::is_entry_usable(
|
||||||
&program,
|
&program,
|
||||||
1,
|
1,
|
||||||
&LoadedProgramMatchCriteria::DeployedOnOrAfterSlot(1)
|
&LoadedProgramMatchCriteria::DeployedOnOrAfterSlot(1)
|
||||||
|
@ -2452,37 +2496,37 @@ mod tests {
|
||||||
Some(2),
|
Some(2),
|
||||||
));
|
));
|
||||||
|
|
||||||
assert!(LoadedPrograms::is_entry_usable(
|
assert!(LoadedPrograms::<TestForkGraph>::is_entry_usable(
|
||||||
&program,
|
&program,
|
||||||
0,
|
0,
|
||||||
&LoadedProgramMatchCriteria::NoCriteria
|
&LoadedProgramMatchCriteria::NoCriteria
|
||||||
));
|
));
|
||||||
|
|
||||||
assert!(LoadedPrograms::is_entry_usable(
|
assert!(LoadedPrograms::<TestForkGraph>::is_entry_usable(
|
||||||
&program,
|
&program,
|
||||||
1,
|
1,
|
||||||
&LoadedProgramMatchCriteria::NoCriteria
|
&LoadedProgramMatchCriteria::NoCriteria
|
||||||
));
|
));
|
||||||
|
|
||||||
assert!(!LoadedPrograms::is_entry_usable(
|
assert!(!LoadedPrograms::<TestForkGraph>::is_entry_usable(
|
||||||
&program,
|
&program,
|
||||||
1,
|
1,
|
||||||
&LoadedProgramMatchCriteria::Tombstone
|
&LoadedProgramMatchCriteria::Tombstone
|
||||||
));
|
));
|
||||||
|
|
||||||
assert!(!LoadedPrograms::is_entry_usable(
|
assert!(!LoadedPrograms::<TestForkGraph>::is_entry_usable(
|
||||||
&program,
|
&program,
|
||||||
2,
|
2,
|
||||||
&LoadedProgramMatchCriteria::NoCriteria
|
&LoadedProgramMatchCriteria::NoCriteria
|
||||||
));
|
));
|
||||||
|
|
||||||
assert!(LoadedPrograms::is_entry_usable(
|
assert!(LoadedPrograms::<TestForkGraph>::is_entry_usable(
|
||||||
&program,
|
&program,
|
||||||
1,
|
1,
|
||||||
&LoadedProgramMatchCriteria::DeployedOnOrAfterSlot(0)
|
&LoadedProgramMatchCriteria::DeployedOnOrAfterSlot(0)
|
||||||
));
|
));
|
||||||
|
|
||||||
assert!(!LoadedPrograms::is_entry_usable(
|
assert!(!LoadedPrograms::<TestForkGraph>::is_entry_usable(
|
||||||
&program,
|
&program,
|
||||||
1,
|
1,
|
||||||
&LoadedProgramMatchCriteria::DeployedOnOrAfterSlot(1)
|
&LoadedProgramMatchCriteria::DeployedOnOrAfterSlot(1)
|
||||||
|
|
|
@ -39,6 +39,7 @@ pub use solana_sdk::reward_type::RewardType;
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
bank::metrics::*,
|
bank::metrics::*,
|
||||||
|
bank_forks::BankForks,
|
||||||
builtins::{BuiltinPrototype, BUILTINS},
|
builtins::{BuiltinPrototype, BUILTINS},
|
||||||
epoch_rewards_hasher::hash_rewards_into_partitions,
|
epoch_rewards_hasher::hash_rewards_into_partitions,
|
||||||
epoch_stakes::{EpochStakes, NodeVoteAccounts},
|
epoch_stakes::{EpochStakes, NodeVoteAccounts},
|
||||||
|
@ -820,7 +821,7 @@ pub struct Bank {
|
||||||
|
|
||||||
pub incremental_snapshot_persistence: Option<BankIncrementalSnapshotPersistence>,
|
pub incremental_snapshot_persistence: Option<BankIncrementalSnapshotPersistence>,
|
||||||
|
|
||||||
pub loaded_programs_cache: Arc<RwLock<LoadedPrograms>>,
|
pub loaded_programs_cache: Arc<RwLock<LoadedPrograms<BankForks>>>,
|
||||||
|
|
||||||
pub check_program_modification_slot: bool,
|
pub check_program_modification_slot: bool,
|
||||||
|
|
||||||
|
@ -1070,7 +1071,7 @@ impl Bank {
|
||||||
accounts_data_size_delta_on_chain: AtomicI64::new(0),
|
accounts_data_size_delta_on_chain: AtomicI64::new(0),
|
||||||
accounts_data_size_delta_off_chain: AtomicI64::new(0),
|
accounts_data_size_delta_off_chain: AtomicI64::new(0),
|
||||||
fee_structure: FeeStructure::default(),
|
fee_structure: FeeStructure::default(),
|
||||||
loaded_programs_cache: Arc::<RwLock<LoadedPrograms>>::default(),
|
loaded_programs_cache: Arc::<RwLock<LoadedPrograms<BankForks>>>::default(),
|
||||||
check_program_modification_slot: false,
|
check_program_modification_slot: false,
|
||||||
epoch_reward_status: EpochRewardStatus::default(),
|
epoch_reward_status: EpochRewardStatus::default(),
|
||||||
};
|
};
|
||||||
|
@ -1856,7 +1857,7 @@ impl Bank {
|
||||||
accounts_data_size_delta_on_chain: AtomicI64::new(0),
|
accounts_data_size_delta_on_chain: AtomicI64::new(0),
|
||||||
accounts_data_size_delta_off_chain: AtomicI64::new(0),
|
accounts_data_size_delta_off_chain: AtomicI64::new(0),
|
||||||
fee_structure: FeeStructure::default(),
|
fee_structure: FeeStructure::default(),
|
||||||
loaded_programs_cache: Arc::<RwLock<LoadedPrograms>>::default(),
|
loaded_programs_cache: Arc::<RwLock<LoadedPrograms<BankForks>>>::default(),
|
||||||
check_program_modification_slot: false,
|
check_program_modification_slot: false,
|
||||||
epoch_reward_status: EpochRewardStatus::default(),
|
epoch_reward_status: EpochRewardStatus::default(),
|
||||||
};
|
};
|
||||||
|
|
|
@ -55,6 +55,7 @@ struct SetRootTimings {
|
||||||
prune_remove_ms: i64,
|
prune_remove_ms: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct BankForks {
|
pub struct BankForks {
|
||||||
banks: HashMap<Slot, Arc<Bank>>,
|
banks: HashMap<Slot, Arc<Bank>>,
|
||||||
descendants: HashMap<Slot, HashSet<Slot>>,
|
descendants: HashMap<Slot, HashSet<Slot>>,
|
||||||
|
@ -404,6 +405,16 @@ impl BankForks {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn prune_program_cache(&self, root: Slot) {
|
||||||
|
if let Some(root_bank) = self.banks.get(&root) {
|
||||||
|
root_bank
|
||||||
|
.loaded_programs_cache
|
||||||
|
.write()
|
||||||
|
.unwrap()
|
||||||
|
.prune(root, root_bank.epoch());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_root(
|
pub fn set_root(
|
||||||
&mut self,
|
&mut self,
|
||||||
root: Slot,
|
root: Slot,
|
||||||
|
@ -411,15 +422,6 @@ impl BankForks {
|
||||||
highest_super_majority_root: Option<Slot>,
|
highest_super_majority_root: Option<Slot>,
|
||||||
) -> Vec<Arc<Bank>> {
|
) -> Vec<Arc<Bank>> {
|
||||||
let program_cache_prune_start = Instant::now();
|
let program_cache_prune_start = Instant::now();
|
||||||
let root_bank = self
|
|
||||||
.banks
|
|
||||||
.get(&root)
|
|
||||||
.expect("root bank didn't exist in bank_forks");
|
|
||||||
root_bank
|
|
||||||
.loaded_programs_cache
|
|
||||||
.write()
|
|
||||||
.unwrap()
|
|
||||||
.prune(self, root, root_bank.epoch());
|
|
||||||
let set_root_start = Instant::now();
|
let set_root_start = Instant::now();
|
||||||
let (removed_banks, set_root_metrics) = self.do_set_root_return_metrics(
|
let (removed_banks, set_root_metrics) = self.do_set_root_return_metrics(
|
||||||
root,
|
root,
|
||||||
|
|
Loading…
Reference in New Issue