diff --git a/src/mod_shared_roster_ldap.erl b/src/mod_shared_roster_ldap.erl index feb1880b626..951ff073929 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].