1 // Copyright 2019 The etcd Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package quorum 16 17 // JointConfig is a configuration of two groups of (possibly overlapping) 18 // majority configurations. Decisions require the support of both majorities. 19 type JointConfig [2]MajorityConfig 20 21 func (c JointConfig) String() string { 22 if len(c[1]) > 0 { 23 return c[0].String() + "&&" + c[1].String() 24 } 25 return c[0].String() 26 } 27 28 // IDs returns a newly initialized map representing the set of voters present 29 // in the joint configuration. 30 func (c JointConfig) IDs() map[uint64]struct{} { 31 m := map[uint64]struct{}{} 32 for _, cc := range c { 33 for id := range cc { 34 m[id] = struct{}{} 35 } 36 } 37 return m 38 } 39 40 // Describe returns a (multi-line) representation of the commit indexes for the 41 // given lookuper. 42 func (c JointConfig) Describe(l AckedIndexer) string { 43 return MajorityConfig(c.IDs()).Describe(l) 44 } 45 46 // CommittedIndex returns the largest committed index for the given joint 47 // quorum. An index is jointly committed if it is committed in both constituent 48 // majorities. 49 func (c JointConfig) CommittedIndex(l AckedIndexer) Index { 50 idx0 := c[0].CommittedIndex(l) 51 idx1 := c[1].CommittedIndex(l) 52 if idx0 < idx1 { 53 return idx0 54 } 55 return idx1 56 } 57 58 // VoteResult takes a mapping of voters to yes/no (true/false) votes and returns 59 // a result indicating whether the vote is pending, lost, or won. A joint quorum 60 // requires both majority quorums to vote in favor. 61 func (c JointConfig) VoteResult(votes map[uint64]bool) VoteResult { 62 r1 := c[0].VoteResult(votes) 63 r2 := c[1].VoteResult(votes) 64 65 if r1 == r2 { 66 // If they agree, return the agreed state. 67 return r1 68 } 69 if r1 == VoteLost || r2 == VoteLost { 70 // If either config has lost, loss is the only possible outcome. 71 return VoteLost 72 } 73 // One side won, the other one is pending, so the whole outcome is. 74 return VotePending 75 } 76