35
35
-module (pg_local ).
36
36
37
37
-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 ]).
39
40
-export ([start /0 , start_link /0 , init /1 , handle_call /3 , handle_cast /2 ,
40
41
handle_info /2 , terminate /2 ]).
41
42
54
55
55
56
% %----------------------------------------------------------------------------
56
57
57
- % %% As of R13B03 monitors are used instead of links .
58
+ - define ( TABLE , pg_local_table ) .
58
59
59
60
% %%
60
61
% %% Exported functions
@@ -92,19 +93,27 @@ sync() ->
92
93
_ = ensure_started (),
93
94
gen_server :call (? MODULE , sync , infinity ).
94
95
96
+ clear () ->
97
+ _ = ensure_started (),
98
+ gen_server :call (? MODULE , clear , infinity ).
99
+
95
100
% %%
96
101
% %% Callback functions from gen_server
97
102
% %%
98
103
99
104
-record (state , {}).
100
105
101
106
init ([]) ->
102
- pg_local_table = ets :new (pg_local_table , [ordered_set , protected , named_table ]),
107
+ ? TABLE = ets :new (? TABLE , [ordered_set , protected , named_table ]),
103
108
{ok , # state {}}.
104
109
105
110
handle_call (sync , _From , S ) ->
106
111
{reply , ok , S };
107
112
113
+ handle_call (clear , _From , S ) ->
114
+ ets :delete_all_objects (? TABLE ),
115
+ {reply , ok , S };
116
+
108
117
handle_call (Request , From , S ) ->
109
118
error_logger :warning_msg (" The pg_local server received an unexpected message:\n "
110
119
" handle_call(~p , ~p , _)\n " ,
@@ -120,14 +129,14 @@ handle_cast({leave, Name, Pid}, S) ->
120
129
handle_cast (_ , S ) ->
121
130
{noreply , S }.
122
131
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 ),
125
134
{noreply , S };
126
135
handle_info (_ , S ) ->
127
136
{noreply , S }.
128
137
129
138
terminate (_Reason , _S ) ->
130
- true = ets :delete (pg_local_table ),
139
+ true = ets :delete (? TABLE ),
131
140
ok .
132
141
133
142
% %%
@@ -148,46 +157,57 @@ terminate(_Reason, _S) ->
148
157
% %% {{pid, Pid, Name}}
149
158
% %% Pid is a member of group Name.
150
159
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 ) ->
153
174
Names = member_groups (Pid ),
154
175
_ = [leave_group (Name , P ) ||
155
176
Name <- Names ,
156
- P <- member_in_group (Pid , Name )],
157
- ok .
177
+ P <- member_in_group (Pid , Name )].
158
178
159
179
join_group (Name , Pid ) ->
160
180
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 })
162
182
catch _ :_ ->
163
183
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 })
166
186
end ,
167
187
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 })
169
189
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 }})
172
192
end .
173
193
174
194
leave_group (Name , Pid ) ->
175
195
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
177
197
N ->
178
198
if
179
199
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 );
182
202
true ->
183
203
ok
184
204
end ,
185
205
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
187
207
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 ),
191
211
true = erlang :demonitor (Ref , [flush ]),
192
212
ok ;
193
213
_ ->
@@ -199,21 +219,21 @@ leave_group(Name, Pid) ->
199
219
200
220
group_members (Name ) ->
201
221
[P ||
202
- [P , N ] <- ets :match (pg_local_table , {{member , Name , '$1' },'$2' }),
222
+ [P , N ] <- ets :match (? TABLE , {{member , Name , '$1' },'$2' }),
203
223
_ <- lists :seq (1 , N )].
204
224
205
225
member_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 }),
207
227
lists :duplicate (N , Pid ).
208
228
209
229
member_present (Name , Pid ) ->
210
- case ets :lookup (pg_local_table , {member , Name , Pid }) of
230
+ case ets :lookup (? TABLE , {member , Name , Pid }) of
211
231
[_ ] -> true ;
212
232
[] -> false
213
233
end .
214
234
215
235
member_groups (Pid ) ->
216
- [Name || [Name ] <- ets :match (pg_local_table , {{pid , Pid , '$1' }})].
236
+ [Name || [Name ] <- ets :match (? TABLE , {{pid , Pid , '$1' }})].
217
237
218
238
ensure_started () ->
219
239
case whereis (? MODULE ) of
0 commit comments