Skip to content

Commit

Permalink
Make StakeDelegations clone-on-write
Browse files Browse the repository at this point in the history
  • Loading branch information
brooksprumo committed Dec 1, 2021
1 parent 393c765 commit 0d1b6b9
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 9 deletions.
14 changes: 8 additions & 6 deletions runtime/src/bank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ use solana_sdk::{
},
};
use solana_stake_program::stake_state::{
self, Delegation, InflationPointCalculationEvent, PointValue, StakeState,
self, InflationPointCalculationEvent, PointValue, StakeState,
};
use solana_vote_program::{
vote_instruction::VoteInstruction,
Expand Down Expand Up @@ -5774,11 +5774,6 @@ impl Bank {
}
}

/// current stake delegations for this bank
pub fn cloned_stake_delegations(&self) -> HashMap<Pubkey, Delegation> {
self.stakes.read().unwrap().stake_delegations().clone()
}

pub fn staked_nodes(&self) -> Arc<HashMap<Pubkey, u64>> {
self.stakes.read().unwrap().staked_nodes()
}
Expand Down Expand Up @@ -6460,6 +6455,7 @@ pub(crate) mod tests {
create_genesis_config_with_leader, create_genesis_config_with_vote_accounts,
GenesisConfigInfo, ValidatorVoteKeypairs,
},
stake_delegations::StakeDelegations,
status_cache::MAX_CACHE_ENTRIES,
};
use crossbeam_channel::{bounded, unbounded};
Expand Down Expand Up @@ -6498,6 +6494,12 @@ pub(crate) mod tests {
};
use std::{result, thread::Builder, time::Duration};

impl Bank {
fn cloned_stake_delegations(&self) -> StakeDelegations {
self.stakes.read().unwrap().stake_delegations().clone()
}
}

fn new_sanitized_message(
instructions: &[Instruction],
payer: Option<&Pubkey>,
Expand Down
1 change: 1 addition & 0 deletions runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ pub mod snapshot_hash;
pub mod snapshot_package;
pub mod snapshot_utils;
pub mod sorted_storages;
pub mod stake_delegations;
pub mod stake_weighted_timestamp;
pub mod stakes;
pub mod status_cache;
Expand Down
86 changes: 86 additions & 0 deletions runtime/src/stake_delegations.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
//! Map pubkeys to stake delegations
//!
//! This module implements clone-on-write semantics for `StakeDelegations` to reduce unnecessary
//! cloning of the underlying map.
use {
solana_sdk::{pubkey::Pubkey, stake::state::Delegation},
std::{
collections::HashMap,
ops::{Deref, DerefMut},
sync::Arc,
},
};

/// A map of pubkey-to-stake-delegation with clone-on-write semantics
#[derive(Default, Clone, PartialEq, Debug, Deserialize, Serialize)]
pub struct StakeDelegations(Arc<StakeDelegationsInner>);

impl Deref for StakeDelegations {
type Target = StakeDelegationsInner;
fn deref(&self) -> &Self::Target {
&self.0
}
}

impl DerefMut for StakeDelegations {
fn deref_mut(&mut self) -> &mut Self::Target {
Arc::make_mut(&mut self.0)
}
}

/// The inner type, which maps pubkeys to stake delegations
type StakeDelegationsInner = HashMap<Pubkey, Delegation>;

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_stake_delegations_is_cow() {
let voter_pubkey = Pubkey::new_unique();
let stake = rand::random();
let activation_epoch = rand::random();
let warmup_cooldown_rate = rand::random();
let delegation =
Delegation::new(&voter_pubkey, stake, activation_epoch, warmup_cooldown_rate);

let pubkey = Pubkey::new_unique();

let mut stake_delegations = StakeDelegations::default();
stake_delegations.insert(pubkey, delegation);

// Test: Clone the stake delegations and **do not modify**. Assert the underlying maps are
// the same instance.
{
let stake_delegations2 = stake_delegations.clone();
assert_eq!(stake_delegations, stake_delegations2);
assert!(
Arc::ptr_eq(&stake_delegations.0, &stake_delegations2.0),
"Inner Arc must point to the same HashMap"
);
assert!(
std::ptr::eq(stake_delegations.deref(), stake_delegations2.deref()),
"Deref must point to the same HashMap"
);
}

// Test: Clone the stake delegations and then modify (remove the K-V, then re-add the same
// one, so the stake delegations are still logically equal). Assert the underlying maps
// are unique instances.
{
let mut stake_delegations2 = stake_delegations.clone();
stake_delegations2.clear();
assert_ne!(stake_delegations, stake_delegations2);
stake_delegations2.insert(pubkey, delegation);
assert_eq!(stake_delegations, stake_delegations2);
assert!(
!Arc::ptr_eq(&stake_delegations.0, &stake_delegations2.0),
"Inner Arc must point to different HashMaps"
);
assert!(
!std::ptr::eq(stake_delegations.deref(), stake_delegations2.deref()),
"Deref must point to different HashMaps"
);
}
}
}
9 changes: 6 additions & 3 deletions runtime/src/stakes.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
//! Stakes serve as a cache of stake and vote accounts to derive
//! node stakes
use {
crate::vote_account::{VoteAccount, VoteAccounts, VoteAccountsHashMap},
crate::{
stake_delegations::StakeDelegations,
vote_account::{VoteAccount, VoteAccounts, VoteAccountsHashMap},
},
rayon::{
iter::{IntoParallelRefIterator, ParallelIterator},
ThreadPool,
Expand All @@ -27,7 +30,7 @@ pub struct Stakes {
vote_accounts: VoteAccounts,

/// stake_delegations
stake_delegations: HashMap<Pubkey, Delegation>,
stake_delegations: StakeDelegations,

/// unused
unused: u64,
Expand Down Expand Up @@ -275,7 +278,7 @@ impl Stakes {
&self.vote_accounts
}

pub fn stake_delegations(&self) -> &HashMap<Pubkey, Delegation> {
pub fn stake_delegations(&self) -> &StakeDelegations {
&self.stake_delegations
}

Expand Down

0 comments on commit 0d1b6b9

Please sign in to comment.