You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by rn...@apache.org on 2014/08/01 11:09:57 UTC

[01/35] git commit: Initial commit

Repository: couchdb-couch-event
Updated Branches:
  refs/heads/windsor-merge [created] b52b9c5ab


Initial commit


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/commit/73b38e88
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/tree/73b38e88
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/diff/73b38e88

Branch: refs/heads/windsor-merge
Commit: 73b38e8866c4c90352945f349c223726c7e0e590
Parents: 
Author: Paul J. Davis <pa...@gmail.com>
Authored: Mon Apr 22 12:44:14 2013 -0500
Committer: Robert Newson <rn...@apache.org>
Committed: Wed Jul 30 17:31:53 2014 +0100

----------------------------------------------------------------------
 README.md | 3 +++
 1 file changed, 3 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/73b38e88/README.md
----------------------------------------------------------------------
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..ab2e568
--- /dev/null
+++ b/README.md
@@ -0,0 +1,3 @@
+# Couch Event Notifications
+
+The replacement for couch\_db\_update and related code.


[07/35] git commit: Fix start/start_link return values

Posted by rn...@apache.org.
Fix start/start_link return values


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/commit/a280611c
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/tree/a280611c
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/diff/a280611c

Branch: refs/heads/windsor-merge
Commit: a280611ccc81431c8763e9d01e597524001ae881
Parents: 320cf0c
Author: Paul J. Davis <pa...@gmail.com>
Authored: Tue Apr 23 15:41:27 2013 -0500
Committer: Robert Newson <rn...@apache.org>
Committed: Wed Jul 30 17:36:13 2014 +0100

----------------------------------------------------------------------
 src/couch_event_listener.erl | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/a280611c/src/couch_event_listener.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_listener.erl b/src/couch_event_listener.erl
index 042500f..7c942bd 100644
--- a/src/couch_event_listener.erl
+++ b/src/couch_event_listener.erl
@@ -51,7 +51,8 @@ behaviour_info(_) ->
 
 
 start(Mod, Arg, Options) ->
-    erlang:spawn(?MODULE, do_init, [Mod, Arg, Options]).
+    Pid = erlang:spawn(?MODULE, do_init, [Mod, Arg, Options]),
+    {ok, Pid}.
 
 
 start(Name, Mod, Arg, Options) ->
@@ -64,7 +65,8 @@ start(Name, Mod, Arg, Options) ->
 
 
 start_link(Mod, Arg, Options) ->
-    erlang:spawn_link(?MODULE, do_init, [Mod, Arg, Options]).
+    Pid = erlang:spawn_link(?MODULE, do_init, [Mod, Arg, Options]),
+    {ok, Pid}.
 
 
 start_link(Name, Mod, Arg, Options) ->


[21/35] git commit: Fix minor syntax errors and typos

Posted by rn...@apache.org.
Fix minor syntax errors and typos


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/commit/ed821717
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/tree/ed821717
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/diff/ed821717

Branch: refs/heads/windsor-merge
Commit: ed82171709506cc4ba4148e9d3aba4a9cd87c98f
Parents: 2bd7db0
Author: Paul J. Davis <pa...@gmail.com>
Authored: Wed Apr 24 14:17:18 2013 -0500
Committer: Robert Newson <rn...@apache.org>
Committed: Wed Jul 30 17:42:04 2014 +0100

----------------------------------------------------------------------
 src/couch_event_listener_mfa.erl | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/ed821717/src/couch_event_listener_mfa.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_listener_mfa.erl b/src/couch_event_listener_mfa.erl
