summaryrefslogtreecommitdiff
path: root/src/ddoc_cache/src/ddoc_cache_entry.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/ddoc_cache/src/ddoc_cache_entry.erl')
-rw-r--r--src/ddoc_cache/src/ddoc_cache_entry.erl73
1 files changed, 22 insertions, 51 deletions
diff --git a/src/ddoc_cache/src/ddoc_cache_entry.erl b/src/ddoc_cache/src/ddoc_cache_entry.erl
index 32d3ec1a7..5a1711dd8 100644
--- a/src/ddoc_cache/src/ddoc_cache_entry.erl
+++ b/src/ddoc_cache/src/ddoc_cache_entry.erl
@@ -43,17 +43,14 @@
do_open/1
]).
-
-include("ddoc_cache.hrl").
-
-ifndef(TEST).
-define(ENTRY_SHUTDOWN_TIMEOUT, 5000).
-else.
-define(ENTRY_SHUTDOWN_TIMEOUT, 500).
-endif.
-
-record(st, {
key,
val,
@@ -63,28 +60,22 @@
accessed
}).
-
dbname({Mod, Arg}) ->
Mod:dbname(Arg).
-
ddocid({Mod, Arg}) ->
Mod:ddocid(Arg).
-
recover({Mod, Arg}) ->
Mod:recover(Arg).
-
insert({Mod, Arg}, Value) ->
Mod:insert(Arg, Value).
-
start_link(Key, Default) ->
Pid = proc_lib:spawn_link(?MODULE, init, [{Key, Default}]),
{ok, Pid}.
-
shutdown(Pid) ->
Ref = erlang:monitor(process, Pid),
ok = gen_server:cast(Pid, shutdown),
@@ -98,7 +89,6 @@ shutdown(Pid) ->
erlang:exit({timeout, {entry_shutdown, Pid}})
end.
-
open(Pid, Key) ->
try
Resp = gen_server:call(Pid, open),
@@ -118,15 +108,12 @@ open(Pid, Key) ->
recover(Key)
end.
-
accessed(Pid) ->
gen_server:cast(Pid, accessed).
-
refresh(Pid) ->
gen_server:cast(Pid, force_refresh).
-
init({Key, undefined}) ->
true = ets:update_element(?CACHE, Key, {#entry.pid, self()}),
St = #st{
@@ -137,7 +124,6 @@ init({Key, undefined}) ->
},
?EVENT(started, Key),
gen_server:enter_loop(?MODULE, [], St);
-
init({Key, Wrapped}) ->
Default = ddoc_cache_value:unwrap(Wrapped),
Updates = [
@@ -158,7 +144,6 @@ init({Key, Wrapped}) ->
?EVENT(default_started, Key),
gen_server:enter_loop(?MODULE, [], St, hibernate).
-
terminate(_Reason, St) ->
#st{
key = Key,
@@ -172,30 +157,30 @@ terminate(_Reason, St) ->
true = ets:select_delete(?CACHE, CacheMSpec) < 2,
% We may have already deleted our LRU entry
% during shutdown
- if Ts == undefined -> ok; true ->
- LruMSpec = [{{{Ts, Key, self()}}, [], [true]}],
- true = ets:select_delete(?LRU, LruMSpec) < 2
+ if
+ Ts == undefined ->
+ ok;
+ true ->
+ LruMSpec = [{{{Ts, Key, self()}}, [], [true]}],
+ true = ets:select_delete(?LRU, LruMSpec) < 2
end,
% Blow away any current opener if it exists
- if not is_pid(Pid) -> ok; true ->
- catch exit(Pid, kill)
+ if
+ not is_pid(Pid) -> ok;
+ true -> catch exit(Pid, kill)
end,
ok.
-
handle_call(open, From, #st{opener = Pid} = St) when is_pid(Pid) ->
NewSt = St#st{
waiters = [From | St#st.waiters]
},
{noreply, NewSt};
-
handle_call(open, _From, St) ->
{reply, St#st.val, St};
-
handle_call(Msg, _From, St) ->
{stop, {bad_call, Msg}, {bad_call, Msg}, St}.
-
handle_cast(accessed, St) ->
?EVENT(accessed, St#st.key),
drain_accessed(),
@@ -203,7 +188,6 @@ handle_cast(accessed, St) ->
accessed = St#st.accessed + 1
},
{noreply, update_lru(NewSt)};
-
handle_cast(force_refresh, St) ->
% If we had frequent design document updates
% they could end up racing accessed events and
@@ -211,18 +195,18 @@ handle_cast(force_refresh, St) ->
% cache. To prevent this we just make sure that
% accessed is set to at least 1 before we
% execute a refresh.
- NewSt = if St#st.accessed > 0 -> St; true ->
- St#st{accessed = 1}
- end,
+ NewSt =
+ if
+ St#st.accessed > 0 -> St;
+ true -> St#st{accessed = 1}
+ end,
% We remove the cache entry value so that any
% new client comes to us for the refreshed
% value.
true = ets:update_element(?CACHE, St#st.key, {#entry.val, undefined}),
handle_cast(refresh, NewSt);
-
handle_cast(refresh, #st{accessed = 0} = St) ->
{stop, normal, St};
-
handle_cast(refresh, #st{opener = Ref} = St) when is_reference(Ref) ->
#st{
key = Key
@@ -233,7 +217,6 @@ handle_cast(refresh, #st{opener = Ref} = St) when is_reference(Ref) ->
accessed = 0
},
{noreply, NewSt};
-
handle_cast(refresh, #st{opener = Pid} = St) when is_pid(Pid) ->
catch exit(Pid, kill),
receive
@@ -244,15 +227,12 @@ handle_cast(refresh, #st{opener = Pid} = St) when is_pid(Pid) ->
accessed = 0
},
{noreply, NewSt};
-
handle_cast(shutdown, St) ->
remove_from_cache(St),
{stop, normal, St};
-
handle_cast(Msg, St) ->
{stop, {bad_cast, Msg}, St}.
-
handle_info({'DOWN', _, _, Pid, Resp}, #st{key = Key, opener = Pid} = St) ->
case Resp of
{open_ok, Key, {ok, Val}} ->
@@ -275,26 +255,22 @@ handle_info({'DOWN', _, _, Pid, Resp}, #st{key = Key, opener = Pid} = St) ->
respond(St#st.waiters, {Status, Other}),
{stop, normal, NewSt}
end;
-
handle_info(Msg, St) ->
{stop, {bad_info, Msg}, St}.
-
code_change(_, St, _) ->
{ok, St}.
-
spawn_opener(Key) ->
{Pid, _} = erlang:spawn_monitor(?MODULE, do_open, [Key]),
Pid.
-
start_timer() ->
TimeOut = config:get_integer(
- "ddoc_cache", "refresh_timeout", ?REFRESH_TIMEOUT),
+ "ddoc_cache", "refresh_timeout", ?REFRESH_TIMEOUT
+ ),
erlang:send_after(TimeOut, self(), {'$gen_cast', refresh}).
-
do_open(Key) ->
try recover(Key) of
Resp ->
@@ -303,26 +279,21 @@ do_open(Key) ->
erlang:exit({open_error, Key, {T, R, S}})
end.
-
update_lru(#st{key = Key, ts = Ts} = St) ->
remove_from_lru(Ts, Key),
NewTs = os:timestamp(),
true = ets:insert(?LRU, {{NewTs, Key, self()}}),
St#st{ts = NewTs}.
-
update_cache(#st{val = undefined} = St, Val) ->
true = ets:update_element(?CACHE, St#st.key, {#entry.val, Val}),
?EVENT(inserted, St#st.key);
-
update_cache(#st{val = V1} = _St, V2) when {open_ok, {ok, V2}} == V1 ->
?EVENT(update_noop, _St#st.key);
-
update_cache(St, Val) ->
true = ets:update_element(?CACHE, St#st.key, {#entry.val, Val}),
?EVENT(updated, {St#st.key, Val}).
-
remove_from_cache(St) ->
#st{
key = Key,
@@ -335,14 +306,15 @@ remove_from_cache(St) ->
?EVENT(removed, St#st.key),
ok.
-
remove_from_lru(Ts, Key) ->
- if Ts == undefined -> ok; true ->
- LruMSpec = [{{{Ts, Key, self()}}, [], [true]}],
- 1 = ets:select_delete(?LRU, LruMSpec)
+ if
+ Ts == undefined ->
+ ok;
+ true ->
+ LruMSpec = [{{{Ts, Key, self()}}, [], [true]}],
+ 1 = ets:select_delete(?LRU, LruMSpec)
end.
-
drain_accessed() ->
receive
{'$gen_cast', accessed} ->
@@ -351,6 +323,5 @@ drain_accessed() ->
ok
end.
-
respond(Waiters, Resp) ->
[gen_server:reply(W, Resp) || W <- Waiters].