Require Redis version >= 3.2.0

Since we now use Lua scripting for cleaning up c2s sessions
the minimum supported Redis version is 3.2.0 or above because
we need to work correctly with Redis replication mechanism.

****** BACKWARD INCOMPATIBILITY WARNING *******
** THIS SHOULD BE ADDED TO THE RELEASE NOTES **
*** PACKAGE MAINTAINERS SHOULD BE INFORMED  ***
***********************************************
This commit is contained in:
Evgeniy Khramtsov 2018-07-15 09:52:03 +03:00
parent 12e537c43f
commit 8faa6afa67
4 changed files with 56 additions and 14 deletions

View File

@ -33,7 +33,7 @@
%% API %% API
-export([start_link/1, get_proc/1, get_connection/1, q/1, qp/1, format_error/1]). -export([start_link/1, get_proc/1, get_connection/1, q/1, qp/1, format_error/1]).
%% Commands %% Commands
-export([multi/1, get/1, set/2, del/1, -export([multi/1, get/1, set/2, del/1, info/1,
sadd/2, srem/2, smembers/1, sismember/2, scard/1, sadd/2, srem/2, smembers/1, sismember/2, scard/1,
hget/2, hset/3, hdel/2, hlen/1, hgetall/1, hkeys/1, hget/2, hset/3, hdel/2, hlen/1, hgetall/1, hkeys/1,
subscribe/1, publish/2, script_load/1, evalsha/3]). subscribe/1, publish/2, script_load/1, evalsha/3]).
@ -61,6 +61,9 @@
-type redis_reply() :: binary() | [binary()]. -type redis_reply() :: binary() | [binary()].
-type redis_command() :: [binary()]. -type redis_command() :: [binary()].
-type redis_pipeline() :: [redis_command()]. -type redis_pipeline() :: [redis_command()].
-type redis_info() :: server | clients | memory | persistence |
stats | replication | cpu | commandstats |
cluster | keyspace | default | all.
-type state() :: #state{}. -type state() :: #state{}.
-export_type([error_reason/0]). -export_type([error_reason/0]).
@ -334,6 +337,22 @@ evalsha(SHA, Keys, Args) ->
erlang:error(transaction_unsupported) erlang:error(transaction_unsupported)
end. end.
-spec info(redis_info()) -> {ok, [{atom(), binary()}]} | redis_error().
info(Type) ->
case erlang:get(?TR_STACK) of
undefined ->
case q([<<"INFO">>, misc:atom_to_binary(Type)]) of
{ok, Info} ->
Lines = binary:split(Info, <<"\r\n">>, [global]),
KVs = [binary:split(Line, <<":">>) || Line <- Lines],
{ok, [{misc:binary_to_atom(K), V} || [K, V] <- KVs]};
{error, _} = Err ->
Err
end;
_ ->
erlang:error(transaction_unsupported)
end.
%%%=================================================================== %%%===================================================================
%%% gen_server callbacks %%% gen_server callbacks
%%%=================================================================== %%%===================================================================

View File

@ -426,15 +426,22 @@ config_reloaded() ->
init([]) -> init([]) ->
process_flag(trap_exit, true), process_flag(trap_exit, true),
init_cache(), init_cache(),
lists:foreach(fun(Mod) -> Mod:init() end, get_sm_backends()), case lists:foldl(
clean_cache(), fun(Mod, ok) -> Mod:init();
gen_iq_handler:start(?MODULE), (_, Err) -> Err
ejabberd_hooks:add(host_up, ?MODULE, host_up, 50), end, ok, get_sm_backends()) of
ejabberd_hooks:add(host_down, ?MODULE, host_down, 60), ok ->
ejabberd_hooks:add(config_reloaded, ?MODULE, config_reloaded, 50), clean_cache(),
lists:foreach(fun host_up/1, ejabberd_config:get_myhosts()), gen_iq_handler:start(?MODULE),
ejabberd_commands:register_commands(get_commands_spec()), ejabberd_hooks:add(host_up, ?MODULE, host_up, 50),
{ok, #state{}}. ejabberd_hooks:add(host_down, ?MODULE, host_down, 60),
ejabberd_hooks:add(config_reloaded, ?MODULE, config_reloaded, 50),
lists:foreach(fun host_up/1, ejabberd_config:get_myhosts()),
ejabberd_commands:register_commands(get_commands_spec()),
{ok, #state{}};
{error, Why} ->
{stop, Why}
end.
handle_call(_Request, _From, State) -> handle_call(_Request, _From, State) ->
Reply = ok, {reply, Reply, State}. Reply = ok, {reply, Reply, State}.

View File

@ -40,6 +40,7 @@
-include("logger.hrl"). -include("logger.hrl").
-define(SM_KEY, <<"ejabberd:sm">>). -define(SM_KEY, <<"ejabberd:sm">>).
-define(MIN_REDIS_VERSION, <<"3.2.0">>).
-record(state, {}). -record(state, {}).
%%%=================================================================== %%%===================================================================
@ -142,8 +143,10 @@ get_sessions(LUser, LServer) ->
%%%=================================================================== %%%===================================================================
init([]) -> init([]) ->
ejabberd_redis:subscribe([?SM_KEY]), ejabberd_redis:subscribe([?SM_KEY]),
clean_table(), case clean_table() of
{ok, #state{}}. ok -> {ok, #state{}};
{error, Why} -> {stop, Why}
end.
handle_call(_Request, _From, State) -> handle_call(_Request, _From, State) ->
Reply = ok, Reply = ok,
@ -240,7 +243,20 @@ clean_node_sessions(Node, Host, SHA) ->
load_script() -> load_script() ->
case misc:read_lua("redis_sm.lua") of case misc:read_lua("redis_sm.lua") of
{ok, Data} -> {ok, Data} ->
ejabberd_redis:script_load(Data); case ejabberd_redis:info(server) of
{ok, Info} ->
case proplists:get_value(redis_version, Info) of
V when V >= ?MIN_REDIS_VERSION ->
ejabberd_redis:script_load(Data);
V ->
?CRITICAL_MSG("Unsupported Redis version: ~s. "
"The version must be ~s or above",
[V, ?MIN_REDIS_VERSION]),
{error, unsupported_redis_version}
end;
{error, _} = Err ->
Err
end;
{error, _} = Err -> {error, _} = Err ->
Err Err
end. end.

View File

@ -55,7 +55,7 @@ init() ->
ok; ok;
Err -> Err ->
?ERROR_MSG("failed to clean 'sm' table: ~p", [Err]), ?ERROR_MSG("failed to clean 'sm' table: ~p", [Err]),
Err {error, db_failure}
end; end;
(_, Err) -> (_, Err) ->
Err Err