Clean up cruft, add more comments

This commit is contained in:
Scott Lystig Fritchie 2014-11-05 15:00:32 +09:00
parent 32cfcccf34
commit 30f5a84cea

View file

@ -33,6 +33,9 @@
-define(D(X), io:format(user, "~s ~p\n", [??X, X])). -define(D(X), io:format(user, "~s ~p\n", [??X, X])).
-define(Dw(X), io:format(user, "~s ~w\n", [??X, X])). -define(Dw(X), io:format(user, "~s ~w\n", [??X, X])).
%% Keep a history of our flowchart execution in the process dictionary.
-define(REACT(T), put(react, [T|get(react)])).
%% API %% API
-export([start_link/3, stop/1, ping/1, -export([start_link/3, stop/1, ping/1,
calculate_projection_internal_old/1]). calculate_projection_internal_old/1]).
@ -92,7 +95,8 @@ test_calc_proposed_projection(Pid) ->
gen_server:cast(Pid, {test_calc_proposed_projection}). gen_server:cast(Pid, {test_calc_proposed_projection}).
test_read_latest_public_projection(Pid, ReadRepairP) -> test_read_latest_public_projection(Pid, ReadRepairP) ->
gen_server:call(Pid, {test_read_latest_public_projection, ReadRepairP}, infinity). gen_server:call(Pid, {test_read_latest_public_projection, ReadRepairP},
infinity).
test_react_to_env(Pid) -> test_react_to_env(Pid) ->
gen_server:call(Pid, {test_react_to_env}, infinity). gen_server:call(Pid, {test_react_to_env}, infinity).
@ -133,7 +137,8 @@ init({MyName, All_list, MyFLUPid}) ->
handle_call(_Call, _From, #ch_mgr{init_finished=false} = S) -> handle_call(_Call, _From, #ch_mgr{init_finished=false} = S) ->
{reply, not_initialized, S}; {reply, not_initialized, S};
handle_call({calculate_projection_internal_old}, _From, #ch_mgr{myflu=MyFLU}=S) -> handle_call({calculate_projection_internal_old}, _From,
#ch_mgr{myflu=MyFLU}=S) ->
RelativeToServer = MyFLU, RelativeToServer = MyFLU,
{Reply, S2} = calc_projection(S, RelativeToServer, [{author_proc, call}]), {Reply, S2} = calc_projection(S, RelativeToServer, [{author_proc, call}]),
{reply, Reply, S2}; {reply, Reply, S2};
@ -148,7 +153,8 @@ handle_call({ping}, _From, S) ->
{reply, pong, S}; {reply, pong, S};
handle_call({stop}, _From, S) -> handle_call({stop}, _From, S) ->
{stop, normal, ok, S}; {stop, normal, ok, S};
handle_call({test_calc_projection, KeepRunenvP}, _From, #ch_mgr{myflu=MyFLU}=S) -> handle_call({test_calc_projection, KeepRunenvP}, _From,
#ch_mgr{myflu=MyFLU}=S) ->
RelativeToServer = MyFLU, RelativeToServer = MyFLU,
{P, S2} = calc_projection(S, RelativeToServer, [{author_proc, call}]), {P, S2} = calc_projection(S, RelativeToServer, [{author_proc, call}]),
{reply, {ok, P}, if KeepRunenvP -> S2; {reply, {ok, P}, if KeepRunenvP -> S2;
@ -253,7 +259,7 @@ cl_write_public_proj_local(Epoch, Proj, SkipLocalWriteErrorP,
end. end.
cl_write_public_proj_remote(FLUs, Partitions, Epoch, Proj, S) -> cl_write_public_proj_remote(FLUs, Partitions, Epoch, Proj, S) ->
%% We're going to be very cavalier about this write because we'll rely %% We're going to be very care-free about this write because we'll rely
%% on the read side to do any read repair. %% on the read side to do any read repair.
DoIt = fun(X) -> machi_flu0:proj_write(X, Epoch, public, Proj) end, DoIt = fun(X) -> machi_flu0:proj_write(X, Epoch, public, Proj) end,
Rs = [{FLU, perhaps_call_t(S, Partitions, FLU, fun() -> DoIt(FLU) end)} || Rs = [{FLU, perhaps_call_t(S, Partitions, FLU, fun() -> DoIt(FLU) end)} ||
@ -306,17 +312,6 @@ cl_read_latest_public_projection(#ch_mgr{proj=CurrentProj}=S) ->
{UnanimousTag, BestProj, Extra2, S2} {UnanimousTag, BestProj, Extra2, S2}
end. end.
%% 1. Do the results contain a projection?
%% perhaps figure that in cl_read_latest_public_projection()?
%% 2. Were there any error_unwritten?
%% 3. Repair the unwritten FLUs.
%% 4. Nothing to do with timeouts, right? They're
%% hopeless for the moment, need to wait.
%%
%% For read-repair, just choose the best and then brute-
%% force write, don't care about write status, then
%% repeat do_cl_read_latest_public_projection() ??
do_read_repair(FLUsRs, _Extra, #ch_mgr{proj=CurrentProj} = S) -> do_read_repair(FLUsRs, _Extra, #ch_mgr{proj=CurrentProj} = S) ->
Unwrittens = [x || {_FLU, error_unwritten} <- FLUsRs], Unwrittens = [x || {_FLU, error_unwritten} <- FLUsRs],
Ps = [Proj || {_FLU, Proj} <- FLUsRs, is_record(Proj, projection)], Ps = [Proj || {_FLU, Proj} <- FLUsRs, is_record(Proj, projection)],
@ -379,7 +374,7 @@ calc_projection(#ch_mgr{proj=LastProj, runenv=RunEnv} = S, RelativeToServer,
RelativeToServer, Dbg, S). RelativeToServer, Dbg, S).
%% OldThreshold: Percent chance of using the old/previous network partition list %% OldThreshold: Percent chance of using the old/previous network partition list
%% NoPartitionThreshold: If the network partition changes, what are the odds %% NoPartitionThreshold: If the network partition changes, what percent chance
%% that there are no partitions at all? %% that there are no partitions at all?
calc_projection(_OldThreshold, _NoPartitionThreshold, LastProj, calc_projection(_OldThreshold, _NoPartitionThreshold, LastProj,
@ -446,7 +441,6 @@ calc_projection(_OldThreshold, _NoPartitionThreshold, LastProj,
P = make_projection(OldEpochNum + 1, P = make_projection(OldEpochNum + 1,
MyName, All_list, Down, NewUPI, NewRepairing, MyName, All_list, Down, NewUPI, NewRepairing,
Dbg ++ [{nodes_up, Up}]), Dbg ++ [{nodes_up, Up}]),
if P#projection.upi == [] -> io:format(user, "old: ~w\n", [make_projection_summary(LastProj)]), io:format(user, "new: ~w\n", [make_projection_summary(P)]), exit(zoozoo); true -> ok end,
{P, S#ch_mgr{runenv=RunEnv3}}. {P, S#ch_mgr{runenv=RunEnv3}}.
calc_up_nodes(#ch_mgr{name=MyName, proj=Proj, runenv=RunEnv1}=S) -> calc_up_nodes(#ch_mgr{name=MyName, proj=Proj, runenv=RunEnv1}=S) ->
@ -456,9 +450,9 @@ calc_up_nodes(#ch_mgr{name=MyName, proj=Proj, runenv=RunEnv1}=S) ->
{UpNodes, Partitions, S#ch_mgr{runenv=RunEnv2}}. {UpNodes, Partitions, S#ch_mgr{runenv=RunEnv2}}.
calc_up_nodes(MyName, AllMembers, RunEnv1) -> calc_up_nodes(MyName, AllMembers, RunEnv1) ->
%% Seed1 = proplists:get_value(seed, RunEnv1),
{Partitions2, Islands2} = machi_partition_simulator:get(AllMembers), {Partitions2, Islands2} = machi_partition_simulator:get(AllMembers),
catch put(react, [{partitions,Partitions2},{islands,Islands2}|get(react)]), catch ?REACT({partitions,Partitions2}),
catch ?REACT({islands,Islands2}),
UpNodes = lists:sort( UpNodes = lists:sort(
[Node || Node <- AllMembers, [Node || Node <- AllMembers,
not lists:member({MyName, Node}, Partitions2), not lists:member({MyName, Node}, Partitions2),
@ -474,11 +468,6 @@ replace(PropList, Items) ->
lists:keyreplace(Key, 1, Ps, {Key,Val}) lists:keyreplace(Key, 1, Ps, {Key,Val})
end, PropList, Items). end, PropList, Items).
-ifdef(TEST).
mps(P) ->
make_projection_summary(P).
-endif. % TEST
make_projection_summary(#projection{epoch_number=EpochNum, make_projection_summary(#projection{epoch_number=EpochNum,
all_members=_All_list, all_members=_All_list,
down=Down_list, down=Down_list,
@ -522,22 +511,24 @@ do_react_to_env(S) ->
react_to_env_A10(S). react_to_env_A10(S).
react_to_env_A10(S) -> react_to_env_A10(S) ->
put(react, [a10|get(react)]), ?REACT(a10),
react_to_env_A20(0, S). react_to_env_A20(0, S).
react_to_env_A20(Retries, #ch_mgr{myflu=MyFLU} = S) -> react_to_env_A20(Retries, #ch_mgr{myflu=MyFLU} = S) ->
put(react, [a20|get(react)]), ?REACT(a20),
%% io:format(user, "current: ~w\n", [make_projection_summary(S#ch_mgr.proj)]),
RelativeToServer = MyFLU, RelativeToServer = MyFLU,
{P_newprop, S2} = calc_projection(S, RelativeToServer, {P_newprop, S2} = calc_projection(S, RelativeToServer,
[{author_proc, react}]), [{author_proc, react}]),
%% if P_newprop#projection.upi == [] -> io:format(user, "current: ~w\n", [make_projection_summary(S#ch_mgr.proj)]),io:format(user, "proposed: ~w\n", [make_projection_summary(P_newprop)]), timer:sleep(100); true -> ok end,
react_to_env_A30(Retries, P_newprop, S2). react_to_env_A30(Retries, P_newprop, S2).
react_to_env_A30(Retries, P_newprop, S) -> react_to_env_A30(Retries, P_newprop, S) ->
put(react, [a30|get(react)]), ?REACT(a30),
{UnanimousTag, P_latest, ReadExtra, S2} = {UnanimousTag, P_latest, ReadExtra, S2} =
do_cl_read_latest_public_projection(true, S), do_cl_read_latest_public_projection(true, S),
%% The UnanimousTag isn't quite sufficient for our needs. We need
%% to determine if *all* of the UPI+Repairing FLUs are members of
%% the unanimous server replies.
UnanimousFLUs = lists:sort(proplists:get_value(unanimous_flus, ReadExtra)), UnanimousFLUs = lists:sort(proplists:get_value(unanimous_flus, ReadExtra)),
UPI_Repairing_FLUs = lists:sort(P_latest#projection.upi ++ UPI_Repairing_FLUs = lists:sort(P_latest#projection.upi ++
P_latest#projection.repairing), P_latest#projection.repairing),
@ -545,35 +536,34 @@ react_to_env_A30(Retries, P_newprop, S) ->
LatestUnanimousP = LatestUnanimousP =
if UnanimousTag == unanimous if UnanimousTag == unanimous
andalso andalso
All_UPI_Repairing_were_unanimous -> put(react, [{a30,?LINE}|get(react)]),true; All_UPI_Repairing_were_unanimous ->
UnanimousTag == unanimous -> put(react, [{a30,?LINE,UPI_Repairing_FLUs, UnanimousFLUs}|get(react)]),false; ?REACT({a30,?LINE}),
UnanimousTag == not_unanimous -> put(react, [{a30,?LINE}|get(react)]),false; true;
true -> exit({badbad, UnanimousTag}) UnanimousTag == unanimous ->
?REACT({a30,?LINE,UPI_Repairing_FLUs,UnanimousFLUs}),
false;
UnanimousTag == not_unanimous ->
?REACT({a30,?LINE}),
false;
true ->
exit({badbad, UnanimousTag})
end, end,
react_to_env_A40(Retries, P_newprop, P_latest, react_to_env_A40(Retries, P_newprop, P_latest,
LatestUnanimousP, S2). LatestUnanimousP, S2).
react_to_env_A40(Retries, P_newprop, P_latest, LatestUnanimousP, react_to_env_A40(Retries, P_newprop, P_latest, LatestUnanimousP,
#ch_mgr{myflu=MyFLU, proj=P_current}=S) -> #ch_mgr{myflu=MyFLU, proj=P_current}=S) ->
put(react, [a40|get(react)]), ?REACT(a40),
[{Rank_newprop, _}] = rank_projections([P_newprop], P_current), [{Rank_newprop, _}] = rank_projections([P_newprop], P_current),
[{Rank_latest, _}] = rank_projections([P_latest], P_current), [{Rank_latest, _}] = rank_projections([P_latest], P_current),
LatestAuthorDownP = lists:member(P_latest#projection.author_server, LatestAuthorDownP = lists:member(P_latest#projection.author_server,
P_newprop#projection.down), P_newprop#projection.down),
if P_newprop#projection.epoch_number == 666
orelse P_latest#projection.epoch_number == 666 ->
io:format(user, "\nBUMMER\nLatest ~p\nNewprop ~p\nRunenv ~p\nTsns ~w", [make_projection_summary(P_newprop), make_projection_summary(P_latest), S#ch_mgr.runenv, lists:reverse(get(react))]),
exit(bummer);
true ->
ok
end,
if if
P_latest#projection.epoch_number > P_current#projection.epoch_number P_latest#projection.epoch_number > P_current#projection.epoch_number
orelse orelse
not LatestUnanimousP -> not LatestUnanimousP ->
put(react, [{a40, ?LINE, P_latest#projection.epoch_number > P_current#projection.epoch_number, not LatestUnanimousP}|get(react)]), ?REACT({a40, ?LINE,P_latest#projection.epoch_number > P_current#projection.epoch_number, not LatestUnanimousP}),
%% 1st clause: someone else has written a newer projection %% 1st clause: someone else has written a newer projection
%% 2nd clause: a network partition has healed, revealing a %% 2nd clause: a network partition has healed, revealing a
@ -584,7 +574,7 @@ react_to_env_A40(Retries, P_newprop, P_latest, LatestUnanimousP,
P_latest#projection.epoch_number < P_current#projection.epoch_number P_latest#projection.epoch_number < P_current#projection.epoch_number
orelse orelse
P_latest /= P_current -> P_latest /= P_current ->
put(react, [{a40, ?LINE}|get(react)]), ?REACT({a40, ?LINE}),
%% Both of these cases are rare. Elsewhere, the code %% Both of these cases are rare. Elsewhere, the code
%% assumes that the local FLU's projection store is always %% assumes that the local FLU's projection store is always
@ -609,7 +599,16 @@ react_to_env_A40(Retries, P_newprop, P_latest, LatestUnanimousP,
%% A40a (see flowchart) %% A40a (see flowchart)
Rank_newprop > Rank_latest -> Rank_newprop > Rank_latest ->
put(react, [{a40, ?LINE}|get(react)]), ?REACT({a40, ?LINE}),
%% TODO: There may be an "improvement" here. If we're the
%% highest-ranking FLU in the all_members list, then if we make a
%% projection where our UPI list is the same as P_latest's, and
%% our repairing list is the same as P_latest's, then it may not
%% be necessary to write our projection: it doesn't "improve"
%% anything UPI-wise or repairing-wise. But it isn't clear to me
%% if it's 100% correct to "improve" here and skip writing
%% P_newprop, yet.
react_to_env_C300(P_newprop, P_latest, S); react_to_env_C300(P_newprop, P_latest, S);
%% A40b (see flowchart) %% A40b (see flowchart)
@ -618,12 +617,13 @@ react_to_env_A40(Retries, P_newprop, P_latest, LatestUnanimousP,
(P_newprop#projection.upi /= P_latest#projection.upi (P_newprop#projection.upi /= P_latest#projection.upi
orelse orelse
P_newprop#projection.repairing /= P_latest#projection.repairing) -> P_newprop#projection.repairing /= P_latest#projection.repairing) ->
put(react, [{a40, ?LINE}|get(react)]), ?REACT({a40, ?LINE}),
react_to_env_C300(P_newprop, P_latest, S); react_to_env_C300(P_newprop, P_latest, S);
%% A40c (see flowchart) %% A40c (see flowchart)
LatestAuthorDownP -> LatestAuthorDownP ->
put(react, [{a40, ?LINE}|get(react)]), ?REACT({a40, ?LINE}),
%% TODO: I believe that membership in the %% TODO: I believe that membership in the
%% P_newprop#projection.down is not sufficient for long %% P_newprop#projection.down is not sufficient for long
@ -642,25 +642,25 @@ react_to_env_A40(Retries, P_newprop, P_latest, LatestUnanimousP,
%% * if we accept ring1's proj: two functioning chains %% * if we accept ring1's proj: two functioning chains
%% ([ring1,ring2] and [ring4,ring5] indepependently) %% ([ring1,ring2] and [ring4,ring5] indepependently)
%% but unstable: we're probably going to flap back & forth?! %% but unstable: we're probably going to flap back & forth?!
?D({{{{{yoyoyo_A40c}}}}}),
react_to_env_C300(P_newprop, P_latest, S); react_to_env_C300(P_newprop, P_latest, S);
true -> true ->
put(react, [{a40, ?LINE}|get(react)]), ?REACT({a40, ?LINE}),
{{no_change, P_latest#projection.epoch_number}, S} {{no_change, P_latest#projection.epoch_number}, S}
end. end.
react_to_env_B10(Retries, P_newprop, P_latest, LatestUnanimousP, react_to_env_B10(Retries, P_newprop, P_latest, LatestUnanimousP,
Rank_newprop, Rank_latest, #ch_mgr{name=MyName}=S) -> Rank_newprop, Rank_latest, #ch_mgr{name=MyName}=S) ->
put(react, [b10|get(react)]), ?REACT(b10),
if if
LatestUnanimousP -> LatestUnanimousP ->
put(react, [{b10, ?LINE}|get(react)]), ?REACT({b10, ?LINE}),
react_to_env_C100(P_newprop, P_latest, S); react_to_env_C100(P_newprop, P_latest, S);
Retries > 2 -> Retries > 2 ->
put(react, [{b10, ?LINE}|get(react)]), ?REACT({b10, ?LINE}),
%% The author of P_latest is too slow or crashed. %% The author of P_latest is too slow or crashed.
%% Let's try to write P_newprop and see what happens! %% Let's try to write P_newprop and see what happens!
@ -669,7 +669,7 @@ react_to_env_B10(Retries, P_newprop, P_latest, LatestUnanimousP,
Rank_latest >= Rank_newprop Rank_latest >= Rank_newprop
andalso andalso
P_latest#projection.author_server /= MyName -> P_latest#projection.author_server /= MyName ->
put(react, [{b10, ?LINE}|get(react)]), ?REACT({b10, ?LINE}),
%% Give the author of P_latest an opportunite to write a %% Give the author of P_latest an opportunite to write a
%% new projection in a new epoch to resolve this mixed %% new projection in a new epoch to resolve this mixed
@ -677,7 +677,7 @@ react_to_env_B10(Retries, P_newprop, P_latest, LatestUnanimousP,
react_to_env_C200(Retries, P_latest, S); react_to_env_C200(Retries, P_latest, S);
true -> true ->
put(react, [{b10, ?LINE}|get(react)]), ?REACT({b10, ?LINE}),
%% P_newprop is best, so let's write it. %% P_newprop is best, so let's write it.
react_to_env_C300(P_newprop, P_latest, S) react_to_env_C300(P_newprop, P_latest, S)
@ -685,9 +685,10 @@ react_to_env_B10(Retries, P_newprop, P_latest, LatestUnanimousP,
react_to_env_C100(P_newprop, P_latest, react_to_env_C100(P_newprop, P_latest,
#ch_mgr{myflu=MyFLU, proj=P_current}=S) -> #ch_mgr{myflu=MyFLU, proj=P_current}=S) ->
put(react, [c100|get(react)]), ?REACT(c100),
I_am_UPI_in_newprop_p = lists:member(MyFLU, P_newprop#projection.upi), I_am_UPI_in_newprop_p = lists:member(MyFLU, P_newprop#projection.upi),
I_am_Repairing_in_latest_p = lists:member(MyFLU, P_latest#projection.repairing), I_am_Repairing_in_latest_p = lists:member(MyFLU,
P_latest#projection.repairing),
ShortCircuit_p = ShortCircuit_p =
P_latest#projection.epoch_number > P_current#projection.epoch_number P_latest#projection.epoch_number > P_current#projection.epoch_number
andalso andalso
@ -698,26 +699,25 @@ react_to_env_C100(P_newprop, P_latest,
case {ShortCircuit_p, projection_transition_is_sane(P_current, P_latest, case {ShortCircuit_p, projection_transition_is_sane(P_current, P_latest,
MyFLU)} of MyFLU)} of
{true, _} -> {true, _} ->
?REACT({c100, repairing_short_circuit}),
%% Someone else believes that I am repairing. We assume %% Someone else believes that I am repairing. We assume
%% that nobody is being Byzantine, so we'll believe it. %% that nobody is being Byzantine, so we'll believe that I
%% We ignore our proposal and try to go with the latest. %% am/should be repairing. We ignore our proposal and try
%% to go with the latest.
react_to_env_C110(P_latest, S); react_to_env_C110(P_latest, S);
{_, true} -> {_, true} ->
?REACT({c100, sane}),
react_to_env_C110(P_latest, S); react_to_env_C110(P_latest, S);
{_, _AnyOtherReturnValue} -> {_, _AnyOtherReturnValue} ->
%% %% P_latest is known to be crap. ?REACT({c100, not_sane}),
%% %% By process of elimination, P_newprop is best, %% P_latest is not sane.
%% %% so let's write it. %% By process of elimination, P_newprop is best,
%% MaxEpoch = erlang:max(P_newprop#projection.epoch_number, %% so let's write it.
%% P_latest#projection.epoch_number) + 1,
%% P_newprop2 = update_projection_checksum(
%% P_newprop#projection{epoch_number=MaxEpoch}),
%% react_to_env_C300(P_newprop2, P_latest, S)
react_to_env_C300(P_newprop, P_latest, S) react_to_env_C300(P_newprop, P_latest, S)
end. end.
react_to_env_C110(P_latest, #ch_mgr{myflu=MyFLU} = S) -> react_to_env_C110(P_latest, #ch_mgr{myflu=MyFLU} = S) ->
put(react, [c110|get(react)]), ?REACT(c110),
%% TOOD: Should we carry along any extra info that that would be useful %% TOOD: Should we carry along any extra info that that would be useful
%% in the dbg2 list? %% in the dbg2 list?
Extra_todo = [], Extra_todo = [],
@ -725,18 +725,19 @@ react_to_env_C110(P_latest, #ch_mgr{myflu=MyFLU} = S) ->
Islands = proplists:get_value(network_islands, RunEnv), Islands = proplists:get_value(network_islands, RunEnv),
P_latest2 = update_projection_dbg2( P_latest2 = update_projection_dbg2(
P_latest, P_latest,
[{network_islands, Islands},{hooray, {v2, date(), time()}}|Extra_todo]), [{network_islands, Islands},
{hooray, {v2, date(), time()}}|Extra_todo]),
Epoch = P_latest2#projection.epoch_number, Epoch = P_latest2#projection.epoch_number,
ok = machi_flu0:proj_write(MyFLU, Epoch, private, P_latest2), ok = machi_flu0:proj_write(MyFLU, Epoch, private, P_latest2),
react_to_env_C120(P_latest, S). react_to_env_C120(P_latest, S).
react_to_env_C120(P_latest, S) -> react_to_env_C120(P_latest, S) ->
put(react, [c120|get(react)]), ?REACT(c120),
{{now_using, P_latest#projection.epoch_number}, {{now_using, P_latest#projection.epoch_number},
S#ch_mgr{proj=P_latest, proj_proposed=none}}. S#ch_mgr{proj=P_latest, proj_proposed=none}}.
react_to_env_C200(Retries, P_latest, S) -> react_to_env_C200(Retries, P_latest, S) ->
put(react, [c200|get(react)]), ?REACT(c200),
try try
yo:tell_author_yo(P_latest#projection.author_server) yo:tell_author_yo(P_latest#projection.author_server)
catch Type:Err -> catch Type:Err ->
@ -746,30 +747,27 @@ react_to_env_C200(Retries, P_latest, S) ->
react_to_env_C210(Retries, S). react_to_env_C210(Retries, S).
react_to_env_C210(Retries, #ch_mgr{myflu=MyFLU, proj=Proj} = S) -> react_to_env_C210(Retries, #ch_mgr{myflu=MyFLU, proj=Proj} = S) ->
put(react, [c210|get(react)]), ?REACT(c210),
%% TODO: implement the ranked sleep thingie?
sleep_ranked_order(10, 100, MyFLU, Proj#projection.all_members), sleep_ranked_order(10, 100, MyFLU, Proj#projection.all_members),
react_to_env_C220(Retries, S). react_to_env_C220(Retries, S).
react_to_env_C220(Retries, S) -> react_to_env_C220(Retries, S) ->
put(react, [c220|get(react)]), ?REACT(c220),
react_to_env_A20(Retries + 1, S). react_to_env_A20(Retries + 1, S).
react_to_env_C300(#projection{epoch_number=Epoch_newprop}=P_newprop, react_to_env_C300(#projection{epoch_number=Epoch_newprop}=P_newprop,
#projection{epoch_number=_Epoch_latest}=_P_latest, S) -> #projection{epoch_number=Epoch_latest}=_P_latest, S) ->
put(react, [c300|get(react)]), ?REACT(c300),
NewEpoch = erlang:max(Epoch_newprop, _Epoch_latest) + 1, NewEpoch = erlang:max(Epoch_newprop, Epoch_latest) + 1,
P_newprop2 = P_newprop#projection{epoch_number=NewEpoch}, P_newprop2 = P_newprop#projection{epoch_number=NewEpoch},
%% %% Let's return to the old epoch thingie and see what happens.........
%% Epoch = Epoch_newprop,
%% P_newprop2 = P_newprop#projection{epoch_number=Epoch + 1},
react_to_env_C310(update_projection_checksum(P_newprop2), S). react_to_env_C310(update_projection_checksum(P_newprop2), S).
react_to_env_C310(P_newprop, S) -> react_to_env_C310(P_newprop, S) ->
put(react, [{c310,make_projection_summary(P_newprop)}|get(react)]), ?REACT(c310),
Epoch = P_newprop#projection.epoch_number, Epoch = P_newprop#projection.epoch_number,
{_Res, S2} = cl_write_public_proj_skip_local_error(Epoch, P_newprop, S), {_Res, S2} = cl_write_public_proj_skip_local_error(Epoch, P_newprop, S),
put(react, [{c310,_Res}|get(react)]), ?REACT({c310,make_projection_summary(P_newprop)}),
?REACT({c310,_Res}),
react_to_env_A10(S2). react_to_env_A10(S2).
@ -794,6 +792,16 @@ projection_transition_is_sane(
dbg=Dbg2} = P2, dbg=Dbg2} = P2,
RelativeToServer) -> RelativeToServer) ->
try try
%% General notes:
%%
%% I'm making no attempt to be "efficient" here. All of these data
%% structures are small, and they're not called zillions of times per
%% second.
%%
%% The chain sequence/order checks at the bottom of this function aren't
%% as easy-to-read as they ought to be. However, I'm moderately confident
%% that it isn't buggy. TODO: refactor them for clarity.
true = is_integer(Epoch1) andalso is_integer(Epoch2), true = is_integer(Epoch1) andalso is_integer(Epoch2),
true = is_binary(CSum1) andalso is_binary(CSum2), true = is_binary(CSum1) andalso is_binary(CSum2),
{_,_,_} = CreationTime1, {_,_,_} = CreationTime1,