Browse Source

rebar.config.script and dynamic deps handling

Ulf Wiger 12 years ago
parent
commit
44a3ad7d34
7 changed files with 167 additions and 51 deletions
  1. 13 13
      README.md
  2. 9 2
      doc/gproc_dist.md
  3. 17 5
      doc/gproc_ps.md
  4. 33 0
      priv/check_edown.script
  5. 18 0
      priv/remove_deps.script
  6. 1 0
      rebar.config.script
  7. 76 31
      src/gproc_dist.erl

+ 13 - 13
README.md

@@ -62,8 +62,8 @@ alternative sources, and cache them for efficient lookup. Caching also provides
 a way to see which processes rely on certain configuration values, as well as
 which values they actually ended up using.
 
-See [`gproc:get_env/4`](http://github.com/esl/gproc/blob/master/doc/gproc.md#get_env-4), [`gproc:get_set_env/4`](http://github.com/esl/gproc/blob/master/doc/gproc.md#get_set_env-4) and
-[`gproc:set_env/5`](http://github.com/esl/gproc/blob/master/doc/gproc.md#set_env-5) for details.
+See [`gproc:get_env/4`](http://github.com/esl/gproc/blob/0.2.14/doc/gproc.md#get_env-4), [`gproc:get_set_env/4`](http://github.com/esl/gproc/blob/0.2.14/doc/gproc.md#get_set_env-4) and
+[`gproc:set_env/5`](http://github.com/esl/gproc/blob/0.2.14/doc/gproc.md#set_env-5) for details.
 
 ##Testing##
 
@@ -82,21 +82,21 @@ global gproc.
 
 By default, `./rebar doc` generates Github-flavored Markdown files.
 If you want to change this, remove the `edoc_opts` line from `rebar.config`.Gproc was first introduced at the ACM SIGPLAN Erlang Workshop in
-Freiburg 2007 ([Paper available here](http://github.com/esl/gproc/blob/master/doc/erlang07-wiger.pdf)).
+Freiburg 2007 ([Paper available here](http://github.com/esl/gproc/blob/0.2.14/doc/erlang07-wiger.pdf)).
 
 
 ##Modules##
 
 
 <table width="100%" border="0" summary="list of modules">
-<tr><td><a href="http://github.com/esl/gproc/blob/master/doc/gproc.md" class="module">gproc</a></td></tr>
-<tr><td><a href="http://github.com/esl/gproc/blob/master/doc/gproc_app.md" class="module">gproc_app</a></td></tr>
-<tr><td><a href="http://github.com/esl/gproc/blob/master/doc/gproc_bcast.md" class="module">gproc_bcast</a></td></tr>
-<tr><td><a href="http://github.com/esl/gproc/blob/master/doc/gproc_dist.md" class="module">gproc_dist</a></td></tr>
-<tr><td><a href="http://github.com/esl/gproc/blob/master/doc/gproc_info.md" class="module">gproc_info</a></td></tr>
-<tr><td><a href="http://github.com/esl/gproc/blob/master/doc/gproc_init.md" class="module">gproc_init</a></td></tr>
-<tr><td><a href="http://github.com/esl/gproc/blob/master/doc/gproc_lib.md" class="module">gproc_lib</a></td></tr>
-<tr><td><a href="http://github.com/esl/gproc/blob/master/doc/gproc_monitor.md" class="module">gproc_monitor</a></td></tr>
-<tr><td><a href="http://github.com/esl/gproc/blob/master/doc/gproc_ps.md" class="module">gproc_ps</a></td></tr>
-<tr><td><a href="http://github.com/esl/gproc/blob/master/doc/gproc_sup.md" class="module">gproc_sup</a></td></tr></table>
+<tr><td><a href="http://github.com/esl/gproc/blob/0.2.14/doc/gproc.md" class="module">gproc</a></td></tr>
+<tr><td><a href="http://github.com/esl/gproc/blob/0.2.14/doc/gproc_app.md" class="module">gproc_app</a></td></tr>
+<tr><td><a href="http://github.com/esl/gproc/blob/0.2.14/doc/gproc_bcast.md" class="module">gproc_bcast</a></td></tr>
+<tr><td><a href="http://github.com/esl/gproc/blob/0.2.14/doc/gproc_dist.md" class="module">gproc_dist</a></td></tr>
+<tr><td><a href="http://github.com/esl/gproc/blob/0.2.14/doc/gproc_info.md" class="module">gproc_info</a></td></tr>
+<tr><td><a href="http://github.com/esl/gproc/blob/0.2.14/doc/gproc_init.md" class="module">gproc_init</a></td></tr>
+<tr><td><a href="http://github.com/esl/gproc/blob/0.2.14/doc/gproc_lib.md" class="module">gproc_lib</a></td></tr>
+<tr><td><a href="http://github.com/esl/gproc/blob/0.2.14/doc/gproc_monitor.md" class="module">gproc_monitor</a></td></tr>
+<tr><td><a href="http://github.com/esl/gproc/blob/0.2.14/doc/gproc_ps.md" class="module">gproc_ps</a></td></tr>
+<tr><td><a href="http://github.com/esl/gproc/blob/0.2.14/doc/gproc_sup.md" class="module">gproc_sup</a></td></tr></table>
 

+ 9 - 2
doc/gproc_dist.md

@@ -23,7 +23,7 @@ For a detailed description, see gproc/doc/erlang07-wiger.pdf.<a name="index"></a
 ##Function Index##
 
 
-<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#code_change-4">code_change/4</a></td><td></td></tr><tr><td valign="top"><a href="#elected-2">elected/2</a></td><td></td></tr><tr><td valign="top"><a href="#elected-3">elected/3</a></td><td></td></tr><tr><td valign="top"><a href="#from_leader-3">from_leader/3</a></td><td></td></tr><tr><td valign="top"><a href="#get_leader-0">get_leader/0</a></td><td>Returns the node of the current gproc leader.</td></tr><tr><td valign="top"><a href="#give_away-2">give_away/2</a></td><td></td></tr><tr><td valign="top"><a href="#handle_DOWN-3">handle_DOWN/3</a></td><td></td></tr><tr><td valign="top"><a href="#handle_call-4">handle_call/4</a></td><td></td></tr><tr><td valign="top"><a href="#handle_cast-3">handle_cast/3</a></td><td></td></tr><tr><td valign="top"><a href="#handle_info-2">handle_info/2</a></td><td></td></tr><tr><td valign="top"><a href="#handle_leader_call-4">handle_leader_call/4</a></td><td></td></tr><tr><td valign="top"><a href="#handle_leader_cast-3">handle_leader_cast/3</a></td><td></td></tr><tr><td valign="top"><a href="#init-1">init/1</a></td><td></td></tr><tr><td valign="top"><a href="#leader_call-1">leader_call/1</a></td><td></td></tr><tr><td valign="top"><a href="#leader_cast-1">leader_cast/1</a></td><td></td></tr><tr><td valign="top"><a href="#mreg-2">mreg/2</a></td><td></td></tr><tr><td valign="top"><a href="#munreg-2">munreg/2</a></td><td></td></tr><tr><td valign="top"><a href="#reg-1">reg/1</a></td><td></td></tr><tr><td valign="top"><a href="#reg-2">reg/2</a></td><td>
+<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#code_change-4">code_change/4</a></td><td></td></tr><tr><td valign="top"><a href="#elected-2">elected/2</a></td><td></td></tr><tr><td valign="top"><a href="#elected-3">elected/3</a></td><td></td></tr><tr><td valign="top"><a href="#from_leader-3">from_leader/3</a></td><td></td></tr><tr><td valign="top"><a href="#get_leader-0">get_leader/0</a></td><td>Returns the node of the current gproc leader.</td></tr><tr><td valign="top"><a href="#give_away-2">give_away/2</a></td><td></td></tr><tr><td valign="top"><a href="#handle_DOWN-3">handle_DOWN/3</a></td><td></td></tr><tr><td valign="top"><a href="#handle_call-4">handle_call/4</a></td><td></td></tr><tr><td valign="top"><a href="#handle_cast-3">handle_cast/3</a></td><td></td></tr><tr><td valign="top"><a href="#handle_info-2">handle_info/2</a></td><td></td></tr><tr><td valign="top"><a href="#handle_info-3">handle_info/3</a></td><td></td></tr><tr><td valign="top"><a href="#handle_leader_call-4">handle_leader_call/4</a></td><td></td></tr><tr><td valign="top"><a href="#handle_leader_cast-3">handle_leader_cast/3</a></td><td></td></tr><tr><td valign="top"><a href="#init-1">init/1</a></td><td></td></tr><tr><td valign="top"><a href="#leader_call-1">leader_call/1</a></td><td></td></tr><tr><td valign="top"><a href="#leader_cast-1">leader_cast/1</a></td><td></td></tr><tr><td valign="top"><a href="#mreg-2">mreg/2</a></td><td></td></tr><tr><td valign="top"><a href="#munreg-2">munreg/2</a></td><td></td></tr><tr><td valign="top"><a href="#reg-1">reg/1</a></td><td></td></tr><tr><td valign="top"><a href="#reg-2">reg/2</a></td><td>
 Class = n  - unique name
 | p  - non-unique property
 | c  - counter
@@ -107,6 +107,13 @@ Returns the node of the current gproc leader.<a name="give_away-2"></a>
 
 `handle_info(X1, S) -> any()`
 
+<a name="handle_info-3"></a>
+
+###handle_info/3##
+
+
+`handle_info(Msg, S, E) -> any()`
+
 <a name="handle_leader_call-4"></a>
 
 ###handle_leader_call/4##
@@ -222,7 +229,7 @@ Scope = l | g (global or local)<a name="reg_or_locate-3"></a>
 ###surrendered/3##
 
 
-`surrendered(S, X2, E) -> any()`
+`surrendered(State, X2, E) -> any()`
 
 <a name="sync-0"></a>
 

+ 17 - 5
doc/gproc_ps.md

@@ -280,11 +280,17 @@ Subscribe to events of type `Event`
 
 
 
-Any messages published with `gproc_ps:publish(Scope, Event, Msg)` will be delivered to
-the current process, along with all other subscribers.
+Any messages published with `gproc_ps:publish(Scope, Event, Msg)` will be
+delivered to the current process, along with all other subscribers.
 
-This function creates a property, `{p,Scope,{gproc_ps_event,Event}}`, which can be
-searched and displayed for debugging purposes.<a name="subscribe_cond-3"></a>
+
+
+This function creates a property, `{p,Scope,{gproc_ps_event,Event}}`, which
+can be searched and displayed for debugging purposes.
+
+Note that, as with [`gproc:reg/1`](gproc.md#reg-1), this function will raise an
+exception if you try to subscribe to the same event twice from the same
+process.<a name="subscribe_cond-3"></a>
 
 ###subscribe_cond/3##
 
@@ -322,8 +328,14 @@ like [`publish/3`](#publish-3) does, except that `publish/3` strictly speaking
 ignores the Value part of the property completely, whereas `publish_cond/3`
 expects it to be either undefined or a valid match spec).
 
+
+
 This means that `Cond=undefined` and `Cond=[{'_',[],[true]}]` are
-equivalent.<a name="tell_singles-3"></a>
+equivalent.
+
+Note that, as with [`gproc:reg/1`](gproc.md#reg-1), this function will raise an
+exception if you try to subscribe to the same event twice from the same
+process.<a name="tell_singles-3"></a>
 
 ###tell_singles/3##
 

+ 33 - 0
priv/check_edown.script

@@ -0,0 +1,33 @@
+%% -*- erlang -*-
+%%
+%% This helper script checks if doc is being built, otherwise removes edoc dep.
+%% To build docs, call `rebar get-deps doc`
+%% Assumes that the rebar config is bound to CONFIG
+
+[_|Args] = init:get_plain_arguments().  % rebar 'commands' and options
+case lists:member("doc", Args) of
+    false ->
+	{ok,C1} = file:script(filename:join(filename:dirname(SCRIPT),
+					    "remove_deps.script"),
+			      [{'CONFIG', CONFIG}, {'DEPS', [edown]}]),
+	C1;
+    true ->
+        case code:lib_dir(edown) of
+            {error, bad_name} ->
+                io:fwrite("cannot find edown~n", []),
+                D = {edown, ".*",
+                     {git, "git://github.com/esl/edown.git", "HEAD"}},
+                Deps = case lists:keyfind(deps, 1, CONFIG) of
+                           false -> [D];
+                           {_, Ds} ->
+                               case lists:keymember(edown, 1, Ds) of
+                                   true -> Ds;
+                                   false -> [D|Ds]
+                               end
+                       end,
+                lists:keystore(deps, 1, CONFIG, {deps, Deps});
+            _ ->
+                io:fwrite("edown in path~n", []),
+                CONFIG
+        end
+end.

+ 18 - 0
priv/remove_deps.script

@@ -0,0 +1,18 @@
+%% -*- erlang -*-
+%%
+%% Assumes the following bound variables:
+%% CONFIG - a rebar.config options list
+%% DEPS :: [atom()]  - a list of deps to remove
+case lists:keyfind(deps, 1, CONFIG) of
+    {_, Deps0} ->
+	Deps1 = lists:filter(
+		  fun(D) when is_atom(D) ->
+			  not lists:member(D, DEPS);
+		     (D) when is_tuple(D) ->
+			  not lists:member(element(1,D), DEPS)
+		  end, Deps0),
+	lists:keyreplace(deps, 1, CONFIG, {deps, Deps1});
+    false ->
+	CONFIG
+end.
+

+ 1 - 0
rebar.config.script

@@ -0,0 +1 @@
+/Users/uwiger/FL/rebar.config.script

+ 76 - 31
src/gproc_dist.erl

@@ -44,7 +44,7 @@
 -export([init/1,
          handle_cast/3,
          handle_call/4,
-         handle_info/2,
+         handle_info/2, handle_info/3,
          handle_leader_call/4,
          handle_leader_cast/3,
          handle_DOWN/3,
@@ -208,11 +208,15 @@ handle_call(_, _, S, _) ->
     {reply, badarg, S}.
 
 handle_info({'DOWN', _MRef, process, Pid, _}, S) ->
+    ets:delete(?TAB, {{Pid, g}}),
     leader_cast({pid_is_DOWN, Pid}),
     {ok, S};
 handle_info(_, S) ->
     {ok, S}.
 
+handle_info(Msg, S, _E) ->
+    handle_info(Msg, S).
+
 
 elected(S, _E) ->
     {ok, {globals,globs()}, S#state{is_leader = true}}.
@@ -233,8 +237,14 @@ elected(S, _E, _Node) ->
     end.
 
 globs() ->
-    ets:select(?TAB, [{{{{'_',g,'_'},'_'},'_','_'},[],['$_']}]).
+    Gs = ets:select(?TAB, [{{{{'_',g,'_'},'_'},'_','_'},[],['$_']}]),
+    _ = [gproc_lib:ensure_monitor(Pid, g) || {_, Pid, _} <- Gs],
+    Gs.
 
+surrendered(#state{is_leader = true} = S, {globals, Globs}, _E) ->
+    %% Leader conflict!
+    surrendered_1(Globs),
+    {ok, S#state{is_leader = false}};
 surrendered(S, {globals, Globs}, _E) ->
     %% globals from this node should be more correct in our table than
     %% in the leader's
@@ -276,22 +286,23 @@ handle_leader_call(sync, From, #state{sync_requests = SReqs} = S, E) ->
             gen_leader:broadcast({from_leader, {sync, From}}, Alive, E),
             {noreply, S#state{sync_requests = [{From, Alive}|SReqs]}}
     end;
-handle_leader_call({reg, {C,g,Name} = K, Value, Pid}, _From, S, _E) ->
+handle_leader_call({reg, {_C,g,_Name} = K, Value, Pid}, _From, S, _E) ->
     case gproc_lib:insert_reg(K, Value, Pid, g) of
         false ->
             {reply, badarg, S};
         true ->
             _ = gproc_lib:ensure_monitor(Pid,g),
-            Vals =
-                if C == a ->
-                        ets:lookup(?TAB, {K,a});
-                   C == c ->
-                        [{{K,Pid},Pid,Value} | ets:lookup(?TAB,{{a,g,Name},a})];
-                   C == n ->
-                        [{{K,n},Pid,Value}];
-                   true ->
-                        [{{K,Pid},Pid,Value}]
-                end,
+	    Vals = mk_broadcast_insert_vals([{K, Pid, Value}]),
+            %% Vals =
+            %%     if C == a ->
+            %%             ets:lookup(?TAB, {K,a});
+            %%        C == c ->
+            %%             [{{K,Pid},Pid,Value} | ets:lookup(?TAB,{{a,g,Name},a})];
+            %%        C == n ->
+            %%             [{{K,n},Pid,Value}];
+            %%        true ->
+            %%             [{{K,Pid},Pid,Value}]
+            %%     end,
             {reply, true, [{insert, Vals}], S}
     end;
 handle_leader_call({reg_or_locate, {n,g,_} = K, Value, Pid}, _From, S, _E) ->
@@ -500,8 +511,8 @@ handle_leader_cast({add_globals, Missing}, S, _E) ->
     %% This is an audit message: a peer (non-leader) had info about granted
     %% global resources that we didn't know of when we became leader.
     %% This could happen due to a race condition when the old leader died.
-    ets:insert(?TAB, Missing),
-    {ok, [{insert, Missing}], S};
+    Update = insert_globals(Missing),
+    {ok, [{insert, Update}], S};
 handle_leader_cast({remove_globals, Globals}, S, _E) ->
     delete_globals(Globals, []),
     {ok, S};
@@ -533,6 +544,22 @@ handle_leader_cast({pid_is_DOWN, Pid}, S, _E) ->
             {ok, Broadcast, S}
     end.
 
+mk_broadcast_insert_vals(Objs) ->
+    lists:flatmap(
+      fun({{C, g, Name} = K, Pid, Value}) ->
+	      if C == a ->
+		      ets:lookup(?TAB, {K,a}) ++ ets:lookup(?TAB, {Pid,K});
+		 C == c ->
+		      [{{K,Pid},Pid,Value} | ets:lookup(?TAB,{{a,g,Name},a})]
+			  ++ ets:lookup(?TAB, {Pid,K});
+		 C == n ->
+		      [{{K,n},Pid,Value}| ets:lookup(?TAB, {Pid,K})];
+		 true ->
+		      [{{K,Pid},Pid,Value} | ets:lookup(?TAB, {Pid,K})]
+	      end
+      end, Objs).
+
+
 process_globals(Globals) ->
     Modified =
         lists:foldl(
@@ -579,20 +606,36 @@ from_leader(Ops, S, _E) ->
       fun({delete, Globals, Event}) ->
               delete_globals(Globals, Event);
          ({insert, Globals}) ->
-              ets:insert(?TAB, Globals),
-              lists:foreach(
-                fun({{{_,g,_}=Key,_}, P, _}) ->
-                        ets:insert_new(?TAB, {{P,Key}, []}),
-                        gproc_lib:ensure_monitor(P,g);
-                   ({{P,_K}, _Opts} = Obj) when is_pid(P) ->
-			ets:insert(?TAB, Obj),
-                        gproc_lib:ensure_monitor(P,g);
-                   (_) ->
-                        skip
-                end, Globals)
+	      _ = insert_globals(Globals)
       end, Ops),
     {ok, S}.
 
+insert_globals(Globals) ->
+    ets:insert(?TAB, Globals),
+    lists:foldl(
+      fun({{{T,_,_} = Key,Pid}, Pid, _}, A) ->
+	      A1 = case T of
+		       c ->
+			   Incr = ets:lookup_element(?TAB, {Key,Pid}, 3),
+			   update_aggr_counter(Key, -Incr) ++ A;
+		       _ ->
+			   A
+		   end,
+	      ets:insert_new(?TAB, {{Pid,Key}, []}),
+	      gproc_lib:ensure_monitor(Pid,g),
+	      A1;
+	 ({{{_,_,_}, n}, Pid, _}, A) ->
+	      gproc_lib:ensure_monitor(Pid,g),
+	      A;
+	 ({{P,_K}, Opts} = Obj, A) when is_pid(P), is_list(Opts),Opts =/= [] ->
+	      ets:insert(?TAB, Obj),
+	      gproc_lib:ensure_monitor(P,g),
+	      [Obj] ++ A;
+	 (_Other, A) ->
+	      A
+      end, Globals, Globals).
+
+
 delete_globals(Globals, Event) ->
     lists:foreach(
       fun({{_,g,_},T} = K) when is_atom(T) ->
@@ -629,10 +672,11 @@ init(Opts) ->
 
 surrendered_1(Globs) ->
     My_local_globs =
-        ets:select(?TAB, [{{{{'_',g,'_'},'_'},'$1', '_'},
+        ets:select(?TAB, [{{{{'_',g,'_'},'_'},'$1', '$2'},
                            [{'==', {node,'$1'}, node()}],
-                           ['$_']}]),
-    %% remove all remote globals - we don't have monitors on them.
+                           [{{ {element,1,{element,1,'$_'}}, '$1', '$2' }}]}]),
+    _ = [gproc_lib:ensure_monitor(Pid, g) || {_, Pid, _} <- My_local_globs],
+    %% remove all remote globals.
     ets:select_delete(?TAB, [{{{{'_',g,'_'},'_'}, '$1', '_'},
                               [{'=/=', {node,'$1'}, node()}],
                               [true]}]),
@@ -642,7 +686,8 @@ surrendered_1(Globs) ->
         lists:foldl(
           fun({{Key,_}=K, Pid, V}, Acc) when node(Pid) =/= node() ->
                   ets:insert(?TAB, {K, Pid, V}),
-		  ets:insert_new(?TAB, {{Pid,Key}, r}),
+		  _ = gproc_lib:ensure_monitor(Pid, g),
+		  ets:insert_new(?TAB, {{Pid,Key}, []}),
                   Acc;
 	     ({{Pid,_}=K, Opts}, Acc) when node(Pid) =/= node() ->
 		     ets:insert(?TAB, {K, Opts}),
@@ -658,7 +703,7 @@ surrendered_1(Globs) ->
             ok;
         [_|_] = Missing ->
             %% This is very unlikely, I think
-            leader_cast({add_globals, Missing})
+            leader_cast({add_globals, mk_broadcast_insert_vals(Missing)})
     end,
     case [{K,P} || {K,P,_} <- Ldr_local_globs,
 		   is_pid(P) andalso