3535-module (pg_local ).
3636
3737-export ([join /2 , leave /2 , get_members /1 , in_group /2 ]).
38- -export ([sync /0 ]). % % intended for testing only; not part of official API
38+ % % intended for testing only; not part of official API
39+ -export ([sync /0 , clear /0 ]).
3940-export ([start /0 , start_link /0 , init /1 , handle_call /3 , handle_cast /2 ,
4041 handle_info /2 , terminate /2 ]).
4142
5455
5556% %----------------------------------------------------------------------------
5657
57- % %% As of R13B03 monitors are used instead of links .
58+ - define ( TABLE , pg_local_table ) .
5859
5960% %%
6061% %% Exported functions
@@ -92,19 +93,27 @@ sync() ->
9293 _ = ensure_started (),
9394 gen_server :call (? MODULE , sync , infinity ).
9495
96+ clear () ->
97+ _ = ensure_started (),
98+ gen_server :call (? MODULE , clear , infinity ).
99+
95100% %%
96101% %% Callback functions from gen_server
97102% %%
98103
99104-record (state , {}).
100105
101106init ([]) ->
102- pg_local_table = ets :new (pg_local_table , [ordered_set , protected , named_table ]),
107+ ? TABLE = ets :new (? TABLE , [ordered_set , protected , named_table ]),
103108 {ok , # state {}}.
104109
105110handle_call (sync , _From , S ) ->
106111 {reply , ok , S };
107112
113+ handle_call (clear , _From , S ) ->
114+ ets :delete_all_objects (? TABLE ),
115+ {reply , ok , S };
116+
108117handle_call (Request , From , S ) ->
109118 error_logger :warning_msg (" The pg_local server received an unexpected message:\n "
110119 " handle_call(~p , ~p , _)\n " ,
@@ -120,14 +129,14 @@ handle_cast({leave, Name, Pid}, S) ->
120129handle_cast (_ , S ) ->
121130 {noreply , S }.
122131
123- handle_info ({'DOWN' , MonitorRef , process , _Pid , _Info }, S ) ->
124- member_died (MonitorRef ),
132+ handle_info ({'DOWN' , MonitorRef , process , Pid , _Info }, S ) ->
133+ member_died (MonitorRef , Pid ),
125134 {noreply , S };
126135handle_info (_ , S ) ->
127136 {noreply , S }.
128137
129138terminate (_Reason , _S ) ->
130- true = ets :delete (pg_local_table ),
139+ true = ets :delete (? TABLE ),
131140 ok .
132141
133142% %%
@@ -148,46 +157,57 @@ terminate(_Reason, _S) ->
148157% %% {{pid, Pid, Name}}
149158% %% Pid is a member of group Name.
150159
151- member_died (Ref ) ->
152- [{{ref , Ref }, Pid }] = ets :lookup (pg_local_table , {ref , Ref }),
160+ member_died (Ref , Pid ) ->
161+ case ets :lookup (? TABLE , {ref , Ref }) of
162+ [{{ref , Ref }, Pid }] ->
163+ leave_all_groups (Pid );
164+ % % in case the key has already been removed
165+ % % we can perform the lookup using the DOWN message pid
166+ [] ->
167+ leave_all_groups (Pid );
168+ _ ->
169+ leave_all_groups (Pid )
170+ end ,
171+ ok .
172+
173+ leave_all_groups (Pid ) ->
153174 Names = member_groups (Pid ),
154175 _ = [leave_group (Name , P ) ||
155176 Name <- Names ,
156- P <- member_in_group (Pid , Name )],
157- ok .
177+ P <- member_in_group (Pid , Name )].
158178
159179join_group (Name , Pid ) ->
160180 Ref_Pid = {ref , Pid },
161- try _ = ets :update_counter (pg_local_table , Ref_Pid , {3 , + 1 })
181+ try _ = ets :update_counter (? TABLE , Ref_Pid , {3 , + 1 })
162182 catch _ :_ ->
163183 Ref = erlang :monitor (process , Pid ),
164- true = ets :insert (pg_local_table , {Ref_Pid , Ref , 1 }),
165- true = ets :insert (pg_local_table , {{ref , Ref }, Pid })
184+ true = ets :insert (? TABLE , {Ref_Pid , Ref , 1 }),
185+ true = ets :insert (? TABLE , {{ref , Ref }, Pid })
166186 end ,
167187 Member_Name_Pid = {member , Name , Pid },
168- try _ = ets :update_counter (pg_local_table , Member_Name_Pid , {2 , + 1 })
188+ try _ = ets :update_counter (? TABLE , Member_Name_Pid , {2 , + 1 })
169189 catch _ :_ ->
170- true = ets :insert (pg_local_table , {Member_Name_Pid , 1 }),
171- true = ets :insert (pg_local_table , {{pid , Pid , Name }})
190+ true = ets :insert (? TABLE , {Member_Name_Pid , 1 }),
191+ true = ets :insert (? TABLE , {{pid , Pid , Name }})
172192 end .
173193
174194leave_group (Name , Pid ) ->
175195 Member_Name_Pid = {member , Name , Pid },
176- try ets :update_counter (pg_local_table , Member_Name_Pid , {2 , - 1 }) of
196+ try ets :update_counter (? TABLE , Member_Name_Pid , {2 , - 1 }) of
177197 N ->
178198 if
179199 N =:= 0 ->
180- true = ets :delete (pg_local_table , {pid , Pid , Name }),
181- true = ets :delete (pg_local_table , Member_Name_Pid );
200+ true = ets :delete (? TABLE , {pid , Pid , Name }),
201+ true = ets :delete (? TABLE , Member_Name_Pid );
182202 true ->
183203 ok
184204 end ,
185205 Ref_Pid = {ref , Pid },
186- case ets :update_counter (pg_local_table , Ref_Pid , {3 , - 1 }) of
206+ case ets :update_counter (? TABLE , Ref_Pid , {3 , - 1 }) of
187207 0 ->
188- [{Ref_Pid ,Ref ,0 }] = ets :lookup (pg_local_table , Ref_Pid ),
189- true = ets :delete (pg_local_table , {ref , Ref }),
190- true = ets :delete (pg_local_table , Ref_Pid ),
208+ [{Ref_Pid ,Ref ,0 }] = ets :lookup (? TABLE , Ref_Pid ),
209+ true = ets :delete (? TABLE , {ref , Ref }),
210+ true = ets :delete (? TABLE , Ref_Pid ),
191211 true = erlang :demonitor (Ref , [flush ]),
192212 ok ;
193213 _ ->
@@ -199,21 +219,21 @@ leave_group(Name, Pid) ->
199219
200220group_members (Name ) ->
201221 [P ||
202- [P , N ] <- ets :match (pg_local_table , {{member , Name , '$1' },'$2' }),
222+ [P , N ] <- ets :match (? TABLE , {{member , Name , '$1' },'$2' }),
203223 _ <- lists :seq (1 , N )].
204224
205225member_in_group (Pid , Name ) ->
206- [{{member , Name , Pid }, N }] = ets :lookup (pg_local_table , {member , Name , Pid }),
226+ [{{member , Name , Pid }, N }] = ets :lookup (? TABLE , {member , Name , Pid }),
207227 lists :duplicate (N , Pid ).
208228
209229member_present (Name , Pid ) ->
210- case ets :lookup (pg_local_table , {member , Name , Pid }) of
230+ case ets :lookup (? TABLE , {member , Name , Pid }) of
211231 [_ ] -> true ;
212232 [] -> false
213233 end .
214234
215235member_groups (Pid ) ->
216- [Name || [Name ] <- ets :match (pg_local_table , {{pid , Pid , '$1' }})].
236+ [Name || [Name ] <- ets :match (? TABLE , {{pid , Pid , '$1' }})].
217237
218238ensure_started () ->
219239 case whereis (? MODULE ) of
0 commit comments