perf: micro optimisation: no lookup for non-wildcard in trie
This commit is contained in:
parent
3c03047c9f
commit
55316b3ac3
|
@ -194,6 +194,11 @@ delete_key(Key) ->
|
||||||
ok
|
ok
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
%% micro-optimization: no need to lookup when topic is not wildcard
|
||||||
|
%% because we only insert wildcards to emqx_trie
|
||||||
|
lookup_topic(_Topic, false) -> [];
|
||||||
|
lookup_topic(Topic, true) -> lookup_topic(Topic).
|
||||||
|
|
||||||
lookup_topic(Topic) when is_binary(Topic) ->
|
lookup_topic(Topic) when is_binary(Topic) ->
|
||||||
case ets:lookup(?TRIE, ?TOPIC(Topic)) of
|
case ets:lookup(?TRIE, ?TOPIC(Topic)) of
|
||||||
[#?TRIE{count = C}] -> [Topic || C > 0];
|
[#?TRIE{count = C}] -> [Topic || C > 0];
|
||||||
|
@ -220,20 +225,20 @@ do_match(Words) ->
|
||||||
|
|
||||||
do_match(Words, Prefix) ->
|
do_match(Words, Prefix) ->
|
||||||
case is_compact() of
|
case is_compact() of
|
||||||
true -> match_compact(Words, Prefix, []);
|
true -> match_compact(Words, Prefix, false, []);
|
||||||
false -> match_no_compact(Words, Prefix, [])
|
false -> match_no_compact(Words, Prefix, false, [])
|
||||||
end.
|
end.
|
||||||
|
|
||||||
match_no_compact([], Topic, Acc) ->
|
match_no_compact([], Topic, IsWildcard, Acc) ->
|
||||||
'match_#'(Topic) ++ %% try match foo/bar/#
|
'match_#'(Topic) ++ %% try match foo/+/# or foo/bar/#
|
||||||
lookup_topic(Topic) ++ %% try match foo/bar
|
lookup_topic(Topic, IsWildcard) ++ %% e.g. foo/+
|
||||||
Acc;
|
Acc;
|
||||||
match_no_compact([Word | Words], Prefix, Acc0) ->
|
match_no_compact([Word | Words], Prefix, IsWildcard, Acc0) ->
|
||||||
case has_prefix(Prefix) of
|
case has_prefix(Prefix) of
|
||||||
true ->
|
true ->
|
||||||
Acc1 = 'match_#'(Prefix) ++ Acc0,
|
Acc1 = 'match_#'(Prefix) ++ Acc0,
|
||||||
Acc = match_no_compact(Words, join(Prefix, '+'), Acc1),
|
Acc = match_no_compact(Words, join(Prefix, '+'), true, Acc1),
|
||||||
match_no_compact(Words, join(Prefix, Word), Acc);
|
match_no_compact(Words, join(Prefix, Word), IsWildcard, Acc);
|
||||||
false ->
|
false ->
|
||||||
%% non-compact paths in database
|
%% non-compact paths in database
|
||||||
%% if there is no prefix matches the current topic prefix
|
%% if there is no prefix matches the current topic prefix
|
||||||
|
@ -250,20 +255,20 @@ match_no_compact([Word | Words], Prefix, Acc0) ->
|
||||||
Acc0
|
Acc0
|
||||||
end.
|
end.
|
||||||
|
|
||||||
match_compact([], Topic, Acc) ->
|
match_compact([], Topic, IsWildcard, Acc) ->
|
||||||
'match_#'(Topic) ++ %% try match foo/bar/#
|
'match_#'(Topic) ++ %% try match foo/bar/#
|
||||||
lookup_topic(Topic) ++ %% try match foo/bar
|
lookup_topic(Topic, IsWildcard) ++ %% try match foo/bar
|
||||||
Acc;
|
Acc;
|
||||||
match_compact([Word | Words], Prefix, Acc0) ->
|
match_compact([Word | Words], Prefix, IsWildcard, Acc0) ->
|
||||||
Acc1 = 'match_#'(Prefix) ++ Acc0,
|
Acc1 = 'match_#'(Prefix) ++ Acc0,
|
||||||
Acc = match_compact(Words, join(Prefix, Word), Acc1),
|
Acc = match_compact(Words, join(Prefix, Word), IsWildcard, Acc1),
|
||||||
WildcardPrefix = join(Prefix, '+'),
|
WildcardPrefix = join(Prefix, '+'),
|
||||||
%% go deeper to match current_prefix/+ only when:
|
%% go deeper to match current_prefix/+ only when:
|
||||||
%% 1. current word is the last
|
%% 1. current word is the last
|
||||||
%% OR
|
%% OR
|
||||||
%% 2. there is a prefix = 'current_prefix/+'
|
%% 2. there is a prefix = 'current_prefix/+'
|
||||||
case Words =:= [] orelse has_prefix(WildcardPrefix) of
|
case Words =:= [] orelse has_prefix(WildcardPrefix) of
|
||||||
true -> match_compact(Words, WildcardPrefix, Acc);
|
true -> match_compact(Words, WildcardPrefix, true, Acc);
|
||||||
false -> Acc
|
false -> Acc
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
|
@ -102,11 +102,11 @@ t_match2(_) ->
|
||||||
?assertEqual([], ?TRIE:match(<<"$SYS/broker/zenmq">>)).
|
?assertEqual([], ?TRIE:match(<<"$SYS/broker/zenmq">>)).
|
||||||
|
|
||||||
t_match3(_) ->
|
t_match3(_) ->
|
||||||
Topics = [<<"d/#">>, <<"a/b/c">>, <<"a/b/+">>, <<"a/#">>, <<"#">>, <<"$SYS/#">>],
|
Topics = [<<"d/#">>, <<"a/b/+">>, <<"a/#">>, <<"#">>, <<"$SYS/#">>],
|
||||||
trans(fun() -> [emqx_trie:insert(Topic) || Topic <- Topics] end),
|
trans(fun() -> [emqx_trie:insert(Topic) || Topic <- Topics] end),
|
||||||
Matched = mnesia:async_dirty(fun emqx_trie:match/1, [<<"a/b/c">>]),
|
Matched = mnesia:async_dirty(fun emqx_trie:match/1, [<<"a/b/c">>]),
|
||||||
case length(Matched) of
|
case length(Matched) of
|
||||||
4 -> ok;
|
3 -> ok;
|
||||||
_ -> error({unexpected, Matched})
|
_ -> error({unexpected, Matched})
|
||||||
end,
|
end,
|
||||||
SysMatched = emqx_trie:match(<<"$SYS/a/b/c">>),
|
SysMatched = emqx_trie:match(<<"$SYS/a/b/c">>),
|
||||||
|
|
Loading…
Reference in New Issue