Permalink
Browse files

manual clock control and fixed merge function

  • Loading branch information...
1 parent b1671d7 commit 13d25eb1eb6c83cdf82b890fb8fd9349883edbe7 @etrepum etrepum committed Jun 16, 2011
Showing with 44 additions and 19 deletions.
  1. +10 −7 src/statebox_counter.erl
  2. +34 −12 test/statebox_counter_tests.erl
View
@@ -51,14 +51,17 @@ op_inc_acc(Timestamp, Key, Value, Counter) ->
%% Internal API
merge_prune(Counters) ->
- merge_prune(lists:umerge(Counters), []).
+ prune(lists:umerge(Counters)).
-merge_prune(L=[{{_, acc}, _} | _], Acc) ->
- lists:reverse(Acc, L);
-merge_prune([H | T], Acc) ->
- merge_prune(T, [H | Acc]);
-merge_prune([], Acc) ->
- lists:reverse(Acc).
+prune(All) ->
+ prune(All, All).
+
+prune(Here=[{{_Ts, acc}, _V} | Rest], _Last) ->
+ prune(Rest, Here);
+prune([_ | Rest], Last) ->
+ prune(Rest, Last);
+prune([], Last) ->
+ Last.
accumulate(Timestamp, [{{T1, _Id}, Value} | Rest], Sum) when T1 =< Timestamp ->
accumulate(Timestamp, Rest, Value + Sum);
@@ -2,7 +2,7 @@
-behaviour(proper_statem).
-export([initial_state/0, command/1,
precondition/2, postcondition/3, next_state/3]).
--export([apply_f_inc_acc/3, add_sibling/0, merge_siblings/1]).
+-export([apply_f_inc_acc/4, add_sibling/0, merge_siblings/1]).
-include_lib("proper/include/proper.hrl").
-include_lib("eunit/include/eunit.hrl").
@@ -13,9 +13,10 @@ clock_step() ->
default_age() ->
10 * clock_step().
-apply_f_inc_acc(Value, N, Counters) ->
+apply_f_inc_acc(Value, Clock, N, Counters) ->
+ Key = {Clock, statebox_identity:entropy()},
statebox:apply_op(
- statebox_counter:f_inc_acc(Value, default_age()),
+ statebox_counter:f_inc_acc(Value, default_age(), Key),
lists:nth(N, Counters)).
add_sibling() ->
@@ -31,34 +32,55 @@ merge_siblings(_N) ->
%% Update existing counter (apply_f_inc_acc)
%% Merge (up to) N siblings (merge_siblings)
%% Expiration used will be for 20 clock cycles
--record(state, {counters=[[]], num_counters=1, value=[]}).
+-record(state, {counters=[[]], num_counters=1, value=[], clock=0}).
initial_state() ->
- #state{}.
+ #state{clock=10000}.
-command(#state{counters=Counters, num_counters=N}) ->
+command(#state{counters=Counters, num_counters=N, clock=Clock}) ->
oneof([{call, ?MODULE, add_sibling, []},
{call, ?MODULE, merge_siblings, [range(1, N)]},
- {call, ?MODULE, apply_f_inc_acc, [range(-3, 3), range(1, N), Counters]}]).
+ {call, ?MODULE, apply_f_inc_acc, [range(-3, 3), Clock, range(1, N), Counters]}]).
precondition(_S, _Call) ->
true.
postcondition(S, {call, _, apply_f_inc_acc, [Inc, _]}, Res) ->
- (Inc + lists:sum(S#state.value)) =:= statebox_counter:value(Res);
+ sane_counter(Res)
+ andalso (Inc + lists:sum(S#state.value)) =:= statebox_counter:value(Res);
postcondition(S, {call, _, _, _}, _Res) ->
- lists:sum(S#state.value) =:=
- statebox_counter:value(statebox_counter:merge(S#state.counters)).
+ lists:all(fun sane_counter/1, S#state.counters)
+ andalso (lists:sum(S#state.value) =:=
+ statebox_counter:value(statebox_counter:merge(S#state.counters))).
next_state(S=#state{counters=[H|T]}, _V, {call, _, add_sibling, []}) ->
S#state{counters=[H,H|T]};
next_state(S=#state{counters=Counters}, _V, {call, _, merge_siblings, [N]}) ->
{L, T} = lists:split(N, Counters),
S#state{counters=[statebox_counter:merge(L) | T]};
-next_state(S=#state{counters=Counters}, V, {call, _, apply_f_inc_acc, [Inc, N, _C]}) ->
+next_state(S=#state{counters=Counters, clock=Clock}, V, {call, _, apply_f_inc_acc, [Inc, Clock, N, _C]}) ->
Counters1 = lists:sublist(Counters, N - 1) ++ [V | lists:nthtail(N, Counters)],
S#state{counters=Counters1,
- value=[Inc | S#state.value]}.
+ value=[Inc | S#state.value],
+ clock=Clock + clock_step()}.
+
+sane_counter([]) ->
+ true;
+sane_counter([{Timestamp, Id} | Rest]) ->
+ sane_counter(Rest, Id =:= acc, Timestamp).
+
+sane_counter([A, A | _], _, _) ->
+ false;
+sane_counter([{T1, _} | _], true, T0) when T1 < T0 ->
+ false;
+sane_counter([{_, acc} | _], true, _) ->
+ false;
+sane_counter([{T1, acc} | Rest], false, _T0) ->
+ sane_counter(Rest, true, T1);
+sane_counter([{T1, _} | Rest], HasAcc, _T0) ->
+ sane_counter(Rest, HasAcc, T1);
+sane_counter([], _, _) ->
+ true.
%% properties

0 comments on commit 13d25eb

Please sign in to comment.