Skip to content

Commit 27a533b

Browse files
author
Alex Valiushko
committed
address feedback
1 parent 22b272c commit 27a533b

File tree

7 files changed

+65
-35
lines changed

7 files changed

+65
-35
lines changed

src/ra.hrl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848

4949
%% If set, server will start as non-voter until later promoted by the
5050
%% leader.
51-
init_non_voter => ra_nvid()}.
51+
non_voter_id => ra_nvid()}.
5252

5353
-type ra_peer_status() :: normal |
5454
{sending_snapshot, pid()} |

src/ra_server.erl

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@
197197
max_pipeline_count => non_neg_integer(),
198198
ra_event_formatter => {module(), atom(), [term()]},
199199
counter => counters:counters_ref(),
200-
init_non_voter => ra_nvid(),
200+
non_voter_id => ra_nvid(),
201201
system_config => ra_system:config()}.
202202

203203
-type mutable_config() :: #{cluster_name => ra_cluster_name(),
@@ -2899,19 +2899,21 @@ already_member(State) ->
28992899
%%% Voter status helpers
29002900
%%% ====================
29012901

2902-
-spec ensure_promotion_target(ra_voter_status(), ra_server_state()) ->
2902+
-spec ensure_promotion_target(ra_voter_status(), ra_index()) ->
29032903
{ok, ra_voter_status()} | {error, term()}.
29042904
ensure_promotion_target({voter, Reason}, _) ->
29052905
{ok, {voter, Reason}};
29062906
ensure_promotion_target({nonvoter, #{target := _, nvid := _} = Reason}, _) ->
29072907
{ok, {nonvoter, Reason}};
2908-
ensure_promotion_target({nonvoter, #{nvid := _} = Reason}, #{commit_index := CI}) ->
2909-
{ok, {nonvoter, Reason#{target => CI}}};
2908+
ensure_promotion_target({nonvoter, #{nvid := _} = Reason},
2909+
#{log := Log}) ->
2910+
Target = ra_log:next_index(Log),
2911+
{ok, {nonvoter, Reason#{target => Target}}};
29102912
ensure_promotion_target(_, _) ->
29112913
{error, missing_nvid}.
29122914

29132915
-spec init_voter_status(ra_server_config() | ra_new_server()) -> ra_voter_status().
2914-
init_voter_status(#{init_non_voter := NVId}) ->
2916+
init_voter_status(#{non_voter_id := NVId}) ->
29152917
{nonvoter, #{nvid => NVId}};
29162918
init_voter_status(_) ->
29172919
{voter, #{}}.
@@ -2949,25 +2951,19 @@ maybe_promote_self(NewCluster, State) ->
29492951
maybe_promote_peer(PeerID, #{cluster := Cluster}, Effects) ->
29502952
% Unknown peer handled in the caller.
29512953
#{PeerID := #{match_index := MI,
2952-
voter_status := OldStatus}} = Cluster,
2953-
case update_voter_status(OldStatus, MI) of
2954-
OldStatus ->
2955-
Effects;
2956-
NewStatus ->
2954+
voter_status := Status}} = Cluster,
2955+
case Status of
2956+
{nonvoter, #{target := Target} = Reason} when MI >= Target ->
29572957
[{next_event,
29582958
{command, {'$ra_join',
29592959
#{ts => os:system_time(millisecond)},
2960-
#{id => PeerID, voter_status => NewStatus},
2960+
#{id => PeerID, voter_status => {voter, Reason}},
29612961
noreply}}} |
2962-
Effects]
2962+
Effects];
2963+
_ ->
2964+
Effects
29632965
end.
29642966

2965-
update_voter_status({nonvoter, #{target := Target} = Reason}, MI)
2966-
when MI >= Target ->
2967-
{voter, Reason};
2968-
update_voter_status(Permanent, _) ->
2969-
Permanent.
2970-
29712967
-spec required_quorum(ra_cluster()) -> pos_integer().
29722968
required_quorum(Cluster) ->
29732969
Voters = count_voters(Cluster),

src/ra_server_proc.erl

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ log_fold(ServerId, Fun, InitialState, Timeout) ->
183183
-spec state_query(server_loc(),
184184
all |
185185
overview |
186+
voters |
186187
members |
187188
initial_members |
188189
machine, timeout()) ->
@@ -193,6 +194,7 @@ state_query(ServerLoc, Spec, Timeout) ->
193194
-spec local_state_query(server_loc(),
194195
all |
195196
overview |
197+
voters |
196198
members |
197199
initial_members |
198200
machine, timeout()) ->
@@ -1519,6 +1521,12 @@ do_state_query(overview, State) ->
15191521
ra_server:overview(State);
15201522
do_state_query(machine, #{machine_state := MacState}) ->
15211523
MacState;
1524+
do_state_query(voters, #{cluster := Cluster}) ->
1525+
Voters = maps:filter(fun(_, Peer) ->
1526+
{Voter, _} = maps:get(voter_status, Peer, {voter, legacy}),
1527+
Voter == voter
1528+
end, Cluster),
1529+
maps:keys(Voters);
15221530
do_state_query(members, #{cluster := Cluster}) ->
15231531
maps:keys(Cluster);
15241532
do_state_query(initial_members, #{log := Log}) ->
@@ -1735,8 +1743,8 @@ can_execute_locally(RaftState, TargetNode,
17351743
leader when TargetNode =/= node() ->
17361744
%% We need to evaluate whether to send the message.
17371745
%% Only send if there isn't a local node for the target pid.
1738-
Members = do_state_query(members, State#state.server_state),
1739-
not lists:any(fun ({_, N}) -> N == TargetNode end, Members);
1746+
Voters = do_state_query(voters, State#state.server_state),
1747+
not lists:any(fun ({_, N}) -> N == TargetNode end, Voters);
17401748
leader ->
17411749
true;
17421750
_ ->

test/coordination_SUITE.erl

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -298,50 +298,76 @@ start_cluster_minority(Config) ->
298298
send_local_msg(Config) ->
299299
PrivDir = ?config(data_dir, Config),
300300
ClusterName = ?config(cluster_name, Config),
301-
NodeIds = [{ClusterName, start_follower(N, PrivDir)} || N <- [s1,s2,s3]],
301+
[A, B, NonVoter] = [{ClusterName, start_follower(N, PrivDir)} || N <- [s1,s2,s3]],
302+
NodeIds = [A, B],
302303
Machine = {module, ?MODULE, #{}},
303304
{ok, Started, []} = ra:start_cluster(?SYS, ClusterName, Machine, NodeIds),
304305
% assert all were said to be started
305306
[] = Started -- NodeIds,
306-
%% spawn a receiver process on one node
307+
% add permanent non-voter
307308
{ok, _, Leader} = ra:members(hd(NodeIds)),
309+
{ok, _, _} = ra:process_command(Leader, banana),
310+
New = #{id => NonVoter,
311+
voter_status => {nonvoter, #{nvid => <<"test">>, target => 999}},
312+
non_voter_id => <<"test">>},
313+
{ok, _, _} = ra:add_member(A, New),
314+
ok = ra:start_server(?SYS, ClusterName, New, Machine, NodeIds),
308315
%% select a non-leader node to spawn on
309316
[{_, N} | _] = lists:delete(Leader, NodeIds),
310317
test_local_msg(Leader, N, N, send_local_msg, local),
311318
test_local_msg(Leader, N, N, send_local_msg, [local, ra_event]),
312319
test_local_msg(Leader, N, N, send_local_msg, [local, cast]),
313320
test_local_msg(Leader, N, N, send_local_msg, [local, cast, ra_event]),
314321
{_, LeaderNode} = Leader,
322+
%% test the same but for a local pid (non-member)
315323
test_local_msg(Leader, node(), LeaderNode, send_local_msg, local),
316324
test_local_msg(Leader, node(), LeaderNode, send_local_msg, [local, ra_event]),
317325
test_local_msg(Leader, node(), LeaderNode, send_local_msg, [local, cast]),
318326
test_local_msg(Leader, node(), LeaderNode, send_local_msg, [local, cast, ra_event]),
319-
%% test the same but for a local pid (non-member)
327+
%% same for non-voter
328+
{_, NonVoterNode} = NonVoter,
329+
test_local_msg(Leader, NonVoterNode, LeaderNode, send_local_msg, local),
330+
test_local_msg(Leader, NonVoterNode, LeaderNode, send_local_msg, [local, ra_event]),
331+
test_local_msg(Leader, NonVoterNode, LeaderNode, send_local_msg, [local, cast]),
332+
test_local_msg(Leader, NonVoterNode, LeaderNode, send_local_msg, [local, cast, ra_event]),
320333
[ok = slave:stop(S) || {_, S} <- NodeIds],
321334
ok.
322335

323336
local_log_effect(Config) ->
324337
PrivDir = ?config(data_dir, Config),
325338
ClusterName = ?config(cluster_name, Config),
326-
NodeIds = [{ClusterName, start_follower(N, PrivDir)} || N <- [s1,s2,s3]],
339+
[A, B, NonVoter] = [{ClusterName, start_follower(N, PrivDir)} || N <- [s1,s2,s3]],
340+
NodeIds = [A, B],
327341
Machine = {module, ?MODULE, #{}},
328342
{ok, Started, []} = ra:start_cluster(?SYS, ClusterName, Machine, NodeIds),
329343
% assert all were said to be started
330344
[] = Started -- NodeIds,
331-
%% spawn a receiver process on one node
345+
% add permanent non-voter
332346
{ok, _, Leader} = ra:members(hd(NodeIds)),
347+
{ok, _, _} = ra:process_command(Leader, banana),
348+
New = #{id => NonVoter,
349+
voter_status => {nonvoter, #{nvid => <<"test">>, target => 999}},
350+
non_voter_id => <<"test">>},
351+
{ok, _, _} = ra:add_member(A, New),
352+
ok = ra:start_server(?SYS, ClusterName, New, Machine, NodeIds),
333353
%% select a non-leader node to spawn on
334354
[{_, N} | _] = lists:delete(Leader, NodeIds),
335355
test_local_msg(Leader, N, N, do_local_log, local),
336356
test_local_msg(Leader, N, N, do_local_log, [local, ra_event]),
337357
test_local_msg(Leader, N, N, do_local_log, [local, cast]),
338358
test_local_msg(Leader, N, N, do_local_log, [local, cast, ra_event]),
359+
%% test the same but for a local pid (non-member)
339360
{_, LeaderNode} = Leader,
340361
test_local_msg(Leader, node(), LeaderNode, do_local_log, local),
341362
test_local_msg(Leader, node(), LeaderNode, do_local_log, [local, ra_event]),
342363
test_local_msg(Leader, node(), LeaderNode, do_local_log, [local, cast]),
343364
test_local_msg(Leader, node(), LeaderNode, do_local_log, [local, cast, ra_event]),
344-
%% test the same but for a local pid (non-member)
365+
%% same for non-voter
366+
{_, NonVoterNode} = NonVoter,
367+
test_local_msg(Leader, NonVoterNode, LeaderNode, do_local_log, local),
368+
test_local_msg(Leader, NonVoterNode, LeaderNode, do_local_log, [local, ra_event]),
369+
test_local_msg(Leader, NonVoterNode, LeaderNode, do_local_log, [local, cast]),
370+
test_local_msg(Leader, NonVoterNode, LeaderNode, do_local_log, [local, cast, ra_event]),
345371
[ok = slave:stop(S) || {_, S} <- NodeIds],
346372
ok.
347373

@@ -408,7 +434,7 @@ nonvoter_catches_up(Config) ->
408434
|| N <- lists:seq(1, 10000)],
409435
{ok, _, _} = ra:process_command(Leader, banana),
410436

411-
New = #{id => C, init_non_voter => <<"test">>},
437+
New = #{id => C, non_voter_id => <<"test">>},
412438
{ok, _, _} = ra:add_member(A, New),
413439
ok = ra:start_server(?SYS, ClusterName, New, Machine, [A, B]),
414440
NonVoter = {nonvoter, #{nvid => <<"test">>}},
@@ -444,7 +470,7 @@ nonvoter_catches_up_after_restart(Config) ->
444470
|| N <- lists:seq(1, 10000)],
445471
{ok, _, _} = ra:process_command(Leader, banana),
446472

447-
New = #{id => C, init_non_voter => <<"test">>},
473+
New = #{id => C, non_voter_id => <<"test">>},
448474
{ok, _, _} = ra:add_member(A, New),
449475
ok = ra:start_server(?SYS, ClusterName, New, Machine, [A, B]),
450476
NonVoter = {nonvoter, #{nvid => <<"test">>}},
@@ -482,7 +508,7 @@ nonvoter_catches_up_after_leader_restart(Config) ->
482508
|| N <- lists:seq(1, 10000)],
483509
{ok, _, _} = ra:process_command(Leader, banana),
484510

485-
New = #{id => C, init_non_voter => <<"test">>},
511+
New = #{id => C, non_voter_id => <<"test">>},
486512
{ok, _, _} = ra:add_member(A, New),
487513
ok = ra:start_server(?SYS, ClusterName, New, Machine, [A, B]),
488514
NonVoter = {nonvoter, #{nvid => <<"test">>}},

test/ra_2_SUITE.erl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -713,12 +713,12 @@ force_start_follower_as_single_member_nonvoter(Config) ->
713713
ServerId4 = ?config(server_id4, Config),
714714
UId4 = ?config(uid4, Config),
715715
Conf4 = conf(ClusterName, UId4, ServerId4, PrivDir, [ServerId3]),
716-
{ok, _, _} = ra:add_member(ServerId3, #{id => ServerId4, init_non_voter => <<"test">>}),
716+
{ok, _, _} = ra:add_member(ServerId3, #{id => ServerId4, non_voter_id => <<"test">>}),
717717
%% the membership has changed but member not running yet
718718
%% it is nonvoter and does not affect quorum size
719719
{ok, _, _} = ra:process_command(ServerId3, {enq, banana}),
720720
%% start new member
721-
ok = ra:start_server(?SYS, Conf4#{init_non_voter => <<"test">>}),
721+
ok = ra:start_server(?SYS, Conf4#{non_voter_id => <<"test">>}),
722722
{ok, _, ServerId3} = ra:members(ServerId4),
723723
ok = enqueue(ServerId3, msg3),
724724

test/ra_SUITE.erl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1175,7 +1175,7 @@ start_and_join({ClusterName, _} = ServerRef, {_, _} = New) ->
11751175
ok.
11761176

11771177
start_and_join_nonvoter({ClusterName, _} = ServerRef, {_, _} = New) ->
1178-
Server = #{id => New, init_non_voter => <<"test">>},
1178+
Server = #{id => New, non_voter_id => <<"test">>},
11791179
{ok, _, _} = ra:add_member(ServerRef, Server),
11801180
ok = ra:start_server(default, ClusterName, Server, add_machine(), [ServerRef]),
11811181
ok.

test/ra_server_SUITE.erl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1447,7 +1447,7 @@ leader_server_join_nonvoter(_Config) ->
14471447
commit_index := Target,
14481448
cluster_change_permitted := false} = _State1, Effects} =
14491449
ra_server:handle_leader({command, {'$ra_join', meta(),
1450-
#{id => N4, init_non_voter => <<"test">>}, await_consensus}}, State0),
1450+
#{id => N4, non_voter_id => <<"test">>}, await_consensus}}, State0),
14511451
% new member should join as non-voter
14521452
[
14531453
{send_rpc, N4,
@@ -1608,7 +1608,7 @@ leader_applies_new_cluster_nonvoter(_Config) ->
16081608
N3 => new_peer_with(#{next_index => 4, match_index => 3})},
16091609

16101610
State = (base_state(3, ?FUNCTION_NAME))#{cluster => OldCluster},
1611-
Command = {command, {'$ra_join', meta(), #{id => N4, init_non_voter => <<"test">>}, await_consensus}},
1611+
Command = {command, {'$ra_join', meta(), #{id => N4, non_voter_id => <<"test">>}, await_consensus}},
16121612
% cluster records index and term it was applied to determine whether it has
16131613
% been applied
16141614
{leader, #{cluster_index_term := {4, 5},

0 commit comments

Comments
 (0)