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
+++ /dev/null
-This package, the RabbitMQ server is licensed under the MPL.
-
-If you have any questions regarding licensing, please contact us at
-info@rabbitmq.com.
-
+++ /dev/null
-
-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.]
+++ /dev/null
-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.
-rabbitmq-server (3.5.4-1~u14.04+mos2) mos7.0; urgency=medium
+rabbitmq-server (3.5.6-1~u14.04+mos1) mos8.0; urgency=medium
- * Fall back to original MOS 7.0 package
+ * New upstream release.
+ * Disable auto-start on package install.
+ * Increase ulimit on number of file descriptors.
- -- Dmitry Mescheryakov <dmescheryakov@mirantis.com> Thu, 07 Aug 2015 22:03:00 +0300
+ -- Alexey Lebedeff <alebedev@mirantis.com> Fri, 16 Oct 2015 13:59:11 +0300
-rabbitmq-server (3.5.4-1~u14.04+mos1) mos7.0; urgency=medium
+rabbitmq-server (3.5.4-1) unstable; urgency=medium
- * Pick the source from Debian Sid, changes:
- - build-depend on default version of dh-systemd;
- - changelog was taken from original package;
+ * New upstream release.
- -- Aleksandr Mogylchenko <amogylchenko@mirantis.com> Thu, 06 Aug 2015 23:00:41 +0200
+ -- James Page <james.page@ubuntu.com> Tue, 04 Aug 2015 14:52:31 +0200
-rabbitmq-server (3.3.5-1~u14.04+mos2) mos7.0; urgency=medium
+rabbitmq-server (3.5.1-2) unstable; urgency=medium
- * Repackaged for 7.0
+ [ Tony Breeds ]
+ * systemd: Ensure that rabbitmq has started before marking service as
+ running (LP: #1449056).
- -- Artem Silenkov <asilenkov@mirantis.com> Wed, 24 Jun 2015 21:10:35 +0300
+ [ James Page ]
+ * systemd: Drop use of /etc/default/rabbitmq-server.
-rabbitmq-server (3.3.5-1~u14.04+mos1) mos6.1; urgency=medium
+ -- James Page <james.page@ubuntu.com> Tue, 02 Jun 2015 11:40:59 +0100
- * Adjust the package revision according to the versioning policy
- stated in the separate-mos-from-linux blueprint.
+rabbitmq-server (3.5.1-1) unstable; urgency=medium
- -- Alexei Sheplyakov <asheplyakov@mirantis.com> Thu, 09 Apr 2015 16:33:12 +0300
+ * New upstream release.
-rabbitmq-server (3.3.5-1~mos6.1+0b1) trusty; urgency=low
+ -- James Page <james.page@ubuntu.com> Wed, 13 May 2015 21:35:52 +0100
- * Minor packaging fixes; no actual code changes:
- - rename the source directory (make it unversioned)
- - fix the package meta-data (proper Maintainer, etc)
+rabbitmq-server (3.4.3-2) unstable; urgency=medium
- -- Alexei Sheplyakov <asheplyakov@mirantis.com> Fri, 27 Mar 2015 14:43:20 +0300
+ * Restore missing changes from 3.4.2-4.
-rabbitmq-server (3.3.5-1~mos6.1) trusty; urgency=low
+ -- James Page <james.page@ubuntu.com> Mon, 02 Feb 2015 07:44:33 +0200
- * Pick the source from packages/precise/rabbitmq-server, commit
- 55fbf9f2223244c363790e84913232adf9fed990.
- * Bump the version for MOS 6.1
+rabbitmq-server (3.4.3-1) unstable; urgency=medium
- -- Alexei Sheplyakov <asheplyakov@mirantis.com> Wed, 28 Jan 2015 17:48:06 +0300
+ * New upstream point release.
-rabbitmq-server (3.3.5-1) unstable; urgency=low
+ -- James Page <james.page@ubuntu.com> Wed, 28 Jan 2015 16:12:32 +0000
- * New Upstream Release
- * Changed Uploaders from Emile Joubert to Blair Hester
+rabbitmq-server (3.4.2-4) unstable; urgency=medium
- -- Simon MacMullen <simon@rabbitmq.com> Mon, 11 Aug 2014 12:23:31 +0100
+ * Re-added /usr/lib/erlang/lib /var/lib/rabbitmq/mnesia and
+ /var/log/rabbitmq which I removed form the package by mistake on the last
+ upload.
-rabbitmq-server (3.3.4-1) unstable; urgency=low
+ -- Thomas Goirand <zigo@debian.org> Wed, 28 Jan 2015 13:11:02 +0000
- * New Upstream Release
+rabbitmq-server (3.4.2-3) unstable; urgency=medium
- -- Simon MacMullen <simon@rabbitmq.com> Tue, 24 Jun 2014 12:50:29 +0100
+ * Removes debian/README which is useless (Closes: #703021).
+ * Provides a default /etc/rabbitmq/rabbitmq-env.conf (Closes: #543638).
-rabbitmq-server (3.3.3-1) unstable; urgency=low
+ -- Thomas Goirand <zigo@debian.org> Tue, 27 Jan 2015 15:08:08 +0100
- * New Upstream Release
+rabbitmq-server (3.4.2-2) unstable; urgency=medium
- -- Simon MacMullen <simon@rabbitmq.com> Mon, 16 Jun 2014 13:00:00 +0100
+ * d/rabbitmq-server.dirs: Restore missing /etc/rabbitmq directory
+ (LP: #1410155).
-rabbitmq-server (3.3.2-1) unstable; urgency=low
+ -- James Page <james.page@ubuntu.com> Tue, 13 Jan 2015 09:53:47 +0000
- * New Upstream Release
+rabbitmq-server (3.4.2-1) unstable; urgency=medium
+
+ [ James Page ]
+ * New upstream point release.
+ * d/control: Update for new maintainer information, add VCS repository
+ locations.
+ * d/source/format: Switch packaging to source format 3.0 (quilt).
+ * d/compat,control: Bump debhelper compat level to 9.
+ * d/*: wrap-and-sort.
+ * d/*: Move to standard debhelper, drop use of cdbs.
+ * d/rules,control,rabbitmq-server.service: Add systemd service
+ configuration.
+ * d/control: Bumped Standards-Version 3.9.6, no changes.
+
+ [ Thomas Goirand ]
+ * d/copyright: Rewrote as format 1.0.
+
+ -- James Page <james.page@ubuntu.com> Fri, 19 Dec 2014 11:09:20 +0000
+
+rabbitmq-server (3.4.1-1) unstable; urgency=high
+
+ * New upstream release.
+
+ -- Blair Hester <bhester@gopivotal.com> Tue, 04 Nov 2014 07:33:44 +0100
+
+rabbitmq-server (3.3.5-1) unstable; urgency=low
+
+ * New upstream release:
+ - Provides unminimized versions of all bundled Javascript
+ libraries (Closes: #736781).
+ * d/control: Added Blair Hester to Uploaders, dropped Emile Joubert
+ (thanks for all your work Emile!).
+
+ -- Blair Hester <bhester@gopivotal.com> Tue, 12 Aug 2014 11:47:14 +0100
- -- Simon MacMullen <simon@rabbitmq.com> Mon, 09 Jun 2014 10:25:22 +0100
+rabbitmq-server (3.3.4-1) unstable; urgency=low
+
+ * New upstream release
+
+ -- Emile Joubert <emile@rabbitmq.com> Tue, 24 Jun 2014 18:00:48 +0100
+
+rabbitmq-server (3.3.3-1) unstable; urgency=low
+
+ * New upstream release
+
+ -- Emile Joubert <emile@rabbitmq.com> Tue, 17 Jun 2014 16:59:14 +0100
rabbitmq-server (3.3.1-1) unstable; urgency=low
- * New Upstream Release
+ * New upstream release
- -- Simon MacMullen <simon@rabbitmq.com> Tue, 29 Apr 2014 11:49:23 +0100
+ -- Emile Joubert <emile@rabbitmq.com> Tue, 29 Apr 2014 21:05:49 +0100
rabbitmq-server (3.3.0-1) unstable; urgency=low
- * New Upstream Release
+ * New upstream release
- -- Simon MacMullen <simon@rabbitmq.com> Wed, 02 Apr 2014 14:23:14 +0100
+ -- Emile Joubert <emile@rabbitmq.com> Wed, 02 Apr 2014 16:23:08 +0100
-rabbitmq-server (3.2.4-1) unstable; urgency=low
+rabbitmq-server (3.2.4-1.1) unstable; urgency=high
- * New Upstream Release
+ * Non-maintainer upload.
+ * Bind on 127.0.0.1 by default, to avoid listening on all ipv6 interface with
+ guest/guest as default configured user. Note that this only fixes *new*
+ installation, and that any already existing setup will have to edit the
+ /etc/rabbitmq/rabbitmq-env.conf manually if affected. (Closes: #727607)
+ * Removed useless and deprecated DM-Upload field.
+ * Cleans plugins-src/rabbitmq-server to be able to build twice. Also cleans
+ debian/postrm which is generated from debian/postrm.in and plugins/README.
- -- Simon MacMullen <simon@rabbitmq.com> Mon, 03 Mar 2014 14:50:18 +0000
+ -- Thomas Goirand <zigo@debian.org> Mon, 31 Mar 2014 06:11:46 +0000
-rabbitmq-server (3.2.3-1+mira.1) precise; urgency=low
+rabbitmq-server (3.2.4-1) unstable; urgency=low
- * Disable rabbitmq-server autostart
+ * New upstream release
- -- Vladimir Kuklin <vkuklin@mirantis.com> Thu, 10 Jul 2014 14:01:02 +0400
+ -- Emile Joubert <emile@rabbitmq.com> Tue, 04 Mar 2014 13:21:45 +0000
rabbitmq-server (3.2.3-1) unstable; urgency=low
- [ Emile Joubert ]
- * New Upstream Release
-
- [ Vladimir Kuklin ]
- * +mira
+ * New upstream release
- -- Vladimir Kuklin <vvk@vvk-workstation> Thu, 10 Jul 2014 14:00:41 +0400
+ -- Emile Joubert <emile@rabbitmq.com> Thu, 23 Jan 2014 16:49:45 +0000
rabbitmq-server (3.2.2-1) unstable; urgency=low
- * New Upstream Release
+ * New upstream release
+
+ -- Emile Joubert <emile@rabbitmq.com> Wed, 11 Dec 2013 17:31:14 +0000
+
+rabbitmq-server (3.2.1-1) unstable; urgency=low
+
+ * New upstream release
- -- Emile Joubert <emile@rabbitmq.com> Tue, 10 Dec 2013 16:08:08 +0000
+ -- Emile Joubert <emile@rabbitmq.com> Mon, 11 Nov 2013 09:49:42 +0000
rabbitmq-server (3.2.0-1) unstable; urgency=low
- * New Upstream Release
+ * New upstream release
- -- Emile Joubert <emile@rabbitmq.com> Wed, 23 Oct 2013 12:44:10 +0100
+ -- Emile Joubert <emile@rabbitmq.com> Wed, 23 Oct 2013 15:42:19 +0100
-rabbitmq-server (3.1.5-1) unstable; urgency=low
+rabbitmq-server (3.1.4-1) unstable; urgency=low
- * New Upstream Release
+ * New upstream release
- -- Simon MacMullen <simon@rabbitmq.com> Thu, 15 Aug 2013 11:03:13 +0100
+ -- Emile Joubert <emile@rabbitmq.com> Thu, 07 Aug 2013 15:16:28 +0100
rabbitmq-server (3.1.3-1) unstable; urgency=low
- * New Upstream Release
+ * New upstream release
- -- Tim Watson <tim@rabbitmq.com> Tue, 25 Jun 2013 15:01:12 +0100
+ -- Emile Joubert <emile@rabbitmq.com> Thu, 27 Jun 2013 14:06:11 +0100
rabbitmq-server (3.1.2-1) unstable; urgency=low
- * New Upstream Release
+ * New upstream release
- -- Tim Watson <tim@rabbitmq.com> Mon, 24 Jun 2013 11:16:41 +0100
+ -- Emile Joubert <emile@rabbitmq.com> Thu, 25 Jun 2013 11:28:52 +0100
rabbitmq-server (3.1.1-1) unstable; urgency=low
- * Test release
+ * New upstream release
- -- Tim Watson <tim@rabbitmq.com> Mon, 20 May 2013 16:21:20 +0100
+ -- Emile Joubert <emile@rabbitmq.com> Thu, 28 May 2013 11:15:13 +0100
rabbitmq-server (3.1.0-1) unstable; urgency=low
- * New Upstream Release
+ * New upstream release
+
+ -- Emile Joubert <emile@rabbitmq.com> Thu, 02 May 2013 11:19:31 +0100
+
+rabbitmq-server (3.0.4-1) unstable; urgency=low
+
+ * New upstream release
+
+ -- Emile Joubert <emile@rabbitmq.com> Wed, 13 Mar 2013 10:53:18 +0000
+
+rabbitmq-server (3.0.4-1) unstable; urgency=low
+
+ * New upstream release
+
+ -- Emile Joubert <emile@rabbitmq.com> Wed, 13 Mar 2013 10:53:18 +0000
+
+rabbitmq-server (3.0.3-1) unstable; urgency=low
+
+ * New upstream release
+
+ -- Emile Joubert <emile@rabbitmq.com> Thu, 07 Mar 2013 10:03:31 +0000
- -- Simon MacMullen <simon@rabbitmq.com> Wed, 01 May 2013 11:57:58 +0100
+rabbitmq-server (3.0.2-1) unstable; urgency=low
+
+ * New upstream release
+
+ -- Emile Joubert <emile@rabbitmq.com> Tue, 31 Jan 2013 15:28:12 +0000
rabbitmq-server (3.0.1-1) unstable; urgency=low
- * New Upstream Release
+ * New upstream release
- -- Simon MacMullen <simon@rabbitmq.com> Tue, 11 Dec 2012 11:29:55 +0000
+ -- Emile Joubert <emile@rabbitmq.com> Tue, 11 Dec 2012 15:47:52 +0000
rabbitmq-server (3.0.0-1) unstable; urgency=low
- * New Upstream Release
+ * New upstream release
- -- Simon MacMullen <simon@rabbitmq.com> Fri, 16 Nov 2012 14:15:29 +0000
+ -- Emile Joubert <emile@rabbitmq.com> Mon, 19 Nov 2012 11:42:31 +0000
-rabbitmq-server (2.7.1-1) natty; urgency=low
+rabbitmq-server (2.8.7-1) unstable; urgency=low
- * New Upstream Release
+ * New upstream release
- -- Steve Powell <steve@rabbitmq.com> Fri, 16 Dec 2011 12:12:36 +0000
+ -- Emile Joubert <emile@rabbitmq.com> Thu, 27 Sep 2012 16:28:21 +0100
-rabbitmq-server (2.7.0-1) natty; urgency=low
+rabbitmq-server (2.8.6-1) unstable; urgency=low
- * New Upstream Release
+ * New upstream release
- -- Steve Powell <steve@rabbitmq.com> Tue, 08 Nov 2011 16:47:50 +0000
+ -- Emile Joubert <emile@rabbitmq.com> Wed, 22 Aug 2012 13:28:21 +0100
-rabbitmq-server (2.6.1-1) natty; urgency=low
+rabbitmq-server (2.8.5-1) unstable; urgency=low
- * New Upstream Release
+ * New upstream release
- -- Tim <tim@rabbitmq.com> Fri, 09 Sep 2011 14:38:45 +0100
+ -- Emile Joubert <emile@rabbitmq.com> Thu, 02 Aug 2012 16:12:21 +0100
-rabbitmq-server (2.6.0-1) natty; urgency=low
+rabbitmq-server (2.8.4-1) unstable; urgency=low
- * New Upstream Release
+ * New upstream release
- -- Tim <tim@rabbitmq.com> Fri, 26 Aug 2011 16:29:40 +0100
+ -- Emile Joubert <emile@rabbitmq.com> Fri, 22 Jun 2012 17:48:28 +0100
-rabbitmq-server (2.5.1-1) lucid; urgency=low
+rabbitmq-server (2.8.3-1) unstable; urgency=low
- * New Upstream Release
+ * New upstream release
- -- Simon MacMullen <simon@rabbitmq.com> Mon, 27 Jun 2011 11:21:49 +0100
+ -- Emile Joubert <emile@rabbitmq.com> Thu, 21 Jun 2012 13:38:57 +0100
-rabbitmq-server (2.5.0-1) lucid; urgency=low
+rabbitmq-server (2.8.2-2) unstable; urgency=low
- * New Upstream Release
+ * Add version numbers to plugins
- -- <jerryk@vmware.com> Thu, 09 Jun 2011 07:20:29 -0700
+ -- Emile Joubert <emile@rabbitmq.com> Tue, 01 May 2012 10:48:57 +0100
-rabbitmq-server (2.4.1-1) lucid; urgency=low
+rabbitmq-server (2.8.2-1) unstable; urgency=low
- * New Upstream Release
+ * New upstream release
- -- Alexandru Scvortov <alexandru@rabbitmq.com> Thu, 07 Apr 2011 16:49:22 +0100
+ -- Emile Joubert <emile@rabbitmq.com> Mon, 30 Apr 2012 14:07:32 +0100
-rabbitmq-server (2.4.0-1) lucid; urgency=low
+rabbitmq-server (2.8.1-1) unstable; urgency=low
- * New Upstream Release
+ * New upstream release
- -- Alexandru Scvortov <alexandru@rabbitmq.com> Tue, 22 Mar 2011 17:34:31 +0000
+ -- Emile Joubert <emile@rabbitmq.com> Fri, 23 Mar 2012 10:05:24 +0000
-rabbitmq-server (2.3.1-1) lucid; urgency=low
+rabbitmq-server (2.8.0-1) unstable; urgency=low
- * New Upstream Release
+ * New upstream release
- -- Simon MacMullen <simon@rabbitmq.com> Thu, 03 Feb 2011 12:43:56 +0000
+ -- Emile Joubert <emile@rabbitmq.com> Tue, 20 Mar 2012 11:55:10 +0000
-rabbitmq-server (2.3.0-1) lucid; urgency=low
+rabbitmq-server (2.6.1-2) unstable; urgency=low
- * New Upstream Release
+ * Add DM-Upload-Allowed flag to control file to allow Maintainer uploads
- -- Simon MacMullen <simon@rabbitmq.com> Tue, 01 Feb 2011 12:52:16 +0000
+ -- John Leuner <jewel@debian.org> Mon, 19 Mar 2012 21:13:54 +0200
-rabbitmq-server (2.2.0-1) lucid; urgency=low
+rabbitmq-server (2.6.1-1) unstable; urgency=low
- * New Upstream Release
+ * New upstream release
- -- Rob Harrop <rob@rabbitmq.com> Mon, 29 Nov 2010 12:24:48 +0000
+ -- John Leuner <jewel@debian.org> Tue, 27 Sep 2011 17:53:57 +0200
-rabbitmq-server (2.1.1-1) lucid; urgency=low
+rabbitmq-server (2.5.0-1) unstable; urgency=low
- * New Upstream Release
+ * New upstream release
- -- Vlad Alexandru Ionescu <vlad@rabbitmq.com> Tue, 19 Oct 2010 17:20:10 +0100
+ -- John Leuner <jewel@debian.org> Thu, 16 Jun 2011 09:55:40 +0200
-rabbitmq-server (2.1.0-1) lucid; urgency=low
+rabbitmq-server (2.4.1-1) unstable; urgency=low
- * New Upstream Release
+ * New upstream release
- -- Marek Majkowski <marek@rabbitmq.com> Tue, 14 Sep 2010 14:20:17 +0100
+ -- John Leuner <jewel@debian.org> Sat, 09 Apr 2011 09:34:06 +0200
-rabbitmq-server (2.0.0-1) karmic; urgency=low
+rabbitmq-server (2.4.0-1) unstable; urgency=low
- * New Upstream Release
+ * New upstream release
- -- Michael Bridgen <mikeb@rabbitmq.com> Mon, 23 Aug 2010 14:55:39 +0100
+ -- John Leuner <jewel@debian.org> Wed, 23 Mar 2011 21:11:17 +0200
-rabbitmq-server (1.8.1-1) lucid; urgency=low
+rabbitmq-server (2.3.1-1) unstable; urgency=low
- * New Upstream Release
+ * New upstream release, closes: #611253
- -- Emile Joubert <emile@rabbitmq.com> Wed, 14 Jul 2010 15:05:24 +0100
+ -- John Leuner <jewel@debian.org> Sat, 05 Feb 2011 10:21:16 +0200
-rabbitmq-server (1.8.0-1) intrepid; urgency=low
+rabbitmq-server (2.2.0-1) unstable; urgency=low
- * New Upstream Release
+ * New upstream release
- -- Matthew Sackman <matthew@rabbitmq.com> Tue, 15 Jun 2010 12:48:48 +0100
+ -- John Leuner <jewel@debian.org> Thu, 02 Dec 2010 20:41:53 +0200
-rabbitmq-server (1.7.2-1) intrepid; urgency=low
+rabbitmq-server (2.1.0-1) unstable; urgency=low
- * New Upstream Release
+ * New upstream release
- -- Matthew Sackman <matthew@lshift.net> Mon, 15 Feb 2010 15:54:47 +0000
+ -- John Leuner <jewel@debian.org> Mon, 27 Sep 2010 20:28:06 +0200
-rabbitmq-server (1.7.1-1) intrepid; urgency=low
+rabbitmq-server (2.0.0-2) unstable; urgency=low
- * New Upstream Release
+ * Fix various scripts that were not updated correctly in
+ - the 2.0.0-1 package, closes: #594724
- -- Matthew Sackman <matthew@lshift.net> Fri, 22 Jan 2010 14:14:29 +0000
+ -- John Leuner <jewel@debian.org> Thu, 02 Sep 2010 18:01:37 +0200
-rabbitmq-server (1.7.0-1) intrepid; urgency=low
+rabbitmq-server (2.0.0-1) unstable; urgency=low
- * New Upstream Release
+ * New upstream release
- -- David Wragg <dpw@lshift.net> Mon, 05 Oct 2009 13:44:41 +0100
+ -- John Leuner <jewel@debian.org> Sat, 28 Aug 2010 11:21:48 +0200
-rabbitmq-server (1.6.0-1) hardy; urgency=low
+rabbitmq-server (1.8.1-1) unstable; urgency=low
- * New Upstream Release
+ * New upstream release
- -- Matthias Radestock <matthias@lshift.net> Tue, 16 Jun 2009 15:02:58 +0100
+ -- John Leuner <jewel@debian.org> Sun, 01 Aug 2010 15:47:46 +0200
-rabbitmq-server (1.5.5-1) hardy; urgency=low
+rabbitmq-server (1.8.0-1) unstable; urgency=low
- * New Upstream Release
+ * New upstream release
- -- Matthias Radestock <matthias@lshift.net> Tue, 19 May 2009 09:57:54 +0100
+ -- John Leuner <jewel@debian.org> Thu, 24 Jun 2010 18:43:04 +0200
-rabbitmq-server (1.5.4-1) hardy; urgency=low
+rabbitmq-server (1.7.0-3) unstable; urgency=low
- * New Upstream Release
+ * Add missing entries in rabbitmq-server.init
- -- Matthias Radestock <matthias@lshift.net> Mon, 06 Apr 2009 09:19:32 +0100
+ -- John Leuner <jewel@debian.org> Sun, 25 Oct 2009 10:21:25 +0200
-rabbitmq-server (1.5.3-1) hardy; urgency=low
+rabbitmq-server (1.7.0-2) unstable; urgency=low
- * New Upstream Release
+ * moved debian/init.d to rabbitmq-server.init
+ * included fixes to rabbitmq-script-wrapper
- -- Tony Garnock-Jones <tonyg@lshift.net> Tue, 24 Feb 2009 18:23:33 +0000
+ -- John Leuner <jewel@debian.org> Wed, 14 Oct 2009 12:23:52 +0200
-rabbitmq-server (1.5.2-1) hardy; urgency=low
+rabbitmq-server (1.7.0-1) unstable; urgency=low
- * New Upstream Release
+ * New upstream release
- -- Tony Garnock-Jones <tonyg@lshift.net> Mon, 23 Feb 2009 16:03:38 +0000
+ -- John Leuner <jewel@debian.org> Sat, 10 Oct 2009 13:28:39 +0200
-rabbitmq-server (1.5.1-1) hardy; urgency=low
+rabbitmq-server (1.6.0-1) unstable; urgency=low
- * New Upstream Release
+ * New upstream release
- -- Simon MacMullen <simon@lshift.net> Mon, 19 Jan 2009 15:46:13 +0000
+ -- John Leuner <jewel@debian.org> Sat, 20 Jun 2009 12:22:17 +0200
-rabbitmq-server (1.5.0-1) testing; urgency=low
+rabbitmq-server (1.5.5-3) unstable; urgency=low
- * New Upstream Release
+ * debian/control: Reduce Erlang dependencies to just
+ erlang-mnesia and erlang-os-mon, closes: #532867
- -- Matthias Radestock <matthias@lshift.net> Wed, 17 Dec 2008 18:23:47 +0000
+ -- John Leuner <jewel@debian.org> Tue, 16 Jun 2009 14:15:20 +0200
-rabbitmq-server (1.4.0-1) testing; urgency=low
+rabbitmq-server (1.5.5-2) unstable; urgency=low
- * New Upstream Release
+ * Include updates to debian package by rabbit team:
+ - quiet log rotate
+ - update build-depends and depends for new erlang packages
+ - debian/watch file
+ - add rabbitmq-script-wrapper
+ - update init.d scripts
+ - clean /etc/rabbitmq in postrm
- -- Tony Garnock-Jones <tonyg@lshift.net> Thu, 24 Jul 2008 13:21:48 +0100
+ -- John Leuner <jewel@debian.org> Wed, 03 Jun 2009 12:23:50 +0200
-rabbitmq-server (1.3.0-1) testing; urgency=low
+rabbitmq-server (1.5.5-1) unstable; urgency=low
- * New Upstream Release
+ * New upstream release
- -- Adrien Pierard <adrien@lshift.net> Mon, 03 Mar 2008 15:34:38 +0000
+ -- John Leuner <jewel@debian.org> Tue, 02 Jun 2009 12:53:32 +0200
-rabbitmq-server (1.2.0-2) testing; urgency=low
+rabbitmq-server (1.5.4-4) unstable; urgency=low
- * Fixed rabbitmqctl wrapper script
+ * Add new dependency on erlang-os-mon to work with new erlang packages in
+ debian
- -- Simon MacMullen <simon@lshift.net> Fri, 05 Oct 2007 11:55:00 +0100
+ -- John Leuner <jewel@debian.org> Mon, 11 May 2009 21:20:04 +0200
-rabbitmq-server (1.2.0-1) testing; urgency=low
+rabbitmq-server (1.5.4-3) unstable; urgency=low
- * New upstream release
+ * Previous partial upload failed
+
+ -- John Leuner <jewel@debian.org> Fri, 10 Apr 2009 20:25:51 +0200
+
+rabbitmq-server (1.5.4-2) unstable; urgency=low
+
+ * Fix incorrect changed-by field in .changes file
- -- Simon MacMullen <simon@lshift.net> Wed, 26 Sep 2007 11:49:26 +0100
+ -- John Leuner <jewel@debian.org> Fri, 10 Apr 2009 19:40:04 +0200
-rabbitmq-server (1.1.1-1) testing; urgency=low
+rabbitmq-server (1.5.4-1) unstable; urgency=low
* New upstream release
- -- Simon MacMullen <simon@lshift.net> Wed, 29 Aug 2007 12:03:15 +0100
+ -- John Leuner <jewel@debian.org> Fri, 10 Apr 2009 17:54:21 +0200
-rabbitmq-server (1.1.0-alpha-2) testing; urgency=low
+rabbitmq-server (1.5.0-5) unstable; urgency=low
- * Fixed erlang-nox dependency
+ * Include the full license for amqp-0.8.json in debian/copyright
- -- Simon MacMullen <simon@lshift.net> Thu, 02 Aug 2007 11:27:13 +0100
+ -- John Leuner <jewel@debian.org> Fri, 27 Feb 2009 16:16:54 +0200
-rabbitmq-server (1.1.0-alpha-1) testing; urgency=low
+rabbitmq-server (1.5.0-4) unstable; urgency=low
- * New upstream release
+ * Clarify and explicitly list the license and copyright for
+ codegen/amqp-0.8.json
+
+ * Explicitly list the authors and copyright for the rest of the codebase
+ at the top of debian/copyright
+
+ * Clarify the copyright of the files in src/tcp_* . The rabbitmq authors have
+ confirmed that they are the original authors of this code and that the
+ files at http://code.google.com/p/cacherl/ were taken without their
+ knowledge from the rabbitmq project. (Comparing the commit dates in version
+ control shows that cacherl is newer)
+
+ -- John Leuner <jewel@debian.org> Wed, 25 Feb 2009 13:10:15 +0200
+
+rabbitmq-server (1.5.0-3) unstable; urgency=low
+
+ * Previous changelog entry had an incorrect Maintainer name
- -- Simon MacMullen <simon@lshift.net> Fri, 20 Jul 2007 18:17:33 +0100
+ -- John Leuner <jewel@debian.org> Wed, 28 Jan 2009 16:45:33 +0200
-rabbitmq-server (1.0.0-alpha-1) unstable; urgency=low
+rabbitmq-server (1.5.0-2) unstable; urgency=low
- * Initial release
+ * Reupload package to unstable. Mistakenly uploaded to testing last time, closes: #507902
- -- Tony Garnock-Jones <tonyg@shortstop.lshift.net> Wed, 31 Jan 2007 19:06:33 +0000
+ -- John Leuner <jewel@debian.org> Mon, 19 Jan 2009 17:38:43 +0200
+
+rabbitmq-server (1.5.0-1) testing; urgency=low
+
+ * New Upstream Release
+ * First Debian upload, closes: #507902
+ -- John Leuner <jewel@debian.org> Wed, 17 Dec 2008 18:23:47 +0000
Source: rabbitmq-server
Section: net
Priority: extra
-Maintainer: MOS Linux team <mos-linux@mirantis.com>
-XSBC-Orig-Maintainer: RabbitMQ Team <packaging@rabbitmq.com>
-Build-Depends: cdbs, debhelper (>= 9), erlang-dev, python-simplejson, xmlto, xsltproc, erlang-nox (>= 1:13.b.3), erlang-src (>= 1:13.b.3), unzip, zip
-Standards-Version: 3.9.2
+Maintainer: PKG OpenStack <openstack-devel@lists.alioth.debian.org>
+Uploaders: James Page <james.page@ubuntu.com>, Thomas Goirand <zigo@debian.org>
+Build-Depends: debhelper (>= 9~),
+ dh-systemd (>= 1.5),
+ erlang-dev,
+ erlang-nox (>= 1:13.b.3),
+ erlang-src (>= 1:13.b.3),
+ python-simplejson,
+ unzip,
+ xmlto,
+ xsltproc,
+ zip
+Standards-Version: 3.9.6
+Vcs-Browser: http://anonscm.debian.org/gitweb/?p=openstack/rabbitmq-server.git
+Vcs-Git: git://anonscm.debian.org/openstack/rabbitmq-server.git
+Homepage: http://www.rabbitmq.com/
Package: rabbitmq-server
Architecture: all
-Depends: erlang-nox (>= 1:13.b.3) | esl-erlang, adduser, logrotate, ${misc:Depends}
+Depends: adduser,
+ erlang-nox (>= 1:13.b.3) | esl-erlang,
+ logrotate,
+ ${misc:Depends}
Description: AMQP server written in Erlang
RabbitMQ is an implementation of AMQP, the emerging standard for high
performance enterprise messaging. The RabbitMQ server is a robust and
scalable implementation of an AMQP broker.
-Homepage: http://www.rabbitmq.com/
-This package was debianized by Tony Garnock-Jones <tonyg@rabbitmq.com> on
-Wed, 3 Jan 2007 15:43:44 +0000.
-
-It was downloaded from http://www.rabbitmq.com/
-
-
-This package, the RabbitMQ server is licensed under the MPL.
-
-If you have any questions regarding licensing, please contact us at
-info@rabbitmq.com.
-
-The files amqp-rabbitmq-0.8.json and amqp-rabbitmq-0.9.1.json are
-"Copyright (C) 2008-2013 GoPivotal", Inc. and are covered by the MIT
-license.
-
-jQuery is "Copyright (c) 2010 John Resig" and is covered by the MIT
-license. It was downloaded from http://jquery.com/
-
-EJS is "Copyright (c) 2007 Edward Benson" and is covered by the MIT
-license. It was downloaded from http://embeddedjs.com/
-
-Sammy is "Copyright (c) 2008 Aaron Quint, Quirkey NYC, LLC" and is
-covered by the MIT license. It was downloaded from
-http://code.quirkey.com/sammy/
-
-ExplorerCanvas is "Copyright 2006 Google Inc" and is covered by the
-Apache License version 2.0. It was downloaded from
-http://code.google.com/p/explorercanvas/
-
-Flot is "Copyright (c) 2007-2013 IOLA and Ole Laursen" and is covered
-by the MIT license. It was downloaded from
-http://www.flotcharts.org/
-Webmachine is Copyright (c) Basho Technologies and is covered by the
-Apache License 2.0. It was downloaded from http://webmachine.basho.com/
-
-Eldap is "Copyright (c) 2010, Torbjorn Tornkvist" and is covered by
-the MIT license. It was downloaded from https://github.com/etnt/eldap
-
-Mochiweb is "Copyright (c) 2007 Mochi Media, Inc." and is covered by
-the MIT license. It was downloaded from
-http://github.com/mochi/mochiweb/
-
-glMatrix is "Copyright (c) 2011, Brandon Jones" and is covered by the
-BSD 2-Clause license. It was downloaded from
-http://code.google.com/p/glmatrix/
-
-
-The MIT license is as follows:
-
- "Permission is hereby granted, free of charge, to any person
- obtaining a copy of this file (the Software), to deal in the
- Software without restriction, including without limitation the
- rights to use, copy, modify, merge, publish, distribute,
- sublicense, and/or sell copies of the Software, and to permit
- persons to whom the Software is furnished to do so, subject to
- the following conditions:
-
- The above copyright notice and this permission notice shall be
- included in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- OTHER DEALINGS IN THE SOFTWARE."
-
-
-The BSD 2-Clause license is as follows:
-
- "Redistribution and use in source and binary forms, with or
- without modification, are permitted provided that the
- following conditions are met:
-
- 1. Redistributions of source code must retain the above
- copyright notice, this list of conditions and the following
- disclaimer.
-
- 2. Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the following
- disclaimer in the documentation and/or other materials
- provided with the distribution.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
- CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-
-
-The rest of this package is licensed under the Mozilla Public License 1.1
-Authors and Copyright are as described below:
-
- The Initial Developer of the Original Code is GoPivotal, Inc.
- Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved.
-
-
- MOZILLA PUBLIC LICENSE
- Version 1.1
-
- ---------------
-
-1. Definitions.
-
- 1.0.1. "Commercial Use" means distribution or otherwise making the
- Covered Code available to a third party.
-
- 1.1. "Contributor" means each entity that creates or contributes to
- the creation of Modifications.
-
- 1.2. "Contributor Version" means the combination of the Original
- Code, prior Modifications used by a Contributor, and the Modifications
- made by that particular Contributor.
-
- 1.3. "Covered Code" means the Original Code or Modifications or the
- combination of the Original Code and Modifications, in each case
- including portions thereof.
-
- 1.4. "Electronic Distribution Mechanism" means a mechanism generally
- accepted in the software development community for the electronic
- transfer of data.
-
- 1.5. "Executable" means Covered Code in any form other than Source
- Code.
-
- 1.6. "Initial Developer" means the individual or entity identified
- as the Initial Developer in the Source Code notice required by Exhibit
- A.
-
- 1.7. "Larger Work" means a work which combines Covered Code or
- portions thereof with code not governed by the terms of this License.
-
- 1.8. "License" means this document.
-
- 1.8.1. "Licensable" means having the right to grant, to the maximum
- extent possible, whether at the time of the initial grant or
- subsequently acquired, any and all of the rights conveyed herein.
-
- 1.9. "Modifications" means any addition to or deletion from the
- substance or structure of either the Original Code or any previous
- Modifications. When Covered Code is released as a series of files, a
- Modification is:
- A. Any addition to or deletion from the contents of a file
- containing Original Code or previous Modifications.
-
- B. Any new file that contains any part of the Original Code or
- previous Modifications.
-
- 1.10. "Original Code" means Source Code of computer software code
- which is described in the Source Code notice required by Exhibit A as
- Original Code, and which, at the time of its release under this
- License is not already Covered Code governed by this License.
-
- 1.10.1. "Patent Claims" means any patent claim(s), now owned or
- hereafter acquired, including without limitation, method, process,
- and apparatus claims, in any patent Licensable by grantor.
-
- 1.11. "Source Code" means the preferred form of the Covered Code for
- making modifications to it, including all modules it contains, plus
- any associated interface definition files, scripts used to control
- compilation and installation of an Executable, or source code
- differential comparisons against either the Original Code or another
- well known, available Covered Code of the Contributor's choice. The
- Source Code can be in a compressed or archival form, provided the
- appropriate decompression or de-archiving software is widely available
- for no charge.
-
- 1.12. "You" (or "Your") means an individual or a legal entity
- exercising rights under, and complying with all of the terms of, this
- License or a future version of this License issued under Section 6.1.
- For legal entities, "You" includes any entity which controls, is
- controlled by, or is under common control with You. For purposes of
- this definition, "control" means (a) the power, direct or indirect,
- to cause the direction or management of such entity, whether by
- contract or otherwise, or (b) ownership of more than fifty percent
- (50%) of the outstanding shares or beneficial ownership of such
- entity.
-
-2. Source Code License.
-
- 2.1. The Initial Developer Grant.
- The Initial Developer hereby grants You a world-wide, royalty-free,
- non-exclusive license, subject to third party intellectual property
- claims:
- (a) under intellectual property rights (other than patent or
- trademark) Licensable by Initial Developer to use, reproduce,
- modify, display, perform, sublicense and distribute the Original
- Code (or portions thereof) with or without Modifications, and/or
- as part of a Larger Work; and
-
- (b) under Patents Claims infringed by the making, using or
- selling of Original Code, to make, have made, use, practice,
- sell, and offer for sale, and/or otherwise dispose of the
- Original Code (or portions thereof).
-
- (c) the licenses granted in this Section 2.1(a) and (b) are
- effective on the date Initial Developer first distributes
- Original Code under the terms of this License.
-
- (d) Notwithstanding Section 2.1(b) above, no patent license is
- granted: 1) for code that You delete from the Original Code; 2)
- separate from the Original Code; or 3) for infringements caused
- by: i) the modification of the Original Code or ii) the
- combination of the Original Code with other software or devices.
-
- 2.2. Contributor Grant.
- Subject to third party intellectual property claims, each Contributor
- hereby grants You a world-wide, royalty-free, non-exclusive license
-
- (a) under intellectual property rights (other than patent or
- trademark) Licensable by Contributor, to use, reproduce, modify,
- display, perform, sublicense and distribute the Modifications
- created by such Contributor (or portions thereof) either on an
- unmodified basis, with other Modifications, as Covered Code
- and/or as part of a Larger Work; and
-
- (b) under Patent Claims infringed by the making, using, or
- selling of Modifications made by that Contributor either alone
- and/or in combination with its Contributor Version (or portions
- of such combination), to make, use, sell, offer for sale, have
- made, and/or otherwise dispose of: 1) Modifications made by that
- Contributor (or portions thereof); and 2) the combination of
- Modifications made by that Contributor with its Contributor
- Version (or portions of such combination).
-
- (c) the licenses granted in Sections 2.2(a) and 2.2(b) are
- effective on the date Contributor first makes Commercial Use of
- the Covered Code.
-
- (d) Notwithstanding Section 2.2(b) above, no patent license is
- granted: 1) for any code that Contributor has deleted from the
- Contributor Version; 2) separate from the Contributor Version;
- 3) for infringements caused by: i) third party modifications of
- Contributor Version or ii) the combination of Modifications made
- by that Contributor with other software (except as part of the
- Contributor Version) or other devices; or 4) under Patent Claims
- infringed by Covered Code in the absence of Modifications made by
- that Contributor.
-
-3. Distribution Obligations.
-
- 3.1. Application of License.
- The Modifications which You create or to which You contribute are
- governed by the terms of this License, including without limitation
- Section 2.2. The Source Code version of Covered Code may be
- distributed only under the terms of this License or a future version
- of this License released under Section 6.1, and You must include a
- copy of this License with every copy of the Source Code You
- distribute. You may not offer or impose any terms on any Source Code
- version that alters or restricts the applicable version of this
- License or the recipients' rights hereunder. However, You may include
- an additional document offering the additional rights described in
- Section 3.5.
-
- 3.2. Availability of Source Code.
- Any Modification which You create or to which You contribute must be
- made available in Source Code form under the terms of this License
- either on the same media as an Executable version or via an accepted
- Electronic Distribution Mechanism to anyone to whom you made an
- Executable version available; and if made available via Electronic
- Distribution Mechanism, must remain available for at least twelve (12)
- months after the date it initially became available, or at least six
- (6) months after a subsequent version of that particular Modification
- has been made available to such recipients. You are responsible for
- ensuring that the Source Code version remains available even if the
- Electronic Distribution Mechanism is maintained by a third party.
-
- 3.3. Description of Modifications.
- You must cause all Covered Code to which You contribute to contain a
- file documenting the changes You made to create that Covered Code and
- the date of any change. You must include a prominent statement that
- the Modification is derived, directly or indirectly, from Original
- Code provided by the Initial Developer and including the name of the
- Initial Developer in (a) the Source Code, and (b) in any notice in an
- Executable version or related documentation in which You describe the
- origin or ownership of the Covered Code.
-
- 3.4. Intellectual Property Matters
- (a) Third Party Claims.
- If Contributor has knowledge that a license under a third party's
- intellectual property rights is required to exercise the rights
- granted by such Contributor under Sections 2.1 or 2.2,
- Contributor must include a text file with the Source Code
- distribution titled "LEGAL" which describes the claim and the
- party making the claim in sufficient detail that a recipient will
- know whom to contact. If Contributor obtains such knowledge after
- the Modification is made available as described in Section 3.2,
- Contributor shall promptly modify the LEGAL file in all copies
- Contributor makes available thereafter and shall take other steps
- (such as notifying appropriate mailing lists or newsgroups)
- reasonably calculated to inform those who received the Covered
- Code that new knowledge has been obtained.
-
- (b) Contributor APIs.
- If Contributor's Modifications include an application programming
- interface and Contributor has knowledge of patent licenses which
- are reasonably necessary to implement that API, Contributor must
- also include this information in the LEGAL file.
-
- (c) Representations.
- Contributor represents that, except as disclosed pursuant to
- Section 3.4(a) above, Contributor believes that Contributor's
- Modifications are Contributor's original creation(s) and/or
- Contributor has sufficient rights to grant the rights conveyed by
- this License.
-
- 3.5. Required Notices.
- You must duplicate the notice in Exhibit A in each file of the Source
- Code. If it is not possible to put such notice in a particular Source
- Code file due to its structure, then You must include such notice in a
- location (such as a relevant directory) where a user would be likely
- to look for such a notice. If You created one or more Modification(s)
- You may add your name as a Contributor to the notice described in
- Exhibit A. You must also duplicate this License in any documentation
- for the Source Code where You describe recipients' rights or ownership
- rights relating to Covered Code. You may choose to offer, and to
- charge a fee for, warranty, support, indemnity or liability
- obligations to one or more recipients of Covered Code. However, You
- may do so only on Your own behalf, and not on behalf of the Initial
- Developer or any Contributor. You must make it absolutely clear than
- any such warranty, support, indemnity or liability obligation is
- offered by You alone, and You hereby agree to indemnify the Initial
- Developer and every Contributor for any liability incurred by the
- Initial Developer or such Contributor as a result of warranty,
- support, indemnity or liability terms You offer.
-
- 3.6. Distribution of Executable Versions.
- You may distribute Covered Code in Executable form only if the
- requirements of Section 3.1-3.5 have been met for that Covered Code,
- and if You include a notice stating that the Source Code version of
- the Covered Code is available under the terms of this License,
- including a description of how and where You have fulfilled the
- obligations of Section 3.2. The notice must be conspicuously included
- in any notice in an Executable version, related documentation or
- collateral in which You describe recipients' rights relating to the
- Covered Code. You may distribute the Executable version of Covered
- Code or ownership rights under a license of Your choice, which may
- contain terms different from this License, provided that You are in
- compliance with the terms of this License and that the license for the
- Executable version does not attempt to limit or alter the recipient's
- rights in the Source Code version from the rights set forth in this
- License. If You distribute the Executable version under a different
- license You must make it absolutely clear that any terms which differ
- from this License are offered by You alone, not by the Initial
- Developer or any Contributor. You hereby agree to indemnify the
- Initial Developer and every Contributor for any liability incurred by
- the Initial Developer or such Contributor as a result of any such
- terms You offer.
-
- 3.7. Larger Works.
- You may create a Larger Work by combining Covered Code with other code
- not governed by the terms of this License and distribute the Larger
- Work as a single product. In such a case, You must make sure the
- requirements of this License are fulfilled for the Covered Code.
-
-4. Inability to Comply Due to Statute or Regulation.
-
- If it is impossible for You to comply with any of the terms of this
- License with respect to some or all of the Covered Code due to
- statute, judicial order, or regulation then You must: (a) comply with
- the terms of this License to the maximum extent possible; and (b)
- describe the limitations and the code they affect. Such description
- must be included in the LEGAL file described in Section 3.4 and must
- be included with all distributions of the Source Code. Except to the
- extent prohibited by statute or regulation, such description must be
- sufficiently detailed for a recipient of ordinary skill to be able to
- understand it.
-
-5. Application of this License.
-
- This License applies to code to which the Initial Developer has
- attached the notice in Exhibit A and to related Covered Code.
-
-6. Versions of the License.
-
- 6.1. New Versions.
- Netscape Communications Corporation ("Netscape") may publish revised
- and/or new versions of the License from time to time. Each version
- will be given a distinguishing version number.
-
- 6.2. Effect of New Versions.
- Once Covered Code has been published under a particular version of the
- License, You may always continue to use it under the terms of that
- version. You may also choose to use such Covered Code under the terms
- of any subsequent version of the License published by Netscape. No one
- other than Netscape has the right to modify the terms applicable to
- Covered Code created under this License.
-
- 6.3. Derivative Works.
- If You create or use a modified version of this License (which you may
- only do in order to apply it to code which is not already Covered Code
- governed by this License), You must (a) rename Your license so that
- the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape",
- "MPL", "NPL" or any confusingly similar phrase do not appear in your
- license (except to note that your license differs from this License)
- and (b) otherwise make it clear that Your version of the license
- contains terms which differ from the Mozilla Public License and
- Netscape Public License. (Filling in the name of the Initial
- Developer, Original Code or Contributor in the notice described in
- Exhibit A shall not of themselves be deemed to be modifications of
- this License.)
-
-7. DISCLAIMER OF WARRANTY.
-
- COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
- WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
- WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF
- DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.
- THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE
- IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,
- YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
- COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER
- OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
- ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
-
-8. TERMINATION.
-
- 8.1. This License and the rights granted hereunder will terminate
- automatically if You fail to comply with terms herein and fail to cure
- such breach within 30 days of becoming aware of the breach. All
- sublicenses to the Covered Code which are properly granted shall
- survive any termination of this License. Provisions which, by their
- nature, must remain in effect beyond the termination of this License
- shall survive.
-
- 8.2. If You initiate litigation by asserting a patent infringement
- claim (excluding declatory judgment actions) against Initial Developer
- or a Contributor (the Initial Developer or Contributor against whom
- You file such action is referred to as "Participant") alleging that:
-
- (a) such Participant's Contributor Version directly or indirectly
- infringes any patent, then any and all rights granted by such
- Participant to You under Sections 2.1 and/or 2.2 of this License
- shall, upon 60 days notice from Participant terminate prospectively,
- unless if within 60 days after receipt of notice You either: (i)
- agree in writing to pay Participant a mutually agreeable reasonable
- royalty for Your past and future use of Modifications made by such
- Participant, or (ii) withdraw Your litigation claim with respect to
- the Contributor Version against such Participant. If within 60 days
- of notice, a reasonable royalty and payment arrangement are not
- mutually agreed upon in writing by the parties or the litigation claim
- is not withdrawn, the rights granted by Participant to You under
- Sections 2.1 and/or 2.2 automatically terminate at the expiration of
- the 60 day notice period specified above.
-
- (b) any software, hardware, or device, other than such Participant's
- Contributor Version, directly or indirectly infringes any patent, then
- any rights granted to You by such Participant under Sections 2.1(b)
- and 2.2(b) are revoked effective as of the date You first made, used,
- sold, distributed, or had made, Modifications made by that
- Participant.
-
- 8.3. If You assert a patent infringement claim against Participant
- alleging that such Participant's Contributor Version directly or
- indirectly infringes any patent where such claim is resolved (such as
- by license or settlement) prior to the initiation of patent
- infringement litigation, then the reasonable value of the licenses
- granted by such Participant under Sections 2.1 or 2.2 shall be taken
- into account in determining the amount or value of any payment or
- license.
-
- 8.4. In the event of termination under Sections 8.1 or 8.2 above,
- all end user license agreements (excluding distributors and resellers)
- which have been validly granted by You or any distributor hereunder
- prior to termination shall survive termination.
-
-9. LIMITATION OF LIABILITY.
-
- UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
- (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL
- DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,
- OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR
- ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
- CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL,
- WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
- COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
- INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
- LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
- RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW
- PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
- EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
- THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
-
-10. U.S. GOVERNMENT END USERS.
-
- The Covered Code is a "commercial item," as that term is defined in
- 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
- software" and "commercial computer software documentation," as such
- terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48
- C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
- all U.S. Government End Users acquire Covered Code with only those
- rights set forth herein.
-
-11. MISCELLANEOUS.
-
- This License represents the complete agreement concerning subject
- matter hereof. If any provision of this License is held to be
- unenforceable, such provision shall be reformed only to the extent
- necessary to make it enforceable. This License shall be governed by
- California law provisions (except to the extent applicable law, if
- any, provides otherwise), excluding its conflict-of-law provisions.
- With respect to disputes in which at least one party is a citizen of,
- or an entity chartered or registered to do business in the United
- States of America, any litigation relating to this License shall be
- subject to the jurisdiction of the Federal Courts of the Northern
- District of California, with venue lying in Santa Clara County,
- California, with the losing party responsible for costs, including
- without limitation, court costs and reasonable attorneys' fees and
- expenses. The application of the United Nations Convention on
- Contracts for the International Sale of Goods is expressly excluded.
- Any law or regulation which provides that the language of a contract
- shall be construed against the drafter shall not apply to this
- License.
-
-12. RESPONSIBILITY FOR CLAIMS.
-
- As between Initial Developer and the Contributors, each party is
- responsible for claims and damages arising, directly or indirectly,
- out of its utilization of rights under this License and You agree to
- work with Initial Developer and Contributors to distribute such
- responsibility on an equitable basis. Nothing herein is intended or
- shall be deemed to constitute any admission of liability.
-
-13. MULTIPLE-LICENSED CODE.
-
- Initial Developer may designate portions of the Covered Code as
- "Multiple-Licensed". "Multiple-Licensed" means that the Initial
- Developer permits you to utilize portions of the Covered Code under
- Your choice of the NPL or the alternative licenses, if any, specified
- by the Initial Developer in the file described in Exhibit A.
-
-EXHIBIT A -Mozilla Public License.
-
- ``The contents of this file are subject to the Mozilla Public License
- Version 1.1 (the "License"); you may not use this file except in
- compliance with the License. You may obtain a copy of the License at
- http://www.mozilla.org/MPL/
-
- Software distributed under the License is distributed on an "AS IS"
- basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
- License for the specific language governing rights and limitations
- under the License.
-
- The Original Code is RabbitMQ.
-
- The Initial Developer of the Original Code is GoPivotal, Inc.
- Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved.''
-
- [NOTE: The text of this Exhibit A may differ slightly from the text of
- the notices in the Source Code files of the Original Code. You should
- use the text of this Exhibit A rather than the text found in the
- Original Code Source Code for Your Modifications.]
-
-
-The Debian packaging is (C) 2007-2013, GoPivotal, Inc. and is licensed
-under the MPL 1.1, see above.
-
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: RabbitMQ
+Source: http://www.rabbitmq.com/
+
+Files: debian/*
+Copyright: (c) 2007-2013, GoPivotal, Inc.
+ (c) 2007, Tony Garnock-Jones <tonyg@rabbitmq.com>
+ (c) 2014, Blair Hester <bhester@gopivotal.com>
+ (c) 2012-2014, Emile Joubert <emile@rabbitmq.com>
+ (c) 2008-2012, John Leuner <jewel@debian.org>
+ (c) 2014, James Page <james.page@canonical.com>
+ (c) 2014, Thomas Goirand <zigo@debian.org>
+License: MPL-1.1
+
+Files: codegen/amqp-rabbitmq-*.json
+Copyright: (c) 2008-2013, GoPivotal Inc.
+License: Expat
+
+Files: plugins-src/rabbitmq-management/priv/www/js/jquery*.js
+Copyright: (c) 2010 John Resig
+License: Expat
+Comments: Downloaded from http://jquery.com/
+
+Files: plugins-src/rabbitmq-management/priv/www/js/ejs*
+ plugins-src/rabbitmq-management/priv/www/js/tmpl
+Copyright: (c) 2007, Edward Benson
+License: Expat
+Comments: downloaded from http://embeddedjs.com/
+
+Files: plugins-src/rabbitmq-management/priv/www/js/sammy*.js
+Copyright: (c) 2008 Aaron Quint, Quirkey NYC, LLC
+License: Expat
+Comments: Downloaded from http://code.quirkey.com/sammy/
+
+Files: plugins-src/rabbitmq-management/priv/www/js/excanvas*.js
+Copyright: (c) 2006, Google Inc
+License: Apache-2.0
+Comments: Downloaded from http://code.google.com/p/explorercanvas/
+
+Files: plugins-src/rabbitmq-management/priv/www/js/jquery.flot*.js
+Copyright: (c) 2007-2013, IOLA and Ole Laursen
+License: Expat
+Comments: Downloaded from http://www.flotcharts.org/
+
+Files: plugins-src/webmachine-wrapper/*
+Copyright: (c) Basho Technologies
+License: Apache-2.0
+Comments: Downloaded from http://webmachine.basho.com/
+
+Files: plugins-src/eldap-wrapper/*
+Copyright: (c) 2010, Torbjorn Tornkvist
+License: Expat
+Comments: Downloaded from https://github.com/etnt/eldap
+
+Files: plugins-src/mochiweb-wrapper/mochiweb-git/*
+Copyright: (c) 2007, Mochi Media, Inc.
+License: Expat
+Comments: Downloaded from http://github.com/mochi/mochiweb/
+
+Files:
+ plugins-src/rabbitmq-management-visualiser/priv/www/visualiser/js/glMatrix*.js
+Copyright: (c) 2011, Brandon Jones
+License: BSD-2-Clause
+Comments: Downloaded from http://code.google.com/p/glmatrix/
+
+Files: *
+Copyright: (c) 2007-2014 GoPivotal, Inc.
+License: MPL-1.1
+
+License: Expat
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this file (the Software), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the following
+ conditions:
+ .
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+ .
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE."
+
+License: BSD-2-Clause
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ .
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ .
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ .
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE."
+
+License: MPL-1.1
+ MOZILLA PUBLIC LICENSE Version 1.1
+ 1. Definitions.
+ .
+ 1.0.1. "Commercial Use" means distribution or otherwise making the Covered
+ Code available to a third party.
+ .
+ 1.1. "Contributor" means each entity that creates or contributes to the
+ creation of Modifications.
+ .
+ 1.2. "Contributor Version" means the combination of the Original Code, prior
+ Modifications used by a Contributor, and the Modifications made by that
+ particular Contributor.
+ .
+ 1.3. "Covered Code" means the Original Code or Modifications or the
+ combination of the Original Code and Modifications, in each case including
+ portions thereof.
+ .
+ 1.4. "Electronic Distribution Mechanism" means a mechanism generally accepted
+ in the software development community for the electronic transfer of data.
+ .
+ 1.5. "Executable" means Covered Code in any form other than Source Code.
+ .
+ 1.6. "Initial Developer" means the individual or entity identified as the
+ Initial Developer in the Source Code notice required by Exhibit A.
+ .
+ 1.7. "Larger Work" means a work which combines Covered Code or portions
+ thereof with code not governed by the terms of this License.
+ .
+ 1.8. "License" means this document.
+ .
+ 1.8.1. "Licensable" means having the right to grant, to the maximum extent
+ possible, whether at the time of the initial grant or subsequently acquired,
+ any and all of the rights conveyed herein.
+ .
+ 1.9. "Modifications" means any addition to or deletion from the substance or
+ structure of either the Original Code or any previous Modifications. When
+ Covered Code is released as a series of files, a Modification is:
+ .
+ A. Any addition to or deletion from the contents of a file containing
+ Original Code or previous Modifications.
+ .
+ B. Any new file that contains any part of the Original Code or previous
+ Modifications.
+ .
+ 1.10. "Original Code" means Source Code of computer software code which is
+ described in the Source Code notice required by Exhibit A as Original Code,
+ and which, at the time of its release under this License is not already
+ Covered Code governed by this License.
+ .
+ 1.10.1. "Patent Claims" means any patent claim(s), now owned or hereafter
+ acquired, including without limitation, method, process, and apparatus
+ claims, in any patent Licensable by grantor.
+ .
+ 1.11. "Source Code" means the preferred form of the Covered Code for making
+ modifications to it, including all modules it contains, plus any associated
+ interface definition files, scripts used to control compilation and
+ installation of an Executable, or source code differential comparisons
+ against either the Original Code or another well known, available Covered
+ Code of the Contributor's choice. The Source Code can be in a compressed or
+ archival form, provided the appropriate decompression or de-archiving
+ software is widely available for no charge.
+ .
+ 1.12. "You" (or "Your") means an individual or a legal entity exercising
+ rights under, and complying with all of the terms of, this License or a
+ future version of this License issued under Section 6.1. For legal entities,
+ "You" includes any entity which controls, is controlled by, or is under
+ common control with You. For purposes of this definition, "control" means (a)
+ the power, direct or indirect, to cause the direction or management of such
+ entity, whether by contract or otherwise, or (b) ownership of more than fifty
+ percent (50%) of the outstanding shares or beneficial ownership of such
+ entity.
+ .
+ 2. Source Code License.
+ .
+ 2.1. The Initial Developer Grant.
+ The Initial Developer hereby grants You a world-wide, royalty-free,
+ non-exclusive license, subject to third party intellectual property claims:
+ .
+ (a) under intellectual property rights (other than patent or
+ trademark) Licensable by Initial Developer to use, reproduce,
+ modify, display, perform, sublicense and distribute the Original
+ Code (or portions thereof) with or without Modifications, and/or
+ as part of a Larger Work; and
+ .
+ (b) under Patents Claims infringed by the making, using or
+ selling of Original Code, to make, have made, use, practice,
+ sell, and offer for sale, and/or otherwise dispose of the
+ Original Code (or portions thereof).
+ .
+ (c) the licenses granted in this Section 2.1(a) and (b) are
+ effective on the date Initial Developer first distributes
+ Original Code under the terms of this License.
+ .
+ (d) Notwithstanding Section 2.1(b) above, no patent license is
+ granted: 1) for code that You delete from the Original Code; 2)
+ separate from the Original Code; or 3) for infringements caused
+ by: i) the modification of the Original Code or ii) the
+ combination of the Original Code with other software or devices.
+ .
+ 2.2. Contributor Grant.
+ Subject to third party intellectual property claims, each Contributor hereby
+ grants You a world-wide, royalty-free, non-exclusive license
+ .
+ (a) under intellectual property rights (other than patent or
+ trademark) Licensable by Contributor, to use, reproduce, modify,
+ display, perform, sublicense and distribute the Modifications
+ created by such Contributor (or portions thereof) either on an
+ unmodified basis, with other Modifications, as Covered Code
+ and/or as part of a Larger Work; and
+ .
+ (b) under Patent Claims infringed by the making, using, or
+ selling of Modifications made by that Contributor either alone
+ and/or in combination with its Contributor Version (or portions
+ of such combination), to make, use, sell, offer for sale, have
+ made, and/or otherwise dispose of: 1) Modifications made by that
+ Contributor (or portions thereof); and 2) the combination of
+ Modifications made by that Contributor with its Contributor
+ Version (or portions of such combination).
+ .
+ (c) the licenses granted in Sections 2.2(a) and 2.2(b) are
+ effective on the date Contributor first makes Commercial Use of
+ the Covered Code.
+ .
+ (d) Notwithstanding Section 2.2(b) above, no patent license is
+ granted: 1) for any code that Contributor has deleted from the
+ Contributor Version; 2) separate from the Contributor Version;
+ 3) for infringements caused by: i) third party modifications of
+ Contributor Version or ii) the combination of Modifications made
+ by that Contributor with other software (except as part of the
+ Contributor Version) or other devices; or 4) under Patent Claims
+ infringed by Covered Code in the absence of Modifications made by
+ that Contributor.
+ .
+ 3. Distribution Obligations.
+ .
+ 3.1. Application of License.
+ .
+ The Modifications which You create or to which You contribute are governed by
+ the terms of this License, including without limitation Section 2.2. The
+ Source Code version of Covered Code may be distributed only under the terms of
+ this License or a future version of this License released under Section 6.1,
+ and You must include a copy of this License with every copy of the Source Code
+ You distribute. You may not offer or impose any terms on any Source Code
+ version that alters or restricts the applicable version of this License or the
+ recipients' rights hereunder. However, You may include an additional document
+ offering the additional rights described in Section 3.5.
+ .
+ 3.2. Availability of Source Code.
+ .
+ Any Modification which You create or to which You contribute must be made
+ available in Source Code form under the terms of this License either on the
+ same media as an Executable version or via an accepted Electronic Distribution
+ Mechanism to anyone to whom you made an Executable version available; and if
+ made available via Electronic Distribution Mechanism, must remain available
+ for at least twelve (12) months after the date it initially became available,
+ or at least six (6) months after a subsequent version of that particular
+ Modification has been made available to such recipients. You are responsible
+ for ensuring that the Source Code version remains available even if the
+ Electronic Distribution Mechanism is maintained by a third party.
+ .
+ 3.3. Description of Modifications.
+ .
+ You must cause all Covered Code to which You contribute to contain a file
+ documenting the changes You made to create that Covered Code and the date of
+ any change. You must include a prominent statement that the Modification is
+ derived, directly or indirectly, from Original Code provided by the Initial
+ Developer and including the name of the Initial Developer in (a) the Source
+ Code, and (b) in any notice in an Executable version or related documentation
+ in which You describe the origin or ownership of the Covered Code.
+ .
+ 3.4. Intellectual Property Matters
+ .
+ (a) Third Party Claims.
+ .
+ If Contributor has knowledge that a license under a third party's
+ intellectual property rights is required to exercise the rights
+ granted by such Contributor under Sections 2.1 or 2.2,
+ Contributor must include a text file with the Source Code
+ distribution titled "LEGAL" which describes the claim and the
+ party making the claim in sufficient detail that a recipient will
+ know whom to contact. If Contributor obtains such knowledge after
+ the Modification is made available as described in Section 3.2,
+ Contributor shall promptly modify the LEGAL file in all copies
+ Contributor makes available thereafter and shall take other steps
+ (such as notifying appropriate mailing lists or newsgroups)
+ reasonably calculated to inform those who received the Covered
+ Code that new knowledge has been obtained.
+ .
+ (b) Contributor APIs.
+ .
+ If Contributor's Modifications include an application programming
+ interface and Contributor has knowledge of patent licenses which
+ are reasonably necessary to implement that API, Contributor must
+ also include this information in the LEGAL file.
+ .
+ (c) Representations.
+ .
+ Contributor represents that, except as disclosed pursuant to
+ Section 3.4(a) above, Contributor believes that Contributor's
+ Modifications are Contributor's original creation(s) and/or
+ Contributor has sufficient rights to grant the rights conveyed by
+ this License.
+ .
+ 3.5. Required Notices.
+ .
+ You must duplicate the notice in Exhibit A in each file of the Source
+ Code. If it is not possible to put such notice in a particular Source
+ Code file due to its structure, then You must include such notice in a
+ location (such as a relevant directory) where a user would be likely
+ to look for such a notice. If You created one or more Modification(s)
+ You may add your name as a Contributor to the notice described in
+ Exhibit A. You must also duplicate this License in any documentation
+ for the Source Code where You describe recipients' rights or ownership
+ rights relating to Covered Code. You may choose to offer, and to
+ charge a fee for, warranty, support, indemnity or liability
+ obligations to one or more recipients of Covered Code. However, You
+ may do so only on Your own behalf, and not on behalf of the Initial
+ Developer or any Contributor. You must make it absolutely clear than
+ any such warranty, support, indemnity or liability obligation is
+ offered by You alone, and You hereby agree to indemnify the Initial
+ Developer and every Contributor for any liability incurred by the
+ Initial Developer or such Contributor as a result of warranty,
+ support, indemnity or liability terms You offer.
+ .
+ 3.6. Distribution of Executable Versions.
+ .
+ You may distribute Covered Code in Executable form only if the
+ requirements of Section 3.1-3.5 have been met for that Covered Code,
+ and if You include a notice stating that the Source Code version of
+ the Covered Code is available under the terms of this License,
+ including a description of how and where You have fulfilled the
+ obligations of Section 3.2. The notice must be conspicuously included
+ in any notice in an Executable version, related documentation or
+ collateral in which You describe recipients' rights relating to the
+ Covered Code. You may distribute the Executable version of Covered
+ Code or ownership rights under a license of Your choice, which may
+ contain terms different from this License, provided that You are in
+ compliance with the terms of this License and that the license for the
+ Executable version does not attempt to limit or alter the recipient's
+ rights in the Source Code version from the rights set forth in this
+ License. If You distribute the Executable version under a different
+ license You must make it absolutely clear that any terms which differ
+ from this License are offered by You alone, not by the Initial
+ Developer or any Contributor. You hereby agree to indemnify the
+ Initial Developer and every Contributor for any liability incurred by
+ the Initial Developer or such Contributor as a result of any such
+ terms You offer.
+ .
+ 3.7. Larger Works.
+ .
+ You may create a Larger Work by combining Covered Code with other code
+ not governed by the terms of this License and distribute the Larger
+ Work as a single product. In such a case, You must make sure the
+ requirements of this License are fulfilled for the Covered Code.
+ .
+ 4. Inability to Comply Due to Statute or Regulation.
+ .
+ If it is impossible for You to comply with any of the terms of this
+ License with respect to some or all of the Covered Code due to
+ statute, judicial order, or regulation then You must: (a) comply with
+ the terms of this License to the maximum extent possible; and (b)
+ describe the limitations and the code they affect. Such description
+ must be included in the LEGAL file described in Section 3.4 and must
+ be included with all distributions of the Source Code. Except to the
+ extent prohibited by statute or regulation, such description must be
+ sufficiently detailed for a recipient of ordinary skill to be able to
+ understand it.
+ .
+ 5. Application of this License.
+ .
+ This License applies to code to which the Initial Developer has
+ attached the notice in Exhibit A and to related Covered Code.
+ .
+ 6. Versions of the License.
+ .
+ 6.1. New Versions.
+ .
+ Netscape Communications Corporation ("Netscape") may publish revised
+ and/or new versions of the License from time to time. Each version
+ will be given a distinguishing version number.
+ .
+ 6.2. Effect of New Versions.
+ .
+ Once Covered Code has been published under a particular version of the
+ License, You may always continue to use it under the terms of that
+ version. You may also choose to use such Covered Code under the terms
+ of any subsequent version of the License published by Netscape. No one
+ other than Netscape has the right to modify the terms applicable to
+ Covered Code created under this License.
+ .
+ 6.3. Derivative Works.
+ .
+ If You create or use a modified version of this License (which you may
+ only do in order to apply it to code which is not already Covered Code
+ governed by this License), You must (a) rename Your license so that
+ the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape",
+ "MPL", "NPL" or any confusingly similar phrase do not appear in your
+ license (except to note that your license differs from this License)
+ and (b) otherwise make it clear that Your version of the license
+ contains terms which differ from the Mozilla Public License and
+ Netscape Public License. (Filling in the name of the Initial
+ Developer, Original Code or Contributor in the notice described in
+ Exhibit A shall not of themselves be deemed to be modifications of
+ this License.)
+ .
+ 7. DISCLAIMER OF WARRANTY.
+ .
+ COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF
+ DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.
+ THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE
+ IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,
+ YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
+ COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER
+ OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
+ ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
+ .
+ 8. TERMINATION.
+ .
+ 8.1. This License and the rights granted hereunder will terminate
+ automatically if You fail to comply with terms herein and fail to cure
+ such breach within 30 days of becoming aware of the breach. All
+ sublicenses to the Covered Code which are properly granted shall
+ survive any termination of this License. Provisions which, by their
+ nature, must remain in effect beyond the termination of this License
+ shall survive.
+ .
+ 8.2. If You initiate litigation by asserting a patent infringement
+ claim (excluding declatory judgment actions) against Initial Developer
+ or a Contributor (the Initial Developer or Contributor against whom
+ You file such action is referred to as "Participant") alleging that:
+ .
+ (a) such Participant's Contributor Version directly or indirectly
+ infringes any patent, then any and all rights granted by such
+ Participant to You under Sections 2.1 and/or 2.2 of this License
+ shall, upon 60 days notice from Participant terminate prospectively,
+ unless if within 60 days after receipt of notice You either: (i)
+ agree in writing to pay Participant a mutually agreeable reasonable
+ royalty for Your past and future use of Modifications made by such
+ Participant, or (ii) withdraw Your litigation claim with respect to
+ the Contributor Version against such Participant. If within 60 days
+ of notice, a reasonable royalty and payment arrangement are not
+ mutually agreed upon in writing by the parties or the litigation claim
+ is not withdrawn, the rights granted by Participant to You under
+ Sections 2.1 and/or 2.2 automatically terminate at the expiration of
+ the 60 day notice period specified above.
+ .
+ (b) any software, hardware, or device, other than such Participant's
+ Contributor Version, directly or indirectly infringes any patent, then
+ any rights granted to You by such Participant under Sections 2.1(b)
+ and 2.2(b) are revoked effective as of the date You first made, used,
+ sold, distributed, or had made, Modifications made by that
+ Participant.
+ .
+ 8.3. If You assert a patent infringement claim against Participant
+ alleging that such Participant's Contributor Version directly or
+ indirectly infringes any patent where such claim is resolved (such as
+ by license or settlement) prior to the initiation of patent
+ infringement litigation, then the reasonable value of the licenses
+ granted by such Participant under Sections 2.1 or 2.2 shall be taken
+ into account in determining the amount or value of any payment or
+ license.
+ .
+ 8.4. In the event of termination under Sections 8.1 or 8.2 above,
+ all end user license agreements (excluding distributors and resellers)
+ which have been validly granted by You or any distributor hereunder
+ prior to termination shall survive termination.
+ .
+ 9. LIMITATION OF LIABILITY.
+ .
+ UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
+ (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL
+ DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,
+ OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR
+ ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
+ CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL,
+ WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
+ COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
+ INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
+ LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
+ RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW
+ PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
+ EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
+ THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
+ .
+ 10. U.S. GOVERNMENT END USERS.
+ .
+ The Covered Code is a "commercial item," as that term is defined in
+ 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
+ software" and "commercial computer software documentation," as such
+ terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48
+ C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
+ all U.S. Government End Users acquire Covered Code with only those
+ rights set forth herein.
+ .
+ 11. MISCELLANEOUS.
+ .
+ This License represents the complete agreement concerning subject
+ matter hereof. If any provision of this License is held to be
+ unenforceable, such provision shall be reformed only to the extent
+ necessary to make it enforceable. This License shall be governed by
+ California law provisions (except to the extent applicable law, if
+ any, provides otherwise), excluding its conflict-of-law provisions.
+ With respect to disputes in which at least one party is a citizen of,
+ or an entity chartered or registered to do business in the United
+ States of America, any litigation relating to this License shall be
+ subject to the jurisdiction of the Federal Courts of the Northern
+ District of California, with venue lying in Santa Clara County,
+ California, with the losing party responsible for costs, including
+ without limitation, court costs and reasonable attorneys' fees and
+ expenses. The application of the United Nations Convention on
+ Contracts for the International Sale of Goods is expressly excluded.
+ Any law or regulation which provides that the language of a contract
+ shall be construed against the drafter shall not apply to this
+ License.
+ .
+ 12. RESPONSIBILITY FOR CLAIMS.
+ .
+ As between Initial Developer and the Contributors, each party is
+ responsible for claims and damages arising, directly or indirectly,
+ out of its utilization of rights under this License and You agree to
+ work with Initial Developer and Contributors to distribute such
+ responsibility on an equitable basis. Nothing herein is intended or
+ shall be deemed to constitute any admission of liability.
+ .
+ 13. MULTIPLE-LICENSED CODE.
+ .
+ Initial Developer may designate portions of the Covered Code as
+ "Multiple-Licensed". "Multiple-Licensed" means that the Initial
+ Developer permits you to utilize portions of the Covered Code under
+ Your choice of the NPL or the alternative licenses, if any, specified
+ by the Initial Developer in the file described in Exhibit A.
+ .
+ EXHIBIT A -Mozilla Public License.
+ .
+ The contents of this file are subject to the Mozilla Public License Version
+ 1.1 (the "License"); you may not use this file except in compliance with the
+ License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+ .
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+ the specific language governing rights and limitations under the License.
+ .
+ The Original Code is RabbitMQ.
+ .
+ The Initial Developer of the Original Code is GoPivotal, Inc. Copyright (c)
+ 2007-2014 GoPivotal, Inc. All rights reserved.
+
+License: Apache-2.0
+ On Debian GNU/Linux system you can find the complete text of the
+ Apache-2.0 license in '/usr/share/common-licenses/Apache-2.0'
+++ /dev/null
-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
-
--- /dev/null
+[DEFAULT]
+debian-branch = master
+pristine-tar = True
+
+[buildpackage]
+export-dir = ../build-area/
--- /dev/null
+# 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
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}"
--- /dev/null
+#!/bin/sh -e
+## The contents of this file are subject to the Mozilla Public License
+## Version 1.1 (the "License"); you may not use this file except in
+## compliance with the License. You may obtain a copy of the License
+## at http://www.mozilla.org/MPL/
+##
+## Software distributed under the License is distributed on an "AS IS"
+## basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+## the License for the specific language governing rights and
+## limitations under the License.
+##
+## The Original Code is RabbitMQ.
+##
+## The Initial Developer of the Original Code is GoPivotal, Inc.
+## Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved.
+##
+
+# Get default settings with user overrides for (RABBITMQ_)<var_name>
+# Non-empty defaults should be set in rabbitmq-env
+. `dirname $0`/rabbitmq-env
+
+/usr/lib/rabbitmq/bin/rabbitmqctl wait $RABBITMQ_PID_FILE
# 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
-
--- /dev/null
+usr/lib/erlang/lib
+var/lib/rabbitmq/mnesia
+var/log/rabbitmq
--- /dev/null
+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
--- /dev/null
+/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
--- /dev/null
+[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
#!/usr/bin/make -f
+# -*- makefile -*-
+#export DH_VERBOSE=1
-include /usr/share/cdbs/1/rules/debhelper.mk
-include /usr/share/cdbs/1/class/makefile.mk
+%:
+ dh $@ --parallel --with systemd
-RABBIT_LIB=$(DEB_DESTDIR)usr/lib/rabbitmq/lib/rabbitmq_server-$(DEB_UPSTREAM_VERSION)/
-RABBIT_BIN=$(DEB_DESTDIR)usr/lib/rabbitmq/bin/
+override_dh_systemd_enable:
+ dh_systemd_enable --no-enable
-DOCDIR=$(DEB_DESTDIR)usr/share/doc/rabbitmq-server/
-DEB_MAKE_INSTALL_TARGET := install TARGET_DIR=$(RABBIT_LIB) SBIN_DIR=$(RABBIT_BIN) DOC_INSTALL_DIR=$(DOCDIR) MAN_DIR=$(DEB_DESTDIR)usr/share/man/
-DEB_MAKE_CLEAN_TARGET:= distclean
-DEB_INSTALL_DOCS_ALL=debian/README
+override_dh_systemd_start:
+ dh_systemd_start --no-start
-DEB_DH_INSTALLINIT_ARGS="--no-start"
+override_dh_installinit:
+ dh_installinit --noscripts
-install/rabbitmq-server::
- mkdir -p $(DOCDIR)
- rm $(RABBIT_LIB)LICENSE* $(RABBIT_LIB)INSTALL*
- for script in rabbitmqctl rabbitmq-server rabbitmq-plugins; do \
- install -p -D -m 0755 debian/rabbitmq-script-wrapper $(DEB_DESTDIR)usr/sbin/$$script; \
- done
- sed -e 's|@RABBIT_LIB@|/usr/lib/rabbitmq/lib/rabbitmq_server-$(DEB_UPSTREAM_VERSION)|g' <debian/postrm.in >debian/postrm
- install -p -D -m 0755 debian/rabbitmq-server.ocf $(DEB_DESTDIR)usr/lib/ocf/resource.d/rabbitmq/rabbitmq-server
- install -p -D -m 0644 debian/rabbitmq-server.default $(DEB_DESTDIR)etc/default/rabbitmq-server
-clean::
- rm -f plugins-src/rabbitmq-server debian/postrm plugins/README
+DEB_UPSTREAM_VERSION=$(shell dpkg-parsechangelog | sed -rne 's,^Version: ([^+]+)-.*,\1,p')
+DEB_DESTDIR=debian/rabbitmq-server
+RABBIT_LIB=$(DEB_DESTDIR)/usr/lib/rabbitmq/lib/rabbitmq_server-$(DEB_UPSTREAM_VERSION)
+RABBIT_BIN=$(DEB_DESTDIR)/usr/lib/rabbitmq/bin
+DOCDIR=$(DEB_DESTDIR)/usr/share/doc/rabbitmq-server
+
+override_dh_auto_install:
+ dh_auto_install -- TARGET_DIR=$(RABBIT_LIB) SBIN_DIR=$(RABBIT_BIN) \
+ DOC_INSTALL_DIR=$(DOCDIR) MAN_DIR=$(DEB_DESTDIR)/usr/share/man
+ rm -f $(RABBIT_LIB)/LICENSE* $(RABBIT_LIB)/INSTALL*
+
+override_dh_auto_clean:
+ rm -f plugins-src/rabbitmq-server plugins/README
+ dh_auto_clean
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
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
$(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=.
##
## 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.
##
%%
%% 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.
%%"""
all:
- echo "Please select a target from the Makefile."
+ @echo "Please select a target from the Makefile."
clean:
rm -f *.pyc
{application, rabbit, %% -*- erlang -*-
[{description, "RabbitMQ"},
{id, "RabbitMQ"},
- {vsn, "3.5.4"},
+ {vsn, "3.5.6"},
{modules, []},
{registered, [rabbit_amqqueue_sup,
rabbit_log,
%% breaks the QPid Java client
{frame_max, 131072},
{channel_max, 0},
- {heartbeat, 580},
+ {heartbeat, 60},
{msg_store_file_size_limit, 16777216},
- {queue_index_max_journal_entries, 65536},
+ {fhc_write_buffering, true},
+ {fhc_read_buffering, true},
+ {queue_index_max_journal_entries, 32768},
{queue_index_embed_msgs_below, 4096},
{default_user, <<"guest">>},
{default_pass, <<"guest">>},
gen_fsm, ssl]},
{ssl_apps, [asn1, crypto, public_key, ssl]},
%% see rabbitmq-server#114
- {mirroring_flow_control, true}
+ {mirroring_flow_control, true},
+ %% see rabbitmq-server#227 and related tickets.
+ %% msg_store_credit_disc_bound only takes effect when
+ %% messages are persisted to the message store. If messages
+ %% are embedded on the queue index, then modifying this
+ %% setting has no effect because credit_flow is not used when
+ %% writing to the queue index. See the setting
+ %% queue_index_embed_msgs_below above.
+ {msg_store_credit_disc_bound, {2000, 500}},
+ {msg_store_io_batch_size, 2048},
+ %% see rabbitmq-server#143
+ {credit_flow_default_credit, {200, 50}}
]}]}.
%%
%% 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.
%%
%%
%% The Original Code is RabbitMQ.
%%
-%% The Initial Developer of the Original Code is GoPivotal, Inc.
+%% The Initial Developer of the Original Code is Pivotal Software, Inc.
%% Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved.
%%
-define(HIBERNATE_AFTER_MIN, 1000).
-define(DESIRED_HIBERNATE, 10000).
-define(CREDIT_DISC_BOUND, {2000, 500}).
+%% When we discover that we should write some indices to disk for some
+%% betas, the IO_BATCH_SIZE sets the number of betas that we must be
+%% due to write indices for before we do any work at all.
+-define(IO_BATCH_SIZE, 2048). %% next power-of-2 after ?CREDIT_DISC_BOUND
-define(INVALID_HEADERS_KEY, <<"x-invalid-headers">>).
-define(ROUTING_HEADERS, [<<"CC">>, <<"BCC">>]).
%%
%% 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.
%%
%%
%% 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.
%%
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
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) ->
%% 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),
--- /dev/null
+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
%% -*- 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"},
{'not', {equals, "${username}", "Mike Bridgen"}}]}
]}}
]}}
- ]}}
+ ]}},
+ {tag_queries, [{administrator, {constant, false}},
+ {management, {constant, false}}]}
]}
].
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,
-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
%%--------------------------------------------------------------------
-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">>},
{?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">>},
{?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}) ->
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).
+
--- /dev/null
+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
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.
-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.
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) ->
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,
[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.
rabbit_queue_collector,
rabbit_queue_decorator,
rabbit_amqqueue,
- supervisor2
+ ssl_compat,
+ supervisor2,
+ time_compat
]},
{registered, []},
{env, []},
'Maximum number of unacknowledged messages that may be in flight over a federation link at one time. Defaults to 1000 if not set.';
HELP['federation-reconnect'] =
- 'Time in seconds to wait after a network link goes down before attempting reconnection. Defaults to 1 if not set.';
+ 'Time in seconds to wait after a network link goes down before attempting reconnection. Defaults to 5 if not set.';
HELP['federation-ack-mode'] =
'<dl>\
+++ /dev/null
-Generic build instructions are at:
- http://www.rabbitmq.com/plugin-development.html
-
-See http://www.rabbitmq.com/federation.html
--- /dev/null
+## 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.
%% 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">>;
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),
-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">>}].
--- /dev/null
+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
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) {
xmerl_ucs:from_utf8(V),
V
catch exit:{ucs, _} ->
- Enc = base64:encode(V),
- <<"Invalid UTF-8, base64 is: ", Enc/binary>>
+ Enc = split_lines(base64:encode(V)),
+ <<"Not UTF-8, base64 is: ", Enc/binary>>
end.
+% MIME enforces a limit on line length of base 64-encoded data to 76 characters.
+split_lines(<<Text:76/binary, Rest/binary>>) ->
+ <<Text/binary, $\n, (split_lines(Rest))/binary>>;
+split_lines(Text) ->
+ Text.
+
parameter(P) -> pset(value, rabbit_misc:term_to_json(pget(value, P)), P).
tuple(unknown) -> unknown;
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())
# 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)
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
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
{QueueQ1,
#'queue.declare'{ queue = QueueQ1,
durable = true,
- auto_delete = CleanSess,
+ auto_delete = false,
arguments = Qos1Args },
#'basic.consume'{ queue = QueueQ1,
no_ack = false }};
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) ->
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 {
mqttOut.flush();
mqttIn.readMqttWireMessage();
fail("Error expected if CONNECT is not first packet");
- } catch (IOException _) {}
+ } catch (IOException ignored) {}
}
public void testInvalidUser() throws MqttException {
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) {
}
}
--- /dev/null
+%% 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)).
--- /dev/null
+{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]}]}.
--- /dev/null
+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
--- /dev/null
+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)
+
-define(HEADER_PREFETCH_COUNT, "prefetch-count").
-define(HEADER_PRIORITY, "priority").
-define(HEADER_RECEIPT, "receipt").
+-define(HEADER_REDELIVERED, "redelivered").
-define(HEADER_REPLY_TO, "reply-to").
-define(HEADER_SERVER, "server").
-define(HEADER_SESSION, "session").
-define(HEADER_TYPE, "type").
-define(HEADER_USER_ID, "user-id").
-define(HEADER_VERSION, "version").
+-define(HEADER_X_DEAD_LETTER_EXCHANGE, "x-dead-letter-exchange").
+-define(HEADER_X_DEAD_LETTER_ROUTING_KEY, "x-dead-letter-routing-key").
+-define(HEADER_X_EXPIRES, "x-expires").
+-define(HEADER_X_MAX_LENGTH, "x-max-length").
+-define(HEADER_X_MAX_LENGTH_BYTES, "x-max-length-bytes").
+-define(HEADER_X_MAX_PRIORITY, "x-max-priority").
+-define(HEADER_X_MESSAGE_TTL, "x-message-ttl").
-define(MESSAGE_ID_SEPARATOR, "@@").
-define(HEADERS_NOT_ON_SEND, [?HEADER_MESSAGE_ID]).
-define(TEMP_QUEUE_ID_PREFIX, "/temp-queue/").
+
+-define(HEADER_ARGUMENTS, [
+ ?HEADER_X_DEAD_LETTER_EXCHANGE,
+ ?HEADER_X_DEAD_LETTER_ROUTING_KEY,
+ ?HEADER_X_EXPIRES,
+ ?HEADER_X_MAX_LENGTH,
+ ?HEADER_X_MAX_LENGTH_BYTES,
+ ?HEADER_X_MAX_PRIORITY,
+ ?HEADER_X_MESSAGE_TTL
+ ]).
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
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
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.
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,
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].
-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}).
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}
}.
_ -> 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.
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
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
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) ->
-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]).
#'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}];
_ -> []
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)}];
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
%%--------------------------------------------------------------------
{packet, raw},
{reuseaddr, true},
{backlog, 128},
- {nodelay, true}]}]},
+ {nodelay, true}]},
+ %% see rabbitmq/rabbitmq-stomp#39
+ {trailing_lf, true}]},
{applications, [kernel, stdlib, rabbit, amqp_client]}]}.
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)
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()
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):
self.assertEquals("'" + content + "' is not a valid " +
dtype + " destination\n",
err['message'])
-
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'
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')
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')
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'
'subscription:(.*)\n'
'destination:/topic/da9d4779\n'
'message-id:(.*)\n'
+ 'redelivered:false\n'
'content-type:text/plain\n'
'content-length:8\n'
'\n'
'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)
'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)
--- /dev/null
+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()
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);
rabbit_stomp_client:send(
Client, "LOL", [{"", ""}])
end,
- lists:seq(1, 1000)),
+ lists:seq(1, 100)),
timer:sleep(5000),
N = count_connections(),
ok.
#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").
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()).
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".
--- /dev/null
+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()
if __name__ == '__main__':
modules = [
- 'parsing',
- 'destinations',
- 'lifecycle',
- 'transactions',
'ack',
+ 'destinations',
'errors',
+ 'lifecycle',
+ 'parsing',
+ 'queue_properties',
+ 'redelivered',
'reliability',
+ 'transactions',
]
test_runner.run_unittests(modules)
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()
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
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
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)
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
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
)
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
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))
# 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
\r
set RABBITMQ_START_RABBIT=\r
if "!RABBITMQ_NODE_ONLY!"=="" (\r
- set RABBITMQ_START_RABBIT=-s rabbit boot\r
+ set RABBITMQ_START_RABBIT=-s "!RABBITMQ_BOOT_MODULE!" boot\r
)\r
\r
if "!RABBITMQ_IO_THREAD_POOL_SIZE!"=="" (\r
+W w ^\r
+A "!RABBITMQ_IO_THREAD_POOL_SIZE!" ^\r
+P 1048576 ^\r
--kernel inet_default_connect_options "[{nodelay,true}]" ^\r
!RABBITMQ_LISTEN_ARG! ^\r
!RABBITMQ_SERVER_ERL_ARGS! ^\r
+-kernel inet_default_connect_options "[{nodelay,true}]" ^\r
+!RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS! ^\r
-sasl errlog_type error ^\r
-sasl sasl_error_logger false ^\r
-rabbit error_logger {file,\""!LOGS:\=/!"\"} ^\r
-os_mon start_memsup false ^\r
-mnesia dir \""!RABBITMQ_MNESIA_DIR:\=/!"\" ^\r
!RABBITMQ_SERVER_START_ARGS! ^\r
-!RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS! ^\r
!RABBITMQ_DIST_ARG! ^\r
!STARVAR!\r
\r
-stopaction "rabbit:stop_and_halt()." ^\r
!RABBITMQ_NAME_TYPE! !RABBITMQ_NODENAME! ^\r
!CONSOLE_FLAG! ^\r
--comment "A robust and scalable messaging broker" ^\r
+-comment "Multi-protocol open source messaging broker" ^\r
-args "!ERLANG_SERVICE_ARGUMENTS!" > NUL\r
\r
goto END\r
%% 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]).
%% 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).
[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,
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;
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,
%%% 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)).
broadcast_buffer,
broadcast_buffer_sz,
broadcast_timer,
- txn_executor
+ txn_executor,
+ shutting_down
}).
-record(gm_group, { name, version, members }).
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);
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);
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).
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]) ->
%% 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,
print_banner(),
log_banner(),
warn_if_kernel_config_dubious(),
+ warn_if_disc_io_options_dubious(),
run_boot_steps(),
{ok, SupPid};
Error ->
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;
%% 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),
%% 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;
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]};
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.
%% 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
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 ->
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]
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)});
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) ->
%%
%% 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()}.
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}).
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,
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);
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
-export([safe_handle_event/3]).
+%% extracted from error_logger_file_h. Since 18.1 the state of the
+%% error logger module changed. See:
+%% https://github.com/erlang/otp/commit/003091a1fcc749a182505ef5675c763f71eacbb0#diff-d9a19ba08f5d2b60fadfc3aa1566b324R108
+%% github issue:
+%% https://github.com/rabbitmq/rabbitmq-server/issues/324
+-record(st, {fd,
+ filename,
+ prev_handler,
+ depth = unlimited}).
+
+%% extracted from error_logger_file_h. See comment above.
+get_depth() ->
+ case application:get_env(kernel, error_logger_format_depth) of
+ {ok, Depth} when is_integer(Depth) ->
+ erlang:max(10, Depth);
+ undefined ->
+ unlimited
+ end.
+
+-define(ERTS_NEW_LOGGER_STATE, "7.1").
+
%% rabbit_error_logger_file_h is a wrapper around the error_logger_file_h
%% module because the original's init/1 does not match properly
%% with the result of closing the old handler when swapping handlers.
%% lib/stdlib/src/error_logger_file_h.erl from R14B3 was copied as
%% init_file/2 and changed so that it opens the file in 'append' mode.
-%% Used only when swapping handlers in log rotation
+%% Used only when swapping handlers in log rotation, pre OTP 18.1
init({{File, Suffix}, []}) ->
- case rabbit_file:append_file(File, Suffix) of
- ok -> file:delete(File),
- ok;
- {error, Error} ->
- rabbit_log:error("Failed to append contents of "
- "log file '~s' to '~s':~n~p~n",
- [File, [File, Suffix], Error])
- end,
+ rotate_logs(File, Suffix),
+ init(File);
+%% Used only when swapping handlers in log rotation, since OTP 18.1
+init({{File, Suffix}, ok}) ->
+ rotate_logs(File, Suffix),
init(File);
%% Used only when swapping handlers and the original handler
%% failed to terminate or was never installed
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) ->
%%----------------------------------------------------------------------
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.
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) ->
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).
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,
%% 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,
file_handles_ets,
file_summary_ets,
cur_file_cache_ets,
- flying_ets
+ flying_ets,
+ credit_disc_bound
}).
-record(file_summary,
file_handles_ets :: ets:tid(),
file_summary_ets :: ets:tid(),
cur_file_cache_ets :: ets:tid(),
- flying_ets :: ets:tid()}).
+ flying_ets :: ets:tid(),
+ credit_disc_bound :: {pos_integer(), pos_integer()}}).
-type(msg_ref_delta_gen(A) ::
fun ((A) -> 'finished' |
{rabbit_types:msg_id(), non_neg_integer(), A})).
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(),
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),
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).
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,
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
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}),
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);
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},
+%% 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").
-module(rabbit_queue_index).
--export([erase/1, init/3, recover/6,
+-export([erase/1, init/3, reset_state/1, recover/6,
terminate/2, delete_and_terminate/1,
+ pre_publish/7, flush_pre_publish_cache/2,
publish/6, deliver/2, ack/2, sync/1, needs_sync/1, flush/1,
read/3, next_segment_boundary/1, bounds/1, start/1, stop/0]).
%% binary generation/matching with constant vs variable lengths.
-define(REL_SEQ_BITS, 14).
--define(SEGMENT_ENTRY_COUNT, 16384). %% trunc(math:pow(2,?REL_SEQ_BITS))).
+%% calculated as trunc(math:pow(2,?REL_SEQ_BITS))).
+-define(SEGMENT_ENTRY_COUNT, 16384).
%% seq only is binary 01 followed by 14 bits of rel seq id
%% (range: 0 - 16383)
-record(qistate, {dir, segments, journal_handle, dirty_count,
max_journal_entries, on_sync, on_sync_msg,
- unconfirmed, unconfirmed_msg}).
+ unconfirmed, unconfirmed_msg,
+ pre_publish_cache, delivered_cache}).
--record(segment, {num, path, journal_entries, unacked}).
+-record(segment, {num, path, journal_entries,
+ entries_to_segment, unacked}).
-include("rabbit.hrl").
-type(hdl() :: ('undefined' | any())).
-type(segment() :: ('undefined' |
- #segment { num :: non_neg_integer(),
- path :: file:filename(),
- journal_entries :: array:array(),
- unacked :: non_neg_integer()
+ #segment { num :: non_neg_integer(),
+ path :: file:filename(),
+ journal_entries :: array:array(),
+ entries_to_segment :: array:array(),
+ unacked :: non_neg_integer()
})).
-type(seq_id() :: integer()).
-type(seg_dict() :: {dict:dict(), [segment()]}).
on_sync :: on_sync_fun(),
on_sync_msg :: on_sync_fun(),
unconfirmed :: gb_sets:set(),
- unconfirmed_msg :: gb_sets:set()
+ unconfirmed_msg :: gb_sets:set(),
+ pre_publish_cache :: list(),
+ delivered_cache :: list()
}).
-type(contains_predicate() :: fun ((rabbit_types:msg_id()) -> boolean())).
-type(walker(A) :: fun ((A) -> 'finished' |
-type(shutdown_terms() :: [term()] | 'non_clean_shutdown').
-spec(erase/1 :: (rabbit_amqqueue:name()) -> 'ok').
+-spec(reset_state/1 :: (qistate()) -> qistate()).
-spec(init/3 :: (rabbit_amqqueue:name(),
on_sync_fun(), on_sync_fun()) -> qistate()).
-spec(recover/6 :: (rabbit_amqqueue:name(), shutdown_terms(), boolean(),
erase(Name) ->
#qistate { dir = Dir } = blank_state(Name),
- case rabbit_file:is_dir(Dir) of
- true -> rabbit_file:recursive_delete([Dir]);
- false -> ok
- end.
+ erase_index_dir(Dir).
+
+%% used during variable queue purge when there are no pending acks
+reset_state(#qistate{ dir = Dir,
+ on_sync = OnSyncFun,
+ on_sync_msg = OnSyncMsgFun,
+ journal_handle = JournalHdl }) ->
+ ok = case JournalHdl of
+ undefined -> ok;
+ _ -> file_handle_cache:close(JournalHdl)
+ end,
+ ok = erase_index_dir(Dir),
+ blank_state_dir_funs(Dir, OnSyncFun, OnSyncMsgFun).
init(Name, OnSyncFun, OnSyncMsgFun) ->
State = #qistate { dir = Dir } = blank_state(Name),
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}) ->
%% 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,
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)
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) ->
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,
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) }
{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 } |_]}) ->
segments_new() ->
{dict:new(), []}.
-entry_to_segment(_RelSeq, {?PUB, del, ack}, Buf) ->
- Buf;
-entry_to_segment(RelSeq, {Pub, Del, Ack}, Buf) ->
+entry_to_segment(_RelSeq, {?PUB, del, ack}, Initial) ->
+ Initial;
+entry_to_segment(RelSeq, {Pub, Del, Ack}, Initial) ->
%% NB: we are assembling the segment in reverse order here, so
%% del/ack comes first.
Buf1 = case {Del, Ack} of
{no_del, no_ack} ->
- Buf;
+ Initial;
_ ->
Binary = <<?REL_SEQ_ONLY_PREFIX:?REL_SEQ_ONLY_PREFIX_BITS,
RelSeq:?REL_SEQ_BITS>>,
case {Del, Ack} of
- {del, ack} -> [[Binary, Binary] | Buf];
- _ -> [Binary | Buf]
+ {del, ack} -> [[Binary, Binary] | Initial];
+ _ -> [Binary | Initial]
end
end,
case Pub of
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.
%% 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
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) ->
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}
msg_store_clients,
durable,
transient_threshold,
+ qi_embed_msgs_below,
len, %% w/o unacked
bytes, %% w/o unacked
%% Unlike the other counters these two do not feed into
%% #rates{} and get reset
disk_read_count,
- disk_write_count
+ disk_write_count,
+
+ io_batch_size
}).
-record(rates, { in, out, ack_in, ack_out, timestamp }).
end_seq_id %% end_seq_id is exclusive
}).
-%% When we discover that we should write some indices to disk for some
-%% betas, the IO_BATCH_SIZE sets the number of betas that we must be
-%% due to write indices for before we do any work at all.
--define(IO_BATCH_SIZE, 2048). %% next power-of-2 after ?CREDIT_DISC_BOUND
-define(HEADER_GUESS_SIZE, 100). %% see determine_persist_to/2
-define(PERSISTENT_MSG_STORE, msg_store_persistent).
-define(TRANSIENT_MSG_STORE, msg_store_transient).
{any(), binary()}},
durable :: boolean(),
transient_threshold :: non_neg_integer(),
+ qi_embed_msgs_below :: non_neg_integer(),
len :: non_neg_integer(),
bytes :: non_neg_integer(),
ack_out_counter :: non_neg_integer(),
ack_in_counter :: non_neg_integer(),
disk_read_count :: non_neg_integer(),
- disk_write_count :: non_neg_integer() }).
+ disk_write_count :: non_neg_integer(),
+
+ io_batch_size :: pos_integer()}).
%% Duplicated from rabbit_backing_queue
-spec(ack/2 :: ([ack()], state()) -> {[rabbit_guid:guid()], state()}).
%% 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)).
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) };
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),
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
{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) })}.
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 {
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,
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},
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,
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),
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,
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(),
msg_store_clients = {PersistentClient, TransientClient},
durable = IsDurable,
transient_threshold = NextSeqId,
+ qi_embed_msgs_below = IndexMaxSize,
len = DeltaCount1,
persistent_count = DeltaCount1,
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) ->
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,
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
%%----------------------------------------------------------------------------
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};
{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.
%%
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(
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(), []}.
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)
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,
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,
{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,
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),
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.
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),
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
%%----------------------------------------------------------------------------
--- /dev/null
+%% 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)}.
--- /dev/null
+%%
+%% %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.
%%----------------------------------------------------------------------------
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 ->
-VERSION?=3.5.4
+VERSION?=3.5.6