Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Enhance gen_ets_ns behaviour to support batch iteration
  • Loading branch information
norton committed Jun 9, 2014
1 parent d8943da commit a18e29a
Show file tree
Hide file tree
Showing 4 changed files with 260 additions and 83 deletions.
148 changes: 148 additions & 0 deletions src/gen_ets_impl_ets.erl
Expand Up @@ -48,6 +48,14 @@
, prev/2
, prev_iter/2
, notify/4
, first/2
, first_iter/2
, last/2
, last_iter/2
, next/3
, next_iter/3
, prev/3
, prev_iter/3
]).


Expand Down Expand Up @@ -150,6 +158,146 @@ prev_iter(#gen_tid{impl=Impl}, Key) ->
notify(#gen_tid{impl=_Impl}, _Event, _Pid, _Msg) ->
false.

first(#gen_tid{impl=Impl}=Tid, N) when N > 0 ->
case ets:first(Impl) of
'$end_of_table' ->
'$end_of_table';
Key when N==1 ->
[Key];
Key ->
case next(Tid, Key, N-1) of
'$end_of_table' ->
[Key];
Keys ->
[Key|Keys]
end
end;
first(Tid, N) ->
erlang:error(badarg, [Tid, N]).

first_iter(#gen_tid{impl=Impl}=Tid, N) when N > 0 ->
case ets:first(Impl) of
'$end_of_table' ->
'$end_of_table';
Key when N==1 ->
[safe_lookup(Impl, Key)];
Key ->
case next_iter(Tid, Key, N-1) of
'$end_of_table' ->
[safe_lookup(Impl, Key)];
Objects ->
[safe_lookup(Impl, Key)|Objects]
end

end;
first_iter(Tid, N) ->
erlang:error(badarg, [Tid, N]).

last(#gen_tid{impl=Impl}=Tid, N) when N > 0 ->
case ets:last(Impl) of
'$end_of_table' ->
'$end_of_table';
Key when N==1 ->
[Key];
Key ->
case prev(Tid, Key, N-1) of
'$end_of_table' ->
[Key];
Keys ->
Keys++[Key]
end
end;

last(Tid, N) ->
erlang:error(badarg, [Tid, N]).

last_iter(#gen_tid{impl=Impl}=Tid, N) when N > 0 ->
case ets:last(Impl) of
'$end_of_table' ->
'$end_of_table';
Key when N==1 ->
[safe_lookup(Impl, Key)];
Key ->
case prev_iter(Tid, Key, N-1) of
'$end_of_table' ->
[safe_lookup(Impl, Key)];
Objects ->
Objects++[safe_lookup(Impl, Key)]
end

end;
last_iter(Tid, N) ->
erlang:error(badarg, [Tid, N]).

next(#gen_tid{impl=Impl}=Tid, Key, N) when N > 0 ->
case ets:next(Impl, Key) of
'$end_of_table' ->
'$end_of_table';
NextKey when N==1 ->
[NextKey];
NextKey ->
case next(Tid, NextKey, N-1) of
'$end_of_table' ->
[NextKey];
Keys ->
[NextKey|Keys]
end
end;
next(Tid, Key, N) ->
erlang:error(badarg, [Tid, Key, N]).

next_iter(#gen_tid{impl=Impl}=Tid, Key, N) when N > 0 ->
case safe_next(Impl, Key) of
'$end_of_table' ->
'$end_of_table';
NextKey when N==1 ->
[safe_lookup(Impl, NextKey)];
NextKey ->
case next_iter(Tid, NextKey, N-1) of
'$end_of_table' ->
[safe_lookup(Impl, NextKey)];
Objects ->
[safe_lookup(Impl, NextKey)|Objects]
end
end;
next_iter(Tid, Key, N) ->
erlang:error(badarg, [Tid, Key, N]).

prev(#gen_tid{impl=Impl}=Tid, Key, N) when N > 0 ->
case ets:prev(Impl, Key) of
'$end_of_table' ->
'$end_of_table';
PrevKey when N==1 ->
[PrevKey];
PrevKey ->
case prev(Tid, PrevKey, N-1) of
'$end_of_table' ->
[PrevKey];
Keys ->
Keys++[PrevKey]
end
end;
prev(Tid, Key, N) ->
erlang:error(badarg, [Tid, Key, N]).

prev_iter(#gen_tid{impl=Impl}=Tid, Key, N) when N > 0 ->
case safe_prev(Impl, Key) of
'$end_of_table' ->
'$end_of_table';
PrevKey when N==1 ->
[safe_lookup(Impl, PrevKey)];
PrevKey ->
case prev_iter(Tid, PrevKey, N-1) of
'$end_of_table' ->
[safe_lookup(Impl, PrevKey)];
Objects ->
Objects++[safe_lookup(Impl, PrevKey)]
end
end;
prev_iter(Tid, Key, N) ->
erlang:error(badarg, [Tid, Key, N]).


%%%----------------------------------------------------------------------
%%% Internal functions
%%%----------------------------------------------------------------------
Expand Down
88 changes: 48 additions & 40 deletions src/gen_ets_lib.erl
Expand Up @@ -65,28 +65,28 @@ foldr(Fun, Acc0, #gen_tid{mod=Mod}=Tid) ->
foldr(Fun, Acc0, Tid, Mod:last_iter(Tid)).

nfoldl(Fun, Acc0, #gen_tid{mod=Mod}=Tid, Limit) when Limit > 0 ->
nfoldl(Fun, Acc0, Acc0, Tid, Limit, Limit, Mod:first_iter(Tid));
nfoldl(Fun, Acc0, Acc0, Tid, Limit, Mod:first_iter(Tid, Limit));
nfoldl(_Fun, _Acc0, _Tid, Limit) ->
exit({badarg,Limit}).

nfoldl('$end_of_table') ->
'$end_of_table';
nfoldl({_Fun, _Acc0, _Tid, _Limit0, '$end_of_table'}) ->
nfoldl({_Fun, _Acc0, _Tid, _Limit, '$end_of_table'}) ->
'$end_of_table';
nfoldl({Fun, Acc0, #gen_tid{mod=Mod}=Tid, Limit0, Key}) ->
nfoldl(Fun, Acc0, Acc0, Tid, Limit0, Limit0, Mod:next_iter(Tid, Key)).
nfoldl({Fun, Acc0, #gen_tid{mod=Mod}=Tid, Limit, Key}) ->
nfoldl(Fun, Acc0, Acc0, Tid, Limit, Mod:next_iter(Tid, Key, Limit)).

nfoldr(Fun, Acc0, #gen_tid{mod=Mod}=Tid, Limit) when Limit > 0 ->
nfoldr(Fun, Acc0, Acc0, Tid, Limit, Limit, Mod:last_iter(Tid));
nfoldr(Fun, Acc0, Acc0, Tid, Limit, Mod:last_iter(Tid, Limit));
nfoldr(_Fun, _Acc0, _Tid, Limit) ->
exit({badarg,Limit}).

nfoldr('$end_of_table') ->
'$end_of_table';
nfoldr({_Fun, _Acc0, _Tid, _Limit0, '$end_of_table'}) ->
nfoldr({_Fun, _Acc0, _Tid, _Limit, '$end_of_table'}) ->
'$end_of_table';
nfoldr({Fun, Acc0, #gen_tid{mod=Mod}=Tid, Limit0, Key}) ->
nfoldr(Fun, Acc0, Acc0, Tid, Limit0, Limit0, Mod:prev_iter(Tid, Key)).
nfoldr({Fun, Acc0, #gen_tid{mod=Mod}=Tid, Limit, Key}) ->
nfoldr(Fun, Acc0, Acc0, Tid, Limit, Mod:prev_iter(Tid, Key, Limit)).

tab2list(Tid) ->
foldr(fun(X, Acc) -> [X|Acc] end, [], Tid).
Expand Down Expand Up @@ -187,44 +187,52 @@ foldr(Fun, Acc, #gen_tid{keypos=KeyPos, mod=Mod}=Tid, Object) ->
Key = element(KeyPos, Object),
foldr(Fun, Fun(Object, Acc), Tid, Mod:prev_iter(Tid, Key)).

nfoldl(_Fun, Acc0, Acc0, Tid, _Limit0, _Limit, '$end_of_table') ->
nfoldl(_Fun, Acc0, Acc0, Tid, _Limit, '$end_of_table') ->
ets_safe_fixtable(Tid, false),
'$end_of_table';
nfoldl(_Fun, _Acc0, Acc, Tid, _Limit0, _Limit, '$end_of_table'=Cont) ->
nfoldl(_Fun, _Acc0, Acc, Tid, _Limit, '$end_of_table'=Cont) ->
ets_safe_fixtable(Tid, false),
{Acc, Cont};
nfoldl(Fun, Acc0, Acc, #gen_tid{keypos=KeyPos, mod=Mod}=Tid, Limit0, Limit, Object) ->
Key = element(KeyPos, Object),
case Fun(Object, Acc) of
{true, NewAcc} ->
if Limit > 1 ->
nfoldl(Fun, Acc0, NewAcc, Tid, Limit0, Limit-1, Mod:next_iter(Tid, Key));
true ->
Cont = {Fun, Acc0, Tid, Limit0, Key},
{NewAcc, Cont}
end;
{false, NewAcc} ->
nfoldl(Fun, Acc0, NewAcc, Tid, Limit0, Limit, Mod:next_iter(Tid, Key))
nfoldl(Fun, Acc0, Acc, #gen_tid{keypos=KeyPos, mod=Mod}=Tid, Limit, Objects) ->
Fun1 = fun(Object, {N, _, Acc1}) ->
Key = element(KeyPos, Object),
case Fun(Object, Acc1) of
{true, NewAcc} ->
{N+1, Key, NewAcc};
{false, NewAcc} ->
{N, Key, NewAcc}
end
end,
case lists:foldl(Fun1, {0, undefined, Acc}, Objects) of
{0, Key, Acc2} ->
nfoldl(Fun, Acc0, Acc2, Tid, Limit, Mod:next_iter(Tid, Key, Limit));
{_, Key, Acc2} ->
Cont = {Fun, Acc0, Tid, Limit, Key},
{Acc2, Cont}
end.

nfoldr(_Fun, Acc0, Acc0, Tid, _Limit0, _Limit, '$end_of_table') ->
nfoldr(_Fun, Acc0, Acc0, Tid, _Limit, '$end_of_table') ->
ets_safe_fixtable(Tid, false),
'$end_of_table';
nfoldr(_Fun, _Acc0, Acc, Tid, _Limit0, _Limit, '$end_of_table'=Cont) ->
nfoldr(_Fun, _Acc0, Acc, Tid, _Limit, '$end_of_table'=Cont) ->
ets_safe_fixtable(Tid, false),
{Acc, Cont};
nfoldr(Fun, Acc0, Acc, #gen_tid{keypos=KeyPos, mod=Mod}=Tid, Limit0, Limit, Object) ->
Key = element(KeyPos, Object),
case Fun(Object, Acc) of
{true, NewAcc} ->
if Limit > 1 ->
nfoldr(Fun, Acc0, NewAcc, Tid, Limit0, Limit-1, Mod:prev_iter(Tid, Key));
true ->
Cont = {Fun, Acc0, Tid, Limit0, Key},
{NewAcc, Cont}
end;
{false, NewAcc} ->
nfoldr(Fun, Acc0, NewAcc, Tid, Limit0, Limit, Mod:prev_iter(Tid, Key))
nfoldr(Fun, Acc0, Acc, #gen_tid{keypos=KeyPos, mod=Mod}=Tid, Limit, Objects) ->
Fun1 = fun(Object, {N, _, Acc1}) ->
Key = element(KeyPos, Object),
case Fun(Object, Acc1) of
{true, NewAcc} ->
{N+1, Key, NewAcc};
{false, NewAcc} ->
{N, Key, NewAcc}
end
end,
case lists:foldr(Fun1, {0, undefined, Acc}, Objects) of
{0, Key, Acc2} ->
nfoldr(Fun, Acc0, Acc2, Tid, Limit, Mod:prev_iter(Tid, Key, Limit));
{_, Key, Acc2} ->
Cont = {Fun, Acc0, Tid, Limit, Key},
{Acc2, Cont}
end.

selectl(Fun, Acc0, Tid, Spec) ->
Expand All @@ -235,13 +243,13 @@ selectr(Fun, Acc0, Tid, Spec) ->
ets_safe_fixtable(Tid, true),
foldr(selectfun(Fun, Spec), Acc0, Tid).

nselectl(Fun, Acc0, Tid, Spec, Limit0) ->
nselectl(Fun, Acc0, Tid, Spec, Limit) ->
ets_safe_fixtable(Tid, true),
nfoldl(nselectfun(Fun, Spec), Acc0, Tid, Limit0).
nfoldl(nselectfun(Fun, Spec), Acc0, Tid, Limit).

nselectr(Fun, Acc0, Tid, Spec, Limit0) ->
nselectr(Fun, Acc0, Tid, Spec, Limit) ->
ets_safe_fixtable(Tid, true),
nfoldr(nselectfun(Fun, Spec), Acc0, Tid, Limit0).
nfoldr(nselectfun(Fun, Spec), Acc0, Tid, Limit).

nselectl(Cont) ->
nfoldl(Cont).
Expand Down
11 changes: 10 additions & 1 deletion src/gen_ets_ns.erl
Expand Up @@ -96,7 +96,16 @@
-callback next_iter(#gen_tid{}, key()) -> object() | '$end_of_table'.
-callback prev(#gen_tid{}, key()) -> key() | '$end_of_table'.
-callback prev_iter(#gen_tid{}, key()) -> object() | '$end_of_table'.
-callback notify(#gen_tid{}, when_destroyed, pid(), term()) -> true.
-callback notify(#gen_tid{}, when_destroyed, pid(), term()) -> boolean().

-callback first(#gen_tid{}, pos_integer()) -> [key()] | '$end_of_table'.
-callback first_iter(#gen_tid{}, pos_integer()) -> [object()] | '$end_of_table'.
-callback last(#gen_tid{}, pos_integer()) -> [key()] | '$end_of_table'.
-callback last_iter(#gen_tid{}, pos_integer()) -> [object()] | '$end_of_table'.
-callback next(#gen_tid{}, key(), pos_integer()) -> [key()] | '$end_of_table'.
-callback next_iter(#gen_tid{}, key(), pos_integer()) -> [object()] | '$end_of_table'.
-callback prev(#gen_tid{}, key(), pos_integer()) -> [key()] | '$end_of_table'.
-callback prev_iter(#gen_tid{}, key(), pos_integer()) -> [object()] | '$end_of_table'.

-else. % -ifndef(old_callbacks).

Expand Down

0 comments on commit a18e29a

Please sign in to comment.