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.
This commit is contained in:
Andrew Mayorov 2023-08-17 01:13:19 +04:00
parent e39bbf4c49
commit 5d79823891
No known key found for this signature in database
GPG Key ID: 2837C62ACFBFED5D
1 changed files with 21 additions and 9 deletions

View File

@ -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 = #{}) ->