From 0da86179667a89596e9e5a7e432db25a37563955 Mon Sep 17 00:00:00 2001 From: Vlad Alexandru Ionescu Date: Fri, 6 Aug 2010 19:00:28 +0100 Subject: [PATCH 01/31] updating API edoc documentation --- deps/amqp_client/src/amqp_channel.erl | 125 ++++++++++------------- deps/amqp_client/src/amqp_connection.erl | 19 +++- deps/amqp_client/src/overview.edoc.in | 16 ++- 3 files changed, 79 insertions(+), 81 deletions(-) mode change 100644 => 100755 deps/amqp_client/src/overview.edoc.in diff --git a/deps/amqp_client/src/amqp_channel.erl b/deps/amqp_client/src/amqp_channel.erl index e71ecf7ff6..f5860de59a 100755 --- a/deps/amqp_client/src/amqp_channel.erl +++ b/deps/amqp_client/src/amqp_channel.erl @@ -25,10 +25,8 @@ %% @doc This module encapsulates the client's view of an AMQP channel. Each %% server side channel is represented by an amqp_channel process on the client -%% side. Channel processes are created using the {@link amqp_connection} -%% module, but channels are respsonsible for closing themselves. Channel -%% processes are linked to the connnection process from which they were -%% created. +%% side. Channel processes are created using the {@link amqp_connection}. +%% Channel processes are supervised under amqp_client's supervision tree. -module(amqp_channel). -include("amqp_client.hrl"). @@ -62,32 +60,6 @@ consumers = dict:new(), default_consumer = unknown}). -%% This diagram shows the interaction between the different component -%% processes in an AMQP client scenario. -%% -%% message* / reply* +-------+ -%% +---------------------- | queue | -%% | +-------+ -%% | -%% | +-----+ -%% v | | -%% request reply* | v -%% +------+ -------+ +--------------+ <------+ +----------------+ -%% | User | | | amqp_channel | | | direct_channel | -%% +------+ <------+ +--------------+ -------+ +----------------+ -%% response / | request -%% cast/call / | -%% / | message -%% / v -%% +-------------+/ +----------+ -%% | Pending RPC | | Consumer | -%% +-------------+ +----------+ -%% | -%% [consumer tag --> consumer pid] -%% -%% These notifications are processed asynchronously via -%% handle_info/2 callbacks - %%--------------------------------------------------------------------------- %% Type Definitions %%--------------------------------------------------------------------------- @@ -97,57 +69,73 @@ %% AMQP execution model. As indicated in the overview, the attributes of each %% commands in the execution model are described in the protocol %% documentation. The Erlang record definitions are autogenerated from a -%% parseable version of the specification. +%% parseable version of the specification. Most fields in the generated records +%% have sensible default values that you need not worry in the case of a simple +%% usage of the client library. -%% @type content() = #'basic.publish'{} | -%% #'basic.deliver'{} | -%% #'basic.return'{}. -%% These are the content bearing AMQP commands. +%% @type amqp_msg() = #amqp_msg{}. +%% This is the content encapsulated in content bearing AMQP commands. It +%% contains the following fields: +%% %%--------------------------------------------------------------------------- %% AMQP Channel API methods %%--------------------------------------------------------------------------- -%% @spec (Channel, amqp_command()) -> amqp_command() -%% where -%% Channel = pid() -%% @doc This is a generic RPC mechanism that sends an AMQP command and -%% receives an AMQP command as a response. This function blocks until the -%% response is returned. +%% @spec (Channel, Method) -> Result +%% @doc This is equivalent to amqp_channel:call(Channel, Command, none). call(Channel, Method) -> gen_server:call(Channel, {call, Method, none}, infinity). -%% @spec (Channel, amqp_command(), content()) -> ok | blocked | closing +%% @spec (Channel, Method, Content) -> Result %% where %% Channel = pid() -%% @doc This sends an AMQP command with content and waits for a synchronous -%% response. Generally this is used with the #basic.publish{} command. -%% This will return a blocked atom if either the server has throttled the -%% client for flow control reasons or if the channel is shutting down due to a -%% broker initiated close. -%% It will return a closing atom if the channel is in the process of shutting -%% down. +%% Method = amqp_command() +%% Content = amqp_msg() | none +%% Result = amqp_command() | ok | blocked | closing +%% @doc This sends an AMQP command on the channel. +%% For content bearing methods, Content has to be an amqp_msg(), whereas +%% for non-content bearing methods, it needs to be the atom 'none'.
+%% In the case of synchronous methods, this function blocks until the +%% corresponding reply comes back from the server and returns it. +%% In the case of asynchronous methods, the function blocks until the method +%% gets sent on the wire and returns the atom 'ok' on success.
+%% This will return the atom 'blocked' if the server has +%% throttled the client for flow control reasons. Also, it will return the +%% atom 'closing' if the channel is in the process of shutting down.
%% Note that the synchronicity only means that the client has transmitted the -%% command to the broker. It does not imply that the broker has accepted -%% responsibility for the message. To acheive guaranteed delivery, this -%% function would have to be called within the context of a transaction. +%% command to the broker. It does not necessarily imply that the broker has +%% accepted responsibility for the message. To acheive guaranteed delivery, +%% this function would have to be called within the context of a transaction. call(Channel, Method, Content) -> gen_server:call(Channel, {call, Method, Content}, infinity). -%% @spec (Channel, amqp_command()) -> ok -%% @doc Asynchronous variant of {@link call/2} +%% @spec (Channel, Method) -> ok +%% @doc This is equivalent to amqp_channel:cast(Channel, Command, none). cast(Channel, Method) -> gen_server:cast(Channel, {cast, Method, none}). -%% @spec (Channel, amqp_command(), content()) -> ok -%% @doc Asynchronous variant of {@link call/3} +%% @spec (Channel, Method, Content) -> ok +%% where +%% Channel = pid() +%% Method = amqp_command() +%% Content = amqp_msg() | none +%% @doc This function is the same as {@link call/3}, except that it returns +%% immediately with the atom 'ok', without blocking the caller process. +%% This function is not recommended with synchronous methods, since there is no +%% way to verify that the server has received the command. cast(Channel, Method, Content) -> gen_server:cast(Channel, {cast, Method, Content}). %% @spec (Channel) -> ok %% where %% Channel = pid() -%% @doc Closes the channel, invokes close(Channel, 200, <<"Goodbye">>). +%% @doc Closes the channel, invokes +%% close(Channel, 200, <<"Goodbye">>). close(Channel) -> close(Channel, 200, <<"Goodbye">>). @@ -165,6 +153,7 @@ close(Channel, Code, Text) -> method_id = 0}, #'channel.close_ok'{} = call(Channel, Close), ok. + %%--------------------------------------------------------------------------- %% Consumer registration (API) %%--------------------------------------------------------------------------- @@ -176,7 +165,7 @@ close(Channel, Code, Text) -> %% Channel = pid() %% Consumer = pid() %% @doc Creates a subscription to a queue. This subscribes a consumer pid to -%% the queue defined in the #'basic.consume'{} command record. Note that both +%% the queue defined in the #'basic.consume'{} command record. Note that %% both the process invoking this method and the supplied consumer process %% receive an acknowledgement of the subscription. The calling process will %% receive the acknowledgement as the return value of this function, whereas @@ -210,22 +199,20 @@ register_flow_handler(Channel, FlowHandler) -> %% Under certain circumstances it is possible for a channel to receive a %% message delivery which does not match any consumer which is currently %% set up via basic.consume. This will occur after the following sequence -%% of events: -%% -%% basic.consume with explicit acks -%% %% some deliveries take place but are not acked -%% basic.cancel -%% basic.recover{requeue = false} -%% +%% of events:
+%%
+%% basic.consume with explicit acks
+%% %% some deliveries take place but are not acked
+%% basic.cancel
+%% basic.recover{requeue = false}
+%%
%% Since requeue is specified to be false in the basic.recover, the spec %% states that the message must be redelivered to "the original recipient" %% - i.e. the same channel / consumer-tag. But the consumer is no longer -%% active. -%% +%% active.
%% In these circumstances, you can register a default consumer to handle %% such deliveries. If no default consumer is registered then the channel -%% will exit on receiving such a delivery. -%% +%% will exit on receiving such a delivery.
%% Most people will not need to use this. register_default_consumer(Channel, Consumer) -> gen_server:cast(Channel, {register_default_consumer, Consumer}). diff --git a/deps/amqp_client/src/amqp_connection.erl b/deps/amqp_client/src/amqp_connection.erl index b39f6cad3e..e8f58e4441 100755 --- a/deps/amqp_client/src/amqp_connection.erl +++ b/deps/amqp_client/src/amqp_connection.erl @@ -25,9 +25,12 @@ %% @doc This module is responsible for maintaining a connection to an AMQP %% broker and manages channels within the connection. This module is used to %% open and close connections to the broker as well as creating new channels -%% within a connection. Each amqp_connection process maintains a mapping of -%% the channels that were created by that connection process. Each resulting -%% amqp_channel process is linked to the parent connection process. +%% within a connection.
+%% The connections and channels created by this module are supervised under +%% amqp_client's supervision tree. Please note that connections and channels +%% do not get restarted automatically by the supervision tree in the case of a +%% failure. If you need robust connections and channels, we recommend you use +%% Erlang monitors on the returned connection and channel PID. -module(amqp_connection). -include("amqp_client.hrl"). @@ -58,6 +61,16 @@ %% defaults to "localhost" %%
  • port :: integer() - The port the broker is listening on, %% defaults to 5672
  • +%%
  • channel_max :: non_neg_integer() - The channel_max handshake parameter, +%% defaults to 0
  • +%%
  • frame_max :: non_neg_integer() - The frame_max handshake parameter, +%% defaults to 0
  • +%%
  • heartbeat :: non_neg_integer() - The hearbeat interval in seconds, +%% defaults to 0 (turned off)
  • +%%
  • ssl_options :: term() - The second parameter to be used with the +%% ssl:connect/2 function, defaults to 'none'
  • +%%
  • client_properties :: [{binary(), atom(), binary()}] - A list of extra +%% client properties to be sent to the server, defaults to []
  • %% %%--------------------------------------------------------------------------- diff --git a/deps/amqp_client/src/overview.edoc.in b/deps/amqp_client/src/overview.edoc.in old mode 100644 new mode 100755 index 12d90d2212..2402655507 --- a/deps/amqp_client/src/overview.edoc.in +++ b/deps/amqp_client/src/overview.edoc.in @@ -1,19 +1,19 @@ @title AMQP Client for Erlang -@author LShift Ltd. -@copyright 2009 LShift Ltd. +@author Rabbit Technologies Ltd. +@copyright 2010 Rabbit Technologies Ltd. @version %%VERSION%% -@reference AMQP Specification, the 0-8 version of the AMQP specification +@reference AMQP Specification, the 0-9-1 version of the AMQP specification @reference AMQP Protocol Documentation, the documentation of the commands in the 0-8 version of the protocol +href="http://www.amqp.org/confluence/download/attachments/720900/amqp-xml-doc0-9-1.pdf?version=1">AMQP Protocol Documentation, the documentation of the commands in the 0-9-1 version of the protocol @doc

    An implementation of AMQP for Erlang.

    == Overview == -This application provides an Erlang library to interact with an AMQP compliant message broker. The module documentation assumes that the programmer has some basic familiarity with the execution model defined in the AMQP specification. +This application provides an Erlang library to interact with an AMQP 0-9-1 compliant message broker. The module documentation assumes that the programmer has some basic familiarity with the execution model defined in the AMQP specification. The main components are {@link amqp_connection} and {@link amqp_channel}. The {@link amqp_connection} module is used to open and close connections to an AMQP broker as well as creating channels. The {@link amqp_channel} module is used to send and receive commands and messages to and from a broker within the context of a channel. @@ -23,10 +23,8 @@ Many of the API functions take structured records as arguments. These records re == Programming Model == -For more information, refer to the Erlang AMQP client developer's guide on the RabbitMQ website. +For more information, refer to the Erlang AMQP client developer's guide on the RabbitMQ website. == RPC Components == -The {@link amqp_rpc_server} module provides a generic building block to expose -Erlang functions via an RPC over AMQP mechanism. The {@link amqp_rpc_client} -provides a simple client utility to submit RPC requests to a server via AMQP. +The {@link amqp_rpc_server} module provides a generic building block to expose Erlang functions via an RPC over AMQP mechanism. The {@link amqp_rpc_client} provides a simple client utility to submit RPC requests to a server via AMQP. From d6394a3a47903713481753111211ae0dc599d322 Mon Sep 17 00:00:00 2001 From: Vlad Alexandru Ionescu Date: Mon, 9 Aug 2010 16:14:40 +0100 Subject: [PATCH 02/31] updating amqp_connection API documentation; changing README to get its content from the Erlang client build page on the website; other minor --- deps/amqp_client/Makefile | 6 +- deps/amqp_client/README | 257 ----------------------- deps/amqp_client/README.in | 10 + deps/amqp_client/src/amqp_connection.erl | 22 +- deps/amqp_client/src/amqp_rpc_client.erl | 2 +- deps/amqp_client/src/overview.edoc.in | 2 +- 6 files changed, 29 insertions(+), 270 deletions(-) delete mode 100755 deps/amqp_client/README create mode 100755 deps/amqp_client/README.in diff --git a/deps/amqp_client/Makefile b/deps/amqp_client/Makefile index 1d1f991254..92c7a8e485 100755 --- a/deps/amqp_client/Makefile +++ b/deps/amqp_client/Makefile @@ -28,6 +28,9 @@ DEPS=$(shell erl -noshell -eval '{ok,[{_,_,[_,_,{modules, Mods},_,_,_]}]} = \ [io:format("~p ",[M]) || M <- Mods], halt().') VERSION=0.0.0 + +WEB_URL=http://www.rabbitmq.com/ + SOURCE_PACKAGE_DIR=$(PACKAGE)-$(VERSION)-src SOURCE_PACKAGE_TAR_GZ=$(SOURCE_PACKAGE_DIR).tar.gz @@ -128,7 +131,8 @@ $(DIST_DIR)/$(COMMON_PACKAGE_DIR): $(BROKER_DEPS) $(COMMON_PACKAGE_DIR).app | $( source_tarball: clean $(DIST_DIR)/$(COMMON_PACKAGE_EZ) | $(DIST_DIR) mkdir -p $(DIST_DIR)/$(SOURCE_PACKAGE_DIR)/$(DIST_DIR) $(COPY) $(DIST_DIR)/$(COMMON_PACKAGE_EZ) $(DIST_DIR)/$(SOURCE_PACKAGE_DIR)/$(DIST_DIR)/ - $(COPY) README $(DIST_DIR)/$(SOURCE_PACKAGE_DIR)/ + $(COPY) README.in $(DIST_DIR)/$(SOURCE_PACKAGE_DIR)/README + elinks -dump -no-references -no-numbering $(WEB_URL)build-erlang-client.html >> $(DIST_DIR)/$(SOURCE_PACKAGE_DIR)/README $(COPY) common.mk $(DIST_DIR)/$(SOURCE_PACKAGE_DIR)/ $(COPY) Makefile.in $(DIST_DIR)/$(SOURCE_PACKAGE_DIR)/Makefile mkdir -p $(DIST_DIR)/$(SOURCE_PACKAGE_DIR)/$(SOURCE_DIR) diff --git a/deps/amqp_client/README b/deps/amqp_client/README deleted file mode 100755 index 079715b833..0000000000 --- a/deps/amqp_client/README +++ /dev/null @@ -1,257 +0,0 @@ -AMQP client for Erlang -====================== -This code implements a client for AMQP in the Erlang programming -language. - -This client offers both a networked version that uses standard -TCP-based AMQP framing and a direct client that uses native Erlang -message passing to a RabbitMQ broker. - -The API exposed to the user is common to both clients, so each version -can be used interchangeably without having to modify any client code. - -The TCP networked client has been tested with RabbitMQ server 1.4.0, -but should theoretically work with any 0-8 compliant AMQP server. - -The direct client is bound to an 0-8 compliant broker using native -Erlang message passing, which in the absence of an alternative Erlang -AMQP implementation means that it only works with RabbitMQ. - -It does however provide a level of abstraction above the internal -server API of RabbitMQ, meaning that you can write client code in -Erlang and still remain isolated from any API changes in the -underlying broker. - -It also provides a client-orientated API into RabbitMQ, allowing the -user to reuse AMQP knowledge gained by using AMQP clients in other -languages. - -The advantage of the direct client is that it eliminates the network -overhead as well as the marshaling to and from the AMQP wire format, -so that neither side has to decode or encode any AMQP frames. - -Prerequisites -------------- -In order to compile/run this code you must have the following -installed: - -- Erlang/OTP, R11B-5 or later, http://www.erlang.org/download.html -- The RabbitMQ server, 93cc2ca0ba62 or later -- Eunit, the Erlang unit testing framework - currently the whole build process - depends on eunit because all of the modules are compiled together. - A future version of the build process could remove this dependency when you - only want to compile the core libraries. - -Getting Eunit -------------- -The test suite uses eunit which is either available bundled with OTP from -release R12B-5 onwards or as a separate download that you will need to build -yourself if you are using an older version of Erlang. - -* If you are using R12B-5 or newer: - -Just skip to the next section. - -* If you are using R12B-4 or older: - -Check out eunit from their Subversion repository and build it: - - $ svn co http://svn.process-one.net/contribs/trunk/eunit eunit - $ cd eunit - $ make - -After this has sucessfully been built, you will need to create a symlink to -the eunit directory in your OTP installation directory: - - $ cd $OTP_HOME/lib/erlang/lib - $ ln -sf PATH_TO_EUNIT eunit - -where $OTP_HOME is the location of your Erlang/OTP installation. - -Compiling the Erlang client -------------------------- -You will need to get a copy of the server in order to be able to use it's -header files and runtime libraries. A good place to put this is in the sibling -directory to the Erlang client (i.e: ../rabbitmq-server), which is the default -that the Makefile expects. In this case, you can just run make: - - $ make - -If the source tree for the server is not in the sibling directory, you will -need to specify the path to this directory: - - $ make BROKER_DIR=/path/to/server - -In this case, make sure you specify BROKER_DIR every time you run a make target. - -Running the network client, direct client and packaging tests -------------------------------------------------------------- -The direct client has to be run in the same Erlang VM instance as the -RabbitMQ server. In order to use the makefile to run tests, you will need to -shutdown any other running instance of RabbitMQ server that you may have on -your machine. This is because the Makefile test targets boot their own instance -of RabbitMQ with settings depending on the test. -To run these tests, use either of the following targets: - - $ make test_network - $ make test_direct - $ make test_common_package - -Or to run all tests: - - $ make all_tests - -If any test fails, the make command will return a non-zero exit code. The reason -is logged by the server in /tmp/rabbit-sasl.log by default. - -The network client test can also be run from a separate Erlang VM instance from -RabbitMQ server. You can *start an instance of the server* and then, in the -rabbitmq-erlang-client folder, type - - rabbitmq-erlang-client $ make compile_tests - rabbitmq-erlang-client $ make run - erl -pa ebin ../rabbitmq-server/ebin tests - Erlang (BEAM) emulator version 5.6.5 [source] [64-bit] [smp:4] \ - [async-threads:0] [hipe] [kernel-poll:false] - - Eshell V5.6.5 (abort with ^G) - 1> network_client_SUITE:test(). - -To get more examples of the API, look at the functions in the test_util module. - -Running the channel flow tests ------------------------------- -There are two tests for producer control flow. The first is a unit -test that asserts the reception of the correct chain of commands in -conjunction with a direct manipulation of the high water mark. The -second test does not make any assertion about the behavior of the -server but it does produce output that demonstrates that the client -library is indeed notifying higher level application code that flow -control has been activated or deactivated. - -Both tests require that the memory alarms are turned on in the -server. By default they are turned off. To turn them on, set the -memory_alarms flag in the rabbit.app config file. - -First of all, in the *rabbitmq-erlang-client directory*, type - - rabbitmq-erlang-client $ make compile_tests - -to make sure test modules are compiled. - -Because the unit test accesses memsup directly, it needs to use the -direct API and hence needs to run in the same VM as the server. To do -this from the *rabbitmq-erlang-client directory*, type - - rabbitmq-erlang-client $ make run_in_broker - -When that has booted, you need to *wait one minute* for the memory -alarms to become active. After that, you can run the following from -the Erlang shell: - - 1> direct_client_SUITE:test_channel_flow(). - ok - -The non-unit test can be run in separate VM, because it uses the -network client driver. Whilst it can be run using the direct client, -it produces log output which makes it difficult to enter in commands -interactively (which you need to do to see the throttling). - -After *having booted* an *instance of the server* with alarms handlers -turned on, run the following in the *rabbitmq-erlang-client directory*: - - rabbitmq-erlang-client $ make compile_tests - rabbitmq-erlang-client $ make run - Erlang (BEAM) emulator version 5.6.3 [source] [smp:2] \ - [async-threads:0][kernel-poll:false] - - Eshell V5.6.3 (abort with ^G) - 1> P = #amqp_params{}. - 2> test_util:channel_flow_sync(amqp_connection:start_network(P)). - {<0.39.0>,<0.40.0>} - -After having done this, you should see output similar to this: - - Producer (<0.39.0>) has sent about 0 messages since it started - Producer (<0.39.0>) has sent about 5000 messages since it started - Producer (<0.39.0>) has sent about 10000 messages since it started - -To throttle the producer, go to the *server shell* and turn the memory -limit to some suitably low value: - - 2> memsup:set_sysmem_high_watermark(0.01). - ok - -Back in the *client shell*, you should see the following output: - ..... - Producer (<0.39.0>) has sent about 235000 messages since it started - Producer throttling ON - Producer (<0.39.0>) is blocked, will go to sleep.....ZZZ - -If you now set the high water mark to say 99%, the producer should -wake up again: - - Producer throttling OFF, waking up producer (<0.39.0>) - Producer (<0.39.0>) has woken up :-) - Producer (<0.39.0>) has sent about 240000 messages since it started - ..... - -Make targets ------------- -Interesting rabbitmq-erlang-client make targets include - -all - The default target. Builds the client (does not compile the tests). - -compile - Builds the client. - -compile_tests - Builds the client test modules. - -run - Builds the client and starts an Erlang shell with both the client and the - server in the load path. - -run_in_broker - Builds the client and starts RabbitMQ server with shell and the client - included in load path. - -clean - Removes build products and wipes all files produced by any other - rabbitmq-erlang-client make targets or client errors. - -dialyze - Analyses the client source code with dialyzer. Uses PLT file from default - location: ~/.dialyzer_plt. Use - - $ make PLT=/path/to/plt dialyze - - to override this. Add broker to PLT beforehand, otherwise you will a lot - of 'unknown function' warnings. See add_broker_to_plt make target. - -dialyze_all - Same as dialyze, except that this also analyses tests source code. - -add_broker_to_plt - Adds broker .beam files to default plt. Use - - $ make PLT=/path/to/plt add_broker_to_plt - - to override default plt location ( ~/.dialyzer_plt ). - -source_tarball - Creates tarball of all the client source code. - -package - Creates an erlang archive of the client. - -common_package - Creates an erlang archive of the server modules required by the erlang - client. - -all_tests - Clean compiles the client and client tests source code and runs - network_client_SUITE, direct_client_SUITE and packaging tests. During the - testing, this make target runs an instance of the broker, so make sure - there is no other instance of RabbitMQ server running. diff --git a/deps/amqp_client/README.in b/deps/amqp_client/README.in new file mode 100755 index 0000000000..3e6cb36980 --- /dev/null +++ b/deps/amqp_client/README.in @@ -0,0 +1,10 @@ +Please see http://www.rabbitmq.com/build-erlang-client.html for build +instructions. + +For your convenience, a text copy of these instructions is available +below. Please be aware that the instructions here may not be as up to +date as those at the above URL. + +=========================================================================== + + diff --git a/deps/amqp_client/src/amqp_connection.erl b/deps/amqp_client/src/amqp_connection.erl index e8f58e4441..ff8d8f35ed 100755 --- a/deps/amqp_client/src/amqp_connection.erl +++ b/deps/amqp_client/src/amqp_connection.erl @@ -74,7 +74,7 @@ %% %%--------------------------------------------------------------------------- -%% AMQP Connection API Methods +%% Starting a connection %%--------------------------------------------------------------------------- %% @spec () -> [Connection] @@ -173,26 +173,28 @@ start_internal(Params, Module, _Link = false) when is_atom(Module) -> %% Commands %%--------------------------------------------------------------------------- -%% @doc Invokes open_channel(ConnectionPid, none, <<>>). +%% @doc Invokes open_channel(ConnectionPid, none). %% Opens a channel without having to specify a channel number. open_channel(ConnectionPid) -> open_channel(ConnectionPid, none). -%% @spec (ConnectionPid, ChannelNumber) -> ChannelPid +%% @spec (ConnectionPid, ChannelNumber) -> Result %% where -%% ChannelNumber = integer() +%% ChannelNumber = pos_integer() %% ConnectionPid = pid() +%% Result = {ok, ChannelPid} | {error, term()} %% ChannelPid = pid() -%% @doc Opens an AMQP channel. +%% @doc Opens an AMQP channel.
    %% This function assumes that an AMQP connection (networked or direct) -%% has already been successfully established. +%% has already been successfully established.
    +%% ChannelNumber must be less than or equal to the negotiated max_channel value, +%% or less than or equal to ?MAX_CHANNEL_NUMBER if the negotiated max_channel +%% value is 0.
    +%% In the direct connection, max_channel is always 0. open_channel(ConnectionPid, ChannelNumber) -> command(ConnectionPid, {open_channel, ChannelNumber}). -%% @spec (ConnectionPid) -> ok | Error -%% where -%% ConnectionPid = pid() -%% @doc Closes the channel, invokes close(Channel, 200, <<"Goodbye">>). +%% @doc Invokes close(Channel, 200, <<"Goodbye">>). close(ConnectionPid) -> close(ConnectionPid, 200, <<"Goodbye">>). diff --git a/deps/amqp_client/src/amqp_rpc_client.erl b/deps/amqp_client/src/amqp_rpc_client.erl index 4cf4eac2cf..7fad85f384 100755 --- a/deps/amqp_client/src/amqp_rpc_client.erl +++ b/deps/amqp_client/src/amqp_rpc_client.erl @@ -166,7 +166,7 @@ handle_info({#'basic.deliver'{delivery_tag = DeliveryTag}, From = dict:fetch(Id, Conts), gen_server:reply(From, Payload), amqp_channel:call(Channel, #'basic.ack'{delivery_tag = DeliveryTag}), - {noreply, State#rpc_c_state{continuations = dict:erase(Id, Conts) }}. + {noreply, State#rpc_c_state{continuations = dict:erase(Id, Conts)}}. %% @private code_change(_OldVsn, State, _Extra) -> diff --git a/deps/amqp_client/src/overview.edoc.in b/deps/amqp_client/src/overview.edoc.in index 2402655507..13cc6978ad 100755 --- a/deps/amqp_client/src/overview.edoc.in +++ b/deps/amqp_client/src/overview.edoc.in @@ -9,7 +9,7 @@ @reference AMQP Protocol Documentation, the documentation of the commands in the 0-9-1 version of the protocol -@doc

    An implementation of AMQP for Erlang.

    +@doc == Overview == From 8682b3297cb013ea6d1de2433dabc653b0325b4f Mon Sep 17 00:00:00 2001 From: Vlad Alexandru Ionescu Date: Fri, 3 Sep 2010 15:22:29 +0100 Subject: [PATCH 03/31] making the use of uname compatible with OS X --- deps/amqp_client/common.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deps/amqp_client/common.mk b/deps/amqp_client/common.mk index dcb1cab51c..a3cefeaf27 100644 --- a/deps/amqp_client/common.mk +++ b/deps/amqp_client/common.mk @@ -81,8 +81,8 @@ TEST_SOURCES=$(wildcard $(TEST_DIR)/*.erl) TEST_TARGETS=$(patsubst $(TEST_DIR)/%.erl, $(TEST_DIR)/%.beam, $(TEST_SOURCES)) LIBS_PATH_UNIX=$(DEPS_DIR):$(DIST_DIR)$(ERL_LIBS) -OSTYPE=$(shell uname -o) -ifeq ($(OSTYPE),Cygwin) +IS_CYGWIN=$(shell if [ $(shell expr match "$(shell uname -s)" 'CYGWIN_NT') -gt 0 ]; then echo "true"; else echo "false"; fi) +ifeq ($(IS_CYGWIN),true) LIBS_PATH=ERL_LIBS="$(shell cygpath -wp $(LIBS_PATH_UNIX))" else LIBS_PATH=ERL_LIBS=$(LIBS_PATH_UNIX) From f453368d3dc74d3d54b28b42326a88c4853ef535 Mon Sep 17 00:00:00 2001 From: Vlad Alexandru Ionescu Date: Fri, 3 Sep 2010 15:38:49 +0100 Subject: [PATCH 04/31] expr match not compatible with OS X --- deps/amqp_client/common.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/amqp_client/common.mk b/deps/amqp_client/common.mk index a3cefeaf27..265e0f3f39 100644 --- a/deps/amqp_client/common.mk +++ b/deps/amqp_client/common.mk @@ -81,7 +81,7 @@ TEST_SOURCES=$(wildcard $(TEST_DIR)/*.erl) TEST_TARGETS=$(patsubst $(TEST_DIR)/%.erl, $(TEST_DIR)/%.beam, $(TEST_SOURCES)) LIBS_PATH_UNIX=$(DEPS_DIR):$(DIST_DIR)$(ERL_LIBS) -IS_CYGWIN=$(shell if [ $(shell expr match "$(shell uname -s)" 'CYGWIN_NT') -gt 0 ]; then echo "true"; else echo "false"; fi) +IS_CYGWIN=$(shell if [ $(shell expr "$(shell uname -s)" : 'CYGWIN_NT') -gt 0 ]; then echo "true"; else echo "false"; fi) ifeq ($(IS_CYGWIN),true) LIBS_PATH=ERL_LIBS="$(shell cygpath -wp $(LIBS_PATH_UNIX))" else From ef2faba6b1c9f390269e246d4624f2b8992e9e7c Mon Sep 17 00:00:00 2001 From: Matthew Sackman Date: Mon, 6 Sep 2010 11:47:01 +0100 Subject: [PATCH 05/31] Make amqp_connection API more OTPish and better abstracted (changes lifted from bug 22993) --- deps/amqp_client/src/amqp_connection.erl | 107 +++++------------- deps/amqp_client/test/direct_client_SUITE.erl | 3 +- .../amqp_client/test/network_client_SUITE.erl | 10 +- deps/amqp_client/test/ssl_client_SUITE.erl | 3 +- 4 files changed, 37 insertions(+), 86 deletions(-) mode change 100644 => 100755 deps/amqp_client/test/ssl_client_SUITE.erl diff --git a/deps/amqp_client/src/amqp_connection.erl b/deps/amqp_client/src/amqp_connection.erl index 38baea8b2c..c2ba123cc9 100755 --- a/deps/amqp_client/src/amqp_connection.erl +++ b/deps/amqp_client/src/amqp_connection.erl @@ -33,8 +33,7 @@ -include("amqp_client.hrl"). -export([open_channel/1, open_channel/2]). --export([start_direct/0, start_direct/1, start_direct_link/0, start_direct_link/1]). --export([start_network/0, start_network/1, start_network_link/0, start_network_link/1]). +-export([start/1, start/2]). -export([close/1, close/3]). -export([info/2, info_keys/1, info_keys/0]). @@ -64,97 +63,45 @@ %% AMQP Connection API Methods %%--------------------------------------------------------------------------- -%% @spec () -> [Connection] +%% @spec (Type) -> {ok, Connection} | {error, Error} %% where +%% Type = network | direct %% Connection = pid() -%% @doc Starts a direct connection to a RabbitMQ server, assuming that -%% the server is running in the same process space, and with a default -%% set of amqp_params. If a different vhost or credential set is required, -%% start_direct/1 should be used. -start_direct() -> - start_direct(#amqp_params{}). +%% @doc Starts a connection to an AMQP server. Use network type to connect +%% to a remote AMQP server - default connection settings are used, meaning that +%% the server is expected to be at localhost:5672, with a vhost of "/" +%% authorising a user guest/guest. Use direct type for a direct connection to +%% a RabbitMQ server, assuming that the server is running in the same process +%% space, and with a default set of amqp_params. If a different host, port, +%% vhost or credential set is required, start/2 should be used. +start(Type) -> + start(Type, #amqp_params{}). -%% @spec (amqp_params()) -> [Connection] +%% @spec (Type, amqp_params()) -> {ok, Connection} | {error, Error} %% where +%% Type = network | direct %% Connection = pid() -%% @doc Starts a direct connection to a RabbitMQ server, assuming that -%% the server is running in the same process space. -start_direct(Params) -> - start_direct_internal(Params, false). +%% @doc Starts a connection to an AMQP server. Use network type to connect +%% to a remote AMQP server or direct type for a direct connection to +%% a RabbitMQ server, assuming that the server is running in the same process +%% space. +start(direct, AmqpParams) -> + start_internal(AmqpParams, amqp_direct_connection); +start(network, AmqpParams) -> + start_network_internal(AmqpParams). -%% @spec () -> [Connection] -%% where -%% Connection = pid() -%% @doc Starts a direct connection to a RabbitMQ server, assuming that -%% the server is running in the same process space, and with a default -%% set of amqp_params. If a different vhost or credential set is required, -%% start_direct_link/1 should be used. The resulting -%% process is linked to the invoking process. -start_direct_link() -> - start_direct_link(#amqp_params{}). - -%% @spec (amqp_params()) -> [Connection] -%% where -%% Connection = pid() -%% @doc Starts a direct connection to a RabbitMQ server, assuming that -%% the server is running in the same process space. The resulting process -%% is linked to the invoking process. -start_direct_link(Params) -> - start_direct_internal(Params, true). - -start_direct_internal(#amqp_params{} = Params, ProcLink) -> - {ok, Pid} = start_internal(Params, amqp_direct_connection, ProcLink), - Pid. - -%% @spec () -> [Connection] -%% where -%% Connection = pid() -%% @doc Starts a networked conection to a remote AMQP server. Default -%% connection settings are used, meaning that the server is expected -%% to be at localhost:5672, with a vhost of "/" authorising a user -%% guest/guest. -start_network() -> - start_network(#amqp_params{}). - -%% @spec (amqp_params()) -> [Connection] -%% where -%% Connection = pid() -%% @doc Starts a networked conection to a remote AMQP server. -start_network(Params) -> - start_network_internal(Params, false). - -%% @spec () -> [Connection] -%% where -%% Connection = pid() -%% @doc Starts a networked conection to a remote AMQP server. Default -%% connection settings are used, meaning that the server is expected -%% to be at localhost:5672, with a vhost of "/" authorising a user -%% guest/guest. The resulting process is linked to the invoking process. -start_network_link() -> - start_network_link(#amqp_params{}). - -%% @spec (amqp_params()) -> [Connection] -%% where -%% Connection = pid() -%% @doc Starts a networked connection to a remote AMQP server. The resulting -%% process is linked to the invoking process. -start_network_link(Params) -> - start_network_internal(Params, true). - -start_network_internal(#amqp_params{} = AmqpParams, ProcLink) -> - case start_internal(AmqpParams, amqp_network_connection, ProcLink) of +start_network_internal(#amqp_params{} = AmqpParams) -> + case start_internal(AmqpParams, amqp_network_connection) of {ok, Pid} -> - Pid; + {ok, Pid}; {error, {protocol_version_mismatch, _, _}} = Err -> throw(Err); Bad -> throw({error, {auth_failure_likely, Bad}}) end. -start_internal(Params, Module, _Link = true) when is_atom(Module) -> - gen_server:start_link(Module, Params, []); -start_internal(Params, Module, _Link = false) when is_atom(Module) -> - gen_server:start(Module, Params, []). +start_internal(Params, Module) when is_atom(Module) -> + gen_server:start_link(Module, Params, []). %%--------------------------------------------------------------------------- %% Commands diff --git a/deps/amqp_client/test/direct_client_SUITE.erl b/deps/amqp_client/test/direct_client_SUITE.erl index f5c889218d..302962c0ca 100755 --- a/deps/amqp_client/test/direct_client_SUITE.erl +++ b/deps/amqp_client/test/direct_client_SUITE.erl @@ -103,7 +103,8 @@ channel_death_test() -> %%--------------------------------------------------------------------------- new_connection() -> - amqp_connection:start_direct(). + {ok, Conn} = amqp_connection:start(direct), + Conn. test_coverage() -> rabbit_misc:enable_cover(), diff --git a/deps/amqp_client/test/network_client_SUITE.erl b/deps/amqp_client/test/network_client_SUITE.erl index 48890b9ad8..e7f79f64cf 100755 --- a/deps/amqp_client/test/network_client_SUITE.erl +++ b/deps/amqp_client/test/network_client_SUITE.erl @@ -87,8 +87,7 @@ pub_and_close_test_() -> end}. channel_tune_negotiation_test() -> - amqp_connection:close(amqp_connection:start_network( - #amqp_params{ channel_max = 10 })). + amqp_connection:close(new_connection(#amqp_params{ channel_max = 10 })). %%--------------------------------------------------------------------------- %% Negative Tests @@ -132,9 +131,12 @@ shortstr_overflow_field_test() -> repeat(Fun, Times) -> [ Fun(new_connection()) || _ <- lists:seq(1, Times)]. - new_connection() -> - amqp_connection:start_network(). + new_connection(#amqp_params{}). + +new_connection(AmqpParams) -> + {ok, Conn} = amqp_connection:start(network, AmqpParams), + Conn. test_coverage() -> rabbit_misc:enable_cover(), diff --git a/deps/amqp_client/test/ssl_client_SUITE.erl b/deps/amqp_client/test/ssl_client_SUITE.erl old mode 100644 new mode 100755 index aab602913b..e293913be0 --- a/deps/amqp_client/test/ssl_client_SUITE.erl +++ b/deps/amqp_client/test/ssl_client_SUITE.erl @@ -87,7 +87,8 @@ new_connection() -> {keyfile, CertsDir ++ "/client/key.pem"}, {verify, verify_peer}, {fail_if_no_peer_cert, true}]}, - amqp_connection:start_network(Params). + {ok, Conn} = amqp_connection:start(network, Params), + Conn. test_coverage() -> rabbit_misc:enable_cover(), From 1a3eafcf080092c57a6f9701a78380b6e7541a1b Mon Sep 17 00:00:00 2001 From: Matthew Sackman Date: Mon, 6 Sep 2010 12:09:00 +0100 Subject: [PATCH 06/31] Support older API still on default --- deps/amqp_client/src/amqp_connection.erl | 51 ++++++++++++++----- deps/amqp_client/test/direct_client_SUITE.erl | 3 +- deps/amqp_client/test/negative_test_util.erl | 2 +- .../amqp_client/test/network_client_SUITE.erl | 10 ++-- deps/amqp_client/test/ssl_client_SUITE.erl | 2 +- 5 files changed, 45 insertions(+), 23 deletions(-) diff --git a/deps/amqp_client/src/amqp_connection.erl b/deps/amqp_client/src/amqp_connection.erl index a9ce0fa98d..4cccf78050 100644 --- a/deps/amqp_client/src/amqp_connection.erl +++ b/deps/amqp_client/src/amqp_connection.erl @@ -33,7 +33,8 @@ -include("amqp_client.hrl"). -export([open_channel/1, open_channel/2]). --export([start/1, start/2]). +-export([start_direct_link/0, start_direct_link/1]). +-export([start_network_link/0, start_network_link/1]). -export([close/1, close/3]). -export([info/2, info_keys/1, info_keys/0]). @@ -63,19 +64,43 @@ %% AMQP Connection API Methods %%--------------------------------------------------------------------------- -%% @spec (Type) -> {ok, Connection} | {error, Error} +%% @spec () -> Connection %% where -%% Type = network | direct %% Connection = pid() -%% @doc Starts a connection to an AMQP server. Use network type to connect -%% to a remote AMQP server - default connection settings are used, meaning that -%% the server is expected to be at localhost:5672, with a vhost of "/" -%% authorising a user guest/guest. Use direct type for a direct connection to -%% a RabbitMQ server, assuming that the server is running in the same process -%% space, and with a default set of amqp_params. If a different host, port, -%% vhost or credential set is required, start/2 should be used. -start(Type) -> - start(Type, #amqp_params{}). +%% @doc Starts a direct connection to a RabbitMQ server, assuming that +%% the server is running in the same process space, and with a default +%% set of amqp_params. If a different vhost or credential set is required, +%% start_direct_link/1 should be used. The resulting +%% process is linked to the invoking process. +start_direct_link() -> + start(direct, #amqp_params{}). + +%% @spec (amqp_params()) -> Connection +%% where +%% Connection = pid() +%% @doc Starts a direct connection to a RabbitMQ server, assuming that +%% the server is running in the same process space. The resulting process +%% is linked to the invoking process. +start_direct_link(Params) -> + start(direct, Params). + +%% @spec () -> Connection +%% where +%% Connection = pid() +%% @doc Starts a networked conection to a remote AMQP server. Default +%% connection settings are used, meaning that the server is expected +%% to be at localhost:5672, with a vhost of "/" authorising a user +%% guest/guest. The resulting process is linked to the invoking process. +start_network_link() -> + start(network, #amqp_params{}). + +%% @spec (amqp_params()) -> Connection +%% where +%% Connection = pid() +%% @doc Starts a networked connection to a remote AMQP server. The resulting +%% process is linked to the invoking process. +start_network_link(Params) -> + start(network, Params). %% @spec (Type, amqp_params()) -> {ok, Connection} | {error, Error} %% where @@ -94,7 +119,7 @@ start(Type, AmqpParams) -> network -> amqp_network_connection end, try Module:connect(Connection) of - ok -> {ok, Connection} + ok -> Connection catch exit:{Reason = {protocol_version_mismatch, _, _}, _} -> {error, Reason}; diff --git a/deps/amqp_client/test/direct_client_SUITE.erl b/deps/amqp_client/test/direct_client_SUITE.erl index 3df974c01c..36026ae37e 100644 --- a/deps/amqp_client/test/direct_client_SUITE.erl +++ b/deps/amqp_client/test/direct_client_SUITE.erl @@ -103,8 +103,7 @@ channel_death_test() -> %%--------------------------------------------------------------------------- new_connection() -> - {ok, Pid} = amqp_connection:start(direct), - Pid. + amqp_connection:start_direct_link(). test_coverage() -> rabbit_misc:enable_cover(), diff --git a/deps/amqp_client/test/negative_test_util.erl b/deps/amqp_client/test/negative_test_util.erl index 175f87d2b4..6329129e5d 100644 --- a/deps/amqp_client/test/negative_test_util.erl +++ b/deps/amqp_client/test/negative_test_util.erl @@ -150,5 +150,5 @@ no_permission_test() -> assert_fail_start_with_params(Params) -> {error, {auth_failure_likely, _}} = - amqp_connection:start(network, Params), + amqp_connection:start_network_link(Params), ok. diff --git a/deps/amqp_client/test/network_client_SUITE.erl b/deps/amqp_client/test/network_client_SUITE.erl index 7227b006cb..ff152ddb22 100644 --- a/deps/amqp_client/test/network_client_SUITE.erl +++ b/deps/amqp_client/test/network_client_SUITE.erl @@ -131,13 +131,11 @@ shortstr_overflow_field_test() -> repeat(Fun, Times) -> [ Fun(new_connection()) || _ <- lists:seq(1, Times)]. -new_connection(Params) -> - {ok, Pid} = amqp_connection:start(network, Params), - Pid. - new_connection() -> - {ok, Pid} = amqp_connection:start(network), - Pid. + new_connection(#amqp_params{}). + +new_connection(Params) -> + amqp_connection:start_network_link(Params). test_coverage() -> rabbit_misc:enable_cover(), diff --git a/deps/amqp_client/test/ssl_client_SUITE.erl b/deps/amqp_client/test/ssl_client_SUITE.erl index d2df46f650..da18a7798e 100644 --- a/deps/amqp_client/test/ssl_client_SUITE.erl +++ b/deps/amqp_client/test/ssl_client_SUITE.erl @@ -87,7 +87,7 @@ new_connection() -> {keyfile, CertsDir ++ "/client/key.pem"}, {verify, verify_peer}, {fail_if_no_peer_cert, true}]}, - {ok, Pid} = amqp_connection:start_link(Params), + Pid = amqp_connection:start_network_link(Params), [{supervisor, Sup}] = amqp_connection:info(Pid, [supervisor]), unlink(Sup), Pid. From 955520a7ecbbcf90ddff1db28937128f17122557 Mon Sep 17 00:00:00 2001 From: Matthew Sackman Date: Mon, 6 Sep 2010 17:17:44 +0100 Subject: [PATCH 07/31] Turns out to be very important to support both start_link and start variants --- deps/amqp_client/src/amqp_connection.erl | 21 ++++++++++++++----- deps/amqp_client/test/direct_client_SUITE.erl | 6 ++++-- deps/amqp_client/test/negative_test_util.erl | 13 ++++++++---- .../amqp_client/test/network_client_SUITE.erl | 8 ++++--- deps/amqp_client/test/ssl_client_SUITE.erl | 6 ++++-- deps/amqp_client/test/test_util.erl | 2 +- 6 files changed, 39 insertions(+), 17 deletions(-) diff --git a/deps/amqp_client/src/amqp_connection.erl b/deps/amqp_client/src/amqp_connection.erl index c2ba123cc9..417b8e37b2 100755 --- a/deps/amqp_client/src/amqp_connection.erl +++ b/deps/amqp_client/src/amqp_connection.erl @@ -34,6 +34,7 @@ -export([open_channel/1, open_channel/2]). -export([start/1, start/2]). +-export([start_link/1, start_link/2]). -export([close/1, close/3]). -export([info/2, info_keys/1, info_keys/0]). @@ -77,6 +78,9 @@ start(Type) -> start(Type, #amqp_params{}). +start_link(Type) -> + start_link(Type, #amqp_params{}). + %% @spec (Type, amqp_params()) -> {ok, Connection} | {error, Error} %% where %% Type = network | direct @@ -86,12 +90,17 @@ start(Type) -> %% a RabbitMQ server, assuming that the server is running in the same process %% space. start(direct, AmqpParams) -> - start_internal(AmqpParams, amqp_direct_connection); + start_internal(AmqpParams, amqp_direct_connection, false); start(network, AmqpParams) -> - start_network_internal(AmqpParams). + start_network_internal(AmqpParams, false). -start_network_internal(#amqp_params{} = AmqpParams) -> - case start_internal(AmqpParams, amqp_network_connection) of +start_link(direct, AmqpParams) -> + start_internal(AmqpParams, amqp_direct_connection, true); +start_link(network, AmqpParams) -> + start_network_internal(AmqpParams, true). + +start_network_internal(#amqp_params{} = AmqpParams, Link) -> + case start_internal(AmqpParams, amqp_network_connection, Link) of {ok, Pid} -> {ok, Pid}; {error, {protocol_version_mismatch, _, _}} = Err -> @@ -100,7 +109,9 @@ start_network_internal(#amqp_params{} = AmqpParams) -> throw({error, {auth_failure_likely, Bad}}) end. -start_internal(Params, Module) when is_atom(Module) -> +start_internal(Params, Module, false) when is_atom(Module) -> + gen_server:start(Module, Params, []); +start_internal(Params, Module, true) when is_atom(Module) -> gen_server:start_link(Module, Params, []). %%--------------------------------------------------------------------------- diff --git a/deps/amqp_client/test/direct_client_SUITE.erl b/deps/amqp_client/test/direct_client_SUITE.erl index 302962c0ca..b59893dd98 100755 --- a/deps/amqp_client/test/direct_client_SUITE.erl +++ b/deps/amqp_client/test/direct_client_SUITE.erl @@ -103,8 +103,10 @@ channel_death_test() -> %%--------------------------------------------------------------------------- new_connection() -> - {ok, Conn} = amqp_connection:start(direct), - Conn. + case amqp_connection:start(direct) of + {ok, Conn} -> Conn; + Error -> Error + end. test_coverage() -> rabbit_misc:enable_cover(), diff --git a/deps/amqp_client/test/negative_test_util.erl b/deps/amqp_client/test/negative_test_util.erl index e4568e42d1..4df5bcb9ce 100755 --- a/deps/amqp_client/test/negative_test_util.erl +++ b/deps/amqp_client/test/negative_test_util.erl @@ -61,6 +61,7 @@ bogus_rpc_test(Connection) -> amqp_connection:close(Connection). hard_error_test(Connection) -> + unlink(Connection), Channel = amqp_connection:open_channel(Connection), Qos = #'basic.qos'{global = true}, try amqp_channel:call(Channel, Qos) of @@ -132,18 +133,22 @@ shortstr_overflow_field_test(Connection) -> non_existent_user_test() -> Params = #amqp_params{username = test_util:uuid(), password = test_util:uuid()}, - ?assertThrow({error, {auth_failure_likely, _}}, amqp_connection:start_network(Params)). + ?assertThrow({error, {auth_failure_likely, _}}, + network_client_SUITE:new_connection(Params)). invalid_password_test() -> Params = #amqp_params{username = <<"guest">>, password = test_util:uuid()}, - ?assertThrow({error, {auth_failure_likely, _}}, amqp_connection:start_network(Params)). + ?assertThrow({error, {auth_failure_likely, _}}, + network_client_SUITE:new_connection(Params)). non_existent_vhost_test() -> Params = #amqp_params{virtual_host = test_util:uuid()}, - ?assertThrow({error, {auth_failure_likely, _}}, amqp_connection:start_network(Params)). + ?assertThrow({error, {auth_failure_likely, _}}, + network_client_SUITE:new_connection(Params)). no_permission_test() -> Params = #amqp_params{username = <<"test_user_no_perm">>, password = <<"test_user_no_perm">>}, - ?assertThrow({error, {auth_failure_likely, _}}, amqp_connection:start_network(Params)). + ?assertThrow({error, {auth_failure_likely, _}}, + network_client_SUITE:new_connection(Params)). diff --git a/deps/amqp_client/test/network_client_SUITE.erl b/deps/amqp_client/test/network_client_SUITE.erl index e7f79f64cf..9dfd0df04a 100755 --- a/deps/amqp_client/test/network_client_SUITE.erl +++ b/deps/amqp_client/test/network_client_SUITE.erl @@ -25,7 +25,7 @@ -module(network_client_SUITE). --export([test_coverage/0]). +-export([test_coverage/0, new_connection/1]). -include("amqp_client.hrl"). -include_lib("eunit/include/eunit.hrl"). @@ -135,8 +135,10 @@ new_connection() -> new_connection(#amqp_params{}). new_connection(AmqpParams) -> - {ok, Conn} = amqp_connection:start(network, AmqpParams), - Conn. + case amqp_connection:start(network, AmqpParams) of + {ok, Conn} -> Conn; + Error -> Error + end. test_coverage() -> rabbit_misc:enable_cover(), diff --git a/deps/amqp_client/test/ssl_client_SUITE.erl b/deps/amqp_client/test/ssl_client_SUITE.erl index e293913be0..6eeefe692f 100755 --- a/deps/amqp_client/test/ssl_client_SUITE.erl +++ b/deps/amqp_client/test/ssl_client_SUITE.erl @@ -87,8 +87,10 @@ new_connection() -> {keyfile, CertsDir ++ "/client/key.pem"}, {verify, verify_peer}, {fail_if_no_peer_cert, true}]}, - {ok, Conn} = amqp_connection:start(network, Params), - Conn. + case amqp_connection:start(network, Params) of + {ok, Conn} -> Conn; + Error -> Error + end. test_coverage() -> rabbit_misc:enable_cover(), diff --git a/deps/amqp_client/test/test_util.erl b/deps/amqp_client/test/test_util.erl index aa9e358129..261f304db3 100755 --- a/deps/amqp_client/test/test_util.erl +++ b/deps/amqp_client/test/test_util.erl @@ -46,7 +46,7 @@ %% %% This is an example of how the client interaction should work %% -%% Connection = amqp_connection:start_network(), +%% Connection = amqp_connection:start(network), %% Channel = amqp_connection:open_channel(Connection), %% %%...do something useful %% amqp_channel:close(Channel), From 19c5eae78c5a725eb445b0f5d9ed22b90f03ebd5 Mon Sep 17 00:00:00 2001 From: Matthew Sackman Date: Mon, 6 Sep 2010 17:35:25 +0100 Subject: [PATCH 08/31] Support linked and unlinked versions in the supervisor branch too. Unfortunately, there's no supervisor:start, only supervisor:start_child. Luckily, all the children are dynamically started, thus we can unlink it after it's created and before it has any children added. However, I still can't get the negative_test_util:channel_writer_death_test test to pass --- deps/amqp_client/src/amqp_connection.erl | 30 ++++++++++++------- deps/amqp_client/src/amqp_connection_sup.erl | 8 +++-- deps/amqp_client/test/direct_client_SUITE.erl | 2 +- deps/amqp_client/test/negative_test_util.erl | 2 +- .../amqp_client/test/network_client_SUITE.erl | 4 +-- deps/amqp_client/test/ssl_client_SUITE.erl | 5 +--- 6 files changed, 31 insertions(+), 20 deletions(-) diff --git a/deps/amqp_client/src/amqp_connection.erl b/deps/amqp_client/src/amqp_connection.erl index 4cccf78050..f772805ddf 100644 --- a/deps/amqp_client/src/amqp_connection.erl +++ b/deps/amqp_client/src/amqp_connection.erl @@ -33,8 +33,8 @@ -include("amqp_client.hrl"). -export([open_channel/1, open_channel/2]). --export([start_direct_link/0, start_direct_link/1]). --export([start_network_link/0, start_network_link/1]). +-export([start_direct/0, start_direct/1, start_direct_link/0, start_direct_link/1]). +-export([start_network/0, start_network/1, start_network_link/0, start_network_link/1]). -export([close/1, close/3]). -export([info/2, info_keys/1, info_keys/0]). @@ -72,8 +72,11 @@ %% set of amqp_params. If a different vhost or credential set is required, %% start_direct_link/1 should be used. The resulting %% process is linked to the invoking process. +start_direct() -> + start(direct, #amqp_params{}, false). + start_direct_link() -> - start(direct, #amqp_params{}). + start(direct, #amqp_params{}, true). %% @spec (amqp_params()) -> Connection %% where @@ -81,8 +84,11 @@ start_direct_link() -> %% @doc Starts a direct connection to a RabbitMQ server, assuming that %% the server is running in the same process space. The resulting process %% is linked to the invoking process. +start_direct(Params) -> + start(direct, Params, false). + start_direct_link(Params) -> - start(direct, Params). + start(direct, Params, true). %% @spec () -> Connection %% where @@ -91,16 +97,22 @@ start_direct_link(Params) -> %% connection settings are used, meaning that the server is expected %% to be at localhost:5672, with a vhost of "/" authorising a user %% guest/guest. The resulting process is linked to the invoking process. +start_network() -> + start(network, #amqp_params{}, false). + start_network_link() -> - start(network, #amqp_params{}). + start(network, #amqp_params{}, true). %% @spec (amqp_params()) -> Connection %% where %% Connection = pid() %% @doc Starts a networked connection to a remote AMQP server. The resulting %% process is linked to the invoking process. +start_network(Params) -> + start(network, Params, false). + start_network_link(Params) -> - start(network, Params). + start(network, Params, true). %% @spec (Type, amqp_params()) -> {ok, Connection} | {error, Error} %% where @@ -110,10 +122,8 @@ start_network_link(Params) -> %% to a remote AMQP server or direct type for a direct connection to %% a RabbitMQ server, assuming that the server is running in the same process %% space. -start(Type, AmqpParams) -> - {ok, Sup} = amqp_connection_sup:start_link(Type, AmqpParams), - %% This unlink will disappear as part of bug 23003 - unlink(Sup), +start(Type, AmqpParams, Link) -> + {ok, Sup} = amqp_connection_sup:start_link(Type, AmqpParams, Link), [Connection] = supervisor2:find_child(Sup, connection), Module = case Type of direct -> amqp_direct_connection; network -> amqp_network_connection diff --git a/deps/amqp_client/src/amqp_connection_sup.erl b/deps/amqp_client/src/amqp_connection_sup.erl index 5ec4f6a526..f24b940323 100644 --- a/deps/amqp_client/src/amqp_connection_sup.erl +++ b/deps/amqp_client/src/amqp_connection_sup.erl @@ -29,15 +29,19 @@ -behaviour(supervisor2). --export([start_link/2]). +-export([start_link/3]). -export([init/1]). %%--------------------------------------------------------------------------- %% Interface %%--------------------------------------------------------------------------- -start_link(Type, AmqpParams) -> +start_link(Type, AmqpParams, Link) -> {ok, Sup} = supervisor2:start_link(?MODULE, []), + case Link of + true -> ok; + false -> unlink(Sup) + end, {ok, ChSupSup} = supervisor2:start_child(Sup, {channel_sup_sup, {amqp_channel_sup_sup, start_link, [Type]}, diff --git a/deps/amqp_client/test/direct_client_SUITE.erl b/deps/amqp_client/test/direct_client_SUITE.erl index 36026ae37e..0733cfa44c 100644 --- a/deps/amqp_client/test/direct_client_SUITE.erl +++ b/deps/amqp_client/test/direct_client_SUITE.erl @@ -103,7 +103,7 @@ channel_death_test() -> %%--------------------------------------------------------------------------- new_connection() -> - amqp_connection:start_direct_link(). + amqp_connection:start_direct(). test_coverage() -> rabbit_misc:enable_cover(), diff --git a/deps/amqp_client/test/negative_test_util.erl b/deps/amqp_client/test/negative_test_util.erl index 6329129e5d..ee4151d555 100644 --- a/deps/amqp_client/test/negative_test_util.erl +++ b/deps/amqp_client/test/negative_test_util.erl @@ -150,5 +150,5 @@ no_permission_test() -> assert_fail_start_with_params(Params) -> {error, {auth_failure_likely, _}} = - amqp_connection:start_network_link(Params), + network_client_SUITE:new_connection(Params), ok. diff --git a/deps/amqp_client/test/network_client_SUITE.erl b/deps/amqp_client/test/network_client_SUITE.erl index ff152ddb22..b6cc758a9a 100644 --- a/deps/amqp_client/test/network_client_SUITE.erl +++ b/deps/amqp_client/test/network_client_SUITE.erl @@ -25,7 +25,7 @@ -module(network_client_SUITE). --export([test_coverage/0]). +-export([test_coverage/0, new_connection/1]). -include("amqp_client.hrl"). -include_lib("eunit/include/eunit.hrl"). @@ -135,7 +135,7 @@ new_connection() -> new_connection(#amqp_params{}). new_connection(Params) -> - amqp_connection:start_network_link(Params). + amqp_connection:start_network(Params). test_coverage() -> rabbit_misc:enable_cover(), diff --git a/deps/amqp_client/test/ssl_client_SUITE.erl b/deps/amqp_client/test/ssl_client_SUITE.erl index da18a7798e..7a559a8682 100644 --- a/deps/amqp_client/test/ssl_client_SUITE.erl +++ b/deps/amqp_client/test/ssl_client_SUITE.erl @@ -87,10 +87,7 @@ new_connection() -> {keyfile, CertsDir ++ "/client/key.pem"}, {verify, verify_peer}, {fail_if_no_peer_cert, true}]}, - Pid = amqp_connection:start_network_link(Params), - [{supervisor, Sup}] = amqp_connection:info(Pid, [supervisor]), - unlink(Sup), - Pid. + amqp_connection:start_network(Params). test_coverage() -> rabbit_misc:enable_cover(), From 60dd766b0e0364c1a2c26a0fc8cdbc04672b850c Mon Sep 17 00:00:00 2001 From: Matthew Sackman Date: Tue, 7 Sep 2010 16:56:44 +0100 Subject: [PATCH 09/31] Be more robust in waiting for process termination --- deps/amqp_client/test/negative_test_util.erl | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/deps/amqp_client/test/negative_test_util.erl b/deps/amqp_client/test/negative_test_util.erl index ee4151d555..083b1575e9 100644 --- a/deps/amqp_client/test/negative_test_util.erl +++ b/deps/amqp_client/test/negative_test_util.erl @@ -80,9 +80,8 @@ channel_writer_death_test(Connection) -> Publish = #'basic.publish'{routing_key = <<>>, exchange = <<>>}, Message = #amqp_msg{props = <<>>, payload = <<>>}, ?assertExit(_, amqp_channel:call(Channel, Publish, Message)), - timer:sleep(300), - ?assertNot(is_process_alive(Channel)), - ?assertNot(is_process_alive(Connection)), + test_util:wait_for_death(Channel), + test_util:wait_for_death(Connection), ok. %% An error in the channel process should result in the death of the entire @@ -91,9 +90,8 @@ channel_writer_death_test(Connection) -> channel_death_test(Connection) -> Channel = amqp_connection:open_channel(Connection), ?assertExit(_, amqp_channel:call(Channel, bogus_message)), - timer:sleep(300), - ?assertNot(is_process_alive(Channel)), - ?assertNot(is_process_alive(Connection)), + test_util:wait_for_death(Channel), + test_util:wait_for_death(Connection), ok. %% Attempting to send a shortstr longer than 255 bytes in a property field @@ -108,9 +106,8 @@ shortstr_overflow_property_test(Connection) -> PBasic = #'P_basic'{content_type = SentString}, AmqpMsg = #amqp_msg{payload = Payload, props = PBasic}, ?assertExit(_, amqp_channel:call(Channel, Publish, AmqpMsg)), - timer:sleep(300), - ?assertNot(is_process_alive(Channel)), - ?assertNot(is_process_alive(Connection)), + test_util:wait_for_death(Channel), + test_util:wait_for_death(Connection), ok. %% Attempting to send a shortstr longer than 255 bytes in a method's field @@ -124,9 +121,8 @@ shortstr_overflow_field_test(Connection) -> Channel, #'basic.consume'{queue = Q, no_ack = true, consumer_tag = SentString}, self())), - timer:sleep(300), - ?assertNot(is_process_alive(Channel)), - ?assertNot(is_process_alive(Connection)), + test_util:wait_for_death(Channel), + test_util:wait_for_death(Connection), ok. non_existent_user_test() -> From 50091a9c951d3e422453dcf41927dc58a8853254 Mon Sep 17 00:00:00 2001 From: Vlad Alexandru Ionescu Date: Wed, 8 Sep 2010 14:41:27 +0100 Subject: [PATCH 10/31] removing connection:start_link; making open_channel return {ok, Pid} | {error, Error} --- deps/amqp_client/src/amqp_connection.erl | 32 +++--------- .../src/amqp_direct_connection.erl | 4 +- .../src/amqp_network_connection.erl | 4 +- deps/amqp_client/src/amqp_rpc_client.erl | 2 +- deps/amqp_client/src/amqp_rpc_server.erl | 2 +- deps/amqp_client/test/direct_client_SUITE.erl | 4 +- deps/amqp_client/test/negative_test_util.erl | 31 +++++------ .../amqp_client/test/network_client_SUITE.erl | 4 +- deps/amqp_client/test/ssl_client_SUITE.erl | 4 +- deps/amqp_client/test/test_util.erl | 52 +++++++++---------- 10 files changed, 62 insertions(+), 77 deletions(-) diff --git a/deps/amqp_client/src/amqp_connection.erl b/deps/amqp_client/src/amqp_connection.erl index 417b8e37b2..1852bb9972 100755 --- a/deps/amqp_client/src/amqp_connection.erl +++ b/deps/amqp_client/src/amqp_connection.erl @@ -34,7 +34,6 @@ -export([open_channel/1, open_channel/2]). -export([start/1, start/2]). --export([start_link/1, start_link/2]). -export([close/1, close/3]). -export([info/2, info_keys/1, info_keys/0]). @@ -78,9 +77,6 @@ start(Type) -> start(Type, #amqp_params{}). -start_link(Type) -> - start_link(Type, #amqp_params{}). - %% @spec (Type, amqp_params()) -> {ok, Connection} | {error, Error} %% where %% Type = network | direct @@ -89,31 +85,19 @@ start_link(Type) -> %% to a remote AMQP server or direct type for a direct connection to %% a RabbitMQ server, assuming that the server is running in the same process %% space. -start(direct, AmqpParams) -> - start_internal(AmqpParams, amqp_direct_connection, false); -start(network, AmqpParams) -> - start_network_internal(AmqpParams, false). - -start_link(direct, AmqpParams) -> - start_internal(AmqpParams, amqp_direct_connection, true); -start_link(network, AmqpParams) -> - start_network_internal(AmqpParams, true). - -start_network_internal(#amqp_params{} = AmqpParams, Link) -> - case start_internal(AmqpParams, amqp_network_connection, Link) of +start(Type, AmqpParams) -> + Module = case Type of network -> amqp_network_connection; + direct -> amqp_direct_connection + end, + case gen_server:start(Module, AmqpParams, []) of {ok, Pid} -> {ok, Pid}; {error, {protocol_version_mismatch, _, _}} = Err -> - throw(Err); + Err; Bad -> - throw({error, {auth_failure_likely, Bad}}) + {error, {auth_failure_likely, Bad}} end. -start_internal(Params, Module, false) when is_atom(Module) -> - gen_server:start(Module, Params, []); -start_internal(Params, Module, true) when is_atom(Module) -> - gen_server:start_link(Module, Params, []). - %%--------------------------------------------------------------------------- %% Commands %%--------------------------------------------------------------------------- @@ -123,7 +107,7 @@ start_internal(Params, Module, true) when is_atom(Module) -> open_channel(ConnectionPid) -> open_channel(ConnectionPid, none). -%% @spec (ConnectionPid, ChannelNumber) -> ChannelPid +%% @spec (ConnectionPid, ChannelNumber) -> {ok, ChannelPid} | {error, Error} %% where %% ChannelNumber = integer() %% ConnectionPid = pid() diff --git a/deps/amqp_client/src/amqp_direct_connection.erl b/deps/amqp_client/src/amqp_direct_connection.erl index fa51e6afa3..fecd2eb235 100755 --- a/deps/amqp_client/src/amqp_direct_connection.erl +++ b/deps/amqp_client/src/amqp_direct_connection.erl @@ -118,10 +118,10 @@ handle_command({open_channel, ProposedNumber}, _From, direct, {User, VHost, Collector}, Channels) of {ChannelPid, NewChannels} -> - {reply, ChannelPid, State#dc_state{channels = NewChannels}} + {reply, {ok, ChannelPid}, State#dc_state{channels = NewChannels}} catch error:out_of_channel_numbers = Error -> - {reply, {Error, ?MAX_CHANNEL_NUMBER}, State} + {reply, {error, {Error, ?MAX_CHANNEL_NUMBER}}, State} end; handle_command({close, Close}, From, State) -> diff --git a/deps/amqp_client/src/amqp_network_connection.erl b/deps/amqp_client/src/amqp_network_connection.erl index 2ec9484bbf..0f79b6c1b3 100755 --- a/deps/amqp_client/src/amqp_network_connection.erl +++ b/deps/amqp_client/src/amqp_network_connection.erl @@ -121,10 +121,10 @@ handle_command({open_channel, ProposedNumber}, _From, try amqp_channel_util:open_channel(ProposedNumber, MaxChannel, network, {Sock, MainReader}, Channels) of {ChannelPid, NewChannels} -> - {reply, ChannelPid, State#nc_state{channels = NewChannels}} + {reply, {ok, ChannelPid}, State#nc_state{channels = NewChannels}} catch error:out_of_channel_numbers = Error -> - {reply, {Error, MaxChannel}, State} + {reply, {error, {Error, MaxChannel}}, State} end; handle_command({close, #'connection.close'{} = Close}, From, State) -> diff --git a/deps/amqp_client/src/amqp_rpc_client.erl b/deps/amqp_client/src/amqp_rpc_client.erl index 4cf4eac2cf..e1560dab00 100755 --- a/deps/amqp_client/src/amqp_rpc_client.erl +++ b/deps/amqp_client/src/amqp_rpc_client.erl @@ -122,7 +122,7 @@ publish(Payload, From, %% Sets up a reply queue and consumer within an existing channel %% @private init([Connection, RoutingKey]) -> - Channel = amqp_connection:open_channel(Connection), + {ok, Channel} = amqp_connection:open_channel(Connection), InitialState = #rpc_c_state{channel = Channel, exchange = <<>>, routing_key = RoutingKey}, diff --git a/deps/amqp_client/src/amqp_rpc_server.erl b/deps/amqp_client/src/amqp_rpc_server.erl index d5656ad4d2..9d3bc0ab98 100755 --- a/deps/amqp_client/src/amqp_rpc_server.erl +++ b/deps/amqp_client/src/amqp_rpc_server.erl @@ -73,7 +73,7 @@ stop(Pid) -> %% @private init([Connection, Q, Fun]) -> - Channel = amqp_connection:open_channel(Connection), + {ok, Channel} = amqp_connection:open_channel(Connection), amqp_channel:call(Channel, #'queue.declare'{queue = Q}), amqp_channel:subscribe(Channel, #'basic.consume'{queue = Q}, self()), {ok, #rpc_s_state{channel = Channel, handler = Fun} }. diff --git a/deps/amqp_client/test/direct_client_SUITE.erl b/deps/amqp_client/test/direct_client_SUITE.erl index b59893dd98..434e404b26 100755 --- a/deps/amqp_client/test/direct_client_SUITE.erl +++ b/deps/amqp_client/test/direct_client_SUITE.erl @@ -104,8 +104,8 @@ channel_death_test() -> new_connection() -> case amqp_connection:start(direct) of - {ok, Conn} -> Conn; - Error -> Error + {ok, Conn} -> Conn; + {error, _} = Error -> Error end. test_coverage() -> diff --git a/deps/amqp_client/test/negative_test_util.erl b/deps/amqp_client/test/negative_test_util.erl index 4df5bcb9ce..5e2499eedd 100755 --- a/deps/amqp_client/test/negative_test_util.erl +++ b/deps/amqp_client/test/negative_test_util.erl @@ -33,7 +33,7 @@ non_existent_exchange_test(Connection) -> X = test_util:uuid(), RoutingKey = <<"a">>, Payload = <<"foobar">>, - Channel = amqp_connection:open_channel(Connection), + {ok, Channel} = amqp_connection:open_channel(Connection), amqp_channel:call(Channel, #'exchange.declare'{exchange = X}), %% Deliberately mix up the routingkey and exchange arguments Publish = #'basic.publish'{exchange = RoutingKey, routing_key = X}, @@ -46,7 +46,7 @@ bogus_rpc_test(Connection) -> X = test_util:uuid(), Q = test_util:uuid(), R = test_util:uuid(), - Channel = amqp_connection:open_channel(Connection), + {ok, Channel} = amqp_connection:open_channel(Connection), amqp_channel:call(Channel, #'exchange.declare'{exchange = X}), %% Deliberately bind to a non-existent queue Bind = #'queue.bind'{exchange = X, queue = Q, routing_key = R}, @@ -62,7 +62,7 @@ bogus_rpc_test(Connection) -> hard_error_test(Connection) -> unlink(Connection), - Channel = amqp_connection:open_channel(Connection), + {ok, Channel} = amqp_connection:open_channel(Connection), Qos = #'basic.qos'{global = true}, try amqp_channel:call(Channel, Qos) of _ -> exit(expected_to_exit) @@ -77,7 +77,7 @@ hard_error_test(Connection) -> %% The death of the channel is caused by an error in generating the frames %% (writer dies) - only in the network case channel_writer_death_test(Connection) -> - Channel = amqp_connection:open_channel(Connection), + {ok, Channel} = amqp_connection:open_channel(Connection), Publish = #'basic.publish'{routing_key = <<>>, exchange = <<>>}, Message = #amqp_msg{props = <<>>, payload = <<>>}, ok = amqp_channel:call(Channel, Publish, Message), @@ -90,7 +90,7 @@ channel_writer_death_test(Connection) -> %% connection. The death of the channel is caused by making a call with an %% invalid message to the channel process channel_death_test(Connection) -> - Channel = amqp_connection:open_channel(Connection), + {ok, Channel} = amqp_connection:open_channel(Connection), ?assertExit(_, amqp_channel:call(Channel, bogus_message)), timer:sleep(300), ?assertNot(is_process_alive(Channel)), @@ -100,7 +100,7 @@ channel_death_test(Connection) -> %% Attempting to send a shortstr longer than 255 bytes in a property field %% should fail - this only applies to the network case shortstr_overflow_property_test(Connection) -> - Channel = amqp_connection:open_channel(Connection), + {ok, Channel} = amqp_connection:open_channel(Connection), SentString = << <<"k">> || _ <- lists:seq(1, 340)>>, Q = test_util:uuid(), X = test_util:uuid(), Key = test_util:uuid(), Payload = <<"foobar">>, @@ -117,7 +117,7 @@ shortstr_overflow_property_test(Connection) -> %% Attempting to send a shortstr longer than 255 bytes in a method's field %% should fail - this only applies to the network case shortstr_overflow_field_test(Connection) -> - Channel = amqp_connection:open_channel(Connection), + {ok, Channel} = amqp_connection:open_channel(Connection), SentString = << <<"k">> || _ <- lists:seq(1, 340)>>, Q = test_util:uuid(), X = test_util:uuid(), Key = test_util:uuid(), test_util:setup_exchange(Channel, Q, X, Key), @@ -133,22 +133,23 @@ shortstr_overflow_field_test(Connection) -> non_existent_user_test() -> Params = #amqp_params{username = test_util:uuid(), password = test_util:uuid()}, - ?assertThrow({error, {auth_failure_likely, _}}, - network_client_SUITE:new_connection(Params)). + assert_fail_start_with_params(Params). invalid_password_test() -> Params = #amqp_params{username = <<"guest">>, password = test_util:uuid()}, - ?assertThrow({error, {auth_failure_likely, _}}, - network_client_SUITE:new_connection(Params)). + assert_fail_start_with_params(Params). non_existent_vhost_test() -> Params = #amqp_params{virtual_host = test_util:uuid()}, - ?assertThrow({error, {auth_failure_likely, _}}, - network_client_SUITE:new_connection(Params)). + assert_fail_start_with_params(Params). no_permission_test() -> Params = #amqp_params{username = <<"test_user_no_perm">>, password = <<"test_user_no_perm">>}, - ?assertThrow({error, {auth_failure_likely, _}}, - network_client_SUITE:new_connection(Params)). + assert_fail_start_with_params(Params). + +assert_fail_start_with_params(Params) -> + {error, {auth_failure_likely, _}} = + amqp_connection:start(network, Params), + ok. diff --git a/deps/amqp_client/test/network_client_SUITE.erl b/deps/amqp_client/test/network_client_SUITE.erl index 9dfd0df04a..9779ef5e4d 100755 --- a/deps/amqp_client/test/network_client_SUITE.erl +++ b/deps/amqp_client/test/network_client_SUITE.erl @@ -136,8 +136,8 @@ new_connection() -> new_connection(AmqpParams) -> case amqp_connection:start(network, AmqpParams) of - {ok, Conn} -> Conn; - Error -> Error + {ok, Conn} -> Conn; + {error, Error} = Error -> Error end. test_coverage() -> diff --git a/deps/amqp_client/test/ssl_client_SUITE.erl b/deps/amqp_client/test/ssl_client_SUITE.erl index 6eeefe692f..695775a304 100755 --- a/deps/amqp_client/test/ssl_client_SUITE.erl +++ b/deps/amqp_client/test/ssl_client_SUITE.erl @@ -88,8 +88,8 @@ new_connection() -> {verify, verify_peer}, {fail_if_no_peer_cert, true}]}, case amqp_connection:start(network, Params) of - {ok, Conn} -> Conn; - Error -> Error + {ok, Conn} -> Conn; + {error, _} = Error -> Error end. test_coverage() -> diff --git a/deps/amqp_client/test/test_util.erl b/deps/amqp_client/test/test_util.erl index 261f304db3..a8e2b75578 100755 --- a/deps/amqp_client/test/test_util.erl +++ b/deps/amqp_client/test/test_util.erl @@ -46,8 +46,8 @@ %% %% This is an example of how the client interaction should work %% -%% Connection = amqp_connection:start(network), -%% Channel = amqp_connection:open_channel(Connection), +%% {ok, Connection} = amqp_connection:start(network), +%% {ok, Channel} = amqp_connection:open_channel(Connection), %% %%...do something useful %% amqp_channel:close(Channel), %% amqp_connection:close(Connection). @@ -55,7 +55,7 @@ lifecycle_test(Connection) -> X = <<"x">>, - Channel = amqp_connection:open_channel(Connection), + {ok, Channel} = amqp_connection:open_channel(Connection), amqp_channel:call(Channel, #'exchange.declare'{exchange = X, type = <<"topic">>}), @@ -71,7 +71,7 @@ lifecycle_test(Connection) -> nowait_exchange_declare_test(Connection) -> X = <<"x">>, - Channel = amqp_connection:open_channel(Connection), + {ok, Channel} = amqp_connection:open_channel(Connection), ?assertEqual( ok, amqp_channel:call(Channel, @@ -99,16 +99,16 @@ queue_exchange_binding(Channel, X, Parent, Tag) -> Parent ! finished. channel_lifecycle_test(Connection) -> - Channel = amqp_connection:open_channel(Connection), + {ok, Channel} = amqp_connection:open_channel(Connection), amqp_channel:close(Channel), - Channel2 = amqp_connection:open_channel(Connection), + {ok, Channel2} = amqp_connection:open_channel(Connection), teardown(Connection, Channel2), ok. %% This is designed to exercize the internal queuing mechanism %% to ensure that commands are properly serialized command_serialization_test(Connection) -> - Channel = amqp_connection:open_channel(Connection), + {ok, Channel} = amqp_connection:open_channel(Connection), Parent = self(), [spawn(fun() -> Q = uuid(), @@ -121,7 +121,7 @@ command_serialization_test(Connection) -> teardown(Connection, Channel). recover_after_cancel_test(Connection) -> - Channel = amqp_connection:open_channel(Connection), + {ok, Channel} = amqp_connection:open_channel(Connection), {ok, Q} = setup_publish(Channel), amqp_channel:subscribe(Channel, #'basic.consume'{queue = Q}, self()), amqp_channel:register_default_consumer(Channel, self()), @@ -148,7 +148,7 @@ recover_after_cancel_test(Connection) -> queue_unbind_test(Connection) -> X = <<"eggs">>, Q = <<"foobar">>, Key = <<"quay">>, Payload = <<"foobar">>, - Channel = amqp_connection:open_channel(Connection), + {ok, Channel} = amqp_connection:open_channel(Connection), amqp_channel:call(Channel, #'exchange.declare'{exchange = X}), amqp_channel:call(Channel, #'queue.declare'{queue = Q}), Bind = #'queue.bind'{queue = Q, @@ -177,7 +177,7 @@ get_and_assert_equals(Channel, Q, Payload) -> ?assertMatch(Payload, Payload2). basic_get_test(Connection) -> - Channel = amqp_connection:open_channel(Connection), + {ok, Channel} = amqp_connection:open_channel(Connection), {ok, Q} = setup_publish(Channel), get_and_assert_equals(Channel, Q, <<"foobar">>), get_and_assert_empty(Channel, Q), @@ -188,7 +188,7 @@ basic_return_test(Connection) -> Q = uuid(), Key = uuid(), Payload = <<"qwerty">>, - Channel = amqp_connection:open_channel(Connection), + {ok, Channel} = amqp_connection:open_channel(Connection), amqp_channel:register_return_handler(Channel, self()), amqp_channel:call(Channel, #'exchange.declare'{exchange = X}), amqp_channel:call(Channel, #'queue.declare'{queue = Q}), @@ -212,7 +212,7 @@ basic_return_test(Connection) -> teardown(Connection, Channel). basic_ack_test(Connection) -> - Channel = amqp_connection:open_channel(Connection), + {ok, Channel} = amqp_connection:open_channel(Connection), {ok, Q} = setup_publish(Channel), {#'basic.get_ok'{delivery_tag = Tag}, _} = amqp_channel:call(Channel, #'basic.get'{queue = Q, no_ack = false}), @@ -220,7 +220,7 @@ basic_ack_test(Connection) -> teardown(Connection, Channel). basic_ack_call_test(Connection) -> - Channel = amqp_connection:open_channel(Connection), + {ok, Channel} = amqp_connection:open_channel(Connection), {ok, Q} = setup_publish(Channel), {#'basic.get_ok'{delivery_tag = Tag}, _} = amqp_channel:call(Channel, #'basic.get'{queue = Q, no_ack = false}), @@ -228,7 +228,7 @@ basic_ack_call_test(Connection) -> teardown(Connection, Channel). basic_consume_test(Connection) -> - Channel = amqp_connection:open_channel(Connection), + {ok, Channel} = amqp_connection:open_channel(Connection), X = uuid(), amqp_channel:call(Channel, #'exchange.declare'{exchange = X}), RoutingKey = uuid(), @@ -266,7 +266,7 @@ consume_loop(Channel, X, RoutingKey, Parent, Tag) -> Parent ! finished. basic_recover_test(Connection) -> - Channel = amqp_connection:open_channel(Connection), + {ok, Channel} = amqp_connection:open_channel(Connection), #'queue.declare_ok'{queue = Q} = amqp_channel:call(Channel, #'queue.declare'{}), #'basic.consume_ok'{consumer_tag = Tag} = @@ -309,12 +309,12 @@ basic_qos_test(Connection, Prefetch) -> Messages = 100, Workers = [5, 50], Parent = self(), - Chan = amqp_connection:open_channel(Connection), + {ok, Chan} = amqp_connection:open_channel(Connection), #'queue.declare_ok'{queue = Q} = amqp_channel:call(Chan, #'queue.declare'{}), Kids = [spawn( fun() -> - Channel = amqp_connection:open_channel(Connection), + {ok, Channel} = amqp_connection:open_channel(Connection), amqp_channel:call(Channel, #'basic.qos'{prefetch_count = Prefetch}), amqp_channel:subscribe(Channel, @@ -324,8 +324,8 @@ basic_qos_test(Connection, Prefetch) -> sleeping_consumer(Channel, Sleep, Parent) end) || Sleep <- Workers], latch_loop(length(Kids)), - spawn(fun() -> producer_loop(amqp_connection:open_channel(Connection), - Q, Messages) end), + spawn(fun() -> {ok, Ch} = amqp_connection:open_channel(Connection), + producer_loop(Ch, Q, Messages) end), {Res, ok} = timer:tc(erlang, apply, [fun latch_loop/1, [Messages]]), [Kid ! stop || Kid <- Kids], latch_loop(length(Kids)), @@ -372,7 +372,7 @@ basic_reject_test(Connection) -> amqp_connection:close(Connection). large_content_test(Connection) -> - Channel = amqp_connection:open_channel(Connection), + {ok, Channel} = amqp_connection:open_channel(Connection), #'queue.declare_ok'{queue = Q} = amqp_channel:call(Channel, #'queue.declare'{}), {A1,A2,A3} = now(), random:seed(A1, A2, A3), @@ -391,7 +391,7 @@ large_content_test(Connection) -> pub_and_close_test(Connection1, Connection2) -> X = uuid(), Q = uuid(), Key = uuid(), Payload = <<"eggs">>, NMessages = 50000, - Channel1 = amqp_connection:open_channel(Connection1), + {ok, Channel1} = amqp_connection:open_channel(Connection1), amqp_channel:call(Channel1, #'exchange.declare'{exchange = X}), amqp_channel:call(Channel1, #'queue.declare'{queue = Q}), Route = #'queue.bind'{queue = Q, @@ -403,7 +403,7 @@ pub_and_close_test(Connection1, Connection2) -> %% Close connection without closing channels amqp_connection:close(Connection1), %% Get sent messages back and count them - Channel2 = amqp_connection:open_channel(Connection2), + {ok, Channel2} = amqp_connection:open_channel(Connection2), amqp_channel:subscribe(Channel2, #'basic.consume'{queue = Q, no_ack = true}, self()), @@ -455,7 +455,7 @@ channel_flow_test(Connection) -> K = Payload = <<"x">>, memsup:set_sysmem_high_watermark(0.99), timer:sleep(1000), - Channel = amqp_connection:open_channel(Connection), + {ok, Channel} = amqp_connection:open_channel(Connection), Parent = self(), Child = spawn_link( fun() -> @@ -498,7 +498,7 @@ start_channel_flow(Connection, PublishFun) -> Key = uuid(), Producer = spawn_link( fun() -> - Channel = amqp_connection:open_channel(Connection), + {ok, Channel} = amqp_connection:open_channel(Connection), Parent = self(), FlowHandler = spawn_link(fun() -> cf_handler_loop(Parent) end), amqp_channel:register_flow_handler(Channel, FlowHandler), @@ -507,7 +507,7 @@ start_channel_flow(Connection, PublishFun) -> end), Consumer = spawn_link( fun() -> - Channel = amqp_connection:open_channel(Connection), + {ok, Channel} = amqp_connection:open_channel(Connection), #'queue.declare_ok'{queue = Q} = amqp_channel:call(Channel, #'queue.declare'{}), Bind = #'queue.bind'{queue = Q, @@ -616,7 +616,7 @@ teardown(Connection, Channel) -> wait_for_death(Connection). teardown_test(Connection) -> - Channel = amqp_connection:open_channel(Connection), + {ok, Channel} = amqp_connection:open_channel(Connection), ?assertMatch(true, is_process_alive(Channel)), ?assertMatch(true, is_process_alive(Connection)), teardown(Connection, Channel), From 75686bdf78682a31617e8e15bb9ef3bac01088e2 Mon Sep 17 00:00:00 2001 From: Vlad Alexandru Ionescu Date: Wed, 8 Sep 2010 16:39:24 +0100 Subject: [PATCH 11/31] renaming all state records in all modules to #state --- deps/amqp_client/src/amqp_channel.erl | 150 +++++++------- .../src/amqp_direct_connection.erl | 92 +++++---- deps/amqp_client/src/amqp_main_reader.erl | 30 ++- .../src/amqp_network_connection.erl | 187 +++++++++--------- deps/amqp_client/src/amqp_rpc_client.erl | 48 +++-- deps/amqp_client/src/amqp_rpc_server.erl | 10 +- 6 files changed, 255 insertions(+), 262 deletions(-) diff --git a/deps/amqp_client/src/amqp_channel.erl b/deps/amqp_client/src/amqp_channel.erl index e71ecf7ff6..65de697887 100755 --- a/deps/amqp_client/src/amqp_channel.erl +++ b/deps/amqp_client/src/amqp_channel.erl @@ -47,20 +47,20 @@ -define(TIMEOUT_FLUSH, 60000). -define(TIMEOUT_CLOSE_OK, 3000). --record(c_state, {number, - parent_connection, - reader_pid, - writer_pid, - driver, - rpc_requests = queue:new(), - anon_sub_requests = queue:new(), - tagged_sub_requests = dict:new(), - closing = false, - return_handler_pid = none, - flow_control = false, - flow_handler_pid = none, - consumers = dict:new(), - default_consumer = unknown}). +-record(state, {number, + parent_connection, + reader_pid, + writer_pid, + driver, + rpc_requests = queue:new(), + anon_sub_requests = queue:new(), + tagged_sub_requests = dict:new(), + closing = false, + return_handler_pid = none, + flow_control = false, + flow_handler_pid = none, + consumers = dict:new(), + default_consumer = unknown}). %% This diagram shows the interaction between the different component %% processes in an AMQP client scenario. @@ -235,16 +235,16 @@ register_default_consumer(Channel, Consumer) -> %%--------------------------------------------------------------------------- rpc_top_half(Method, Content, From, - State0 = #c_state{rpc_requests = RequestQueue}) -> + State0 = #state{rpc_requests = RequestQueue}) -> % Enqueue the incoming RPC request to serialize RPC dispatching - State1 = State0#c_state{ + State1 = State0#state{ rpc_requests = queue:in({From, Method, Content}, RequestQueue)}, IsFirstElement = queue:is_empty(RequestQueue), if IsFirstElement -> do_rpc(State1); true -> State1 end. -rpc_bottom_half(Reply, State = #c_state{rpc_requests = RequestQueue}) -> +rpc_bottom_half(Reply, State = #state{rpc_requests = RequestQueue}) -> case queue:out(RequestQueue) of {empty, _} -> exit(empty_rpc_bottom_half); @@ -252,15 +252,15 @@ rpc_bottom_half(Reply, State = #c_state{rpc_requests = RequestQueue}) -> case From of none -> ok; _ -> gen_server:reply(From, Reply) end, - do_rpc(State#c_state{rpc_requests = NewRequestQueue}) + do_rpc(State#state{rpc_requests = NewRequestQueue}) end. -do_rpc(State = #c_state{rpc_requests = RequestQueue, +do_rpc(State = #state{rpc_requests = RequestQueue, closing = Closing}) -> case queue:peek(RequestQueue) of {value, {_From, Method = #'channel.close'{}, Content}} -> do(Method, Content, State), - State#c_state{closing = just_channel}; + State#state{closing = just_channel}; {value, {_From, Method, Content}} -> do(Method, Content, State), State; @@ -276,14 +276,14 @@ do_rpc(State = #c_state{rpc_requests = RequestQueue, %% Internal plumbing %%--------------------------------------------------------------------------- -do(Method, Content, #c_state{writer_pid = Writer, - driver = Driver}) -> +do(Method, Content, #state{writer_pid = Writer, + driver = Driver}) -> amqp_channel_util:do(Driver, Writer, Method, Content). -resolve_consumer(_ConsumerTag, #c_state{consumers = []}) -> +resolve_consumer(_ConsumerTag, #state{consumers = []}) -> exit(no_consumers_registered); -resolve_consumer(ConsumerTag, #c_state{consumers = Consumers, - default_consumer = DefaultConsumer}) -> +resolve_consumer(ConsumerTag, #state{consumers = Consumers, + default_consumer = DefaultConsumer}) -> case dict:find(ConsumerTag, Consumers) of {ok, Value} -> Value; @@ -295,14 +295,14 @@ resolve_consumer(ConsumerTag, #c_state{consumers = Consumers, end. register_consumer(ConsumerTag, Consumer, - State = #c_state{consumers = Consumers0}) -> + State = #state{consumers = Consumers0}) -> Consumers1 = dict:store(ConsumerTag, Consumer, Consumers0), - State#c_state{consumers = Consumers1}. + State#state{consumers = Consumers1}. unregister_consumer(ConsumerTag, - State = #c_state{consumers = Consumers0}) -> + State = #state{consumers = Consumers0}) -> Consumers1 = dict:erase(ConsumerTag, Consumers0), - State#c_state{consumers = Consumers1}. + State#state{consumers = Consumers1}. amqp_msg(none) -> none; @@ -315,15 +315,15 @@ build_content(none) -> build_content(#amqp_msg{props = Props, payload = Payload}) -> rabbit_basic:build_content(Props, Payload). -check_block(_Method, _AmqpMsg, #c_state{closing = just_channel}) -> +check_block(_Method, _AmqpMsg, #state{closing = just_channel}) -> channel_closing; -check_block(_Method, _AmqpMsg, #c_state{closing = {connection, _}}) -> +check_block(_Method, _AmqpMsg, #state{closing = {connection, _}}) -> connection_closing; -check_block(_Method, none, #c_state{}) -> +check_block(_Method, none, #state{}) -> ok; -check_block(_Method, _AmqpMsg, #c_state{flow_control = true}) -> +check_block(_Method, _AmqpMsg, #state{flow_control = true}) -> blocked; -check_block(_Method, _AmqpMsg, #c_state{}) -> +check_block(_Method, _AmqpMsg, #state{}) -> ok. shutdown_with_reason({_, 200, _}, State) -> @@ -335,7 +335,7 @@ shutdown_with_reason(Reason, State) -> %% Handling of methods from the server %%--------------------------------------------------------------------------- -handle_method(Method, Content, #c_state{closing = Closing} = State) -> +handle_method(Method, Content, #state{closing = Closing} = State) -> case {Method, Content} of %% Handle 'channel.close': send 'channel.close_ok' and stop channel. %% Do this even if already closing, as per 0-9-1 spec. @@ -364,19 +364,19 @@ handle_method(Method, Content, #c_state{closing = Closing} = State) -> handle_regular_method( #'basic.consume_ok'{consumer_tag = ConsumerTag} = ConsumeOk, none, - #c_state{tagged_sub_requests = Tagged, - anon_sub_requests = Anon} = State) -> + #state{tagged_sub_requests = Tagged, + anon_sub_requests = Anon} = State) -> {_From, Consumer, State0} = case dict:find(ConsumerTag, Tagged) of {ok, {F, C}} -> NewTagged = dict:erase(ConsumerTag,Tagged), - {F, C, State#c_state{tagged_sub_requests = NewTagged}}; + {F, C, State#state{tagged_sub_requests = NewTagged}}; error -> case queue:out(Anon) of {empty, _} -> exit({anonymous_queue_empty, ConsumerTag}); {{value, {F, C}}, NewAnon} -> - {F, C, State#c_state{anon_sub_requests = NewAnon}} + {F, C, State#state{anon_sub_requests = NewAnon}} end end, Consumer ! ConsumeOk, @@ -385,7 +385,7 @@ handle_regular_method( handle_regular_method( #'basic.cancel_ok'{consumer_tag = ConsumerTag} = CancelOk, none, - #c_state{} = State) -> + #state{} = State) -> Consumer = resolve_consumer(ConsumerTag, State), Consumer ! CancelOk, NewState = unregister_consumer(ConsumerTag, State), @@ -395,13 +395,13 @@ handle_regular_method( %% If flow_control flag is defined, it informs the flow control handler to %% suspend submitting any content bearing methods handle_regular_method(#'channel.flow'{active = Active} = Flow, none, - #c_state{flow_handler_pid = FlowHandler} = State) -> + #state{flow_handler_pid = FlowHandler} = State) -> case FlowHandler of none -> ok; _ -> FlowHandler ! Flow end, do(#'channel.flow_ok'{active = Active}, none, State), - {noreply, State#c_state{flow_control = not(Active)}}; + {noreply, State#state{flow_control = not(Active)}}; handle_regular_method(#'basic.deliver'{consumer_tag = ConsumerTag} = Deliver, AmqpMsg, State) -> @@ -411,7 +411,7 @@ handle_regular_method(#'basic.deliver'{consumer_tag = ConsumerTag} = Deliver, handle_regular_method( #'basic.return'{} = BasicReturn, AmqpMsg, - #c_state{return_handler_pid = ReturnHandler} = State) -> + #state{return_handler_pid = ReturnHandler} = State) -> case ReturnHandler of none -> ?LOG_WARN("Channel (~p): received {~p, ~p} but there is no " "return handler registered~n", @@ -436,11 +436,11 @@ init({ParentConnection, ChannelNumber, Driver, StartArgs}) -> {ReaderPid, WriterPid} = amqp_channel_util:start_channel_infrastructure(Driver, ChannelNumber, StartArgs), - InitialState = #c_state{parent_connection = ParentConnection, - number = ChannelNumber, - driver = Driver, - reader_pid = ReaderPid, - writer_pid = WriterPid}, + InitialState = #state{parent_connection = ParentConnection, + number = ChannelNumber, + driver = Driver, + reader_pid = ReaderPid, + writer_pid = WriterPid}, {ok, InitialState}. %% Standard implementation of the call/{2,3} command @@ -463,7 +463,7 @@ handle_call({call, Method, AmqpMsg}, From, State) -> %% Standard implementation of the subscribe/3 command %% @private handle_call({subscribe, #'basic.consume'{consumer_tag = Tag} = Method, Consumer}, - From, #c_state{tagged_sub_requests = Tagged, + From, #state{tagged_sub_requests = Tagged, anon_sub_requests = Anon} = State) -> case check_block(Method, none, State) of ok -> @@ -471,14 +471,14 @@ handle_call({subscribe, #'basic.consume'{consumer_tag = Tag} = Method, Consumer} if Tag =:= undefined orelse size(Tag) == 0 -> NewAnon = queue:in({From,Consumer}, Anon), {Method#'basic.consume'{consumer_tag = <<"">>}, - State#c_state{anon_sub_requests = NewAnon}}; + State#state{anon_sub_requests = NewAnon}}; is_binary(Tag) -> %% TODO test whether this tag already exists, either in %% the pending tagged request map or in general as %% already subscribed consumer NewTagged = dict:store(Tag,{From,Consumer}, Tagged), {Method, - State#c_state{tagged_sub_requests = NewTagged}} + State#state{tagged_sub_requests = NewTagged}} end, {noreply, rpc_top_half(NewMethod, none, From, NewState)}; BlockReply -> @@ -514,19 +514,19 @@ handle_cast({cast, Method, AmqpMsg} = Cast, State) -> %% @private handle_cast({register_return_handler, ReturnHandler}, State) -> link(ReturnHandler), - {noreply, State#c_state{return_handler_pid = ReturnHandler}}; + {noreply, State#state{return_handler_pid = ReturnHandler}}; %% Registers a handler to process flow control messages %% @private handle_cast({register_flow_handler, FlowHandler}, State) -> link(FlowHandler), - {noreply, State#c_state{flow_handler_pid = FlowHandler}}; + {noreply, State#state{flow_handler_pid = FlowHandler}}; %% Registers a handler to process unexpected deliveries %% @private handle_cast({register_default_consumer, Consumer}, State) -> link(Consumer), - {noreply, State#c_state{default_consumer = Consumer}}; + {noreply, State#state{default_consumer = Consumer}}; %% @private handle_cast({notify_sent, _Peer}, State) -> @@ -564,7 +564,7 @@ handle_info({shutdown, Reason}, State) -> %% @private handle_info({shutdown, FailShutdownReason, InitialReason}, - #c_state{number = Number} = State) -> + #state{number = Number} = State) -> case FailShutdownReason of {connection_closing, timed_out_flushing_channel} -> ?LOG_WARN("Channel ~p closing: timed out flushing while connection " @@ -580,15 +580,15 @@ handle_info({shutdown, FailShutdownReason, InitialReason}, %% flush the RPC queue (optional), and terminate %% @private handle_info({connection_closing, CloseType, Reason}, - #c_state{rpc_requests = RpcQueue, - closing = Closing} = State) -> + #state{rpc_requests = RpcQueue, + closing = Closing} = State) -> case {CloseType, Closing, queue:is_empty(RpcQueue)} of {flush, false, false} -> erlang:send_after(?TIMEOUT_FLUSH, self(), {shutdown, {connection_closing, timed_out_flushing_channel}, Reason}), - {noreply, State#c_state{closing = {connection, Reason}}}; + {noreply, State#state{closing = {connection, Reason}}}; {flush, just_channel, false} -> erlang:send_after(?TIMEOUT_CLOSE_OK, self(), {shutdown, @@ -604,7 +604,7 @@ handle_info({connection_closing, CloseType, Reason}, %% @private handle_info({channel_exit, _Channel, #amqp_error{name = ErrorName, explanation = Expl} = Error}, - State = #c_state{number = Number}) -> + State = #state{number = Number}) -> ?LOG_WARN("Channel ~p closing: server sent error ~p~n", [Number, Error]), {_, Code, _} = ?PROTOCOL:lookup_amqp_exception(ErrorName), {stop, {server_initiated_close, Code, Expl}, State}; @@ -616,8 +616,8 @@ handle_info({channel_exit, _Channel, #amqp_error{name = ErrorName, %% Handle parent connection exit %% @private handle_info({'EXIT', ConnectionPid, Reason}, - State = #c_state{number = ChannelNumber, - parent_connection = ConnectionPid}) -> + State = #state{number = ChannelNumber, + parent_connection = ConnectionPid}) -> ?LOG_WARN("Channel ~p closing: parent connection died. Reason: ~p~n", [ChannelNumber, Reason]), {stop, {parent_connection_died, ConnectionPid, Reason}, State}; @@ -625,8 +625,8 @@ handle_info({'EXIT', ConnectionPid, Reason}, %% Handle writer exit %% @private handle_info({'EXIT', WriterPid, Reason}, - State = #c_state{number = ChannelNumber, - writer_pid = WriterPid}) -> + State = #state{number = ChannelNumber, + writer_pid = WriterPid}) -> ?LOG_WARN("Channel ~p closing: received exit signal from writer. " "Reason: ~p~n", [ChannelNumber, Reason]), {stop, {writer_died, WriterPid, Reason}, State}; @@ -634,8 +634,8 @@ handle_info({'EXIT', WriterPid, Reason}, %% Handle reader exit %% @private handle_info({'EXIT', ReaderPid, Reason}, - State = #c_state{number = ChannelNumber, - reader_pid = ReaderPid}) -> + State = #state{number = ChannelNumber, + reader_pid = ReaderPid}) -> ?LOG_WARN("Channel ~p closing: received exit signal from reader. " "Reason: ~p~n", [ChannelNumber, Reason]), {stop, {reader_died, ReaderPid, Reason}, State}; @@ -643,24 +643,24 @@ handle_info({'EXIT', ReaderPid, Reason}, %% Handle flow handler exit %% @private handle_info({'EXIT', FlowHandler, Reason}, - State = #c_state{number = ChannelNumber, - flow_handler_pid = FlowHandler}) -> + State = #state{number = ChannelNumber, + flow_handler_pid = FlowHandler}) -> ?LOG_INFO("Channel ~p: unregistering flow handler because it is " "closing: ~p~n", [ChannelNumber, Reason]), - {noreply, State#c_state{flow_handler_pid = none}}; + {noreply, State#state{flow_handler_pid = none}}; %% Handle return handler exit %% @private handle_info({'EXIT', ReturnHandler, Reason}, - State = #c_state{number = ChannelNumber, - return_handler_pid = ReturnHandler}) -> + State = #state{number = ChannelNumber, + return_handler_pid = ReturnHandler}) -> ?LOG_INFO("Channel ~p: unregistering return handler because it is " "closing: ~p~n", [ChannelNumber, Reason]), - {noreply, State#c_state{return_handler_pid = none}}; + {noreply, State#state{return_handler_pid = none}}; %% Handle other exit %% @private -handle_info({'EXIT', Pid, Reason}, State = #c_state{number = ChannelNumber}) -> +handle_info({'EXIT', Pid, Reason}, State = #state{number = ChannelNumber}) -> ?LOG_WARN("Channel ~p closing: received unexpected exit signal from (~p). " "Reason: ~p~n", [ChannelNumber, Pid, Reason]), {stop, {unexpected_exit_signal, Pid, Reason}, State}. @@ -670,9 +670,9 @@ handle_info({'EXIT', Pid, Reason}, State = #c_state{number = ChannelNumber}) -> %%--------------------------------------------------------------------------- %% @private -terminate(_Reason, #c_state{driver = Driver, - reader_pid = ReaderPid, - writer_pid = WriterPid}) -> +terminate(_Reason, #state{driver = Driver, + reader_pid = ReaderPid, + writer_pid = WriterPid}) -> amqp_channel_util:terminate_channel_infrastructure( Driver, {ReaderPid, WriterPid}). diff --git a/deps/amqp_client/src/amqp_direct_connection.erl b/deps/amqp_client/src/amqp_direct_connection.erl index fa51e6afa3..3d947c82ab 100755 --- a/deps/amqp_client/src/amqp_direct_connection.erl +++ b/deps/amqp_client/src/amqp_direct_connection.erl @@ -32,16 +32,16 @@ -export([init/1, terminate/2, code_change/3, handle_call/3, handle_cast/2, handle_info/2]). --record(dc_state, {params = #amqp_params{}, - closing = false, - server_properties, - channels = amqp_channel_util:new_channel_dict(), - queue_collector = none}). +-record(state, {params = #amqp_params{}, + closing = false, + server_properties, + channels = amqp_channel_util:new_channel_dict(), + queue_collector = none}). --record(dc_closing, {reason, - close = none, %% At least one of close and reply has to be - reply = none, %% none at any given moment - from = none}). +-record(closing, {reason, + close = none, %% At least one of close and reply has to be + reply = none, %% none at any given moment + from = none}). -define(INFO_KEYS, (amqp_connection:info_keys() ++ [])). @@ -64,12 +64,12 @@ init(AmqpParams = #amqp_params{username = User, VHost), {ok, Collector} = rabbit_queue_collector:start_link(), ServerProperties = rabbit_reader:server_properties(), - {ok, #dc_state{params = AmqpParams, - queue_collector = Collector, - server_properties = ServerProperties}}. + {ok, #state{params = AmqpParams, + queue_collector = Collector, + server_properties = ServerProperties}}. %% Standard handling of an app initiated command -handle_call({command, Command}, From, #dc_state{closing = Closing} = State) -> +handle_call({command, Command}, From, #state{closing = Closing} = State) -> case Closing of false -> handle_command(Command, From, State); _ -> {reply, closing, State} @@ -109,23 +109,23 @@ code_change(_OldVsn, State, _Extra) -> %%--------------------------------------------------------------------------- handle_command({open_channel, ProposedNumber}, _From, - State = #dc_state{params = #amqp_params{username = User, - virtual_host = VHost}, - channels = Channels, - queue_collector = Collector}) -> + State = #state{params = #amqp_params{username = User, + virtual_host = VHost}, + channels = Channels, + queue_collector = Collector}) -> try amqp_channel_util:open_channel(ProposedNumber, ?MAX_CHANNEL_NUMBER, direct, {User, VHost, Collector}, Channels) of {ChannelPid, NewChannels} -> - {reply, ChannelPid, State#dc_state{channels = NewChannels}} + {reply, ChannelPid, State#state{channels = NewChannels}} catch error:out_of_channel_numbers = Error -> {reply, {Error, ?MAX_CHANNEL_NUMBER}, State} end; handle_command({close, Close}, From, State) -> - {noreply, set_closing_state(flush, #dc_closing{reason = app_initiated_close, + {noreply, set_closing_state(flush, #closing{reason = app_initiated_close, close = Close, from = From}, State)}. @@ -134,11 +134,11 @@ handle_command({close, Close}, From, State) -> %% Infos %%--------------------------------------------------------------------------- -i(server_properties, State) -> State#dc_state.server_properties; -i(is_closing, State) -> State#dc_state.closing =/= false; -i(amqp_params, State) -> State#dc_state.params; +i(server_properties, State) -> State#state.server_properties; +i(is_closing, State) -> State#state.closing =/= false; +i(amqp_params, State) -> State#state.params; i(num_channels, State) -> amqp_channel_util:num_channels( - State#dc_state.channels); + State#state.channels); i(Item, _State) -> throw({bad_argument, Item}). %%--------------------------------------------------------------------------- @@ -155,16 +155,15 @@ i(Item, _State) -> throw({bad_argument, Item}). %% mentioned in the above list). We can rely on erlang's comparison of atoms %% for this. set_closing_state(ChannelCloseType, Closing, - #dc_state{closing = false, + #state{closing = false, channels = Channels} = State) -> amqp_channel_util:broadcast_to_channels( {connection_closing, ChannelCloseType, closing_to_reason(Closing)}, Channels), - check_trigger_all_channels_closed_event(State#dc_state{closing = Closing}); + check_trigger_all_channels_closed_event(State#state{closing = Closing}); %% Already closing, override situation set_closing_state(ChannelCloseType, NewClosing, - #dc_state{closing = CurClosing, - channels = Channels} = State) -> + #state{closing = CurClosing, channels = Channels} = State) -> %% Do not override reason in channels (because it might cause channels to %% to exit with different reasons) but do cause them to close abruptly %% if the new closing type requires it @@ -179,55 +178,54 @@ set_closing_state(ChannelCloseType, NewClosing, ResClosing = if %% Override (rely on erlang's comparison of atoms) - NewClosing#dc_closing.reason >= CurClosing#dc_closing.reason -> + NewClosing#closing.reason >= CurClosing#closing.reason -> NewClosing; %% Do not override true -> CurClosing end, - State#dc_state{closing = ResClosing}. + State#state{closing = ResClosing}. %% The all_channels_closed_event is called when all channels have been closed %% after the connection broadcasts a connection_closing message to all channels -all_channels_closed_event(#dc_state{closing = Closing, - queue_collector = Collector} = State) -> +all_channels_closed_event(#state{closing = Closing, + queue_collector = Collector} = State) -> rabbit_queue_collector:delete_all(Collector), rabbit_queue_collector:shutdown(Collector), rabbit_misc:unlink_and_capture_exit(Collector), - case Closing#dc_closing.from of + case Closing#closing.from of none -> ok; From -> gen_server:reply(From, ok) end, self() ! {shutdown, closing_to_reason(Closing)}, State. -closing_to_reason(#dc_closing{reason = Reason, - close = #'connection.close'{reply_code = Code, - reply_text = Text}, - reply = none}) -> +closing_to_reason(#closing{reason = Reason, + close = #'connection.close'{reply_code = Code, + reply_text = Text}, + reply = none}) -> {Reason, Code, Text}; -closing_to_reason(#dc_closing{reason = Reason, - reply = {_, Code, Text}, - close = none}) -> +closing_to_reason(#closing{reason = Reason, + reply = {_, Code, Text}, + close = none}) -> {Reason, Code, Text}. internal_error_closing() -> - #dc_closing{reason = internal_error, - reply = {internal_error, ?INTERNAL_ERROR, <<>>}}. + #closing{reason = internal_error, + reply = {internal_error, ?INTERNAL_ERROR, <<>>}}. %%--------------------------------------------------------------------------- %% Channel utilities %%--------------------------------------------------------------------------- -unregister_channel(Pid, State = #dc_state{channels = Channels}) -> +unregister_channel(Pid, State = #state{channels = Channels}) -> NewChannels = amqp_channel_util:unregister_channel_pid(Pid, Channels), - NewState = State#dc_state{channels = NewChannels}, + NewState = State#state{channels = NewChannels}, check_trigger_all_channels_closed_event(NewState). -check_trigger_all_channels_closed_event(#dc_state{closing = false} = State) -> +check_trigger_all_channels_closed_event(#state{closing = false} = State) -> State; -check_trigger_all_channels_closed_event( - #dc_state{channels = Channels} = State) -> +check_trigger_all_channels_closed_event(#state{channels = Channels} = State) -> case amqp_channel_util:is_channel_dict_empty(Channels) of true -> all_channels_closed_event(State); false -> State @@ -239,7 +237,7 @@ check_trigger_all_channels_closed_event( %% Standard handling of exit signals handle_exit(Pid, Reason, - #dc_state{channels = Channels, closing = Closing} = State) -> + #state{channels = Channels, closing = Closing} = State) -> case amqp_channel_util:handle_exit(Pid, Reason, Channels, Closing) of stop -> {stop, Reason, State}; normal -> {noreply, unregister_channel(Pid, State)}; diff --git a/deps/amqp_client/src/amqp_main_reader.erl b/deps/amqp_client/src/amqp_main_reader.erl index f6630bd88a..5cfc501885 100755 --- a/deps/amqp_client/src/amqp_main_reader.erl +++ b/deps/amqp_client/src/amqp_main_reader.erl @@ -33,9 +33,9 @@ -export([init/1, terminate/2, code_change/3, handle_call/3, handle_cast/2, handle_info/2]). --record(mr_state, {sock, - message = none, %% none | {Type, Channel, Length} - framing_channels = amqp_channel_util:new_channel_dict()}). +-record(state, {sock, + message = none, %% none | {Type, Channel, Length} + framing_channels = amqp_channel_util:new_channel_dict()}). %%--------------------------------------------------------------------------- %% Interface @@ -56,12 +56,12 @@ start_heartbeat(MainReaderPid, Heartbeat) -> %%--------------------------------------------------------------------------- init([Sock, Framing0Pid]) -> - State0 = #mr_state{sock = Sock}, + State0 = #state{sock = Sock}, State1 = internal_register_framing_channel(0, Framing0Pid, State0), {ok, _Ref} = rabbit_net:async_recv(Sock, 7, infinity), {ok, State1}. -terminate(Reason, #mr_state{sock = Sock}) -> +terminate(Reason, #state{sock = Sock}) -> Nice = case Reason of normal -> true; shutdown -> true; @@ -79,7 +79,7 @@ code_change(_OldVsn, State, _Extra) -> handle_call({register_framing_channel, Number, Pid}, _From, State) -> {reply, ok, internal_register_framing_channel(Number, Pid, State)}. -handle_cast({heartbeat, Heartbeat}, State = #mr_state{sock = Sock}) -> +handle_cast({heartbeat, Heartbeat}, State = #state{sock = Sock}) -> rabbit_heartbeat:start_heartbeat(Sock, Heartbeat), {noreply, State}. @@ -99,8 +99,7 @@ handle_info(close, State) -> %%--------------------------------------------------------------------------- handle_inet_async({inet_async, Sock, _, Msg}, - State = #mr_state{sock = Sock, - message = CurMessage}) -> + State = #state{sock = Sock, message = CurMessage}) -> {Type, Channel, Length} = case CurMessage of {T, C, L} -> {T, C, L}; none -> {none, none, none} @@ -111,11 +110,11 @@ handle_inet_async({inet_async, Sock, _, Msg}, closed_ok -> {stop, normal, State}; _ -> {ok, _Ref} = rabbit_net:async_recv(Sock, 7, infinity), - {noreply, State#mr_state{message = none}} + {noreply, State#state{message = none}} end; {ok, <>} -> {ok, _Ref} = rabbit_net:async_recv(Sock, NewLength + 1, infinity), - {noreply, State#mr_state{message={NewType, NewChannel, NewLength}}}; + {noreply, State#state{message={NewType, NewChannel, NewLength}}}; {error, closed} -> {stop, socket_closed, State}; {error, Reason} -> @@ -140,7 +139,7 @@ handle_frame(Type, Channel, Payload, State) -> pass_frame(Channel, AnalyzedFrame, State) end. -pass_frame(Channel, Frame, #mr_state{framing_channels = Channels}) -> +pass_frame(Channel, Frame, #state{framing_channels = Channels}) -> case amqp_channel_util:resolve_channel_number(Channel, Channels) of undefined -> ?LOG_INFO("Dropping frame ~p for invalid or closed channel " @@ -151,19 +150,18 @@ pass_frame(Channel, Frame, #mr_state{framing_channels = Channels}) -> end. handle_down({'DOWN', _MonitorRef, process, Pid, Info}, - State = #mr_state{framing_channels = Channels}) -> + State = #state{framing_channels = Channels}) -> case amqp_channel_util:is_channel_pid_registered(Pid, Channels) of true -> NewChannels = amqp_channel_util:unregister_channel_pid(Pid, Channels), - {noreply, State#mr_state{framing_channels = NewChannels}}; + {noreply, State#state{framing_channels = NewChannels}}; false -> {stop, {unexpected_down, Pid, Info}, State} end. internal_register_framing_channel( - Number, Pid, State = #mr_state{framing_channels = Channels}) -> + Number, Pid, State = #state{framing_channels = Channels}) -> NewChannels = amqp_channel_util:register_channel(Number, Pid, Channels), erlang:monitor(process, Pid), - State#mr_state{framing_channels = NewChannels}. - + State#state{framing_channels = NewChannels}. diff --git a/deps/amqp_client/src/amqp_network_connection.erl b/deps/amqp_client/src/amqp_network_connection.erl index 2ec9484bbf..e83dc31592 100755 --- a/deps/amqp_client/src/amqp_network_connection.erl +++ b/deps/amqp_client/src/amqp_network_connection.erl @@ -37,21 +37,21 @@ -define(CLIENT_CLOSE_TIMEOUT, 60000). -define(HANDSHAKE_RECEIVE_TIMEOUT, 60000). --record(nc_state, {params = #amqp_params{}, - sock, - main_reader_pid, - channel0_writer_pid, - channel0_framing_pid, - max_channel, - heartbeat, - closing = false, - server_properties, - channels = amqp_channel_util:new_channel_dict()}). +-record(state, {params = #amqp_params{}, + sock, + main_reader_pid, + channel0_writer_pid, + channel0_framing_pid, + max_channel, + heartbeat, + closing = false, + server_properties, + channels = amqp_channel_util:new_channel_dict()}). --record(nc_closing, {reason, - close, - from = none, - phase = terminate_channels}). +-record(closing, {reason, + close, + from = none, + phase = terminate_channels}). -define(INFO_KEYS, (amqp_connection:info_keys() ++ [max_channel, heartbeat, sock])). @@ -62,11 +62,11 @@ init(AmqpParams) -> process_flag(trap_exit, true), - State0 = handshake(#nc_state{params = AmqpParams}), + State0 = handshake(#state{params = AmqpParams}), {ok, State0}. %% Standard handling of an app initiated command -handle_call({command, Command}, From, #nc_state{closing = Closing} = State) -> +handle_call({command, Command}, From, #state{closing = Closing} = State) -> case Closing of false -> handle_command(Command, From, State); _ -> {reply, closing, State} @@ -86,7 +86,7 @@ handle_cast({method, Method, Content}, State) -> %% This is received after we have sent 'connection.close' to the server %% but timed out waiting for 'connection.close_ok' back handle_info(timeout_waiting_for_close_ok = Msg, - State = #nc_state{closing = Closing}) -> + State = #state{closing = Closing}) -> ?LOG_WARN("Connection ~p closing: timed out waiting for" "'connection.close_ok'.", [self()]), {stop, {Msg, closing_to_reason(Closing)}, State}; @@ -95,9 +95,9 @@ handle_info(timeout_waiting_for_close_ok = Msg, handle_info({'EXIT', Pid, Reason}, State) -> handle_exit(Pid, Reason, State). -terminate(_Reason, #nc_state{channel0_framing_pid = Framing0Pid, - channel0_writer_pid = Writer0Pid, - main_reader_pid = MainReaderPid}) -> +terminate(_Reason, #state{channel0_framing_pid = Framing0Pid, + channel0_writer_pid = Writer0Pid, + main_reader_pid = MainReaderPid}) -> ok = amqp_channel_util:terminate_channel_infrastructure( network, {Framing0Pid, Writer0Pid}), case MainReaderPid of @@ -114,23 +114,23 @@ code_change(_OldVsn, State, _Extra) -> %%--------------------------------------------------------------------------- handle_command({open_channel, ProposedNumber}, _From, - State = #nc_state{sock = Sock, - main_reader_pid = MainReader, - channels = Channels, - max_channel = MaxChannel}) -> + State = #state{sock = Sock, + main_reader_pid = MainReader, + channels = Channels, + max_channel = MaxChannel}) -> try amqp_channel_util:open_channel(ProposedNumber, MaxChannel, network, {Sock, MainReader}, Channels) of {ChannelPid, NewChannels} -> - {reply, ChannelPid, State#nc_state{channels = NewChannels}} + {reply, ChannelPid, State#state{channels = NewChannels}} catch error:out_of_channel_numbers = Error -> {reply, {Error, MaxChannel}, State} end; handle_command({close, #'connection.close'{} = Close}, From, State) -> - {noreply, set_closing_state(flush, #nc_closing{reason = app_initiated_close, - close = Close, - from = From}, + {noreply, set_closing_state(flush, #closing{reason = app_initiated_close, + close = Close, + from = From}, State)}. %%--------------------------------------------------------------------------- @@ -139,14 +139,14 @@ handle_command({close, #'connection.close'{} = Close}, From, State) -> handle_method(#'connection.close'{} = Close, none, State) -> {noreply, set_closing_state(abrupt, - #nc_closing{reason = server_initiated_close, + #closing{reason = server_initiated_close, close = Close}, State)}; handle_method(#'connection.close_ok'{}, none, - State = #nc_state{closing = Closing}) -> - #nc_closing{from = From, - close = #'connection.close'{reply_code = ReplyCode}} = Closing, + State = #state{closing = Closing}) -> + #closing{from = From, + close = #'connection.close'{reply_code = ReplyCode}} = Closing, case From of none -> ok; _ -> gen_server:reply(From, ok) @@ -159,14 +159,14 @@ handle_method(#'connection.close_ok'{}, none, %% Infos %%--------------------------------------------------------------------------- -i(server_properties, State) -> State#nc_state.server_properties; -i(is_closing, State) -> State#nc_state.closing =/= false; -i(amqp_params, State) -> State#nc_state.params; -i(max_channel, State) -> State#nc_state.max_channel; -i(heartbeat, State) -> State#nc_state.heartbeat; -i(sock, State) -> State#nc_state.sock; +i(server_properties, State) -> State#state.server_properties; +i(is_closing, State) -> State#state.closing =/= false; +i(amqp_params, State) -> State#state.params; +i(max_channel, State) -> State#state.max_channel; +i(heartbeat, State) -> State#state.heartbeat; +i(sock, State) -> State#state.sock; i(num_channels, State) -> amqp_channel_util:num_channels( - State#nc_state.channels); + State#state.channels); i(Item, _State) -> throw({bad_argument, Item}). %%--------------------------------------------------------------------------- @@ -177,7 +177,7 @@ i(Item, _State) -> throw({bad_argument, Item}). %% %% ChannelCloseType can be flush or abrupt %% -%% The closing reason (Closing#nc_closing.reason) can be one of the following +%% The closing reason (Closing#closing.reason) can be one of the following %% app_initiated_close - app has invoked the close/{1,3} command. In this %% case the close field is the method to be sent to the server after all %% the channels have terminated (and flushed); the from field is the @@ -198,16 +198,16 @@ i(Item, _State) -> throw({bad_argument, Item}). %% mentioned in the above list). We can rely on erlang's comparison of atoms %% for this. set_closing_state(ChannelCloseType, Closing, - #nc_state{closing = false, - channels = Channels} = State) -> + #state{closing = false, + channels = Channels} = State) -> amqp_channel_util:broadcast_to_channels( {connection_closing, ChannelCloseType, closing_to_reason(Closing)}, Channels), - check_trigger_all_channels_closed_event(State#nc_state{closing = Closing}); + check_trigger_all_channels_closed_event(State#state{closing = Closing}); %% Already closing, override situation set_closing_state(ChannelCloseType, NewClosing, - #nc_state{closing = CurClosing, - channels = Channels} = State) -> + #state{closing = CurClosing, + channels = Channels} = State) -> %% Do not override reason in channels (because it might cause channels to %% to exit with different reasons) but do cause them to close abruptly %% if the new closing type requires it @@ -219,19 +219,19 @@ set_closing_state(ChannelCloseType, NewClosing, Channels); _ -> ok end, - #nc_closing{reason = NewReason, close = NewClose} = NewClosing, - #nc_closing{reason = CurReason} = CurClosing, + #closing{reason = NewReason, close = NewClose} = NewClosing, + #closing{reason = CurReason} = CurClosing, ResClosing = if %% Override (rely on erlang's comparison of atoms) NewReason >= CurReason -> %% Note that when overriding, we keep the current phase - CurClosing#nc_closing{reason = NewReason, close = NewClose}; + CurClosing#closing{reason = NewReason, close = NewClose}; %% Do not override true -> CurClosing end, - NewState = State#nc_state{closing = ResClosing}, + NewState = State#state{closing = ResClosing}, %% Now check if it's the case that the server has sent a connection.close %% while we were in the closing state (for whatever reason). We need to %% send connection.close_ok (it might be even be the case that we are @@ -243,51 +243,50 @@ set_closing_state(ChannelCloseType, NewClosing, %% The all_channels_closed_event is called when all channels have been closed %% after the connection broadcasts a connection_closing message to all channels -all_channels_closed_event(#nc_state{channel0_writer_pid = Writer0, +all_channels_closed_event(#state{channel0_writer_pid = Writer0, main_reader_pid = MainReader, closing = Closing} = State) -> - #nc_closing{reason = Reason, close = Close} = Closing, + #closing{reason = Reason, close = Close} = Closing, case Reason of server_initiated_close -> amqp_channel_util:do(network, Writer0, #'connection.close_ok'{}, none), erlang:send_after(?SOCKET_CLOSING_TIMEOUT, MainReader, socket_closing_timeout), - State#nc_state{closing = - Closing#nc_closing{phase = wait_socket_close}}; + State#state{closing = Closing#closing{phase = wait_socket_close}}; _ -> amqp_channel_util:do(network, Writer0, Close, none), erlang:send_after(?CLIENT_CLOSE_TIMEOUT, self(), timeout_waiting_for_close_ok), - State#nc_state{closing = Closing#nc_closing{phase = wait_close_ok}} + State#state{closing = Closing#closing{phase = wait_close_ok}} end. -closing_to_reason(#nc_closing{reason = Reason, +closing_to_reason(#closing{reason = Reason, close = #'connection.close'{reply_code = Code, reply_text = Text}}) -> {Reason, Code, Text}. internal_error_closing() -> - #nc_closing{reason = internal_error, - close = #'connection.close'{reply_text = <<>>, - reply_code = ?INTERNAL_ERROR, - class_id = 0, - method_id = 0}}. + #closing{reason = internal_error, + close = #'connection.close'{reply_text = <<>>, + reply_code = ?INTERNAL_ERROR, + class_id = 0, + method_id = 0}}. %%--------------------------------------------------------------------------- %% Channel utilities %%--------------------------------------------------------------------------- -unregister_channel(Pid, State = #nc_state{channels = Channels}) -> +unregister_channel(Pid, State = #state{channels = Channels}) -> NewChannels = amqp_channel_util:unregister_channel_pid(Pid, Channels), - NewState = State#nc_state{channels = NewChannels}, + NewState = State#state{channels = NewChannels}, check_trigger_all_channels_closed_event(NewState). -check_trigger_all_channels_closed_event(#nc_state{closing = false} = State) -> +check_trigger_all_channels_closed_event(#state{closing = false} = State) -> State; -check_trigger_all_channels_closed_event(#nc_state{channels = Channels, +check_trigger_all_channels_closed_event(#state{channels = Channels, closing = Closing} = State) -> - #nc_closing{phase = terminate_channels} = Closing, % assertion + #closing{phase = terminate_channels} = Closing, % assertion case amqp_channel_util:is_channel_dict_empty(Channels) of true -> all_channels_closed_event(State); false -> State @@ -299,32 +298,32 @@ check_trigger_all_channels_closed_event(#nc_state{channels = Channels, %% Handle exit from writer0 handle_exit(Writer0Pid, Reason, - #nc_state{channel0_writer_pid = Writer0Pid} = State) -> + #state{channel0_writer_pid = Writer0Pid} = State) -> ?LOG_WARN("Connection (~p) closing: received exit signal from writer0. " "Reason: ~p~n", [self(), Reason]), {stop, {writer0_died, Reason}, State}; %% Handle exit from framing0 handle_exit(Framing0Pid, Reason, - #nc_state{channel0_framing_pid = Framing0Pid} = State) -> + #state{channel0_framing_pid = Framing0Pid} = State) -> ?LOG_WARN("Connection (~p) closing: received exit signal from framing0. " "Reason: ~p~n", [self(), Reason]), {stop, {framing0_died, Reason}, State}; %% Handle exit from main reader handle_exit(MainReaderPid, Reason, - #nc_state{main_reader_pid = MainReaderPid, - closing = Closing} = State) -> + #state{main_reader_pid = MainReaderPid, + closing = Closing} = State) -> case {Closing, Reason} of %% Normal server initiated shutdown exit (socket has been closed after %% replying with 'connection.close_ok') - {#nc_closing{reason = server_initiated_close, + {#closing{reason = server_initiated_close, phase = wait_socket_close}, socket_closed} -> {stop, closing_to_reason(Closing), State}; %% Timed out waiting for socket to close after replying with %% 'connection.close_ok' - {#nc_closing{reason = server_initiated_close, + {#closing{reason = server_initiated_close, phase = wait_socket_close}, socket_closing_timeout} -> ?LOG_WARN("Connection (~p) closing: timed out waiting for socket " @@ -339,7 +338,7 @@ handle_exit(MainReaderPid, Reason, %% Handle exit from channel or other pid handle_exit(Pid, Reason, - #nc_state{channels = Channels, closing = Closing} = State) -> + #state{channels = Channels, closing = Closing} = State) -> case amqp_channel_util:handle_exit(Pid, Reason, Channels, Closing) of stop -> {stop, Reason, State}; normal -> {noreply, unregister_channel(Pid, State)}; @@ -353,25 +352,25 @@ handle_exit(Pid, Reason, %% Handshake %%--------------------------------------------------------------------------- -handshake(State = #nc_state{params = #amqp_params{host = Host, - port = Port, - ssl_options = none}}) -> +handshake(State = #state{params = #amqp_params{host = Host, + port = Port, + ssl_options = none}}) -> case gen_tcp:connect(Host, Port, ?RABBIT_TCP_OPTS) of - {ok, Sock} -> do_handshake(State#nc_state{sock = Sock}); + {ok, Sock} -> do_handshake(State#state{sock = Sock}); {error, Reason} -> ?LOG_WARN("Could not start the network driver: ~p~n", [Reason]), exit(Reason) end; -handshake(State = #nc_state{params = #amqp_params{host = Host, - port = Port, - ssl_options = SslOpts}}) -> +handshake(State = #state{params = #amqp_params{host = Host, + port = Port, + ssl_options = SslOpts}}) -> rabbit_misc:start_applications([crypto, ssl]), case gen_tcp:connect(Host, Port, ?RABBIT_TCP_OPTS) of {ok, Sock} -> case ssl:connect(Sock, SslOpts) of {ok, SslSock} -> RabbitSslSock = #ssl_socket{ssl = SslSock, tcp = Sock}, - do_handshake(State#nc_state{sock = RabbitSslSock}); + do_handshake(State#state{sock = RabbitSslSock}); {error, Reason} -> ?LOG_WARN("Could not upgrade the network driver to ssl: " "~p~n", [Reason]), @@ -382,20 +381,20 @@ handshake(State = #nc_state{params = #amqp_params{host = Host, exit(Reason) end. -do_handshake(State0 = #nc_state{sock = Sock}) -> +do_handshake(State0 = #state{sock = Sock}) -> ok = rabbit_net:send(Sock, ?PROTOCOL_HEADER), {Framing0Pid, Writer0Pid} = amqp_channel_util:start_channel_infrastructure(network, 0, {Sock, none}), {ok, MainReaderPid} = amqp_main_reader:start_link(Sock, Framing0Pid), - State1 = State0#nc_state{channel0_framing_pid = Framing0Pid, - channel0_writer_pid = Writer0Pid, - main_reader_pid = MainReaderPid}, + State1 = State0#state{channel0_framing_pid = Framing0Pid, + channel0_writer_pid = Writer0Pid, + main_reader_pid = MainReaderPid}, State2 = network_handshake(State1), - amqp_main_reader:start_heartbeat(MainReaderPid, State2#nc_state.heartbeat), + amqp_main_reader:start_heartbeat(MainReaderPid, State2#state.heartbeat), State2. -network_handshake(State = #nc_state{channel0_writer_pid = Writer0, - params = Params}) -> +network_handshake(State = #state{channel0_writer_pid = Writer0, + params = Params}) -> Start = handshake_recv(State), #'connection.start'{server_properties = ServerProperties} = Start, ok = check_version(Start), @@ -413,9 +412,9 @@ network_handshake(State = #nc_state{channel0_writer_pid = Writer0, ?LOG_INFO("Negotiated maximums: (Channel = ~p, " "Frame= ~p, Heartbeat=~p)~n", [ChannelMax, FrameMax, Heartbeat]), - State#nc_state{max_channel = ChannelMax, - heartbeat = Heartbeat, - server_properties = ServerProperties}. + State#state{max_channel = ChannelMax, + heartbeat = Heartbeat, + server_properties = ServerProperties}. check_version(#'connection.start'{version_major = ?PROTOCOL_VERSION_MAJOR, version_minor = ?PROTOCOL_VERSION_MINOR}) -> @@ -443,9 +442,9 @@ negotiate_max_value(Client, Server) when Client =:= 0; Server =:= 0 -> negotiate_max_value(Client, Server) -> lists:min([Client, Server]). -start_ok(#nc_state{params = #amqp_params{username = Username, - password = Password, - client_properties = UserProps}}) -> +start_ok(#state{params = #amqp_params{username = Username, + password = Password, + client_properties = UserProps}}) -> LoginTable = [{<<"LOGIN">>, longstr, Username}, {<<"PASSWORD">>, longstr, Password}], #'connection.start_ok'{ @@ -475,7 +474,7 @@ client_properties(UserProperties) -> lists:keystore(K, 1, Acc, Tuple) end, Default, UserProperties). -handshake_recv(#nc_state{main_reader_pid = MainReaderPid}) -> +handshake_recv(#state{main_reader_pid = MainReaderPid}) -> receive {'$gen_cast', {method, Method, _Content}} -> Method; diff --git a/deps/amqp_client/src/amqp_rpc_client.erl b/deps/amqp_client/src/amqp_rpc_client.erl index 4cf4eac2cf..056315f2b2 100755 --- a/deps/amqp_client/src/amqp_rpc_client.erl +++ b/deps/amqp_client/src/amqp_rpc_client.erl @@ -39,12 +39,12 @@ -export([init/1, terminate/2, code_change/3, handle_call/3, handle_cast/2, handle_info/2]). --record(rpc_c_state, {channel, - reply_queue, - exchange, - routing_key, - continuations = dict:new(), - correlation_id = 0}). +-record(state, {channel, + reply_queue, + exchange, + routing_key, + continuations = dict:new(), + correlation_id = 0}). %%-------------------------------------------------------------------------- %% API @@ -83,26 +83,25 @@ call(RpcClient, Payload) -> %%-------------------------------------------------------------------------- %% Sets up a reply queue for this client to listen on -setup_reply_queue(State = #rpc_c_state{channel = Channel}) -> +setup_reply_queue(State = #state{channel = Channel}) -> #'queue.declare_ok'{queue = Q} = amqp_channel:call(Channel, #'queue.declare'{}), - State#rpc_c_state{reply_queue = Q}. + State#state{reply_queue = Q}. %% Registers this RPC client instance as a consumer to handle rpc responses -setup_consumer(#rpc_c_state{channel = Channel, - reply_queue = Q}) -> +setup_consumer(#state{channel = Channel, reply_queue = Q}) -> amqp_channel:subscribe(Channel, #'basic.consume'{queue = Q}, self()). %% Publishes to the broker, stores the From address against %% the correlation id and increments the correlationid for %% the next request publish(Payload, From, - State = #rpc_c_state{channel = Channel, - reply_queue = Q, - exchange = X, - routing_key = RoutingKey, - correlation_id = CorrelationId, - continuations = Continuations}) -> + State = #state{channel = Channel, + reply_queue = Q, + exchange = X, + routing_key = RoutingKey, + correlation_id = CorrelationId, + continuations = Continuations}) -> Props = #'P_basic'{correlation_id = <>, content_type = <<"application/octet-stream">>, reply_to = Q}, @@ -111,9 +110,8 @@ publish(Payload, From, mandatory = true}, amqp_channel:call(Channel, Publish, #amqp_msg{props = Props, payload = Payload}), - State#rpc_c_state{correlation_id = CorrelationId + 1, - continuations = - dict:store(CorrelationId, From, Continuations)}. + State#state{correlation_id = CorrelationId + 1, + continuations = dict:store(CorrelationId, From, Continuations)}. %%-------------------------------------------------------------------------- %% gen_server callbacks @@ -123,16 +121,16 @@ publish(Payload, From, %% @private init([Connection, RoutingKey]) -> Channel = amqp_connection:open_channel(Connection), - InitialState = #rpc_c_state{channel = Channel, - exchange = <<>>, - routing_key = RoutingKey}, + InitialState = #state{channel = Channel, + exchange = <<>>, + routing_key = RoutingKey}, State = setup_reply_queue(InitialState), setup_consumer(State), {ok, State}. %% Closes the channel this gen_server instance started %% @private -terminate(_Reason, #rpc_c_state{channel = Channel}) -> +terminate(_Reason, #state{channel = Channel}) -> amqp_channel:close(Channel), ok. @@ -162,11 +160,11 @@ handle_info(#'basic.cancel_ok'{}, State) -> handle_info({#'basic.deliver'{delivery_tag = DeliveryTag}, #amqp_msg{props = #'P_basic'{correlation_id = <>}, payload = Payload}}, - State = #rpc_c_state{continuations = Conts, channel = Channel}) -> + State = #state{continuations = Conts, channel = Channel}) -> From = dict:fetch(Id, Conts), gen_server:reply(From, Payload), amqp_channel:call(Channel, #'basic.ack'{delivery_tag = DeliveryTag}), - {noreply, State#rpc_c_state{continuations = dict:erase(Id, Conts) }}. + {noreply, State#state{continuations = dict:erase(Id, Conts) }}. %% @private code_change(_OldVsn, State, _Extra) -> diff --git a/deps/amqp_client/src/amqp_rpc_server.erl b/deps/amqp_client/src/amqp_rpc_server.erl index d5656ad4d2..5907880e77 100755 --- a/deps/amqp_client/src/amqp_rpc_server.erl +++ b/deps/amqp_client/src/amqp_rpc_server.erl @@ -39,8 +39,8 @@ -export([start/3]). -export([stop/1]). --record(rpc_s_state, {channel, - handler}). +-record(state, {channel, + handler}). %%-------------------------------------------------------------------------- %% API @@ -76,7 +76,7 @@ init([Connection, Q, Fun]) -> Channel = amqp_connection:open_channel(Connection), amqp_channel:call(Channel, #'queue.declare'{queue = Q}), amqp_channel:subscribe(Channel, #'basic.consume'{queue = Q}, self()), - {ok, #rpc_s_state{channel = Channel, handler = Fun} }. + {ok, #state{channel = Channel, handler = Fun} }. %% @private handle_info(shutdown, State) -> @@ -93,7 +93,7 @@ handle_info(#'basic.cancel_ok'{}, State) -> %% @private handle_info({#'basic.deliver'{delivery_tag = DeliveryTag}, #amqp_msg{props = Props, payload = Payload}}, - State = #rpc_s_state{handler = Fun, channel = Channel}) -> + State = #state{handler = Fun, channel = Channel}) -> #'P_basic'{correlation_id = CorrelationId, reply_to = Q} = Props, Response = Fun(Payload), @@ -120,7 +120,7 @@ handle_cast(_Message, State) -> %% Closes the channel this gen_server instance started %% @private -terminate(_Reason, #rpc_s_state{channel = Channel}) -> +terminate(_Reason, #state{channel = Channel}) -> amqp_channel:close(Channel), ok. From 92f9e7f233cf7adadab3559106879bd11d239de7 Mon Sep 17 00:00:00 2001 From: Matthew Sackman Date: Thu, 9 Sep 2010 14:31:25 +0100 Subject: [PATCH 12/31] Revert connection API to throw on error, as it does on default --- deps/amqp_client/src/amqp_connection.erl | 4 ++-- deps/amqp_client/test/negative_test_util.erl | 13 ++++--------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/deps/amqp_client/src/amqp_connection.erl b/deps/amqp_client/src/amqp_connection.erl index f772805ddf..54eb3bc307 100644 --- a/deps/amqp_client/src/amqp_connection.erl +++ b/deps/amqp_client/src/amqp_connection.erl @@ -132,9 +132,9 @@ start(Type, AmqpParams, Link) -> ok -> Connection catch exit:{Reason = {protocol_version_mismatch, _, _}, _} -> - {error, Reason}; + throw({error, Reason}); exit:Reason -> - {error, {auth_failure_likely, Reason}} + throw({error, {auth_failure_likely, Reason}}) end. %%--------------------------------------------------------------------------- diff --git a/deps/amqp_client/test/negative_test_util.erl b/deps/amqp_client/test/negative_test_util.erl index 083b1575e9..cb50ac5451 100644 --- a/deps/amqp_client/test/negative_test_util.erl +++ b/deps/amqp_client/test/negative_test_util.erl @@ -128,23 +128,18 @@ shortstr_overflow_field_test(Connection) -> non_existent_user_test() -> Params = #amqp_params{username = test_util:uuid(), password = test_util:uuid()}, - assert_fail_start_with_params(Params). + ?assertThrow({error, {auth_failure_likely, _}}, amqp_connection:start_network(Params)). invalid_password_test() -> Params = #amqp_params{username = <<"guest">>, password = test_util:uuid()}, - assert_fail_start_with_params(Params). + ?assertThrow({error, {auth_failure_likely, _}}, amqp_connection:start_network(Params)). non_existent_vhost_test() -> Params = #amqp_params{virtual_host = test_util:uuid()}, - assert_fail_start_with_params(Params). + ?assertThrow({error, {auth_failure_likely, _}}, amqp_connection:start_network(Params)). no_permission_test() -> Params = #amqp_params{username = <<"test_user_no_perm">>, password = <<"test_user_no_perm">>}, - assert_fail_start_with_params(Params). - -assert_fail_start_with_params(Params) -> - {error, {auth_failure_likely, _}} = - network_client_SUITE:new_connection(Params), - ok. + ?assertThrow({error, {auth_failure_likely, _}}, amqp_connection:start_network(Params)). From a3fb2272394cafe0a557950a9f5e80b1f3dee6cc Mon Sep 17 00:00:00 2001 From: Matthew Sackman Date: Thu, 9 Sep 2010 15:24:09 +0100 Subject: [PATCH 13/31] Cosmetics --- deps/amqp_client/src/amqp_channel.erl | 41 ++++++++++++----------- deps/amqp_client/src/amqp_channel_sup.erl | 4 +-- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/deps/amqp_client/src/amqp_channel.erl b/deps/amqp_client/src/amqp_channel.erl index c37cf5a5cf..6ebe80c999 100644 --- a/deps/amqp_client/src/amqp_channel.erl +++ b/deps/amqp_client/src/amqp_channel.erl @@ -51,17 +51,18 @@ -record(state, {number, sup, driver, - rpc_requests = queue:new(), - anon_sub_requests = queue:new(), + rpc_requests = queue:new(), + anon_sub_requests = queue:new(), tagged_sub_requests = dict:new(), - closing = false, + closing = false, writer, - return_handler_pid = none, - flow_control = false, - flow_handler_pid = none, - consumers = dict:new(), - default_consumer = none, - start_infrastructure_fun}). + return_handler_pid = none, + flow_control = false, + flow_handler_pid = none, + consumers = dict:new(), + default_consumer = none, + start_infrastructure_fun + }). %% This diagram shows the interaction between the different component %% processes in an AMQP client scenario. @@ -95,12 +96,12 @@ %% @type amqp_command(). %% This abstract datatype represents the set of commands that comprise the -%% AMQP execution model. As indicated in the overview, the attributes of each +%% AMQP execution model. As indicated in the overview, the attributes of each %% commands in the execution model are described in the protocol %% documentation. The Erlang record definitions are autogenerated from a %% parseable version of the specification. -%% @type content() = #'basic.publish'{} | +%% @type content() = #'basic.publish'{} | %% #'basic.deliver'{} | %% #'basic.return'{}. %% These are the content bearing AMQP commands. @@ -160,7 +161,7 @@ close(Channel) -> %% @doc Closes the channel, allowing the caller to supply a reply code and %% text. close(Channel, Code, Text) -> - Close = #'channel.close'{reply_text = Text, + Close = #'channel.close'{reply_text = Text, reply_code = Code, class_id = 0, method_id = 0}, @@ -176,7 +177,7 @@ close(Channel, Code, Text) -> %% where %% Channel = pid() %% Consumer = pid() -%% @doc Creates a subscription to a queue. This subscribes a consumer pid to +%% @doc Creates a subscription to a queue. This subscribes a consumer pid to %% the queue defined in the #'basic.consume'{} command record. Note that both %% both the process invoking this method and the supplied consumer process %% receive an acknowledgement of the subscription. The calling process will @@ -189,7 +190,7 @@ subscribe(Channel, BasicConsume = #'basic.consume'{}, Consumer) -> %% where %% Channel = pid() %% ReturnHandler = pid() -%% @doc This registers a handler to deal with returned messages. The +%% @doc This registers a handler to deal with returned messages. The %% registered process will receive #basic.return{} commands. register_return_handler(Channel, ReturnHandler) -> gen_server:cast(Channel, {register_return_handler, ReturnHandler} ). @@ -235,7 +236,7 @@ register_default_consumer(Channel, Consumer) -> %% RPC mechanism %%--------------------------------------------------------------------------- -rpc_top_half(Method, Content, From, +rpc_top_half(Method, Content, From, State0 = #state{rpc_requests = RequestQueue}) -> State1 = State0#state{ rpc_requests = queue:in({From, Method, Content}, RequestQueue)}, @@ -255,11 +256,11 @@ rpc_bottom_half(Reply, State = #state{rpc_requests = RequestQueue}) -> exit(empty_rpc_bottom_half) end. -do_rpc(State0 = #state{rpc_requests = RequestQueue, - closing = Closing}) -> +do_rpc(State = #state{rpc_requests = RequestQueue, + closing = Closing}) -> case queue:peek(RequestQueue) of {value, {_From, Method, Content}} -> - State1 = pre_do(Method, Content, State0), + State1 = pre_do(Method, Content, State), do(Method, Content, State1), State1; empty -> @@ -267,7 +268,7 @@ do_rpc(State0 = #state{rpc_requests = RequestQueue, {connection, Reason} -> self() ! {shutdown, Reason}; _ -> ok end, - State0 + State end. pre_do(#'channel.open'{}, _Content, State) -> @@ -285,7 +286,7 @@ do(Method, Content, #state{driver = Driver, writer = Writer}) -> ok = amqp_channel_util:do(Driver, Writer, Method, Content). start_infrastructure(State = #state{start_infrastructure_fun = SIF}) -> - {Writer} = SIF(), + {ok, Writer} = SIF(), State#state{writer = Writer}. resolve_consumer(_ConsumerTag, #state{consumers = []}) -> diff --git a/deps/amqp_client/src/amqp_channel_sup.erl b/deps/amqp_client/src/amqp_channel_sup.erl index 7463e95ef2..85e287ca7a 100644 --- a/deps/amqp_client/src/amqp_channel_sup.erl +++ b/deps/amqp_client/src/amqp_channel_sup.erl @@ -56,7 +56,7 @@ start_infrastructure_fun(Sup, direct, [User, VHost, Collector], ChNumber) -> [ChNumber, ChPid, ChPid, User, VHost, Collector, start_limiter_fun(Sup)]}, transient, ?MAX_WAIT, worker, [rabbit_channel]}), - {RabbitChannel} + {ok, RabbitChannel} end; start_infrastructure_fun(Sup, network, [Sock, MainReader], ChNumber) -> fun() -> @@ -74,7 +74,7 @@ start_infrastructure_fun(Sup, network, [Sock, MainReader], ChNumber) -> %% This call will disappear as part of bug 23024 amqp_main_reader:register_framing_channel(MainReader, ChNumber, Framing), - {Writer} + {ok, Writer} end. start_limiter_fun(Sup) -> From d4dcf15602115a47e4d7ffe47a203550c07e3799 Mon Sep 17 00:00:00 2001 From: Matthew Sackman Date: Thu, 9 Sep 2010 16:15:21 +0100 Subject: [PATCH 14/31] Cosmetics, refactorings and simplifications --- deps/amqp_client/src/amqp_channel.erl | 51 +++++++++++---------------- 1 file changed, 20 insertions(+), 31 deletions(-) diff --git a/deps/amqp_client/src/amqp_channel.erl b/deps/amqp_client/src/amqp_channel.erl index 6ebe80c999..7294849fe3 100644 --- a/deps/amqp_client/src/amqp_channel.erl +++ b/deps/amqp_client/src/amqp_channel.erl @@ -246,15 +246,13 @@ rpc_top_half(Method, Content, From, end. rpc_bottom_half(Reply, State = #state{rpc_requests = RequestQueue}) -> - case queue:out(RequestQueue) of - {{value, {From, _Method, _Content}}, NewRequestQueue} -> - case From of none -> ok; - _ -> gen_server:reply(From, Reply) - end, - do_rpc(State#state{rpc_requests = NewRequestQueue}); - {empty, _} -> - exit(empty_rpc_bottom_half) - end. + {{value, {From, _Method, _Content}}, RequestQueue1} = + queue:out(RequestQueue), + case From of + none -> ok; + _ -> gen_server:reply(From, Reply) + end, + do_rpc(State#state{rpc_requests = RequestQueue1}). do_rpc(State = #state{rpc_requests = RequestQueue, closing = Closing}) -> @@ -373,19 +371,15 @@ handle_method(Method, Content, State = #state{closing = Closing}) -> handle_regular_method( #'basic.consume_ok'{consumer_tag = ConsumerTag} = ConsumeOk, none, #state{tagged_sub_requests = Tagged, - anon_sub_requests = Anon} = State) -> - {_From, Consumer, State0} = + anon_sub_requests = Anon} = State) -> + {Consumer, State0} = case dict:find(ConsumerTag, Tagged) of - {ok, {F, C}} -> - NewTagged = dict:erase(ConsumerTag,Tagged), - {F, C, State#state{tagged_sub_requests = NewTagged}}; + {ok, C} -> + NewTagged = dict:erase(ConsumerTag, Tagged), + {C, State#state{tagged_sub_requests = NewTagged}}; error -> - case queue:out(Anon) of - {empty, _} -> - exit({anonymous_queue_empty, ConsumerTag}); - {{value, {F, C}}, NewAnon} -> - {F, C, State#state{anon_sub_requests = NewAnon}} - end + {{value, C}, NewAnon} = queue:out(Anon), + {C, State#state{anon_sub_requests = NewAnon}} end, Consumer ! ConsumeOk, State1 = register_consumer(ConsumerTag, Consumer, State0), @@ -447,9 +441,9 @@ start_link(Driver, ChannelNumber, SIF) -> %% @private init([Sup, Driver, ChannelNumber, SIF]) -> - {ok, #state{sup = Sup, - driver = Driver, - number = ChannelNumber, + {ok, #state{sup = Sup, + driver = Driver, + number = ChannelNumber, start_infrastructure_fun = SIF}}. %% Standard implementation of the call/{2,3} command @@ -478,16 +472,15 @@ handle_call({subscribe, #'basic.consume'{consumer_tag = Tag} = Method, Consumer} ok -> {NewMethod, NewState} = if Tag =:= undefined orelse size(Tag) == 0 -> - NewAnon = queue:in({From,Consumer}, Anon), + NewAnon = queue:in(Consumer, Anon), {Method#'basic.consume'{consumer_tag = <<"">>}, State#state{anon_sub_requests = NewAnon}}; is_binary(Tag) -> %% TODO test whether this tag already exists, either in %% the pending tagged request map or in general as %% already subscribed consumer - NewTagged = dict:store(Tag,{From,Consumer}, Tagged), - {Method, - State#state{tagged_sub_requests = NewTagged}} + NewTagged = dict:store(Tag, Consumer, Tagged), + {Method, State#state{tagged_sub_requests = NewTagged}} end, {noreply, rpc_top_half(NewMethod, none, From, NewState)}; BlockReply -> @@ -575,10 +568,6 @@ handle_info({send_command_and_notify, Q, ChPid, Method, Content}, State) -> rabbit_amqqueue:notify_sent(Q, ChPid), {noreply, State}; -%% @private -handle_info(shutdown, State) -> - {stop, normal, State}; - %% @private handle_info({shutdown, Reason}, State) -> shutdown_with_reason(Reason, State); From 25672b8d388e5867b3ef8e666fd9b4a85486b0cf Mon Sep 17 00:00:00 2001 From: Matthew Sackman Date: Thu, 9 Sep 2010 16:31:54 +0100 Subject: [PATCH 15/31] Cosmetics --- deps/amqp_client/src/amqp_channel_sup.erl | 64 ++++++++++++----------- 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/deps/amqp_client/src/amqp_channel_sup.erl b/deps/amqp_client/src/amqp_channel_sup.erl index 85e287ca7a..51714bd1c3 100644 --- a/deps/amqp_client/src/amqp_channel_sup.erl +++ b/deps/amqp_client/src/amqp_channel_sup.erl @@ -49,41 +49,45 @@ start_link(Driver, InfraArgs, ChNumber) -> %%--------------------------------------------------------------------------- start_infrastructure_fun(Sup, direct, [User, VHost, Collector], ChNumber) -> - fun() -> - ChPid = self(), - {ok, RabbitChannel} = supervisor2:start_child(Sup, - {rabbit_channel, {rabbit_channel, start_link, - [ChNumber, ChPid, ChPid, User, VHost, - Collector, start_limiter_fun(Sup)]}, - transient, ?MAX_WAIT, worker, [rabbit_channel]}), - {ok, RabbitChannel} + fun () -> + ChPid = self(), + supervisor2:start_child( + Sup, + {rabbit_channel, {rabbit_channel, start_link, + [ChNumber, ChPid, ChPid, User, VHost, + Collector, start_limiter_fun(Sup)]}, + transient, ?MAX_WAIT, worker, [rabbit_channel]}) end; start_infrastructure_fun(Sup, network, [Sock, MainReader], ChNumber) -> - fun() -> - ChPid = self(), - {ok, Framing} = supervisor2:start_child(Sup, - {framing, {rabbit_framing_channel, start_link, - [Sup, ChPid, ?PROTOCOL]}, - intrinsic, ?MAX_WAIT, worker, - [rabbit_framing_channel]}), - {ok, Writer} = supervisor2:start_child(Sup, - {writer, {rabbit_writer, start_link, - [Sock, ChNumber, ?FRAME_MIN_SIZE, - ?PROTOCOL, MainReader]}, - intrinsic, ?MAX_WAIT, worker, [rabbit_writer]}), - %% This call will disappear as part of bug 23024 - amqp_main_reader:register_framing_channel(MainReader, ChNumber, - Framing), - {ok, Writer} + fun () -> + ChPid = self(), + {ok, Framing} = + supervisor2:start_child( + Sup, + {framing, {rabbit_framing_channel, start_link, + [Sup, ChPid, ?PROTOCOL]}, + intrinsic, ?MAX_WAIT, worker, [rabbit_framing_channel]}), + {ok, Writer} = + supervisor2:start_child( + Sup, + {writer, {rabbit_writer, start_link, + [Sock, ChNumber, ?FRAME_MIN_SIZE, ?PROTOCOL, + MainReader]}, + intrinsic, ?MAX_WAIT, worker, [rabbit_writer]}), + %% This call will disappear as part of bug 23024 + amqp_main_reader:register_framing_channel(MainReader, ChNumber, + Framing), + {ok, Writer} end. start_limiter_fun(Sup) -> - fun(UnackedCount) -> - Parent = self(), - {ok, _} = supervisor2:start_child(Sup, - {limiter, {rabbit_limiter, start_link, - [Parent, UnackedCount]}, - transient, ?MAX_WAIT, worker, [rabbit_limiter]}) + fun (UnackedCount) -> + Parent = self(), + {ok, _} = supervisor2:start_child( + Sup, + {limiter, {rabbit_limiter, start_link, + [Parent, UnackedCount]}, + transient, ?MAX_WAIT, worker, [rabbit_limiter]}) end. %%--------------------------------------------------------------------------- From cf0889d77ea069ab98ddf9628f3d6740f5ec2920 Mon Sep 17 00:00:00 2001 From: Matthew Sackman Date: Thu, 9 Sep 2010 17:03:06 +0100 Subject: [PATCH 16/31] cosmetic and avoid a use of supervisor2:find_child --- deps/amqp_client/src/amqp_channel_sup.erl | 9 +++++---- deps/amqp_client/src/amqp_channel_util.erl | 5 ++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/deps/amqp_client/src/amqp_channel_sup.erl b/deps/amqp_client/src/amqp_channel_sup.erl index 51714bd1c3..2ead9eef32 100644 --- a/deps/amqp_client/src/amqp_channel_sup.erl +++ b/deps/amqp_client/src/amqp_channel_sup.erl @@ -39,10 +39,11 @@ start_link(Driver, InfraArgs, ChNumber) -> {ok, Sup} = supervisor2:start_link(?MODULE, []), SIF = start_infrastructure_fun(Sup, Driver, InfraArgs, ChNumber), - {ok, _} = supervisor2:start_child(Sup, - {channel, {amqp_channel, start_link, [Driver, ChNumber, SIF]}, - intrinsic, brutal_kill, worker, [amqp_channel]}), - {ok, Sup}. + {ok, ChPid} = + supervisor2:start_child( + Sup, {channel, {amqp_channel, start_link, [Driver, ChNumber, SIF]}, + intrinsic, brutal_kill, worker, [amqp_channel]}), + {ok, Sup, ChPid}. %%--------------------------------------------------------------------------- %% Internal plumbing diff --git a/deps/amqp_client/src/amqp_channel_util.erl b/deps/amqp_client/src/amqp_channel_util.erl index 0a929315f7..f0df394948 100644 --- a/deps/amqp_client/src/amqp_channel_util.erl +++ b/deps/amqp_client/src/amqp_channel_util.erl @@ -42,9 +42,8 @@ open_channel(ChSupSup, ProposedNumber, MaxChannel, InfraArgs, Channels) -> ChannelNumber = channel_number(ProposedNumber, Channels, MaxChannel), - {ok, ChannelSup} = amqp_channel_sup_sup:start_channel_sup( - ChSupSup, InfraArgs, ChannelNumber), - [ChPid] = supervisor2:find_child(ChannelSup, channel), + {ok, ChannelSup, ChPid} = amqp_channel_sup_sup:start_channel_sup( + ChSupSup, InfraArgs, ChannelNumber), #'channel.open_ok'{} = amqp_channel:call(ChPid, #'channel.open'{}), erlang:monitor(process, ChPid), NewChannels = register_channel(ChannelNumber, ChPid, Channels), From e1c763e1f432ee3ff1343eb866f8bfd4d440041f Mon Sep 17 00:00:00 2001 From: Matthew Sackman Date: Thu, 9 Sep 2010 17:13:45 +0100 Subject: [PATCH 17/31] Same trick again --- deps/amqp_client/src/amqp_channel_util.erl | 4 ++-- deps/amqp_client/src/amqp_connection.erl | 6 +++--- deps/amqp_client/src/amqp_connection_sup.erl | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/deps/amqp_client/src/amqp_channel_util.erl b/deps/amqp_client/src/amqp_channel_util.erl index f0df394948..6509460f58 100644 --- a/deps/amqp_client/src/amqp_channel_util.erl +++ b/deps/amqp_client/src/amqp_channel_util.erl @@ -42,8 +42,8 @@ open_channel(ChSupSup, ProposedNumber, MaxChannel, InfraArgs, Channels) -> ChannelNumber = channel_number(ProposedNumber, Channels, MaxChannel), - {ok, ChannelSup, ChPid} = amqp_channel_sup_sup:start_channel_sup( - ChSupSup, InfraArgs, ChannelNumber), + {ok, _ChannelSup, ChPid} = amqp_channel_sup_sup:start_channel_sup( + ChSupSup, InfraArgs, ChannelNumber), #'channel.open_ok'{} = amqp_channel:call(ChPid, #'channel.open'{}), erlang:monitor(process, ChPid), NewChannels = register_channel(ChannelNumber, ChPid, Channels), diff --git a/deps/amqp_client/src/amqp_connection.erl b/deps/amqp_client/src/amqp_connection.erl index 54eb3bc307..99fb0c2592 100644 --- a/deps/amqp_client/src/amqp_connection.erl +++ b/deps/amqp_client/src/amqp_connection.erl @@ -123,8 +123,8 @@ start_network_link(Params) -> %% a RabbitMQ server, assuming that the server is running in the same process %% space. start(Type, AmqpParams, Link) -> - {ok, Sup} = amqp_connection_sup:start_link(Type, AmqpParams, Link), - [Connection] = supervisor2:find_child(Sup, connection), + {ok, Sup, Connection} = + amqp_connection_sup:start_link(Type, AmqpParams, Link), Module = case Type of direct -> amqp_direct_connection; network -> amqp_network_connection end, @@ -141,7 +141,7 @@ start(Type, AmqpParams, Link) -> %% Commands %%--------------------------------------------------------------------------- -%% @doc Invokes open_channel(ConnectionPid, none, <<>>). +%% @doc Invokes open_channel(ConnectionPid, none, <<>>). %% Opens a channel without having to specify a channel number. open_channel(ConnectionPid) -> open_channel(ConnectionPid, none). diff --git a/deps/amqp_client/src/amqp_connection_sup.erl b/deps/amqp_client/src/amqp_connection_sup.erl index f24b940323..a9064c160d 100644 --- a/deps/amqp_client/src/amqp_connection_sup.erl +++ b/deps/amqp_client/src/amqp_connection_sup.erl @@ -47,10 +47,10 @@ start_link(Type, AmqpParams, Link) -> [Type]}, intrinsic, infinity, supervisor, [amqp_channel_sup_sup]}), - start_connection(Sup, Type, AmqpParams, ChSupSup, - start_infrastructure_fun(Sup, Type)), - {ok, Sup}. - + {ok, Connection} = start_connection(Sup, Type, AmqpParams, ChSupSup, + start_infrastructure_fun(Sup, Type)), + {ok, Sup, Connection}. + %%--------------------------------------------------------------------------- %% Internal plumbing %%--------------------------------------------------------------------------- From fbab8456e5a74cab0d109ba156cff66c1c6cd9af Mon Sep 17 00:00:00 2001 From: Matthew Sackman Date: Thu, 9 Sep 2010 17:42:56 +0100 Subject: [PATCH 18/31] And the same trick yet again - thus now there are no uses of supervisor2:find_child in the erlang client --- deps/amqp_client/src/amqp_connection_sup.erl | 60 ++++++++-------- .../src/amqp_connection_type_sup.erl | 72 ++++++++++--------- .../src/amqp_direct_connection.erl | 7 +- .../src/amqp_network_connection.erl | 2 +- 4 files changed, 74 insertions(+), 67 deletions(-) diff --git a/deps/amqp_client/src/amqp_connection_sup.erl b/deps/amqp_client/src/amqp_connection_sup.erl index a9064c160d..25b3c568b4 100644 --- a/deps/amqp_client/src/amqp_connection_sup.erl +++ b/deps/amqp_client/src/amqp_connection_sup.erl @@ -56,40 +56,42 @@ start_link(Type, AmqpParams, Link) -> %%--------------------------------------------------------------------------- start_connection(Sup, network, AmqpParams, ChSupSup, SIF) -> - {ok, _} = supervisor2:start_child(Sup, - {connection, {amqp_network_connection, start_link, - [AmqpParams, ChSupSup, SIF]}, - intrinsic, brutal_kill, worker, [amqp_network_connection]}); + {ok, _} = supervisor2:start_child( + Sup, + {connection, {amqp_network_connection, start_link, + [AmqpParams, ChSupSup, SIF]}, + intrinsic, brutal_kill, worker, [amqp_network_connection]}); start_connection(Sup, direct, AmqpParams, ChSupSup, SIF) -> - {ok, _} = supervisor2:start_child(Sup, - {connection, {amqp_direct_connection, start_link, - [AmqpParams, ChSupSup, SIF]}, - intrinsic, brutal_kill, worker, [amqp_direct_connection]}). + {ok, _} = supervisor2:start_child( + Sup, + {connection, {amqp_direct_connection, start_link, + [AmqpParams, ChSupSup, SIF]}, + intrinsic, brutal_kill, worker, [amqp_direct_connection]}). start_infrastructure_fun(Sup, network) -> - fun(Sock) -> - Connection = self(), - {ok, CTSup} = supervisor2:start_child(Sup, - {connection_type_sup, {amqp_connection_type_sup, - start_link_network, - [Sock, Connection]}, - intrinsic, infinity, supervisor, - [amqp_connection_type_sup]}), - [MainReader] = supervisor2:find_child(CTSup, main_reader), - [Framing] = supervisor2:find_child(CTSup, framing), - [Writer] = supervisor2:find_child(CTSup, writer), - {MainReader, Framing, Writer, - amqp_connection_type_sup:start_heartbeat_fun(CTSup)} + fun (Sock) -> + Connection = self(), + {ok, CTSup, {MainReader, Framing, Writer}} = + supervisor2:start_child( + Sup, + {connection_type_sup, + {amqp_connection_type_sup, start_link_network, + [Sock, Connection]}, + intrinsic, infinity, supervisor, + [amqp_connection_type_sup]}), + {ok, {MainReader, Framing, Writer, + amqp_connection_type_sup:start_heartbeat_fun(CTSup)}} end; start_infrastructure_fun(Sup, direct) -> - fun() -> - {ok, CTSup} = supervisor2:start_child(Sup, - {connection_type_sup, {amqp_connection_type_sup, - start_link_direct, []}, - intrinsic, infinity, supervisor, - [amqp_connection_type_sup]}), - [Collector] = supervisor2:find_child(CTSup, collector), - {Collector} + fun () -> + {ok, _CTSup, Collector} = + supervisor2:start_child( + Sup, + {connection_type_sup, + {amqp_connection_type_sup, start_link_direct, []}, + intrinsic, infinity, supervisor, + [amqp_connection_type_sup]}), + {ok, Collector} end. %%--------------------------------------------------------------------------- diff --git a/deps/amqp_client/src/amqp_connection_type_sup.erl b/deps/amqp_client/src/amqp_connection_type_sup.erl index a2fe7a2899..6c854dad10 100644 --- a/deps/amqp_client/src/amqp_connection_type_sup.erl +++ b/deps/amqp_client/src/amqp_connection_type_sup.erl @@ -38,44 +38,50 @@ start_link_direct() -> {ok, Sup} = supervisor2:start_link(?MODULE, []), - {ok, _} = supervisor2:start_child(Sup, - {collector, {rabbit_queue_collector, start_link, []}, - intrinsic, ?MAX_WAIT, worker, [rabbit_queue_collector]}), - {ok, Sup}. + {ok, Collector} = + supervisor2:start_child( + Sup, {collector, {rabbit_queue_collector, start_link, []}, + intrinsic, ?MAX_WAIT, worker, [rabbit_queue_collector]}), + {ok, Sup, Collector}. start_link_network(Sock, ConnectionPid) -> {ok, Sup} = supervisor2:start_link(?MODULE, []), - {ok, Framing0} = supervisor2:start_child(Sup, - {framing, {rabbit_framing_channel, start_link, - [Sup, ConnectionPid, ?PROTOCOL]}, - intrinsic, ?MAX_WAIT, worker, - [rabbit_framing_channel]}), - {ok, MainReader} = supervisor2:start_child(Sup, - {main_reader, {amqp_main_reader, start_link, - [Sock, Framing0, ConnectionPid]}, - intrinsic, ?MAX_WAIT, worker, [amqp_main_reader]}), - {ok, _} = supervisor2:start_child(Sup, - {writer, {rabbit_writer, start_link, - [Sock, 0, ?FRAME_MIN_SIZE, ?PROTOCOL, MainReader]}, - intrinsic, ?MAX_WAIT, worker, [rabbit_writer]}), - {ok, Sup}. + {ok, Framing} = + supervisor2:start_child( + Sup, {framing, {rabbit_framing_channel, start_link, + [Sup, ConnectionPid, ?PROTOCOL]}, + intrinsic, ?MAX_WAIT, worker, [rabbit_framing_channel]}), + {ok, MainReader} = + supervisor2:start_child( + Sup, {main_reader, {amqp_main_reader, start_link, + [Sock, Framing, ConnectionPid]}, + intrinsic, ?MAX_WAIT, worker, [amqp_main_reader]}), + {ok, Writer} = + supervisor2:start_child( + Sup, {writer, {rabbit_writer, start_link, + [Sock, 0, ?FRAME_MIN_SIZE, ?PROTOCOL, MainReader]}, + intrinsic, ?MAX_WAIT, worker, [rabbit_writer]}), + {ok, Sup, {MainReader, Framing, Writer}}. start_heartbeat_fun(Sup) -> - fun(_Sock, 0) -> - none; - (Sock, Timeout) -> - Connection = self(), - {ok, Sender} = supervisor2:start_child(Sup, - {heartbeat_sender, {rabbit_heartbeat, - start_heartbeat_sender, - [Connection, Sock, Timeout]}, - intrinsic, ?MAX_WAIT, worker, [rabbit_heartbeat]}), - {ok, Receiver} = supervisor2:start_child(Sup, - {heartbeat_receiver, {rabbit_heartbeat, - start_heartbeat_receiver, - [Connection, Sock, Timeout]}, - intrinsic, ?MAX_WAIT, worker, [rabbit_heartbeat]}), - {Sender, Receiver} + fun (_Sock, 0) -> + none; + (Sock, Timeout) -> + Connection = self(), + {ok, Sender} = + supervisor2:start_child( + Sup, + {heartbeat_sender, {rabbit_heartbeat, start_heartbeat_sender, + [Connection, Sock, Timeout]}, + intrinsic, ?MAX_WAIT, worker, [rabbit_heartbeat]}), + {ok, Receiver} = + supervisor2:start_child( + Sup, + {heartbeat_receiver, + {rabbit_heartbeat, start_heartbeat_receiver, + [Connection, Sock, Timeout]}, + intrinsic, ?MAX_WAIT, worker, [rabbit_heartbeat]}), + {Sender, Receiver} end. %%--------------------------------------------------------------------------- diff --git a/deps/amqp_client/src/amqp_direct_connection.erl b/deps/amqp_client/src/amqp_direct_connection.erl index 233a608974..4b67570441 100644 --- a/deps/amqp_client/src/amqp_direct_connection.erl +++ b/deps/amqp_client/src/amqp_direct_connection.erl @@ -186,9 +186,8 @@ set_closing_state(ChannelCloseType, NewClosing, %% The all_channels_closed_event is called when all channels have been closed %% after the connection broadcasts a connection_closing message to all channels -all_channels_closed_event(#state{sup = Sup, closing = Closing} = State) -> - [CTSup] = supervisor2:find_child(Sup, connection_type_sup), - [Collector] = supervisor2:find_child(CTSup, collector), +all_channels_closed_event(#state{sup = Sup, closing = Closing, + collector = Collector} = State) -> rabbit_queue_collector:delete_all(Collector), case Closing#closing.from of none -> ok; @@ -259,5 +258,5 @@ do_connect(State0 = #state{params = #amqp_params{username = User, State1#state{server_properties = ServerProperties}. start_infrastructure(State = #state{start_infrastructure_fun = SIF}) -> - {Collector} = SIF(), + {ok, Collector} = SIF(), State#state{collector = Collector}. diff --git a/deps/amqp_client/src/amqp_network_connection.erl b/deps/amqp_client/src/amqp_network_connection.erl index da2e00af3d..c1accef523 100644 --- a/deps/amqp_client/src/amqp_network_connection.erl +++ b/deps/amqp_client/src/amqp_network_connection.erl @@ -362,7 +362,7 @@ handshake(State0 = #state{sock = Sock}) -> start_infrastructure(State = #state{start_infrastructure_fun = SIF, sock = Sock}) -> - {MainReader, Framing, Writer, SHF} = SIF(Sock), + {ok, {MainReader, Framing, Writer, SHF}} = SIF(Sock), State#state{main_reader = MainReader, framing0 = Framing, writer0 = Writer, From e9a84a5d4b3e0ea0b8622c57b68eef4a9d68b8f2 Mon Sep 17 00:00:00 2001 From: Matthew Sackman Date: Thu, 9 Sep 2010 17:46:53 +0100 Subject: [PATCH 19/31] Drive-by bug fix - network_connection was failing to handle the timeout message that the heartbeat receiver can send --- deps/amqp_client/src/amqp_network_connection.erl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/deps/amqp_client/src/amqp_network_connection.erl b/deps/amqp_client/src/amqp_network_connection.erl index c1accef523..f25be5cfe5 100644 --- a/deps/amqp_client/src/amqp_network_connection.erl +++ b/deps/amqp_client/src/amqp_network_connection.erl @@ -112,7 +112,10 @@ handle_info(socket_closed, State) -> handle_socket_closed(State); %% DOWN signals from channels handle_info({'DOWN', _, process, Pid, Reason}, State) -> - handle_channel_exit(Pid, Reason, State). + handle_channel_exit(Pid, Reason, State); +%% timeout from heartbeat receiver +handle_info(timeout, State) -> + {stop, heartbeat_timeout, State}. terminate(_Reason, _State) -> ok. From d1706303541a9ba20b2a383a6e523c9419b64b18 Mon Sep 17 00:00:00 2001 From: Matthew Sackman Date: Thu, 9 Sep 2010 18:00:16 +0100 Subject: [PATCH 20/31] Just like in the broker, heartbeaters should be transient, not intrinsic, given that they message the connection whenever anything goes wrong (receiver heartbeat timeout) --- deps/amqp_client/src/amqp_connection_type_sup.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deps/amqp_client/src/amqp_connection_type_sup.erl b/deps/amqp_client/src/amqp_connection_type_sup.erl index 6c854dad10..7105779f16 100644 --- a/deps/amqp_client/src/amqp_connection_type_sup.erl +++ b/deps/amqp_client/src/amqp_connection_type_sup.erl @@ -73,14 +73,14 @@ start_heartbeat_fun(Sup) -> Sup, {heartbeat_sender, {rabbit_heartbeat, start_heartbeat_sender, [Connection, Sock, Timeout]}, - intrinsic, ?MAX_WAIT, worker, [rabbit_heartbeat]}), + transient, ?MAX_WAIT, worker, [rabbit_heartbeat]}), {ok, Receiver} = supervisor2:start_child( Sup, {heartbeat_receiver, {rabbit_heartbeat, start_heartbeat_receiver, [Connection, Sock, Timeout]}, - intrinsic, ?MAX_WAIT, worker, [rabbit_heartbeat]}), + transient, ?MAX_WAIT, worker, [rabbit_heartbeat]}), {Sender, Receiver} end. From b40ae8b8907f9c828bb3ae7eec29db509bbff882 Mon Sep 17 00:00:00 2001 From: Matthew Sackman Date: Thu, 9 Sep 2010 18:27:48 +0100 Subject: [PATCH 21/31] More tidying - mainly cosmetics --- .../src/amqp_direct_connection.erl | 54 +++++++++---------- 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/deps/amqp_client/src/amqp_direct_connection.erl b/deps/amqp_client/src/amqp_direct_connection.erl index 4b67570441..a8cb003eb0 100644 --- a/deps/amqp_client/src/amqp_direct_connection.erl +++ b/deps/amqp_client/src/amqp_direct_connection.erl @@ -45,7 +45,7 @@ -record(closing, {reason, close = none, %% At least one of close and reply has to be reply = none, %% none at any given moment - from = none}). + from = none}). -define(INFO_KEYS, (amqp_connection:info_keys() ++ [])). @@ -65,9 +65,9 @@ connect(Pid) -> %%--------------------------------------------------------------------------- init([Sup, AmqpParams, ChSupSup, SIF]) -> - {ok, #state{sup = Sup, - params = AmqpParams, - channel_sup_sup = ChSupSup, + {ok, #state{sup = Sup, + params = AmqpParams, + channel_sup_sup = ChSupSup, start_infrastructure_fun = SIF}}. handle_call({command, Command}, From, #state{closing = Closing} = State) -> @@ -105,12 +105,12 @@ code_change(_OldVsn, State, _Extra) -> %% Command handling %%--------------------------------------------------------------------------- -handle_command({open_channel, ProposedNumber}, _From, - State = #state{collector = Collector, - channel_sup_sup = ChSupSup, - params = #amqp_params{username = User, - virtual_host = VHost}, - channels = Channels}) -> +handle_command({open_channel, ProposedNumber}, _From, State = + #state{collector = Collector, + channel_sup_sup = ChSupSup, + params = #amqp_params{username = User, + virtual_host = VHost}, + channels = Channels}) -> try amqp_channel_util:open_channel(ChSupSup, ProposedNumber, ?MAX_CHANNEL_NUMBER, [User, VHost, Collector], Channels) of @@ -123,8 +123,8 @@ handle_command({open_channel, ProposedNumber}, _From, handle_command({close, Close}, From, State) -> {noreply, set_closing_state(flush, #closing{reason = app_initiated_close, - close = Close, - from = From}, + close = Close, + from = From}, State)}. %%--------------------------------------------------------------------------- @@ -152,16 +152,14 @@ i(Item, _State) -> throw({bad_argument, Item}). %% mentioned in the above list). We can rely on erlang's comparison of atoms %% for this. set_closing_state(ChannelCloseType, Closing, - #state{closing = false, - channels = Channels} = State) -> + State = #state{closing = false, channels = Channels}) -> amqp_channel_util:broadcast_to_channels( {connection_closing, ChannelCloseType, closing_to_reason(Closing)}, Channels), check_trigger_all_channels_closed_event(State#state{closing = Closing}); %% Already closing, override situation set_closing_state(ChannelCloseType, NewClosing, - #state{closing = CurClosing, - channels = Channels} = State) -> + State = #state{closing = CurClosing, channels = Channels}) -> %% Do not override reason in channels (because it might cause channels to %% to exit with different reasons) but do cause them to close abruptly %% if the new closing type requires it @@ -186,8 +184,8 @@ set_closing_state(ChannelCloseType, NewClosing, %% The all_channels_closed_event is called when all channels have been closed %% after the connection broadcasts a connection_closing message to all channels -all_channels_closed_event(#state{sup = Sup, closing = Closing, - collector = Collector} = State) -> +all_channels_closed_event(State = #state{closing = Closing, + collector = Collector}) -> rabbit_queue_collector:delete_all(Collector), case Closing#closing.from of none -> ok; @@ -197,18 +195,18 @@ all_channels_closed_event(#state{sup = Sup, closing = Closing, State. closing_to_reason(#closing{reason = Reason, - close = #'connection.close'{reply_code = Code, - reply_text = Text}, - reply = none}) -> + close = #'connection.close'{reply_code = Code, + reply_text = Text}, + reply = none}) -> {Reason, Code, Text}; closing_to_reason(#closing{reason = Reason, - reply = {_, Code, Text}, - close = none}) -> + reply = {_, Code, Text}, + close = none}) -> {Reason, Code, Text}. internal_error_closing() -> #closing{reason = internal_error, - reply = {internal_error, ?INTERNAL_ERROR, <<>>}}. + reply = {internal_error, ?INTERNAL_ERROR, <<>>}}. %%--------------------------------------------------------------------------- %% Channel utilities @@ -219,10 +217,9 @@ unregister_channel(Pid, State = #state{channels = Channels}) -> NewState = State#state{channels = NewChannels}, check_trigger_all_channels_closed_event(NewState). -check_trigger_all_channels_closed_event(#state{closing = false} = State) -> +check_trigger_all_channels_closed_event(State = #state{closing = false}) -> State; -check_trigger_all_channels_closed_event( - #state{channels = Channels} = State) -> +check_trigger_all_channels_closed_event(State = #state{channels = Channels}) -> case amqp_channel_util:is_channel_dict_empty(Channels) of true -> all_channels_closed_event(State); false -> State @@ -254,8 +251,7 @@ do_connect(State0 = #state{params = #amqp_params{username = User, rabbit_access_control:check_vhost_access( #user{username = User, password = Pass}, VHost), State1 = start_infrastructure(State0), - ServerProperties = rabbit_reader:server_properties(), - State1#state{server_properties = ServerProperties}. + State1#state{server_properties = rabbit_reader:server_properties()}. start_infrastructure(State = #state{start_infrastructure_fun = SIF}) -> {ok, Collector} = SIF(), From 643a424b7d1bc56ce8bec3aa3bd617c803b230d2 Mon Sep 17 00:00:00 2001 From: Matthew Sackman Date: Thu, 9 Sep 2010 19:03:29 +0100 Subject: [PATCH 22/31] A whole load more cosmetics --- deps/amqp_client/src/amqp_connection.erl | 2 +- .../src/amqp_network_connection.erl | 55 ++++++++++--------- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/deps/amqp_client/src/amqp_connection.erl b/deps/amqp_client/src/amqp_connection.erl index 99fb0c2592..8f25467c9f 100644 --- a/deps/amqp_client/src/amqp_connection.erl +++ b/deps/amqp_client/src/amqp_connection.erl @@ -123,7 +123,7 @@ start_network_link(Params) -> %% a RabbitMQ server, assuming that the server is running in the same process %% space. start(Type, AmqpParams, Link) -> - {ok, Sup, Connection} = + {ok, _Sup, Connection} = amqp_connection_sup:start_link(Type, AmqpParams, Link), Module = case Type of direct -> amqp_direct_connection; network -> amqp_network_connection diff --git a/deps/amqp_client/src/amqp_network_connection.erl b/deps/amqp_client/src/amqp_network_connection.erl index f25be5cfe5..cfb05fd411 100644 --- a/deps/amqp_client/src/amqp_network_connection.erl +++ b/deps/amqp_client/src/amqp_network_connection.erl @@ -76,9 +76,9 @@ connect(Pid) -> %%--------------------------------------------------------------------------- init([Sup, AmqpParams, ChSupSup, SIF]) -> - {ok, #state{sup = Sup, - params = AmqpParams, - channel_sup_sup = ChSupSup, + {ok, #state{sup = Sup, + params = AmqpParams, + channel_sup_sup = ChSupSup, start_infrastructure_fun = SIF}}. handle_call({command, Command}, From, #state{closing = Closing} = State) -> @@ -128,10 +128,10 @@ code_change(_OldVsn, State, _Extra) -> %%--------------------------------------------------------------------------- handle_command({open_channel, ProposedNumber}, _From, - State = #state{sock = Sock, - channels = Channels, - max_channel = MaxChannel, - main_reader = MainReader, + State = #state{sock = Sock, + channels = Channels, + max_channel = MaxChannel, + main_reader = MainReader, channel_sup_sup = ChSupSup}) -> try amqp_channel_util:open_channel(ChSupSup, ProposedNumber, MaxChannel, [Sock, MainReader], Channels) of @@ -144,8 +144,8 @@ handle_command({open_channel, ProposedNumber}, _From, handle_command({close, #'connection.close'{} = Close}, From, State) -> {noreply, set_closing_state(flush, #closing{reason = app_initiated_close, - close = Close, - from = From}, + close = Close, + from = From}, State)}. %%--------------------------------------------------------------------------- @@ -155,7 +155,7 @@ handle_command({close, #'connection.close'{} = Close}, From, State) -> handle_method(#'connection.close'{} = Close, none, State) -> {noreply, set_closing_state(abrupt, #closing{reason = server_initiated_close, - close = Close}, + close = Close}, State)}; handle_method(#'connection.close_ok'{}, none, @@ -287,8 +287,9 @@ internal_error_closing() -> class_id = 0, method_id = 0}}. -handle_socket_closed(State = #state{closing = - Closing = #closing{phase = wait_socket_close}}) -> +handle_socket_closed(State = #state{ + closing = Closing = #closing{ + phase = wait_socket_close}}) -> {stop, closing_to_reason(Closing), State}; handle_socket_closed(State) -> {stop, socket_closed_unexpectedly, State}. @@ -305,8 +306,8 @@ unregister_channel(Pid, State = #state{channels = Channels}) -> check_trigger_all_channels_closed_event(#state{closing = false} = State) -> State; check_trigger_all_channels_closed_event(#state{channels = Channels, - closing = Closing} = State) -> - #closing{phase = terminate_channels} = Closing, % assertion + closing = Closing} = State) -> + #closing{phase = terminate_channels} = Closing, %% assertion case amqp_channel_util:is_channel_dict_empty(Channels) of true -> all_channels_closed_event(State); false -> State @@ -327,8 +328,8 @@ handle_channel_exit(Pid, Reason, %% Handshake %%--------------------------------------------------------------------------- -do_connect(State = #state{params = #amqp_params{host = Host, - port = Port, +do_connect(State = #state{params = #amqp_params{host = Host, + port = Port, ssl_options = none}}) -> case gen_tcp:connect(Host, Port, ?RABBIT_TCP_OPTS) of {ok, Sock} -> handshake(State#state{sock = Sock}); @@ -336,8 +337,8 @@ do_connect(State = #state{params = #amqp_params{host = Host, [Reason]), exit(Reason) end; -do_connect(State = #state{params = #amqp_params{host = Host, - port = Port, +do_connect(State = #state{params = #amqp_params{host = Host, + port = Port, ssl_options = SslOpts}}) -> rabbit_misc:start_applications([crypto, ssl]), case gen_tcp:connect(Host, Port, ?RABBIT_TCP_OPTS) of @@ -366,9 +367,9 @@ handshake(State0 = #state{sock = Sock}) -> start_infrastructure(State = #state{start_infrastructure_fun = SIF, sock = Sock}) -> {ok, {MainReader, Framing, Writer, SHF}} = SIF(Sock), - State#state{main_reader = MainReader, - framing0 = Framing, - writer0 = Writer, + State#state{main_reader = MainReader, + framing0 = Framing, + writer0 = Writer, start_heartbeat_fun = SHF}. network_handshake(State = #state{writer0 = Writer, params = Params}) -> @@ -389,13 +390,13 @@ network_handshake(State = #state{writer0 = Writer, params = Params}) -> ?LOG_INFO("Negotiated maximums: (Channel = ~p, Frame = ~p, " "Heartbeat = ~p)~n", [ChannelMax, FrameMax, Heartbeat]), - State#state{max_channel = ChannelMax, - heartbeat = Heartbeat, + State#state{max_channel = ChannelMax, + heartbeat = Heartbeat, server_properties = ServerProperties}. start_heartbeat(#state{start_heartbeat_fun = SHF, - sock = Sock, - heartbeat = Heartbeat}) -> + sock = Sock, + heartbeat = Heartbeat}) -> SHF(Sock, Heartbeat). check_version(#'connection.start'{version_major = ?PROTOCOL_VERSION_MAJOR, @@ -424,8 +425,8 @@ negotiate_max_value(Client, Server) when Client =:= 0; Server =:= 0 -> negotiate_max_value(Client, Server) -> lists:min([Client, Server]). -start_ok(#state{params = #amqp_params{username = Username, - password = Password, +start_ok(#state{params = #amqp_params{username = Username, + password = Password, client_properties = UserProps}}) -> LoginTable = [{<<"LOGIN">>, longstr, Username}, {<<"PASSWORD">>, longstr, Password}], From 37ce81930807348c740afb15b1f85e7fc1ec1a72 Mon Sep 17 00:00:00 2001 From: Matthew Sackman Date: Fri, 10 Sep 2010 12:17:16 +0100 Subject: [PATCH 23/31] minor refactor --- deps/amqp_client/src/amqp_network_connection.erl | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/deps/amqp_client/src/amqp_network_connection.erl b/deps/amqp_client/src/amqp_network_connection.erl index cfb05fd411..9d07a3e302 100644 --- a/deps/amqp_client/src/amqp_network_connection.erl +++ b/deps/amqp_client/src/amqp_network_connection.erl @@ -81,11 +81,10 @@ init([Sup, AmqpParams, ChSupSup, SIF]) -> channel_sup_sup = ChSupSup, start_infrastructure_fun = SIF}}. -handle_call({command, Command}, From, #state{closing = Closing} = State) -> - case Closing of - false -> handle_command(Command, From, State); - _ -> {reply, closing, State} - end; +handle_call({command, Command}, From, #state{closing = false} = State) -> + handle_command(Command, From, State); +handle_call({command, Command}, From, State) -> + {reply, closing, State}; handle_call({info, Items}, _From, State) -> {reply, [{Item, i(Item, State)} || Item <- Items], State}; handle_call(info_keys, _From, State) -> From 32d1c20f883ce38332d7c286a044d1f255b71c45 Mon Sep 17 00:00:00 2001 From: Matthew Sackman Date: Fri, 10 Sep 2010 14:28:01 +0100 Subject: [PATCH 24/31] Whoops --- deps/amqp_client/src/amqp_network_connection.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/amqp_client/src/amqp_network_connection.erl b/deps/amqp_client/src/amqp_network_connection.erl index 9d07a3e302..eed49d2ddc 100644 --- a/deps/amqp_client/src/amqp_network_connection.erl +++ b/deps/amqp_client/src/amqp_network_connection.erl @@ -83,7 +83,7 @@ init([Sup, AmqpParams, ChSupSup, SIF]) -> handle_call({command, Command}, From, #state{closing = false} = State) -> handle_command(Command, From, State); -handle_call({command, Command}, From, State) -> +handle_call({command, _Command}, _From, State) -> {reply, closing, State}; handle_call({info, Items}, _From, State) -> {reply, [{Item, i(Item, State)} || Item <- Items], State}; From cc7bf1cd6d86c0d4997933d8337fa264e165b1fd Mon Sep 17 00:00:00 2001 From: Matthew Sackman Date: Fri, 10 Sep 2010 14:46:13 +0100 Subject: [PATCH 25/31] Correct some obvious bugs that dialyzer found - reader:analyze_frame never returns 'none' in the 3rd position of the tuple, and the trace stuff got stripped out recently --- deps/amqp_client/src/amqp_main_reader.erl | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/deps/amqp_client/src/amqp_main_reader.erl b/deps/amqp_client/src/amqp_main_reader.erl index dfbd2819ca..e11a418632 100644 --- a/deps/amqp_client/src/amqp_main_reader.erl +++ b/deps/amqp_client/src/amqp_main_reader.erl @@ -117,14 +117,10 @@ handle_frame(Type, Channel, Payload, State) -> case rabbit_reader:analyze_frame(Type, Payload, ?PROTOCOL) of heartbeat when Channel /= 0 -> rabbit_misc:die(frame_error); - trace when Channel /= 0 -> - rabbit_misc:die(frame_error); - %% Match heartbeats and trace frames, but don't do anything with them + %% Match heartbeats but don't do anything with them heartbeat -> heartbeat; - trace -> - trace; - {method, Method = 'connection.close_ok', none} -> + {method, Method = 'connection.close_ok', _FieldsBin} -> pass_frame(Channel, {method, Method}, State), closed_ok; AnalyzedFrame -> From 3327cf8e03d56084429068b2f07fa984e1584153 Mon Sep 17 00:00:00 2001 From: Matthew Sackman Date: Fri, 10 Sep 2010 14:57:05 +0100 Subject: [PATCH 26/31] Remove clause which now matches (and causes errors) whereas before, the erroneous 'none' prevented the clause from ever matching --- deps/amqp_client/src/amqp_main_reader.erl | 3 --- 1 file changed, 3 deletions(-) diff --git a/deps/amqp_client/src/amqp_main_reader.erl b/deps/amqp_client/src/amqp_main_reader.erl index e11a418632..5a01706960 100644 --- a/deps/amqp_client/src/amqp_main_reader.erl +++ b/deps/amqp_client/src/amqp_main_reader.erl @@ -120,9 +120,6 @@ handle_frame(Type, Channel, Payload, State) -> %% Match heartbeats but don't do anything with them heartbeat -> heartbeat; - {method, Method = 'connection.close_ok', _FieldsBin} -> - pass_frame(Channel, {method, Method}, State), - closed_ok; AnalyzedFrame -> pass_frame(Channel, AnalyzedFrame, State) end. From da76756e9d41be2c88d90ddab9f6aea8c730ca5a Mon Sep 17 00:00:00 2001 From: Matthew Sackman Date: Fri, 10 Sep 2010 15:42:02 +0100 Subject: [PATCH 27/31] Remove more dead code - this is ok - the network_connection will receive the connection.close_ok and tear down the whole world via the supervision tree --- deps/amqp_client/src/amqp_main_reader.erl | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/deps/amqp_client/src/amqp_main_reader.erl b/deps/amqp_client/src/amqp_main_reader.erl index 5a01706960..903a4afca5 100644 --- a/deps/amqp_client/src/amqp_main_reader.erl +++ b/deps/amqp_client/src/amqp_main_reader.erl @@ -97,12 +97,9 @@ handle_inet_async({inet_async, Sock, _, Msg}, end, case Msg of {ok, <>} -> - case handle_frame(Type, Channel, Payload, State) of - closed_ok -> {stop, normal, State}; - _ -> {ok, _Ref} = - rabbit_net:async_recv(Sock, 7, infinity), - {noreply, State#state{message = none}} - end; + handle_frame(Type, Channel, Payload, State), + {ok, _Ref} = rabbit_net:async_recv(Sock, 7, infinity), + {noreply, State#state{message = none}}; {ok, <>} -> {ok, _Ref} = rabbit_net:async_recv(Sock, NewLength + 1, infinity), {noreply, State#state{message={NewType, NewChannel, NewLength}}}; From 46bd7bab0044400337b8f0e360c72ab7843d916f Mon Sep 17 00:00:00 2001 From: Vlad Alexandru Ionescu Date: Mon, 13 Sep 2010 16:35:29 +0100 Subject: [PATCH 28/31] reverting changes in Makefile and README --- deps/amqp_client/Makefile | 7 +- deps/amqp_client/README | 258 +++++++++++++++++++++++++++++++++++++ deps/amqp_client/README.in | 10 -- 3 files changed, 260 insertions(+), 15 deletions(-) create mode 100755 deps/amqp_client/README delete mode 100755 deps/amqp_client/README.in diff --git a/deps/amqp_client/Makefile b/deps/amqp_client/Makefile index 10e60b0a79..d437aba3c5 100644 --- a/deps/amqp_client/Makefile +++ b/deps/amqp_client/Makefile @@ -25,8 +25,6 @@ VERSION=0.0.0 -WEB_URL=http://www.rabbitmq.com/ - SOURCE_PACKAGE_DIR=$(PACKAGE)-$(VERSION)-src SOURCE_PACKAGE_TAR_GZ=$(SOURCE_PACKAGE_DIR).tar.gz @@ -127,8 +125,7 @@ $(DIST_DIR)/$(COMMON_PACKAGE_DIR): $(BROKER_DEPS) $(COMMON_PACKAGE).app | $(DIST source_tarball: $(DIST_DIR)/$(COMMON_PACKAGE_EZ) $(EBIN_DIR)/$(PACKAGE).app | $(DIST_DIR) mkdir -p $(DIST_DIR)/$(SOURCE_PACKAGE_DIR)/$(DIST_DIR) $(COPY) $(DIST_DIR)/$(COMMON_PACKAGE_EZ) $(DIST_DIR)/$(SOURCE_PACKAGE_DIR)/$(DIST_DIR)/ - $(COPY) README.in $(DIST_DIR)/$(SOURCE_PACKAGE_DIR)/README - elinks -dump -no-references -no-numbering $(WEB_URL)build-erlang-client.html >> $(DIST_DIR)/$(SOURCE_PACKAGE_DIR)/README + $(COPY) README $(DIST_DIR)/$(SOURCE_PACKAGE_DIR)/ $(COPY) common.mk $(DIST_DIR)/$(SOURCE_PACKAGE_DIR)/ sed 's/%%VSN%%/$(VERSION)/' Makefile.in > $(DIST_DIR)/$(SOURCE_PACKAGE_DIR)/Makefile mkdir -p $(DIST_DIR)/$(SOURCE_PACKAGE_DIR)/$(SOURCE_DIR) @@ -143,4 +140,4 @@ source_tarball: $(DIST_DIR)/$(COMMON_PACKAGE_EZ) $(EBIN_DIR)/$(PACKAGE).app | $( cd $(DIST_DIR) ; tar cvzf $(SOURCE_PACKAGE_TAR_GZ) $(SOURCE_PACKAGE_DIR) $(DIST_DIR): - mkdir -p $@ \ No newline at end of file + mkdir -p $@ diff --git a/deps/amqp_client/README b/deps/amqp_client/README new file mode 100755 index 0000000000..325260a2d4 --- /dev/null +++ b/deps/amqp_client/README @@ -0,0 +1,258 @@ +AMQP client for Erlang +====================== +This code implements a client for AMQP in the Erlang programming +language. + +This client offers both a networked version that uses standard +TCP-based AMQP framing and a direct client that uses native Erlang +message passing to a RabbitMQ broker. + +The API exposed to the user is common to both clients, so each version +can be used interchangeably without having to modify any client code. + +The TCP networked client has been tested with RabbitMQ server 1.4.0, +but should theoretically work with any 0-8 compliant AMQP server. + +The direct client is bound to an 0-8 compliant broker using native +Erlang message passing, which in the absence of an alternative Erlang +AMQP implementation means that it only works with RabbitMQ. + +It does however provide a level of abstraction above the internal +server API of RabbitMQ, meaning that you can write client code in +Erlang and still remain isolated from any API changes in the +underlying broker. + +It also provides a client-orientated API into RabbitMQ, allowing the +user to reuse AMQP knowledge gained by using AMQP clients in other +languages. + +The advantage of the direct client is that it eliminates the network +overhead as well as the marshaling to and from the AMQP wire format, +so that neither side has to decode or encode any AMQP frames. + +Prerequisites +------------- +In order to compile/run this code you must have the following +installed: + +- Erlang/OTP, R11B-5 or later, http://www.erlang.org/download.html +- The RabbitMQ server, 93cc2ca0ba62 or later +- Eunit, the Erlang unit testing framework - currently the whole build process + depends on eunit because all of the modules are compiled together. + A future version of the build process could remove this dependency when you + only want to compile the core libraries. + +Getting Eunit +------------- +The test suite uses eunit which is either available bundled with OTP from +release R12B-5 onwards or as a separate download that you will need to build +yourself if you are using an older version of Erlang. + +* If you are using R12B-5 or newer: + +Just skip to the next section. + +* If you are using R12B-4 or older: + +Check out eunit from their Subversion repository and build it: + + $ svn co http://svn.process-one.net/contribs/trunk/eunit eunit + $ cd eunit + $ make + +After this has sucessfully been built, you will need to create a symlink to +the eunit directory in your OTP installation directory: + + $ cd $OTP_HOME/lib/erlang/lib + $ ln -sf PATH_TO_EUNIT eunit + +where $OTP_HOME is the location of your Erlang/OTP installation. + +Compiling the Erlang client +------------------------- +You will need to get a copy of the server in order to be able to use it's +header files and runtime libraries. A good place to put this is in the sibling +directory to the Erlang client (i.e: ../rabbitmq-server), which is the default +that the Makefile expects. In this case, you can just run make: + + $ make + +If the source tree for the server is not in the sibling directory, you will +need to specify the path to this directory: + + $ make BROKER_DIR=/path/to/server + +In this case, make sure you specify BROKER_DIR every time you run a make target. + +Running the network client, direct client and packaging tests +------------------------------------------------------------- +The direct client has to be run in the same Erlang VM instance as the +RabbitMQ server. In order to use the makefile to run tests, you will need to +shutdown any other running instance of RabbitMQ server that you may have on +your machine. This is because the Makefile test targets boot their own instance +of RabbitMQ with settings depending on the test. +To run these tests, use either of the following targets: + + $ make test_network + $ make test_direct + $ make test_common_package + +Or to run all tests: + + $ make all_tests + +If any test fails, the make command will return a non-zero exit code. The reason +is logged by the server in /tmp/rabbit-sasl.log by default. + +The network client test can also be run from a separate Erlang VM instance from +RabbitMQ server. You can *start an instance of the server* and then, in the +rabbitmq-erlang-client folder, type + + rabbitmq-erlang-client $ make compile_tests + rabbitmq-erlang-client $ make run + erl -pa ebin ../rabbitmq-server/ebin tests + Erlang (BEAM) emulator version 5.6.5 [source] [64-bit] [smp:4] \ + [async-threads:0] [hipe] [kernel-poll:false] + + Eshell V5.6.5 (abort with ^G) + 1> network_client_SUITE:test(). + +To get more examples of the API, look at the functions in the test_util module. + +Running the channel flow tests +------------------------------ +There are two tests for producer control flow. The first is a unit +test that asserts the reception of the correct chain of commands in +conjunction with a direct manipulation of the high water mark. The +second test does not make any assertion about the behavior of the +server but it does produce output that demonstrates that the client +library is indeed notifying higher level application code that flow +control has been activated or deactivated. + +Both tests require that the memory alarms are turned on in the +server. By default they are turned off. To turn them on, set the +memory_alarms flag in the rabbit.app config file. + +First of all, in the *rabbitmq-erlang-client directory*, type + + rabbitmq-erlang-client $ make compile_tests + +to make sure test modules are compiled. + +Because the unit test accesses memsup directly, it needs to use the +direct API and hence needs to run in the same VM as the server. To do +this from the *rabbitmq-erlang-client directory*, type + + rabbitmq-erlang-client $ make run_in_broker + +When that has booted, you need to *wait one minute* for the memory +alarms to become active. After that, you can run the following from +the Erlang shell: + + 1> direct_client_SUITE:test_channel_flow(). + ok + +The non-unit test can be run in separate VM, because it uses the +network client driver. Whilst it can be run using the direct client, +it produces log output which makes it difficult to enter in commands +interactively (which you need to do to see the throttling). + +After *having booted* an *instance of the server* with alarms handlers +turned on, run the following in the *rabbitmq-erlang-client directory*: + + rabbitmq-erlang-client $ make compile_tests + rabbitmq-erlang-client $ make run + Erlang (BEAM) emulator version 5.6.3 [source] [smp:2] \ + [async-threads:0][kernel-poll:false] + + Eshell V5.6.3 (abort with ^G) + 1> P = #amqp_params{}. + 2> test_util:channel_flow_sync(amqp_connection:start_network(P)). + {<0.39.0>,<0.40.0>} + +After having done this, you should see output similar to this: + + Producer (<0.39.0>) has sent about 0 messages since it started + Producer (<0.39.0>) has sent about 5000 messages since it started + Producer (<0.39.0>) has sent about 10000 messages since it started + +To throttle the producer, go to the *server shell* and turn the memory +limit to some suitably low value: + + 2> memsup:set_sysmem_high_watermark(0.01). + ok + +Back in the *client shell*, you should see the following output: + ..... + Producer (<0.39.0>) has sent about 235000 messages since it started + Producer throttling ON + Producer (<0.39.0>) is blocked, will go to sleep.....ZZZ + +If you now set the high water mark to say 99%, the producer should +wake up again: + + Producer throttling OFF, waking up producer (<0.39.0>) + Producer (<0.39.0>) has woken up :-) + Producer (<0.39.0>) has sent about 240000 messages since it started + ..... + +Make targets +------------ +Interesting rabbitmq-erlang-client make targets include + +all + The default target. Builds the client (does not compile the tests). + +compile + Builds the client. + +compile_tests + Builds the client test modules. + +run + Builds the client and starts an Erlang shell with both the client and the + server in the load path. + +run_in_broker + Builds the client and starts RabbitMQ server with shell and the client + included in load path. + +clean + Removes build products and wipes all files produced by any other + rabbitmq-erlang-client make targets or client errors. + +dialyze + Analyses the client source code with dialyzer. Uses PLT file from default + location: ~/.dialyzer_plt. Use + + $ make PLT=/path/to/plt dialyze + + to override this. Add broker to PLT beforehand, otherwise you will a lot + of 'unknown function' warnings. See add_broker_to_plt make target. + +dialyze_all + Same as dialyze, except that this also analyses tests source code. + +add_broker_to_plt + Adds broker .beam files to default plt. Use + + $ make PLT=/path/to/plt add_broker_to_plt + + to override default plt location ( ~/.dialyzer_plt ). + +source_tarball + Creates tarball of all the client source code. + +package + Creates an erlang archive of the client. + +common_package + Creates an erlang archive of the server modules required by the erlang + client. + +all_tests + Clean compiles the client and client tests source code and runs + network_client_SUITE, direct_client_SUITE and packaging tests. During the + testing, this make target runs an instance of the broker, so make sure + there is no other instance of RabbitMQ server running. + diff --git a/deps/amqp_client/README.in b/deps/amqp_client/README.in deleted file mode 100755 index 3e6cb36980..0000000000 --- a/deps/amqp_client/README.in +++ /dev/null @@ -1,10 +0,0 @@ -Please see http://www.rabbitmq.com/build-erlang-client.html for build -instructions. - -For your convenience, a text copy of these instructions is available -below. Please be aware that the instructions here may not be as up to -date as those at the above URL. - -=========================================================================== - - From fca2a8ea72e9533dc9a609e48cfaf6c1ec6b9a98 Mon Sep 17 00:00:00 2001 From: Matthew Sackman Date: Mon, 13 Sep 2010 17:10:18 +0100 Subject: [PATCH 29/31] Minor corrections --- deps/amqp_client/src/amqp_channel.erl | 36 ++++++++++++++------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/deps/amqp_client/src/amqp_channel.erl b/deps/amqp_client/src/amqp_channel.erl index 622abe42b3..bb94c0a6d2 100644 --- a/deps/amqp_client/src/amqp_channel.erl +++ b/deps/amqp_client/src/amqp_channel.erl @@ -23,10 +23,11 @@ %% Contributor(s): Ben Hood <0x6e6562@gmail.com>. %% -%% @doc This module encapsulates the client's view of an AMQP channel. Each -%% server side channel is represented by an amqp_channel process on the client -%% side. Channel processes are created using the {@link amqp_connection}. -%% Channel processes are supervised under amqp_client's supervision tree. +%% @doc This module encapsulates the client's view of an AMQP +%% channel. Each server side channel is represented by an amqp_channel +%% process on the client side. Channel processes are created using the +%% {@link amqp_connection} module. Channel processes are supervised +%% under amqp_client's supervision tree. -module(amqp_channel). -include("amqp_client.hrl"). @@ -67,16 +68,17 @@ %%--------------------------------------------------------------------------- %% @type amqp_command(). -%% This abstract datatype represents the set of commands that comprise the -%% AMQP execution model. As indicated in the overview, the attributes of each -%% commands in the execution model are described in the protocol -%% documentation. The Erlang record definitions are autogenerated from a -%% parseable version of the specification. Most fields in the generated records -%% have sensible default values that you need not worry in the case of a simple -%% usage of the client library. +%% This abstract datatype represents the set of commands that comprise +%% the AMQP execution model. As indicated in the overview, the +%% attributes of each command in the execution model are described in +%% the protocol documentation. The Erlang record definitions are +%% autogenerated from a parseable version of the specification. Most +%% fields in the generated records have sensible default values that +%% you need not worry in the case of a simple usage of the client +%% library. %% @type amqp_msg() = #amqp_msg{}. -%% This is the content encapsulated in content bearing AMQP commands. It +%% This is the content encapsulated in content-bearing AMQP commands. It %% contains the following fields: %%
      %%
    • props :: class_property() - A class property record, defaults to @@ -107,12 +109,12 @@ call(Channel, Method) -> %% In the case of asynchronous methods, the function blocks until the method %% gets sent on the wire and returns the atom 'ok' on success.
      %% This will return the atom 'blocked' if the server has -%% throttled the client for flow control reasons. Also, it will return the +%% throttled the client for flow control reasons. This will return the %% atom 'closing' if the channel is in the process of shutting down.
      -%% Note that the synchronicity only means that the client has transmitted the -%% command to the broker. It does not necessarily imply that the broker has -%% accepted responsibility for the message. To acheive guaranteed delivery, -%% this function would have to be called within the context of a transaction. +%% Note that for asynchronous methods, the synchronicity implied by +%% 'call' only means that the client has transmitted the command to +%% the broker. It does not necessarily imply that the broker has +%% accepted responsibility for the message. call(Channel, Method, Content) -> gen_server:call(Channel, {call, Method, Content}, infinity). From e7d866ad22a47938cf188f5f2fdab81bb5071c89 Mon Sep 17 00:00:00 2001 From: Vlad Alexandru Ionescu Date: Mon, 13 Sep 2010 17:24:41 +0100 Subject: [PATCH 30/31] changing 'command' to 'method' --- deps/amqp_client/src/amqp_channel.erl | 34 +++++++++++++-------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/deps/amqp_client/src/amqp_channel.erl b/deps/amqp_client/src/amqp_channel.erl index bb94c0a6d2..5134a30da8 100644 --- a/deps/amqp_client/src/amqp_channel.erl +++ b/deps/amqp_client/src/amqp_channel.erl @@ -67,10 +67,10 @@ %% Type Definitions %%--------------------------------------------------------------------------- -%% @type amqp_command(). -%% This abstract datatype represents the set of commands that comprise +%% @type amqp_method(). +%% This abstract datatype represents the set of methods that comprise %% the AMQP execution model. As indicated in the overview, the -%% attributes of each command in the execution model are described in +%% attributes of each method in the execution model are described in %% the protocol documentation. The Erlang record definitions are %% autogenerated from a parseable version of the specification. Most %% fields in the generated records have sensible default values that @@ -78,7 +78,7 @@ %% library. %% @type amqp_msg() = #amqp_msg{}. -%% This is the content encapsulated in content-bearing AMQP commands. It +%% This is the content encapsulated in content-bearing AMQP methods. It %% contains the following fields: %%
        %%
      • props :: class_property() - A class property record, defaults to @@ -91,17 +91,17 @@ %%--------------------------------------------------------------------------- %% @spec (Channel, Method) -> Result -%% @doc This is equivalent to amqp_channel:call(Channel, Command, none). +%% @doc This is equivalent to amqp_channel:call(Channel, Method, none). call(Channel, Method) -> gen_server:call(Channel, {call, Method, none}, infinity). %% @spec (Channel, Method, Content) -> Result %% where %% Channel = pid() -%% Method = amqp_command() +%% Method = amqp_method() %% Content = amqp_msg() | none -%% Result = amqp_command() | ok | blocked | closing -%% @doc This sends an AMQP command on the channel. +%% Result = amqp_method() | ok | blocked | closing +%% @doc This sends an AMQP method on the channel. %% For content bearing methods, Content has to be an amqp_msg(), whereas %% for non-content bearing methods, it needs to be the atom 'none'.
        %% In the case of synchronous methods, this function blocks until the @@ -112,26 +112,26 @@ call(Channel, Method) -> %% throttled the client for flow control reasons. This will return the %% atom 'closing' if the channel is in the process of shutting down.
        %% Note that for asynchronous methods, the synchronicity implied by -%% 'call' only means that the client has transmitted the command to +%% 'call' only means that the client has transmitted the method to %% the broker. It does not necessarily imply that the broker has %% accepted responsibility for the message. call(Channel, Method, Content) -> gen_server:call(Channel, {call, Method, Content}, infinity). %% @spec (Channel, Method) -> ok -%% @doc This is equivalent to amqp_channel:cast(Channel, Command, none). +%% @doc This is equivalent to amqp_channel:cast(Channel, Method, none). cast(Channel, Method) -> gen_server:cast(Channel, {cast, Method, none}). %% @spec (Channel, Method, Content) -> ok %% where %% Channel = pid() -%% Method = amqp_command() +%% Method = amqp_method() %% Content = amqp_msg() | none %% @doc This function is the same as {@link call/3}, except that it returns %% immediately with the atom 'ok', without blocking the caller process. %% This function is not recommended with synchronous methods, since there is no -%% way to verify that the server has received the command. +%% way to verify that the server has received the method. cast(Channel, Method, Content) -> gen_server:cast(Channel, {cast, Method, Content}). @@ -163,13 +163,13 @@ close(Channel, Code, Text) -> %%--------------------------------------------------------------------------- %% @type consume() = #'basic.consume'{}. -%% The AMQP command that is used to subscribe a consumer to a queue. -%% @spec (Channel, consume(), Consumer) -> amqp_command() +%% The AMQP method that is used to subscribe a consumer to a queue. +%% @spec (Channel, consume(), Consumer) -> amqp_method() %% where %% Channel = pid() %% Consumer = pid() %% @doc Creates a subscription to a queue. This subscribes a consumer pid to -%% the queue defined in the #'basic.consume'{} command record. Note that +%% the queue defined in the #'basic.consume'{} method record. Note that %% both the process invoking this method and the supplied consumer process %% receive an acknowledgement of the subscription. The calling process will %% receive the acknowledgement as the return value of this function, whereas @@ -182,7 +182,7 @@ subscribe(Channel, BasicConsume = #'basic.consume'{}, Consumer) -> %% Channel = pid() %% ReturnHandler = pid() %% @doc This registers a handler to deal with returned messages. The -%% registered process will receive #basic.return{} commands. +%% registered process will receive #basic.return{} methods. register_return_handler(Channel, ReturnHandler) -> gen_server:cast(Channel, {register_return_handler, ReturnHandler} ). @@ -191,7 +191,7 @@ register_return_handler(Channel, ReturnHandler) -> %% Channel = pid() %% FlowHandler = pid() %% @doc This registers a handler to deal with channel flow notifications. -%% The registered process will receive #channel.flow{} commands. +%% The registered process will receive #channel.flow{} method. register_flow_handler(Channel, FlowHandler) -> gen_server:cast(Channel, {register_flow_handler, FlowHandler} ). From 90874610c99720de3211799f2301b44919c32c50 Mon Sep 17 00:00:00 2001 From: Matthew Sackman Date: Mon, 13 Sep 2010 17:41:12 +0100 Subject: [PATCH 31/31] Minor corrections --- deps/amqp_client/src/amqp_channel.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deps/amqp_client/src/amqp_channel.erl b/deps/amqp_client/src/amqp_channel.erl index 5134a30da8..0cdb1293cc 100644 --- a/deps/amqp_client/src/amqp_channel.erl +++ b/deps/amqp_client/src/amqp_channel.erl @@ -182,7 +182,7 @@ subscribe(Channel, BasicConsume = #'basic.consume'{}, Consumer) -> %% Channel = pid() %% ReturnHandler = pid() %% @doc This registers a handler to deal with returned messages. The -%% registered process will receive #basic.return{} methods. +%% registered process will receive #basic.return{} records. register_return_handler(Channel, ReturnHandler) -> gen_server:cast(Channel, {register_return_handler, ReturnHandler} ). @@ -191,7 +191,7 @@ register_return_handler(Channel, ReturnHandler) -> %% Channel = pid() %% FlowHandler = pid() %% @doc This registers a handler to deal with channel flow notifications. -%% The registered process will receive #channel.flow{} method. +%% The registered process will receive #channel.flow{} records. register_flow_handler(Channel, FlowHandler) -> gen_server:cast(Channel, {register_flow_handler, FlowHandler} ).