Browse Source

proper restart logic in gproc

Ulf Wiger 14 years ago
parent
commit
94cb9af840
1 changed files with 61 additions and 10 deletions
  1. 61 10
      src/gproc.erl

+ 61 - 10
src/gproc.erl

@@ -118,7 +118,7 @@
 %% @end
 start_link() ->
     create_tabs(),
-    gen_server:start({local, ?SERVER}, ?MODULE, [], []).
+    gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
 
 %% spec(Name::any()) -> true
 %%
@@ -959,23 +959,31 @@ process_is_down(Pid) ->
     ok.
 
 create_tabs() ->
-    ets:new(?MODULE, [ordered_set, public, named_table]).
+    case ets:info(?TAB, name) of
+	undefined ->
+	    ets:new(?TAB, [ordered_set, public, named_table]);
+	_ ->
+	    ok
+    end.
 
 
 %% @hidden
 init([]) ->
+    set_monitors(),
     {ok, #state{}}.
 
 
+set_monitors() ->
+    set_monitors(ets:select(?TAB, [{{{'$1',l}},[],['$1']}], 100)).
+
+
+set_monitors('$end_of_table') ->
+    ok;
+set_monitors({Pids, Cont}) ->
+    [erlang:monitor(process,Pid) || Pid <- Pids],
+    set_monitors(ets:select(Cont)).
 
 
-%% ensure_monitor(Pid) when node(Pid) == node() ->
-%%     case ets:insert_new(?TAB, {Pid}) of
-%%         false -> ok;
-%%         true  -> erlang:monitor(process, Pid)
-%%     end;
-%% ensure_monitor(_) ->
-%%     true.
 
 monitor_me() ->
     case ets:insert_new(?TAB, {{self(),l}}) of
@@ -1271,6 +1279,8 @@ reg_test_() ->
       , ?_test(t_is_clean())
       , {spawn, ?_test(t_simple_mreg())}
       , ?_test(t_is_clean())
+      , {spawn, ?_test(t_gproc_crash())}
+      , ?_test(t_is_clean())
      ]}.
 
 t_simple_reg() ->
@@ -1314,9 +1324,50 @@ t_await() ->
 t_is_clean() ->
     sys:get_status(gproc), % in order to synch
     T = ets:tab2list(gproc),
-    ?debugFmt("T = ~p~n", [T]),
     ?assert(T =:= []).
                                         
 
 t_simple_mreg() ->
     ok.
+
+
+t_gproc_crash() ->
+    P = spawn_helper(),
+    ?assert(gproc:where({n,l,P}) =:= P),
+    exit(whereis(gproc), kill),
+    give_gproc_some_time(100),
+    ?assert(whereis(gproc) =/= undefined),
+    %%
+    %% Check that the registration is still there using an ets:lookup(),
+    %% Once we've killed the process, gproc will always return undefined
+    %% if the process is not alive, regardless of whether the registration
+    %% is still there. So, here, the lookup should find something...
+    %%
+    ?assert(ets:lookup(gproc,{{n,l,P},n}) =/= []),
+    ?assert(gproc:where({n,l,P}) =:= P),
+    exit(P, kill),
+    %% ...and here, it shouldn't.
+    %% (sleep for a while first to let gproc handle the EXIT
+    give_gproc_some_time(10),
+    ?assert(ets:lookup(gproc,{{n,l,P},n}) =:= []).
+
+    
+spawn_helper() ->
+    Parent = self(),
+    P = spawn(fun() ->
+		      ?assert(gproc:reg({n,l,self()}) =:= true),
+		      Ref = erlang:monitor(process, Parent),
+		      Parent ! {ok,self()},
+		      receive 
+			  {'DOWN', Ref, _, _, _} ->
+			      ok
+		      end
+	      end),
+    receive
+	{ok,P} ->
+	     P
+    end.
+
+give_gproc_some_time(T) ->
+    timer:sleep(T),
+    sys:get_status(gproc).