Skip to content
This repository has been archived by the owner on May 25, 2021. It is now read-only.

Commit

Permalink
Minor optimizations for couch_event_registry
Browse files Browse the repository at this point in the history
Mostly making use of batch operations with match and multiple inserts. I
tried some more aggressive optimizations before these but those only
managed to make things slower. The major thing I tried was to use the
zero timeout trick to collect messages and then batch load those into
ets but that only managed to cause a large number of timeouts.
  • Loading branch information
davisp authored and rnewson committed Jul 30, 2014
1 parent a8b378b commit 2ad40ed
Showing 1 changed file with 53 additions and 30 deletions.
83 changes: 53 additions & 30 deletions src/couch_event_registry.erl
Expand Up @@ -57,63 +57,86 @@ terminate(_Reason, _St) ->


handle_call({register, Pid, DbNames}, _From, St) ->
lists:foreach(fun(DbName) ->
ets:insert(?REGISTRY_TABLE, #client{dbname=DbName, pid=Pid})
end, DbNames),
case ets:lookup(?MONITOR_TABLE, Pid) of
[] ->
ToAdd = [#client{dbname=DBN, pid=Pid} || DBN <- DbNames],
ets:insert(?REGISTRY_TABLE, ToAdd),
case ets:member(?MONITOR_TABLE, Pid) of
true ->
ok;
false ->
Ref = erlang:monitor(process, Pid),
ets:insert(?MONITOR_TABLE, {Pid, Ref});
[{Pid, _}] ->
ok
ets:insert(?MONITOR_TABLE, {Pid, Ref})
end,
{reply, ok, St};

handle_call({unregister, Pid, DbNames}, _From, St) ->
% TODO: Check into a multi-pattern matchspec and the
% use of select_delete to see if that's faster.
lists:foreach(fun(DbName) ->
unregister_pattern(#client{dbname=DbName, pid=Pid, _='_'})
ets:match_delete(?REGISTRY_TABLE, pattern(DbName, Pid))
end, DbNames),
maybe_drop_monitor(Pid),
{reply, ok, St};

handle_call({unregister_all, Pid}, _From, St) ->
unregister_pattern(#client{pid=Pid, _='_'}),
ets:match_delete(?REGISTRY_TABLE, pattern(Pid)),
drop_monitor(Pid),
{reply, ok, St};

handle_call(Msg, From, St) ->
couch_log:notice("~s ignoring call ~w from ~w", [?MODULE, Msg, From]),
{reply, ignored, St, 0}.
{reply, ignored, St}.


handle_cast(Msg, St) ->
couch_log:notice("~s ignoring cast ~w", [?MODULE, Msg]),
{noreply, St, 0}.
{noreply, St}.


handle_info({'DOWN', _Ref, process, Pid, _Reason}, St) ->
unregister_pattern(#client{pid=Pid, _='_'}),
{noreply, St};
ets:match_delete(?REGISTRY_TABLE, pattern(Pid)),
ets:delete(?REGISTRY_TABLE, Pid),
{norepy, St};

handle_info(Msg, St) ->
couch_log:notice("~s ignoring info ~w", [?MODULE, Msg]),
{noreply, St, 0}.
{noreply, St}.


code_change(_OldVsn, St, _Extra) ->
{ok, St}.


unregister_pattern(Pattern) ->
Clients = ets:match_object(?REGISTRY_TABLE, Pattern),
Refs = lists:foldl(fun(#client{pid=Pid}=Cli, Acc) ->
ets:delete_object(?REGISTRY_TABLE, Cli),
case ets:lookup(?MONITOR_TABLE, Pid) of
[{Pid, Ref}] ->
ets:delete(?MONITOR_TABLE, Pid),
[Ref | Acc];
[] ->
Acc
end
end, [], Clients),
lists:foreach(fun(Ref) ->
erlang:demonitor(Ref, [flush])
end, Refs).
maybe_drop_monitor(Pid) ->
case ets:select_count(?REGISTRY_TABLE, mspec(Pid)) of
0 -> drop_monitor(Pid);
_ -> ok
end.


drop_monitor(Pid) ->
case ets:lookup(?MONITOR_TABLE, Pid) of
[{Pid, Ref}] ->
ets:delete(?MONITOR_TABLE, Pid),
erlang:demonitor(Ref, [flush]);
[] ->
ok
end.


-compile({inline, [
mspec/1,
pattern/1,
pattern/2
]}).


mspec(Pid) ->
[{pattern(Pid), [], ['$_']}].


pattern(Pid) ->
#client{pid=Pid, _='_'}.


pattern(DbName, Pid) ->
#client{dbname=DbName, pid=Pid, _='_'}.

0 comments on commit 2ad40ed

Please sign in to comment.