Skip to content

Commit

Permalink
customizes override logic for gossip ContactInfo
Browse files Browse the repository at this point in the history
If there are two running instances of the same node, we want the one
with more recent start time to be propagated through gossip regardless
of wallclocks.

The commit adds custom override logic for ContactInfo to first compare
by outset timestamp.
  • Loading branch information
behzadnouri committed Aug 13, 2024
1 parent b09567c commit 9b898ec
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 3 deletions.
43 changes: 43 additions & 0 deletions gossip/src/contact_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use {
solana_streamer::socket::SocketAddrSpace,
static_assertions::const_assert_eq,
std::{
cmp::Ordering,
collections::HashSet,
net::{IpAddr, Ipv4Addr, SocketAddr},
time::{SystemTime, UNIX_EPOCH},
Expand Down Expand Up @@ -443,6 +444,24 @@ impl ContactInfo {
pub(crate) fn check_duplicate(&self, other: &ContactInfo) -> bool {
self.pubkey == other.pubkey && self.outset < other.outset
}

// Returns None if the contact-infos have different pubkey.
// Otherwise returns true if (self.outset, self.wallclock) tuple is larger
// than (other.outset, other.wallclock).
// If the tuples are equal it returns None.
#[inline]
#[must_use]
pub(crate) fn overrides(&self, other: &ContactInfo) -> Option<bool> {
if self.pubkey != other.pubkey {
return None;
}
let other = (other.outset, other.wallclock);
match (self.outset, self.wallclock).cmp(&other) {
Ordering::Less => Some(false),
Ordering::Greater => Some(true),
Ordering::Equal => None,
}
}
}

impl Default for ContactInfo {
Expand Down Expand Up @@ -1038,6 +1057,8 @@ mod tests {
let other = node.clone();
assert!(!node.check_duplicate(&other));
assert!(!other.check_duplicate(&node));
assert_eq!(node.overrides(&other), None);
assert_eq!(other.overrides(&node), None);
}
// Updated socket address is not a duplicate instance.
{
Expand All @@ -1046,16 +1067,28 @@ mod tests {
while other.set_serve_repair(new_rand_socket(&mut rng)).is_err() {}
assert!(!node.check_duplicate(&other));
assert!(!other.check_duplicate(&node));
assert_eq!(node.overrides(&other), None);
assert_eq!(other.overrides(&node), None);
other.remove_serve_repair();
assert!(!node.check_duplicate(&other));
assert!(!other.check_duplicate(&node));
assert_eq!(node.overrides(&other), None);
assert_eq!(other.overrides(&node), None);
}
// Updated wallclock is not a duplicate instance.
{
let other = node.clone();
node.set_wallclock(rng.gen());
assert!(!node.check_duplicate(&other));
assert!(!other.check_duplicate(&node));
assert_eq!(
node.overrides(&other),
Some(other.wallclock < node.wallclock)
);
assert_eq!(
other.overrides(&node),
Some(node.wallclock < other.wallclock)
);
}
// Different pubkey is not a duplicate instance.
{
Expand All @@ -1066,6 +1099,8 @@ mod tests {
);
assert!(!node.check_duplicate(&other));
assert!(!other.check_duplicate(&node));
assert_eq!(node.overrides(&other), None);
assert_eq!(other.overrides(&node), None);
}
// Same pubkey, more recent outset timestamp is a duplicate instance.
{
Expand All @@ -1077,6 +1112,14 @@ mod tests {
assert!(node.outset < other.outset);
assert!(node.check_duplicate(&other));
assert!(!other.check_duplicate(&node));
assert_eq!(node.overrides(&other), Some(false));
assert_eq!(other.overrides(&node), Some(true));
node.set_wallclock(other.wallclock);
assert!(node.outset < other.outset);
assert!(node.check_duplicate(&other));
assert!(!other.check_duplicate(&node));
assert_eq!(node.overrides(&other), Some(false));
assert_eq!(other.overrides(&node), Some(true));
}
}
}
13 changes: 10 additions & 3 deletions gossip/src/crds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,14 +196,21 @@ impl Default for Crds {
// Both values should have the same key/label.
fn overrides(value: &CrdsValue, other: &VersionedCrdsValue) -> bool {
assert_eq!(value.label(), other.value.label(), "labels mismatch!");
// Node instances are special cased so that if there are two running
// instances of the same node, the more recent start is propagated through
// gossip regardless of wallclocks.
// Contact-infos and node instances are special cased so that if there are
// two running instances of the same node, the more recent start is
// propagated through gossip regardless of wallclocks.
if let CrdsData::NodeInstance(value) = &value.data {
if let Some(out) = value.overrides(&other.value) {
return out;
}
}
if let CrdsData::ContactInfo(value) = &value.data {
if let CrdsData::ContactInfo(other) = &other.value.data {
if let Some(out) = value.overrides(other) {
return out;
}
}
}
match value.wallclock().cmp(&other.value.wallclock()) {
Ordering::Less => false,
Ordering::Greater => true,
Expand Down

0 comments on commit 9b898ec

Please sign in to comment.