* src/mod_muc/mod_muc.erl: Now mod_muc can be distributed on

several nodes
* src/mod_muc/mod_muc_room.erl: Likewise

* src/ejabberd_router.erl: Added bare_source and bare_destination
service balancing options and domain_balancing_component_number
option for specifying the number of connected components for the
domain
* src/ejabberd_config.erl: Likewise

SVN Revision: 706
This commit is contained in:
Alexey Shchepin 2007-01-19 04:46:44 +00:00
parent 7fb38dd38a
commit efab31848e
5 changed files with 205 additions and 90 deletions

View File

@ -1,3 +1,15 @@
2007-01-19 Alexey Shchepin <alexey@sevcom.net>
* src/mod_muc/mod_muc.erl: Now mod_muc can be distributed on
several nodes
* src/mod_muc/mod_muc_room.erl: Likewise
* src/ejabberd_router.erl: Added bare_source and bare_destination
service balancing options and domain_balancing_component_number
option for specifying the number of connected components for the
domain
* src/ejabberd_config.erl: Likewise
2007-01-11 Mickael Remond <mickael.remond@process-one.net>
* doc/guide.tex: Latex / Hevea related improvements for documentation

View File

@ -121,9 +121,11 @@ process_term(Term, State) ->
add_option(cluster_nodes, Nodes, State);
{domain_balancing, Domain, Balancing} ->
add_option({domain_balancing, Domain}, Balancing, State);
{loglevel, Loglevel} ->
ejabberd_loglevel:set(Loglevel),
State;
{domain_balancing_component_number, Domain, N} ->
add_option({domain_balancing_component_number, Domain}, N, State);
{loglevel, Loglevel} ->
ejabberd_loglevel:set(Loglevel),
State;
{Opt, Val} ->
lists:foldl(fun(Host, S) -> process_host_term(Term, Host, S) end,
State, State#state.hosts)

View File

@ -56,30 +56,54 @@ route(From, To, Packet) ->
end.
register_route(Domain) ->
case jlib:nameprep(Domain) of
error ->
[] = {invalid_domain, Domain};
LDomain ->
Pid = self(),
F = fun() ->
mnesia:write(#route{domain = LDomain,
pid = Pid})
end,
mnesia:transaction(F)
end.
register_route(Domain, undefined).
register_route(Domain, LocalHint) ->
case jlib:nameprep(Domain) of
error ->
[] = {invalid_domain, Domain};
erlang:error({invalid_domain, Domain});
LDomain ->
Pid = self(),
F = fun() ->
mnesia:write(#route{domain = LDomain,
pid = Pid,
local_hint = LocalHint})
end,
mnesia:transaction(F)
case get_component_number(LDomain) of
undefined ->
F = fun() ->
mnesia:write(#route{domain = LDomain,
pid = Pid,
local_hint = LocalHint})
end,
mnesia:transaction(F);
N ->
F = fun() ->
case mnesia:read({route, LDomain}) of
[] ->
mnesia:write(
#route{domain = LDomain,
pid = Pid,
local_hint = 1}),
lists:foreach(
fun(I) ->
mnesia:write(
#route{domain = LDomain,
pid = undefined,
local_hint = I})
end, lists:seq(2, N));
Rs ->
lists:any(
fun(#route{pid = undefined,
local_hint = I} = R) ->
mnesia:write(
#route{domain = LDomain,
pid = Pid,
local_hint = I}),
mnesia:delete_object(R),
true;
(_) ->
false
end, Rs)
end
end,
mnesia:transaction(F)
end
end.
register_routes(Domains) ->
@ -90,14 +114,40 @@ register_routes(Domains) ->
unregister_route(Domain) ->
case jlib:nameprep(Domain) of
error ->
[] = {invalid_domain, Domain};
erlang:error({invalid_domain, Domain});
LDomain ->
Pid = self(),
F = fun() ->
mnesia:delete_object(#route{domain = LDomain,
pid = Pid})
end,
mnesia:transaction(F)
case get_component_number(LDomain) of
undefined ->
F = fun() ->
case mnesia:match(#route{domain = LDomain,
pid = Pid,
_ = '_'}) of
[R] ->
mnesia:delete_object(R);
_ ->
ok
end
end,
mnesia:transaction(F);
_ ->
F = fun() ->
case mnesia:match(#route{domain = LDomain,
pid = Pid,
_ = '_'}) of
[R] ->
I = R#route.local_hint,
mnesia:write(
#route{domain = LDomain,
pid = undefined,
local_hint = I}),
mnesia:delete_object(R);
_ ->
ok
end
end,
mnesia:transaction(F)
end
end.
unregister_routes(Domains) ->
@ -188,9 +238,21 @@ handle_info({'DOWN', _Ref, _Type, Pid, _Info}, State) ->
[{#route{pid = Pid, _ = '_'},
[],
['$_']}]),
lists:foreach(fun(E) ->
mnesia:delete_object(E)
end, Es)
lists:foreach(
fun(E) ->
if
is_integer(E#route.local_hint) ->
LDomain = E#route.domain,
I = E#route.local_hint,
mnesia:write(
#route{domain = LDomain,
pid = undefined,
local_hint = I}),
mnesia:delete_object(E);
true ->
mnesia:delete_object(E)
end
end, Es)
end,
mnesia:transaction(F),
{noreply, State};
@ -237,37 +299,56 @@ do_route(OrigFrom, OrigTo, OrigPacket) ->
_ ->
Pid ! {route, From, To, Packet}
end;
is_pid(Pid) ->
Pid ! {route, From, To, Packet};
true ->
Pid ! {route, From, To, Packet}
drop
end;
Rs ->
case [R || R <- Rs, node(R#route.pid) == node()] of
[] ->
Value = case ejabberd_config:get_local_option(
{domain_balancing, LDstDomain}) of
source -> jlib:jid_tolower(From);
destination -> jlib:jid_tolower(To);
random -> now();
undefined -> now()
end,
R = lists:nth(erlang:phash(Value, length(Rs)), Rs),
Value = case ejabberd_config:get_local_option(
{domain_balancing, LDstDomain}) of
undefined -> now();
random -> now();
source -> jlib:jid_tolower(From);
destination -> jlib:jid_tolower(To);
bare_source ->
jlib:jid_remove_resource(
jlib:jid_tolower(From));
bare_destination ->
jlib:jid_remove_resource(
jlib:jid_tolower(To))
end,
case get_component_number(LDstDomain) of
undefined ->
case [R || R <- Rs, node(R#route.pid) == node()] of
[] ->
R = lists:nth(erlang:phash(Value, length(Rs)), Rs),
Pid = R#route.pid,
if
is_pid(Pid) ->
Pid ! {route, From, To, Packet};
true ->
drop
end;
LRs ->
R = lists:nth(erlang:phash(Value, length(LRs)), LRs),
Pid = R#route.pid,
case R#route.local_hint of
{apply, Module, Function} ->
Module:Function(From, To, Packet);
_ ->
Pid ! {route, From, To, Packet}
end
end;
_ ->
SRs = lists:ukeysort(#route.local_hint, Rs),
R = lists:nth(erlang:phash(Value, length(SRs)), SRs),
Pid = R#route.pid,
Pid ! {route, From, To, Packet};
LRs ->
Value = case ejabberd_config:get_local_option(
{domain_balancing, LDstDomain}) of
source -> jlib:jid_tolower(From);
destination -> jlib:jid_tolower(To);
random -> now();
undefined -> now()
end,
R = lists:nth(erlang:phash(Value, length(LRs)), LRs),
Pid = R#route.pid,
case R#route.local_hint of
{apply, Module, Function} ->
Module:Function(From, To, Packet);
_ ->
Pid ! {route, From, To, Packet}
if
is_pid(Pid) ->
Pid ! {route, From, To, Packet};
true ->
drop
end
end
end;
@ -275,7 +356,15 @@ do_route(OrigFrom, OrigTo, OrigPacket) ->
ok
end.
get_component_number(LDomain) ->
case ejabberd_config:get_local_option(
{domain_balancing_component_number, LDomain}) of
N when is_integer(N),
N > 1 ->
N;
_ ->
undefined
end.
update_tables() ->
case catch mnesia:table_info(route, attributes) of

View File

@ -17,7 +17,7 @@
-export([start_link/2,
start/2,
stop/1,
room_destroyed/3,
room_destroyed/4,
store_room/3,
restore_room/2,
forget_room/2,
@ -69,9 +69,9 @@ stop(Host) ->
gen_server:call(Proc, stop),
supervisor:delete_child(ejabberd_sup, Proc).
room_destroyed(Host, Room, ServerHost) ->
room_destroyed(Host, Room, Pid, ServerHost) ->
gen_mod:get_module_proc(ServerHost, ?PROCNAME) !
{room_destroyed, {Room, Host}},
{room_destroyed, {Room, Host}, Pid},
ok.
store_room(Host, Name, Opts) ->
@ -142,6 +142,10 @@ init([Host, Opts]) ->
mnesia:create_table(muc_registered,
[{disc_copies, [node()]},
{attributes, record_info(fields, muc_registered)}]),
mnesia:create_table(muc_online_room,
[{ram_copies, [node()]},
{attributes, record_info(fields, muc_online_room)}]),
mnesia:add_table_copy(muc_online_room, node(), ram_copies),
MyHost = gen_mod:get_opt(host, Opts, "conference." ++ Host),
update_tables(MyHost),
mnesia:add_table_index(muc_registered, nick),
@ -149,9 +153,6 @@ init([Host, Opts]) ->
AccessCreate = gen_mod:get_opt(access_create, Opts, all),
AccessAdmin = gen_mod:get_opt(access_admin, Opts, none),
HistorySize = gen_mod:get_opt(history_size, Opts, 20),
catch ets:new(muc_online_room, [named_table,
public,
{keypos, #muc_online_room.name_host}]),
ejabberd_router:register_route(MyHost),
load_permanent_rooms(MyHost, Host, {Access, AccessCreate, AccessAdmin},
HistorySize),
@ -199,8 +200,12 @@ handle_info({route, From, To, Packet},
ok
end,
{noreply, State};
handle_info({room_destroyed, RoomHost}, State) ->
ets:delete(muc_online_room, RoomHost),
handle_info({room_destroyed, RoomHost, Pid}, State) ->
F = fun() ->
mnesia:delete_object(#muc_online_room{name_host = RoomHost,
pid = Pid})
end,
mnesia:transaction(F),
{noreply, State};
handle_info(_Info, State) ->
{noreply, State}.
@ -373,7 +378,7 @@ do_route1(Host, ServerHost, Access, HistorySize, From, To, Packet) ->
end
end;
_ ->
case ets:lookup(muc_online_room, {Room, Host}) of
case mnesia:dirty_read(muc_online_room, {Room, Host}) of
[] ->
Type = xml:get_attr_s("type", Attrs),
case {Name, Type} of
@ -385,10 +390,7 @@ do_route1(Host, ServerHost, Access, HistorySize, From, To, Packet) ->
Host, ServerHost, Access,
Room, HistorySize, From,
Nick),
ets:insert(
muc_online_room,
#muc_online_room{name_host = {Room, Host},
pid = Pid}),
register_room(Host, Room, Pid),
mod_muc_room:route(Pid, From, Nick, Packet),
ok;
_ ->
@ -425,22 +427,32 @@ load_permanent_rooms(Host, ServerHost, Access, HistorySize) ->
?ERROR_MSG("~p", [Reason]),
ok;
Rs ->
lists:foreach(fun(R) ->
{Room, Host} = R#muc_room.name_host,
{ok, Pid} = mod_muc_room:start(
Host,
ServerHost,
Access,
Room,
HistorySize,
R#muc_room.opts),
ets:insert(
muc_online_room,
#muc_online_room{name_host = {Room, Host},
pid = Pid})
end, Rs)
lists:foreach(
fun(R) ->
{Room, Host} = R#muc_room.name_host,
case mnesia:dirty_read(muc_online_room, {Room, Host}) of
[] ->
{ok, Pid} = mod_muc_room:start(
Host,
ServerHost,
Access,
Room,
HistorySize,
R#muc_room.opts),
register_room(Host, Room, Pid);
_ ->
ok
end
end, Rs)
end.
register_room(Host, Room, Pid) ->
F = fun() ->
mnesia:write(#muc_online_room{name_host = {Room, Host},
pid = Pid})
end,
mnesia:transaction(F).
iq_disco_info() ->
[{xmlelement, "identity",
@ -598,10 +610,10 @@ broadcast_service_message(Host, Msg) ->
end, get_vh_rooms(Host)).
get_vh_rooms(Host) ->
ets:select(muc_online_room,
[{#muc_online_room{name_host = '$1', _ = '_'},
[{'==', {element, 2, '$1'}, Host}],
['$_']}]).
mnesia:dirty_select(muc_online_room,
[{#muc_online_room{name_host = '$1', _ = '_'},
[{'==', {element, 2, '$1'}, Host}],
['$_']}]).

View File

@ -677,7 +677,7 @@ handle_info(_Info, StateName, StateData) ->
%% Returns: any
%%----------------------------------------------------------------------
terminate(_Reason, _StateName, StateData) ->
mod_muc:room_destroyed(StateData#state.host, StateData#state.room,
mod_muc:room_destroyed(StateData#state.host, StateData#state.room, self(),
StateData#state.server_host),
ok.