Skip to main content

d_engine_server/membership/
membership_snapshot.rs

1use std::collections::BTreeSet;
2
3/// A point-in-time snapshot of committed cluster membership.
4///
5/// Delivered via [`crate::EmbeddedEngine::watch_membership`] whenever a `ConfChange`
6/// entry commits.  The snapshot reflects the membership state **after** the
7/// change has been applied, so `borrow()` always returns a consistent view.
8///
9/// ## Idempotency
10///
11/// `committed_index` is the Raft log index of the `ConfChange` entry that
12/// triggered this snapshot.  It is strictly monotonically increasing across
13/// snapshots and can be used as an idempotency key:
14///
15/// ```ignore
16/// if snapshot.committed_index <= self.last_applied {
17///     return; // already handled
18/// }
19/// self.last_applied = snapshot.committed_index;
20/// scheduler.rebalance(&snapshot);
21/// ```
22///
23/// ## Diff computation
24///
25/// No diff fields are included.  Because `watch::channel` is lossy (only the
26/// latest value is retained), a diff embedded in the snapshot could be stale
27/// if the receiver is slow and skips an intermediate change.  Callers that
28/// need a diff should compute it against their own previous snapshot:
29///
30/// ```ignore
31/// let prev = std::mem::replace(&mut self.prev_snapshot, snapshot.clone());
32/// let joined: BTreeSet<_> = snapshot.members.difference(&prev.members).copied().collect();
33/// let left:   BTreeSet<_> = prev.members.difference(&snapshot.members).copied().collect();
34/// ```
35#[derive(Debug, Clone, PartialEq, Eq, Default)]
36pub struct MembershipSnapshot {
37    /// Current voting members (Follower / Leader role, Active status).
38    pub members: BTreeSet<u32>,
39
40    /// Current non-voting learners (Learner role, Promotable or ReadOnly status).
41    pub learners: BTreeSet<u32>,
42
43    /// Raft log index of the ConfChange entry that produced this snapshot.
44    /// Monotonically increasing; use as an idempotency key.
45    pub committed_index: u64,
46}