1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
use std::{
net::{IpAddr, Ipv4Addr, SocketAddr},
time::Duration,
};
/// Configuration for one Datum cluster member.
#[derive(Debug, Clone)]
pub struct ClusterConfig {
/// Stable logical node id used by Datum control-plane APIs.
pub node_id: String,
/// Akka-style role labels advertised in membership gossip.
pub roles: Vec<String>,
/// Local UDP address used for membership gossip.
pub bind_addr: SocketAddr,
/// Address peers should use to contact this node. If the port is `0`, the
/// bound UDP port is substituted at startup.
pub advertise_addr: SocketAddr,
/// DCP agent address peers should use for node-to-node control sessions.
///
/// `ClusterAgent` fills this from the bound DCP listener when it starts the
/// agent and membership together. Bare membership nodes may leave it empty.
pub agent_addr: Option<SocketAddr>,
/// Seed node UDP addresses. The seed identity is resolved by foca from the
/// first announce reply, so only addresses are required here.
pub seed_nodes: Vec<SocketAddr>,
/// Foca probe period and periodic gossip cadence.
pub gossip_interval: Duration,
/// Direct probe round-trip timeout before foca asks indirect probes.
pub probe_timeout: Duration,
/// Foca suspect-to-down timeout. Keep this longer than the downing timeout
/// when `TimeoutDowning` should make the public downing decision first.
pub suspect_timeout: Duration,
/// Default timeout used by [`crate::TimeoutDowning`].
pub downing_timeout: Duration,
/// How long foca remembers down identities before accepting the exact same
/// identity again. New incarnations can rejoin before this expires.
pub remove_down_after: Duration,
/// Maximum UDP packet size foca will produce and consume.
pub max_packet_size: usize,
/// Bounded event-feed capacity for [`crate::MemberEvent`] subscribers.
pub event_buffer: usize,
}
impl ClusterConfig {
/// Create a config with loopback defaults and no seed nodes.
#[must_use]
pub fn new(node_id: impl Into<String>) -> Self {
Self {
node_id: node_id.into(),
..Self::default()
}
}
/// Return a copy using the supplied roles.
#[must_use]
pub fn with_roles(mut self, roles: impl IntoIterator<Item = impl Into<String>>) -> Self {
self.roles = roles.into_iter().map(Into::into).collect();
self
}
/// Return a copy using the supplied seed-node addresses.
#[must_use]
pub fn with_seed_nodes(mut self, seed_nodes: impl IntoIterator<Item = SocketAddr>) -> Self {
self.seed_nodes = seed_nodes.into_iter().collect();
self
}
pub(crate) fn normalized_roles(&self) -> Vec<String> {
let mut roles = self
.roles
.iter()
.map(|role| role.trim().to_owned())
.filter(|role| !role.is_empty())
.collect::<Vec<_>>();
roles.sort();
roles.dedup();
roles
}
}
impl Default for ClusterConfig {
fn default() -> Self {
let loopback = IpAddr::V4(Ipv4Addr::LOCALHOST);
Self {
node_id: format!("datum-node-{}", std::process::id()),
roles: Vec::new(),
bind_addr: SocketAddr::new(loopback, 0),
advertise_addr: SocketAddr::new(loopback, 0),
agent_addr: None,
seed_nodes: Vec::new(),
gossip_interval: Duration::from_millis(250),
probe_timeout: Duration::from_millis(75),
suspect_timeout: Duration::from_secs(2),
downing_timeout: Duration::from_millis(500),
remove_down_after: Duration::from_secs(60),
max_packet_size: 1400,
event_buffer: 256,
}
}
}