From 117652bea3699dc449fdd510388a745c4885b7d4 Mon Sep 17 00:00:00 2001 From: David Ansari Date: Mon, 10 Nov 2025 17:21:18 +0100 Subject: [PATCH 1/5] Fix quorum queue `drop-head` dead letter order Prior to this commit, quorum queue at-most-once dead lettering for the overflow behaviour `drop-head` was dead lettering in the wrong order. (cherry picked from commit 960918e81f4e6b9501725664a502e2a44e4b655f) --- deps/rabbit/src/rabbit_fifo.erl | 30 +++++++++-------- deps/rabbit/test/quorum_queue_SUITE.erl | 45 +++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 14 deletions(-) diff --git a/deps/rabbit/src/rabbit_fifo.erl b/deps/rabbit/src/rabbit_fifo.erl index 0c195b04ab29..0b34a642abc1 100644 --- a/deps/rabbit/src/rabbit_fifo.erl +++ b/deps/rabbit/src/rabbit_fifo.erl @@ -1639,30 +1639,32 @@ drop_head(#?STATE{ra_indexes = Indexes0} = State0, Effects) -> #?STATE{cfg = #cfg{dead_letter_handler = DLH}, dlx = DlxState} = State = State3, {_, DlxEffects} = rabbit_fifo_dlx:discard([Msg], maxlen, DLH, DlxState), - {State, combine_effects(DlxEffects, Effects)}; + {State, add_drop_head_effects(DlxEffects, Effects)}; empty -> {State0, Effects} end. -%% combine global counter update effects to avoid bulding a huge list of -%% effects if many messages are dropped at the same time as could happen -%% when the `max_length' is changed via a configuration update. -combine_effects([{mod_call, - rabbit_global_counters, - messages_dead_lettered, - [Reason, rabbit_quorum_queue, Type, NewLen]}], - [{mod_call, - rabbit_global_counters, - messages_dead_lettered, - [Reason, rabbit_quorum_queue, Type, PrevLen]} | Rem]) -> +add_drop_head_effects([{mod_call, + rabbit_global_counters, + messages_dead_lettered, + [Reason, rabbit_quorum_queue, Type, NewLen]}], + [{mod_call, + rabbit_global_counters, + messages_dead_lettered, + [Reason, rabbit_quorum_queue, Type, PrevLen]} | Rem]) -> + %% combine global counter update effects to avoid bulding a huge list of + %% effects if many messages are dropped at the same time as could happen + %% when the `max_length' is changed via a configuration update. [{mod_call, rabbit_global_counters, messages_dead_lettered, [Reason, rabbit_quorum_queue, Type, PrevLen + NewLen]} | Rem]; -combine_effects(New, Old) -> +add_drop_head_effects([{log, _, _}] = DlxEffs, Effs) -> + %% dead letter in the correct order + Effs ++ DlxEffs; +add_drop_head_effects(New, Old) -> New ++ Old. - maybe_set_msg_ttl(Msg, RaCmdTs, Header, #?STATE{cfg = #cfg{msg_ttl = MsgTTL}}) -> case mc:is(Msg) of diff --git a/deps/rabbit/test/quorum_queue_SUITE.erl b/deps/rabbit/test/quorum_queue_SUITE.erl index 1a3fed31227a..d9da7ac55faa 100644 --- a/deps/rabbit/test/quorum_queue_SUITE.erl +++ b/deps/rabbit/test/quorum_queue_SUITE.erl @@ -167,6 +167,7 @@ all_tests() -> subscribe_redelivery_count, message_bytes_metrics, queue_length_limit_drop_head, + queue_length_bytes_limit_drop_head, queue_length_limit_reject_publish, queue_length_limit_policy_cleared, subscribe_redelivery_limit, @@ -3697,6 +3698,50 @@ queue_length_limit_drop_head(Config) -> amqp_channel:call(Ch, #'basic.get'{queue = QQ, no_ack = true})). +queue_length_bytes_limit_drop_head(Config) -> + [Server | _] = Servers = rabbit_ct_broker_helpers:get_node_configs(Config, nodename), + + Ch = rabbit_ct_client_helpers:open_channel(Config, Server), + QQ = ?config(queue_name, Config), + DLQ = <<"dead letter queue">>, + + ?assertEqual({'queue.declare_ok', DLQ, 0, 0}, + declare(Ch, DLQ, [{<<"x-queue-type">>, longstr, <<"quorum">>}])), + ?assertEqual({'queue.declare_ok', QQ, 0, 0}, + declare(Ch, QQ, [{<<"x-queue-type">>, longstr, <<"quorum">>}, + {<<"x-overflow">>, longstr, <<"drop-head">>}, + {<<"x-max-length-bytes">>, long, 1000}, + {<<"x-dead-letter-exchange">>, longstr, <<>>}, + {<<"x-dead-letter-routing-key">>, longstr, DLQ}])), + + LargePayload = binary:copy(<<"x">>, 1500), + ok = amqp_channel:cast(Ch, + #'basic.publish'{routing_key = QQ}, + #amqp_msg{payload = <<"m1">>}), + ok = amqp_channel:cast(Ch, + #'basic.publish'{routing_key = QQ}, + #amqp_msg{payload = <<"m2">>}), + ok = amqp_channel:cast(Ch, + #'basic.publish'{routing_key = QQ}, + #amqp_msg{payload = LargePayload}), + wait_for_consensus(QQ, Config), + wait_for_consensus(DLQ, Config), + RaName = ra_name(DLQ), + wait_for_messages_ready(Servers, RaName, 3), + ?assertMatch({#'basic.get_ok'{}, #amqp_msg{payload = <<"m1">>}}, + amqp_channel:call(Ch, #'basic.get'{queue = DLQ, + no_ack = true})), + ?assertMatch({#'basic.get_ok'{}, #amqp_msg{payload = <<"m2">>}}, + amqp_channel:call(Ch, #'basic.get'{queue = DLQ, + no_ack = true})), + ?assertMatch({#'basic.get_ok'{}, #amqp_msg{payload = LargePayload}}, + amqp_channel:call(Ch, #'basic.get'{queue = DLQ, + no_ack = true})), + + [?assertEqual(#'queue.delete_ok'{message_count = 0}, + amqp_channel:call(Ch, #'queue.delete'{queue = Q})) + || Q <- [QQ, DLQ]]. + queue_length_limit_reject_publish(Config) -> [Server | _] = Servers = rabbit_ct_broker_helpers:get_node_configs(Config, nodename), From 70d8915a4243498f5b900f170b6e5717975c0f19 Mon Sep 17 00:00:00 2001 From: David Ansari Date: Mon, 10 Nov 2025 18:31:53 +0100 Subject: [PATCH 2/5] Drop large number of messages more efficiently This commit at-most-once dead letters a huge number of quorum queue messages due to overflow behaviour `drop-head` more efficiently by avoiding repeatedly creating huge lists. A huge number of messages gets dropped if for example: * when the `max-length(-bytes)' is changed via a policy update, or * a very large message was just enqueued causing many small messages being dead lettered due to `max-length-bytes` being exceeded. (cherry picked from commit 422cc2e71559a8351620a3c14e6890a86c18266f) --- deps/rabbit/src/rabbit_fifo.erl | 39 +++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/deps/rabbit/src/rabbit_fifo.erl b/deps/rabbit/src/rabbit_fifo.erl index 0b34a642abc1..15492575f182 100644 --- a/deps/rabbit/src/rabbit_fifo.erl +++ b/deps/rabbit/src/rabbit_fifo.erl @@ -1639,30 +1639,27 @@ drop_head(#?STATE{ra_indexes = Indexes0} = State0, Effects) -> #?STATE{cfg = #cfg{dead_letter_handler = DLH}, dlx = DlxState} = State = State3, {_, DlxEffects} = rabbit_fifo_dlx:discard([Msg], maxlen, DLH, DlxState), - {State, add_drop_head_effects(DlxEffects, Effects)}; + {State, combine_effects(DlxEffects, Effects)}; empty -> {State0, Effects} end. -add_drop_head_effects([{mod_call, - rabbit_global_counters, - messages_dead_lettered, - [Reason, rabbit_quorum_queue, Type, NewLen]}], - [{mod_call, - rabbit_global_counters, - messages_dead_lettered, - [Reason, rabbit_quorum_queue, Type, PrevLen]} | Rem]) -> - %% combine global counter update effects to avoid bulding a huge list of - %% effects if many messages are dropped at the same time as could happen - %% when the `max_length' is changed via a configuration update. +%% combine global counter update effects to avoid bulding a huge list of +%% effects if many messages are dropped at the same time as could happen +%% when the `max_length' is changed via a configuration update. +combine_effects([{mod_call, + rabbit_global_counters, + messages_dead_lettered, + [Reason, rabbit_quorum_queue, Type, NewLen]}], + [{mod_call, + rabbit_global_counters, + messages_dead_lettered, + [Reason, rabbit_quorum_queue, Type, PrevLen]} | Rem]) -> [{mod_call, rabbit_global_counters, messages_dead_lettered, [Reason, rabbit_quorum_queue, Type, PrevLen + NewLen]} | Rem]; -add_drop_head_effects([{log, _, _}] = DlxEffs, Effs) -> - %% dead letter in the correct order - Effs ++ DlxEffs; -add_drop_head_effects(New, Old) -> +combine_effects(New, Old) -> New ++ Old. maybe_set_msg_ttl(Msg, RaCmdTs, Header, @@ -2032,13 +2029,21 @@ evaluate_limit(_Index, Result, _BeforeState, {Enqs, Effects} = unblock_enqueuers(Enqs0, Effects0), {State0#?STATE{enqueuers = Enqs}, Result, Effects}; evaluate_limit(Index, Result, BeforeState, - #?STATE{cfg = #cfg{overflow_strategy = Strategy}, + #?STATE{cfg = #cfg{overflow_strategy = Strategy, + dead_letter_handler = DLH}, enqueuers = Enqs0} = State0, Effects0) -> case is_over_limit(State0) of true when Strategy == drop_head -> {State, Effects} = drop_head(State0, Effects0), evaluate_limit(Index, true, BeforeState, State, Effects); + false when Strategy == drop_head andalso + Result =:= true andalso + element(1, DLH) =:= at_most_once -> + %% At most once dead letter in the correct order. + Dropped = BeforeState#?STATE.messages_total - State0#?STATE.messages_total, + {LogEffects, Effects} = lists:split(Dropped, Effects0), + {State0, Result, Effects ++ lists:reverse(LogEffects)}; true when Strategy == reject_publish -> %% generate send_msg effect for each enqueuer to let them know %% they need to block From 0964a2d34e009b58d88c136c6ddc90886dbefbae Mon Sep 17 00:00:00 2001 From: David Ansari Date: Tue, 11 Nov 2025 09:37:40 +0100 Subject: [PATCH 3/5] Simplify (cherry picked from commit 42d208d30bf65761802291e32d6417077d6d1963) --- deps/rabbit/src/rabbit_fifo.erl | 77 ++++++++++++++++----------------- 1 file changed, 37 insertions(+), 40 deletions(-) diff --git a/deps/rabbit/src/rabbit_fifo.erl b/deps/rabbit/src/rabbit_fifo.erl index 15492575f182..a43371cc816b 100644 --- a/deps/rabbit/src/rabbit_fifo.erl +++ b/deps/rabbit/src/rabbit_fifo.erl @@ -411,16 +411,16 @@ apply(#{index := Index, Effects2 = [reply_log_effect(RaftIdx, MsgId, Header, messages_ready(State4), From) | Effects1], - {State, _DroppedMsg, Effects} = - evaluate_limit(Index, false, State0, State4, Effects2), + {State, Effects} = evaluate_limit(Index, State0, + State4, Effects2), {State, '$ra_no_reply', Effects}; {nochange, _ExpiredMsg = true, State2, Effects0} -> %% All ready messages expired. State3 = State2#?STATE{consumers = maps:remove(ConsumerId, State2#?STATE.consumers)}, - {State, _, Effects} = evaluate_limit(Index, false, State0, - State3, Effects0), + {State, Effects} = evaluate_limit(Index, State0, + State3, Effects0), {State, {dequeue, empty}, Effects} end end; @@ -515,8 +515,7 @@ apply(#{index := Index}, #purge{}, }, Effects0 = [{aux, force_checkpoint}, garbage_collection], Reply = {purge, NumReady}, - {State, _, Effects} = evaluate_limit(Index, false, State0, - State1, Effects0), + {State, Effects} = evaluate_limit(Index, State0, State1, Effects0), {State, Reply, Effects}; apply(#{index := _Idx}, #garbage_collection{}, State) -> {State, ok, [{aux, garbage_collection}]}; @@ -1993,10 +1992,8 @@ checkout(#{index := Index} = Meta, State2 = State1#?STATE{msg_cache = undefined, dlx = DlxState}, Effects2 = DlxDeliveryEffects ++ Effects1, - case evaluate_limit(Index, false, OldState, State2, Effects2) of - {State, _, Effects} -> - {State, Reply, Effects} - end. + {State, Effects} = evaluate_limit(Index, OldState, State2, Effects2), + {State, Reply, Effects}. checkout0(Meta, {success, ConsumerKey, MsgId, ?MSG(_, _) = Msg, ExpiredMsg, State, Effects}, @@ -2013,37 +2010,37 @@ checkout0(_Meta, {_Activity, ExpiredMsg, State0, Effects0}, SendAcc) -> Effects = add_delivery_effects(Effects0, SendAcc, State0), {State0, ExpiredMsg, lists:reverse(Effects)}. -evaluate_limit(_Index, Result, - #?STATE{cfg = #cfg{max_length = undefined, - max_bytes = undefined}}, - #?STATE{cfg = #cfg{max_length = undefined, - max_bytes = undefined}} = State, - Effects) -> - {State, Result, Effects}; -evaluate_limit(_Index, Result, _BeforeState, - #?STATE{cfg = #cfg{max_length = undefined, - max_bytes = undefined}, - enqueuers = Enqs0} = State0, - Effects0) -> +evaluate_limit(Idx, State1, State2, OuterEffects) -> + case evaluate_limit0(Idx, State1, State2, []) of + {State, []} -> + {State, OuterEffects}; + {State, Effects} -> + {State, OuterEffects ++ lists:reverse(Effects)} + end. + +evaluate_limit0(_Index, + #?STATE{cfg = #cfg{max_length = undefined, + max_bytes = undefined}}, + #?STATE{cfg = #cfg{max_length = undefined, + max_bytes = undefined}} = State, + Effects) -> + {State, Effects}; +evaluate_limit0(_Index, _BeforeState, + #?STATE{cfg = #cfg{max_length = undefined, + max_bytes = undefined}, + enqueuers = Enqs0} = State0, + Effects0) -> %% max_length and/or max_bytes policies have just been deleted {Enqs, Effects} = unblock_enqueuers(Enqs0, Effects0), - {State0#?STATE{enqueuers = Enqs}, Result, Effects}; -evaluate_limit(Index, Result, BeforeState, - #?STATE{cfg = #cfg{overflow_strategy = Strategy, - dead_letter_handler = DLH}, - enqueuers = Enqs0} = State0, - Effects0) -> + {State0#?STATE{enqueuers = Enqs}, Effects}; +evaluate_limit0(Index, BeforeState, + #?STATE{cfg = #cfg{overflow_strategy = Strategy}, + enqueuers = Enqs0} = State0, + Effects0) -> case is_over_limit(State0) of true when Strategy == drop_head -> {State, Effects} = drop_head(State0, Effects0), - evaluate_limit(Index, true, BeforeState, State, Effects); - false when Strategy == drop_head andalso - Result =:= true andalso - element(1, DLH) =:= at_most_once -> - %% At most once dead letter in the correct order. - Dropped = BeforeState#?STATE.messages_total - State0#?STATE.messages_total, - {LogEffects, Effects} = lists:split(Dropped, Effects0), - {State0, Result, Effects ++ lists:reverse(LogEffects)}; + evaluate_limit0(Index, BeforeState, State, Effects); true when Strategy == reject_publish -> %% generate send_msg effect for each enqueuer to let them know %% they need to block @@ -2057,7 +2054,7 @@ evaluate_limit(Index, Result, BeforeState, (_P, _E, Acc) -> Acc end, {Enqs0, Effects0}, Enqs0), - {State0#?STATE{enqueuers = Enqs}, Result, Effects}; + {State0#?STATE{enqueuers = Enqs}, Effects}; false when Strategy == reject_publish -> %% TODO: optimise as this case gets called for every command %% pretty much @@ -2066,12 +2063,12 @@ evaluate_limit(Index, Result, BeforeState, {false, true} -> %% we have moved below the lower limit {Enqs, Effects} = unblock_enqueuers(Enqs0, Effects0), - {State0#?STATE{enqueuers = Enqs}, Result, Effects}; + {State0#?STATE{enqueuers = Enqs}, Effects}; _ -> - {State0, Result, Effects0} + {State0, Effects0} end; false -> - {State0, Result, Effects0} + {State0, Effects0} end. unblock_enqueuers(Enqs0, Effects0) -> From a198c98c3f5936d10d6690363895d86c9f888370 Mon Sep 17 00:00:00 2001 From: David Ansari Date: Tue, 11 Nov 2025 09:52:52 +0100 Subject: [PATCH 4/5] Add release notes (cherry picked from commit 59fdd73d14ae12089573069bdd983d347c8b4469) # Conflicts: # release-notes/4.3.0.md --- release-notes/4.2.1.md | 11 +++++ release-notes/4.3.0.md | 91 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 release-notes/4.2.1.md create mode 100644 release-notes/4.3.0.md diff --git a/release-notes/4.2.1.md b/release-notes/4.2.1.md new file mode 100644 index 000000000000..f005d9c03a01 --- /dev/null +++ b/release-notes/4.2.1.md @@ -0,0 +1,11 @@ +## RabbitMQ 4.2.1 + +RabbitMQ `4.2.1` is a maintenance release in the `4.2.x` [release series](https://www.rabbitmq.com/release-information). + +### Core Server + +#### Bug Fixes + + * Quorum queue at-most-once dead lettering for the overflow behaviour `drop-head` now happens in the correct order. + + GitHub issue: [#14926](https://github.com/rabbitmq/rabbitmq-server/pull/14926) diff --git a/release-notes/4.3.0.md b/release-notes/4.3.0.md new file mode 100644 index 000000000000..f98c06e9e946 --- /dev/null +++ b/release-notes/4.3.0.md @@ -0,0 +1,91 @@ +## RabbitMQ 4.3.0 + + +## Breaking Changes and Compatibility Notes + +TBD + + +## Release Highlights + +TBD + + +## Upgrading to 4.3.0 + +### Documentation guides on upgrades + +See the [Upgrading guide](https://www.rabbitmq.com/docs/upgrade) for documentation on upgrades and [GitHub releases](https://github.com/rabbitmq/rabbitmq-server/releases) +for release notes of individual releases. + +This release series supports upgrades from `4.2.x`. + + +### New Required Feature Flags + +All feature flags introduced in `4.2.0` and earlier are required, including the following: +* `rabbitmq_4.2.0` +* `rabbitmq_4.1.0` +* `rabbitmq_4.0.0` +* `khepri_db` +* `quorum_queue_non_voters` +* `message_containers_deaths_v2` + +Enable all required feature flags before upgrading to `4.3.0`. + +If your RabbitMQ cluster had plugin `rabbitmq_amqp1_0` enabled in RabbitMQ `3.13.x` (and your cluster still serves AMQP 1.0 client connections in `4.x`), your cluster should do at least one rolling update **after** enabling feature flag `rabbitmq_4.0.0` but **before** upgrading to `4.3.0`. + +### Deprecated Features + +In `4.3.0` the deprecation phase of the following features advanced from `permitted_by_default` to `denied_by_default`: +* `amqp_filter_set_bug` + +### Mixed version cluster compatibility + +RabbitMQ 4.3.0 nodes can run alongside `4.2.x`. + +Mixed version clusters are a mechanism that allows rolling upgrade and are not meant to be run for extended +periods of time (no more than a few hours). + +### Recommended Post-upgrade Procedures + +This version does not require any additional post-upgrade procedures +compared to other versions. + + +## Changes Worth Mentioning + +### Core Server + +#### Bug Fixes + + * Quorum queue at-most-once dead lettering for the overflow behaviour `drop-head` now happens in the correct order. + + GitHub issue: [#14926](https://github.com/rabbitmq/rabbitmq-server/pull/14926) + +#### Enhancements + +TBD + +### HTTP Auth Backend + +#### Enhancements + +The HTTP Auth Backend can now optionally provide a custom authorization denial reason to AMQP clients. +To opt in, return `deny ` (instead of only `deny`) in the HTTP response body of your HTTP auth backend and set the following in your `rabbitmq.conf` file: +```ini +auth_http.authorization_failure_disclosure = true +``` + +See the [README](https://github.com/rabbitmq/rabbitmq-server/blob/main/deps/rabbitmq_auth_backend_http/README.md) for more information. + +Pull Request: [#14641](https://github.com/rabbitmq/rabbitmq-server/pull/14641) + +### Dependency Changes + +TBD + +## Source Code Archives + +To obtain source code of the entire distribution, please download the archive named `rabbitmq-server-4.3.0.tar.xz` +instead of the source tarball produced by GitHub. From ee10f11fcf016e28643ff1eabfd7d14e0c1c9052 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Tue, 11 Nov 2025 13:35:05 -0800 Subject: [PATCH 5/5] Resolve a conflict #14926 #14938 4.3.0 release notes should not be on the v4.2.x branch (but 4.2.x release notes are/will be in main/v4.3.x). --- release-notes/4.3.0.md | 91 ------------------------------------------ 1 file changed, 91 deletions(-) delete mode 100644 release-notes/4.3.0.md diff --git a/release-notes/4.3.0.md b/release-notes/4.3.0.md deleted file mode 100644 index f98c06e9e946..000000000000 --- a/release-notes/4.3.0.md +++ /dev/null @@ -1,91 +0,0 @@ -## RabbitMQ 4.3.0 - - -## Breaking Changes and Compatibility Notes - -TBD - - -## Release Highlights - -TBD - - -## Upgrading to 4.3.0 - -### Documentation guides on upgrades - -See the [Upgrading guide](https://www.rabbitmq.com/docs/upgrade) for documentation on upgrades and [GitHub releases](https://github.com/rabbitmq/rabbitmq-server/releases) -for release notes of individual releases. - -This release series supports upgrades from `4.2.x`. - - -### New Required Feature Flags - -All feature flags introduced in `4.2.0` and earlier are required, including the following: -* `rabbitmq_4.2.0` -* `rabbitmq_4.1.0` -* `rabbitmq_4.0.0` -* `khepri_db` -* `quorum_queue_non_voters` -* `message_containers_deaths_v2` - -Enable all required feature flags before upgrading to `4.3.0`. - -If your RabbitMQ cluster had plugin `rabbitmq_amqp1_0` enabled in RabbitMQ `3.13.x` (and your cluster still serves AMQP 1.0 client connections in `4.x`), your cluster should do at least one rolling update **after** enabling feature flag `rabbitmq_4.0.0` but **before** upgrading to `4.3.0`. - -### Deprecated Features - -In `4.3.0` the deprecation phase of the following features advanced from `permitted_by_default` to `denied_by_default`: -* `amqp_filter_set_bug` - -### Mixed version cluster compatibility - -RabbitMQ 4.3.0 nodes can run alongside `4.2.x`. - -Mixed version clusters are a mechanism that allows rolling upgrade and are not meant to be run for extended -periods of time (no more than a few hours). - -### Recommended Post-upgrade Procedures - -This version does not require any additional post-upgrade procedures -compared to other versions. - - -## Changes Worth Mentioning - -### Core Server - -#### Bug Fixes - - * Quorum queue at-most-once dead lettering for the overflow behaviour `drop-head` now happens in the correct order. - - GitHub issue: [#14926](https://github.com/rabbitmq/rabbitmq-server/pull/14926) - -#### Enhancements - -TBD - -### HTTP Auth Backend - -#### Enhancements - -The HTTP Auth Backend can now optionally provide a custom authorization denial reason to AMQP clients. -To opt in, return `deny ` (instead of only `deny`) in the HTTP response body of your HTTP auth backend and set the following in your `rabbitmq.conf` file: -```ini -auth_http.authorization_failure_disclosure = true -``` - -See the [README](https://github.com/rabbitmq/rabbitmq-server/blob/main/deps/rabbitmq_auth_backend_http/README.md) for more information. - -Pull Request: [#14641](https://github.com/rabbitmq/rabbitmq-server/pull/14641) - -### Dependency Changes - -TBD - -## Source Code Archives - -To obtain source code of the entire distribution, please download the archive named `rabbitmq-server-4.3.0.tar.xz` -instead of the source tarball produced by GitHub.