aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rebar.config4
-rw-r--r--src/acl.erl2
-rw-r--r--src/ejabberd_admin.erl11
-rw-r--r--src/ejabberd_app.erl25
-rw-r--r--src/ejabberd_auth_mnesia.erl158
-rw-r--r--src/ejabberd_auth_riak.erl7
-rw-r--r--src/ejabberd_auth_sql.erl7
-rw-r--r--src/ejabberd_commands.erl1
-rw-r--r--src/ejabberd_config.erl94
-rw-r--r--src/ejabberd_listener.erl10
-rw-r--r--src/ejabberd_local.erl1
-rw-r--r--src/ejabberd_mnesia.erl482
-rw-r--r--src/ejabberd_oauth.erl107
-rw-r--r--src/ejabberd_oauth_mnesia.erl5
-rw-r--r--src/ejabberd_oauth_rest.erl14
-rw-r--r--src/ejabberd_oauth_sql.erl32
-rw-r--r--src/ejabberd_redis.erl2
-rw-r--r--src/ejabberd_riak_sup.erl7
-rw-r--r--src/ejabberd_router_mnesia.erl1
-rw-r--r--src/ejabberd_router_multicast.erl1
-rw-r--r--src/ejabberd_s2s.erl1
-rw-r--r--src/ejabberd_sql_sup.erl5
-rw-r--r--src/mod_announce_mnesia.erl59
-rw-r--r--src/mod_bosh_mnesia.erl3
-rw-r--r--src/mod_caps_mnesia.erl61
-rw-r--r--src/mod_carboncopy_mnesia.erl3
-rw-r--r--src/mod_irc_mnesia.erl40
-rw-r--r--src/mod_last_mnesia.erl34
-rw-r--r--src/mod_muc_mnesia.erl81
-rw-r--r--src/mod_muc_room.erl17
-rw-r--r--src/mod_offline.erl6
-rw-r--r--src/mod_offline_mnesia.erl41
-rw-r--r--src/mod_privacy_mnesia.erl67
-rw-r--r--src/mod_private_mnesia.erl37
-rw-r--r--src/mod_proxy65_mnesia.erl1
-rw-r--r--src/mod_register.erl2
-rw-r--r--src/mod_roster_mnesia.erl95
-rw-r--r--src/mod_shared_roster_ldap.erl163
-rw-r--r--src/mod_shared_roster_mnesia.erl68
-rw-r--r--src/mod_stream_mgmt.erl2
-rw-r--r--src/mod_vcard_mnesia.erl70
-rw-r--r--src/mod_vcard_xupdate_mnesia.erl31
-rw-r--r--src/pubsub_migrate.erl88
-rw-r--r--src/randoms.erl7
-rw-r--r--src/shaper.erl1
-rw-r--r--test/acl_test.exs3
-rw-r--r--test/ejabberd_commands_mock_test.exs8
-rw-r--r--test/ejabberd_commands_test.exs1
-rw-r--r--test/ejabberd_cyrsasl_test.exs3
-rw-r--r--test/mod_http_api_mock_test.exs1
-rw-r--r--test/mod_http_api_test.exs1
51 files changed, 1055 insertions, 916 deletions
diff --git a/rebar.config b/rebar.config
index 8c542c11e..8b1454de9 100644
--- a/rebar.config
+++ b/rebar.config
@@ -20,11 +20,11 @@
{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"}}},
- {cache_tab, ".*", {git, "https://github.com/processone/cache_tab", "8985b03"}},
+ {cache_tab, ".*", {git, "https://github.com/processone/cache_tab", "b0c787a"}},
{fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.0.11"}}},
{stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.8"}}},
{fast_xml, ".*", {git, "https://github.com/processone/fast_xml", {tag, "1.1.21"}}},
- {xmpp, ".*", {git, "https://github.com/processone/xmpp", "06d4d5720c2609c5b44ca59400fddcf944d6f3fa"}},
+ {xmpp, ".*", {git, "https://github.com/processone/xmpp", "e8dbfec277e7eb27b8130b13873b969cc346fafc"}},
{stun, ".*", {git, "https://github.com/processone/stun", {tag, "1.0.10"}}},
{esip, ".*", {git, "https://github.com/processone/esip", {tag, "1.0.11"}}},
{fast_yaml, ".*", {git, "https://github.com/processone/fast_yaml", {tag, "1.0.9"}}},
diff --git a/src/acl.erl b/src/acl.erl
index 40ab682e5..0cdd7daa6 100644
--- a/src/acl.erl
+++ b/src/acl.erl
@@ -92,8 +92,6 @@ init([]) ->
[{ram_copies, [node()]},
{local_content, true},
{attributes, record_info(fields, access)}]),
- mnesia:add_table_copy(acl, node(), ram_copies),
- mnesia:add_table_copy(access, node(), ram_copies),
ejabberd_hooks:add(config_reloaded, ?MODULE, load_from_config, 20),
load_from_config(),
{ok, #state{}}.
diff --git a/src/ejabberd_admin.erl b/src/ejabberd_admin.erl
index 39262f0e4..15cd78c02 100644
--- a/src/ejabberd_admin.erl
+++ b/src/ejabberd_admin.erl
@@ -54,6 +54,7 @@
dump_to_textfile/1, dump_to_textfile/2,
mnesia_change_nodename/4,
restore/1, % Still used by some modules
+ clear_cache/0,
get_commands_spec/0
]).
%% gen_server callbacks
@@ -360,7 +361,11 @@ get_commands_spec() ->
module = ?MODULE, function = install_fallback_mnesia,
args_desc = ["Full path to the fallback file"],
args_example = ["/var/lib/ejabberd/database.fallback"],
- args = [{file, string}], result = {res, restuple}}
+ args = [{file, string}], result = {res, restuple}},
+ #ejabberd_commands{name = clear_cache, tags = [server],
+ desc = "Clear database cache on all nodes",
+ module = ?MODULE, function = clear_cache,
+ args = [], result = {res, rescode}}
].
@@ -759,3 +764,7 @@ mnesia_change_nodename(FromString, ToString, Source, Target) ->
{[Other], Acc}
end,
mnesia:traverse_backup(Source, Target, Convert, switched).
+
+clear_cache() ->
+ Nodes = ejabberd_cluster:get_nodes(),
+ lists:foreach(fun(T) -> ets_cache:clear(T, Nodes) end, ets_cache:all()).
diff --git a/src/ejabberd_app.erl b/src/ejabberd_app.erl
index 579696302..214c38b21 100644
--- a/src/ejabberd_app.erl
+++ b/src/ejabberd_app.erl
@@ -46,7 +46,7 @@ start(normal, _Args) ->
start_apps(),
start_elixir_application(),
ejabberd:check_app(ejabberd),
- db_init(),
+ ejabberd_mnesia:start(),
setup_if_elixir_conf_used(),
ejabberd_config:start(),
set_settings_from_config(),
@@ -87,29 +87,6 @@ stop(_State) ->
%%% Internal functions
%%%
-db_init() ->
- ejabberd_config:env_binary_to_list(mnesia, dir),
- MyNode = node(),
- DbNodes = mnesia:system_info(db_nodes),
- case lists:member(MyNode, DbNodes) of
- true ->
- ok;
- false ->
- ?CRITICAL_MSG("Node name mismatch: I'm [~s], "
- "the database is owned by ~p", [MyNode, DbNodes]),
- ?CRITICAL_MSG("Either set ERLANG_NODE in ejabberdctl.cfg "
- "or change node name in Mnesia", []),
- erlang:error(node_name_mismatch)
- end,
- case mnesia:system_info(extra_db_nodes) of
- [] ->
- mnesia:create_schema([node()]);
- _ ->
- ok
- end,
- ejabberd:start_app(mnesia, permanent),
- mnesia:wait_for_tables(mnesia:system_info(local_tables), infinity).
-
connect_nodes() ->
Nodes = ejabberd_config:get_option(
cluster_nodes,
diff --git a/src/ejabberd_auth_mnesia.erl b/src/ejabberd_auth_mnesia.erl
index 457e4c1b8..f856c8a9c 100644
--- a/src/ejabberd_auth_mnesia.erl
+++ b/src/ejabberd_auth_mnesia.erl
@@ -42,6 +42,7 @@
get_password_s/2, is_user_exists/2, remove_user/2,
remove_user/3, store_type/0, export/1, import/2,
plain_password_required/0, opt_type/1]).
+-export([need_transform/1, transform/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
@@ -60,9 +61,7 @@
%%%----------------------------------------------------------------------
start(Host) ->
init_db(),
- update_table(),
update_reg_users_counter_table(Host),
- maybe_alert_password_scrammed_without_option(),
ok.
stop(_Host) ->
@@ -90,10 +89,8 @@ plain_password_required() ->
is_scrammed().
store_type() ->
- case is_scrammed() of
- false -> plain; %% allows: PLAIN DIGEST-MD5 SCRAM
- true -> scram %% allows: PLAIN SCRAM
- end.
+ ejabberd_config:get_option({auth_password_format, ?MYNAME},
+ opt_type(auth_password_format), plain).
check_password(User, AuthzId, Server, Password) ->
if AuthzId /= <<>> andalso AuthzId /= User ->
@@ -374,100 +371,72 @@ remove_user(User, Server, Password) ->
_ -> bad_request
end.
-update_table() ->
- Fields = record_info(fields, passwd),
- case mnesia:table_info(passwd, attributes) of
- Fields ->
- convert_to_binary(Fields),
- maybe_scram_passwords(),
- ok;
- _ ->
- ?INFO_MSG("Recreating passwd table", []),
- mnesia:transform_table(passwd, ignore, Fields)
+need_transform(#passwd{us = {U, S}, password = Pass}) ->
+ if is_binary(Pass) ->
+ IsScrammed = is_scrammed(),
+ if IsScrammed ->
+ ?INFO_MSG("Passwords in Mnesia table 'passwd' "
+ "will be SCRAM'ed", []);
+ true ->
+ ok
+ end,
+ IsScrammed;
+ is_record(Pass, scram) ->
+ case is_scrammed() of
+ true ->
+ next;
+ false ->
+ ?WARNING_MSG("Some passwords were stored in the database "
+ "as SCRAM, but 'auth_password_format' "
+ "is not configured as 'scram'.", []),
+ false
+ end;
+ is_list(U) orelse is_list(S) orelse is_list(Pass) ->
+ ?INFO_MSG("Mnesia table 'passwd' will be converted to binary", []),
+ true
end.
-convert_to_binary(Fields) ->
- ejabberd_config:convert_table_to_binary(
- passwd, Fields, set,
- fun(#passwd{us = {U, _}}) -> U end,
- fun(#passwd{us = {U, S}, password = Pass} = R) ->
- NewUS = {iolist_to_binary(U), iolist_to_binary(S)},
- NewPass = case Pass of
- #scram{storedkey = StoredKey,
- serverkey = ServerKey,
- salt = Salt} ->
- Pass#scram{
- storedkey = iolist_to_binary(StoredKey),
- serverkey = iolist_to_binary(ServerKey),
- salt = iolist_to_binary(Salt)};
- _ ->
- iolist_to_binary(Pass)
- end,
- R#passwd{us = NewUS, password = NewPass}
- end).
+transform(#passwd{us = {U, S}, password = Pass} = R)
+ when is_list(U) orelse is_list(S) orelse is_list(Pass) ->
+ NewUS = {iolist_to_binary(U), iolist_to_binary(S)},
+ NewPass = case Pass of
+ #scram{storedkey = StoredKey,
+ serverkey = ServerKey,
+ salt = Salt} ->
+ Pass#scram{
+ storedkey = iolist_to_binary(StoredKey),
+ serverkey = iolist_to_binary(ServerKey),
+ salt = iolist_to_binary(Salt)};
+ _ ->
+ iolist_to_binary(Pass)
+ end,
+ transform(R#passwd{us = NewUS, password = NewPass});
+transform(#passwd{us = {U, S}, password = Password} = P)
+ when is_binary(Password) ->
+ case is_scrammed() of
+ true ->
+ case jid:resourceprep(Password) of
+ error ->
+ ?ERROR_MSG("SASLprep failed for password of user ~s@~s",
+ [U, S]),
+ P;
+ _ ->
+ Scram = password_to_scram(Password),
+ P#passwd{password = Scram}
+ end;
+ false ->
+ P
+ end;
+transform(#passwd{password = Password} = P)
+ when is_record(Password, scram) ->
+ P.
%%%
%%% SCRAM
%%%
-%% The passwords are stored scrammed in the table either if the option says so,
-%% or if at least the first password is scrammed.
is_scrammed() ->
- OptionScram = is_option_scram(),
- FirstElement = mnesia:dirty_read(passwd,
- mnesia:dirty_first(passwd)),
- case {OptionScram, FirstElement} of
- {true, _} -> true;
- {false, [#passwd{password = Scram}]}
- when is_record(Scram, scram) ->
- true;
- _ -> false
- end.
-
-is_option_scram() ->
- scram ==
- ejabberd_config:get_option({auth_password_format, ?MYNAME},
- fun(V) -> V end).
-
-maybe_alert_password_scrammed_without_option() ->
- case is_scrammed() andalso not is_option_scram() of
- true ->
- ?ERROR_MSG("Some passwords were stored in the database "
- "as SCRAM, but 'auth_password_format' "
- "is not configured 'scram'. The option "
- "will now be considered to be 'scram'.",
- []);
- false -> ok
- end.
-
-maybe_scram_passwords() ->
- case is_scrammed() of
- true -> scram_passwords();
- false -> ok
- end.
-
-scram_passwords() ->
- ?INFO_MSG("Converting the stored passwords into "
- "SCRAM bits",
- []),
- Fun = fun (#passwd{us = {U, S}, password = Password} = P)
- when is_binary(Password) ->
- case jid:resourceprep(Password) of
- error ->
- ?ERROR_MSG(
- "SASLprep failed for "
- "password of user ~s@~s",
- [U, S]),
- P;
- _ ->
- Scram = password_to_scram(Password),
- P#passwd{password = Scram}
- end;
- (P) ->
- P
- end,
- Fields = record_info(fields, passwd),
- mnesia:transform_table(passwd, Fun, Fields).
+ scram == store_type().
password_to_scram(Password) ->
password_to_scram(Password,
@@ -526,5 +495,8 @@ import(LServer, [LUser, Password, _TimeStamp]) ->
mnesia:dirty_write(
#passwd{us = {LUser, LServer}, password = Password}).
-opt_type(auth_password_format) -> fun (V) -> V end;
+opt_type(auth_password_format) ->
+ fun (plain) -> plain;
+ (scram) -> scram
+ end;
opt_type(_) -> [auth_password_format].
diff --git a/src/ejabberd_auth_riak.erl b/src/ejabberd_auth_riak.erl
index c41e8f63a..9555fcad8 100644
--- a/src/ejabberd_auth_riak.erl
+++ b/src/ejabberd_auth_riak.erl
@@ -274,7 +274,7 @@ remove_user(User, Server, Password) ->
is_scrammed() ->
scram ==
ejabberd_config:get_option({auth_password_format, ?MYNAME},
- fun(V) -> V end).
+ opt_type(auth_password_format), plain).
password_to_scram(Password) ->
password_to_scram(Password,
@@ -321,5 +321,8 @@ import(LServer, [LUser, Password, _TimeStamp]) ->
Passwd = #passwd{us = {LUser, LServer}, password = Password},
ejabberd_riak:put(Passwd, passwd_schema(), [{'2i', [{<<"host">>, LServer}]}]).
-opt_type(auth_password_format) -> fun (V) -> V end;
+opt_type(auth_password_format) ->
+ fun (plain) -> plain;
+ (scram) -> scram
+ end;
opt_type(_) -> [auth_password_format].
diff --git a/src/ejabberd_auth_sql.erl b/src/ejabberd_auth_sql.erl
index d64909771..0d9665afc 100644
--- a/src/ejabberd_auth_sql.erl
+++ b/src/ejabberd_auth_sql.erl
@@ -410,7 +410,7 @@ remove_user(User, Server, Password) ->
is_scrammed() ->
scram ==
ejabberd_config:get_option({auth_password_format, ?MYNAME},
- fun(V) -> V end).
+ opt_type(auth_password_format), plain).
password_to_scram(Password) ->
password_to_scram(Password,
@@ -510,5 +510,8 @@ convert_to_scram(Server) ->
end
end.
-opt_type(auth_password_format) -> fun (V) -> V end;
+opt_type(auth_password_format) ->
+ fun (plain) -> plain;
+ (scram) -> scram
+ end;
opt_type(_) -> [auth_password_format].
diff --git a/src/ejabberd_commands.erl b/src/ejabberd_commands.erl
index d84a671d5..df0ce9123 100644
--- a/src/ejabberd_commands.erl
+++ b/src/ejabberd_commands.erl
@@ -297,7 +297,6 @@ init([]) ->
{local_content, true},
{attributes, record_info(fields, ejabberd_commands)},
{type, bag}]),
- mnesia:add_table_copy(ejabberd_commands, node(), ram_copies),
register_commands(get_commands_spec()),
ejabberd_access_permissions:register_permission_addon(?MODULE, fun permission_addon/0),
{ok, #state{}}.
diff --git a/src/ejabberd_config.erl b/src/ejabberd_config.erl
index 4b9e20f7a..139549413 100644
--- a/src/ejabberd_config.erl
+++ b/src/ejabberd_config.erl
@@ -31,8 +31,7 @@
get_vh_by_auth_method/1, is_file_readable/1,
get_version/0, get_myhosts/0, get_mylang/0,
get_ejabberd_config_path/0, is_using_elixir_config/0,
- prepare_opt_val/4, convert_table_to_binary/5,
- transform_options/1, collect_options/1,
+ prepare_opt_val/4, transform_options/1, collect_options/1,
convert_to_yaml/1, convert_to_yaml/2, v_db/2,
env_binary_to_list/2, opt_type/1, may_hide_data/1,
is_elixir_enabled/0, v_dbs/1, v_dbs_mods/1,
@@ -116,8 +115,7 @@ mnesia_init() ->
ejabberd_mnesia:create(?MODULE, local_config,
[{ram_copies, [node()]},
{local_content, true},
- {attributes, record_info(fields, local_config)}]),
- mnesia:add_table_copy(local_config, node(), ram_copies).
+ {attributes, record_info(fields, local_config)}]).
%% @doc Get the filename of the ejabberd configuration file.
%% The filename can be specified with: erl -config "/path/to/ejabberd.yml".
@@ -1340,94 +1338,6 @@ transform_options({include_config_file, _, _} = Opt, Opts) ->
transform_options(Opt, Opts) ->
[Opt|Opts].
--spec convert_table_to_binary(atom(), [atom()], atom(),
- fun(), fun()) -> ok.
-
-convert_table_to_binary(Tab, Fields, Type, DetectFun, ConvertFun) ->
- case is_table_still_list(Tab, DetectFun) of
- true ->
- ?INFO_MSG("Converting '~s' table from strings to binaries.", [Tab]),
- TmpTab = list_to_atom(atom_to_list(Tab) ++ "_tmp_table"),
- catch mnesia:delete_table(TmpTab),
- case ejabberd_mnesia:create(?MODULE, TmpTab,
- [{disc_only_copies, [node()]},
- {type, Type},
- {local_content, true},
- {record_name, Tab},
- {attributes, Fields}]) of
- {atomic, ok} ->
- mnesia:transform_table(Tab, ignore, Fields),
- case mnesia:transaction(
- fun() ->
- mnesia:write_lock_table(TmpTab),
- mnesia:foldl(
- fun(R, _) ->
- NewR = ConvertFun(R),
- mnesia:dirty_write(TmpTab, NewR)
- end, ok, Tab)
- end) of
- {atomic, ok} ->
- mnesia:clear_table(Tab),
- case mnesia:transaction(
- fun() ->
- mnesia:write_lock_table(Tab),
- mnesia:foldl(
- fun(R, _) ->
- mnesia:dirty_write(R)
- end, ok, TmpTab)
- end) of
- {atomic, ok} ->
- mnesia:delete_table(TmpTab);
- Err ->
- report_and_stop(Tab, Err)
- end;
- Err ->
- report_and_stop(Tab, Err)
- end;
- Err ->
- report_and_stop(Tab, Err)
- end;
- false ->
- ok
- end.
-
-is_table_still_list(Tab, DetectFun) ->
- is_table_still_list(Tab, DetectFun, mnesia:dirty_first(Tab)).
-
-is_table_still_list(_Tab, _DetectFun, '$end_of_table') ->
- false;
-is_table_still_list(Tab, DetectFun, Key) ->
- Rs = mnesia:dirty_read(Tab, Key),
- Res = lists:foldl(fun(_, true) ->
- true;
- (_, false) ->
- false;
- (R, _) ->
- case DetectFun(R) of
- '$next' ->
- '$next';
- El ->
- is_list(El)
- end
- end, '$next', Rs),
- case Res of
- true ->
- true;
- false ->
- false;
- '$next' ->
- is_table_still_list(Tab, DetectFun, mnesia:dirty_next(Tab, Key))
- end.
-
-report_and_stop(Tab, Err) ->
- ErrTxt = lists:flatten(
- io_lib:format(
- "Failed to convert '~s' table to binary: ~p",
- [Tab, Err])),
- ?CRITICAL_MSG(ErrTxt, []),
- timer:sleep(1000),
- halt(string:substr(ErrTxt, 1, 199)).
-
emit_deprecation_warning(Module, NewModule, DBType) ->
?WARNING_MSG("Module ~s is deprecated, use ~s with 'db_type: ~s'"
" instead", [Module, NewModule, DBType]).
diff --git a/src/ejabberd_listener.erl b/src/ejabberd_listener.erl
index fc6cacc5f..7d3c53574 100644
--- a/src/ejabberd_listener.erl
+++ b/src/ejabberd_listener.erl
@@ -429,16 +429,6 @@ delete_listener(PortIP, Module) ->
delete_listener(PortIP, Module, Opts) ->
{Port, IPT, _, _, Proto, _} = parse_listener_portip(PortIP, Opts),
PortIP1 = {Port, IPT, Proto},
- Ports = case ejabberd_config:get_option(
- listen, fun validate_cfg/1) of
- undefined ->
- [];
- Ls ->
- Ls
- end,
- Ports1 = lists:keydelete(PortIP1, 1, Ports),
- Ports2 = lists:map(fun transform_option/1, Ports1),
- ejabberd_config:add_option(listen, Ports2),
stop_listener(PortIP1, Module).
diff --git a/src/ejabberd_local.erl b/src/ejabberd_local.erl
index 00ce22274..c1b21d508 100644
--- a/src/ejabberd_local.erl
+++ b/src/ejabberd_local.erl
@@ -207,7 +207,6 @@ init([]) ->
ejabberd_mnesia:create(?MODULE, iq_response,
[{ram_copies, [node()]},
{attributes, record_info(fields, iq_response)}]),
- mnesia:add_table_copy(iq_response, node(), ram_copies),
{ok, #state{}}.
handle_call(_Request, _From, State) ->
diff --git a/src/ejabberd_mnesia.erl b/src/ejabberd_mnesia.erl
index c0f25131a..34691545a 100644
--- a/src/ejabberd_mnesia.erl
+++ b/src/ejabberd_mnesia.erl
@@ -30,130 +30,281 @@
-module(ejabberd_mnesia).
-author('christophe.romain@process-one.net').
--export([create/3, reset/2, update/2]).
+
+-behaviour(gen_server).
+
+-export([start/0, create/3, update/2, transform/2, transform/3,
+ dump_schema/0]).
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2, code_change/3]).
-define(STORAGE_TYPES, [disc_copies, disc_only_copies, ram_copies]).
-define(NEED_RESET, [local_content, type]).
-include("logger.hrl").
-create(Module, Name, TabDef)
- when is_atom(Module), is_atom(Name), is_list(TabDef) ->
- Path = os:getenv("EJABBERD_SCHEMA_PATH"),
- Schema = schema(Path, Module, Name, TabDef),
+-record(state, {tables = #{} :: map(),
+ schema = [] :: [{atom(), [{atom(), any()}]}]}).
+
+start() ->
+ gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
+
+-spec create(module(), atom(), list()) -> any().
+create(Module, Name, TabDef) ->
+ gen_server:call(?MODULE, {create, Module, Name, TabDef},
+ %% Huge timeout is need to have enough
+ %% time to transform huge tables
+ timer:minutes(30)).
+
+init([]) ->
+ ejabberd_config:env_binary_to_list(mnesia, dir),
+ MyNode = node(),
+ DbNodes = mnesia:system_info(db_nodes),
+ case lists:member(MyNode, DbNodes) of
+ true ->
+ case mnesia:system_info(extra_db_nodes) of
+ [] -> mnesia:create_schema([node()]);
+ _ -> ok
+ end,
+ ejabberd:start_app(mnesia, permanent),
+ ?DEBUG("Waiting for Mnesia tables synchronization...", []),
+ mnesia:wait_for_tables(mnesia:system_info(local_tables), infinity),
+ Schema = read_schema_file(),
+ {ok, #state{schema = Schema}};
+ false ->
+ ?CRITICAL_MSG("Node name mismatch: I'm [~s], "
+ "the database is owned by ~p", [MyNode, DbNodes]),
+ ?CRITICAL_MSG("Either set ERLANG_NODE in ejabberdctl.cfg "
+ "or change node name in Mnesia", []),
+ {stop, node_name_mismatch}
+ end.
+
+handle_call({create, Module, Name, TabDef}, _From, State) ->
+ case maps:get(Name, State#state.tables, undefined) of
+ {TabDef, Result} ->
+ {reply, Result, State};
+ _ ->
+ Result = do_create(Module, Name, TabDef, State#state.schema),
+ Tables = maps:put(Name, {TabDef, Result}, State#state.tables),
+ {reply, Result, State#state{tables = Tables}}
+ end;
+handle_call(_Request, _From, State) ->
+ {noreply, State}.
+
+handle_cast(_Msg, State) ->
+ {noreply, State}.
+
+handle_info(_Info, State) ->
+ {noreply, State}.
+
+terminate(_Reason, _State) ->
+ ok.
+
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+do_create(Module, Name, TabDef, TabDefs) ->
+ code:ensure_loaded(Module),
+ Schema = schema(Name, TabDef, TabDefs),
{attributes, Attrs} = lists:keyfind(attributes, 1, Schema),
case catch mnesia:table_info(Name, attributes) of
{'EXIT', _} ->
- mnesia_op(create_table, [Name, TabDef]);
+ create(Name, TabDef);
Attrs ->
case need_reset(Name, Schema) of
- true -> reset(Name, Schema);
- false -> update(Name, Attrs, Schema)
+ true ->
+ reset(Name, Schema);
+ false ->
+ case update(Name, Attrs, Schema) of
+ {atomic, ok} ->
+ transform(Module, Name, Attrs, Attrs);
+ Err ->
+ Err
+ end
end;
OldAttrs ->
- Fun = case lists:member({transform,1}, Module:module_info(exports)) of
- true -> fun(Old) -> Module:transform(Old) end;
- false -> fun(Old) -> transform(OldAttrs, Attrs, Old) end
- end,
- mnesia_op(transform_table, [Name, Fun, Attrs])
+ transform(Module, Name, OldAttrs, Attrs)
end.
-reset(Name, TabDef)
- when is_atom(Name), is_list(TabDef) ->
+reset(Name, TabDef) ->
+ ?INFO_MSG("Deleting Mnesia table '~s'", [Name]),
mnesia_op(delete_table, [Name]),
- mnesia_op(create_table, [Name, TabDef]).
+ create(Name, TabDef).
-update(Name, TabDef)
- when is_atom(Name), is_list(TabDef) ->
+update(Name, TabDef) ->
{attributes, Attrs} = lists:keyfind(attributes, 1, TabDef),
update(Name, Attrs, TabDef).
+
update(Name, Attrs, TabDef) ->
- Storage = case catch mnesia:table_info(Name, storage_type) of
- {'EXIT', _} -> unknown;
- Type -> Type
- end,
- NewStorage = lists:foldl(
- fun({Key, _}, Acc) ->
- case lists:member(Key, ?STORAGE_TYPES) of
- true -> Key;
- false -> Acc
- end
- end, Storage, TabDef),
- R1 = [mnesia_op(change_table_copy_type, [Name, node(), NewStorage])
- || Storage=/=NewStorage],
- CurIndexes = [lists:nth(N-1, Attrs) || N<-mnesia:table_info(Name, index)],
- NewIndexes = proplists:get_value(index, TabDef, []),
- R2 = [mnesia_op(del_table_index, [Name, Attr])
- || Attr <- CurIndexes--NewIndexes],
- R3 = [mnesia_op(add_table_index, [Name, Attr])
- || Attr <- NewIndexes--CurIndexes],
- lists:foldl(
- fun({atomic, ok}, Acc) -> Acc;
- (Error, _Acc) -> Error
- end, {atomic, ok}, R1++R2++R3).
+ case change_table_copy_type(Name, TabDef) of
+ {atomic, ok} ->
+ CurrIndexes = [lists:nth(N-1, Attrs) ||
+ N <- mnesia:table_info(Name, index)],
+ NewIndexes = proplists:get_value(index, TabDef, []),
+ case delete_indexes(Name, CurrIndexes -- NewIndexes) of
+ {atomic, ok} ->
+ add_indexes(Name, NewIndexes -- CurrIndexes);
+ Err ->
+ Err
+ end;
+ Err ->
+ Err
+ end.
+
+change_table_copy_type(Name, TabDef) ->
+ CurrType = mnesia:table_info(Name, storage_type),
+ NewType = case lists:filter(fun is_storage_type_option/1, TabDef) of
+ [{Type, _}|_] -> Type;
+ [] -> CurrType
+ end,
+ if NewType /= CurrType ->
+ ?INFO_MSG("Changing Mnesia table '~s' from ~s to ~s",
+ [Name, CurrType, NewType]),
+ mnesia_op(change_table_copy_type, [Name, node(), NewType]);
+ true ->
+ {atomic, ok}
+ end.
+
+delete_indexes(Name, [Index|Indexes]) ->
+ ?INFO_MSG("Deleting index '~s' from Mnesia table '~s'", [Index, Name]),
+ case mnesia_op(del_table_index, [Name, Index]) of
+ {atomic, ok} ->
+ delete_indexes(Name, Indexes);
+ Err ->
+ Err
+ end;
+delete_indexes(_Name, []) ->
+ {atomic, ok}.
+
+add_indexes(Name, [Index|Indexes]) ->
+ ?INFO_MSG("Adding index '~s' to Mnesia table '~s'", [Index, Name]),
+ case mnesia_op(add_table_index, [Name, Index]) of
+ {atomic, ok} ->
+ add_indexes(Name, Indexes);
+ Err ->
+ Err
+ end;
+add_indexes(_Name, []) ->
+ {atomic, ok}.
%
% utilities
%
-schema(false, Module, _Name, TabDef) ->
- ?DEBUG("No custom ~s schema path", [Module]),
- TabDef;
-schema(Path, Module, Name, TabDef) ->
- File = filename:join(Path, atom_to_list(Module)++".mnesia"),
- case parse(File) of
- {ok, CustomDefs} ->
- case lists:keyfind(Name, 1, CustomDefs) of
- {Name, CustomDef} ->
- ?INFO_MSG("Using custom ~s schema for table ~s",
- [Module, Name]),
- merge(TabDef, CustomDef);
- _ ->
- TabDef
- end;
+schema(Name, Default, Schema) ->
+ case lists:keyfind(Name, 1, Schema) of
+ {_, Custom} ->
+ TabDefs = merge(Custom, Default),
+ ?DEBUG("Using custom schema for table '~s': ~p",
+ [Name, TabDefs]),
+ TabDefs;
+ false ->
+ ?DEBUG("No custom Mnesia schema for table '~s' found",
+ [Name]),
+ Default
+ end.
+
+read_schema_file() ->
+ File = schema_path(),
+ case fast_yaml:decode_from_file(File, [plain_as_atom]) of
+ {ok, [Defs|_]} ->
+ ?INFO_MSG("Using custom Mnesia schema from ~s", [File]),
+ lists:flatmap(
+ fun({Tab, Opts}) ->
+ case validate_schema_opts(File, Opts) of
+ {ok, NewOpts} ->
+ [{Tab, lists:ukeysort(1, NewOpts)}];
+ error ->
+ []
+ end
+ end, Defs);
+ {ok, []} ->
+ ?WARNING_MSG("Mnesia schema file ~s is empty", [File]),
+ [];
{error, enoent} ->
- ?DEBUG("No custom ~s schema path", [Module]),
- TabDef;
- {error, Error} ->
- ?ERROR_MSG("Can not use custom ~s schema for table ~s: ~p",
- [Module, Name, Error]),
- TabDef
- end.
-
-merge(TabDef, CustomDef) ->
- {CustomKeys, _} = lists:unzip(CustomDef),
- CleanDef = lists:foldl(
- fun(Elem, Acc) ->
- case lists:member(Elem, ?STORAGE_TYPES) of
- true ->
- lists:foldl(
- fun(Key, CleanAcc) ->
- lists:keydelete(Key, 1, CleanAcc)
- end, Acc, ?STORAGE_TYPES);
- false ->
- Acc
- end
- end, TabDef, CustomKeys),
- lists:ukeymerge(1,
- lists:ukeysort(1, CustomDef),
- lists:ukeysort(1, CleanDef)).
-
-parse(File) ->
- case file:consult(File) of
- {ok, Terms} -> parse(Terms, []);
- Error -> Error
- end.
-parse([], Acc) ->
- {ok, lists:reverse(Acc)};
-parse([{Name, Storage, TabDef}|Tail], Acc)
- when is_atom(Name), is_atom(Storage), is_list(TabDef) ->
- NewDef = case lists:member(Storage, ?STORAGE_TYPES) of
- true -> [{Storage, [node()]} | TabDef];
- false -> TabDef
- end,
- parse(Tail, [{Name, NewDef} | Acc]);
-parse([Other|_], _) ->
- {error, {invalid, Other}}.
+ ?DEBUG("No custom Mnesia schema file found", []),
+ [];
+ {error, Reason} ->
+ ?ERROR_MSG("Failed to read Mnesia schema file ~s: ~s",
+ [File, fast_yaml:format_error(Reason)]),
+ []
+ end.
+
+validate_schema_opts(File, Opts) ->
+ try {ok, lists:map(
+ fun({storage_type, Type}) when Type == ram_copies;
+ Type == disc_copies;
+ Type == disc_only_copies ->
+ {Type, [node()]};
+ ({storage_type, _} = Opt) ->
+ erlang:error({invalid_value, Opt});
+ ({local_content, Bool}) when is_boolean(Bool) ->
+ {local_content, Bool};
+ ({local_content, _} = Opt) ->
+ erlang:error({invalid_value, Opt});
+ ({type, Type}) when Type == set;
+ Type == ordered_set;
+ Type == bag ->
+ {type, Type};
+ ({type, _} = Opt) ->
+ erlang:error({invalid_value, Opt});
+ ({attributes, Attrs} = Opt) ->
+ try lists:all(fun is_atom/1, Attrs) of
+ true -> {attributes, Attrs};
+ false -> erlang:error({invalid_value, Opt})
+ catch _:_ -> erlang:error({invalid_value, Opt})
+ end;
+ ({index, Indexes} = Opt) ->
+ try lists:all(fun is_atom/1, Indexes) of
+ true -> {index, Indexes};
+ false -> erlang:error({invalid_value, Opt})
+ catch _:_ -> erlang:error({invalid_value, Opt})
+ end;
+ (Opt) ->
+ erlang:error({unknown_option, Opt})
+ end, Opts)}
+ catch _:{invalid_value, {Opt, Val}} ->
+ ?ERROR_MSG("Mnesia schema ~s is incorrect: invalid value ~p of "
+ "option '~s'", [File, Val, Opt]),
+ error;
+ _:{unknown_option, Opt} ->
+ ?ERROR_MSG("Mnesia schema ~s is incorrect: unknown option ~p",
+ [File, Opt]),
+ error
+ end.
+
+create(Name, TabDef) ->
+ ?INFO_MSG("Creating Mnesia table '~s'", [Name]),
+ case mnesia_op(create_table, [Name, TabDef]) of
+ {atomic, ok} ->
+ add_table_copy(Name);
+ Err ->
+ Err
+ end.
+
+%% The table MUST exist, otherwise the function would fail
+add_table_copy(Name) ->
+ Type = mnesia:table_info(Name, storage_type),
+ Nodes = mnesia:table_info(Name, Type),
+ case lists:member(node(), Nodes) of
+ true ->
+ {atomic, ok};
+ false ->
+ mnesia_op(add_table_copy, [Name, node(), Type])
+ end.
+
+merge(Custom, Default) ->
+ NewDefault = case lists:any(fun is_storage_type_option/1, Custom) of
+ true ->
+ lists:filter(
+ fun(O) ->
+ not is_storage_type_option(O)
+ end, Default);
+ false ->
+ Default
+ end,
+ lists:ukeymerge(1, Custom, lists:ukeysort(1, NewDefault)).
need_reset(Table, TabDef) ->
ValuesF = [mnesia:table_info(Table, Key) || Key <- ?NEED_RESET],
@@ -164,7 +315,61 @@ need_reset(Table, TabDef) ->
({_, _}, _) -> true
end, false, lists:zip(ValuesF, ValuesT)).
-transform(OldAttrs, Attrs, Old) ->
+transform(Module, Name) ->
+ try mnesia:table_info(Name, attributes) of
+ Attrs ->
+ transform(Module, Name, Attrs, Attrs)
+ catch _:{aborted, _} = Err ->
+ Err
+ end.
+
+transform(Module, Name, NewAttrs) ->
+ try mnesia:table_info(Name, attributes) of
+ OldAttrs ->
+ transform(Module, Name, OldAttrs, NewAttrs)
+ catch _:{aborted, _} = Err ->
+ Err
+ end.
+
+transform(Module, Name, Attrs, Attrs) ->
+ case need_transform(Module, Name) of
+ true ->
+ ?INFO_MSG("Transforming table '~s', this may take a while", [Name]),
+ transform_table(Module, Name);
+ false ->
+ {atomic, ok}
+ end;
+transform(Module, Name, OldAttrs, NewAttrs) ->
+ Fun = case erlang:function_exported(Module, transform, 1) of
+ true -> transform_fun(Module, Name);
+ false -> fun(Old) -> do_transform(OldAttrs, NewAttrs, Old) end
+ end,
+ mnesia_op(transform_table, [Name, Fun, NewAttrs]).
+
+-spec need_transform(module(), atom()) -> boolean().
+need_transform(Module, Name) ->
+ case erlang:function_exported(Module, need_transform, 1) of
+ true ->
+ do_need_transform(Module, Name, mnesia:dirty_first(Name));
+ false ->
+ false
+ end.
+
+do_need_transform(_Module, _Name, '$end_of_table') ->
+ false;
+do_need_transform(Module, Name, Key) ->
+ Objs = mnesia:dirty_read(Name, Key),
+ case lists:foldl(
+ fun(_, true) -> true;
+ (Obj, _) -> Module:need_transform(Obj)
+ end, undefined, Objs) of
+ true -> true;
+ false -> false;
+ _ ->
+ do_need_transform(Module, Name, mnesia:dirty_next(Name, Key))
+ end.
+
+do_transform(OldAttrs, Attrs, Old) ->
[Name|OldValues] = tuple_to_list(Old),
Before = lists:zip(OldAttrs, OldValues),
After = lists:foldl(
@@ -177,6 +382,56 @@ transform(OldAttrs, Attrs, Old) ->
{Attrs, NewRecord} = lists:unzip(After),
list_to_tuple([Name|NewRecord]).
+transform_fun(Module, Name) ->
+ fun(Obj) ->
+ try Module:transform(Obj)
+ catch E:R ->
+ StackTrace = erlang:get_stacktrace(),
+ ?ERROR_MSG("Failed to transform Mnesia table ~s:~n"
+ "** Record: ~p~n"
+ "** Reason: ~p~n"
+ "** StackTrace: ~p",
+ [Name, Obj, R, StackTrace]),
+ erlang:raise(E, R, StackTrace)
+ end
+ end.
+
+transform_table(Module, Name) ->
+ Type = mnesia:table_info(Name, type),
+ Attrs = mnesia:table_info(Name, attributes),
+ TmpTab = list_to_atom(atom_to_list(Name) ++ "_backup"),
+ StorageType = if Type == ordered_set -> disc_copies;
+ true -> disc_only_copies
+ end,
+ mnesia:create_table(TmpTab,
+ [{StorageType, [node()]},
+ {type, Type},
+ {local_content, true},
+ {record_name, Name},
+ {attributes, Attrs}]),
+ mnesia:clear_table(TmpTab),
+ Fun = transform_fun(Module, Name),
+ Res = mnesia_op(
+ transaction,
+ [fun() -> do_transform_table(Name, Fun, TmpTab, mnesia:first(Name)) end]),
+ mnesia:delete_table(TmpTab),
+ Res.
+
+do_transform_table(Name, _Fun, TmpTab, '$end_of_table') ->
+ mnesia:foldl(
+ fun(Obj, _) ->
+ mnesia:write(Name, Obj, write)
+ end, ok, TmpTab);
+do_transform_table(Name, Fun, TmpTab, Key) ->
+ Next = mnesia:next(Name, Key),
+ Objs = mnesia:read(Name, Key),
+ lists:foreach(
+ fun(Obj) ->
+ mnesia:write(TmpTab, Fun(Obj), write),
+ mnesia:delete_object(Obj)
+ end, Objs),
+ do_transform_table(Name, Fun, TmpTab, Next).
+
mnesia_op(Fun, Args) ->
case apply(mnesia, Fun, Args) of
{atomic, ok} ->
@@ -186,3 +441,32 @@ mnesia_op(Fun, Args) ->
[Fun, Args, Other]),
Other
end.
+
+schema_path() ->
+ Dir = case os:getenv("EJABBERD_MNESIA_SCHEMA") of
+ false -> mnesia:system_info(directory);
+ Path -> Path
+ end,
+ filename:join(Dir, "ejabberd.schema").
+
+is_storage_type_option({O, _}) ->
+ O == ram_copies orelse O == disc_copies orelse O == disc_only_copies.
+
+dump_schema() ->
+ File = schema_path(),
+ Schema = lists:flatmap(
+ fun(schema) ->
+ [];
+ (Tab) ->
+ [{Tab, [{storage_type,
+ mnesia:table_info(Tab, storage_type)},
+ {local_content,
+ mnesia:table_info(Tab, local_content)}]}]
+ end, mnesia:system_info(tables)),
+ case file:write_file(File, [fast_yaml:encode(Schema), io_lib:nl()]) of
+ ok ->
+ io:format("Mnesia schema is written to ~s~n", [File]);
+ {error, Reason} ->
+ io:format("Failed to write Mnesia schema to ~s: ~s",
+ [File, file:format_error(Reason)])
+ end.
diff --git a/src/ejabberd_oauth.erl b/src/ejabberd_oauth.erl
index 3a0b276d1..8527c9271 100644
--- a/src/ejabberd_oauth.erl
+++ b/src/ejabberd_oauth.erl
@@ -28,6 +28,8 @@
-behaviour(gen_server).
+-compile(export_all).
+
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2,
handle_info/2, terminate/2, code_change/3]).
@@ -46,6 +48,7 @@
check_token/2,
scope_in_scope_list/2,
process/2,
+ config_reloaded/0,
opt_type/1]).
-export([oauth_issue_token/3, oauth_list_tokens/0, oauth_revoke_token/1, oauth_list_scopes/0]).
@@ -140,8 +143,14 @@ oauth_revoke_token(Token) ->
oauth_list_scopes() ->
[ {Scope, string:join([atom_to_list(Cmd) || Cmd <- Cmds], ",")} || {Scope, Cmds} <- dict:to_list(get_cmd_scopes())].
-
-
+config_reloaded() ->
+ DBMod = get_db_backend(),
+ case init_cache(DBMod) of
+ true ->
+ ets_cache:setopts(oauth_cache, cache_opts());
+ false ->
+ ok
+ end.
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
@@ -150,23 +159,13 @@ start_link() ->
init([]) ->
DBMod = get_db_backend(),
DBMod:init(),
- MaxSize =
- ejabberd_config:get_option(
- oauth_cache_size,
- fun(I) when is_integer(I), I>0 -> I end,
- 1000),
- LifeTime =
- ejabberd_config:get_option(
- oauth_cache_life_time,
- fun(I) when is_integer(I), I>0 -> I end,
- timer:hours(1) div 1000),
- cache_tab:new(oauth_token,
- [{max_size, MaxSize}, {life_time, LifeTime}]),
+ init_cache(DBMod),
Expire = expire(),
application:set_env(oauth2, backend, ejabberd_oauth),
application:set_env(oauth2, expiry_time, Expire),
application:start(oauth2),
ejabberd_commands:register_commands(get_commands_spec()),
+ ejabberd_hooks:add(config_reloaded, ?MODULE, config_reloaded, 50),
erlang:send_after(expire() * 1000, self(), clean),
{ok, ok}.
@@ -371,24 +370,59 @@ check_token(ScopeList, Token) ->
store(R) ->
- cache_tab:insert(
- oauth_token, R#oauth_token.token, R,
- fun() ->
- DBMod = get_db_backend(),
- DBMod:store(R)
- end).
+ DBMod = get_db_backend(),
+ case DBMod:store(R) of
+ ok ->
+ ets_cache:delete(oauth_cache, R#oauth_token.token,
+ ejabberd_cluster:get_nodes());
+ {error, _} = Err ->
+ Err
+ end.
lookup(Token) ->
- cache_tab:lookup(
- oauth_token, Token,
- fun() ->
- DBMod = get_db_backend(),
- case DBMod:lookup(Token) of
- #oauth_token{} = R -> {ok, R};
- _ -> error
- end
- end).
+ ets_cache:lookup(oauth_cache, Token,
+ fun() ->
+ DBMod = get_db_backend(),
+ DBMod:lookup(Token)
+ end).
+
+-spec init_cache(module()) -> boolean().
+init_cache(DBMod) ->
+ UseCache = use_cache(DBMod),
+ case UseCache of
+ true ->
+ ets_cache:new(oauth_cache, cache_opts());
+ false ->
+ ets_cache:delete(oauth_cache)
+ end,
+ UseCache.
+
+use_cache(DBMod) ->
+ case erlang:function_exported(DBMod, use_cache, 0) of
+ true -> DBMod:use_cache();
+ false ->
+ ejabberd_config:get_option(
+ oauth_use_cache, opt_type(oauth_use_cache),
+ ejabberd_config:use_cache(global))
+ end.
+cache_opts() ->
+ MaxSize = ejabberd_config:get_option(
+ oauth_cache_size,
+ opt_type(oauth_cache_size),
+ ejabberd_config:cache_size(global)),
+ CacheMissed = ejabberd_config:get_option(
+ oauth_cache_missed,
+ opt_type(oauth_cache_missed),
+ ejabberd_config:cache_missed(global)),
+ LifeTime = case ejabberd_config:get_option(
+ oauth_cache_life_time,
+ opt_type(oauth_cache_life_time),
+ ejabberd_config:cache_life_time(global)) of
+ infinity -> infinity;
+ I -> timer:seconds(I)
+ end,
+ [{max_size, MaxSize}, {life_time, LifeTime}, {cache_missed, CacheMissed}].
expire() ->
ejabberd_config:get_option(
@@ -746,8 +780,13 @@ opt_type(oauth_access) ->
fun acl:access_rules_validator/1;
opt_type(oauth_db_type) ->
fun(T) -> ejabberd_config:v_db(?MODULE, T) end;
-opt_type(oauth_cache_life_time) ->
- fun (I) when is_integer(I), I > 0 -> I end;
-opt_type(oauth_cache_size) ->
- fun (I) when is_integer(I), I > 0 -> I end;
-opt_type(_) -> [oauth_expire, oauth_access, oauth_db_type].
+opt_type(O) when O == oauth_cache_life_time; O == oauth_cache_size ->
+ fun (I) when is_integer(I), I > 0 -> I;
+ (infinity) -> infinity
+ end;
+opt_type(O) when O == oauth_use_cache; O == oauth_cache_missed ->
+ fun (B) when is_boolean(B) -> B end;
+opt_type(_) ->
+ [oauth_expire, oauth_access, oauth_db_type,
+ oauth_cache_life_time, oauth_cache_size, oauth_use_cache,
+ oauth_cache_missed].
diff --git a/src/ejabberd_oauth_mnesia.erl b/src/ejabberd_oauth_mnesia.erl
index c9ef6dcac..8908afd39 100644
--- a/src/ejabberd_oauth_mnesia.erl
+++ b/src/ejabberd_oauth_mnesia.erl
@@ -38,7 +38,6 @@ init() ->
[{disc_copies, [node()]},
{attributes,
record_info(fields, oauth_token)}]),
- mnesia:add_table_copy(oauth_token, node(), disc_copies),
ok.
store(R) ->
@@ -47,9 +46,9 @@ store(R) ->
lookup(Token) ->
case catch mnesia:dirty_read(oauth_token, Token) of
[R] ->
- R;
+ {ok, R};
_ ->
- false
+ error
end.
clean(TS) ->
diff --git a/src/ejabberd_oauth_rest.erl b/src/ejabberd_oauth_rest.erl
index b9614eb09..15e118a0b 100644
--- a/src/ejabberd_oauth_rest.erl
+++ b/src/ejabberd_oauth_rest.erl
@@ -58,7 +58,7 @@ store(R) ->
ok;
Err ->
?ERROR_MSG("failed to store oauth record ~p: ~p", [R, Err]),
- {error, Err}
+ {error, db_failure}
end.
lookup(Token) ->
@@ -72,15 +72,15 @@ lookup(Token) ->
US = {JID#jid.luser, JID#jid.lserver},
Scope = proplists:get_value(<<"scope">>, Data, []),
Expire = proplists:get_value(<<"expire">>, Data, 0),
- #oauth_token{token = Token,
- us = US,
- scope = Scope,
- expire = Expire};
+ {ok, #oauth_token{token = Token,
+ us = US,
+ scope = Scope,
+ expire = Expire}};
{ok, 404, _Resp} ->
- false;
+ error;
Other ->
?ERROR_MSG("Unexpected response for oauth lookup: ~p", [Other]),
- {error, rest_failed}
+ error
end.
clean(_TS) ->
diff --git a/src/ejabberd_oauth_sql.erl b/src/ejabberd_oauth_sql.erl
index 10ca49844..5c4a96641 100644
--- a/src/ejabberd_oauth_sql.erl
+++ b/src/ejabberd_oauth_sql.erl
@@ -37,6 +37,7 @@
-include("ejabberd.hrl").
-include("ejabberd_sql_pt.hrl").
-include("jid.hrl").
+-include("logger.hrl").
init() ->
ok.
@@ -47,13 +48,20 @@ store(R) ->
SJID = jid:encode({User, Server, <<"">>}),
Scope = str:join(R#oauth_token.scope, <<" ">>),
Expire = R#oauth_token.expire,
- ?SQL_UPSERT(
- ?MYNAME,
- "oauth_token",
- ["!token=%(Token)s",
- "jid=%(SJID)s",
- "scope=%(Scope)s",
- "expire=%(Expire)d"]).
+ case ?SQL_UPSERT(
+ ?MYNAME,
+ "oauth_token",
+ ["!token=%(Token)s",
+ "jid=%(SJID)s",
+ "scope=%(Scope)s",
+ "expire=%(Expire)d"]) of
+ ok ->
+ ok;
+ Err ->
+ ?ERROR_MSG("Failed to write to SQL 'oauth_token' table: ~p",
+ [Err]),
+ {error, db_failure}
+ end.
lookup(Token) ->
case ejabberd_sql:sql_query(
@@ -63,12 +71,12 @@ lookup(Token) ->
{selected, [{SJID, Scope, Expire}]} ->
JID = jid:decode(SJID),
US = {JID#jid.luser, JID#jid.lserver},
- #oauth_token{token = Token,
- us = US,
- scope = str:tokens(Scope, <<" ">>),
- expire = Expire};
+ {ok, #oauth_token{token = Token,
+ us = US,
+ scope = str:tokens(Scope, <<" ">>),
+ expire = Expire}};
_ ->
- false
+ error
end.
clean(TS) ->
diff --git a/src/ejabberd_redis.erl b/src/ejabberd_redis.erl
index bd85f0ee5..7757c6df3 100644
--- a/src/ejabberd_redis.erl
+++ b/src/ejabberd_redis.erl
@@ -516,7 +516,7 @@ log_error(Cmd, Reason) ->
-spec get_rnd_id() -> pos_integer().
get_rnd_id() ->
- randoms:uniform(2, ejabberd_redis_sup:get_pool_size()).
+ randoms:round_robin(ejabberd_redis_sup:get_pool_size() - 1) + 2.
-spec get_result([{error, atom() | binary()} | {ok, iodata()}]) ->
{ok, [redis_reply()]} | {error, binary()}.
diff --git a/src/ejabberd_riak_sup.erl b/src/ejabberd_riak_sup.erl
index f5c8f7e4f..a01f3538a 100644
--- a/src/ejabberd_riak_sup.erl
+++ b/src/ejabberd_riak_sup.erl
@@ -30,7 +30,7 @@
-author('alexey@process-one.net').
-export([start_link/0, init/1, get_pids/0,
- transform_options/1, get_random_pid/0, get_random_pid/1,
+ transform_options/1, get_random_pid/0,
host_up/1, config_reloaded/0, opt_type/1]).
-include("ejabberd.hrl").
@@ -199,10 +199,7 @@ get_pids() ->
[ejabberd_riak:get_proc(I) || I <- lists:seq(1, get_pool_size())].
get_random_pid() ->
- get_random_pid(p1_time_compat:system_time()).
-
-get_random_pid(Term) ->
- I = erlang:phash2(Term, get_pool_size()) + 1,
+ I = randoms:round_robin(get_pool_size()) + 1,
ejabberd_riak:get_proc(I).
transform_options(Opts) ->
diff --git a/src/ejabberd_router_mnesia.erl b/src/ejabberd_router_mnesia.erl
index d8664fee9..76336d0b0 100644
--- a/src/ejabberd_router_mnesia.erl
+++ b/src/ejabberd_router_mnesia.erl
@@ -145,7 +145,6 @@ init([]) ->
[{ram_copies, [node()]},
{type, bag},
{attributes, record_info(fields, route)}]),
- mnesia:add_table_copy(route, node(), ram_copies),
mnesia:subscribe({table, route, simple}),
lists:foreach(
fun (Pid) -> erlang:monitor(process, Pid) end,
diff --git a/src/ejabberd_router_multicast.erl b/src/ejabberd_router_multicast.erl
index 39c119fbb..5d5acfcaa 100644
--- a/src/ejabberd_router_multicast.erl
+++ b/src/ejabberd_router_multicast.erl
@@ -120,7 +120,6 @@ init([]) ->
{type, bag},
{attributes,
record_info(fields, route_multicast)}]),
- mnesia:add_table_copy(route_multicast, node(), ram_copies),
mnesia:subscribe({table, route_multicast, simple}),
lists:foreach(
fun(Pid) ->
diff --git a/src/ejabberd_s2s.erl b/src/ejabberd_s2s.erl
index 717e85ae4..61d3b021b 100644
--- a/src/ejabberd_s2s.erl
+++ b/src/ejabberd_s2s.erl
@@ -303,7 +303,6 @@ init([]) ->
[{ram_copies, [node()]},
{type, bag},
{attributes, record_info(fields, s2s)}]),
- mnesia:add_table_copy(s2s, node(), ram_copies),
mnesia:subscribe(system),
ejabberd_commands:register_commands(get_commands_spec()),
ejabberd_mnesia:create(?MODULE, temporarily_blocked,
diff --git a/src/ejabberd_sql_sup.erl b/src/ejabberd_sql_sup.erl
index 995f90317..d778e32b7 100644
--- a/src/ejabberd_sql_sup.erl
+++ b/src/ejabberd_sql_sup.erl
@@ -53,7 +53,6 @@ start_link(Host) ->
[{ram_copies, [node()]}, {type, bag},
{local_content, true},
{attributes, record_info(fields, sql_pool)}]),
- mnesia:add_table_copy(sql_pool, node(), ram_copies),
F = fun () -> mnesia:delete({sql_pool, Host}) end,
mnesia:ets(F),
supervisor:start_link({local,
@@ -99,7 +98,9 @@ get_pids(Host) ->
get_random_pid(Host) ->
case get_pids(Host) of
[] -> none;
- Pids -> lists:nth(erlang:phash(p1_time_compat:unique_integer(), length(Pids)), Pids)
+ Pids ->
+ I = randoms:round_robin(length(Pids)) + 1,
+ lists:nth(I, Pids)
end.
add_pid(Host, Pid) ->
diff --git a/src/mod_announce_mnesia.erl b/src/mod_announce_mnesia.erl
index 09316189a..c298627eb 100644
--- a/src/mod_announce_mnesia.erl
+++ b/src/mod_announce_mnesia.erl
@@ -29,6 +29,7 @@
%% API
-export([init/2, set_motd_users/2, set_motd/2, delete_motd/1,
get_motd/1, is_motd_user/2, set_motd_user/2, import/3]).
+-export([need_transform/1, transform/1]).
-include("xmpp.hrl").
-include("mod_announce.hrl").
@@ -45,8 +46,7 @@ init(_Host, _Opts) ->
ejabberd_mnesia:create(?MODULE, motd_users,
[{disc_copies, [node()]},
{attributes,
- record_info(fields, motd_users)}]),
- update_tables().
+ record_info(fields, motd_users)}]).
set_motd_users(_LServer, USRs) ->
F = fun() ->
@@ -98,6 +98,23 @@ set_motd_user(LUser, LServer) ->
end,
mnesia:transaction(F).
+need_transform(#motd{server = S}) when is_list(S) ->
+ ?INFO_MSG("Mnesia table 'motd' will be converted to binary", []),
+ true;
+need_transform(#motd_users{us = {U, S}}) when is_list(U) orelse is_list(S) ->
+ ?INFO_MSG("Mnesia table 'motd_users' will be converted to binary", []),
+ true;
+need_transform(_) ->
+ false.
+
+transform(#motd{server = S, packet = P} = R) ->
+ NewS = iolist_to_binary(S),
+ NewP = fxml:to_xmlel(P),
+ R#motd{server = NewS, packet = NewP};
+transform(#motd_users{us = {U, S}} = R) ->
+ NewUS = {iolist_to_binary(U), iolist_to_binary(S)},
+ R#motd_users{us = NewUS}.
+
import(LServer, <<"motd">>, [<<>>, XML, _TimeStamp]) ->
El = fxml_stream:parse_element(XML),
mnesia:dirty_write(#motd{server = LServer, packet = El});
@@ -107,41 +124,3 @@ import(LServer, <<"motd">>, [LUser, <<>>, _TimeStamp]) ->
%%%===================================================================
%%% Internal functions
%%%===================================================================
-update_tables() ->
- update_motd_table(),
- update_motd_users_table().
-
-update_motd_table() ->
- Fields = record_info(fields, motd),
- case mnesia:table_info(motd, attributes) of
- Fields ->
- ejabberd_config:convert_table_to_binary(
- motd, Fields, set,
- fun(#motd{server = S}) -> S end,
- fun(#motd{server = S, packet = P} = R) ->
- NewS = iolist_to_binary(S),
- NewP = fxml:to_xmlel(P),
- R#motd{server = NewS, packet = NewP}
- end);
- _ ->
- ?INFO_MSG("Recreating motd table", []),
- mnesia:transform_table(motd, ignore, Fields)
- end.
-
-
-update_motd_users_table() ->
- Fields = record_info(fields, motd_users),
- case mnesia:table_info(motd_users, attributes) of
- Fields ->
- ejabberd_config:convert_table_to_binary(
- motd_users, Fields, set,
- fun(#motd_users{us = {U, _}}) -> U end,
- fun(#motd_users{us = {U, S}} = R) ->
- NewUS = {iolist_to_binary(U),
- iolist_to_binary(S)},
- R#motd_users{us = NewUS}
- end);
- _ ->
- ?INFO_MSG("Recreating motd_users table", []),
- mnesia:transform_table(motd_users, ignore, Fields)
- end.
diff --git a/src/mod_bosh_mnesia.erl b/src/mod_bosh_mnesia.erl
index 5954cbe49..d018077cb 100644
--- a/src/mod_bosh_mnesia.erl
+++ b/src/mod_bosh_mnesia.erl
@@ -168,5 +168,4 @@ setup_database() ->
end,
ejabberd_mnesia:create(?MODULE, bosh,
[{ram_copies, [node()]}, {local_content, true},
- {attributes, record_info(fields, bosh)}]),
- mnesia:add_table_copy(bosh, node(), ram_copies).
+ {attributes, record_info(fields, bosh)}]).
diff --git a/src/mod_caps_mnesia.erl b/src/mod_caps_mnesia.erl
index 02ea9aaf0..7362b1cd1 100644
--- a/src/mod_caps_mnesia.erl
+++ b/src/mod_caps_mnesia.erl
@@ -28,6 +28,7 @@
%% API
-export([init/2, caps_read/2, caps_write/3, import/3]).
+-export([need_transform/1, transform/1]).
-include("mod_caps.hrl").
-include("logger.hrl").
@@ -36,22 +37,10 @@
%%% API
%%%===================================================================
init(_Host, _Opts) ->
- case catch mnesia:table_info(caps_features, storage_type) of
- {'EXIT', _} ->
- ok;
- disc_only_copies ->
- ok;
- _ ->
- mnesia:delete_table(caps_features)
- end,
ejabberd_mnesia:create(?MODULE, caps_features,
- [{disc_only_copies, [node()]},
- {local_content, true},
- {attributes,
- record_info(fields, caps_features)}]),
- update_table(),
- mnesia:add_table_copy(caps_features, node(),
- disc_only_copies).
+ [{disc_only_copies, [node()]},
+ {local_content, true},
+ {attributes, record_info(fields, caps_features)}]).
caps_read(_LServer, Node) ->
case mnesia:dirty_read({caps_features, Node}) of
@@ -70,28 +59,26 @@ import(_LServer, NodePair, Features) ->
mnesia:dirty_write(
#caps_features{node_pair = NodePair, features = Features}).
+need_transform(#caps_features{node_pair = {N, P}, features = Fs}) ->
+ case is_list(N) orelse is_list(P) orelse
+ (is_list(Fs) andalso lists:any(fun is_list/1, Fs)) of
+ true ->
+ ?INFO_MSG("Mnesia table 'caps_features' will be "
+ "converted to binary", []),
+ true;
+ false ->
+ false
+ end.
+
+transform(#caps_features{node_pair = {N, P}, features = Fs} = R) ->
+ NewFs = if is_integer(Fs) ->
+ Fs;
+ true ->
+ [iolist_to_binary(F) || F <- Fs]
+ end,
+ R#caps_features{node_pair = {iolist_to_binary(N), iolist_to_binary(P)},
+ features = NewFs}.
+
%%%===================================================================
%%% Internal functions
%%%===================================================================
-update_table() ->
- Fields = record_info(fields, caps_features),
- case mnesia:table_info(caps_features, attributes) of
- Fields ->
- ejabberd_config:convert_table_to_binary(
- caps_features, Fields, set,
- fun(#caps_features{node_pair = {N, _}}) -> N end,
- fun(#caps_features{node_pair = {N, P},
- features = Fs} = R) ->
- NewFs = if is_integer(Fs) ->
- Fs;
- true ->
- [iolist_to_binary(F) || F <- Fs]
- end,
- R#caps_features{node_pair = {iolist_to_binary(N),
- iolist_to_binary(P)},
- features = NewFs}
- end);
- _ ->
- ?INFO_MSG("Recreating caps_features table", []),
- mnesia:transform_table(caps_features, ignore, Fields)
- end.
diff --git a/src/mod_carboncopy_mnesia.erl b/src/mod_carboncopy_mnesia.erl
index 8b248a2de..589686c71 100644
--- a/src/mod_carboncopy_mnesia.erl
+++ b/src/mod_carboncopy_mnesia.erl
@@ -49,8 +49,7 @@ init(_Host, _Opts) ->
ejabberd_mnesia:create(?MODULE, carboncopy,
[{ram_copies, [node()]},
{attributes, record_info(fields, carboncopy)},
- {type, bag}]),
- mnesia:add_table_copy(carboncopy, node(), ram_copies).
+ {type, bag}]).
enable(LUser, LServer, LResource, NS) ->
mnesia:dirty_write(
diff --git a/src/mod_irc_mnesia.erl b/src/mod_irc_mnesia.erl
index 25cdd6d4d..eb982e1fa 100644
--- a/src/mod_irc_mnesia.erl
+++ b/src/mod_irc_mnesia.erl
@@ -28,6 +28,7 @@
%% API
-export([init/2, get_data/3, set_data/4, import/2]).
+-export([need_transform/1, transform/1]).
-include("jid.hrl").
-include("mod_irc.hrl").
@@ -38,9 +39,8 @@
%%%===================================================================
init(_Host, _Opts) ->
ejabberd_mnesia:create(?MODULE, irc_custom,
- [{disc_copies, [node()]},
- {attributes, record_info(fields, irc_custom)}]),
- update_table().
+ [{disc_copies, [node()]},
+ {attributes, record_info(fields, irc_custom)}]).
get_data(_LServer, Host, From) ->
{U, S, _} = jid:tolower(From),
@@ -61,25 +61,21 @@ set_data(_LServer, Host, From, Data) ->
import(_LServer, #irc_custom{} = R) ->
mnesia:dirty_write(R).
+need_transform(#irc_custom{us_host = {{U, S}, H}})
+ when is_list(U) orelse is_list(S) orelse is_list(H) ->
+ ?INFO_MSG("Mnesia table 'irc_custom' will be converted to binary", []),
+ true;
+need_transform(_) ->
+ false.
+
+transform(#irc_custom{us_host = {{U, S}, H},
+ data = Data} = R) ->
+ JID = jid:make(U, S),
+ R#irc_custom{us_host = {{iolist_to_binary(U),
+ iolist_to_binary(S)},
+ iolist_to_binary(H)},
+ data = mod_irc:data_to_binary(JID, Data)}.
+
%%%===================================================================
%%% Internal functions
%%%===================================================================
-update_table() ->
- Fields = record_info(fields, irc_custom),
- case mnesia:table_info(irc_custom, attributes) of
- Fields ->
- ejabberd_config:convert_table_to_binary(
- irc_custom, Fields, set,
- fun(#irc_custom{us_host = {_, H}}) -> H end,
- fun(#irc_custom{us_host = {{U, S}, H},
- data = Data} = R) ->
- JID = jid:make(U, S),
- R#irc_custom{us_host = {{iolist_to_binary(U),
- iolist_to_binary(S)},
- iolist_to_binary(H)},
- data = mod_irc:data_to_binary(JID, Data)}
- end);
- _ ->
- ?INFO_MSG("Recreating irc_custom table", []),
- mnesia:transform_table(irc_custom, ignore, Fields)
- end.
diff --git a/src/mod_last_mnesia.erl b/src/mod_last_mnesia.erl
index 1ca9fb112..ab8f47478 100644
--- a/src/mod_last_mnesia.erl
+++ b/src/mod_last_mnesia.erl
@@ -28,6 +28,7 @@
%% API
-export([init/2, import/2, get_last/2, store_last_info/4, remove_user/2]).
+-export([need_transform/1, transform/1]).
-include("mod_last.hrl").
-include("logger.hrl").
@@ -37,10 +38,8 @@
%%%===================================================================
init(_Host, _Opts) ->
ejabberd_mnesia:create(?MODULE, last_activity,
- [{disc_copies, [node()]},
- {attributes,
- record_info(fields, last_activity)}]),
- update_table().
+ [{disc_copies, [node()]},
+ {attributes, record_info(fields, last_activity)}]).
get_last(LUser, LServer) ->
case mnesia:dirty_read(last_activity, {LUser, LServer}) of
@@ -68,22 +67,17 @@ remove_user(LUser, LServer) ->
import(_LServer, #last_activity{} = LA) ->
mnesia:dirty_write(LA).
+need_transform(#last_activity{us = {U, S}, status = Status})
+ when is_list(U) orelse is_list(S) orelse is_list(Status) ->
+ ?INFO_MSG("Mnesia table 'last_activity' will be converted to binary", []),
+ true;
+need_transform(_) ->
+ false.
+
+transform(#last_activity{us = {U, S}, status = Status} = R) ->
+ R#last_activity{us = {iolist_to_binary(U), iolist_to_binary(S)},
+ status = iolist_to_binary(Status)}.
+
%%%===================================================================
%%% Internal functions
%%%===================================================================
-update_table() ->
- Fields = record_info(fields, last_activity),
- case mnesia:table_info(last_activity, attributes) of
- Fields ->
- ejabberd_config:convert_table_to_binary(
- last_activity, Fields, set,
- fun(#last_activity{us = {U, _}}) -> U end,
- fun(#last_activity{us = {U, S}, status = Status} = R) ->
- R#last_activity{us = {iolist_to_binary(U),
- iolist_to_binary(S)},
- status = iolist_to_binary(Status)}
- end);
- _ ->
- ?INFO_MSG("Recreating last_activity table", []),
- mnesia:transform_table(last_activity, ignore, Fields)
- end.
diff --git a/src/mod_muc_mnesia.erl b/src/mod_muc_mnesia.erl
index 6a9adf4b5..53f31cb9f 100644
--- a/src/mod_muc_mnesia.erl
+++ b/src/mod_muc_mnesia.erl
@@ -39,6 +39,7 @@
%% gen_server callbacks
-export([start_link/2, init/1, handle_cast/2, handle_call/3, handle_info/2,
terminate/2, code_change/3]).
+-export([need_transform/1, transform/1]).
-include("mod_muc.hrl").
-include("logger.hrl").
@@ -306,19 +307,16 @@ init([Host, Opts]) ->
[{disc_copies, [node()]},
{attributes,
record_info(fields, muc_registered)},
- {index, [nick]}]),
- update_tables(MyHost);
+ {index, [nick]}]);
_ ->
ok
end,
case gen_mod:ram_db_mod(Host, Opts, mod_muc) of
?MODULE ->
- update_muc_online_table(),
ejabberd_mnesia:create(?MODULE, muc_online_room,
[{ram_copies, [node()]},
{type, ordered_set},
{attributes, record_info(fields, muc_online_room)}]),
- mnesia:add_table_copy(muc_online_room, node(), ram_copies),
catch ets:new(muc_online_users, [bag, named_table, public, {keypos, 2}]),
clean_table_from_bad_node(node(), MyHost),
mnesia:subscribe(system);
@@ -378,60 +376,21 @@ clean_table_from_bad_node(Node, Host) ->
end,
mnesia:async_dirty(F).
-update_tables(Host) ->
- update_muc_room_table(Host),
- update_muc_registered_table(Host).
-
-update_muc_room_table(_Host) ->
- Fields = record_info(fields, muc_room),
- case mnesia:table_info(muc_room, attributes) of
- Fields ->
- ejabberd_config:convert_table_to_binary(
- muc_room, Fields, set,
- fun(#muc_room{name_host = {N, _}}) -> N end,
- fun(#muc_room{name_host = {N, H},
- opts = Opts} = R) ->
- R#muc_room{name_host = {iolist_to_binary(N),
- iolist_to_binary(H)},
- opts = mod_muc:opts_to_binary(Opts)}
- end);
- _ ->
- ?INFO_MSG("Recreating muc_room table", []),
- mnesia:transform_table(muc_room, ignore, Fields)
- end.
-
-update_muc_registered_table(_Host) ->
- Fields = record_info(fields, muc_registered),
- case mnesia:table_info(muc_registered, attributes) of
- Fields ->
- ejabberd_config:convert_table_to_binary(
- muc_registered, Fields, set,
- fun(#muc_registered{us_host = {_, H}}) -> H end,
- fun(#muc_registered{us_host = {{U, S}, H},
- nick = Nick} = R) ->
- R#muc_registered{us_host = {{iolist_to_binary(U),
- iolist_to_binary(S)},
- iolist_to_binary(H)},
- nick = iolist_to_binary(Nick)}
- end);
- _ ->
- ?INFO_MSG("Recreating muc_registered table", []),
- mnesia:transform_table(muc_registered, ignore, Fields)
- end.
-
-update_muc_online_table() ->
- try
- case mnesia:table_info(muc_online_room, type) of
- ordered_set -> ok;
- _ ->
- case mnesia:delete_table(muc_online_room) of
- {atomic, ok} -> ok;
- Err -> erlang:error(Err)
- end
- end
- catch _:{aborted, {no_exists, muc_online_room}} -> ok;
- _:{aborted, {no_exists, muc_online_room, type}} -> ok;
- E:R ->
- ?ERROR_MSG("failed to update mnesia table '~s': ~p",
- [muc_online_room, {E, R, erlang:get_stacktrace()}])
- end.
+need_transform(#muc_room{name_host = {N, H}})
+ when is_list(N) orelse is_list(H) ->
+ ?INFO_MSG("Mnesia table 'muc_room' will be converted to binary", []),
+ true;
+need_transform(#muc_registered{us_host = {{U, S}, H}, nick = Nick})
+ when is_list(U) orelse is_list(S) orelse is_list(H) orelse is_list(Nick) ->
+ ?INFO_MSG("Mnesia table 'muc_registered' will be converted to binary", []),
+ true;
+need_transform(_) ->
+ false.
+
+transform(#muc_room{name_host = {N, H}, opts = Opts} = R) ->
+ R#muc_room{name_host = {iolist_to_binary(N), iolist_to_binary(H)},
+ opts = mod_muc:opts_to_binary(Opts)};
+transform(#muc_registered{us_host = {{U, S}, H}, nick = Nick} = R) ->
+ R#muc_registered{us_host = {{iolist_to_binary(U), iolist_to_binary(S)},
+ iolist_to_binary(H)},
+ nick = iolist_to_binary(Nick)}.
diff --git a/src/mod_muc_room.erl b/src/mod_muc_room.erl
index f93828962..ca5b12925 100644
--- a/src/mod_muc_room.erl
+++ b/src/mod_muc_room.erl
@@ -3713,6 +3713,21 @@ process_iq_mucsub(_From, #iq{type = set, lang = Lang,
{error, xmpp:err_not_allowed(<<"Subscriptions are not allowed">>, Lang)};
process_iq_mucsub(From,
#iq{type = set, lang = Lang,
+ sub_els = [#muc_subscribe{jid = #jid{} = SubJid} = Mucsub]},
+ StateData) ->
+ FAffiliation = get_affiliation(From, StateData),
+ FRole = get_role(From, StateData),
+ if FRole == moderator; FAffiliation == owner; FAffiliation == admin ->
+ process_iq_mucsub(SubJid,
+ #iq{type = set, lang = Lang,
+ sub_els = [Mucsub#muc_subscribe{jid = undefined}]},
+ StateData);
+ true ->
+ Txt = <<"Moderator privileges required">>,
+ {error, xmpp:err_forbidden(Txt, Lang)}
+ end;
+process_iq_mucsub(From,
+ #iq{type = set, lang = Lang,
sub_els = [#muc_subscribe{nick = Nick}]} = Packet,
StateData) ->
LBareJID = jid:tolower(jid:remove_resource(From)),
@@ -3748,7 +3763,7 @@ process_iq_mucsub(From, #iq{type = set, lang = Lang,
FRole = get_role(From, StateData),
if FRole == moderator; FAffiliation == owner; FAffiliation == admin ->
process_iq_mucsub(UnsubJid,
- #iq{type = set,
+ #iq{type = set, lang = Lang,
sub_els = [#muc_unsubscribe{jid = undefined}]},
StateData);
true ->
diff --git a/src/mod_offline.erl b/src/mod_offline.erl
index db2efb040..373200c12 100644
--- a/src/mod_offline.erl
+++ b/src/mod_offline.erl
@@ -532,15 +532,15 @@ has_no_store_hint(Packet) ->
%% Check if the packet has any content about XEP-0022
-spec check_event(message()) -> boolean().
-check_event(#message{from = From, to = To, id = ID} = Msg) ->
+check_event(#message{from = From, to = To, id = ID, type = Type} = Msg) ->
case xmpp:get_subtag(Msg, #xevent{}) of
false ->
true;
#xevent{id = undefined, offline = false} ->
true;
#xevent{id = undefined, offline = true} ->
- NewMsg = Msg#message{from = To, to = From,
- sub_els = [#xevent{id = ID, offline = true}]},
+ NewMsg = #message{from = To, to = From, id = ID, type = Type,
+ sub_els = [#xevent{id = ID, offline = true}]},
ejabberd_router:route(NewMsg),
true;
_ ->
diff --git a/src/mod_offline_mnesia.erl b/src/mod_offline_mnesia.erl
index f04321237..d0d0de418 100644
--- a/src/mod_offline_mnesia.erl
+++ b/src/mod_offline_mnesia.erl
@@ -30,6 +30,7 @@
remove_old_messages/2, remove_user/2, read_message_headers/2,
read_message/3, remove_message/3, read_all_messages/2,
remove_all_messages/2, count_messages/2, import/1]).
+-export([need_transform/1, transform/1]).
-include("xmpp.hrl").
-include("mod_offline.hrl").
@@ -42,9 +43,8 @@
%%%===================================================================
init(_Host, _Opts) ->
ejabberd_mnesia:create(?MODULE, offline_msg,
- [{disc_only_copies, [node()]}, {type, bag},
- {attributes, record_info(fields, offline_msg)}]),
- update_table().
+ [{disc_only_copies, [node()]}, {type, bag},
+ {attributes, record_info(fields, offline_msg)}]).
store_messages(_Host, US, Msgs, Len, MaxOfflineMsgs) ->
F = fun () ->
@@ -183,6 +183,19 @@ count_messages(LUser, LServer) ->
import(#offline_msg{} = Msg) ->
mnesia:dirty_write(Msg).
+need_transform(#offline_msg{us = {U, S}}) when is_list(U) orelse is_list(S) ->
+ ?INFO_MSG("Mnesia table 'offline_msg' will be converted to binary", []),
+ true;
+need_transform(_) ->
+ false.
+
+transform(#offline_msg{us = {U, S}, from = From, to = To,
+ packet = El} = R) ->
+ R#offline_msg{us = {iolist_to_binary(U), iolist_to_binary(S)},
+ from = jid_to_binary(From),
+ to = jid_to_binary(To),
+ packet = fxml:to_xmlel(El)}.
+
%%%===================================================================
%%% Internal functions
%%%===================================================================
@@ -230,25 +243,3 @@ integer_to_now(Int) ->
MSec = Secs div 1000000,
Sec = Secs rem 1000000,
{MSec, Sec, USec}.
-
-update_table() ->
- Fields = record_info(fields, offline_msg),
- case mnesia:table_info(offline_msg, attributes) of
- Fields ->
- ejabberd_config:convert_table_to_binary(
- offline_msg, Fields, bag,
- fun(#offline_msg{us = {U, _}}) -> U end,
- fun(#offline_msg{us = {U, S},
- from = From,
- to = To,
- packet = El} = R) ->
- R#offline_msg{us = {iolist_to_binary(U),
- iolist_to_binary(S)},
- from = jid_to_binary(From),
- to = jid_to_binary(To),
- packet = fxml:to_xmlel(El)}
- end);
- _ ->
- ?INFO_MSG("Recreating offline_msg table", []),
- mnesia:transform_table(offline_msg, ignore, Fields)
- end.
diff --git a/src/mod_privacy_mnesia.erl b/src/mod_privacy_mnesia.erl
index e3adc7948..efa4ae6c8 100644
--- a/src/mod_privacy_mnesia.erl
+++ b/src/mod_privacy_mnesia.erl
@@ -32,6 +32,7 @@
remove_privacy_list/3, set_privacy_list/1,
set_privacy_list/4, get_user_list/2, get_user_lists/2,
remove_user/2, import/1]).
+-export([need_transform/1, transform/1]).
-include("xmpp.hrl").
-include("mod_privacy.hrl").
@@ -42,9 +43,8 @@
%%%===================================================================
init(_Host, _Opts) ->
ejabberd_mnesia:create(?MODULE, privacy,
- [{disc_copies, [node()]},
- {attributes, record_info(fields, privacy)}]),
- update_table().
+ [{disc_copies, [node()]},
+ {attributes, record_info(fields, privacy)}]).
process_lists_get(LUser, LServer) ->
case catch mnesia:dirty_read(privacy, {LUser, LServer}) of
@@ -163,25 +163,18 @@ remove_user(LUser, LServer) ->
import(#privacy{} = P) ->
mnesia:dirty_write(P).
-%%%===================================================================
-%%% Internal functions
-%%%===================================================================
-update_table() ->
- Fields = record_info(fields, privacy),
- case mnesia:table_info(privacy, attributes) of
- Fields ->
- ejabberd_config:convert_table_to_binary(
- privacy, Fields, set,
- fun(#privacy{us = {U, _}}) -> U end,
- fun(#privacy{us = {U, S}, default = Def, lists = Lists} = R) ->
- NewLists =
- lists:map(
- fun({Name, Ls}) ->
- NewLs =
- lists:map(
- fun(#listitem{value = Val} = L) ->
- NewVal =
- case Val of
+need_transform(#privacy{us = {U, S}}) when is_list(U) orelse is_list(S) ->
+ ?INFO_MSG("Mnesia table 'privacy' will be converted to binary", []),
+ true;
+need_transform(_) ->
+ false.
+
+transform(#privacy{us = {U, S}, default = Def, lists = Lists} = R) ->
+ NewLists = lists:map(
+ fun({Name, Ls}) ->
+ NewLs = lists:map(
+ fun(#listitem{value = Val} = L) ->
+ NewVal = case Val of
{LU, LS, LR} ->
{iolist_to_binary(LU),
iolist_to_binary(LS),
@@ -192,19 +185,17 @@ update_table() ->
to -> to;
_ -> iolist_to_binary(Val)
end,
- L#listitem{value = NewVal}
- end, Ls),
- {iolist_to_binary(Name), NewLs}
- end, Lists),
- NewDef = case Def of
- none -> none;
- _ -> iolist_to_binary(Def)
- end,
- NewUS = {iolist_to_binary(U), iolist_to_binary(S)},
- R#privacy{us = NewUS, default = NewDef,
- lists = NewLists}
- end);
- _ ->
- ?INFO_MSG("Recreating privacy table", []),
- mnesia:transform_table(privacy, ignore, Fields)
- end.
+ L#listitem{value = NewVal}
+ end, Ls),
+ {iolist_to_binary(Name), NewLs}
+ end, Lists),
+ NewDef = case Def of
+ none -> none;
+ _ -> iolist_to_binary(Def)
+ end,
+ NewUS = {iolist_to_binary(U), iolist_to_binary(S)},
+ R#privacy{us = NewUS, default = NewDef, lists = NewLists}.
+
+%%%===================================================================
+%%% Internal functions
+%%%===================================================================
diff --git a/src/mod_private_mnesia.erl b/src/mod_private_mnesia.erl
index fd588aac2..67417bb7f 100644
--- a/src/mod_private_mnesia.erl
+++ b/src/mod_private_mnesia.erl
@@ -29,6 +29,7 @@
%% API
-export([init/2, set_data/3, get_data/3, get_all_data/2, remove_user/2,
import/3]).
+-export([need_transform/1, transform/1]).
-include("xmpp.hrl").
-include("mod_private.hrl").
@@ -39,10 +40,8 @@
%%%===================================================================
init(_Host, _Opts) ->
ejabberd_mnesia:create(?MODULE, private_storage,
- [{disc_only_copies, [node()]},
- {attributes,
- record_info(fields, private_storage)}]),
- update_table().
+ [{disc_only_copies, [node()]},
+ {attributes, record_info(fields, private_storage)}]).
set_data(LUser, LServer, Data) ->
F = fun () ->
@@ -95,23 +94,19 @@ import(LServer, <<"private_storage">>,
PS = #private_storage{usns = {LUser, LServer, XMLNS}, xml = El},
mnesia:dirty_write(PS).
+need_transform(#private_storage{usns = {U, S, NS}})
+ when is_list(U) orelse is_list(S) orelse is_list(NS) ->
+ ?INFO_MSG("Mnesia table 'private_storage' will be converted to binary", []),
+ true;
+need_transform(_) ->
+ false.
+
+transform(#private_storage{usns = {U, S, NS}, xml = El} = R) ->
+ R#private_storage{usns = {iolist_to_binary(U),
+ iolist_to_binary(S),
+ iolist_to_binary(NS)},
+ xml = fxml:to_xmlel(El)}.
+
%%%===================================================================
%%% Internal functions
%%%===================================================================
-update_table() ->
- Fields = record_info(fields, private_storage),
- case mnesia:table_info(private_storage, attributes) of
- Fields ->
- ejabberd_config:convert_table_to_binary(
- private_storage, Fields, set,
- fun(#private_storage{usns = {U, _, _}}) -> U end,
- fun(#private_storage{usns = {U, S, NS}, xml = El} = R) ->
- R#private_storage{usns = {iolist_to_binary(U),
- iolist_to_binary(S),
- iolist_to_binary(NS)},
- xml = fxml:to_xmlel(El)}
- end);
- _ ->
- ?INFO_MSG("Recreating private_storage table", []),
- mnesia:transform_table(private_storage, ignore, Fields)
- end.
diff --git a/src/mod_proxy65_mnesia.erl b/src/mod_proxy65_mnesia.erl
index 2763fab6a..f2a7cc8d5 100644
--- a/src/mod_proxy65_mnesia.erl
+++ b/src/mod_proxy65_mnesia.erl
@@ -104,7 +104,6 @@ init([]) ->
ejabberd_mnesia:create(?MODULE, bytestream,
[{ram_copies, [node()]},
{attributes, record_info(fields, bytestream)}]),
- mnesia:add_table_copy(bytestream, node(), ram_copies),
{ok, #state{}}.
handle_call({activate_stream, SHA1, Initiator, MaxConnections}, _From, State) ->
diff --git a/src/mod_register.erl b/src/mod_register.erl
index d14d49358..e15165f77 100644
--- a/src/mod_register.erl
+++ b/src/mod_register.erl
@@ -57,8 +57,6 @@ start(Host, Opts) ->
ejabberd_mnesia:create(?MODULE, mod_register_ip,
[{ram_copies, [node()]}, {local_content, true},
{attributes, [key, value]}]),
- mnesia:add_table_copy(mod_register_ip, node(),
- ram_copies),
ok.
stop(Host) ->
diff --git a/src/mod_roster_mnesia.erl b/src/mod_roster_mnesia.erl
index e1a1fa1b5..0207b6dc5 100644
--- a/src/mod_roster_mnesia.erl
+++ b/src/mod_roster_mnesia.erl
@@ -32,6 +32,7 @@
roster_subscribe/4, get_roster_by_jid_with_groups/3,
remove_user/2, update_roster/4, del_roster/3, transaction/2,
read_subscription_and_groups/3, import/3, create_roster/1]).
+-export([need_transform/1, transform/1]).
-include("mod_roster.hrl").
-include("logger.hrl").
@@ -47,8 +48,7 @@ init(_Host, _Opts) ->
ejabberd_mnesia:create(?MODULE, roster_version,
[{disc_copies, [node()]},
{attributes,
- record_info(fields, roster_version)}]),
- update_tables().
+ record_info(fields, roster_version)}]).
read_roster_version(LUser, LServer) ->
US = {LUser, LServer},
@@ -127,63 +127,40 @@ import(LServer, <<"roster_version">>, [LUser, Ver]) ->
RV = #roster_version{us = {LUser, LServer}, version = Ver},
mnesia:dirty_write(RV).
+need_transform(#roster{usj = {U, S, _}}) when is_list(U) orelse is_list(S) ->
+ ?INFO_MSG("Mnesia table 'roster' will be converted to binary", []),
+ true;
+need_transform(#roster_version{us = {U, S}, version = Ver})
+ when is_list(U) orelse is_list(S) orelse is_list(Ver) ->
+ ?INFO_MSG("Mnesia table 'roster_version' will be converted to binary", []),
+ true;
+need_transform(_) ->
+ false.
+
+transform(#roster{usj = {U, S, {LU, LS, LR}},
+ us = {U1, S1},
+ jid = {U2, S2, R2},
+ name = Name,
+ groups = Gs,
+ askmessage = Ask,
+ xs = Xs} = R) ->
+ R#roster{usj = {iolist_to_binary(U), iolist_to_binary(S),
+ {iolist_to_binary(LU),
+ iolist_to_binary(LS),
+ iolist_to_binary(LR)}},
+ us = {iolist_to_binary(U1), iolist_to_binary(S1)},
+ jid = {iolist_to_binary(U2),
+ iolist_to_binary(S2),
+ iolist_to_binary(R2)},
+ name = iolist_to_binary(Name),
+ groups = [iolist_to_binary(G) || G <- Gs],
+ askmessage = try iolist_to_binary(Ask)
+ catch _:_ -> <<"">> end,
+ xs = [fxml:to_xmlel(X) || X <- Xs]};
+transform(#roster_version{us = {U, S}, version = Ver} = R) ->
+ R#roster_version{us = {iolist_to_binary(U), iolist_to_binary(S)},
+ version = iolist_to_binary(Ver)}.
+
%%%===================================================================
%%% Internal functions
%%%===================================================================
-update_tables() ->
- update_roster_table(),
- update_roster_version_table().
-
-update_roster_table() ->
- Fields = record_info(fields, roster),
- case mnesia:table_info(roster, attributes) of
- Fields ->
- ejabberd_config:convert_table_to_binary(
- roster, Fields, set,
- fun(#roster{usj = {U, _, _}}) -> U end,
- fun(#roster{usj = {U, S, {LU, LS, LR}},
- us = {U1, S1},
- jid = {U2, S2, R2},
- name = Name,
- groups = Gs,
- askmessage = Ask,
- xs = Xs} = R) ->
- R#roster{usj = {iolist_to_binary(U),
- iolist_to_binary(S),
- {iolist_to_binary(LU),
- iolist_to_binary(LS),
- iolist_to_binary(LR)}},
- us = {iolist_to_binary(U1),
- iolist_to_binary(S1)},
- jid = {iolist_to_binary(U2),
- iolist_to_binary(S2),
- iolist_to_binary(R2)},
- name = iolist_to_binary(Name),
- groups = [iolist_to_binary(G) || G <- Gs],
- askmessage = try iolist_to_binary(Ask)
- catch _:_ -> <<"">> end,
- xs = [fxml:to_xmlel(X) || X <- Xs]}
- end);
- _ ->
- ?INFO_MSG("Recreating roster table", []),
- mnesia:transform_table(roster, ignore, Fields)
- end.
-
-%% Convert roster table to support virtual host
-%% Convert roster table: xattrs fields become
-update_roster_version_table() ->
- Fields = record_info(fields, roster_version),
- case mnesia:table_info(roster_version, attributes) of
- Fields ->
- ejabberd_config:convert_table_to_binary(
- roster_version, Fields, set,
- fun(#roster_version{us = {U, _}}) -> U end,
- fun(#roster_version{us = {U, S}, version = Ver} = R) ->
- R#roster_version{us = {iolist_to_binary(U),
- iolist_to_binary(S)},
- version = iolist_to_binary(Ver)}
- end);
- _ ->
- ?INFO_MSG("Recreating roster_version table", []),
- mnesia:transform_table(roster_version, ignore, Fields)
- end.
diff --git a/src/mod_shared_roster_ldap.erl b/src/mod_shared_roster_ldap.erl
index feb1880b6..951ff0739 100644
--- a/src/mod_shared_roster_ldap.erl
+++ b/src/mod_shared_roster_ldap.erl
@@ -33,7 +33,7 @@
-behaviour(gen_mod).
%% API
--export([start/2, stop/1]).
+-export([start/2, stop/1, reload/3]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2,
@@ -41,7 +41,8 @@
-export([get_user_roster/2, c2s_session_opened/1,
get_jid_info/4, process_item/2, in_subscription/6,
- out_subscription/4, mod_opt_type/1, opt_type/1, depends/2]).
+ out_subscription/4, mod_opt_type/1, opt_type/1, depends/2,
+ transform_module_options/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
@@ -50,9 +51,8 @@
-include("eldap.hrl").
-define(SETS, gb_sets).
--define(CACHE_SIZE, 1000).
--define(USER_CACHE_VALIDITY, 300). %% in seconds
--define(GROUP_CACHE_VALIDITY, 300).
+-define(USER_CACHE, shared_roster_ldap_user_cache).
+-define(GROUP_CACHE, shared_roster_ldap_group_cache).
-define(LDAP_SEARCH_TIMEOUT, 5). %% Timeout for LDAP search queries in seconds
-define(INVALID_SETTING_MSG, "~s is not properly set! ~s will not function.").
@@ -79,11 +79,7 @@
ufilter = <<"">> :: binary(),
rfilter = <<"">> :: binary(),
gfilter = <<"">> :: binary(),
- auth_check = true :: boolean(),
- user_cache_size = ?CACHE_SIZE :: non_neg_integer(),
- group_cache_size = ?CACHE_SIZE :: non_neg_integer(),
- user_cache_validity = ?USER_CACHE_VALIDITY :: non_neg_integer(),
- group_cache_validity = ?GROUP_CACHE_VALIDITY :: non_neg_integer()}).
+ auth_check = true :: boolean()}).
-record(group_info, {desc, members}).
@@ -96,6 +92,17 @@ start(Host, Opts) ->
stop(Host) ->
gen_mod:stop_child(?MODULE, Host).
+reload(Host, NewOpts, _OldOpts) ->
+ case init_cache(Host, NewOpts) of
+ true ->
+ ets_cache:setopts(?USER_CACHE, cache_opts(Host, NewOpts)),
+ ets_cache:setopts(?GROUP_CACHE, cache_opts(Host, NewOpts));
+ false ->
+ ok
+ end,
+ Proc = gen_mod:get_module_proc(Host, ?MODULE),
+ gen_server:cast(Proc, {set_state, parse_options(Host, NewOpts)}).
+
depends(_Host, _Opts) ->
[{mod_roster, hard}].
@@ -231,12 +238,7 @@ process_subscription(Direction, User, Server, JID,
init([Host, Opts]) ->
process_flag(trap_exit, true),
State = parse_options(Host, Opts),
- cache_tab:new(shared_roster_ldap_user,
- [{max_size, State#state.user_cache_size}, {lru, false},
- {life_time, State#state.user_cache_validity}]),
- cache_tab:new(shared_roster_ldap_group,
- [{max_size, State#state.group_cache_size}, {lru, false},
- {life_time, State#state.group_cache_validity}]),
+ init_cache(Host, Opts),
ejabberd_hooks:add(roster_get, Host, ?MODULE,
get_user_roster, 70),
ejabberd_hooks:add(roster_in_subscription, Host,
@@ -260,6 +262,8 @@ handle_call(get_state, _From, State) ->
handle_call(_Request, _From, State) ->
{reply, {error, badarg}, State}.
+handle_cast({set_state, NewState}, _State) ->
+ {noreply, NewState};
handle_cast(_Msg, State) -> {noreply, State}.
handle_info(_Info, State) -> {noreply, State}.
@@ -341,9 +345,9 @@ get_user_displayed_groups({User, Host}) ->
get_group_users(Host, Group) ->
{ok, State} = eldap_utils:get_state(Host, ?MODULE),
- case cache_tab:dirty_lookup(shared_roster_ldap_group,
- {Group, Host},
- fun () -> search_group_info(State, Group) end) of
+ case ets_cache:lookup(?GROUP_CACHE,
+ {Group, Host},
+ fun () -> search_group_info(State, Group) end) of
{ok, #group_info{members = Members}}
when Members /= undefined ->
Members;
@@ -352,9 +356,9 @@ get_group_users(Host, Group) ->
get_group_name(Host, Group) ->
{ok, State} = eldap_utils:get_state(Host, ?MODULE),
- case cache_tab:dirty_lookup(shared_roster_ldap_group,
- {Group, Host},
- fun () -> search_group_info(State, Group) end)
+ case ets_cache:lookup(?GROUP_CACHE,
+ {Group, Host},
+ fun () -> search_group_info(State, Group) end)
of
{ok, #group_info{desc = GroupName}}
when GroupName /= undefined ->
@@ -364,9 +368,9 @@ get_group_name(Host, Group) ->
get_user_name(User, Host) ->
{ok, State} = eldap_utils:get_state(Host, ?MODULE),
- case cache_tab:dirty_lookup(shared_roster_ldap_user,
- {User, Host},
- fun () -> search_user_name(State, User) end)
+ case ets_cache:lookup(?USER_CACHE,
+ {User, Host},
+ fun () -> search_user_name(State, User) end)
of
{ok, UserName} -> UserName;
error -> User
@@ -494,22 +498,6 @@ parse_options(Host, Opts) ->
(false) -> false;
(true) -> true
end, true),
- UserCacheValidity = gen_mod:get_opt(
- {ldap_user_cache_validity, Host}, Opts,
- fun(I) when is_integer(I), I>0 -> I end,
- ?USER_CACHE_VALIDITY),
- GroupCacheValidity = gen_mod:get_opt(
- {ldap_group_cache_validity, Host}, Opts,
- fun(I) when is_integer(I), I>0 -> I end,
- ?GROUP_CACHE_VALIDITY),
- UserCacheSize = gen_mod:get_opt(
- {ldap_user_cache_size, Host}, Opts,
- fun(I) when is_integer(I), I>0 -> I end,
- ?CACHE_SIZE),
- GroupCacheSize = gen_mod:get_opt(
- {ldap_group_cache_size, Host}, Opts,
- fun(I) when is_integer(I), I>0 -> I end,
- ?CACHE_SIZE),
ConfigFilter = gen_mod:get_opt({ldap_filter, Host}, Opts,
fun check_filter/1, <<"">>),
ConfigUserFilter = gen_mod:get_opt({ldap_ufilter, Host}, Opts,
@@ -562,17 +550,67 @@ parse_options(Host, Opts) ->
uid_format = UIDAttrFormat,
uid_format_re = UIDAttrFormatRe, filter = Filter,
ufilter = UserFilter, rfilter = RosterFilter,
- gfilter = GroupFilter, auth_check = AuthCheck,
- user_cache_size = UserCacheSize,
- user_cache_validity = UserCacheValidity,
- group_cache_size = GroupCacheSize,
- group_cache_validity = GroupCacheValidity}.
+ gfilter = GroupFilter, auth_check = AuthCheck}.
check_filter(F) ->
NewF = iolist_to_binary(F),
{ok, _} = eldap_filter:parse(NewF),
NewF.
+init_cache(Host, Opts) ->
+ UseCache = use_cache(Host, Opts),
+ case UseCache of
+ true ->
+ CacheOpts = cache_opts(Host, Opts),
+ ets_cache:new(?USER_CACHE, CacheOpts),
+ ets_cache:new(?GROUP_CACHE, CacheOpts);
+ false ->
+ ets_cache:delete(?USER_CACHE),
+ ets_cache:delete(?GROUP_CACHE)
+ end,
+ UseCache.
+
+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}].
+
+transform_module_options(Opts) ->
+ lists:map(
+ fun({ldap_group_cache_size, I}) ->
+ ?WARNING_MSG("Option 'ldap_group_cache_size' is deprecated, "
+ "use 'cache_size' instead", []),
+ {cache_size, I};
+ ({ldap_user_cache_size, I}) ->
+ ?WARNING_MSG("Option 'ldap_user_cache_size' is deprecated, "
+ "use 'cache_size' instead", []),
+ {cache_size, I};
+ ({ldap_group_cache_validity, Secs}) ->
+ ?WARNING_MSG("Option 'ldap_group_cache_validity' is deprecated, "
+ "use 'cache_life_time' instead", []),
+ {cache_life_time, Secs};
+ ({ldap_user_cache_validity, Secs}) ->
+ ?WARNING_MSG("Option 'ldap_user_cache_validity' is deprecated, "
+ "use 'cache_life_time' instead", []),
+ {cache_life_time, Secs};
+ (Opt) ->
+ Opt
+ end, Opts).
+
mod_opt_type(deref_aliases) ->
fun (never) -> never;
(searching) -> searching;
@@ -618,10 +656,13 @@ mod_opt_type(ldap_auth_check) ->
end;
mod_opt_type(ldap_filter) -> fun check_filter/1;
mod_opt_type(ldap_gfilter) -> fun check_filter/1;
-mod_opt_type(ldap_group_cache_size) ->
- fun (I) when is_integer(I), I > 0 -> I end;
-mod_opt_type(ldap_group_cache_validity) ->
- fun (I) when is_integer(I), I > 0 -> I end;
+mod_opt_type(O) when O == cache_size;
+ O == cache_life_time ->
+ fun (I) when is_integer(I), I > 0 -> I;
+ (infinity) -> infinity
+ end;
+mod_opt_type(O) when O == use_cache; O == cache_missed ->
+ fun (B) when is_boolean(B) -> B end;
mod_opt_type(ldap_groupattr) -> fun iolist_to_binary/1;
mod_opt_type(ldap_groupdesc) -> fun iolist_to_binary/1;
mod_opt_type(ldap_memberattr) -> fun iolist_to_binary/1;
@@ -633,38 +674,22 @@ mod_opt_type(ldap_memberattr_format_re) ->
end;
mod_opt_type(ldap_rfilter) -> fun check_filter/1;
mod_opt_type(ldap_ufilter) -> fun check_filter/1;
-mod_opt_type(ldap_user_cache_size) ->
- fun (I) when is_integer(I), I > 0 -> I end;
-mod_opt_type(ldap_user_cache_validity) ->
- fun (I) when is_integer(I), I > 0 -> I end;
mod_opt_type(ldap_userdesc) -> fun iolist_to_binary/1;
mod_opt_type(ldap_useruid) -> fun iolist_to_binary/1;
mod_opt_type(_) ->
[ldap_auth_check, ldap_filter, ldap_gfilter,
- ldap_group_cache_size, ldap_group_cache_validity,
ldap_groupattr, ldap_groupdesc, ldap_memberattr,
ldap_memberattr_format, ldap_memberattr_format_re,
- ldap_rfilter, ldap_ufilter, ldap_user_cache_size,
- ldap_user_cache_validity, ldap_userdesc, ldap_useruid,
+ ldap_rfilter, ldap_ufilter, ldap_userdesc, ldap_useruid,
deref_aliases, ldap_backups, ldap_base,
ldap_deref_aliases, ldap_encrypt, ldap_password,
ldap_port, ldap_rootdn, ldap_servers,
ldap_tls_cacertfile, ldap_tls_certfile, ldap_tls_depth,
- ldap_tls_verify].
+ ldap_tls_verify, use_cache, cache_missed, cache_size, cache_life_time].
opt_type(ldap_filter) -> fun check_filter/1;
opt_type(ldap_gfilter) -> fun check_filter/1;
-opt_type(ldap_group_cache_size) ->
- fun (I) when is_integer(I), I > 0 -> I end;
-opt_type(ldap_group_cache_validity) ->
- fun (I) when is_integer(I), I > 0 -> I end;
opt_type(ldap_rfilter) -> fun check_filter/1;
opt_type(ldap_ufilter) -> fun check_filter/1;
-opt_type(ldap_user_cache_size) ->
- fun (I) when is_integer(I), I > 0 -> I end;
-opt_type(ldap_user_cache_validity) ->
- fun (I) when is_integer(I), I > 0 -> I end;
opt_type(_) ->
- [ldap_filter, ldap_gfilter, ldap_group_cache_size,
- ldap_group_cache_validity, ldap_rfilter, ldap_ufilter,
- ldap_user_cache_size, ldap_user_cache_validity].
+ [ldap_filter, ldap_gfilter, ldap_rfilter, ldap_ufilter].
diff --git a/src/mod_shared_roster_mnesia.erl b/src/mod_shared_roster_mnesia.erl
index 1e3012794..adfbac680 100644
--- a/src/mod_shared_roster_mnesia.erl
+++ b/src/mod_shared_roster_mnesia.erl
@@ -32,6 +32,7 @@
get_user_groups/2, get_group_explicit_users/2,
get_user_displayed_groups/3, is_user_in_group/3,
add_user_to_group/3, remove_user_from_group/3, import/3]).
+-export([need_transform/1, transform/1]).
-include("mod_roster.hrl").
-include("mod_shared_roster.hrl").
@@ -43,13 +44,12 @@
%%%===================================================================
init(_Host, _Opts) ->
ejabberd_mnesia:create(?MODULE, sr_group,
- [{disc_copies, [node()]},
- {attributes, record_info(fields, sr_group)}]),
+ [{disc_copies, [node()]},
+ {attributes, record_info(fields, sr_group)}]),
ejabberd_mnesia:create(?MODULE, sr_user,
- [{disc_copies, [node()]}, {type, bag},
- {attributes, record_info(fields, sr_user)},
- {index, [group_host]}]),
- update_tables().
+ [{disc_copies, [node()]}, {type, bag},
+ {attributes, record_info(fields, sr_user)},
+ {index, [group_host]}]).
list_groups(Host) ->
mnesia:dirty_select(sr_group,
@@ -144,44 +144,24 @@ import(LServer, <<"sr_user">>, [SJID, Group, _TimeStamp]) ->
User = #sr_user{us = {U, S}, group_host = {Group, LServer}},
mnesia:dirty_write(User).
+need_transform(#sr_group{group_host = {G, H}})
+ when is_list(G) orelse is_list(H) ->
+ ?INFO_MSG("Mnesia table 'sr_group' will be converted to binary", []),
+ true;
+need_transform(#sr_user{us = {U, S}, group_host = {G, H}})
+ when is_list(U) orelse is_list(S) orelse is_list(G) orelse is_list(H) ->
+ ?INFO_MSG("Mnesia table 'sr_user' will be converted to binary", []),
+ true;
+need_transform(_) ->
+ false.
+
+transform(#sr_group{group_host = {G, H}, opts = Opts} = R) ->
+ R#sr_group{group_host = {iolist_to_binary(G), iolist_to_binary(H)},
+ opts = mod_shared_roster:opts_to_binary(Opts)};
+transform(#sr_user{us = {U, S}, group_host = {G, H}} = R) ->
+ R#sr_user{us = {iolist_to_binary(U), iolist_to_binary(S)},
+ group_host = {iolist_to_binary(G), iolist_to_binary(H)}}.
+
%%%===================================================================
%%% Internal functions
%%%===================================================================
-update_tables() ->
- update_sr_group_table(),
- update_sr_user_table().
-
-update_sr_group_table() ->
- Fields = record_info(fields, sr_group),
- case mnesia:table_info(sr_group, attributes) of
- Fields ->
- ejabberd_config:convert_table_to_binary(
- sr_group, Fields, set,
- fun(#sr_group{group_host = {G, _}}) -> G end,
- fun(#sr_group{group_host = {G, H},
- opts = Opts} = R) ->
- R#sr_group{group_host = {iolist_to_binary(G),
- iolist_to_binary(H)},
- opts = mod_shared_roster:opts_to_binary(Opts)}
- end);
- _ ->
- ?INFO_MSG("Recreating sr_group table", []),
- mnesia:transform_table(sr_group, ignore, Fields)
- end.
-
-update_sr_user_table() ->
- Fields = record_info(fields, sr_user),
- case mnesia:table_info(sr_user, attributes) of
- Fields ->
- ejabberd_config:convert_table_to_binary(
- sr_user, Fields, bag,
- fun(#sr_user{us = {U, _}}) -> U end,
- fun(#sr_user{us = {U, S}, group_host = {G, H}} = R) ->
- R#sr_user{us = {iolist_to_binary(U), iolist_to_binary(S)},
- group_host = {iolist_to_binary(G),
- iolist_to_binary(H)}}
- end);
- _ ->
- ?INFO_MSG("Recreating sr_user table", []),
- mnesia:transform_table(sr_user, ignore, Fields)
- end.
diff --git a/src/mod_stream_mgmt.erl b/src/mod_stream_mgmt.erl
index a1d1ba2e9..64cb0fd1b 100644
--- a/src/mod_stream_mgmt.erl
+++ b/src/mod_stream_mgmt.erl
@@ -522,7 +522,7 @@ route_unacked_stanzas(#{mgmt_state := MgmtState,
Resend when is_boolean(Resend) ->
Resend;
if_offline ->
- case ejabberd_sm:get_user_resources(User, Resource) of
+ case ejabberd_sm:get_user_resources(User, LServer) of
[Resource] ->
%% Same resource opened new session
true;
diff --git a/src/mod_vcard_mnesia.erl b/src/mod_vcard_mnesia.erl
index 5faff5261..340f8928e 100644
--- a/src/mod_vcard_mnesia.erl
+++ b/src/mod_vcard_mnesia.erl
@@ -30,6 +30,7 @@
-export([init/2, stop/1, import/3, get_vcard/2, set_vcard/4, search/4,
search_fields/1, search_reported/1, remove_user/2]).
-export([is_search_supported/1]).
+-export([need_transform/1, transform/1]).
-include("ejabberd.hrl").
-include("xmpp.hrl").
@@ -51,8 +52,7 @@ init(_Host, _Opts) ->
lgiven, lmiddle, lnickname,
lbday, lctry, llocality,
lemail, lorgname, lorgunit
- ]}]),
- update_tables().
+ ]}]).
stop(_Host) ->
ok.
@@ -158,53 +158,31 @@ import(LServer, <<"vcard_search">>,
orgname = OrgName, lorgname = LOrgName,
orgunit = OrgUnit, lorgunit = LOrgUnit}).
+need_transform(#vcard{us = {U, S}}) when is_list(U) orelse is_list(S) ->
+ ?INFO_MSG("Mnesia table 'vcard' will be converted to binary", []),
+ true;
+need_transform(#vcard_search{us = {U, S}}) when is_list(U) orelse is_list(S) ->
+ ?INFO_MSG("Mnesia table 'vcard_search' will be converted to binary", []),
+ true;
+need_transform(_) ->
+ false.
+
+transform(#vcard{us = {U, S}, vcard = El} = R) ->
+ R#vcard{us = {iolist_to_binary(U), iolist_to_binary(S)},
+ vcard = fxml:to_xmlel(El)};
+transform(#vcard_search{} = VS) ->
+ [vcard_search | L] = tuple_to_list(VS),
+ NewL = lists:map(
+ fun({U, S}) ->
+ {iolist_to_binary(U), iolist_to_binary(S)};
+ (Str) ->
+ iolist_to_binary(Str)
+ end, L),
+ list_to_tuple([vcard_search | NewL]).
+
%%%===================================================================
%%% Internal functions
%%%===================================================================
-update_tables() ->
- update_vcard_table(),
- update_vcard_search_table().
-
-update_vcard_table() ->
- Fields = record_info(fields, vcard),
- case mnesia:table_info(vcard, attributes) of
- Fields ->
- ejabberd_config:convert_table_to_binary(
- vcard, Fields, set,
- fun(#vcard{us = {U, _}}) -> U end,
- fun(#vcard{us = {U, S}, vcard = El} = R) ->
- R#vcard{us = {iolist_to_binary(U),
- iolist_to_binary(S)},
- vcard = fxml:to_xmlel(El)}
- end);
- _ ->
- ?INFO_MSG("Recreating vcard table", []),
- mnesia:transform_table(vcard, ignore, Fields)
- end.
-
-update_vcard_search_table() ->
- Fields = record_info(fields, vcard_search),
- case mnesia:table_info(vcard_search, attributes) of
- Fields ->
- ejabberd_config:convert_table_to_binary(
- vcard_search, Fields, set,
- fun(#vcard_search{us = {U, _}}) -> U end,
- fun(#vcard_search{} = VS) ->
- [vcard_search | L] = tuple_to_list(VS),
- NewL = lists:map(
- fun({U, S}) ->
- {iolist_to_binary(U),
- iolist_to_binary(S)};
- (Str) ->
- iolist_to_binary(Str)
- end, L),
- list_to_tuple([vcard_search | NewL])
- end);
- _ ->
- ?INFO_MSG("Recreating vcard_search table", []),
- mnesia:transform_table(vcard_search, ignore, Fields)
- end.
-
make_matchspec(LServer, Data) ->
GlobMatch = #vcard_search{_ = '_'},
Match = filter_fields(Data, GlobMatch, LServer),
diff --git a/src/mod_vcard_xupdate_mnesia.erl b/src/mod_vcard_xupdate_mnesia.erl
index 879f5b115..9b80e0672 100644
--- a/src/mod_vcard_xupdate_mnesia.erl
+++ b/src/mod_vcard_xupdate_mnesia.erl
@@ -28,6 +28,7 @@
%% API
-export([init/2, import/3, add_xupdate/3, get_xupdate/2, remove_xupdate/2]).
+-export([need_transform/1, transform/1]).
-include("mod_vcard_xupdate.hrl").
-include("logger.hrl").
@@ -39,8 +40,7 @@ init(_Host, _Opts) ->
ejabberd_mnesia:create(?MODULE, vcard_xupdate,
[{disc_copies, [node()]},
{attributes,
- record_info(fields, vcard_xupdate)}]),
- update_table().
+ record_info(fields, vcard_xupdate)}]).
add_xupdate(LUser, LServer, Hash) ->
F = fun () ->
@@ -66,22 +66,17 @@ import(LServer, <<"vcard_xupdate">>, [LUser, Hash, _TimeStamp]) ->
mnesia:dirty_write(
#vcard_xupdate{us = {LUser, LServer}, hash = Hash}).
+need_transform(#vcard_xupdate{us = {U, S}, hash = Hash})
+ when is_list(U) orelse is_list(S) orelse is_list(Hash) ->
+ ?INFO_MSG("Mnesia table 'vcard_xupdate' will be converted to binary", []),
+ true;
+need_transform(_) ->
+ false.
+
+transform(#vcard_xupdate{us = {U, S}, hash = Hash} = R) ->
+ R#vcard_xupdate{us = {iolist_to_binary(U), iolist_to_binary(S)},
+ hash = iolist_to_binary(Hash)}.
+
%%%===================================================================
%%% Internal functions
%%%===================================================================
-update_table() ->
- Fields = record_info(fields, vcard_xupdate),
- case mnesia:table_info(vcard_xupdate, attributes) of
- Fields ->
- ejabberd_config:convert_table_to_binary(
- vcard_xupdate, Fields, set,
- fun(#vcard_xupdate{us = {U, _}}) -> U end,
- fun(#vcard_xupdate{us = {U, S}, hash = Hash} = R) ->
- R#vcard_xupdate{us = {iolist_to_binary(U),
- iolist_to_binary(S)},
- hash = iolist_to_binary(Hash)}
- end);
- _ ->
- ?INFO_MSG("Recreating vcard_xupdate table", []),
- mnesia:transform_table(vcard_xupdate, ignore, Fields)
- end.
diff --git a/src/pubsub_migrate.erl b/src/pubsub_migrate.erl
index 17bdb2368..f0b324461 100644
--- a/src/pubsub_migrate.erl
+++ b/src/pubsub_migrate.erl
@@ -430,7 +430,7 @@ convert_list_lasts() ->
convert_list_records(Tab, Fields, DetectFun, ConvertFun) ->
case mnesia:table_info(Tab, attributes) of
Fields ->
- ejabberd_config:convert_table_to_binary(
+ convert_table_to_binary(
Tab, Fields, set, DetectFun, ConvertFun);
_ ->
?INFO_MSG("Recreating ~p table", [Tab]),
@@ -445,3 +445,89 @@ binusr({U,S,R}) -> {bin(U), bin(S), bin(R)}.
bin(L) -> iolist_to_binary(L).
+%% The code should be updated to support new ejabberd_mnesia
+%% transform functions (i.e. need_transform/1 and transform/1)
+convert_table_to_binary(Tab, Fields, Type, DetectFun, ConvertFun) ->
+ case is_table_still_list(Tab, DetectFun) of
+ true ->
+ ?INFO_MSG("Converting '~s' table from strings to binaries.", [Tab]),
+ TmpTab = list_to_atom(atom_to_list(Tab) ++ "_tmp_table"),
+ catch mnesia:delete_table(TmpTab),
+ case ejabberd_mnesia:create(?MODULE, TmpTab,
+ [{disc_only_copies, [node()]},
+ {type, Type},
+ {local_content, true},
+ {record_name, Tab},
+ {attributes, Fields}]) of
+ {atomic, ok} ->
+ mnesia:transform_table(Tab, ignore, Fields),
+ case mnesia:transaction(
+ fun() ->
+ mnesia:write_lock_table(TmpTab),
+ mnesia:foldl(
+ fun(R, _) ->
+ NewR = ConvertFun(R),
+ mnesia:dirty_write(TmpTab, NewR)
+ end, ok, Tab)
+ end) of
+ {atomic, ok} ->
+ mnesia:clear_table(Tab),
+ case mnesia:transaction(
+ fun() ->
+ mnesia:write_lock_table(Tab),
+ mnesia:foldl(
+ fun(R, _) ->
+ mnesia:dirty_write(R)
+ end, ok, TmpTab)
+ end) of
+ {atomic, ok} ->
+ mnesia:delete_table(TmpTab);
+ Err ->
+ report_and_stop(Tab, Err)
+ end;
+ Err ->
+ report_and_stop(Tab, Err)
+ end;
+ Err ->
+ report_and_stop(Tab, Err)
+ end;
+ false ->
+ ok
+ end.
+
+is_table_still_list(Tab, DetectFun) ->
+ is_table_still_list(Tab, DetectFun, mnesia:dirty_first(Tab)).
+
+is_table_still_list(_Tab, _DetectFun, '$end_of_table') ->
+ false;
+is_table_still_list(Tab, DetectFun, Key) ->
+ Rs = mnesia:dirty_read(Tab, Key),
+ Res = lists:foldl(fun(_, true) ->
+ true;
+ (_, false) ->
+ false;
+ (R, _) ->
+ case DetectFun(R) of
+ '$next' ->
+ '$next';
+ El ->
+ is_list(El)
+ end
+ end, '$next', Rs),
+ case Res of
+ true ->
+ true;
+ false ->
+ false;
+ '$next' ->
+ is_table_still_list(Tab, DetectFun, mnesia:dirty_next(Tab, Key))
+ end.
+
+report_and_stop(Tab, Err) ->
+ ErrTxt = lists:flatten(
+ io_lib:format(
+ "Failed to convert '~s' table to binary: ~p",
+ [Tab, Err])),
+ ?CRITICAL_MSG(ErrTxt, []),
+ timer:sleep(1000),
+ halt(string:substr(ErrTxt, 1, 199)).
diff --git a/src/randoms.erl b/src/randoms.erl
index ea21b4a1d..ad07b47c2 100644
--- a/src/randoms.erl
+++ b/src/randoms.erl
@@ -27,7 +27,8 @@
-author('alexey@process-one.net').
--export([get_string/0, uniform/0, uniform/1, uniform/2, bytes/1]).
+-export([get_string/0, uniform/0, uniform/1, uniform/2, bytes/1,
+ round_robin/1]).
-define(THRESHOLD, 16#10000000000000000).
@@ -51,3 +52,7 @@ bytes(N) ->
bytes(N) ->
crypto:rand_bytes(N).
-endif.
+
+-spec round_robin(pos_integer()) -> non_neg_integer().
+round_robin(N) ->
+ p1_time_compat:unique_integer([monotonic, positive]) rem N.
diff --git a/src/shaper.erl b/src/shaper.erl
index cc1923f86..b4db64586 100644
--- a/src/shaper.erl
+++ b/src/shaper.erl
@@ -62,7 +62,6 @@ init([]) ->
[{ram_copies, [node()]},
{local_content, true},
{attributes, record_info(fields, shaper)}]),
- mnesia:add_table_copy(shaper, node(), ram_copies),
ejabberd_hooks:add(config_reloaded, ?MODULE, load_from_config, 20),
load_from_config(),
{ok, #state{}}.
diff --git a/test/acl_test.exs b/test/acl_test.exs
index ada2d8fb1..99377e4c1 100644
--- a/test/acl_test.exs
+++ b/test/acl_test.exs
@@ -25,7 +25,8 @@ defmodule ACLTest do
setup_all do
:ok = :mnesia.start
- {:ok, _} = :jid.start
+ :ejabberd_mnesia.start
+ :jid.start
:ejabberd_hooks.start_link
:stringprep.start
:ok = :ejabberd_config.start(["domain1", "domain2"], [])
diff --git a/test/ejabberd_commands_mock_test.exs b/test/ejabberd_commands_mock_test.exs
index 3a6874333..a19d0720c 100644
--- a/test/ejabberd_commands_mock_test.exs
+++ b/test/ejabberd_commands_mock_test.exs
@@ -49,11 +49,13 @@ defmodule EjabberdCommandsMockTest do
_ -> :ok
end
:mnesia.start
- {:ok, _} = :jid.start
+ :ejabberd_mnesia.start
+ :jid.start
:ejabberd_hooks.start_link
:ok = :ejabberd_config.start(["domain1", "domain2"], [])
{:ok, _} = :ejabberd_access_permissions.start_link()
{:ok, _} = :acl.start_link
+ :ejabberd_commands.start_link
EjabberdOauthMock.init
on_exit fn -> :meck.unload end
end
@@ -61,8 +63,8 @@ defmodule EjabberdCommandsMockTest do
setup do
:meck.unload
:meck.new(@module, [:non_strict])
- :mnesia.delete_table(:ejabberd_commands)
- :ejabberd_commands.start_link
+ :mnesia.clear_table(:ejabberd_commands)
+ :ejabberd_commands.register_commands(:ejabberd_commands.get_commands_spec())
:ok
end
diff --git a/test/ejabberd_commands_test.exs b/test/ejabberd_commands_test.exs
index dff64b1ea..40e860c27 100644
--- a/test/ejabberd_commands_test.exs
+++ b/test/ejabberd_commands_test.exs
@@ -28,6 +28,7 @@ defmodule EjabberdCommandsTest do
setup_all do
:mnesia.start
+ :ejabberd_mnesia.start
:stringprep.start
:ok = :ejabberd_config.start(["localhost"], [])
{:ok, _} = :ejabberd_access_permissions.start_link()
diff --git a/test/ejabberd_cyrsasl_test.exs b/test/ejabberd_cyrsasl_test.exs
index 1f190680d..a5127f0e0 100644
--- a/test/ejabberd_cyrsasl_test.exs
+++ b/test/ejabberd_cyrsasl_test.exs
@@ -27,8 +27,9 @@ defmodule EjabberdCyrsaslTest do
:ok = :ejabberd.start_app(:lager)
:p1_sha.load_nif()
:mnesia.start
+ :ejabberd_mnesia.start
:ok = start_module(:stringprep)
- {:ok, _} = start_module(:jid)
+ start_module(:jid)
:ok = :ejabberd_config.start(["domain1"], [])
{:ok, _} = :cyrsasl.start_link
cyrstate = :cyrsasl.server_new("domain1", "domain1", "domain1", :ok, &get_password/1,
diff --git a/test/mod_http_api_mock_test.exs b/test/mod_http_api_mock_test.exs
index d7661ce4f..4dde78939 100644
--- a/test/mod_http_api_mock_test.exs
+++ b/test/mod_http_api_mock_test.exs
@@ -44,6 +44,7 @@ defmodule ModHttpApiMockTest do
try do
:jid.start
:mnesia.start
+ :ejabberd_mnesia.start
:stringprep.start
:ejabberd_config.start([@domain], [])
{:ok, _} = :ejabberd_access_permissions.start_link()
diff --git a/test/mod_http_api_test.exs b/test/mod_http_api_test.exs
index a9d05eafb..c39af79dc 100644
--- a/test/mod_http_api_test.exs
+++ b/test/mod_http_api_test.exs
@@ -29,6 +29,7 @@ defmodule ModHttpApiTest do
setup_all do
:ok = :mnesia.start
+ :ejabberd_mnesia.start
:stringprep.start
:ok = :ejabberd_config.start(["localhost"], [])
{:ok, _} = :ejabberd_access_permissions.start_link()