Skip to content

Commit 1d0e6d5

Browse files
Merge pull request #16710 from rabbitmq/mergify/bp/v4.3.x/pr-16706
Handle infinity for max super stream partitions (backport #16706)
2 parents 51b5217 + 6d7e86c commit 1d0e6d5

6 files changed

Lines changed: 184 additions & 65 deletions

File tree

deps/rabbitmq_stream/src/Elixir.RabbitMQ.CLI.Ctl.Commands.AddSuperStreamCommand.erl

Lines changed: 5 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,8 @@ run([SuperStream],
176176
timeout := Timeout,
177177
partitions := Partitions} =
178178
Opts) ->
179-
Streams = streams_from_partitions(SuperStream, Partitions),
180-
RoutingKeys = routing_keys(Partitions),
179+
Streams = rabbit_stream_utils:streams_from_partitions(SuperStream, Partitions),
180+
RoutingKeys = rabbit_stream_utils:routing_keys(Partitions),
181181
create_super_stream(NodeName,
182182
Timeout,
183183
VHost,
@@ -191,8 +191,9 @@ run([SuperStream],
191191
timeout := Timeout,
192192
binding_keys := BindingKeysStr} =
193193
Opts) ->
194-
BindingKeys = binding_keys(BindingKeysStr),
195-
Streams = streams_from_binding_keys(SuperStream, BindingKeys),
194+
BindingKeys = rabbit_stream_utils:binding_keys(BindingKeysStr),
195+
Streams = rabbit_stream_utils:streams_from_binding_keys(SuperStream,
196+
BindingKeys),
196197

197198
create_super_stream(NodeName,
198199
Timeout,
@@ -202,24 +203,6 @@ run([SuperStream],
202203
stream_arguments(Opts),
203204
BindingKeys).
204205

205-
streams_from_partitions(Name, Partitions) ->
206-
[<<Name/binary, "-", (integer_to_binary(K))/binary>> ||
207-
K <- lists:seq(0, Partitions - 1)].
208-
209-
routing_keys(Partitions) ->
210-
[integer_to_binary(K) || K <- lists:seq(0, Partitions - 1)].
211-
212-
binding_keys(BindingKeysBin) ->
213-
Keys = binary:split(rabbit_data_coercion:to_binary(BindingKeysBin),
214-
<<",">>, [global]),
215-
%% Trim first, then verify the token is not an empty binary
216-
[Trimmed || K <- Keys,
217-
Trimmed <- [string:trim(K)],
218-
Trimmed =/= <<>>].
219-
220-
streams_from_binding_keys(Name, BindingKeys) ->
221-
[<<Name/binary, "-", K/binary>> || K <- BindingKeys].
222-
223206
stream_arguments(Opts) ->
224207
stream_arguments(#{}, Opts).
225208

deps/rabbitmq_stream/src/rabbit_stream_manager.erl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -674,14 +674,14 @@ validate_super_stream_partitions(Partitions) ->
674674
end.
675675

676676
validate_super_stream_max_partitions(Partitions) ->
677-
MaxPartitions = rabbit_stream_utils:max_super_stream_partitions(),
678-
case erlang:length(Partitions) > MaxPartitions of
677+
case rabbit_stream_utils:validate_super_stream_max_partitions(Partitions) of
679678
true ->
679+
ok;
680+
false ->
681+
MaxPartitions = rabbit_stream_utils:max_super_stream_partitions(),
680682
{error, {validation_failed,
681683
{rabbit_misc:format("The partition number must not exceed ~w",
682-
[MaxPartitions])}}};
683-
false ->
684-
ok
684+
[MaxPartitions])}}}
685685
end.
686686

687687
exchange_exists(VirtualHost, Name) ->

deps/rabbitmq_stream/src/rabbit_stream_utils.erl

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,18 @@
4040
check_super_stream_permitted/3,
4141
offset_lag/4,
4242
consumer_offset/3,
43+
validate_super_stream_max_partitions/1,
4344
max_super_stream_partitions/0]).
4445

