1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20-module(global_search).
21
22%% Search for globally registered names in the global groups.
23%% This is a help module to the global_group.erl
24
25
26%% External exports
27-export([start/2]).
28-export([init_send/1]).
29-export([init_whereis/1]).
30-export([init_names/1]).
31
32
33%% ONLY for test purpose
34-export([send_test/1]).
35-export([whereis_test/1]).
36-export([names_test/1]).
37
38
39
40
41%%%====================================================================================
42%%% The search is done in a process separate from the global_group process
43%%%====================================================================================
44start(Flag, Arg) ->
45    case Flag of
46	send ->
47	    spawn_link(?MODULE, init_send, [Arg]);
48	whereis ->
49	    spawn_link(?MODULE, init_whereis, [Arg]);
50	names ->
51	    spawn_link(?MODULE, init_names, [Arg]);
52	%% ONLY for test suites, tests what happens when this process exits.
53	send_test ->
54	    spawn_link(?MODULE, send_test, [Arg]);
55	whereis_test ->
56	    spawn_link(?MODULE, whereis_test, [Arg]);
57	names_test ->
58	    spawn_link(?MODULE, names_test, [Arg])
59    end.
60
61
62%%%====================================================================================
63%%%====================================================================================
64%%%====================================================================================
65%%% Search after a registered global Name anywhere (any), in a specified group or
66%%% in a specified node.
67%%% Return the result to the global_group process in own node and wait for
68%%% this process to be killed.
69%%%====================================================================================
70%%%====================================================================================
71%%%====================================================================================
72
73-spec init_send(_) -> no_return().
74init_send({any, NodesList, Name, Msg, From}) ->
75    case whereis_any_loop(NodesList, Name) of
76	undefined ->
77	    Res = {badarg,{Name, Msg}},
78	    gen_server:cast(global_group, {send_res, Res, Name, Msg, self(), From});
79	Pid ->
80	    gen_server:cast(global_group, {send_res, Pid, Name, Msg, self(), From})
81    end,
82    end_loop();
83init_send({group, Nodes, Name, Msg, From}) ->
84    case whereis_group_loop(Nodes, Name) of
85	group_down ->
86	    Res = {badarg,{Name, Msg}},
87	    gen_server:cast(global_group, {send_res, Res, Name, Msg, self(), From});
88	undefined ->
89	    Res = {badarg,{Name, Msg}},
90	    gen_server:cast(global_group, {send_res, Res, Name, Msg, self(), From});
91	Pid ->
92	    gen_server:cast(global_group, {send_res, Pid, Name, Msg, self(), From})
93    end,
94    end_loop();
95init_send({node, Node, Name, Msg, From}) ->
96    case whereis_check_node(Node, Name) of
97	node_down ->
98	    Res = {badarg,{Name, Msg}},
99	    gen_server:cast(global_group, {send_res, Res, Name, Msg, self(), From});
100	undefined ->
101	    Res = {badarg,{Name, Msg}},
102	    gen_server:cast(global_group, {send_res, Res, Name, Msg, self(), From});
103	Pid ->
104	    gen_server:cast(global_group, {send_res, Pid, Name, Msg, self(), From})
105    end,
106    end_loop().
107
108
109%%%====================================================================================
110%%%====================================================================================
111%%%====================================================================================
112%%% Search after a registered global Name anywhere (any), in a specified group or
113%%% in a specified node.
114%%% Return the result to the global_group process in own node and wait for
115%%% this process to be killed.
116%%%====================================================================================
117%%%====================================================================================
118%%%====================================================================================
119
120-spec init_whereis(_) -> no_return().
121init_whereis({any, NodesList, Name, From}) ->
122    R = whereis_any_loop(NodesList, Name),
123    gen_server:cast(global_group, {find_name_res, R, self(), From}),
124    end_loop();
125init_whereis({group, Nodes, Name, From}) ->
126    case whereis_group_loop(Nodes, Name) of
127	group_down ->
128	    gen_server:cast(global_group, {find_name_res, undefined, self(), From});
129	R ->
130	    gen_server:cast(global_group, {find_name_res, R, self(), From})
131    end,
132    end_loop();
133init_whereis({node, Node, Name, From}) ->
134    case whereis_check_node(Node, Name) of
135	node_down ->
136	    gen_server:cast(global_group, {find_name_res, undefined, self(), From});
137	R ->
138	    gen_server:cast(global_group, {find_name_res, R, self(), From})
139    end,
140    end_loop().
141
142
143%%%====================================================================================
144%%%====================================================================================
145%%%====================================================================================
146%%% Get the registered names, in a specified group or in a specified node.
147%%% Return the result to the global_group process in own node and wait for
148%%% this process to be killed.
149%%%====================================================================================
150%%%====================================================================================
151%%%====================================================================================
152-spec init_names(_) -> no_return().
153init_names({group, Nodes, From}) ->
154    case names_group_loop(Nodes) of
155	group_down ->
156	    gen_server:cast(global_group, {registered_names_res, [], self(), From});
157	R ->
158	    gen_server:cast(global_group, {registered_names_res, R, self(), From})
159    end,
160    end_loop();
161init_names({node, Node, From}) ->
162    case names_check_node(Node) of
163	node_down ->
164	    gen_server:cast(global_group, {registered_names_res, [], self(), From});
165	R ->
166	    gen_server:cast(global_group, {registered_names_res, R, self(), From})
167    end,
168    end_loop().
169
170%%%====================================================================================
171%%% Wait for the kill message.
172%%%====================================================================================
173
174-spec end_loop() -> no_return().
175
176end_loop() ->
177    receive
178	kill ->
179	    exit(normal)
180    end.
181
182%%%====================================================================================
183%%% Search for the globally registered name in the whole known world.
184%%%====================================================================================
185whereis_any_loop([], _Name) ->
186    undefined;
187whereis_any_loop([{_Group_name, Nodes}|T], Name) ->
188    case whereis_group_loop(Nodes, Name) of
189	group_down ->
190	    whereis_any_loop(T, Name);
191	undefined ->
192	    whereis_any_loop(T, Name);
193	R ->
194	    R
195    end.
196
197%%%====================================================================================
198%%% Search for the globally registered name in a specified global group.
199%%%====================================================================================
200whereis_group_loop([], _Name) ->
201    group_down;
202whereis_group_loop([Node|T], Name) ->
203    case whereis_check_node(Node, Name) of
204	node_down ->
205	    whereis_group_loop(T, Name);
206	R ->
207	    R
208    end.
209%%%====================================================================================
210%%% Search for the globally registered name on a specified node.
211%%%====================================================================================
212whereis_check_node(Node, Name) ->
213    case net_adm:ping(Node) of
214	pang ->
215	    node_down;
216	pong ->
217	    monitor_node(Node, true),
218	    gen_server:cast({global_group, Node},{find_name, self(), Name}),
219	    receive
220		{nodedown, Node} ->
221		    node_down;
222		{find_name_res, Result} ->
223		    monitor_node(Node, false),
224		    Result
225	    end
226    end.
227
228
229
230
231%%%====================================================================================
232%%% Search for all globally registered name in a specified global group.
233%%%====================================================================================
234names_group_loop([]) ->
235    group_down;
236names_group_loop([Node|T]) ->
237    case names_check_node(Node) of
238	node_down ->
239	    names_group_loop(T);
240	R ->
241	    R
242    end.
243%%%====================================================================================
244%%% Search for all globally registered name on a specified node.
245%%%====================================================================================
246names_check_node(Node) ->
247    case net_adm:ping(Node) of
248	pang ->
249	    node_down;
250	pong ->
251	    monitor_node(Node, true),
252	    gen_server:cast({global_group, Node},{registered_names, self()}),
253	    receive
254		{nodedown, Node} ->
255		    node_down;
256		{registered_names_res, Result} ->
257		    monitor_node(Node, false),
258		    Result
259	    end
260    end.
261
262
263
264
265
266
267%%%====================================================================================
268%%% Test what happens when this process exits.
269%%%====================================================================================
270send_test(_Args) ->
271    timer:sleep(5000),
272    exit(testing_exit).
273
274whereis_test(_Args) ->
275    timer:sleep(5000),
276    exit(testing_exit).
277
278names_test(_Args) ->
279    timer:sleep(5000),
280    exit(testing_exit).
281
282
283
284