summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Watson <tim@rabbitmq.com>2014-01-28 16:25:49 +0000
committerTim Watson <tim@rabbitmq.com>2014-01-28 16:25:49 +0000
commite3159b1f4f2977a9cf6d1e1f9beb4ff3e634e17a (patch)
tree8483e4eaf30864351a84ba7be550cb78af63f8f9
parent81bd7f7e2600a30d7473a512487a3d33a1c8a4af (diff)
downloadrabbitmq-server-git-e3159b1f4f2977a9cf6d1e1f9beb4ff3e634e17a.tar.gz
Handle varying destinations in mcall/1
-rw-r--r--src/gen_server2.erl39
-rw-r--r--src/rabbit_tests.erl16
2 files changed, 46 insertions, 9 deletions
diff --git a/src/gen_server2.erl b/src/gen_server2.erl
index 0fea8dd1bc..4326a4473c 100644
--- a/src/gen_server2.erl
+++ b/src/gen_server2.erl
@@ -393,7 +393,10 @@ multi_call(Nodes, Name, Req, Timeout)
%%% -----------------------------------------------------------------
%%% Make multiple calls to multiple servers, given pairs of servers
%%% and messages.
-%%% Returns: {[{Pid, Reply}], [{Pid, Error}]}
+%%% Returns: {[{Dest, Reply}], [{Dest, Error}]}
+%%%
+%%% Dest can be pid() | RegName :: atom() |
+%%% {Name :: atom(), Node :: atom()} | {global, Name :: atom()}
%%%
%%% A middleman process is used to avoid clogging up the callers
%%% message queue.
@@ -411,11 +414,35 @@ mcall(CallSpecs) ->
{'DOWN', MRef, _, _, Reason} -> exit(Reason)
end.
-do_mcall({Pid, Request}, Dict) ->
- MRef = erlang:monitor(process, Pid),
- catch erlang:send(Pid, {'$gen_call', {self(), MRef}, Request},
- [noconnect]),
- dict:store(MRef, Pid, Dict).
+do_mcall({Dest={global, Name}, Request}, Dict) ->
+ %% whereis_name is simply an ets lookup, and is precisely what
+ %% global:send/2 does, yet we need a Ref to put in the call to the
+ %% server, so invoking whereis_name makes a lot more sense here.
+ GRef = case global:whereis_name(Name) of
+ Pid when is_pid(Pid) ->
+ MRef = erlang:monitor(process, Pid),
+ catch msend(Pid, MRef, Request),
+ MRef;
+ undefined ->
+ Ref = make_ref(),
+ self() ! {'DOWN', Ref, process, Dest, unknown_name},
+ Ref
+ end,
+ dict:store(GRef, Dest, Dict);
+
+do_mcall({Dest, Request}, Dict) ->
+ MRef = case Dest of
+ {Name, Node} when is_atom(Name), is_atom(Node) ->
+ {_Node, Ref} = start_monitor(Node, Name),
+ Ref;
+ _PidOrRegName ->
+ erlang:monitor(process, Dest)
+ end,
+ catch msend(Dest, MRef, Request),
+ dict:store(MRef, Dest, Dict).
+
+msend(Dest, MRef, Request) ->
+ erlang:send(Dest, {'$gen_call', {self(), MRef}, Request}, [noconnect]).
collect_replies(Tag, Refs, Replies, Errors) ->
case dict:size(Refs) of
diff --git a/src/rabbit_tests.erl b/src/rabbit_tests.erl
index a5e91f67af..bb0cd42177 100644
--- a/src/rabbit_tests.erl
+++ b/src/rabbit_tests.erl
@@ -1370,11 +1370,21 @@ test_with_state() ->
passed.
test_mcall() ->
- Pids = [spawn_link(fun gs2_test_listener/0) || _ <- lists:seq(1, 250)],
- BadPids = [spawn(fun gs2_test_crasher/0) || _ <- lists:seq(1, 10)],
+ Pids1 = [spawn_link(fun gs2_test_listener/0) || _ <- lists:seq(1, 5)],
+ Pids2 = [spawn_link(fun() ->
+ register(cottontail, self()),
+ gs2_test_listener()
+ end)],
+ Pids = Pids1 ++ Pids2,
+ BadPids1 = [spawn(fun gs2_test_crasher/0) || _ <- lists:seq(1, 10)],
+ BadPids2 = [{global, foo}, {nonode@nohost, bar}],
+ BadPids = BadPids1 ++ BadPids2,
{Replies, Errors} = gen_server2:mcall([{P, hello} || P <- Pids ++ BadPids]),
true = lists:sort(Replies) == lists:sort([{Pid, goodbye} || Pid <- Pids]),
- true = lists:sort(Errors) == lists:sort([{Pid, boom} || Pid <- BadPids]),
+ true = lists:sort(Errors) ==
+ lists:sort([{Pid, boom} || Pid <- BadPids1] ++
+ [{{nonode@nohost,bar},nodedown},
+ {{global,foo},unknown_name}]),
passed.
gs2_test_crasher() ->