46+
%% super stream partition helpers
47+
-export([streams_from_partitions/2,
48+
streams_from_binding_keys/2,
49+
binding_keys/1,
50+
routing_keys/1]).
51+
52+
%% for tests
53+
-export([validate_super_stream_max_partitions/2]).
54+
4555
-include_lib("rabbit_common/include/rabbit.hrl").
4656
-include_lib("rabbitmq_stream_common/include/rabbit_stream.hrl").
4757
-include_lib("kernel/include/logger.hrl").
@@ -361,6 +371,44 @@ offset_lag(_, 0, 0, LastListenerOffset) when LastListenerOffset > 0 ->
361371
offset_lag(CommittedOffset, ConsumerOffset, _, _) ->
362372
CommittedOffset - ConsumerOffset.
363373

374+
-spec validate_super_stream_max_partitions(list() | integer()) -> boolean().
375+
validate_super_stream_max_partitions(Partitions) ->
376+
MaxPartitions = rabbit_stream_utils:max_super_stream_partitions(),
377+
validate_super_stream_max_partitions(Partitions, MaxPartitions).
378+
379+
-spec validate_super_stream_max_partitions(list() | integer(),
380+
infinity | non_neg_integer()) -> boolean().
381+
validate_super_stream_max_partitions(_, infinity) ->
382+
true;
383+
validate_super_stream_max_partitions(Partitions, Max) when is_list(Partitions) ->
384+
length(Partitions) =< Max;
385+
validate_super_stream_max_partitions(Partitions, Max) when is_integer(Partitions) ->
386+
Partitions =< Max.
387+
388+
-spec max_super_stream_partitions() -> infinity | non_neg_integer().
364389
max_super_stream_partitions() ->
365390
application:get_env(rabbitmq_stream, max_super_stream_partitions,
366391
?MAX_SUPER_STREAM_PARTITIONS).
392+
393+
%% super stream partition helpers
394+
-spec streams_from_partitions(binary(), non_neg_integer()) -> [binary()].
395+
streams_from_partitions(Name, Partitions) ->
396+
[<<Name/binary, "-", (integer_to_binary(K))/binary>> ||
397+
K <- lists:seq(0, Partitions - 1)].
398+
399+
-spec streams_from_binding_keys(binary(), [binary()]) -> [binary()].
400+
streams_from_binding_keys(Name, BindingKeys) ->
401+
[<<Name/binary, "-", K/binary>> || K <- BindingKeys].
402+
403+
-spec routing_keys(non_neg_integer()) -> [binary()].
404+
routing_keys(Partitions) ->
405+
[integer_to_binary(K) || K <- lists:seq(0, Partitions - 1)].
406+
407+
-spec binding_keys(unicode:chardata()) -> [binary()].
408+
binding_keys(BindingKeysBin) ->
409+
Keys = binary:split(rabbit_data_coercion:to_binary(BindingKeysBin),
410+
<<",">>, [global]),
411+
%% Trim first, then verify the token is not an empty binary
412+
[Trimmed || K <- Keys,
413+
Trimmed <- [string:trim(K)],
414+
Trimmed =/= <<>>].

deps/rabbitmq_stream/test/rabbit_stream_manager_SUITE.erl

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,16 @@
1818

1919
-compile(export_all).
2020

21+
-define(TEST_MAX_SUPER_STREAM_PARTITIONS, 5).
22+
2123
all() ->
2224
[{group, non_parallel_tests}].
2325

