* 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> 2007-01-11 Mickael Remond <mickael.remond@process-one.net>
* doc/guide.tex: Latex / Hevea related improvements for documentation * 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); add_option(cluster_nodes, Nodes, State);
{domain_balancing, Domain, Balancing} -> {domain_balancing, Domain, Balancing} ->
add_option({domain_balancing, Domain}, Balancing, State); add_option({domain_balancing, Domain}, Balancing, State);
{loglevel, Loglevel} -> {domain_balancing_component_number, Domain, N} ->
ejabberd_loglevel:set(Loglevel), add_option({domain_balancing_component_number, Domain}, N, State);
State; {loglevel, Loglevel} ->
ejabberd_loglevel:set(Loglevel),
State;
{Opt, Val} -> {Opt, Val} ->
lists:foldl(fun(Host, S) -> process_host_term(Term, Host, S) end, lists:foldl(fun(Host, S) -> process_host_term(Term, Host, S) end,
State, State#state.hosts) State, State#state.hosts)

View File

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

View File

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

View File

@ -677,7 +677,7 @@ handle_info(_Info, StateName, StateData) ->
%% Returns: any %% Returns: any
%%---------------------------------------------------------------------- %%----------------------------------------------------------------------
terminate(_Reason, _StateName, StateData) -> 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), StateData#state.server_host),
ok. ok.