64 lines
1.9 KiB
Erlang
64 lines
1.9 KiB
Erlang
-module(dns_pending_wheel).
|
|
|
|
-export([start/0, insert/2, lookup/1, delete/1]).
|
|
|
|
-define(TTL, 5).
|
|
-define(TICK_MS, 1000).
|
|
-define(WHEEL_SIZE, (?TTL + 1)).
|
|
|
|
%%% =====================================================
|
|
%%% Public API
|
|
%%% =====================================================
|
|
|
|
start() ->
|
|
ets:new(dns_pending_data, [ordered_set, public, named_table, {read_concurrency, true}, {write_concurrency, true}]),
|
|
ets:new(dns_pending_wheel, [bag, public, named_table, {read_concurrency, true}, {write_concurrency, true}]),
|
|
start_scanner().
|
|
|
|
-spec insert(Key :: any(), Val :: any()) -> ok.
|
|
insert(Key, Val) ->
|
|
Tick = now_tick(),
|
|
Slot = Tick rem ?WHEEL_SIZE,
|
|
ets:insert(dns_pending_data, {Key, {Val, Tick}}),
|
|
ets:insert(dns_pending_wheel, {Slot, {Key, Tick}}),
|
|
ok.
|
|
|
|
-spec lookup(Key :: any()) -> [term()].
|
|
lookup(Key) ->
|
|
ets:lookup(dns_pending_data, Key).
|
|
|
|
-spec delete(Key :: any()) -> ok.
|
|
delete(Key) ->
|
|
ets:delete(dns_pending_data, Key),
|
|
ok.
|
|
|
|
%%% =====================================================
|
|
%%% Internal
|
|
%%% =====================================================
|
|
|
|
start_scanner() ->
|
|
{ok, spawn_link(fun tick_loop/0)}.
|
|
|
|
%% 当前插入数据是在Tick, 而清理是从 Tick + 1 开始的,没有问题
|
|
tick_loop() ->
|
|
Tick = now_tick(),
|
|
CleanSlot = (Tick + 1) rem ?WHEEL_SIZE,
|
|
spawn(fun() -> clean_slot(CleanSlot) end),
|
|
timer:sleep(?TICK_MS),
|
|
tick_loop().
|
|
|
|
clean_slot(Slot) ->
|
|
Items = ets:lookup(dns_pending_wheel, Slot),
|
|
true = ets:delete(dns_pending_wheel, Slot),
|
|
lists:foreach(fun({_, {Key, InsertTick}}) ->
|
|
case ets:lookup(dns_pending_data, Key) of
|
|
[{Key, {_Val, InsertTick}}] ->
|
|
ets:delete(dns_pending_data, Key);
|
|
_ ->
|
|
ok
|
|
end
|
|
end, Items).
|
|
|
|
-spec now_tick() -> integer().
|
|
now_tick() ->
|
|
erlang:system_time(second). |