2426
groups() ->
2527
[{non_parallel_tests, [],
2628
[manage_super_stream,
2729
manage_super_stream_max_partitions,
30+
manage_super_stream_max_partitions_infinity,
2831
lookup_leader,
2932
lookup_member,
3033
partition_index,
@@ -58,7 +61,7 @@ init_per_group(_, Config) ->
5861
1000}]},
5962
RmqStreamAppConf = {rabbitmq_stream,
6063
[{connection_negotiation_step_timeout, 500},
61-
{max_super_stream_partitions, 5}]},
64+
{max_super_stream_partitions, ?TEST_MAX_SUPER_STREAM_PARTITIONS}]},
6265
run_setup_steps(Config1,
6366
[fun(StepConfig) ->
6467
merge_app_env(StepConfig, RmqAppConf)
@@ -72,9 +75,24 @@ end_per_group(_, Config) ->
7275
rabbit_ct_helpers:run_steps(Config,
7376
rabbit_ct_broker_helpers:teardown_steps()).
7477

78+
init_per_testcase(manage_super_stream_max_partitions_infinity = TestCase, Config) ->
79+
ok = rabbit_ct_broker_helpers:rpc(Config,
80+
0,
81+
application,
82+
set_env,
83+
[rabbitmq_stream, max_super_stream_partitions, infinity]),
84+
rabbit_ct_helpers:testcase_started(Config, TestCase);
7585
init_per_testcase(Testcase, Config) ->
7686
rabbit_ct_helpers:testcase_started(Config, Testcase).
7787

88+
end_per_testcase(manage_super_stream_max_partitions_infinity = TestCase, Config) ->
89+
ok = rabbit_ct_broker_helpers:rpc(Config,
90+
0,
91+
application,
92+
set_env,
93+
[rabbitmq_stream, max_super_stream_partitions,
94+
?TEST_MAX_SUPER_STREAM_PARTITIONS]),
95+
rabbit_ct_helpers:testcase_finished(Config, TestCase);
7896
end_per_testcase(Testcase, Config) ->
7997
rabbit_ct_helpers:testcase_finished(Config, Testcase).
8098

@@ -157,7 +175,7 @@ manage_super_stream(Config) ->
157175
ok.
158176

159177
manage_super_stream_max_partitions(Config) ->
160-
Partitions = 6,
178+
Partitions = ?TEST_MAX_SUPER_STREAM_PARTITIONS + 1,
161179
Name = <<"invoices">>,
162180
Streams =[<<Name/binary, "-", (integer_to_binary(K))/binary>> ||
163181
K <- lists:seq(0, Partitions - 1)],
@@ -167,6 +185,22 @@ manage_super_stream_max_partitions(Config) ->
167185
{validation_failed,
168186
{"The partition number must not exceed 5"}}},
169187
create_super_stream(Config, Name, Streams, RKs)),
188+
189+
ok.
190+
191+
manage_super_stream_max_partitions_infinity(Config) ->
192+
Partitions = ?TEST_MAX_SUPER_STREAM_PARTITIONS + 1,
193+
Name = <<"invoices">>,
194+
Streams =[<<Name/binary, "-", (integer_to_binary(K))/binary>> ||
195+
K <- lists:seq(0, Partitions - 1)],
196+
RKs = [integer_to_binary(K) || K <- lists:seq(0, Partitions - 1)],
197+
198+
?assertEqual(ok,
199+
create_super_stream(Config, Name, Streams, RKs)),
200+
?assertEqual({ok, Streams},
201+
partitions(Config, <<"invoices">>)),
202+
203+
?assertEqual(ok, delete_super_stream(Config, <<"invoices">>)),
170204
ok.
171205

172206
partition_index(Config) ->

deps/rabbitmq_stream/test/rabbit_stream_utils_SUITE.erl

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
-include_lib("eunit/include/eunit.hrl").
77
-include_lib("rabbit_common/include/rabbit.hrl").
88

9+
-import(rabbit_stream_utils,
10+
[validate_super_stream_max_partitions/2]).
11+
912
%%%===================================================================
1013
%%% Common Test callbacks
1114
%%%===================================================================
@@ -17,7 +20,12 @@ suite() ->
1720
[{timetrap, {seconds, 30}}].
1821

1922
groups() ->
20-
[{tests, [], [sort_partitions, filter_spec, filter_defined]}].
23+
[{tests, [],
24+
[sort_partitions,
25+
filter_spec,
26+
filter_defined,
27+
test_validate_max_super_stream_partitions,
28+
super_stream_partition_helpers]}].
2129

