Use new cache API in mod_caps
This commit is contained in:
parent
ca9d04ba6b
commit
a26f90a346
|
@ -20,7 +20,7 @@
|
||||||
|
|
||||||
{deps, [{lager, ".*", {git, "https://github.com/basho/lager", {tag, "3.2.1"}}},
|
{deps, [{lager, ".*", {git, "https://github.com/basho/lager", {tag, "3.2.1"}}},
|
||||||
{p1_utils, ".*", {git, "https://github.com/processone/p1_utils", {tag, "1.0.8"}}},
|
{p1_utils, ".*", {git, "https://github.com/processone/p1_utils", {tag, "1.0.8"}}},
|
||||||
{cache_tab, ".*", {git, "https://github.com/processone/cache_tab", "35cc9904fde"}},
|
{cache_tab, ".*", {git, "https://github.com/processone/cache_tab", "8985b03"}},
|
||||||
{fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.0.11"}}},
|
{fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.0.11"}}},
|
||||||
{stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.8"}}},
|
{stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.8"}}},
|
||||||
{fast_xml, ".*", {git, "https://github.com/processone/fast_xml", {tag, "1.1.21"}}},
|
{fast_xml, ".*", {git, "https://github.com/processone/fast_xml", {tag, "1.1.21"}}},
|
||||||
|
|
125
src/mod_caps.erl
125
src/mod_caps.erl
|
@ -80,7 +80,7 @@ get_features(Host, #caps{node = Node, version = Version,
|
||||||
SubNodes = [Version | Exts],
|
SubNodes = [Version | Exts],
|
||||||
lists:foldl(fun (SubNode, Acc) ->
|
lists:foldl(fun (SubNode, Acc) ->
|
||||||
NodePair = {Node, SubNode},
|
NodePair = {Node, SubNode},
|
||||||
case cache_tab:lookup(caps_features, NodePair,
|
case ets_cache:lookup(caps_features_cache, NodePair,
|
||||||
caps_read_fun(Host, NodePair))
|
caps_read_fun(Host, NodePair))
|
||||||
of
|
of
|
||||||
{ok, Features} when is_list(Features) ->
|
{ok, Features} when is_list(Features) ->
|
||||||
|
@ -250,7 +250,8 @@ reload(Host, NewOpts, OldOpts) ->
|
||||||
fun(I) when is_integer(I), I>0 -> I end,
|
fun(I) when is_integer(I), I>0 -> I end,
|
||||||
1000) of
|
1000) of
|
||||||
{false, MaxSize, _} ->
|
{false, MaxSize, _} ->
|
||||||
cache_tab:setopts(caps_features, [{max_size, MaxSize}]);
|
ets_cache:setopts(caps_features_cache, [{max_size, MaxSize}]),
|
||||||
|
ets_cache:setopts(caps_requests_cache, [{max_size, MaxSize}]);
|
||||||
true ->
|
true ->
|
||||||
ok
|
ok
|
||||||
end,
|
end,
|
||||||
|
@ -258,7 +259,7 @@ reload(Host, NewOpts, OldOpts) ->
|
||||||
fun(I) when is_integer(I), I>0 -> I end,
|
fun(I) when is_integer(I), I>0 -> I end,
|
||||||
timer:hours(24) div 1000) of
|
timer:hours(24) div 1000) of
|
||||||
{false, LifeTime, _} ->
|
{false, LifeTime, _} ->
|
||||||
cache_tab:setopts(caps_features, [{life_time, LifeTime}]);
|
ets_cache:setopts(caps_features_cache, [{life_time, LifeTime}]);
|
||||||
true ->
|
true ->
|
||||||
ok
|
ok
|
||||||
end.
|
end.
|
||||||
|
@ -266,15 +267,8 @@ reload(Host, NewOpts, OldOpts) ->
|
||||||
init([Host, Opts]) ->
|
init([Host, Opts]) ->
|
||||||
process_flag(trap_exit, true),
|
process_flag(trap_exit, true),
|
||||||
Mod = gen_mod:db_mod(Host, Opts, ?MODULE),
|
Mod = gen_mod:db_mod(Host, Opts, ?MODULE),
|
||||||
|
init_cache(Host, Opts),
|
||||||
Mod:init(Host, Opts),
|
Mod:init(Host, Opts),
|
||||||
MaxSize = gen_mod:get_opt(cache_size, Opts,
|
|
||||||
fun(I) when is_integer(I), I>0 -> I end,
|
|
||||||
1000),
|
|
||||||
LifeTime = gen_mod:get_opt(cache_life_time, Opts,
|
|
||||||
fun(I) when is_integer(I), I>0 -> I end,
|
|
||||||
timer:hours(24) div 1000),
|
|
||||||
cache_tab:new(caps_features,
|
|
||||||
[{max_size, MaxSize}, {life_time, LifeTime}]),
|
|
||||||
ejabberd_hooks:add(c2s_presence_in, Host, ?MODULE,
|
ejabberd_hooks:add(c2s_presence_in, Host, ?MODULE,
|
||||||
c2s_presence_in, 75),
|
c2s_presence_in, 75),
|
||||||
ejabberd_hooks:add(user_send_packet, Host, ?MODULE,
|
ejabberd_hooks:add(user_send_packet, Host, ?MODULE,
|
||||||
|
@ -329,35 +323,32 @@ feature_request(Host, From, Caps,
|
||||||
[SubNode | Tail] = SubNodes) ->
|
[SubNode | Tail] = SubNodes) ->
|
||||||
Node = Caps#caps.node,
|
Node = Caps#caps.node,
|
||||||
NodePair = {Node, SubNode},
|
NodePair = {Node, SubNode},
|
||||||
case cache_tab:lookup(caps_features, NodePair,
|
case ets_cache:lookup(caps_features_cache, NodePair,
|
||||||
caps_read_fun(Host, NodePair))
|
caps_read_fun(Host, NodePair)) of
|
||||||
of
|
{ok, Fs} when is_list(Fs) ->
|
||||||
{ok, Fs} when is_list(Fs) ->
|
feature_request(Host, From, Caps, Tail);
|
||||||
feature_request(Host, From, Caps, Tail);
|
_ ->
|
||||||
Other ->
|
LFrom = jid:tolower(From),
|
||||||
NeedRequest = case Other of
|
case ets_cache:insert_new(caps_requests_cache, {LFrom, NodePair}, ok) of
|
||||||
{ok, TS} -> now_ts() >= TS + (?BAD_HASH_LIFETIME);
|
true ->
|
||||||
_ -> true
|
IQ = #iq{type = get,
|
||||||
|
from = jid:make(Host),
|
||||||
|
to = From,
|
||||||
|
sub_els = [#disco_info{node = <<Node/binary, "#",
|
||||||
|
SubNode/binary>>}]},
|
||||||
|
F = fun (IQReply) ->
|
||||||
|
feature_response(IQReply, Host, From, Caps,
|
||||||
|
SubNodes)
|
||||||
end,
|
end,
|
||||||
if NeedRequest ->
|
ejabberd_local:route_iq(IQ, F);
|
||||||
IQ = #iq{type = get,
|
false ->
|
||||||
from = jid:make(Host),
|
ok
|
||||||
to = From,
|
end,
|
||||||
sub_els = [#disco_info{node = <<Node/binary, "#",
|
feature_request(Host, From, Caps, Tail)
|
||||||
SubNode/binary>>}]},
|
|
||||||
cache_tab:insert(caps_features, NodePair, now_ts(),
|
|
||||||
caps_write_fun(Host, NodePair, now_ts())),
|
|
||||||
F = fun (IQReply) ->
|
|
||||||
feature_response(IQReply, Host, From, Caps,
|
|
||||||
SubNodes)
|
|
||||||
end,
|
|
||||||
ejabberd_local:route_iq(IQ, F);
|
|
||||||
true -> feature_request(Host, From, Caps, Tail)
|
|
||||||
end
|
|
||||||
end;
|
end;
|
||||||
feature_request(_Host, _From, _Caps, []) -> ok.
|
feature_request(_Host, _From, _Caps, []) -> ok.
|
||||||
|
|
||||||
-spec feature_response(iq(), binary(), jid(), caps(), [binary()]) -> any().
|
-spec feature_response(iq(), binary(), ljid(), caps(), [binary()]) -> any().
|
||||||
feature_response(#iq{type = result, sub_els = [El]},
|
feature_response(#iq{type = result, sub_els = [El]},
|
||||||
Host, From, Caps, [SubNode | SubNodes]) ->
|
Host, From, Caps, [SubNode | SubNodes]) ->
|
||||||
NodePair = {Caps#caps.node, SubNode},
|
NodePair = {Caps#caps.node, SubNode},
|
||||||
|
@ -366,9 +357,14 @@ feature_response(#iq{type = result, sub_els = [El]},
|
||||||
case check_hash(Caps, DiscoInfo) of
|
case check_hash(Caps, DiscoInfo) of
|
||||||
true ->
|
true ->
|
||||||
Features = DiscoInfo#disco_info.features,
|
Features = DiscoInfo#disco_info.features,
|
||||||
cache_tab:insert(caps_features, NodePair,
|
LServer = jid:nameprep(Host),
|
||||||
Features,
|
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||||
caps_write_fun(Host, NodePair, Features));
|
case Mod:caps_write(LServer, NodePair, Features) of
|
||||||
|
ok ->
|
||||||
|
ets_cache:delete(caps_features_cache, NodePair);
|
||||||
|
{error, _} ->
|
||||||
|
ok
|
||||||
|
end;
|
||||||
false -> ok
|
false -> ok
|
||||||
end
|
end
|
||||||
catch _:{xmpp_codec, _Why} ->
|
catch _:{xmpp_codec, _Why} ->
|
||||||
|
@ -386,13 +382,6 @@ caps_read_fun(Host, Node) ->
|
||||||
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||||
fun() -> Mod:caps_read(LServer, Node) end.
|
fun() -> Mod:caps_read(LServer, Node) end.
|
||||||
|
|
||||||
-spec caps_write_fun(binary(), {binary(), binary()},
|
|
||||||
[binary()] | non_neg_integer()) -> fun().
|
|
||||||
caps_write_fun(Host, Node, Features) ->
|
|
||||||
LServer = jid:nameprep(Host),
|
|
||||||
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
|
||||||
fun() -> Mod:caps_write(LServer, Node, Features) end.
|
|
||||||
|
|
||||||
-spec make_my_disco_hash(binary()) -> binary().
|
-spec make_my_disco_hash(binary()) -> binary().
|
||||||
make_my_disco_hash(Host) ->
|
make_my_disco_hash(Host) ->
|
||||||
JID = jid:make(Host),
|
JID = jid:make(Host),
|
||||||
|
@ -471,10 +460,6 @@ concat_xdata_fields(#xdata{fields = Fields} = X) ->
|
||||||
is_binary(Var), Var /= <<"FORM_TYPE">>],
|
is_binary(Var), Var /= <<"FORM_TYPE">>],
|
||||||
[Form, $<, lists:sort(Res)].
|
[Form, $<, lists:sort(Res)].
|
||||||
|
|
||||||
-spec now_ts() -> integer().
|
|
||||||
now_ts() ->
|
|
||||||
p1_time_compat:system_time(seconds).
|
|
||||||
|
|
||||||
-spec is_valid_node(binary()) -> boolean().
|
-spec is_valid_node(binary()) -> boolean().
|
||||||
is_valid_node(Node) ->
|
is_valid_node(Node) ->
|
||||||
case str:tokens(Node, <<"#">>) of
|
case str:tokens(Node, <<"#">>) of
|
||||||
|
@ -484,6 +469,38 @@ is_valid_node(Node) ->
|
||||||
false
|
false
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
init_cache(Host, Opts) ->
|
||||||
|
CacheOpts = cache_opts(Host, Opts),
|
||||||
|
case use_cache(Host, Opts) of
|
||||||
|
true ->
|
||||||
|
ets_cache:new(caps_features_cache, CacheOpts);
|
||||||
|
false ->
|
||||||
|
ok
|
||||||
|
end,
|
||||||
|
CacheSize = proplists:get_value(max_size, CacheOpts),
|
||||||
|
ets_cache:new(caps_requests_cache,
|
||||||
|
[{max_size, CacheSize},
|
||||||
|
{life_time, timer:seconds(?BAD_HASH_LIFETIME)}]).
|
||||||
|
|
||||||
|
use_cache(Host, Opts) ->
|
||||||
|
gen_mod:get_opt(use_cache, Opts, mod_opt_type(use_cache),
|
||||||
|
ejabberd_config:use_cache(Host)).
|
||||||
|
|
||||||
|
cache_opts(Host, Opts) ->
|
||||||
|
MaxSize = gen_mod:get_opt(cache_size, Opts,
|
||||||
|
mod_opt_type(cache_size),
|
||||||
|
ejabberd_config:cache_size(Host)),
|
||||||
|
CacheMissed = gen_mod:get_opt(cache_missed, Opts,
|
||||||
|
mod_opt_type(cache_missed),
|
||||||
|
ejabberd_config:cache_missed(Host)),
|
||||||
|
LifeTime = case gen_mod:get_opt(cache_life_time, Opts,
|
||||||
|
mod_opt_type(cache_life_time),
|
||||||
|
ejabberd_config:cache_life_time(Host)) of
|
||||||
|
infinity -> infinity;
|
||||||
|
I -> timer:seconds(I)
|
||||||
|
end,
|
||||||
|
[{max_size, MaxSize}, {cache_missed, CacheMissed}, {life_time, LifeTime}].
|
||||||
|
|
||||||
export(LServer) ->
|
export(LServer) ->
|
||||||
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||||
Mod:export(LServer).
|
Mod:export(LServer).
|
||||||
|
@ -519,10 +536,10 @@ import_next(LServer, DBType, NodePair) ->
|
||||||
Mod:import(LServer, NodePair, Features),
|
Mod:import(LServer, NodePair, Features),
|
||||||
import_next(LServer, DBType, ets:next(caps_features_tmp, NodePair)).
|
import_next(LServer, DBType, ets:next(caps_features_tmp, NodePair)).
|
||||||
|
|
||||||
mod_opt_type(cache_life_time) ->
|
mod_opt_type(O) when O == cache_life_time; O == cache_size ->
|
||||||
fun (I) when is_integer(I), I > 0 -> I end;
|
|
||||||
mod_opt_type(cache_size) ->
|
|
||||||
fun (I) when is_integer(I), I > 0 -> I end;
|
fun (I) when is_integer(I), I > 0 -> I end;
|
||||||
|
mod_opt_type(O) when O == use_cache; O == cache_missed ->
|
||||||
|
fun (B) when is_boolean(B) -> B end;
|
||||||
mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end;
|
mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end;
|
||||||
mod_opt_type(_) ->
|
mod_opt_type(_) ->
|
||||||
[cache_life_time, cache_size, db_type].
|
[cache_life_time, cache_size, use_cache, cache_missed, db_type].
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
|
|
||||||
-include("mod_caps.hrl").
|
-include("mod_caps.hrl").
|
||||||
-include("ejabberd_sql_pt.hrl").
|
-include("ejabberd_sql_pt.hrl").
|
||||||
|
-include("logger.hrl").
|
||||||
|
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% API
|
%%% API
|
||||||
|
@ -57,9 +58,16 @@ caps_read(LServer, {Node, SubNode}) ->
|
||||||
end.
|
end.
|
||||||
|
|
||||||
caps_write(LServer, NodePair, Features) ->
|
caps_write(LServer, NodePair, Features) ->
|
||||||
ejabberd_sql:sql_transaction(
|
case ejabberd_sql:sql_transaction(
|
||||||
LServer,
|
LServer,
|
||||||
sql_write_features_t(NodePair, Features)).
|
sql_write_features_t(NodePair, Features)) of
|
||||||
|
{atomic, _} ->
|
||||||
|
ok;
|
||||||
|
{aborted, Reason} ->
|
||||||
|
?ERROR_MSG("Failed to write to SQL 'caps_features' table: ~p",
|
||||||
|
[Reason]),
|
||||||
|
{error, db_failure}
|
||||||
|
end.
|
||||||
|
|
||||||
export(_Server) ->
|
export(_Server) ->
|
||||||
[{caps_features,
|
[{caps_features,
|
||||||
|
|
Loading…
Reference in New Issue