Skip to content

Commit ae27de2

Browse files
committed
perf: optimize lookup_entry and list for single-table fast path
Pattern-match on ets-flip presence instead of calling get_tables.
1 parent 656d619 commit ae27de2

1 file changed

Lines changed: 70 additions & 38 deletions

File tree

src/hb_store_volatile.erl

Lines changed: 70 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -266,27 +266,39 @@ resolve(Opts, CurrPath, [Next | Rest], Depth) ->
266266
resolve(Opts, PathPart, Rest, Depth)
267267
end.
268268

269-
%% @doc Look up an entry. Checks new table first, falls back to old.
270-
%% Promotes raw/link entries from old to new (with ensure_parent_groups).
271-
%% Groups are NOT promoted — they expire with their table. They get
272-
%% recreated in new as a side-effect when children are promoted.
269+
%% @doc Look up an entry. Single-table: direct lookup (original speed).
270+
%% Double-buffer: checks new first, falls back to old with promote.
271+
%% Groups are NOT promoted — they expire with their table.
273272
lookup_entry(Opts, Key) when is_map(Opts) ->
274-
{New, Old} = get_tables(Opts),
275-
case ets:lookup(New, Key) of
276-
[{_, Entry}] ->
277-
Entry;
278-
[] when Old =:= undefined ->
279-
nil;
280-
[] ->
281-
case ets:lookup(Old, Key) of
282-
[{_, {group, _} = Entry}] ->
283-
Entry;
273+
Found = hb_store:find(Opts),
274+
case Found of
275+
#{<<"ets-flip">> := Flip,
276+
<<"ets-table">> := T1,
277+
<<"ets-table-2">> := T2} ->
278+
{New, Old} =
279+
case atomics:get(Flip, 1) of
280+
0 -> {T1, T2};
281+
1 -> {T2, T1}
282+
end,
283+
case ets:lookup(New, Key) of
284284
[{_, Entry}] ->
285-
ets:insert(New, {Key, Entry}),
286-
ensure_parent_groups(New, Key),
287285
Entry;
288286
[] ->
289-
nil
287+
case ets:lookup(Old, Key) of
288+
[{_, {group, _} = Entry}] ->
289+
Entry;
290+
[{_, Entry}] ->
291+
ets:insert(New, {Key, Entry}),
292+
ensure_parent_groups(New, Key),
293+
Entry;
294+
[] ->
295+
nil
296+
end
297+
end;
298+
#{<<"ets-table">> := Table} ->
299+
case ets:lookup(Table, Key) of
300+
[] -> nil;
301+
[{_, Entry}] -> Entry
290302
end
291303
end;
292304
lookup_entry(Table, Key) ->
@@ -306,30 +318,50 @@ list(Opts, Path) ->
306318
list_resolved(Opts, resolve(Opts, Path)).
307319

308320
list_resolved(Opts, ResolvedPath) ->
309-
{New, Old} = get_tables(Opts),
310-
S1 = group_set(New, ResolvedPath),
311-
S2 =
312-
case Old of
313-
undefined -> sets:new();
314-
_ -> group_set(Old, ResolvedPath)
315-
end,
316-
Union = sets:union(S1, S2),
317-
case sets:size(Union) > 0 of
318-
true ->
319-
{ok, sets:to_list(Union)};
320-
false ->
321-
case lookup_entry(Opts, ResolvedPath) of
322-
{link, Link} ->
323-
list(Opts, Link);
324-
{raw, Value} when is_map(Value) ->
325-
{ok, maps:keys(Value)};
326-
{raw, Value} when is_list(Value) ->
327-
{ok, Value};
328-
_ ->
329-
not_found
321+
Found = hb_store:find(Opts),
322+
case Found of
323+
#{<<"ets-flip">> := Flip,
324+
<<"ets-table">> := T1,
325+
<<"ets-table-2">> := T2} ->
326+
{New, Old} =
327+
case atomics:get(Flip, 1) of
328+
0 -> {T1, T2};
329+
1 -> {T2, T1}
330+
end,
331+
Union = sets:union(
332+
group_set(New, ResolvedPath),
333+
group_set(Old, ResolvedPath)
334+
),
335+
case sets:size(Union) > 0 of
336+
true ->
337+
{ok, sets:to_list(Union)};
338+
false ->
339+
list_fallback(Opts, ResolvedPath)
340+
end;
341+
#{<<"ets-table">> := Table} ->
342+
case lookup_entry(Table, ResolvedPath) of
343+
{group, Set} ->
344+
{ok, sets:to_list(Set)};
345+
Other ->
346+
list_from_entry(Opts, ResolvedPath, Other)
330347
end
331348
end.
332349

350+
list_fallback(Opts, ResolvedPath) ->
351+
case lookup_entry(Opts, ResolvedPath) of
352+
{link, Link} -> list(Opts, Link);
353+
Other -> list_from_entry(Opts, ResolvedPath, Other)
354+
end.
355+
356+
list_from_entry(_Opts, _Path, {raw, Value}) when is_map(Value) ->
357+
{ok, maps:keys(Value)};
358+
list_from_entry(_Opts, _Path, {raw, Value}) when is_list(Value) ->
359+
{ok, Value};
360+
list_from_entry(Opts, _Path, {link, Link}) ->
361+
list(Opts, Link);
362+
list_from_entry(_Opts, _Path, _) ->
363+
not_found.
364+
333365
%% @doc Determine the item type at a path.
334366
type(Opts, RawKey) ->
335367
Key = resolve(Opts, RawKey),

0 commit comments

Comments
 (0)