2230
init_per_suite(Config) ->
2331
Config.
@@ -94,6 +102,66 @@ filter_spec(_) ->
94102
#{} = rabbit_stream_utils:filter_spec(#{<<"sac">> => true}),
95103
ok.
96104

105+
test_validate_max_super_stream_partitions(_) ->
106+
%% infinity means no limit applies
107+
?assertEqual(true, validate_super_stream_max_partitions([], infinity)),
108+
?assertEqual(true, validate_super_stream_max_partitions([a, b, c], infinity)),
109+
?assertEqual(true, validate_super_stream_max_partitions(0, infinity)),
110+
?assertEqual(true, validate_super_stream_max_partitions(1000, infinity)),
111+
%% max = 0: only an empty list and integer 0 are valid
112+
?assertEqual(true, validate_super_stream_max_partitions([], 0)),
113+
?assertEqual(false, validate_super_stream_max_partitions([a], 0)),
114+
?assertEqual(true, validate_super_stream_max_partitions(0, 0)),
115+
?assertEqual(false, validate_super_stream_max_partitions(1, 0)),
116+
%% exactly at the limit is valid
117+
?assertEqual(true, validate_super_stream_max_partitions([a, b, c], 3)),
118+
?assertEqual(true, validate_super_stream_max_partitions(3, 3)),
119+
%% one over the limit is invalid
120+
?assertEqual(false, validate_super_stream_max_partitions([a, b, c, d], 3)),
121+
?assertEqual(false, validate_super_stream_max_partitions(4, 3)),
122+
ok.
123+
124+
super_stream_partition_helpers(_) ->
125+
%% streams_from_partitions/2
126+
?assertEqual([],
127+
rabbit_stream_utils:streams_from_partitions(<<"invoices">>, 0)),
128+
?assertEqual([<<"invoices-0">>],
129+
rabbit_stream_utils:streams_from_partitions(<<"invoices">>, 1)),
130+
?assertEqual([<<"invoices-0">>, <<"invoices-1">>, <<"invoices-2">>],
131+
rabbit_stream_utils:streams_from_partitions(<<"invoices">>, 3)),
132+
133+
%% streams_from_binding_keys/2
134+
?assertEqual([],
135+
rabbit_stream_utils:streams_from_binding_keys(<<"invoices">>, [])),
136+
?assertEqual([<<"invoices-amer">>],
137+
rabbit_stream_utils:streams_from_binding_keys(<<"invoices">>,
138+
[<<"amer">>])),
139+
?assertEqual([<<"invoices-amer">>, <<"invoices-emea">>, <<"invoices-apac">>],
140+
rabbit_stream_utils:streams_from_binding_keys(<<"invoices">>,
141+
[<<"amer">>,
142+
<<"emea">>,
143+
<<"apac">>])),
144+
145+
%% routing_keys/1
146+
?assertEqual([], rabbit_stream_utils:routing_keys(0)),
147+
?assertEqual([<<"0">>], rabbit_stream_utils:routing_keys(1)),
148+
?assertEqual([<<"0">>, <<"1">>, <<"2">>],
149+
rabbit_stream_utils:routing_keys(3)),
150+
151+
%% binding_keys/1
152+
?assertEqual([<<"amer">>],
153+
rabbit_stream_utils:binding_keys(<<"amer">>)),
154+
?assertEqual([<<"amer">>, <<"emea">>, <<"apac">>],
155+
rabbit_stream_utils:binding_keys(<<"amer,emea,apac">>)),
156+
?assertEqual([<<"amer">>, <<"emea">>, <<"apac">>],
157+
rabbit_stream_utils:binding_keys(<<"amer, emea, apac">>)),
158+
?assertEqual([],
159+
rabbit_stream_utils:binding_keys(<<"">>)),
160+
?assertEqual([],
161+
rabbit_stream_utils:binding_keys(<<" ">>)),
162+
163+
ok.
164+
97165
binding(Destination, Order) ->
98166
#binding{destination = #resource{name = Destination},
99167
args = [{<<"x-stream-partition-order">>, signedint, Order}]}.

0 commit comments

Comments
 (0)