WIP: Refactoring and prototyping goop, broken test
This commit is contained in:
parent
8820a71152
commit
9cf77f4406
3 changed files with 203 additions and 54 deletions
|
@ -2,7 +2,7 @@
|
||||||
%%
|
%%
|
||||||
%% Machi: a small village of replicated files
|
%% Machi: a small village of replicated files
|
||||||
%%
|
%%
|
||||||
%% Copyright (c) 2014 Basho Technologies, Inc. All Rights Reserved.
|
%% Copyright (c) 2014-2015 Basho Technologies, Inc. All Rights Reserved.
|
||||||
%%
|
%%
|
||||||
%% This file is provided to you under the Apache License,
|
%% This file is provided to you under the Apache License,
|
||||||
%% Version 2.0 (the "License"); you may not use this file
|
%% Version 2.0 (the "License"); you may not use this file
|
||||||
|
@ -262,6 +262,9 @@ catch _Err:_What ->
|
||||||
exit({line, ?LINE, _Err, _What})
|
exit({line, ?LINE, _Err, _What})
|
||||||
end,
|
end,
|
||||||
io:format(user, "Yay!\n", []),
|
io:format(user, "Yay!\n", []),
|
||||||
|
ReportXXX = machi_chain_manager1_test:unanimous_report(Namez),
|
||||||
|
true = machi_chain_manager1_test:all_reports_are_disjoint(ReportXXX),
|
||||||
|
io:format(user, "\nLast Reports: ~p\n", [lists:nthtail(length(ReportXXX)-8,ReportXXX)]),
|
||||||
timer:sleep(1250),
|
timer:sleep(1250),
|
||||||
ok
|
ok
|
||||||
end || {Partition, Count} <- PartitionCounts
|
end || {Partition, Count} <- PartitionCounts
|
||||||
|
@ -287,6 +290,7 @@ io:format(user, "Yay!\n", []),
|
||||||
%% members appear in only one unique chain, i.e., the sets of
|
%% members appear in only one unique chain, i.e., the sets of
|
||||||
%% 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),
|
||||||
|
io:format(user, "\nLast Reports: ~p\n", [lists:nthtail(length(Report)-8,Report)]),
|
||||||
|
|
||||||
%% 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.
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
%%
|
%%
|
||||||
%% Machi: a small village of replicated files
|
%% Machi: a small village of replicated files
|
||||||
%%
|
%%
|
||||||
%% Copyright (c) 2014 Basho Technologies, Inc. All Rights Reserved.
|
%% Copyright (c) 2014-2015 Basho Technologies, Inc. All Rights Reserved.
|
||||||
%%
|
%%
|
||||||
%% This file is provided to you under the Apache License,
|
%% This file is provided to you under the Apache License,
|
||||||
%% Version 2.0 (the "License"); you may not use this file
|
%% Version 2.0 (the "License"); you may not use this file
|
||||||
|
@ -82,7 +82,8 @@ command(S) ->
|
||||||
{ 1, {call, ?MODULE, change_partitions,
|
{ 1, {call, ?MODULE, change_partitions,
|
||||||
[gen_old_threshold(), gen_no_partition_threshold()]}},
|
[gen_old_threshold(), gen_no_partition_threshold()]}},
|
||||||
{50, {call, ?MODULE, do_ticks,
|
{50, {call, ?MODULE, do_ticks,
|
||||||
[choose(5, 200), S#state.pids,
|
%% [choose(5, 200), S#state.pids,
|
||||||
|
[choose(5, 10), S#state.pids,
|
||||||
gen_old_threshold(), gen_no_partition_threshold()]}}
|
gen_old_threshold(), gen_no_partition_threshold()]}}
|
||||||
]).
|
]).
|
||||||
|
|
||||||
|
@ -225,32 +226,31 @@ dump_state() ->
|
||||||
%% [io_lib:format("~p ~p ~p: ~w\n", [FLUName, Type, P#projection_v1.epoch_number, machi_projection:make_summary(P)]) || P <- Ps]
|
%% [io_lib:format("~p ~p ~p: ~w\n", [FLUName, Type, P#projection_v1.epoch_number, machi_projection:make_summary(P)]) || P <- Ps]
|
||||||
%% end || {FLUName, Proxy} <- orddict:to_list(ProxiesDict),
|
%% end || {FLUName, Proxy} <- orddict:to_list(ProxiesDict),
|
||||||
%% Type <- [public] ],
|
%% Type <- [public] ],
|
||||||
|
%% P_lists0 = [{FLUName, Type,
|
||||||
UniquePrivateEs =
|
%% element(2,?FLU_PC:get_all_projections(Proxy, Type))} ||
|
||||||
lists:usort(lists:flatten(
|
%% {FLUName, Proxy} <- orddict:to_list(ProxiesDict),
|
||||||
[element(2,?FLU_PC:list_all_projections(Proxy,private)) ||
|
%% Type <- [public,private]],
|
||||||
{_FLUName, Proxy} <- orddict:to_list(ProxiesDict)])),
|
%% P_lists = [{FLUName, Type, P} || {FLUName, Type, Ps} <- P_lists0,
|
||||||
P_lists0 = [{FLUName, Type,
|
%% P <- Ps],
|
||||||
element(2,?FLU_PC:get_all_projections(Proxy, Type))} ||
|
%% AllDict = lists:foldl(fun({FLU, Type, P}, D) ->
|
||||||
{FLUName, Proxy} <- orddict:to_list(ProxiesDict),
|
%% K = {FLU, Type, P#projection_v1.epoch_number},
|
||||||
Type <- [public,private]],
|
%% dict:store(K, P, D)
|
||||||
P_lists = [{FLUName, Type, P} || {FLUName, Type, Ps} <- P_lists0,
|
%% end, dict:new(), lists:flatten(P_lists)),
|
||||||
P <- Ps],
|
%% DumbFinderBackward =
|
||||||
AllDict = lists:foldl(fun({FLU, Type, P}, D) ->
|
%% fun(FLUName) ->
|
||||||
K = {FLU, Type, P#projection_v1.epoch_number},
|
%% fun(E, error_unwritten) ->
|
||||||
dict:store(K, P, D)
|
%% case dict:find({FLUName, private, E}, AllDict) of
|
||||||
end, dict:new(), lists:flatten(P_lists)),
|
%% {ok, T} -> T;
|
||||||
DumbFinderBackward =
|
%% error -> error_unwritten
|
||||||
fun(FLUName) ->
|
%% end;
|
||||||
fun(E, error_unwritten) ->
|
%% (_E, Acc) ->
|
||||||
case dict:find({FLUName, private, E}, AllDict) of
|
%% Acc
|
||||||
{ok, T} -> T;
|
%% end
|
||||||
error -> error_unwritten
|
%% end,
|
||||||
end;
|
%% UniquePrivateEs =
|
||||||
(_E, Acc) ->
|
%% lists:usort(lists:flatten(
|
||||||
Acc
|
%% [element(2,?FLU_PC:list_all_projections(Proxy,private)) ||
|
||||||
end
|
%% {_FLUName, Proxy} <- orddict:to_list(ProxiesDict)])),
|
||||||
end,
|
|
||||||
%% Diag2 = [[
|
%% Diag2 = [[
|
||||||
%% io_lib:format("~p private: ~w\n",
|
%% io_lib:format("~p private: ~w\n",
|
||||||
%% [FLUName,
|
%% [FLUName,
|
||||||
|
@ -295,7 +295,6 @@ prop_pulse() ->
|
||||||
LastTriggerTicks = {set,{var,99999997},
|
LastTriggerTicks = {set,{var,99999997},
|
||||||
{call, ?MODULE, do_ticks, [123, undefined, no, no]}},
|
{call, ?MODULE, do_ticks, [123, undefined, no, no]}},
|
||||||
Cmds1 = lists:duplicate(2, LastTriggerTicks),
|
Cmds1 = lists:duplicate(2, LastTriggerTicks),
|
||||||
%% Cmds1 = lists:duplicate(length(all_list())*2, LastTriggerTicks),
|
|
||||||
Cmds = Cmds0 ++
|
Cmds = Cmds0 ++
|
||||||
Stabilize1 ++
|
Stabilize1 ++
|
||||||
Cmds1 ++
|
Cmds1 ++
|
||||||
|
|
|
@ -45,36 +45,47 @@
|
||||||
-include_lib("eunit/include/eunit.hrl").
|
-include_lib("eunit/include/eunit.hrl").
|
||||||
-compile(export_all).
|
-compile(export_all).
|
||||||
|
|
||||||
|
%% @doc Create a summary report of all of the *private* projections of
|
||||||
|
%% each of the FLUs in the chain, and create a summary for each
|
||||||
|
%% epoch number.
|
||||||
|
%%
|
||||||
|
%% Report format: list({EpochNumber::non_neg_integer(), Report::rpt()})
|
||||||
|
%% rpt(): {ok_disjoint | bummer_NOT_DISJOINT, agree_list()}
|
||||||
|
%% agree_list(): list(agree())
|
||||||
|
%% agree(): {agreed_membership, UPIandRepairing()} |
|
||||||
|
%% {not_agreed, ......TODO LEFT OFF HERE
|
||||||
|
%%
|
||||||
%% Example:
|
%% Example:
|
||||||
%% [{1,{ok_disjoint,[{agreed_membership,{[a],[b,c]}}]}},
|
%% TODO LEFT OFF HERE
|
||||||
%% {3,{ok_disjoint,[{agreed_membership,{[a],[b,c]}}]}},
|
|
||||||
%% {8,
|
|
||||||
%% {ok_disjoint,[{not_agreed,{[a],[b,c]},
|
|
||||||
%% [{b,not_in_this_epoch},
|
|
||||||
%% <<65,159,66,113,232,15,156,244,197,
|
|
||||||
%% 210,39,82,229,84,192,19,27,45,161,38>>]}]}},
|
|
||||||
%% {10,{ok_disjoint,[{agreed_membership,{[c],[]}}]}},
|
|
||||||
%% ...]
|
|
||||||
|
|
||||||
unanimous_report(Namez) ->
|
unanimous_report(Namez) ->
|
||||||
UniquePrivateEs =
|
UniquePrivateEs =
|
||||||
lists:usort(lists:flatten(
|
lists:usort(lists:flatten(
|
||||||
[element(2, ?FLU_PC:list_all_projections(FLU, private)) ||
|
[element(2, ?FLU_PC:list_all_projections(FLU, private)) ||
|
||||||
{_FLUName, FLU} <- Namez])),
|
{_FLUName, FLU} <- Namez])),
|
||||||
[unanimous_report(Epoch, Namez) || Epoch <- UniquePrivateEs,
|
[{Epoch, unanimous_report(Epoch, Namez)} || Epoch <- UniquePrivateEs,
|
||||||
Epoch /= 0].
|
Epoch /= 0].
|
||||||
|
|
||||||
unanimous_report(Epoch, Namez) ->
|
unanimous_report(Epoch, Namez) ->
|
||||||
Projs = [{FLUName,
|
FLU_Projs = [{FLUName,
|
||||||
case ?FLU_PC:read_projection(FLU, private, Epoch) of
|
case ?FLU_PC:read_projection(FLU, private, Epoch) of
|
||||||
{ok, T} ->
|
{ok, T} ->
|
||||||
machi_chain_manager1:inner_projection_or_self(T);
|
machi_chain_manager1:inner_projection_or_self(T);
|
||||||
_Else ->
|
_Else ->
|
||||||
{FLUName, not_in_this_epoch}
|
not_in_this_epoch
|
||||||
end} || {FLUName, FLU} <- Namez],
|
end} || {FLUName, FLU} <- Namez],
|
||||||
|
unanimous_report2(Epoch, FLU_Projs).
|
||||||
|
|
||||||
|
unanimous_report2(Epoch, FLU_Projs) ->
|
||||||
|
ProjsSumms = [{FLU, if is_tuple(P) ->
|
||||||
|
Summ = machi_projection:make_summary(P),
|
||||||
|
lists:flatten(io_lib:format("~w", [Summ]));
|
||||||
|
is_atom(P) ->
|
||||||
|
P
|
||||||
|
end} || {FLU, P} <- FLU_Projs],
|
||||||
UPI_R_Sums = [{Proj#projection_v1.upi, Proj#projection_v1.repairing,
|
UPI_R_Sums = [{Proj#projection_v1.upi, Proj#projection_v1.repairing,
|
||||||
Proj#projection_v1.epoch_csum} ||
|
Proj#projection_v1.epoch_csum} ||
|
||||||
{_FLUname, Proj} <- Projs,
|
{_FLUname, Proj} <- FLU_Projs,
|
||||||
is_record(Proj, projection_v1)],
|
is_record(Proj, projection_v1)],
|
||||||
UniqueUPIs = lists:usort([UPI || {UPI, _Repairing, _CSum} <- UPI_R_Sums]),
|
UniqueUPIs = lists:usort([UPI || {UPI, _Repairing, _CSum} <- UPI_R_Sums]),
|
||||||
Res =
|
Res =
|
||||||
|
@ -86,7 +97,7 @@ unanimous_report(Epoch, Namez) ->
|
||||||
%% that all FLUs are in agreement.
|
%% that all FLUs are in agreement.
|
||||||
{UPI, Repairing, _CSum} =
|
{UPI, Repairing, _CSum} =
|
||||||
lists:keyfind(UPI, 1, UPI_R_Sums),
|
lists:keyfind(UPI, 1, UPI_R_Sums),
|
||||||
Tmp = [{FLU, case proplists:get_value(FLU, Projs) of
|
Tmp = [{FLU, case proplists:get_value(FLU, FLU_Projs) of
|
||||||
P when is_record(P, projection_v1) ->
|
P when is_record(P, projection_v1) ->
|
||||||
P#projection_v1.epoch_csum;
|
P#projection_v1.epoch_csum;
|
||||||
Else ->
|
Else ->
|
||||||
|
@ -95,11 +106,11 @@ unanimous_report(Epoch, Namez) ->
|
||||||
case lists:usort([CSum || {_FLU, CSum} <- Tmp]) of
|
case lists:usort([CSum || {_FLU, CSum} <- Tmp]) of
|
||||||
[_] ->
|
[_] ->
|
||||||
{agreed_membership, {UPI, Repairing}};
|
{agreed_membership, {UPI, Repairing}};
|
||||||
Else2 ->
|
_Else2 ->
|
||||||
{not_agreed, {UPI, Repairing}, Else2}
|
{not_agreed, ProjsSumms}
|
||||||
end;
|
end;
|
||||||
_Else ->
|
_Else ->
|
||||||
{not_agreed, {undefined, undefined}, Projs}
|
{not_agreed, [checksum_disagreement|ProjsSumms]}
|
||||||
end
|
end
|
||||||
end || UPI <- UniqueUPIs],
|
end || UPI <- UniqueUPIs],
|
||||||
AgreedResUPI_Rs = [UPI++Repairing ||
|
AgreedResUPI_Rs = [UPI++Repairing ||
|
||||||
|
@ -111,7 +122,7 @@ unanimous_report(Epoch, Namez) ->
|
||||||
false ->
|
false ->
|
||||||
bummer_NOT_DISJOINT
|
bummer_NOT_DISJOINT
|
||||||
end,
|
end,
|
||||||
{Epoch, {Tag, Res}}.
|
{Tag, Res}.
|
||||||
|
|
||||||
all_reports_are_disjoint(Report) ->
|
all_reports_are_disjoint(Report) ->
|
||||||
[] == [X || {_Epoch, Tuple}=X <- Report,
|
[] == [X || {_Epoch, Tuple}=X <- Report,
|
||||||
|
@ -130,6 +141,110 @@ chain_to_projection(MyName, Epoch, UPI_list, Repairing_list, All_list) ->
|
||||||
All_list -- (UPI_list ++ Repairing_list),
|
All_list -- (UPI_list ++ Repairing_list),
|
||||||
UPI_list, Repairing_list, [{artificial_by, ?MODULE}]).
|
UPI_list, Repairing_list, [{artificial_by, ?MODULE}]).
|
||||||
|
|
||||||
|
simple_chain_state_transition_is_sane(UPI1, Repair1, UPI2) ->
|
||||||
|
{KeepsDels, Orders} = mk(UPI1, Repair1, UPI2),
|
||||||
|
NumKeeps = length([x || keep <- KeepsDels]),
|
||||||
|
NumOrders = length(Orders),
|
||||||
|
false == lists:member(error, Orders)
|
||||||
|
andalso Orders == lists:sort(Orders)
|
||||||
|
andalso length(UPI2) == NumKeeps + NumOrders.
|
||||||
|
|
||||||
|
mk(UPI1, Repair1, UPI2) ->
|
||||||
|
mk(UPI1, Repair1, UPI2, []).
|
||||||
|
|
||||||
|
mk([X|UPI1], Repair1, [X|UPI2], Acc) ->
|
||||||
|
mk(UPI1, Repair1, UPI2, [keep|Acc]);
|
||||||
|
mk([X|UPI1], Repair1, UPI2, Acc) ->
|
||||||
|
mk(UPI1, Repair1, UPI2 -- [X], [del|Acc]);
|
||||||
|
mk([], [], [], Acc) ->
|
||||||
|
{lists:reverse(Acc), []};
|
||||||
|
mk([], Repair1, UPI2, Acc) ->
|
||||||
|
{lists:reverse(Acc), mk_order(UPI2, Repair1)}.
|
||||||
|
|
||||||
|
mk_order(UPI2, Repair1) ->
|
||||||
|
R1 = length(Repair1),
|
||||||
|
Repair1_order_d = orddict:from_list(lists:zip(Repair1, lists:seq(1, R1))),
|
||||||
|
UPI2_order = [case orddict:find(X, Repair1_order_d) of
|
||||||
|
{ok, Idx} -> Idx;
|
||||||
|
error -> error
|
||||||
|
end || X <- UPI2],
|
||||||
|
UPI2_order.
|
||||||
|
|
||||||
|
perms([]) -> [[]];
|
||||||
|
perms(L) -> [[H|T] || H <- L, T <- perms(L--[H])].
|
||||||
|
|
||||||
|
combinations(L) ->
|
||||||
|
lists:usort(perms(L) ++ lists:append([ combinations(L -- [X]) || X <- L])).
|
||||||
|
|
||||||
|
ordered_combinations(Master) ->
|
||||||
|
[L || L <- combinations(Master), is_ordered(L, Master)].
|
||||||
|
|
||||||
|
is_ordered(L, Reference) ->
|
||||||
|
L_order = mk_order(L, Reference),
|
||||||
|
lists:all(fun(X) -> is_integer(X) end, L_order) andalso
|
||||||
|
L_order == lists:sort(L_order).
|
||||||
|
|
||||||
|
mk_order_is_sane_test_() ->
|
||||||
|
{timeout, 300, fun() -> mk_order_is_sane_test2() end}.
|
||||||
|
|
||||||
|
mk_order_is_sane_test2() ->
|
||||||
|
%% All: A list of all FLUS for a particular test
|
||||||
|
%% UPI1: some combination of All that represents UPI1
|
||||||
|
%% Repair1: Some combination of (All -- UP1) that represents Repairing1
|
||||||
|
%% ... then we test check_sane_func_with_upi_and_repair() with all
|
||||||
|
%% possible UPI1 and Repair1.
|
||||||
|
[true = check_sane_func_with_upi_and_repair(UPI1, Repair1) ||
|
||||||
|
%% The five elements below runs on my MacBook Pro in about 4.8 seconds
|
||||||
|
%% All <- [ [a], [a,b], [a,b,c], [a,b,c,d], [a,b,c,d,e] ],
|
||||||
|
All <- [ [a], [a,b], [a,b,c], [a,b,c,d] ],
|
||||||
|
UPI1 <- combinations(All),
|
||||||
|
Repair1 <- combinations(All -- UPI1)].
|
||||||
|
|
||||||
|
%% Given a UPI1 and Repair1 list, we calculate all possible good UPI2
|
||||||
|
%% lists. For all good {UPI1, Repair1} -> UPI2 transitions, then the
|
||||||
|
%% simple_chain_state_transition_is_sane() function must be true. For
|
||||||
|
%% all other UPI2 transitions, simple_chain_state_transition_is_sane()
|
||||||
|
%% must be false.
|
||||||
|
%%
|
||||||
|
%% We include adding an extra possible participant, 'bogus', to the
|
||||||
|
%% list of all possible UPI2 transitions, just to demonstrate that
|
||||||
|
%% adding an extra element/participant/thingie is never sane.
|
||||||
|
|
||||||
|
check_sane_func_with_upi_and_repair([], []) ->
|
||||||
|
true;
|
||||||
|
check_sane_func_with_upi_and_repair(UPI1, Repair1) ->
|
||||||
|
Good_UPI2s = [ X ++ Y || X <- ordered_combinations(UPI1),
|
||||||
|
Y <- ordered_combinations(Repair1)],
|
||||||
|
All_UPI2s = combinations(lists:usort(UPI1 ++ Repair1) ++ [bogus]),
|
||||||
|
|
||||||
|
[true = simple_chain_state_transition_is_sane(UPI1, Repair1, UPI2) ||
|
||||||
|
UPI2 <- Good_UPI2s],
|
||||||
|
[false = simple_chain_state_transition_is_sane(UPI1, Repair1, UPI2) ||
|
||||||
|
UPI2 <- (All_UPI2s -- Good_UPI2s)],
|
||||||
|
|
||||||
|
All = UPI1 ++ Repair1,
|
||||||
|
Me = hd(All),
|
||||||
|
MembersDict = orddict:from_list([{X, #p_srvr{name=X}} || X <- All]),
|
||||||
|
[true = begin
|
||||||
|
Down1 = All -- (UPI1 ++ Repair1),
|
||||||
|
Repair2 = [],
|
||||||
|
Down2 = All -- (UPI2 ++ Repair2),
|
||||||
|
P1 = machi_projection:new(1, Me, MembersDict,
|
||||||
|
Down1, UPI1, Repair1, []),
|
||||||
|
P2 = machi_projection:new(2, Me, MembersDict,
|
||||||
|
Down2, UPI2, Repair2, []),
|
||||||
|
QQ = machi_chain_manager1:projection_transition_is_sane(P1, P2, Me,
|
||||||
|
false),
|
||||||
|
if QQ /= true ->
|
||||||
|
io:format(user, "QQ ~p\n", [QQ]);
|
||||||
|
true ->
|
||||||
|
ok
|
||||||
|
end,
|
||||||
|
QQ
|
||||||
|
end || UPI2 <- Good_UPI2s],
|
||||||
|
|
||||||
|
true.
|
||||||
|
|
||||||
-ifndef(PULSE).
|
-ifndef(PULSE).
|
||||||
|
|
||||||
smoke0_test() ->
|
smoke0_test() ->
|
||||||
|
@ -250,5 +365,36 @@ nonunanimous_setup_and_fix_test() ->
|
||||||
ok = machi_partition_simulator:stop()
|
ok = machi_partition_simulator:stop()
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
foo_TODO_UNFINISHED_KEEP_PERHAPS_unanimous_report_test() ->
|
||||||
|
TcpPort = 63877,
|
||||||
|
FluInfo = [{a,TcpPort+0,"./data.a"}, {b,TcpPort+1,"./data.b"}],
|
||||||
|
P_s = [#p_srvr{name=Name, address="localhost", port=Port} ||
|
||||||
|
{Name,Port,_Dir} <- FluInfo],
|
||||||
|
MembersDict = machi_projection:make_members_dict(P_s),
|
||||||
|
|
||||||
|
E5 = 5,
|
||||||
|
UPI5 = [a,b],
|
||||||
|
Rep5 = [],
|
||||||
|
P5 = machi_projection:new(E5, a, MembersDict, [], UPI5, Rep5, []),
|
||||||
|
{ok_disjoint, [{agreed_membership, {UPI5, Rep5}}]} =
|
||||||
|
unanimous_report2(E5, [{a, P5}, {b, P5}]),
|
||||||
|
{ok_disjoint, [{not_agreed, _}]} =
|
||||||
|
unanimous_report2(E5, [{a, not_in_this_epoch}, {b, P5}]),
|
||||||
|
{ok_disjoint, [{not_agreed, _}]} =
|
||||||
|
unanimous_report2(E5, [{a, P5}, {b, not_in_this_epoch}]),
|
||||||
|
|
||||||
|
P5_other_csum = machi_projection:update_checksum(
|
||||||
|
P5#projection_v1{author_server=b}),
|
||||||
|
{ok_disjoint, [{not_agreed, _}]} =
|
||||||
|
unanimous_report2(E5, [{a, P5}, {b, P5_other_csum}]),
|
||||||
|
|
||||||
|
UPI5_b = [a],
|
||||||
|
Rep5_b = [b],
|
||||||
|
P5_b = machi_projection:new(E5, b, MembersDict, [], UPI5_b, Rep5_b, []),
|
||||||
|
XX =
|
||||||
|
unanimous_report2(E5, [{a, P5}, {b, P5_b}]),
|
||||||
|
|
||||||
|
io:format(user, "\nXX ~p\n", [XX]).
|
||||||
|
|
||||||
-endif. % !PULSE
|
-endif. % !PULSE
|
||||||
-endif. % TEST
|
-endif. % TEST
|
||||||
|
|
Loading…
Reference in a new issue