aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEvgeniy Khramtsov <ekhramtsov@process-one.net>2017-03-28 19:34:04 +0300
committerEvgeniy Khramtsov <ekhramtsov@process-one.net>2017-03-28 19:34:04 +0300
commitcba6e1b3abbb76addfafedabcdecae9a447549b2 (patch)
tree8f2b8b78da7f2179170370ef77f769eeeae4b9a4
parentMix needs include path to p1_utils (diff)
Add Redis as router RAM backend
-rw-r--r--src/ejabberd_redis.erl4
-rw-r--r--src/ejabberd_router.erl7
-rw-r--r--src/ejabberd_router_mnesia.erl6
-rw-r--r--src/ejabberd_router_redis.erl154
-rw-r--r--src/ejabberd_router_sql.erl18
5 files changed, 185 insertions, 4 deletions
diff --git a/src/ejabberd_redis.erl b/src/ejabberd_redis.erl
index f349baac5..1d8f32c28 100644
--- a/src/ejabberd_redis.erl
+++ b/src/ejabberd_redis.erl
@@ -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,
diff --git a/src/ejabberd_router.erl b/src/ejabberd_router.erl
index dca3ac25d..7591822e3 100644
--- a/src/ejabberd_router.erl
+++ b/src/ejabberd_router.erl
@@ -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
diff --git a/src/ejabberd_router_mnesia.erl b/src/ejabberd_router_mnesia.erl
index 15cdf64c0..e3b550a75 100644
--- a/src/ejabberd_router_mnesia.erl
+++ b/src/ejabberd_router_mnesia.erl
@@ -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
index 000000000..be8d166b9
--- /dev/null
+++ b/src/ejabberd_router_redis.erl
@@ -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(_, []) ->
+ [].
diff --git a/src/ejabberd_router_sql.erl b/src/ejabberd_router_sql.erl
index 1daa92fb1..e64b6afeb 100644
--- a/src/ejabberd_router_sql.erl
+++ b/src/ejabberd_router_sql.erl
@@ -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
%%%===================================================================