Skip to content

Commit

Permalink
FIXUP: Reuse fabric lookup results
Browse files Browse the repository at this point in the history
On suggestion from @chewbranca I've gone ahead and made the optimization
to insert the revid or non-revid specific version of the request design
document.
  • Loading branch information
davisp committed Jul 6, 2017
1 parent 0e9aadc commit 85b5385
Show file tree
Hide file tree
Showing 13 changed files with 161 additions and 42 deletions.
33 changes: 29 additions & 4 deletions src/ddoc_cache/src/ddoc_cache_entry.erl
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@
dbname/1,
ddocid/1,
recover/1,
insert/2,

start_link/1,
start_link/2,
shutdown/1,
open/2,
accessed/1,
Expand Down Expand Up @@ -65,8 +66,12 @@ recover({Mod, Arg}) ->
Mod:recover(Arg).


start_link(Key) ->
Pid = proc_lib:spawn_link(?MODULE, init, [Key]),
insert({Mod, Arg}, Value) ->
Mod:insert(Arg, Value).


start_link(Key, Default) ->
Pid = proc_lib:spawn_link(?MODULE, init, [{Key, Default}]),
{ok, Pid}.


Expand Down Expand Up @@ -99,7 +104,7 @@ refresh(Pid) ->
gen_server:cast(Pid, force_refresh).


