From dbcc87b4a46807df9398ffdda52082449c7eaa54 Mon Sep 17 00:00:00 2001 From: Scott Lystig Fritchie Date: Fri, 31 Oct 2014 01:57:13 +0900 Subject: [PATCH] WIP: Chain manager projection store flowchart goop --- .../docs/machi/chain-mgmt-flowchart.dot | 109 ++++++++++++++++++ .../poc-machi/src/machi_chain_manager1.erl | 75 ++++++++++++ 2 files changed, 184 insertions(+) create mode 100644 prototype/poc-machi/docs/machi/chain-mgmt-flowchart.dot diff --git a/prototype/poc-machi/docs/machi/chain-mgmt-flowchart.dot b/prototype/poc-machi/docs/machi/chain-mgmt-flowchart.dot new file mode 100644 index 0000000..e0183ce --- /dev/null +++ b/prototype/poc-machi/docs/machi/chain-mgmt-flowchart.dot @@ -0,0 +1,109 @@ +digraph { + compound=true + label="Machi chain management flowchart (sample)"; + + node[shape="box", style="rounded"] + start; + node[shape="box", style="rounded", label="stop1"] + stop1; + node[shape="box", style="rounded", label="stop2"] + stop2; + node[shape="box", style="rounded"] + crash; + + subgraph clustera { + node[shape="parallelogram", style="", label="Set retry counter = 0"] + a05_retry; + node[shape="parallelogram", style="", label="Create P_newprop @ epoch E+1\nbased on P_current @ epoch E"] + a10_create; + node[shape="parallelogram", style="", label="Get latest public projection, P_latest"] + a20_get; + node[shape="diamond", style="", label="Epoch(P_latest) > Epoch(P_current)\norelse\nP_latest was not unanimous"] + a30_epoch; + node[shape="diamond", style="", label="Epoch(P_latest) == Epoch(P_current)"] + a40_epochequal; + node[shape="diamond", style="", label="P_latest == P_current"] + a50_equal; + } + + subgraph clustera100 { + node[shape="diamond", style="", label="Write P_newprop to everyone"] + a100_write; + } + + subgraph clusterb { + node[shape="diamond", style="", label="P_latest was unanimous?"] + b10_unanimous; + node[shape="diamond", style="", label="Retry counter too big?"] + b20_counter; + node[shape="diamond", style="", label="Rank(P_latest) >= Rank(P_newprop)"] + b30_rank; + node[shape="diamond", style="", label="P_latest.upi == P_newprop.upi\nand also\nPlatest.repairing == P_newprop.repairing"] + b40_condc; + node[shape="square", style="", label="P_latest author is\ntoo slow, let's try!"] + b45_lets; + node[shape="parallelogram", style="", label="P_newprop is better than P_latest.\nSet P_newprop.epoch = P_latest.epoch + 1."] + b50_better; + } + + subgraph clusterc { + node[shape="diamond", style="", label="Is Move(P_current, P_latest) ok?"] + c10_move; + node[shape="parallelogram", style="", label="Tell Author(P_latest) to rewrite\nwith a bigger epoch number"] + c20_tell; +} + + subgraph clusterd { + node[shape="diamond", style="", label="Use P_latest as the\nnew P_current"] + d10_use; +} + + start -> a05_retry; + + a05_retry -> a10_create; + a10_create -> a20_get; + a20_get -> a30_epoch; + a30_epoch -> a40_epochequal[label="false"]; + a30_epoch -> b10_unanimous[label="true"]; + a40_epochequal -> a50_equal[label="true"]; + a40_epochequal -> crash[label="falseXX"]; + a50_equal -> stop1[label="true"]; + a50_equal -> b20_counter[label="false"]; + + a100_write -> a10_create; + + b10_unanimous -> c10_move[label="yes"]; + b10_unanimous -> b20_counter[label="no"]; + b20_counter -> b45_lets[label="true"]; + b20_counter -> b30_rank[label="false"]; + b30_rank -> b40_condc[label="false"]; + b30_rank -> c20_tell[label="true"]; + b40_condc -> b50_better[label="false"]; + b40_condc -> c20_tell[label="true"]; + b45_lets -> b50_better; + b50_better -> a100_write; + + c10_move -> d10_use[label="yes"]; + c10_move -> a100_write[label="no"]; + c20_tell -> b50_better; + + d10_use -> stop2; + + {rank=same; clustera clusterb clusterc clusterd}; + +// {rank=same; a10_create b10_unanimous c10_move d10_use stop2}; +// {rank=same; a20_get b20_counter c20_tell}; +// {rank=same; a30_epoch b40_condc}; +// {rank=same; a40_epochequal b40_condc crash}; +// {rank=same; stop1 a50_equal b50_better}; + +// if_valid; +// +// start -> input; +// input -> if_valid; +// if_valid -> message[label="no"]; +// if_valid -> end[label="yes"]; +// message -> input; + +// {rank=same; message input} +} diff --git a/prototype/poc-machi/src/machi_chain_manager1.erl b/prototype/poc-machi/src/machi_chain_manager1.erl index ee52565..c6c1b9c 100644 --- a/prototype/poc-machi/src/machi_chain_manager1.erl +++ b/prototype/poc-machi/src/machi_chain_manager1.erl @@ -36,6 +36,81 @@ -export([make_projection_summary/1]). -ifdef(TEST). + +%% NOTE NOTE NOTE NOTE NOTE NOTE +%% The sketch below is old ... the flowchart is newer. +%% TODO todo delete these comments when the flowchart +%% and its implementation have been debugged +%% NOTE NOTE NOTE NOTE NOTE NOTE + +%% Sketch for chain management simulator: the 'monitor' +%% +%% Principles: +%% * Monitor based on only one dimension of the FLU's inherent state: +%% up or down +%% * Plus one additional aspect that is experienced by the external +%% repair coordinator: not_started, in_progress, finished_ok, or +%% finished_failed +%% * For simulation purposes, start first with the repair coordinator +%% happening completely by magic, e.g., an oracle implemented by the +%% test harness. +%% - Then add more complexity, slowly, and only when necessary. +%% * Assumption for ease-of-implementation: assume that the repair +%% coordinator will be the head of the chain (or some process that +%% is managed by the head). +%% - So the simulator need only worry about the head making any +%% decisions about changes in repair state. +%% +%% Implementation: +%% +%% A. Calculate a local projection, P_{newprop} @ epoch E+1 that is +%% based on the current projection P_{current} @ epoch E. +%% - NOTE: This has side-effects in the current simulator: +%% e.g., newenv changing perception of up/down state +%% and other network partition effects. +%% +%% B. Get the latest public projection, P_{latest}. Then consider: +%% +%% B1a). If Epoch(P_{latest}) == Epoch(P_{current}), then goto step C. +%% +%% B1b). If Epoch(P_{latest}) < Epoch(P_{current}), then we have a +%% serious invariant violation/logic problem. Shouldn't happen, +%% but keep an eye out for it anyway. +%% +%% B1c). If Epoch(P_{latest}) > Epoch(P_{current}), then some other +%% manager has noticed a change. +%% +%% If we haven't stopped yet, then continue: +%% +%% B2a). If P_{latest} was read unanimously, then use it as the new +%% P_{current}. Then stop. +%% +%% B2b). If P_{latest} is not unanimous, then compare rank. +%% +%% - If Rank(P_{latest}) >= Rank(P_{newprop}), then we encourage +%% the author to re-write this projection with a bigger epoch +%% number. +%% - If the counter has exceeded some # of tries, F=2?, then +%% goto Step D instead. +%% - Set a counter of the # of times that we've encouraged +%% the author to re-write. +%% - Sleep a while, then goto A. +%% +%% - If Rank(P_{latest}) < Rank(P_{newprop}) and also +%% P_{latest}.upi == P_{newprop}.upi and also +%% P_{latest}.repairing == P_{newprop}.repairing, then our +%% proposal P_{newprop} isn't anything substantially new. +%% - Use the same encouragement & retry loop as described above. +%% +%% - If Rank(P_{latest}) < Rank(P_{newprop}) (last case)... +%% ... our proposal is better. Goto step D. +%% +%% C. If P_{latest}.upi == P_{newprop}.upi and also +%% P_{latest}.repairing == P_{newprop}.repairing, then our proposal +%% P_{newprop} isn't anything substantially new. Stop. +%% +%% D. Write P_{newprop} to everyone. Then goto A. + -export([test_calc_projection/2, test_calc_proposed_projection/1, test_write_proposed_projection/1,