%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
%% %CopyrightEnd%
%%
-module(global_search).
%% Search for globally registered names in the global groups.
%% This is a help module to the global_group.erl
%% External exports
-export([start/2]).
-export([init_send/1]).
-export([init_whereis/1]).
-export([init_names/1]).
%% ONLY for test purpose
-export([send_test/1]).
-export([whereis_test/1]).
-export([names_test/1]).
%%%====================================================================================
%%% The search is done in a process separate from the global_group process
%%%====================================================================================
start(Flag, Arg) ->
case Flag of
send ->
spawn_link(?MODULE, init_send, [Arg]);
whereis ->
spawn_link(?MODULE, init_whereis, [Arg]);
names ->
spawn_link(?MODULE, init_names, [Arg]);
%% ONLY for test suites, tests what happens when this process exits.
send_test ->
spawn_link(?MODULE, send_test, [Arg]);
whereis_test ->
spawn_link(?MODULE, whereis_test, [Arg]);
names_test ->
spawn_link(?MODULE, names_test, [Arg])
end.
%%%====================================================================================
%%%====================================================================================
%%%====================================================================================
%%% Search after a registered global Name anywhere (any), in a specified group or
%%% in a specified node.
%%% Return the result to the global_group process in own node and wait for
%%% this process to be killed.
%%%====================================================================================
%%%====================================================================================
%%%====================================================================================
-spec init_send(_) -> no_return().
init_send({any, NodesList, Name, Msg, From}) ->
case whereis_any_loop(NodesList, Name) of
undefined ->
Res = {badarg,{Name, Msg}},
gen_server:cast(global_group, {send_res, Res, Name, Msg, self(), From});
Pid ->
gen_server:cast(global_group, {send_res, Pid, Name, Msg, self(), From})
end,
end_loop();
init_send({group, Nodes, Name, Msg, From}) ->
case whereis_group_loop(Nodes, Name) of
group_down ->
Res = {badarg,{Name, Msg}},
gen_server:cast(global_group, {send_res, Res, Name, Msg, self(), From});
undefined ->
Res = {badarg,{Name, Msg}},
gen_server:cast(global_group, {send_res, Res, Name, Msg, self(), From});
Pid ->
gen_server:cast(global_group, {send_res, Pid, Name, Msg, self(), From})
end,
end_loop();
init_send({node, Node, Name, Msg, From}) ->
case whereis_check_node(Node, Name) of
node_down ->
Res = {badarg,{Name, Msg}},
gen_server:cast(global_group, {send_res, Res, Name, Msg, self(), From});
undefined ->
Res = {badarg,{Name, Msg}},
gen_server:cast(global_group, {send_res, Res, Name, Msg, self(), From});
Pid ->
gen_server:cast(global_group, {send_res, Pid, Name, Msg, self(), From})
end,
end_loop().
%%%====================================================================================
%%%====================================================================================
%%%====================================================================================
%%% Search after a registered global Name anywhere (any), in a specified group or
%%% in a specified node.
%%% Return the result to the global_group process in own node and wait for
%%% this process to be killed.
%%%====================================================================================
%%%====================================================================================
%%%====================================================================================
-spec init_whereis(_) -> no_return().
init_whereis({any, NodesList, Name, From}) ->
R = whereis_any_loop(NodesList, Name),
gen_server:cast(global_group, {find_name_res, R, self(), From}),
end_loop();
init_whereis({group, Nodes, Name, From}) ->
case whereis_group_loop(Nodes, Name) of
group_down ->
gen_server:cast(global_group, {find_name_res, undefined, self(), From});
R ->
gen_server:cast(global_group, {find_name_res, R, self(), From})
end,
end_loop();
init_whereis({node, Node, Name, From}) ->
case whereis_check_node(Node, Name) of
node_down ->
gen_server:cast(global_group, {find_name_res, undefined, self(), From});
R ->
gen_server:cast(global_group, {find_name_res, R, self(), From})
end,
end_loop().
%%%====================================================================================
%%%====================================================================================
%%%====================================================================================
%%% Get the registered names, in a specified group or in a specified node.
%%% Return the result to the global_group process in own node and wait for
%%% this process to be killed.
%%%====================================================================================
%%%====================================================================================
%%%====================================================================================
-spec init_names(_) -> no_return().
init_names({group, Nodes, From}) ->
case names_group_loop(Nodes) of
group_down ->
gen_server:cast(global_group, {registered_names_res, [], self(), From});
R ->
gen_server:cast(global_group, {registered_names_res, R, self(), From})
end,
end_loop();
init_names({node, Node, From}) ->
case names_check_node(Node) of
node_down ->
gen_server:cast(global_group, {registered_names_res, [], self(), From});
R ->
gen_server:cast(global_group, {registered_names_res, R, self(), From})
end,
end_loop().
%%%====================================================================================
%%% Wait for the kill message.
%%%====================================================================================
-spec end_loop() -> no_return().
end_loop() ->
receive
kill ->
exit(normal)
end.
%%%====================================================================================
%%% Search for the globally registered name in the whole known world.
%%%====================================================================================
whereis_any_loop([], _Name) ->
undefined;
whereis_any_loop([{_Group_name, Nodes}|T], Name) ->
case whereis_group_loop(Nodes, Name) of
group_down ->
whereis_any_loop(T, Name);
undefined ->
whereis_any_loop(T, Name);
R ->
R
end.
%%%====================================================================================
%%% Search for the globally registered name in a specified global group.
%%%====================================================================================
whereis_group_loop([], _Name) ->
group_down;
whereis_group_loop([Node|T], Name) ->
case whereis_check_node(Node, Name) of
node_down ->
whereis_group_loop(T, Name);
R ->
R
end.
%%%====================================================================================
%%% Search for the globally registered name on a specified node.
%%%====================================================================================
whereis_check_node(Node, Name) ->
case net_adm:ping(Node) of
pang ->
node_down;
pong ->
monitor_node(Node, true),
gen_server:cast({global_group, Node},{find_name, self(), Name}),
receive
{nodedown, Node} ->
node_down;
{find_name_res, Result} ->
monitor_node(Node, false),
Result
end
end.
%%%====================================================================================
%%% Search for all globally registered name in a specified global group.
%%%====================================================================================
names_group_loop([]) ->
group_down;
names_group_loop([Node|T]) ->
case names_check_node(Node) of
node_down ->
names_group_loop(T);
R ->
R
end.
%%%====================================================================================
%%% Search for all globally registered name on a specified node.
%%%====================================================================================
names_check_node(Node) ->
case net_adm:ping(Node) of
pang ->
node_down;
pong ->
monitor_node(Node, true),
gen_server:cast({global_group, Node},{registered_names, self()}),
receive
{nodedown, Node} ->
node_down;
{registered_names_res, Result} ->
monitor_node(Node, false),
Result
end
end.
%%%====================================================================================
%%% Test what happens when this process exits.
%%%====================================================================================
send_test(_Args) ->
timer:sleep(5000),
exit(testing_exit).
whereis_test(_Args) ->
timer:sleep(5000),
exit(testing_exit).
names_test(_Args) ->
timer:sleep(5000),
exit(testing_exit).