3
3
-include (" rafter.hrl" ).
4
4
5
5
% % API
6
- -export ([quorum /3 , quorum_min /3 , voters /1 , voters /2 , followers /2 ,
6
+ -export ([quorum /3 , quorum_max /3 , voters /1 , voters /2 , followers /2 ,
7
7
reconfig /2 , allow_config /2 , has_vote /2 ]).
8
8
9
9
% %====================================================================
10
10
% % API
11
11
% %====================================================================
12
12
13
- -spec quorum_min ( term (), # config {} | [], dict ()) -> non_neg_integer ().
14
- quorum_min (_Me , # config {state = blank }, _ ) ->
13
+ -spec quorum_max ( peer (), # config {} | [], dict ()) -> non_neg_integer ().
14
+ quorum_max (_Me , # config {state = blank }, _ ) ->
15
15
0 ;
16
- quorum_min (Me , # config {state = stable , oldservers = OldServers }, Responses ) ->
17
- quorum_min (Me , OldServers , Responses );
18
- quorum_min (Me , # config {state = staging , oldservers = OldServers }, Responses ) ->
19
- quorum_min (Me , OldServers , Responses );
20
- quorum_min (Me , # config {state = transitional ,
16
+ quorum_max (Me , # config {state = stable , oldservers = OldServers }, Responses ) ->
17
+ quorum_max (Me , OldServers , Responses );
18
+ quorum_max (Me , # config {state = staging , oldservers = OldServers }, Responses ) ->
19
+ quorum_max (Me , OldServers , Responses );
20
+ quorum_max (Me , # config {state = transitional ,
21
21
oldservers = Old ,
22
22
newservers = New }, Responses ) ->
23
- min (quorum_min (Me , Old , Responses ), quorum_min (Me , New , Responses ));
23
+ min (quorum_max (Me , Old , Responses ), quorum_max (Me , New , Responses ));
24
24
25
- % % Responses doesn't contain the local response so it will be marked as 0
26
- % % when it's a member of the consensus group. In this case we must
27
- % % skip past it in a sorted list so we add 1 to the quorum offset.
28
- quorum_min (_ , [], _ ) ->
25
+ % % Sort the values received from the peers from lowest to highest
26
+ % % Peers that haven't responded have a 0 for their value.
27
+ % % This peer (Me) will always have the maximum value
28
+ quorum_max (_ , [], _ ) ->
29
29
0 ;
30
- quorum_min (Me , Servers , Responses ) ->
31
- Indexes = lists :sort (lists :map (fun (S ) -> index (S , Responses ) end , Servers )),
32
- case lists :member (Me , Servers ) of
33
- true ->
34
- lists :nth (length (Indexes ) div 2 + 2 , Indexes );
35
- false ->
36
- lists :nth (length (Indexes ) div 2 + 1 , Indexes )
37
- end .
30
+ quorum_max (Me , Servers , Responses ) when (length (Servers ) rem 2 ) =:= 0 ->
31
+ Values = sorted_values (Me , Servers , Responses ),
32
+ lists :nth (length (Values ) div 2 , Values );
33
+ quorum_max (Me , Servers , Responses ) ->
34
+ Values = sorted_values (Me , Servers , Responses ),
35
+ lists :nth (length (Values ) div 2 + 1 , Values ).
38
36
39
- -spec quorum (term (), # config {} | list (), dict ()) -> boolean ().
37
+ -spec quorum (peer (), # config {} | list (), dict ()) -> boolean ().
40
38
quorum (_Me , # config {state = blank }, _Responses ) ->
41
39
false ;
42
40
quorum (Me , # config {state = stable , oldservers = OldServers }, Responses ) ->
@@ -63,7 +61,7 @@ quorum(Me, Servers, Responses) ->
63
61
end .
64
62
65
63
% % @doc list of voters excluding me
66
- -spec voters (term (), # config {}) -> list ().
64
+ -spec voters (peer (), # config {}) -> list ().
67
65
voters (Me , Config ) ->
68
66
lists :delete (Me , voters (Config )).
69
67
@@ -74,7 +72,7 @@ voters(#config{state=transitional, oldservers=Old, newservers=New}) ->
74
72
voters (# config {oldservers = Old }) ->
75
73
Old .
76
74
77
- -spec has_vote (term (), # config {}) -> boolean ().
75
+ -spec has_vote (peer (), # config {}) -> boolean ().
78
76
has_vote (_Me , # config {state = blank }) ->
79
77
false ;
80
78
has_vote (Me , # config {state = transitional , oldservers = Old , newservers = New })->
@@ -83,7 +81,7 @@ has_vote(Me, #config{oldservers=Old}) ->
83
81
lists :member (Me , Old ).
84
82
85
83
% % @doc All followers. In staging, some followers are not voters.
86
- -spec followers (term (), # config {}) -> list ().
84
+ -spec followers (peer (), # config {}) -> list ().
87
85
followers (Me , # config {state = transitional , oldservers = Old , newservers = New }) ->
88
86
lists :delete (Me , sets :to_list (sets :from_list (Old ++ New )));
89
87
followers (Me , # config {state = staging , oldservers = Old , newservers = New }) ->
@@ -114,11 +112,24 @@ allow_config(_Config, _NewServers) ->
114
112
% % Internal Functions
115
113
% %====================================================================
116
114
117
- -spec index (atom () | {atom (), atom ()}, dict ()) -> non_neg_integer ().
118
- index (Peer , Responses ) ->
115
+ -spec sorted_values (peer (), [peer ()], dict ()) -> [non_neg_integer ()].
116
+ sorted_values (Me , Servers , Responses ) ->
117
+ Vals = lists :sort (lists :map (fun (S ) -> value (S , Responses ) end , Servers )),
118
+ case lists :member (Me , Servers ) of
119
+ true ->
120
+ % % Me is always in front because it is 0 from having no response
121
+ % % Strip it off the front, and add the max to the end of the list
122
+ [_ | T ] = Vals ,
123
+ lists :reverse ([lists :max (Vals ) | lists :reverse (T )]);
124
+ false ->
125
+ Vals
126
+ end .
127
+
128
+ -spec value (peer (), dict ()) -> non_neg_integer ().
129
+ value (Peer , Responses ) ->
119
130
case dict :find (Peer , Responses ) of
120
- {ok , Index } ->
121
- Index ;
131
+ {ok , Value } ->
132
+ Value ;
122
133
error ->
123
134
0
124
135
end .
0 commit comments