Fix witness calculation projections, part I

This commit is contained in:
Scott Lystig Fritchie 2015-08-05 15:50:32 +09:00
parent 91496c656b
commit f43a5ca96d

View file

@ -325,7 +325,6 @@ handle_info(tick_check_environment, #ch_mgr{ignore_timer=true}=S) ->
{noreply, S};
handle_info(tick_check_environment, S) ->
{{_Delta, Props, _Epoch}, S1} = do_react_to_env(S),
io:format(user, "tick ~p ~p ~p\n~p\n", [S#ch_mgr.name, _Delta, _Epoch, get(react)]),
S2 = sanitize_repair_state(S1),
S3 = perhaps_start_repair(S2),
case proplists:get_value(throttle_seconds, Props) of
@ -504,7 +503,9 @@ rank_and_sort_projections_with_extra(All_queried_list, FLUsRs, ProjectionType,
if All_queried_list == []
orelse
length(UnwrittenRs) == length(FLUsRs) ->
NoneProj = make_none_projection(MyName, [], orddict:new()),
Witness_list = CurrentProj#projection_v1.witnesses,
NoneProj = make_none_projection(MyName, [], Witness_list,
orddict:new()),
Extra2 = [{all_members_replied, true},
{all_queried_list, All_queried_list},
{flus_rs, FLUsRs},
@ -601,7 +602,11 @@ calc_projection(_OldThreshold, _NoPartitionThreshold, LastProj,
NewUp = Up -- LastUp,
Down = AllMembers -- Up,
NewUPI_list = [X || X <- OldUPI_list, lists:member(X, Up)],
NewUPI_list =
[W || W <- Up, lists:member(W, OldWitness_list)]
++
[X || X <- OldUPI_list, lists:member(X, Up) andalso
not lists:member(X, OldWitness_list)],
#projection_v1{upi=CurrentUPI_list} = CurrentProj,
LastInCurrentUPI = case CurrentUPI_list of
[] -> does_not_exist_because_upi_is_empty;
@ -611,7 +616,9 @@ calc_projection(_OldThreshold, _NoPartitionThreshold, LastProj,
[] -> does_not_exist_because_upi_is_empty;
[_|_] -> lists:last(NewUPI_list)
end,
Repairing_list2 = [X || X <- OldRepairing_list, lists:member(X, Up)],
Repairing_list2 = [X || X <- OldRepairing_list,
lists:member(X, Up),
not lists:member(X, OldWitness_list)],
Simulator_p = proplists:get_value(use_partition_simulator, RunEnv2, false),
SimRepair_p = proplists:get_value(simulate_repair, RunEnv2, true),
{NewUPI_list3, Repairing_list3, RunEnv3} =
@ -651,32 +658,30 @@ calc_projection(_OldThreshold, _NoPartitionThreshold, LastProj,
[] -> Repairing_list3;
NewUp -> Repairing_list3 ++ NewUp
end,
Repairing_list5 = Repairing_list4 -- Down,
Repairing_list5 = (Repairing_list4 -- Down) -- OldWitness_list,
TentativeUPI = NewUPI_list3,
TentativeRepairing = Repairing_list5,
AllTentativeUPI_witnesses_p =
lists:all(fun(X) -> lists:member(X, OldWitness_list) end,
TentativeUPI),
{NewUPI, NewRepairing} =
if TentativeUPI == [] andalso TentativeRepairing /= [] ->
if (TentativeUPI == [] orelse AllTentativeUPI_witnesses_p)
andalso TentativeRepairing /= [] ->
%% UPI is empty or all in UPI are witnesses, so grab
%% the first from the repairing list and make it the
%% only non-witness in the UPI.
[FirstRepairing|TailRepairing] = TentativeRepairing,
{[FirstRepairing], TailRepairing};
{TentativeUPI ++ [FirstRepairing], TailRepairing};
true ->
{TentativeUPI, TentativeRepairing}
end,
P = case NewUPI -- OldWitness_list of
[] ->
io:format(user, "\nNONE proj ~p\n", [OldEpochNum+1]),
NP = make_none_projection(MyName, OldAll_list, OldWitness_list,
MembersDict),
NP#projection_v1{epoch_number=OldEpochNum + 1};
_ ->
machi_projection:new(OldEpochNum + 1,
MyName, MembersDict,
Down, NewUPI, NewRepairing,
P = machi_projection:new(OldEpochNum + 1,
MyName, MembersDict, Down, NewUPI, NewRepairing,
D_foo ++
Dbg ++ [{ps, Partitions},{nodes_up, Up}])
end,
Dbg ++ [{ps, Partitions},{nodes_up, Up}]),
P2 = machi_projection:update_checksum(
P#projection_v1{witnesses=OldWitness_list}),
{P2, S#ch_mgr{runenv=RunEnv3}}.
@ -793,28 +798,18 @@ rank_projections(Projs, CurrentProj) ->
rank_projection(#projection_v1{upi=[]}, _MemberRank, _N) ->
-100;
rank_projection(#projection_v1{author_server=_Author,
witnesses=Witness_list,
upi=UPI_list,
repairing=Repairing_list}, _MemberRank, N) ->
%% It's possible that there's "cross-talk" across projection
%% stores. For example, we were a chain of [a,b], then the
%% administrator sets a's members_dict to include only a.
%% However, b is still running and has written a public projection
%% suggestion to a, and a has seen it. (Or perhaps b has old
%% chain information from one/many configurations ago, and its
%% projection store was not wiped clean, then b was restarted &
%% begins using its local outdated projection information.)
%%
%% Server b is no longer a member of a's MemberRank scheme, so we
%% need to compensate for this by giving b an extremely low author
%% ranking.
AuthorRank = 0,
%% AuthorRank = case orddict:find(Author, MemberRank) of
%% {ok, Rank} -> Rank;
%% error -> -(N*N*N*N)
%% end,
case UPI_list -- Witness_list of
[] ->
-100;
_ ->
AuthorRank +
( N * length(Repairing_list)) +
(N*N * length(UPI_list)).
(N*N * length(UPI_list))
end.
do_set_chain_members_dict(MembersDict, #ch_mgr{proxies_dict=OldProxiesDict}=S)->
_ = ?FLU_PC:stop_proxies(OldProxiesDict),
@ -1194,15 +1189,18 @@ react_to_env_A40(Retries, P_newprop, P_latest, LatestUnanimousP,
[{Rank_newprop, _}] = rank_projections([P_newprop], P_current),
[{Rank_latest, _}] = rank_projections([P_latest], P_current),
LatestAuthorDownP = lists:member(P_latest#projection_v1.author_server,
P_newprop#projection_v1.down),
P_newprop#projection_v1.down)
andalso P_latest#projection_v1.author_server /= MyName,
if
%% Epoch == 0 is reserved for first-time, just booting conditions.
(P_current#projection_v1.epoch_number > 0
Rank_newprop > 0
andalso
((P_current#projection_v1.epoch_number > 0
andalso
P_latest#projection_v1.epoch_number > P_current#projection_v1.epoch_number)
orelse
not LatestUnanimousP ->
not LatestUnanimousP) ->
?REACT({a40, ?LINE,
[{latest_epoch, P_latest#projection_v1.epoch_number},
{current_epoch, P_current#projection_v1.epoch_number},
@ -1214,9 +1212,11 @@ react_to_env_A40(Retries, P_newprop, P_latest, LatestUnanimousP,
react_to_env_B10(Retries, P_newprop, P_latest, LatestUnanimousP,
Rank_newprop, Rank_latest, S);
P_latest#projection_v1.epoch_number < P_current#projection_v1.epoch_number
Rank_newprop > 0
andalso
(P_latest#projection_v1.epoch_number < P_current#projection_v1.epoch_number
orelse
P_latest /= P_current ->
P_latest /= P_current) ->
?REACT({a40, ?LINE,
[{latest_epoch, P_latest#projection_v1.epoch_number},
{current_epoch, P_current#projection_v1.epoch_number},
@ -1261,6 +1261,8 @@ react_to_env_A40(Retries, P_newprop, P_latest, LatestUnanimousP,
react_to_env_C300(P_newprop, P_latest, S);
%% A40b (see flowchart)
Rank_newprop > 0
andalso
P_latest#projection_v1.author_server == MyName
andalso
(P_newprop#projection_v1.upi /= P_latest#projection_v1.upi
@ -1677,11 +1679,6 @@ react_to_env_C300(#projection_v1{epoch_number=_Epoch_newprop}=P_newprop,
#projection_v1{epoch_number=_Epoch_latest}=_P_latest, S) ->
?REACT(c300),
%% This logic moved to A30.
%% NewEpoch = erlang:max(Epoch_newprop, Epoch_latest) + 1,
%% P_newprop2 = P_newprop#projection_v1{epoch_number=NewEpoch},
%% react_to_env_C310(update_checksum(P_newprop2), S).
react_to_env_C310(machi_projection:update_checksum(P_newprop), S).
react_to_env_C310(P_newprop, S) ->
@ -2161,7 +2158,8 @@ perhaps_start_repair(S) ->
S.
do_repair(#ch_mgr{name=MyName,
proj=#projection_v1{upi=UPI,
proj=#projection_v1{witnesses=Witness_list,
upi=UPI0,
repairing=[_|_]=Repairing,
members_dict=MembersDict}}=S,
Opts, ap_mode=RepairMode) ->
@ -2187,8 +2185,9 @@ do_repair(#ch_mgr{name=MyName,
RepairId = proplists:get_value(repair_id, Opts, id1),
error_logger:info_msg(
"Repair start: tail ~p of ~p -> ~p, ~p ID ~w\n",
[MyName, UPI, Repairing, RepairMode, RepairId]),
[MyName, UPI0, Repairing, RepairMode, RepairId]),
UPI = UPI0 -- Witness_list,
Res = machi_chain_repair:repair(ap_mode, MyName, Repairing, UPI,
MembersDict, ETS, Opts),
T2 = os:timestamp(),
@ -2201,7 +2200,7 @@ do_repair(#ch_mgr{name=MyName,
error_logger:info_msg(
"Repair ~s: tail ~p of ~p finished ~p repair ID ~w: "
"~p\nStats ~p\n",
[Summary, MyName, UPI, RepairMode, RepairId,
[Summary, MyName, UPI0, RepairMode, RepairId,
Res, Stats]),
ets:delete(ETS),
exit({repair_final_status, Res});