index 81adb8f..7b13604 100644
--- a/src/couch_event_listener_mfa.erl
+++ b/src/couch_event_listener_mfa.erl
@@ -17,7 +17,7 @@
 -export([
     start_link/4,
     enter_loop/4,
-    stop/1,
+    stop/1
 ]).
 
 -export([
@@ -71,7 +71,7 @@ terminate(_Reason, _MFA) ->
 
 handle_event(DbName, Event, #st{mod=Mod, func=Func, state=State}=St) ->
     case (catch Mod:Func(DbName, Event, State)) of
-        {ok, NewSt} ->
+        {ok, NewState} ->
             {ok, St#st{state=NewState}};
         stop ->
             {stop, normal, St};


[31/35] git commit: Kill couch_db_event with supervisor functions

Posted by rn...@apache.org.
Kill couch_db_event with supervisor functions

Apparently gen_event ignores unknown kill messages so we'll force a
clean shutdown with superisor functions.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/commit/de231715
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/tree/de231715
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/diff/de231715

Branch: refs/heads/windsor-merge
Commit: de231715e270d685389e0e8e79eed2715bc1e61c
Parents: 022af54
Author: Paul J. Davis <pa...@gmail.com>
Authored: Sat Jun 15 13:13:05 2013 -0500
Committer: Robert Newson <rn...@apache.org>
Committed: Wed Jul 30 17:49:11 2014 +0100

----------------------------------------------------------------------
 src/couch_event_server.erl | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/de231715/src/couch_event_server.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_server.erl b/src/couch_event_server.erl
index 1bf8f1e..bd291aa 100644
--- a/src/couch_event_server.erl
+++ b/src/couch_event_server.erl
@@ -126,7 +126,10 @@ watchdog() ->
     Handlers = gen_event:which_handlers(couch_db_update),
     case length(Handlers) > 0 of
         true ->
-            exit(whereis(couch_db_update), force_upgrade);
+            supervisor:terminate_child(
+                    couch_primary_services, couch_db_update_event),
+            supervisor:restart_child(
+                    couch_primary_services, couch_db_update_event);
         false ->
             ok
     end,


[28/35] git commit: Fix compilation warning by sending not_registered

Posted by rn...@apache.org.
Fix compilation warning by sending not_registered


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/commit/2bb6b744
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/tree/2bb6b744
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/diff/2bb6b744

Branch: refs/heads/windsor-merge
Commit: 2bb6b744636b83fa728ee4ab7a8bed62bcbcd11d
Parents: 6b82918
Author: Adam Kocoloski <ad...@cloudant.com>
Authored: Fri May 24 14:10:49 2013 -0400
Committer: Robert Newson <rn...@apache.org>
Committed: Wed Jul 30 17:47:49 2014 +0100

----------------------------------------------------------------------
 src/couch_event_server.erl | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/2bb6b744/src/couch_event_server.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_server.erl b/src/couch_event_server.erl
index 77e6ce3..866bf7c 100644
--- a/src/couch_event_server.erl
+++ b/src/couch_event_server.erl
@@ -66,14 +66,15 @@ handle_call({register, Pid, NewDbNames}, _From, St) ->
     {reply, ok, St};
 
 handle_call({unregister, Pid}, _From, St) ->
-    case khash:get(St#st.by_pid, Pid) of
+    Reply = case khash:get(St#st.by_pid, Pid) of
         undefined ->
-            {reply, not_registered, St};
+            not_registered;
         {Ref, OldDbNames} ->
             unregister(St, Pid, OldDbNames),
-            erlang:demonitor(Ref, [flush])
+            erlang:demonitor(Ref, [flush]),
+            ok
     end,
-    {reply, ok, St};
+    {reply, Reply, St};
 
 handle_call(Msg, From, St) ->
     couch_log:notice("~s ignoring call ~w from ~w", [?MODULE, Msg, From]),
@@ -151,4 +152,3 @@ rem_listener(ByDbName, DbName, Pid) ->
     if Size > 0 -> ok; true ->
         khash:del(ByDbName, DbName)
     end.
-            


[23/35] git commit: Add a event count metrics

Posted by rn...@apache.org.
Add a event count metrics


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/commit/a8b378b9
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/tree/a8b378b9
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/diff/a8b378b9

Branch: refs/heads/windsor-merge
Commit: a8b378b9967b56c3e8473931d00adf691d18b863
Parents: 7d5c7e1
Author: Paul J. Davis <pa...@gmail.com>
Authored: Fri Apr 26 13:50:14 2013 -0500
Committer: Robert Newson <rn...@apache.org>
Committed: Wed Jul 30 17:42:31 2014 +0100

----------------------------------------------------------------------
 src/couch_event_dist.erl | 21 +++++++++++++--------
 1 file changed, 13 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/a8b378b9/src/couch_event_dist.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_dist.erl b/src/couch_event_dist.erl
index 7f99a2d..95aaf65 100644
--- a/src/couch_event_dist.erl
+++ b/src/couch_event_dist.erl
@@ -54,10 +54,10 @@ handle_call(Msg, From, St) ->
 
 
 handle_cast({DbName, Event}, #st{batch_size=BS}=St) when is_binary(DbName) ->
-    P1 = #client{dbname=DbName, _='_'},
-    notify_clients(ets:select(?REGISTRY_TABLE, P1, BS), DbName, Event),
-    P2 = #client{dbname=all_dbs, _='_'},
-    notify_clients(ets:select(?REGISTRY_TABLE, P2, BS), DbName, Event),
+    margaret_counter:increment([couch_event, events_received]),
+    T1 = notify_clients(#client{dbname=DbName, _='_'}, BS, DbName, Event),
+    T2 = notify_clients(#client{dbname=all_dbs, _='_'}, BS, DbName, Event),
+    margaret_counter:increment([couch_event, events_delivered], T1 + T2),
     {noreply, St};
 
 handle_cast(Msg, St) ->
@@ -74,10 +74,15 @@ code_change(_OldVsn, St, _Extra) ->
     {ok, St}.
 
 
-notify_clients('$end_of_table', _DbName, _Event) ->
-    ok;
-notify_clients({Clients, Cont}, DbName, Event) ->
+notify_clients(Pattern, BatchSize, DbName, Event) ->
+    MSpec = [{Pattern, [], ['$_']}],
+    do_notify(ets:select(?REGISTRY_TABLE, MSpec, BatchSize), DbName, Event, 0).
+
+
+do_notify('$end_of_table', _DbName, _Event, Total) ->
+    Total;
+do_notify({Clients, Cont}, DbName, Event, Total) ->
     lists:foreach(fun(#client{pid=Pid}) ->
         Pid ! {'$couch_event', DbName, Event}
     end, Clients),
-    notify_clients(ets:select(Cont), DbName, Event).
+    do_notify(ets:select(Cont), DbName, Event, Total + length(Clients)).


[09/35] git commit: Add an API for the common case

Posted by rn...@apache.org.
Add an API for the common case

Most of our current event listeners are single functions that don't
carry much state. Rather than force us to write a behavior module for
every one of these cases we can use this link_listener/4,
stop_listener/1 API to handle this common pattern.

Under the covers this just wraps couch_event_listener rather thinly to
give us the single callback export version of listening for events.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/commit/bf25e9f0
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/tree/bf25e9f0
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/diff/bf25e9f0

Branch: refs/heads/windsor-merge
Commit: bf25e9f0b3fd763b1d8e657ea3ef828747437e15
Parents: 8f63a78
Author: Paul J. Davis <pa...@gmail.com>
Authored: Tue Apr 23 16:37:08 2013 -0500
Committer: Robert Newson <rn...@apache.org>
Committed: Wed Jul 30 17:36:40 2014 +0100

----------------------------------------------------------------------
 src/couch_event.erl              | 29 +++++++++---
 src/couch_event_listener_mfa.erl | 85 +++++++++++++++++++++++++++++++++++
 2 files changed, 107 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/bf25e9f0/src/couch_event.erl
----------------------------------------------------------------------
diff --git a/src/couch_event.erl b/src/couch_event.erl
index ffee077..fd04824 100644
--- a/src/couch_event.erl
+++ b/src/couch_event.erl
@@ -13,20 +13,39 @@
 -module(couch_event).
 
 -export([
+    notify/2
+]).
+
+-export([
+    link_listener/4,
+    stop_listener/1
+]).
+
+-export([
     register/2,
     register_many/2,
     register_all/1,
     unregister/2,
     unregister_many/2,
-    unregister_all/1,
-    notify/2
+    unregister_all/1
 ]).
 
-
 -define(REGISTRY, couch_event_registry).
 -define(DIST, couch_event_dist).
 
 
+notify(DbName, Event) ->
+    gen_server:cast(?DIST, {DbName, Event}).
+
+
+link_listener(Module, Function, State, Options) ->
+    couch_event_listener_mfa:start_link(Module, Function, State, Options).
+
+
+stop_listener(Pid) ->
+    couch_event_listener_mfa:stop(Pid).
+
+
 register(Pid, DbName) ->
     gen_server:call(?REGISTRY, {register, Pid, [DbName]}).
 
@@ -49,7 +68,3 @@ unregister_many(Pid, DbNames) when is_list(DbNames) ->
 
 unregister_all(Pid) ->
     gen_server:call(?REGISTRY, {unregister, Pid}).
-
-
-notify(DbName, Event) ->
-    gen_server:cast(?DIST, {DbName, Event}).

http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/bf25e9f0/src/couch_event_listener_mfa.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_listener_mfa.erl b/src/couch_event_listener_mfa.erl
new file mode 100644
index 0000000..2231448
--- /dev/null
+++ b/src/couch_event_listener_mfa.erl
@@ -0,0 +1,85 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-module(couch_event_listener_mfa).
+-behavior(couch_event_listener).
+
+
+-export([
+    start_link/4,
+    stop/1
+]).
+
+-export([
+    init/1,
+    terminate/2,
+    handle_event/3,
+    handle_cast/2,
+    handle_info/2
+]).
+
+
+-record(st, {
+    mod,
+    func,
+    state,
+    parent
+}).
+
+
+start_link(Mod, Func, State, Options) ->
+    Arg = {self(), Mod, Func, State},
+    couch_event_listener:start_link(?MODULE, Arg, Options).
+
+
+stop(Pid) ->
+    couch_event_listener:stop(Pid).
+
+
+init({Parent, Mod, Func, State}) ->
+    erlang:monitor(process, Parent),
+    {ok, #st{
+        mod = Mod,
+        func = Func,
+        state = State,
+        parent = Parent
+    }}.
+
+
+terminate(_Reason, _MFA) ->
+    ok.
+
+
+handle_event(DbName, Event, #st{mod=Mod, func=Func, state=State}=St) ->
+    case (catch Mod:Func(DbName, Event, State)) of
+        {ok, NewSt} ->
+            {ok, St#st{state=NewState}};
+        stop ->
+            {stop, normal, St};
+        Else ->
+            erlang:error(Else)
+    end.
+
+
+handle_cast(shutdown, St) ->
+    {stop, normal, St};
+
+handle_cast(_Msg, St) ->
+    {ok, St}.
+
+
+handle_info({'DOWN', _Ref, process, Parent, _Reason}, #st{parent=Parent}=St) ->
+    {stop, normal, St};
+
+handle_info(_Msg, St) ->
+    {ok, St}.
+


[04/35] git commit: Add an API to register for multiple DbNames

Posted by rn...@apache.org.
Add an API to register for multiple DbNames

Just a convenience thing for code that may want to listen to more than
one database's update notifications.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/commit/475af68c
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/tree/475af68c
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/diff/475af68c

Branch: refs/heads/windsor-merge
Commit: 475af68c2d99825efb4c492183ebdf5175a52fba
Parents: f4c80d7
Author: Paul J. Davis <pa...@gmail.com>
Authored: Tue Apr 23 14:41:24 2013 -0500
Committer: Robert Newson <rn...@apache.org>
Committed: Wed Jul 30 17:35:36 2014 +0100

----------------------------------------------------------------------
 src/couch_event.erl          | 16 +++++++++++++---
 src/couch_event_registry.erl | 16 ++++++++--------
 2 files changed, 21 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/475af68c/src/couch_event.erl
----------------------------------------------------------------------
diff --git a/src/couch_event.erl b/src/couch_event.erl
index eaa4c88..ffee077 100644
--- a/src/couch_event.erl
+++ b/src/couch_event.erl
@@ -14,8 +14,10 @@
 
 -export([
     register/2,
+    register_many/2,
     register_all/1,
     unregister/2,
+    unregister_many/2,
     unregister_all/1,
     notify/2
 ]).
@@ -26,15 +28,23 @@
 
 
 register(Pid, DbName) ->
-    gen_server:call(?REGISTRY, {register, Pid, DbName}).
+    gen_server:call(?REGISTRY, {register, Pid, [DbName]}).
+
+
+register_many(Pid, DbNames) when is_list(DbNames) ->
+    gen_server:call(?REGISTRY, {register, Pid, DbNames}).
 
 
 register_all(Pid) ->
-    gen_server:call(?REGISTRY, {register, Pid, all_dbs}).
+    gen_server:call(?REGISTRY, {register, Pid, [all_dbs]}).
 
 
 unregister(Pid, DbName) ->
-    gen_server:call(?REGISTRY, {unregister, Pid, DbName}).
+    gen_server:call(?REGISTRY, {unregister, Pid, [DbName]}).
+
+
+unregister_many(Pid, DbNames) when is_list(DbNames) ->
+    gen_server:call(?REGISTRY, {unregister, Pid, DbNames}).
 
 
 unregister_all(Pid) ->

http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/475af68c/src/couch_event_registry.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_registry.erl b/src/couch_event_registry.erl
index e956a83..19e70c2 100644
--- a/src/couch_event_registry.erl
+++ b/src/couch_event_registry.erl
@@ -56,12 +56,10 @@ terminate(_Reason, _St) ->
     ok.
 
 
-handle_call({register, Pid, DbName}, _From, St) ->
-    Client = #client{
-        dbname = DbName,
-        pid = Pid
-    },
-    ets:insert(?REGISTRY_TABLE, Client),
+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
         [] ->
             Ref = erlang:monitor(process, Pid),
@@ -71,8 +69,10 @@ handle_call({register, Pid, DbName}, _From, St) ->
     end,
     {reply, ok, St};
 
-handle_call({unregister, Pid, DbName}, _From, St) ->
-    unregister_pattern(#client{dbname=DbName, pid=Pid, _='_'}),
+handle_call({unregister, Pid, DbNames}, _From, St) ->
+    lists:foreach(fun(DbName) ->
+        unregister_pattern(#client{dbname=DbName, pid=Pid, _='_'})
+    end, DbNames),
     {reply, ok, St};
 
 handle_call({unregister_all, Pid}, _From, St) ->


[27/35] git commit: Fix callback spec arity

Posted by rn...@apache.org.
Fix callback spec arity


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/commit/6b829185
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/tree/6b829185
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/diff/6b829185

Branch: refs/heads/windsor-merge
Commit: 6b829185d03d80963466258b1c92719acf3be5ec
Parents: 8e6797a
Author: Adam Kocoloski <ad...@cloudant.com>
Authored: Fri May 24 14:09:56 2013 -0400
Committer: Robert Newson <rn...@apache.org>
Committed: Wed Jul 30 17:47:13 2014 +0100

----------------------------------------------------------------------
 src/couch_event_listener.erl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/6b829185/src/couch_event_listener.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_listener.erl b/src/couch_event_listener.erl
index 34db139..9d4c8da 100644
--- a/src/couch_event_listener.erl
+++ b/src/couch_event_listener.erl
@@ -43,7 +43,7 @@ behaviour_info(callbacks) ->
         {init,1},
         {terminate,2},
         {handle_cast,2},
-        {handle_event,2},
+        {handle_event,3},
         {handle_info,2}
     ];
 behaviour_info(_) ->


[30/35] git commit: Kill couch_db_event when it has installed handlers

Posted by rn...@apache.org.
Kill couch_db_event when it has installed handlers

This is to force the upgrade switch to the new couch_event application
force update notifications. Theoretically we could accomplish the same
thing with custom appups to forcefully remove couch_db_event from the
supervision tree but it turns out that's really hard.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/commit/022af54f
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/tree/022af54f
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/diff/022af54f

Branch: refs/heads/windsor-merge
Commit: 022af54ff972e3ff7ce842f5c905dbfeb7d162f9
Parents: 0547000
Author: Paul J. Davis <pa...@gmail.com>
Authored: Sat Jun 15 11:45:59 2013 -0500
Committer: Robert Newson <rn...@apache.org>
Committed: Wed Jul 30 17:48:55 2014 +0100

----------------------------------------------------------------------
 src/couch_event_server.erl | 30 ++++++++++++++++++++++++++++--
 1 file changed, 28 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/022af54f/src/couch_event_server.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_server.erl b/src/couch_event_server.erl
index 866bf7c..1bf8f1e 100644
--- a/src/couch_event_server.erl
+++ b/src/couch_event_server.erl
@@ -27,13 +27,18 @@
     code_change/3
 ]).
 
+-export([
+    watchdog/0
+]).
+
 
 -include("couch_event_int.hrl").
 
 
 -record(st, {
     by_pid,
-    by_dbname
+    by_dbname,
+    watchdog
 }).
 
 
@@ -46,7 +51,8 @@ init(_) ->
     {ok, ByDbName} = khash:new(),
     {ok, #st{
         by_pid = ByPid,
-        by_dbname = ByDbName
+        by_dbname = ByDbName,
+        watchdog = spawn_monitor(?MODULE, watchdog, [])
     }}.
 
 
@@ -90,6 +96,10 @@ handle_cast(Msg, St) ->
     {noreply, St}.
 
 
+handle_info({'DOWN', Ref, _, _, Reason}, #st{watchdog={_,Ref}}=St) ->
+    couch_log:notice("~s watchdog died: ~w", [?MODULE, Reason]),
+    erlang:send_after(60000, self(), spawn_watchdog),
+    {noreply, St#st{watchdog=undefined}};
 handle_info({'DOWN', Ref, process, Pid, _Reason}, St) ->
     case khash:get(St#st.by_pid, Pid) of
         {Ref, OldDbNames} ->
@@ -99,6 +109,10 @@ handle_info({'DOWN', Ref, process, Pid, _Reason}, St) ->
     end,
     {noreply, St};
 
+
+handle_info(spawn_watchdog, #st{watchdog=undefined}=St) ->
+    NewWD = spawn_monitor(?MODULE, watchdog, []),
+    {noreply, St#st{watchdog=NewWD}};
 handle_info(Msg, St) ->
     couch_log:notice("~s ignoring info ~w", [?MODULE, Msg]),
     {noreply, St}.
@@ -108,6 +122,18 @@ code_change(_OldVsn, St, _Extra) ->
     {ok, St}.
 
 
+watchdog() ->
+    Handlers = gen_event:which_handlers(couch_db_update),
+    case length(Handlers) > 0 of
+        true ->
+            exit(whereis(couch_db_update), force_upgrade);
+        false ->
+            ok
+    end,
+    timer:sleep(5000),
+    ?MODULE:watchdog().
+
+
 notify_listeners(ByDbName, DbName, Event) ->
     Msg = {'$couch_event', DbName, Event},
     notify_listeners(khash:get(ByDbName, all_dbs), Msg),


[24/35] git commit: Minor optimizations for couch_event_registry

Posted by rn...@apache.org.
Minor optimizations for couch_event_registry

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.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/commit/2ad40edc
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/tree/2ad40edc
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/diff/2ad40edc

Branch: refs/heads/windsor-merge
Commit: 2ad40edc94130e91cf0f96b55de6dadbf2cada42
Parents: a8b378b
Author: Paul J. Davis <pa...@gmail.com>
Authored: Fri Apr 26 13:52:12 2013 -0500
Committer: Robert Newson <rn...@apache.org>
Committed: Wed Jul 30 17:44:23 2014 +0100

----------------------------------------------------------------------
 src/couch_event_registry.erl | 83 +++++++++++++++++++++++++--------------
 1 file changed, 53 insertions(+), 30 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/2ad40edc/src/couch_event_registry.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_registry.erl b/src/couch_event_registry.erl
index 19e70c2..adea994 100644
--- a/src/couch_event_registry.erl
+++ b/src/couch_event_registry.erl
@@ -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, _='_'}.


[35/35] git commit: set module version to 1

Posted by rn...@apache.org.
set module version to 1


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/commit/b52b9c5a
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/tree/b52b9c5a
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/diff/b52b9c5a

Branch: refs/heads/windsor-merge
Commit: b52b9c5abf4abffe5d5216593465eabec7b8c7ff
Parents: ddc0db2
Author: Robert Newson <ro...@cloudant.com>
Authored: Fri Nov 22 16:37:37 2013 +0000
Committer: Robert Newson <rn...@apache.org>
Committed: Wed Jul 30 17:50:16 2014 +0100

----------------------------------------------------------------------
 src/couch_event_os_listener.erl | 3 ++-
 src/couch_event_server.erl      | 3 ++-
 2 files changed, 4 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/b52b9c5a/src/couch_event_os_listener.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_os_listener.erl b/src/couch_event_os_listener.erl
index 3ba5dcf..4de0a44 100644
--- a/src/couch_event_os_listener.erl
+++ b/src/couch_event_os_listener.erl
@@ -11,7 +11,8 @@
 % the License.
 
 -module(couch_event_os_listener).
--behavior(gen_server).
+-behaviour(gen_server).
+-vsn(1).
 
 
 -export([

http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/b52b9c5a/src/couch_event_server.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_server.erl b/src/couch_event_server.erl
index 1c7bcf4..18509ec 100644
--- a/src/couch_event_server.erl
+++ b/src/couch_event_server.erl
@@ -11,7 +11,8 @@
 % the License.
 
 -module(couch_event_server).
--behavior(gen_server).
+-behaviour(gen_server).
+-vsn(1).
 
 
 -export([


[05/35] git commit: Abandon the gen_server "inheritance" approach

Posted by rn...@apache.org.
Abandon the gen_server "inheritance" approach

There's not much benefit since these things aren't currently in the
supervision tree and the code in fabric_db_update_listener makes things
even more difficult for starting gen_servers.

I did contemplate having fabric_db_udpate_listener make use of
gen_server:enter_loop/N but rexi doesn't use proc_lib to start processes
and I don't have the desire to find out how much overhead that would add
to rexi_server.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/commit/7c728ff7
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/tree/7c728ff7
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/diff/7c728ff7

Branch: refs/heads/windsor-merge
Commit: 7c728ff7cfe7170827bc165ff7e9e6571099c0f3
Parents: 475af68
Author: Paul J. Davis <pa...@gmail.com>
Authored: Tue Apr 23 14:42:24 2013 -0500
Committer: Robert Newson <rn...@apache.org>
Committed: Wed Jul 30 17:35:46 2014 +0100

----------------------------------------------------------------------
 src/couch_event_listener.erl | 243 ++++++++++++++++++++++----------------
 1 file changed, 139 insertions(+), 104 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/7c728ff7/src/couch_event_listener.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_listener.erl b/src/couch_event_listener.erl
index c665036..7baca46 100644
--- a/src/couch_event_listener.erl
+++ b/src/couch_event_listener.erl
@@ -11,14 +11,14 @@
 % the License.
 
 -module(couch_event_listener).
--behavior(gen_server).
 
 
 -export([
     start/3,
     start/4,
     start_link/3,
-    start_link/4
+    start_link/4,
+    enter_loop/3
 ]).
 
 -export([
@@ -26,144 +26,179 @@
 ]).
 
 -export([
-    init/1,
-    terminate/2,
-    handle_call/3,
-    handle_cast/2,
-    handle_info/2,
-    code_change/3
+    do_init/3,
+    loop/2
 ]).
 
 
+-record(st, {
+    module,
+    state
+}).
+
+
 behaviour_info(callbacks) ->
     [
         {init,1},
         {terminate/2},
-        {handle_event/2}
+        {handle_event/2},
+        {handle_info/2}
     ];
 behaviour_info(_) ->
     undefined.
 
 
-start(Mod, Args, Options) ->
-    gen_server:start(?MODULE, {Mod, Args}, Options).
+start(Mod, Arg, Options) ->
+    erlang:spawn(?MODULE, do_init, [Mod, Arg, Options]).
 
 
-start(Name, Mod, Args, Options) ->
-    gen_server:start(Name, ?MODULE, {Mod, Args}, Options).
+start(Name, Mod, Arg, Options) ->
+    case where(Name) of
+        undefined ->
+            start(Mod, Arg, [{name, Name} | Options]);
+        Pid ->
+            {error, {already_started, Pid}}
+    end.
 
 
-start_link(Mod, Args, Options) ->
-    gen_server:start_link(?MODULE, {Mod, Args}, Options).
+start_link(Mod, Arg, Options) ->
+    erlang:spawn_link(?MODULE, do_init, [Mod, Arg, Options]).
 
 
-start_link(Name, Mod, Args, Options) ->
-    gen_server:start_link(Name, ?MODULE, {Mod, Args}, Options).
+start_link(Name, Mod, Arg, Options) ->
+    case where(Name) of
+        undefined ->
+            start_link(Mod, Arg, [{name, Name} | Options]);
+        Pid ->
+            {error, {already_started, Pid}}
+    end.
 
 
-init({Mod, Args}) ->
-    case Mod:init(Args) of
-        {ok, St} ->
-            {ok, {Mod, St}};
-        {ok, St, Timeout} ->
-            {ok, {Mod, St}, Timeout};
-        {stop, Reason} ->
-            {stop, Reason};
-        ignore ->
-            ignore;
+enter_loop(Module, State, Options) ->
+    ok = register_listeners(Options),
+    ?MODULE:loop(#st{module=Module, state=State}, infinity).
+
+
+do_init(Module, Arg, Options) ->
+    ok = maybe_name_process(Options),
+    ok = register_listeners(Options),
+    case (catch Module:init(Arg)) of
+        {ok, State} ->
+            ?MODULE:loop(#st{module=Module, state=State}, infinity);
+        {ok, State, Timeout} when is_integer(Timeout), Timeout >= 0 ->
+            ?MODULE:loop(#st{module=Module, state=State}, Timeout);
         Else ->
-            erlang:error({bad_return, Else})
+            erlang:exit(Else)
     end.
 
 
-terminate(Reason, {Mod, St}) ->
-    Mod:terminate(Reason, St).
-
-
-handle_call(Msg, From, {Mod, St}) ->
-    case erlang:function_exported(Mod, handle_call, 3) of
-        true ->
-            case Mod:handle_call(Msg, From, St) of
-                {reply, Reply, NewState} ->
-                    {reply, Reply, {Mod, NewState}};
-                {reply, Reply, NewState, Timeout} ->
-                    {reply, Reply, {Mod, NewState}, Timeout};
-                {noreply, NewState} ->
-                    {noreply, {Mod, NewState}};
-                {noreply, NewState, Timeout} ->
-                    {noreply, {Mod, NewState}, Timeout};
-                {stop, Reason, Reply, NewState} ->
-                    {stop, Reason, Reply, {Mod, NewState}};
-                {stop, Reason, NewState} ->
-                    {stop, Reason, {Mod, NewState}};
-                Else ->
-                    erlang:error({bad_return, Else})
-            end;
-        false ->
-            {stop, {invalid_call, Msg}, invalid_call, St}
+loop(St, Timeout) ->
+    receive
+        {'$couch_event', DbName, Event} ->
+            do_event(St, DbName, Event);
+        Else ->
+            do_info(St, Else)
+    after Timeout ->
+        do_info(St, timeout)
     end.
 
 
-handle_cast(Msg, {Mod, St}) ->
-    case erlang:function_exported(Mod, handle_cast, 2) of
-        true ->
-            case Mod:handle_cast(Msg, St) of
-                {noreply, NewState} ->
-                    {noreply, {Mod, NewState}};
-                {noreply, NewState, Timeout} ->
-                    {noreply, {Mod, NewState}, Timeout};
-                {stop, Reason, NewState} ->
-                    {stop, Reason, {Mod, NewState}};
-                Else ->
-                    erlang:error({bad_return, Else})
+maybe_name_process(Options) ->
+    case proplists:lookup(name, Options) of
+        {name, Name} ->
+            case name_register(Name) of
+                true ->
+                    ok;
+                {false, Pid} ->
+                    erlang:error({already_started, Pid})
             end;
-        false ->
-            {stop, {invalid_cast, Msg}, St}
+        undefined ->
+            ok
     end.
 
 
-handle_info({'$couch_event', DbName, Event}, {Mod, St}) ->
-    case Mod:handle_event(DbName, Event, St) of
-        {noreply, NewState} ->
-            {noreply, {Mod, NewState}};
-        {noreply, NewState, Timeout} ->
-            {noreply, {Mod, NewState}, Timeout};
+register_listeners(Options) ->
+    case get_all_dbnames(Options) of
+        all_dbs ->
+            couch_event:register_all(self());
+        DbNames ->
+            couch_event:register_many(self(), DbNames)
+    end,
+    ok.
+
+
+do_event(#st{module=Module, state=State}=St, DbName, Event) ->
+    case (catch Module:handle_event(DbName, Event, State)) of
+        {ok, NewState} ->
+            ?MODULE:loop(St#st{state=NewState}, infinity);
+        {ok, NewState, Timeout} when is_integer(Timeout), Timeout >= 0 ->
+            ?MODULE:loop(St#st{state=NewState}, Timeout);
         {stop, Reason, NewState} ->
-            {stop, Reason, {Mod, NewState}};
+            do_terminate(Reason, St#st{state=NewState});
         Else ->
-            erlang:error({bad_return, Else})
-    end;
+            erlang:error(Else)
+    end.
 
-handle_info(Msg, {Mod, St}) ->
-    case erlang:function_export(Mod, handle_info, 2) of
-        true ->
-            case Mod:handle_info(Msg, St) of
-                {noreply, NewState} ->
-                    {noreply, {Mod, NewState}};
-                {noreply, NewState, Timeout} ->
-                    {noreply, {Mod, NewState}, Timeout};
-                {stop, Reason, NewState} ->
-                    {stop, Reason, {Mod, NewState}};
-                Else ->
-                    erlang:error({bad_return, Else})
-            end;
-        false ->
-            {stop, {invalid_info, Msg}, St}
+
+do_info(#st{module=Module, state=State}=St, Message) ->
+    case (catch Module:handle_info(Message, State)) of
+        {ok, NewState} ->
+            ?MODULE:loop(St#st{state=NewState}, infinity);
+        {ok, NewState, Timeout} when is_integer(Timeout), Timeout >= 0 ->
+            ?MODULE:loop(St#st{state=NewState}, Timeout);
+        {stop, Reason, NewState} ->
+            do_terminate(Reason, St#st{state=NewState});
+        Else ->
+            erlang:error(Else)
     end.
 
 
-code_change(OldVsn, {Mod, St}, Extra) ->
-    case erlang:function_exported(Mod, code_change, 3) of
-        true ->
-            case Mod:code_change(OldVsn, St, Extra) of
-                {ok, NewState} ->
-                    {ok, {Mod, NewState}};
-                {error, Reason} ->
-                    {error, Reason};
-                Else ->
-                    erlang:error({bad_return, Else})
-            end;
-        false ->
-            {ok, {Mod, St}}
+do_terminate(Reason, #st{module=Module, state=State}) ->
+    % Order matters. We want to make sure Module:terminate/1
+    % is called even if couch_event:unregister_all/1 hangs
+    % indefinitely.
+    catch Module:terminate(Reason, State),
+    catch couch_event:unregister_all(self()),
+    case Reason of
+        normal -> ok;
+        shutdown -> ok;
+        ignore -> ok;
+        Else -> erlang:error(Else)
     end.
 
+
+where({global, Name}) -> global:safe_whereis_name(Name);
+where({local, Name}) -> whereis(Name).
+
+
+name_register({global, Name}=GN) ->
+    case global:register_name(Name, self()) of
+        yes -> true;
+        no -> {false, where(GN)}
+    end;
+name_register({local, Name}=LN) ->
+    try register(Name, self()) of
+        true -> true
+    catch error:_ ->
+        {false, where(LN)}
+    end.
+
+
+get_all_dbnames(Options) ->
+    case proplists:get_value(all_dbs, Options) of
+        true -> all_dbs;
+        false -> get_all_dbnames(Options, [])
+    end.
+
+
+get_all_dbnames([], []) ->
+    erlang:error(no_dbnames_provided);
+get_all_dbnames([], Acc) ->
+    lists:usort(Acc);
+get_all_dbnames([{dbname, DbName} | Rest], Acc) when is_binary(DbName) ->
+    get_all_dbnames(Rest, [DbName | Acc]);
+get_all_dbnames([{dbnames, DbNames} | Rest], Acc) when is_list(DbNames) ->
+    BinDbNames = [DbName || DbName <- DbNames, is_binary(DbName)],
+    get_all_dbnames(Rest, BinDbNames ++ Acc);
+get_all_dbnames([_Ignored | Rest], Acc) ->
+    get_all_dbnames(Rest, Acc).


[11/35] git commit: Fix callback module name for couch_event_registry

Posted by rn...@apache.org.
Fix callback module name for couch_event_registry


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/commit/7e6c02cf
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/tree/7e6c02cf
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/diff/7e6c02cf

Branch: refs/heads/windsor-merge
Commit: 7e6c02cf58d5bff0fda08785fcbd4b6c4b3a00b6
Parents: b00c879
Author: Paul J. Davis <pa...@gmail.com>
Authored: Wed Apr 24 12:23:36 2013 -0500
Committer: Robert Newson <rn...@apache.org>
Committed: Wed Jul 30 17:37:03 2014 +0100

----------------------------------------------------------------------
 src/couch_event_sup2.erl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/7e6c02cf/src/couch_event_sup2.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_sup2.erl b/src/couch_event_sup2.erl
index 039b897..e7387e0 100644
--- a/src/couch_event_sup2.erl
+++ b/src/couch_event_sup2.erl
@@ -37,7 +37,7 @@ init(_) ->
             permanent,
             5000,
             worker,
-            [couch_event_register]
+            [couch_event_registry]
         },
         {couch_event_dist,
             {couch_event_dist, start_link, []},


[16/35] git commit: Avoid use of undocumented functions

Posted by rn...@apache.org.
Avoid use of undocumented functions

I'd copied this pattern from R14B01's gen_server. Apparently newer
Erlang's complain about it. I've updated to the version found in
R15B03-1.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/commit/b34d5330
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/tree/b34d5330
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/diff/b34d5330

Branch: refs/heads/windsor-merge
Commit: b34d5330301f5a4f268f4307634d1c5ac2c1bc57
Parents: 6e4f69e
Author: Paul J. Davis <pa...@gmail.com>
Authored: Wed Apr 24 14:11:11 2013 -0500
Committer: Robert Newson <rn...@apache.org>
Committed: Wed Jul 30 17:41:25 2014 +0100

----------------------------------------------------------------------
 src/couch_event_listener.erl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/b34d5330/src/couch_event_listener.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_listener.erl b/src/couch_event_listener.erl
index cbe754f..0eae00e 100644
--- a/src/couch_event_listener.erl
+++ b/src/couch_event_listener.erl
@@ -192,7 +192,7 @@ do_terminate(Reason, #st{module=Module, state=State}) ->
     erlang:exit(Status).
 
 
-where({global, Name}) -> global:safe_whereis_name(Name);
+where({global, Name}) -> global:whereis_name(Name);
 where({local, Name}) -> whereis(Name).
 
 


[33/35] git commit: Implement option to provide a parent to monitor

Posted by rn...@apache.org.
Implement option to provide a parent to monitor

The couch_event_listener_mfa already had the necessary logic for
monitoring the parent process that spawned it for a start_link usage. In
some instances we have rexi_worker process use the enter_loop style APIs
to avoid the need to spawn a separate process. This just adds an option
`{parent, pid()}` that allows these processes to specify the parent to
monitor.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/commit/fbe7ae64
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/tree/fbe7ae64
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/diff/fbe7ae64

Branch: refs/heads/windsor-merge
Commit: fbe7ae64dcd72a09f4cd7bd2999dfff7a4412171
Parents: 707997e
Author: Paul J. Davis <pa...@gmail.com>
Authored: Thu Aug 8 12:15:32 2013 +0100
Committer: Robert Newson <rn...@apache.org>
Committed: Wed Jul 30 17:49:52 2014 +0100

----------------------------------------------------------------------
 src/couch_event_listener_mfa.erl | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/fbe7ae64/src/couch_event_listener_mfa.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_listener_mfa.erl b/src/couch_event_listener_mfa.erl
index 4ffa92b..acc646c 100644
--- a/src/couch_event_listener_mfa.erl
+++ b/src/couch_event_listener_mfa.erl
@@ -38,15 +38,25 @@
 
 
 start_link(Mod, Func, State, Options) ->
-    Arg = {self(), Mod, Func, State},
+    Parent = case proplists:get_value(parent, Options) of
+        P when is_pid(P) -> P;
+        _ -> self()
+    end,
+    Arg = {Parent, Mod, Func, State},
     couch_event_listener:start_link(?MODULE, Arg, Options).
 
 
 enter_loop(Mod, Func, State, Options) ->
+    Parent = case proplists:get_value(parent, Options) of
+        P when is_pid(P) -> P;
+        _ -> undefined
+    end,
+    erlang:monitor(process, Parent),
     St = #st{
         mod = Mod,
         func = Func,
-        state = State
+        state = State,
+        parent = Parent
     },
     couch_event_listener:enter_loop(?MODULE, St, Options).
 


[15/35] git commit: Fix proplists:lookup/2 check

Posted by rn...@apache.org.
Fix proplists:lookup/2 check

Apparently someone was smoking something strong when they designed the
API of the proplists module. lookup/2 returns none when a key isn't
found which does not at all match get_value/2 which returns undefined.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/commit/6e4f69ef
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/tree/6e4f69ef
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/diff/6e4f69ef

Branch: refs/heads/windsor-merge
Commit: 6e4f69efa11fce639d8545f88cbe0b60ffa6f99f
Parents: 34aeaee
Author: Paul J. Davis <pa...@gmail.com>
Authored: Wed Apr 24 14:10:20 2013 -0500
Committer: Robert Newson <rn...@apache.org>
Committed: Wed Jul 30 17:41:18 2014 +0100

----------------------------------------------------------------------
 src/couch_event_listener.erl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/6e4f69ef/src/couch_event_listener.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_listener.erl b/src/couch_event_listener.erl
index ac8114e..cbe754f 100644
--- a/src/couch_event_listener.erl
+++ b/src/couch_event_listener.erl
@@ -123,7 +123,7 @@ maybe_name_process(Options) ->
                 {false, Pid} ->
                     erlang:error({already_started, Pid})
             end;
-        undefined ->
+        none ->
             ok
     end.
 


[12/35] git commit: Add OS process listeners

Posted by rn...@apache.org.
Add OS process listeners

We don't use this in dbcore but if we ever merge this back to CouchDB
then we'll want to have this feature.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/commit/2e0f5438
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/tree/2e0f5438
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/diff/2e0f5438

Branch: refs/heads/windsor-merge
Commit: 2e0f5438d34b884733808495e7f648e2573958e7
Parents: 7e6c02c
Author: Paul J. Davis <pa...@gmail.com>
Authored: Wed Apr 24 12:24:13 2013 -0500
Committer: Robert Newson <rn...@apache.org>
Committed: Wed Jul 30 17:40:48 2014 +0100

----------------------------------------------------------------------
 src/couch_event_os_listener.erl | 75 ++++++++++++++++++++++++++++++++++++
 src/couch_event_os_sup.erl      | 73 +++++++++++++++++++++++++++++++++++
 src/couch_event_sup2.erl        |  7 ++++
 3 files changed, 155 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/2e0f5438/src/couch_event_os_listener.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_os_listener.erl b/src/couch_event_os_listener.erl
new file mode 100644
index 0000000..b2014ed
--- /dev/null
+++ b/src/couch_event_os_listener.erl
@@ -0,0 +1,75 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-module(couch_event_os_listener).
+-behavior(gen_server).
+
+
+-export([
+    start_link/0
+]).
+
+-export([
+    init/1,
+    terminate/2,
+    handle_call/3,
+    handle_cast/2,
+    handle_info/2,
+    code_change/3
+]).
+
+
+start_link(Exe) when is_list(Exe) ->
+    gen_server:start_link(?MODULE, Exe, []).
+
+
+init(Exe) ->
+    process_flag(trap_exit, true),
+    ok = couch_event:register_all(self()),
+    couch_os_process:start_link(Exe, []).
+
+
+terminate(_Reason, Pid) when is_pid(Pid) ->
+    couch_os_process:stop(Pid);
+terminate(_Reason, _Pid) ->
+    ok.
+
+
+handle_call(Msg, From, Pid) ->
+    couch_log:notice("~s ignoring call ~w from ~w", [?MODULE, Msg, From]),
+    {reply, ignored, Pid, 0}.
+
+
+handle_cast(Msg, Pid) ->
+    couch_log:notice("~s ignoring cast ~w", [?MODULE, Msg]),
+    {noreply, Pid, 0}.
+
+
+handle_info({'$couch_event', DbName, Event}, Pid) ->
+    Obj = {[
+        {db, DbName},
+        {type, list_to_binary(atom_to_list(Event))}
+    ]},
+    ok = couch_os_process:send(Pid, Obj),
+    {noreply, Pid};
+
+handle_info({'EXIT', Pid, Reason}, Pid) ->
+    couch_log:error("Update notificatio process ~w died: ~w", [Pid, Reason]),
+    {stop, normal, nil};
+
+handle_info(Msg, Pid) ->
+    couch_log:notice("~s ignoring info ~w", [?MODULE, Msg]),
+    {noreply, Pid, 0}.
+
+
+code_change(_OldVsn, St, _Extra) ->
+    {ok, St}.

http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/2e0f5438/src/couch_event_os_sup.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_os_sup.erl b/src/couch_event_os_sup.erl
new file mode 100644
index 0000000..ff4daaa
--- /dev/null
+++ b/src/couch_event_os_sup.erl
@@ -0,0 +1,73 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+
+% This causes an OS process to spawned and it is notified every time a database
+% is updated.
+%
+% The notifications are in the form of a the database name sent as a line of
+% text to the OS processes stdout.
+
+
+-module(couch_event_os_sup).
+-behaviour(supervisor).
+-behaviour(config_listener).
+
+
+-export([
+    start_link/0,
+    init/1
+]).
+
+-export([
+    handle_config_change/5
+]).
+
+
+start_link() ->
+    supervisor:start_link({local, ?MODULE}, ?MODULE, []).
+
+
+init([]) ->
+    ok = config:listen_for_changes(?MODULE, nil),
+
+    UpdateNotifierExes = config:get("update_notification"),
+    Children = [child(Id, Exe) || {Id, Exe} <- UpdateNotifierExes],
+
+    {ok, {
+        {one_for_one, 10, 3600},
+        Children
+    }.
+
+
+handle_config_change("update_notification", Id, deleted, _, _) ->
+    supervisor:terminate_child(?MODULE, Id),
+    supervisor:delete_child(?MODULE, Id),
+    {ok, nil};
+handle_config_change("update_notification", Id, Exe, _, _) when is_list(Exe) ->
+    supervisor:terminate_child(?MODULE, Id),
+    supervisor:delete_child(?MODULE, Id),
+    supervisor:start_child(?MODULE, child(Id, Exe)),
+    {ok, nil};
+handle_config_change(_, _, _, _, _) ->
+    {ok, nil}.
+
+
+child(Id, Arg) ->
+    {
+        Id,
+        {couch_event_os_listener, start_link, [Arg]},
+        permanent,
+        1000,
+        supervisor,
+        [couch_event_os_listener]
+    }.

http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/2e0f5438/src/couch_event_sup2.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_sup2.erl b/src/couch_event_sup2.erl
index e7387e0..1a74979 100644
--- a/src/couch_event_sup2.erl
+++ b/src/couch_event_sup2.erl
@@ -45,6 +45,13 @@ init(_) ->
             5000,
             worker,
             [couch_event_dist]
+        },
+        {couch_event_os_sup,
+            {couch_event_os_sup, start_link, []},
+            permanent,
+            5000,
+            supervisor,
+            [couch_event_os_sup]
         }
     ],
     {ok, {{one_for_one, 5, 10}, Children}}.


[13/35] git commit: Export the listen/4 function

Posted by rn...@apache.org.
Export the listen/4 function


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/commit/81835ba0
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/tree/81835ba0
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/diff/81835ba0

Branch: refs/heads/windsor-merge
Commit: 81835ba06d680565314caea7bb9fc28df3e13ece
Parents: 2e0f543
Author: Paul J. Davis <pa...@gmail.com>
Authored: Wed Apr 24 14:09:24 2013 -0500
Committer: Robert Newson <rn...@apache.org>
Committed: Wed Jul 30 17:41:04 2014 +0100

----------------------------------------------------------------------
 src/couch_event.erl | 1 +
 1 file changed, 1 insertion(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/81835ba0/src/couch_event.erl
----------------------------------------------------------------------
diff --git a/src/couch_event.erl b/src/couch_event.erl
index 7e77bff..72926d6 100644
--- a/src/couch_event.erl
+++ b/src/couch_event.erl
@@ -17,6 +17,7 @@
 ]).
 
 -export([
+    listen/4,
     link_listener/4,
     stop_listener/1
 ]).


[19/35] git commit: Fix export definition for start_link/1

Posted by rn...@apache.org.
Fix export definition for start_link/1


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/commit/6d9f614f
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/tree/6d9f614f
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/diff/6d9f614f

Branch: refs/heads/windsor-merge
Commit: 6d9f614fa4f7ad5a27321c3ae47c55e4dde96995
Parents: ecd110a
Author: Paul J. Davis <pa...@gmail.com>
Authored: Wed Apr 24 14:16:04 2013 -0500
Committer: Robert Newson <rn...@apache.org>
Committed: Wed Jul 30 17:41:48 2014 +0100

----------------------------------------------------------------------
 src/couch_event_os_listener.erl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/6d9f614f/src/couch_event_os_listener.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_os_listener.erl b/src/couch_event_os_listener.erl
index b2014ed..3ba5dcf 100644
--- a/src/couch_event_os_listener.erl
+++ b/src/couch_event_os_listener.erl
@@ -15,7 +15,7 @@
 
 
 -export([
-    start_link/0
+    start_link/1
 ]).
 
 -export([


[20/35] git commit: Minor syntax error

Posted by rn...@apache.org.
Minor syntax error


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/commit/2bd7db0b
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/tree/2bd7db0b
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/diff/2bd7db0b

Branch: refs/heads/windsor-merge
Commit: 2bd7db0b796ed322980fb41ce716edf9234edf7d
Parents: 6d9f614
Author: Paul J. Davis <pa...@gmail.com>
Authored: Wed Apr 24 14:16:28 2013 -0500
Committer: Robert Newson <rn...@apache.org>
Committed: Wed Jul 30 17:41:56 2014 +0100

----------------------------------------------------------------------
 src/couch_event_os_sup.erl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/2bd7db0b/src/couch_event_os_sup.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_os_sup.erl b/src/couch_event_os_sup.erl
index ff4daaa..fa7e66d 100644
--- a/src/couch_event_os_sup.erl
+++ b/src/couch_event_os_sup.erl
@@ -46,7 +46,7 @@ init([]) ->
     {ok, {
         {one_for_one, 10, 3600},
         Children
-    }.
+    }}.
 
 
 handle_config_change("update_notification", Id, deleted, _, _) ->


[25/35] git commit: Add dependency on khash

Posted by rn...@apache.org.
Add dependency on khash


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/commit/1deb3d42
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/tree/1deb3d42
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/diff/1deb3d42

Branch: refs/heads/windsor-merge
Commit: 1deb3d4289bcd0dc588238456b1c2f430aa67085
Parents: 2ad40ed
Author: Paul J. Davis <pa...@gmail.com>
Authored: Sat May 11 15:21:11 2013 -0500
Committer: Robert Newson <rn...@apache.org>
Committed: Wed Jul 30 17:45:05 2014 +0100

----------------------------------------------------------------------
 src/couch_event.app.src | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/1deb3d42/src/couch_event.app.src
----------------------------------------------------------------------
diff --git a/src/couch_event.app.src b/src/couch_event.app.src
index 17fbafd..b2ac917 100644
--- a/src/couch_event.app.src
+++ b/src/couch_event.app.src
@@ -17,6 +17,6 @@
         couch_event_sup,
         couch_event_server
     ]},
-    {applications, [kernel, stdlib, couch_log, config]},
+    {applications, [kernel, stdlib, khash, couch_log, config]},
     {mod, {couch_event_app, []}}
 ]}.


[17/35] git commit: Support db names specified as a list

Posted by rn...@apache.org.
Support db names specified as a list

I was being a bit conservative before in gathering database names to
listen to. This keeps all binaries and converts lists to binaries.
Anything that's not a list or binary throws an error.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/commit/634658db
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/tree/634658db
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/diff/634658db

Branch: refs/heads/windsor-merge
Commit: 634658dbc56ee8babd98fc99543cb94026f0762f
Parents: b34d533
Author: Paul J. Davis <pa...@gmail.com>
Authored: Wed Apr 24 14:12:16 2013 -0500
Committer: Robert Newson <rn...@apache.org>
Committed: Wed Jul 30 17:41:32 2014 +0100

----------------------------------------------------------------------
 src/couch_event_listener.erl | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/634658db/src/couch_event_listener.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_listener.erl b/src/couch_event_listener.erl
index 0eae00e..ca2bf29 100644
--- a/src/couch_event_listener.erl
+++ b/src/couch_event_listener.erl
@@ -219,11 +219,20 @@ get_all_dbnames(Options) ->
 get_all_dbnames([], []) ->
     erlang:error(no_dbnames_provided);
 get_all_dbnames([], Acc) ->
-    lists:usort(Acc);
-get_all_dbnames([{dbname, DbName} | Rest], Acc) when is_binary(DbName) ->
+    lists:usort(convert_dbname_list(Acc));
+get_all_dbnames([{dbname, DbName} | Rest], Acc) ->
     get_all_dbnames(Rest, [DbName | Acc]);
 get_all_dbnames([{dbnames, DbNames} | Rest], Acc) when is_list(DbNames) ->
-    BinDbNames = [DbName || DbName <- DbNames, is_binary(DbName)],
-    get_all_dbnames(Rest, BinDbNames ++ Acc);
+    get_all_dbnames(Rest, DbNames ++ Acc);
 get_all_dbnames([_Ignored | Rest], Acc) ->
     get_all_dbnames(Rest, Acc).
+
+
+convert_dbname_list([]) ->
+    [];
+convert_dbname_list([DbName | Rest]) when is_binary(DbName) ->
+    [DbName | convert_dbname_list(Rest)];
+convert_dbname_list([DbName | Rest]) when is_list(DbName) ->
+    [list_to_binary(DbName) | convert_dbname_list(Rest)];
+convert_dbname_list([DbName | _]) ->
+    erlang:error({invalid_dbname, DbName}).


[03/35] git commit: Minimize message from monitors

Posted by rn...@apache.org.
Minimize message from monitors

I wasn't deduping monitors before. That bugged me enough to add an extra
ets table so that we can dedupe those messages and avoid the extra work
done by couch_event_registry.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/commit/f4c80d73
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/tree/f4c80d73
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/diff/f4c80d73

Branch: refs/heads/windsor-merge
Commit: f4c80d73e8b6c09ff9bdf300875fb2d501209e66
Parents: cc616a7
Author: Paul J. Davis <pa...@gmail.com>
Authored: Mon Apr 22 15:48:06 2013 -0500
Committer: Robert Newson <rn...@apache.org>
Committed: Wed Jul 30 17:35:26 2014 +0100

----------------------------------------------------------------------
 src/couch_event_int.hrl      |  4 +--
 src/couch_event_registry.erl | 64 ++++++++++++++++++++++-----------------
 2 files changed, 39 insertions(+), 29 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/f4c80d73/src/couch_event_int.hrl
----------------------------------------------------------------------
diff --git a/src/couch_event_int.hrl b/src/couch_event_int.hrl
index dc4739e..f837e1d 100644
--- a/src/couch_event_int.hrl
+++ b/src/couch_event_int.hrl
@@ -11,9 +11,9 @@
 % the License.
 
 -define(REGISTRY_TABLE, couch_event_registry).
+-define(MONITOR_TABLE, couch_event_registry_monitors).
 
 -record(client, {
     dbname,
-    pid,
-    ref
+    pid
 }).

http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/f4c80d73/src/couch_event_registry.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_registry.erl b/src/couch_event_registry.erl
index 65fa160..e956a83 100644
--- a/src/couch_event_registry.erl
+++ b/src/couch_event_registry.erl
@@ -36,13 +36,19 @@ start_link() ->
 
 
 init(_) ->
-    EtsOpts = [
+    RegistryOpts = [
         protected,
         named_table,
         bag,
         {keypos, #client.dbname}
     ],
-    ets:new(?REGISTRY_TABLE, EtsOpts),
+    MonitorOpts = [
+        protected,
+        named_table,
+        set
+    ],
+    ets:new(?REGISTRY_TABLE, RegistryOpts),
+    ets:new(?MONITOR_TABLE, MonitorOpts),
     {ok, nil}.
 
 
@@ -53,36 +59,24 @@ terminate(_Reason, _St) ->
 handle_call({register, Pid, DbName}, _From, St) ->
     Client = #client{
         dbname = DbName,
-        pid = Pid,
-        ref = erlang:monitor(process, Pid)
+        pid = Pid
     },
     ets:insert(?REGISTRY_TABLE, Client),
+    case ets:lookup(?MONITOR_TABLE, Pid) of
+        [] ->
+            Ref = erlang:monitor(process, Pid),
+            ets:insert(?MONITOR_TABLE, {Pid, Ref});
+        [{Pid, _}] ->
+            ok
+    end,
     {reply, ok, St};
 
 handle_call({unregister, Pid, DbName}, _From, St) ->
-    Pattern = #client{dbname=DbName, pid=Pid, _='_'},
-    case ets:match_object(?REGISTRY_TABLE, Pattern) of
-        [] ->
-            ok;
-        [#client{ref=Ref}=Cli] ->
-            erlang:demonitor(Ref, [flush]),
-            ets:delete_object(?REGISTRY_TABLE, Cli)
-    end,
+    unregister_pattern(#client{dbname=DbName, pid=Pid, _='_'}),
     {reply, ok, St};
 
 handle_call({unregister_all, Pid}, _From, St) ->
-    Pattern = #client{pid=Pid, _='_'},
-    case ets:match_object(?REGISTRY_TABLE, Pattern) of
-        [] ->
-            ok;
-        Clients ->
-            lists:foreach(fun(Cli) ->
-                erlang:demonitor(Cli#client.ref, [flush]),
-                % I wonder if match_delete/2 is faster
-                % than repeated calls to delete_object.
-                ets:delete_object(Cli)
-            end, Clients)
-    end,
+    unregister_pattern(#client{pid=Pid, _='_'}),
     {reply, ok, St};
 
 handle_call(Msg, From, St) ->
@@ -95,9 +89,8 @@ handle_cast(Msg, St) ->
     {noreply, St, 0}.
 
 
-handle_info({'DOWN', Ref, process, Pid, _Reason}, St) ->
-    Pattern = #client{pid=Pid, ref=Ref, _='_'},
-    ets:match_delete(?REGISTRY_TABLE, Pattern),
+handle_info({'DOWN', _Ref, process, Pid, _Reason}, St) ->
+    unregister_pattern(#client{pid=Pid, _='_'}),
     {noreply, St};
 
 handle_info(Msg, St) ->
@@ -107,3 +100,20 @@ handle_info(Msg, 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).


[06/35] git commit: Add a cast API for couch_event_listener

Posted by rn...@apache.org.
Add a cast API for couch_event_listener


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/commit/320cf0c6
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/tree/320cf0c6
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/diff/320cf0c6

Branch: refs/heads/windsor-merge
Commit: 320cf0c62793fd73af8789d2dc48ac33fcafd6f3
Parents: 7c728ff
Author: Paul J. Davis <pa...@gmail.com>
Authored: Tue Apr 23 15:40:26 2013 -0500
Committer: Robert Newson <rn...@apache.org>
Committed: Wed Jul 30 17:35:58 2014 +0100

----------------------------------------------------------------------
 src/couch_event_listener.erl | 24 +++++++++++++++++++++++-
 1 file changed, 23 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/320cf0c6/src/couch_event_listener.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_listener.erl b/src/couch_event_listener.erl
index 7baca46..042500f 100644
--- a/src/couch_event_listener.erl
+++ b/src/couch_event_listener.erl
@@ -18,7 +18,8 @@
     start/4,
     start_link/3,
     start_link/4,
-    enter_loop/3
+    enter_loop/3,
+    cast/2
 ]).
 
 -export([
@@ -41,6 +42,7 @@ behaviour_info(callbacks) ->
     [
         {init,1},
         {terminate/2},
+        {handle_cast/2},
         {handle_event/2},
         {handle_info/2}
     ];
@@ -79,6 +81,11 @@ enter_loop(Module, State, Options) ->
     ?MODULE:loop(#st{module=Module, state=State}, infinity).
 
 
+cast(Pid, Message) ->
+    Pid ! {'$couch_event_cast', Message},
+    ok.
+
+
 do_init(Module, Arg, Options) ->
     ok = maybe_name_process(Options),
     ok = register_listeners(Options),
@@ -96,6 +103,8 @@ loop(St, Timeout) ->
     receive
         {'$couch_event', DbName, Event} ->
             do_event(St, DbName, Event);
+        {'$couch_event_cast', Message} ->
+            do_cast(St, Message);
         Else ->
             do_info(St, Else)
     after Timeout ->
@@ -140,6 +149,19 @@ do_event(#st{module=Module, state=State}=St, DbName, Event) ->
     end.
 
 
+do_cast(#st{module=Module, state=State}=St, Message) ->
+    case (catch Module:handle_cast(Message, State)) of
+        {ok, NewState} ->
+            ?MODULE:loop(St#st{state=NewState}, infinity);
+        {ok, NewState, Timeout} when is_integer(Timeout), Timeout >= 0 ->
+            ?MODULE:loop(St#st{state=NewState}, Timeout);
+        {stop, Reason, NewState} ->
+            do_terminate(Reason, St#st{state=NewState});
+        Else ->
+            erlang:error(Else)
+    end.
+
+
 do_info(#st{module=Module, state=State}=St, Message) ->
     case (catch Module:handle_info(Message, State)) of
         {ok, NewState} ->


[18/35] git commit: Fix use of proplists:get_value/2

Posted by rn...@apache.org.
Fix use of proplists:get_value/2

It returns undefined when the key isn't found, not false.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/commit/ecd110a4
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/tree/ecd110a4
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/diff/ecd110a4

Branch: refs/heads/windsor-merge
Commit: ecd110a4e645e4e35bd0681dfbe293b0d94f8fa3
Parents: 634658d
Author: Paul J. Davis <pa...@gmail.com>
Authored: Wed Apr 24 14:15:26 2013 -0500
Committer: Robert Newson <rn...@apache.org>
Committed: Wed Jul 30 17:41:40 2014 +0100

----------------------------------------------------------------------
 src/couch_event_listener.erl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/ecd110a4/src/couch_event_listener.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_listener.erl b/src/couch_event_listener.erl
index ca2bf29..04d5fc1 100644
--- a/src/couch_event_listener.erl
+++ b/src/couch_event_listener.erl
@@ -212,7 +212,7 @@ name_register({local, Name}=LN) ->
 get_all_dbnames(Options) ->
     case proplists:get_value(all_dbs, Options) of
         true -> all_dbs;
-        false -> get_all_dbnames(Options, [])
+        _ -> get_all_dbnames(Options, [])
     end.
 
 


[22/35] git commit: Fix use of non-existant APIs

Posted by rn...@apache.org.
Fix use of non-existant APIs

I must've been thinking I was going to add a stop function at some point
in the future. Rather than do that I just used the cast I added
previously.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/commit/7d5c7e1a
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/tree/7d5c7e1a
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/diff/7d5c7e1a

Branch: refs/heads/windsor-merge
Commit: 7d5c7e1af8b47bbc163c91d0ea0d1f3ae0f1f46e
Parents: ed82171
Author: Paul J. Davis <pa...@gmail.com>
Authored: Wed Apr 24 14:17:30 2013 -0500
Committer: Robert Newson <rn...@apache.org>
Committed: Wed Jul 30 17:42:21 2014 +0100

----------------------------------------------------------------------
 src/couch_event_listener_mfa.erl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/7d5c7e1a/src/couch_event_listener_mfa.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_listener_mfa.erl b/src/couch_event_listener_mfa.erl
index 7b13604..52fd389 100644
--- a/src/couch_event_listener_mfa.erl
+++ b/src/couch_event_listener_mfa.erl
@@ -52,7 +52,7 @@ enter_loop(Mod, Func, State, Options) ->
 
 
 stop(Pid) ->
-    couch_event_listener:stop(Pid).
+    couch_event_listener:cast(Pid, shutown).
 
 
 init({Parent, Mod, Func, State}) ->


[14/35] git commit: Fix the behaviour_info callback

Posted by rn...@apache.org.
Fix the behaviour_info callback


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/commit/34aeaeeb
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/tree/34aeaeeb
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/diff/34aeaeeb

Branch: refs/heads/windsor-merge
Commit: 34aeaeeb3669611285ce7c39d19414c1d8aedf06
Parents: 81835ba
Author: Paul J. Davis <pa...@gmail.com>
Authored: Wed Apr 24 14:10:06 2013 -0500
Committer: Robert Newson <rn...@apache.org>
Committed: Wed Jul 30 17:41:11 2014 +0100

----------------------------------------------------------------------
 src/couch_event_listener.erl | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/34aeaeeb/src/couch_event_listener.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_listener.erl b/src/couch_event_listener.erl
index 94bb133..ac8114e 100644
--- a/src/couch_event_listener.erl
+++ b/src/couch_event_listener.erl
@@ -41,10 +41,10 @@
 behaviour_info(callbacks) ->
     [
         {init,1},
-        {terminate/2},
-        {handle_cast/2},
-        {handle_event/2},
-        {handle_info/2}
+        {terminate,2},
+        {handle_cast,2},
+        {handle_event,2},
+        {handle_info,2}
     ];
 behaviour_info(_) ->
     undefined.


[29/35] git commit: Fix typo in the shutdown sequence

Posted by rn...@apache.org.
Fix typo in the shutdown sequence


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/commit/05470003
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/tree/05470003
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/diff/05470003

Branch: refs/heads/windsor-merge
Commit: 054700030083cbbbf6b1376144d40be6dd06bb61
Parents: 2bb6b74
Author: Paul J. Davis <pa...@gmail.com>
Authored: Fri Jun 14 16:24:08 2013 -0500
Committer: Robert Newson <rn...@apache.org>
Committed: Wed Jul 30 17:48:18 2014 +0100

----------------------------------------------------------------------
 src/couch_event_listener_mfa.erl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/05470003/src/couch_event_listener_mfa.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_listener_mfa.erl b/src/couch_event_listener_mfa.erl
index 52fd389..4ffa92b 100644
--- a/src/couch_event_listener_mfa.erl
+++ b/src/couch_event_listener_mfa.erl
@@ -52,7 +52,7 @@ enter_loop(Mod, Func, State, Options) ->
 
 
 stop(Pid) ->
-    couch_event_listener:cast(Pid, shutown).
+    couch_event_listener:cast(Pid, shutdown).
 
 
 init({Parent, Mod, Func, State}) ->


[34/35] git commit: Fix monitoring when no parent is provided.

Posted by rn...@apache.org.
Fix monitoring when no parent is provided.

Will squash this down after review.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/commit/ddc0db2c
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/tree/ddc0db2c
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/diff/ddc0db2c

Branch: refs/heads/windsor-merge
Commit: ddc0db2c520eb0d82afaaa777130da0463cd6229
Parents: fbe7ae6
Author: Paul J. Davis <pa...@gmail.com>
Authored: Thu Aug 8 13:33:50 2013 +0100
Committer: Robert Newson <rn...@apache.org>
Committed: Wed Jul 30 17:50:01 2014 +0100

----------------------------------------------------------------------
 src/couch_event_listener_mfa.erl | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/ddc0db2c/src/couch_event_listener_mfa.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_listener_mfa.erl b/src/couch_event_listener_mfa.erl
index acc646c..9be5888 100644
--- a/src/couch_event_listener_mfa.erl
+++ b/src/couch_event_listener_mfa.erl
@@ -48,10 +48,12 @@ start_link(Mod, Func, State, Options) ->
 
 enter_loop(Mod, Func, State, Options) ->
     Parent = case proplists:get_value(parent, Options) of
-        P when is_pid(P) -> P;
-        _ -> undefined
+        P when is_pid(P) ->
+            erlang:monitor(process, P),
+            P;
+        _ ->
+            undefined
     end,
-    erlang:monitor(process, Parent),
     St = #st{
         mod = Mod,
         func = Func,


[02/35] git commit: Initial implementation

Posted by rn...@apache.org.
Initial implementation

There are a few places we could be more efficient in managing the ets
table for event listeners but this simple approach should be able to
give us a rough idea on how fast we can pump messages through this sort
of design.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/commit/cc616a77
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/tree/cc616a77
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/diff/cc616a77

Branch: refs/heads/windsor-merge
Commit: cc616a77717730ac4dddc2940aff51f584385e6f
Parents: 73b38e8
Author: Paul J. Davis <pa...@gmail.com>
Authored: Mon Apr 22 15:03:47 2013 -0500
Committer: Robert Newson <rn...@apache.org>
Committed: Wed Jul 30 17:35:08 2014 +0100

----------------------------------------------------------------------
 .gitignore                   |   2 +
 src/couch_event.app.src      |  22 +++++
 src/couch_event.erl          |  45 ++++++++++
 src/couch_event_app.erl      |  27 ++++++
 src/couch_event_dist.erl     |  83 +++++++++++++++++++
 src/couch_event_int.hrl      |  19 +++++
 src/couch_event_listener.erl | 169 ++++++++++++++++++++++++++++++++++++++
 src/couch_event_registry.erl | 109 ++++++++++++++++++++++++
 src/couch_event_sup2.erl     |  51 ++++++++++++
 9 files changed, 527 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/cc616a77/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..1204ed7
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+deps/
+ebin/

http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/cc616a77/src/couch_event.app.src
----------------------------------------------------------------------
diff --git a/src/couch_event.app.src b/src/couch_event.app.src
new file mode 100644
index 0000000..17fbafd
--- /dev/null
+++ b/src/couch_event.app.src
@@ -0,0 +1,22 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+{application, couch_event, [
+    {description, "Event notification system for Apache CouchDB"},
+    {vsn, git},
+    {registered, [
+        couch_event_sup,
+        couch_event_server
+    ]},
+    {applications, [kernel, stdlib, couch_log, config]},
+    {mod, {couch_event_app, []}}
+]}.

http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/cc616a77/src/couch_event.erl
----------------------------------------------------------------------
diff --git a/src/couch_event.erl b/src/couch_event.erl
new file mode 100644
index 0000000..eaa4c88
--- /dev/null
+++ b/src/couch_event.erl
@@ -0,0 +1,45 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-module(couch_event).
+
+-export([
+    register/2,
+    register_all/1,
+    unregister/2,
+    unregister_all/1,
+    notify/2
+]).
+
+
+-define(REGISTRY, couch_event_registry).
+-define(DIST, couch_event_dist).
+
+
+register(Pid, DbName) ->
+    gen_server:call(?REGISTRY, {register, Pid, DbName}).
+
+
+register_all(Pid) ->
+    gen_server:call(?REGISTRY, {register, Pid, all_dbs}).
+
+
+unregister(Pid, DbName) ->
+    gen_server:call(?REGISTRY, {unregister, Pid, DbName}).
+
+
+unregister_all(Pid) ->
+    gen_server:call(?REGISTRY, {unregister, Pid}).
+
+
+notify(DbName, Event) ->
+    gen_server:cast(?DIST, {DbName, Event}).

http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/cc616a77/src/couch_event_app.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_app.erl b/src/couch_event_app.erl
new file mode 100644
index 0000000..3a8341b
--- /dev/null
+++ b/src/couch_event_app.erl
@@ -0,0 +1,27 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-module(couch_event_app).
+-behavior(application).
+
+-export([
+    start/2,
+    stop/1
+]).
+
+
+start(_StartType, _StartArgs) ->
+    couch_event_sup2:start_link().
+
+
+stop(_State) ->
+    ok.

http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/cc616a77/src/couch_event_dist.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_dist.erl b/src/couch_event_dist.erl
new file mode 100644
index 0000000..7f99a2d
--- /dev/null
+++ b/src/couch_event_dist.erl
@@ -0,0 +1,83 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-module(couch_event_dist).
+-behavior(gen_server).
+
+
+-export([
+    start_link/0
+]).
+
+-export([
+    init/1,
+    terminate/2,
+    handle_call/3,
+    handle_cast/2,
+    handle_info/2,
+    code_change/3
+]).
+
+
+-include("couch_event_int.hrl").
+
+
+-record(st, {
+    batch_size
+}).
+
+
+start_link() ->
+    gen_server:start_link({local, ?MODULE}, ?MODULE, nil, []).
+
+
+init(_) ->
+    {ok, #st{batch_size=25}}.
+
+
+terminate(_Reason, _St) ->
+    ok.
+
+
+handle_call(Msg, From, St) ->
+    couch_log:notice("~s ignoring call ~w from ~w", [?MODULE, Msg, From]),
+    {reply, ignored, St}.
+
+
+handle_cast({DbName, Event}, #st{batch_size=BS}=St) when is_binary(DbName) ->
+    P1 = #client{dbname=DbName, _='_'},
+    notify_clients(ets:select(?REGISTRY_TABLE, P1, BS), DbName, Event),
+    P2 = #client{dbname=all_dbs, _='_'},
+    notify_clients(ets:select(?REGISTRY_TABLE, P2, BS), DbName, Event),
+    {noreply, St};
+
+handle_cast(Msg, St) ->
+    couch_log:notice("~s ignoring cast ~w", [?MODULE, Msg]),
+    {noreply, St}.
+
+
+handle_info(Msg, St) ->
+    couch_log:notice("~s ignoring info ~w", [?MODULE, Msg]),
+    {noreply, St}.
+
+
+code_change(_OldVsn, St, _Extra) ->
+    {ok, St}.
+
+
+notify_clients('$end_of_table', _DbName, _Event) ->
+    ok;
+notify_clients({Clients, Cont}, DbName, Event) ->
+    lists:foreach(fun(#client{pid=Pid}) ->
+        Pid ! {'$couch_event', DbName, Event}
+    end, Clients),
+    notify_clients(ets:select(Cont), DbName, Event).

http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/cc616a77/src/couch_event_int.hrl
----------------------------------------------------------------------
diff --git a/src/couch_event_int.hrl b/src/couch_event_int.hrl
new file mode 100644
index 0000000..dc4739e
--- /dev/null
+++ b/src/couch_event_int.hrl
@@ -0,0 +1,19 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-define(REGISTRY_TABLE, couch_event_registry).
+
+-record(client, {
+    dbname,
+    pid,
+    ref
+}).

http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/cc616a77/src/couch_event_listener.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_listener.erl b/src/couch_event_listener.erl
new file mode 100644
index 0000000..c665036
--- /dev/null
+++ b/src/couch_event_listener.erl
@@ -0,0 +1,169 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-module(couch_event_listener).
+-behavior(gen_server).
+
+
+-export([
+    start/3,
+    start/4,
+    start_link/3,
+    start_link/4
+]).
+
+-export([
+    behaviour_info/1
+]).
+
+-export([
+    init/1,
+    terminate/2,
+    handle_call/3,
+    handle_cast/2,
+    handle_info/2,
+    code_change/3
+]).
+
+
+behaviour_info(callbacks) ->
+    [
+        {init,1},
+        {terminate/2},
+        {handle_event/2}
+    ];
+behaviour_info(_) ->
+    undefined.
+
+
+start(Mod, Args, Options) ->
+    gen_server:start(?MODULE, {Mod, Args}, Options).
+
+
+start(Name, Mod, Args, Options) ->
+    gen_server:start(Name, ?MODULE, {Mod, Args}, Options).
+
+
+start_link(Mod, Args, Options) ->
+    gen_server:start_link(?MODULE, {Mod, Args}, Options).
+
+
+start_link(Name, Mod, Args, Options) ->
+    gen_server:start_link(Name, ?MODULE, {Mod, Args}, Options).
+
+
+init({Mod, Args}) ->
+    case Mod:init(Args) of
+        {ok, St} ->
+            {ok, {Mod, St}};
+        {ok, St, Timeout} ->
+            {ok, {Mod, St}, Timeout};
+        {stop, Reason} ->
+            {stop, Reason};
+        ignore ->
+            ignore;
+        Else ->
+            erlang:error({bad_return, Else})
+    end.
+
+
+terminate(Reason, {Mod, St}) ->
+    Mod:terminate(Reason, St).
+
+
+handle_call(Msg, From, {Mod, St}) ->
+    case erlang:function_exported(Mod, handle_call, 3) of
+        true ->
+            case Mod:handle_call(Msg, From, St) of
+                {reply, Reply, NewState} ->
+                    {reply, Reply, {Mod, NewState}};
+                {reply, Reply, NewState, Timeout} ->
+                    {reply, Reply, {Mod, NewState}, Timeout};
+                {noreply, NewState} ->
+                    {noreply, {Mod, NewState}};
+                {noreply, NewState, Timeout} ->
+                    {noreply, {Mod, NewState}, Timeout};
+                {stop, Reason, Reply, NewState} ->
+                    {stop, Reason, Reply, {Mod, NewState}};
+                {stop, Reason, NewState} ->
+                    {stop, Reason, {Mod, NewState}};
+                Else ->
+                    erlang:error({bad_return, Else})
+            end;
+        false ->
+            {stop, {invalid_call, Msg}, invalid_call, St}
+    end.
+
+
+handle_cast(Msg, {Mod, St}) ->
+    case erlang:function_exported(Mod, handle_cast, 2) of
+        true ->
+            case Mod:handle_cast(Msg, St) of
+                {noreply, NewState} ->
+                    {noreply, {Mod, NewState}};
+                {noreply, NewState, Timeout} ->
+                    {noreply, {Mod, NewState}, Timeout};
+                {stop, Reason, NewState} ->
+                    {stop, Reason, {Mod, NewState}};
+                Else ->
+                    erlang:error({bad_return, Else})
+            end;
+        false ->
+            {stop, {invalid_cast, Msg}, St}
+    end.
+
+
+handle_info({'$couch_event', DbName, Event}, {Mod, St}) ->
+    case Mod:handle_event(DbName, Event, St) of
+        {noreply, NewState} ->
+            {noreply, {Mod, NewState}};
+        {noreply, NewState, Timeout} ->
+            {noreply, {Mod, NewState}, Timeout};
+        {stop, Reason, NewState} ->
+            {stop, Reason, {Mod, NewState}};
+        Else ->
+            erlang:error({bad_return, Else})
+    end;
+
+handle_info(Msg, {Mod, St}) ->
+    case erlang:function_export(Mod, handle_info, 2) of
+        true ->
+            case Mod:handle_info(Msg, St) of
+                {noreply, NewState} ->
+                    {noreply, {Mod, NewState}};
+                {noreply, NewState, Timeout} ->
+                    {noreply, {Mod, NewState}, Timeout};
+                {stop, Reason, NewState} ->
+                    {stop, Reason, {Mod, NewState}};
+                Else ->
+                    erlang:error({bad_return, Else})
+            end;
+        false ->
+            {stop, {invalid_info, Msg}, St}
+    end.
+
+
+code_change(OldVsn, {Mod, St}, Extra) ->
+    case erlang:function_exported(Mod, code_change, 3) of
+        true ->
+            case Mod:code_change(OldVsn, St, Extra) of
+                {ok, NewState} ->
+                    {ok, {Mod, NewState}};
+                {error, Reason} ->
+                    {error, Reason};
+                Else ->
+                    erlang:error({bad_return, Else})
+            end;
+        false ->
+            {ok, {Mod, St}}
+    end.
+

http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/cc616a77/src/couch_event_registry.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_registry.erl b/src/couch_event_registry.erl
new file mode 100644
index 0000000..65fa160
--- /dev/null
+++ b/src/couch_event_registry.erl
@@ -0,0 +1,109 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-module(couch_event_registry).
+-behavior(gen_server).
+
+
+-export([
+    start_link/0
+]).
+
+-export([
+    init/1,
+    terminate/2,
+    handle_call/3,
+    handle_cast/2,
+    handle_info/2,
+    code_change/3
+]).
+
+
+-include("couch_event_int.hrl").
+
+
+start_link() ->
+    gen_server:start_link({local, ?MODULE}, ?MODULE, nil, []).
+
+
+init(_) ->
+    EtsOpts = [
+        protected,
+        named_table,
+        bag,
+        {keypos, #client.dbname}
+    ],
+    ets:new(?REGISTRY_TABLE, EtsOpts),
+    {ok, nil}.
+
+
+terminate(_Reason, _St) ->
+    ok.
+
+
+handle_call({register, Pid, DbName}, _From, St) ->
+    Client = #client{
+        dbname = DbName,
+        pid = Pid,
+        ref = erlang:monitor(process, Pid)
+    },
+    ets:insert(?REGISTRY_TABLE, Client),
+    {reply, ok, St};
+
+handle_call({unregister, Pid, DbName}, _From, St) ->
+    Pattern = #client{dbname=DbName, pid=Pid, _='_'},
+    case ets:match_object(?REGISTRY_TABLE, Pattern) of
+        [] ->
+            ok;
+        [#client{ref=Ref}=Cli] ->
+            erlang:demonitor(Ref, [flush]),
+            ets:delete_object(?REGISTRY_TABLE, Cli)
+    end,
+    {reply, ok, St};
+
+handle_call({unregister_all, Pid}, _From, St) ->
+    Pattern = #client{pid=Pid, _='_'},
+    case ets:match_object(?REGISTRY_TABLE, Pattern) of
+        [] ->
+            ok;
+        Clients ->
+            lists:foreach(fun(Cli) ->
+                erlang:demonitor(Cli#client.ref, [flush]),
+                % I wonder if match_delete/2 is faster
+                % than repeated calls to delete_object.
+                ets:delete_object(Cli)
+            end, Clients)
+    end,
+    {reply, ok, St};
+
+handle_call(Msg, From, St) ->
+    couch_log:notice("~s ignoring call ~w from ~w", [?MODULE, Msg, From]),
+    {reply, ignored, St, 0}.
+
+
+handle_cast(Msg, St) ->
+    couch_log:notice("~s ignoring cast ~w", [?MODULE, Msg]),
+    {noreply, St, 0}.
+
+
+handle_info({'DOWN', Ref, process, Pid, _Reason}, St) ->
+    Pattern = #client{pid=Pid, ref=Ref, _='_'},
+    ets:match_delete(?REGISTRY_TABLE, Pattern),
+    {noreply, St};
+
+handle_info(Msg, St) ->
+    couch_log:notice("~s ignoring info ~w", [?MODULE, Msg]),
+    {noreply, St, 0}.
+
+
+code_change(_OldVsn, St, _Extra) ->
+    {ok, St}.

http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/cc616a77/src/couch_event_sup2.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_sup2.erl b/src/couch_event_sup2.erl
new file mode 100644
index 0000000..039b897
--- /dev/null
+++ b/src/couch_event_sup2.erl
@@ -0,0 +1,51 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+% This is named couch_event_sup2 to avoid
+% naming collisions with the couch_event_sup
+% module contained in the couch app. When
+% that supervisor is removed we'll be free
+% to rename this one.
+
+-module(couch_event_sup2).
+-behavior(supervisor).
+
+
+-export([
+    start_link/0,
+    init/1
+]).
+
+
+start_link() ->
+    supervisor:start_link({local, ?MODULE}, ?MODULE, nil).
+
+
+init(_) ->
+    Children = [
+        {couch_event_registry,
+            {couch_event_registry, start_link, []},
+            permanent,
+            5000,
+            worker,
+            [couch_event_register]
+        },
+        {couch_event_dist,
+            {couch_event_dist, start_link, []},
+            permanent,
+            5000,
+            worker,
+            [couch_event_dist]
+        }
+    ],
+    {ok, {{one_for_one, 5, 10}, Children}}.
+


[10/35] git commit: New couch_event:listen/4 API

Posted by rn...@apache.org.
New couch_event:listen/4 API

This function doesn't return but allows a process to become an event
listener. Useful in RPC situations to avoid spawning an extra process
and doubling the message passing.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/commit/b00c879d
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/tree/b00c879d
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/diff/b00c879d

Branch: refs/heads/windsor-merge
Commit: b00c879dabef34edb30c1ce6606e2b7e700532c8
Parents: bf25e9f
Author: Paul J. Davis <pa...@gmail.com>
Authored: Wed Apr 24 11:33:21 2013 -0500
Committer: Robert Newson <rn...@apache.org>
Committed: Wed Jul 30 17:36:52 2014 +0100

----------------------------------------------------------------------
 src/couch_event.erl              |  4 ++++
 src/couch_event_listener_mfa.erl | 12 +++++++++++-
 2 files changed, 15 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/b00c879d/src/couch_event.erl
----------------------------------------------------------------------
diff --git a/src/couch_event.erl b/src/couch_event.erl
index fd04824..7e77bff 100644
--- a/src/couch_event.erl
+++ b/src/couch_event.erl
@@ -38,6 +38,10 @@ notify(DbName, Event) ->
     gen_server:cast(?DIST, {DbName, Event}).
 
 
+listen(Module, Function, State, Options) ->
+    couch_event_listener_mfa:enter_loop(Module, Function, State, Options).
+
+
 link_listener(Module, Function, State, Options) ->
     couch_event_listener_mfa:start_link(Module, Function, State, Options).
 

http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/b00c879d/src/couch_event_listener_mfa.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_listener_mfa.erl b/src/couch_event_listener_mfa.erl
index 2231448..81adb8f 100644
--- a/src/couch_event_listener_mfa.erl
+++ b/src/couch_event_listener_mfa.erl
@@ -16,7 +16,8 @@
 
 -export([
     start_link/4,
-    stop/1
+    enter_loop/4,
+    stop/1,
 ]).
 
 -export([
@@ -41,6 +42,15 @@ start_link(Mod, Func, State, Options) ->
     couch_event_listener:start_link(?MODULE, Arg, Options).
 
 
+enter_loop(Mod, Func, State, Options) ->
+    St = #st{
+        mod = Mod,
+        func = Func,
+        state = State
+    },
+    couch_event_listener:enter_loop(?MODULE, St, Options).
+
+
 stop(Pid) ->
     couch_event_listener:stop(Pid).
 


[26/35] git commit: Use khash for tracking event listeners

Posted by rn...@apache.org.
Use khash for tracking event listeners

After doing some testing locally it became apparent that ets is a bit of
a bottleneck when used as a bag with many duplicate keys. Theoretically
this new approach could be accomplished by nesting ets tables but the
ets table limit makes that approach untenable in the long run.

This just replaces the use of ets with khash as well as runs a nested
hash table structure to store the list of pids for each database name.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/commit/8e6797a2
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/tree/8e6797a2
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/diff/8e6797a2

Branch: refs/heads/windsor-merge
Commit: 8e6797a2db00813d62d0bf3054153de6618022b3
Parents: 1deb3d4
Author: Paul J. Davis <pa...@gmail.com>
Authored: Sat May 11 15:51:42 2013 -0500
Committer: Robert Newson <rn...@apache.org>
Committed: Wed Jul 30 17:46:56 2014 +0100

----------------------------------------------------------------------
 src/couch_event.erl          |  28 +++----
 src/couch_event_dist.erl     |  88 ----------------------
 src/couch_event_listener.erl |   4 +-
 src/couch_event_registry.erl | 142 -----------------------------------
 src/couch_event_server.erl   | 154 ++++++++++++++++++++++++++++++++++++++
 src/couch_event_sup2.erl     |  13 +---
 6 files changed, 168 insertions(+), 261 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/8e6797a2/src/couch_event.erl
----------------------------------------------------------------------
diff --git a/src/couch_event.erl b/src/couch_event.erl
index 72926d6..9f8e501 100644
--- a/src/couch_event.erl
+++ b/src/couch_event.erl
@@ -26,17 +26,15 @@
     register/2,
     register_many/2,
     register_all/1,
-    unregister/2,
-    unregister_many/2,
-    unregister_all/1
+    unregister/1
 ]).
 
--define(REGISTRY, couch_event_registry).
--define(DIST, couch_event_dist).
+
+-define(SERVER, couch_event_server).
 
 
 notify(DbName, Event) ->
-    gen_server:cast(?DIST, {DbName, Event}).
+    gen_server:cast(?SERVER, {notify, DbName, Event}).
 
 
 listen(Module, Function, State, Options) ->
@@ -52,24 +50,16 @@ stop_listener(Pid) ->
 
 
 register(Pid, DbName) ->
-    gen_server:call(?REGISTRY, {register, Pid, [DbName]}).
+    gen_server:call(?SERVER, {register, Pid, [DbName]}).
 
 
 register_many(Pid, DbNames) when is_list(DbNames) ->
-    gen_server:call(?REGISTRY, {register, Pid, DbNames}).
+    gen_server:call(?SERVER, {register, Pid, DbNames}).
 
 
 register_all(Pid) ->
-    gen_server:call(?REGISTRY, {register, Pid, [all_dbs]}).
-
-
-unregister(Pid, DbName) ->
-    gen_server:call(?REGISTRY, {unregister, Pid, [DbName]}).
-
-
-unregister_many(Pid, DbNames) when is_list(DbNames) ->
-    gen_server:call(?REGISTRY, {unregister, Pid, DbNames}).
+    gen_server:call(?SERVER, {register, Pid, [all_dbs]}).
 
 
-unregister_all(Pid) ->
-    gen_server:call(?REGISTRY, {unregister, Pid}).
+unregister(Pid) ->
+    gen_server:call(?SERVER, {unregister, Pid}).

http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/8e6797a2/src/couch_event_dist.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_dist.erl b/src/couch_event_dist.erl
deleted file mode 100644
index 95aaf65..0000000
--- a/src/couch_event_dist.erl
+++ /dev/null
@@ -1,88 +0,0 @@
-% Licensed under the Apache License, Version 2.0 (the "License"); you may not
-% use this file except in compliance with the License. You may obtain a copy of
-% the License at
-%
-%   http://www.apache.org/licenses/LICENSE-2.0
-%
-% Unless required by applicable law or agreed to in writing, software
-% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-% License for the specific language governing permissions and limitations under
-% the License.
-
--module(couch_event_dist).
--behavior(gen_server).
-
-
--export([
-    start_link/0
-]).
-
--export([
-    init/1,
-    terminate/2,
-    handle_call/3,
-    handle_cast/2,
-    handle_info/2,
-    code_change/3
-]).
-
-
--include("couch_event_int.hrl").
-
-
--record(st, {
-    batch_size
-}).
-
-
-start_link() ->
-    gen_server:start_link({local, ?MODULE}, ?MODULE, nil, []).
-
-
-init(_) ->
-    {ok, #st{batch_size=25}}.
-
-
-terminate(_Reason, _St) ->
-    ok.
-
-
-handle_call(Msg, From, St) ->
-    couch_log:notice("~s ignoring call ~w from ~w", [?MODULE, Msg, From]),
-    {reply, ignored, St}.
-
-
-handle_cast({DbName, Event}, #st{batch_size=BS}=St) when is_binary(DbName) ->
-    margaret_counter:increment([couch_event, events_received]),
-    T1 = notify_clients(#client{dbname=DbName, _='_'}, BS, DbName, Event),
-    T2 = notify_clients(#client{dbname=all_dbs, _='_'}, BS, DbName, Event),
-    margaret_counter:increment([couch_event, events_delivered], T1 + T2),
-    {noreply, St};
-
-handle_cast(Msg, St) ->
-    couch_log:notice("~s ignoring cast ~w", [?MODULE, Msg]),
-    {noreply, St}.
-
-
-handle_info(Msg, St) ->
-    couch_log:notice("~s ignoring info ~w", [?MODULE, Msg]),
-    {noreply, St}.
-
-
-code_change(_OldVsn, St, _Extra) ->
-    {ok, St}.
-
-
-notify_clients(Pattern, BatchSize, DbName, Event) ->
-    MSpec = [{Pattern, [], ['$_']}],
-    do_notify(ets:select(?REGISTRY_TABLE, MSpec, BatchSize), DbName, Event, 0).
-
-
-do_notify('$end_of_table', _DbName, _Event, Total) ->
-    Total;
-do_notify({Clients, Cont}, DbName, Event, Total) ->
-    lists:foreach(fun(#client{pid=Pid}) ->
-        Pid ! {'$couch_event', DbName, Event}
-    end, Clients),
-    do_notify(ets:select(Cont), DbName, Event, Total + length(Clients)).

http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/8e6797a2/src/couch_event_listener.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_listener.erl b/src/couch_event_listener.erl
index 04d5fc1..34db139 100644
--- a/src/couch_event_listener.erl
+++ b/src/couch_event_listener.erl
@@ -179,10 +179,10 @@ do_info(#st{module=Module, state=State}=St, Message) ->
 
 do_terminate(Reason, #st{module=Module, state=State}) ->
     % Order matters. We want to make sure Module:terminate/1
-    % is called even if couch_event:unregister_all/1 hangs
+    % is called even if couch_event:unregister/1 hangs
     % indefinitely.
     catch Module:terminate(Reason, State),
-    catch couch_event:unregister_all(self()),
+    catch couch_event:unregister(self()),
     Status = case Reason of
         normal -> normal;
         shutdown -> normal;

http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/8e6797a2/src/couch_event_registry.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_registry.erl b/src/couch_event_registry.erl
deleted file mode 100644
index adea994..0000000
--- a/src/couch_event_registry.erl
+++ /dev/null
@@ -1,142 +0,0 @@
-% Licensed under the Apache License, Version 2.0 (the "License"); you may not
-% use this file except in compliance with the License. You may obtain a copy of
-% the License at
-%
-%   http://www.apache.org/licenses/LICENSE-2.0
-%
-% Unless required by applicable law or agreed to in writing, software
-% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-% License for the specific language governing permissions and limitations under
-% the License.
-
--module(couch_event_registry).
--behavior(gen_server).
-
-
--export([
-    start_link/0
-]).
-
--export([
-    init/1,
-    terminate/2,
-    handle_call/3,
-    handle_cast/2,
-    handle_info/2,
-    code_change/3
-]).
-
-
--include("couch_event_int.hrl").
-
-
-start_link() ->
-    gen_server:start_link({local, ?MODULE}, ?MODULE, nil, []).
-
-
-init(_) ->
-    RegistryOpts = [
-        protected,
-        named_table,
-        bag,
-        {keypos, #client.dbname}
-    ],
-    MonitorOpts = [
-        protected,
-        named_table,
-        set
-    ],
-    ets:new(?REGISTRY_TABLE, RegistryOpts),
-    ets:new(?MONITOR_TABLE, MonitorOpts),
-    {ok, nil}.
-
-
-terminate(_Reason, _St) ->
-    ok.
-
-
-handle_call({register, Pid, DbNames}, _From, St) ->
-    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})
-    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) ->
-        ets:match_delete(?REGISTRY_TABLE, pattern(DbName, Pid))
-    end, DbNames),
-    maybe_drop_monitor(Pid),
-    {reply, ok, St};
-
-handle_call({unregister_all, Pid}, _From, St) ->
-    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}.
-
-
-handle_cast(Msg, St) ->
-    couch_log:notice("~s ignoring cast ~w", [?MODULE, Msg]),
-    {noreply, St}.
-
-
-handle_info({'DOWN', _Ref, process, Pid, _Reason}, 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}.
-
-
-code_change(_OldVsn, St, _Extra) ->
-    {ok, St}.
-
-
-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, _='_'}.

http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/8e6797a2/src/couch_event_server.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_server.erl b/src/couch_event_server.erl
new file mode 100644
index 0000000..77e6ce3
--- /dev/null
+++ b/src/couch_event_server.erl
@@ -0,0 +1,154 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-module(couch_event_server).
+-behavior(gen_server).
+
+
+-export([
+    start_link/0
+]).
+
+-export([
+    init/1,
+    terminate/2,
+    handle_call/3,
+    handle_cast/2,
+    handle_info/2,
+    code_change/3
+]).
+
+
+-include("couch_event_int.hrl").
+
+
+-record(st, {
+    by_pid,
+    by_dbname
+}).
+
+
+start_link() ->
+    gen_server:start_link({local, ?MODULE}, ?MODULE, nil, []).
+
+
+init(_) ->
+    {ok, ByPid} = khash:new(),
+    {ok, ByDbName} = khash:new(),
+    {ok, #st{
+        by_pid = ByPid,
+        by_dbname = ByDbName
+    }}.
+
+
+terminate(_Reason, _St) ->
+    ok.
+
+
+handle_call({register, Pid, NewDbNames}, _From, St) ->
+    case khash:get(St#st.by_pid, Pid) of
+        undefined ->
+            NewRef = erlang:monitor(process, Pid),
+            register(St, NewRef, Pid, NewDbNames);
+        {ReuseRef, OldDbNames} ->
+            unregister(St, Pid, OldDbNames),
+            register(St, ReuseRef, Pid, NewDbNames)
+    end,
+    {reply, ok, St};
+
+handle_call({unregister, Pid}, _From, St) ->
+    case khash:get(St#st.by_pid, Pid) of
+        undefined ->
+            {reply, not_registered, St};
+        {Ref, OldDbNames} ->
+            unregister(St, Pid, OldDbNames),
+            erlang:demonitor(Ref, [flush])
+    end,
+    {reply, ok, St};
+
+handle_call(Msg, From, St) ->
+    couch_log:notice("~s ignoring call ~w from ~w", [?MODULE, Msg, From]),
+    {reply, ignored, St}.
+
+
+handle_cast({notify, DbName, Event}, St) ->
+    notify_listeners(St#st.by_dbname, DbName, Event),
+    {noreply, St};
+
+handle_cast(Msg, St) ->
+    couch_log:notice("~s ignoring cast ~w", [?MODULE, Msg]),
+    {noreply, St}.
+
+
+handle_info({'DOWN', Ref, process, Pid, _Reason}, St) ->
+    case khash:get(St#st.by_pid, Pid) of
+        {Ref, OldDbNames} ->
+            unregister(St, Pid, OldDbNames);
+        undefined ->
+            ok
+    end,
+    {noreply, St};
+
+handle_info(Msg, St) ->
+    couch_log:notice("~s ignoring info ~w", [?MODULE, Msg]),
+    {noreply, St}.
+
+
+code_change(_OldVsn, St, _Extra) ->
+    {ok, St}.
+
+
+notify_listeners(ByDbName, DbName, Event) ->
+    Msg = {'$couch_event', DbName, Event},
+    notify_listeners(khash:get(ByDbName, all_dbs), Msg),
+    notify_listeners(khash:get(ByDbName, DbName), Msg).
+
+
+notify_listeners(undefined, _) ->
+    ok;
+notify_listeners(Listeners, Msg) ->
+    khash:fold(Listeners, fun(Pid, _, _) -> Pid ! Msg, nil end, nil).
+
+
+register(St, Ref, Pid, DbNames) ->
+    khash:put(St#st.by_pid, Pid, {Ref, DbNames}),
+    lists:foreach(fun(DbName) ->
+        add_listener(St#st.by_dbname, DbName, Pid)
+    end, DbNames).
+
+
+add_listener(ByDbName, DbName, Pid) ->
+    case khash:lookup(ByDbName, DbName) of
+        {value, Listeners} ->
+            khash:put(Listeners, Pid, nil);
+        not_found ->
+            {ok, NewListeners} = khash:new(),
+            khash:put(NewListeners, Pid, nil),
+            khash:put(ByDbName, DbName, NewListeners)
+    end.
+
+
+unregister(St, Pid, OldDbNames) ->
+    ok = khash:del(St#st.by_pid, Pid),
+    lists:foreach(fun(DbName) ->
+        rem_listener(St#st.by_dbname, DbName, Pid)
+    end, OldDbNames).
+
+
+rem_listener(ByDbName, DbName, Pid) ->
+    {value, Listeners} = khash:lookup(ByDbName, DbName),
+    khash:del(Listeners, Pid),
+    Size = khash:size(Listeners),
+    if Size > 0 -> ok; true ->
+        khash:del(ByDbName, DbName)
+    end.
+            

http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/8e6797a2/src/couch_event_sup2.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_sup2.erl b/src/couch_event_sup2.erl
index 1a74979..36fbe54 100644
--- a/src/couch_event_sup2.erl
+++ b/src/couch_event_sup2.erl
@@ -32,19 +32,12 @@ start_link() ->
 
 init(_) ->
     Children = [
-        {couch_event_registry,
-            {couch_event_registry, start_link, []},
+        {couch_event_server,
+            {couch_event_server, start_link, []},
             permanent,
             5000,
             worker,
-            [couch_event_registry]
-        },
-        {couch_event_dist,
-            {couch_event_dist, start_link, []},
-            permanent,
-            5000,
-            worker,
-            [couch_event_dist]
+            [couch_event_server]
         },
         {couch_event_os_sup,
             {couch_event_os_sup, start_link, []},


[32/35] git commit: Rearrange and lengthen the watchdog delay

Posted by rn...@apache.org.
Rearrange and lengthen the watchdog delay

I did not completely comprehend that code upgrades are not atomic for
all code. This watchdog ended up causing a node reboot into an unusable
state because it killed couch_db_update_notifier handlers before the new
code was installed for each app.

This lead to mem3 quickly cycling trying to use couch_db_update_notifier
which eventually took down the mem3 app which took down the node. Then
the node would reboot into 1202 after databases had upgraded their
headers which prevented the node from booting correctly.

By extending the timeout to five minutes and placing it before the first
call to terminating couch_db_update I hope to give the release enough
time to complete before telling each handler to upgrade.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/commit/707997e3
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/tree/707997e3
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/diff/707997e3

Branch: refs/heads/windsor-merge
Commit: 707997e37db11aa8194b00c0a432e49c7071b1f2
Parents: de23171
Author: Paul J. Davis <pa...@gmail.com>
Authored: Tue Jun 18 12:14:17 2013 -0500
Committer: Robert Newson <rn...@apache.org>
Committed: Wed Jul 30 17:49:19 2014 +0100

----------------------------------------------------------------------
 src/couch_event_server.erl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/707997e3/src/couch_event_server.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_server.erl b/src/couch_event_server.erl
index bd291aa..1c7bcf4 100644
--- a/src/couch_event_server.erl
+++ b/src/couch_event_server.erl
@@ -123,6 +123,7 @@ code_change(_OldVsn, St, _Extra) ->
 
 
 watchdog() ->
+    timer:sleep(300000),
     Handlers = gen_event:which_handlers(couch_db_update),
     case length(Handlers) > 0 of
         true ->
@@ -133,7 +134,6 @@ watchdog() ->
         false ->
             ok
     end,
-    timer:sleep(5000),
     ?MODULE:watchdog().
 
 


[08/35] git commit: Make sure and exit with the reason given

Posted by rn...@apache.org.
Make sure and exit with the reason given


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/commit/8f63a783
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/tree/8f63a783
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/diff/8f63a783

Branch: refs/heads/windsor-merge
Commit: 8f63a7839f32906335529ade04add975cb49da66
Parents: a280611
Author: Paul J. Davis <pa...@gmail.com>
Authored: Tue Apr 23 15:41:44 2013 -0500
Committer: Robert Newson <rn...@apache.org>
Committed: Wed Jul 30 17:36:27 2014 +0100

----------------------------------------------------------------------
 src/couch_event_listener.erl | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch-event/blob/8f63a783/src/couch_event_listener.erl
----------------------------------------------------------------------
diff --git a/src/couch_event_listener.erl b/src/couch_event_listener.erl
index 7c942bd..94bb133 100644
--- a/src/couch_event_listener.erl
+++ b/src/couch_event_listener.erl
@@ -183,12 +183,13 @@ do_terminate(Reason, #st{module=Module, state=State}) ->
     % indefinitely.
     catch Module:terminate(Reason, State),
     catch couch_event:unregister_all(self()),
-    case Reason of
-        normal -> ok;
-        shutdown -> ok;
-        ignore -> ok;
-        Else -> erlang:error(Else)
-    end.
+    Status = case Reason of
+        normal -> normal;
+        shutdown -> normal;
+        ignore -> normal;
+        Else -> Else
+    end,
+    erlang:exit(Status).
 
 
 where({global, Name}) -> global:safe_whereis_name(Name);