]> review.fuel-infra Code Review - packages/trusty/rabbitmq-server.git/commitdiff
Build rabbitmq 3.5.6 for ubuntu 83/14583/1
authorAlexey Lebedeff <alebedev@mirantis.com>
Thu, 10 Dec 2015 15:19:57 +0000 (18:19 +0300)
committerAlexey Lebedeff <alebedev@mirantis.com>
Thu, 10 Dec 2015 15:19:57 +0000 (18:19 +0300)
debian/ from http://archive.ubuntu.com/ubuntu/pool/main/r/rabbitmq-server/rabbitmq-server_3.5.4-1.debian.tar.xz
RabbitMQ source from https://www.rabbitmq.com/releases/rabbitmq-server/v3.5.6/rabbitmq-server-3.5.6.tar.gz

Tune rabbitmq 3.5.6 for MOS:
* Disable auto-start on package install.
* Increase ulimit on number of file descriptors.

Change-Id: I0c2fcc524caeb9bdc4c048166fed7299350198ec

109 files changed:
debian/LICENSE.head [deleted file]
debian/LICENSE.tail [deleted file]
debian/README [deleted file]
debian/changelog
debian/compat
debian/control
debian/copyright
debian/dirs [deleted file]
debian/gbp.conf [new file with mode: 0644]
debian/ocf/rabbitmq-server [moved from debian/rabbitmq-server.ocf with 100% similarity, mode: 0755]
debian/rabbitmq-env.conf [new file with mode: 0644]
debian/rabbitmq-script-wrapper [changed mode: 0644->0755]
debian/rabbitmq-server-wait [new file with mode: 0755]
debian/rabbitmq-server.default
debian/rabbitmq-server.dirs [new file with mode: 0644]
debian/rabbitmq-server.install [new file with mode: 0644]
debian/rabbitmq-server.links [new file with mode: 0644]
debian/rabbitmq-server.postinst [moved from debian/postinst with 100% similarity]
debian/rabbitmq-server.postrm [moved from debian/postrm.in with 100% similarity]
debian/rabbitmq-server.service [new file with mode: 0644]
debian/rules [changed mode: 0644->0755]
debian/watch
rabbitmq-server/Makefile
rabbitmq-server/codegen.py
rabbitmq-server/codegen/Makefile
rabbitmq-server/ebin/rabbit_app.in
rabbitmq-server/include/gm_specs.hrl
rabbitmq-server/include/rabbit.hrl
rabbitmq-server/include/rabbit_cli.hrl
rabbitmq-server/include/rabbit_msg_store.hrl
rabbitmq-server/plugins-src/rabbitmq-amqp1.0/src/rabbit_amqp1_0_reader.erl
rabbitmq-server/plugins-src/rabbitmq-amqp1.0/src/rabbit_amqp1_0_writer.erl
rabbitmq-server/plugins-src/rabbitmq-auth-backend-ldap/.travis.yml [new file with mode: 0644]
rabbitmq-server/plugins-src/rabbitmq-auth-backend-ldap/etc/rabbit-test.config
rabbitmq-server/plugins-src/rabbitmq-auth-backend-ldap/src/rabbit_auth_backend_ldap.erl
rabbitmq-server/plugins-src/rabbitmq-auth-backend-ldap/test/src/rabbit_auth_backend_ldap_test.erl
rabbitmq-server/plugins-src/rabbitmq-consistent-hash-exchange/.travis.yml [new file with mode: 0644]
rabbitmq-server/plugins-src/rabbitmq-consistent-hash-exchange/src/rabbit_exchange_type_consistent_hash.erl
rabbitmq-server/plugins-src/rabbitmq-consistent-hash-exchange/test/src/rabbit_exchange_type_consistent_hash_test.erl
rabbitmq-server/plugins-src/rabbitmq-erlang-client/rabbit_common.app.in
rabbitmq-server/plugins-src/rabbitmq-federation-management/priv/www/js/federation.js
rabbitmq-server/plugins-src/rabbitmq-federation/README [deleted file]
rabbitmq-server/plugins-src/rabbitmq-federation/README.md [new file with mode: 0644]
rabbitmq-server/plugins-src/rabbitmq-federation/src/rabbit_federation_queue_link.erl
rabbitmq-server/plugins-src/rabbitmq-federation/src/rabbit_federation_upstream.erl
rabbitmq-server/plugins-src/rabbitmq-management-visualiser/src/rabbit_visualiser_mgmt.erl
rabbitmq-server/plugins-src/rabbitmq-management/.travis.yml [new file with mode: 0644]
rabbitmq-server/plugins-src/rabbitmq-management/priv/www/js/formatters.js
rabbitmq-server/plugins-src/rabbitmq-management/src/rabbit_mgmt_format.erl
rabbitmq-server/plugins-src/rabbitmq-management/test/src/rabbitmqadmin-test.py
rabbitmq-server/plugins-src/rabbitmq-mqtt/package.mk
rabbitmq-server/plugins-src/rabbitmq-mqtt/src/rabbit_mqtt_processor.erl
rabbitmq-server/plugins-src/rabbitmq-mqtt/src/rabbit_mqtt_util.erl
rabbitmq-server/plugins-src/rabbitmq-mqtt/test/src/com/rabbitmq/mqtt/test/MqttTest.java
rabbitmq-server/plugins-src/rabbitmq-mqtt/test/src/com/rabbitmq/mqtt/test/tls/MqttSSLTest.java
rabbitmq-server/plugins-src/rabbitmq-mqtt/test/src/rabbit_mqtt_util_tests.erl [new file with mode: 0644]
rabbitmq-server/plugins-src/rabbitmq-mqtt/test/src/rabbitmq_mqtt_standalone.app.src [new file with mode: 0644]
rabbitmq-server/plugins-src/rabbitmq-stomp/.travis.yml [new file with mode: 0644]
rabbitmq-server/plugins-src/rabbitmq-stomp/deps/pika/Makefile [new file with mode: 0644]
rabbitmq-server/plugins-src/rabbitmq-stomp/include/rabbit_stomp_headers.hrl
rabbitmq-server/plugins-src/rabbitmq-stomp/package.mk
rabbitmq-server/plugins-src/rabbitmq-stomp/src/rabbit_stomp_frame.erl
rabbitmq-server/plugins-src/rabbitmq-stomp/src/rabbit_stomp_processor.erl
rabbitmq-server/plugins-src/rabbitmq-stomp/src/rabbit_stomp_util.erl
rabbitmq-server/plugins-src/rabbitmq-stomp/src/rabbitmq_stomp.app.src
rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/ack.py
rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/destinations.py
rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/errors.py
rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/parsing.py
rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/queue_properties.py [new file with mode: 0644]
rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/rabbit_stomp_client.erl
rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/rabbit_stomp_test.erl
rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/rabbit_stomp_test_frame.erl
rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/redelivered.py [new file with mode: 0644]
rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/test.py
rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/test_runner.py
rabbitmq-server/plugins-src/rabbitmq-test/Makefile
rabbitmq-server/plugins-src/rabbitmq-test/package.mk
rabbitmq-server/plugins-src/rabbitmq-test/test/src/clustering_management.erl
rabbitmq-server/plugins-src/rabbitmq-test/test/src/sync_detection.erl
rabbitmq-server/scripts/rabbitmq-defaults.bat
rabbitmq-server/scripts/rabbitmq-env.bat
rabbitmq-server/scripts/rabbitmq-server
rabbitmq-server/scripts/rabbitmq-service.bat
rabbitmq-server/src/credit_flow.erl
rabbitmq-server/src/file_handle_cache.erl
rabbitmq-server/src/gen_server2.erl
rabbitmq-server/src/gm.erl
rabbitmq-server/src/rabbit.erl
rabbitmq-server/src/rabbit_access_control.erl
rabbitmq-server/src/rabbit_amqqueue.erl
rabbitmq-server/src/rabbit_amqqueue_process.erl
rabbitmq-server/src/rabbit_auth_backend_internal.erl
rabbitmq-server/src/rabbit_authz_backend.erl
rabbitmq-server/src/rabbit_channel.erl
rabbitmq-server/src/rabbit_error_logger_file_h.erl
rabbitmq-server/src/rabbit_exchange_type_topic.erl
rabbitmq-server/src/rabbit_mirror_queue_slave.erl
rabbitmq-server/src/rabbit_msg_store.erl
rabbitmq-server/src/rabbit_networking.erl
rabbitmq-server/src/rabbit_queue_decorator.erl
rabbitmq-server/src/rabbit_queue_index.erl
rabbitmq-server/src/rabbit_reader.erl
rabbitmq-server/src/rabbit_table.erl
rabbitmq-server/src/rabbit_variable_queue.erl
rabbitmq-server/src/ssl_compat.erl [new file with mode: 0644]
rabbitmq-server/src/time_compat.erl [new file with mode: 0644]
rabbitmq-server/src/vm_memory_monitor.erl
rabbitmq-server/version.mk

diff --git a/debian/LICENSE.head b/debian/LICENSE.head
deleted file mode 100644 (file)
index 2b5a17e..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-This package, the RabbitMQ server is licensed under the MPL.
-
-If you have any questions regarding licensing, please contact us at
-info@rabbitmq.com.
-
diff --git a/debian/LICENSE.tail b/debian/LICENSE.tail
deleted file mode 100644 (file)
index 7858a04..0000000
+++ /dev/null
@@ -1,516 +0,0 @@
-
-The MIT license is as follows:
-
-        "Permission is hereby granted, free of charge, to any person
-        obtaining a copy of this file (the Software), to deal in the
-        Software without restriction, including without limitation the
-        rights to use, copy, modify, merge, publish, distribute,
-        sublicense, and/or sell copies of the Software, and to permit
-        persons to whom the Software is furnished to do so, subject to
-        the following conditions:
-
-        The above copyright notice and this permission notice shall be
-        included in all copies or substantial portions of the Software.
-
-        THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
-        EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-        OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-        NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-        HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-        WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-        FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-        OTHER DEALINGS IN THE SOFTWARE."
-
-
-The BSD 2-Clause license is as follows:
-
-        "Redistribution and use in source and binary forms, with or
-        without modification, are permitted provided that the
-        following conditions are met:
-
-        1. Redistributions of source code must retain the above
-        copyright notice, this list of conditions and the following
-        disclaimer.
-
-        2. Redistributions in binary form must reproduce the above
-        copyright notice, this list of conditions and the following
-        disclaimer in the documentation and/or other materials
-        provided with the distribution.
-
-        THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
-        CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
-        INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-        MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-        DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
-        CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-        SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-        NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-        LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-        HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-        CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-        OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
-        EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-
-
-The rest of this package is licensed under the Mozilla Public License 1.1
-Authors and Copyright are as described below:
-
-     The Initial Developer of the Original Code is GoPivotal, Inc.
-     Copyright (c) 2007-2014 GoPivotal, Inc.  All rights reserved.
-
-
-                          MOZILLA PUBLIC LICENSE
-                                Version 1.1
-
-                              ---------------
-
-1. Definitions.
-
-     1.0.1. "Commercial Use" means distribution or otherwise making the
-     Covered Code available to a third party.
-
-     1.1. "Contributor" means each entity that creates or contributes to
-     the creation of Modifications.
-
-     1.2. "Contributor Version" means the combination of the Original
-     Code, prior Modifications used by a Contributor, and the Modifications
-     made by that particular Contributor.
-
-     1.3. "Covered Code" means the Original Code or Modifications or the
-     combination of the Original Code and Modifications, in each case
-     including portions thereof.
-
-     1.4. "Electronic Distribution Mechanism" means a mechanism generally
-     accepted in the software development community for the electronic
-     transfer of data.
-
-     1.5. "Executable" means Covered Code in any form other than Source
-     Code.
-
-     1.6. "Initial Developer" means the individual or entity identified
-     as the Initial Developer in the Source Code notice required by Exhibit
-     A.
-
-     1.7. "Larger Work" means a work which combines Covered Code or
-     portions thereof with code not governed by the terms of this License.
-
-     1.8. "License" means this document.
-
-     1.8.1. "Licensable" means having the right to grant, to the maximum
-     extent possible, whether at the time of the initial grant or
-     subsequently acquired, any and all of the rights conveyed herein.
-
-     1.9. "Modifications" means any addition to or deletion from the
-     substance or structure of either the Original Code or any previous
-     Modifications. When Covered Code is released as a series of files, a
-     Modification is:
-          A. Any addition to or deletion from the contents of a file
-          containing Original Code or previous Modifications.
-
-          B. Any new file that contains any part of the Original Code or
-          previous Modifications.
-
-     1.10. "Original Code" means Source Code of computer software code
-     which is described in the Source Code notice required by Exhibit A as
-     Original Code, and which, at the time of its release under this
-     License is not already Covered Code governed by this License.
-
-     1.10.1. "Patent Claims" means any patent claim(s), now owned or
-     hereafter acquired, including without limitation,  method, process,
-     and apparatus claims, in any patent Licensable by grantor.
-
-     1.11. "Source Code" means the preferred form of the Covered Code for
-     making modifications to it, including all modules it contains, plus
-     any associated interface definition files, scripts used to control
-     compilation and installation of an Executable, or source code
-     differential comparisons against either the Original Code or another
-     well known, available Covered Code of the Contributor's choice. The
-     Source Code can be in a compressed or archival form, provided the
-     appropriate decompression or de-archiving software is widely available
-     for no charge.
-
-     1.12. "You" (or "Your")  means an individual or a legal entity
-     exercising rights under, and complying with all of the terms of, this
-     License or a future version of this License issued under Section 6.1.
-     For legal entities, "You" includes any entity which controls, is
-     controlled by, or is under common control with You. For purposes of
-     this definition, "control" means (a) the power, direct or indirect,
-     to cause the direction or management of such entity, whether by
-     contract or otherwise, or (b) ownership of more than fifty percent
-     (50%) of the outstanding shares or beneficial ownership of such
-     entity.
-
-2. Source Code License.
-
-     2.1. The Initial Developer Grant.
-     The Initial Developer hereby grants You a world-wide, royalty-free,
-     non-exclusive license, subject to third party intellectual property
-     claims:
-          (a)  under intellectual property rights (other than patent or
-          trademark) Licensable by Initial Developer to use, reproduce,
-          modify, display, perform, sublicense and distribute the Original
-          Code (or portions thereof) with or without Modifications, and/or
-          as part of a Larger Work; and
-
-          (b) under Patents Claims infringed by the making, using or
-          selling of Original Code, to make, have made, use, practice,
-          sell, and offer for sale, and/or otherwise dispose of the
-          Original Code (or portions thereof).
-
-          (c) the licenses granted in this Section 2.1(a) and (b) are
-          effective on the date Initial Developer first distributes
-          Original Code under the terms of this License.
-
-          (d) Notwithstanding Section 2.1(b) above, no patent license is
-          granted: 1) for code that You delete from the Original Code; 2)
-          separate from the Original Code;  or 3) for infringements caused
-          by: i) the modification of the Original Code or ii) the
-          combination of the Original Code with other software or devices.
-
-     2.2. Contributor Grant.
-     Subject to third party intellectual property claims, each Contributor
-     hereby grants You a world-wide, royalty-free, non-exclusive license
-
-          (a)  under intellectual property rights (other than patent or
-          trademark) Licensable by Contributor, to use, reproduce, modify,
-          display, perform, sublicense and distribute the Modifications
-          created by such Contributor (or portions thereof) either on an
-          unmodified basis, with other Modifications, as Covered Code
-          and/or as part of a Larger Work; and
-
-          (b) under Patent Claims infringed by the making, using, or
-          selling of  Modifications made by that Contributor either alone
-          and/or in combination with its Contributor Version (or portions
-          of such combination), to make, use, sell, offer for sale, have
-          made, and/or otherwise dispose of: 1) Modifications made by that
-          Contributor (or portions thereof); and 2) the combination of
-          Modifications made by that Contributor with its Contributor
-          Version (or portions of such combination).
-
-          (c) the licenses granted in Sections 2.2(a) and 2.2(b) are
-          effective on the date Contributor first makes Commercial Use of
-          the Covered Code.
-
-          (d)    Notwithstanding Section 2.2(b) above, no patent license is
-          granted: 1) for any code that Contributor has deleted from the
-          Contributor Version; 2)  separate from the Contributor Version;
-          3)  for infringements caused by: i) third party modifications of
-          Contributor Version or ii)  the combination of Modifications made
-          by that Contributor with other software  (except as part of the
-          Contributor Version) or other devices; or 4) under Patent Claims
-          infringed by Covered Code in the absence of Modifications made by
-          that Contributor.
-
-3. Distribution Obligations.
-
-     3.1. Application of License.
-     The Modifications which You create or to which You contribute are
-     governed by the terms of this License, including without limitation
-     Section 2.2. The Source Code version of Covered Code may be
-     distributed only under the terms of this License or a future version
-     of this License released under Section 6.1, and You must include a
-     copy of this License with every copy of the Source Code You
-     distribute. You may not offer or impose any terms on any Source Code
-     version that alters or restricts the applicable version of this
-     License or the recipients' rights hereunder. However, You may include
-     an additional document offering the additional rights described in
-     Section 3.5.
-
-     3.2. Availability of Source Code.
-     Any Modification which You create or to which You contribute must be
-     made available in Source Code form under the terms of this License
-     either on the same media as an Executable version or via an accepted
-     Electronic Distribution Mechanism to anyone to whom you made an
-     Executable version available; and if made available via Electronic
-     Distribution Mechanism, must remain available for at least twelve (12)
-     months after the date it initially became available, or at least six
-     (6) months after a subsequent version of that particular Modification
-     has been made available to such recipients. You are responsible for
-     ensuring that the Source Code version remains available even if the
-     Electronic Distribution Mechanism is maintained by a third party.
-
-     3.3. Description of Modifications.
-     You must cause all Covered Code to which You contribute to contain a
-     file documenting the changes You made to create that Covered Code and
-     the date of any change. You must include a prominent statement that
-     the Modification is derived, directly or indirectly, from Original
-     Code provided by the Initial Developer and including the name of the
-     Initial Developer in (a) the Source Code, and (b) in any notice in an
-     Executable version or related documentation in which You describe the
-     origin or ownership of the Covered Code.
-
-     3.4. Intellectual Property Matters
-          (a) Third Party Claims.
-          If Contributor has knowledge that a license under a third party's
-          intellectual property rights is required to exercise the rights
-          granted by such Contributor under Sections 2.1 or 2.2,
-          Contributor must include a text file with the Source Code
-          distribution titled "LEGAL" which describes the claim and the
-          party making the claim in sufficient detail that a recipient will
-          know whom to contact. If Contributor obtains such knowledge after
-          the Modification is made available as described in Section 3.2,
-          Contributor shall promptly modify the LEGAL file in all copies
-          Contributor makes available thereafter and shall take other steps
-          (such as notifying appropriate mailing lists or newsgroups)
-          reasonably calculated to inform those who received the Covered
-          Code that new knowledge has been obtained.
-
-          (b) Contributor APIs.
-          If Contributor's Modifications include an application programming
-          interface and Contributor has knowledge of patent licenses which
-          are reasonably necessary to implement that API, Contributor must
-          also include this information in the LEGAL file.
-
-               (c)    Representations.
-          Contributor represents that, except as disclosed pursuant to
-          Section 3.4(a) above, Contributor believes that Contributor's
-          Modifications are Contributor's original creation(s) and/or
-          Contributor has sufficient rights to grant the rights conveyed by
-          this License.
-
-     3.5. Required Notices.
-     You must duplicate the notice in Exhibit A in each file of the Source
-     Code.  If it is not possible to put such notice in a particular Source
-     Code file due to its structure, then You must include such notice in a
-     location (such as a relevant directory) where a user would be likely
-     to look for such a notice.  If You created one or more Modification(s)
-     You may add your name as a Contributor to the notice described in
-     Exhibit A.  You must also duplicate this License in any documentation
-     for the Source Code where You describe recipients' rights or ownership
-     rights relating to Covered Code.  You may choose to offer, and to
-     charge a fee for, warranty, support, indemnity or liability
-     obligations to one or more recipients of Covered Code. However, You
-     may do so only on Your own behalf, and not on behalf of the Initial
-     Developer or any Contributor. You must make it absolutely clear than
-     any such warranty, support, indemnity or liability obligation is
-     offered by You alone, and You hereby agree to indemnify the Initial
-     Developer and every Contributor for any liability incurred by the
-     Initial Developer or such Contributor as a result of warranty,
-     support, indemnity or liability terms You offer.
-
-     3.6. Distribution of Executable Versions.
-     You may distribute Covered Code in Executable form only if the
-     requirements of Section 3.1-3.5 have been met for that Covered Code,
-     and if You include a notice stating that the Source Code version of
-     the Covered Code is available under the terms of this License,
-     including a description of how and where You have fulfilled the
-     obligations of Section 3.2. The notice must be conspicuously included
-     in any notice in an Executable version, related documentation or
-     collateral in which You describe recipients' rights relating to the
-     Covered Code. You may distribute the Executable version of Covered
-     Code or ownership rights under a license of Your choice, which may
-     contain terms different from this License, provided that You are in
-     compliance with the terms of this License and that the license for the
-     Executable version does not attempt to limit or alter the recipient's
-     rights in the Source Code version from the rights set forth in this
-     License. If You distribute the Executable version under a different
-     license You must make it absolutely clear that any terms which differ
-     from this License are offered by You alone, not by the Initial
-     Developer or any Contributor. You hereby agree to indemnify the
-     Initial Developer and every Contributor for any liability incurred by
-     the Initial Developer or such Contributor as a result of any such
-     terms You offer.
-
-     3.7. Larger Works.
-     You may create a Larger Work by combining Covered Code with other code
-     not governed by the terms of this License and distribute the Larger
-     Work as a single product. In such a case, You must make sure the
-     requirements of this License are fulfilled for the Covered Code.
-
-4. Inability to Comply Due to Statute or Regulation.
-
-     If it is impossible for You to comply with any of the terms of this
-     License with respect to some or all of the Covered Code due to
-     statute, judicial order, or regulation then You must: (a) comply with
-     the terms of this License to the maximum extent possible; and (b)
-     describe the limitations and the code they affect. Such description
-     must be included in the LEGAL file described in Section 3.4 and must
-     be included with all distributions of the Source Code. Except to the
-     extent prohibited by statute or regulation, such description must be
-     sufficiently detailed for a recipient of ordinary skill to be able to
-     understand it.
-
-5. Application of this License.
-
-     This License applies to code to which the Initial Developer has
-     attached the notice in Exhibit A and to related Covered Code.
-
-6. Versions of the License.
-
-     6.1. New Versions.
-     Netscape Communications Corporation ("Netscape") may publish revised
-     and/or new versions of the License from time to time. Each version
-     will be given a distinguishing version number.
-
-     6.2. Effect of New Versions.
-     Once Covered Code has been published under a particular version of the
-     License, You may always continue to use it under the terms of that
-     version. You may also choose to use such Covered Code under the terms
-     of any subsequent version of the License published by Netscape. No one
-     other than Netscape has the right to modify the terms applicable to
-     Covered Code created under this License.
-
-     6.3. Derivative Works.
-     If You create or use a modified version of this License (which you may
-     only do in order to apply it to code which is not already Covered Code
-     governed by this License), You must (a) rename Your license so that
-     the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape",
-     "MPL", "NPL" or any confusingly similar phrase do not appear in your
-     license (except to note that your license differs from this License)
-     and (b) otherwise make it clear that Your version of the license
-     contains terms which differ from the Mozilla Public License and
-     Netscape Public License. (Filling in the name of the Initial
-     Developer, Original Code or Contributor in the notice described in
-     Exhibit A shall not of themselves be deemed to be modifications of
-     this License.)
-
-7. DISCLAIMER OF WARRANTY.
-
-     COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
-     WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
-     WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF
-     DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.
-     THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE
-     IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,
-     YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
-     COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER
-     OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
-     ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
-
-8. TERMINATION.
-
-     8.1.  This License and the rights granted hereunder will terminate
-     automatically if You fail to comply with terms herein and fail to cure
-     such breach within 30 days of becoming aware of the breach. All
-     sublicenses to the Covered Code which are properly granted shall
-     survive any termination of this License. Provisions which, by their
-     nature, must remain in effect beyond the termination of this License
-     shall survive.
-
-     8.2.  If You initiate litigation by asserting a patent infringement
-     claim (excluding declatory judgment actions) against Initial Developer
-     or a Contributor (the Initial Developer or Contributor against whom
-     You file such action is referred to as "Participant")  alleging that:
-
-     (a)  such Participant's Contributor Version directly or indirectly
-     infringes any patent, then any and all rights granted by such
-     Participant to You under Sections 2.1 and/or 2.2 of this License
-     shall, upon 60 days notice from Participant terminate prospectively,
-     unless if within 60 days after receipt of notice You either: (i)
-     agree in writing to pay Participant a mutually agreeable reasonable
-     royalty for Your past and future use of Modifications made by such
-     Participant, or (ii) withdraw Your litigation claim with respect to
-     the Contributor Version against such Participant.  If within 60 days
-     of notice, a reasonable royalty and payment arrangement are not
-     mutually agreed upon in writing by the parties or the litigation claim
-     is not withdrawn, the rights granted by Participant to You under
-     Sections 2.1 and/or 2.2 automatically terminate at the expiration of
-     the 60 day notice period specified above.
-
-     (b)  any software, hardware, or device, other than such Participant's
-     Contributor Version, directly or indirectly infringes any patent, then
-     any rights granted to You by such Participant under Sections 2.1(b)
-     and 2.2(b) are revoked effective as of the date You first made, used,
-     sold, distributed, or had made, Modifications made by that
-     Participant.
-
-     8.3.  If You assert a patent infringement claim against Participant
-     alleging that such Participant's Contributor Version directly or
-     indirectly infringes any patent where such claim is resolved (such as
-     by license or settlement) prior to the initiation of patent
-     infringement litigation, then the reasonable value of the licenses
-     granted by such Participant under Sections 2.1 or 2.2 shall be taken
-     into account in determining the amount or value of any payment or
-     license.
-
-     8.4.  In the event of termination under Sections 8.1 or 8.2 above,
-     all end user license agreements (excluding distributors and resellers)
-     which have been validly granted by You or any distributor hereunder
-     prior to termination shall survive termination.
-
-9. LIMITATION OF LIABILITY.
-
-     UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
-     (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL
-     DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,
-     OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR
-     ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
-     CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL,
-     WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
-     COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
-     INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
-     LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
-     RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW
-     PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
-     EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
-     THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
-
-10. U.S. GOVERNMENT END USERS.
-
-     The Covered Code is a "commercial item," as that term is defined in
-     48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
-     software" and "commercial computer software documentation," as such
-     terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48
-     C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
-     all U.S. Government End Users acquire Covered Code with only those
-     rights set forth herein.
-
-11. MISCELLANEOUS.
-
-     This License represents the complete agreement concerning subject
-     matter hereof. If any provision of this License is held to be
-     unenforceable, such provision shall be reformed only to the extent
-     necessary to make it enforceable. This License shall be governed by
-     California law provisions (except to the extent applicable law, if
-     any, provides otherwise), excluding its conflict-of-law provisions.
-     With respect to disputes in which at least one party is a citizen of,
-     or an entity chartered or registered to do business in the United
-     States of America, any litigation relating to this License shall be
-     subject to the jurisdiction of the Federal Courts of the Northern
-     District of California, with venue lying in Santa Clara County,
-     California, with the losing party responsible for costs, including
-     without limitation, court costs and reasonable attorneys' fees and
-     expenses. The application of the United Nations Convention on
-     Contracts for the International Sale of Goods is expressly excluded.
-     Any law or regulation which provides that the language of a contract
-     shall be construed against the drafter shall not apply to this
-     License.
-
-12. RESPONSIBILITY FOR CLAIMS.
-
-     As between Initial Developer and the Contributors, each party is
-     responsible for claims and damages arising, directly or indirectly,
-     out of its utilization of rights under this License and You agree to
-     work with Initial Developer and Contributors to distribute such
-     responsibility on an equitable basis. Nothing herein is intended or
-     shall be deemed to constitute any admission of liability.
-
-13. MULTIPLE-LICENSED CODE.
-
-     Initial Developer may designate portions of the Covered Code as
-     "Multiple-Licensed".  "Multiple-Licensed" means that the Initial
-     Developer permits you to utilize portions of the Covered Code under
-     Your choice of the NPL or the alternative licenses, if any, specified
-     by the Initial Developer in the file described in Exhibit A.
-
-EXHIBIT A -Mozilla Public License.
-
-     ``The contents of this file are subject to the Mozilla Public License
-     Version 1.1 (the "License"); you may not use this file except in
-     compliance with the License. You may obtain a copy of the License at
-     http://www.mozilla.org/MPL/
-
-     Software distributed under the License is distributed on an "AS IS"
-     basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
-     License for the specific language governing rights and limitations
-     under the License.
-
-     The Original Code is RabbitMQ.
-
-     The Initial Developer of the Original Code is GoPivotal, Inc.
-     Copyright (c) 2007-2014 GoPivotal, Inc.  All rights reserved.''
-
-     [NOTE: The text of this Exhibit A may differ slightly from the text of
-     the notices in the Source Code files of the Original Code. You should
-     use the text of this Exhibit A rather than the text found in the
-     Original Code Source Code for Your Modifications.]
diff --git a/debian/README b/debian/README
deleted file mode 100644 (file)
index 0a29ee2..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-This is rabbitmq-server, a message broker implementing AMQP, STOMP and MQTT.
-
-Most of the documentation for RabbitMQ is provided on the RabbitMQ web
-site. You can see documentation for the current version at:
-
-http://www.rabbitmq.com/documentation.html
-
-and for previous versions at:
-
-http://www.rabbitmq.com/previous.html
-
-Man pages are installed with this package. Of particular interest are
-rabbitmqctl(1), to interact with a running RabbitMQ server, and
-rabbitmq-plugins(1), to enable and disable plugins. These should be
-run as the superuser.
-
-An example configuration file is provided in the same directory as
-this README. Copy it to /etc/rabbitmq/rabbitmq.config to use it. The
-RabbitMQ server must be restarted after changing the configuration
-file or enabling or disabling plugins.
index 31751f93a74992019ed113215c635f4c50b6af54..993b3543819162a16928fffabbff676c0c5f3f14 100644 (file)
-rabbitmq-server (3.5.4-1~u14.04+mos2) mos7.0; urgency=medium
+rabbitmq-server (3.5.6-1~u14.04+mos1) mos8.0; urgency=medium
 
-  * Fall back to original MOS 7.0 package
+  * New upstream release.
+  * Disable auto-start on package install.
+  * Increase ulimit on number of file descriptors.
 
- -- Dmitry Mescheryakov <dmescheryakov@mirantis.com>  Thu, 07 Aug 2015 22:03:00 +0300
+ -- Alexey Lebedeff <alebedev@mirantis.com>  Fri, 16 Oct 2015 13:59:11 +0300
 
-rabbitmq-server (3.5.4-1~u14.04+mos1) mos7.0; urgency=medium
+rabbitmq-server (3.5.4-1) unstable; urgency=medium
 
-  * Pick the source from Debian Sid, changes:
-    - build-depend on default version of dh-systemd;
-    - changelog was taken from original package;
+  * New upstream release.
 
- -- Aleksandr Mogylchenko <amogylchenko@mirantis.com>  Thu, 06 Aug 2015 23:00:41 +0200
+ -- James Page <james.page@ubuntu.com>  Tue, 04 Aug 2015 14:52:31 +0200
 
-rabbitmq-server (3.3.5-1~u14.04+mos2) mos7.0; urgency=medium
+rabbitmq-server (3.5.1-2) unstable; urgency=medium
 
-  * Repackaged for 7.0
+  [ Tony Breeds ]
+  * systemd: Ensure that rabbitmq has started before marking service as
+    running (LP: #1449056).
 
- -- Artem Silenkov <asilenkov@mirantis.com>  Wed, 24 Jun 2015 21:10:35 +0300
+  [ James Page ]
+  * systemd: Drop use of /etc/default/rabbitmq-server.
 
-rabbitmq-server (3.3.5-1~u14.04+mos1) mos6.1; urgency=medium
+ -- James Page <james.page@ubuntu.com>  Tue, 02 Jun 2015 11:40:59 +0100
 
-  * Adjust the package revision according to the versioning policy
-    stated in the separate-mos-from-linux blueprint.
+rabbitmq-server (3.5.1-1) unstable; urgency=medium
 
- -- Alexei Sheplyakov <asheplyakov@mirantis.com>  Thu, 09 Apr 2015 16:33:12 +0300
+  * New upstream release.
 
-rabbitmq-server (3.3.5-1~mos6.1+0b1) trusty; urgency=low
+ -- James Page <james.page@ubuntu.com>  Wed, 13 May 2015 21:35:52 +0100
 
-  * Minor packaging fixes; no actual code changes:
-    - rename the source directory (make it unversioned)
-    - fix the package meta-data (proper Maintainer, etc)
+rabbitmq-server (3.4.3-2) unstable; urgency=medium
 
- -- Alexei Sheplyakov <asheplyakov@mirantis.com>  Fri, 27 Mar 2015 14:43:20 +0300
+  * Restore missing changes from 3.4.2-4.
 
-rabbitmq-server (3.3.5-1~mos6.1) trusty; urgency=low
+ -- James Page <james.page@ubuntu.com>  Mon, 02 Feb 2015 07:44:33 +0200
 
-  * Pick the source from packages/precise/rabbitmq-server, commit
-    55fbf9f2223244c363790e84913232adf9fed990.
-  * Bump the version for MOS 6.1
+rabbitmq-server (3.4.3-1) unstable; urgency=medium
 
- -- Alexei Sheplyakov <asheplyakov@mirantis.com>  Wed, 28 Jan 2015 17:48:06 +0300
+  * New upstream point release.
 
-rabbitmq-server (3.3.5-1) unstable; urgency=low
+ -- James Page <james.page@ubuntu.com>  Wed, 28 Jan 2015 16:12:32 +0000
 
-  * New Upstream Release
-  * Changed Uploaders from Emile Joubert to Blair Hester
+rabbitmq-server (3.4.2-4) unstable; urgency=medium
 
- -- Simon MacMullen <simon@rabbitmq.com>  Mon, 11 Aug 2014 12:23:31 +0100
+  * Re-added /usr/lib/erlang/lib /var/lib/rabbitmq/mnesia and
+    /var/log/rabbitmq which I removed form the package by mistake on the last
+    upload.
 
-rabbitmq-server (3.3.4-1) unstable; urgency=low
+ -- Thomas Goirand <zigo@debian.org>  Wed, 28 Jan 2015 13:11:02 +0000
 
-  * New Upstream Release
+rabbitmq-server (3.4.2-3) unstable; urgency=medium
 
- -- Simon MacMullen <simon@rabbitmq.com>  Tue, 24 Jun 2014 12:50:29 +0100
+  * Removes debian/README which is useless (Closes: #703021).
+  * Provides a default /etc/rabbitmq/rabbitmq-env.conf (Closes: #543638).
 
-rabbitmq-server (3.3.3-1) unstable; urgency=low
+ -- Thomas Goirand <zigo@debian.org>  Tue, 27 Jan 2015 15:08:08 +0100
 
-  * New Upstream Release
+rabbitmq-server (3.4.2-2) unstable; urgency=medium
 
- -- Simon MacMullen <simon@rabbitmq.com>  Mon, 16 Jun 2014 13:00:00 +0100
+  * d/rabbitmq-server.dirs: Restore missing /etc/rabbitmq directory
+    (LP: #1410155).
 
-rabbitmq-server (3.3.2-1) unstable; urgency=low
+ -- James Page <james.page@ubuntu.com>  Tue, 13 Jan 2015 09:53:47 +0000
 
-  * New Upstream Release
+rabbitmq-server (3.4.2-1) unstable; urgency=medium
+
+  [ James Page ]
+  * New upstream point release.
+  * d/control: Update for new maintainer information, add VCS repository
+    locations.
+  * d/source/format: Switch packaging to source format 3.0 (quilt).
+  * d/compat,control: Bump debhelper compat level to 9.
+  * d/*: wrap-and-sort.
+  * d/*: Move to standard debhelper, drop use of cdbs.
+  * d/rules,control,rabbitmq-server.service: Add systemd service
+    configuration.
+  * d/control: Bumped Standards-Version 3.9.6, no changes.
+
+  [ Thomas Goirand ]
+  * d/copyright: Rewrote as format 1.0.
+
+ -- James Page <james.page@ubuntu.com>  Fri, 19 Dec 2014 11:09:20 +0000
+
+rabbitmq-server (3.4.1-1) unstable; urgency=high
+
+  * New upstream release.
+
+ -- Blair Hester <bhester@gopivotal.com>  Tue, 04 Nov 2014 07:33:44 +0100
+
+rabbitmq-server (3.3.5-1) unstable; urgency=low
+
+  * New upstream release:
+    - Provides unminimized versions of all bundled Javascript
+      libraries (Closes: #736781).
+  * d/control: Added Blair Hester to Uploaders, dropped Emile Joubert 
+    (thanks for all your work Emile!).
+
+ -- Blair Hester <bhester@gopivotal.com>  Tue, 12 Aug 2014 11:47:14 +0100
 
- -- Simon MacMullen <simon@rabbitmq.com>  Mon, 09 Jun 2014 10:25:22 +0100
+rabbitmq-server (3.3.4-1) unstable; urgency=low
+
+  * New upstream release
+
+ -- Emile Joubert <emile@rabbitmq.com>  Tue, 24 Jun 2014 18:00:48 +0100
+
+rabbitmq-server (3.3.3-1) unstable; urgency=low
+
+  * New upstream release
+
+ -- Emile Joubert <emile@rabbitmq.com>  Tue, 17 Jun 2014 16:59:14 +0100
 
 rabbitmq-server (3.3.1-1) unstable; urgency=low
 
-  * New Upstream Release
+  * New upstream release
 
- -- Simon MacMullen <simon@rabbitmq.com>  Tue, 29 Apr 2014 11:49:23 +0100
+ -- Emile Joubert <emile@rabbitmq.com>  Tue, 29 Apr 2014 21:05:49 +0100
 
 rabbitmq-server (3.3.0-1) unstable; urgency=low
 
-  * New Upstream Release
+  * New upstream release
 
- -- Simon MacMullen <simon@rabbitmq.com>  Wed, 02 Apr 2014 14:23:14 +0100
+ -- Emile Joubert <emile@rabbitmq.com>  Wed, 02 Apr 2014 16:23:08 +0100
 
-rabbitmq-server (3.2.4-1) unstable; urgency=low
+rabbitmq-server (3.2.4-1.1) unstable; urgency=high
 
-  * New Upstream Release
+  * Non-maintainer upload.
+  * Bind on 127.0.0.1 by default, to avoid listening on all ipv6 interface with
+    guest/guest as default configured user. Note that this only fixes *new*
+    installation, and that any already existing setup will have to edit the
+    /etc/rabbitmq/rabbitmq-env.conf manually if affected. (Closes: #727607)
+  * Removed useless and deprecated DM-Upload field.
+  * Cleans plugins-src/rabbitmq-server to be able to build twice. Also cleans
+    debian/postrm which is generated from debian/postrm.in and plugins/README.
 
- -- Simon MacMullen <simon@rabbitmq.com>  Mon, 03 Mar 2014 14:50:18 +0000
+ -- Thomas Goirand <zigo@debian.org>  Mon, 31 Mar 2014 06:11:46 +0000
 
-rabbitmq-server (3.2.3-1+mira.1) precise; urgency=low
+rabbitmq-server (3.2.4-1) unstable; urgency=low
 
-  * Disable rabbitmq-server autostart
+  * New upstream release
 
- -- Vladimir Kuklin <vkuklin@mirantis.com>  Thu, 10 Jul 2014 14:01:02 +0400
+ -- Emile Joubert <emile@rabbitmq.com>  Tue, 04 Mar 2014 13:21:45 +0000
 
 rabbitmq-server (3.2.3-1) unstable; urgency=low
 
-  [ Emile Joubert ]
-  * New Upstream Release
-
-  [ Vladimir Kuklin ]
-  * +mira
+  * New upstream release
 
- -- Vladimir Kuklin <vvk@vvk-workstation>  Thu, 10 Jul 2014 14:00:41 +0400
+ -- Emile Joubert <emile@rabbitmq.com>  Thu, 23 Jan 2014 16:49:45 +0000
 
 rabbitmq-server (3.2.2-1) unstable; urgency=low
 
-  * New Upstream Release
+  * New upstream release
+
+ -- Emile Joubert <emile@rabbitmq.com>  Wed, 11 Dec 2013 17:31:14 +0000
+
+rabbitmq-server (3.2.1-1) unstable; urgency=low
+
+  * New upstream release
 
- -- Emile Joubert <emile@rabbitmq.com>  Tue, 10 Dec 2013 16:08:08 +0000
+ -- Emile Joubert <emile@rabbitmq.com>  Mon, 11 Nov 2013 09:49:42 +0000
 
 rabbitmq-server (3.2.0-1) unstable; urgency=low
 
-  * New Upstream Release
+  * New upstream release
 
- -- Emile Joubert <emile@rabbitmq.com>  Wed, 23 Oct 2013 12:44:10 +0100
+ -- Emile Joubert <emile@rabbitmq.com>  Wed, 23 Oct 2013 15:42:19 +0100
 
-rabbitmq-server (3.1.5-1) unstable; urgency=low
+rabbitmq-server (3.1.4-1) unstable; urgency=low
 
-  * New Upstream Release
+  * New upstream release
 
- -- Simon MacMullen <simon@rabbitmq.com>  Thu, 15 Aug 2013 11:03:13 +0100
+ -- Emile Joubert <emile@rabbitmq.com>  Thu, 07 Aug 2013 15:16:28 +0100
 
 rabbitmq-server (3.1.3-1) unstable; urgency=low
 
-  * New Upstream Release
+  * New upstream release
 
- -- Tim Watson <tim@rabbitmq.com>  Tue, 25 Jun 2013 15:01:12 +0100
+ -- Emile Joubert <emile@rabbitmq.com>  Thu, 27 Jun 2013 14:06:11 +0100
 
 rabbitmq-server (3.1.2-1) unstable; urgency=low
 
-  * New Upstream Release
+  * New upstream release
 
- -- Tim Watson <tim@rabbitmq.com>  Mon, 24 Jun 2013 11:16:41 +0100
+ -- Emile Joubert <emile@rabbitmq.com>  Thu, 25 Jun 2013 11:28:52 +0100
 
 rabbitmq-server (3.1.1-1) unstable; urgency=low
 
-  * Test release
+  * New upstream release
 
- -- Tim Watson <tim@rabbitmq.com>  Mon, 20 May 2013 16:21:20 +0100
+ -- Emile Joubert <emile@rabbitmq.com>  Thu, 28 May 2013 11:15:13 +0100
 
 rabbitmq-server (3.1.0-1) unstable; urgency=low
 
-  * New Upstream Release
+  * New upstream release
+
+ -- Emile Joubert <emile@rabbitmq.com>  Thu, 02 May 2013 11:19:31 +0100
+
+rabbitmq-server (3.0.4-1) unstable; urgency=low
+
+  * New upstream release
+
+ -- Emile Joubert <emile@rabbitmq.com>  Wed, 13 Mar 2013 10:53:18 +0000
+
+rabbitmq-server (3.0.4-1) unstable; urgency=low
+
+  * New upstream release
+
+ -- Emile Joubert <emile@rabbitmq.com>  Wed, 13 Mar 2013 10:53:18 +0000
+
+rabbitmq-server (3.0.3-1) unstable; urgency=low
+
+  * New upstream release
+
+ -- Emile Joubert <emile@rabbitmq.com>  Thu, 07 Mar 2013 10:03:31 +0000
 
- -- Simon MacMullen <simon@rabbitmq.com>  Wed, 01 May 2013 11:57:58 +0100
+rabbitmq-server (3.0.2-1) unstable; urgency=low
+
+  * New upstream release
+
+ -- Emile Joubert <emile@rabbitmq.com>  Tue, 31 Jan 2013 15:28:12 +0000
 
 rabbitmq-server (3.0.1-1) unstable; urgency=low
 
-  * New Upstream Release
+  * New upstream release
 
- -- Simon MacMullen <simon@rabbitmq.com>  Tue, 11 Dec 2012 11:29:55 +0000
+ -- Emile Joubert <emile@rabbitmq.com>  Tue, 11 Dec 2012 15:47:52 +0000
 
 rabbitmq-server (3.0.0-1) unstable; urgency=low
 
-  * New Upstream Release
+  * New upstream release
 
- -- Simon MacMullen <simon@rabbitmq.com>  Fri, 16 Nov 2012 14:15:29 +0000
+ -- Emile Joubert <emile@rabbitmq.com>  Mon, 19 Nov 2012 11:42:31 +0000
 
-rabbitmq-server (2.7.1-1) natty; urgency=low
+rabbitmq-server (2.8.7-1) unstable; urgency=low
 
-  * New Upstream Release
+  * New upstream release
 
- -- Steve Powell <steve@rabbitmq.com>  Fri, 16 Dec 2011 12:12:36 +0000
+ -- Emile Joubert <emile@rabbitmq.com>  Thu, 27 Sep 2012 16:28:21 +0100
 
-rabbitmq-server (2.7.0-1) natty; urgency=low
+rabbitmq-server (2.8.6-1) unstable; urgency=low
 
-  * New Upstream Release
+  * New upstream release
 
- -- Steve Powell <steve@rabbitmq.com>  Tue, 08 Nov 2011 16:47:50 +0000
+ -- Emile Joubert <emile@rabbitmq.com>  Wed, 22 Aug 2012 13:28:21 +0100
 
-rabbitmq-server (2.6.1-1) natty; urgency=low
+rabbitmq-server (2.8.5-1) unstable; urgency=low
 
-  * New Upstream Release
+  * New upstream release
 
- -- Tim <tim@rabbitmq.com>  Fri, 09 Sep 2011 14:38:45 +0100
+ -- Emile Joubert <emile@rabbitmq.com>  Thu, 02 Aug 2012 16:12:21 +0100
 
-rabbitmq-server (2.6.0-1) natty; urgency=low
+rabbitmq-server (2.8.4-1) unstable; urgency=low
 
-  * New Upstream Release
+  * New upstream release
 
- -- Tim <tim@rabbitmq.com>  Fri, 26 Aug 2011 16:29:40 +0100
+ -- Emile Joubert <emile@rabbitmq.com>  Fri, 22 Jun 2012 17:48:28 +0100
 
-rabbitmq-server (2.5.1-1) lucid; urgency=low
+rabbitmq-server (2.8.3-1) unstable; urgency=low
 
-  * New Upstream Release
+  * New upstream release
 
- -- Simon MacMullen <simon@rabbitmq.com>  Mon, 27 Jun 2011 11:21:49 +0100
+ -- Emile Joubert <emile@rabbitmq.com>  Thu, 21 Jun 2012 13:38:57 +0100
 
-rabbitmq-server (2.5.0-1) lucid; urgency=low
+rabbitmq-server (2.8.2-2) unstable; urgency=low
 
-  * New Upstream Release
+  * Add version numbers to plugins
 
- --  <jerryk@vmware.com>  Thu, 09 Jun 2011 07:20:29 -0700
+ -- Emile Joubert <emile@rabbitmq.com>  Tue, 01 May 2012 10:48:57 +0100
 
-rabbitmq-server (2.4.1-1) lucid; urgency=low
+rabbitmq-server (2.8.2-1) unstable; urgency=low
 
-  * New Upstream Release
+  * New upstream release
 
- -- Alexandru Scvortov <alexandru@rabbitmq.com>  Thu, 07 Apr 2011 16:49:22 +0100
+ -- Emile Joubert <emile@rabbitmq.com>  Mon, 30 Apr 2012 14:07:32 +0100
 
-rabbitmq-server (2.4.0-1) lucid; urgency=low
+rabbitmq-server (2.8.1-1) unstable; urgency=low
 
-  * New Upstream Release
+  * New upstream release
 
- -- Alexandru Scvortov <alexandru@rabbitmq.com>  Tue, 22 Mar 2011 17:34:31 +0000
+ -- Emile Joubert <emile@rabbitmq.com>  Fri, 23 Mar 2012 10:05:24 +0000
 
-rabbitmq-server (2.3.1-1) lucid; urgency=low
+rabbitmq-server (2.8.0-1) unstable; urgency=low
 
-  * New Upstream Release
+  * New upstream release
 
- -- Simon MacMullen <simon@rabbitmq.com>  Thu, 03 Feb 2011 12:43:56 +0000
+ -- Emile Joubert <emile@rabbitmq.com>  Tue, 20 Mar 2012 11:55:10 +0000
 
-rabbitmq-server (2.3.0-1) lucid; urgency=low
+rabbitmq-server (2.6.1-2) unstable; urgency=low
 
-  * New Upstream Release
+  * Add DM-Upload-Allowed flag to control file to allow Maintainer uploads
 
- -- Simon MacMullen <simon@rabbitmq.com>  Tue, 01 Feb 2011 12:52:16 +0000
+ -- John Leuner <jewel@debian.org>  Mon, 19 Mar 2012 21:13:54 +0200
 
-rabbitmq-server (2.2.0-1) lucid; urgency=low
+rabbitmq-server (2.6.1-1) unstable; urgency=low
 
-  * New Upstream Release
+  * New upstream release
 
- -- Rob Harrop <rob@rabbitmq.com>  Mon, 29 Nov 2010 12:24:48 +0000
+ -- John Leuner <jewel@debian.org>  Tue, 27 Sep 2011 17:53:57 +0200
 
-rabbitmq-server (2.1.1-1) lucid; urgency=low
+rabbitmq-server (2.5.0-1) unstable; urgency=low
 
-  * New Upstream Release
+  * New upstream release 
 
- -- Vlad Alexandru Ionescu <vlad@rabbitmq.com>  Tue, 19 Oct 2010 17:20:10 +0100
+ -- John Leuner <jewel@debian.org>  Thu, 16 Jun 2011 09:55:40 +0200
 
-rabbitmq-server (2.1.0-1) lucid; urgency=low
+rabbitmq-server (2.4.1-1) unstable; urgency=low
 
-  * New Upstream Release
+  * New upstream release
 
- -- Marek Majkowski <marek@rabbitmq.com>  Tue, 14 Sep 2010 14:20:17 +0100
+ -- John Leuner <jewel@debian.org>  Sat, 09 Apr 2011 09:34:06 +0200
 
-rabbitmq-server (2.0.0-1) karmic; urgency=low
+rabbitmq-server (2.4.0-1) unstable; urgency=low
 
-  * New Upstream Release
+  * New upstream release
 
- -- Michael Bridgen <mikeb@rabbitmq.com>  Mon, 23 Aug 2010 14:55:39 +0100
+ -- John Leuner <jewel@debian.org>  Wed, 23 Mar 2011 21:11:17 +0200
 
-rabbitmq-server (1.8.1-1) lucid; urgency=low
+rabbitmq-server (2.3.1-1) unstable; urgency=low
 
-  * New Upstream Release
+  * New upstream release, closes: #611253
 
- -- Emile Joubert <emile@rabbitmq.com>  Wed, 14 Jul 2010 15:05:24 +0100
+ -- John Leuner <jewel@debian.org>  Sat, 05 Feb 2011 10:21:16 +0200
 
-rabbitmq-server (1.8.0-1) intrepid; urgency=low
+rabbitmq-server (2.2.0-1) unstable; urgency=low
 
-  * New Upstream Release
+  * New upstream release
 
- -- Matthew Sackman <matthew@rabbitmq.com>  Tue, 15 Jun 2010 12:48:48 +0100
+ -- John Leuner <jewel@debian.org>  Thu, 02 Dec 2010 20:41:53 +0200
 
-rabbitmq-server (1.7.2-1) intrepid; urgency=low
+rabbitmq-server (2.1.0-1) unstable; urgency=low
 
-  * New Upstream Release
+  * New upstream release
 
- -- Matthew Sackman <matthew@lshift.net>  Mon, 15 Feb 2010 15:54:47 +0000
+ -- John Leuner <jewel@debian.org>  Mon, 27 Sep 2010 20:28:06 +0200
 
-rabbitmq-server (1.7.1-1) intrepid; urgency=low
+rabbitmq-server (2.0.0-2) unstable; urgency=low
 
-  * New Upstream Release
+  * Fix various scripts that were not updated correctly in
+    - the 2.0.0-1 package, closes: #594724
 
- -- Matthew Sackman <matthew@lshift.net>  Fri, 22 Jan 2010 14:14:29 +0000
+ -- John Leuner <jewel@debian.org>  Thu, 02 Sep 2010 18:01:37 +0200
 
-rabbitmq-server (1.7.0-1) intrepid; urgency=low
+rabbitmq-server (2.0.0-1) unstable; urgency=low
 
-  * New Upstream Release
+  * New upstream release
 
- -- David Wragg <dpw@lshift.net>  Mon, 05 Oct 2009 13:44:41 +0100
+ -- John Leuner <jewel@debian.org>  Sat, 28 Aug 2010 11:21:48 +0200
 
-rabbitmq-server (1.6.0-1) hardy; urgency=low
+rabbitmq-server (1.8.1-1) unstable; urgency=low
 
-  * New Upstream Release
+  * New upstream release
 
- -- Matthias Radestock <matthias@lshift.net>  Tue, 16 Jun 2009 15:02:58 +0100
+ -- John Leuner <jewel@debian.org>  Sun, 01 Aug 2010 15:47:46 +0200
 
-rabbitmq-server (1.5.5-1) hardy; urgency=low
+rabbitmq-server (1.8.0-1) unstable; urgency=low
 
-  * New Upstream Release
+  * New upstream release
 
- -- Matthias Radestock <matthias@lshift.net>  Tue, 19 May 2009 09:57:54 +0100
+ -- John Leuner <jewel@debian.org>  Thu, 24 Jun 2010 18:43:04 +0200
 
-rabbitmq-server (1.5.4-1) hardy; urgency=low
+rabbitmq-server (1.7.0-3) unstable; urgency=low
 
-  * New Upstream Release
+  * Add missing entries in rabbitmq-server.init
 
- -- Matthias Radestock <matthias@lshift.net>  Mon, 06 Apr 2009 09:19:32 +0100
+ -- John Leuner <jewel@debian.org>  Sun, 25 Oct 2009 10:21:25 +0200
 
-rabbitmq-server (1.5.3-1) hardy; urgency=low
+rabbitmq-server (1.7.0-2) unstable; urgency=low
 
-  * New Upstream Release
+  * moved debian/init.d to rabbitmq-server.init
+  * included fixes to rabbitmq-script-wrapper
 
- -- Tony Garnock-Jones <tonyg@lshift.net>  Tue, 24 Feb 2009 18:23:33 +0000
+ -- John Leuner <jewel@debian.org>  Wed, 14 Oct 2009 12:23:52 +0200
 
-rabbitmq-server (1.5.2-1) hardy; urgency=low
+rabbitmq-server (1.7.0-1) unstable; urgency=low
 
-  * New Upstream Release
+  * New upstream release
 
- -- Tony Garnock-Jones <tonyg@lshift.net>  Mon, 23 Feb 2009 16:03:38 +0000
+ -- John Leuner <jewel@debian.org>  Sat, 10 Oct 2009 13:28:39 +0200
 
-rabbitmq-server (1.5.1-1) hardy; urgency=low
+rabbitmq-server (1.6.0-1) unstable; urgency=low
 
-  * New Upstream Release
+  * New upstream release
 
- -- Simon MacMullen <simon@lshift.net>  Mon, 19 Jan 2009 15:46:13 +0000
+ -- John Leuner <jewel@debian.org>  Sat, 20 Jun 2009 12:22:17 +0200
 
-rabbitmq-server (1.5.0-1) testing; urgency=low
+rabbitmq-server (1.5.5-3) unstable; urgency=low
 
-  * New Upstream Release
+  *  debian/control: Reduce Erlang dependencies to just
+     erlang-mnesia and erlang-os-mon, closes: #532867
 
- -- Matthias Radestock <matthias@lshift.net>  Wed, 17 Dec 2008 18:23:47 +0000
+ -- John Leuner <jewel@debian.org>  Tue, 16 Jun 2009 14:15:20 +0200
 
-rabbitmq-server (1.4.0-1) testing; urgency=low
+rabbitmq-server (1.5.5-2) unstable; urgency=low
 
-  * New Upstream Release
+  * Include updates to debian package by rabbit team:
+    - quiet log rotate 
+    - update build-depends and depends for new erlang packages
+    - debian/watch file
+    - add rabbitmq-script-wrapper
+    - update init.d scripts
+    - clean /etc/rabbitmq in postrm
 
- -- Tony Garnock-Jones <tonyg@lshift.net>  Thu, 24 Jul 2008 13:21:48 +0100
+ -- John Leuner <jewel@debian.org>  Wed, 03 Jun 2009 12:23:50 +0200
 
-rabbitmq-server (1.3.0-1) testing; urgency=low
+rabbitmq-server (1.5.5-1) unstable; urgency=low
 
-  * New Upstream Release
+  * New upstream release
 
- -- Adrien Pierard <adrien@lshift.net>  Mon, 03 Mar 2008 15:34:38 +0000
+ -- John Leuner <jewel@debian.org>  Tue, 02 Jun 2009 12:53:32 +0200
 
-rabbitmq-server (1.2.0-2) testing; urgency=low
+rabbitmq-server (1.5.4-4) unstable; urgency=low
 
-  * Fixed rabbitmqctl wrapper script
+  * Add new dependency on erlang-os-mon to work with new erlang packages in
+    debian
 
- -- Simon MacMullen <simon@lshift.net>  Fri, 05 Oct 2007 11:55:00 +0100
+ -- John Leuner <jewel@debian.org>  Mon, 11 May 2009 21:20:04 +0200
 
-rabbitmq-server (1.2.0-1) testing; urgency=low
+rabbitmq-server (1.5.4-3) unstable; urgency=low
 
-  * New upstream release
+  * Previous partial upload failed
+
+ -- John Leuner <jewel@debian.org>  Fri, 10 Apr 2009 20:25:51 +0200
+
+rabbitmq-server (1.5.4-2) unstable; urgency=low
+
+  * Fix incorrect changed-by field in .changes file
 
- -- Simon MacMullen <simon@lshift.net>  Wed, 26 Sep 2007 11:49:26 +0100
+ -- John Leuner <jewel@debian.org>  Fri, 10 Apr 2009 19:40:04 +0200
 
-rabbitmq-server (1.1.1-1) testing; urgency=low
+rabbitmq-server (1.5.4-1) unstable; urgency=low
 
   * New upstream release
 
- -- Simon MacMullen <simon@lshift.net>  Wed, 29 Aug 2007 12:03:15 +0100
+ -- John Leuner <jewel@debian.org>  Fri, 10 Apr 2009 17:54:21 +0200
 
-rabbitmq-server (1.1.0-alpha-2) testing; urgency=low
+rabbitmq-server (1.5.0-5) unstable; urgency=low
 
-  * Fixed erlang-nox dependency
+  * Include the full license for amqp-0.8.json in debian/copyright
 
- -- Simon MacMullen <simon@lshift.net>  Thu, 02 Aug 2007 11:27:13 +0100
+ -- John Leuner <jewel@debian.org>  Fri, 27 Feb 2009 16:16:54 +0200
 
-rabbitmq-server (1.1.0-alpha-1) testing; urgency=low
+rabbitmq-server (1.5.0-4) unstable; urgency=low
 
-  * New upstream release
+  * Clarify and explicitly list the license and copyright for
+    codegen/amqp-0.8.json
+       
+  * Explicitly list the authors and copyright for the rest of the codebase
+    at the top of debian/copyright
+       
+  * Clarify the copyright of the files in src/tcp_* . The rabbitmq authors have
+    confirmed that they are the original authors of this code and that the
+    files at http://code.google.com/p/cacherl/ were taken without their
+    knowledge from the rabbitmq project. (Comparing the commit dates in version
+    control shows that cacherl is newer)
+
+ -- John Leuner <jewel@debian.org>  Wed, 25 Feb 2009 13:10:15 +0200
+
+rabbitmq-server (1.5.0-3) unstable; urgency=low
+
+  * Previous changelog entry had an incorrect Maintainer name
 
- -- Simon MacMullen <simon@lshift.net>  Fri, 20 Jul 2007 18:17:33 +0100
+ -- John Leuner <jewel@debian.org>  Wed, 28 Jan 2009 16:45:33 +0200
 
-rabbitmq-server (1.0.0-alpha-1) unstable; urgency=low
+rabbitmq-server (1.5.0-2) unstable; urgency=low
 
-  * Initial release
+  * Reupload package to unstable. Mistakenly uploaded to testing last time, closes: #507902
 
- -- Tony Garnock-Jones <tonyg@shortstop.lshift.net>  Wed, 31 Jan 2007 19:06:33 +0000
+ -- John Leuner <jewel@debian.org>  Mon, 19 Jan 2009 17:38:43 +0200
+
+rabbitmq-server (1.5.0-1) testing; urgency=low
+
+  * New Upstream Release
+  * First Debian upload, closes: #507902
 
+ -- John Leuner <jewel@debian.org>  Wed, 17 Dec 2008 18:23:47 +0000
index 45a4fb75db864000d01701c0f7a51864bd4daabf..ec635144f60048986bc560c5576355344005e6e7 100644 (file)
@@ -1 +1 @@
-8
+9
index 944fae4a92e283293af82f2a763316c4f781bc92..dd615458646f13ac9e6dc801a0e4af22f3925b76 100644 (file)
@@ -1,16 +1,30 @@
 Source: rabbitmq-server
 Section: net
 Priority: extra
-Maintainer: MOS Linux team <mos-linux@mirantis.com>
-XSBC-Orig-Maintainer: RabbitMQ Team <packaging@rabbitmq.com>
-Build-Depends: cdbs, debhelper (>= 9), erlang-dev, python-simplejson, xmlto, xsltproc, erlang-nox (>= 1:13.b.3), erlang-src (>= 1:13.b.3), unzip, zip
-Standards-Version: 3.9.2
+Maintainer: PKG OpenStack <openstack-devel@lists.alioth.debian.org>
+Uploaders: James Page <james.page@ubuntu.com>, Thomas Goirand <zigo@debian.org>
+Build-Depends: debhelper (>= 9~),
+               dh-systemd (>= 1.5),
+               erlang-dev,
+               erlang-nox (>= 1:13.b.3),
+               erlang-src (>= 1:13.b.3),
+               python-simplejson,
+               unzip,
+               xmlto,
+               xsltproc,
+               zip
+Standards-Version: 3.9.6
+Vcs-Browser: http://anonscm.debian.org/gitweb/?p=openstack/rabbitmq-server.git
+Vcs-Git: git://anonscm.debian.org/openstack/rabbitmq-server.git
+Homepage: http://www.rabbitmq.com/
 
 Package: rabbitmq-server
 Architecture: all
-Depends: erlang-nox (>= 1:13.b.3) | esl-erlang, adduser, logrotate, ${misc:Depends}
+Depends: adduser,
+         erlang-nox (>= 1:13.b.3) | esl-erlang,
+         logrotate,
+         ${misc:Depends}
 Description: AMQP server written in Erlang
  RabbitMQ is an implementation of AMQP, the emerging standard for high
  performance enterprise messaging. The RabbitMQ server is a robust and
  scalable implementation of an AMQP broker.
-Homepage: http://www.rabbitmq.com/
index e384a7c8f8b99692735ab627b9e222bd2b95f3f3..3ce58ffa780c25bfb974d8bcb8063b0bfecb2531 100644 (file)
-This package was debianized by Tony Garnock-Jones <tonyg@rabbitmq.com> on
-Wed,  3 Jan 2007 15:43:44 +0000.
-
-It was downloaded from http://www.rabbitmq.com/
-
-
-This package, the RabbitMQ server is licensed under the MPL.
-
-If you have any questions regarding licensing, please contact us at
-info@rabbitmq.com.
-
-The files amqp-rabbitmq-0.8.json and amqp-rabbitmq-0.9.1.json are
-"Copyright (C) 2008-2013 GoPivotal", Inc. and are covered by the MIT
-license.
-
-jQuery is "Copyright (c) 2010 John Resig" and is covered by the MIT
-license.  It was downloaded from http://jquery.com/
-
-EJS is "Copyright (c) 2007 Edward Benson" and is covered by the MIT
-license.  It was downloaded from http://embeddedjs.com/
-
-Sammy is "Copyright (c) 2008 Aaron Quint, Quirkey NYC, LLC" and is
-covered by the MIT license.  It was downloaded from
-http://code.quirkey.com/sammy/
-
-ExplorerCanvas is "Copyright 2006 Google Inc" and is covered by the
-Apache License version 2.0. It was downloaded from
-http://code.google.com/p/explorercanvas/
-
-Flot is "Copyright (c) 2007-2013 IOLA and Ole Laursen" and is covered
-by the MIT license. It was downloaded from
-http://www.flotcharts.org/
-Webmachine is Copyright (c) Basho Technologies and is covered by the
-Apache License 2.0.  It was downloaded from http://webmachine.basho.com/
-
-Eldap is "Copyright (c) 2010, Torbjorn Tornkvist" and is covered by
-the MIT license.  It was downloaded from https://github.com/etnt/eldap
-
-Mochiweb is "Copyright (c) 2007 Mochi Media, Inc." and is covered by
-the MIT license.  It was downloaded from
-http://github.com/mochi/mochiweb/
-
-glMatrix is "Copyright (c) 2011, Brandon Jones" and is covered by the
-BSD 2-Clause license.  It was downloaded from
-http://code.google.com/p/glmatrix/
-
-
-The MIT license is as follows:
-
-        "Permission is hereby granted, free of charge, to any person
-        obtaining a copy of this file (the Software), to deal in the
-        Software without restriction, including without limitation the
-        rights to use, copy, modify, merge, publish, distribute,
-        sublicense, and/or sell copies of the Software, and to permit
-        persons to whom the Software is furnished to do so, subject to
-        the following conditions:
-
-        The above copyright notice and this permission notice shall be
-        included in all copies or substantial portions of the Software.
-
-        THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
-        EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-        OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-        NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-        HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-        WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-        FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-        OTHER DEALINGS IN THE SOFTWARE."
-
-
-The BSD 2-Clause license is as follows:
-
-        "Redistribution and use in source and binary forms, with or
-        without modification, are permitted provided that the
-        following conditions are met:
-
-        1. Redistributions of source code must retain the above
-        copyright notice, this list of conditions and the following
-        disclaimer.
-
-        2. Redistributions in binary form must reproduce the above
-        copyright notice, this list of conditions and the following
-        disclaimer in the documentation and/or other materials
-        provided with the distribution.
-
-        THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
-        CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
-        INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-        MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-        DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
-        CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-        SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-        NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-        LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-        HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-        CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-        OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
-        EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-
-
-The rest of this package is licensed under the Mozilla Public License 1.1
-Authors and Copyright are as described below:
-
-     The Initial Developer of the Original Code is GoPivotal, Inc.
-     Copyright (c) 2007-2014 GoPivotal, Inc.  All rights reserved.
-
-
-                          MOZILLA PUBLIC LICENSE
-                                Version 1.1
-
-                              ---------------
-
-1. Definitions.
-
-     1.0.1. "Commercial Use" means distribution or otherwise making the
-     Covered Code available to a third party.
-
-     1.1. "Contributor" means each entity that creates or contributes to
-     the creation of Modifications.
-
-     1.2. "Contributor Version" means the combination of the Original
-     Code, prior Modifications used by a Contributor, and the Modifications
-     made by that particular Contributor.
-
-     1.3. "Covered Code" means the Original Code or Modifications or the
-     combination of the Original Code and Modifications, in each case
-     including portions thereof.
-
-     1.4. "Electronic Distribution Mechanism" means a mechanism generally
-     accepted in the software development community for the electronic
-     transfer of data.
-
-     1.5. "Executable" means Covered Code in any form other than Source
-     Code.
-
-     1.6. "Initial Developer" means the individual or entity identified
-     as the Initial Developer in the Source Code notice required by Exhibit
-     A.
-
-     1.7. "Larger Work" means a work which combines Covered Code or
-     portions thereof with code not governed by the terms of this License.
-
-     1.8. "License" means this document.
-
-     1.8.1. "Licensable" means having the right to grant, to the maximum
-     extent possible, whether at the time of the initial grant or
-     subsequently acquired, any and all of the rights conveyed herein.
-
-     1.9. "Modifications" means any addition to or deletion from the
-     substance or structure of either the Original Code or any previous
-     Modifications. When Covered Code is released as a series of files, a
-     Modification is:
-          A. Any addition to or deletion from the contents of a file
-          containing Original Code or previous Modifications.
-
-          B. Any new file that contains any part of the Original Code or
-          previous Modifications.
-
-     1.10. "Original Code" means Source Code of computer software code
-     which is described in the Source Code notice required by Exhibit A as
-     Original Code, and which, at the time of its release under this
-     License is not already Covered Code governed by this License.
-
-     1.10.1. "Patent Claims" means any patent claim(s), now owned or
-     hereafter acquired, including without limitation,  method, process,
-     and apparatus claims, in any patent Licensable by grantor.
-
-     1.11. "Source Code" means the preferred form of the Covered Code for
-     making modifications to it, including all modules it contains, plus
-     any associated interface definition files, scripts used to control
-     compilation and installation of an Executable, or source code
-     differential comparisons against either the Original Code or another
-     well known, available Covered Code of the Contributor's choice. The
-     Source Code can be in a compressed or archival form, provided the
-     appropriate decompression or de-archiving software is widely available
-     for no charge.
-
-     1.12. "You" (or "Your")  means an individual or a legal entity
-     exercising rights under, and complying with all of the terms of, this
-     License or a future version of this License issued under Section 6.1.
-     For legal entities, "You" includes any entity which controls, is
-     controlled by, or is under common control with You. For purposes of
-     this definition, "control" means (a) the power, direct or indirect,
-     to cause the direction or management of such entity, whether by
-     contract or otherwise, or (b) ownership of more than fifty percent
-     (50%) of the outstanding shares or beneficial ownership of such
-     entity.
-
-2. Source Code License.
-
-     2.1. The Initial Developer Grant.
-     The Initial Developer hereby grants You a world-wide, royalty-free,
-     non-exclusive license, subject to third party intellectual property
-     claims:
-          (a)  under intellectual property rights (other than patent or
-          trademark) Licensable by Initial Developer to use, reproduce,
-          modify, display, perform, sublicense and distribute the Original
-          Code (or portions thereof) with or without Modifications, and/or
-          as part of a Larger Work; and
-
-          (b) under Patents Claims infringed by the making, using or
-          selling of Original Code, to make, have made, use, practice,
-          sell, and offer for sale, and/or otherwise dispose of the
-          Original Code (or portions thereof).
-
-          (c) the licenses granted in this Section 2.1(a) and (b) are
-          effective on the date Initial Developer first distributes
-          Original Code under the terms of this License.
-
-          (d) Notwithstanding Section 2.1(b) above, no patent license is
-          granted: 1) for code that You delete from the Original Code; 2)
-          separate from the Original Code;  or 3) for infringements caused
-          by: i) the modification of the Original Code or ii) the
-          combination of the Original Code with other software or devices.
-
-     2.2. Contributor Grant.
-     Subject to third party intellectual property claims, each Contributor
-     hereby grants You a world-wide, royalty-free, non-exclusive license
-
-          (a)  under intellectual property rights (other than patent or
-          trademark) Licensable by Contributor, to use, reproduce, modify,
-          display, perform, sublicense and distribute the Modifications
-          created by such Contributor (or portions thereof) either on an
-          unmodified basis, with other Modifications, as Covered Code
-          and/or as part of a Larger Work; and
-
-          (b) under Patent Claims infringed by the making, using, or
-          selling of  Modifications made by that Contributor either alone
-          and/or in combination with its Contributor Version (or portions
-          of such combination), to make, use, sell, offer for sale, have
-          made, and/or otherwise dispose of: 1) Modifications made by that
-          Contributor (or portions thereof); and 2) the combination of
-          Modifications made by that Contributor with its Contributor
-          Version (or portions of such combination).
-
-          (c) the licenses granted in Sections 2.2(a) and 2.2(b) are
-          effective on the date Contributor first makes Commercial Use of
-          the Covered Code.
-
-          (d)    Notwithstanding Section 2.2(b) above, no patent license is
-          granted: 1) for any code that Contributor has deleted from the
-          Contributor Version; 2)  separate from the Contributor Version;
-          3)  for infringements caused by: i) third party modifications of
-          Contributor Version or ii)  the combination of Modifications made
-          by that Contributor with other software  (except as part of the
-          Contributor Version) or other devices; or 4) under Patent Claims
-          infringed by Covered Code in the absence of Modifications made by
-          that Contributor.
-
-3. Distribution Obligations.
-
-     3.1. Application of License.
-     The Modifications which You create or to which You contribute are
-     governed by the terms of this License, including without limitation
-     Section 2.2. The Source Code version of Covered Code may be
-     distributed only under the terms of this License or a future version
-     of this License released under Section 6.1, and You must include a
-     copy of this License with every copy of the Source Code You
-     distribute. You may not offer or impose any terms on any Source Code
-     version that alters or restricts the applicable version of this
-     License or the recipients' rights hereunder. However, You may include
-     an additional document offering the additional rights described in
-     Section 3.5.
-
-     3.2. Availability of Source Code.
-     Any Modification which You create or to which You contribute must be
-     made available in Source Code form under the terms of this License
-     either on the same media as an Executable version or via an accepted
-     Electronic Distribution Mechanism to anyone to whom you made an
-     Executable version available; and if made available via Electronic
-     Distribution Mechanism, must remain available for at least twelve (12)
-     months after the date it initially became available, or at least six
-     (6) months after a subsequent version of that particular Modification
-     has been made available to such recipients. You are responsible for
-     ensuring that the Source Code version remains available even if the
-     Electronic Distribution Mechanism is maintained by a third party.
-
-     3.3. Description of Modifications.
-     You must cause all Covered Code to which You contribute to contain a
-     file documenting the changes You made to create that Covered Code and
-     the date of any change. You must include a prominent statement that
-     the Modification is derived, directly or indirectly, from Original
-     Code provided by the Initial Developer and including the name of the
-     Initial Developer in (a) the Source Code, and (b) in any notice in an
-     Executable version or related documentation in which You describe the
-     origin or ownership of the Covered Code.
-
-     3.4. Intellectual Property Matters
-          (a) Third Party Claims.
-          If Contributor has knowledge that a license under a third party's
-          intellectual property rights is required to exercise the rights
-          granted by such Contributor under Sections 2.1 or 2.2,
-          Contributor must include a text file with the Source Code
-          distribution titled "LEGAL" which describes the claim and the
-          party making the claim in sufficient detail that a recipient will
-          know whom to contact. If Contributor obtains such knowledge after
-          the Modification is made available as described in Section 3.2,
-          Contributor shall promptly modify the LEGAL file in all copies
-          Contributor makes available thereafter and shall take other steps
-          (such as notifying appropriate mailing lists or newsgroups)
-          reasonably calculated to inform those who received the Covered
-          Code that new knowledge has been obtained.
-
-          (b) Contributor APIs.
-          If Contributor's Modifications include an application programming
-          interface and Contributor has knowledge of patent licenses which
-          are reasonably necessary to implement that API, Contributor must
-          also include this information in the LEGAL file.
-
-               (c)    Representations.
-          Contributor represents that, except as disclosed pursuant to
-          Section 3.4(a) above, Contributor believes that Contributor's
-          Modifications are Contributor's original creation(s) and/or
-          Contributor has sufficient rights to grant the rights conveyed by
-          this License.
-
-     3.5. Required Notices.
-     You must duplicate the notice in Exhibit A in each file of the Source
-     Code.  If it is not possible to put such notice in a particular Source
-     Code file due to its structure, then You must include such notice in a
-     location (such as a relevant directory) where a user would be likely
-     to look for such a notice.  If You created one or more Modification(s)
-     You may add your name as a Contributor to the notice described in
-     Exhibit A.  You must also duplicate this License in any documentation
-     for the Source Code where You describe recipients' rights or ownership
-     rights relating to Covered Code.  You may choose to offer, and to
-     charge a fee for, warranty, support, indemnity or liability
-     obligations to one or more recipients of Covered Code. However, You
-     may do so only on Your own behalf, and not on behalf of the Initial
-     Developer or any Contributor. You must make it absolutely clear than
-     any such warranty, support, indemnity or liability obligation is
-     offered by You alone, and You hereby agree to indemnify the Initial
-     Developer and every Contributor for any liability incurred by the
-     Initial Developer or such Contributor as a result of warranty,
-     support, indemnity or liability terms You offer.
-
-     3.6. Distribution of Executable Versions.
-     You may distribute Covered Code in Executable form only if the
-     requirements of Section 3.1-3.5 have been met for that Covered Code,
-     and if You include a notice stating that the Source Code version of
-     the Covered Code is available under the terms of this License,
-     including a description of how and where You have fulfilled the
-     obligations of Section 3.2. The notice must be conspicuously included
-     in any notice in an Executable version, related documentation or
-     collateral in which You describe recipients' rights relating to the
-     Covered Code. You may distribute the Executable version of Covered
-     Code or ownership rights under a license of Your choice, which may
-     contain terms different from this License, provided that You are in
-     compliance with the terms of this License and that the license for the
-     Executable version does not attempt to limit or alter the recipient's
-     rights in the Source Code version from the rights set forth in this
-     License. If You distribute the Executable version under a different
-     license You must make it absolutely clear that any terms which differ
-     from this License are offered by You alone, not by the Initial
-     Developer or any Contributor. You hereby agree to indemnify the
-     Initial Developer and every Contributor for any liability incurred by
-     the Initial Developer or such Contributor as a result of any such
-     terms You offer.
-
-     3.7. Larger Works.
-     You may create a Larger Work by combining Covered Code with other code
-     not governed by the terms of this License and distribute the Larger
-     Work as a single product. In such a case, You must make sure the
-     requirements of this License are fulfilled for the Covered Code.
-
-4. Inability to Comply Due to Statute or Regulation.
-
-     If it is impossible for You to comply with any of the terms of this
-     License with respect to some or all of the Covered Code due to
-     statute, judicial order, or regulation then You must: (a) comply with
-     the terms of this License to the maximum extent possible; and (b)
-     describe the limitations and the code they affect. Such description
-     must be included in the LEGAL file described in Section 3.4 and must
-     be included with all distributions of the Source Code. Except to the
-     extent prohibited by statute or regulation, such description must be
-     sufficiently detailed for a recipient of ordinary skill to be able to
-     understand it.
-
-5. Application of this License.
-
-     This License applies to code to which the Initial Developer has
-     attached the notice in Exhibit A and to related Covered Code.
-
-6. Versions of the License.
-
-     6.1. New Versions.
-     Netscape Communications Corporation ("Netscape") may publish revised
-     and/or new versions of the License from time to time. Each version
-     will be given a distinguishing version number.
-
-     6.2. Effect of New Versions.
-     Once Covered Code has been published under a particular version of the
-     License, You may always continue to use it under the terms of that
-     version. You may also choose to use such Covered Code under the terms
-     of any subsequent version of the License published by Netscape. No one
-     other than Netscape has the right to modify the terms applicable to
-     Covered Code created under this License.
-
-     6.3. Derivative Works.
-     If You create or use a modified version of this License (which you may
-     only do in order to apply it to code which is not already Covered Code
-     governed by this License), You must (a) rename Your license so that
-     the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape",
-     "MPL", "NPL" or any confusingly similar phrase do not appear in your
-     license (except to note that your license differs from this License)
-     and (b) otherwise make it clear that Your version of the license
-     contains terms which differ from the Mozilla Public License and
-     Netscape Public License. (Filling in the name of the Initial
-     Developer, Original Code or Contributor in the notice described in
-     Exhibit A shall not of themselves be deemed to be modifications of
-     this License.)
-
-7. DISCLAIMER OF WARRANTY.
-
-     COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
-     WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
-     WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF
-     DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.
-     THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE
-     IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,
-     YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
-     COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER
-     OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
-     ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
-
-8. TERMINATION.
-
-     8.1.  This License and the rights granted hereunder will terminate
-     automatically if You fail to comply with terms herein and fail to cure
-     such breach within 30 days of becoming aware of the breach. All
-     sublicenses to the Covered Code which are properly granted shall
-     survive any termination of this License. Provisions which, by their
-     nature, must remain in effect beyond the termination of this License
-     shall survive.
-
-     8.2.  If You initiate litigation by asserting a patent infringement
-     claim (excluding declatory judgment actions) against Initial Developer
-     or a Contributor (the Initial Developer or Contributor against whom
-     You file such action is referred to as "Participant")  alleging that:
-
-     (a)  such Participant's Contributor Version directly or indirectly
-     infringes any patent, then any and all rights granted by such
-     Participant to You under Sections 2.1 and/or 2.2 of this License
-     shall, upon 60 days notice from Participant terminate prospectively,
-     unless if within 60 days after receipt of notice You either: (i)
-     agree in writing to pay Participant a mutually agreeable reasonable
-     royalty for Your past and future use of Modifications made by such
-     Participant, or (ii) withdraw Your litigation claim with respect to
-     the Contributor Version against such Participant.  If within 60 days
-     of notice, a reasonable royalty and payment arrangement are not
-     mutually agreed upon in writing by the parties or the litigation claim
-     is not withdrawn, the rights granted by Participant to You under
-     Sections 2.1 and/or 2.2 automatically terminate at the expiration of
-     the 60 day notice period specified above.
-
-     (b)  any software, hardware, or device, other than such Participant's
-     Contributor Version, directly or indirectly infringes any patent, then
-     any rights granted to You by such Participant under Sections 2.1(b)
-     and 2.2(b) are revoked effective as of the date You first made, used,
-     sold, distributed, or had made, Modifications made by that
-     Participant.
-
-     8.3.  If You assert a patent infringement claim against Participant
-     alleging that such Participant's Contributor Version directly or
-     indirectly infringes any patent where such claim is resolved (such as
-     by license or settlement) prior to the initiation of patent
-     infringement litigation, then the reasonable value of the licenses
-     granted by such Participant under Sections 2.1 or 2.2 shall be taken
-     into account in determining the amount or value of any payment or
-     license.
-
-     8.4.  In the event of termination under Sections 8.1 or 8.2 above,
-     all end user license agreements (excluding distributors and resellers)
-     which have been validly granted by You or any distributor hereunder
-     prior to termination shall survive termination.
-
-9. LIMITATION OF LIABILITY.
-
-     UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
-     (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL
-     DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,
-     OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR
-     ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
-     CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL,
-     WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
-     COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
-     INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
-     LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
-     RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW
-     PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
-     EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
-     THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
-
-10. U.S. GOVERNMENT END USERS.
-
-     The Covered Code is a "commercial item," as that term is defined in
-     48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
-     software" and "commercial computer software documentation," as such
-     terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48
-     C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
-     all U.S. Government End Users acquire Covered Code with only those
-     rights set forth herein.
-
-11. MISCELLANEOUS.
-
-     This License represents the complete agreement concerning subject
-     matter hereof. If any provision of this License is held to be
-     unenforceable, such provision shall be reformed only to the extent
-     necessary to make it enforceable. This License shall be governed by
-     California law provisions (except to the extent applicable law, if
-     any, provides otherwise), excluding its conflict-of-law provisions.
-     With respect to disputes in which at least one party is a citizen of,
-     or an entity chartered or registered to do business in the United
-     States of America, any litigation relating to this License shall be
-     subject to the jurisdiction of the Federal Courts of the Northern
-     District of California, with venue lying in Santa Clara County,
-     California, with the losing party responsible for costs, including
-     without limitation, court costs and reasonable attorneys' fees and
-     expenses. The application of the United Nations Convention on
-     Contracts for the International Sale of Goods is expressly excluded.
-     Any law or regulation which provides that the language of a contract
-     shall be construed against the drafter shall not apply to this
-     License.
-
-12. RESPONSIBILITY FOR CLAIMS.
-
-     As between Initial Developer and the Contributors, each party is
-     responsible for claims and damages arising, directly or indirectly,
-     out of its utilization of rights under this License and You agree to
-     work with Initial Developer and Contributors to distribute such
-     responsibility on an equitable basis. Nothing herein is intended or
-     shall be deemed to constitute any admission of liability.
-
-13. MULTIPLE-LICENSED CODE.
-
-     Initial Developer may designate portions of the Covered Code as
-     "Multiple-Licensed".  "Multiple-Licensed" means that the Initial
-     Developer permits you to utilize portions of the Covered Code under
-     Your choice of the NPL or the alternative licenses, if any, specified
-     by the Initial Developer in the file described in Exhibit A.
-
-EXHIBIT A -Mozilla Public License.
-
-     ``The contents of this file are subject to the Mozilla Public License
-     Version 1.1 (the "License"); you may not use this file except in
-     compliance with the License. You may obtain a copy of the License at
-     http://www.mozilla.org/MPL/
-
-     Software distributed under the License is distributed on an "AS IS"
-     basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
-     License for the specific language governing rights and limitations
-     under the License.
-
-     The Original Code is RabbitMQ.
-
-     The Initial Developer of the Original Code is GoPivotal, Inc.
-     Copyright (c) 2007-2014 GoPivotal, Inc.  All rights reserved.''
-
-     [NOTE: The text of this Exhibit A may differ slightly from the text of
-     the notices in the Source Code files of the Original Code. You should
-     use the text of this Exhibit A rather than the text found in the
-     Original Code Source Code for Your Modifications.]
-
-
-The Debian packaging is (C) 2007-2013, GoPivotal, Inc. and is licensed
-under the MPL 1.1, see above.
-
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: RabbitMQ
+Source: http://www.rabbitmq.com/
+
+Files: debian/*
+Copyright: (c) 2007-2013, GoPivotal, Inc.
+           (c) 2007, Tony Garnock-Jones <tonyg@rabbitmq.com>
+           (c) 2014, Blair Hester <bhester@gopivotal.com>
+           (c) 2012-2014, Emile Joubert <emile@rabbitmq.com>
+           (c) 2008-2012, John Leuner <jewel@debian.org>
+           (c) 2014, James Page <james.page@canonical.com>
+           (c) 2014, Thomas Goirand <zigo@debian.org>
+License: MPL-1.1
+
+Files: codegen/amqp-rabbitmq-*.json
+Copyright: (c) 2008-2013, GoPivotal Inc.
+License: Expat
+
+Files: plugins-src/rabbitmq-management/priv/www/js/jquery*.js
+Copyright: (c) 2010 John Resig
+License: Expat
+Comments: Downloaded from http://jquery.com/
+
+Files: plugins-src/rabbitmq-management/priv/www/js/ejs*
+ plugins-src/rabbitmq-management/priv/www/js/tmpl
+Copyright: (c) 2007, Edward Benson
+License: Expat
+Comments: downloaded from http://embeddedjs.com/
+
+Files: plugins-src/rabbitmq-management/priv/www/js/sammy*.js
+Copyright: (c) 2008 Aaron Quint, Quirkey NYC, LLC
+License: Expat
+Comments: Downloaded from http://code.quirkey.com/sammy/
+
+Files: plugins-src/rabbitmq-management/priv/www/js/excanvas*.js
+Copyright: (c) 2006, Google Inc
+License: Apache-2.0
+Comments: Downloaded from http://code.google.com/p/explorercanvas/
+
+Files: plugins-src/rabbitmq-management/priv/www/js/jquery.flot*.js
+Copyright: (c) 2007-2013, IOLA and Ole Laursen
+License: Expat
+Comments: Downloaded from http://www.flotcharts.org/
+
+Files: plugins-src/webmachine-wrapper/*
+Copyright: (c) Basho Technologies
+License: Apache-2.0
+Comments: Downloaded from http://webmachine.basho.com/
+
+Files: plugins-src/eldap-wrapper/*
+Copyright: (c) 2010, Torbjorn Tornkvist
+License: Expat
+Comments: Downloaded from https://github.com/etnt/eldap
+
+Files: plugins-src/mochiweb-wrapper/mochiweb-git/*
+Copyright: (c) 2007, Mochi Media, Inc.
+License: Expat
+Comments: Downloaded from http://github.com/mochi/mochiweb/
+
+Files: 
+ plugins-src/rabbitmq-management-visualiser/priv/www/visualiser/js/glMatrix*.js
+Copyright: (c) 2011, Brandon Jones
+License: BSD-2-Clause
+Comments: Downloaded from http://code.google.com/p/glmatrix/
+
+Files: *
+Copyright: (c) 2007-2014 GoPivotal, Inc.
+License: MPL-1.1
+
+License: Expat
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this file (the Software), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the following
+ conditions:
+ .
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+ .
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE."
+
+License: BSD-2-Clause
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ .
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+ .
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ .
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE."
+
+License: MPL-1.1
+ MOZILLA PUBLIC LICENSE Version 1.1
+ 1. Definitions.
+ .
+ 1.0.1. "Commercial Use" means distribution or otherwise making the Covered
+ Code available to a third party.
+ .
+ 1.1. "Contributor" means each entity that creates or contributes to the
+ creation of Modifications.
+ .
+ 1.2. "Contributor Version" means the combination of the Original Code, prior
+ Modifications used by a Contributor, and the Modifications made by that
+ particular Contributor.
+ .
+ 1.3. "Covered Code" means the Original Code or Modifications or the
+ combination of the Original Code and Modifications, in each case including
+ portions thereof.
+ .
+ 1.4. "Electronic Distribution Mechanism" means a mechanism generally accepted
+ in the software development community for the electronic transfer of data.
+ .
+ 1.5. "Executable" means Covered Code in any form other than Source Code.
+ .
+ 1.6. "Initial Developer" means the individual or entity identified as the
+ Initial Developer in the Source Code notice required by Exhibit A.
+ .
+ 1.7. "Larger Work" means a work which combines Covered Code or portions
+ thereof with code not governed by the terms of this License.
+ .
+ 1.8. "License" means this document.
+ .
+ 1.8.1. "Licensable" means having the right to grant, to the maximum extent
+ possible, whether at the time of the initial grant or subsequently acquired,
+ any and all of the rights conveyed herein.
+ .
+ 1.9. "Modifications" means any addition to or deletion from the substance or
+ structure of either the Original Code or any previous Modifications. When
+ Covered Code is released as a series of files, a Modification is:
+ .
+ A. Any addition to or deletion from the contents of a file containing
+    Original Code or previous Modifications.
+ .
+ B. Any new file that contains any part of the Original Code or previous
+    Modifications.
+ .
+ 1.10. "Original Code" means Source Code of computer software code which is
+ described in the Source Code notice required by Exhibit A as Original Code,
+ and which, at the time of its release under this License is not already
+ Covered Code governed by this License.
+ .
+ 1.10.1. "Patent Claims" means any patent claim(s), now owned or hereafter
+ acquired, including without limitation,  method, process, and apparatus
+ claims, in any patent Licensable by grantor.
+ .
+ 1.11. "Source Code" means the preferred form of the Covered Code for making
+ modifications to it, including all modules it contains, plus any associated
+ interface definition files, scripts used to control compilation and
+ installation of an Executable, or source code differential comparisons
+ against either the Original Code or another well known, available Covered
+ Code of the Contributor's choice. The Source Code can be in a compressed or
+ archival form, provided the appropriate decompression or de-archiving
+ software is widely available for no charge.
+ .
+ 1.12. "You" (or "Your")  means an individual or a legal entity exercising
+ rights under, and complying with all of the terms of, this License or a
+ future version of this License issued under Section 6.1. For legal entities,
+ "You" includes any entity which controls, is controlled by, or is under
+ common control with You. For purposes of this definition, "control" means (a)
+ the power, direct or indirect, to cause the direction or management of such
+ entity, whether by contract or otherwise, or (b) ownership of more than fifty
+ percent (50%) of the outstanding shares or beneficial ownership of such
+ entity.
+ .
+ 2. Source Code License.
+ .
+ 2.1. The Initial Developer Grant.
+ The Initial Developer hereby grants You a world-wide, royalty-free,
+ non-exclusive license, subject to third party intellectual property claims:
+ .
+ (a) under intellectual property rights (other than patent or
+     trademark) Licensable by Initial Developer to use, reproduce,
+     modify, display, perform, sublicense and distribute the Original
+     Code (or portions thereof) with or without Modifications, and/or
+     as part of a Larger Work; and
+ .
+ (b) under Patents Claims infringed by the making, using or
+     selling of Original Code, to make, have made, use, practice,
+     sell, and offer for sale, and/or otherwise dispose of the
+     Original Code (or portions thereof).
+ .
+ (c) the licenses granted in this Section 2.1(a) and (b) are
+     effective on the date Initial Developer first distributes
+     Original Code under the terms of this License.
+ .
+ (d) Notwithstanding Section 2.1(b) above, no patent license is
+     granted: 1) for code that You delete from the Original Code; 2)
+     separate from the Original Code;  or 3) for infringements caused
+     by: i) the modification of the Original Code or ii) the
+     combination of the Original Code with other software or devices.
+ .
+ 2.2. Contributor Grant.
+ Subject to third party intellectual property claims, each Contributor hereby
+ grants You a world-wide, royalty-free, non-exclusive license
+ .
+ (a) under intellectual property rights (other than patent or
+     trademark) Licensable by Contributor, to use, reproduce, modify,
+     display, perform, sublicense and distribute the Modifications
+     created by such Contributor (or portions thereof) either on an
+     unmodified basis, with other Modifications, as Covered Code
+     and/or as part of a Larger Work; and
+ .
+ (b) under Patent Claims infringed by the making, using, or
+     selling of  Modifications made by that Contributor either alone
+     and/or in combination with its Contributor Version (or portions
+     of such combination), to make, use, sell, offer for sale, have
+     made, and/or otherwise dispose of: 1) Modifications made by that
+     Contributor (or portions thereof); and 2) the combination of
+     Modifications made by that Contributor with its Contributor
+     Version (or portions of such combination).
+ .
+ (c) the licenses granted in Sections 2.2(a) and 2.2(b) are
+     effective on the date Contributor first makes Commercial Use of
+     the Covered Code.
+ .
+ (d) Notwithstanding Section 2.2(b) above, no patent license is
+     granted: 1) for any code that Contributor has deleted from the
+     Contributor Version; 2)  separate from the Contributor Version;
+     3)  for infringements caused by: i) third party modifications of
+     Contributor Version or ii)  the combination of Modifications made
+     by that Contributor with other software  (except as part of the
+     Contributor Version) or other devices; or 4) under Patent Claims
+     infringed by Covered Code in the absence of Modifications made by
+     that Contributor.
+ .
+ 3. Distribution Obligations.
+ .
+ 3.1. Application of License.
+ .
+ The Modifications which You create or to which You contribute are governed by
+ the terms of this License, including without limitation Section 2.2. The
+ Source Code version of Covered Code may be distributed only under the terms of
+ this License or a future version of this License released under Section 6.1,
+ and You must include a copy of this License with every copy of the Source Code
+ You distribute. You may not offer or impose any terms on any Source Code
+ version that alters or restricts the applicable version of this License or the
+ recipients' rights hereunder. However, You may include an additional document
+ offering the additional rights described in Section 3.5.
+ .
+ 3.2. Availability of Source Code.
+ .
+ Any Modification which You create or to which You contribute must be made
+ available in Source Code form under the terms of this License either on the
+ same media as an Executable version or via an accepted Electronic Distribution
+ Mechanism to anyone to whom you made an Executable version available; and if
+ made available via Electronic Distribution Mechanism, must remain available
+ for at least twelve (12) months after the date it initially became available,
+ or at least six (6) months after a subsequent version of that particular
+ Modification has been made available to such recipients. You are responsible
+ for ensuring that the Source Code version remains available even if the
+ Electronic Distribution Mechanism is maintained by a third party.
+ .
+ 3.3. Description of Modifications.
+ .
+ You must cause all Covered Code to which You contribute to contain a file
+ documenting the changes You made to create that Covered Code and the date of
+ any change. You must include a prominent statement that the Modification is
+ derived, directly or indirectly, from Original Code provided by the Initial
+ Developer and including the name of the Initial Developer in (a) the Source
+ Code, and (b) in any notice in an Executable version or related documentation
+ in which You describe the origin or ownership of the Covered Code.
+ .
+ 3.4. Intellectual Property Matters
+ .
+ (a) Third Party Claims.
+ .
+ If Contributor has knowledge that a license under a third party's
+ intellectual property rights is required to exercise the rights
+ granted by such Contributor under Sections 2.1 or 2.2,
+ Contributor must include a text file with the Source Code
+ distribution titled "LEGAL" which describes the claim and the
+ party making the claim in sufficient detail that a recipient will
+ know whom to contact. If Contributor obtains such knowledge after
+ the Modification is made available as described in Section 3.2,
+ Contributor shall promptly modify the LEGAL file in all copies
+ Contributor makes available thereafter and shall take other steps
+ (such as notifying appropriate mailing lists or newsgroups)
+ reasonably calculated to inform those who received the Covered
+ Code that new knowledge has been obtained.
+ .
+ (b) Contributor APIs.
+ .
+ If Contributor's Modifications include an application programming
+ interface and Contributor has knowledge of patent licenses which
+ are reasonably necessary to implement that API, Contributor must
+ also include this information in the LEGAL file.
+ .
+ (c) Representations.
+ .
+ Contributor represents that, except as disclosed pursuant to
+ Section 3.4(a) above, Contributor believes that Contributor's
+ Modifications are Contributor's original creation(s) and/or
+ Contributor has sufficient rights to grant the rights conveyed by
+ this License.
+ .
+ 3.5. Required Notices.
+ .
+ You must duplicate the notice in Exhibit A in each file of the Source
+ Code.  If it is not possible to put such notice in a particular Source
+ Code file due to its structure, then You must include such notice in a
+ location (such as a relevant directory) where a user would be likely
+ to look for such a notice.  If You created one or more Modification(s)
+ You may add your name as a Contributor to the notice described in
+ Exhibit A.  You must also duplicate this License in any documentation
+ for the Source Code where You describe recipients' rights or ownership
+ rights relating to Covered Code.  You may choose to offer, and to
+ charge a fee for, warranty, support, indemnity or liability
+ obligations to one or more recipients of Covered Code. However, You
+ may do so only on Your own behalf, and not on behalf of the Initial
+ Developer or any Contributor. You must make it absolutely clear than
+ any such warranty, support, indemnity or liability obligation is
+ offered by You alone, and You hereby agree to indemnify the Initial
+ Developer and every Contributor for any liability incurred by the
+ Initial Developer or such Contributor as a result of warranty,
+ support, indemnity or liability terms You offer.
+ .
+ 3.6. Distribution of Executable Versions.
+ .
+ You may distribute Covered Code in Executable form only if the
+ requirements of Section 3.1-3.5 have been met for that Covered Code,
+ and if You include a notice stating that the Source Code version of
+ the Covered Code is available under the terms of this License,
+ including a description of how and where You have fulfilled the
+ obligations of Section 3.2. The notice must be conspicuously included
+ in any notice in an Executable version, related documentation or
+ collateral in which You describe recipients' rights relating to the
+ Covered Code. You may distribute the Executable version of Covered
+ Code or ownership rights under a license of Your choice, which may
+ contain terms different from this License, provided that You are in
+ compliance with the terms of this License and that the license for the
+ Executable version does not attempt to limit or alter the recipient's
+ rights in the Source Code version from the rights set forth in this
+ License. If You distribute the Executable version under a different
+ license You must make it absolutely clear that any terms which differ
+ from this License are offered by You alone, not by the Initial
+ Developer or any Contributor. You hereby agree to indemnify the
+ Initial Developer and every Contributor for any liability incurred by
+ the Initial Developer or such Contributor as a result of any such
+ terms You offer.
+ .
+ 3.7. Larger Works.
+ .
+ You may create a Larger Work by combining Covered Code with other code
+ not governed by the terms of this License and distribute the Larger
+ Work as a single product. In such a case, You must make sure the
+ requirements of this License are fulfilled for the Covered Code.
+ .
+ 4. Inability to Comply Due to Statute or Regulation.
+ .
+ If it is impossible for You to comply with any of the terms of this
+ License with respect to some or all of the Covered Code due to
+ statute, judicial order, or regulation then You must: (a) comply with
+ the terms of this License to the maximum extent possible; and (b)
+ describe the limitations and the code they affect. Such description
+ must be included in the LEGAL file described in Section 3.4 and must
+ be included with all distributions of the Source Code. Except to the
+ extent prohibited by statute or regulation, such description must be
+ sufficiently detailed for a recipient of ordinary skill to be able to
+ understand it.
+ .
+ 5. Application of this License.
+ .
+ This License applies to code to which the Initial Developer has
+ attached the notice in Exhibit A and to related Covered Code.
+ .
+ 6. Versions of the License.
+ .
+ 6.1. New Versions.
+ .
+ Netscape Communications Corporation ("Netscape") may publish revised
+ and/or new versions of the License from time to time. Each version
+ will be given a distinguishing version number.
+ .
+ 6.2. Effect of New Versions.
+ .
+ Once Covered Code has been published under a particular version of the
+ License, You may always continue to use it under the terms of that
+ version. You may also choose to use such Covered Code under the terms
+ of any subsequent version of the License published by Netscape. No one
+ other than Netscape has the right to modify the terms applicable to
+ Covered Code created under this License.
+ .
+ 6.3. Derivative Works.
+ .
+ If You create or use a modified version of this License (which you may
+ only do in order to apply it to code which is not already Covered Code
+ governed by this License), You must (a) rename Your license so that
+ the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape",
+ "MPL", "NPL" or any confusingly similar phrase do not appear in your
+ license (except to note that your license differs from this License)
+ and (b) otherwise make it clear that Your version of the license
+ contains terms which differ from the Mozilla Public License and
+ Netscape Public License. (Filling in the name of the Initial
+ Developer, Original Code or Contributor in the notice described in
+ Exhibit A shall not of themselves be deemed to be modifications of
+ this License.)
+ .
+ 7. DISCLAIMER OF WARRANTY.
+ .
+ COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF
+ DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.
+ THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE
+ IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,
+ YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
+ COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER
+ OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
+ ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
+ .
+ 8. TERMINATION.
+ .
+ 8.1.  This License and the rights granted hereunder will terminate
+ automatically if You fail to comply with terms herein and fail to cure
+ such breach within 30 days of becoming aware of the breach. All
+ sublicenses to the Covered Code which are properly granted shall
+ survive any termination of this License. Provisions which, by their
+ nature, must remain in effect beyond the termination of this License
+ shall survive.
+ .
+ 8.2.  If You initiate litigation by asserting a patent infringement
+ claim (excluding declatory judgment actions) against Initial Developer
+ or a Contributor (the Initial Developer or Contributor against whom
+ You file such action is referred to as "Participant")  alleging that:
+ .
+ (a)  such Participant's Contributor Version directly or indirectly
+ infringes any patent, then any and all rights granted by such
+ Participant to You under Sections 2.1 and/or 2.2 of this License
+ shall, upon 60 days notice from Participant terminate prospectively,
+ unless if within 60 days after receipt of notice You either: (i)
+ agree in writing to pay Participant a mutually agreeable reasonable
+ royalty for Your past and future use of Modifications made by such
+ Participant, or (ii) withdraw Your litigation claim with respect to
+ the Contributor Version against such Participant.  If within 60 days
+ of notice, a reasonable royalty and payment arrangement are not
+ mutually agreed upon in writing by the parties or the litigation claim
+ is not withdrawn, the rights granted by Participant to You under
+ Sections 2.1 and/or 2.2 automatically terminate at the expiration of
+ the 60 day notice period specified above.
+ .
+ (b)  any software, hardware, or device, other than such Participant's
+ Contributor Version, directly or indirectly infringes any patent, then
+ any rights granted to You by such Participant under Sections 2.1(b)
+ and 2.2(b) are revoked effective as of the date You first made, used,
+ sold, distributed, or had made, Modifications made by that
+ Participant.
+ .
+ 8.3.  If You assert a patent infringement claim against Participant
+ alleging that such Participant's Contributor Version directly or
+ indirectly infringes any patent where such claim is resolved (such as
+ by license or settlement) prior to the initiation of patent
+ infringement litigation, then the reasonable value of the licenses
+ granted by such Participant under Sections 2.1 or 2.2 shall be taken
+ into account in determining the amount or value of any payment or
+ license.
+ .
+ 8.4.  In the event of termination under Sections 8.1 or 8.2 above,
+ all end user license agreements (excluding distributors and resellers)
+ which have been validly granted by You or any distributor hereunder
+ prior to termination shall survive termination.
+ .
+ 9. LIMITATION OF LIABILITY.
+ .
+ UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
+ (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL
+ DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,
+ OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR
+ ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
+ CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL,
+ WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
+ COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
+ INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
+ LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
+ RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW
+ PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
+ EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
+ THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
+ .
+ 10. U.S. GOVERNMENT END USERS.
+ .
+ The Covered Code is a "commercial item," as that term is defined in
+ 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
+ software" and "commercial computer software documentation," as such
+ terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48
+ C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
+ all U.S. Government End Users acquire Covered Code with only those
+ rights set forth herein.
+ .
+ 11. MISCELLANEOUS.
+ .
+ This License represents the complete agreement concerning subject
+ matter hereof. If any provision of this License is held to be
+ unenforceable, such provision shall be reformed only to the extent
+ necessary to make it enforceable. This License shall be governed by
+ California law provisions (except to the extent applicable law, if
+ any, provides otherwise), excluding its conflict-of-law provisions.
+ With respect to disputes in which at least one party is a citizen of,
+ or an entity chartered or registered to do business in the United
+ States of America, any litigation relating to this License shall be
+ subject to the jurisdiction of the Federal Courts of the Northern
+ District of California, with venue lying in Santa Clara County,
+ California, with the losing party responsible for costs, including
+ without limitation, court costs and reasonable attorneys' fees and
+ expenses. The application of the United Nations Convention on
+ Contracts for the International Sale of Goods is expressly excluded.
+ Any law or regulation which provides that the language of a contract
+ shall be construed against the drafter shall not apply to this
+ License.
+ .
+ 12. RESPONSIBILITY FOR CLAIMS.
+ .
+ As between Initial Developer and the Contributors, each party is
+ responsible for claims and damages arising, directly or indirectly,
+ out of its utilization of rights under this License and You agree to
+ work with Initial Developer and Contributors to distribute such
+ responsibility on an equitable basis. Nothing herein is intended or
+ shall be deemed to constitute any admission of liability.
+ .
+ 13. MULTIPLE-LICENSED CODE.
+ .
+ Initial Developer may designate portions of the Covered Code as
+ "Multiple-Licensed".  "Multiple-Licensed" means that the Initial
+ Developer permits you to utilize portions of the Covered Code under
+ Your choice of the NPL or the alternative licenses, if any, specified
+ by the Initial Developer in the file described in Exhibit A.
+ .
+ EXHIBIT A -Mozilla Public License.
+ .
+ The contents of this file are subject to the Mozilla Public License Version
+ 1.1 (the "License"); you may not use this file except in compliance with the
+ License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+ .
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+ the specific language governing rights and limitations under the License.
+ .
+ The Original Code is RabbitMQ.
+ .
+ The Initial Developer of the Original Code is GoPivotal, Inc. Copyright (c)
+ 2007-2014 GoPivotal, Inc. All rights reserved.
+
+License: Apache-2.0
+  On Debian GNU/Linux system you can find the complete text of the
+  Apache-2.0 license in '/usr/share/common-licenses/Apache-2.0'
diff --git a/debian/dirs b/debian/dirs
deleted file mode 100644 (file)
index 625b7d4..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-usr/lib/rabbitmq/bin
-usr/lib/erlang/lib
-usr/sbin
-usr/share/man
-var/lib/rabbitmq/mnesia
-var/log/rabbitmq
-etc/logrotate.d
-etc/rabbitmq
-
diff --git a/debian/gbp.conf b/debian/gbp.conf
new file mode 100644 (file)
index 0000000..ee339ed
--- /dev/null
@@ -0,0 +1,6 @@
+[DEFAULT]
+debian-branch = master
+pristine-tar = True
+
+[buildpackage]
+export-dir = ../build-area/
old mode 100644 (file)
new mode 100755 (executable)
similarity index 100%
rename from debian/rabbitmq-server.ocf
rename to debian/ocf/rabbitmq-server
diff --git a/debian/rabbitmq-env.conf b/debian/rabbitmq-env.conf
new file mode 100644 (file)
index 0000000..bebe2ab
--- /dev/null
@@ -0,0 +1,13 @@
+# Defaults to rabbit. This can be useful if you want to run more than one node
+# per machine - RABBITMQ_NODENAME should be unique per erlang-node-and-machine
+# combination. See the clustering on a single machine guide for details:
+# http://www.rabbitmq.com/clustering.html#single-machine
+#NODENAME=rabbit
+
+# By default RabbitMQ will bind to all interfaces, on IPv4 and IPv6 if
+# available. Set this if you only want to bind to one network interface or#
+# address family.
+#NODE_IP_ADDRESS=127.0.0.1
+
+# Defaults to 5672.
+#NODE_PORT=5672
old mode 100644 (file)
new mode 100755 (executable)
index 4fecc2e..a622ae2
@@ -32,6 +32,9 @@ SCRIPT=`basename $0`
 if [ `id -u` = `id -u rabbitmq` -a "$SCRIPT" = "rabbitmq-server" ] ; then
     /usr/lib/rabbitmq/bin/rabbitmq-server "$@"  > "/var/log/rabbitmq/startup_log" 2> "/var/log/rabbitmq/startup_err"
 elif [ `id -u` = `id -u rabbitmq` -o "$SCRIPT" = "rabbitmq-plugins" ] ; then
+    if [ -f $PWD/.erlang.cookie ] ; then
+        export HOME=.
+    fi
     /usr/lib/rabbitmq/bin/${SCRIPT} "$@"
 elif [ `id -u` = 0 ] ; then
     su rabbitmq -s /bin/sh -c "/usr/lib/rabbitmq/bin/${SCRIPT} ${CMDLINE}"
diff --git a/debian/rabbitmq-server-wait b/debian/rabbitmq-server-wait
new file mode 100755 (executable)
index 0000000..cdf53e5
--- /dev/null
@@ -0,0 +1,22 @@
+#!/bin/sh -e
+##  The contents of this file are subject to the Mozilla Public License
+##  Version 1.1 (the "License"); you may not use this file except in
+##  compliance with the License. You may obtain a copy of the License
+##  at http://www.mozilla.org/MPL/
+##
+##  Software distributed under the License is distributed on an "AS IS"
+##  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+##  the License for the specific language governing rights and
+##  limitations under the License.
+##
+##  The Original Code is RabbitMQ.
+##
+##  The Initial Developer of the Original Code is GoPivotal, Inc.
+##  Copyright (c) 2007-2014 GoPivotal, Inc.  All rights reserved.
+##
+
+# Get default settings with user overrides for (RABBITMQ_)<var_name>
+# Non-empty defaults should be set in rabbitmq-env
+. `dirname $0`/rabbitmq-env
+
+/usr/lib/rabbitmq/bin/rabbitmqctl wait $RABBITMQ_PID_FILE
index 1efb35670ba1b7906ccf100d2a593e8924f12f95..3eebe2fab5283d62c11a6b41e3f10e17705e2b44 100644 (file)
@@ -6,6 +6,11 @@
 # to handle many simultaneous connections. Refer to the system
 # documentation for ulimit (in man bash) for more information.
 #
+# Default value is 1024, but it's absolutely unreasonable default in a
+# modern world, as rabbitmq consumes file descriptors for everything:
+# for client connections, for per-queue files, etc. Its documentation
+# recommends to allow for at least 65536 open file descriptors in
+# production. Values were chosen in
+# https://bugs.launchpad.net/fuel/+bug/1279594
 ulimit -H -n 105472
 ulimit -S -n 102400
-
diff --git a/debian/rabbitmq-server.dirs b/debian/rabbitmq-server.dirs
new file mode 100644 (file)
index 0000000..e6127a0
--- /dev/null
@@ -0,0 +1,3 @@
+usr/lib/erlang/lib
+var/lib/rabbitmq/mnesia
+var/log/rabbitmq
diff --git a/debian/rabbitmq-server.install b/debian/rabbitmq-server.install
new file mode 100644 (file)
index 0000000..902f3dd
--- /dev/null
@@ -0,0 +1,4 @@
+debian/ocf/rabbitmq-server /usr/lib/ocf/resource.d/rabbitmq/
+debian/rabbitmq-server-wait /usr/lib/rabbitmq/bin
+debian/rabbitmq-script-wrapper /usr/lib/rabbitmq/bin
+debian/rabbitmq-env.conf       /etc/rabbitmq
diff --git a/debian/rabbitmq-server.links b/debian/rabbitmq-server.links
new file mode 100644 (file)
index 0000000..0bfa1c5
--- /dev/null
@@ -0,0 +1,3 @@
+/usr/lib/rabbitmq/bin/rabbitmq-script-wrapper /usr/sbin/rabbitmqctl
+/usr/lib/rabbitmq/bin/rabbitmq-script-wrapper /usr/sbin/rabbitmq-server
+/usr/lib/rabbitmq/bin/rabbitmq-script-wrapper /usr/sbin/rabbitmq-plugins
diff --git a/debian/rabbitmq-server.service b/debian/rabbitmq-server.service
new file mode 100644 (file)
index 0000000..faa73c1
--- /dev/null
@@ -0,0 +1,15 @@
+[Unit]
+Description=RabbitMQ Messaging Server
+After=network.target
+
+[Service]
+Type=simple
+User=rabbitmq
+SyslogIdentifier=rabbitmq
+LimitNOFILE=65536
+ExecStart=/usr/sbin/rabbitmq-server
+ExecStartPost=/usr/lib/rabbitmq/bin/rabbitmq-server-wait
+ExecStop=/usr/sbin/rabbitmqctl stop
+
+[Install]
+WantedBy=multi-user.target
old mode 100644 (file)
new mode 100755 (executable)
index cac29c8..bee4e81
@@ -1,27 +1,31 @@
 #!/usr/bin/make -f
+# -*- makefile -*-
+#export DH_VERBOSE=1
 
-include /usr/share/cdbs/1/rules/debhelper.mk
-include /usr/share/cdbs/1/class/makefile.mk
+%:
+       dh $@ --parallel --with systemd
 
-RABBIT_LIB=$(DEB_DESTDIR)usr/lib/rabbitmq/lib/rabbitmq_server-$(DEB_UPSTREAM_VERSION)/
-RABBIT_BIN=$(DEB_DESTDIR)usr/lib/rabbitmq/bin/
+override_dh_systemd_enable:
+       dh_systemd_enable --no-enable
 
-DOCDIR=$(DEB_DESTDIR)usr/share/doc/rabbitmq-server/
-DEB_MAKE_INSTALL_TARGET := install TARGET_DIR=$(RABBIT_LIB) SBIN_DIR=$(RABBIT_BIN) DOC_INSTALL_DIR=$(DOCDIR) MAN_DIR=$(DEB_DESTDIR)usr/share/man/
-DEB_MAKE_CLEAN_TARGET:= distclean
-DEB_INSTALL_DOCS_ALL=debian/README
+override_dh_systemd_start:
+       dh_systemd_start --no-start
 
-DEB_DH_INSTALLINIT_ARGS="--no-start"
+override_dh_installinit:
+       dh_installinit --noscripts
 
-install/rabbitmq-server::
-       mkdir -p $(DOCDIR)
-       rm $(RABBIT_LIB)LICENSE* $(RABBIT_LIB)INSTALL*
-       for script in rabbitmqctl rabbitmq-server rabbitmq-plugins; do \
-               install -p -D -m 0755 debian/rabbitmq-script-wrapper $(DEB_DESTDIR)usr/sbin/$$script; \
-       done
-       sed -e 's|@RABBIT_LIB@|/usr/lib/rabbitmq/lib/rabbitmq_server-$(DEB_UPSTREAM_VERSION)|g' <debian/postrm.in >debian/postrm
-       install -p -D -m 0755 debian/rabbitmq-server.ocf $(DEB_DESTDIR)usr/lib/ocf/resource.d/rabbitmq/rabbitmq-server
-       install -p -D -m 0644 debian/rabbitmq-server.default $(DEB_DESTDIR)etc/default/rabbitmq-server
 
-clean::
-       rm -f plugins-src/rabbitmq-server debian/postrm plugins/README
+DEB_UPSTREAM_VERSION=$(shell dpkg-parsechangelog | sed -rne 's,^Version: ([^+]+)-.*,\1,p')
+DEB_DESTDIR=debian/rabbitmq-server
+RABBIT_LIB=$(DEB_DESTDIR)/usr/lib/rabbitmq/lib/rabbitmq_server-$(DEB_UPSTREAM_VERSION)
+RABBIT_BIN=$(DEB_DESTDIR)/usr/lib/rabbitmq/bin
+DOCDIR=$(DEB_DESTDIR)/usr/share/doc/rabbitmq-server
+
+override_dh_auto_install:
+       dh_auto_install -- TARGET_DIR=$(RABBIT_LIB) SBIN_DIR=$(RABBIT_BIN) \
+               DOC_INSTALL_DIR=$(DOCDIR) MAN_DIR=$(DEB_DESTDIR)/usr/share/man
+       rm -f $(RABBIT_LIB)/LICENSE* $(RABBIT_LIB)/INSTALL*
+
+override_dh_auto_clean:
+       rm -f plugins-src/rabbitmq-server plugins/README
+       dh_auto_clean
index b41aff9aedc1003866091af62a3d65c914776e34..e41153d6127aea21226109334dc2289673df1b2d 100644 (file)
@@ -1,4 +1,2 @@
 version=3
-
-http://www.rabbitmq.com/releases/rabbitmq-server/v(.*)/rabbitmq-server-(\d.*)\.tar\.gz \
-       debian uupdate
+http://www.rabbitmq.com/releases/rabbitmq-server/v(.*)/rabbitmq-server-(\d.*)\.tar\.gz
index 1c9800188e4478723fdad5d409f253e5e1e58286..c2cae4a1614898a9a3ccb22baf272890f3ba388f 100644 (file)
@@ -48,20 +48,38 @@ endif
 BASIC_PLT=basic.plt
 RABBIT_PLT=rabbit.plt
 
-ifndef USE_SPECS
-# our type specs rely on dict:dict/0 etc, which are only available in 17.0
-# upwards.
-USE_SPECS:=$(shell erl -noshell -eval 'io:format([list_to_integer(X) || X <- string:tokens(erlang:system_info(version), ".")] >= [5,11]), halt().')
-endif
-
 ifndef USE_PROPER_QC
 # PropEr needs to be installed for property checking
 # http://proper.softlab.ntua.gr/
-USE_PROPER_QC:=$(shell erl -noshell -eval 'io:format({module, proper} =:= code:ensure_loaded(proper)), halt().')
+USE_PROPER_QC=$(shell erl -noshell -eval 'io:format({module, proper} =:= code:ensure_loaded(proper)), halt().')
 endif
 
 #other args: +native +"{hipe,[o3,verbose]}" -Ddebug=true +debug_info +no_strict_record_tests
-ERLC_OPTS=-I $(INCLUDE_DIR) -Wall -v +debug_info $(call boolean_macro,$(USE_SPECS),use_specs) $(call boolean_macro,$(USE_PROPER_QC),use_proper_qc)
+ERLC_OPTS=-I $(INCLUDE_DIR) -Wall +warn_export_vars -v +debug_info $(call boolean_macro,$(USE_SPECS),use_specs) $(call boolean_macro,$(USE_PROPER_QC),use_proper_qc)
+
+# Our type specs rely on dict:dict/0 etc, which are only available in
+# 17.0 upwards.
+define compare_version
+$(shell awk 'BEGIN {
+       split("$(1)", v1, "\.");
+       version1 = v1[1] * 1000000 + v1[2] * 10000 + v1[3] * 100 + v1[4];
+
+       split("$(2)", v2, "\.");
+       version2 = v2[1] * 1000000 + v2[2] * 10000 + v2[3] * 100 + v2[4];
+
+       if (version1 $(3) version2) {
+               print "true";
+       } else {
+               print "false";
+       }
+}')
+endef
+
+ERTS_VER = $(shell erl -version 2>&1 | sed -E 's/.* version //')
+USE_SPECS_MIN_ERTS_VER = 5.11
+ifeq ($(call compare_version,$(ERTS_VER),$(USE_SPECS_MIN_ERTS_VER),>=),true)
+ERLC_OPTS += -Duse_specs
+endif
 
 ifdef INSTRUMENT_FOR_QC
 ERLC_OPTS += -DINSTR_MOD=gm_qc
@@ -270,7 +288,11 @@ clear-resource-alarm: all
        $(ERL_CALL)
 
 stop-node:
-       -$(ERL_CALL) -q
+       -( \
+       pid=$$(./scripts/rabbitmqctl -n $(RABBITMQ_NODENAME) eval 'os:getpid().') && \
+       $(ERL_CALL) -q && \
+       while ps -p $$pid >/dev/null 2>&1; do sleep 1; done \
+       )
 
 # code coverage will be created for subdirectory "ebin" of COVER_DIR
 COVER_DIR=.
index 9f16b32425eedda1e95d451c577c3217330faae1..fbc6f61f8ac53631848933323617b8490ee7cf61 100644 (file)
@@ -10,7 +10,7 @@
 ##
 ##  The Original Code is RabbitMQ.
 ##
-##  The Initial Developer of the Original Code is GoPivotal, Inc.
+##  The Initial Developer of the Original Code is Pivotal Software, Inc.
 ##  Copyright (c) 2007-2015 Pivotal Software, Inc.  All rights reserved.
 ##
 
@@ -105,7 +105,7 @@ def printFileHeader():
 %%
 %%  The Original Code is RabbitMQ.
 %%
-%%  The Initial Developer of the Original Code is GoPivotal, Inc.
+%%  The Initial Developer of the Original Code is Pivotal Software, Inc.
 %%  Copyright (c) 2007-2015 Pivotal Software, Inc.  All rights reserved.
 %%"""
 
index 8c3bfa96cae856d98f668281270eb3acee09578a..8e028c8db9970339d072e52d02bc2214b0943eed 100644 (file)
@@ -1,5 +1,5 @@
 all:
-       echo "Please select a target from the Makefile."
+       @echo "Please select a target from the Makefile."
 
 clean:
        rm -f *.pyc
index df58ba3988ac6745ebca9bf057ae93d1737f4e72..bd4a9f33c031c6297172efc5500ce58c606cb3c3 100644 (file)
@@ -1,7 +1,7 @@
 {application, rabbit,           %% -*- erlang -*-
  [{description, "RabbitMQ"},
   {id, "RabbitMQ"},
-  {vsn, "3.5.4"},
+  {vsn, "3.5.6"},
   {modules, []},
   {registered, [rabbit_amqqueue_sup,
                 rabbit_log,
          %% breaks the QPid Java client
          {frame_max, 131072},
          {channel_max, 0},
-         {heartbeat, 580},
+         {heartbeat, 60},
          {msg_store_file_size_limit, 16777216},
-         {queue_index_max_journal_entries, 65536},
+         {fhc_write_buffering, true},
+         {fhc_read_buffering, true},
+         {queue_index_max_journal_entries, 32768},
          {queue_index_embed_msgs_below, 4096},
          {default_user, <<"guest">>},
          {default_pass, <<"guest">>},
            gen_fsm, ssl]},
          {ssl_apps, [asn1, crypto, public_key, ssl]},
          %% see rabbitmq-server#114
-         {mirroring_flow_control, true}
+         {mirroring_flow_control, true},
+         %% see rabbitmq-server#227 and related tickets.
+         %% msg_store_credit_disc_bound only takes effect when
+         %% messages are persisted to the message store. If messages
+         %% are embedded on the queue index, then modifying this
+         %% setting has no effect because credit_flow is not used when
+         %% writing to the queue index. See the setting
+         %% queue_index_embed_msgs_below above.
+         {msg_store_credit_disc_bound, {2000, 500}},
+         {msg_store_io_batch_size, 2048},
+         %% see rabbitmq-server#143
+         {credit_flow_default_credit, {200, 50}}
         ]}]}.
index 5a98e7059beed27f84b75e033f985f7ce27265f7..bc20b4415d11a04c6c8a9c1d92df790f530ccf57 100644 (file)
@@ -10,7 +10,7 @@
 %%
 %% The Original Code is RabbitMQ.
 %%
-%% The Initial Developer of the Original Code is GoPivotal, Inc.
+%% The Initial Developer of the Original Code is Pivotal Software, Inc.
 %% Copyright (c) 2007-2015 Pivotal Software, Inc.  All rights reserved.
 %%
 
index ddcfd6a6480357336d1e1f790aed885e310ee876..5b90956122363596f6f4245997d5dee49002570d 100644 (file)
@@ -10,7 +10,7 @@
 %%
 %% The Original Code is RabbitMQ.
 %%
-%% The Initial Developer of the Original Code is GoPivotal, Inc.
+%% The Initial Developer of the Original Code is Pivotal Software, Inc.
 %% Copyright (c) 2007-2015 Pivotal Software, Inc.  All rights reserved.
 %%
 
 -define(HIBERNATE_AFTER_MIN,        1000).
 -define(DESIRED_HIBERNATE,         10000).
 -define(CREDIT_DISC_BOUND,   {2000, 500}).
+%% When we discover that we should write some indices to disk for some
+%% betas, the IO_BATCH_SIZE sets the number of betas that we must be
+%% due to write indices for before we do any work at all.
+-define(IO_BATCH_SIZE, 2048). %% next power-of-2 after ?CREDIT_DISC_BOUND
 
 -define(INVALID_HEADERS_KEY, <<"x-invalid-headers">>).
 -define(ROUTING_HEADERS, [<<"CC">>, <<"BCC">>]).
index 1bffc9a60488934dce98eb9cbe9eca07c7731963..737bb4ea3dae2c3b3079a5e07ca5e849beb45c01 100644 (file)
@@ -10,7 +10,7 @@
 %%
 %% The Original Code is RabbitMQ.
 %%
-%% The Initial Developer of the Original Code is GoPivotal, Inc.
+%% The Initial Developer of the Original Code is Pivotal Software, Inc.
 %% Copyright (c) 2007-2015 Pivotal Software, Inc.  All rights reserved.
 %%
 
index 803ed6b7ce5e305cbe82699464866fd96d03d5cd..8bcf2ce6298b6ea5bc5056e061b0edfbf75ba761 100644 (file)
@@ -10,7 +10,7 @@
 %%
 %% The Original Code is RabbitMQ.
 %%
-%% The Initial Developer of the Original Code is GoPivotal, Inc.
+%% The Initial Developer of the Original Code is Pivotal Software, Inc.
 %% Copyright (c) 2007-2015 Pivotal Software, Inc.  All rights reserved.
 %%
 
index fbff350d25814a52f9ad58acb6dfcf03b98d8cb9..06664ff6d90207889a14b59111acfd02ee8d142b 100644 (file)
@@ -348,18 +348,13 @@ parse_1_0_frame(Payload, _Channel) ->
 handle_1_0_connection_frame(#'v1_0.open'{ max_frame_size = ClientFrameMax,
                                           channel_max = ClientChannelMax,
                                           idle_time_out = IdleTimeout,
-                                          hostname = Hostname,
-                                          properties = Props },
+                                          hostname = Hostname },
                             State = #v1{
                               connection_state = starting,
                               connection = Connection,
                               throttle   = Throttle,
                               helper_sup = HelperSupPid,
                               sock = Sock}) ->
-    ClientProps        = case Props of
-                             undefined -> [];
-                             {map, Ps} -> Ps
-                         end,
     ClientHeartbeatSec = case IdleTimeout of
                              undefined        -> 0;
                              {uint, Interval} -> Interval div 1000
@@ -368,10 +363,6 @@ handle_1_0_connection_frame(#'v1_0.open'{ max_frame_size = ClientFrameMax,
                              undefined -> unlimited;
                              {_, FM}   -> FM
                          end,
-    ChannelMax         = case ClientChannelMax of
-                             undefined -> unlimited;
-                             {_, CM}   -> CM
-                         end,
     {ok, HeartbeatSec} = application:get_env(rabbit, heartbeat),
     State1 =
         if (FrameMax =/= unlimited) and (FrameMax < ?FRAME_1_0_MIN_SIZE) ->
index 846f7a1bf0324f74df2ae67f4021a407867a21ba..399e4e4b7a736b3fa3a66f19aed277ef75af82e9 100644 (file)
@@ -222,7 +222,7 @@ assemble_frame(Channel, Performative, rabbit_amqp1_0_sasl) ->
 %% content records. However, that's already been handled for us, we're
 %% just sending a chunk, so from this perspective it's just a binary.
 
-assemble_frames(Channel, Performative, Content, FrameMax,
+assemble_frames(Channel, Performative, Content, _FrameMax,
                 rabbit_amqp1_0_framing) ->
     ?DEBUG("Channel ~p <-~n~p~n  followed by ~p bytes of content~n~n",
            [Channel, rabbit_amqp1_0_framing:pprint(Performative),
diff --git a/rabbitmq-server/plugins-src/rabbitmq-auth-backend-ldap/.travis.yml b/rabbitmq-server/plugins-src/rabbitmq-auth-backend-ldap/.travis.yml
new file mode 100644 (file)
index 0000000..6b022a8
--- /dev/null
@@ -0,0 +1,37 @@
+sudo: true
+language: erlang
+notifications:
+  email:
+    - alerts@rabbitmq.com
+addons:
+  apt:
+    packages:
+      - slapd
+      - ldap-utils
+      - xsltproc
+otp_release:
+  - "R16B03-1"
+  - "17.5"
+  - "18.0"
+install:
+  - if [ ! -d "$HOME/rabbitmq-public-umbrella/.git" ]; then git clone https://github.com/rabbitmq/rabbitmq-public-umbrella.git $HOME/rabbitmq-public-umbrella; fi
+  - cd $HOME/rabbitmq-public-umbrella
+  - make co
+  - make up
+services:
+  - slapd
+before_script:
+  - IFS="/" read -a PARTS <<< "$TRAVIS_REPO_SLUG"
+  - export TEST_DIR=$HOME/rabbitmq-public-umbrella/${PARTS[1]}
+  - rm -rf ${TEST_DIR}
+  - cp -r ${TRAVIS_BUILD_DIR} ${TEST_DIR}
+  - cd ${TEST_DIR}
+  - ./example/setup.sh
+script: make test
+before_cache:
+  - rm -rf ${TEST_DIR}
+  - cd $HOME
+cache:
+  apt: true
+  directories:
+    - $HOME/rabbitmq-public-umbrella
index 9b8e69d6a829d2cf096dc30f70a17e17dad6d15b..b65d9c4d3c88abd752015345d94ed84ca8518223 100644 (file)
@@ -1,6 +1,5 @@
 %% -*- erlang -*-
-[{rabbit, [{auth_backends, [rabbit_auth_backend_ldap]},
-           {default_vhost, <<"test">>}]},
+[{rabbit, [{default_vhost, <<"test">>}]},
  {rabbitmq_auth_backend_ldap,
   [ {servers,            ["localhost"]},
     {user_dn_pattern,    "cn=${username},ou=People,dc=example,dc=com"},
@@ -37,6 +36,8 @@
                          {'not', {equals, "${username}", "Mike Bridgen"}}]}
                       ]}}
                    ]}}
-            ]}}
+            ]}},
+    {tag_queries, [{administrator, {constant, false}},
+                   {management,    {constant, false}}]}
   ]}
 ].
index 943ac551cac7232622610d31f9f5a9f6496415c7..7a7e91f74bcf9506aec73533416d0d5d35e535f9 100644 (file)
@@ -70,8 +70,8 @@ user_login_authentication(Username, AuthProps) ->
 
 user_login_authorization(Username) ->
     case user_login_authentication(Username, []) of
-        {ok, #auth_user{impl = Impl}} -> {ok, Impl};
-        Else                          -> Else
+        {ok, #auth_user{impl = Impl, tags = Tags}} -> {ok, Impl, Tags};
+        Else                                       -> Else
     end.
 
 check_vhost_access(User = #auth_user{username = Username,
index 2b92632e29f3d4c9a25e3437026e6f24ccbeaf4f..c340d6839c89bf342e99642f52ddb286a4dce196 100644 (file)
 -include_lib("eunit/include/eunit.hrl").
 -include_lib("amqp_client/include/amqp_client.hrl").
 
--define(SIMON, #amqp_params_network{username     = <<"Simon MacMullen">>,
+-define(SIMON_NAME, "Simon MacMullen").
+-define(MIKEB_NAME, "Mike Bridgen").
+-define(VHOST, "test").
+
+-define(SIMON, #amqp_params_network{username     = << ?SIMON_NAME >>,
                                     password     = <<"password">>,
-                                    virtual_host = <<"test">>}).
+                                    virtual_host = << ?VHOST >>}).
 
--define(MIKEB, #amqp_params_network{username     = <<"Mike Bridgen">>,
+-define(MIKEB, #amqp_params_network{username     = << ?MIKEB_NAME >>,
                                     password     = <<"password">>,
-                                    virtual_host = <<"test">>}).
+                                    virtual_host = << ?VHOST >>}).
+
+%%--------------------------------------------------------------------
+
+ldap_only_test_() ->
+    { setup,
+      fun () -> ok = application:set_env(rabbit, auth_backends,
+          [rabbit_auth_backend_ldap]) end,
+      fun (_) -> ok = application:unset_env(rabbit, auth_backends) end,
+      [ {"LDAP Login", login()},
+        {"LDAP In group", in_group()},
+        {"LDAP Constant", const()},
+        {"LDAP String match", string_match()},
+        {"LDAP Boolean check", boolean_logic()},
+        {"LDAP Tags", tag_check([])}
+    ]}.
+
+ldap_and_internal_test_() ->
+    { setup,
+      fun () ->
+          ok = application:set_env(rabbit, auth_backends,
+              [{rabbit_auth_backend_ldap, rabbit_auth_backend_internal}]),
+          ok = control_action(add_user, [ ?SIMON_NAME, ""]),
+          ok = control_action(set_permissions, [ ?SIMON_NAME, "prefix-.*", "prefix-.*", "prefix-.*"]),
+          ok = control_action(set_user_tags, [ ?SIMON_NAME, "management", "foo"]),
+          ok = control_action(add_user, [ ?MIKEB_NAME, ""]),
+          ok = control_action(set_permissions, [ ?MIKEB_NAME, "", "", ""])
+      end,
+      fun (_) ->
+          ok = application:unset_env(rabbit, auth_backends),
+          ok = control_action(delete_user, [ ?SIMON_NAME ]),
+          ok = control_action(delete_user, [ ?MIKEB_NAME ])
+      end,
+      [ {"LDAP&Internal Login", login()},
+        {"LDAP&Internal Permissions", permission_match()},
+        {"LDAP&Internal Tags", tag_check([management, foo])}
+    ]}.
+
+internal_followed_ldap_and_internal_test_() ->
+    { setup,
+      fun () ->
+          ok = application:set_env(rabbit, auth_backends,
+              [rabbit_auth_backend_internal, {rabbit_auth_backend_ldap, rabbit_auth_backend_internal}]),
+          ok = control_action(add_user, [ ?SIMON_NAME, ""]),
+          ok = control_action(set_permissions, [ ?SIMON_NAME, "prefix-.*", "prefix-.*", "prefix-.*"]),
+          ok = control_action(set_user_tags, [ ?SIMON_NAME, "management", "foo"]),
+          ok = control_action(add_user, [ ?MIKEB_NAME, ""]),
+          ok = control_action(set_permissions, [ ?MIKEB_NAME, "", "", ""])
+      end,
+      fun (_) ->
+          ok = application:unset_env(rabbit, auth_backends),
+          ok = control_action(delete_user, [ ?SIMON_NAME ]),
+          ok = control_action(delete_user, [ ?MIKEB_NAME ])
+      end,
+      [ {"Internal, LDAP&Internal Login", login()},
+        {"Internal, LDAP&Internal Permissions", permission_match()},
+        {"Internal, LDAP&Internal Tags", tag_check([management, foo])}
+    ]}.
+
 
 %%--------------------------------------------------------------------
 
-login_test_() ->
+login() ->
     [test_login(Env, L, case {LGood, EnvGood} of
                             {good, good} -> fun succ/1;
                             _            -> fun fail/1
@@ -90,17 +152,17 @@ fail(Login) -> ?assertMatch({error, _}, amqp_connection:start(Login)).
 
 %%--------------------------------------------------------------------
 
-in_group_test_() ->
+in_group() ->
     X = [#'exchange.declare'{exchange = <<"test">>}],
     test_resource_funs([{?SIMON, X, ok},
                          {?MIKEB, X, fail}]).
 
-const_test_() ->
+const() ->
     Q = [#'queue.declare'{queue = <<"test">>}],
     test_resource_funs([{?SIMON, Q, ok},
                         {?MIKEB, Q, fail}]).
 
-string_match_test_() ->
+string_match() ->
     B = fun(N) ->
                 [#'exchange.declare'{exchange = N},
                  #'queue.declare'{queue = <<"test">>},
@@ -110,7 +172,7 @@ string_match_test_() ->
                         {?SIMON, B(<<"abc123">>),                     fail},
                         {?SIMON, B(<<"xch-Someone Else-abc123">>),    fail}]).
 
-boolean_logic_test_() ->
+boolean_logic() ->
     Q1 = [#'queue.declare'{queue = <<"test1">>},
           #'basic.consume'{queue = <<"test1">>}],
     Q2 = [#'queue.declare'{queue = <<"test2">>},
@@ -120,6 +182,26 @@ boolean_logic_test_() ->
                                        {?MIKEB, Q1, fail},
                                        {?MIKEB, Q2, fail}]].
 
+permission_match() ->
+    B = fun(N) ->
+                [#'exchange.declare'{exchange = N},
+                 #'queue.declare'{queue = <<"prefix-test">>},
+                 #'queue.bind'{exchange = N, queue = <<"prefix-test">>}]
+        end,
+    test_resource_funs([{?SIMON, B(<<"prefix-abc123">>),              ok},
+                        {?SIMON, B(<<"abc123">>),                     fail},
+                        {?SIMON, B(<<"xch-Simon MacMullen-abc123">>), fail}]).
+
+tag_check(Tags) ->
+    fun() ->
+            {ok, User} = rabbit_access_control:check_user_pass_login(
+                        << ?SIMON_NAME >>, <<"password">>),
+            ?assertEqual(Tags, User#user.tags)
+    end.
+
+
+%%--------------------------------------------------------------------
+
 test_resource_funs(PTRs) -> [test_resource_fun(PTR) || PTR <- PTRs].
 
 test_resource_fun({Person, Things, Result}) ->
@@ -135,4 +217,34 @@ test_resource_fun({Person, Things, Result}) ->
                          end)
     end.
 
-%%--------------------------------------------------------------------
+control_action(Command, Args) ->
+    control_action(Command, node(), Args, default_options()).
+
+control_action(Command, Args, NewOpts) ->
+    control_action(Command, node(), Args,
+                   expand_options(default_options(), NewOpts)).
+
+control_action(Command, Node, Args, Opts) ->
+    case catch rabbit_control_main:action(
+                 Command, Node, Args, Opts,
+                 fun (Format, Args1) ->
+                         io:format(Format ++ " ...~n", Args1)
+                 end) of
+        ok ->
+            io:format("done.~n"),
+            ok;
+        Other ->
+            io:format("failed.~n"),
+            Other
+    end.
+
+default_options() -> [{"-p", ?VHOST}, {"-q", "false"}].
+
+expand_options(As, Bs) ->
+    lists:foldl(fun({K, _}=A, R) ->
+                        case proplists:is_defined(K, R) of
+                            true -> R;
+                            false -> [A | R]
+                        end
+                end, Bs, As).
+
diff --git a/rabbitmq-server/plugins-src/rabbitmq-consistent-hash-exchange/.travis.yml b/rabbitmq-server/plugins-src/rabbitmq-consistent-hash-exchange/.travis.yml
new file mode 100644 (file)
index 0000000..09fbd63
--- /dev/null
@@ -0,0 +1,32 @@
+sudo: false
+language: erlang
+addons:
+  apt:
+    packages:
+      - xsltproc
+otp_release:
+  - R16B03-1
+  - 17.5
+  - 18.0
+install:
+  - if [ ! -d "$HOME/rabbitmq-public-umbrella/.git" ]; then git clone https://github.com/rabbitmq/rabbitmq-public-umbrella.git $HOME/rabbitmq-public-umbrella; fi
+  - cd $HOME/rabbitmq-public-umbrella
+  - make co
+  - make up
+before_script:
+  - IFS="/" read -a PARTS <<< "$TRAVIS_REPO_SLUG"
+  - export TEST_DIR=$HOME/rabbitmq-public-umbrella/${PARTS[1]}
+  - rm -rf ${TEST_DIR}
+  - cp -r ${TRAVIS_BUILD_DIR} ${TEST_DIR}
+  - cd ${TEST_DIR}
+script: make test
+before_cache:
+  - rm -rf ${TEST_DIR}
+  - cd $HOME
+cache:
+  apt: true
+  directories:
+    - $HOME/rabbitmq-public-umbrella
+notifications:
+  email:
+    - alerts@rabbitmq.com
index 68e3253241027204e2895fd9013f02cb98844c54..36b4cf4518b4b2bd7b34b6c683de1cbb63cc257b 100644 (file)
@@ -86,7 +86,16 @@ route(#exchange { name      = Name,
 
 validate(_X) -> ok.
 
-validate_binding(_X, _B) -> ok.
+validate_binding(_X, #binding { key = K }) ->
+    try
+        V = list_to_integer(binary_to_list(K)),
+        case V < 1 of
+            true -> {error, {binding_invalid, "The binding key must be greater than 0", []}};
+            false -> ok
+        end
+    catch error:badarg ->
+            {error, {binding_invalid, "The binding key must be an integer: ~p", [K]}}
+    end.
 
 create(_Tx, _X) -> ok.
 
index 702fdb46c1c319584c2af5388d2ab6c8dd44b10e..9bb619d9b1a5886586e35daddecf91b39e231138 100644 (file)
@@ -17,6 +17,7 @@
 -module(rabbit_exchange_type_consistent_hash_test).
 -export([test/0]).
 -include_lib("amqp_client/include/amqp_client.hrl").
+-include_lib("eunit/include/eunit.hrl").
 
 %% Because the routing is probabilistic, we can't really test a great
 %% deal here.
@@ -29,6 +30,8 @@ test() ->
 t(Qs) ->
     ok = test_with_rk(Qs),
     ok = test_with_header(Qs),
+    ok = test_binding_with_negative_routing_key(),
+    ok = test_binding_with_non_numeric_routing_key(),
     ok.
 
 test_with_rk(Qs) ->
@@ -63,19 +66,19 @@ test0(MakeMethod, MakeMsg, DeclareArgs, [Q1, Q2, Q3, Q4] = Queues) ->
                             type = <<"x-consistent-hash">>,
                             auto_delete = true,
                             arguments = DeclareArgs
-                           }),
+                          }),
     [#'queue.declare_ok'{} =
          amqp_channel:call(Chan, #'queue.declare' {
-                             queue = Q, exclusive = true }) || Q <- Queues],
+                             queue = Q, exclusive = true}) || Q <- Queues],
     [#'queue.bind_ok'{} =
-         amqp_channel:call(Chan, #'queue.bind' { queue = Q,
+         amqp_channel:call(Chan, #'queue.bind' {queue = Q,
                                                  exchange = <<"e">>,
-                                                 routing_key = <<"10">> })
+                                                 routing_key = <<"10">>})
      || Q <- [Q1, Q2]],
     [#'queue.bind_ok'{} =
-         amqp_channel:call(Chan, #'queue.bind' { queue = Q,
+         amqp_channel:call(Chan, #'queue.bind' {queue = Q,
                                                  exchange = <<"e">>,
-                                                 routing_key = <<"20">> })
+                                                 routing_key = <<"20">>})
      || Q <- [Q3, Q4]],
     #'tx.select_ok'{} = amqp_channel:call(Chan, #'tx.select'{}),
     [amqp_channel:call(Chan,
@@ -86,13 +89,49 @@ test0(MakeMethod, MakeMsg, DeclareArgs, [Q1, Q2, Q3, Q4] = Queues) ->
         [begin
             #'queue.declare_ok'{message_count = M} =
                  amqp_channel:call(Chan, #'queue.declare' {queue     = Q,
-                                                           exclusive = true }),
+                                                           exclusive = true}),
              M
          end || Q <- Queues],
     Count = lists:sum(Counts), %% All messages got routed
     [true = C > 0.01 * Count || C <- Counts], %% We are not *grossly* unfair
-    amqp_channel:call(Chan, #'exchange.delete' { exchange = <<"e">> }),
-    [amqp_channel:call(Chan, #'queue.delete' { queue = Q }) || Q <- Queues],
+    amqp_channel:call(Chan, #'exchange.delete' {exchange = <<"e">>}),
+    [amqp_channel:call(Chan, #'queue.delete' {queue = Q}) || Q <- Queues],
     amqp_channel:close(Chan),
     amqp_connection:close(Conn),
     ok.
+
+test_binding_with_negative_routing_key() ->
+    {ok, Conn} = amqp_connection:start(#amqp_params_network{}),
+    {ok, Chan} = amqp_connection:open_channel(Conn),
+    Declare1 = #'exchange.declare'{exchange = <<"bind-fail">>,
+                                    type = <<"x-consistent-hash">>},
+    #'exchange.declare_ok'{} = amqp_channel:call(Chan, Declare1),
+    Q = <<"test-queue">>,
+    Declare2 = #'queue.declare'{queue = Q},
+    #'queue.declare_ok'{} = amqp_channel:call(Chan, Declare2),
+    process_flag(trap_exit, true),
+    Cmd = #'queue.bind'{exchange = <<"bind-fail">>,
+                         routing_key = <<"-1">>},
+    ?assertExit(_, amqp_channel:call(Chan, Cmd)),
+    {ok, Ch2} = amqp_connection:open_channel(Conn),
+    amqp_channel:call(Ch2, #'queue.delete'{queue = Q}),
+    amqp_connection:close(Conn),
+    ok.
+
+test_binding_with_non_numeric_routing_key() ->
+    {ok, Conn} = amqp_connection:start(#amqp_params_network{}),
+    {ok, Chan} = amqp_connection:open_channel(Conn),
+    Declare1 = #'exchange.declare'{exchange = <<"bind-fail">>,
+                                    type = <<"x-consistent-hash">>},
+    #'exchange.declare_ok'{} = amqp_channel:call(Chan, Declare1),
+    Q = <<"test-queue">>,
+    Declare2 = #'queue.declare'{queue = Q},
+    #'queue.declare_ok'{} = amqp_channel:call(Chan, Declare2),
+    process_flag(trap_exit, true),
+    Cmd = #'queue.bind'{exchange = <<"bind-fail">>,
+                         routing_key = <<"not-a-number">>},
+    ?assertExit(_, amqp_channel:call(Chan, Cmd)),
+    {ok, Ch2} = amqp_connection:open_channel(Conn),
+    amqp_channel:call(Ch2, #'queue.delete'{queue = Q}),
+    amqp_connection:close(Conn),
+    ok.
index 46b2a4d6e3b3efeb1a2148a3304e6b0298e29c2b..930e232875247b0ee8715faeb3c000126871b8bc 100644 (file)
@@ -37,7 +37,9 @@
              rabbit_queue_collector,
              rabbit_queue_decorator,
              rabbit_amqqueue,
-             supervisor2
+             ssl_compat,
+             supervisor2,
+             time_compat
   ]},
   {registered, []},
   {env, []},
index 7110ea260fcf464d09d78c7eb7ddd768b040acd6..c989072e86a5acaa3beb74c3ae05d47445b34e37 100644 (file)
@@ -50,7 +50,7 @@ HELP['federation-prefetch'] =
     'Maximum number of unacknowledged messages that may be in flight over a federation link at one time. Defaults to 1000 if not set.';
 
 HELP['federation-reconnect'] =
-    'Time in seconds to wait after a network link goes down before attempting reconnection. Defaults to 1 if not set.';
+    'Time in seconds to wait after a network link goes down before attempting reconnection. Defaults to 5 if not set.';
 
 HELP['federation-ack-mode'] =
     '<dl>\
diff --git a/rabbitmq-server/plugins-src/rabbitmq-federation/README b/rabbitmq-server/plugins-src/rabbitmq-federation/README
deleted file mode 100644 (file)
index 250b42a..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-Generic build instructions are at:
-        http://www.rabbitmq.com/plugin-development.html
-
-See http://www.rabbitmq.com/federation.html
diff --git a/rabbitmq-server/plugins-src/rabbitmq-federation/README.md b/rabbitmq-server/plugins-src/rabbitmq-federation/README.md
new file mode 100644 (file)
index 0000000..e7d8c0e
--- /dev/null
@@ -0,0 +1,23 @@
+## RabbitMQ Federation
+
+RabbitMQ federation offers a group of features for loosely
+coupled and WAN-friendly distributed RabbitMQ setups. Note that
+this is not an alternative to queue mirroring.
+
+
+## Supported RabbitMQ Versions
+
+This plugin ships with RabbitMQ, there is no need to
+install it separately.
+
+
+## Documentation        
+
+See [RabbitMQ federation plugin](http://www.rabbitmq.com/federation.html) on rabbitmq.com.
+
+
+## License and Copyright
+
+Released under [the same license as RabbitMQ](https://www.rabbitmq.com/mpl.html).
+
+2007-2015 (c) Pivotal Software Inc.
index 4dd7810c01385e71ffd46dd8fb10b1aa20cbf3dd..e498f76a536fc0b09efcd35e10cf186ade485524 100644 (file)
@@ -253,30 +253,41 @@ update_headers(#upstream_params{table = Table}, Redelivered, X, K, Headers) ->
                 %% routing key the first time a message gets
                 %% forwarded; after that it's known that they were
                 %% <<>> and QueueName respectively.
-                {rabbit_misc:set_table_value(
-                   rabbit_misc:set_table_value(
-                     Headers, <<"x-original-exchange">>, longstr, X),
-                   <<"x-original-routing-key">>, longstr, K), 0};
+                {init_x_original_source_headers(Headers, X, K), 0};
             {array, Been} ->
-                {Found, Been1} = lists:partition(
-                                      fun (I) -> visit_match(I, Table) end,
-                                      Been),
-                C = case Found of
-                        []           -> 0;
-                        [{table, T}] -> case rabbit_misc:table_lookup(
-                                               T, <<"visit-count">>) of
-                                            {_, I} when is_number(I) -> I;
-                                            _                        -> 0
-                                        end
-                    end,
-                {rabbit_misc:set_table_value(
-                   Headers, ?ROUTING_HEADER, array, Been1), C}
+                update_visit_count(Table, Been, Headers);
+            %% this means the header comes from the client
+            %% which re-published the message, most likely unintentionally.
+            %% We can't assume much about the value, so we simply ignore it.
+            _Other ->
+                {init_x_original_source_headers(Headers, X, K), 0}
         end,
     rabbit_basic:prepend_table_header(
       ?ROUTING_HEADER, Table ++ [{<<"redelivered">>, bool, Redelivered},
                                  {<<"visit-count">>, long, Count + 1}],
       swap_cc_header(Headers1)).
 
+init_x_original_source_headers(Headers, X, K) ->
+    rabbit_misc:set_table_value(
+        rabbit_misc:set_table_value(
+            Headers, <<"x-original-exchange">>, longstr, X),
+        <<"x-original-routing-key">>, longstr, K).
+
+update_visit_count(Table, Been, Headers) ->
+    {Found, Been1} = lists:partition(
+        fun(I) -> visit_match(I, Table) end,
+        Been),
+    C = case Found of
+            [] -> 0;
+            [{table, T}] -> case rabbit_misc:table_lookup(
+                T, <<"visit-count">>) of
+                                {_, I} when is_number(I) -> I;
+                                _ -> 0
+                            end
+        end,
+    {rabbit_misc:set_table_value(
+        Headers, ?ROUTING_HEADER, array, Been1), C}.
+
 swap_cc_header(Table) ->
     [{case K of
           <<"CC">> -> <<"x-original-cc">>;
index 398dbcf6cba8d4d907747f4f21aff65c93791cce..ae4c512d3973400bb1621544bb06ec19480f57da 100644 (file)
@@ -122,7 +122,7 @@ from_upstream_or_set(US, Name, U, XorQ) ->
               exchange_name   = bget(exchange,          US, U, name(XorQ)),
               queue_name      = bget(queue,             US, U, name(XorQ)),
               prefetch_count  = bget('prefetch-count',  US, U, ?DEF_PREFETCH),
-              reconnect_delay = bget('reconnect-delay', US, U, 1),
+              reconnect_delay = bget('reconnect-delay', US, U, 5),
               max_hops        = bget('max-hops',        US, U, 1),
               expires         = bget(expires,           US, U, none),
               message_ttl     = bget('message-ttl',     US, U, none),
index e07b69d5a49a03beb4d2d226d595077016b0f271..a5aecc6b01e930d5e91d5aca87a5a4686a88d6c4 100644 (file)
@@ -19,6 +19,7 @@
 -behaviour(rabbit_mgmt_extension).
 
 -export([dispatcher/0, web_ui/0]).
+
 dispatcher() -> [{["all"],        rabbit_mgmt_wm_all, []},
                  {["all", vhost], rabbit_mgmt_wm_all, []}].
 web_ui()     -> [{javascript, <<"visualiser.js">>}].
diff --git a/rabbitmq-server/plugins-src/rabbitmq-management/.travis.yml b/rabbitmq-server/plugins-src/rabbitmq-management/.travis.yml
new file mode 100644 (file)
index 0000000..2d93510
--- /dev/null
@@ -0,0 +1,33 @@
+sudo: false
+language: erlang
+notifications:
+  email:
+    - alerts@rabbitmq.com
+addons:
+  apt:
+    packages:
+      - xsltproc
+      - python3
+otp_release:
+  - "R16B03-1"
+  - "17.5"
+  - "18.0"
+install:
+  - if [ ! -d "$HOME/rabbitmq-public-umbrella/.git" ]; then git clone https://github.com/rabbitmq/rabbitmq-public-umbrella.git $HOME/rabbitmq-public-umbrella; fi
+  - cd $HOME/rabbitmq-public-umbrella
+  - make co
+  - make up
+before_script:
+  - IFS="/" read -a PARTS <<< "$TRAVIS_REPO_SLUG"
+  - export TEST_DIR=$HOME/rabbitmq-public-umbrella/${PARTS[1]}
+  - rm -rf ${TEST_DIR}
+  - cp -r ${TRAVIS_BUILD_DIR} ${TEST_DIR}
+  - cd ${TEST_DIR}
+script: make test
+before_cache:
+  - rm -rf ${TEST_DIR}
+  - cd $HOME
+cache:
+  apt: true
+  directories:
+    - $HOME/rabbitmq-public-umbrella
index 8f7f8138af4da4c94d4927c75d6396c3e01aa095..b3c5bc9089467b78f4957cc3136dc65cf03580b9 100644 (file)
@@ -205,14 +205,20 @@ function fmt_rate_num(num) {
     if (num == undefined) return UNKNOWN_REPR;
     else if (num < 1)     return num.toFixed(2);
     else if (num < 10)    return num.toFixed(1);
-    else                  return fmt_num_thousands(num.toFixed(0));
+    else                  return fmt_num_thousands(num);
 }
 
 function fmt_num_thousands(num) {
-    if (num == undefined) return UNKNOWN_REPR;
-    num = '' + num;
-    if (num.length < 4) return num;
-    return fmt_num_thousands(num.slice(0, -3)) + ',' + num.slice(-3);
+    var conv_num = parseFloat(num); // to avoid errors, if someone calls fmt_num_thousands(someNumber.toFixed(0))
+    return fmt_num_thousands_unfixed(conv_num.toFixed(0));
+}
+
+function fmt_num_thousands_unfixed(num) {
+     if (num == undefined) return UNKNOWN_REPR;
+     num = '' + num;
+     if (num.length < 4) return num;
+     res= fmt_num_thousands_unfixed(num.slice(0, -3)) + ',' + num.slice(-3);
+     return res;
 }
 
 function fmt_percent(num) {
index b16d13136f0e22c7553ea333856870ca4c6a1360..d2a06414dcaa84fc4b3565faec9217054d357e40 100644 (file)
@@ -100,10 +100,16 @@ utf8_safe(V) ->
         xmerl_ucs:from_utf8(V),
         V
     catch exit:{ucs, _} ->
-            Enc = base64:encode(V),
-            <<"Invalid UTF-8, base64 is: ", Enc/binary>>
+            Enc = split_lines(base64:encode(V)),
+            <<"Not UTF-8, base64 is: ", Enc/binary>>
     end.
 
+% MIME enforces a limit on line length of base 64-encoded data to 76 characters.
+split_lines(<<Text:76/binary, Rest/binary>>) ->
+    <<Text/binary, $\n, (split_lines(Rest))/binary>>;
+split_lines(Text) ->
+    Text.
+
 parameter(P) -> pset(value, rabbit_misc:term_to_json(pget(value, P)), P).
 
 tuple(unknown)                    -> unknown;
index 470af56551e23cc051d8ed649d81723ea18bdc8f..47af73b3d32243d99778fe6a9e83e656a619d3c2 100755 (executable)
@@ -163,6 +163,7 @@ tracing: False
         self.assert_table([exp_msg('test', 0, False, 'test_3')], ['get', 'queue=test', 'requeue=false'])
         self.run_success(['publish', 'routing_key=test'], stdin=b'test_4')
         filename = '/tmp/rabbitmq-test/get.txt'
+        ensure_dir(filename)
         self.run_success(['get', 'queue=test', 'requeue=false', 'payload_file=' + filename])
         with open(filename) as f:
             self.assertEqual('test_4', f.read())
@@ -242,6 +243,11 @@ def exp_msg(key, count, redelivered, payload):
     # routing_key, exchange, message_count, payload, payload_bytes, payload_encoding, properties, redelivered
     return [key, '', str(count), payload, str(len(payload)), 'string', '', str(redelivered)]
 
+def ensure_dir(f):
+    d = os.path.dirname(f)
+    if not os.path.exists(d):
+        os.makedirs(d)
+
 if __name__ == '__main__':
     print("\nrabbitmqadmin tests\n===================\n")
     suite = unittest.TestLoader().loadTestsFromTestCase(TestRabbitMQAdmin)
index c5d5bcc756469822f598ce3e6c8738124c6511e5..9db089546a89ab8fe5f27007b814144f85e96719 100644 (file)
@@ -1,5 +1,6 @@
 RELEASABLE:=true
 DEPS:=rabbitmq-server rabbitmq-erlang-client rabbitmq-test
+STANDALONE_TEST_COMMANDS:=eunit:test(rabbit_mqtt_util)
 WITH_BROKER_TEST_SCRIPTS:=$(PACKAGE_DIR)/test/test.sh
 WITH_BROKER_TEST_CONFIG:=$(PACKAGE_DIR)/test/ebin/test
 WITH_BROKER_SETUP_SCRIPTS:=$(PACKAGE_DIR)/test/setup-rabbit-test.sh
@@ -12,6 +13,7 @@ $(PACKAGE_DIR)+pre-test::
        mkdir -p $(PACKAGE_DIR)/test/ebin
        sed -E -e "s|%%CERTS_DIR%%|$(abspath $(PACKAGE_DIR))/test/certs|g" < $(PACKAGE_DIR)/test/src/test.config > $(PACKAGE_DIR)/test/ebin/test.config
        $(MAKE) -C $(PACKAGE_DIR)/../rabbitmq-test/certs all PASSWORD=bunnychow DIR=$(abspath $(PACKAGE_DIR))/test/certs
+       cp $(PACKAGE_DIR)/test/src/rabbitmq_mqtt_standalone.app.src $(PACKAGE_DIR)/test/ebin/rabbitmq_mqtt.app
 
 $(PACKAGE_DIR)+clean::
        rm -rf $(PACKAGE_DIR)/test/certs
index 8ab736c458285610d84a75dde87a704da5d71870..5c51a8bf0b0dca72be66072a55f2c067467701cb 100644 (file)
@@ -429,7 +429,7 @@ ensure_queue(Qos, #proc_state{ channels      = {Channel, _},
                 {QueueQ1,
                  #'queue.declare'{ queue       = QueueQ1,
                                    durable     = true,
-                                   auto_delete = CleanSess,
+                                   auto_delete = false,
                                    arguments   = Qos1Args },
                  #'basic.consume'{ queue  = QueueQ1,
                                    no_ack = false }};
index 9c1787a5898fa5d3c63f13ac0e6c21e4694065fd..336e2a4062f70b5cc10d4dd837c4d96d5f2e8f52 100644 (file)
@@ -43,10 +43,19 @@ gen_client_id() ->
 
 env(Key) ->
     case application:get_env(rabbitmq_mqtt, Key) of
-        {ok, Val} -> Val;
+        {ok, Val} -> coerce_env_value(Key, Val);
         undefined -> undefined
     end.
 
+coerce_env_value(default_pass, Val) -> to_binary(Val);
+coerce_env_value(default_user, Val) -> to_binary(Val);
+coerce_env_value(exchange, Val)     -> to_binary(Val);
+coerce_env_value(vhost, Val)        -> to_binary(Val);
+coerce_env_value(_, Val)            -> Val.
+
+to_binary(Val) when is_list(Val) -> list_to_binary(Val);
+to_binary(Val)                   -> Val.
+
 table_lookup(undefined, _Key) ->
     undefined;
 table_lookup(Table, Key) ->
index b5a491375781feda8c59edccd7ce263199fff77a..ca31b5c7eb07f23ba2ad02fdf73995fb57f6e25f 100644 (file)
@@ -102,13 +102,13 @@ public class MqttTest extends TestCase implements MqttCallback {
         try {
             client.connect(conOpt);
             client.disconnect();
-        } catch (Exception _) {}
+        } catch (Exception ignored) {}
 
         client2 = new MqttClient(brokerUrl, clientId2, null);
         try {
             client2.connect(conOpt);
             client2.disconnect();
-        } catch (Exception _) {}
+        } catch (Exception ignored) {}
     }
 
     private void setUpAmqp() throws IOException, TimeoutException {
@@ -140,7 +140,7 @@ public class MqttTest extends TestCase implements MqttCallback {
             mqttOut.flush();
             mqttIn.readMqttWireMessage();
             fail("Error expected if CONNECT is not first packet");
-        } catch (IOException _) {}
+        } catch (IOException ignored) {}
     }
 
     public void testInvalidUser() throws MqttException {
index f89d9635a2b7f8fd6092e4ce723026e2f7e0d8b2..8bf9629758842fe2b59bc5aa91572dc2d4f3d2fb 100644 (file)
@@ -92,14 +92,14 @@ public class MqttSSLTest extends TestCase implements MqttCallback {
         try {
             client.connect(conOpt);
             client.disconnect();
-        } catch (Exception _) {
+        } catch (Exception ignored) {
         }
 
         client2 = new MqttClient(brokerUrl, clientId2, null);
         try {
             client2.connect(conOpt);
             client2.disconnect();
-        } catch (Exception _) {
+        } catch (Exception ignored) {
         }
     }
 
diff --git a/rabbitmq-server/plugins-src/rabbitmq-mqtt/test/src/rabbit_mqtt_util_tests.erl b/rabbitmq-server/plugins-src/rabbitmq-mqtt/test/src/rabbit_mqtt_util_tests.erl
new file mode 100644 (file)
index 0000000..be307bf
--- /dev/null
@@ -0,0 +1,42 @@
+%% The contents of this file are subject to the Mozilla Public License
+%% Version 1.1 (the "License"); you may not use this file except in
+%% compliance with the License. You may obtain a copy of the License
+%% at http://www.mozilla.org/MPL/
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and
+%% limitations under the License.
+%%
+%% The Original Code is RabbitMQ.
+%%
+%% The Initial Developer of the Original Code is GoPivotal, Inc.
+%% Copyright (c) 2007-2015 Pivotal Software, Inc.  All rights reserved.
+%%
+
+-module(rabbit_mqtt_util_tests).
+
+-include_lib("eunit/include/eunit.hrl").
+
+all_test_() ->
+    {setup,
+     fun setup/0,
+     [fun coerce_exchange/0,
+      fun coerce_vhost/0,
+      fun coerce_default_user/0,
+      fun coerce_default_pass/0]}.
+
+setup() ->
+    application:load(rabbitmq_mqtt).
+
+coerce_exchange() ->
+    ?assertEqual(<<"amq.topic">>, rabbit_mqtt_util:env(exchange)).
+
+coerce_vhost() ->
+    ?assertEqual(<<"/">>, rabbit_mqtt_util:env(vhost)).
+
+coerce_default_user() ->
+    ?assertEqual(<<"guest_user">>, rabbit_mqtt_util:env(default_user)).
+
+coerce_default_pass() ->
+    ?assertEqual(<<"guest_pass">>, rabbit_mqtt_util:env(default_pass)).
diff --git a/rabbitmq-server/plugins-src/rabbitmq-mqtt/test/src/rabbitmq_mqtt_standalone.app.src b/rabbitmq-server/plugins-src/rabbitmq-mqtt/test/src/rabbitmq_mqtt_standalone.app.src
new file mode 100644 (file)
index 0000000..1c9fcb4
--- /dev/null
@@ -0,0 +1,22 @@
+{application, rabbitmq_mqtt,
+ [{description, "RabbitMQ MQTT Adapter"},
+  {vsn, "%%VSN%%"},
+  {modules, []},
+  {registered, []},
+  {mod, {rabbit_mqtt, []}},
+  {env, [{default_user, "guest_user"},
+         {default_pass, "guest_pass"},
+         {ssl_cert_login,false},
+         {allow_anonymous, true},
+         {vhost, "/"},
+         {exchange, "amq.topic"},
+         {subscription_ttl, 1800000}, % 30 min
+         {prefetch, 10},
+         {ssl_listeners, []},
+         {tcp_listeners, [1883]},
+         {tcp_listen_options, [binary,
+                               {packet,    raw},
+                               {reuseaddr, true},
+                               {backlog,   128},
+                               {nodelay,   true}]}]},
+  {applications, [kernel, stdlib, rabbit, amqp_client]}]}.
diff --git a/rabbitmq-server/plugins-src/rabbitmq-stomp/.travis.yml b/rabbitmq-server/plugins-src/rabbitmq-stomp/.travis.yml
new file mode 100644 (file)
index 0000000..467bda0
--- /dev/null
@@ -0,0 +1,32 @@
+sudo: false
+language: erlang
+notifications:
+  email:
+    - alerts@rabbitmq.com
+addons:
+  apt:
+    packages:
+      - xsltproc
+otp_release:
+  - R16B03-1
+  - "17.5"
+  - "18.0"
+install:
+  - if [ ! -d "$HOME/rabbitmq-public-umbrella/.git" ]; then git clone https://github.com/rabbitmq/rabbitmq-public-umbrella.git $HOME/rabbitmq-public-umbrella; fi
+  - cd $HOME/rabbitmq-public-umbrella
+  - make co
+  - make up
+before_script:
+  - IFS="/" read -a PARTS <<< "$TRAVIS_REPO_SLUG"
+  - export TEST_DIR=$HOME/rabbitmq-public-umbrella/${PARTS[1]}
+  - rm -rf ${TEST_DIR}
+  - cp -r ${TRAVIS_BUILD_DIR} ${TEST_DIR}
+  - cd ${TEST_DIR}
+script: make test
+before_cache:
+  - rm -rf ${TEST_DIR}
+  - cd $HOME
+cache:
+  apt: true
+  directories:
+    - $HOME/rabbitmq-public-umbrella
diff --git a/rabbitmq-server/plugins-src/rabbitmq-stomp/deps/pika/Makefile b/rabbitmq-server/plugins-src/rabbitmq-stomp/deps/pika/Makefile
new file mode 100644 (file)
index 0000000..b082bb5
--- /dev/null
@@ -0,0 +1,27 @@
+UPSTREAM_GIT=https://github.com/pika/pika.git
+REVISION=0.9.14
+
+LIB_DIR=pika
+CHECKOUT_DIR=pika-git
+
+TARGETS=$(LIB_DIR)
+
+all: $(TARGETS)
+
+clean:
+       rm -rf $(LIB_DIR)
+
+distclean: clean
+       rm -rf $(CHECKOUT_DIR)
+
+$(LIB_DIR) : $(CHECKOUT_DIR)
+       rm -rf $@
+       cp -R $< $@
+
+$(CHECKOUT_DIR):
+       git clone $(UPSTREAM_GIT) $@
+       (cd $@ && git checkout $(REVISION)) || rm -rf $@
+
+echo-revision:
+       @echo $(REVISION)
+
index 398ce4216973abc50604c249ef983a6cf2c80f09..3aff8b50dfec24685958f43d9c916c573ff29fe4 100644 (file)
@@ -34,6 +34,7 @@
 -define(HEADER_PREFETCH_COUNT, "prefetch-count").
 -define(HEADER_PRIORITY, "priority").
 -define(HEADER_RECEIPT, "receipt").
+-define(HEADER_REDELIVERED, "redelivered").
 -define(HEADER_REPLY_TO, "reply-to").
 -define(HEADER_SERVER, "server").
 -define(HEADER_SESSION, "session").
 -define(HEADER_TYPE, "type").
 -define(HEADER_USER_ID, "user-id").
 -define(HEADER_VERSION, "version").
+-define(HEADER_X_DEAD_LETTER_EXCHANGE, "x-dead-letter-exchange").
+-define(HEADER_X_DEAD_LETTER_ROUTING_KEY, "x-dead-letter-routing-key").
+-define(HEADER_X_EXPIRES, "x-expires").
+-define(HEADER_X_MAX_LENGTH, "x-max-length").
+-define(HEADER_X_MAX_LENGTH_BYTES, "x-max-length-bytes").
+-define(HEADER_X_MAX_PRIORITY, "x-max-priority").
+-define(HEADER_X_MESSAGE_TTL, "x-message-ttl").
 
 -define(MESSAGE_ID_SEPARATOR, "@@").
 
 -define(HEADERS_NOT_ON_SEND, [?HEADER_MESSAGE_ID]).
 
 -define(TEMP_QUEUE_ID_PREFIX, "/temp-queue/").
+
+-define(HEADER_ARGUMENTS, [
+                           ?HEADER_X_DEAD_LETTER_EXCHANGE,
+                           ?HEADER_X_DEAD_LETTER_ROUTING_KEY,
+                           ?HEADER_X_EXPIRES,
+                           ?HEADER_X_MAX_LENGTH,
+                           ?HEADER_X_MAX_LENGTH_BYTES,
+                           ?HEADER_X_MAX_PRIORITY,
+                           ?HEADER_X_MESSAGE_TTL
+                          ]).
index 67cb2c83cc8122cff3c1f8128daadd7159652636..daacc687e0ff7fa54557f3c0ea4d8d32715fa04b 100644 (file)
@@ -1,8 +1,8 @@
 RELEASABLE:=true
 DEPS:=rabbitmq-server rabbitmq-erlang-client rabbitmq-test
-#STANDALONE_TEST_COMMANDS:=eunit:test([rabbit_stomp_test_util,rabbit_stomp_test_frame],[verbose])
+STANDALONE_TEST_COMMANDS:=eunit:test([rabbit_stomp_test_util,rabbit_stomp_test_frame],[verbose])
 WITH_BROKER_TEST_SCRIPTS:=$(PACKAGE_DIR)/test/src/test.py $(PACKAGE_DIR)/test/src/test_connect_options.py $(PACKAGE_DIR)/test/src/test_ssl.py
-#WITH_BROKER_TEST_COMMANDS:=rabbit_stomp_test:all_tests() rabbit_stomp_amqqueue_test:all_tests()
+WITH_BROKER_TEST_COMMANDS:=rabbit_stomp_test:all_tests() rabbit_stomp_amqqueue_test:all_tests()
 WITH_BROKER_TEST_CONFIG:=$(PACKAGE_DIR)/test/ebin/test
 
 define package_rules
@@ -14,11 +14,13 @@ $(PACKAGE_DIR)+pre-test::
        sed -e "s|%%CERTS_DIR%%|$(abspath $(PACKAGE_DIR))/test/certs|g" < $(PACKAGE_DIR)/test/src/test.config > $(PACKAGE_DIR)/test/ebin/test.config
        $(MAKE) -C $(PACKAGE_DIR)/../rabbitmq-test/certs all PASSWORD=test DIR=$(abspath $(PACKAGE_DIR))/test/certs
        $(MAKE) -C $(PACKAGE_DIR)/deps/stomppy
+       $(MAKE) -C $(PACKAGE_DIR)/deps/pika
 
 $(PACKAGE_DIR)+clean::
        rm -rf $(PACKAGE_DIR)/test/certs
 
 $(PACKAGE_DIR)+clean-with-deps::
        $(MAKE) -C $(PACKAGE_DIR)/deps/stomppy distclean
+       $(MAKE) -C $(PACKAGE_DIR)/deps/pika distclean
 
 endef
index ecd636524f722a1584bda2bd7079b1773ce4c94f..e6cedcfac07741f3a665181a9393f5c35b6aba1d 100644 (file)
@@ -27,7 +27,7 @@
          boolean_header/2, boolean_header/3,
          integer_header/2, integer_header/3,
          binary_header/2, binary_header/3]).
--export([serialize/1]).
+-export([serialize/1, serialize/2]).
 
 initial_state() -> none.
 
@@ -222,9 +222,16 @@ binary_header(F, K) ->
 
 binary_header(F, K, D) -> default_value(binary_header(F, K), D).
 
+serialize(Frame) ->
+    serialize(Frame, true).
+
+%% second argument controls whether a trailing linefeed
+%% character should be added, see rabbitmq/rabbitmq-stomp#39.
+serialize(Frame, true) ->
+    serialize(Frame, false) ++ [?LF];
 serialize(#stomp_frame{command = Command,
                        headers = Headers,
-                       body_iolist = BodyFragments}) ->
+                       body_iolist = BodyFragments}, false) ->
     Len = iolist_size(BodyFragments),
     [Command, ?LF,
      lists:map(fun serialize_header/1,
@@ -233,11 +240,15 @@ serialize(#stomp_frame{command = Command,
          Len > 0 -> [?HEADER_CONTENT_LENGTH ++ ":", integer_to_list(Len), ?LF];
          true    -> []
      end,
-     ?LF, BodyFragments, 0, ?LF].
+     ?LF, BodyFragments, 0].
 
 serialize_header({K, V}) when is_integer(V) -> hdr(escape(K), integer_to_list(V));
+serialize_header({K, V}) when is_boolean(V) -> hdr(escape(K), boolean_to_list(V));
 serialize_header({K, V}) when is_list(V)    -> hdr(escape(K), escape(V)).
 
+boolean_to_list(true) -> "true";
+boolean_to_list(_)    -> "false".
+
 hdr(K, V) -> [K, ?COLON, V, ?LF].
 
 escape(Str) -> [escape1(Ch) || Ch <- Str].
index 0a6dae72ce2a9891a406605750db9127fd77bc0a..80edb6676382b1269bd9c805707482b29271c07d 100644 (file)
@@ -30,7 +30,9 @@
 -record(state, {session_id, channel, connection, subscriptions,
                 version, start_heartbeat_fun, pending_receipts,
                 config, route_state, reply_queues, frame_transformer,
-                adapter_info, send_fun, ssl_login_name, peer_addr}).
+                adapter_info, send_fun, ssl_login_name, peer_addr,
+                %% see rabbitmq/rabbitmq-stomp#39
+                trailing_lf}).
 
 -record(subscription, {dest_hdr, ack_mode, multi_ack, description}).
 
@@ -71,7 +73,8 @@ init(Configuration) ->
        config              = Configuration,
        route_state         = rabbit_routing_util:init_state(),
        reply_queues        = dict:new(),
-       frame_transformer   = undefined},
+       frame_transformer   = undefined,
+       trailing_lf         = rabbit_misc:get_env(rabbitmq_stomp, trailing_lf, true)},
      hibernate,
      {backoff, 1000, 1000, 10000}
     }.
@@ -592,41 +595,51 @@ do_subscribe(Destination, DestHdr, Frame,
                 _         -> amqp_channel:call(
                                Channel, #'basic.qos'{prefetch_count = Prefetch})
             end,
-            ExchangeAndKey = rabbit_routing_util:parse_routing(Destination),
-            try
-                amqp_channel:subscribe(Channel,
-                                       #'basic.consume'{
-                                          queue        = Queue,
-                                          consumer_tag = ConsumerTag,
-                                          no_local     = false,
-                                          no_ack       = (AckMode == auto),
-                                          exclusive    = false,
-                                          arguments    = []},
-                                       self()),
-                ok = rabbit_routing_util:ensure_binding(
-                       Queue, ExchangeAndKey, Channel)
-            catch exit:Err ->
-                    %% it's safe to delete this queue, it was server-named
-                    %% and declared by us
-                    case Destination of
-                        {exchange, _} ->
-                            ok = maybe_clean_up_queue(Queue, State);
-                        {topic, _} ->
-                            ok = maybe_clean_up_queue(Queue, State);
-                        _ ->
-                            ok
+            case dict:find(ConsumerTag, Subs) of
+                {ok, _} ->
+                    Message = "Duplicated subscription identifier",
+                    Detail = "A subscription identified by '~s' alredy exists.",
+                    error(Message, Detail, [ConsumerTag], State),
+                    send_error(Message, Detail, [ConsumerTag], State),
+                    {stop, normal, close_connection(State)};
+                error ->
+                    ExchangeAndKey =
+                        rabbit_routing_util:parse_routing(Destination),
+                    try
+                        amqp_channel:subscribe(Channel,
+                                               #'basic.consume'{
+                                                  queue        = Queue,
+                                                  consumer_tag = ConsumerTag,
+                                                  no_local     = false,
+                                                  no_ack       = (AckMode == auto),
+                                                  exclusive    = false,
+                                                  arguments    = []},
+                                               self()),
+                        ok = rabbit_routing_util:ensure_binding(
+                               Queue, ExchangeAndKey, Channel)
+                    catch exit:Err ->
+                            %% it's safe to delete this queue, it
+                            %% was server-named and declared by us
+                            case Destination of
+                                {exchange, _} ->
+                                    ok = maybe_clean_up_queue(Queue, State);
+                                {topic, _} ->
+                                    ok = maybe_clean_up_queue(Queue, State);
+                                _ ->
+                                    ok
+                            end,
+                            exit(Err)
                     end,
-                    exit(Err)
-            end,
-            ok(State#state{subscriptions =
-                               dict:store(
-                                 ConsumerTag,
-                                 #subscription{dest_hdr    = DestHdr,
-                                               ack_mode    = AckMode,
-                                               multi_ack   = IsMulti,
-                                               description = Description},
-                                 Subs),
-                           route_state = RouteState1});
+                    ok(State#state{subscriptions =
+                                       dict:store(
+                                         ConsumerTag,
+                                         #subscription{dest_hdr    = DestHdr,
+                                                       ack_mode    = AckMode,
+                                                       multi_ack   = IsMulti,
+                                                       description = Description},
+                                         Subs),
+                                   route_state = RouteState1})
+            end;
         {error, _} = Err ->
             Err
     end.
@@ -973,7 +986,7 @@ millis_to_seconds(M)               -> M div 1000.
 ensure_endpoint(_Direction, {queue, []}, _Frame, _Channel, _State) ->
     {error, {invalid_destination, "Destination cannot be blank"}};
 
-ensure_endpoint(source, EndPoint, Frame, Channel, State) ->
+ensure_endpoint(source, EndPoint, {_, _, Headers, _} = Frame, Channel, State) ->
     Params =
         case rabbit_stomp_frame:boolean_header(
                Frame, ?HEADER_PERSISTENT, false) of
@@ -998,10 +1011,12 @@ ensure_endpoint(source, EndPoint, Frame, Channel, State) ->
                   end},
                  {durable, false}]
         end,
-    rabbit_routing_util:ensure_endpoint(source, Channel, EndPoint, Params, State);
+    Arguments = rabbit_stomp_util:build_arguments(Headers),
+    rabbit_routing_util:ensure_endpoint(source, Channel, EndPoint, [Arguments | Params], State);
 
-ensure_endpoint(Direction, Endpoint, _Frame, Channel, State) ->
-    rabbit_routing_util:ensure_endpoint(Direction, Channel, Endpoint, State).
+ensure_endpoint(Direction, Endpoint, {_, _, Headers, _}, Channel, State) ->
+    Arguments = rabbit_stomp_util:build_arguments(Headers),
+    rabbit_routing_util:ensure_endpoint(Direction, Channel, Endpoint, [Arguments], State).
 
 %%----------------------------------------------------------------------------
 %% Success/error handling
@@ -1051,8 +1066,9 @@ send_frame(Command, Headers, BodyFragments, State) ->
                             body_iolist = BodyFragments},
                State).
 
-send_frame(Frame, State = #state{send_fun = SendFun}) ->
-    SendFun(async, rabbit_stomp_frame:serialize(Frame)),
+send_frame(Frame, State = #state{send_fun = SendFun,
+                                 trailing_lf = TrailingLF}) ->
+    SendFun(async, rabbit_stomp_frame:serialize(Frame, TrailingLF)),
     State.
 
 send_error_frame(Message, ExtraHeaders, Format, Args, State) ->
index bb8530ea0b9b789a0164110222eadfa4418b74da..9034a2bd87692f0ca0a4a45712554e35494bd49c 100644 (file)
@@ -20,7 +20,7 @@
 -export([longstr_field/2]).
 -export([ack_mode/1, consumer_tag_reply_to/1, consumer_tag/1, message_headers/1,
          headers_post_process/1, headers/5, message_properties/1, tag_to_id/1,
-         msg_header_name/1, ack_header_name/1]).
+         msg_header_name/1, ack_header_name/1, build_arguments/1]).
 -export([negotiate_version/2]).
 -export([trim_headers/1]).
 
@@ -122,7 +122,8 @@ headers_extra(SessionId, AckMode, Version,
               #'basic.deliver'{consumer_tag = ConsumerTag,
                                delivery_tag = DeliveryTag,
                                exchange     = ExchangeBin,
-                               routing_key  = RoutingKeyBin}) ->
+                               routing_key  = RoutingKeyBin,
+                               redelivered  = Redelivered}) ->
     case tag_to_id(ConsumerTag) of
         {ok, {internal, Id}} -> [{?HEADER_SUBSCRIPTION, Id}];
         _                    -> []
@@ -131,7 +132,8 @@ headers_extra(SessionId, AckMode, Version,
       format_destination(binary_to_list(ExchangeBin),
                          binary_to_list(RoutingKeyBin))},
      {?HEADER_MESSAGE_ID,
-      create_message_id(ConsumerTag, SessionId, DeliveryTag)}] ++
+      create_message_id(ConsumerTag, SessionId, DeliveryTag)},
+     {?HEADER_REDELIVERED, Redelivered}] ++
     case AckMode == client andalso Version == "1.2" of
         true  -> [{?HEADER_ACK,
                    create_message_id(ConsumerTag, SessionId, DeliveryTag)}];
@@ -260,6 +262,41 @@ msg_header_name("1.2") -> ?HEADER_ACK;
 msg_header_name("1.1") -> ?HEADER_MESSAGE_ID;
 msg_header_name("1.0") -> ?HEADER_MESSAGE_ID.
 
+build_arguments(Headers) ->
+    Arguments =
+        lists:foldl(fun({K, V}, Acc) ->
+                            case lists:member(K, ?HEADER_ARGUMENTS) of
+                                true  -> [build_argument(K, V) | Acc];
+                                false -> Acc
+                            end
+                    end,
+                    [],
+                    Headers),
+    {arguments, Arguments}.
+
+%% build the actual value thru pattern matching
+build_argument(?HEADER_X_DEAD_LETTER_EXCHANGE, Val) ->
+    {list_to_binary(?HEADER_X_DEAD_LETTER_EXCHANGE), longstr,
+     list_to_binary(string:strip(Val))};
+build_argument(?HEADER_X_DEAD_LETTER_ROUTING_KEY, Val) ->
+    {list_to_binary(?HEADER_X_DEAD_LETTER_ROUTING_KEY), longstr,
+     list_to_binary(string:strip(Val))};
+build_argument(?HEADER_X_EXPIRES, Val) ->
+    {list_to_binary(?HEADER_X_EXPIRES), long,
+     list_to_integer(string:strip(Val))};
+build_argument(?HEADER_X_MAX_LENGTH, Val) ->
+    {list_to_binary(?HEADER_X_MAX_LENGTH), long,
+     list_to_integer(string:strip(Val))};
+build_argument(?HEADER_X_MAX_LENGTH_BYTES, Val) ->
+    {list_to_binary(?HEADER_X_MAX_LENGTH_BYTES), long,
+     list_to_integer(string:strip(Val))};
+build_argument(?HEADER_X_MAX_PRIORITY, Val) ->
+    {list_to_binary(?HEADER_X_MAX_PRIORITY), long,
+     list_to_integer(string:strip(Val))};
+build_argument(?HEADER_X_MESSAGE_TTL, Val) ->
+    {list_to_binary(?HEADER_X_MESSAGE_TTL), long,
+     list_to_integer(string:strip(Val))}.
+
 %%--------------------------------------------------------------------
 %% Destination Formatting
 %%--------------------------------------------------------------------
index f0f4718aadb17d7b6fea1ec402e2268774e4ab80..6757e2597b8604ff147727c7b04f732cca3cb27b 100644 (file)
@@ -16,5 +16,7 @@
                                {packet,    raw},
                                {reuseaddr, true},
                                {backlog,   128},
-                               {nodelay,   true}]}]},
+                               {nodelay,   true}]},
+        %% see rabbitmq/rabbitmq-stomp#39
+        {trailing_lf, true}]},
   {applications, [kernel, stdlib, rabbit, amqp_client]}]}.
index 4c47cd3de9646a1d022822767cfca6890f1ea0d0..e87bca3836a79510590f1d1e8a57789b68024c45 100644 (file)
@@ -216,3 +216,27 @@ class TestAck(base.BaseTest):
 
         self.conn.send_frame("NACK", {self.ack_id_header: message_id, "requeue": False})
         self.assertFalse(self.listener.await(4), "Received message after NACK with requeue = False")
+
+class TestAck11(TestAck):
+
+   def create_connection_obj(self, version='1.1', vhost='/', heartbeats=(0, 0)):
+       conn = stomp.StompConnection11(vhost=vhost,
+                                      heartbeats=heartbeats)
+       self.ack_id_source_header = 'message-id'
+       self.ack_id_header = 'message-id'
+       return conn
+
+   def test_version(self):
+       self.assertEquals('1.1', self.conn.version)
+
+class TestAck12(TestAck):
+
+   def create_connection_obj(self, version='1.2', vhost='/', heartbeats=(0, 0)):
+       conn = stomp.StompConnection12(vhost=vhost,
+                                      heartbeats=heartbeats)
+       self.ack_id_source_header = 'ack'
+       self.ack_id_header = 'id'
+       return conn
+
+   def test_version(self):
+       self.assertEquals('1.2', self.conn.version)
index b1d0cd1914766fa97ef064d7dfe9b915e36f5be1..760bb9fa5f8d5720f8d3a68789fa9a704d913f1a 100644 (file)
@@ -499,8 +499,9 @@ class TestDurableSubscription(base.BaseTest):
             self.__subscribe(destination, conn2, "other.id")
 
             for l in [self.listener, listener2]:
-                self.assertTrue(l.await(20))
-                self.assertEquals(100, len(l.messages))
+                self.assertTrue(l.await(15))
+                self.assertTrue(len(l.messages) >= 90)
+                self.assertTrue(len(l.messages) <= 100)
 
         finally:
             conn2.disconnect()
index e52b3ac0622362fc773d1c2f829f91f0a361aa93..d3fa60a658a7d6930873fc572bfde1305cdb4818 100644 (file)
@@ -3,6 +3,34 @@ import stomp
 import base
 import time
 
+class TestErrorsAndCloseConnection(base.BaseTest):
+    def __test_duplicate_consumer_tag_with_headers(self, destination, headers):
+        self.subscribe_dest(self.conn, destination, None,
+                            headers = headers)
+
+        self.subscribe_dest(self.conn, destination, None,
+                            headers = headers)
+
+        self.assertTrue(self.listener.await())
+
+        self.assertEquals(1, len(self.listener.errors))
+        errorReceived = self.listener.errors[0]
+        self.assertEquals("Duplicated subscription identifier", errorReceived['headers']['message'])
+        self.assertEquals("A subscription identified by 'T_1' alredy exists.", errorReceived['message'])
+        time.sleep(2)
+        self.assertFalse(self.conn.is_connected())
+
+
+    def test_duplicate_consumer_tag_with_transient_destination(self):
+        destination = "/exchange/amq.direct/duplicate-consumer-tag-test1"
+        self.__test_duplicate_consumer_tag_with_headers(destination, {'id': 1})
+
+    def test_duplicate_consumer_tag_with_durable_destination(self):
+        destination = "/queue/duplicate-consumer-tag-test2"
+        self.__test_duplicate_consumer_tag_with_headers(destination, {'id': 1,
+                                                                      'persistent': True})
+
+
 class TestErrors(base.BaseTest):
 
     def test_invalid_queue_destination(self):
@@ -64,4 +92,3 @@ class TestErrors(base.BaseTest):
         self.assertEquals("'" + content + "' is not a valid " +
                               dtype + " destination\n",
                           err['message'])
-
index 2e08836381ac212884b2df8615ace5d1ceb9e9ff..27326b6dc5f596e19c0ea63f8fb214bb75c75852 100644 (file)
@@ -84,6 +84,7 @@ class TestParsing(unittest.TestCase):
         resp = ('MESSAGE\n'
                 'destination:/exchange/amq.fanout\n'
                 'message-id:Q_/exchange/amq.fanout@@session-(.*)\n'
+                'redelivered:false\n'
                 'content-type:text/plain\n'
                 'content-length:6\n'
                 '\n'
@@ -102,6 +103,7 @@ class TestParsing(unittest.TestCase):
         resp = ('MESSAGE\n'
                 'destination:/exchange/amq.fanout\n'
                 'message-id:Q_/exchange/amq.fanout@@session-(.*)\n'
+                'redelivered:false\n'
                 'content-length:6\n'
                 '\n'
                 'hello\n\0')
@@ -121,6 +123,7 @@ class TestParsing(unittest.TestCase):
         resp = ('MESSAGE\n'
                 'destination:/exchange/amq.fanout\n'
                 'message-id:Q_/exchange/amq.fanout@@session-(.*)\n'
+                'redelivered:false\n'
                 'content-length:'+str(len(msg))+'\n'
                 '\n'
                 + msg + '\0')
@@ -139,6 +142,7 @@ class TestParsing(unittest.TestCase):
         resp = ('MESSAGE\n'
                 'destination:/exchange/amq.fanout\n'
                 'message-id:Q_/exchange/amq.fanout@@session-(.*)\n'
+                'redelivered:false\n'
                 'content-type:text/plain\n'
                 'content-length:6\n'
                 '\n'
@@ -188,6 +192,7 @@ class TestParsing(unittest.TestCase):
             'subscription:(.*)\n'
             'destination:/topic/da9d4779\n'
             'message-id:(.*)\n'
+            'redelivered:false\n'
             'content-type:text/plain\n'
             'content-length:8\n'
             '\n'
@@ -227,12 +232,13 @@ class TestParsing(unittest.TestCase):
             'subscription:(.*)\n'        # 14 + subscription
             +resp_dest+                  # 44
             'message-id:(.*)\n'          # 12 + message-id
+            'redelivered:false\n'        # 18
             'content-type:text/plain\n'  # 24
             'content-length:%i\n'        # 16 + 4==len('1024')
             '\n'                         # 1
             '(.*)$'                      # prefix of body+null (potentially)
              % len(message) )
-        headlen = 8 + 24 + 14 + (3) + 44 + 12 + (48) + 16 + (4) + 1 + (1)
+        headlen = 8 + 24 + 14 + (3) + 44 + 12 + 18 + (48) + 16 + (4) + 1 + (1)
 
         headbuf = self.recv_atleast(headlen)
         self.assertFalse(len(headbuf) == 0)
@@ -286,12 +292,13 @@ class TestParsing(unittest.TestCase):
             'subscription:(.*)\n'       # 14 + subscription
             +resp_dest+                 # 44
             'message-id:(.*)\n'         # 12 + message-id
+            'redelivered:false\n'       # 18
             'content-type:text/plain\n' # 24
             'content-length:%i\n'       # 16 + 4==len('1024')
             '\n'                        # 1
             '(.*)$'                     # prefix of body+null (potentially)
              % len(message) )
-        headlen = 8 + 24 + 14 + (3) + 44 + 12 + (48) + 16 + (4) + 1 + (1)
+        headlen = 8 + 24 + 14 + (3) + 44 + 12 + 18 + (48) + 16 + (4) + 1 + (1)
 
         headbuf = self.recv_atleast(headlen)
         self.assertFalse(len(headbuf) == 0)
diff --git a/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/queue_properties.py b/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/queue_properties.py
new file mode 100644 (file)
index 0000000..cc85487
--- /dev/null
@@ -0,0 +1,79 @@
+import unittest
+import stomp
+import pika
+import base
+import time
+
+class TestQueueProperties(base.BaseTest):
+
+    def test_subscribe(self):
+        destination = "/queue/queue-properties-subscribe-test"
+
+        # subscribe
+        self.subscribe_dest(self.conn, destination, None,
+                            headers={
+                                'x-message-ttl': 60000,
+                                'x-expires': 70000,
+                                'x-max-length': 10,
+                                'x-max-length-bytes': 20000,
+                                'x-dead-letter-exchange': 'dead-letter-exchange',
+                                'x-dead-letter-routing-key': 'dead-letter-routing-key',
+                                'x-max-priority': 6,
+                                })
+
+        # now try to declare the queue using pika
+        # if the properties are the same we should
+        # not get any error
+        connection = pika.BlockingConnection(pika.ConnectionParameters(
+                    host='localhost'))
+        channel = connection.channel()
+        channel.queue_declare(queue='queue-properties-subscribe-test',
+                              durable=True,
+                              arguments={
+                                  'x-message-ttl': 60000,
+                                  'x-expires': 70000,
+                                  'x-max-length': 10,
+                                  'x-max-length-bytes': 20000,
+                                  'x-dead-letter-exchange': 'dead-letter-exchange',
+                                  'x-dead-letter-routing-key': 'dead-letter-routing-key',
+                                  'x-max-priority': 6,
+                                  })
+
+        self.conn.disconnect()
+        connection.close()
+
+    def test_send(self):
+        destination = "/queue/queue-properties-send-test"
+
+        # send
+        self.conn.send(destination, "test1",
+                       headers={
+                           'x-message-ttl': 60000,
+                           'x-expires': 70000,
+                           'x-max-length': 10,
+                           'x-max-length-bytes': 20000,
+                           'x-dead-letter-exchange': 'dead-letter-exchange',
+                           'x-dead-letter-routing-key': 'dead-letter-routing-key',
+                           'x-max-priority': 6,
+                           })
+
+        # now try to declare the queue using pika
+        # if the properties are the same we should
+        # not get any error
+        connection = pika.BlockingConnection(pika.ConnectionParameters(
+                    host='localhost'))
+        channel = connection.channel()
+        channel.queue_declare(queue='queue-properties-send-test',
+                              durable=True,
+                              arguments={
+                                  'x-message-ttl': 60000,
+                                  'x-expires': 70000,
+                                  'x-max-length': 10,
+                                  'x-max-length-bytes': 20000,
+                                  'x-dead-letter-exchange': 'dead-letter-exchange',
+                                  'x-dead-letter-routing-key': 'dead-letter-routing-key',
+                                  'x-max-priority': 6,
+                                  })
+
+        self.conn.disconnect()
+        connection.close()
index ee67807e76003a3f8a967e2b78a513fdcf6a88fc..2ae06991977f63cb21d8d602620833a15513a092 100644 (file)
@@ -73,6 +73,8 @@ parse(Payload, Client = {Sock, FramesRev}, FrameState, Length) ->
     case rabbit_stomp_frame:parse(Payload, FrameState) of
         {ok, Frame, <<>>} ->
             recv({Sock, lists:reverse([Frame | FramesRev])});
+        {ok, Frame, <<"\n">>} ->
+            recv({Sock, lists:reverse([Frame | FramesRev])});
         {ok, Frame, Rest} ->
             parse(Rest, {Sock, [Frame | FramesRev]},
                   rabbit_stomp_frame:initial_state(), Length);
index 25290986f92e1cf26861a23e78b671035f7e05af..2f5b580c0102fcc3060814592ff1a441dcfc640b 100644 (file)
@@ -41,7 +41,7 @@ test_direct_client_connections_are_not_leaked() ->
                           rabbit_stomp_client:send(
                            Client, "LOL", [{"", ""}])
                   end,
-                  lists:seq(1, 1000)),
+                  lists:seq(1, 100)),
     timer:sleep(5000),
     N = count_connections(),
     ok.
index a2cbdf3cc84817c69a2c5c36148b347b02e5e8a0..c53fff700454b6690034ea758c9341bd4956f508 100644 (file)
@@ -40,33 +40,6 @@ parse_simple_frame_gen(Term) ->
     #stomp_frame{body_iolist = Body} = Frame,
     ?assertEqual(<<"Body Content">>, iolist_to_binary(Body)).
 
-parse_simple_frame_with_null_test() ->
-    Headers = [{"header1", "value1"}, {"header2", "value2"},
-               {?HEADER_CONTENT_LENGTH, "12"}],
-    Content = frame_string("COMMAND",
-                           Headers,
-                           "Body\0Content"),
-    {"COMMAND", Frame, _State} = parse_complete(Content),
-    [?assertEqual({ok, Value},
-                  rabbit_stomp_frame:header(Frame, Key)) ||
-        {Key, Value} <- Headers],
-    #stomp_frame{body_iolist = Body} = Frame,
-    ?assertEqual(<<"Body\0Content">>, iolist_to_binary(Body)).
-
-parse_large_content_frame_with_nulls_test() ->
-    BodyContent = string:copies("012345678\0", 1024),
-    Headers = [{"header1", "value1"}, {"header2", "value2"},
-               {?HEADER_CONTENT_LENGTH, integer_to_list(string:len(BodyContent))}],
-    Content = frame_string("COMMAND",
-                           Headers,
-                           BodyContent),
-    {"COMMAND", Frame, _State} = parse_complete(Content),
-    [?assertEqual({ok, Value},
-                  rabbit_stomp_frame:header(Frame, Key)) ||
-        {Key, Value} <- Headers],
-    #stomp_frame{body_iolist = Body} = Frame,
-    ?assertEqual(list_to_binary(BodyContent), iolist_to_binary(Body)).
-
 parse_command_only_test() ->
     {ok, #stomp_frame{command = "COMMAND"}, _Rest} = parse("COMMAND\n\n\0").
 
@@ -166,13 +139,18 @@ header_value_with_colon_test() ->
                                headers     = [{"header", "val:ue"}],
                                body_iolist = []}).
 
-headers_escaping_roundtrip_test() ->
-    Content = "COMMAND\nhead\\r\\c\\ner:\\c\\n\\r\\\\\n\n\0",
-    {ok, Frame, _} = parse(Content),
+test_frame_serialization(Expected, TrailingLF) ->
+    {ok, Frame, _} = parse(Expected),
     {ok, Val} = rabbit_stomp_frame:header(Frame, "head\r:\ner"),
     ?assertEqual(":\n\r\\", Val),
-    Serialized = lists:flatten(rabbit_stomp_frame:serialize(Frame)),
-    ?assertEqual(Content, rabbit_misc:format("~s", [Serialized])).
+    Serialized = lists:flatten(rabbit_stomp_frame:serialize(Frame, TrailingLF)),
+    ?assertEqual(Expected, rabbit_misc:format("~s", [Serialized])).
+
+headers_escaping_roundtrip_test() ->
+    test_frame_serialization("COMMAND\nhead\\r\\c\\ner:\\c\\n\\r\\\\\n\n\0\n", true).
+
+headers_escaping_roundtrip_without_trailing_lf_test() ->
+    test_frame_serialization("COMMAND\nhead\\r\\c\\ner:\\c\\n\\r\\\\\n\n\0", false).
 
 parse(Content) ->
     parse(Content, rabbit_stomp_frame:initial_state()).
@@ -189,5 +167,5 @@ frame_string(Command, Headers, BodyContent) ->
 frame_string(Command, Headers, BodyContent, Term) ->
     HeaderString =
         lists:flatten([Key ++ ":" ++ Value ++ Term || {Key, Value} <- Headers]),
-    Command ++ Term ++ HeaderString ++ Term ++ BodyContent ++ "\0".
+    Command ++ Term ++ HeaderString ++ Term ++ BodyContent ++ "\0" ++ "\n".
 
diff --git a/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/redelivered.py b/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/redelivered.py
new file mode 100644 (file)
index 0000000..bbabd3f
--- /dev/null
@@ -0,0 +1,32 @@
+import unittest
+import stomp
+import base
+import time
+
+class TestRedelivered(base.BaseTest):
+
+    def test_redelivered(self):
+        destination = "/queue/redelivered-test"
+
+        # subscribe and send message
+        self.subscribe_dest(self.conn, destination, None, ack='client')
+        self.conn.send(destination, "test1")
+        self.assertTrue(self.listener.await(4), "initial message not received")
+        self.assertEquals(1, len(self.listener.messages))
+        self.assertEquals('false', self.listener.messages[0]['headers']['redelivered'])
+
+        # disconnect with no ack
+        self.conn.disconnect()
+
+        # now reconnect
+        conn2 = self.create_connection()
+        try:
+            listener2 = base.WaitableListener()
+            listener2.reset(1)
+            conn2.set_listener('', listener2)
+            self.subscribe_dest(conn2, destination, None, ack='client')
+            self.assertTrue(listener2.await(), "message not received again")
+            self.assertEquals(1, len(listener2.messages))
+            self.assertEquals('true', listener2.messages[0]['headers']['redelivered'])
+        finally:
+            conn2.disconnect()
index ddeb1fe1108b472e1656ce2ff2a792e475979cfd..381c5b4893e48752f7a3c81eb30603112720ea85 100755 (executable)
@@ -4,13 +4,15 @@ import test_runner
 
 if __name__ == '__main__':
     modules = [
-        'parsing',
-        'destinations',
-        'lifecycle',
-        'transactions',
         'ack',
+        'destinations',
         'errors',
+        'lifecycle',
+        'parsing',
+        'queue_properties',
+        'redelivered',
         'reliability',
+        'transactions',
     ]
     test_runner.run_unittests(modules)
 
index 7216865e7c9d9c092cb89818489c55832c983260..90a5456694db80262be82e2917305c8e88501b1f 100644 (file)
@@ -7,6 +7,7 @@ import os
 def add_deps_to_path():
     deps_dir = os.path.realpath(os.path.join(__file__, "..", "..", "..", "deps"))
     sys.path.append(os.path.join(deps_dir, "stomppy", "stomppy"))
+    sys.path.append(os.path.join(deps_dir, "pika", "pika"))
 
 def run_unittests(modules):
     add_deps_to_path()
index 03466a7e56f93e7435f4f26c6ced02677d104cfb..3f1141478d050dac1166bb76a221b4aab28ce5b5 100644 (file)
@@ -174,6 +174,37 @@ cleanup:
                RABBITMQ_ENABLED_PLUGINS_FILE=/does-not-exist \
                stop-rabbit-on-node ${COVER_STOP} stop-node
 
+define compare_version
+$(shell awk 'BEGIN {
+       split("$(1)", v1, "\.");
+       version1 = v1[1] * 1000000 + v1[2] * 10000 + v1[3] * 100 + v1[4];
+
+       split("$(2)", v2, "\.");
+       version2 = v2[1] * 1000000 + v2[2] * 10000 + v2[3] * 100 + v2[4];
+
+       if (version1 $(3) version2) {
+               print "true";
+       } else {
+               print "false";
+       }
+}')
+endef
+
+ERLANG_SSL_VER = $(shell erl -noshell -eval '\
+       ok = application:load(ssl), \
+       {ok, VSN} = application:get_key(ssl, vsn), \
+       io:format("~s~n", [VSN]), \
+       halt(0).')
+MINIMUM_ERLANG_SSL_VER = 5.3
+
+ifeq ($(call compare_version,$(ERLANG_SSL_VER),$(MINIMUM_ERLANG_SSL_VER),>=),true)
 create_ssl_certs:
        $(MAKE) -C certs DIR=$(SSL_CERTS_DIR) clean all
-
+else
+create_ssl_certs:
+       @# Skip SSL certs if Erlang is older than R16B01 (ssl 5.3).
+       $(MAKE) -C certs DIR=$(SSL_CERTS_DIR) clean
+       @echo "WARNING: Skip SSL certs creation; Erlang's SSL application is too" \
+           "old ($(ERLANG_SSL_VER) < $(MINIMUM_ERLANG_SSL_VER)) and SSL support" \
+           "is disabled in RabbitMQ"
+endif
index 8808931fda7e588dc1ea5f13a7a3341c3424dcc2..161d0160f41f82101e988a0e7d0fa15b5dc7fd28 100644 (file)
@@ -2,10 +2,10 @@ DEPS:=rabbitmq-erlang-client
 FILTER:=all
 COVER:=false
 WITH_BROKER_TEST_COMMANDS:=rabbit_test_runner:run_in_broker(\"$(PACKAGE_DIR)/test/ebin\",\"$(FILTER)\")
-STANDALONE_TEST_COMMANDS:=rabbit_test_runner:run_multi(\"$(UMBRELLA_BASE_DIR)/rabbitmq-server\",\"$(PACKAGE_DIR)/test/ebin\",\"$(FILTER)\",$(COVER),none)
 
 ## Require R15B to compile inet_proxy_dist since it requires includes
 ## introduced there.
 ifeq ($(shell erl -noshell -eval 'io:format([list_to_integer(X) || X <- string:tokens(erlang:system_info(version), ".")] >= [5,9]), halt().'),true)
+STANDALONE_TEST_COMMANDS:=rabbit_test_runner:run_multi(\"$(UMBRELLA_BASE_DIR)/rabbitmq-server\",\"$(PACKAGE_DIR)/test/ebin\",\"$(FILTER)\",$(COVER),none)
 PACKAGE_ERLC_OPTS+=-Derlang_r15b_or_later
 endif
index f8b6cfd1635a698cdf565f87480f15513839aaf0..b114aabfab03801ae8182522ff11748a6ac15d28 100644 (file)
@@ -505,10 +505,10 @@ wait_for_cluster_status(Status, AllNodes, Nodes) ->
     wait_for_cluster_status(0, Max, Status, AllNodes, Nodes).
 
 wait_for_cluster_status(N, Max, Status, _AllNodes, Nodes) when N >= Max ->
-    error({cluster_status_max_tries_failed,
-           [{nodes, Nodes},
-            {expected_status, Status},
-            {max_tried, Max}]});
+    erlang:error({cluster_status_max_tries_failed,
+                  [{nodes, Nodes},
+                   {expected_status, Status},
+                   {max_tried, Max}]});
 wait_for_cluster_status(N, Max, Status, AllNodes, Nodes) ->
     case lists:all(fun (Node) ->
                             verify_status_equal(Node, Status, AllNodes)
index c284d1457ffee5b16a43dbce6967ece612772b2d..18f6f5d266e4196c9514b38e83b9bf6322617a18 100644 (file)
@@ -154,11 +154,11 @@ wait_for_sync_status(Status, Cfg, Queue) ->
     wait_for_sync_status(0, Max, Status, pget(node, Cfg), Queue).
 
 wait_for_sync_status(N, Max, Status, Node, Queue) when N >= Max ->
-    error({sync_status_max_tries_failed,
-          [{queue, Queue},
-           {node, Node},
-           {expected_status, Status},
-           {max_tried, Max}]});
+    erlang:error({sync_status_max_tries_failed,
+                  [{queue, Queue},
+                   {node, Node},
+                   {expected_status, Status},
+                   {max_tried, Max}]});
 wait_for_sync_status(N, Max, Status, Node, Queue) ->
     Synced = length(slave_pids(Node, Queue)) =:= 1,
     case Synced =:= Status of
index d3983f22cf8e91b050158cbc9ddee5744b1359b4..d1e3b4141bff96806b00f3254a2fcbed59e413db 100755 (executable)
@@ -33,5 +33,5 @@ set PLUGINS_DIR=!TDP0!..\plugins
 
 REM CONF_ENV_FILE=${SYS_PREFIX}/etc/rabbitmq/rabbitmq-env.conf
 if "!RABBITMQ_CONF_ENV_FILE!"=="" (
-    set CONF_ENV_FILE=!APPDATA!\RabbitMQ\rabbitmq-env-conf.bat
+    set RABBITMQ_CONF_ENV_FILE=!RABBITMQ_BASE!\rabbitmq-env-conf.bat
 )
index 8657f1e60922067362d13c0425bdea0df24fb453..7465072d1916da1a5461b2e5960edb44ee0815de 100755 (executable)
@@ -35,7 +35,7 @@ REM set SERVER_ERL_ARGS=+P 1048576
 REM ## Get configuration variables from the configure environment file
 REM [ -f ${CONF_ENV_FILE} ] && . ${CONF_ENV_FILE} || true
 if exist "!RABBITMQ_CONF_ENV_FILE!" (
-       call !RABBITMQ_CONF_ENV_FILE!
+       call "!RABBITMQ_CONF_ENV_FILE!"
 )
 
 REM Check for the short names here too
@@ -84,23 +84,28 @@ REM       set RABBITMQ_NODE_PORT=5672
 REM    )
 REM )
 
-REM DOUBLE CHECK THIS LOGIC
 if "!RABBITMQ_NODE_IP_ADDRESS!"=="" (
-       if "!NODE_IP_ADDRESS!"=="" (
-               set RABBITMQ_NODE_IP_ADDRESS=auto
-       ) else (
+       if not "!NODE_IP_ADDRESS!"=="" (
                set RABBITMQ_NODE_IP_ADDRESS=!NODE_IP_ADDRESS!
        )
 )
 
 if "!RABBITMQ_NODE_PORT!"=="" (
-       if "!NODE_PORT!"=="" (
-               set RABBITMQ_NODE_PORT=5672
-       ) else (
+       if not "!NODE_PORT!"=="" (
                set RABBITMQ_NODE_PORT=!NODE_PORT!
        )
 )
 
+if "!RABBITMQ_NODE_IP_ADDRESS!"=="" (
+    if not "!RABBITMQ_NODE_PORT!"=="" (
+       set RABBITMQ_NODE_IP_ADDRESS=auto
+    )
+) else (
+    if "!RABBITMQ_NODE_PORT!"=="" (
+       set RABBITMQ_NODE_PORT=5672
+    )
+)
+
 REM [ "x" = "x$RABBITMQ_DIST_PORT" ] && RABBITMQ_DIST_PORT=${DIST_PORT}
 REM [ "x" = "x$RABBITMQ_DIST_PORT" ] && [ "x" = "x$RABBITMQ_NODE_PORT" ] && RABBITMQ_DIST_PORT=$((${DEFAULT_NODE_PORT} + 20000))
 REM [ "x" = "x$RABBITMQ_DIST_PORT" ] && [ "x" != "x$RABBITMQ_NODE_PORT" ] && RABBITMQ_DIST_PORT=$((${RABBITMQ_NODE_PORT} + 20000))
index 1800b8713c1e4fb4b0778b1f1649cd82db65c70a..71a6530321681f782ad84c623f889e92f247e51d 100755 (executable)
@@ -99,31 +99,69 @@ fi
 # there is no other way of preventing their expansion.
 set -f
 
-RABBITMQ_CONFIG_FILE=$RABBITMQ_CONFIG_FILE \
-exec ${ERL_DIR}erl \
-    -pa ${RABBITMQ_EBIN_ROOT} \
-    ${RABBITMQ_START_RABBIT} \
-    ${RABBITMQ_NAME_TYPE} ${RABBITMQ_NODENAME} \
-    -boot "${SASL_BOOT_FILE}" \
-    ${RABBITMQ_CONFIG_ARG} \
-    +W w \
-    +A ${RABBITMQ_IO_THREAD_POOL_SIZE} \
-    ${RABBITMQ_SERVER_ERL_ARGS} \
-    +K true \
-    -kernel inet_default_connect_options "[{nodelay,true}]" \
-    ${RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS} \
-    ${RABBITMQ_LISTEN_ARG} \
-    -sasl errlog_type error \
-    -sasl sasl_error_logger "$SASL_ERROR_LOGGER" \
-    -rabbit error_logger "$RABBIT_ERROR_LOGGER" \
-    -rabbit sasl_error_logger "$RABBIT_SASL_ERROR_LOGGER" \
-    -rabbit enabled_plugins_file "\"$RABBITMQ_ENABLED_PLUGINS_FILE\"" \
-    -rabbit plugins_dir "\"$RABBITMQ_PLUGINS_DIR\"" \
-    -rabbit plugins_expand_dir "\"$RABBITMQ_PLUGINS_EXPAND_DIR\"" \
-    -os_mon start_cpu_sup false \
-    -os_mon start_disksup false \
-    -os_mon start_memsup false \
-    -mnesia dir "\"${RABBITMQ_MNESIA_DIR}\"" \
-    ${RABBITMQ_SERVER_START_ARGS} \
-    ${RABBITMQ_DIST_ARG} \
-    "$@"
+start_rabbitmq_server() {
+    RABBITMQ_CONFIG_FILE=$RABBITMQ_CONFIG_FILE \
+    exec ${ERL_DIR}erl \
+        -pa ${RABBITMQ_EBIN_ROOT} \
+        ${RABBITMQ_START_RABBIT} \
+        ${RABBITMQ_NAME_TYPE} ${RABBITMQ_NODENAME} \
+        -boot "${SASL_BOOT_FILE}" \
+        ${RABBITMQ_CONFIG_ARG} \
+        +W w \
+        +A ${RABBITMQ_IO_THREAD_POOL_SIZE} \
+        ${RABBITMQ_SERVER_ERL_ARGS} \
+        +K true \
+        -kernel inet_default_connect_options "[{nodelay,true}]" \
+        ${RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS} \
+        ${RABBITMQ_LISTEN_ARG} \
+        -sasl errlog_type error \
+        -sasl sasl_error_logger "$SASL_ERROR_LOGGER" \
+        -rabbit error_logger "$RABBIT_ERROR_LOGGER" \
+        -rabbit sasl_error_logger "$RABBIT_SASL_ERROR_LOGGER" \
+        -rabbit enabled_plugins_file "\"$RABBITMQ_ENABLED_PLUGINS_FILE\"" \
+        -rabbit plugins_dir "\"$RABBITMQ_PLUGINS_DIR\"" \
+        -rabbit plugins_expand_dir "\"$RABBITMQ_PLUGINS_EXPAND_DIR\"" \
+        -os_mon start_cpu_sup false \
+        -os_mon start_disksup false \
+        -os_mon start_memsup false \
+        -mnesia dir "\"${RABBITMQ_MNESIA_DIR}\"" \
+        ${RABBITMQ_SERVER_START_ARGS} \
+        ${RABBITMQ_DIST_ARG} \
+        "$@"
+}
+
+stop_rabbitmq_server() {
+    RABBITMQCTL="$(dirname "$0")/rabbitmqctl"
+
+    if ${RABBITMQCTL} -n ${RABBITMQ_NODENAME} status >/dev/null 2>&1; then
+        ${RABBITMQCTL} -n ${RABBITMQ_NODENAME} stop
+    fi
+}
+
+if [ 'x' = "x$RABBITMQ_ALLOW_INPUT" -a -z "$detached" ]; then
+    # When RabbitMQ runs in the foreground but the Erlang shell is
+    # disabled, we setup signal handlers to stop RabbitMQ properly. This
+    # is at least useful in the case of Docker.
+
+    # The Erlang VM should ignore SIGINT.
+    RABBITMQ_SERVER_START_ARGS="${RABBITMQ_SERVER_START_ARGS} +B i"
+
+    # Signal handlers. They all stop RabbitMQ properly (using
+    # rabbitmqctl stop). Depending on the signal, this script will exwit
+    # with a non-zero error code:
+    #   SIGHUP SIGTERM SIGTSTP
+    #     They are considered a normal process termination, so the script
+    #     exits with 0.
+    #   SIGINT
+    #     They are considered an abnormal process termination, the script
+    #     exits with the job exit code.
+    trap "stop_rabbitmq_server; exit 0" HUP TERM TSTP
+    trap "stop_rabbitmq_server" INT
+
+    start_rabbitmq_server "$@" &
+
+    # Block until RabbitMQ exits or a signal is caught.
+    wait
+else
+    start_rabbitmq_server "$@"
+fi
index d6dd902ee9c82af1c39fbe43609e8e1797cba155..0845bbf58e01409c96fa38c0ac27741a3d8f0de7 100755 (executable)
@@ -146,7 +146,7 @@ if not "!RABBITMQ_NODE_IP_ADDRESS!"=="" (
 \r
 set RABBITMQ_START_RABBIT=\r
 if "!RABBITMQ_NODE_ONLY!"=="" (\r
-    set RABBITMQ_START_RABBIT=-s rabbit boot\r
+    set RABBITMQ_START_RABBIT=-s "!RABBITMQ_BOOT_MODULE!" boot\r
 )\r
 \r
 if "!RABBITMQ_IO_THREAD_POOL_SIZE!"=="" (\r
@@ -161,9 +161,10 @@ set ERLANG_SERVICE_ARGUMENTS= ^
 +W w ^\r
 +A "!RABBITMQ_IO_THREAD_POOL_SIZE!" ^\r
 +P 1048576 ^\r
--kernel inet_default_connect_options "[{nodelay,true}]" ^\r
 !RABBITMQ_LISTEN_ARG! ^\r
 !RABBITMQ_SERVER_ERL_ARGS! ^\r
+-kernel inet_default_connect_options "[{nodelay,true}]" ^\r
+!RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS! ^\r
 -sasl errlog_type error ^\r
 -sasl sasl_error_logger false ^\r
 -rabbit error_logger {file,\""!LOGS:\=/!"\"} ^\r
@@ -177,7 +178,6 @@ set ERLANG_SERVICE_ARGUMENTS= ^
 -os_mon start_memsup false ^\r
 -mnesia dir \""!RABBITMQ_MNESIA_DIR:\=/!"\" ^\r
 !RABBITMQ_SERVER_START_ARGS! ^\r
-!RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS! ^\r
 !RABBITMQ_DIST_ARG! ^\r
 !STARVAR!\r
 \r
@@ -191,7 +191,7 @@ set ERLANG_SERVICE_ARGUMENTS=!ERLANG_SERVICE_ARGUMENTS:"=\"!
 -stopaction "rabbit:stop_and_halt()." ^\r
 !RABBITMQ_NAME_TYPE! !RABBITMQ_NODENAME! ^\r
 !CONSOLE_FLAG! ^\r
--comment "A robust and scalable messaging broker" ^\r
+-comment "Multi-protocol open source messaging broker" ^\r
 -args "!ERLANG_SERVICE_ARGUMENTS!" > NUL\r
 \r
 goto END\r
index 6b2417538848c23160a5638595e6dcc1df2226ea..b9547cff1cf9d3d396f9f1e21270572174e1c3fc 100644 (file)
 %% receiver it will not grant any more credit to its senders when it
 %% is itself blocked - thus the only processes that need to check
 %% blocked/0 are ones that read from network sockets.
-
--define(DEFAULT_CREDIT, {200, 50}).
+%%
+%% Credit flows left to right when process send messags down the
+%% chain, starting at the rabbit_reader, ending at the msg_store:
+%%  reader -> channel -> queue_process -> msg_store.
+%%
+%% If the message store has a back log, then it will block the
+%% queue_process, which will block the channel, and finally the reader
+%% will be blocked, throttling down publishers.
+%%
+%% Once a process is unblocked, it will grant credits up the chain,
+%% possibly unblocking other processes:
+%% reader <--grant channel <--grant queue_process <--grant msg_store.
+%%
+%% Grepping the project files for `credit_flow` will reveal the places
+%% where this module is currently used, with extra comments on what's
+%% going on at each instance. Note that credit flow between mirrors
+%% synchronization has not been documented, since this doesn't affect
+%% client publishes.
+
+-define(DEFAULT_INITIAL_CREDIT, 200).
+-define(DEFAULT_MORE_CREDIT_AFTER, 50).
+
+-define(DEFAULT_CREDIT,
+        case get(credit_flow_default_credit) of
+            undefined ->
+                Val = rabbit_misc:get_env(rabbit, credit_flow_default_credit,
+                                           {?DEFAULT_INITIAL_CREDIT,
+                                            ?DEFAULT_MORE_CREDIT_AFTER}),
+                put(credit_flow_default_credit, Val),
+                Val;
+            Val       -> Val
+        end).
 
 -export([send/1, send/2, ack/1, ack/2, handle_bump_msg/1, blocked/0, state/0]).
 -export([peer_down/1]).
@@ -61,9 +91,9 @@
             %% We deliberately allow Var to escape from the case here
             %% to be used in Expr. Any temporary var we introduced
             %% would also escape, and might conflict.
-            case get(Key) of
-                undefined -> Var = Default;
-                Var       -> ok
+            Var = case get(Key) of
+                undefined -> Default;
+                V         -> V
             end,
             put(Key, Expr)
         end).
index 8be19e5be322b919b688348cbe35232929139cc4..d7e5abc8730bb241e3bfa931752db00659de9afc 100644 (file)
@@ -343,6 +343,16 @@ read(Ref, Count) ->
       [Ref], keep,
       fun ([#handle { is_read = false }]) ->
               {error, not_open_for_reading};
+          ([#handle{read_buffer_size_limit = 0,
+                    hdl = Hdl, offset = Offset} = Handle]) ->
+              %% The read buffer is disabled. This is just an
+              %% optimization: the clauses below can handle this case.
+              case prim_file_read(Hdl, Count) of
+                  {ok, Data} -> {{ok, Data},
+                                 [Handle#handle{offset = Offset+size(Data)}]};
+                  eof        -> {eof, [Handle #handle { at_eof = true }]};
+                  Error      -> {Error, Handle}
+              end;
           ([Handle = #handle{read_buffer       = Buf,
                              read_buffer_pos   = BufPos,
                              read_buffer_rem   = BufRem,
@@ -584,8 +594,11 @@ info() -> info(?INFO_KEYS).
 info(Items) -> gen_server2:call(?SERVER, {info, Items}, infinity).
 
 clear_read_cache() ->
-    gen_server2:cast(?SERVER, clear_read_cache),
-    clear_vhost_read_cache(rabbit_vhost:list()).
+    case application:get_env(rabbit, fhc_read_buffering) of
+        false -> ok;
+        true  -> gen_server2:cast(?SERVER, clear_read_cache),
+                 clear_vhost_read_cache(rabbit_vhost:list())
+    end.
 
 clear_vhost_read_cache([]) ->
     ok;
@@ -816,15 +829,23 @@ oldest(Tree, DefaultFun) ->
 
 new_closed_handle(Path, Mode, Options) ->
     WriteBufferSize =
-        case proplists:get_value(write_buffer, Options, unbuffered) of
-            unbuffered           -> 0;
-            infinity             -> infinity;
-            N when is_integer(N) -> N
+        case application:get_env(rabbit, fhc_write_buffering) of
+            {ok, false} -> 0;
+            {ok, true}  ->
+                case proplists:get_value(write_buffer, Options, unbuffered) of
+                    unbuffered           -> 0;
+                    infinity             -> infinity;
+                    N when is_integer(N) -> N
+                end
         end,
     ReadBufferSize =
-        case proplists:get_value(read_buffer, Options, unbuffered) of
-            unbuffered             -> 0;
-            N2 when is_integer(N2) -> N2
+        case application:get_env(rabbit, fhc_read_buffering) of
+            {ok, false} -> 0;
+            {ok, true}  ->
+                case proplists:get_value(read_buffer, Options, unbuffered) of
+                    unbuffered             -> 0;
+                    N2 when is_integer(N2) -> N2
+                end
         end,
     Ref = make_ref(),
     put({Ref, fhc_handle}, #handle { hdl                     = closed,
index fd0e6553b597a158155cc23b467d8a3cdc34533c..ffc075da7f0c7d31eb60c24578418ffbea8f6bca 100644 (file)
@@ -633,8 +633,15 @@ extend_backoff({backoff, InitialTimeout, MinimumTimeout, DesiredHibPeriod}) ->
 %%% The MAIN loop.
 %%% ---------------------------------------------------
 loop(GS2State = #gs2_state { time          = hibernate,
-                             timeout_state = undefined }) ->
-    pre_hibernate(GS2State);
+                             timeout_state = undefined,
+                             queue         = Queue }) ->
+    case priority_queue:is_empty(Queue) of
+        true  ->
+            pre_hibernate(GS2State);
+        false ->
+            process_next_msg(GS2State)
+    end;
+
 loop(GS2State) ->
     process_next_msg(drain(GS2State)).
 
index 95dc84e41bbd4a58d354cd44c8ddb404106d8feb..dbf9c295f9437de9c82f4b2853cca79db57a7524 100644 (file)
           broadcast_buffer,
           broadcast_buffer_sz,
           broadcast_timer,
-          txn_executor
+          txn_executor,
+          shutting_down
         }).
 
 -record(gm_group, { name, version, members }).
@@ -567,10 +568,15 @@ init([GroupName, Module, Args, TxnFun]) ->
                   broadcast_buffer    = [],
                   broadcast_buffer_sz = 0,
                   broadcast_timer     = undefined,
-                  txn_executor        = TxnFun }, hibernate,
+                  txn_executor        = TxnFun,
+                  shutting_down       = false }, hibernate,
      {backoff, ?HIBERNATE_AFTER_MIN, ?HIBERNATE_AFTER_MIN, ?DESIRED_HIBERNATE}}.
 
 
+handle_call({confirmed_broadcast, _Msg}, _From,
+            State = #state { shutting_down = {true, _} }) ->
+    reply(shutting_down, State);
+
 handle_call({confirmed_broadcast, _Msg}, _From,
             State = #state { members_state = undefined }) ->
     reply(not_joined, State);
@@ -645,6 +651,10 @@ handle_cast({?TAG, ReqVer, Msg},
       if_callback_success(
         Result, fun handle_msg_true/3, fun handle_msg_false/3, Msg, State1));
 
+handle_cast({broadcast, _Msg, _SizeHint},
+            State = #state { shutting_down = {true, _} }) ->
+    noreply(State);
+
 handle_cast({broadcast, _Msg, _SizeHint},
             State = #state { members_state = undefined }) ->
     noreply(State);
@@ -742,9 +752,7 @@ handle_info({'DOWN', MRef, process, _Pid, Reason},
     end.
 
 
-terminate(Reason, State = #state { module        = Module,
-                                   callback_args = Args }) ->
-    flush_broadcast_buffer(State),
+terminate(Reason, #state { module = Module, callback_args = Args }) ->
     Module:handle_terminate(Args, Reason).
 
 
@@ -1427,15 +1435,41 @@ activity_true(_Result, Activity, State = #state { module        = Module,
 activity_false(Result, _Activity, State) ->
     {Result, State}.
 
-if_callback_success(ok, True, _False, Arg, State) ->
+if_callback_success(Result, True, False, Arg, State) ->
+    {NewResult, NewState} = maybe_stop(Result, State),
+    if_callback_success1(NewResult, True, False, Arg, NewState).
+
+if_callback_success1(ok, True, _False, Arg, State) ->
     True(ok, Arg, State);
-if_callback_success(
+if_callback_success1(
   {become, Module, Args} = Result, True, _False, Arg, State) ->
     True(Result, Arg, State #state { module        = Module,
                                      callback_args = Args });
-if_callback_success({stop, _Reason} = Result, _True, False, Arg, State) ->
+if_callback_success1({stop, _Reason} = Result, _True, False, Arg, State) ->
     False(Result, Arg, State).
 
+maybe_stop({stop, Reason}, #state{ shutting_down = false } = State) ->
+    ShuttingDown = {true, Reason},
+    case has_pending_messages(State) of
+        true  -> {ok, State #state{ shutting_down = ShuttingDown }};
+        false -> {{stop, Reason}, State #state{ shutting_down = ShuttingDown }}
+    end;
+maybe_stop(Result, #state{ shutting_down = false } = State) ->
+    {Result, State};
+maybe_stop(Result, #state{ shutting_down = {true, Reason} } = State) ->
+    case has_pending_messages(State) of
+        true  -> {Result, State};
+        false -> {{stop, Reason}, State}
+    end.
+
+has_pending_messages(#state{ broadcast_buffer = Buffer })
+  when Buffer =/= [] ->
+    true;
+has_pending_messages(#state{ members_state = MembersState }) ->
+    [] =/= [M || {_, #member{last_pub = LP, last_ack = LA} = M}
+                 <- MembersState,
+                 LP =/= LA].
+
 maybe_confirm(_Self, _Id, Confirms, []) ->
     Confirms;
 maybe_confirm(Self, Self, Confirms, [PubNum | PubNums]) ->
index 84aaf4e20ca42f0a15b4b2c27d6cffa5abd2d228..bb906ede4f7a8fad5c02edd0893db7ff4a7cf82e 100644 (file)
@@ -30,6 +30,9 @@
 %% Boot steps.
 -export([maybe_insert_default_data/0, boot_delegate/0, recover/0]).
 
+%% for tests
+-export([validate_msg_store_io_batch_size_and_credit_disc_bound/2]).
+
 -rabbit_boot_step({pre_boot, [{description, "rabbit boot start"}]}).
 
 -rabbit_boot_step({codec_correctness_check,
@@ -520,6 +523,7 @@ start(normal, []) ->
             print_banner(),
             log_banner(),
             warn_if_kernel_config_dubious(),
+            warn_if_disc_io_options_dubious(),
             run_boot_steps(),
             {ok, SupPid};
         Error ->
@@ -848,6 +852,86 @@ warn_if_kernel_config_dubious() ->
         true  -> ok
     end.
 
+warn_if_disc_io_options_dubious() ->
+    %% if these values are not set, it doesn't matter since
+    %% rabbit_variable_queue will pick up the values defined in the
+    %% IO_BATCH_SIZE and CREDIT_DISC_BOUND constants.
+    CreditDiscBound = rabbit_misc:get_env(rabbit, msg_store_credit_disc_bound,
+                                          undefined),
+    IoBatchSize = rabbit_misc:get_env(rabbit, msg_store_io_batch_size,
+                                      undefined),
+    case catch validate_msg_store_io_batch_size_and_credit_disc_bound(
+                 CreditDiscBound, IoBatchSize) of
+        ok -> ok;
+        {error, {Reason, Vars}} ->
+            rabbit_log:warning(Reason, Vars)
+    end.
+
+validate_msg_store_io_batch_size_and_credit_disc_bound(CreditDiscBound,
+                                                       IoBatchSize) ->
+    case IoBatchSize of
+        undefined ->
+            ok;
+        IoBatchSize when is_integer(IoBatchSize) ->
+            if IoBatchSize < ?IO_BATCH_SIZE ->
+                    throw({error,
+                     {"io_batch_size of ~b lower than recommended value ~b, "
+                      "paging performance may worsen~n",
+                      [IoBatchSize, ?IO_BATCH_SIZE]}});
+               true ->
+                    ok
+            end;
+        IoBatchSize ->
+            throw({error,
+             {"io_batch_size should be an integer, but ~b given",
+              [IoBatchSize]}})
+    end,
+
+    %% CreditDiscBound = {InitialCredit, MoreCreditAfter}
+    {RIC, RMCA} = ?CREDIT_DISC_BOUND,
+    case CreditDiscBound of
+        undefined ->
+            ok;
+        {IC, MCA} when is_integer(IC), is_integer(MCA) ->
+            if IC < RIC; MCA < RMCA ->
+                    throw({error,
+                     {"msg_store_credit_disc_bound {~b, ~b} lower than"
+                      "recommended value {~b, ~b},"
+                      " paging performance may worsen~n",
+                      [IC, MCA, RIC, RMCA]}});
+               true ->
+                    ok
+            end;
+        {IC, MCA} ->
+            throw({error,
+             {"both msg_store_credit_disc_bound values should be integers, but ~p given",
+              [{IC, MCA}]}});
+        CreditDiscBound ->
+            throw({error,
+             {"invalid msg_store_credit_disc_bound value given: ~p",
+              [CreditDiscBound]}})
+    end,
+
+    case {CreditDiscBound, IoBatchSize} of
+        {undefined, undefined} ->
+            ok;
+        {_CDB, undefined} ->
+            ok;
+        {undefined, _IBS} ->
+            ok;
+        {{InitialCredit, _MCA}, IoBatchSize} ->
+            if IoBatchSize < InitialCredit ->
+                    throw(
+                      {error,
+                       {"msg_store_io_batch_size ~b should be bigger than the initial "
+                        "credit value from msg_store_credit_disc_bound ~b,"
+                        " paging performance may worsen~n",
+                        [IoBatchSize, InitialCredit]}});
+               true ->
+                    ok
+            end
+    end.
+
 home_dir() ->
     case init:get_argument(home) of
         {ok, [[Home]]} -> Home;
@@ -898,6 +982,17 @@ ensure_working_fhc() ->
     %% file_handle_cache, we spawn a separate process.
     Parent = self(),
     TestFun = fun() ->
+        ReadBuf = case application:get_env(rabbit, fhc_read_buffering) of
+            {ok, true}  -> "ON";
+            {ok, false} -> "OFF"
+        end,
+        WriteBuf = case application:get_env(rabbit, fhc_write_buffering) of
+            {ok, true}  -> "ON";
+            {ok, false} -> "OFF"
+        end,
+        rabbit_log:info(
+          "FHC read buffering:  ~s~n"
+          "FHC write buffering: ~s~n", [ReadBuf, WriteBuf]),
         Filename = filename:join(code:lib_dir(kernel, ebin), "kernel.app"),
         {ok, Fd} = file_handle_cache:open(Filename, [raw, binary, read], []),
         {ok, _} = file_handle_cache:read(Fd, 1),
index fc7a59c7433f255e73d3f1367dabd6505048426b..d9dd9cc3dc02973ab9d69de1d8909f15e7c839ba 100644 (file)
@@ -76,7 +76,7 @@ check_user_login(Username, AuthProps) ->
                   %% it gives us
                   case try_authenticate(Mod, Username, AuthProps) of
                       {ok, ModNUser = #auth_user{impl = Impl}} ->
-                          user(ModNUser, {ok, [{Mod, Impl}]});
+                          user(ModNUser, {ok, [{Mod, Impl}], []});
                       Else ->
                           Else
                   end;
@@ -98,9 +98,10 @@ try_authenticate(Module, Username, AuthProps) ->
 
 try_authorize(Modules, Username) ->
     lists:foldr(
-      fun (Module, {ok, ModsImpls}) ->
+      fun (Module, {ok, ModsImpls, ModsTags}) ->
               case Module:user_login_authorization(Username) of
-                  {ok, Impl}      -> {ok, [{Module, Impl} | ModsImpls]};
+                  {ok, Impl, Tags}-> {ok, [{Module, Impl} | ModsImpls], ModsTags ++ Tags};
+                  {ok, Impl}      -> {ok, [{Module, Impl} | ModsImpls], ModsTags};
                   {error, E}      -> {refused, Username,
                                         "~s failed authorizing ~s: ~p~n",
                                         [Module, Username, E]};
@@ -108,11 +109,11 @@ try_authorize(Modules, Username) ->
               end;
           (_,      {refused, F, A}) ->
               {refused, Username, F, A}
-      end, {ok, []}, Modules).
+      end, {ok, [], []}, Modules).
 
-user(#auth_user{username = Username, tags = Tags}, {ok, ModZImpls}) ->
+user(#auth_user{username = Username, tags = Tags}, {ok, ModZImpls, ModZTags}) ->
     {ok, #user{username       = Username,
-               tags           = Tags,
+               tags           = Tags ++ ModZTags,
                authz_backends = ModZImpls}};
 user(_AuthUser, Error) ->
     Error.
index 5bfa006e09051529857be7b2aead608866f2eb02..f6cc0fbddab374b03a20080e82b8dede5b468c22 100644 (file)
@@ -873,6 +873,9 @@ deliver(Qs, Delivery = #delivery{flow = Flow}) ->
     %% the slave receives the message direct from the channel, and the
     %% other when it receives it via GM.
     case Flow of
+        %% Here we are tracking messages sent by the rabbit_channel
+        %% process. We are accessing the rabbit_channel process
+        %% dictionary.
         flow   -> [credit_flow:send(QPid) || QPid <- QPids],
                   [credit_flow:send(QPid) || QPid <- SPids];
         noflow -> ok
index c5e4206fe36e5203be2765746cb97e359fd9e198..999e66aee3d8dae10838fc5197d8f06d141cd650 100644 (file)
@@ -662,9 +662,21 @@ handle_ch_down(DownPid, State = #q{consumers          = Consumers,
                                    exclusive_consumer = Holder,
                                    senders            = Senders}) ->
     State1 = State#q{senders = case pmon:is_monitored(DownPid, Senders) of
-                                   false -> Senders;
-                                   true  -> credit_flow:peer_down(DownPid),
-                                            pmon:demonitor(DownPid, Senders)
+                                   false ->
+                                       Senders;
+                                   true  ->
+    %% A rabbit_channel process died. Here credit_flow will take care
+    %% of cleaning up the rabbit_amqqueue_process process dictionary
+    %% with regards to the credit we were tracking for the channel
+    %% process. See handle_cast({deliver, Deliver}, State) in this
+    %% module. In that cast function we process deliveries from the
+    %% channel, which means we credit_flow:ack/1 said
+    %% messages. credit_flow:ack'ing messages means we are increasing
+    %% a counter to know when we need to send MoreCreditAfter. Since
+    %% the process died, the credit_flow flow module will clean up
+    %% that for us.
+                                       credit_flow:peer_down(DownPid),
+                                       pmon:demonitor(DownPid, Senders)
                                end},
     case rabbit_queue_consumers:erase_ch(DownPid, Consumers) of
         not_found ->
@@ -1110,6 +1122,9 @@ handle_cast({deliver, Delivery = #delivery{sender = Sender,
                                            flow   = Flow}, SlaveWhenPublished},
             State = #q{senders = Senders}) ->
     Senders1 = case Flow of
+    %% In both credit_flow:ack/1 we are acking messages to the channel
+    %% process that sent us the message delivery. See handle_ch_down
+    %% for more info.
                    flow   -> credit_flow:ack(Sender),
                              case SlaveWhenPublished of
                                  true  -> credit_flow:ack(Sender); %% [0]
@@ -1289,6 +1304,12 @@ handle_info({'EXIT', _Pid, Reason}, State) ->
 
 handle_info({bump_credit, Msg}, State = #q{backing_queue       = BQ,
                                            backing_queue_state = BQS}) ->
+    %% The message_store is granting us more credit. This means the
+    %% backing queue (for the rabbit_variable_queue case) might
+    %% continue paging messages to disk if it still needs to. We
+    %% consume credits from the message_store whenever we need to
+    %% persist a message to disk. See:
+    %% rabbit_variable_queue:msg_store_write/4.
     credit_flow:handle_bump_msg(Msg),
     noreply(State#q{backing_queue_state = BQ:resume(BQS)});
 
index e53ce50c22dfea65f06f3ba37f8839cec4b8e491..2b2a0ba20e29eed07187ff3d9edaf8ae646a8081 100644 (file)
@@ -92,8 +92,8 @@ user_login_authentication(Username, AuthProps) ->
 
 user_login_authorization(Username) ->
     case user_login_authentication(Username, []) of
-        {ok, #auth_user{impl = Impl}} -> {ok, Impl};
-        Else                          -> Else
+        {ok, #auth_user{impl = Impl, tags = Tags}} -> {ok, Impl, Tags};
+        Else                                       -> Else
     end.
 
 internal_check_user_login(Username, Fun) ->
index 12364b654b262c48f1c155ea6b4228a79142e2f1..495a79695d86149f285c54a337c8c6b4f27748de 100644 (file)
 %%
 %% Possible responses:
 %% {ok, Impl}
-%%     User authorisation succeeded, and here's the impl field.
+%% {ok, Impl, Tags}
+%%     User authorisation succeeded, and here's the impl and potential extra tags fields.
 %% {error, Error}
 %%     Something went wrong. Log and die.
 %% {refused, Msg, Args}
 %%     User authorisation failed. Log and die.
 -callback user_login_authorization(rabbit_types:username()) ->
     {'ok', any()} |
+    {'ok', any(), any()} |
     {'refused', string(), [any()]} |
     {'error', any()}.
 
index 489f7b346971b783b978666f47cf53ec56be16fe..b23a8410c52f95b11783df185e60f6ef8e51fe0c 100644 (file)
@@ -133,6 +133,8 @@ do(Pid, Method, Content) ->
     gen_server2:cast(Pid, {method, Method, Content, noflow}).
 
 do_flow(Pid, Method, Content) ->
+    %% Here we are tracking messages sent by the rabbit_reader
+    %% process. We are accessing the rabbit_reader process dictionary.
     credit_flow:send(Pid),
     gen_server2:cast(Pid, {method, Method, Content, flow}).
 
@@ -327,6 +329,9 @@ handle_cast({method, Method, Content, Flow},
             State = #ch{reader_pid   = Reader,
                         virtual_host = VHost}) ->
     case Flow of
+        %% We are going to process a message from the rabbit_reader
+        %% process, so here we ack it. In this case we are accessing
+        %% the rabbit_channel process dictionary.
         flow   -> credit_flow:ack(Reader);
         noflow -> ok
     end,
@@ -435,6 +440,12 @@ handle_cast({confirm, MsgSeqNos, QPid}, State = #ch{unconfirmed = UC}) ->
     noreply_coalesce(record_confirms(MXs, State#ch{unconfirmed = UC1})).
 
 handle_info({bump_credit, Msg}, State) ->
+    %% A rabbit_amqqueue_process is granting credit to our channel. If
+    %% our channel was being blocked by this process, and no other
+    %% process is blocking our channel, then this channel will be
+    %% unblocked. This means that any credit that was deferred will be
+    %% sent to rabbit_reader processs that might be blocked by this
+    %% particular channel.
     credit_flow:handle_bump_msg(Msg),
     noreply(State);
 
@@ -452,6 +463,11 @@ handle_info({'DOWN', _MRef, process, QPid, Reason}, State) ->
     State1 = handle_publishing_queue_down(QPid, Reason, State),
     State3 = handle_consuming_queue_down(QPid, State1),
     State4 = handle_delivering_queue_down(QPid, State3),
+    %% A rabbit_amqqueue_process has died. If our channel was being
+    %% blocked by this process, and no other process is blocking our
+    %% channel, then this channel will be unblocked. This means that
+    %% any credit that was deferred will be sent to the rabbit_reader
+    %% processs that might be blocked by this particular channel.
     credit_flow:peer_down(QPid),
     #ch{queue_names = QNames, queue_monitors = QMons} = State4,
     case dict:find(QPid, QNames) of
index 65ab7fcca84b50b58646b1c97b37d147e8fcfeb4..f8166bfcd13be4462d2d895b5c059fdb3193e56f 100644 (file)
 
 -export([safe_handle_event/3]).
 
+%% extracted from error_logger_file_h. Since 18.1 the state of the
+%% error logger module changed. See:
+%% https://github.com/erlang/otp/commit/003091a1fcc749a182505ef5675c763f71eacbb0#diff-d9a19ba08f5d2b60fadfc3aa1566b324R108
+%% github issue:
+%% https://github.com/rabbitmq/rabbitmq-server/issues/324
+-record(st, {fd,
+             filename,
+             prev_handler,
+             depth = unlimited}).
+
+%% extracted from error_logger_file_h. See comment above.
+get_depth() ->
+    case application:get_env(kernel, error_logger_format_depth) of
+        {ok, Depth} when is_integer(Depth) ->
+            erlang:max(10, Depth);
+        undefined ->
+            unlimited
+    end.
+
+-define(ERTS_NEW_LOGGER_STATE, "7.1").
+
 %% rabbit_error_logger_file_h is a wrapper around the error_logger_file_h
 %% module because the original's init/1 does not match properly
 %% with the result of closing the old handler when swapping handlers.
 %% lib/stdlib/src/error_logger_file_h.erl from R14B3 was copied as
 %% init_file/2 and changed so that it opens the file in 'append' mode.
 
-%% Used only when swapping handlers in log rotation
+%% Used only when swapping handlers in log rotation, pre OTP 18.1
 init({{File, Suffix}, []}) ->
-    case rabbit_file:append_file(File, Suffix) of
-        ok -> file:delete(File),
-              ok;
-        {error, Error} ->
-            rabbit_log:error("Failed to append contents of "
-                             "log file '~s' to '~s':~n~p~n",
-                             [File, [File, Suffix], Error])
-    end,
+    rotate_logs(File, Suffix),
+    init(File);
+%% Used only when swapping handlers in log rotation, since OTP 18.1
+init({{File, Suffix}, ok}) ->
+    rotate_logs(File, Suffix),
     init(File);
 %% Used only when swapping handlers and the original handler
 %% failed to terminate or was never installed
@@ -65,18 +83,31 @@ init(File) ->
 
 init_file(File, {error_logger, Buf}) ->
     case init_file(File, error_logger) of
-        {ok, {Fd, File, PrevHandler}} ->
-            [handle_event(Event, {Fd, File, PrevHandler}) ||
+        {ok, State} ->
+            [handle_event(Event, State) ||
                 {_, Event} <- lists:reverse(Buf)],
-            {ok, {Fd, File, PrevHandler}};
+            {ok, State};
         Error ->
             Error
     end;
 init_file(File, PrevHandler) ->
     process_flag(trap_exit, true),
     case file:open(File, [append]) of
-        {ok,Fd} -> {ok, {Fd, File, PrevHandler}};
-        Error   -> Error
+        {ok, Fd} ->
+            FoundVer = erlang:system_info(version),
+            State =
+                case rabbit_misc:version_compare(
+                       ?ERTS_NEW_LOGGER_STATE, FoundVer, lte) of
+                    true ->
+                        #st{fd           = Fd,
+                            filename     = File,
+                            prev_handler = PrevHandler,
+                            depth        = get_depth()};
+                    _    ->
+                        {Fd, File, PrevHandler}
+                end,
+            {ok, State};
+        Error    -> Error
     end.
 
 handle_event(Event, State) ->
@@ -134,3 +165,13 @@ code_change(OldVsn, State, Extra) ->
 %%----------------------------------------------------------------------
 
 t(Term) -> truncate:log_event(Term, ?LOG_TRUNC).
+
+rotate_logs(File, Suffix) ->
+    case rabbit_file:append_file(File, Suffix) of
+        ok -> file:delete(File),
+              ok;
+        {error, Error} ->
+            rabbit_log:error("Failed to append contents of "
+                             "log file '~s' to '~s':~n~p~n",
+                             [File, [File, Suffix], Error])
+    end.
index afbfc652b1b4d7370ef33051f4d7ceab3164ae62..53fb7625393f27f62dbaed793326142f4bd4bef2 100644 (file)
@@ -76,11 +76,14 @@ remove_bindings(transaction, _X, Bs) ->
                          rabbit_topic_trie_edge,
                          rabbit_topic_trie_binding]]
     end,
-    [begin
-         Path = [{FinalNode, _} | _] =
-             follow_down_get_path(X, split_topic_key(K)),
-         trie_remove_binding(X, FinalNode, D, Args),
-         remove_path_if_empty(X, Path)
+    [case follow_down_get_path(X, split_topic_key(K)) of
+         {ok, Path = [{FinalNode, _} | _]} ->
+             trie_remove_binding(X, FinalNode, D, Args),
+             remove_path_if_empty(X, Path);
+         {error, _Node, _RestW} ->
+             %% We're trying to remove a binding that no longer exists.
+             %% That's unexpected, but shouldn't be a problem.
+             ok
      end ||  #binding{source = X, key = K, destination = D, args = Args} <- Bs],
     ok;
 remove_bindings(none, _X, _Bs) ->
@@ -137,10 +140,8 @@ follow_down_last_node(X, Words) ->
     follow_down(X, fun (_, Node, _) -> Node end, root, Words).
 
 follow_down_get_path(X, Words) ->
-    {ok, Path} =
-        follow_down(X, fun (W, Node, PathAcc) -> [{Node, W} | PathAcc] end,
-                    [{root, none}], Words),
-    Path.
+    follow_down(X, fun (W, Node, PathAcc) -> [{Node, W} | PathAcc] end,
+                [{root, none}], Words).
 
 follow_down(X, AccFun, Acc0, Words) ->
     follow_down(X, root, AccFun, Acc0, Words).
index 168e71170b816443f150c73a975a68fad4896ba4..7f309ab0b79e0969928a9bcebdbefd19e595fdf6 100644 (file)
@@ -257,6 +257,9 @@ handle_cast({deliver, Delivery = #delivery{sender = Sender, flow = Flow}, true},
             State) ->
     %% Asynchronous, non-"mandatory", deliver mode.
     case Flow of
+        %% We are acking messages to the channel process that sent us
+        %% the message delivery. See
+        %% rabbit_amqqueue_process:handle_ch_down for more info.
         flow   -> credit_flow:ack(Sender);
         noflow -> ok
     end,
index 02a3bd0f15f2747b62e96558b9a96fb5a939c46b..8909484984d7f3c35931f2fc9fba3f7f2636a48f 100644 (file)
@@ -77,7 +77,8 @@
                                   %% to callbacks
           successfully_recovered, %% boolean: did we recover state?
           file_size_limit,        %% how big are our files allowed to get?
-          cref_to_msg_ids         %% client ref to synced messages mapping
+          cref_to_msg_ids,        %% client ref to synced messages mapping
+          credit_disc_bound       %% See rabbit.hrl CREDIT_DISC_BOUND
         }).
 
 -record(client_msstate,
@@ -91,7 +92,8 @@
           file_handles_ets,
           file_summary_ets,
           cur_file_cache_ets,
-          flying_ets
+          flying_ets,
+          credit_disc_bound
         }).
 
 -record(file_summary,
                       file_handles_ets   :: ets:tid(),
                       file_summary_ets   :: ets:tid(),
                       cur_file_cache_ets :: ets:tid(),
-                      flying_ets         :: ets:tid()}).
+                      flying_ets         :: ets:tid(),
+                      credit_disc_bound  :: {pos_integer(), pos_integer()}}).
 -type(msg_ref_delta_gen(A) ::
         fun ((A) -> 'finished' |
                     {rabbit_types:msg_id(), non_neg_integer(), A})).
@@ -442,6 +445,8 @@ client_init(Server, Ref, MsgOnDiskFun, CloseFDsFun) ->
         gen_server2:call(
           Server, {new_client_state, Ref, self(), MsgOnDiskFun, CloseFDsFun},
           infinity),
+    CreditDiscBound = rabbit_misc:get_env(rabbit, msg_store_credit_disc_bound,
+                                          ?CREDIT_DISC_BOUND),
     #client_msstate { server             = Server,
                       client_ref         = Ref,
                       file_handle_cache  = dict:new(),
@@ -452,7 +457,8 @@ client_init(Server, Ref, MsgOnDiskFun, CloseFDsFun) ->
                       file_handles_ets   = FileHandlesEts,
                       file_summary_ets   = FileSummaryEts,
                       cur_file_cache_ets = CurFileCacheEts,
-                      flying_ets         = FlyingEts }.
+                      flying_ets         = FlyingEts,
+                      credit_disc_bound  = CreditDiscBound }.
 
 client_terminate(CState = #client_msstate { client_ref = Ref }) ->
     close_all_handles(CState),
@@ -465,8 +471,15 @@ client_delete_and_terminate(CState = #client_msstate { client_ref = Ref }) ->
 
 client_ref(#client_msstate { client_ref = Ref }) -> Ref.
 
-write_flow(MsgId, Msg, CState = #client_msstate { server = Server }) ->
-    credit_flow:send(whereis(Server), ?CREDIT_DISC_BOUND),
+write_flow(MsgId, Msg,
+           CState = #client_msstate {
+                       server = Server,
+                       credit_disc_bound = CreditDiscBound }) ->
+    %% Here we are tracking messages sent by the
+    %% rabbit_amqqueue_process process via the
+    %% rabbit_variable_queue. We are accessing the
+    %% rabbit_amqqueue_process process dictionary.
+    credit_flow:send(whereis(Server), CreditDiscBound),
     client_write(MsgId, Msg, flow, CState).
 
 write(MsgId, Msg, CState) -> client_write(MsgId, Msg, noflow, CState).
@@ -709,6 +722,9 @@ init([Server, BaseDir, ClientRefs, StartupFunState]) ->
                                 msg_store        = self()
                               }),
 
+    CreditDiscBound = rabbit_misc:get_env(rabbit, msg_store_credit_disc_bound,
+                                          ?CREDIT_DISC_BOUND),
+
     State = #msstate { dir                    = Dir,
                        index_module           = IndexModule,
                        index_state            = IndexState,
@@ -728,7 +744,8 @@ init([Server, BaseDir, ClientRefs, StartupFunState]) ->
                        clients                = Clients,
                        successfully_recovered = CleanShutdown,
                        file_size_limit        = FileSizeLimit,
-                       cref_to_msg_ids        = dict:new()
+                       cref_to_msg_ids        = dict:new(),
+                       credit_disc_bound      = CreditDiscBound
                      },
 
     %% If we didn't recover the msg location index then we need to
@@ -812,10 +829,14 @@ handle_cast({client_delete, CRef},
 
 handle_cast({write, CRef, MsgId, Flow},
             State = #msstate { cur_file_cache_ets = CurFileCacheEts,
-                               clients            = Clients }) ->
+                               clients            = Clients,
+                               credit_disc_bound  = CreditDiscBound }) ->
     case Flow of
         flow   -> {CPid, _, _} = dict:fetch(CRef, Clients),
-                  credit_flow:ack(CPid, ?CREDIT_DISC_BOUND);
+                  %% We are going to process a message sent by the
+                  %% rabbit_amqqueue_process. Now we are accessing the
+                  %% msg_store process dictionary.
+                  credit_flow:ack(CPid, CreditDiscBound);
         noflow -> ok
     end,
     true = 0 =< ets:update_counter(CurFileCacheEts, MsgId, {3, -1}),
@@ -890,6 +911,10 @@ handle_info(timeout, State) ->
     noreply(internal_sync(State));
 
 handle_info({'DOWN', _MRef, process, Pid, _Reason}, State) ->
+    %% similar to what happens in
+    %% rabbit_amqqueue_process:handle_ch_down but with a relation of
+    %% msg_store -> rabbit_amqqueue_process instead of
+    %% rabbit_amqqueue_process -> rabbit_channel.
     credit_flow:peer_down(Pid),
     noreply(State);
 
index 5d877434725efeaf3f1c149709237393c463af19..f95f8c5818703b11a63749b8e683ab326ccc6502 100644 (file)
@@ -475,8 +475,22 @@ hostname() ->
 cmap(F) -> rabbit_misc:filter_exit_map(F, connections()).
 
 tcp_opts() ->
-    {ok, Opts} = application:get_env(rabbit, tcp_listen_options),
-    Opts.
+    {ok, ConfigOpts} = application:get_env(rabbit, tcp_listen_options),
+    merge_essential_tcp_listen_options(ConfigOpts).
+
+-define(ESSENTIAL_LISTEN_OPTIONS,
+        [binary,
+         {active, false},
+         {packet, raw},
+         {reuseaddr, true},
+         {nodelay, true}]).
+
+merge_essential_tcp_listen_options(Opts) ->
+    lists:foldl(fun ({K, _} = Opt, Acc) ->
+                        lists:keystore(K, 1, Acc, Opt);
+                    (Opt, Acc) ->
+                        [Opt | Acc]
+                end , Opts, ?ESSENTIAL_LISTEN_OPTIONS).
 
 %% inet_parse:address takes care of ip string, like "0.0.0.0"
 %% inet:getaddr returns immediately for ip tuple {0,0,0,0},
index adfe0c7faec0d6e79aa811ee295bd25baeb9b476..129f51d099b8c6723bf7dd5a5b1fcc603d2e76b6 100644 (file)
@@ -1,3 +1,19 @@
+%% The contents of this file are subject to the Mozilla Public License
+%% Version 1.1 (the "License"); you may not use this file except in
+%% compliance with the License. You may obtain a copy of the License
+%% at http://www.mozilla.org/MPL/
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and
+%% limitations under the License.
+%%
+%% The Original Code is RabbitMQ.
+%%
+%% The Initial Developer of the Original Code is GoPivotal, Inc.
+%% Copyright (c) 2007-2015 Pivotal Software, Inc.  All rights reserved.
+%%
+
 -module(rabbit_queue_decorator).
 
 -include("rabbit.hrl").
index 0c7d7c230a884aa44364d0b41689efc86c28ca5c..176f65b18b6b95564a15379b824439dcf507b419 100644 (file)
@@ -16,8 +16,9 @@
 
 -module(rabbit_queue_index).
 
--export([erase/1, init/3, recover/6,
+-export([erase/1, init/3, reset_state/1, recover/6,
          terminate/2, delete_and_terminate/1,
+         pre_publish/7, flush_pre_publish_cache/2,
          publish/6, deliver/2, ack/2, sync/1, needs_sync/1, flush/1,
          read/3, next_segment_boundary/1, bounds/1, start/1, stop/0]).
 
 %% binary generation/matching with constant vs variable lengths.
 
 -define(REL_SEQ_BITS, 14).
--define(SEGMENT_ENTRY_COUNT, 16384). %% trunc(math:pow(2,?REL_SEQ_BITS))).
+%% calculated as trunc(math:pow(2,?REL_SEQ_BITS))).
+-define(SEGMENT_ENTRY_COUNT, 16384).
 
 %% seq only is binary 01 followed by 14 bits of rel seq id
 %% (range: 0 - 16383)
 
 -record(qistate, {dir, segments, journal_handle, dirty_count,
                   max_journal_entries, on_sync, on_sync_msg,
-                  unconfirmed, unconfirmed_msg}).
+                  unconfirmed, unconfirmed_msg,
+                  pre_publish_cache, delivered_cache}).
 
--record(segment, {num, path, journal_entries, unacked}).
+-record(segment, {num, path, journal_entries,
+                  entries_to_segment, unacked}).
 
 -include("rabbit.hrl").
 
 
 -type(hdl() :: ('undefined' | any())).
 -type(segment() :: ('undefined' |
-                    #segment { num             :: non_neg_integer(),
-                               path            :: file:filename(),
-                               journal_entries :: array:array(),
-                               unacked         :: non_neg_integer()
+                    #segment { num                :: non_neg_integer(),
+                               path               :: file:filename(),
+                               journal_entries    :: array:array(),
+                               entries_to_segment :: array:array(),
+                               unacked            :: non_neg_integer()
                              })).
 -type(seq_id() :: integer()).
 -type(seg_dict() :: {dict:dict(), [segment()]}).
                               on_sync             :: on_sync_fun(),
                               on_sync_msg         :: on_sync_fun(),
                               unconfirmed         :: gb_sets:set(),
-                              unconfirmed_msg     :: gb_sets:set()
+                              unconfirmed_msg     :: gb_sets:set(),
+                              pre_publish_cache   :: list(),
+                              delivered_cache     :: list()
                             }).
 -type(contains_predicate() :: fun ((rabbit_types:msg_id()) -> boolean())).
 -type(walker(A) :: fun ((A) -> 'finished' |
 -type(shutdown_terms() :: [term()] | 'non_clean_shutdown').
 
 -spec(erase/1 :: (rabbit_amqqueue:name()) -> 'ok').
+-spec(reset_state/1 :: (qistate()) -> qistate()).
 -spec(init/3 :: (rabbit_amqqueue:name(),
                  on_sync_fun(), on_sync_fun()) -> qistate()).
 -spec(recover/6 :: (rabbit_amqqueue:name(), shutdown_terms(), boolean(),
 
 erase(Name) ->
     #qistate { dir = Dir } = blank_state(Name),
-    case rabbit_file:is_dir(Dir) of
-        true  -> rabbit_file:recursive_delete([Dir]);
-        false -> ok
-    end.
+    erase_index_dir(Dir).
+
+%% used during variable queue purge when there are no pending acks
+reset_state(#qistate{ dir            = Dir,
+                      on_sync        = OnSyncFun,
+                      on_sync_msg    = OnSyncMsgFun,
+                      journal_handle = JournalHdl }) ->
+    ok = case JournalHdl of
+             undefined -> ok;
+             _         -> file_handle_cache:close(JournalHdl)
+         end,
+    ok = erase_index_dir(Dir),
+    blank_state_dir_funs(Dir, OnSyncFun, OnSyncMsgFun).
 
 init(Name, OnSyncFun, OnSyncMsgFun) ->
     State = #qistate { dir = Dir } = blank_state(Name),
@@ -288,6 +305,78 @@ delete_and_terminate(State) ->
     ok = rabbit_file:recursive_delete([Dir]),
     State1.
 
+pre_publish(MsgOrId, SeqId, MsgProps, IsPersistent, IsDelivered, JournalSizeHint,
+            State = #qistate{unconfirmed       = UC,
+                             unconfirmed_msg   = UCM,
+                             pre_publish_cache = PPC,
+                             delivered_cache   = DC}) ->
+    MsgId = case MsgOrId of
+                #basic_message{id = Id} -> Id;
+                Id when is_binary(Id)   -> Id
+            end,
+    ?MSG_ID_BYTES = size(MsgId),
+
+    State1 =
+        case {MsgProps#message_properties.needs_confirming, MsgOrId} of
+            {true,  MsgId} -> UC1  = gb_sets:add_element(MsgId, UC),
+                              State#qistate{unconfirmed     = UC1};
+            {true,  _}     -> UCM1 = gb_sets:add_element(MsgId, UCM),
+                              State#qistate{unconfirmed_msg = UCM1};
+            {false, _}     -> State
+        end,
+
+    {Bin, MsgBin} = create_pub_record_body(MsgOrId, MsgProps),
+
+    PPC1 =
+        [[<<(case IsPersistent of
+                true  -> ?PUB_PERSIST_JPREFIX;
+                false -> ?PUB_TRANS_JPREFIX
+            end):?JPREFIX_BITS,
+           SeqId:?SEQ_BITS, Bin/binary,
+           (size(MsgBin)):?EMBEDDED_SIZE_BITS>>, MsgBin], PPC],
+
+    DC1 =
+        case IsDelivered of
+            true ->
+                [SeqId | DC];
+            false ->
+                DC
+        end,
+
+    add_to_journal(SeqId, {IsPersistent, Bin, MsgBin},
+                   maybe_flush_pre_publish_cache(
+                     JournalSizeHint,
+                     State1#qistate{pre_publish_cache = PPC1,
+                                    delivered_cache   = DC1})).
+
+%% pre_publish_cache is the entry with most elements when comapred to
+%% delivered_cache so we only check the former in the guard.
+maybe_flush_pre_publish_cache(JournalSizeHint,
+                              #qistate{pre_publish_cache = PPC} = State)
+  when length(PPC) >= ?SEGMENT_ENTRY_COUNT ->
+    flush_pre_publish_cache(JournalSizeHint, State);
+maybe_flush_pre_publish_cache(_JournalSizeHint, State) ->
+    State.
+
+flush_pre_publish_cache(JournalSizeHint, State) ->
+    State1 = flush_pre_publish_cache(State),
+    State2 = flush_delivered_cache(State1),
+    maybe_flush_journal(JournalSizeHint, State2).
+
+flush_pre_publish_cache(#qistate{pre_publish_cache = []} = State) ->
+    State;
+flush_pre_publish_cache(State = #qistate{pre_publish_cache = PPC}) ->
+    {JournalHdl, State1} = get_journal_handle(State),
+    file_handle_cache_stats:update(queue_index_journal_write),
+    ok = file_handle_cache:append(JournalHdl, lists:reverse(PPC)),
+    State1#qistate{pre_publish_cache = []}.
+
+flush_delivered_cache(#qistate{delivered_cache = []} = State) ->
+    State;
+flush_delivered_cache(State = #qistate{delivered_cache = DC}) ->
+    State1 = deliver(lists:reverse(DC), State),
+    State1#qistate{delivered_cache = []}.
+
 publish(MsgOrId, SeqId, MsgProps, IsPersistent, JournalSizeHint,
         State = #qistate{unconfirmed     = UC,
                          unconfirmed_msg = UCM}) ->
@@ -428,11 +517,22 @@ all_queue_directory_names(Dir) ->
 %% startup and shutdown
 %%----------------------------------------------------------------------------
 
+erase_index_dir(Dir) ->
+    case rabbit_file:is_dir(Dir) of
+        true  -> rabbit_file:recursive_delete([Dir]);
+        false -> ok
+    end.
+
 blank_state(QueueName) ->
     blank_state_dir(
       filename:join(queues_dir(), queue_name_to_dir_name(QueueName))).
 
 blank_state_dir(Dir) ->
+    blank_state_dir_funs(Dir,
+                         fun (_) -> ok end,
+                         fun (_) -> ok end).
+
+blank_state_dir_funs(Dir, OnSyncFun, OnSyncMsgFun) ->
     {ok, MaxJournal} =
         application:get_env(rabbit, queue_index_max_journal_entries),
     #qistate { dir                 = Dir,
@@ -440,10 +540,12 @@ blank_state_dir(Dir) ->
                journal_handle      = undefined,
                dirty_count         = 0,
                max_journal_entries = MaxJournal,
-               on_sync             = fun (_) -> ok end,
-               on_sync_msg         = fun (_) -> ok end,
+               on_sync             = OnSyncFun,
+               on_sync_msg         = OnSyncMsgFun,
                unconfirmed         = gb_sets:new(),
-               unconfirmed_msg     = gb_sets:new() }.
+               unconfirmed_msg     = gb_sets:new(),
+               pre_publish_cache   = [],
+               delivered_cache     = [] }.
 
 init_clean(RecoveredCounts, State) ->
     %% Load the journal. Since this is a clean recovery this (almost)
@@ -649,30 +751,46 @@ add_to_journal(SeqId, Action, State = #qistate { dirty_count = DCount,
 
 add_to_journal(RelSeq, Action,
                Segment = #segment { journal_entries = JEntries,
+                                    entries_to_segment = EToSeg,
                                     unacked = UnackedCount }) ->
+
+    {Fun, Entry} = action_to_entry(RelSeq, Action, JEntries),
+
+    {JEntries1, EToSeg1} =
+        case Fun of
+            set ->
+                {array:set(RelSeq, Entry, JEntries),
+                 array:set(RelSeq, entry_to_segment(RelSeq, Entry, []),
+                           EToSeg)};
+            reset ->
+                {array:reset(RelSeq, JEntries),
+                 array:reset(RelSeq, EToSeg)}
+        end,
+
     Segment #segment {
-      journal_entries = add_to_journal(RelSeq, Action, JEntries),
+      journal_entries = JEntries1,
+      entries_to_segment = EToSeg1,
       unacked = UnackedCount + case Action of
                                    ?PUB -> +1;
                                    del  ->  0;
                                    ack  -> -1
-                               end};
+                               end}.
 
-add_to_journal(RelSeq, Action, JEntries) ->
+action_to_entry(RelSeq, Action, JEntries) ->
     case array:get(RelSeq, JEntries) of
         undefined ->
-            array:set(RelSeq,
-                      case Action of
-                          ?PUB -> {Action, no_del, no_ack};
-                          del  -> {no_pub,    del, no_ack};
-                          ack  -> {no_pub, no_del,    ack}
-                      end, JEntries);
+            {set,
+             case Action of
+                 ?PUB -> {Action, no_del, no_ack};
+                 del  -> {no_pub,    del, no_ack};
+                 ack  -> {no_pub, no_del,    ack}
+             end};
         ({Pub,    no_del, no_ack}) when Action == del ->
-            array:set(RelSeq, {Pub,    del, no_ack}, JEntries);
+            {set, {Pub,    del, no_ack}};
         ({no_pub,    del, no_ack}) when Action == ack ->
-            array:set(RelSeq, {no_pub, del,    ack}, JEntries);
+            {set, {no_pub, del,    ack}};
         ({?PUB,      del, no_ack}) when Action == ack ->
-            array:reset(RelSeq, JEntries)
+            {reset, none}
     end.
 
 maybe_flush_journal(State) ->
@@ -703,18 +821,23 @@ flush_journal(State = #qistate { segments = Segments }) ->
     notify_sync(State1 #qistate { dirty_count = 0 }).
 
 append_journal_to_segment(#segment { journal_entries = JEntries,
+                                     entries_to_segment = EToSeg,
                                      path = Path } = Segment) ->
     case array:sparse_size(JEntries) of
         0 -> Segment;
-        _ -> Seg = array:sparse_foldr(
-                     fun entry_to_segment/3, [], JEntries),
-             file_handle_cache_stats:update(queue_index_write),
-
-             {ok, Hdl} = file_handle_cache:open(Path, ?WRITE_MODE,
-                                                [{write_buffer, infinity}]),
-             file_handle_cache:append(Hdl, Seg),
-             ok = file_handle_cache:close(Hdl),
-             Segment #segment { journal_entries = array_new() }
+        _ ->
+            file_handle_cache_stats:update(queue_index_write),
+
+            {ok, Hdl} = file_handle_cache:open(Path, ?WRITE_MODE,
+                                               [{write_buffer, infinity}]),
+            %% the file_handle_cache also does a list reverse, so this
+            %% might not be required here, but before we were doing a
+            %% sparse_foldr, a lists:reverse/1 seems to be the correct
+            %% thing to do for now.
+            file_handle_cache:append(Hdl, lists:reverse(array:to_list(EToSeg))),
+            ok = file_handle_cache:close(Hdl),
+            Segment #segment { journal_entries    = array_new(),
+                               entries_to_segment = array_new([]) }
     end.
 
 get_journal_handle(State = #qistate { journal_handle = undefined,
@@ -747,14 +870,16 @@ recover_journal(State) ->
     Segments1 =
         segment_map(
           fun (Segment = #segment { journal_entries = JEntries,
+                                    entries_to_segment = EToSeg,
                                     unacked = UnackedCountInJournal }) ->
                   %% We want to keep ack'd entries in so that we can
                   %% remove them if duplicates are in the journal. The
                   %% counts here are purely from the segment itself.
                   {SegEntries, UnackedCountInSeg} = load_segment(true, Segment),
-                  {JEntries1, UnackedCountDuplicates} =
-                      journal_minus_segment(JEntries, SegEntries),
+                  {JEntries1, EToSeg1, UnackedCountDuplicates} =
+                      journal_minus_segment(JEntries, EToSeg, SegEntries),
                   Segment #segment { journal_entries = JEntries1,
+                                     entries_to_segment = EToSeg1,
                                      unacked = (UnackedCountInJournal +
                                                     UnackedCountInSeg -
                                                     UnackedCountDuplicates) }
@@ -841,10 +966,11 @@ segment_find_or_new(Seg, Dir, Segments) ->
         {ok, Segment} -> Segment;
         error         -> SegName = integer_to_list(Seg)  ++ ?SEGMENT_EXTENSION,
                          Path = filename:join(Dir, SegName),
-                         #segment { num             = Seg,
-                                    path            = Path,
-                                    journal_entries = array_new(),
-                                    unacked         = 0 }
+                         #segment { num                = Seg,
+                                    path               = Path,
+                                    journal_entries    = array_new(),
+                                    entries_to_segment = array_new([]),
+                                    unacked            = 0 }
     end.
 
 segment_find(Seg, {_Segments, [Segment = #segment { num = Seg } |_]}) ->
@@ -884,20 +1010,20 @@ segment_nums({Segments, CachedSegments}) ->
 segments_new() ->
     {dict:new(), []}.
 
-entry_to_segment(_RelSeq, {?PUB, del, ack}, Buf) ->
-    Buf;
-entry_to_segment(RelSeq, {Pub, Del, Ack}, Buf) ->
+entry_to_segment(_RelSeq, {?PUB, del, ack}, Initial) ->
+    Initial;
+entry_to_segment(RelSeq, {Pub, Del, Ack}, Initial) ->
     %% NB: we are assembling the segment in reverse order here, so
     %% del/ack comes first.
     Buf1 = case {Del, Ack} of
                {no_del, no_ack} ->
-                   Buf;
+                   Initial;
                _ ->
                    Binary = <<?REL_SEQ_ONLY_PREFIX:?REL_SEQ_ONLY_PREFIX_BITS,
                               RelSeq:?REL_SEQ_BITS>>,
                    case {Del, Ack} of
-                       {del, ack} -> [[Binary, Binary] | Buf];
-                       _          -> [Binary | Buf]
+                       {del, ack} -> [[Binary, Binary] | Initial];
+                       _          -> [Binary | Initial]
                    end
            end,
     case Pub of
@@ -986,7 +1112,10 @@ add_segment_relseq_entry(KeepAcked, RelSeq, {SegEntries, Unacked}) ->
     end.
 
 array_new() ->
-    array:new([{default, undefined}, fixed, {size, ?SEGMENT_ENTRY_COUNT}]).
+    array_new(undefined).
+
+array_new(Default) ->
+    array:new([{default, Default}, fixed, {size, ?SEGMENT_ENTRY_COUNT}]).
 
 bool_to_int(true ) -> 1;
 bool_to_int(false) -> 0.
@@ -1032,19 +1161,29 @@ segment_plus_journal1({?PUB, del, no_ack},          {no_pub, no_del, ack}) ->
 %% Remove from the journal entries for a segment, items that are
 %% duplicates of entries found in the segment itself. Used on start up
 %% to clean up the journal.
-journal_minus_segment(JEntries, SegEntries) ->
+%%
+%% We need to update the entries_to_segment since they are just a
+%% cache of what's on the journal.
+journal_minus_segment(JEntries, EToSeg, SegEntries) ->
     array:sparse_foldl(
-      fun (RelSeq, JObj, {JEntriesOut, UnackedRemoved}) ->
+      fun (RelSeq, JObj, {JEntriesOut, EToSegOut, UnackedRemoved}) ->
               SegEntry = array:get(RelSeq, SegEntries),
               {Obj, UnackedRemovedDelta} =
                   journal_minus_segment1(JObj, SegEntry),
-              {case Obj of
-                   keep      -> JEntriesOut;
-                   undefined -> array:reset(RelSeq, JEntriesOut);
-                   _         -> array:set(RelSeq, Obj, JEntriesOut)
-               end,
-               UnackedRemoved + UnackedRemovedDelta}
-      end, {JEntries, 0}, JEntries).
+              {JEntriesOut1, EToSegOut1} =
+                  case Obj of
+                      keep      ->
+                          {JEntriesOut, EToSegOut};
+                      undefined ->
+                          {array:reset(RelSeq, JEntriesOut),
+                           array:reset(RelSeq, EToSegOut)};
+                      _         ->
+                          {array:set(RelSeq, Obj, JEntriesOut),
+                           array:set(RelSeq, entry_to_segment(RelSeq, Obj, []),
+                                     EToSegOut)}
+                  end,
+               {JEntriesOut1, EToSegOut1, UnackedRemoved + UnackedRemovedDelta}
+      end, {JEntries, EToSeg, 0}, JEntries).
 
 %% Here, the result is a tuple with the first element containing the
 %% item we are adding to or modifying in the (initially fresh) journal
index d296c41344de29119439c5ac321106abb02820b7..8812e1d0e1e3a1ec2b28b0231804580c35a422f1 100644 (file)
@@ -478,6 +478,7 @@ handle_other(ensure_stats, State) ->
 handle_other(emit_stats, State) ->
     emit_stats(State);
 handle_other({bump_credit, Msg}, State) ->
+    %% Here we are receiving credit by some channel process.
     credit_flow:handle_bump_msg(Msg),
     control_throttle(State);
 handle_other(Other, State) ->
index e716345b85277f5a8f2d247b4034fce326f82640..a873a714e13a272e0cf5e567907c226d4b2eaca1 100644 (file)
@@ -189,9 +189,12 @@ check_content(Tab, TabDef) ->
 
 check(Fun) ->
     case [Error || {Tab, TabDef} <- definitions(),
-                   case Fun(Tab, TabDef) of
-                       ok             -> Error = none, false;
-                       {error, Error} -> true
+                   begin
+                       {Ret, Error} = case Fun(Tab, TabDef) of
+                           ok         -> {false, none};
+                           {error, E} -> {true, E}
+                       end,
+                       Ret
                    end] of
         []     -> ok;
         Errors -> {error, Errors}
index 691e4ce2e2191acda3c169dbe94492f7dea1fdac..a0e71c69de85043169629820d5d9f93c9b7a6ec5 100644 (file)
           msg_store_clients,
           durable,
           transient_threshold,
+          qi_embed_msgs_below,
 
           len,                %% w/o unacked
           bytes,              %% w/o unacked
           %% Unlike the other counters these two do not feed into
           %% #rates{} and get reset
           disk_read_count,
-          disk_write_count
+          disk_write_count,
+
+          io_batch_size
         }).
 
 -record(rates, { in, out, ack_in, ack_out, timestamp }).
           end_seq_id    %% end_seq_id is exclusive
         }).
 
-%% When we discover that we should write some indices to disk for some
-%% betas, the IO_BATCH_SIZE sets the number of betas that we must be
-%% due to write indices for before we do any work at all.
--define(IO_BATCH_SIZE, 2048). %% next power-of-2 after ?CREDIT_DISC_BOUND
 -define(HEADER_GUESS_SIZE, 100). %% see determine_persist_to/2
 -define(PERSISTENT_MSG_STORE, msg_store_persistent).
 -define(TRANSIENT_MSG_STORE,  msg_store_transient).
                                                     {any(), binary()}},
              durable               :: boolean(),
              transient_threshold   :: non_neg_integer(),
+             qi_embed_msgs_below   :: non_neg_integer(),
 
              len                   :: non_neg_integer(),
              bytes                 :: non_neg_integer(),
              ack_out_counter       :: non_neg_integer(),
              ack_in_counter        :: non_neg_integer(),
              disk_read_count       :: non_neg_integer(),
-             disk_write_count      :: non_neg_integer() }).
+             disk_write_count      :: non_neg_integer(),
+
+             io_batch_size         :: pos_integer()}).
 %% Duplicated from rabbit_backing_queue
 -spec(ack/2 :: ([ack()], state()) -> {[rabbit_guid:guid()], state()}).
 
@@ -531,38 +533,29 @@ terminate(_Reason, State) ->
 %% the only difference between purge and delete is that delete also
 %% needs to delete everything that's been delivered and not ack'd.
 delete_and_terminate(_Reason, State) ->
-    %% TODO: there is no need to interact with qi at all - which we do
-    %% as part of 'purge' and 'purge_pending_ack', other than
-    %% deleting it.
-    {_PurgeCount, State1} = purge(State),
-    State2 = #vqstate { index_state         = IndexState,
-                        msg_store_clients   = {MSCStateP, MSCStateT} } =
-        purge_pending_ack(false, State1),
-    IndexState1 = rabbit_queue_index:delete_and_terminate(IndexState),
+    %% Normally when we purge messages we interact with the qi by
+    %% issues delivers and acks for every purged message. In this case
+    %% we don't need to do that, so we just delete the qi.
+    State1 = purge_and_index_reset(State),
+    State2 = #vqstate { msg_store_clients = {MSCStateP, MSCStateT} } =
+        purge_pending_ack_delete_and_terminate(State1),
     case MSCStateP of
         undefined -> ok;
         _         -> rabbit_msg_store:client_delete_and_terminate(MSCStateP)
     end,
     rabbit_msg_store:client_delete_and_terminate(MSCStateT),
-    a(State2 #vqstate { index_state       = IndexState1,
-                        msg_store_clients = undefined }).
+    a(State2 #vqstate { msg_store_clients = undefined }).
 
 delete_crashed(#amqqueue{name = QName}) ->
     ok = rabbit_queue_index:erase(QName).
 
-purge(State = #vqstate { q4  = Q4,
-                         len = Len }) ->
-    %% TODO: when there are no pending acks, which is a common case,
-    %% we could simply wipe the qi instead of issuing delivers and
-    %% acks for all the messages.
-    State1 = remove_queue_entries(Q4, State),
-
-    State2 = #vqstate { q1 = Q1 } =
-        purge_betas_and_deltas(State1 #vqstate { q4 = ?QUEUE:new() }),
-
-    State3 = remove_queue_entries(Q1, State2),
-
-    {Len, a(State3 #vqstate { q1 = ?QUEUE:new() })}.
+purge(State = #vqstate { len = Len }) ->
+    case is_pending_ack_empty(State) of
+        true ->
+            {Len, purge_and_index_reset(State)};
+        false ->
+            {Len, purge_when_pending_acks(State)}
+    end.
 
 purge_acks(State) -> a(purge_pending_ack(false, State)).
 
@@ -570,12 +563,13 @@ publish(Msg = #basic_message { is_persistent = IsPersistent, id = MsgId },
         MsgProps = #message_properties { needs_confirming = NeedsConfirming },
         IsDelivered, _ChPid, _Flow,
         State = #vqstate { q1 = Q1, q3 = Q3, q4 = Q4,
-                           next_seq_id      = SeqId,
-                           in_counter       = InCount,
-                           durable          = IsDurable,
-                           unconfirmed      = UC }) ->
+                           qi_embed_msgs_below = IndexMaxSize,
+                           next_seq_id         = SeqId,
+                           in_counter          = InCount,
+                           durable             = IsDurable,
+                           unconfirmed         = UC }) ->
     IsPersistent1 = IsDurable andalso IsPersistent,
-    MsgStatus = msg_status(IsPersistent1, IsDelivered, SeqId, Msg, MsgProps),
+    MsgStatus = msg_status(IsPersistent1, IsDelivered, SeqId, Msg, MsgProps, IndexMaxSize),
     {MsgStatus1, State1} = maybe_write_to_disk(false, false, MsgStatus, State),
     State2 = case ?QUEUE:is_empty(Q3) of
                  false -> State1 #vqstate { q1 = ?QUEUE:in(m(MsgStatus1), Q1) };
@@ -594,13 +588,14 @@ publish_delivered(Msg = #basic_message { is_persistent = IsPersistent,
                   MsgProps = #message_properties {
                     needs_confirming = NeedsConfirming },
                   _ChPid, _Flow,
-                  State = #vqstate { next_seq_id      = SeqId,
-                                     out_counter      = OutCount,
-                                     in_counter       = InCount,
-                                     durable          = IsDurable,
-                                     unconfirmed      = UC }) ->
+                  State = #vqstate { qi_embed_msgs_below = IndexMaxSize,
+                                     next_seq_id         = SeqId,
+                                     out_counter         = OutCount,
+                                     in_counter          = InCount,
+                                     durable             = IsDurable,
+                                     unconfirmed         = UC }) ->
     IsPersistent1 = IsDurable andalso IsPersistent,
-    MsgStatus = msg_status(IsPersistent1, true, SeqId, Msg, MsgProps),
+    MsgStatus = msg_status(IsPersistent1, true, SeqId, Msg, MsgProps, IndexMaxSize),
     {MsgStatus1, State1} = maybe_write_to_disk(false, false, MsgStatus, State),
     State2 = record_pending_ack(m(MsgStatus1), State1),
     UC1 = gb_sets_maybe_insert(NeedsConfirming, MsgId, UC),
@@ -621,29 +616,14 @@ drain_confirmed(State = #vqstate { confirmed = C }) ->
     end.
 
 dropwhile(Pred, State) ->
-    case queue_out(State) of
-        {empty, State1} ->
-            {undefined, a(State1)};
-        {{value, MsgStatus = #msg_status { msg_props = MsgProps }}, State1} ->
-            case Pred(MsgProps) of
-                true  -> {_, State2} = remove(false, MsgStatus, State1),
-                         dropwhile(Pred, State2);
-                false -> {MsgProps, a(in_r(MsgStatus, State1))}
-            end
-    end.
+    {MsgProps, State1} =
+        remove_by_predicate(Pred, State),
+    {MsgProps, a(State1)}.
 
 fetchwhile(Pred, Fun, Acc, State) ->
-    case queue_out(State) of
-        {empty, State1} ->
-            {undefined, Acc, a(State1)};
-        {{value, MsgStatus = #msg_status { msg_props = MsgProps }}, State1} ->
-            case Pred(MsgProps) of
-                true  -> {Msg, State2} = read_msg(MsgStatus, State1),
-                         {AckTag, State3} = remove(true, MsgStatus, State2),
-                         fetchwhile(Pred, Fun, Fun(Msg, AckTag, Acc), State3);
-                false -> {MsgProps, Acc, a(in_r(MsgStatus, State1))}
-            end
-    end.
+    {MsgProps, Acc1, State1} =
+         fetch_by_predicate(Pred, Fun, Acc, State),
+    {MsgProps, Acc1, a(State1)}.
 
 fetch(AckRequired, State) ->
     case queue_out(State) of
@@ -701,8 +681,7 @@ ack(AckTags, State) ->
                   {accumulate_ack(MsgStatus, Acc), State3}
           end, {accumulate_ack_init(), State}, AckTags),
     IndexState1 = rabbit_queue_index:ack(IndexOnDiskSeqIds, IndexState),
-    [ok = msg_store_remove(MSCState, IsPersistent, MsgIds)
-     || {IsPersistent, MsgIds} <- orddict:to_list(MsgIdsByStore)],
+    remove_msgs_by_id(MsgIdsByStore, MSCState),
     {lists:reverse(AllMsgIds),
      a(State1 #vqstate { index_state      = IndexState1,
                          ack_out_counter  = AckOutCount + length(AckTags) })}.
@@ -750,10 +729,8 @@ len(#vqstate { len = Len }) -> Len.
 
 is_empty(State) -> 0 == len(State).
 
-depth(State = #vqstate { ram_pending_ack  = RPA,
-                         disk_pending_ack = DPA,
-                         qi_pending_ack   = QPA }) ->
-    len(State) + gb_trees:size(RPA) + gb_trees:size(DPA) + gb_trees:size(QPA).
+depth(State) ->
+    len(State) + count_pending_acks(State).
 
 set_ram_duration_target(
   DurationTarget, State = #vqstate {
@@ -968,7 +945,7 @@ gb_sets_maybe_insert(false, _Val, Set) -> Set;
 gb_sets_maybe_insert(true,   Val, Set) -> gb_sets:add(Val, Set).
 
 msg_status(IsPersistent, IsDelivered, SeqId,
-           Msg = #basic_message {id = MsgId}, MsgProps) ->
+           Msg = #basic_message {id = MsgId}, MsgProps, IndexMaxSize) ->
     #msg_status{seq_id        = SeqId,
                 msg_id        = MsgId,
                 msg           = Msg,
@@ -976,7 +953,7 @@ msg_status(IsPersistent, IsDelivered, SeqId,
                 is_delivered  = IsDelivered,
                 msg_in_store  = false,
                 index_on_disk = false,
-                persist_to    = determine_persist_to(Msg, MsgProps),
+                persist_to    = determine_persist_to(Msg, MsgProps, IndexMaxSize),
                 msg_props     = MsgProps}.
 
 beta_msg_status({Msg = #basic_message{id = MsgId},
@@ -1068,7 +1045,7 @@ maybe_write_delivered(false, _SeqId, IndexState) ->
 maybe_write_delivered(true, SeqId, IndexState) ->
     rabbit_queue_index:deliver([SeqId], IndexState).
 
-betas_from_index_entries(List, TransientThreshold, RPA, DPA, QPA, IndexState) ->
+betas_from_index_entries(List, TransientThreshold, DelsAndAcksFun, State) ->
     {Filtered, Delivers, Acks, RamReadyCount, RamBytes} =
         lists:foldr(
           fun ({_MsgOrId, SeqId, _MsgProps, IsPersistent, IsDelivered} = M,
@@ -1080,9 +1057,7 @@ betas_from_index_entries(List, TransientThreshold, RPA, DPA, QPA, IndexState) ->
                       false -> MsgStatus = m(beta_msg_status(M)),
                                HaveMsg = msg_in_ram(MsgStatus),
                                Size = msg_size(MsgStatus),
-                               case (gb_trees:is_defined(SeqId, RPA) orelse
-                                     gb_trees:is_defined(SeqId, DPA) orelse
-                                     gb_trees:is_defined(SeqId, QPA)) of
+                               case is_msg_in_pending_acks(SeqId, State) of
                                    false -> {?QUEUE:in_r(MsgStatus, Filtered1),
                                              Delivers1, Acks1,
                                              RRC + one_if(HaveMsg),
@@ -1091,14 +1066,19 @@ betas_from_index_entries(List, TransientThreshold, RPA, DPA, QPA, IndexState) ->
                                end
                   end
           end, {?QUEUE:new(), [], [], 0, 0}, List),
-    {Filtered, RamReadyCount, RamBytes,
-     rabbit_queue_index:ack(
-       Acks, rabbit_queue_index:deliver(Delivers, IndexState))}.
+    {Filtered, RamReadyCount, RamBytes, DelsAndAcksFun(Delivers, Acks, State)}.
 %% [0] We don't increase RamBytes here, even though it pertains to
 %% unacked messages too, since if HaveMsg then the message must have
 %% been stored in the QI, thus the message must have been in
 %% qi_pending_ack, thus it must already have been in RAM.
 
+is_msg_in_pending_acks(SeqId, #vqstate { ram_pending_ack  = RPA,
+                                         disk_pending_ack = DPA,
+                                         qi_pending_ack   = QPA }) ->
+    (gb_trees:is_defined(SeqId, RPA) orelse
+     gb_trees:is_defined(SeqId, DPA) orelse
+     gb_trees:is_defined(SeqId, QPA)).
+
 expand_delta(SeqId, ?BLANK_DELTA_PATTERN(X)) ->
     d(#delta { start_seq_id = SeqId, count = 1, end_seq_id = SeqId + 1 });
 expand_delta(SeqId, #delta { start_seq_id = StartSeqId,
@@ -1135,6 +1115,11 @@ init(IsDurable, IndexState, DeltaCount, DeltaBytes, Terms,
                                     end_seq_id   = NextSeqId })
             end,
     Now = now(),
+    IoBatchSize = rabbit_misc:get_env(rabbit, msg_store_io_batch_size,
+                                      ?IO_BATCH_SIZE),
+
+    {ok, IndexMaxSize} = application:get_env(
+                           rabbit, queue_index_embed_msgs_below),
     State = #vqstate {
       q1                  = ?QUEUE:new(),
       q2                  = ?QUEUE:new(),
@@ -1149,6 +1134,7 @@ init(IsDurable, IndexState, DeltaCount, DeltaBytes, Terms,
       msg_store_clients   = {PersistentClient, TransientClient},
       durable             = IsDurable,
       transient_threshold = NextSeqId,
+      qi_embed_msgs_below = IndexMaxSize,
 
       len                 = DeltaCount1,
       persistent_count    = DeltaCount1,
@@ -1171,7 +1157,9 @@ init(IsDurable, IndexState, DeltaCount, DeltaBytes, Terms,
       ack_out_counter     = 0,
       ack_in_counter      = 0,
       disk_read_count     = 0,
-      disk_write_count    = 0 },
+      disk_write_count    = 0,
+
+      io_batch_size       = IoBatchSize },
     a(maybe_deltas_to_betas(State)).
 
 blank_rates(Now) ->
@@ -1268,68 +1256,223 @@ msg_size(#msg_status{msg_props = #message_properties{size = Size}}) -> Size.
 
 msg_in_ram(#msg_status{msg = Msg}) -> Msg =/= undefined.
 
-remove(AckRequired, MsgStatus = #msg_status {
-                      seq_id        = SeqId,
-                      msg_id        = MsgId,
-                      is_persistent = IsPersistent,
-                      is_delivered  = IsDelivered,
-                      msg_in_store  = MsgInStore,
-                      index_on_disk = IndexOnDisk },
+%% first param: AckRequired
+remove(true, MsgStatus = #msg_status {
+               seq_id        = SeqId,
+               is_delivered  = IsDelivered,
+               index_on_disk = IndexOnDisk },
+       State = #vqstate {out_counter       = OutCount,
+                         index_state       = IndexState}) ->
+    %% Mark it delivered if necessary
+    IndexState1 = maybe_write_delivered(
+                    IndexOnDisk andalso not IsDelivered,
+                    SeqId, IndexState),
+
+    State1 = record_pending_ack(
+               MsgStatus #msg_status {
+                 is_delivered = true }, State),
+
+    State2 = stats({-1, 1}, {MsgStatus, MsgStatus}, State1),
+
+    {SeqId, maybe_update_rates(
+              State2 #vqstate {out_counter = OutCount + 1,
+                               index_state = IndexState1})};
+
+%% This function body has the same behaviour as remove_queue_entries/3
+%% but instead of removing messages based on a ?QUEUE, this removes
+%% just one message, the one referenced by the MsgStatus provided.
+remove(false, MsgStatus = #msg_status {
+                seq_id        = SeqId,
+                msg_id        = MsgId,
+                is_persistent = IsPersistent,
+                is_delivered  = IsDelivered,
+                msg_in_store  = MsgInStore,
+                index_on_disk = IndexOnDisk },
        State = #vqstate {out_counter       = OutCount,
                          index_state       = IndexState,
                          msg_store_clients = MSCState}) ->
-    %% 1. Mark it delivered if necessary
+    %% Mark it delivered if necessary
     IndexState1 = maybe_write_delivered(
                     IndexOnDisk andalso not IsDelivered,
                     SeqId, IndexState),
 
-    %% 2. Remove from msg_store and queue index, if necessary
-    Rem = fun () ->
-                  ok = msg_store_remove(MSCState, IsPersistent, [MsgId])
-          end,
-    Ack = fun () -> rabbit_queue_index:ack([SeqId], IndexState1) end,
-    IndexState2 = case {AckRequired, MsgInStore, IndexOnDisk} of
-                      {false, true,  false} -> Rem(), IndexState1;
-                      {false, true,   true} -> Rem(), Ack();
-                      {false, false,  true} -> Ack();
-                      _                     -> IndexState1
-                  end,
+    %% Remove from msg_store and queue index, if necessary
+    case MsgInStore of
+        true  -> ok = msg_store_remove(MSCState, IsPersistent, [MsgId]);
+        false -> ok
+    end,
 
-    %% 3. If an ack is required, add something sensible to PA
-    {AckTag, State1} = case AckRequired of
-                           true  -> StateN = record_pending_ack(
-                                               MsgStatus #msg_status {
-                                                 is_delivered = true }, State),
-                                    {SeqId, StateN};
-                           false -> {undefined, State}
-                       end,
-    State2       = case AckRequired of
-                       false -> stats({-1, 0}, {MsgStatus, none},     State1);
-                       true  -> stats({-1, 1}, {MsgStatus, MsgStatus}, State1)
-                   end,
-    {AckTag, maybe_update_rates(
-               State2 #vqstate {out_counter = OutCount + 1,
-                                index_state = IndexState2})}.
-
-purge_betas_and_deltas(State = #vqstate { q3 = Q3 }) ->
+    IndexState2 =
+        case IndexOnDisk of
+            true  -> rabbit_queue_index:ack([SeqId], IndexState1);
+            false -> IndexState1
+        end,
+
+    State1 = stats({-1, 0}, {MsgStatus, none}, State),
+
+    {undefined, maybe_update_rates(
+                  State1 #vqstate {out_counter = OutCount + 1,
+                                   index_state = IndexState2})}.
+
+%% This function exists as a way to improve dropwhile/2
+%% performance. The idea of having this function is to optimise calls
+%% to rabbit_queue_index by batching delivers and acks, instead of
+%% sending them one by one.
+%%
+%% Instead of removing every message as their are popped from the
+%% queue, it first accumulates them and then removes them by calling
+%% remove_queue_entries/3, since the behaviour of
+%% remove_queue_entries/3 when used with
+%% process_delivers_and_acks_fun(deliver_and_ack) is the same as
+%% calling remove(false, MsgStatus, State).
+%%
+%% remove/3 also updates the out_counter in every call, but here we do
+%% it just once at the end.
+remove_by_predicate(Pred, State = #vqstate {out_counter = OutCount}) ->
+    {MsgProps, QAcc, State1} =
+        collect_by_predicate(Pred, ?QUEUE:new(), State),
+    State2 =
+        remove_queue_entries(
+          QAcc, process_delivers_and_acks_fun(deliver_and_ack), State1),
+    %% maybe_update_rates/1 is called in remove/2 for every
+    %% message. Since we update out_counter only once, we call it just
+    %% there.
+    {MsgProps, maybe_update_rates(
+                 State2 #vqstate {
+                   out_counter = OutCount + ?QUEUE:len(QAcc)})}.
+
+%% This function exists as a way to improve fetchwhile/4
+%% performance. The idea of having this function is to optimise calls
+%% to rabbit_queue_index by batching delivers, instead of sending them
+%% one by one.
+%%
+%% Fun is the function passed to fetchwhile/4 that's
+%% applied to every fetched message and used to build the fetchwhile/4
+%% result accumulator FetchAcc.
+fetch_by_predicate(Pred, Fun, FetchAcc,
+                   State = #vqstate {
+                              index_state = IndexState,
+                              out_counter = OutCount}) ->
+    {MsgProps, QAcc, State1} =
+        collect_by_predicate(Pred, ?QUEUE:new(), State),
+
+    {Delivers, FetchAcc1, State2} =
+        process_queue_entries(QAcc, Fun, FetchAcc, State1),
+
+    IndexState1 = rabbit_queue_index:deliver(Delivers, IndexState),
+
+    {MsgProps, FetchAcc1, maybe_update_rates(
+                            State2 #vqstate {
+                              index_state = IndexState1,
+                              out_counter = OutCount + ?QUEUE:len(QAcc)})}.
+
+%% We try to do here the same as what remove(true, State) does but
+%% processing several messages at the same time. The idea is to
+%% optimize rabbit_queue_index:deliver/2 calls by sending a list of
+%% SeqIds instead of one by one, thus process_queue_entries1 will
+%% accumulate the required deliveries, will record_pending_ack for
+%% each message, and will update stats, like remove/2 does.
+%%
+%% For the meaning of Fun and FetchAcc arguments see
+%% fetch_by_predicate/4 above.
+process_queue_entries(Q, Fun, FetchAcc, State) ->
+    ?QUEUE:foldl(fun (MsgStatus, Acc) ->
+                         process_queue_entries1(MsgStatus, Fun, Acc)
+                 end,
+                 {[], FetchAcc, State}, Q).
+
+process_queue_entries1(
+  #msg_status { seq_id = SeqId, is_delivered = IsDelivered,
+                index_on_disk = IndexOnDisk} = MsgStatus,
+  Fun,
+  {Delivers, FetchAcc, State}) ->
+    {Msg, State1} = read_msg(MsgStatus, State),
+    State2 = record_pending_ack(
+               MsgStatus #msg_status {
+                 is_delivered = true }, State1),
+    {cons_if(IndexOnDisk andalso not IsDelivered, SeqId, Delivers),
+     Fun(Msg, SeqId, FetchAcc),
+     stats({-1, 1}, {MsgStatus, MsgStatus}, State2)}.
+
+collect_by_predicate(Pred, QAcc, State) ->
+    case queue_out(State) of
+        {empty, State1} ->
+            {undefined, QAcc, State1};
+        {{value, MsgStatus = #msg_status { msg_props = MsgProps }}, State1} ->
+            case Pred(MsgProps) of
+                true  -> collect_by_predicate(Pred, ?QUEUE:in(MsgStatus, QAcc),
+                                              State1);
+                false -> {MsgProps, QAcc, in_r(MsgStatus, State1)}
+            end
+    end.
+
+%%----------------------------------------------------------------------------
+%% Helpers for Public API purge/1 function
+%%----------------------------------------------------------------------------
+
+%% The difference between purge_when_pending_acks/1
+%% vs. purge_and_index_reset/1 is that the first one issues a deliver
+%% and an ack to the queue index for every message that's being
+%% removed, while the later just resets the queue index state.
+purge_when_pending_acks(State) ->
+    State1 = purge1(process_delivers_and_acks_fun(deliver_and_ack), State),
+    a(State1).
+
+purge_and_index_reset(State) ->
+    State1 = purge1(process_delivers_and_acks_fun(none), State),
+    a(reset_qi_state(State1)).
+
+%% This function removes messages from each of {q1, q2, q3, q4}.
+%%
+%% With remove_queue_entries/3 q1 and q4 are emptied, while q2 and q3
+%% are specially handled by purge_betas_and_deltas/2.
+%%
+%% purge_betas_and_deltas/2 loads messages from the queue index,
+%% filling up q3 and in some cases moving messages form q2 to q3 while
+%% reseting q2 to an empty queue (see maybe_deltas_to_betas/2). The
+%% messages loaded into q3 are removed by calling
+%% remove_queue_entries/3 until there are no more messages to be read
+%% from the queue index. Messages are read in batches from the queue
+%% index.
+purge1(AfterFun, State = #vqstate { q4 = Q4}) ->
+    State1 = remove_queue_entries(Q4, AfterFun, State),
+
+    State2 = #vqstate {q1 = Q1} =
+        purge_betas_and_deltas(AfterFun, State1#vqstate{q4 = ?QUEUE:new()}),
+
+    State3 = remove_queue_entries(Q1, AfterFun, State2),
+
+    a(State3#vqstate{q1 = ?QUEUE:new()}).
+
+reset_qi_state(State = #vqstate{index_state = IndexState}) ->
+    State#vqstate{index_state =
+                         rabbit_queue_index:reset_state(IndexState)}.
+
+is_pending_ack_empty(State) ->
+    count_pending_acks(State) =:= 0.
+
+count_pending_acks(#vqstate { ram_pending_ack   = RPA,
+                              disk_pending_ack  = DPA,
+                              qi_pending_ack    = QPA }) ->
+    gb_trees:size(RPA) + gb_trees:size(DPA) + gb_trees:size(QPA).
+
+purge_betas_and_deltas(DelsAndAcksFun, State = #vqstate { q3 = Q3 }) ->
     case ?QUEUE:is_empty(Q3) of
         true  -> State;
-        false -> State1 = remove_queue_entries(Q3, State),
-                 purge_betas_and_deltas(maybe_deltas_to_betas(
+        false -> State1 = remove_queue_entries(Q3, DelsAndAcksFun, State),
+                 purge_betas_and_deltas(DelsAndAcksFun,
+                                        maybe_deltas_to_betas(
+                                          DelsAndAcksFun,
                                           State1#vqstate{q3 = ?QUEUE:new()}))
     end.
 
-remove_queue_entries(Q, State = #vqstate{index_state       = IndexState,
-                                         msg_store_clients = MSCState}) ->
+remove_queue_entries(Q, DelsAndAcksFun,
+                     State = #vqstate{msg_store_clients = MSCState}) ->
     {MsgIdsByStore, Delivers, Acks, State1} =
         ?QUEUE:foldl(fun remove_queue_entries1/2,
                      {orddict:new(), [], [], State}, Q),
-    ok = orddict:fold(fun (IsPersistent, MsgIds, ok) ->
-                              msg_store_remove(MSCState, IsPersistent, MsgIds)
-                      end, ok, MsgIdsByStore),
-    IndexState1 = rabbit_queue_index:ack(
-                    Acks, rabbit_queue_index:deliver(Delivers, IndexState)),
-    State1#vqstate{index_state = IndexState1}.
+    remove_msgs_by_id(MsgIdsByStore, MSCState),
+    DelsAndAcksFun(Delivers, Acks, State1).
 
 remove_queue_entries1(
   #msg_status { msg_id = MsgId, seq_id = SeqId, is_delivered = IsDelivered,
@@ -1344,6 +1487,18 @@ remove_queue_entries1(
      cons_if(IndexOnDisk, SeqId, Acks),
      stats({-1, 0}, {MsgStatus, none}, State)}.
 
+process_delivers_and_acks_fun(deliver_and_ack) ->
+    fun (Delivers, Acks, State = #vqstate { index_state = IndexState }) ->
+            IndexState1 =
+                rabbit_queue_index:ack(
+                  Acks, rabbit_queue_index:deliver(Delivers, IndexState)),
+            State #vqstate { index_state = IndexState1 }
+    end;
+process_delivers_and_acks_fun(_) ->
+    fun (_, _, State) ->
+            State
+    end.
+
 %%----------------------------------------------------------------------------
 %% Internal gubbins for publishing
 %%----------------------------------------------------------------------------
@@ -1367,6 +1522,43 @@ maybe_write_msg_to_disk(Force, MsgStatus = #msg_status {
 maybe_write_msg_to_disk(_Force, MsgStatus, State) ->
     {MsgStatus, State}.
 
+%% Due to certain optimizations made inside
+%% rabbit_queue_index:pre_publish/7 we need to have two separate
+%% functions for index persistence. This one is only used when paging
+%% during memory pressure. We didn't want to modify
+%% maybe_write_index_to_disk/3 because that function is used in other
+%% places.
+maybe_batch_write_index_to_disk(_Force,
+                                MsgStatus = #msg_status {
+                                  index_on_disk = true }, State) ->
+    {MsgStatus, State};
+maybe_batch_write_index_to_disk(Force,
+                                MsgStatus = #msg_status {
+                                  msg           = Msg,
+                                  msg_id        = MsgId,
+                                  seq_id        = SeqId,
+                                  is_persistent = IsPersistent,
+                                  is_delivered  = IsDelivered,
+                                  msg_props     = MsgProps},
+                                State = #vqstate {
+                                           target_ram_count = TargetRamCount,
+                                           disk_write_count = DiskWriteCount,
+                                           index_state      = IndexState})
+  when Force orelse IsPersistent ->
+    {MsgOrId, DiskWriteCount1} =
+        case persist_to(MsgStatus) of
+            msg_store   -> {MsgId, DiskWriteCount};
+            queue_index -> {prepare_to_store(Msg), DiskWriteCount + 1}
+        end,
+    IndexState1 = rabbit_queue_index:pre_publish(
+                    MsgOrId, SeqId, MsgProps, IsPersistent, IsDelivered,
+                    TargetRamCount, IndexState),
+    {MsgStatus#msg_status{index_on_disk = true},
+     State#vqstate{index_state      = IndexState1,
+                   disk_write_count = DiskWriteCount1}};
+maybe_batch_write_index_to_disk(_Force, MsgStatus, State) ->
+    {MsgStatus, State}.
+
 maybe_write_index_to_disk(_Force, MsgStatus = #msg_status {
                                     index_on_disk = true }, State) ->
     {MsgStatus, State};
@@ -1401,12 +1593,15 @@ maybe_write_to_disk(ForceMsg, ForceIndex, MsgStatus, State) ->
     {MsgStatus1, State1} = maybe_write_msg_to_disk(ForceMsg, MsgStatus, State),
     maybe_write_index_to_disk(ForceIndex, MsgStatus1, State1).
 
+maybe_prepare_write_to_disk(ForceMsg, ForceIndex, MsgStatus, State) ->
+    {MsgStatus1, State1} = maybe_write_msg_to_disk(ForceMsg, MsgStatus, State),
+    maybe_batch_write_index_to_disk(ForceIndex, MsgStatus1, State1).
+
 determine_persist_to(#basic_message{
                         content = #content{properties     = Props,
                                            properties_bin = PropsBin}},
-                     #message_properties{size = BodySize}) ->
-    {ok, IndexMaxSize} = application:get_env(
-                           rabbit, queue_index_embed_msgs_below),
+                     #message_properties{size = BodySize},
+                     IndexMaxSize) ->
     %% The >= is so that you can set the env to 0 and never persist
     %% to the index.
     %%
@@ -1498,11 +1693,29 @@ remove_pending_ack(false, SeqId, State = #vqstate{ram_pending_ack  = RPA,
     end.
 
 purge_pending_ack(KeepPersistent,
-                  State = #vqstate { ram_pending_ack   = RPA,
-                                     disk_pending_ack  = DPA,
-                                     qi_pending_ack    = QPA,
-                                     index_state       = IndexState,
+                  State = #vqstate { index_state       = IndexState,
                                      msg_store_clients = MSCState }) ->
+    {IndexOnDiskSeqIds, MsgIdsByStore, State1} = purge_pending_ack1(State),
+    case KeepPersistent of
+        true  -> remove_transient_msgs_by_id(MsgIdsByStore, MSCState),
+                 State1;
+        false -> IndexState1 =
+                     rabbit_queue_index:ack(IndexOnDiskSeqIds, IndexState),
+                 remove_msgs_by_id(MsgIdsByStore, MSCState),
+                 State1 #vqstate { index_state = IndexState1 }
+    end.
+
+purge_pending_ack_delete_and_terminate(
+  State = #vqstate { index_state       = IndexState,
+                     msg_store_clients = MSCState }) ->
+    {_, MsgIdsByStore, State1} = purge_pending_ack1(State),
+    IndexState1 = rabbit_queue_index:delete_and_terminate(IndexState),
+    remove_msgs_by_id(MsgIdsByStore, MSCState),
+    State1 #vqstate { index_state = IndexState1 }.
+
+purge_pending_ack1(State = #vqstate { ram_pending_ack   = RPA,
+                                      disk_pending_ack  = DPA,
+                                      qi_pending_ack    = QPA }) ->
     F = fun (_SeqId, MsgStatus, Acc) -> accumulate_ack(MsgStatus, Acc) end,
     {IndexOnDiskSeqIds, MsgIdsByStore, _AllMsgIds} =
         rabbit_misc:gb_trees_fold(
@@ -1512,19 +1725,26 @@ purge_pending_ack(KeepPersistent,
     State1 = State #vqstate { ram_pending_ack  = gb_trees:empty(),
                               disk_pending_ack = gb_trees:empty(),
                               qi_pending_ack   = gb_trees:empty()},
+    {IndexOnDiskSeqIds, MsgIdsByStore, State1}.
 
-    case KeepPersistent of
-        true  -> case orddict:find(false, MsgIdsByStore) of
-                     error        -> State1;
-                     {ok, MsgIds} -> ok = msg_store_remove(MSCState, false,
-                                                           MsgIds),
-                                    State1
-                 end;
-        false -> IndexState1 =
-                     rabbit_queue_index:ack(IndexOnDiskSeqIds, IndexState),
-                 [ok = msg_store_remove(MSCState, IsPersistent, MsgIds)
-                  || {IsPersistent, MsgIds} <- orddict:to_list(MsgIdsByStore)],
-                 State1 #vqstate { index_state = IndexState1 }
+%% MsgIdsByStore is an orddict with two keys:
+%%
+%% true: holds a list of Persistent Message Ids.
+%% false: holds a list of Transient Message Ids.
+%%
+%% When we call orddict:to_list/1 we get two sets of msg ids, where
+%% IsPersistent is either true for persistent messages or false for
+%% transient ones. The msg_store_remove/3 function takes this boolean
+%% flag to determine from which store the messages should be removed
+%% from.
+remove_msgs_by_id(MsgIdsByStore, MSCState) ->
+    [ok = msg_store_remove(MSCState, IsPersistent, MsgIds)
+     || {IsPersistent, MsgIds} <- orddict:to_list(MsgIdsByStore)].
+
+remove_transient_msgs_by_id(MsgIdsByStore, MSCState) ->
+    case orddict:find(false, MsgIdsByStore) of
+        error        -> ok;
+        {ok, MsgIds} -> ok = msg_store_remove(MSCState, false, MsgIds)
     end.
 
 accumulate_ack_init() -> {[], orddict:new(), []}.
@@ -1699,9 +1919,7 @@ next({delta, #delta{start_seq_id = SeqId,
 next({delta, Delta, [], State}, IndexState) ->
     next({delta, Delta, State}, IndexState);
 next({delta, Delta, [{_, SeqId, _, _, _} = M | Rest], State}, IndexState) ->
-    case (gb_trees:is_defined(SeqId, State#vqstate.ram_pending_ack) orelse
-          gb_trees:is_defined(SeqId, State#vqstate.disk_pending_ack) orelse
-          gb_trees:is_defined(SeqId, State#vqstate.qi_pending_ack)) of
+    case is_msg_in_pending_acks(SeqId, State) of
         false -> Next = {delta, Delta, Rest, State},
                  {value, beta_msg_status(M), false, Next, IndexState};
         true  -> next({delta, Delta, Rest, State}, IndexState)
@@ -1748,6 +1966,7 @@ reduce_memory_use(State = #vqstate {
                     ram_pending_ack  = RPA,
                     ram_msg_count    = RamMsgCount,
                     target_ram_count = TargetRamCount,
+                    io_batch_size    = IoBatchSize,
                     rates            = #rates { in      = AvgIngress,
                                                 out     = AvgEgress,
                                                 ack_in  = AvgAckIngress,
@@ -1773,31 +1992,35 @@ reduce_memory_use(State = #vqstate {
                   State2
         end,
 
-    case chunk_size(?QUEUE:len(Q2) + ?QUEUE:len(Q3),
-                    permitted_beta_count(State1)) of
-        S2 when S2 >= ?IO_BATCH_SIZE ->
-            %% There is an implicit, but subtle, upper bound here. We
-            %% may shuffle a lot of messages from Q2/3 into delta, but
-            %% the number of these that require any disk operation,
-            %% namely index writing, i.e. messages that are genuine
-            %% betas and not gammas, is bounded by the credit_flow
-            %% limiting of the alpha->beta conversion above.
-            push_betas_to_deltas(S2, State1);
-        _  ->
-            State1
-    end.
+    State3 =
+        case chunk_size(?QUEUE:len(Q2) + ?QUEUE:len(Q3),
+                        permitted_beta_count(State1)) of
+            S2 when S2 >= IoBatchSize ->
+                %% There is an implicit, but subtle, upper bound here. We
+                %% may shuffle a lot of messages from Q2/3 into delta, but
+                %% the number of these that require any disk operation,
+                %% namely index writing, i.e. messages that are genuine
+                %% betas and not gammas, is bounded by the credit_flow
+                %% limiting of the alpha->beta conversion above.
+                push_betas_to_deltas(S2, State1);
+            _  ->
+                State1
+        end,
+    %% See rabbitmq-server-290 for the reasons behind this GC call.
+    garbage_collect(),
+    State3.
 
 limit_ram_acks(0, State) ->
-    {0, State};
+    {0, ui(State)};
 limit_ram_acks(Quota, State = #vqstate { ram_pending_ack  = RPA,
                                          disk_pending_ack = DPA }) ->
     case gb_trees:is_empty(RPA) of
         true ->
-            {Quota, State};
+            {Quota, ui(State)};
         false ->
             {SeqId, MsgStatus, RPA1} = gb_trees:take_largest(RPA),
             {MsgStatus1, State1} =
-                maybe_write_to_disk(true, false, MsgStatus, State),
+                maybe_prepare_write_to_disk(true, false, MsgStatus, State),
             MsgStatus2 = m(trim_msg_status(MsgStatus1)),
             DPA1 = gb_trees:insert(SeqId, MsgStatus2, DPA),
             limit_ram_acks(Quota - 1,
@@ -1857,18 +2080,21 @@ fetch_from_q3(State = #vqstate { q1    = Q1,
             {loaded, {MsgStatus, State2}}
     end.
 
-maybe_deltas_to_betas(State = #vqstate { delta = ?BLANK_DELTA_PATTERN(X) }) ->
+maybe_deltas_to_betas(State) ->
+    AfterFun = process_delivers_and_acks_fun(deliver_and_ack),
+    maybe_deltas_to_betas(AfterFun, State).
+
+maybe_deltas_to_betas(_DelsAndAcksFun,
+                      State = #vqstate {delta = ?BLANK_DELTA_PATTERN(X) }) ->
     State;
-maybe_deltas_to_betas(State = #vqstate {
+maybe_deltas_to_betas(DelsAndAcksFun,
+                      State = #vqstate {
                         q2                   = Q2,
                         delta                = Delta,
                         q3                   = Q3,
                         index_state          = IndexState,
                         ram_msg_count        = RamMsgCount,
                         ram_bytes            = RamBytes,
-                        ram_pending_ack      = RPA,
-                        disk_pending_ack     = DPA,
-                        qi_pending_ack       = QPA,
                         disk_read_count      = DiskReadCount,
                         transient_threshold  = TransientThreshold }) ->
     #delta { start_seq_id = DeltaSeqId,
@@ -1879,19 +2105,20 @@ maybe_deltas_to_betas(State = #vqstate {
                    DeltaSeqIdEnd]),
     {List, IndexState1} = rabbit_queue_index:read(DeltaSeqId, DeltaSeqId1,
                                                   IndexState),
-    {Q3a, RamCountsInc, RamBytesInc, IndexState2} =
+    {Q3a, RamCountsInc, RamBytesInc, State1} =
         betas_from_index_entries(List, TransientThreshold,
-                                 RPA, DPA, QPA, IndexState1),
-    State1 = State #vqstate { index_state       = IndexState2,
-                              ram_msg_count     = RamMsgCount   + RamCountsInc,
-                              ram_bytes         = RamBytes      + RamBytesInc,
-                              disk_read_count   = DiskReadCount + RamCountsInc},
+                                 DelsAndAcksFun,
+                                 State #vqstate { index_state = IndexState1 }),
+    State2 = State1 #vqstate { ram_msg_count     = RamMsgCount   + RamCountsInc,
+                               ram_bytes         = RamBytes      + RamBytesInc,
+                               disk_read_count   = DiskReadCount + RamCountsInc },
     case ?QUEUE:len(Q3a) of
         0 ->
             %% we ignored every message in the segment due to it being
             %% transient and below the threshold
             maybe_deltas_to_betas(
-              State1 #vqstate {
+              DelsAndAcksFun,
+              State2 #vqstate {
                 delta = d(Delta #delta { start_seq_id = DeltaSeqId1 })});
         Q3aLen ->
             Q3b = ?QUEUE:join(Q3, Q3a),
@@ -1899,14 +2126,14 @@ maybe_deltas_to_betas(State = #vqstate {
                 0 ->
                     %% delta is now empty, but it wasn't before, so
                     %% can now join q2 onto q3
-                    State1 #vqstate { q2    = ?QUEUE:new(),
+                    State2 #vqstate { q2    = ?QUEUE:new(),
                                       delta = ?BLANK_DELTA,
                                       q3    = ?QUEUE:join(Q3b, Q2) };
                 N when N > 0 ->
                     Delta1 = d(#delta { start_seq_id = DeltaSeqId1,
                                         count        = N,
                                         end_seq_id   = DeltaSeqIdEnd }),
-                    State1 #vqstate { delta = Delta1,
+                    State2 #vqstate { delta = Delta1,
                                       q3    = Q3b }
             end
     end.
@@ -1935,16 +2162,21 @@ push_alphas_to_betas(_Generator, _Consumer, Quota, _Q,
   when Quota =:= 0 orelse
        TargetRamCount =:= infinity orelse
        TargetRamCount >= RamMsgCount ->
-    {Quota, State};
+    {Quota, ui(State)};
 push_alphas_to_betas(Generator, Consumer, Quota, Q, State) ->
+    %% We consume credits from the message_store whenever we need to
+    %% persist a message to disk. See:
+    %% rabbit_variable_queue:msg_store_write/4. So perhaps the
+    %% msg_store is trying to throttle down our queue.
     case credit_flow:blocked() of
-        true  -> {Quota, State};
+        true  -> {Quota, ui(State)};
         false -> case Generator(Q) of
                      {empty, _Q} ->
-                         {Quota, State};
+                         {Quota, ui(State)};
                      {{value, MsgStatus}, Qa} ->
                          {MsgStatus1, State1} =
-                             maybe_write_to_disk(true, false, MsgStatus, State),
+                             maybe_prepare_write_to_disk(true, false, MsgStatus,
+                                                         State),
                          MsgStatus2 = m(trim_msg_status(MsgStatus1)),
                          State2 = stats(
                                     ready0, {MsgStatus, MsgStatus2}, State1),
@@ -1985,24 +2217,31 @@ push_betas_to_deltas(Generator, LimitFun, Q, PushState) ->
             end
     end.
 
-push_betas_to_deltas1(_Generator, _Limit, Q, {0, _Delta, _State} = PushState) ->
-    {Q, PushState};
-push_betas_to_deltas1(Generator, Limit, Q, {Quota, Delta, State} = PushState) ->
+push_betas_to_deltas1(_Generator, _Limit, Q, {0, Delta, State}) ->
+    {Q, {0, Delta, ui(State)}};
+push_betas_to_deltas1(Generator, Limit, Q, {Quota, Delta, State}) ->
     case Generator(Q) of
         {empty, _Q} ->
-            {Q, PushState};
+            {Q, {Quota, Delta, ui(State)}};
         {{value, #msg_status { seq_id = SeqId }}, _Qa}
           when SeqId < Limit ->
-            {Q, PushState};
+            {Q, {Quota, Delta, ui(State)}};
         {{value, MsgStatus = #msg_status { seq_id = SeqId }}, Qa} ->
             {#msg_status { index_on_disk = true }, State1} =
-                maybe_write_index_to_disk(true, MsgStatus, State),
+                maybe_batch_write_index_to_disk(true, MsgStatus, State),
             State2 = stats(ready0, {MsgStatus, none}, State1),
             Delta1 = expand_delta(SeqId, Delta),
             push_betas_to_deltas1(Generator, Limit, Qa,
                                   {Quota - 1, Delta1, State2})
     end.
 
+%% Flushes queue index batch caches and updates queue index state.
+ui(#vqstate{index_state      = IndexState,
+            target_ram_count = TargetRamCount} = State) ->
+    IndexState1 = rabbit_queue_index:flush_pre_publish_cache(
+                    TargetRamCount, IndexState),
+    State#vqstate{index_state = IndexState1}.
+
 %%----------------------------------------------------------------------------
 %% Upgrading
 %%----------------------------------------------------------------------------
diff --git a/rabbitmq-server/src/ssl_compat.erl b/rabbitmq-server/src/ssl_compat.erl
new file mode 100644 (file)
index 0000000..fc83fbc
--- /dev/null
@@ -0,0 +1,75 @@
+%% The contents of this file are subject to the Mozilla Public License
+%% Version 1.1 (the "License"); you may not use this file except in
+%% compliance with the License. You may obtain a copy of the License
+%% at http://www.mozilla.org/MPL/
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and
+%% limitations under the License.
+%%
+%% The Original Code is RabbitMQ.
+%%
+%% The Initial Developer of the Original Code is GoPivotal, Inc.
+%% Copyright (c) 2007-2015 Pivotal Software, Inc.  All rights reserved.
+%%
+
+-module(ssl_compat).
+
+%% We don't want warnings about the use of erlang:now/0 in
+%% this module.
+-compile(nowarn_deprecated_function).
+
+-export([connection_information/1,
+         connection_information/2]).
+
+connection_information(SslSocket) ->
+    try
+        ssl:connection_information(SslSocket)
+    catch
+        error:undef ->
+            case ssl:connection_info(SslSocket) of
+                {ok, {ProtocolVersion, CipherSuite}} ->
+                    {ok, [{protocol, ProtocolVersion},
+                          {cipher_suite, CipherSuite}]};
+                {error, Reason} ->
+                    {error, Reason}
+            end
+    end.
+
+connection_information(SslSocket, Items) ->
+    try
+        ssl:connection_information(SslSocket, Items)
+    catch
+        error:undef ->
+            WantProtocolVersion = lists:member(protocol, Items),
+            WantCipherSuite = lists:member(cipher_suite, Items),
+            if
+                WantProtocolVersion orelse WantCipherSuite ->
+                    case ssl:connection_info(SslSocket) of
+                        {ok, {ProtocolVersion, CipherSuite}} ->
+                            filter_information_items(ProtocolVersion,
+                                                     CipherSuite,
+                                                     Items,
+                                                     []);
+                        {error, Reason} ->
+                            {error, Reason}
+                    end;
+                true ->
+                    {ok, []}
+            end
+    end.
+
+filter_information_items(ProtocolVersion, CipherSuite, [protocol | Rest],
+  Result) ->
+    filter_information_items(ProtocolVersion, CipherSuite, Rest,
+      [{protocol, ProtocolVersion} | Result]);
+filter_information_items(ProtocolVersion, CipherSuite, [cipher_suite | Rest],
+  Result) ->
+    filter_information_items(ProtocolVersion, CipherSuite, Rest,
+      [{cipher_suite, CipherSuite} | Result]);
+filter_information_items(ProtocolVersion, CipherSuite, [_ | Rest],
+  Result) ->
+    filter_information_items(ProtocolVersion, CipherSuite, Rest, Result);
+filter_information_items(_ProtocolVersion, _CipherSuite, [], Result) ->
+    {ok, lists:reverse(Result)}.
diff --git a/rabbitmq-server/src/time_compat.erl b/rabbitmq-server/src/time_compat.erl
new file mode 100644 (file)
index 0000000..b87c6cc
--- /dev/null
@@ -0,0 +1,305 @@
+%%
+%% %CopyrightBegin%
+%% 
+%% Copyright Ericsson AB 2014-2015. All Rights Reserved.
+%% 
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%%     http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%% 
+%% %CopyrightEnd%
+%%
+
+%%
+%% If your code need to be able to execute on ERTS versions both
+%% earlier and later than 7.0, the best approach is to use the new
+%% time API introduced in ERTS 7.0 and implement a fallback
+%% solution using the old primitives to be used on old ERTS
+%% versions. This way your code can automatically take advantage
+%% of the improvements in the API when available. This is an
+%% example of how to implement such an API, but it can be used
+%% as is if you want to. Just add (a preferrably renamed version of)
+%% this module to your project, and call the API via this module
+%% instead of calling the BIFs directly.
+%%
+
+-module(time_compat).
+
+%% We don't want warnings about the use of erlang:now/0 in
+%% this module.
+-compile(nowarn_deprecated_function).
+%%
+%% We don't use
+%%   -compile({nowarn_deprecated_function, [{erlang, now, 0}]}).
+%% since this will produce warnings when compiled on systems
+%% where it has not yet been deprecated.
+%%
+
+-export([monotonic_time/0,
+        monotonic_time/1,
+        erlang_system_time/0,
+        erlang_system_time/1,
+        os_system_time/0,
+        os_system_time/1,
+        time_offset/0,
+        time_offset/1,
+        convert_time_unit/3,
+        timestamp/0,
+        unique_integer/0,
+        unique_integer/1,
+        monitor/2,
+        system_info/1,
+        system_flag/2]).
+
+monotonic_time() ->
+    try
+       erlang:monotonic_time()
+    catch
+       error:undef ->
+           %% Use Erlang system time as monotonic time
+           erlang_system_time_fallback()
+    end.
+
+monotonic_time(Unit) ->
+    try
+       erlang:monotonic_time(Unit)
+    catch
+       error:badarg ->
+           erlang:error(badarg, [Unit]);
+       error:undef ->
+           %% Use Erlang system time as monotonic time
+           STime = erlang_system_time_fallback(),
+           try
+               convert_time_unit_fallback(STime, native, Unit)
+           catch
+               error:bad_time_unit -> erlang:error(badarg, [Unit])
+           end
+    end.
+
+erlang_system_time() ->
+    try
+       erlang:system_time()
+    catch
+       error:undef ->
+           erlang_system_time_fallback()
+    end.
+
+erlang_system_time(Unit) ->
+    try
+       erlang:system_time(Unit)
+    catch
+       error:badarg ->
+           erlang:error(badarg, [Unit]);
+       error:undef ->
+           STime = erlang_system_time_fallback(),
+           try
+               convert_time_unit_fallback(STime, native, Unit)
+           catch
+               error:bad_time_unit -> erlang:error(badarg, [Unit])
+           end
+    end.
+
+os_system_time() ->
+    try
+       os:system_time()
+    catch
+       error:undef ->
+           os_system_time_fallback()
+    end.
+
+os_system_time(Unit) ->
+    try
+       os:system_time(Unit)
+    catch
+       error:badarg ->
+           erlang:error(badarg, [Unit]);
+       error:undef ->
+           STime = os_system_time_fallback(),
+           try
+               convert_time_unit_fallback(STime, native, Unit)
+           catch
+               error:bad_time_unit -> erlang:error(badarg, [Unit])
+           end
+    end.
+
+time_offset() ->
+    try
+       erlang:time_offset()
+    catch
+       error:undef ->
+           %% Erlang system time and Erlang monotonic
+           %% time are always aligned
+           0
+    end.
+
+time_offset(Unit) ->
+    try
+       erlang:time_offset(Unit)
+    catch
+       error:badarg ->
+           erlang:error(badarg, [Unit]);
+       error:undef ->
+           try
+               _ = integer_time_unit(Unit)
+           catch
+               error:bad_time_unit -> erlang:error(badarg, [Unit])
+           end,
+           %% Erlang system time and Erlang monotonic
+           %% time are always aligned
+           0
+    end.
+
+convert_time_unit(Time, FromUnit, ToUnit) ->
+    try
+       erlang:convert_time_unit(Time, FromUnit, ToUnit)
+    catch
+       error:undef ->
+           try
+               convert_time_unit_fallback(Time, FromUnit, ToUnit)
+           catch
+               _:_ ->
+                   erlang:error(badarg, [Time, FromUnit, ToUnit])
+           end;
+       error:Error ->
+           erlang:error(Error, [Time, FromUnit, ToUnit])
+    end.
+
+timestamp() ->
+    try
+       erlang:timestamp()
+    catch
+       error:undef ->
+           erlang:now()
+    end.
+
+unique_integer() ->
+    try
+       erlang:unique_integer()
+    catch
+       error:undef ->
+           {MS, S, US} = erlang:now(),
+           (MS*1000000+S)*1000000+US
+    end.
+
+unique_integer(Modifiers) ->
+    try
+       erlang:unique_integer(Modifiers)
+    catch
+       error:badarg ->
+           erlang:error(badarg, [Modifiers]);
+       error:undef ->
+           case is_valid_modifier_list(Modifiers) of
+               true ->
+                   %% now() converted to an integer
+                   %% fullfill the requirements of
+                   %% all modifiers: unique, positive,
+                   %% and monotonic...
+                   {MS, S, US} = erlang:now(),
+                   (MS*1000000+S)*1000000+US;
+               false ->
+                   erlang:error(badarg, [Modifiers])
+           end
+    end.
+
+monitor(Type, Item) ->
+    try
+       erlang:monitor(Type, Item)
+    catch
+       error:Error ->
+           case {Error, Type, Item} of
+               {badarg, time_offset, clock_service} ->
+                   %% Time offset is final and will never change.
+                   %% Return a dummy reference, there will never
+                   %% be any need for 'CHANGE' messages...
+                   make_ref();
+               _ ->
+                   erlang:error(Error, [Type, Item])
+           end
+    end.
+
+system_info(Item) ->
+    try
+       erlang:system_info(Item)
+    catch
+       error:badarg ->
+           case Item of
+               time_correction ->
+                   case erlang:system_info(tolerant_timeofday) of
+                       enabled -> true;
+                       disabled -> false
+                   end;
+               time_warp_mode ->
+                   no_time_warp;
+               time_offset ->
+                   final;
+               NotSupArg when NotSupArg == os_monotonic_time_source;
+                              NotSupArg == os_system_time_source;
+                              NotSupArg == start_time;
+                              NotSupArg == end_time ->
+                   %% Cannot emulate this...
+                   erlang:error(notsup, [NotSupArg]);
+               _ ->
+                   erlang:error(badarg, [Item])
+           end;
+       error:Error ->
+           erlang:error(Error, [Item])
+    end.
+
+system_flag(Flag, Value) ->
+    try
+       erlang:system_flag(Flag, Value)
+    catch
+       error:Error ->
+           case {Error, Flag, Value} of
+               {badarg, time_offset, finalize} ->
+                   %% Time offset is final
+                   final;
+               _ ->
+                   erlang:error(Error, [Flag, Value])
+           end
+    end.
+
+%%
+%% Internal functions
+%%
+
+integer_time_unit(native) -> 1000*1000;
+integer_time_unit(nano_seconds) -> 1000*1000*1000;
+integer_time_unit(micro_seconds) -> 1000*1000;
+integer_time_unit(milli_seconds) -> 1000;
+integer_time_unit(seconds) -> 1;
+integer_time_unit(I) when is_integer(I), I > 0 -> I;
+integer_time_unit(BadRes) -> erlang:error(bad_time_unit, [BadRes]).
+
+erlang_system_time_fallback() ->
+    {MS, S, US} = erlang:now(),
+    (MS*1000000+S)*1000000+US.
+
+os_system_time_fallback() ->
+    {MS, S, US} = os:timestamp(),
+    (MS*1000000+S)*1000000+US.
+
+convert_time_unit_fallback(Time, FromUnit, ToUnit) ->
+    FU = integer_time_unit(FromUnit),
+    TU = integer_time_unit(ToUnit),
+    case Time < 0 of
+       true -> TU*Time - (FU - 1);
+       false -> TU*Time
+    end div FU.
+
+is_valid_modifier_list([positive|Ms]) ->
+    is_valid_modifier_list(Ms);
+is_valid_modifier_list([monotonic|Ms]) ->
+    is_valid_modifier_list(Ms);
+is_valid_modifier_list([]) ->
+    true;
+is_valid_modifier_list(_) ->
+    false.
index 304518bc5eff85c6ce9021dbeefcbf63a26f79ab..bf9a77c174e5aaf386959e38490659a045984748 100644 (file)
@@ -167,6 +167,15 @@ code_change(_OldVsn, State, _Extra) ->
 %%----------------------------------------------------------------------------
 
 set_mem_limits(State, MemFraction) ->
+    case erlang:system_info(wordsize) of
+        4 ->
+            error_logger:warning_msg(
+              "You are using a 32-bit version of Erlang: you may run into "
+              "memory address~n"
+              "space exhaustion or statistic counters overflow.~n");
+        _ ->
+            ok
+    end,
     TotalMemory =
         case get_total_memory() of
             unknown ->
index fe6e347c1a0f8637d0d3132b2aa9bbfb649d97ab..cc5e40294721322b8bdc0ba91083d52a0ecea033 100644 (file)
@@ -1 +1 @@
-VERSION?=3.5.4
+VERSION?=3.5.6