8000 0817 improve topic-index search by zmstone · Pull Request #11495 · emqx/emqx · GitHub
[go: up one dir, main page]

Skip to content
Prev Previous commit
chore(topic_index): add topic validation
  • Loading branch information
zmstone committed Aug 25, 2023
commit 808963900a8cc9235e81da270af5c6a7fb486818
24 changes: 14 additions & 10 deletions apps/emqx/src/emqx_trie_search.erl
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@
%% @doc Make a search-key for the given topic.
-spec make_key(emqx_types:topic(), ID) -> key(ID).
make_ke 8000 y(Topic, ID) when is_binary(Topic) ->
Words = words(Topic),
Words = filter_words(Topic),
case emqx_topic:wildcard(Words) of
true ->
%% it's a wildcard
Expand Down Expand Up @@ -171,7 +171,7 @@ matches(Topic, NextF, Opts) ->

%% @doc Entrypoint of the search for a given topic.
search(Topic, NextF, Opts) ->
Words = words(Topic),
Words = topic_words(Topic),
Base = base_init(Words),
ORetFirst = proplists:get_bool(return_first, Opts),
OUnique = proplists:get_bool(unique, Opts),
Expand Down Expand Up @@ -309,7 +309,7 @@ compare([W | Filter], [W | Words], RPrefix) ->
compare(Filter, Words, [W | RPrefix]);
compare([F | _Filter], [W | _Words], _RPrefix) when W < F ->
lower;
compare([F | _Filter], [W | _Words], RPrefix) ->
compare([_F | _Filter], [W | _Words], RPrefix) ->
% NOTE
% Topic: a/b/z
% Filter: +/+/x
Expand All @@ -324,18 +324,22 @@ match_add(K, Acc) when is_list(Acc) ->
match_add(K, first) ->
throw({first, K}).

-spec words(emqx_types:topic()) -> [word()].
words(Topic) when is_binary(Topic) ->
-spec filter_words(emqx_types:topic()) -> [word()].
filter_words(Topic) when is_binary(Topic) ->
% NOTE
% This is almost identical to `emqx_topic:words/1`, but it doesn't convert empty
% tokens to ''. This is needed to keep ordering of words consistent with what
% `match_filter/3` expects.
[word(W) || W <- emqx_topic:tokens(Topic)].
[word(W, filter) || W <- emqx_topic:tokens(Topic)].

-spec word(binary()) -> word().
word(<<"+">>) -> '+';
word(<<"#">>) -> '#';
word(Bin) -> Bin.
topic_words(Topic) when is_binary(Topic) ->
[word(W, topic) || W <- emqx_topic:tokens(Topic)].

word(<<"+">>, topic) -> error(badarg);
word(<<"#">>, topic) -> error(badarg);
word(<<"+">>, filter) -> '+';
word(<<"#">>, filter) -> '#';
word(Bin, _) -> Bin.

%% match non-wildcard topics
match_topics(Topic, {Topic, _} = Key, NextF, Acc) ->
Expand Down
32 changes: 32 additions & 0 deletions apps/emqx/test/emqx_trie_search_tests.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
%%--------------------------------------------------------------------
%% Copyright (c) 2023 EMQ Technologies Co., Ltd. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%--------------------------------------------------------------------

-module(emqx_trie_search_tests).

-include_lib("eunit/include/eunit.hrl").

topic_validation_test() ->
NextF = fun(_) -> '$end_of_table' end,
Call = fun(Topic) ->
emqx_trie_search:match(Topic, NextF)
end,
?assertError(badarg, Call(<<"+">>)),
?assertError(badarg, Call(<<"#">>)),
?assertError(badarg, Call(<<"a/+/b">>)),
?assertError(badarg, Call(<<"a/b/#">>)),
?assertEqual(false, Call(<<"a/b/b+">>)),
?assertEqual(false, Call(<<"a/b/c#">>)),
ok.
0