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,55 @@ 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 clean up using the value from the DOWN message
166
+ _ ->
167
+ leave_all_groups (Pid )
168
+ end ,
169
+ ok .
170
+
171
+ leave_all_groups (Pid ) ->
153
172
Names = member_groups (Pid ),
154
173
_ = [leave_group (Name , P ) ||
155
174
Name <- Names ,
156
- P <- member_in_group (Pid , Name )],
157
- ok .
175
+ P <- member_in_group (Pid , Name )].
158
176
159
177
join_group (Name , Pid ) ->
160
178
Ref_Pid = {ref , Pid },
161
- try _ = ets :update_counter (pg_local_table , Ref_Pid , {3 , + 1 })
179
+ try _ = ets :update_counter (? TABLE , Ref_Pid , {3 , + 1 })
162
180
catch _ :_ ->
163
181
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 })
182
+ true = ets :insert (? TABLE , {Ref_Pid , Ref , 1 }),
183
+ true = ets :insert (? TABLE , {{ref , Ref }, Pid })
166
184
end ,
167
185
Member_Name_Pid = {member , Name , Pid },
168
- try _ = ets :update_counter (pg_local_table , Member_Name_Pid , {2 , + 1 })
186
+ try _ = ets :update_counter (? TABLE , Member_Name_Pid , {2 , + 1 })
169
187
catch _ :_ ->
170
- true = ets :insert (pg_local_table , {Member_Name_Pid , 1 }),
171
- true = ets :insert (pg_local_table , {{pid , Pid , Name }})
188
+ true = ets :insert (? TABLE , {Member_Name_Pid , 1 }),
189
+ true = ets :insert (? TABLE , {{pid , Pid , Name }})
172
190
end .
173
191
174
192
leave_group (Name , Pid ) ->
175
193
Member_Name_Pid = {member , Name , Pid },
176
- try ets :update_counter (pg_local_table , Member_Name_Pid , {2 , - 1 }) of
194
+ try ets :update_counter (? TABLE , Member_Name_Pid , {2 , - 1 }) of
177
195
N ->
178
196
if
179
197
N =:= 0 ->
180
- true = ets :delete (pg_local_table , {pid , Pid , Name }),
181
- true = ets :delete (pg_local_table , Member_Name_Pid );
198
+ true = ets :delete (? TABLE , {pid , Pid , Name }),
199
+ true = ets :delete (? TABLE , Member_Name_Pid );
182
200
true ->
183
201
ok
184
202
end ,
185
203
Ref_Pid = {ref , Pid },
186
- case ets :update_counter (pg_local_table , Ref_Pid , {3 , - 1 }) of
204
+ case ets :update_counter (? TABLE , Ref_Pid , {3 , - 1 }) of
187
205
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 ),
206
+ [{Ref_Pid ,Ref ,0 }] = ets :lookup (? TABLE , Ref_Pid ),
207
+ true = ets :delete (? TABLE , {ref , Ref }),
208
+ true = ets :delete (? TABLE , Ref_Pid ),
191
209
true = erlang :demonitor (Ref , [flush ]),
192
210
ok ;
193
211
_ ->
@@ -199,21 +217,21 @@ leave_group(Name, Pid) ->
199
217
200
218
group_members (Name ) ->
201
219
[P ||
202
- [P , N ] <- ets :match (pg_local_table , {{member , Name , '$1' },'$2' }),
220
+ [P , N ] <- ets :match (? TABLE , {{member , Name , '$1' },'$2' }),
203
221
_ <- lists :seq (1 , N )].
204
222
205
223
member_in_group (Pid , Name ) ->
206
- [{{member , Name , Pid }, N }] = ets :lookup (pg_local_table , {member , Name , Pid }),
224
+ [{{member , Name , Pid }, N }] = ets :lookup (? TABLE , {member , Name , Pid }),
207
225
lists :duplicate (N , Pid ).
208
226
209
227
member_present (Name , Pid ) ->
210
- case ets :lookup (pg_local_table , {member , Name , Pid }) of
228
+ case ets :lookup (? TABLE , {member , Name , Pid }) of
211
229
[_ ] -> true ;
212
230
[] -> false
213
231
end .
214
232
215
233
member_groups (Pid ) ->
216
- [Name || [Name ] <- ets :match (pg_local_table , {{pid , Pid , '$1' }})].
234
+ [Name || [Name ] <- ets :match (? TABLE , {{pid , Pid , '$1' }})].
217
235
218
236
ensure_started () ->
219
237
case whereis (? MODULE ) of
0 commit comments