Bug fixes: model and real bugs, thanks PULSE and converge_demo both!

This commit is contained in:
Scott Lystig Fritchie 2015-06-04 17:39:29 +09:00
parent 0cf9627f26
commit be62300b3b
4 changed files with 88 additions and 53 deletions

View file

@ -1352,6 +1352,7 @@ react_to_env_C100(P_newprop, P_latest,
react_to_env_C110(P_latest, #ch_mgr{name=MyName} = S) -> react_to_env_C110(P_latest, #ch_mgr{name=MyName} = S) ->
?REACT(c110), ?REACT(c110),
Extra_todo = [], Extra_todo = [],
%% Extra_todo = [{hee, lists:reverse(get(react))}],
P_latest2 = machi_projection:update_dbg2(P_latest, Extra_todo), P_latest2 = machi_projection:update_dbg2(P_latest, Extra_todo),
MyNamePid = proxy_pid(MyName, S), MyNamePid = proxy_pid(MyName, S),
@ -1446,6 +1447,7 @@ react_to_env_C310(P_newprop, S) ->
?REACT({c310, ?LINE, ?REACT({c310, ?LINE,
[{newprop, machi_projection:make_summary(P_newprop)}, [{newprop, machi_projection:make_summary(P_newprop)},
{write_result, WriteRes}]}), {write_result, WriteRes}]}),
%% io:format(user, "HEE310 ~w ~w ~w\n", [S#ch_mgr.name, self(), lists:reverse(get(react))]),
react_to_env_A10(S2). react_to_env_A10(S2).
calculate_flaps(P_newprop, _P_current, _FlapLimit, calculate_flaps(P_newprop, _P_current, _FlapLimit,
@ -1721,6 +1723,35 @@ projection_transition_is_sane(
not (lists:member(RelativeToServer, Down_list2) orelse not (lists:member(RelativeToServer, Down_list2) orelse
lists:member(RelativeToServer, Repairing_list2)), lists:member(RelativeToServer, Repairing_list2)),
UPIs_are_disjointP = ordsets:is_disjoint(ordsets:from_list(UPI_list1),
ordsets:from_list(UPI_list2)),
case UPI_2_suffix -- UPI_list1 of
[] ->
true;
[_|_] = _Added_by_2 ->
if RetrospectiveP ->
%% Any servers added to the UPI must be added from the
%% repairing list ... but in retrospective mode (where
%% we're checking only the transitions where all
%% UPI+repairing participants have unanimous private
%% projections!), and if we're under asymmetric
%% partition/churn, then we may not see the repairing
%% list. So we will not check that condition here.
true;
not RetrospectiveP ->
%% We're not retrospective. So, if some server was
%% added by to the UPI, then that means that it was
%% added by repair. And repair is coordinated by the
%% UPI tail/last.
%io:format(user, "g: UPI_list1=~w, UPI_list2=~w, UPI_2_suffix=~w, ",
% [UPI_list1, UPI_list2, UPI_2_suffix]),
%io:format(user, "g", []),
true = UPI_list1 == [] orelse
UPIs_are_disjointP orelse
(lists:last(UPI_list1) == AuthorServer2)
end
end,
if not MoreCheckingP -> if not MoreCheckingP ->
ok; ok;
MoreCheckingP -> MoreCheckingP ->
@ -1788,16 +1819,26 @@ projection_transition_is_sane(
%% The retrospective view by %% The retrospective view by
%% machi_chain_manager1_pulse.erl just can't %% machi_chain_manager1_pulse.erl just can't
%% reason correctly about this situation. We %% reason correctly about this situation. We
%% will instead rely on the non-introspective %% will instead rely on the non-retrospective
%% sanity checking that each FLU does before it %% sanity checking that each FLU does before it
%% writes to its private projection store and %% writes to its private projection store and
%% then adopts that projection (and unwedges %% then adopts that projection (and unwedges
%% itself, etc etc). %% itself, etc etc).
exit({todo, revisit, ?MODULE, ?LINE}), if UPIs_are_disjointP ->
true;
true ->
exit({todo, revisit, ?MODULE, ?LINE,
[
{oops_check_UPI_2_suffix, Oops_check_UPI_2_suffix},
{upi_2_suffix, UPI_2_suffix},
{upi_2_concat, UPI_2_concat},
{retrospectivep, RetrospectiveP}
]}),
io:format(user, "|~p,~p TODO revisit|", io:format(user, "|~p,~p TODO revisit|",
[?MODULE, ?LINE]), [?MODULE, ?LINE]),
ok; ok
end;
true -> true ->
%% The following is OK: We're shifting from a %% The following is OK: We're shifting from a
%% normal projection to an inner one. The old %% normal projection to an inner one. The old
@ -1843,7 +1884,13 @@ projection_transition_is_sane(
true; true;
SecondCase_p -> SecondCase_p ->
true; true;
not RetrospectiveP -> UPIs_are_disjointP ->
%% If there's no overlap at all between
%% UPI_list1 & UPI_list2, then we're OK
%% here.
io:format(user, "QQQ Oops_check_UPI_2_suffix=~w, ", [Oops_check_UPI_2_suffix]),
true;
true ->
exit({upi_2_suffix_error, UPI_2_suffix}) exit({upi_2_suffix_error, UPI_2_suffix})
end end
end end

View file

@ -251,35 +251,21 @@ convergence_demo_testfun(NumFLUs) ->
%% unique chains are disjoint. %% unique chains are disjoint.
true = machi_chain_manager1_test:all_reports_are_disjoint(Report), true = machi_chain_manager1_test:all_reports_are_disjoint(Report),
%% Given the report, we flip it around so that we observe the
%% sets of chain transitions relative to each FLU.
%% R_Chains's type is: list({RelativeFlu, list({Epoch, UPI, Repairing})})
%% For example:
%% [{a,[{3,[a],[b,c]},
%% {7,[a,b],[c]},
%% {14,[a,b,c],[]},
%% {83,[a],[]},
%% {164,[c],[a,b]},
%% {218,[a],[]},
%% {226,[a],[b,c]},
%% {228,[a],[b,c]},
%% ....
R_Chains = [machi_chain_manager1_test:extract_chains_relative_to_flu(
FLU, Report) || FLU <- All_list],
%% ?D(R_Chains),
R_Projs = [{FLU, [machi_chain_manager1_test:chain_to_projection(
FLU, Epoch, UPI, Repairing, All_list) ||
{Epoch, UPI, Repairing} <- E_Chains]} ||
{FLU, E_Chains} <- R_Chains],
%% For each chain transition experienced by a particular FLU, %% For each chain transition experienced by a particular FLU,
%% confirm that each state transition is OK. %% confirm that each state transition is OK.
PrivProjs = [{Name, begin
{ok, Ps9} = ?FLU_PC:get_all_projections(FLU,
private),
[P || P <- Ps9,
P#projection_v1.epoch_number /= 0]
end} || {Name, FLU} <- Namez],
try try
[{FLU, true} = {FLU, ?MGR:projection_transitions_are_sane(Psx, FLU)} || [{FLU, true} = {FLU, ?MGR:projection_transitions_are_sane_retrospective(Psx, FLU)} ||
{FLU, Psx} <- R_Projs], {FLU, Psx} <- PrivProjs],
io:format(user, "\nAll sanity checks pass, hooray!\n", []) io:format(user, "\nAll sanity checks pass, hooray!\n", [])
catch _Err:_What -> catch _Err:_What ->
io:format(user, "Report ~p\n", [Report]), io:format(user, "Report ~p\n", [Report]),
io:format(user, "PrivProjs ~p\n", [PrivProjs]),
exit({line, ?LINE, _Err, _What}) exit({line, ?LINE, _Err, _What})
end, end,
%% ?D(R_Projs), %% ?D(R_Projs),
@ -311,9 +297,10 @@ make_partition_list(All_list) ->
A <- All_list, B <- All_list, A /= B, A <- All_list, B <- All_list, A /= B,
C <- All_list, D <- All_list, C /= D, C <- All_list, D <- All_list, C /= D,
X /= A, X /= C, A /= C], X /= A, X /= C, A /= C],
%% _X_Ys1 ++ _X_Ys2. %% Concat = _X_Ys1 ++ _X_Ys2.
%% _X_Ys3. %% Concat = _X_Ys3.
_X_Ys1 ++ _X_Ys2 ++ _X_Ys3. Concat = _X_Ys1 ++ _X_Ys2 ++ _X_Ys3,
lists:usort([lists:sort(L) || L <- Concat]).
%% [ [{a,b},{b,d},{c,b}], %% [ [{a,b},{b,d},{c,b}],
%% [{a,b},{b,d},{c,b}, {a,b},{b,a},{a,c},{c,a},{a,d},{d,a}], %% [{a,b},{b,d},{c,b}, {a,b},{b,a},{a,c},{c,a},{a,d},{d,a}],

View file

@ -110,10 +110,10 @@ all_list_extra() ->
props=[{chmgr, b_chmgr}]}, "./data.pulse.b"} props=[{chmgr, b_chmgr}]}, "./data.pulse.b"}
, {#p_srvr{name=c, address="localhost", port=7402, , {#p_srvr{name=c, address="localhost", port=7402,
props=[{chmgr, c_chmgr}]}, "./data.pulse.c"} props=[{chmgr, c_chmgr}]}, "./data.pulse.c"}
, {#p_srvr{name=d, address="localhost", port=7403, %% , {#p_srvr{name=d, address="localhost", port=7403,
props=[{chmgr, d_chmgr}]}, "./data.pulse.d"} %% props=[{chmgr, d_chmgr}]}, "./data.pulse.d"}
, {#p_srvr{name=e, address="localhost", port=7404, %% , {#p_srvr{name=e, address="localhost", port=7404,
props=[{chmgr, e_chmgr}]}, "./data.pulse.e"} %% props=[{chmgr, e_chmgr}]}, "./data.pulse.e"}
]. ].
all_list() -> all_list() ->
@ -261,11 +261,21 @@ dump_state() ->
%% || {FLUName, _FLU} <- Namez] %% || {FLUName, _FLU} <- Namez]
%% || Epoch <- UniquePrivateEs], %% || Epoch <- UniquePrivateEs],
PrivProjs = [{Name, begin
{ok, Ps} = ?FLU_PC:get_all_projections(Proxy,
private),
[P || P <- Ps,
P#projection_v1.epoch_number /= 0]
end} || {Name, Proxy} <- ProxiesDict],
?QC_FMT(")", []), ?QC_FMT(")", []),
Diag1 = Diag2 = "skip_diags", Diag1 = Diag2 = "skip_diags",
{Report, lists:flatten([Diag1, Diag2])} {Report, PrivProjs, lists:flatten([Diag1, Diag2])}
catch XX:YY -> catch XX:YY ->
?QC_FMT("OUCH: ~p ~p @ ~p\n", [XX, YY, erlang:get_stacktrace()]) ?QC_FMT("OUCH: ~p ~p @ ~p\n", [XX, YY, erlang:get_stacktrace()]),
?QC_FMT("Exiting now to move to manual post-mortem....\n", []),
erlang:halt(0),
false
end. end.
prop_pulse() -> prop_pulse() ->
@ -296,8 +306,6 @@ prop_pulse() ->
{_H, _S, _R} = run_commands(?MODULE, Cmds) {_H, _S, _R} = run_commands(?MODULE, Cmds)
end, [{seed, Seed}, end, [{seed, Seed},
{strategy, unfair}]), {strategy, unfair}]),
ok = shutdown_hard(),
%% ?QC_FMT("S2 ~p\n", [S2]), %% ?QC_FMT("S2 ~p\n", [S2]),
case S2#state.dump_state of case S2#state.dump_state of
undefined -> undefined ->
@ -305,7 +313,7 @@ prop_pulse() ->
_ -> _ ->
ok ok
end, end,
{Report, Diag} = S2#state.dump_state, {Report, PrivProjs, Diag} = S2#state.dump_state,
%% Report is ordered by Epoch. For each private projection %% Report is ordered by Epoch. For each private projection
%% written during any given epoch, confirm that all chain %% written during any given epoch, confirm that all chain
@ -313,21 +321,12 @@ prop_pulse() ->
%% unique chains are disjoint. %% unique chains are disjoint.
AllDisjointP = ?MGRTEST:all_reports_are_disjoint(Report), AllDisjointP = ?MGRTEST:all_reports_are_disjoint(Report),
%% Given the report, we flip it around so that we observe the
%% sets of chain transitions relative to each FLU.
R_Chains = [?MGRTEST:extract_chains_relative_to_flu(FLU, Report) ||
FLU <- all_list()],
R_Projs = [{FLU, [?MGRTEST:chain_to_projection(
FLU, Epoch, UPI, Repairing, all_list()) ||
{Epoch, UPI, Repairing} <- E_Chains]} ||
{FLU, E_Chains} <- R_Chains],
%% For each chain transition experienced by a particular FLU, %% For each chain transition experienced by a particular FLU,
%% confirm that each state transition is OK. %% confirm that each state transition is OK.
Sane = Sane =
[{FLU,_SaneRes} = {FLU,?MGR:projection_transitions_are_sane_retrospective( [{FLU,_SaneRes} = {FLU,?MGR:projection_transitions_are_sane_retrospective(
Ps, FLU)} || Ps, FLU)} ||
{FLU, Ps} <- R_Projs], {FLU, Ps} <- PrivProjs],
SaneP = lists:all(fun({_FLU, SaneRes}) -> SaneRes == true end, Sane), SaneP = lists:all(fun({_FLU, SaneRes}) -> SaneRes == true end, Sane),
%% The final report item should say that all are agreed_membership. %% The final report item should say that all are agreed_membership.
@ -342,12 +341,14 @@ prop_pulse() ->
LastRepXs LastRepXs
end, end,
ok = shutdown_hard(),
?WHENFAIL( ?WHENFAIL(
begin begin
?QC_FMT("Cmds = ~p\n", [Cmds]), ?QC_FMT("Cmds = ~p\n", [Cmds]),
?QC_FMT("Res = ~p\n", [Res]), ?QC_FMT("Res = ~p\n", [Res]),
?QC_FMT("Diag = ~s\n", [Diag]), ?QC_FMT("Diag = ~s\n", [Diag]),
?QC_FMT("Report = ~p\n", [Report]), ?QC_FMT("Report = ~p\n", [Report]),
?QC_FMT("PrivProjs = ~p\n", [PrivProjs]),
?QC_FMT("Sane = ~p\n", [Sane]), ?QC_FMT("Sane = ~p\n", [Sane]),
?QC_FMT("SingleChainNoRepair failure =\n ~p\n", [SingleChainNoRepair]) ?QC_FMT("SingleChainNoRepair failure =\n ~p\n", [SingleChainNoRepair])
,erlang:halt(0) ,erlang:halt(0)

View file

@ -99,7 +99,7 @@ unanimous_report(Epoch, Namez) ->
{not_agreed, {UPI, Repairing}, Else2} {not_agreed, {UPI, Repairing}, Else2}
end; end;
_Else -> _Else ->
exit({UPI, not_unique, Epoch, _Else}) {not_agreed, {undefined, undefined}, Projs}
end end
end || UPI <- UniqueUPIs], end || UPI <- UniqueUPIs],
AgreedResUPI_Rs = [UPI++Repairing || AgreedResUPI_Rs = [UPI++Repairing ||
@ -128,7 +128,7 @@ chain_to_projection(MyName, Epoch, UPI_list, Repairing_list, All_list) ->
FLU <- All_list]), FLU <- All_list]),
machi_projection:new(Epoch, MyName, MemberDict, machi_projection:new(Epoch, MyName, MemberDict,
All_list -- (UPI_list ++ Repairing_list), All_list -- (UPI_list ++ Repairing_list),
UPI_list, Repairing_list, []). UPI_list, Repairing_list, [{artificial_by, ?MODULE}]).
-ifndef(PULSE). -ifndef(PULSE).