quorum_set/quorum/coherent.rs
1use crate::quorum::QuorumSet;
2
3/// Relation between quorum sets whose quorums always intersect.
4///
5/// **Coherent** quorum set A and B is defined as:
6/// `∀ qᵢ ∈ A, ∀ qⱼ ∈ B: qᵢ ∩ qⱼ != ø`, i.e., `A ~ B`.
7/// In words, every quorum in A intersects every quorum in B. Consensus
8/// protocols use this relation to make membership changes without losing
9/// overlap between old and new decisions.
10///
11/// In a Raft-style membership change, coherence is one safety requirement. The
12/// protocol also has to prevent an old, smaller candidate from being elected
13/// during the transition.
14pub trait Coherent<ID, Other>
15where
16 ID: PartialOrd + Ord + 'static,
17 Self: QuorumSet<Id = ID>,
18 Other: QuorumSet<Id = ID>,
19{
20 /// Return `true` if this quorum set is coherent with the other quorum set.
21 fn is_coherent_with(&self, other: &Other) -> bool;
22}
23
24/// Finds an intermediate quorum set coherent with both source and target quorum sets.
25pub trait FindCoherent<ID, Other>
26where
27 ID: PartialOrd + Ord + 'static,
28 Self: QuorumSet<Id = ID>,
29 Other: QuorumSet<Id = ID>,
30{
31 /// Build a quorum set `X` so that `self` is coherent with `X` and `X` is
32 /// coherent with `other`, i.e., `self ~ X ~ other`.
33 ///
34 /// Then `X` is the intermediate quorum set when changing membership from
35 /// `self` to `other`.
36 ///
37 /// E.g.(`cᵢcⱼ` is a joint of `cᵢ` and `cⱼ`):
38 /// - `c₁.find_coherent(c₁)` returns `c₁`
39 /// - `c₁.find_coherent(c₂)` returns `c₁c₂`
40 /// - `c₁c₂.find_coherent(c₂)` returns `c₂`
41 /// - `c₁c₂.find_coherent(c₁)` returns `c₁`
42 /// - `c₁c2.find_coherent(c₃)` returns `c₂c₃`
43 fn find_coherent(&self, other: Other) -> Self;
44}