init(Key) ->
init({Key, undefined}) ->
true = ets:update_element(?CACHE, Key, {#entry.pid, self()}),
St = #st{
key = Key,
Expand All @@ -108,6 +113,26 @@ init(Key) ->
accessed = 1
},
?EVENT(started, Key),
gen_server:enter_loop(?MODULE, [], St);

init({Key, Default}) ->
Updates = [
{#entry.val, Default},
{#entry.pid, self()}
],
NewTs = os:timestamp(),
true = ets:update_element(?CACHE, Key, Updates),
true = ets:insert(?LRU, {{NewTs, Key, self()}}),
Msg = {'$gen_cast', refresh},
St = #st{
key = Key,
val = {open_ok, {ok, Default}},
opener = erlang:send_after(?REFRESH_TIMEOUT, self(), Msg),
waiters = undefined,
ts = NewTs,
accessed = 1
},
?EVENT(default_started, Key),
gen_server:enter_loop(?MODULE, [], St).


Expand Down
7 changes: 6 additions & 1 deletion src/ddoc_cache/src/ddoc_cache_entry_custom.erl
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
-export([
dbname/1,
ddocid/1,
recover/1
recover/1,
insert/2
]).


Expand All @@ -30,3 +31,7 @@ ddocid(_) ->

recover({DbName, Mod}) ->
Mod:recover(DbName).


insert(_, _) ->
ok.
13 changes: 12 additions & 1 deletion src/ddoc_cache/src/ddoc_cache_entry_ddocid.erl
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
-export([
dbname/1,
ddocid/1,
recover/1
recover/1,
insert/2
]).


Expand All @@ -33,3 +34,13 @@ ddocid({_, DDocId}) ->

recover({DbName, DDocId}) ->
fabric:open_doc(DbName, DDocId, [ejson_body, ?ADMIN_CTX]).


insert({DbName, DDocId}, {ok, #doc{revs = Revs} = DDoc}) ->
{Depth, [RevId | _]} = Revs,
Rev = {Depth, RevId},
Key = {ddoc_cache_entry_ddocid_rev, {DbName, DDocId, Rev}},
spawn(fun() -> ddoc_cache_lru:insert(Key, DDoc) end);

insert(_, _) ->
ok.
12 changes: 11 additions & 1 deletion src/ddoc_cache/src/ddoc_cache_entry_ddocid_rev.erl
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
-export([
dbname/1,
ddocid/1,
recover/1
recover/1,
insert/2
]).


Expand All @@ -35,3 +36,12 @@ recover({DbName, DDocId, Rev}) ->
Opts = [ejson_body, ?ADMIN_CTX],
{ok, [Resp]} = fabric:open_revs(DbName, DDocId, [Rev], Opts),
Resp.


insert({DbName, DDocId, _Rev}, {ok, #doc{} = DDoc}) ->
Key = {ddoc_cache_entry_ddocid, {DbName, DDocId}},
spawn(fun() -> ddoc_cache_lru:insert(Key, DDoc) end);

insert(_, _) ->
ok.

7 changes: 6 additions & 1 deletion src/ddoc_cache/src/ddoc_cache_entry_validation_funs.erl
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
-export([
dbname/1,
ddocid/1,
recover/1
recover/1,
insert/2
]).


Expand All @@ -37,3 +38,7 @@ recover(DbName) ->
end
end, DDocs),
{ok, Funs}.


insert(_, _) ->
ok.
30 changes: 22 additions & 8 deletions src/ddoc_cache/src/ddoc_cache_lru.erl
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
-export([
start_link/0,
open/1,
insert/2,
refresh/2
]).

Expand Down Expand Up @@ -53,9 +54,9 @@ start_link() ->
open(Key) ->
try ets:lookup(?CACHE, Key) of
[] ->
lru_start(Key);
lru_start(Key, true);
[#entry{pid = undefined}] ->
lru_start(Key);
lru_start(Key, false);
[#entry{val = undefined, pid = Pid}] ->
couch_stats:increment_counter([ddoc_cache, miss]),
ddoc_cache_entry:open(Pid, Key);
Expand All @@ -69,6 +70,15 @@ open(Key) ->
end.


insert(Key, Value) ->
case ets:lookup(?CACHE, Key) of
[] ->
gen_server:call(?MODULE, {start, Key, Value}, infinity);
[#entry{}] ->
ok
end.


refresh(DbName, DDocIds) ->
gen_server:cast(?MODULE, {refresh, DbName, DDocIds}).

Expand Down Expand Up @@ -96,7 +106,7 @@ terminate(_Reason, St) ->
ok.


handle_call({start, Key}, _From, St) ->
handle_call({start, Key, Default}, _From, St) ->
#st{
pids = Pids,
dbs = Dbs,
Expand All @@ -108,7 +118,7 @@ handle_call({start, Key}, _From, St) ->
case trim(St, CurSize, max(0, MaxSize)) of
{ok, N} ->
true = ets:insert_new(?CACHE, #entry{key = Key}),
{ok, Pid} = ddoc_cache_entry:start_link(Key),
{ok, Pid} = ddoc_cache_entry:start_link(Key, Default),
true = ets:update_element(?CACHE, Key, {#entry.pid, Pid}),
ok = khash:put(Pids, Pid, Key),
store_key(Dbs, Key, Pid),
Expand Down Expand Up @@ -167,7 +177,7 @@ handle_cast({do_refresh, DbName, DDocIdList}, St) ->
lists:foreach(fun(DDocId) ->
case khash:lookup(DDocIds, DDocId) of
{value, Keys} ->
khash:fold(Keys, fun(_, Pid, _) ->
khash:fold(Keys, fun(Key, Pid, _) ->
ddoc_cache_entry:refresh(Pid)
end, nil);
not_found ->
Expand Down Expand Up @@ -222,11 +232,15 @@ handle_db_event(_DbName, _Event, St) ->
{ok, St}.


lru_start(Key) ->
case gen_server:call(?MODULE, {start, Key}, infinity) of
lru_start(Key, DoInsert) ->
case gen_server:call(?MODULE, {start, Key, undefined}, infinity) of
{ok, Pid} ->
couch_stats:increment_counter([ddoc_cache, miss]),
ddoc_cache_entry:open(Pid, Key);
Resp = ddoc_cache_entry:open(Pid, Key),
if not DoInsert -> ok; true ->
ddoc_cache_entry:insert(Key, Resp)
end,
Resp;
full ->
couch_stats:increment_counter([ddoc_cache, recovery]),
ddoc_cache_entry:recover(Key)
Expand Down
39 changes: 30 additions & 9 deletions src/ddoc_cache/test/ddoc_cache_basic_test.erl
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,22 @@ recover(DbName) ->
{ok, {DbName, totes_custom}}.


start_couch() ->
Ctx = ddoc_cache_tutil:start_couch(),
meck:new(ddoc_cache_ev, [passthrough]),
Ctx.


stop_couch(Ctx) ->
meck:unload(),
ddoc_cache_tutil:stop_couch(Ctx).


check_basic_test_() ->
{
setup,
fun ddoc_cache_tutil:start_couch/0,
fun ddoc_cache_tutil:stop_couch/1,
fun start_couch/0,
fun stop_couch/1,
{with, [
fun cache_ddoc/1,
fun cache_ddoc_rev/1,
Expand All @@ -58,25 +69,31 @@ check_no_vdu_test_() ->

cache_ddoc({DbName, _}) ->
ddoc_cache_tutil:clear(),
meck:reset(ddoc_cache_ev),
?assertEqual(0, ets:info(?CACHE, size)),
Resp1 = ddoc_cache:open_doc(DbName, ?FOOBAR),
?assertMatch({ok, #doc{id = ?FOOBAR}}, Resp1),
?assertEqual(1, ets:info(?CACHE, size)),
meck:wait(ddoc_cache_ev, event, [started, '_'], 1000),
meck:wait(ddoc_cache_ev, event, [default_started, '_'], 1000),
?assertEqual(2, ets:info(?CACHE, size)),
Resp2 = ddoc_cache:open_doc(DbName, ?FOOBAR),
?assertEqual(Resp1, Resp2),
?assertEqual(1, ets:info(?CACHE, size)).
?assertEqual(2, ets:info(?CACHE, size)).


cache_ddoc_rev({DbName, _}) ->
ddoc_cache_tutil:clear(),
meck:reset(ddoc_cache_ev),
Rev = ddoc_cache_tutil:get_rev(DbName, ?FOOBAR),
?assertEqual(0, ets:info(?CACHE, size)),
Resp1 = ddoc_cache:open_doc(DbName, ?FOOBAR, Rev),
?assertMatch({ok, #doc{id = ?FOOBAR}}, Resp1),
?assertEqual(1, ets:info(?CACHE, size)),
meck:wait(ddoc_cache_ev, event, [started, '_'], 1000),
meck:wait(ddoc_cache_ev, event, [default_started, '_'], 1000),
?assertEqual(2, ets:info(?CACHE, size)),
Resp2 = ddoc_cache:open_doc(DbName, ?FOOBAR, Rev),
?assertEqual(Resp1, Resp2),
?assertEqual(1, ets:info(?CACHE, size)),
?assertEqual(2, ets:info(?CACHE, size)),

% Assert that the non-rev cache entry is separate
Resp3 = ddoc_cache:open_doc(DbName, ?FOOBAR),
Expand Down Expand Up @@ -108,12 +125,16 @@ cache_custom({DbName, _}) ->

cache_ddoc_refresher_unchanged({DbName, _}) ->
ddoc_cache_tutil:clear(),
meck:reset(ddoc_cache_ev),
?assertEqual(0, ets:info(?CACHE, size)),
ddoc_cache:open_doc(DbName, ?FOOBAR),
[Entry1] = ets:lookup(?CACHE, ets:first(?CACHE)),
meck:wait(ddoc_cache_ev, event, [started, '_'], 1000),
meck:wait(ddoc_cache_ev, event, [default_started, '_'], 1000),
Tab1 = [_, _] = lists:sort(ets:tab2list(?CACHE)),
ddoc_cache:open_doc(DbName, ?FOOBAR),
[Entry2] = ets:lookup(?CACHE, ets:first(?CACHE)),
?assertEqual(Entry1, Entry2).
meck:wait(ddoc_cache_ev, event, [accessed, '_'], 1000),
Tab2 = lists:sort(ets:tab2list(?CACHE)),
?assertEqual(Tab2, Tab1).


dont_cache_not_found({DbName, _}) ->
Expand Down
6 changes: 3 additions & 3 deletions src/ddoc_cache/test/ddoc_cache_entry_test.erl
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ check_entry_test_() ->
cancel_and_replace_opener(_) ->
Key = {ddoc_cache_entry_custom, {<<"foo">>, ?MODULE}},
true = ets:insert_new(?CACHE, #entry{key = Key}),
{ok, Entry} = ddoc_cache_entry:start_link(Key),
{ok, Entry} = ddoc_cache_entry:start_link(Key, undefined),
Opener1 = element(4, sys:get_state(Entry)),
Ref1 = erlang:monitor(process, Opener1),
gen_server:cast(Entry, force_refresh),
Expand All @@ -78,7 +78,7 @@ condenses_access_messages({DbName, _}) ->
meck:reset(ddoc_cache_ev),
Key = {ddoc_cache_entry_custom, {DbName, ?MODULE}},
true = ets:insert(?CACHE, #entry{key = Key}),
{ok, Entry} = ddoc_cache_entry:start_link(Key),
{ok, Entry} = ddoc_cache_entry:start_link(Key, undefined),
erlang:suspend_process(Entry),
lists:foreach(fun(_) ->
gen_server:cast(Entry, accessed)
Expand All @@ -105,7 +105,7 @@ evict_when_not_accessed(_) ->
meck:reset(ddoc_cache_ev),
Key = {ddoc_cache_entry_custom, {<<"bar">>, ?MODULE}},
true = ets:insert_new(?CACHE, #entry{key = Key}),
{ok, Entry} = ddoc_cache_entry:start_link(Key),
{ok, Entry} = ddoc_cache_entry:start_link(Key, undefined),
Ref = erlang:monitor(process, Entry),
?assertEqual(1, element(7, sys:get_state(Entry))),
ok = gen_server:cast(Entry, refresh),
Expand Down
6 changes: 4 additions & 2 deletions src/ddoc_cache/test/ddoc_cache_eviction_test.erl
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,10 @@ check_upgrade_clause({DbName, _}) ->
ddoc_cache_tutil:clear(),
meck:reset(ddoc_cache_ev),
{ok, _} = ddoc_cache:open_doc(DbName, ?FOOBAR),
?assertEqual(1, ets:info(?CACHE, size)),
meck:wait(ddoc_cache_ev, event, [started, '_'], 1000),
meck:wait(ddoc_cache_ev, event, [default_started, '_'], 1000),
?assertEqual(2, ets:info(?CACHE, size)),
gen_server:cast(ddoc_cache_opener, {do_evict, DbName}),
meck:wait(ddoc_cache_ev, event, [evicted, DbName], 1000),
meck:wait(ddoc_cache_ev, event, [removed, '_'], 1000),
meck:wait(2, ddoc_cache_ev, event, [removed, '_'], 1000),
?assertEqual(0, ets:info(?CACHE, size)).
1 change: 1 addition & 0 deletions src/ddoc_cache/test/ddoc_cache_no_cache_test.erl
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
ddoc(DDocId) ->
{ok, #doc{
id = DDocId,
revs = {1, [<<"deadbeefdeadbeef">>]},
body = {[
{<<"ohai">>, null}
]}
Expand Down
2 changes: 1 addition & 1 deletion src/ddoc_cache/test/ddoc_cache_open_error_test.erl
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ stop_couch(Ctx) ->
ddoc_cache_tutil:stop_couch(Ctx).


check_basic_test_() ->
check_open_error_test_() ->
{
setup,
fun start_couch/0,
Expand Down

0 comments on commit 85b5385

Please sign in to comment.