WIP: chain manager simulation test
This commit is contained in:
parent
4ebc80dc39
commit
b8c87b23ad
2 changed files with 226 additions and 0 deletions
126
prototype/poc-machi/src/machi_chain_manager.erl
Normal file
126
prototype/poc-machi/src/machi_chain_manager.erl
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
%% -------------------------------------------------------------------
|
||||||
|
%%
|
||||||
|
%% Machi: a small village of replicated files
|
||||||
|
%%
|
||||||
|
%% Copyright (c) 2014 Basho Technologies, Inc. All Rights Reserved.
|
||||||
|
%%
|
||||||
|
%% This file is provided to you under the Apache License,
|
||||||
|
%% Version 2.0 (the "License"); you may not use this file
|
||||||
|
%% except in compliance with the License. You may obtain
|
||||||
|
%% a copy of the License at
|
||||||
|
%%
|
||||||
|
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
%%
|
||||||
|
%% Unless required by applicable law or agreed to in writing,
|
||||||
|
%% software distributed under the License is distributed on an
|
||||||
|
%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
%% KIND, either express or implied. See the License for the
|
||||||
|
%% specific language governing permissions and limitations
|
||||||
|
%% under the License.
|
||||||
|
%%
|
||||||
|
%% -------------------------------------------------------------------
|
||||||
|
-module(machi_chain_manager).
|
||||||
|
|
||||||
|
-export([]).
|
||||||
|
|
||||||
|
-ifdef(TEST).
|
||||||
|
-compile(export_all).
|
||||||
|
|
||||||
|
-ifdef(EQC).
|
||||||
|
-include_lib("eqc/include/eqc.hrl").
|
||||||
|
-endif.
|
||||||
|
-ifdef(PULSE).
|
||||||
|
-compile({parse_transform, pulse_instrument}).
|
||||||
|
-endif.
|
||||||
|
|
||||||
|
-endif. %TEST
|
||||||
|
|
||||||
|
-type m_csum() :: {none | sha1 | sha1_excl_final_20, binary()}.
|
||||||
|
%% -type m_epoch() :: {m_epoch_n(), m_csum()}.
|
||||||
|
-type m_epoch_n() :: non_neg_integer().
|
||||||
|
-type m_server() :: atom().
|
||||||
|
-type timestamp() :: {non_neg_integer(), non_neg_integer(), non_neg_integer()}.
|
||||||
|
|
||||||
|
-record(projection, {
|
||||||
|
epoch_number :: m_epoch_n(),
|
||||||
|
epoch_csum :: m_csum(),
|
||||||
|
prev_epoch_num :: m_epoch_n(),
|
||||||
|
prev_epoch_csum :: m_csum(),
|
||||||
|
creation_time :: timestamp(),
|
||||||
|
author_server :: m_server(),
|
||||||
|
all_members :: [m_server()],
|
||||||
|
active_upi :: [m_server()],
|
||||||
|
active_repairing:: [m_server()],
|
||||||
|
dbg :: list()%proplist()
|
||||||
|
}).
|
||||||
|
|
||||||
|
-record(state, {
|
||||||
|
name :: m_server(),
|
||||||
|
proj :: #projection{},
|
||||||
|
seed :: timestamp(),
|
||||||
|
last_up :: list(m_server())
|
||||||
|
}).
|
||||||
|
|
||||||
|
make_initial_state(MyName, All_list, Seed) ->
|
||||||
|
#state{name=MyName,
|
||||||
|
proj=make_initial_projection(MyName, All_list, All_list, [], []),
|
||||||
|
seed=Seed,
|
||||||
|
last_up=All_list}.
|
||||||
|
|
||||||
|
make_initial_projection(MyName, All_list, UPI_list, Repairing_list, Ps) ->
|
||||||
|
make_projection(1, 0, <<>>,
|
||||||
|
MyName, All_list, UPI_list, Repairing_list, Ps).
|
||||||
|
|
||||||
|
make_projection(EpochNum, PrevEpochNum, PrevEpochCSum,
|
||||||
|
MyName, All_list, UPI_list, Repairing_list, Ps) ->
|
||||||
|
P = #projection{epoch_number=EpochNum,
|
||||||
|
epoch_csum= <<>>,
|
||||||
|
prev_epoch_num=PrevEpochNum,
|
||||||
|
prev_epoch_csum=PrevEpochCSum,
|
||||||
|
creation_time=now(),
|
||||||
|
author_server=MyName,
|
||||||
|
all_members=All_list,
|
||||||
|
active_upi=UPI_list,
|
||||||
|
active_repairing=Repairing_list,
|
||||||
|
dbg=Ps},
|
||||||
|
CSum = crypto:hash(sha, term_to_binary(P)),
|
||||||
|
P#projection{epoch_csum=CSum}.
|
||||||
|
|
||||||
|
calc_projection(CurrentInfo, #state{name=MyName, proj=OldProj} = S) ->
|
||||||
|
{UpNodes, S2} = calc_up_nodes(CurrentInfo, S),
|
||||||
|
#projection{epoch_number=OldEpochNum,
|
||||||
|
epoch_csum=OldEpochCsum,
|
||||||
|
all_members=All_list
|
||||||
|
%% active_upi=UPI_list,
|
||||||
|
%% active_repairing=Repairing_list,
|
||||||
|
%% dbg=Ps
|
||||||
|
} = OldProj,
|
||||||
|
P = make_projection(OldEpochNum + 1, OldEpochNum, OldEpochCsum,
|
||||||
|
MyName, All_list, UpNodes, [], [{fubar,true}]),
|
||||||
|
{P, S2}.
|
||||||
|
|
||||||
|
calc_up_nodes(CurrentInfo,
|
||||||
|
#state{name=MyName, seed=Seed, last_up=LastUp} = S) ->
|
||||||
|
AllMembers = (S#state.proj)#projection.all_members,
|
||||||
|
{F, Seed2} = random:uniform_s(Seed),
|
||||||
|
Cutoff = trunc(F * 100),
|
||||||
|
if LastUp == undefined orelse Cutoff rem 3 == 0 ->
|
||||||
|
Up = calc_new_up_nodes(MyName, AllMembers, CurrentInfo, Cutoff),
|
||||||
|
{Up, S#state{seed=Seed2, last_up=Up}};
|
||||||
|
true ->
|
||||||
|
{LastUp, S#state{seed=Seed2}}
|
||||||
|
end.
|
||||||
|
|
||||||
|
calc_new_up_nodes(MyName, Nodes, CurrentInfo, Cutoff) ->
|
||||||
|
C_weights = proplists:get_value(communicating_weights, CurrentInfo),
|
||||||
|
lists:usort([MyName] ++
|
||||||
|
[Node || Node <- Nodes,
|
||||||
|
Node /= MyName,
|
||||||
|
Weight_to <- [element(1,
|
||||||
|
lists:keyfind({MyName, Node},
|
||||||
|
2, C_weights))],
|
||||||
|
Weight_from <- [element(1,
|
||||||
|
lists:keyfind({Node, MyName},
|
||||||
|
2, C_weights))],
|
||||||
|
Weight_to =< Cutoff,
|
||||||
|
Weight_from =< Cutoff]).
|
100
prototype/poc-machi/test/machi_chain_manager_test.erl
Normal file
100
prototype/poc-machi/test/machi_chain_manager_test.erl
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
%% -------------------------------------------------------------------
|
||||||
|
%%
|
||||||
|
%% Machi: a small village of replicated files
|
||||||
|
%%
|
||||||
|
%% Copyright (c) 2014 Basho Technologies, Inc. All Rights Reserved.
|
||||||
|
%%
|
||||||
|
%% This file is provided to you under the Apache License,
|
||||||
|
%% Version 2.0 (the "License"); you may not use this file
|
||||||
|
%% except in compliance with the License. You may obtain
|
||||||
|
%% a copy of the License at
|
||||||
|
%%
|
||||||
|
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
%%
|
||||||
|
%% Unless required by applicable law or agreed to in writing,
|
||||||
|
%% software distributed under the License is distributed on an
|
||||||
|
%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
%% KIND, either express or implied. See the License for the
|
||||||
|
%% specific language governing permissions and limitations
|
||||||
|
%% under the License.
|
||||||
|
%%
|
||||||
|
%% -------------------------------------------------------------------
|
||||||
|
-module(machi_chain_manager_test).
|
||||||
|
|
||||||
|
-export([]).
|
||||||
|
|
||||||
|
-ifdef(TEST).
|
||||||
|
|
||||||
|
-ifdef(EQC).
|
||||||
|
-include_lib("eqc/include/eqc.hrl").
|
||||||
|
-include_lib("eqc/include/eqc_statem.hrl").
|
||||||
|
-endif.
|
||||||
|
|
||||||
|
-include_lib("eunit/include/eunit.hrl").
|
||||||
|
-compile(export_all).
|
||||||
|
-endif.
|
||||||
|
|
||||||
|
-record(s, {
|
||||||
|
step = 0 :: non_neg_integer(),
|
||||||
|
seed :: {integer(), integer(), integer()},
|
||||||
|
comm_weights = [] :: list()
|
||||||
|
}).
|
||||||
|
|
||||||
|
gen_all_nodes() ->
|
||||||
|
[a, b, c].
|
||||||
|
|
||||||
|
gen_rand_seed() ->
|
||||||
|
noshrink({gen_num(), gen_num(), gen_num()}).
|
||||||
|
|
||||||
|
gen_num() ->
|
||||||
|
?LET(I, oneof([int(), largeint()]),
|
||||||
|
erlang:abs(I)).
|
||||||
|
|
||||||
|
gen_communicating_weights(Nodes) ->
|
||||||
|
Pairs = make_all_pairs(Nodes),
|
||||||
|
Num = length(Pairs),
|
||||||
|
?LET(Weights, vector(Num, choose(1, 100)),
|
||||||
|
lists:zip(Weights, Pairs)).
|
||||||
|
|
||||||
|
%% gen_communicating_nodes(Nodes) ->
|
||||||
|
%% ?LET(Pairs, make_all_pairs(Nodes),
|
||||||
|
%% frequency([{10, Pairs},
|
||||||
|
%% { 8, gen_take_some(Pairs)}])).
|
||||||
|
|
||||||
|
%% gen_take_some(L) ->
|
||||||
|
%% Num = length(L),
|
||||||
|
%% ?LET({Weights, Cutoff}, {vector(Num, choose(1, 100)), choose(1, 100)},
|
||||||
|
%% [X || {Weight, X} <- lists:zip(Weights, L),
|
||||||
|
%% Weight < Cutoff]).
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
initial_state() ->
|
||||||
|
#s{}.
|
||||||
|
|
||||||
|
command(#s{step=0}) ->
|
||||||
|
L = gen_all_nodes(),
|
||||||
|
{call, ?MODULE, init_run, [gen_rand_seed(), gen_communicating_weights(L)]};
|
||||||
|
command(_S) ->
|
||||||
|
foo.
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
prop_m() ->
|
||||||
|
?FORALL({_Cmds, _PulseSeed}, {commands(?MODULE), pulse:seed()},
|
||||||
|
begin
|
||||||
|
true
|
||||||
|
end).
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
make_all_pairs(L) ->
|
||||||
|
lists:flatten(make_all_pairs2(lists:usort(L))).
|
||||||
|
|
||||||
|
make_all_pairs2([]) ->
|
||||||
|
[];
|
||||||
|
make_all_pairs2([_]) ->
|
||||||
|
[];
|
||||||
|
make_all_pairs2([H1|T]) ->
|
||||||
|
[[{H1, X}, {X, H1}] || X <- T] ++ make_all_pairs(T).
|
||||||
|
%% [{H1, H2}, {H2, H1}|make_all_pairs([H2|T])].
|
Loading…
Reference in a new issue