summaryrefslogtreecommitdiff
path: root/lib/kernel/src/global_search.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kernel/src/global_search.erl')
-rw-r--r--lib/kernel/src/global_search.erl279
1 files changed, 279 insertions, 0 deletions
diff --git a/lib/kernel/src/global_search.erl b/lib/kernel/src/global_search.erl
new file mode 100644
index 0000000000..b723e18a1b
--- /dev/null
+++ b/lib/kernel/src/global_search.erl
@@ -0,0 +1,279 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1998-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights 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.
+%%%====================================================================================
+%%%====================================================================================
+%%%====================================================================================
+
+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.
+%%%====================================================================================
+%%%====================================================================================
+%%%====================================================================================
+
+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.
+%%%====================================================================================
+%%%====================================================================================
+%%%====================================================================================
+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).
+
+
+