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_group). 21 22%% Groups nodes into global groups with an own global name space. 23 24-behaviour(gen_server). 25 26%% External exports 27-export([start/0, start_link/0, stop/0, init/1]). 28-export([handle_call/3, handle_cast/2, handle_info/2, 29 terminate/2, code_change/3]). 30 31-export([global_groups/0]). 32-export([monitor_nodes/1]). 33-export([own_nodes/0]). 34-export([registered_names/1]). 35-export([send/2]). 36-export([send/3]). 37-export([whereis_name/1]). 38-export([whereis_name/2]). 39-export([global_groups_changed/1]). 40-export([global_groups_added/1]). 41-export([global_groups_removed/1]). 42-export([sync/0]). 43-export([ng_add_check/2, ng_add_check/3]). 44 45-export([info/0]). 46-export([registered_names_test/1]). 47-export([send_test/2]). 48-export([whereis_name_test/1]). 49-export([get_own_nodes/0, get_own_nodes_with_errors/0]). 50-export([publish_on_nodes/0]). 51 52-export([config_scan/1, config_scan/2]). 53 54%% Internal exports 55-export([sync_init/4]). 56 57 58-define(cc_vsn, 2). 59 60%%%==================================================================================== 61 62-type publish_type() :: 'hidden' | 'normal'. 63-type sync_state() :: 'no_conf' | 'synced'. 64 65-type group_name() :: atom(). 66-type group_tuple() :: {GroupName :: group_name(), [node()]} 67 | {GroupName :: group_name(), 68 PublishType :: publish_type(), 69 [node()]}. 70 71%%%==================================================================================== 72%%% The state of the global_group process 73%%% 74%%% sync_state = no_conf (global_groups not defined, inital state) | 75%%% synced 76%%% group_name = Own global group name 77%%% nodes = Nodes in the own global group 78%%% no_contact = Nodes which we haven't had contact with yet 79%%% sync_error = Nodes which we haven't had contact with yet 80%%% other_grps = list of other global group names and nodes, [{otherName, [Node]}] 81%%% node_name = Own node 82%%% monitor = List of Pids requesting nodeup/nodedown 83%%%==================================================================================== 84 85-record(state, {sync_state = no_conf :: sync_state(), 86 connect_all :: boolean(), 87 group_name = [] :: group_name() | [], 88 nodes = [] :: [node()], 89 no_contact = [] :: [node()], 90 sync_error = [], 91 other_grps = [], 92 node_name = node() :: node(), 93 monitor = [], 94 publish_type = normal :: publish_type(), 95 group_publish_type = normal :: publish_type()}). 96 97 98%%%==================================================================================== 99%%% External exported 100%%%==================================================================================== 101 102-spec global_groups() -> {GroupName, GroupNames} | undefined when 103 GroupName :: group_name(), 104 GroupNames :: [GroupName]. 105global_groups() -> 106 request(global_groups). 107 108-spec monitor_nodes(Flag) -> 'ok' when 109 Flag :: boolean(). 110monitor_nodes(Flag) -> 111 case Flag of 112 true -> request({monitor_nodes, Flag}); 113 false -> request({monitor_nodes, Flag}); 114 _ -> {error, not_boolean} 115 end. 116 117-spec own_nodes() -> Nodes when 118 Nodes :: [Node :: node()]. 119own_nodes() -> 120 request(own_nodes). 121 122-type name() :: atom(). 123-type where() :: {'node', node()} | {'group', group_name()}. 124 125-spec registered_names(Where) -> Names when 126 Where :: where(), 127 Names :: [Name :: name()]. 128registered_names(Arg) -> 129 request({registered_names, Arg}). 130 131-spec send(Name, Msg) -> pid() | {'badarg', {Name, Msg}} when 132 Name :: name(), 133 Msg :: term(). 134send(Name, Msg) -> 135 request({send, Name, Msg}). 136 137-spec send(Where, Name, Msg) -> pid() | {'badarg', {Name, Msg}} when 138 Where :: where(), 139 Name :: name(), 140 Msg :: term(). 141send(Group, Name, Msg) -> 142 request({send, Group, Name, Msg}). 143 144-spec whereis_name(Name) -> pid() | 'undefined' when 145 Name :: name(). 146whereis_name(Name) -> 147 request({whereis_name, Name}). 148 149-spec whereis_name(Where, Name) -> pid() | 'undefined' when 150 Where :: where(), 151 Name :: name(). 152whereis_name(Group, Name) -> 153 request({whereis_name, Group, Name}). 154 155global_groups_changed(NewPara) -> 156 request({global_groups_changed, NewPara}). 157 158global_groups_added(NewPara) -> 159 request({global_groups_added, NewPara}). 160 161global_groups_removed(NewPara) -> 162 request({global_groups_removed, NewPara}). 163 164-spec sync() -> 'ok'. 165sync() -> 166 request(sync). 167 168ng_add_check(Node, OthersNG) -> 169 ng_add_check(Node, normal, OthersNG). 170 171ng_add_check(Node, PubType, OthersNG) -> 172 request({ng_add_check, Node, PubType, OthersNG}). 173 174-type info_item() :: {'state', State :: sync_state()} 175 | {'own_group_name', GroupName :: group_name()} 176 | {'own_group_nodes', Nodes :: [node()]} 177 | {'synched_nodes', Nodes :: [node()]} 178 | {'sync_error', Nodes :: [node()]} 179 | {'no_contact', Nodes :: [node()]} 180 | {'other_groups', Groups :: [group_tuple()]} 181 | {'monitoring', Pids :: [pid()]}. 182 183-spec info() -> [info_item()]. 184info() -> 185 request(info, 3000). 186 187%% ==== ONLY for test suites ==== 188registered_names_test(Arg) -> 189 request({registered_names_test, Arg}). 190send_test(Name, Msg) -> 191 request({send_test, Name, Msg}). 192whereis_name_test(Name) -> 193 request({whereis_name_test, Name}). 194%% ==== ONLY for test suites ==== 195 196 197request(Req) -> 198 request(Req, infinity). 199 200request(Req, Time) -> 201 case whereis(global_group) of 202 P when is_pid(P) -> 203 gen_server:call(global_group, Req, Time); 204 _Other -> 205 {error, global_group_not_runnig} 206 end. 207 208%%%==================================================================================== 209%%% gen_server start 210%%% 211%%% The first thing to happen is to read if the global_groups key is defined in the 212%%% .config file. If not defined, the whole system is started as one global_group, 213%%% and the services of global_group are superfluous. 214%%% Otherwise a sync process is started to check that all nodes in the own global 215%%% group have the same configuration. This is done by sending 'conf_check' to all 216%%% other nodes and requiring 'conf_check_result' back. 217%%% If the nodes are not in agreement of the configuration the global_group process 218%%% will remove these nodes from the #state.nodes list. This can be a normal case 219%%% at release upgrade when all nodes are not yet upgraded. 220%%% 221%%% It is possible to manually force a sync of the global_group. This is done for 222%%% instance after a release upgrade, after all nodes in the group beeing upgraded. 223%%% The nodes are not synced automatically because it would cause the node to be 224%%% disconnected from those not yet beeing upgraded. 225%%% 226%%% The three process dictionary variables (registered_names, send, and whereis_name) 227%%% are used to store information needed if the search process crashes. 228%%% The search process is a help process to find registered names in the system. 229%%%==================================================================================== 230start() -> gen_server:start({local, global_group}, global_group, [], []). 231start_link() -> gen_server:start_link({local, global_group}, global_group,[],[]). 232stop() -> gen_server:call(global_group, stop, infinity). 233 234init([]) -> 235 process_flag(priority, max), 236 ok = net_kernel:monitor_nodes(true), 237 put(registered_names, [undefined]), 238 put(send, [undefined]), 239 put(whereis_name, [undefined]), 240 process_flag(trap_exit, true), 241 Ca = case init:get_argument(connect_all) of 242 {ok, [["false"]]} -> 243 false; 244 _ -> 245 true 246 end, 247 PT = publish_arg(), 248 case application:get_env(kernel, global_groups) of 249 undefined -> 250 update_publish_nodes(PT), 251 {ok, #state{publish_type = PT, 252 connect_all = Ca}}; 253 {ok, []} -> 254 update_publish_nodes(PT), 255 {ok, #state{publish_type = PT, 256 connect_all = Ca}}; 257 {ok, NodeGrps} -> 258 {DefGroupName, PubTpGrp, DefNodes, DefOther} = 259 case catch config_scan(NodeGrps, publish_type) of 260 {error, _Error2} -> 261 update_publish_nodes(PT), 262 exit({error, {'invalid global_groups definition', NodeGrps}}); 263 {DefGroupNameT, PubType, DefNodesT, DefOtherT} -> 264 update_publish_nodes(PT, {PubType, DefNodesT}), 265 %% First disconnect any nodes not belonging to our own group 266 disconnect_nodes(nodes(connected) -- DefNodesT), 267 lists:foreach(fun(Node) -> 268 erlang:monitor_node(Node, true) 269 end, 270 DefNodesT), 271 {DefGroupNameT, PubType, lists:delete(node(), DefNodesT), DefOtherT} 272 end, 273 {ok, #state{publish_type = PT, group_publish_type = PubTpGrp, 274 sync_state = synced, group_name = DefGroupName, 275 no_contact = lists:sort(DefNodes), 276 other_grps = DefOther, connect_all = Ca}} 277 end. 278 279 280%%%==================================================================================== 281%%% sync() -> ok 282%%% 283%%% An operator ordered sync of the own global group. This must be done after 284%%% a release upgrade. It can also be ordered if somthing has made the nodes 285%%% to disagree of the global_groups definition. 286%%%==================================================================================== 287handle_call(sync, _From, S) -> 288% io:format("~p sync ~p~n",[node(), application:get_env(kernel, global_groups)]), 289 case application:get_env(kernel, global_groups) of 290 undefined -> 291 update_publish_nodes(S#state.publish_type), 292 {reply, ok, S}; 293 {ok, []} -> 294 update_publish_nodes(S#state.publish_type), 295 {reply, ok, S}; 296 {ok, NodeGrps} -> 297 {DefGroupName, PubTpGrp, DefNodes, DefOther} = 298 case catch config_scan(NodeGrps, publish_type) of 299 {error, _Error2} -> 300 exit({error, {'invalid global_groups definition', NodeGrps}}); 301 {DefGroupNameT, PubType, DefNodesT, DefOtherT} -> 302 update_publish_nodes(S#state.publish_type, {PubType, DefNodesT}), 303 %% First inform global on all nodes not belonging to our own group 304 disconnect_nodes(nodes(connected) -- DefNodesT), 305 %% Sync with the nodes in the own group 306 kill_global_group_check(), 307 Pid = spawn_link(?MODULE, sync_init, 308 [sync, DefGroupNameT, PubType, DefNodesT]), 309 register(global_group_check, Pid), 310 {DefGroupNameT, PubType, lists:delete(node(), DefNodesT), DefOtherT} 311 end, 312 {reply, ok, S#state{sync_state = synced, group_name = DefGroupName, 313 no_contact = lists:sort(DefNodes), 314 other_grps = DefOther, group_publish_type = PubTpGrp}} 315 end; 316 317 318 319%%%==================================================================================== 320%%% global_groups() -> {OwnGroupName, [OtherGroupName]} | undefined 321%%% 322%%% Get the names of the global groups 323%%%==================================================================================== 324handle_call(global_groups, _From, S) -> 325 Result = case S#state.sync_state of 326 no_conf -> 327 undefined; 328 synced -> 329 Other = lists:foldl(fun({N,_L}, Acc) -> Acc ++ [N] 330 end, 331 [], S#state.other_grps), 332 {S#state.group_name, Other} 333 end, 334 {reply, Result, S}; 335 336 337 338%%%==================================================================================== 339%%% monitor_nodes(bool()) -> ok 340%%% 341%%% Monitor nodes in the own global group. 342%%% True => send nodeup/nodedown to the requesting Pid 343%%% False => stop sending nodeup/nodedown to the requesting Pid 344%%%==================================================================================== 345handle_call({monitor_nodes, Flag}, {Pid, _}, StateIn) -> 346% io:format("***** handle_call ~p~n",[monitor_nodes]), 347 {Res, State} = monitor_nodes(Flag, Pid, StateIn), 348 {reply, Res, State}; 349 350 351%%%==================================================================================== 352%%% own_nodes() -> [Node] 353%%% 354%%% Get a list of nodes in the own global group 355%%%==================================================================================== 356handle_call(own_nodes, _From, S) -> 357 Nodes = case S#state.sync_state of 358 no_conf -> 359 [node() | nodes()]; 360 synced -> 361 get_own_nodes() 362% S#state.nodes 363 end, 364 {reply, Nodes, S}; 365 366 367 368%%%==================================================================================== 369%%% registered_names({node, Node}) -> [Name] | {error, ErrorMessage} 370%%% registered_names({group, GlobalGroupName}) -> [Name] | {error, ErrorMessage} 371%%% 372%%% Get the registered names from a specified Node, or GlobalGroupName. 373%%%==================================================================================== 374handle_call({registered_names, {group, Group}}, _From, S) when Group =:= S#state.group_name -> 375 Res = global:registered_names(), 376 {reply, Res, S}; 377handle_call({registered_names, {group, Group}}, From, S) -> 378 case lists:keysearch(Group, 1, S#state.other_grps) of 379 false -> 380 {reply, [], S}; 381 {value, {Group, []}} -> 382 {reply, [], S}; 383 {value, {Group, Nodes}} -> 384 Pid = global_search:start(names, {group, Nodes, From}), 385 Wait = get(registered_names), 386 put(registered_names, [{Pid, From} | Wait]), 387 {noreply, S} 388 end; 389handle_call({registered_names, {node, Node}}, _From, S) when Node =:= node() -> 390 Res = global:registered_names(), 391 {reply, Res, S}; 392handle_call({registered_names, {node, Node}}, From, S) -> 393 Pid = global_search:start(names, {node, Node, From}), 394% io:format(">>>>> registered_names Pid ~p~n",[Pid]), 395 Wait = get(registered_names), 396 put(registered_names, [{Pid, From} | Wait]), 397 {noreply, S}; 398 399 400 401%%%==================================================================================== 402%%% send(Name, Msg) -> Pid | {badarg, {Name, Msg}} 403%%% send({node, Node}, Name, Msg) -> Pid | {badarg, {Name, Msg}} 404%%% send({group, GlobalGroupName}, Name, Msg) -> Pid | {badarg, {Name, Msg}} 405%%% 406%%% Send the Msg to the specified globally registered Name in own global group, 407%%% in specified Node, or GlobalGroupName. 408%%% But first the receiver is to be found, the thread is continued at 409%%% handle_cast(send_res) 410%%%==================================================================================== 411%% Search in the whole known world, but check own node first. 412handle_call({send, Name, Msg}, From, S) -> 413 case global:whereis_name(Name) of 414 undefined -> 415 Pid = global_search:start(send, {any, S#state.other_grps, Name, Msg, From}), 416 Wait = get(send), 417 put(send, [{Pid, From, Name, Msg} | Wait]), 418 {noreply, S}; 419 Found -> 420 Found ! Msg, 421 {reply, Found, S} 422 end; 423%% Search in the specified global group, which happens to be the own group. 424handle_call({send, {group, Grp}, Name, Msg}, _From, S) when Grp =:= S#state.group_name -> 425 case global:whereis_name(Name) of 426 undefined -> 427 {reply, {badarg, {Name, Msg}}, S}; 428 Pid -> 429 Pid ! Msg, 430 {reply, Pid, S} 431 end; 432%% Search in the specified global group. 433handle_call({send, {group, Group}, Name, Msg}, From, S) -> 434 case lists:keysearch(Group, 1, S#state.other_grps) of 435 false -> 436 {reply, {badarg, {Name, Msg}}, S}; 437 {value, {Group, []}} -> 438 {reply, {badarg, {Name, Msg}}, S}; 439 {value, {Group, Nodes}} -> 440 Pid = global_search:start(send, {group, Nodes, Name, Msg, From}), 441 Wait = get(send), 442 put(send, [{Pid, From, Name, Msg} | Wait]), 443 {noreply, S} 444 end; 445%% Search on the specified node. 446handle_call({send, {node, Node}, Name, Msg}, From, S) -> 447 Pid = global_search:start(send, {node, Node, Name, Msg, From}), 448 Wait = get(send), 449 put(send, [{Pid, From, Name, Msg} | Wait]), 450 {noreply, S}; 451 452 453 454%%%==================================================================================== 455%%% whereis_name(Name) -> Pid | undefined 456%%% whereis_name({node, Node}, Name) -> Pid | undefined 457%%% whereis_name({group, GlobalGroupName}, Name) -> Pid | undefined 458%%% 459%%% Get the Pid of a globally registered Name in own global group, 460%%% in specified Node, or GlobalGroupName. 461%%% But first the process is to be found, 462%%% the thread is continued at handle_cast(find_name_res) 463%%%==================================================================================== 464%% Search in the whole known world, but check own node first. 465handle_call({whereis_name, Name}, From, S) -> 466 case global:whereis_name(Name) of 467 undefined -> 468 Pid = global_search:start(whereis, {any, S#state.other_grps, Name, From}), 469 Wait = get(whereis_name), 470 put(whereis_name, [{Pid, From} | Wait]), 471 {noreply, S}; 472 Found -> 473 {reply, Found, S} 474 end; 475%% Search in the specified global group, which happens to be the own group. 476handle_call({whereis_name, {group, Group}, Name}, _From, S) 477 when Group =:= S#state.group_name -> 478 Res = global:whereis_name(Name), 479 {reply, Res, S}; 480%% Search in the specified global group. 481handle_call({whereis_name, {group, Group}, Name}, From, S) -> 482 case lists:keysearch(Group, 1, S#state.other_grps) of 483 false -> 484 {reply, undefined, S}; 485 {value, {Group, []}} -> 486 {reply, undefined, S}; 487 {value, {Group, Nodes}} -> 488 Pid = global_search:start(whereis, {group, Nodes, Name, From}), 489 Wait = get(whereis_name), 490 put(whereis_name, [{Pid, From} | Wait]), 491 {noreply, S} 492 end; 493%% Search on the specified node. 494handle_call({whereis_name, {node, Node}, Name}, From, S) -> 495 Pid = global_search:start(whereis, {node, Node, Name, From}), 496 Wait = get(whereis_name), 497 put(whereis_name, [{Pid, From} | Wait]), 498 {noreply, S}; 499 500 501%%%==================================================================================== 502%%% global_groups parameter changed 503%%% The node is not resynced automatically because it would cause this node to 504%%% be disconnected from those nodes not yet been upgraded. 505%%%==================================================================================== 506handle_call({global_groups_changed, NewPara}, _From, S) -> 507 {NewGroupName, PubTpGrp, NewNodes, NewOther} = 508 case catch config_scan(NewPara, publish_type) of 509 {error, _Error2} -> 510 exit({error, {'invalid global_groups definition', NewPara}}); 511 {DefGroupName, PubType, DefNodes, DefOther} -> 512 update_publish_nodes(S#state.publish_type, {PubType, DefNodes}), 513 {DefGroupName, PubType, DefNodes, DefOther} 514 end, 515 516 %% #state.nodes is the common denominator of previous and new definition 517 NN = NewNodes -- (NewNodes -- S#state.nodes), 518 %% rest of the nodes in the new definition are marked as not yet contacted 519 NNC = (NewNodes -- S#state.nodes) -- S#state.sync_error, 520 %% remove sync_error nodes not belonging to the new group 521 NSE = NewNodes -- (NewNodes -- S#state.sync_error), 522 523 %% Disconnect the connection to nodes which are not in our old global group. 524 %% This is done because if we already are aware of new nodes (to our global 525 %% group) global is not going to be synced to these nodes. We disconnect instead 526 %% of connect because upgrades can be done node by node and we cannot really 527 %% know what nodes these new nodes are synced to. The operator can always 528 %% manually force a sync of the nodes after all nodes beeing uppgraded. 529 %% We must disconnect also if some nodes to which we have a connection 530 %% will not be in any global group at all. 531 force_nodedown(nodes(connected) -- NewNodes), 532 533 NewS = S#state{group_name = NewGroupName, 534 nodes = lists:sort(NN), 535 no_contact = lists:sort(lists:delete(node(), NNC)), 536 sync_error = lists:sort(NSE), 537 other_grps = NewOther, 538 group_publish_type = PubTpGrp}, 539 {reply, ok, NewS}; 540 541 542%%%==================================================================================== 543%%% global_groups parameter added 544%%% The node is not resynced automatically because it would cause this node to 545%%% be disconnected from those nodes not yet been upgraded. 546%%%==================================================================================== 547handle_call({global_groups_added, NewPara}, _From, S) -> 548% io:format("### global_groups_changed, NewPara ~p ~n",[NewPara]), 549 {NewGroupName, PubTpGrp, NewNodes, NewOther} = 550 case catch config_scan(NewPara, publish_type) of 551 {error, _Error2} -> 552 exit({error, {'invalid global_groups definition', NewPara}}); 553 {DefGroupName, PubType, DefNodes, DefOther} -> 554 update_publish_nodes(S#state.publish_type, {PubType, DefNodes}), 555 {DefGroupName, PubType, DefNodes, DefOther} 556 end, 557 558 %% disconnect from those nodes which are not going to be in our global group 559 force_nodedown(nodes(connected) -- NewNodes), 560 561 %% Check which nodes are already updated 562 OwnNG = get_own_nodes(), 563 NGACArgs = case S#state.group_publish_type of 564 normal -> 565 [node(), OwnNG]; 566 _ -> 567 [node(), S#state.group_publish_type, OwnNG] 568 end, 569 {NN, NNC, NSE} = 570 lists:foldl(fun(Node, {NN_acc, NNC_acc, NSE_acc}) -> 571 case rpc:call(Node, global_group, ng_add_check, NGACArgs) of 572 {badrpc, _} -> 573 {NN_acc, [Node | NNC_acc], NSE_acc}; 574 agreed -> 575 {[Node | NN_acc], NNC_acc, NSE_acc}; 576 not_agreed -> 577 {NN_acc, NNC_acc, [Node | NSE_acc]} 578 end 579 end, 580 {[], [], []}, lists:delete(node(), NewNodes)), 581 NewS = S#state{sync_state = synced, group_name = NewGroupName, nodes = lists:sort(NN), 582 sync_error = lists:sort(NSE), no_contact = lists:sort(NNC), 583 other_grps = NewOther, group_publish_type = PubTpGrp}, 584 {reply, ok, NewS}; 585 586 587%%%==================================================================================== 588%%% global_groups parameter removed 589%%%==================================================================================== 590handle_call({global_groups_removed, _NewPara}, _From, S) -> 591% io:format("### global_groups_removed, NewPara ~p ~n",[_NewPara]), 592 update_publish_nodes(S#state.publish_type), 593 NewS = S#state{sync_state = no_conf, group_name = [], nodes = [], 594 sync_error = [], no_contact = [], 595 other_grps = []}, 596 {reply, ok, NewS}; 597 598 599%%%==================================================================================== 600%%% global_groups parameter added to some other node which thinks that we 601%%% belong to the same global group. 602%%% It could happen that our node is not yet updated with the new node_group parameter 603%%%==================================================================================== 604handle_call({ng_add_check, Node, PubType, OthersNG}, _From, S) -> 605 %% Check which nodes are already updated 606 OwnNG = get_own_nodes(), 607 case S#state.group_publish_type =:= PubType of 608 true -> 609 case OwnNG of 610 OthersNG -> 611 NN = [Node | S#state.nodes], 612 NSE = lists:delete(Node, S#state.sync_error), 613 NNC = lists:delete(Node, S#state.no_contact), 614 NewS = S#state{nodes = lists:sort(NN), 615 sync_error = NSE, 616 no_contact = NNC}, 617 {reply, agreed, NewS}; 618 _ -> 619 {reply, not_agreed, S} 620 end; 621 _ -> 622 {reply, not_agreed, S} 623 end; 624 625 626 627%%%==================================================================================== 628%%% Misceleaneous help function to read some variables 629%%%==================================================================================== 630handle_call(info, _From, S) -> 631 Reply = [{state, S#state.sync_state}, 632 {own_group_name, S#state.group_name}, 633 {own_group_nodes, get_own_nodes()}, 634% {"nodes()", lists:sort(nodes())}, 635 {synced_nodes, S#state.nodes}, 636 {sync_error, S#state.sync_error}, 637 {no_contact, S#state.no_contact}, 638 {other_groups, S#state.other_grps}, 639 {monitoring, S#state.monitor}], 640 641 {reply, Reply, S}; 642 643handle_call(get, _From, S) -> 644 {reply, get(), S}; 645 646 647%%%==================================================================================== 648%%% Only for test suites. These tests when the search process exits. 649%%%==================================================================================== 650handle_call({registered_names_test, {node, 'test3844zty'}}, From, S) -> 651 Pid = global_search:start(names_test, {node, 'test3844zty'}), 652 Wait = get(registered_names), 653 put(registered_names, [{Pid, From} | Wait]), 654 {noreply, S}; 655handle_call({registered_names_test, {node, _Node}}, _From, S) -> 656 {reply, {error, illegal_function_call}, S}; 657handle_call({send_test, Name, 'test3844zty'}, From, S) -> 658 Pid = global_search:start(send_test, 'test3844zty'), 659 Wait = get(send), 660 put(send, [{Pid, From, Name, 'test3844zty'} | Wait]), 661 {noreply, S}; 662handle_call({send_test, _Name, _Msg }, _From, S) -> 663 {reply, {error, illegal_function_call}, S}; 664handle_call({whereis_name_test, 'test3844zty'}, From, S) -> 665 Pid = global_search:start(whereis_test, 'test3844zty'), 666 Wait = get(whereis_name), 667 put(whereis_name, [{Pid, From} | Wait]), 668 {noreply, S}; 669handle_call({whereis_name_test, _Name}, _From, S) -> 670 {reply, {error, illegal_function_call}, S}; 671 672handle_call(Call, _From, S) -> 673% io:format("***** handle_call ~p~n",[Call]), 674 {reply, {illegal_message, Call}, S}. 675 676 677 678 679 680%%%==================================================================================== 681%%% registered_names({node, Node}) -> [Name] | {error, ErrorMessage} 682%%% registered_names({group, GlobalGroupName}) -> [Name] | {error, ErrorMessage} 683%%% 684%%% Get a list of nodes in the own global group 685%%%==================================================================================== 686handle_cast({registered_names, User}, S) -> 687% io:format(">>>>> registered_names User ~p~n",[User]), 688 Res = global:registered_names(), 689 User ! {registered_names_res, Res}, 690 {noreply, S}; 691 692handle_cast({registered_names_res, Result, Pid, From}, S) -> 693% io:format(">>>>> registered_names_res Result ~p~n",[Result]), 694 unlink(Pid), 695 Pid ! kill, 696 Wait = get(registered_names), 697 NewWait = lists:delete({Pid, From},Wait), 698 put(registered_names, NewWait), 699 gen_server:reply(From, Result), 700 {noreply, S}; 701 702 703 704%%%==================================================================================== 705%%% send(Name, Msg) -> Pid | {error, ErrorMessage} 706%%% send({node, Node}, Name, Msg) -> Pid | {error, ErrorMessage} 707%%% send({group, GlobalGroupName}, Name, Msg) -> Pid | {error, ErrorMessage} 708%%% 709%%% The registered Name is found; send the message to it, kill the search process, 710%%% and return to the requesting process. 711%%%==================================================================================== 712handle_cast({send_res, Result, Name, Msg, Pid, From}, S) -> 713% io:format("~p>>>>> send_res Result ~p~n",[node(), Result]), 714 case Result of 715 {badarg,{Name, Msg}} -> 716 continue; 717 ToPid -> 718 ToPid ! Msg 719 end, 720 unlink(Pid), 721 Pid ! kill, 722 Wait = get(send), 723 NewWait = lists:delete({Pid, From, Name, Msg},Wait), 724 put(send, NewWait), 725 gen_server:reply(From, Result), 726 {noreply, S}; 727 728 729 730%%%==================================================================================== 731%%% A request from a search process to check if this Name is registered at this node. 732%%%==================================================================================== 733handle_cast({find_name, User, Name}, S) -> 734 Res = global:whereis_name(Name), 735% io:format(">>>>> find_name Name ~p Res ~p~n",[Name, Res]), 736 User ! {find_name_res, Res}, 737 {noreply, S}; 738 739%%%==================================================================================== 740%%% whereis_name(Name) -> Pid | undefined 741%%% whereis_name({node, Node}, Name) -> Pid | undefined 742%%% whereis_name({group, GlobalGroupName}, Name) -> Pid | undefined 743%%% 744%%% The registered Name is found; kill the search process 745%%% and return to the requesting process. 746%%%==================================================================================== 747handle_cast({find_name_res, Result, Pid, From}, S) -> 748% io:format(">>>>> find_name_res Result ~p~n",[Result]), 749% io:format(">>>>> find_name_res get() ~p~n",[get()]), 750 unlink(Pid), 751 Pid ! kill, 752 Wait = get(whereis_name), 753 NewWait = lists:delete({Pid, From},Wait), 754 put(whereis_name, NewWait), 755 gen_server:reply(From, Result), 756 {noreply, S}; 757 758 759%%%==================================================================================== 760%%% The node is synced successfully 761%%%==================================================================================== 762handle_cast({synced, NoContact}, S) -> 763% io:format("~p>>>>> synced ~p ~n",[node(), NoContact]), 764 kill_global_group_check(), 765 Nodes = get_own_nodes() -- [node() | NoContact], 766 {noreply, S#state{nodes = lists:sort(Nodes), 767 sync_error = [], 768 no_contact = NoContact}}; 769 770 771%%%==================================================================================== 772%%% The node could not sync with some other nodes. 773%%%==================================================================================== 774handle_cast({sync_error, NoContact, ErrorNodes}, S) -> 775% io:format("~p>>>>> sync_error ~p ~p ~n",[node(), NoContact, ErrorNodes]), 776 Txt = io_lib:format("Global group: Could not synchronize with these nodes ~p~n" 777 "because global_groups were not in agreement. ~n", [ErrorNodes]), 778 error_logger:error_report(Txt), 779 kill_global_group_check(), 780 Nodes = (get_own_nodes() -- [node() | NoContact]) -- ErrorNodes, 781 {noreply, S#state{nodes = lists:sort(Nodes), 782 sync_error = ErrorNodes, 783 no_contact = NoContact}}; 784 785 786%%%==================================================================================== 787%%% Another node is checking this node's group configuration 788%%%==================================================================================== 789handle_cast({conf_check, Vsn, Node, From, sync, CCName, CCNodes}, S) -> 790 handle_cast({conf_check, Vsn, Node, From, sync, CCName, normal, CCNodes}, S); 791 792handle_cast({conf_check, Vsn, Node, From, sync, CCName, PubType, CCNodes}, S) -> 793 CurNodes = S#state.nodes, 794% io:format(">>>>> conf_check,sync Node ~p~n",[Node]), 795 %% Another node is syncing, 796 %% done for instance after upgrade of global_groups parameter 797 NS = 798 case application:get_env(kernel, global_groups) of 799 undefined -> 800 %% We didn't have any node_group definition 801 update_publish_nodes(S#state.publish_type), 802 disconnect_nodes([Node]), 803 {global_group_check, Node} ! {config_error, Vsn, From, node()}, 804 S; 805 {ok, []} -> 806 %% Our node_group definition was empty 807 update_publish_nodes(S#state.publish_type), 808 disconnect_nodes([Node]), 809 {global_group_check, Node} ! {config_error, Vsn, From, node()}, 810 S; 811 %%--------------------------------- 812 %% global_groups defined 813 %%--------------------------------- 814 {ok, NodeGrps} -> 815 case catch config_scan(NodeGrps, publish_type) of 816 {error, _Error2} -> 817 %% Our node_group definition was erroneous 818 disconnect_nodes([Node]), 819 {global_group_check, Node} ! {config_error, Vsn, From, node()}, 820 S#state{nodes = lists:delete(Node, CurNodes)}; 821 822 {CCName, PubType, CCNodes, _OtherDef} -> 823 %% OK, add the node to the #state.nodes if it isn't there 824 update_publish_nodes(S#state.publish_type, {PubType, CCNodes}), 825 global_name_server ! {nodeup, Node}, 826 {global_group_check, Node} ! {config_ok, Vsn, From, node()}, 827 case lists:member(Node, CurNodes) of 828 false -> 829 NewNodes = lists:sort([Node | CurNodes]), 830 NSE = lists:delete(Node, S#state.sync_error), 831 NNC = lists:delete(Node, S#state.no_contact), 832 S#state{nodes = NewNodes, 833 sync_error = NSE, 834 no_contact = NNC}; 835 true -> 836 S 837 end; 838 _ -> 839 %% node_group definitions were not in agreement 840 disconnect_nodes([Node]), 841 {global_group_check, Node} ! {config_error, Vsn, From, node()}, 842 NN = lists:delete(Node, S#state.nodes), 843 NSE = lists:delete(Node, S#state.sync_error), 844 NNC = lists:delete(Node, S#state.no_contact), 845 S#state{nodes = NN, 846 sync_error = NSE, 847 no_contact = NNC} 848 end 849 end, 850 {noreply, NS}; 851 852 853handle_cast(_Cast, S) -> 854% io:format("***** handle_cast ~p~n",[_Cast]), 855 {noreply, S}. 856 857 858 859%%%==================================================================================== 860%%% A node went down. If no global group configuration inform global; 861%%% if global group configuration inform global only if the node is one in 862%%% the own global group. 863%%%==================================================================================== 864handle_info({nodeup, Node}, S) when S#state.sync_state =:= no_conf -> 865% io:format("~p>>>>> nodeup, Node ~p ~n",[node(), Node]), 866 send_monitor(S#state.monitor, {nodeup, Node}, S#state.sync_state), 867 global_name_server ! {nodeup, Node}, 868 {noreply, S}; 869handle_info({nodeup, Node}, S) -> 870% io:format("~p>>>>> nodeup, Node ~p ~n",[node(), Node]), 871 OthersNG = case S#state.sync_state of 872 synced -> 873 X = (catch rpc:call(Node, global_group, get_own_nodes, [])), 874 case X of 875 X when is_list(X) -> 876 lists:sort(X); 877 _ -> 878 [] 879 end; 880 no_conf -> 881 [] 882 end, 883 884 NNC = lists:delete(Node, S#state.no_contact), 885 NSE = lists:delete(Node, S#state.sync_error), 886 OwnNG = get_own_nodes(), 887 case OwnNG of 888 OthersNG -> 889 send_monitor(S#state.monitor, {nodeup, Node}, S#state.sync_state), 890 global_name_server ! {nodeup, Node}, 891 case lists:member(Node, S#state.nodes) of 892 false -> 893 NN = lists:sort([Node | S#state.nodes]), 894 {noreply, S#state{nodes = NN, 895 no_contact = NNC, 896 sync_error = NSE}}; 897 true -> 898 {noreply, S#state{no_contact = NNC, 899 sync_error = NSE}} 900 end; 901 _ -> 902 case {lists:member(Node, get_own_nodes()), 903 lists:member(Node, S#state.sync_error)} of 904 {true, false} -> 905 NSE2 = lists:sort([Node | S#state.sync_error]), 906 {noreply, S#state{no_contact = NNC, 907 sync_error = NSE2}}; 908 _ -> 909 {noreply, S} 910 end 911 end; 912 913%%%==================================================================================== 914%%% A node has crashed. 915%%% nodedown must always be sent to global; this is a security measurement 916%%% because during release upgrade the global_groups parameter is upgraded 917%%% before the node is synced. This means that nodedown may arrive from a 918%%% node which we are not aware of. 919%%%==================================================================================== 920handle_info({nodedown, Node}, S) when S#state.sync_state =:= no_conf -> 921% io:format("~p>>>>> nodedown, no_conf Node ~p~n",[node(), Node]), 922 send_monitor(S#state.monitor, {nodedown, Node}, S#state.sync_state), 923 global_name_server ! {nodedown, Node}, 924 {noreply, S}; 925handle_info({nodedown, Node}, S) -> 926% io:format("~p>>>>> nodedown, Node ~p ~n",[node(), Node]), 927 send_monitor(S#state.monitor, {nodedown, Node}, S#state.sync_state), 928 global_name_server ! {nodedown, Node}, 929 NN = lists:delete(Node, S#state.nodes), 930 NSE = lists:delete(Node, S#state.sync_error), 931 NNC = case {lists:member(Node, get_own_nodes()), 932 lists:member(Node, S#state.no_contact)} of 933 {true, false} -> 934 [Node | S#state.no_contact]; 935 _ -> 936 S#state.no_contact 937 end, 938 {noreply, S#state{nodes = NN, no_contact = NNC, sync_error = NSE}}; 939 940 941%%%==================================================================================== 942%%% A node has changed its global_groups definition, and is telling us that we are not 943%%% included in his group any more. This could happen at release upgrade. 944%%%==================================================================================== 945handle_info({disconnect_node, Node}, S) -> 946% io:format("~p>>>>> disconnect_node Node ~p CN ~p~n",[node(), Node, S#state.nodes]), 947 case {S#state.sync_state, lists:member(Node, S#state.nodes)} of 948 {synced, true} -> 949 send_monitor(S#state.monitor, {nodedown, Node}, S#state.sync_state); 950 _ -> 951 cont 952 end, 953 global_name_server ! {nodedown, Node}, %% nodedown is used to inform global of the 954 %% disconnected node 955 NN = lists:delete(Node, S#state.nodes), 956 NNC = lists:delete(Node, S#state.no_contact), 957 NSE = lists:delete(Node, S#state.sync_error), 958 {noreply, S#state{nodes = NN, no_contact = NNC, sync_error = NSE}}; 959 960 961 962 963handle_info({'EXIT', ExitPid, Reason}, S) -> 964 check_exit(ExitPid, Reason), 965 {noreply, S}; 966 967 968handle_info(_Info, S) -> 969% io:format("***** handle_info = ~p~n",[_Info]), 970 {noreply, S}. 971 972 973 974terminate(_Reason, _S) -> 975 ok. 976 977 978code_change(_OldVsn, State, _Extra) -> 979 {ok, State}. 980 981 982 983 984 985%%%==================================================================================== 986%%% Check the global group configuration. 987%%%==================================================================================== 988 989config_scan(NodeGrps) -> 990 config_scan(NodeGrps, original). 991 992config_scan(NodeGrps, original) -> 993 case config_scan(NodeGrps, publish_type) of 994 {DefGroupName, _, DefNodes, DefOther} -> 995 {DefGroupName, DefNodes, DefOther}; 996 Error -> 997 Error 998 end; 999config_scan(NodeGrps, publish_type) -> 1000 config_scan(node(), normal, NodeGrps, no_name, [], []). 1001 1002config_scan(_MyNode, PubType, [], Own_name, OwnNodes, OtherNodeGrps) -> 1003 {Own_name, PubType, lists:sort(OwnNodes), lists:reverse(OtherNodeGrps)}; 1004config_scan(MyNode, PubType, [GrpTuple|NodeGrps], Own_name, OwnNodes, OtherNodeGrps) -> 1005 {Name, PubTypeGroup, Nodes} = grp_tuple(GrpTuple), 1006 case lists:member(MyNode, Nodes) of 1007 true -> 1008 case Own_name of 1009 no_name -> 1010 config_scan(MyNode, PubTypeGroup, NodeGrps, Name, Nodes, OtherNodeGrps); 1011 _ -> 1012 {error, {'node defined twice', {Own_name, Name}}} 1013 end; 1014 false -> 1015 config_scan(MyNode,PubType,NodeGrps,Own_name,OwnNodes, 1016 [{Name, Nodes}|OtherNodeGrps]) 1017 end. 1018 1019grp_tuple({Name, Nodes}) -> 1020 {Name, normal, Nodes}; 1021grp_tuple({Name, hidden, Nodes}) -> 1022 {Name, hidden, Nodes}; 1023grp_tuple({Name, normal, Nodes}) -> 1024 {Name, normal, Nodes}. 1025 1026 1027%%%==================================================================================== 1028%%% The special process which checks that all nodes in the own global group 1029%%% agrees on the configuration. 1030%%%==================================================================================== 1031-spec sync_init(_, _, _, _) -> no_return(). 1032sync_init(Type, Cname, PubType, Nodes) -> 1033 {Up, Down} = sync_check_node(lists:delete(node(), Nodes), [], []), 1034 sync_check_init(Type, Up, Cname, Nodes, Down, PubType). 1035 1036sync_check_node([], Up, Down) -> 1037 {Up, Down}; 1038sync_check_node([Node|Nodes], Up, Down) -> 1039 case net_adm:ping(Node) of 1040 pang -> 1041 sync_check_node(Nodes, Up, [Node|Down]); 1042 pong -> 1043 sync_check_node(Nodes, [Node|Up], Down) 1044 end. 1045 1046 1047 1048%%%------------------------------------------------------------- 1049%%% Check that all nodes are in agreement of the global 1050%%% group configuration. 1051%%%------------------------------------------------------------- 1052-spec sync_check_init(_, _, _, _, _, _) -> no_return(). 1053sync_check_init(Type, Up, Cname, Nodes, Down, PubType) -> 1054 sync_check_init(Type, Up, Cname, Nodes, 3, [], Down, PubType). 1055 1056-spec sync_check_init(_, _, _, _, _, _, _, _) -> no_return(). 1057sync_check_init(_Type, NoContact, _Cname, _Nodes, 0, ErrorNodes, Down, _PubType) -> 1058 case ErrorNodes of 1059 [] -> 1060 gen_server:cast(global_group, {synced, lists:sort(NoContact ++ Down)}); 1061 _ -> 1062 gen_server:cast(global_group, {sync_error, lists:sort(NoContact ++ Down), 1063 ErrorNodes}) 1064 end, 1065 receive 1066 kill -> 1067 exit(normal) 1068 after 5000 -> 1069 exit(normal) 1070 end; 1071 1072sync_check_init(Type, Up, Cname, Nodes, N, ErrorNodes, Down, PubType) -> 1073 ConfCheckMsg = case PubType of 1074 normal -> 1075 {conf_check, ?cc_vsn, node(), self(), Type, Cname, Nodes}; 1076 _ -> 1077 {conf_check, ?cc_vsn, node(), self(), Type, Cname, PubType, Nodes} 1078 end, 1079 lists:foreach(fun(Node) -> 1080 gen_server:cast({global_group, Node}, ConfCheckMsg) 1081 end, Up), 1082 case sync_check(Up) of 1083 {ok, synced} -> 1084 sync_check_init(Type, [], Cname, Nodes, 0, ErrorNodes, Down, PubType); 1085 {error, NewErrorNodes} -> 1086 sync_check_init(Type, [], Cname, Nodes, 0, ErrorNodes ++ NewErrorNodes, Down, PubType); 1087 {more, Rem, NewErrorNodes} -> 1088 %% Try again to reach the global_group, 1089 %% obviously the node is up but not the global_group process. 1090 sync_check_init(Type, Rem, Cname, Nodes, N-1, ErrorNodes ++ NewErrorNodes, Down, PubType) 1091 end. 1092 1093sync_check(Up) -> 1094 sync_check(Up, Up, []). 1095 1096sync_check([], _Up, []) -> 1097 {ok, synced}; 1098sync_check([], _Up, ErrorNodes) -> 1099 {error, ErrorNodes}; 1100sync_check(Rem, Up, ErrorNodes) -> 1101 receive 1102 {config_ok, ?cc_vsn, Pid, Node} when Pid =:= self() -> 1103 global_name_server ! {nodeup, Node}, 1104 sync_check(Rem -- [Node], Up, ErrorNodes); 1105 {config_error, ?cc_vsn, Pid, Node} when Pid =:= self() -> 1106 sync_check(Rem -- [Node], Up, [Node | ErrorNodes]); 1107 {no_global_group_configuration, ?cc_vsn, Pid, Node} when Pid =:= self() -> 1108 sync_check(Rem -- [Node], Up, [Node | ErrorNodes]); 1109 %% Ignore, illegal vsn or illegal Pid 1110 _ -> 1111 sync_check(Rem, Up, ErrorNodes) 1112 after 2000 -> 1113 %% Try again, the previous conf_check message 1114 %% apparently disapared in the magic black hole. 1115 {more, Rem, ErrorNodes} 1116 end. 1117 1118 1119%%%==================================================================================== 1120%%% A process wants to toggle monitoring nodeup/nodedown from nodes. 1121%%%==================================================================================== 1122monitor_nodes(true, Pid, State) -> 1123 link(Pid), 1124 Monitor = State#state.monitor, 1125 {ok, State#state{monitor = [Pid|Monitor]}}; 1126monitor_nodes(false, Pid, State) -> 1127 Monitor = State#state.monitor, 1128 State1 = State#state{monitor = delete_all(Pid,Monitor)}, 1129 do_unlink(Pid, State1), 1130 {ok, State1}; 1131monitor_nodes(_, _, State) -> 1132 {error, State}. 1133 1134delete_all(From, [From |Tail]) -> delete_all(From, Tail); 1135delete_all(From, [H|Tail]) -> [H|delete_all(From, Tail)]; 1136delete_all(_, []) -> []. 1137 1138%% do unlink if we have no more references to Pid. 1139do_unlink(Pid, State) -> 1140 case lists:member(Pid, State#state.monitor) of 1141 true -> 1142 false; 1143 _ -> 1144% io:format("unlink(Pid) ~p~n",[Pid]), 1145 unlink(Pid) 1146 end. 1147 1148 1149 1150%%%==================================================================================== 1151%%% Send a nodeup/down messages to monitoring Pids in the own global group. 1152%%%==================================================================================== 1153send_monitor([P|T], M, no_conf) -> 1154 _ = safesend_nc(P, M), 1155 send_monitor(T, M, no_conf); 1156send_monitor([P|T], M, SyncState) -> 1157 _ = safesend(P, M), 1158 send_monitor(T, M, SyncState); 1159send_monitor([], _, _) -> 1160 ok. 1161 1162safesend(Name, {Msg, Node}) when is_atom(Name) -> 1163 case lists:member(Node, get_own_nodes()) of 1164 true -> 1165 case whereis(Name) of 1166 undefined -> 1167 {Msg, Node}; 1168 P when is_pid(P) -> 1169 P ! {Msg, Node} 1170 end; 1171 false -> 1172 not_own_group 1173 end; 1174safesend(Pid, {Msg, Node}) -> 1175 case lists:member(Node, get_own_nodes()) of 1176 true -> 1177 Pid ! {Msg, Node}; 1178 false -> 1179 not_own_group 1180 end. 1181 1182safesend_nc(Name, {Msg, Node}) when is_atom(Name) -> 1183 case whereis(Name) of 1184 undefined -> 1185 {Msg, Node}; 1186 P when is_pid(P) -> 1187 P ! {Msg, Node} 1188 end; 1189safesend_nc(Pid, {Msg, Node}) -> 1190 Pid ! {Msg, Node}. 1191 1192 1193 1194 1195 1196 1197%%%==================================================================================== 1198%%% Check which user is associated to the crashed process. 1199%%%==================================================================================== 1200check_exit(ExitPid, Reason) -> 1201% io:format("===EXIT=== ~p ~p ~n~p ~n~p ~n~p ~n~n",[ExitPid, Reason, get(registered_names), get(send), get(whereis_name)]), 1202 check_exit_reg(get(registered_names), ExitPid, Reason), 1203 check_exit_send(get(send), ExitPid, Reason), 1204 check_exit_where(get(whereis_name), ExitPid, Reason). 1205 1206 1207check_exit_reg(undefined, _ExitPid, _Reason) -> 1208 ok; 1209check_exit_reg(Reg, ExitPid, Reason) -> 1210 case lists:keysearch(ExitPid, 1, lists:delete(undefined, Reg)) of 1211 {value, {ExitPid, From}} -> 1212 NewReg = lists:delete({ExitPid, From}, Reg), 1213 put(registered_names, NewReg), 1214 gen_server:reply(From, {error, Reason}); 1215 false -> 1216 not_found_ignored 1217 end. 1218 1219 1220check_exit_send(undefined, _ExitPid, _Reason) -> 1221 ok; 1222check_exit_send(Send, ExitPid, _Reason) -> 1223 case lists:keysearch(ExitPid, 1, lists:delete(undefined, Send)) of 1224 {value, {ExitPid, From, Name, Msg}} -> 1225 NewSend = lists:delete({ExitPid, From, Name, Msg}, Send), 1226 put(send, NewSend), 1227 gen_server:reply(From, {badarg, {Name, Msg}}); 1228 false -> 1229 not_found_ignored 1230 end. 1231 1232 1233check_exit_where(undefined, _ExitPid, _Reason) -> 1234 ok; 1235check_exit_where(Where, ExitPid, Reason) -> 1236 case lists:keysearch(ExitPid, 1, lists:delete(undefined, Where)) of 1237 {value, {ExitPid, From}} -> 1238 NewWhere = lists:delete({ExitPid, From}, Where), 1239 put(whereis_name, NewWhere), 1240 gen_server:reply(From, {error, Reason}); 1241 false -> 1242 not_found_ignored 1243 end. 1244 1245 1246 1247%%%==================================================================================== 1248%%% Kill any possible global_group_check processes 1249%%%==================================================================================== 1250kill_global_group_check() -> 1251 case whereis(global_group_check) of 1252 undefined -> 1253 ok; 1254 Pid -> 1255 unlink(Pid), 1256 global_group_check ! kill, 1257 unregister(global_group_check) 1258 end. 1259 1260 1261%%%==================================================================================== 1262%%% Disconnect nodes not belonging to own global_groups 1263%%%==================================================================================== 1264disconnect_nodes(DisconnectNodes) -> 1265 lists:foreach(fun(Node) -> 1266 {global_group, Node} ! {disconnect_node, node()}, 1267 global:node_disconnected(Node) 1268 end, 1269 DisconnectNodes). 1270 1271 1272%%%==================================================================================== 1273%%% Disconnect nodes not belonging to own global_groups 1274%%%==================================================================================== 1275force_nodedown(DisconnectNodes) -> 1276 lists:foreach(fun(Node) -> 1277 erlang:disconnect_node(Node), 1278 global:node_disconnected(Node) 1279 end, 1280 DisconnectNodes). 1281 1282 1283%%%==================================================================================== 1284%%% Get the current global_groups definition 1285%%%==================================================================================== 1286get_own_nodes_with_errors() -> 1287 case application:get_env(kernel, global_groups) of 1288 undefined -> 1289 {ok, all}; 1290 {ok, []} -> 1291 {ok, all}; 1292 {ok, NodeGrps} -> 1293 case catch config_scan(NodeGrps, publish_type) of 1294 {error, Error} -> 1295 {error, Error}; 1296 {_, _, NodesDef, _} -> 1297 {ok, lists:sort(NodesDef)} 1298 end 1299 end. 1300 1301get_own_nodes() -> 1302 case get_own_nodes_with_errors() of 1303 {ok, all} -> 1304 []; 1305 {error, _} -> 1306 []; 1307 {ok, Nodes} -> 1308 Nodes 1309 end. 1310 1311%%%==================================================================================== 1312%%% -hidden command line argument 1313%%%==================================================================================== 1314publish_arg() -> 1315 case init:get_argument(hidden) of 1316 {ok,[[]]} -> 1317 hidden; 1318 {ok,[["true"]]} -> 1319 hidden; 1320 _ -> 1321 normal 1322 end. 1323 1324 1325%%%==================================================================================== 1326%%% Own group publication type and nodes 1327%%%==================================================================================== 1328own_group() -> 1329 case application:get_env(kernel, global_groups) of 1330 undefined -> 1331 no_group; 1332 {ok, []} -> 1333 no_group; 1334 {ok, NodeGrps} -> 1335 case catch config_scan(NodeGrps, publish_type) of 1336 {error, _} -> 1337 no_group; 1338 {_, PubTpGrp, NodesDef, _} -> 1339 {PubTpGrp, NodesDef} 1340 end 1341 end. 1342 1343 1344%%%==================================================================================== 1345%%% Help function which computes publication list 1346%%%==================================================================================== 1347publish_on_nodes(normal, no_group) -> 1348 all; 1349publish_on_nodes(hidden, no_group) -> 1350 []; 1351publish_on_nodes(normal, {normal, _}) -> 1352 all; 1353publish_on_nodes(hidden, {_, Nodes}) -> 1354 Nodes; 1355publish_on_nodes(_, {hidden, Nodes}) -> 1356 Nodes. 1357 1358%%%==================================================================================== 1359%%% Update net_kernels publication list 1360%%%==================================================================================== 1361update_publish_nodes(PubArg) -> 1362 update_publish_nodes(PubArg, no_group). 1363update_publish_nodes(PubArg, MyGroup) -> 1364 net_kernel:update_publish_nodes(publish_on_nodes(PubArg, MyGroup)). 1365 1366 1367%%%==================================================================================== 1368%%% Fetch publication list 1369%%%==================================================================================== 1370publish_on_nodes() -> 1371 publish_on_nodes(publish_arg(), own_group()). 1372