Bläddra i källkod

fix(rule): fix a quering problem when 'a/b' and 'a/b/#' exist at the same time.

When using `ets:next` to query the next level of topic words, we should prioritize the next level
of '#', '+'.
JianBo He 2 år sedan
förälder
incheckning
e630331de1

+ 10 - 1
apps/emqx_rule_engine/src/emqx_rule_index.erl

@@ -114,6 +114,10 @@ matches(K, Prefix, Words, RPrefix, Acc, Tab) ->
 
 matches_rest(false, [W | Rest], RPrefix, Acc, Tab) ->
     matches(Rest, [W | RPrefix], Acc, Tab);
+matches_rest({false, exact}, [W | Rest], RPrefix, Acc, Tab) ->
+    NAcc1 = matches(Rest, ['#' | RPrefix], Acc, Tab),
+    NAcc2 = matches(Rest, ['+' | RPrefix], NAcc1, Tab),
+    matches(Rest, [W | RPrefix], NAcc2, Tab);
 matches_rest(plus, [W | Rest], RPrefix, Acc, Tab) ->
     NAcc = matches(Rest, ['+' | RPrefix], Acc, Tab),
     matches(Rest, [W | RPrefix], NAcc, Tab);
@@ -129,7 +133,12 @@ match_filter(Prefix, {Filter, _ID}, NotPrefix) ->
     case match_filter(Prefix, Filter) of
         exact ->
             % NOTE: exact match is `true` only if we match whole topic, not prefix
-            NotPrefix;
+            case NotPrefix of
+                true ->
+                    true;
+                false ->
+                    {false, exact}
+            end;
         Match ->
             Match
     end;

+ 1 - 2
apps/emqx_rule_engine/test/emqx_rule_engine_SUITE.erl

@@ -427,8 +427,7 @@ t_get_rules_for_topic_3(_Config) ->
         <<"rule-debug-2">>,
         <<"rule-debug-3">>,
         <<"rule-debug-4">>,
-        <<"rule-debug-5">>,
-        <<"rule-debug-6">>
+        <<"rule-debug-5">>
     ]),
     ok.
 

+ 19 - 1
apps/emqx_rule_engine/test/emqx_rule_index_SUITE.erl

@@ -162,8 +162,26 @@ t_match_ordering(_) ->
     ?assertEqual(Ids1, Ids2),
     ?assertEqual([t_match_id1, t_match_id2, t_match_id3], Ids1).
 
+t_match_wildcards(_) ->
+    Tab = new(),
+    emqx_rule_index:insert(<<"a/b">>, id1, <<>>, Tab),
+    emqx_rule_index:insert(<<"a/b/#">>, id2, <<>>, Tab),
+    emqx_rule_index:insert(<<"a/b/#">>, id3, <<>>, Tab),
+    emqx_rule_index:insert(<<"a/b/c">>, id4, <<>>, Tab),
+    emqx_rule_index:insert(<<"a/b/+">>, id5, <<>>, Tab),
+    emqx_rule_index:insert(<<"a/b/d">>, id6, <<>>, Tab),
+    emqx_rule_index:insert(<<"a/+/+">>, id7, <<>>, Tab),
+    emqx_rule_index:insert(<<"a/+/#">>, id8, <<>>, Tab),
+
+    Rules = [id(M) || M <- emqx_rule_index:matches(<<"a/b/c">>, Tab, [])],
+    ?assertEqual([id2, id3, id4, id5, id7, id8], Rules),
+
+    Rules1 = [id(M) || M <- emqx_rule_index:matches(<<"a/b">>, Tab, [])],
+    ?assertEqual([id1, id2, id3, id8], Rules1),
+    ok.
+
 new() ->
-    ets:new(?MODULE, [public, ordered_set, {write_concurrency, true}]).
+    ets:new(?MODULE, [public, ordered_set, {read_concurrency, true}]).
 
 match(T, Tab) ->
     emqx_rule_index:match(T, Tab).