limits number of unique pubkeys in the crds table (#15539)

This commit is contained in:
behzad nouri
2021-03-10 20:46:05 +00:00
committed by GitHub
parent 9c1198c0c7
commit 56923c91bf
3 changed files with 161 additions and 47 deletions

View File

@@ -114,6 +114,8 @@ pub const DEFAULT_CONTACT_DEBUG_INTERVAL_MILLIS: u64 = 10_000;
pub const DEFAULT_CONTACT_SAVE_INTERVAL_MILLIS: u64 = 60_000;
/// Minimum serialized size of a Protocol::PullResponse packet.
const PULL_RESPONSE_MIN_SERIALIZED_SIZE: usize = 161;
// Limit number of unique pubkeys in the crds table.
const CRDS_UNIQUE_PUBKEY_CAPACITY: usize = 4096;
#[derive(Debug, PartialEq, Eq)]
pub enum ClusterInfoError {
@@ -285,6 +287,8 @@ struct GossipStats {
prune_message_len: Counter,
pull_request_ping_pong_check_failed_count: Counter,
purge: Counter,
trim_crds_table_failed: Counter,
trim_crds_table_purged_values_count: Counter,
epoch_slots_lookup: Counter,
new_pull_requests: Counter,
new_pull_requests_count: Counter,
@@ -603,16 +607,6 @@ impl ClusterInfo {
self.contact_debug_interval = new;
}
pub fn update_contact_info<F>(&self, modify: F)
where
F: FnOnce(&mut ContactInfo),
{
let my_id = self.id();
modify(&mut self.my_contact_info.write().unwrap());
assert_eq!(self.my_contact_info.read().unwrap().id, my_id);
self.insert_self()
}
fn push_self(
&self,
stakes: &HashMap<Pubkey, u64>,
@@ -1726,6 +1720,7 @@ impl ClusterInfo {
stakes: &HashMap<Pubkey, u64>,
generate_pull_requests: bool,
) -> Vec<(SocketAddr, Protocol)> {
self.trim_crds_table(CRDS_UNIQUE_PUBKEY_CAPACITY, &stakes);
let mut pulls: Vec<_> = if generate_pull_requests {
self.new_pull_requests(&thread_pool, gossip_validators, stakes)
} else {
@@ -1839,6 +1834,39 @@ impl ClusterInfo {
inc_new_counter_info!("cluster_info-purge-count", num_purged);
}
// Trims the CRDS table by dropping all values associated with the pubkeys
// with the lowest stake, so that the number of unique pubkeys are bounded.
fn trim_crds_table(&self, cap: usize, stakes: &HashMap<Pubkey, u64>) {
if !self.gossip.read().unwrap().crds.should_trim(cap) {
return;
}
let keep: Vec<_> = self
.entrypoints
.read()
.unwrap()
.iter()
.map(|k| k.id)
.chain(std::iter::once(self.id))
.collect();
let mut gossip = self.gossip.write().unwrap();
match gossip.crds.trim(cap, &keep, stakes) {
Err(err) => {
self.stats.trim_crds_table_failed.add_relaxed(1);
error!("crds table trim failed: {:?}", err);
}
Ok(purged_values) => {
self.stats
.trim_crds_table_purged_values_count
.add_relaxed(purged_values.len() as u64);
gossip.pull.purged_values.extend(
purged_values
.into_iter()
.map(|v| (v.value_hash, v.local_timestamp)),
);
}
}
}
/// randomly pick a node and ask them for updates asynchronously
pub fn gossip(
self: Arc<Self>,
@@ -2663,6 +2691,7 @@ impl ClusterInfo {
response_sender,
);
self.handle_batch_pull_responses(pull_responses, thread_pool, &stakes, epoch_time_ms);
self.trim_crds_table(CRDS_UNIQUE_PUBKEY_CAPACITY, &stakes);
self.handle_batch_pong_messages(pong_messages, Instant::now());
self.handle_batch_pull_requests(
pull_requests,
@@ -3010,6 +3039,16 @@ impl ClusterInfo {
self.stats.packets_sent_push_messages_count.clear(),
i64
),
(
"trim_crds_table_failed",
self.stats.trim_crds_table_failed.clear(),
i64
),
(
"trim_crds_table_purged_values_count",
self.stats.trim_crds_table_purged_values_count.clear(),
i64
),
);
*last_print = Instant::now();
@@ -3718,40 +3757,6 @@ mod tests {
.lookup(&label)
.is_some());
}
#[test]
#[should_panic]
fn test_update_contact_info() {
let d = ContactInfo::new_localhost(&solana_sdk::pubkey::new_rand(), timestamp());
let cluster_info = ClusterInfo::new_with_invalid_keypair(d);
let entry_label = CrdsValueLabel::ContactInfo(cluster_info.id());
assert!(cluster_info
.gossip
.read()
.unwrap()
.crds
.lookup(&entry_label)
.is_some());
let now = timestamp();
cluster_info.update_contact_info(|ci| ci.wallclock = now);
assert_eq!(
cluster_info
.gossip
.read()
.unwrap()
.crds
.lookup(&entry_label)
.unwrap()
.contact_info()
.unwrap()
.wallclock,
now
);
// Inserting Contactinfo with different pubkey should panic,
// and update should fail
cluster_info.update_contact_info(|ci| ci.id = solana_sdk::pubkey::new_rand())
}
fn assert_in_range(x: u16, range: (u16, u16)) {
assert!(x >= range.0);