]> granicus.if.org Git - ejabberd/commitdiff
Add Redis as router RAM backend
authorEvgeniy Khramtsov <ekhramtsov@process-one.net>
Tue, 28 Mar 2017 16:34:04 +0000 (19:34 +0300)
committerEvgeniy Khramtsov <ekhramtsov@process-one.net>
Tue, 28 Mar 2017 16:34:04 +0000 (19:34 +0300)
src/ejabberd_redis.erl
src/ejabberd_router.erl
src/ejabberd_router_mnesia.erl
src/ejabberd_router_redis.erl [new file with mode: 0644]
src/ejabberd_router_sql.erl

index f349baac534fcad972cd8e002bf4771f38b84a9d..1d8f32c28e42710733198f5613e86d0984bdd435 100644 (file)
@@ -72,8 +72,8 @@ config_reloaded() ->
 init([]) ->
     ejabberd_hooks:add(config_reloaded, ?MODULE, config_reloaded, 20),
     process_flag(trap_exit, true),
-    self() ! connect,
-    {ok, #state{}}.
+    {_, State} = handle_info(connect, #state{}),
+    {ok, State}.
 
 handle_call(_Request, _From, State) ->
     Reply = ok,
index dca3ac25d6d611c31d192e3ceacf09070c98e545..7591822e3b00784a3d94e241852edc8ba16d5a58 100644 (file)
@@ -49,6 +49,7 @@
         get_all_routes/0,
         is_my_route/1,
         is_my_host/1,
+        find_routes/0,
         get_backend/0]).
 
 -export([start_link/0]).
@@ -70,6 +71,7 @@
                         undefined | pos_integer(), pid()) -> ok | {error, term()}.
 -callback unregister_route(binary(), undefined | pos_integer(), pid()) -> ok | {error, term()}.
 -callback find_routes(binary()) -> [#route{}].
+-callback find_routes() -> [#route{}].
 -callback host_of_route(binary()) -> {ok, binary()} | error.
 -callback is_my_route(binary()) -> boolean().
 -callback is_my_host(binary()) -> boolean().
@@ -202,6 +204,11 @@ get_all_routes() ->
     Mod = get_backend(),
     Mod:get_all_routes().
 
+-spec find_routes() -> [#route{}].
+find_routes() ->
+    Mod = get_backend(),
+    Mod:find_routes().
+
 -spec host_of_route(binary()) -> binary().
 host_of_route(Domain) ->
     case jid:nameprep(Domain) of
index 15cdf64c01af0e6b7fc6e38762f91780411a1548..e3b550a751231de59baa03e64a1d91eb7854e898 100644 (file)
@@ -25,7 +25,8 @@
 
 %% API
 -export([init/0, register_route/5, unregister_route/3, find_routes/1,
-        host_of_route/1, is_my_route/1, is_my_host/1, get_all_routes/0]).
+        host_of_route/1, is_my_route/1, is_my_host/1, get_all_routes/0,
+        find_routes/0]).
 %% gen_server callbacks
 -export([init/1, handle_cast/2, handle_call/3, handle_info/2,
         terminate/2, code_change/3, start_link/0]).
@@ -152,6 +153,9 @@ get_all_routes() ->
              when Domain /= ServerHost -> Domain
        end)).
 
+find_routes() ->
+    ets:tab2list(route).
+
 %%%===================================================================
 %%% gen_server callbacks
 %%%===================================================================
