1%% This Source Code Form is subject to the terms of the Mozilla Public
2%% License, v. 2.0. If a copy of the MPL was not distributed with this
3%% file, You can obtain one at https://mozilla.org/MPL/2.0/.
4%%
5%% Copyright (c) 2010-2021 VMware, Inc. or its affiliates.  All rights reserved.
6%%
7
8-module(rabbit_mirror_queue_mode_exactly).
9
10-include_lib("rabbit_common/include/rabbit.hrl").
11
12-behaviour(rabbit_mirror_queue_mode).
13
14-export([description/0, suggested_queue_nodes/5, validate_policy/1]).
15
16-rabbit_boot_step({?MODULE,
17                   [{description, "mirror mode exactly"},
18                    {mfa,         {rabbit_registry, register,
19                                   [ha_mode, <<"exactly">>, ?MODULE]}},
20                    {requires,    rabbit_registry},
21                    {enables,     kernel_ready}]}).
22
23description() ->
24    [{description, <<"Mirror queue to a specified number of nodes">>}].
25
26%% When we need to add nodes, we randomise our candidate list as a
27%% crude form of load-balancing. TODO it would also be nice to
28%% randomise the list of ones to remove when we have too many - we
29%% would have to take account of synchronisation though.
30suggested_queue_nodes(Count, MNode, SNodes, _SSNodes, Poss) ->
31    SCount = Count - 1,
32    {MNode, case SCount > length(SNodes) of
33                true  -> Cand = shuffle((Poss -- [MNode]) -- SNodes),
34                         SNodes ++ lists:sublist(Cand, SCount - length(SNodes));
35                false -> lists:sublist(SNodes, SCount)
36            end}.
37
38shuffle(L) ->
39    {_, L1} = lists:unzip(lists:keysort(1, [{rand:uniform(), N} || N <- L])),
40    L1.
41
42validate_policy(N) when is_integer(N) andalso N > 0 ->
43    ok;
44validate_policy(Params) ->
45    {error, "ha-mode=\"exactly\" takes an integer, ~p given", [Params]}.
46