Add PULSE control over sequencer handing out duplicate page numbers
This commit is contained in:
parent
21a3fd6d07
commit
58ced8d14c
2 changed files with 67 additions and 24 deletions
|
@ -23,6 +23,10 @@
|
|||
-behaviour(gen_server).
|
||||
|
||||
-export([start_link/1, stop/1, get/2]).
|
||||
-ifdef(TEST).
|
||||
-export([start_link/2]).
|
||||
-compile(export_all).
|
||||
-endif.
|
||||
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||
terminate/2, code_change/3]).
|
||||
|
@ -37,8 +41,10 @@
|
|||
-define(SERVER, ?MODULE).
|
||||
|
||||
start_link(FLUs) ->
|
||||
%% gen_server:start_link({local, ?SERVER}, ?MODULE, {FLUs}, []).
|
||||
gen_server:start_link(?MODULE, {FLUs}, []).
|
||||
start_link(FLUs, standard).
|
||||
|
||||
start_link(FLUs, SeqType) ->
|
||||
gen_server:start_link(?MODULE, {FLUs, SeqType}, []).
|
||||
|
||||
stop(Pid) ->
|
||||
gen_server:call(Pid, stop, infinity).
|
||||
|
@ -48,12 +54,26 @@ get(Pid, NumPages) ->
|
|||
|
||||
%%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%%
|
||||
|
||||
init({FLUs}) ->
|
||||
init({FLUs, TypeOrSeed}) ->
|
||||
MLP = get_max_logical_page(FLUs),
|
||||
{ok, MLP + 1}.
|
||||
if TypeOrSeed == standard ->
|
||||
{ok, MLP + 1};
|
||||
true ->
|
||||
{Seed, BadPercent, MaxDifference} = TypeOrSeed,
|
||||
random:seed(Seed),
|
||||
{ok, {MLP+1, BadPercent, MaxDifference}}
|
||||
end.
|
||||
|
||||
handle_call({get, NumPages}, _From, MLP) ->
|
||||
handle_call({get, NumPages}, _From, MLP) when is_integer(MLP) ->
|
||||
{reply, MLP, MLP + NumPages};
|
||||
handle_call({get, NumPages}, _From, {MLP, BadPercent, MaxDifference}) ->
|
||||
Fudge = case random:uniform(100) of
|
||||
N when N < BadPercent ->
|
||||
random:uniform(MaxDifference * 2) - MaxDifference;
|
||||
_ ->
|
||||
0
|
||||
end,
|
||||
{reply, erlang:max(1, MLP + Fudge), {MLP + NumPages, BadPercent, MaxDifference}};
|
||||
handle_call(stop, _From, MLP) ->
|
||||
{stop, normal, ok, MLP};
|
||||
handle_call(_Request, _From, MLP) ->
|
||||
|
|
|
@ -65,11 +65,22 @@ initial_state() ->
|
|||
gen_page(PageSize) ->
|
||||
binary(PageSize).
|
||||
|
||||
gen_seed() ->
|
||||
noshrink({choose(1, 20000), choose(1, 20000), choose(1, 20000)}).
|
||||
|
||||
gen_sequencer_percent() ->
|
||||
frequency([{10, choose(1,100)},
|
||||
{5, choose(90,100)}]).
|
||||
|
||||
gen_sequencer() ->
|
||||
frequency([{100, standard},
|
||||
{50, {gen_seed(), gen_sequencer_percent(), choose(1, 2)}}]).
|
||||
|
||||
command(#state{run=Run} = S) ->
|
||||
?LET({NumChains, ChainLen, PageSize},
|
||||
{parameter(num_chains), parameter(chain_len), parameter(page_size)},
|
||||
frequency(
|
||||
[{10, {call, ?MODULE, setup, [NumChains, ChainLen, PageSize]}}
|
||||
[{10, {call, ?MODULE, setup, [NumChains, ChainLen, PageSize, gen_sequencer()]}}
|
||||
|| not S#state.is_setup] ++
|
||||
[{10, {call, ?MODULE, append, [Run, gen_page(PageSize)]}}
|
||||
|| S#state.is_setup] ++
|
||||
|
@ -83,7 +94,7 @@ precondition(S, {call, _, _, _}) ->
|
|||
|
||||
%% Next state transformation, S is the current state and V is the result of the
|
||||
%% command.
|
||||
next_state(S, Res, {call, _, setup, [NumChains, ChainLen, PageSize]}) ->
|
||||
next_state(S, Res, {call, _, setup, [NumChains, ChainLen, PageSize, _SeqType]}) ->
|
||||
S#state{is_setup=true,
|
||||
num_chains=NumChains,
|
||||
chain_len=ChainLen,
|
||||
|
@ -184,18 +195,6 @@ prop_pulse_test_() ->
|
|||
end}.
|
||||
|
||||
|
||||
%% If you want to see PULSE causing crazy scheduling, then
|
||||
%% use this code instead of the usual stuff.
|
||||
%% check_trace(Trace, Cmds, _Seed) ->
|
||||
%% Results = [X || {_TS, {result, _Pid, X}} <- Trace],
|
||||
%% {CmdsSeq, CmdsPars} = Cmds,
|
||||
%% NaiveCmds = CmdsSeq ++ lists:flatten(CmdsPars),
|
||||
%% NaiveCommands = [{Sym, Args} || {set,_,{call,_,Sym,Args}} <- NaiveCmds],
|
||||
%% NaiveAppends = [X || {append, _} = X <- NaiveCommands],
|
||||
%% conjunction(
|
||||
%% [{identity, equals(NaiveAppends, NaiveAppends)},
|
||||
%% {bogus_order_check_do_not_use_me, equals(Results, lists:usort(Results))}]).
|
||||
|
||||
%% Example Trace (raw event info, from the ?LOG macro)
|
||||
%%
|
||||
%% [{32014,{call,<0.467.0>,{append,<<"O">>}}},
|
||||
|
@ -237,16 +236,27 @@ check_trace(Trace, _Cmds, _Seed) ->
|
|||
fun({call, Pid, {append, _Pg}}, {result, Pid, Res}) ->
|
||||
[AppendResultFilter(Res)] end,
|
||||
Events),
|
||||
{_, infinity, AppendLPNs} = lists:last(eqc_temporal:all_future(AppendResults)),
|
||||
|
||||
%% Desired properties
|
||||
AllCallsFinish = eqc_temporal:is_false(eqc_temporal:all_future(Calls)),
|
||||
NoAppendLPNDups = lists:sort(AppendResults) == lists:usort(AppendResults),
|
||||
NoAppendLPNDups = lists:sort(AppendLPNs) == lists:usort(AppendLPNs),
|
||||
|
||||
?WHENFAIL(begin
|
||||
?QC_FMT("*AppendLPNs: ~p\n", [range_ify(AppendLPNs)])
|
||||
end,
|
||||
conjunction(
|
||||
[
|
||||
{all_calls_finish, AllCallsFinish},
|
||||
{no_append_duplicates, NoAppendLPNDups}
|
||||
]).
|
||||
{no_append_duplicates, NoAppendLPNDups},
|
||||
%% If you want to see PULSE causing crazy scheduling, then
|
||||
%% change one of the "true orelse" -> "false orelse" below.
|
||||
{bogus_no_gaps,
|
||||
true orelse
|
||||
(AppendLPNs == [] orelse length(range_ify(AppendLPNs)) == 1)},
|
||||
{bogus_exactly_1_to_N,
|
||||
true orelse (AppendLPNs == lists:seq(1, length(AppendLPNs)))}
|
||||
])).
|
||||
|
||||
%% Presenting command data statistics in a nicer way
|
||||
command_data({set, _, {call, _, Fun, _}}, {_S, _V}) ->
|
||||
|
@ -308,15 +318,28 @@ make_chains(ChainLen, [H|T], SmallAcc, BigAcc) ->
|
|||
make_chains(ChainLen, T, [H|SmallAcc], BigAcc)
|
||||
end.
|
||||
|
||||
setup(NumChains, ChainLen, PageSize) ->
|
||||
setup(NumChains, ChainLen, PageSize, SeqType) ->
|
||||
N = NumChains * ChainLen,
|
||||
FLUs = corfurl_test:setup_basic_flus(N, PageSize, 50000),
|
||||
{ok, Seq} = corfurl_sequencer:start_link(FLUs),
|
||||
{ok, Seq} = corfurl_sequencer:start_link(FLUs, SeqType),
|
||||
Chains = make_chains(ChainLen, FLUs),
|
||||
%% io:format(user, "Cs = ~p\n", [Chains]),
|
||||
Proj = corfurl:new_simple_projection(1, 1, 50000, Chains),
|
||||
#run{seq=Seq, proj=Proj, flus=FLUs}.
|
||||
|
||||
range_ify([]) ->
|
||||
[];
|
||||
range_ify(L) ->
|
||||
[H|T] = lists:sort(L),
|
||||
range_ify(H, H+1, T).
|
||||
|
||||
range_ify(Beginning, Next, [Next|T]) ->
|
||||
range_ify(Beginning, Next+1, T);
|
||||
range_ify(Beginning, Next, [Else|T]) ->
|
||||
[{Beginning, to, Next-1}|range_ify(Else, Else+1, T)];
|
||||
range_ify(Beginning, Next, []) ->
|
||||
[{Beginning, to, Next-1}].
|
||||
|
||||
-define(LOG(Tag, MkCall),
|
||||
event_logger:event({call, self(), Tag}),
|
||||
LOG__Result = MkCall,
|
||||
|
|
Loading…
Reference in a new issue