Reputation: 2495
I use elang ets table as a simple cache. I want to use a process to scan the table and remove expired elements (multiple).
with ets:foldl
expire_table_example() ->
Tab = ets:new(ets_tab, [named_table, set]),
ets:insert(Tab, [{a, 1}, {b, 2}, {c, 3}, {d, 4}, {e, 5},{f,7}]),
Tab1 = ets:foldl(fun({Key, Val}, Acc) ->
if
(Val > 3) -> [{Key, Val} | Acc];
true -> Acc
end
end, Tab, Tab),
io:format("end ~p ~n", [Tab1]).
I got
[{f,7},{e,5},{d,4}|ets_tab] %% the ets_tab is NOT expected.
How Can I fix This?
Any other API's would do this better?
Upvotes: 4
Views: 1265
Reputation: 1306
You may find that deleting huge numbers of objects periodically may result in undesirable latency spikes. There is interesting project which have cache segments as separate ets tables and deletes outdated objects by dropping whole ets, maybe you will find it interesting as well
https://github.com/fogfish/cache
Upvotes: 0
Reputation: 1818
You can't use ets table as accumulator.
For your purpose you can use ets:select_delete/2:
1> Tab = ets:new(ets_tab, [named_table, set]).
ets_tab
2> ets:insert(Tab, [{a, 1}, {b, 2}, {c, 3}, {d, 4}, {e, 5},{f,7}]).
true
3> ets:select_delete(Tab, [{{'$1','$2'},[{'=<','$2',3}],[true]}]).
3
4> ets:tab2list(Tab).
[{f,7},{e,5},{d,4}]
Or you can use ets:tab2list/1 to get list of all values, filter them and after that re-insert to table:
1> Tab = ets:new(ets_tab, [named_table, set]).
ets_tab
2> ets:insert(Tab, [{a, 1}, {b, 2}, {c, 3}, {d, 4}, {e, 5},{f,7}]).
true
3> L = ets:tab2list(Tab).
[{f,7},{e,5},{d,4},{c,3},{b,2},{a,1}]
4> L2 = lists:filter(fun({Key,Val}) -> Val > 3 end, L).
[{f,7},{e,5},{d,4}]
5> ets:delete_all_objects(Tab).
true
6> ets:insert(Tab, L2).
true
7> ets:tab2list(Tab).
[{f,7},{e,5},{d,4}]
Upvotes: 6
Reputation: 311
Another way it can be done is by using list comprehensions.
1> Tab = ets:new(ets_tab, [named_table, set]).
ets_tab
2> ets:insert(Tab, [{a, 1}, {b, 2}, {c, 3}, {d, 4}, {e, 5},{f,7}]).
true
3> [{X,Y} || {X,Y} <- ets:tab2list(Tab), Y>3].
[{f,7},{e,5},{d,4}]
Upvotes: 0