diff options
| -rw-r--r-- | docs/rabbitmq.conf.example | 2 | ||||
| -rw-r--r-- | docs/rabbitmq.config.example | 4 | ||||
| -rw-r--r-- | priv/schema/rabbitmq.schema | 3 | ||||
| -rw-r--r-- | rabbitmq-components.mk | 4 | ||||
| -rw-r--r-- | src/background_gc.erl | 2 | ||||
| -rw-r--r-- | src/rabbit.erl | 79 | ||||
| -rw-r--r-- | src/rabbit_config.erl | 1 | ||||
| -rw-r--r-- | src/rabbit_mnesia.erl | 46 | ||||
| -rw-r--r-- | src/rabbit_node_monitor.erl | 40 | ||||
| -rw-r--r-- | src/rabbit_peer_discovery.erl | 55 | ||||
| -rw-r--r-- | src/rabbit_peer_discovery_classic_config.erl | 12 | ||||
| -rw-r--r-- | src/rabbit_peer_discovery_dns.erl | 11 | ||||
| -rw-r--r-- | src/rabbit_queue_index.erl | 2 | ||||
| -rw-r--r-- | src/term_to_binary_compat.erl | 32 | ||||
| -rw-r--r-- | src/vm_memory_monitor.erl | 21 | ||||
| -rw-r--r-- | test/backing_queue_SUITE.erl | 2 | ||||
| -rw-r--r-- | test/cluster_SUITE.erl | 2 | ||||
| -rw-r--r-- | test/cluster_formation_locking_SUITE.erl | 80 | ||||
| -rw-r--r-- | test/clustering_management_SUITE.erl | 8 | ||||
| -rw-r--r-- | test/partitions_SUITE.erl | 38 | ||||
| -rw-r--r-- | test/term_to_binary_compat_prop_SUITE.erl | 62 | ||||
| -rw-r--r-- | test/unit_SUITE.erl | 6 | ||||
| -rw-r--r-- | test/unit_inbroker_parallel_SUITE.erl | 2 |
23 files changed, 431 insertions, 83 deletions
diff --git a/docs/rabbitmq.conf.example b/docs/rabbitmq.conf.example index 0e8d1e0596..e4c2fff92a 100644 --- a/docs/rabbitmq.conf.example +++ b/docs/rabbitmq.conf.example @@ -386,7 +386,7 @@ ## Disabling background GC may reduce latency for client operations, ## keeping it enabled may reduce median RAM usage. ## -# background_gc_enabled = true +# background_gc_enabled = false ## Target (desired) interval (in milliseconds) at which we run background GC. ## The actual interval will vary depending on how long it takes to execute diff --git a/docs/rabbitmq.config.example b/docs/rabbitmq.config.example index 2be3c74095..4135c5053c 100644 --- a/docs/rabbitmq.config.example +++ b/docs/rabbitmq.config.example @@ -276,7 +276,7 @@ %% See http://www.rabbitmq.com/partitions.html for further details. %% %% {cluster_partition_handling, ignore}, - + %% Mirror sync batch size, in messages. Increasing this will speed %% up syncing but total batch size in bytes must not exceed 2 GiB. %% Available in RabbitMQ 3.6.0 or later. @@ -343,7 +343,7 @@ %% Disabling background GC may reduce latency for client operations, %% keeping it enabled may reduce median RAM usage. %% - %% {background_gc_enabled, true}, + %% {background_gc_enabled, false}, %% %% Target (desired) interval (in milliseconds) at which we run background GC. %% The actual interval will vary depending on how long it takes to execute diff --git a/priv/schema/rabbitmq.schema b/priv/schema/rabbitmq.schema index ecfa14ded4..985c77b9a8 100644 --- a/priv/schema/rabbitmq.schema +++ b/priv/schema/rabbitmq.schema @@ -791,6 +791,9 @@ fun(Conf) -> dns -> rabbit_peer_discovery_dns; aws -> rabbit_peer_discovery_aws; consul -> rabbit_peer_discovery_consul; + etcd -> rabbit_peer_discovery_etcd; + kubernetes -> rabbit_peer_discovery_k8s; + k8s -> rabbit_peer_discovery_k8s; Module -> Module end end}. diff --git a/rabbitmq-components.mk b/rabbitmq-components.mk index 1bc8ccf3d5..63bc1c52bd 100644 --- a/rabbitmq-components.mk +++ b/rabbitmq-components.mk @@ -76,6 +76,8 @@ dep_rabbitmq_objc_client = git_rmq rabbitmq-objc-client $(current_r dep_rabbitmq_peer_discovery_aws = git_rmq rabbitmq-peer-discovery-aws $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_peer_discovery_common = git_rmq rabbitmq-peer-discovery-common $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_peer_discovery_consul = git_rmq rabbitmq-peer-discovery-consul $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_peer_discovery_etcd = git_rmq rabbitmq-peer-discovery-etcd $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_peer_discovery_k8s = git_rmq rabbitmq-peer-discovery-k8s $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_recent_history_exchange = git_rmq rabbitmq-recent-history-exchange $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_routing_node_stamp = git_rmq rabbitmq-routing-node-stamp $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_rtopic_exchange = git_rmq rabbitmq-rtopic-exchange $(current_rmq_ref) $(base_rmq_ref) master @@ -151,6 +153,8 @@ RABBITMQ_COMPONENTS = amqp_client \ rabbitmq_peer_discovery_aws \ rabbitmq_peer_discovery_common \ rabbitmq_peer_discovery_consul \ + rabbitmq_peer_discovery_etcd \ + rabbitmq_peer_discovery_k8s \ rabbitmq_recent_history_exchange \ rabbitmq_routing_node_stamp \ rabbitmq_rtopic_exchange \ diff --git a/src/background_gc.erl b/src/background_gc.erl index 2ae9d93e4e..bbac3138cf 100644 --- a/src/background_gc.erl +++ b/src/background_gc.erl @@ -74,7 +74,7 @@ interval_gc(State = #state{last_interval = LastInterval}) -> State#state{last_interval = Interval}. gc() -> - Enabled = rabbit_misc:get_env(rabbit, background_gc_enabled, true), + Enabled = rabbit_misc:get_env(rabbit, background_gc_enabled, false), case Enabled of true -> [garbage_collect(P) || P <- processes(), diff --git a/src/rabbit.erl b/src/rabbit.erl index 5ae58f57d1..138d03f051 100644 --- a/src/rabbit.erl +++ b/src/rabbit.erl @@ -19,11 +19,12 @@ -behaviour(application). -export([start/0, boot/0, stop/0, - stop_and_halt/0, await_startup/0, status/0, is_running/0, alarms/0, + stop_and_halt/0, await_startup/0, await_startup/1, + status/0, is_running/0, alarms/0, is_running/1, environment/0, rotate_logs/0, force_event_refresh/1, start_fhc/0]). -export([start/2, stop/1, prep_stop/1]). --export([start_apps/1, stop_apps/1]). +-export([start_apps/1, start_apps/2, stop_apps/1]). -export([log_locations/0, config_files/0, decrypt_config/2]). %% for testing and mgmt-agent -ifdef(TEST). @@ -266,6 +267,8 @@ -spec boot_delegate() -> 'ok'. -spec recover() -> 'ok'. -spec start_apps([app_name()]) -> 'ok'. +-spec start_apps([app_name()], + #{app_name() => permanent|transient|temporary}) -> 'ok'. -spec stop_apps([app_name()]) -> 'ok'. %%---------------------------------------------------------------------------- @@ -327,11 +330,7 @@ broker_start() -> ToBeLoaded = Plugins ++ ?APPS, start_apps(ToBeLoaded), maybe_sd_notify(), - ok = log_broker_started(rabbit_plugins:strictly_plugins(rabbit_plugins:active())), - %% See rabbitmq/rabbitmq-server#1202 for details. - rabbit_peer_discovery:maybe_inject_randomized_delay(), - rabbit_peer_discovery:maybe_register(), - ok. + ok = log_broker_started(rabbit_plugins:strictly_plugins(rabbit_plugins:active())). %% Try to send systemd ready notification if it makes sense in the %% current environment. standard_error is used intentionally in all @@ -471,7 +470,7 @@ stop() -> undefined -> ok; _ -> rabbit_log:info("RabbitMQ hasn't finished starting yet. Waiting for startup to finish before stopping..."), - wait_for_boot_to_finish() + ok = wait_for_boot_to_finish(node()) end, rabbit_log:info("RabbitMQ is asked to stop...~n", []), Apps = ?APPS ++ rabbit_plugins:active(), @@ -506,6 +505,9 @@ stop_and_halt() -> ok. start_apps(Apps) -> + start_apps(Apps, #{}). + +start_apps(Apps, AppModes) -> app_utils:load_applications(Apps), ConfigEntryDecoder = case application:get_env(rabbit, config_entry_decoder) of @@ -545,7 +547,8 @@ start_apps(Apps) -> true -> ok %% will run during start of rabbit app end, ok = app_utils:start_applications(OrderedApps, - handle_app_error(could_not_start)). + handle_app_error(could_not_start), + AppModes). %% This function retrieves the correct IoDevice for requesting %% input. The problem with using the default IoDevice is that @@ -621,7 +624,7 @@ decrypt_list([Value|Tail], Algo, Acc) -> stop_apps(Apps) -> rabbit_log:info( - lists:flatten(["Stopping RabbitMQ applications and their dependencies in the following order: ~n", + lists:flatten(["Stopping RabbitMQ applications and their dependencies in the following order:~n", [" ~p~n" || _ <- Apps]]), lists:reverse(Apps)), ok = app_utils:stop_applications( @@ -641,32 +644,52 @@ handle_app_error(Term) -> end. await_startup() -> - case is_booting() of - true -> wait_for_boot_to_finish(); + await_startup(node()). + +await_startup(Node) -> + case is_booting(Node) of + true -> wait_for_boot_to_finish(Node); false -> - case is_running() of + case is_running(Node) of true -> ok; - false -> wait_for_boot_to_start(), - wait_for_boot_to_finish() + false -> wait_for_boot_to_start(Node), + wait_for_boot_to_finish(Node) end end. -is_booting() -> - whereis(rabbit_boot) /= undefined. +is_booting(Node) -> + case rpc:call(Node, erlang, whereis, [rabbit_boot]) of + {badrpc, _} = Err -> Err; + undefined -> false; + P when is_pid(P) -> true + end. -wait_for_boot_to_start() -> - case whereis(rabbit_boot) of - undefined -> timer:sleep(100), - wait_for_boot_to_start(); - _ -> ok +wait_for_boot_to_start(Node) -> + case is_booting(Node) of + false -> + timer:sleep(100), + wait_for_boot_to_start(Node); + {badrpc, _} = Err -> + Err; + true -> + ok end. -wait_for_boot_to_finish() -> - case whereis(rabbit_boot) of - undefined -> true = is_running(), - ok; - _ -> timer:sleep(100), - wait_for_boot_to_finish() +wait_for_boot_to_finish(Node) -> + case is_booting(Node) of + false -> + %% We don't want badrpc error to be interpreted as false, + %% so we don't call rabbit:is_running(Node) + case rpc:call(Node, rabbit, is_running, []) of + true -> ok; + false -> {error, rabbit_is_not_running}; + {badrpc, _} = Err -> Err + end; + {badrpc, _} = Err -> + Err; + true -> + timer:sleep(100), + wait_for_boot_to_finish(Node) end. status() -> diff --git a/src/rabbit_config.erl b/src/rabbit_config.erl index 9e70898c82..a3f7d19136 100644 --- a/src/rabbit_config.erl +++ b/src/rabbit_config.erl @@ -99,7 +99,6 @@ generate_config_file(ConfFiles, ConfDir, ScriptDir) -> generate_config_file(ConfFiles, ConfDir, ScriptDir, SchemaDir, Advanced) -> prepare_plugin_schemas(SchemaDir), - % SchemaFile = filename:join([ScriptDir, "rabbitmq.schema"]), Cuttlefish = filename:join([ScriptDir, "cuttlefish"]), GeneratedDir = filename:join([ConfDir, "generated"]), diff --git a/src/rabbit_mnesia.erl b/src/rabbit_mnesia.erl index e49ea6dfb6..a0363b69d0 100644 --- a/src/rabbit_mnesia.erl +++ b/src/rabbit_mnesia.erl @@ -46,6 +46,11 @@ %% Used internally in rpc calls -export([node_info/0, remove_node_if_mnesia_running/1]). +-ifdef(TEST). +-compile(export_all). +-export([init_with_lock/3]). +-endif. + -include("rabbit.hrl"). %%---------------------------------------------------------------------------- @@ -101,12 +106,13 @@ init() -> rabbit_log:info("Node database directory at ~s is empty. " "Assuming we need to join an existing cluster or initialise from scratch...~n", [dir()]), - rabbit_peer_discovery:log_configured_backend(), - init_from_config(); + rabbit_peer_discovery:log_configured_backend(), + init_with_lock(); false -> NodeType = node_type(), init_db_and_upgrade(cluster_nodes(all), NodeType, - NodeType =:= ram, _Retry = true) + NodeType =:= ram, _Retry = true), + rabbit_peer_discovery:maybe_register() end, %% We intuitively expect the global name server to be synced when %% Mnesia is up. In fact that's not guaranteed to be the case - @@ -114,13 +120,43 @@ init() -> ok = rabbit_node_monitor:global_sync(), ok. +init_with_lock() -> + {Retries, Timeout} = rabbit_peer_discovery:retry_timeout(), + init_with_lock(Retries, Timeout, fun init_from_config/0). + +init_with_lock(0, _, InitFromConfig) -> + case rabbit_peer_discovery:lock_acquisition_failure_mode() of + ignore -> + rabbit_log:warning("Cannot acquire a lock during clustering", []), + InitFromConfig(), + rabbit_peer_discovery:maybe_register(); + fail -> + exit(cannot_acquire_startup_lock) + end; +init_with_lock(Retries, Timeout, InitFromConfig) -> + case rabbit_peer_discovery:lock() of + not_supported -> + %% See rabbitmq/rabbitmq-server#1202 for details. + rabbit_peer_discovery:maybe_inject_randomized_delay(), + InitFromConfig(), + rabbit_peer_discovery:maybe_register(); + {error, _Reason} -> + timer:sleep(Timeout), + init_with_lock(Retries - 1, Timeout, InitFromConfig); + {ok, Data} -> + try + InitFromConfig(), + rabbit_peer_discovery:maybe_register() + after + rabbit_peer_discovery:unlock(Data) + end + end. + init_from_config() -> FindBadNodeNames = fun (Name, BadNames) when is_atom(Name) -> BadNames; (Name, BadNames) -> [Name | BadNames] end, - %% See rabbitmq/rabbitmq-server#1202 for details. - rabbit_peer_discovery:maybe_inject_randomized_delay(), {DiscoveredNodes, NodeType} = case rabbit_peer_discovery:discover_cluster_nodes() of {ok, {Nodes, Type} = Config} diff --git a/src/rabbit_node_monitor.erl b/src/rabbit_node_monitor.erl index 0eadf0ff59..810df2d1fc 100644 --- a/src/rabbit_node_monitor.erl +++ b/src/rabbit_node_monitor.erl @@ -344,8 +344,8 @@ init([]) -> Nodes = possibly_partitioned_nodes(), startup_log(Nodes), Monitors = lists:foldl(fun(Node, Monitors0) -> - pmon:monitor({rabbit, Node}, Monitors0) - end, pmon:new(), Nodes), + pmon:monitor({rabbit, Node}, Monitors0) + end, pmon:new(), Nodes), {ok, ensure_keepalive_timer(#state{monitors = Monitors, subscribers = pmon:new(), partitions = [], @@ -420,12 +420,12 @@ handle_cast({check_partial_partition, Node, Rep, NodeGUID, MyGUID, RepGUID}, fun () -> case rpc:call(Node, rabbit, is_running, []) of {badrpc, _} -> ok; - _ -> - rabbit_log:warning("Received a 'DOWN' message" - " from ~p but still can" - " communicate with it ~n", - [Node]), - cast(Rep, {partial_partition, + _ -> + rabbit_log:warning("Received a 'DOWN' message" + " from ~p but still can" + " communicate with it ~n", + [Node]), + cast(Rep, {partial_partition, Node, node(), RepGUID}) end end); @@ -499,18 +499,18 @@ handle_cast({node_up, Node, NodeType}, rabbit_log:info("rabbit on node ~p up~n", [Node]), {AllNodes, DiscNodes, RunningNodes} = read_cluster_status(), write_cluster_status({add_node(Node, AllNodes), - case NodeType of - disc -> add_node(Node, DiscNodes); - ram -> DiscNodes - end, - add_node(Node, RunningNodes)}), + case NodeType of + disc -> add_node(Node, DiscNodes); + ram -> DiscNodes + end, + add_node(Node, RunningNodes)}), ok = handle_live_rabbit(Node), Monitors1 = case pmon:is_monitored({rabbit, Node}, Monitors) of - true -> - Monitors; - false -> - pmon:monitor({rabbit, Node}, Monitors) - end, + true -> + Monitors; + false -> + pmon:monitor({rabbit, Node}, Monitors) + end, {noreply, maybe_autoheal(State#state{monitors = Monitors1})}; handle_cast({joined_cluster, Node, NodeType}, State) -> @@ -584,7 +584,7 @@ handle_info({mnesia_system_event, State1 = case pmon:is_monitored({rabbit, Node}, Monitors) of true -> State; false -> State#state{ - monitors = pmon:monitor({rabbit, Node}, Monitors)} + monitors = pmon:monitor({rabbit, Node}, Monitors)} end, ok = handle_live_rabbit(Node), Partitions1 = lists:usort([Node | Partitions]), @@ -893,4 +893,4 @@ startup_log([]) -> rabbit_log:info("Starting rabbit_node_monitor~n", []); startup_log(Nodes) -> rabbit_log:info("Starting rabbit_node_monitor, might be partitioned from ~p~n", - [Nodes]). + [Nodes]). diff --git a/src/rabbit_peer_discovery.erl b/src/rabbit_peer_discovery.erl index 628b9f101f..1abf2b7cc7 100644 --- a/src/rabbit_peer_discovery.erl +++ b/src/rabbit_peer_discovery.erl @@ -23,8 +23,9 @@ -export([discover_cluster_nodes/0, backend/0, node_type/0, normalize/1, format_discovered_nodes/1, log_configured_backend/0, register/0, unregister/0, maybe_register/0, maybe_unregister/0, - maybe_inject_randomized_delay/0]). --export([append_node_prefix/1, node_prefix/0]). + maybe_inject_randomized_delay/0, lock/0, unlock/1]). +-export([append_node_prefix/1, node_prefix/0, retry_timeout/0, + lock_acquisition_failure_mode/0]). -define(DEFAULT_BACKEND, rabbit_peer_discovery_classic_config). %% what node type is used by default for this node when joining @@ -60,7 +61,27 @@ node_type() -> ?DEFAULT_NODE_TYPE end. +-spec retry_timeout() -> {Retries :: integer(), Timeout :: integer()}. +retry_timeout() -> + case application:get_env(rabbit, cluster_formation) of + {ok, Proplist} -> + Retries = proplists:get_value(lock_retry_limit, Proplist, 10), + Timeout = proplists:get_value(lock_retry_timeout, Proplist, 30000), + {Retries, Timeout}; + undefined -> + {10, 30000} + end. + +-spec lock_acquisition_failure_mode() -> ignore | fail. + +lock_acquisition_failure_mode() -> + case application:get_env(rabbit, cluster_formation) of + {ok, Proplist} -> + proplists:get_value(lock_acquisition_failure_mode, Proplist, fail); + undefined -> + fail + end. -spec log_configured_backend() -> ok. @@ -139,7 +160,7 @@ inject_randomized_delay() -> true -> Min; false -> RandomVal end, - rabbit_log:info("Will wait for ~p milliseconds before proceeding with regitration...", [Effective]), + rabbit_log:info("Will wait for ~p milliseconds before proceeding with registration...", [Effective]), timer:sleep(Effective), ok end. @@ -183,6 +204,34 @@ unregister() -> ok end. +-spec lock() -> ok | {ok, Data :: term()} | not_supported | {error, Reason :: string()}. + +lock() -> + Backend = backend(), + rabbit_log:info("Will try to lock with peer discovery backend ~s", [Backend]), + case Backend:lock(node()) of + {error, Reason} = Error -> + rabbit_log:error("Failed to lock with peer discovery backend ~s: ~p", + [Backend, Reason]), + Error; + Any -> + Any + end. + +-spec unlock(Data :: term()) -> ok | {error, Reason :: string()}. + +unlock(Data) -> + Backend = backend(), + rabbit_log:info("Will try to unlock with peer discovery backend ~s", [Backend]), + case Backend:unlock(Data) of + {error, Reason} = Error -> + rabbit_log:error("Failed to unlock with peer discovery backend ~s: ~p, " + "lock data: ~p", + [Backend, Reason, Data]), + Error; + Any -> + Any + end. %% %% Implementation diff --git a/src/rabbit_peer_discovery_classic_config.erl b/src/rabbit_peer_discovery_classic_config.erl index da5fb6c971..96d47d8182 100644 --- a/src/rabbit_peer_discovery_classic_config.erl +++ b/src/rabbit_peer_discovery_classic_config.erl @@ -20,7 +20,7 @@ -include("rabbit.hrl"). -export([list_nodes/0, supports_registration/0, register/0, unregister/0, - post_registration/0]). + post_registration/0, lock/1, unlock/1]). %% %% API @@ -54,3 +54,13 @@ unregister() -> post_registration() -> ok. + +-spec lock(Node :: atom()) -> not_supported. + +lock(_Node) -> + not_supported. + +-spec unlock(Data :: term()) -> ok. + +unlock(_Data) -> + ok. diff --git a/src/rabbit_peer_discovery_dns.erl b/src/rabbit_peer_discovery_dns.erl index 5b1ab4405e..7422876c4d 100644 --- a/src/rabbit_peer_discovery_dns.erl +++ b/src/rabbit_peer_discovery_dns.erl @@ -20,7 +20,7 @@ -include("rabbit.hrl"). -export([list_nodes/0, supports_registration/0, register/0, unregister/0, - post_registration/0]). + post_registration/0, lock/1, unlock/1]). %% for tests -export([discover_nodes/2, discover_hostnames/2]). @@ -71,6 +71,15 @@ unregister() -> post_registration() -> ok. +-spec lock(Node :: atom()) -> not_supported. + +lock(_Node) -> + not_supported. + +-spec unlock(Data :: term()) -> ok. + +unlock(_Data) -> + ok. %% %% Implementation diff --git a/src/rabbit_queue_index.erl b/src/rabbit_queue_index.erl index a71eaf1ff4..123bfaba25 100644 --- a/src/rabbit_queue_index.erl +++ b/src/rabbit_queue_index.erl @@ -691,7 +691,7 @@ recover_message(false, _, no_del, RelSeq, {Segment, DirtyCount}) -> DirtyCount + 2}. queue_name_to_dir_name(Name = #resource { kind = queue }) -> - <<Num:128>> = erlang:md5(term_to_binary(Name)), + <<Num:128>> = erlang:md5(term_to_binary_compat:queue_name_to_binary(Name)), rabbit_misc:format("~.36B", [Num]). queues_base_dir() -> diff --git a/src/term_to_binary_compat.erl b/src/term_to_binary_compat.erl new file mode 100644 index 0000000000..8a74bde3e0 --- /dev/null +++ b/src/term_to_binary_compat.erl @@ -0,0 +1,32 @@ +%% 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) 2017 Pivotal Software, Inc. All rights reserved. +%% + +-module(term_to_binary_compat). + +-include("rabbit.hrl"). + +-export([queue_name_to_binary/1]). + +queue_name_to_binary(#resource{kind = queue, virtual_host = VHost, name = Name}) -> + VHostBSize = byte_size(VHost), + NameBSize = byte_size(Name), + <<131, %% Binary format "version" + 104, 4, %% 4-element tuple + 100, 0, 8, "resource", %% `resource` atom + 109, VHostBSize:32, VHost/binary, %% Vhost binary + 100, 0, 5, "queue", %% `queue` atom + 109, NameBSize:32, Name/binary>>. %% Name binary + diff --git a/src/vm_memory_monitor.erl b/src/vm_memory_monitor.erl index ba324d649e..71e9f36c46 100644 --- a/src/vm_memory_monitor.erl +++ b/src/vm_memory_monitor.erl @@ -43,7 +43,7 @@ -define(SERVER, ?MODULE). -define(DEFAULT_MEMORY_CHECK_INTERVAL, 1000). --define(ONE_MB, 1048576). +-define(ONE_MiB, 1048576). %% For an unknown OS, we assume that we have 1GB of memory. It'll be %% wrong. Scale by vm_memory_high_watermark in configuration to get a @@ -214,9 +214,10 @@ set_mem_limits(State, MemLimit) -> memory_limit = undefined } -> error_logger:warning_msg( "Unknown total memory size for your OS ~p. " - "Assuming memory size is ~pMB.~n", + "Assuming memory size is ~p MiB (~p bytes).~n", [os:type(), - trunc(?MEMORY_SIZE_FOR_UNKNOWN_OS/?ONE_MB)]); + trunc(?MEMORY_SIZE_FOR_UNKNOWN_OS/?ONE_MiB), + ?MEMORY_SIZE_FOR_UNKNOWN_OS]); _ -> ok end, @@ -227,18 +228,20 @@ set_mem_limits(State, MemLimit) -> case get_vm_limit() of Limit when Limit < TotalMemory -> error_logger:warning_msg( - "Only ~pMB of ~pMB memory usable due to " + "Only ~p MiB (~p bytes) of ~p MiB (~p bytes) memory usable due to " "limited address space.~n" "Crashes due to memory exhaustion are possible - see~n" "http://www.rabbitmq.com/memory.html#address-space~n", - [trunc(V/?ONE_MB) || V <- [Limit, TotalMemory]]), + [trunc(Limit/?ONE_MiB), Limit, trunc(TotalMemory/?ONE_MiB), + TotalMemory]), Limit; _ -> TotalMemory end, MemLim = interpret_limit(parse_mem_limit(MemLimit), UsableMemory), - error_logger:info_msg("Memory limit set to ~pMB of ~pMB total.~n", - [trunc(MemLim/?ONE_MB), trunc(TotalMemory/?ONE_MB)]), + error_logger:info_msg("Memory limit set to ~p MiB (~p bytes) of ~p MiB (~p bytes) total.~n", + [trunc(MemLim/?ONE_MiB), MemLim, trunc(TotalMemory/?ONE_MiB), + TotalMemory]), internal_update(State #state { total_memory = TotalMemory, memory_limit = MemLim, memory_config_limit = MemLimit}). @@ -402,9 +405,9 @@ parse_line_sunos(Line) -> [Value1 | UnitsRest] = string:tokens(RHS, " "), Value2 = case UnitsRest of ["Gigabytes"] -> - list_to_integer(Value1) * ?ONE_MB * 1024; + list_to_integer(Value1) * ?ONE_MiB * 1024; ["Megabytes"] -> - list_to_integer(Value1) * ?ONE_MB; + list_to_integer(Value1) * ?ONE_MiB; ["Kilobytes"] -> list_to_integer(Value1) * 1024; _ -> diff --git a/test/backing_queue_SUITE.erl b/test/backing_queue_SUITE.erl index 3ff215f497..60f86e0542 100644 --- a/test/backing_queue_SUITE.erl +++ b/test/backing_queue_SUITE.erl @@ -1256,7 +1256,7 @@ make_publish_delivered(IsPersistent, PayloadFun, PropFun, N) -> PropFun(N, #message_properties{size = 10})}. queue_name(Config, Name) -> - Name1 = rabbit_ct_helpers:config_to_testcase_name(Config, Name), + Name1 = iolist_to_binary(rabbit_ct_helpers:config_to_testcase_name(Config, Name)), queue_name(Name1). queue_name(Name) -> diff --git a/test/cluster_SUITE.erl b/test/cluster_SUITE.erl index bc442ecba7..3dba65ae1f 100644 --- a/test/cluster_SUITE.erl +++ b/test/cluster_SUITE.erl @@ -355,7 +355,7 @@ test_spawn_remote() -> end. queue_name(Config, Name) -> - Name1 = rabbit_ct_helpers:config_to_testcase_name(Config, Name), + Name1 = iolist_to_binary(rabbit_ct_helpers:config_to_testcase_name(Config, Name)), queue_name(Name1). queue_name(Name) -> diff --git a/test/cluster_formation_locking_SUITE.erl b/test/cluster_formation_locking_SUITE.erl new file mode 100644 index 0000000000..25b2df308c --- /dev/null +++ b/test/cluster_formation_locking_SUITE.erl @@ -0,0 +1,80 @@ +%% 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-2017 Pivotal Software, Inc. All rights reserved. +%% +-module(cluster_formation_locking_SUITE). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("eunit/include/eunit.hrl"). + +-compile(export_all). + +all() -> + [ + {group, non_parallel_tests} + ]. + +groups() -> + [ + {non_parallel_tests, [], [ + init_with_lock_exits_after_errors, + init_with_lock_ignore_after_errors, + init_with_lock_not_supported, + init_with_lock_supported + ]} + ]. + +init_per_testcase(Testcase, Config) when Testcase == init_with_lock_exits_after_errors; + Testcase == init_with_lock_not_supported; + Testcase == init_with_lock_supported -> + application:set_env(rabbit, cluster_formation, + [{peer_discover_backend, peer_discover_classic_config}, + {lock_acquisition_failure_mode, fail}]), + ok = meck:new(rabbit_peer_discovery_classic_config, [passthrough]), + Config; +init_per_testcase(init_with_lock_ignore_after_errors, Config) -> + application:set_env(rabbit, cluster_formation, + [{peer_discover_backend, peer_discover_classic_config}, + {lock_acquisition_failure_mode, ignore}]), + ok = meck:new(rabbit_peer_discovery_classic_config, [passthrough]), + Config. + +end_per_testcase(_, _) -> + meck:unload(), + application:unset_env(rabbit, cluster_formation). + +init_with_lock_exits_after_errors(_Config) -> + meck:expect(rabbit_peer_discovery_classic_config, lock, fun(_) -> {error, "test error"} end), + ?assertExit(cannot_acquire_startup_lock, rabbit_mnesia:init_with_lock(2, 10, fun() -> ok end)), + ?assert(meck:validate(rabbit_peer_discovery_classic_config)), + passed. + +init_with_lock_ignore_after_errors(_Config) -> + meck:expect(rabbit_peer_discovery_classic_config, lock, fun(_) -> {error, "test error"} end), + ?assertEqual(ok, rabbit_mnesia:init_with_lock(2, 10, fun() -> ok end)), + ?assert(meck:validate(rabbit_peer_discovery_classic_config)), + passed. + +init_with_lock_not_supported(_Config) -> + meck:expect(rabbit_peer_discovery_classic_config, lock, fun(_) -> not_supported end), + ?assertEqual(ok, rabbit_mnesia:init_with_lock(2, 10, fun() -> ok end)), + ?assert(meck:validate(rabbit_peer_discovery_classic_config)), + passed. + +init_with_lock_supported(_Config) -> + meck:expect(rabbit_peer_discovery_classic_config, lock, fun(_) -> {ok, data} end), + meck:expect(rabbit_peer_discovery_classic_config, unlock, fun(data) -> ok end), + ?assertEqual(ok, rabbit_mnesia:init_with_lock(2, 10, fun() -> ok end)), + ?assert(meck:validate(rabbit_peer_discovery_classic_config)), + passed. diff --git a/test/clustering_management_SUITE.erl b/test/clustering_management_SUITE.erl index b0a93ad208..51c0928ba5 100644 --- a/test/clustering_management_SUITE.erl +++ b/test/clustering_management_SUITE.erl @@ -135,7 +135,8 @@ join_and_part_cluster(Config) -> %% Allow clustering with already clustered node ok = stop_app(Rabbit), - {ok, already_member} = join_cluster(Rabbit, Hare), + {ok, <<"The node is already a member of this cluster">>} = + join_cluster(Rabbit, Hare), ok = start_app(Rabbit), stop_reset_start(Rabbit), @@ -388,10 +389,9 @@ force_boot(Config) -> change_cluster_node_type(Config) -> [Rabbit, Hare, _Bunny] = cluster_members(Config), - %% Trying to change the ram node when not clustered should always fail + %% Trying to change the node to the ram type when not clustered should always fail ok = stop_app(Rabbit), assert_failure(fun () -> change_cluster_node_type(Rabbit, ram) end), - assert_failure(fun () -> change_cluster_node_type(Rabbit, disc) end), ok = start_app(Rabbit), ok = stop_app(Rabbit), @@ -643,7 +643,7 @@ wait_for_pid_file_to_contain_running_process_pid(PidFile, Attempts, Timeout) -> Pid = pid_from_file(PidFile), case rabbit_misc:is_os_process_alive(Pid) of true -> ok; - false -> + false -> ct:sleep(Timeout), wait_for_pid_file_to_contain_running_process_pid(PidFile, Attempts - 1, Timeout) end. diff --git a/test/partitions_SUITE.erl b/test/partitions_SUITE.erl index 8c8a772987..b09d05b550 100644 --- a/test/partitions_SUITE.erl +++ b/test/partitions_SUITE.erl @@ -335,16 +335,26 @@ autoheal_unexpected_finish(Config) -> partial_false_positive(Config) -> [A, B, C] = rabbit_ct_broker_helpers:get_node_configs(Config, nodename), + suspend_node_monitor(Config, C), block([{A, B}]), timer:sleep(1000), block([{A, C}]), timer:sleep(?DELAY), + resume_node_monitor(Config, C), + timer:sleep(?DELAY), unblock([{A, B}, {A, C}]), timer:sleep(?DELAY), %% When B times out A's connection, it will check with C. C will %% not have timed out A yet, but already it can't talk to it. We %% need to not consider this a partial partition; B and C should %% still talk to each other. + %% + %% Because there is a chance that C can still talk to A when B + %% requests to check for a partial partition, we suspend C's + %% rabbit_node_monitor at the beginning and resume it after the + %% link between A and C is blocked. This way, when B asks C about + %% A, we make sure that the A<->C link is blocked before C's + %% rabbit_node_monitor processes B's request. [B, C] = partitions(A), [A] = partitions(B), [A] = partitions(C), @@ -369,7 +379,19 @@ partial_to_full(Config) -> partial_pause_minority(Config) -> [A, B, C] = rabbit_ct_broker_helpers:get_node_configs(Config, nodename), set_mode(Config, pause_minority), + %% We suspend rabbit_node_monitor on C while we block the link + %% between A and B. This should make sure C's rabbit_node_monitor + %% processes both partial partition checks from A and B at about + %% the same time, and thus increase the chance both A and B decides + %% there is a partial partition. + %% + %% Without this, one node may see the partial partition and stop, + %% before the other node sees it. In this case, the other node + %% doesn't stop and this testcase fails. + suspend_node_monitor(Config, C), block([{A, B}]), + timer:sleep(?DELAY), + resume_node_monitor(Config, C), [await_running(N, false) || N <- [A, B]], await_running(C, true), unblock([{A, B}]), @@ -394,6 +416,22 @@ set_mode(Config, Mode) -> set_mode(Config, Nodes, Mode) -> rabbit_ct_broker_helpers:set_partition_handling_mode(Config, Nodes, Mode). +suspend_node_monitor(Config, Node) -> + rabbit_ct_broker_helpers:rpc( + Config, Node, ?MODULE, suspend_or_resume_node_monitor, [suspend]). + +resume_node_monitor(Config, Node) -> + rabbit_ct_broker_helpers:rpc( + Config, Node, ?MODULE, suspend_or_resume_node_monitor, [resume]). + +suspend_or_resume_node_monitor(SuspendOrResume) -> + Action = case SuspendOrResume of + suspend -> "Suspending"; + resume -> "Resuming" + end, + rabbit_log:info("(~s) ~s node monitor~n", [?MODULE, Action]), + ok = sys:SuspendOrResume(rabbit_node_monitor). + block_unblock(Pairs) -> block(Pairs), timer:sleep(?DELAY), diff --git a/test/term_to_binary_compat_prop_SUITE.erl b/test/term_to_binary_compat_prop_SUITE.erl new file mode 100644 index 0000000000..d09b23c9ea --- /dev/null +++ b/test/term_to_binary_compat_prop_SUITE.erl @@ -0,0 +1,62 @@ +%% 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) 2017 Pivotal Software, Inc. All rights reserved. +%% + + +-module(term_to_binary_compat_prop_SUITE). + +-compile(export_all). + +-include("rabbit.hrl"). +-include_lib("common_test/include/ct.hrl"). +-include_lib("proper/include/proper.hrl"). + +all() -> + %% The test should run on OTP < 20 (erts < 9) + case erts_gt_8() of + true -> + []; + false -> + [queue_name_to_binary] + end. + +erts_gt_8() -> + Vsn = erlang:system_info(version), + [Maj|_] = string:tokens(Vsn, "."), + list_to_integer(Maj) > 8. + +init_per_suite(Config) -> + rabbit_ct_helpers:log_environment(), + rabbit_ct_helpers:run_setup_steps(Config). + +end_per_suite(Config) -> + rabbit_ct_helpers:run_teardown_steps(Config). + +init_per_testcase(Testcase, Config) -> + rabbit_ct_helpers:testcase_started(Config, Testcase). + +queue_name_to_binary(Config) -> + Fun = fun () -> prop_queue_name_to_binary(Config) end, + rabbit_ct_proper_helpers:run_proper(Fun, [], 10000). + + +prop_queue_name_to_binary(_Config) -> + ?FORALL({Vhost, QName}, {binary(), binary()}, + begin + Resource = rabbit_misc:r(Vhost, queue, QName), + Legacy = term_to_binary_compat:queue_name_to_binary(Resource), + Current = term_to_binary(Resource), + Current =:= Legacy + end).
\ No newline at end of file diff --git a/test/unit_SUITE.erl b/test/unit_SUITE.erl index f3fec06cb4..3e92158595 100644 --- a/test/unit_SUITE.erl +++ b/test/unit_SUITE.erl @@ -332,7 +332,7 @@ do_decrypt_start_app(Config, Passphrase) -> %% %% We expect a failure *after* the decrypting has been done. try - rabbit:start_apps([rabbit_shovel_test]) + rabbit:start_apps([rabbit_shovel_test], #{rabbit => temporary}) catch _:_ -> ok end, @@ -359,7 +359,7 @@ decrypt_start_app_undefined(Config) -> %% %% We expect a failure during decryption because the passphrase is missing. try - rabbit:start_apps([rabbit_shovel_test]) + rabbit:start_apps([rabbit_shovel_test], #{rabbit => temporary}) catch exit:{bad_configuration, config_entry_decoder} -> ok; _:_ -> exit(unexpected_exception) @@ -379,7 +379,7 @@ decrypt_start_app_wrong_passphrase(Config) -> %% %% We expect a failure during decryption because the passphrase is wrong. try - rabbit:start_apps([rabbit_shovel_test]) + rabbit:start_apps([rabbit_shovel_test], #{rabbit => temporary}) catch exit:{decryption_error,_,_} -> ok; _:_ -> exit(unexpected_exception) diff --git a/test/unit_inbroker_parallel_SUITE.erl b/test/unit_inbroker_parallel_SUITE.erl index f9cfd58eaa..9c274ab525 100644 --- a/test/unit_inbroker_parallel_SUITE.erl +++ b/test/unit_inbroker_parallel_SUITE.erl @@ -146,7 +146,7 @@ on_disk_stop(Pid) -> end. queue_name(Config, Name) -> - Name1 = rabbit_ct_helpers:config_to_testcase_name(Config, Name), + Name1 = iolist_to_binary(rabbit_ct_helpers:config_to_testcase_name(Config, Name)), queue_name(Name1). queue_name(Name) -> |
