Merge pull request #12092 from keynslug/fix/EMQX-11520/ds-empty-levels

fix(ds): pass topics to emqx_topic:words/1 before feeding LTS tree
This commit is contained in:
Andrew Mayorov 2023-12-04 18:34:39 +03:00 committed by GitHub
commit 6a1db5db4a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 81 additions and 13 deletions

View File

@ -91,13 +91,11 @@ match([H | T1], [H | T2]) ->
match(T1, T2);
match([_H | T1], ['+' | T2]) ->
match(T1, T2);
match([<<>> | T1], ['' | T2]) ->
match(T1, T2);
match(_, ['#']) ->
true;
match([_H1 | _], [_H2 | _]) ->
false;
match([_H1 | _], []) ->
false;
match([], [_H | _T2]) ->
match(_, _) ->
false.
-spec match_share(Name, Filter) -> boolean() when

View File

@ -282,6 +282,34 @@ t_publish_as_persistent(_Config) ->
emqtt:stop(Pub)
end.
t_publish_empty_topic_levels(_Config) ->
Sub = connect(<<?MODULE_STRING "1">>, true, 30),
Pub = connect(<<?MODULE_STRING "2">>, true, 30),
try
{ok, _, [?RC_GRANTED_QOS_1]} = emqtt:subscribe(Sub, <<"t//+//#">>, qos1),
Messages = [
{<<"t//1">>, <<"1">>},
{<<"t//1/">>, <<"2">>},
{<<"t//2//">>, <<"3">>},
{<<"t//2//foo">>, <<"4">>},
{<<"t//2/foo">>, <<"5">>},
{<<"t/3/bar">>, <<"6">>}
],
[emqtt:publish(Pub, Topic, Payload, ?QOS_1) || {Topic, Payload} <- Messages],
Received = receive_messages(length(Messages), 1_500),
?assertMatch(
[
#{topic := <<"t//1/">>, payload := <<"2">>},
#{topic := <<"t//2//">>, payload := <<"3">>},
#{topic := <<"t//2//foo">>, payload := <<"4">>}
],
lists:sort(emqx_utils_maps:key_comparer(payload), Received)
)
after
emqtt:stop(Sub),
emqtt:stop(Pub)
end.
%%
connect(ClientId, CleanStart, EI) ->
@ -322,15 +350,18 @@ consume(It) ->
end.
receive_messages(Count) ->
lists:reverse(receive_messages(Count, [])).
receive_messages(Count, 5_000).
receive_messages(0, Msgs) ->
receive_messages(Count, Timeout) ->
lists:reverse(receive_messages(Count, [], Timeout)).
receive_messages(0, Msgs, _Timeout) ->
Msgs;
receive_messages(Count, Msgs) ->
receive_messages(Count, Msgs, Timeout) ->
receive
{publish, Msg} ->
receive_messages(Count - 1, [Msg | Msgs])
after 5_000 ->
receive_messages(Count - 1, [Msg | Msgs], Timeout)
after Timeout ->
Msgs
end.

View File

@ -115,6 +115,12 @@ t_sys_match(_) ->
true = match(<<"a/b/$c">>, <<"a/b/#">>),
true = match(<<"a/b/$c">>, <<"a/#">>).
t_match_tokens(_) ->
true = match(emqx_topic:tokens(<<"a/b/c">>), words(<<"a/+/c">>)),
true = match(emqx_topic:tokens(<<"a//c">>), words(<<"a/+/c">>)),
false = match(emqx_topic:tokens(<<"a//c/">>), words(<<"a/+/c">>)),
true = match(emqx_topic:tokens(<<"a//c/">>), words(<<"a/+/c/#">>)).
t_match_perf(_) ->
true = match(<<"a/b/ccc">>, <<"a/#">>),
Name = <<"/abkc/19383/192939/akakdkkdkak/xxxyyuya/akakak">>,

View File

@ -368,7 +368,7 @@ check_message(
#{?tag := ?IT, ?start_time := StartTime, ?topic_filter := TopicFilter},
#message{timestamp = Timestamp, topic = Topic}
) when Timestamp >= StartTime ->
emqx_topic:match(emqx_topic:words(Topic), TopicFilter);
emqx_topic:match(emqx_topic:tokens(Topic), TopicFilter);
check_message(_Cutoff, _It, _Msg) ->
false.
@ -378,7 +378,7 @@ format_key(KeyMapper, Key) ->
-spec make_key(s(), emqx_types:message()) -> {binary(), [binary()]}.
make_key(#s{keymappers = KeyMappers, trie = Trie}, #message{timestamp = Timestamp, topic = TopicBin}) ->
Tokens = emqx_topic:tokens(TopicBin),
Tokens = emqx_topic:words(TopicBin),
{TopicIndex, Varying} = emqx_ds_lts:topic_key(Trie, fun threshold_fun/1, Tokens),
VaryingHashes = [hash_topic_level(I) || I <- Varying],
KeyMapper = array:get(length(Varying), KeyMappers),

View File

@ -35,7 +35,8 @@
if_only_to_toggle_enable/2,
update_if_present/3,
put_if/4,
rename/3
rename/3,
key_comparer/1
]).
-export_type([config_key/0, config_key_path/0]).
@ -318,3 +319,16 @@ rename(OldKey, NewKey, Map) ->
error ->
Map
end.
-spec key_comparer(K) -> fun((M, M) -> boolean()) when M :: #{K => _V}.
key_comparer(K) ->
fun
(#{K := V1}, #{K := V2}) ->
V1 < V2;
(#{K := _}, _) ->
false;
(_, #{K := _}) ->
true;
(M1, M2) ->
M1 < M2
end.

View File

@ -110,3 +110,22 @@ best_effort_recursive_sum_test_() ->
)
)
].
key_comparer_test() ->
Comp = emqx_utils_maps:key_comparer(foo),
?assertEqual(
[
#{},
#{baz => 42},
#{foo => 1},
#{foo => 42},
#{foo => bar, baz => 42}
],
lists:sort(Comp, [
#{foo => 42},
#{baz => 42},
#{foo => bar, baz => 42},
#{foo => 1},
#{}
])
).