diff --git a/src/ejabberd_router_redis.erl b/src/ejabberd_router_redis.erl
new file mode 100644 (file)
index 0000000..be8d166
--- /dev/null
@@ -0,0 +1,154 @@
+%%%-------------------------------------------------------------------
+%%% @author Evgeny Khramtsov <ekhramtsov@process-one.net>
+%%% Created : 28 Mar 2017 by Evgeny Khramtsov <ekhramtsov@process-one.net>
+%%%
+%%%
+%%% ejabberd, Copyright (C) 2002-2017   ProcessOne
+%%%
+%%% This program is free software; you can redistribute it and/or
+%%% modify it under the terms of the GNU General Public License as
+%%% published by the Free Software Foundation; either version 2 of the
+%%% License, or (at your option) any later version.
+%%%
+%%% This program is distributed in the hope that it will be useful,
+%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
+%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+%%% General Public License for more details.
+%%%
+%%% You should have received a copy of the GNU General Public License along
+%%% with this program; if not, write to the Free Software Foundation, Inc.,
+%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+%%%
+%%%-------------------------------------------------------------------
+-module(ejabberd_router_redis).
+-behaviour(ejabberd_router).
+
+%% API
+-export([init/0, register_route/5, unregister_route/3, find_routes/1,
+        host_of_route/1, is_my_route/1, is_my_host/1, get_all_routes/0,
+        find_routes/0]).
+
+-include("ejabberd.hrl").
+-include("logger.hrl").
+-include("ejabberd_router.hrl").
+
+-define(ROUTES_KEY, "ejabberd:routes").
+
+%%%===================================================================
+%%% API
+%%%===================================================================
+init() ->
+    clean_table().
+
+register_route(Domain, ServerHost, LocalHint, _, Pid) ->
+    DomKey = domain_key(Domain),
+    PidKey = term_to_binary(Pid),
+    T = term_to_binary({ServerHost, LocalHint}),
+    case ejabberd_redis:qp([["HSET", DomKey, PidKey, T],
+                           ["SADD", ?ROUTES_KEY, Domain]]) of
+       [{ok, _}, {ok, _}] ->
+           ok;
+       Err ->
+           ?ERROR_MSG("failed to register route in redis: ~p", [Err]),
+           Err
+    end.
+
+unregister_route(Domain, _, Pid) ->
+    DomKey = domain_key(Domain),
+    PidKey = term_to_binary(Pid),
+    try
+       {ok, _} = ejabberd_redis:q(["HDEL", DomKey, PidKey]),
+       {ok, Num} = ejabberd_redis:q(["HLEN", DomKey]),
+       case binary_to_integer(Num) of
+           0 ->
+               {ok, _} = ejabberd_redis:q(["SREM", ?ROUTES_KEY, Domain]),
+               ok;
+           _ ->
+               ok
+       end
+    catch _:{badmatch, Err} ->
+           ?ERROR_MSG("failed to unregister route in redis: ~p", [Err]),
+           Err
+    end.
+
+find_routes(Domain) ->
+    DomKey = domain_key(Domain),
+    case ejabberd_redis:q(["HGETALL", DomKey]) of
+       {ok, Vals} ->
+           decode_routes(Domain, Vals);
+       Err ->
+           ?ERROR_MSG("failed to find routes in redis: ~p", [Err]),
+           []
+    end.
+
+host_of_route(Domain) ->
+    DomKey = domain_key(Domain),
+    case ejabberd_redis:q(["HGETALL", DomKey]) of
+       {ok, [_, Data|_]} ->
+           {ServerHost, _} = binary_to_term(Data),
+           {ok, ServerHost};
+       {ok, []} ->
+           error;
+       Err ->
+           ?ERROR_MSG("failed to get host of route in redis: ~p", [Err]),
+           error
+    end.
+
+is_my_route(Domain) ->
+    case ejabberd_redis:q(["SISMEMBER", ?ROUTES_KEY, Domain]) of
+       {ok, <<"1">>} -> true;
+       {ok, _} -> false;
+       Err ->
+           ?ERROR_MSG("failed to check route in redis: ~p", [Err]),
+           false
+    end.
+
+is_my_host(Domain) ->
+    {ok, Domain} == host_of_route(Domain).
+
+get_all_routes() ->
+    case ejabberd_redis:q(["SMEMBERS", ?ROUTES_KEY]) of
+       {ok, Routes} ->
+           Routes;
+       Err ->
+           ?ERROR_MSG("failed to fetch routes from redis: ~p", [Err]),
+           []
+    end.
+
+find_routes() ->
+    lists:flatmap(
+      fun(Domain) ->
+             DomKey = domain_key(Domain),
+             case ejabberd_redis:q(["HGETALL", DomKey]) of
+                 {ok, Vals} ->
+                     decode_routes(Domain, Vals);
+                 Err ->
+                     ?ERROR_MSG("failed to fetch routes from redis: ~p",
+                                [Err]),
+                     []
+             end
+      end, get_all_routes()).
+
+%%%===================================================================
+%%% Internal functions
+%%%===================================================================
+clean_table() ->
+    lists:foreach(
+      fun(#route{domain = Domain, pid = Pid}) when node(Pid) == node() ->
+             unregister_route(Domain, undefined, Pid);
+        (_) ->
+             ok
+      end, find_routes()).
+
+domain_key(Domain) ->
+    <<"ejabberd:route:", Domain/binary>>.
+
+decode_routes(Domain, [Pid, Data|Vals]) ->
+    {ServerHost, LocalHint} = binary_to_term(Data),
+    [#route{domain = Domain,
+           pid = binary_to_term(Pid),
+           server_host = ServerHost,
+           local_hint = LocalHint}|
+     decode_routes(Domain, Vals)];
+decode_routes(_, []) ->
+    [].
index 1daa92fb198f9b2bc193a0c2f8f526dfda9d930c..e64b6afeb4f62288612606401d3ff1eefda870aa 100644 (file)
@@ -27,7 +27,8 @@
 
 %% API
 -export([init/0, register_route/5, unregister_route/3, find_routes/1,
-        host_of_route/1, is_my_route/1, is_my_host/1, get_all_routes/0]).
+        host_of_route/1, is_my_route/1, is_my_host/1, get_all_routes/0,
+        find_routes/0]).
 
 -include("ejabberd.hrl").
 -include("logger.hrl").
@@ -124,6 +125,21 @@ get_all_routes() ->
            []
     end.
 
+find_routes() ->
+    case ejabberd_sql:sql_query(
+          ?MYNAME,
+          ?SQL("select @(domain)s, @(server_host)s, @(node)s, @(pid)s, "
+               "@(local_hint)s from route")) of
+       {selected, Rows} ->
+           lists:flatmap(
+             fun({Domain, ServerHost, Node, Pid, LocalHint}) ->
+                     row_to_route(Domain, {ServerHost, Node, Pid, LocalHint})
+             end, Rows);
+       Err ->
+           ?ERROR_MSG("failed to select from 'route' table: ~p", [Err]),
+           []
+    end.
+
 %%%===================================================================
 %%% Internal functions
 %%%===================================================================