emqx/apps/emqx_s3/src/emqx_s3_profile_http_pools.erl
2024-02-23 08:21:06 +01:00

125 lines
3.1 KiB
Erlang

%%--------------------------------------------------------------------
%% Copyright (c) 2022-2024 EMQ Technologies Co., Ltd. All Rights Reserved.
%%--------------------------------------------------------------------
-module(emqx_s3_profile_http_pools).
-include_lib("stdlib/include/ms_transform.hrl").
-export([
create_table/0,
register/2,
unregister/2,
register_client/2,
unregister_client/2,
set_outdated/3,
outdated/1,
all/1
]).
-export_type([pool_name/0]).
-define(TAB, ?MODULE).
-type pool_name() :: ecpool:pool_name().
-type pool_key() :: {emqx_s3:profile_id(), pool_name()}.
-record(pool, {
key :: pool_key(),
client_count = 0 :: integer(),
deadline = undefined :: undefined | integer(),
extra = #{} :: map()
}).
-spec create_table() -> ok.
create_table() ->
_ = ets:new(?TAB, [
named_table,
public,
ordered_set,
{keypos, #pool.key},
{read_concurrency, true},
{write_concurrency, true}
]),
ok.
-spec register(emqx_s3:profile_id(), pool_name()) ->
ok.
register(ProfileId, PoolName) ->
Key = key(ProfileId, PoolName),
true = ets:insert(?TAB, #pool{
key = Key,
client_count = 0,
deadline = undefined,
extra = #{}
}),
ok.
-spec unregister(emqx_s3:profile_id(), pool_name()) ->
ok.
unregister(ProfileId, PoolName) ->
Key = key(ProfileId, PoolName),
true = ets:delete(?TAB, Key),
ok.
-spec register_client(emqx_s3:profile_id(), pool_name()) ->
integer().
register_client(ProfileId, PoolName) ->
Key = key(ProfileId, PoolName),
ets:update_counter(?TAB, Key, {#pool.client_count, 1}).
-spec unregister_client(emqx_s3:profile_id(), pool_name()) ->
integer().
unregister_client(ProfileId, PoolName) ->
Key = key(ProfileId, PoolName),
try
ets:update_counter(?TAB, Key, {#pool.client_count, -1})
catch
error:badarg ->
undefined
end.
-spec set_outdated(emqx_s3:profile_id(), pool_name(), integer()) ->
ok.
set_outdated(ProfileId, PoolName, Timeout) ->
Key = key(ProfileId, PoolName),
Now = erlang:monotonic_time(millisecond),
_ = ets:update_element(?TAB, Key, {#pool.deadline, Now + Timeout}),
ok.
-spec outdated(emqx_s3:profile_id()) ->
[pool_name()].
outdated(ProfileId) ->
Now = erlang:monotonic_time(millisecond),
MS = ets:fun2ms(
fun(#pool{key = {CurProfileId, CurPoolName}, deadline = CurDeadline}) when
CurProfileId =:= ProfileId andalso
CurDeadline =/= undefined andalso CurDeadline < Now
->
CurPoolName
end
),
ets:select(?TAB, MS).
-spec all(emqx_s3:profile_id()) ->
[pool_name()].
all(ProfileId) ->
MS = ets:fun2ms(
fun(#pool{key = {CurProfileId, CurPoolName}}) when CurProfileId =:= ProfileId ->
CurPoolName
end
),
ets:select(?TAB, MS).
%%--------------------------------------------------------------------
%% Helpers
%%--------------------------------------------------------------------
key(ProfileId, PoolName) ->
{ProfileId, PoolName}.