Skip to content

Commit 268fa86

Browse files
committed
cluster: sort accepted view-change proposals
This makes it possible to search a MultiNodeCut by SocketAddr without doing a linear scan. Unfortunately, SocketAddr doesn't implement Ord, so we have to base the sort on tuples of (ip, port). related: rust-lang/rust#72239
1 parent 9f0ce60 commit 268fa86

File tree

3 files changed

+47
-6
lines changed

3 files changed

+47
-6
lines changed

src/cluster/cut.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use std::{
1212
collections::HashMap,
1313
convert::TryInto,
1414
net::SocketAddr,
15+
ops::Index,
1516
result,
1617
sync::{Arc, Weak},
1718
};
@@ -89,6 +90,21 @@ pub struct MultiNodeCut {
8990
pub(crate) kicked: Arc<[Member]>,
9091
}
9192

93+
impl Index<SocketAddr> for MultiNodeCut {
94+
type Output = Member;
95+
96+
/// Binary search for the provided `addr`.
97+
///
98+
/// O(log n)
99+
///
100+
/// # Panics
101+
/// Panics if a member with `addr` doesn't exist in the configuration.
102+
#[inline]
103+
fn index(&self, addr: SocketAddr) -> &Self::Output {
104+
self.lookup(addr).unwrap()
105+
}
106+
}
107+
92108
impl MultiNodeCut {
93109
/// Returns the number of cuts that were skipped between this and the last received
94110
/// cut.
@@ -139,6 +155,18 @@ impl MultiNodeCut {
139155
pub fn kicked(&self) -> &Arc<[Member]> {
140156
&self.kicked
141157
}
158+
159+
/// Lookup a specific member in the configuration by socket address.
160+
///
161+
/// Executes in O(log n) time.
162+
pub fn lookup(&self, addr: SocketAddr) -> Option<&Member> {
163+
let key = |s: SocketAddr| (s.ip(), s.port());
164+
165+
self.members
166+
.binary_search_by_key(&key(addr), |m| key(m.addr()))
167+
.ok()
168+
.map(|i| &self.members[i])
169+
}
142170
}
143171

144172
/// A cluster member.

src/cluster/mod.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -633,14 +633,21 @@ impl<St: partition::Strategy> Cluster<St> {
633633

634634
let local_node = self.local_node();
635635

636+
joined.sort_by_key(|m| (m.addr().ip(), m.addr().port()));
637+
kicked.sort_by_key(|m| (m.addr().ip(), m.addr().port()));
638+
639+
let mut members: Vec<_> = (state.nodes.iter())
640+
.map(|node| self.resolve_member(state, node).unwrap())
641+
.collect();
642+
643+
members.sort_by_key(|m| (m.addr().ip(), m.addr().port()));
644+
636645
let cut = MultiNodeCut {
637646
skipped: 0,
638647
local_addr: self.addr,
639648
degraded: !state.nodes.contains(&local_node),
640649
conf_id: state.refresh_config(),
641-
members: (state.nodes.iter())
642-
.map(|node| self.resolve_member(state, node).unwrap())
643-
.collect(),
650+
members: members.into(),
644651
joined: joined.into(),
645652
kicked: kicked.into(),
646653
};

src/cluster/partition.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,14 +186,20 @@ impl<St: Strategy> Cluster<St> {
186186
assert!(state.uuids.insert(uuid));
187187
}
188188

189+
joined.sort_by_key(|m| (m.addr().ip(), m.addr().port()));
190+
191+
let mut members: Vec<_> = (state.nodes.iter())
192+
.map(|node| self.resolve_member(&state, node).unwrap())
193+
.collect();
194+
195+
members.sort_by_key(|m| (m.addr().ip(), m.addr().port()));
196+
189197
let cut = MultiNodeCut {
190198
skipped: 0,
191199
local_addr: self.addr,
192200
degraded: !state.nodes.contains(&self.local_node()),
193201
conf_id: state.refresh_config(),
194-
members: (state.nodes.iter())
195-
.map(|node| self.resolve_member(&state, node).unwrap())
196-
.collect(),
202+
members: members.into(),
197203
joined: joined.into(),
198204
kicked: vec![].into(),
199205
};

0 commit comments

Comments
 (0)