Skip to content

Commit

Permalink
Merge pull request #4838 from apache/ets-lru-idle
Browse files Browse the repository at this point in the history
add eviction for idleness to ets_lru
  • Loading branch information
rnewson committed Nov 10, 2023
2 parents 5a21bb2 + 813d51c commit 6d393ed
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 8 deletions.
43 changes: 38 additions & 5 deletions src/ets_lru/src/ets_lru.erl
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
max_objs :: non_neg_integer() | undefined,
max_size :: non_neg_integer() | undefined,
max_lifetime :: non_neg_integer() | undefined,
max_idle :: non_neg_integer() | undefined,
time_unit = ?DEFAULT_TIME_UNIT :: atom()
}).

Expand Down Expand Up @@ -236,7 +237,8 @@ accessed(Key, St) ->
trim(St) ->
trim_count(St),
trim_size(St),
trim_lifetime(St).
trim_lifetime(St),
trim_idle(St).

trim_count(#st{max_objs = undefined}) ->
ok;
Expand Down Expand Up @@ -280,6 +282,28 @@ trim_lifetime(#st{max_lifetime = Max} = St) ->
end
end.

trim_idle(#st{max_idle = undefined}) ->
ok;
trim_idle(#st{max_idle = Max} = St) ->
Now = erlang:monotonic_time(St#st.time_unit),
case ets:first(St#st.atimes) of
'$end_of_table' ->
ok;
ATime = {Time, _} ->
case Now - Time > Max of
true ->
[{ATime, Key}] = ets:lookup(St#st.atimes, ATime),
Pattern = #entry{key = Key, ctime = '$1', _ = '_'},
[[CTime]] = ets:match(St#st.objects, Pattern),
true = ets:delete(St#st.objects, Key),
true = ets:delete(St#st.atimes, ATime),
true = ets:delete(St#st.ctimes, CTime),
trim_idle(St);
false ->
ok
end
end.

drop_lru(St, Continue) ->
case ets:first(St#st.atimes) of
'$end_of_table' ->
Expand All @@ -294,16 +318,23 @@ drop_lru(St, Continue) ->
Continue(St)
end.

next_timeout(#st{max_lifetime = undefined}) ->
next_timeout(#st{max_lifetime = undefined, max_idle = undefined}) ->
infinity;
next_timeout(St) ->
case ets:first(St#st.ctimes) of
Now = erlang:monotonic_time(St#st.time_unit),
CTimeout = next_timeout(St#st.ctimes, Now, St#st.max_lifetime),
ATimeout = next_timeout(St#st.atimes, Now, St#st.max_idle),
min(CTimeout, ATimeout).

next_timeout(_Tab, _Now, undefined) ->
infinity;
next_timeout(Tab, Now, Max) ->
case ets:first(Tab) of
'$end_of_table' ->
infinity;
{Time, _} ->
Now = erlang:monotonic_time(St#st.time_unit),
TimeDiff = Now - Time,
erlang:max(St#st.max_lifetime - TimeDiff, 0)
erlang:max(Max - TimeDiff, 0)
end.

set_options(St, []) ->
Expand All @@ -314,6 +345,8 @@ set_options(St, [{max_size, N} | Rest]) when is_integer(N), N >= 0 ->
set_options(St#st{max_size = N}, Rest);
set_options(St, [{max_lifetime, N} | Rest]) when is_integer(N), N >= 0 ->
set_options(St#st{max_lifetime = N}, Rest);
set_options(St, [{max_idle, N} | Rest]) when is_integer(N), N >= 0 ->
set_options(St#st{max_idle = N}, Rest);
set_options(St, [{time_unit, T} | Rest]) when is_atom(T) ->
set_options(St#st{time_unit = T}, Rest);
set_options(_, [Opt | _]) ->
Expand Down
10 changes: 7 additions & 3 deletions src/ets_lru/test/ets_lru_test.erl
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,10 @@ lru_good_options_test_() ->
{[{max_size, 2342923423942309423094}], fun test_good_opts/2},
{[{max_lifetime, 1}], fun test_good_opts/2},
{[{max_lifetime, 5}], fun test_good_opts/2},
{[{max_lifetime, 1244209909180928348}], fun test_good_opts/2}
{[{max_lifetime, 1244209909180928348}], fun test_good_opts/2},
{[{max_idle, 1}], fun test_good_opts/2},
{[{max_idle, 5}], fun test_good_opts/2},
{[{max_idle, 1244209909180928348}], fun test_good_opts/2}
]}
}.

Expand Down Expand Up @@ -215,7 +218,8 @@ lru_limits_test_() ->
[
{[{max_objects, 25}], fun test_limits/2},
{[{max_size, 1024}], fun test_limits/2},
{[{max_lifetime, 100}], fun test_limits/2}
{[{max_lifetime, 100}], fun test_limits/2},
{[{max_idle, 100}], fun test_limits/2}
]}
}.

Expand Down Expand Up @@ -306,7 +310,7 @@ test_limits([{max_size, N}], {ok, LRU}) ->
"Max size ok",
?_assert(insert_kvs(memory, LRU, 10 * N, N))
};
test_limits([{max_lifetime, N}], {ok, LRU}) ->
test_limits([{Max, N}], {ok, LRU}) when Max == max_lifetime; Max == max_idle ->
[
{
"Expire leaves new entries",
Expand Down

0 comments on commit 6d393ed

Please sign in to comment.