Просмотр исходного кода

perf(topicidx): preserve next key on the stack to reuse later

This should further optimize the number of `ets:next/2` calls
required for a single match query.
Andrew Mayorov 2 лет назад
Родитель
Сommit
5d79823891
1 измененных файлов с 21 добавлено и 9 удалено
  1. 21 9
      apps/emqx/src/emqx_topic_index.erl

+ 21 - 9
apps/emqx/src/emqx_topic_index.erl

@@ -127,6 +127,17 @@ matches(Words, RPrefix, Acc, Tab) ->
     Prefix = lists:reverse(RPrefix),
     matches(ets:next(Tab, {Prefix, {}}), Prefix, Words, RPrefix, Acc, Tab).
 
+matches(Words, RPrefix, K = {Filter, _}, Acc, Tab) ->
+    Prefix = lists:reverse(RPrefix),
+    case Prefix > Filter of
+        true ->
+            % NOTE: Prefix already greater than the last key seen, need to `ets:next/2`.
+            matches(ets:next(Tab, {Prefix, {}}), Prefix, Words, RPrefix, Acc, Tab);
+        false ->
+            % NOTE: Prefix is still less than or equal to the last key seen, reuse it.
+            matches(K, Prefix, Words, RPrefix, Acc, Tab)
+    end.
+
 matches(K, Prefix, Words, RPrefix, Acc, Tab) ->
     case match_next(Prefix, K, Words) of
         true ->
@@ -136,26 +147,27 @@ matches(K, Prefix, Words, RPrefix, Acc, Tab) ->
         stop ->
             Acc;
         Matched ->
-            matches_rest(Matched, Words, RPrefix, Acc, Tab)
+            % NOTE: Prserve next key on the stack to save on `ets:next/2` calls.
+            matches_rest(Matched, Words, RPrefix, K, Acc, Tab)
     end.
 
-matches_rest([W1 | [W2 | _] = SLast], [W1 | [W2 | _] = Rest], RPrefix, Acc, Tab) ->
+matches_rest([W1 | [W2 | _] = SLast], [W1 | [W2 | _] = Rest], RPrefix, K, Acc, Tab) ->
     % NOTE
     % Fast-forward through identical words in the topic and the last key suffixes.
     % This should save us a few redundant `ets:next` calls at the cost of slightly
     % more complex match patterns.
-    matches_rest(SLast, Rest, [W1 | RPrefix], Acc, Tab);
-matches_rest(SLast, [W | Rest], RPrefix, Acc, Tab) when is_list(SLast) ->
-    matches(Rest, [W | RPrefix], Acc, Tab);
-matches_rest(plus, [W | Rest], RPrefix, Acc, Tab) ->
+    matches_rest(SLast, Rest, [W1 | RPrefix], K, Acc, Tab);
+matches_rest(SLast, [W | Rest], RPrefix, K, Acc, Tab) when is_list(SLast) ->
+    matches(Rest, [W | RPrefix], K, Acc, Tab);
+matches_rest(plus, [W | Rest], RPrefix, K, Acc, Tab) ->
     % NOTE
     % There's '+' in the key suffix, meaning we should accumulate all matches from
     % each of 2 branches:
     % 1. Match the rest of the topic as if there was '+' in the current position.
     % 2. Skip this key and try to match the topic as it is.
-    NAcc = matches(Rest, ['+' | RPrefix], Acc, Tab),
-    matches(Rest, [W | RPrefix], NAcc, Tab);
-matches_rest(_, [], _RPrefix, Acc, _Tab) ->
+    NAcc = matches(Rest, ['+' | RPrefix], K, Acc, Tab),
+    matches(Rest, [W | RPrefix], K, NAcc, Tab);
+matches_rest(_, [], _RPrefix, _K, Acc, _Tab) ->
     Acc.
 
 match_add(K = {_Filter, ID}, Acc = #{}) ->