From c0efb34c964b47c16855f880593752e52fd57e29 Mon Sep 17 00:00:00 2001 From: Magnus Ahltorp Date: Wed, 19 Nov 2014 04:06:19 +0100 Subject: ht: Only process a limited amount of entries per gen_server call --- src/ht.erl | 56 ++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 46 insertions(+), 10 deletions(-) diff --git a/src/ht.erl b/src/ht.erl index 4b08e34..96a6172 100644 --- a/src/ht.erl +++ b/src/ht.erl @@ -39,6 +39,9 @@ -include_lib("eunit/include/eunit.hrl"). -import(lists, [foreach/2, foldl/3, reverse/1]). +-define(MAX_READ_ENTRIES, 10000). +-define(MAX_CALC_ENTRIES, 10000). + %% Data types. -record(tree, {version :: integer(), evaluated :: integer(), @@ -52,9 +55,14 @@ start_link() -> start_link(NEntries) -> gen_server:start_link({local, ?MODULE}, ?MODULE, [NEntries], []). reset_tree(Arg) -> - call(?MODULE, {reset_tree, Arg}). + gen_server:call(?MODULE, {reset_tree, Arg}, infinity). load_tree(Version) -> - call(?MODULE, {load_tree, Version}). + case call(?MODULE, {load_tree, Version}) of + eagain -> + load_tree(Version); + Result -> + Result + end. stop() -> call(?MODULE, stop). size() -> @@ -62,9 +70,19 @@ size() -> add(Hash) -> call(?MODULE, {add, Hash}). root() -> - call(?MODULE, root). + case call(?MODULE, root) of + eagain -> + root(); + Result -> + Result + end. root(Version) -> - call(?MODULE, {root, Version}). + case call(?MODULE, {root, Version}) of + eagain -> + root(Version); + Result -> + Result + end. path(I, V) -> call(?MODULE, {path, I, V}). consistency(V1, V2) -> @@ -192,13 +210,25 @@ get_hash(Tree, {R, I}) -> head(Tree, -1) -> {Tree, hash(<<"">>)}; head(Tree = #tree{version = V}, Version) when Version == V -> - NewTree = update(Tree), - {NewTree, get_hash(NewTree, {depth(Tree) - 1, 0})}; + EndBound = min(Version, Tree#tree.evaluated + ?MAX_CALC_ENTRIES), + NewTree = update(Tree, EndBound), + case EndBound of + Version -> + {NewTree, get_hash(NewTree, {depth(Tree) - 1, 0})}; + _ -> + {NewTree, eagain} + end; head(Tree = #tree{version = V}, Version) when Version > V -> {Tree, enotimetravel}; head(Tree, Version) -> - NewTree = update(Tree, Version), - {NewTree, old_version_tree_head(NewTree, Version)}. + EndBound = min(Version, Tree#tree.evaluated + ?MAX_CALC_ENTRIES), + NewTree = update(Tree, EndBound), + case EndBound of + Version -> + {NewTree, old_version_tree_head(NewTree, Version)}; + _ -> + {NewTree, eagain} + end. -spec old_version_tree_head(tree(), non_neg_integer()) -> binary(). old_version_tree_head(Tree, Version) -> @@ -262,12 +292,18 @@ add(Tree = #tree{version = V, store = Store}, Hash) -> Tree#tree{version = V + 1, store = ts:add(Store, 0, Hash)}. read_new_entries(State, Version) when is_integer(Version) -> - NewEntries = db:get_by_indices(State#tree.version + 1, Version, {sorted, true}), + EndBound = min(Version, State#tree.version + ?MAX_READ_ENTRIES), + NewEntries = db:get_by_indices(State#tree.version + 1, EndBound, {sorted, true}), NewState = foldl(fun(Hash, Tree) -> add(Tree, Hash) end, State, [H || {_I, H, _E} <- NewEntries]), - {ok, NewState}. + case EndBound of + Version -> + {ok, NewState}; + _ -> + {eagain, NewState} + end. %% @doc Return a new tree. -spec new(list()) -> tree(). -- cgit v1.1