From: Alexey Lebedeff Date: Thu, 10 Dec 2015 15:19:57 +0000 (+0300) Subject: Build rabbitmq 3.5.6 for ubuntu X-Git-Tag: mos-9.0~6 X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=686c3b2fc3ca79fb5c0c0e53cec63c315ea983cb;p=packages%2Ftrusty%2Frabbitmq-server.git Build rabbitmq 3.5.6 for ubuntu 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 --- diff --git a/debian/LICENSE.head b/debian/LICENSE.head deleted file mode 100644 index 2b5a17e..0000000 --- a/debian/LICENSE.head +++ /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 index 7858a04..0000000 --- a/debian/LICENSE.tail +++ /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 index 0a29ee2..0000000 --- a/debian/README +++ /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. diff --git a/debian/changelog b/debian/changelog index 31751f9..993b354 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,360 +1,475 @@ -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 Thu, 07 Aug 2015 22:03:00 +0300 + -- Alexey Lebedeff 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 Thu, 06 Aug 2015 23:00:41 +0200 + -- James Page 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 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 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 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 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 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 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 Wed, 28 Jan 2015 17:48:06 +0300 + * New upstream point release. -rabbitmq-server (3.3.5-1) unstable; urgency=low + -- James Page 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 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 Wed, 28 Jan 2015 13:11:02 +0000 - * New Upstream Release +rabbitmq-server (3.4.2-3) unstable; urgency=medium - -- Simon MacMullen 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 Tue, 27 Jan 2015 15:08:08 +0100 - * New Upstream Release +rabbitmq-server (3.4.2-2) unstable; urgency=medium - -- Simon MacMullen 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 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 Fri, 19 Dec 2014 11:09:20 +0000 + +rabbitmq-server (3.4.1-1) unstable; urgency=high + + * New upstream release. + + -- Blair Hester 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 Tue, 12 Aug 2014 11:47:14 +0100 - -- Simon MacMullen Mon, 09 Jun 2014 10:25:22 +0100 +rabbitmq-server (3.3.4-1) unstable; urgency=low + + * New upstream release + + -- Emile Joubert Tue, 24 Jun 2014 18:00:48 +0100 + +rabbitmq-server (3.3.3-1) unstable; urgency=low + + * New upstream release + + -- Emile Joubert 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 Tue, 29 Apr 2014 11:49:23 +0100 + -- Emile Joubert 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 Wed, 02 Apr 2014 14:23:14 +0100 + -- Emile Joubert 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 Mon, 03 Mar 2014 14:50:18 +0000 + -- Thomas Goirand 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 Thu, 10 Jul 2014 14:01:02 +0400 + -- Emile Joubert 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 Thu, 10 Jul 2014 14:00:41 +0400 + -- Emile Joubert 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 Wed, 11 Dec 2013 17:31:14 +0000 + +rabbitmq-server (3.2.1-1) unstable; urgency=low + + * New upstream release - -- Emile Joubert Tue, 10 Dec 2013 16:08:08 +0000 + -- Emile Joubert 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 Wed, 23 Oct 2013 12:44:10 +0100 + -- Emile Joubert 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 Thu, 15 Aug 2013 11:03:13 +0100 + -- Emile Joubert 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 Tue, 25 Jun 2013 15:01:12 +0100 + -- Emile Joubert 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 Mon, 24 Jun 2013 11:16:41 +0100 + -- Emile Joubert Thu, 25 Jun 2013 11:28:52 +0100 rabbitmq-server (3.1.1-1) unstable; urgency=low - * Test release + * New upstream release - -- Tim Watson Mon, 20 May 2013 16:21:20 +0100 + -- Emile Joubert 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 Thu, 02 May 2013 11:19:31 +0100 + +rabbitmq-server (3.0.4-1) unstable; urgency=low + + * New upstream release + + -- Emile Joubert Wed, 13 Mar 2013 10:53:18 +0000 + +rabbitmq-server (3.0.4-1) unstable; urgency=low + + * New upstream release + + -- Emile Joubert Wed, 13 Mar 2013 10:53:18 +0000 + +rabbitmq-server (3.0.3-1) unstable; urgency=low + + * New upstream release + + -- Emile Joubert Thu, 07 Mar 2013 10:03:31 +0000 - -- Simon MacMullen Wed, 01 May 2013 11:57:58 +0100 +rabbitmq-server (3.0.2-1) unstable; urgency=low + + * New upstream release + + -- Emile Joubert 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 Tue, 11 Dec 2012 11:29:55 +0000 + -- Emile Joubert 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 Fri, 16 Nov 2012 14:15:29 +0000 + -- Emile Joubert 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 Fri, 16 Dec 2011 12:12:36 +0000 + -- Emile Joubert 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 Tue, 08 Nov 2011 16:47:50 +0000 + -- Emile Joubert 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 Fri, 09 Sep 2011 14:38:45 +0100 + -- Emile Joubert 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 Fri, 26 Aug 2011 16:29:40 +0100 + -- Emile Joubert 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 Mon, 27 Jun 2011 11:21:49 +0100 + -- Emile Joubert 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 - -- Thu, 09 Jun 2011 07:20:29 -0700 + -- Emile Joubert 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 Thu, 07 Apr 2011 16:49:22 +0100 + -- Emile Joubert 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 Tue, 22 Mar 2011 17:34:31 +0000 + -- Emile Joubert 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 Thu, 03 Feb 2011 12:43:56 +0000 + -- Emile Joubert 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 Tue, 01 Feb 2011 12:52:16 +0000 + -- John Leuner 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 Mon, 29 Nov 2010 12:24:48 +0000 + -- John Leuner 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 Tue, 19 Oct 2010 17:20:10 +0100 + -- John Leuner 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 Tue, 14 Sep 2010 14:20:17 +0100 + -- John Leuner 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 Mon, 23 Aug 2010 14:55:39 +0100 + -- John Leuner 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 Wed, 14 Jul 2010 15:05:24 +0100 + -- John Leuner 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 Tue, 15 Jun 2010 12:48:48 +0100 + -- John Leuner 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 Mon, 15 Feb 2010 15:54:47 +0000 + -- John Leuner 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 Fri, 22 Jan 2010 14:14:29 +0000 + -- John Leuner 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 Mon, 05 Oct 2009 13:44:41 +0100 + -- John Leuner 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 Tue, 16 Jun 2009 15:02:58 +0100 + -- John Leuner 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 Tue, 19 May 2009 09:57:54 +0100 + -- John Leuner 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 Mon, 06 Apr 2009 09:19:32 +0100 + -- John Leuner 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 Tue, 24 Feb 2009 18:23:33 +0000 + -- John Leuner 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 Mon, 23 Feb 2009 16:03:38 +0000 + -- John Leuner 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 Mon, 19 Jan 2009 15:46:13 +0000 + -- John Leuner 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 Wed, 17 Dec 2008 18:23:47 +0000 + -- John Leuner 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 Thu, 24 Jul 2008 13:21:48 +0100 + -- John Leuner 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 Mon, 03 Mar 2008 15:34:38 +0000 + -- John Leuner 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 Fri, 05 Oct 2007 11:55:00 +0100 + -- John Leuner 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 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 Wed, 26 Sep 2007 11:49:26 +0100 + -- John Leuner 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 Wed, 29 Aug 2007 12:03:15 +0100 + -- John Leuner 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 Thu, 02 Aug 2007 11:27:13 +0100 + -- John Leuner 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 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 Fri, 20 Jul 2007 18:17:33 +0100 + -- John Leuner 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 Wed, 31 Jan 2007 19:06:33 +0000 + -- John Leuner 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 Wed, 17 Dec 2008 18:23:47 +0000 diff --git a/debian/compat b/debian/compat index 45a4fb7..ec63514 100644 --- a/debian/compat +++ b/debian/compat @@ -1 +1 @@ -8 +9 diff --git a/debian/control b/debian/control index 944fae4..dd61545 100644 --- a/debian/control +++ b/debian/control @@ -1,16 +1,30 @@ Source: rabbitmq-server Section: net Priority: extra -Maintainer: MOS Linux team -XSBC-Orig-Maintainer: RabbitMQ Team -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 +Uploaders: James Page , Thomas Goirand +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/ diff --git a/debian/copyright b/debian/copyright index e384a7c..3ce58ff 100644 --- a/debian/copyright +++ b/debian/copyright @@ -1,567 +1,564 @@ -This package was debianized by Tony Garnock-Jones 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 + (c) 2014, Blair Hester + (c) 2012-2014, Emile Joubert + (c) 2008-2012, John Leuner + (c) 2014, James Page + (c) 2014, Thomas Goirand +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 index 625b7d4..0000000 --- a/debian/dirs +++ /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 index 0000000..ee339ed --- /dev/null +++ b/debian/gbp.conf @@ -0,0 +1,6 @@ +[DEFAULT] +debian-branch = master +pristine-tar = True + +[buildpackage] +export-dir = ../build-area/ diff --git a/debian/rabbitmq-server.ocf b/debian/ocf/rabbitmq-server old mode 100644 new mode 100755 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 index 0000000..bebe2ab --- /dev/null +++ b/debian/rabbitmq-env.conf @@ -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 diff --git a/debian/rabbitmq-script-wrapper b/debian/rabbitmq-script-wrapper old mode 100644 new mode 100755 index 4fecc2e..a622ae2 --- a/debian/rabbitmq-script-wrapper +++ b/debian/rabbitmq-script-wrapper @@ -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 index 0000000..cdf53e5 --- /dev/null +++ b/debian/rabbitmq-server-wait @@ -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_) +# Non-empty defaults should be set in rabbitmq-env +. `dirname $0`/rabbitmq-env + +/usr/lib/rabbitmq/bin/rabbitmqctl wait $RABBITMQ_PID_FILE diff --git a/debian/rabbitmq-server.default b/debian/rabbitmq-server.default index 1efb356..3eebe2f 100644 --- a/debian/rabbitmq-server.default +++ b/debian/rabbitmq-server.default @@ -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 index 0000000..e6127a0 --- /dev/null +++ b/debian/rabbitmq-server.dirs @@ -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 index 0000000..902f3dd --- /dev/null +++ b/debian/rabbitmq-server.install @@ -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 index 0000000..0bfa1c5 --- /dev/null +++ b/debian/rabbitmq-server.links @@ -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/postinst b/debian/rabbitmq-server.postinst similarity index 100% rename from debian/postinst rename to debian/rabbitmq-server.postinst diff --git a/debian/postrm.in b/debian/rabbitmq-server.postrm similarity index 100% rename from debian/postrm.in rename to debian/rabbitmq-server.postrm diff --git a/debian/rabbitmq-server.service b/debian/rabbitmq-server.service new file mode 100644 index 0000000..faa73c1 --- /dev/null +++ b/debian/rabbitmq-server.service @@ -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 diff --git a/debian/rules b/debian/rules old mode 100644 new mode 100755 index cac29c8..bee4e81 --- a/debian/rules +++ b/debian/rules @@ -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 - 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 diff --git a/debian/watch b/debian/watch index b41aff9..e41153d 100644 --- a/debian/watch +++ b/debian/watch @@ -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 diff --git a/rabbitmq-server/Makefile b/rabbitmq-server/Makefile index 1c98001..c2cae4a 100644 --- a/rabbitmq-server/Makefile +++ b/rabbitmq-server/Makefile @@ -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=. diff --git a/rabbitmq-server/codegen.py b/rabbitmq-server/codegen.py index 9f16b32..fbc6f61 100644 --- a/rabbitmq-server/codegen.py +++ b/rabbitmq-server/codegen.py @@ -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. %%""" diff --git a/rabbitmq-server/codegen/Makefile b/rabbitmq-server/codegen/Makefile index 8c3bfa9..8e028c8 100644 --- a/rabbitmq-server/codegen/Makefile +++ b/rabbitmq-server/codegen/Makefile @@ -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 diff --git a/rabbitmq-server/ebin/rabbit_app.in b/rabbitmq-server/ebin/rabbit_app.in index df58ba3..bd4a9f3 100644 --- a/rabbitmq-server/ebin/rabbit_app.in +++ b/rabbitmq-server/ebin/rabbit_app.in @@ -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, @@ -26,9 +26,11 @@ %% 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">>}, @@ -81,5 +83,16 @@ 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}} ]}]}. diff --git a/rabbitmq-server/include/gm_specs.hrl b/rabbitmq-server/include/gm_specs.hrl index 5a98e70..bc20b44 100644 --- a/rabbitmq-server/include/gm_specs.hrl +++ b/rabbitmq-server/include/gm_specs.hrl @@ -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. %% diff --git a/rabbitmq-server/include/rabbit.hrl b/rabbitmq-server/include/rabbit.hrl index ddcfd6a..5b90956 100644 --- a/rabbitmq-server/include/rabbit.hrl +++ b/rabbitmq-server/include/rabbit.hrl @@ -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. %% @@ -122,6 +122,10 @@ -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">>]). diff --git a/rabbitmq-server/include/rabbit_cli.hrl b/rabbitmq-server/include/rabbit_cli.hrl index 1bffc9a..737bb4e 100644 --- a/rabbitmq-server/include/rabbit_cli.hrl +++ b/rabbitmq-server/include/rabbit_cli.hrl @@ -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. %% diff --git a/rabbitmq-server/include/rabbit_msg_store.hrl b/rabbitmq-server/include/rabbit_msg_store.hrl index 803ed6b..8bcf2ce 100644 --- a/rabbitmq-server/include/rabbit_msg_store.hrl +++ b/rabbitmq-server/include/rabbit_msg_store.hrl @@ -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. %% diff --git a/rabbitmq-server/plugins-src/rabbitmq-amqp1.0/src/rabbit_amqp1_0_reader.erl b/rabbitmq-server/plugins-src/rabbitmq-amqp1.0/src/rabbit_amqp1_0_reader.erl index fbff350..06664ff 100644 --- a/rabbitmq-server/plugins-src/rabbitmq-amqp1.0/src/rabbit_amqp1_0_reader.erl +++ b/rabbitmq-server/plugins-src/rabbitmq-amqp1.0/src/rabbit_amqp1_0_reader.erl @@ -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) -> diff --git a/rabbitmq-server/plugins-src/rabbitmq-amqp1.0/src/rabbit_amqp1_0_writer.erl b/rabbitmq-server/plugins-src/rabbitmq-amqp1.0/src/rabbit_amqp1_0_writer.erl index 846f7a1..399e4e4 100644 --- a/rabbitmq-server/plugins-src/rabbitmq-amqp1.0/src/rabbit_amqp1_0_writer.erl +++ b/rabbitmq-server/plugins-src/rabbitmq-amqp1.0/src/rabbit_amqp1_0_writer.erl @@ -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 index 0000000..6b022a8 --- /dev/null +++ b/rabbitmq-server/plugins-src/rabbitmq-auth-backend-ldap/.travis.yml @@ -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 diff --git a/rabbitmq-server/plugins-src/rabbitmq-auth-backend-ldap/etc/rabbit-test.config b/rabbitmq-server/plugins-src/rabbitmq-auth-backend-ldap/etc/rabbit-test.config index 9b8e69d..b65d9c4 100644 --- a/rabbitmq-server/plugins-src/rabbitmq-auth-backend-ldap/etc/rabbit-test.config +++ b/rabbitmq-server/plugins-src/rabbitmq-auth-backend-ldap/etc/rabbit-test.config @@ -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}}]} ]} ]. diff --git a/rabbitmq-server/plugins-src/rabbitmq-auth-backend-ldap/src/rabbit_auth_backend_ldap.erl b/rabbitmq-server/plugins-src/rabbitmq-auth-backend-ldap/src/rabbit_auth_backend_ldap.erl index 943ac55..7a7e91f 100644 --- a/rabbitmq-server/plugins-src/rabbitmq-auth-backend-ldap/src/rabbit_auth_backend_ldap.erl +++ b/rabbitmq-server/plugins-src/rabbitmq-auth-backend-ldap/src/rabbit_auth_backend_ldap.erl @@ -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, diff --git a/rabbitmq-server/plugins-src/rabbitmq-auth-backend-ldap/test/src/rabbit_auth_backend_ldap_test.erl b/rabbitmq-server/plugins-src/rabbitmq-auth-backend-ldap/test/src/rabbit_auth_backend_ldap_test.erl index 2b92632..c340d68 100644 --- a/rabbitmq-server/plugins-src/rabbitmq-auth-backend-ldap/test/src/rabbit_auth_backend_ldap_test.erl +++ b/rabbitmq-server/plugins-src/rabbitmq-auth-backend-ldap/test/src/rabbit_auth_backend_ldap_test.erl @@ -19,17 +19,79 @@ -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 index 0000000..09fbd63 --- /dev/null +++ b/rabbitmq-server/plugins-src/rabbitmq-consistent-hash-exchange/.travis.yml @@ -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 diff --git a/rabbitmq-server/plugins-src/rabbitmq-consistent-hash-exchange/src/rabbit_exchange_type_consistent_hash.erl b/rabbitmq-server/plugins-src/rabbitmq-consistent-hash-exchange/src/rabbit_exchange_type_consistent_hash.erl index 68e3253..36b4cf4 100644 --- a/rabbitmq-server/plugins-src/rabbitmq-consistent-hash-exchange/src/rabbit_exchange_type_consistent_hash.erl +++ b/rabbitmq-server/plugins-src/rabbitmq-consistent-hash-exchange/src/rabbit_exchange_type_consistent_hash.erl @@ -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. diff --git a/rabbitmq-server/plugins-src/rabbitmq-consistent-hash-exchange/test/src/rabbit_exchange_type_consistent_hash_test.erl b/rabbitmq-server/plugins-src/rabbitmq-consistent-hash-exchange/test/src/rabbit_exchange_type_consistent_hash_test.erl index 702fdb4..9bb619d 100644 --- a/rabbitmq-server/plugins-src/rabbitmq-consistent-hash-exchange/test/src/rabbit_exchange_type_consistent_hash_test.erl +++ b/rabbitmq-server/plugins-src/rabbitmq-consistent-hash-exchange/test/src/rabbit_exchange_type_consistent_hash_test.erl @@ -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. diff --git a/rabbitmq-server/plugins-src/rabbitmq-erlang-client/rabbit_common.app.in b/rabbitmq-server/plugins-src/rabbitmq-erlang-client/rabbit_common.app.in index 46b2a4d..930e232 100644 --- a/rabbitmq-server/plugins-src/rabbitmq-erlang-client/rabbit_common.app.in +++ b/rabbitmq-server/plugins-src/rabbitmq-erlang-client/rabbit_common.app.in @@ -37,7 +37,9 @@ rabbit_queue_collector, rabbit_queue_decorator, rabbit_amqqueue, - supervisor2 + ssl_compat, + supervisor2, + time_compat ]}, {registered, []}, {env, []}, diff --git a/rabbitmq-server/plugins-src/rabbitmq-federation-management/priv/www/js/federation.js b/rabbitmq-server/plugins-src/rabbitmq-federation-management/priv/www/js/federation.js index 7110ea2..c989072 100644 --- a/rabbitmq-server/plugins-src/rabbitmq-federation-management/priv/www/js/federation.js +++ b/rabbitmq-server/plugins-src/rabbitmq-federation-management/priv/www/js/federation.js @@ -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'] = '
\ diff --git a/rabbitmq-server/plugins-src/rabbitmq-federation/README b/rabbitmq-server/plugins-src/rabbitmq-federation/README deleted file mode 100644 index 250b42a..0000000 --- a/rabbitmq-server/plugins-src/rabbitmq-federation/README +++ /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 index 0000000..e7d8c0e --- /dev/null +++ b/rabbitmq-server/plugins-src/rabbitmq-federation/README.md @@ -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. diff --git a/rabbitmq-server/plugins-src/rabbitmq-federation/src/rabbit_federation_queue_link.erl b/rabbitmq-server/plugins-src/rabbitmq-federation/src/rabbit_federation_queue_link.erl index 4dd7810..e498f76 100644 --- a/rabbitmq-server/plugins-src/rabbitmq-federation/src/rabbit_federation_queue_link.erl +++ b/rabbitmq-server/plugins-src/rabbitmq-federation/src/rabbit_federation_queue_link.erl @@ -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">>; diff --git a/rabbitmq-server/plugins-src/rabbitmq-federation/src/rabbit_federation_upstream.erl b/rabbitmq-server/plugins-src/rabbitmq-federation/src/rabbit_federation_upstream.erl index 398dbcf..ae4c512 100644 --- a/rabbitmq-server/plugins-src/rabbitmq-federation/src/rabbit_federation_upstream.erl +++ b/rabbitmq-server/plugins-src/rabbitmq-federation/src/rabbit_federation_upstream.erl @@ -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), diff --git a/rabbitmq-server/plugins-src/rabbitmq-management-visualiser/src/rabbit_visualiser_mgmt.erl b/rabbitmq-server/plugins-src/rabbitmq-management-visualiser/src/rabbit_visualiser_mgmt.erl index e07b69d..a5aecc6 100644 --- a/rabbitmq-server/plugins-src/rabbitmq-management-visualiser/src/rabbit_visualiser_mgmt.erl +++ b/rabbitmq-server/plugins-src/rabbitmq-management-visualiser/src/rabbit_visualiser_mgmt.erl @@ -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 index 0000000..2d93510 --- /dev/null +++ b/rabbitmq-server/plugins-src/rabbitmq-management/.travis.yml @@ -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 diff --git a/rabbitmq-server/plugins-src/rabbitmq-management/priv/www/js/formatters.js b/rabbitmq-server/plugins-src/rabbitmq-management/priv/www/js/formatters.js index 8f7f813..b3c5bc9 100644 --- a/rabbitmq-server/plugins-src/rabbitmq-management/priv/www/js/formatters.js +++ b/rabbitmq-server/plugins-src/rabbitmq-management/priv/www/js/formatters.js @@ -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) { diff --git a/rabbitmq-server/plugins-src/rabbitmq-management/src/rabbit_mgmt_format.erl b/rabbitmq-server/plugins-src/rabbitmq-management/src/rabbit_mgmt_format.erl index b16d131..d2a0641 100644 --- a/rabbitmq-server/plugins-src/rabbitmq-management/src/rabbit_mgmt_format.erl +++ b/rabbitmq-server/plugins-src/rabbitmq-management/src/rabbit_mgmt_format.erl @@ -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(<>) -> + <>; +split_lines(Text) -> + Text. + parameter(P) -> pset(value, rabbit_misc:term_to_json(pget(value, P)), P). tuple(unknown) -> unknown; diff --git a/rabbitmq-server/plugins-src/rabbitmq-management/test/src/rabbitmqadmin-test.py b/rabbitmq-server/plugins-src/rabbitmq-management/test/src/rabbitmqadmin-test.py index 470af56..47af73b 100755 --- a/rabbitmq-server/plugins-src/rabbitmq-management/test/src/rabbitmqadmin-test.py +++ b/rabbitmq-server/plugins-src/rabbitmq-management/test/src/rabbitmqadmin-test.py @@ -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) diff --git a/rabbitmq-server/plugins-src/rabbitmq-mqtt/package.mk b/rabbitmq-server/plugins-src/rabbitmq-mqtt/package.mk index c5d5bcc..9db0895 100644 --- a/rabbitmq-server/plugins-src/rabbitmq-mqtt/package.mk +++ b/rabbitmq-server/plugins-src/rabbitmq-mqtt/package.mk @@ -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 diff --git a/rabbitmq-server/plugins-src/rabbitmq-mqtt/src/rabbit_mqtt_processor.erl b/rabbitmq-server/plugins-src/rabbitmq-mqtt/src/rabbit_mqtt_processor.erl index 8ab736c..5c51a8b 100644 --- a/rabbitmq-server/plugins-src/rabbitmq-mqtt/src/rabbit_mqtt_processor.erl +++ b/rabbitmq-server/plugins-src/rabbitmq-mqtt/src/rabbit_mqtt_processor.erl @@ -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 }}; diff --git a/rabbitmq-server/plugins-src/rabbitmq-mqtt/src/rabbit_mqtt_util.erl b/rabbitmq-server/plugins-src/rabbitmq-mqtt/src/rabbit_mqtt_util.erl index 9c1787a..336e2a4 100644 --- a/rabbitmq-server/plugins-src/rabbitmq-mqtt/src/rabbit_mqtt_util.erl +++ b/rabbitmq-server/plugins-src/rabbitmq-mqtt/src/rabbit_mqtt_util.erl @@ -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) -> diff --git a/rabbitmq-server/plugins-src/rabbitmq-mqtt/test/src/com/rabbitmq/mqtt/test/MqttTest.java b/rabbitmq-server/plugins-src/rabbitmq-mqtt/test/src/com/rabbitmq/mqtt/test/MqttTest.java index b5a4913..ca31b5c 100644 --- a/rabbitmq-server/plugins-src/rabbitmq-mqtt/test/src/com/rabbitmq/mqtt/test/MqttTest.java +++ b/rabbitmq-server/plugins-src/rabbitmq-mqtt/test/src/com/rabbitmq/mqtt/test/MqttTest.java @@ -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 { diff --git a/rabbitmq-server/plugins-src/rabbitmq-mqtt/test/src/com/rabbitmq/mqtt/test/tls/MqttSSLTest.java b/rabbitmq-server/plugins-src/rabbitmq-mqtt/test/src/com/rabbitmq/mqtt/test/tls/MqttSSLTest.java index f89d963..8bf9629 100644 --- a/rabbitmq-server/plugins-src/rabbitmq-mqtt/test/src/com/rabbitmq/mqtt/test/tls/MqttSSLTest.java +++ b/rabbitmq-server/plugins-src/rabbitmq-mqtt/test/src/com/rabbitmq/mqtt/test/tls/MqttSSLTest.java @@ -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 index 0000000..be307bf --- /dev/null +++ b/rabbitmq-server/plugins-src/rabbitmq-mqtt/test/src/rabbit_mqtt_util_tests.erl @@ -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 index 0000000..1c9fcb4 --- /dev/null +++ b/rabbitmq-server/plugins-src/rabbitmq-mqtt/test/src/rabbitmq_mqtt_standalone.app.src @@ -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 index 0000000..467bda0 --- /dev/null +++ b/rabbitmq-server/plugins-src/rabbitmq-stomp/.travis.yml @@ -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 index 0000000..b082bb5 --- /dev/null +++ b/rabbitmq-server/plugins-src/rabbitmq-stomp/deps/pika/Makefile @@ -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) + diff --git a/rabbitmq-server/plugins-src/rabbitmq-stomp/include/rabbit_stomp_headers.hrl b/rabbitmq-server/plugins-src/rabbitmq-stomp/include/rabbit_stomp_headers.hrl index 398ce42..3aff8b5 100644 --- a/rabbitmq-server/plugins-src/rabbitmq-stomp/include/rabbit_stomp_headers.hrl +++ b/rabbitmq-server/plugins-src/rabbitmq-stomp/include/rabbit_stomp_headers.hrl @@ -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"). @@ -43,9 +44,26 @@ -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 + ]). diff --git a/rabbitmq-server/plugins-src/rabbitmq-stomp/package.mk b/rabbitmq-server/plugins-src/rabbitmq-stomp/package.mk index 67cb2c8..daacc68 100644 --- a/rabbitmq-server/plugins-src/rabbitmq-stomp/package.mk +++ b/rabbitmq-server/plugins-src/rabbitmq-stomp/package.mk @@ -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 diff --git a/rabbitmq-server/plugins-src/rabbitmq-stomp/src/rabbit_stomp_frame.erl b/rabbitmq-server/plugins-src/rabbitmq-stomp/src/rabbit_stomp_frame.erl index ecd6365..e6cedcf 100644 --- a/rabbitmq-server/plugins-src/rabbitmq-stomp/src/rabbit_stomp_frame.erl +++ b/rabbitmq-server/plugins-src/rabbitmq-stomp/src/rabbit_stomp_frame.erl @@ -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]. diff --git a/rabbitmq-server/plugins-src/rabbitmq-stomp/src/rabbit_stomp_processor.erl b/rabbitmq-server/plugins-src/rabbitmq-stomp/src/rabbit_stomp_processor.erl index 0a6dae7..80edb66 100644 --- a/rabbitmq-server/plugins-src/rabbitmq-stomp/src/rabbit_stomp_processor.erl +++ b/rabbitmq-server/plugins-src/rabbitmq-stomp/src/rabbit_stomp_processor.erl @@ -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) -> diff --git a/rabbitmq-server/plugins-src/rabbitmq-stomp/src/rabbit_stomp_util.erl b/rabbitmq-server/plugins-src/rabbitmq-stomp/src/rabbit_stomp_util.erl index bb8530e..9034a2b 100644 --- a/rabbitmq-server/plugins-src/rabbitmq-stomp/src/rabbit_stomp_util.erl +++ b/rabbitmq-server/plugins-src/rabbitmq-stomp/src/rabbit_stomp_util.erl @@ -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 %%-------------------------------------------------------------------- diff --git a/rabbitmq-server/plugins-src/rabbitmq-stomp/src/rabbitmq_stomp.app.src b/rabbitmq-server/plugins-src/rabbitmq-stomp/src/rabbitmq_stomp.app.src index f0f4718..6757e25 100644 --- a/rabbitmq-server/plugins-src/rabbitmq-stomp/src/rabbitmq_stomp.app.src +++ b/rabbitmq-server/plugins-src/rabbitmq-stomp/src/rabbitmq_stomp.app.src @@ -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]}]}. diff --git a/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/ack.py b/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/ack.py index 4c47cd3..e87bca3 100644 --- a/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/ack.py +++ b/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/ack.py @@ -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) diff --git a/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/destinations.py b/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/destinations.py index b1d0cd1..760bb9f 100644 --- a/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/destinations.py +++ b/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/destinations.py @@ -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() diff --git a/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/errors.py b/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/errors.py index e52b3ac..d3fa60a 100644 --- a/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/errors.py +++ b/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/errors.py @@ -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']) - diff --git a/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/parsing.py b/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/parsing.py index 2e08836..27326b6 100644 --- a/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/parsing.py +++ b/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/parsing.py @@ -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 index 0000000..cc85487 --- /dev/null +++ b/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/queue_properties.py @@ -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() diff --git a/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/rabbit_stomp_client.erl b/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/rabbit_stomp_client.erl index ee67807..2ae0699 100644 --- a/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/rabbit_stomp_client.erl +++ b/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/rabbit_stomp_client.erl @@ -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); diff --git a/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/rabbit_stomp_test.erl b/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/rabbit_stomp_test.erl index 2529098..2f5b580 100644 --- a/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/rabbit_stomp_test.erl +++ b/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/rabbit_stomp_test.erl @@ -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. diff --git a/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/rabbit_stomp_test_frame.erl b/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/rabbit_stomp_test_frame.erl index a2cbdf3..c53fff7 100644 --- a/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/rabbit_stomp_test_frame.erl +++ b/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/rabbit_stomp_test_frame.erl @@ -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 index 0000000..bbabd3f --- /dev/null +++ b/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/redelivered.py @@ -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() diff --git a/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/test.py b/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/test.py index ddeb1fe..381c5b4 100755 --- a/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/test.py +++ b/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/test.py @@ -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) diff --git a/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/test_runner.py b/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/test_runner.py index 7216865..90a5456 100644 --- a/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/test_runner.py +++ b/rabbitmq-server/plugins-src/rabbitmq-stomp/test/src/test_runner.py @@ -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() diff --git a/rabbitmq-server/plugins-src/rabbitmq-test/Makefile b/rabbitmq-server/plugins-src/rabbitmq-test/Makefile index 03466a7..3f11414 100644 --- a/rabbitmq-server/plugins-src/rabbitmq-test/Makefile +++ b/rabbitmq-server/plugins-src/rabbitmq-test/Makefile @@ -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 diff --git a/rabbitmq-server/plugins-src/rabbitmq-test/package.mk b/rabbitmq-server/plugins-src/rabbitmq-test/package.mk index 8808931..161d016 100644 --- a/rabbitmq-server/plugins-src/rabbitmq-test/package.mk +++ b/rabbitmq-server/plugins-src/rabbitmq-test/package.mk @@ -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 diff --git a/rabbitmq-server/plugins-src/rabbitmq-test/test/src/clustering_management.erl b/rabbitmq-server/plugins-src/rabbitmq-test/test/src/clustering_management.erl index f8b6cfd..b114aab 100644 --- a/rabbitmq-server/plugins-src/rabbitmq-test/test/src/clustering_management.erl +++ b/rabbitmq-server/plugins-src/rabbitmq-test/test/src/clustering_management.erl @@ -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) diff --git a/rabbitmq-server/plugins-src/rabbitmq-test/test/src/sync_detection.erl b/rabbitmq-server/plugins-src/rabbitmq-test/test/src/sync_detection.erl index c284d14..18f6f5d 100644 --- a/rabbitmq-server/plugins-src/rabbitmq-test/test/src/sync_detection.erl +++ b/rabbitmq-server/plugins-src/rabbitmq-test/test/src/sync_detection.erl @@ -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 diff --git a/rabbitmq-server/scripts/rabbitmq-defaults.bat b/rabbitmq-server/scripts/rabbitmq-defaults.bat index d3983f2..d1e3b41 100755 --- a/rabbitmq-server/scripts/rabbitmq-defaults.bat +++ b/rabbitmq-server/scripts/rabbitmq-defaults.bat @@ -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 ) diff --git a/rabbitmq-server/scripts/rabbitmq-env.bat b/rabbitmq-server/scripts/rabbitmq-env.bat index 8657f1e..7465072 100755 --- a/rabbitmq-server/scripts/rabbitmq-env.bat +++ b/rabbitmq-server/scripts/rabbitmq-env.bat @@ -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)) diff --git a/rabbitmq-server/scripts/rabbitmq-server b/rabbitmq-server/scripts/rabbitmq-server index 1800b87..71a6530 100755 --- a/rabbitmq-server/scripts/rabbitmq-server +++ b/rabbitmq-server/scripts/rabbitmq-server @@ -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 diff --git a/rabbitmq-server/scripts/rabbitmq-service.bat b/rabbitmq-server/scripts/rabbitmq-service.bat index d6dd902..0845bbf 100755 --- a/rabbitmq-server/scripts/rabbitmq-service.bat +++ b/rabbitmq-server/scripts/rabbitmq-service.bat @@ -146,7 +146,7 @@ if not "!RABBITMQ_NODE_IP_ADDRESS!"=="" ( set RABBITMQ_START_RABBIT= if "!RABBITMQ_NODE_ONLY!"=="" ( - set RABBITMQ_START_RABBIT=-s rabbit boot + set RABBITMQ_START_RABBIT=-s "!RABBITMQ_BOOT_MODULE!" boot ) if "!RABBITMQ_IO_THREAD_POOL_SIZE!"=="" ( @@ -161,9 +161,10 @@ set ERLANG_SERVICE_ARGUMENTS= ^ +W w ^ +A "!RABBITMQ_IO_THREAD_POOL_SIZE!" ^ +P 1048576 ^ --kernel inet_default_connect_options "[{nodelay,true}]" ^ !RABBITMQ_LISTEN_ARG! ^ !RABBITMQ_SERVER_ERL_ARGS! ^ +-kernel inet_default_connect_options "[{nodelay,true}]" ^ +!RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS! ^ -sasl errlog_type error ^ -sasl sasl_error_logger false ^ -rabbit error_logger {file,\""!LOGS:\=/!"\"} ^ @@ -177,7 +178,6 @@ set ERLANG_SERVICE_ARGUMENTS= ^ -os_mon start_memsup false ^ -mnesia dir \""!RABBITMQ_MNESIA_DIR:\=/!"\" ^ !RABBITMQ_SERVER_START_ARGS! ^ -!RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS! ^ !RABBITMQ_DIST_ARG! ^ !STARVAR! @@ -191,7 +191,7 @@ set ERLANG_SERVICE_ARGUMENTS=!ERLANG_SERVICE_ARGUMENTS:"=\"! -stopaction "rabbit:stop_and_halt()." ^ !RABBITMQ_NAME_TYPE! !RABBITMQ_NODENAME! ^ !CONSOLE_FLAG! ^ --comment "A robust and scalable messaging broker" ^ +-comment "Multi-protocol open source messaging broker" ^ -args "!ERLANG_SERVICE_ARGUMENTS!" > NUL goto END diff --git a/rabbitmq-server/src/credit_flow.erl b/rabbitmq-server/src/credit_flow.erl index 6b24175..b9547cf 100644 --- a/rabbitmq-server/src/credit_flow.erl +++ b/rabbitmq-server/src/credit_flow.erl @@ -27,8 +27,38 @@ %% 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). diff --git a/rabbitmq-server/src/file_handle_cache.erl b/rabbitmq-server/src/file_handle_cache.erl index 8be19e5..d7e5abc 100644 --- a/rabbitmq-server/src/file_handle_cache.erl +++ b/rabbitmq-server/src/file_handle_cache.erl @@ -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, diff --git a/rabbitmq-server/src/gen_server2.erl b/rabbitmq-server/src/gen_server2.erl index fd0e655..ffc075d 100644 --- a/rabbitmq-server/src/gen_server2.erl +++ b/rabbitmq-server/src/gen_server2.erl @@ -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)). diff --git a/rabbitmq-server/src/gm.erl b/rabbitmq-server/src/gm.erl index 95dc84e..dbf9c29 100644 --- a/rabbitmq-server/src/gm.erl +++ b/rabbitmq-server/src/gm.erl @@ -420,7 +420,8 @@ 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]) -> diff --git a/rabbitmq-server/src/rabbit.erl b/rabbitmq-server/src/rabbit.erl index 84aaf4e..bb906ed 100644 --- a/rabbitmq-server/src/rabbit.erl +++ b/rabbitmq-server/src/rabbit.erl @@ -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), diff --git a/rabbitmq-server/src/rabbit_access_control.erl b/rabbitmq-server/src/rabbit_access_control.erl index fc7a59c..d9dd9cc 100644 --- a/rabbitmq-server/src/rabbit_access_control.erl +++ b/rabbitmq-server/src/rabbit_access_control.erl @@ -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. diff --git a/rabbitmq-server/src/rabbit_amqqueue.erl b/rabbitmq-server/src/rabbit_amqqueue.erl index 5bfa006..f6cc0fb 100644 --- a/rabbitmq-server/src/rabbit_amqqueue.erl +++ b/rabbitmq-server/src/rabbit_amqqueue.erl @@ -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 diff --git a/rabbitmq-server/src/rabbit_amqqueue_process.erl b/rabbitmq-server/src/rabbit_amqqueue_process.erl index c5e4206..999e66a 100644 --- a/rabbitmq-server/src/rabbit_amqqueue_process.erl +++ b/rabbitmq-server/src/rabbit_amqqueue_process.erl @@ -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)}); diff --git a/rabbitmq-server/src/rabbit_auth_backend_internal.erl b/rabbitmq-server/src/rabbit_auth_backend_internal.erl index e53ce50..2b2a0ba 100644 --- a/rabbitmq-server/src/rabbit_auth_backend_internal.erl +++ b/rabbitmq-server/src/rabbit_auth_backend_internal.erl @@ -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) -> diff --git a/rabbitmq-server/src/rabbit_authz_backend.erl b/rabbitmq-server/src/rabbit_authz_backend.erl index 12364b6..495a796 100644 --- a/rabbitmq-server/src/rabbit_authz_backend.erl +++ b/rabbitmq-server/src/rabbit_authz_backend.erl @@ -29,13 +29,15 @@ %% %% 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()}. diff --git a/rabbitmq-server/src/rabbit_channel.erl b/rabbitmq-server/src/rabbit_channel.erl index 489f7b3..b23a841 100644 --- a/rabbitmq-server/src/rabbit_channel.erl +++ b/rabbitmq-server/src/rabbit_channel.erl @@ -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 diff --git a/rabbitmq-server/src/rabbit_error_logger_file_h.erl b/rabbitmq-server/src/rabbit_error_logger_file_h.erl index 65ab7fc..f8166bf 100644 --- a/rabbitmq-server/src/rabbit_error_logger_file_h.erl +++ b/rabbitmq-server/src/rabbit_error_logger_file_h.erl @@ -24,6 +24,27 @@ -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. @@ -34,16 +55,13 @@ %% 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. diff --git a/rabbitmq-server/src/rabbit_exchange_type_topic.erl b/rabbitmq-server/src/rabbit_exchange_type_topic.erl index afbfc65..53fb762 100644 --- a/rabbitmq-server/src/rabbit_exchange_type_topic.erl +++ b/rabbitmq-server/src/rabbit_exchange_type_topic.erl @@ -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). diff --git a/rabbitmq-server/src/rabbit_mirror_queue_slave.erl b/rabbitmq-server/src/rabbit_mirror_queue_slave.erl index 168e711..7f309ab 100644 --- a/rabbitmq-server/src/rabbit_mirror_queue_slave.erl +++ b/rabbitmq-server/src/rabbit_mirror_queue_slave.erl @@ -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, diff --git a/rabbitmq-server/src/rabbit_msg_store.erl b/rabbitmq-server/src/rabbit_msg_store.erl index 02a3bd0..8909484 100644 --- a/rabbitmq-server/src/rabbit_msg_store.erl +++ b/rabbitmq-server/src/rabbit_msg_store.erl @@ -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, @@ -134,7 +136,8 @@ 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); diff --git a/rabbitmq-server/src/rabbit_networking.erl b/rabbitmq-server/src/rabbit_networking.erl index 5d87743..f95f8c5 100644 --- a/rabbitmq-server/src/rabbit_networking.erl +++ b/rabbitmq-server/src/rabbit_networking.erl @@ -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}, diff --git a/rabbitmq-server/src/rabbit_queue_decorator.erl b/rabbitmq-server/src/rabbit_queue_decorator.erl index adfe0c7..129f51d 100644 --- a/rabbitmq-server/src/rabbit_queue_decorator.erl +++ b/rabbitmq-server/src/rabbit_queue_decorator.erl @@ -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"). diff --git a/rabbitmq-server/src/rabbit_queue_index.erl b/rabbitmq-server/src/rabbit_queue_index.erl index 0c7d7c2..176f65b 100644 --- a/rabbitmq-server/src/rabbit_queue_index.erl +++ b/rabbitmq-server/src/rabbit_queue_index.erl @@ -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]). @@ -127,7 +128,8 @@ %% 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) @@ -176,9 +178,11 @@ -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"). @@ -193,10 +197,11 @@ -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()]}). @@ -209,7 +214,9 @@ 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' | @@ -217,6 +224,7 @@ -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(), @@ -254,10 +262,19 @@ 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 = <>, 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 diff --git a/rabbitmq-server/src/rabbit_reader.erl b/rabbitmq-server/src/rabbit_reader.erl index d296c41..8812e1d 100644 --- a/rabbitmq-server/src/rabbit_reader.erl +++ b/rabbitmq-server/src/rabbit_reader.erl @@ -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) -> diff --git a/rabbitmq-server/src/rabbit_table.erl b/rabbitmq-server/src/rabbit_table.erl index e716345..a873a71 100644 --- a/rabbitmq-server/src/rabbit_table.erl +++ b/rabbitmq-server/src/rabbit_table.erl @@ -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} diff --git a/rabbitmq-server/src/rabbit_variable_queue.erl b/rabbitmq-server/src/rabbit_variable_queue.erl index 691e4ce..a0e71c6 100644 --- a/rabbitmq-server/src/rabbit_variable_queue.erl +++ b/rabbitmq-server/src/rabbit_variable_queue.erl @@ -273,6 +273,7 @@ msg_store_clients, durable, transient_threshold, + qi_embed_msgs_below, len, %% w/o unacked bytes, %% w/o unacked @@ -297,7 +298,9 @@ %% 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 }). @@ -320,10 +323,6 @@ 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). @@ -373,6 +372,7 @@ {any(), binary()}}, durable :: boolean(), transient_threshold :: non_neg_integer(), + qi_embed_msgs_below :: non_neg_integer(), len :: non_neg_integer(), bytes :: non_neg_integer(), @@ -396,7 +396,9 @@ 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 index 0000000..fc83fbc --- /dev/null +++ b/rabbitmq-server/src/ssl_compat.erl @@ -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 index 0000000..b87c6cc --- /dev/null +++ b/rabbitmq-server/src/time_compat.erl @@ -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. diff --git a/rabbitmq-server/src/vm_memory_monitor.erl b/rabbitmq-server/src/vm_memory_monitor.erl index 304518b..bf9a77c 100644 --- a/rabbitmq-server/src/vm_memory_monitor.erl +++ b/rabbitmq-server/src/vm_memory_monitor.erl @@ -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 -> diff --git a/rabbitmq-server/version.mk b/rabbitmq-server/version.mk index fe6e347..cc5e402 100644 --- a/rabbitmq-server/version.mk +++ b/rabbitmq-server/version.mk @@ -1 +1 @@ -VERSION?=3.5.4 +VERSION?=3.5.6