add wheel
This commit is contained in:
parent
4bd53d0afb
commit
46a4d1e015
@ -1,46 +0,0 @@
|
|||||||
%%%-------------------------------------------------------------------
|
|
||||||
%%% @author anlicheng
|
|
||||||
%%% @copyright (C) 2025, <COMPANY>
|
|
||||||
%%% @doc
|
|
||||||
%%%
|
|
||||||
%%% @end
|
|
||||||
%%% Created : 16. 12月 2025 14:38
|
|
||||||
%%%-------------------------------------------------------------------
|
|
||||||
-module(dns_pending_queries).
|
|
||||||
-author("anlicheng").
|
|
||||||
-include("dns_proxy.hrl").
|
|
||||||
|
|
||||||
%% API
|
|
||||||
-export([new/0, put/3, take/1, delete/1]).
|
|
||||||
|
|
||||||
-spec new() -> no_return().
|
|
||||||
new() ->
|
|
||||||
ets:new(?PENDING_TAB, [set, public, {read_concurrency, true}, {write_concurrency, true}]),
|
|
||||||
ets:new(?PENDING_INDEX_TAB, [bag, public, {read_concurrency, true}, {write_concurrency, true}]).
|
|
||||||
|
|
||||||
-spec put(Key :: any(), Value :: any(), TTL :: integer()) -> no_return().
|
|
||||||
put(Key, Value, TTL) when is_integer(TTL) ->
|
|
||||||
ExpireAt = erlang:monotonic_time(millisecond) + TTL,
|
|
||||||
ets:insert(?PENDING_TAB, {Key, {Value, ExpireAt}}),
|
|
||||||
ets:insert(?PENDING_INDEX_TAB, {ExpireAt, Key}).
|
|
||||||
|
|
||||||
-spec take(Key :: any()) -> error | {ok, Value :: any()}.
|
|
||||||
take(Key) ->
|
|
||||||
case ets:lookup(?PENDING_TAB, Key) of
|
|
||||||
[{Key, {Value, ExpireAt}}] ->
|
|
||||||
ets:delete(?PENDING_TAB, Key),
|
|
||||||
ets:delete(?PENDING_INDEX_TAB, ExpireAt),
|
|
||||||
{ok, Value};
|
|
||||||
[] ->
|
|
||||||
error
|
|
||||||
end.
|
|
||||||
|
|
||||||
-spec delete(Key :: any()) -> no_return().
|
|
||||||
delete(Key) ->
|
|
||||||
case ets:lookup(?PENDING_TAB, Key) of
|
|
||||||
[{Key, {_Value, ExpireAt}}] ->
|
|
||||||
ets:delete(?PENDING_TAB, Key),
|
|
||||||
ets:delete(?PENDING_INDEX_TAB, ExpireAt);
|
|
||||||
[] ->
|
|
||||||
ok
|
|
||||||
end.
|
|
||||||
@ -1,51 +0,0 @@
|
|||||||
%%%-------------------------------------------------------------------
|
|
||||||
%%% @author anlicheng
|
|
||||||
%%% @copyright (C) 2025, <COMPANY>
|
|
||||||
%%% @doc
|
|
||||||
%%%
|
|
||||||
%%% @end
|
|
||||||
%%% Created : 16. 12月 2025 14:46
|
|
||||||
%%%-------------------------------------------------------------------
|
|
||||||
-module(dns_pending_scanner).
|
|
||||||
-author("anlicheng").
|
|
||||||
-include("dns_proxy.hrl").
|
|
||||||
|
|
||||||
%% 每次最多清理的记录条数
|
|
||||||
-define(MAX_NUM, 500).
|
|
||||||
|
|
||||||
-record(state, {
|
|
||||||
|
|
||||||
}).
|
|
||||||
|
|
||||||
%% API
|
|
||||||
-export([start_link/0, init/0]).
|
|
||||||
|
|
||||||
start_link() ->
|
|
||||||
{ok, spawn_link(?MODULE, init, [])}.
|
|
||||||
|
|
||||||
init() ->
|
|
||||||
cleaner_loop(#state{}).
|
|
||||||
|
|
||||||
cleaner_loop(State) ->
|
|
||||||
Now = erlang:monotonic_time(millisecond),
|
|
||||||
do_cleanup(Now, ?MAX_NUM),
|
|
||||||
cleaner_loop(State).
|
|
||||||
|
|
||||||
do_cleanup(Now, Max) ->
|
|
||||||
do_cleanup(Now, Max, ets:first(?PENDING_INDEX_TAB)).
|
|
||||||
|
|
||||||
do_cleanup(_Now, 0, _Key) ->
|
|
||||||
ok;
|
|
||||||
do_cleanup(_Now, _Max, '$end_of_table') ->
|
|
||||||
ok;
|
|
||||||
do_cleanup(Now, Max, ExpireAt) when ExpireAt =< Now ->
|
|
||||||
case ets:lookup(?PENDING_INDEX_TAB, ExpireAt) of
|
|
||||||
[{ExpireAt, Key}] ->
|
|
||||||
ets:delete(?PENDING_INDEX_TAB, ExpireAt),
|
|
||||||
ets:delete(?PENDING_TAB, Key),
|
|
||||||
do_cleanup(Now, Max - 1, ets:next(?PENDING_INDEX_TAB, ExpireAt));
|
|
||||||
[] ->
|
|
||||||
do_cleanup(Now, Max - 1, ets:next(?PENDING_INDEX_TAB, ExpireAt))
|
|
||||||
end;
|
|
||||||
do_cleanup(_Now, _Max, _ExpireAt) ->
|
|
||||||
ok.
|
|
||||||
69
apps/sdlan/src/dns_proxy/dns_pending_wheel.erl
Normal file
69
apps/sdlan/src/dns_proxy/dns_pending_wheel.erl
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
-module(dns_pending_wheel).
|
||||||
|
|
||||||
|
-export([start/0, put/2, get/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]),
|
||||||
|
ets:new(dns_pending_wheel, [bag, public, named_table]),
|
||||||
|
start_scanner().
|
||||||
|
|
||||||
|
-spec put(Key :: any(), Val :: any()) -> ok.
|
||||||
|
put(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 get(Key :: any()) -> error | {ok, Val :: any()}.
|
||||||
|
get(Key) ->
|
||||||
|
case ets:lookup(dns_pending_data, Key) of
|
||||||
|
[{Key, {Val, _Tick}}] ->
|
||||||
|
{ok, Val};
|
||||||
|
[] ->
|
||||||
|
error
|
||||||
|
end.
|
||||||
|
|
||||||
|
-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).
|
||||||
@ -19,6 +19,7 @@ start(_StartType, _StartArgs) ->
|
|||||||
%% 启动注册表
|
%% 启动注册表
|
||||||
sdlan_hostname_regedit:init(),
|
sdlan_hostname_regedit:init(),
|
||||||
sdlan_domain_regedit:init(),
|
sdlan_domain_regedit:init(),
|
||||||
|
dns_pending_wheel:start(),
|
||||||
|
|
||||||
start_http_server(),
|
start_http_server(),
|
||||||
start_tcp_server(),
|
start_tcp_server(),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user