Skip to main content

quorum_set/quorum/
quorum_bridge_impl.rs

1use std::collections::BTreeSet;
2
3use crate::quorum::QuorumBridge;
4use crate::quorum::QuorumIntersection;
5
6/// Builds an intermediate joint quorum set for a target flat config.
7///
8/// The result is the target alone when [`QuorumIntersection::intersects_with`] proves that every
9/// quorum of `self` intersects every quorum of the target, e.g. when the target adds one voter to
10/// a uniform `self`. Otherwise it is the joint of the last config of `self` and the target.
11///
12/// A Raft-style caller that applies a target-alone result must first commit an entry of the
13/// leader's own term. Otherwise two leaders of different terms can each move from the same
14/// committed config to a different target, and the two targets can have disjoint quorums.
15impl<ID> QuorumBridge<BTreeSet<ID>> for Vec<BTreeSet<ID>>
16where ID: Ord + Clone
17{
18    fn bridge_to(&self, other: BTreeSet<ID>) -> Self {
19        let intersects = self.intersects_with(&other);
20        if intersects == Some(true) {
21            vec![other]
22        } else if let Some(last) = self.last() {
23            vec![last.clone(), other]
24        } else {
25            vec![other]
26        }
27    }
28
29    /// Return the configs of `self` followed by `other`. Return an empty joint when `self` is
30    /// empty: an empty joint has no quorum, so a joint with it has no quorum either.
31    fn joint_with(&self, other: BTreeSet<ID>) -> Self {
32        if self.is_empty() {
33            return vec![];
34        }
35        let mut joint = self.clone();
36        joint.push(other);
37        joint
38    }
39}
40
41/// Builds an intermediate joint quorum set for a target joint config.
42///
43/// The result is the target alone when [`QuorumIntersection::intersects_with`] proves that every
44/// quorum of `self` intersects every quorum of the target. Otherwise it is the joint of the last
45/// config of `self` and the configs of the target. For a target that holds one config, the result
46/// equals the result for that config as a [`BTreeSet`] target.
47///
48/// A Raft-style caller that applies a target-alone result must first commit an entry of the
49/// leader's own term. Otherwise two leaders of different terms can each move from the same
50/// committed config to a different target, and the two targets can have disjoint quorums.
51impl<ID> QuorumBridge<Vec<BTreeSet<ID>>> for Vec<BTreeSet<ID>>
52where ID: Ord + Clone
53{
54    fn bridge_to(&self, other: Vec<BTreeSet<ID>>) -> Self {
55        let intersects = self.intersects_with(&other);
56        if intersects == Some(true) {
57            other
58        } else if let Some(last) = self.last() {
59            let mut joint = vec![last.clone()];
60            joint.extend(other);
61            joint
62        } else {
63            other
64        }
65    }
66
67    /// Return the configs of `self` followed by the configs of `other`. Return an empty joint
68    /// when `self` or `other` is empty: an empty joint has no quorum, so a joint with it has no
69    /// quorum either.
70    fn joint_with(&self, other: Vec<BTreeSet<ID>>) -> Self {
71        if self.is_empty() || other.is_empty() {
72            return vec![];
73        }
74        let mut joint = self.clone();
75        joint.extend(other);
76        joint
77    }
78}