Sfoglia il codice sorgente

perf: micro optimisation: no lookup for non-wildcard in trie

Zaiming Shi 4 anni fa
parent
commit
55316b3ac3
2 ha cambiato i file con 20 aggiunte e 15 eliminazioni
  1. 18 13
      src/emqx_trie.erl
  2. 2 2
      test/emqx_trie_SUITE.erl

+ 18 - 13
src/emqx_trie.erl

@@ -194,6 +194,11 @@ delete_key(Key) ->
             ok
     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) ->
     case ets:lookup(?TRIE, ?TOPIC(Topic)) of
         [#?TRIE{count = C}] -> [Topic || C > 0];
@@ -220,20 +225,20 @@ do_match(Words) ->
 
 do_match(Words, Prefix) ->
     case is_compact() of
-        true -> match_compact(Words, Prefix, []);
-        false -> match_no_compact(Words, Prefix, [])
+        true -> match_compact(Words, Prefix, false, []);
+        false -> match_no_compact(Words, Prefix, false, [])
     end.
 
-match_no_compact([], Topic, Acc) ->
-    'match_#'(Topic) ++ %% try match foo/bar/#
-    lookup_topic(Topic) ++ %% try match foo/bar
+match_no_compact([], Topic, IsWildcard, Acc) ->
+    'match_#'(Topic) ++ %% try match foo/+/# or foo/bar/#
+    lookup_topic(Topic, IsWildcard) ++ %% e.g. foo/+
     Acc;
-match_no_compact([Word | Words], Prefix, Acc0) ->
+match_no_compact([Word | Words], Prefix, IsWildcard, Acc0) ->
     case has_prefix(Prefix) of
         true ->
             Acc1 = 'match_#'(Prefix) ++ Acc0,
-            Acc = match_no_compact(Words, join(Prefix, '+'), Acc1),
-            match_no_compact(Words, join(Prefix, Word), Acc);
+            Acc = match_no_compact(Words, join(Prefix, '+'), true, Acc1),
+            match_no_compact(Words, join(Prefix, Word), IsWildcard, Acc);
         false ->
             %% non-compact paths in database
             %% if there is no prefix matches the current topic prefix
@@ -250,20 +255,20 @@ match_no_compact([Word | Words], Prefix, Acc0) ->
             Acc0
     end.
 
-match_compact([], Topic, Acc) ->
+match_compact([], Topic, IsWildcard, Acc) ->
     'match_#'(Topic) ++ %% try match foo/bar/#
-    lookup_topic(Topic) ++ %% try match foo/bar
+    lookup_topic(Topic, IsWildcard) ++ %% try match foo/bar
     Acc;
-match_compact([Word | Words], Prefix, Acc0) ->
+match_compact([Word | Words], Prefix, IsWildcard, 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, '+'),
     %% go deeper to match current_prefix/+ only when:
     %% 1. current word is the last
     %% OR
     %% 2. there is a prefix = 'current_prefix/+'
     case Words =:= [] orelse has_prefix(WildcardPrefix) of
-        true -> match_compact(Words, WildcardPrefix, Acc);
+        true -> match_compact(Words, WildcardPrefix, true, Acc);
         false -> Acc
     end.
 

+ 2 - 2
test/emqx_trie_SUITE.erl

@@ -102,11 +102,11 @@ t_match2(_) ->
     ?assertEqual([], ?TRIE:match(<<"$SYS/broker/zenmq">>)).
 
 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),
     Matched = mnesia:async_dirty(fun emqx_trie:match/1, [<<"a/b/c">>]),
     case length(Matched) of
-        4 -> ok;
+        3 -> ok;
         _ -> error({unexpected, Matched})
     end,
     SysMatched = emqx_trie:match(<<"$SYS/a/b/c">>),