Skip to content

Commit

Permalink
Add mod_caps_rdbms
Browse files Browse the repository at this point in the history
  • Loading branch information
arcusfelis committed Jan 14, 2024
1 parent 07a168e commit 4e259b1
Show file tree
Hide file tree
Showing 14 changed files with 208 additions and 60 deletions.
8 changes: 6 additions & 2 deletions big_tests/tests/disco_and_caps_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -196,10 +196,14 @@ user_can_query_server_info(Config) ->
%% Helpers

required_modules(disco_with_caps) ->
[{mod_caps, config_parser_helper:default_mod_config(mod_caps)},
HostType = domain_helper:host_type(),
Backend = mongoose_helper:get_backend_mnesia_rdbms(HostType),
[{mod_caps, config_parser_helper:mod_config(mod_caps, #{backend => Backend})},
{mod_disco, default_mod_config(mod_disco)}];
required_modules(disco_with_caps_and_extra_features) ->
[{mod_caps, config_parser_helper:default_mod_config(mod_caps)},
HostType = domain_helper:host_type(),
Backend = mongoose_helper:get_backend_mnesia_rdbms(HostType),
[{mod_caps, config_parser_helper:mod_config(mod_caps, #{backend => Backend})},
{mod_disco, mod_config(mod_disco, extra_disco_opts())}];
required_modules(disco_with_extra_features) ->
[{mod_disco, mod_config(mod_disco, extra_disco_opts())}].
Expand Down
5 changes: 4 additions & 1 deletion big_tests/tests/gdpr_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,10 @@ pubsub_required_modules(Plugins) ->
host => HostPattern,
nodetree => nodetree_tree,
plugins => Plugins}),
[{mod_caps, config_parser_helper:default_mod_config(mod_caps)}, {mod_pubsub, PubsubConfig}].
HostType = domain_helper:host_type(),
Backend = mongoose_helper:get_backend_mnesia_rdbms(HostType),
[{mod_caps, config_parser_helper:mod_config(mod_caps, #{backend => Backend})},
{mod_pubsub, PubsubConfig}].

is_mim2_started() ->
#{node := Node} = distributed_helper:mim2(),
Expand Down
2 changes: 1 addition & 1 deletion big_tests/tests/muc_helper.erl
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ load_muc(HostType) ->
hibernated_room_timeout => 2000,
access => muc, access_create => muc_create},
LogOpts = #{outdir => "/tmp/muclogs", access_log => muc},
dynamic_modules:start(HostType, mod_muc, make_opts(Opts)),
Res = dynamic_modules:start(HostType, mod_muc, make_opts(Opts)),
dynamic_modules:start(HostType, mod_muc_log, make_log_opts(LogOpts)).

unload_muc() ->
Expand Down
8 changes: 6 additions & 2 deletions big_tests/tests/pep_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -504,14 +504,18 @@ field_spec({Var, Value}) when is_list(Value) -> #{var => Var, values => Value};
field_spec({Var, Value}) -> #{var => Var, values => [Value]}.

required_modules() ->
[{mod_caps, config_parser_helper:default_mod_config(mod_caps)},
HostType = domain_helper:host_type(),
Backend = mongoose_helper:get_backend_mnesia_rdbms(HostType),
[{mod_caps, config_parser_helper:mod_config(mod_caps, #{backend => Backend})},
{mod_pubsub, mod_config(mod_pubsub, #{plugins => [<<"dag">>, <<"pep">>],
nodetree => nodetree_dag,
backend => mongoose_helper:mnesia_or_rdbms_backend(),
pep_mapping => #{},
host => subhost_pattern("pubsub.@HOST@")})}].
required_modules(cache_tests) ->
[{mod_caps, config_parser_helper:default_mod_config(mod_caps)},
HostType = domain_helper:host_type(),
Backend = mongoose_helper:get_backend_mnesia_rdbms(HostType),
[{mod_caps, config_parser_helper:mod_config(mod_caps, #{backend => Backend})},
{mod_pubsub, mod_config(mod_pubsub, #{plugins => [<<"dag">>, <<"pep">>],
nodetree => nodetree_dag,
backend => mongoose_helper:mnesia_or_rdbms_backend(),
Expand Down
7 changes: 7 additions & 0 deletions priv/mssql2012.sql
Original file line number Diff line number Diff line change
Expand Up @@ -762,3 +762,10 @@ CREATE TABLE discovery_nodes (
PRIMARY KEY (cluster_name, node_name)
);
CREATE UNIQUE INDEX i_discovery_nodes_node_num ON discovery_nodes(cluster_name, node_num);

CREATE TABLE caps (
node varchar(250) NOT NULL,
sub_node varchar(250) NOT NULL,
features text NOT NULL,
PRIMARY KEY (node, sub_node)
);
7 changes: 7 additions & 0 deletions priv/mysql.sql
Original file line number Diff line number Diff line change
Expand Up @@ -554,3 +554,10 @@ CREATE TABLE discovery_nodes (
PRIMARY KEY (cluster_name, node_name)
);
CREATE UNIQUE INDEX i_discovery_nodes_node_num USING BTREE ON discovery_nodes(cluster_name, node_num);

CREATE TABLE caps (
node varchar(250) NOT NULL,
sub_node varchar(250) NOT NULL,
features text NOT NULL,
PRIMARY KEY (node, sub_node)
);
7 changes: 7 additions & 0 deletions priv/pg.sql
Original file line number Diff line number Diff line change
Expand Up @@ -514,3 +514,10 @@ CREATE TABLE discovery_nodes (
PRIMARY KEY (cluster_name, node_name)
);
CREATE UNIQUE INDEX i_discovery_nodes_node_num ON discovery_nodes USING BTREE(cluster_name, node_num);

CREATE TABLE caps (
node varchar(250) NOT NULL,
sub_node varchar(250) NOT NULL,
features text NOT NULL,
PRIMARY KEY (node, sub_node)
);
68 changes: 18 additions & 50 deletions src/mod_caps.erl
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@
filter_pep_recipient/3]).

%% for test cases
-export([delete_caps/1, make_disco_hash/2]).
-ignore_xref([delete_caps/1, make_disco_hash/2, read_caps/1, start_link/2]).
-export([delete_caps/2, make_disco_hash/2]).
-ignore_xref([delete_caps/2, make_disco_hash/2, read_caps/1, start_link/2]).

-include("mongoose.hrl").
-include("mongoose_config_spec.hrl").
Expand All @@ -74,24 +74,19 @@
-type caps() :: #caps{}.
-type caps_resources() :: gb_trees:tree(jid:simple_jid(), caps()).

-export_type([caps/0]).
-export_type([caps/0, node_pair/0, maybe_pending_features/0]).

-type features() :: [binary()].
-type maybe_pending_features() :: features() | pos_integer().
-type node_pair() :: {binary(), binary()}.

-record(caps_features,
{
node_pair = {<<>>, <<>>} :: node_pair(),
features = [] :: maybe_pending_features()
}).
-type node_pair() :: {Node :: binary(), SubNode :: binary()}.

-record(state, {host_type :: mongooseim:host_type()}).

-type state() :: #state{}.

-spec start_link(mongooseim:host_type(), gen_mod:module_opts()) -> any().
start_link(HostType, Opts) ->
mod_caps_backend:init(HostType, Opts),
Proc = gen_mod:get_module_proc(HostType, ?PROCNAME),
gen_server:start_link({local, Proc}, ?MODULE,
[HostType, Opts], []).
Expand All @@ -115,10 +110,13 @@ config_spec() ->
items = #{<<"cache_size">> => #option{type = integer,
validate = positive},
<<"cache_life_time">> => #option{type = integer,
validate = positive}
validate = positive},
<<"backend">> => #option{type = atom,
validate = {module, ?MODULE}}
},
defaults = #{<<"cache_size">> => 1000,
<<"cache_life_time">> => timer:hours(24) div 1000}
<<"cache_life_time">> => timer:hours(24) div 1000,
<<"backend">> => mnesia}
}.

supported_features() -> [dynamic_domains].
Expand Down Expand Up @@ -369,23 +367,8 @@ filter_pep_recipient(InAcc, #{c2s_data := C2SData, feature := Feature, to := To}
_ -> {ok, InAcc}
end.

init_db(mnesia) ->
case catch mnesia:table_info(caps_features, storage_type) of
{'EXIT', _} ->
ok;
disc_only_copies ->
ok;
_ ->
mnesia:delete_table(caps_features)
end,
mongoose_mnesia:create_table(caps_features,
[{disc_only_copies, [node()]},
{local_content, true},
{attributes, record_info(fields, caps_features)}]).

-spec init(list()) -> {ok, state()}.
init([HostType, #{cache_size := MaxSize, cache_life_time := LifeTime}]) ->
init_db(db_type(HostType)),
cache_tab:new(caps_features, [{max_size, MaxSize}, {life_time, LifeTime}]),
gen_hook:add_handlers(hooks(HostType)),
{ok, #state{host_type = HostType}}.
Expand Down Expand Up @@ -493,37 +476,25 @@ feature_response(Acc, _IQResult, LServer, From, Caps, [_SubNode | SubNodes]) ->
-spec caps_read_fun(mongooseim:host_type(), node_pair()) ->
fun(() -> {ok, maybe_pending_features()} | error).
caps_read_fun(HostType, Node) ->
DBType = db_type(HostType),
caps_read_fun(HostType, Node, DBType).

caps_read_fun(_HostType, Node, mnesia) ->
fun () ->
case mnesia:dirty_read({caps_features, Node}) of
[#caps_features{features = Features}] -> {ok, Features};
_ -> error
end
mod_caps_backend:read(HostType, Node)
end.

-spec caps_write_fun(mongooseim:host_type(), node_pair(), maybe_pending_features()) ->
fun(() -> ok).
caps_write_fun(HostType, Node, Features) ->
DBType = db_type(HostType),
caps_write_fun(HostType, Node, Features, DBType).

caps_write_fun(_HostType, Node, Features, mnesia) ->
fun () ->
mnesia:dirty_write(#caps_features{node_pair = Node,
features = Features})
mod_caps_backend:write(HostType, Node, Features)
end.

-spec delete_caps(node_pair()) -> ok.
delete_caps(Node) ->
cache_tab:delete(caps_features, Node, caps_delete_fun(Node)).
-spec delete_caps(mongooseim:host_type(), node_pair()) -> ok.
delete_caps(HostType, Node) ->
cache_tab:delete(caps_features, Node, caps_delete_fun(HostType, Node)).

Check warning on line 492 in src/mod_caps.erl

View check run for this annotation

Codecov / codecov/patch

src/mod_caps.erl#L492

Added line #L492 was not covered by tests

-spec caps_delete_fun(node_pair()) -> fun(() -> ok).
caps_delete_fun(Node) ->
-spec caps_delete_fun(mongooseim:host_type(), node_pair()) -> fun(() -> ok).
caps_delete_fun(HostType, Node) ->
fun () ->
mnesia:dirty_delete(caps_features, Node)
mod_caps_backend:delete_node(HostType, Node)

Check warning on line 497 in src/mod_caps.erl

View check run for this annotation

Codecov / codecov/patch

src/mod_caps.erl#L497

Added line #L497 was not covered by tests
end.

-spec make_my_disco_hash(mongooseim:host_type(), jid:lserver()) -> binary().
Expand Down Expand Up @@ -625,6 +596,3 @@ is_valid_node(Node) ->
_ ->
false
end.

db_type(_HostType) ->
mnesia.
52 changes: 52 additions & 0 deletions src/mod_caps_backend.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
-module(mod_caps_backend).
-export([init/2,
read/2,
write/3,
delete_node/2]).

-define(MAIN_MODULE, mod_caps).

%% ----------------------------------------------------------------------
%% Callbacks
%% (exactly the same as specs in this module)

-callback init(HostType, Opts) -> ok when
HostType :: mongooseim:host_type(),
Opts :: gen_mod:module_opts().

-callback read(mongooseim:host_type(), mod_caps:node_pair()) ->
{ok, mod_caps:maybe_pending_features()} | error.

-callback write(mongooseim:host_type(), mod_caps:node_pair(),
mod_caps:maybe_pending_features()) -> ok.

-callback delete_node(mongooseim:host_type(), mod_caps:node_pair()) -> ok.

%% ----------------------------------------------------------------------
%% API Functions

-spec init(HostType, Opts) -> ok when
HostType :: mongooseim:host_type(),
Opts :: gen_mod:module_opts().
init(HostType, Opts) ->
TrackedFuns = [],
mongoose_backend:init(HostType, ?MAIN_MODULE, TrackedFuns, Opts),
Args = [HostType, Opts],
mongoose_backend:call(HostType, ?MAIN_MODULE, ?FUNCTION_NAME, Args).

-spec read(mongooseim:host_type(), mod_caps:node_pair()) ->
{ok, mod_caps:maybe_pending_features()} | error.
read(HostType, Node) ->
Args = [HostType, Node],
mongoose_backend:call_tracked(HostType, ?MAIN_MODULE, ?FUNCTION_NAME, Args).

-spec write(mongooseim:host_type(), mod_caps:node_pair(),
mod_caps:maybe_pending_features()) -> ok.
write(HostType, Node, Features) ->
Args = [HostType, Node, Features],
mongoose_backend:call_tracked(HostType, ?MAIN_MODULE, ?FUNCTION_NAME, Args).

-spec delete_node(mongooseim:host_type(), mod_caps:node_pair()) -> ok.
delete_node(HostType, Node) ->
Args = [HostType, Node],
mongoose_backend:call_tracked(HostType, ?MAIN_MODULE, ?FUNCTION_NAME, Args).

Check warning on line 52 in src/mod_caps_backend.erl

View check run for this annotation

Codecov / codecov/patch

src/mod_caps_backend.erl#L51-L52

Added lines #L51 - L52 were not covered by tests
49 changes: 49 additions & 0 deletions src/mod_caps_mnesia.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
-module(mod_caps_mnesia).
-behaviour(mod_caps_backend).

-export([init/2,
read/2,
write/3,
delete_node/2]).

-record(caps_features,
{
node_pair = {<<>>, <<>>} :: mod_caps:node_pair(),
features = [] :: mod_caps:maybe_pending_features()
}).

-spec init(mongooseim:host_type(), gen_mod:module_opts()) -> ok.
init(_HostName, _Opts) ->
case catch mnesia:table_info(caps_features, storage_type) of
{'EXIT', _} ->
ok;
disc_only_copies ->
ok;
_ ->
mnesia:delete_table(caps_features)

Check warning on line 23 in src/mod_caps_mnesia.erl

View check run for this annotation

Codecov / codecov/patch

src/mod_caps_mnesia.erl#L23

Added line #L23 was not covered by tests
end,
mongoose_mnesia:create_table(caps_features,
[{disc_only_copies, [node()]},
{local_content, true},
{attributes, record_info(fields, caps_features)}]),
ok.

-spec read(mongooseim:host_type(), mod_caps:node_pair()) ->
{ok, mod_caps:maybe_pending_features()} | error.
read(_HostType, Node) ->
case mnesia:dirty_read({caps_features, Node}) of
[#caps_features{features = Features}] -> {ok, Features};

Check warning on line 35 in src/mod_caps_mnesia.erl

View check run for this annotation

Codecov / codecov/patch

src/mod_caps_mnesia.erl#L35

Added line #L35 was not covered by tests
_ -> error
end.

-spec write(mongooseim:host_type(), mod_caps:node_pair(),
mod_caps:maybe_pending_features()) -> ok.
write(_HostType, Node, Features) ->
mnesia:dirty_write(#caps_features{node_pair = Node,
features = Features}),
ok.

-spec delete_node(mongooseim:host_type(), mod_caps:node_pair()) -> ok.
delete_node(_HostType, Node) ->
mnesia:dirty_delete(caps_features, Node),
ok.

Check warning on line 49 in src/mod_caps_mnesia.erl

View check run for this annotation

Codecov / codecov/patch

src/mod_caps_mnesia.erl#L48-L49

Added lines #L48 - L49 were not covered by tests
45 changes: 45 additions & 0 deletions src/mod_caps_rdbms.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
-module(mod_caps_rdbms).
-behaviour(mod_caps_backend).

-export([init/2,
read/2,
write/3,
delete_node/2]).

-spec init(mongooseim:host_type(), gen_mod:module_opts()) -> ok.
init(HostType, _Opts) ->
rdbms_queries:prepare_upsert(HostType, caps_upsert, caps,
[<<"node">>, <<"sub_node">>, <<"features">>],
[<<"features">>],
[<<"node">>, <<"sub_node">>]),
mongoose_rdbms:prepare(caps_delete, caps,
[node, sub_node],
<<"DELETE FROM caps WHERE node=? AND sub_node=?">>),
mongoose_rdbms:prepare(caps_select, caps,
[node, sub_node],
<<"SELECT features FROM caps WHERE node=? AND sub_node=?">>),
ok.

-spec read(mongooseim:host_type(), mod_caps:node_pair()) ->
{ok, mod_caps:maybe_pending_features()} | error.
read(HostType, {Node, SubNode}) ->
case mongoose_rdbms:execute(HostType, caps_select, [Node, SubNode]) of
[{selected, [{Encoded}]}] -> {ok, jiffy:decode(Encoded)};

Check warning on line 27 in src/mod_caps_rdbms.erl

View check run for this annotation

Codecov / codecov/patch

src/mod_caps_rdbms.erl#L27

Added line #L27 was not covered by tests
_ -> error
end.

-spec write(mongooseim:host_type(), mod_caps:node_pair(),
mod_caps:maybe_pending_features()) -> ok.
write(HostType, {Node, SubNode}, Features) ->
Encoded = jiffy:encode(Features),
InsertParams = [Node, SubNode, Encoded],
UpdateParams = [Encoded],
UniqueKeyValues = [Node, SubNode],
rdbms_queries:execute_upsert(HostType, caps_upsert,
InsertParams, UpdateParams, UniqueKeyValues),
ok.

-spec delete_node(mongooseim:host_type(), mod_caps:node_pair()) -> ok.
delete_node(HostType, {Node, SubNode}) ->
{updated, _} = mongoose_rdbms:execute(HostType, caps_delete, [Node, SubNode]),
ok.

Check warning on line 45 in src/mod_caps_rdbms.erl

View check run for this annotation

Codecov / codecov/patch

src/mod_caps_rdbms.erl#L44-L45

Added lines #L44 - L45 were not covered by tests
3 changes: 2 additions & 1 deletion test/common/config_parser_helper.erl
Original file line number Diff line number Diff line change
Expand Up @@ -838,7 +838,8 @@ default_mod_config(mod_bosh) ->
default_mod_config(mod_cache_users) ->
#{strategy => fifo, time_to_live => 480, number_of_segments => 3};
default_mod_config(mod_caps) ->
#{cache_size => 1000,
#{backend => mnesia,
cache_size => 1000,
cache_life_time => timer:hours(24) div 1000};
default_mod_config(mod_csi) ->
#{buffer_max => 20};
Expand Down
Loading

0 comments on commit 4e259b1

Please sign in to comment.