mirror of
https://github.com/processone/ejabberd.git
synced 2024-12-24 17:29:28 +01:00
New migration procedure
This commit is contained in:
parent
33d4126290
commit
4a2f62062e
@ -194,7 +194,7 @@ stop(FsmRef) ->
|
|||||||
?GEN_FSM:send_event(FsmRef, closed).
|
?GEN_FSM:send_event(FsmRef, closed).
|
||||||
|
|
||||||
migrate(FsmRef, Node, After) ->
|
migrate(FsmRef, Node, After) ->
|
||||||
?GEN_FSM:send_all_state_event(FsmRef, {migrate, Node, After}).
|
erlang:send_after(After, FsmRef, {migrate, Node}).
|
||||||
|
|
||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
%%% Callback functions from gen_fsm
|
%%% Callback functions from gen_fsm
|
||||||
@ -282,6 +282,7 @@ init([StateName, StateData, _FSMLimitOpts]) ->
|
|||||||
El ->
|
El ->
|
||||||
get_priority_from_presence(El)
|
get_priority_from_presence(El)
|
||||||
end,
|
end,
|
||||||
|
ejabberd_sm:drop_session(StateData#state.sid),
|
||||||
ejabberd_sm:open_session(
|
ejabberd_sm:open_session(
|
||||||
SID,
|
SID,
|
||||||
StateData#state.user,
|
StateData#state.user,
|
||||||
@ -289,6 +290,7 @@ init([StateName, StateData, _FSMLimitOpts]) ->
|
|||||||
StateData#state.resource,
|
StateData#state.resource,
|
||||||
Priority,
|
Priority,
|
||||||
Info),
|
Info),
|
||||||
|
%%ejabberd_sm:drop_session(StateData#state.sid),
|
||||||
NewStateData = StateData#state{sid = SID, socket_monitor = MRef},
|
NewStateData = StateData#state{sid = SID, socket_monitor = MRef},
|
||||||
StateData2 = change_reception(NewStateData, true),
|
StateData2 = change_reception(NewStateData, true),
|
||||||
StateData3 = start_keepalive_timer(StateData2),
|
StateData3 = start_keepalive_timer(StateData2),
|
||||||
@ -1232,9 +1234,6 @@ session_established2(El, StateData) ->
|
|||||||
%% {next_state, NextStateName, NextStateData, Timeout} |
|
%% {next_state, NextStateName, NextStateData, Timeout} |
|
||||||
%% {stop, Reason, NewStateData}
|
%% {stop, Reason, NewStateData}
|
||||||
%%----------------------------------------------------------------------
|
%%----------------------------------------------------------------------
|
||||||
handle_event({migrate, Node, After}, StateName, StateData) when Node /= node() ->
|
|
||||||
fsm_migrate(StateName, StateData, Node, After * 2);
|
|
||||||
|
|
||||||
handle_event({add_rosteritem, IJID, ISubscription}, StateName, StateData) ->
|
handle_event({add_rosteritem, IJID, ISubscription}, StateName, StateData) ->
|
||||||
NewStateData = roster_change(IJID, ISubscription, StateData),
|
NewStateData = roster_change(IJID, ISubscription, StateData),
|
||||||
fsm_next_state(StateName, NewStateData);
|
fsm_next_state(StateName, NewStateData);
|
||||||
@ -1624,6 +1623,12 @@ handle_info({force_update_presence, LUser}, StateName,
|
|||||||
StateData
|
StateData
|
||||||
end,
|
end,
|
||||||
{next_state, StateName, NewStateData};
|
{next_state, StateName, NewStateData};
|
||||||
|
handle_info({migrate, Node}, StateName, StateData) ->
|
||||||
|
if Node /= node() ->
|
||||||
|
fsm_migrate(StateName, StateData, Node, 0);
|
||||||
|
true ->
|
||||||
|
fsm_next_state(StateName, StateData)
|
||||||
|
end;
|
||||||
handle_info({broadcast, Type, From, Packet}, StateName, StateData) ->
|
handle_info({broadcast, Type, From, Packet}, StateName, StateData) ->
|
||||||
Recipients = ejabberd_hooks:run_fold(
|
Recipients = ejabberd_hooks:run_fold(
|
||||||
c2s_broadcast_recipients, StateData#state.server,
|
c2s_broadcast_recipients, StateData#state.server,
|
||||||
@ -2535,13 +2540,6 @@ maybe_migrate(StateName, StateData) ->
|
|||||||
StateData2 = change_reception(PackedStateData, true),
|
StateData2 = change_reception(PackedStateData, true),
|
||||||
StateData3 = start_keepalive_timer(StateData2),
|
StateData3 = start_keepalive_timer(StateData2),
|
||||||
erlang:garbage_collect(),
|
erlang:garbage_collect(),
|
||||||
case ejabberd_cluster:get_node_new({U, S}) of
|
|
||||||
Node ->
|
|
||||||
ok;
|
|
||||||
NewNode ->
|
|
||||||
After = ejabberd_cluster:rehash_timeout(),
|
|
||||||
migrate(self(), NewNode, After)
|
|
||||||
end,
|
|
||||||
fsm_next_state(StateName, StateData3);
|
fsm_next_state(StateName, StateData3);
|
||||||
Node ->
|
Node ->
|
||||||
fsm_migrate(StateName, PackedStateData, Node, 0)
|
fsm_migrate(StateName, PackedStateData, Node, 0)
|
||||||
|
@ -22,7 +22,11 @@
|
|||||||
-define(HASHTBL, nodes_hash).
|
-define(HASHTBL, nodes_hash).
|
||||||
-define(HASHTBL_NEW, nodes_hash_new).
|
-define(HASHTBL_NEW, nodes_hash_new).
|
||||||
-define(POINTS, 64).
|
-define(POINTS, 64).
|
||||||
-define(REHASH_TIMEOUT, 30000).
|
-define(REHASH_TIMEOUT, timer:seconds(30)).
|
||||||
|
-define(MIGRATE_TIMEOUT, timer:minutes(2)).
|
||||||
|
%%-define(REHASH_TIMEOUT, timer:seconds(10)).
|
||||||
|
%%-define(MIGRATE_TIMEOUT, timer:seconds(5)).
|
||||||
|
-define(LOCK, {migrate, node()}).
|
||||||
|
|
||||||
-record(state, {}).
|
-record(state, {}).
|
||||||
|
|
||||||
@ -80,13 +84,16 @@ shutdown() ->
|
|||||||
%% gen_server callbacks
|
%% gen_server callbacks
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
init([]) ->
|
init([]) ->
|
||||||
|
{A, B, C} = now(),
|
||||||
|
random:seed(A, B, C),
|
||||||
net_kernel:monitor_nodes(true, [{node_type, visible}]),
|
net_kernel:monitor_nodes(true, [{node_type, visible}]),
|
||||||
ets:new(?HASHTBL, [named_table, public, ordered_set]),
|
ets:new(?HASHTBL, [named_table, public, ordered_set]),
|
||||||
ets:new(?HASHTBL_NEW, [named_table, public, ordered_set]),
|
ets:new(?HASHTBL_NEW, [named_table, public, ordered_set]),
|
||||||
register_node(),
|
register_node(),
|
||||||
AllNodes = mnesia:system_info(running_db_nodes),
|
pg2:create(?MODULE),
|
||||||
|
AllNodes = cluster_group(),
|
||||||
OtherNodes = case AllNodes of
|
OtherNodes = case AllNodes of
|
||||||
[_] ->
|
[_MyNode] ->
|
||||||
AllNodes;
|
AllNodes;
|
||||||
_ ->
|
_ ->
|
||||||
AllNodes -- [node()]
|
AllNodes -- [node()]
|
||||||
@ -96,35 +103,55 @@ init([]) ->
|
|||||||
{ok, #state{}}.
|
{ok, #state{}}.
|
||||||
|
|
||||||
handle_call(announce, _From, State) ->
|
handle_call(announce, _From, State) ->
|
||||||
case mnesia:system_info(running_db_nodes) of
|
case global:set_lock(?LOCK, cluster_group(), 0) of
|
||||||
|
false ->
|
||||||
|
?INFO_MSG("Another node is recently attached to "
|
||||||
|
"the cluster and is being rebalanced. "
|
||||||
|
"Waiting for the rebalancing to be completed "
|
||||||
|
"before starting this node. "
|
||||||
|
"This may take serveral minutes. "
|
||||||
|
"Please, be patient.", []),
|
||||||
|
global:set_lock(?LOCK, cluster_group(), infinity);
|
||||||
|
true ->
|
||||||
|
ok
|
||||||
|
end,
|
||||||
|
case cluster_group() of
|
||||||
[_MyNode] ->
|
[_MyNode] ->
|
||||||
ok;
|
join_cluster_group(),
|
||||||
|
global:del_lock(?LOCK);
|
||||||
Nodes ->
|
Nodes ->
|
||||||
OtherNodes = Nodes -- [node()],
|
OtherNodes = Nodes -- [node()],
|
||||||
lists:foreach(
|
|
||||||
fun(Node) ->
|
|
||||||
{?MODULE, Node} ! {node_ready, node()}
|
|
||||||
end, OtherNodes),
|
|
||||||
?INFO_MSG("waiting for migration from nodes: ~w",
|
?INFO_MSG("waiting for migration from nodes: ~w",
|
||||||
[OtherNodes]),
|
[OtherNodes]),
|
||||||
timer:sleep(?REHASH_TIMEOUT),
|
{_Res, BadNodes} = gen_server:multi_call(
|
||||||
append_node(?HASHTBL, node())
|
OtherNodes, ?MODULE,
|
||||||
|
{node_ready, node()}, ?REHASH_TIMEOUT),
|
||||||
|
append_node(?HASHTBL, node()),
|
||||||
|
join_cluster_group(),
|
||||||
|
gen_server:abcast(OtherNodes -- BadNodes,
|
||||||
|
?MODULE, {node_ready, node()}),
|
||||||
|
erlang:send_after(?MIGRATE_TIMEOUT, self(), del_lock)
|
||||||
end,
|
end,
|
||||||
{reply, ok, State};
|
{reply, ok, State};
|
||||||
|
handle_call({node_ready, Node}, _From, State) ->
|
||||||
|
?INFO_MSG("node ~p is ready, preparing migration", [Node]),
|
||||||
|
append_node(?HASHTBL_NEW, Node),
|
||||||
|
ejabberd_hooks:run(node_up, [Node]),
|
||||||
|
{reply, ok, State};
|
||||||
handle_call(_Request, _From, State) ->
|
handle_call(_Request, _From, State) ->
|
||||||
Reply = ok,
|
Reply = ok,
|
||||||
{reply, Reply, State}.
|
{reply, Reply, State}.
|
||||||
|
|
||||||
|
handle_cast({node_ready, Node}, State) ->
|
||||||
|
?INFO_MSG("adding node ~p to hash and starting migration", [Node]),
|
||||||
|
append_node(?HASHTBL, Node),
|
||||||
|
ejabberd_hooks:run(node_hash_update, [?MIGRATE_TIMEOUT]),
|
||||||
|
{noreply, State};
|
||||||
handle_cast(_Msg, State) ->
|
handle_cast(_Msg, State) ->
|
||||||
{noreply, State}.
|
{noreply, State}.
|
||||||
|
|
||||||
handle_info({node_ready, Node}, State) ->
|
handle_info(del_lock, State) ->
|
||||||
?INFO_MSG("node ~p is ready, starting migration", [Node]),
|
global:del_lock(?LOCK),
|
||||||
append_node(?HASHTBL_NEW, Node),
|
|
||||||
ejabberd_hooks:run(node_hash_update, [?REHASH_TIMEOUT]),
|
|
||||||
timer:sleep(?REHASH_TIMEOUT),
|
|
||||||
?INFO_MSG("adding node ~p to hash", [Node]),
|
|
||||||
append_node(?HASHTBL, Node),
|
|
||||||
{noreply, State};
|
{noreply, State};
|
||||||
handle_info({node_down, Node}, State) ->
|
handle_info({node_down, Node}, State) ->
|
||||||
delete_node(?HASHTBL, Node),
|
delete_node(?HASHTBL, Node),
|
||||||
@ -187,3 +214,9 @@ get_node_by_hash(Tab, Hash) ->
|
|||||||
|
|
||||||
register_node() ->
|
register_node() ->
|
||||||
global:register_name(list_to_atom(node_id()), self()).
|
global:register_name(list_to_atom(node_id()), self()).
|
||||||
|
|
||||||
|
cluster_group() ->
|
||||||
|
[node() | [node(P) || P <- pg2:get_members(?MODULE)]].
|
||||||
|
|
||||||
|
join_cluster_group() ->
|
||||||
|
pg2:join(?MODULE, whereis(?MODULE)).
|
||||||
|
@ -203,9 +203,9 @@ migrate(After) ->
|
|||||||
['$$']}]),
|
['$$']}]),
|
||||||
lists:foreach(
|
lists:foreach(
|
||||||
fun([FromTo, Pid]) ->
|
fun([FromTo, Pid]) ->
|
||||||
case ejabberd_cluster:get_node_new(FromTo) of
|
case ejabberd_cluster:get_node(FromTo) of
|
||||||
Node when Node /= node() ->
|
Node when Node /= node() ->
|
||||||
ejabberd_s2s_out:stop_connection(Pid, After * 2);
|
ejabberd_s2s_out:stop_connection(Pid, After);
|
||||||
_ ->
|
_ ->
|
||||||
ok
|
ok
|
||||||
end
|
end
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
open_session/6,
|
open_session/6,
|
||||||
close_session/4,
|
close_session/4,
|
||||||
close_migrated_session/4,
|
close_migrated_session/4,
|
||||||
|
drop_session/1,
|
||||||
check_in_subscription/6,
|
check_in_subscription/6,
|
||||||
bounce_offline_message/3,
|
bounce_offline_message/3,
|
||||||
disconnect_removed_user/2,
|
disconnect_removed_user/2,
|
||||||
@ -60,6 +61,7 @@
|
|||||||
get_session_pid/3,
|
get_session_pid/3,
|
||||||
get_user_info/3,
|
get_user_info/3,
|
||||||
get_user_ip/3,
|
get_user_ip/3,
|
||||||
|
node_up/1,
|
||||||
migrate/1
|
migrate/1
|
||||||
]).
|
]).
|
||||||
|
|
||||||
@ -108,27 +110,37 @@ open_session(SID, User, Server, Resource, Priority, Info) ->
|
|||||||
[SID, JID, Info]).
|
[SID, JID, Info]).
|
||||||
|
|
||||||
close_session(SID, User, Server, Resource) ->
|
close_session(SID, User, Server, Resource) ->
|
||||||
Info = do_close_session(SID, User, Server, Resource),
|
Info = do_close_session(SID),
|
||||||
|
US = {jlib:nodeprep(User), jlib:nameprep(Server)},
|
||||||
|
case ejabberd_cluster:get_node_new(US) of
|
||||||
|
Node when Node /= node() ->
|
||||||
|
rpc:cast(Node, ?MODULE, drop_session, [SID]);
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
end,
|
||||||
JID = jlib:make_jid(User, Server, Resource),
|
JID = jlib:make_jid(User, Server, Resource),
|
||||||
ejabberd_hooks:run(sm_remove_connection_hook, JID#jid.lserver,
|
ejabberd_hooks:run(sm_remove_connection_hook, JID#jid.lserver,
|
||||||
[SID, JID, Info]).
|
[SID, JID, Info]).
|
||||||
|
|
||||||
close_migrated_session(SID, User, Server, Resource) ->
|
close_migrated_session(SID, User, Server, Resource) ->
|
||||||
Info = do_close_session(SID, User, Server, Resource),
|
Info = do_close_session(SID),
|
||||||
JID = jlib:make_jid(User, Server, Resource),
|
JID = jlib:make_jid(User, Server, Resource),
|
||||||
ejabberd_hooks:run(sm_remove_migrated_connection_hook, JID#jid.lserver,
|
ejabberd_hooks:run(sm_remove_migrated_connection_hook, JID#jid.lserver,
|
||||||
[SID, JID, Info]).
|
[SID, JID, Info]).
|
||||||
|
|
||||||
do_close_session(SID, User, Server, Resource) ->
|
do_close_session(SID) ->
|
||||||
Info = case mnesia:dirty_read({session, SID}) of
|
Info = case mnesia:dirty_read({session, SID}) of
|
||||||
[] -> [];
|
[] -> [];
|
||||||
[#session{info=I}] -> I
|
[#session{info=I}] -> I
|
||||||
end,
|
end,
|
||||||
|
drop_session(SID),
|
||||||
|
Info.
|
||||||
|
|
||||||
|
drop_session(SID) ->
|
||||||
F = fun() ->
|
F = fun() ->
|
||||||
mnesia:delete({session, SID})
|
mnesia:delete({session, SID})
|
||||||
end,
|
end,
|
||||||
mnesia:sync_dirty(F),
|
mnesia:sync_dirty(F).
|
||||||
Info.
|
|
||||||
|
|
||||||
check_in_subscription(Acc, User, Server, _JID, _Type, _Reason) ->
|
check_in_subscription(Acc, User, Server, _JID, _Type, _Reason) ->
|
||||||
case ejabberd_auth:is_user_exists(User, Server) of
|
case ejabberd_auth:is_user_exists(User, Server) of
|
||||||
@ -312,14 +324,33 @@ migrate(After) ->
|
|||||||
['$$']}]),
|
['$$']}]),
|
||||||
lists:foreach(
|
lists:foreach(
|
||||||
fun([US, Pid]) ->
|
fun([US, Pid]) ->
|
||||||
case ejabberd_cluster:get_node_new(US) of
|
case ejabberd_cluster:get_node(US) of
|
||||||
Node when Node /= node() ->
|
Node when Node /= node() ->
|
||||||
ejabberd_c2s:migrate(Pid, Node, After);
|
ejabberd_c2s:migrate(Pid, Node, random:uniform(After));
|
||||||
_ ->
|
_ ->
|
||||||
ok
|
ok
|
||||||
end
|
end
|
||||||
end, Ss).
|
end, Ss).
|
||||||
|
|
||||||
|
node_up(_Node) ->
|
||||||
|
copy_sessions(mnesia:dirty_first(session)).
|
||||||
|
|
||||||
|
copy_sessions('$end_of_table') ->
|
||||||
|
ok;
|
||||||
|
copy_sessions(Key) ->
|
||||||
|
case mnesia:dirty_read(session, Key) of
|
||||||
|
[#session{us = US} = Session] ->
|
||||||
|
case ejabberd_cluster:get_node_new(US) of
|
||||||
|
Node when node() /= Node ->
|
||||||
|
rpc:cast(Node, mnesia, dirty_write, [Session]);
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
end;
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
end,
|
||||||
|
copy_sessions(mnesia:dirty_next(session, Key)).
|
||||||
|
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
%% gen_server callbacks
|
%% gen_server callbacks
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
@ -341,6 +372,7 @@ init([]) ->
|
|||||||
mnesia:add_table_index(session, us),
|
mnesia:add_table_index(session, us),
|
||||||
mnesia:add_table_copy(session, node(), ram_copies),
|
mnesia:add_table_copy(session, node(), ram_copies),
|
||||||
ets:new(sm_iqtable, [named_table]),
|
ets:new(sm_iqtable, [named_table]),
|
||||||
|
ejabberd_hooks:add(node_up, ?MODULE, node_up, 100),
|
||||||
ejabberd_hooks:add(node_hash_update, ?MODULE, migrate, 100),
|
ejabberd_hooks:add(node_hash_update, ?MODULE, migrate, 100),
|
||||||
lists:foreach(
|
lists:foreach(
|
||||||
fun(Host) ->
|
fun(Host) ->
|
||||||
@ -418,6 +450,7 @@ handle_info(_Info, State) ->
|
|||||||
%% The return value is ignored.
|
%% The return value is ignored.
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
terminate(_Reason, _State) ->
|
terminate(_Reason, _State) ->
|
||||||
|
ejabberd_hooks:delete(node_up, ?MODULE, node_up, 100),
|
||||||
ejabberd_hooks:delete(node_hash_update, ?MODULE, migrate, 100),
|
ejabberd_hooks:delete(node_hash_update, ?MODULE, migrate, 100),
|
||||||
ejabberd_commands:unregister_commands(commands()),
|
ejabberd_commands:unregister_commands(commands()),
|
||||||
ok.
|
ok.
|
||||||
@ -433,7 +466,7 @@ code_change(_OldVsn, State, _Extra) ->
|
|||||||
%%% Internal functions
|
%%% Internal functions
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
set_session(SID, User, Server, Resource, Priority, Info) ->
|
set_session({_, Pid} = SID, User, Server, Resource, Priority, Info) ->
|
||||||
LUser = jlib:nodeprep(User),
|
LUser = jlib:nodeprep(User),
|
||||||
LServer = jlib:nameprep(Server),
|
LServer = jlib:nameprep(Server),
|
||||||
LResource = jlib:resourceprep(Resource),
|
LResource = jlib:resourceprep(Resource),
|
||||||
@ -446,7 +479,31 @@ set_session(SID, User, Server, Resource, Priority, Info) ->
|
|||||||
priority = Priority,
|
priority = Priority,
|
||||||
info = Info})
|
info = Info})
|
||||||
end,
|
end,
|
||||||
mnesia:sync_dirty(F).
|
mnesia:sync_dirty(F),
|
||||||
|
case ejabberd_cluster:get_node_new(US) of
|
||||||
|
Node when node() /= Node ->
|
||||||
|
%% New node has just been added. But we may miss session records
|
||||||
|
%% copy procedure, so we copy the session record manually just
|
||||||
|
%% to make sure
|
||||||
|
rpc:cast(Node, mnesia, dirty_write,
|
||||||
|
[#session{sid = SID,
|
||||||
|
usr = USR,
|
||||||
|
us = US,
|
||||||
|
priority = Priority,
|
||||||
|
info = Info}]),
|
||||||
|
case ejabberd_cluster:get_node(US) of
|
||||||
|
Node when node() /= Node ->
|
||||||
|
%% Migration to new node has completed, and seems like
|
||||||
|
%% we missed it, so we migrate the session pid manually.
|
||||||
|
%% It is not a problem if we have already got migration
|
||||||
|
%% notification: dups are just ignored by the c2s pid.
|
||||||
|
ejabberd_c2s:migrate(Pid, Node, 0);
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
end;
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
end.
|
||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
@ -42,6 +42,7 @@
|
|||||||
process_iq_disco_items/4,
|
process_iq_disco_items/4,
|
||||||
broadcast_service_message/2,
|
broadcast_service_message/2,
|
||||||
register_room/3,
|
register_room/3,
|
||||||
|
node_up/1,
|
||||||
migrate/1,
|
migrate/1,
|
||||||
get_vh_rooms/1,
|
get_vh_rooms/1,
|
||||||
can_use_nick/3]).
|
can_use_nick/3]).
|
||||||
@ -175,14 +176,33 @@ migrate(After) ->
|
|||||||
['$$']}]),
|
['$$']}]),
|
||||||
lists:foreach(
|
lists:foreach(
|
||||||
fun([NameHost, Pid]) ->
|
fun([NameHost, Pid]) ->
|
||||||
case ejabberd_cluster:get_node_new(NameHost) of
|
case ejabberd_cluster:get_node(NameHost) of
|
||||||
Node when Node /= node() ->
|
Node when Node /= node() ->
|
||||||
mod_muc_room:migrate(Pid, Node, After);
|
mod_muc_room:migrate(Pid, Node, random:uniform(After));
|
||||||
_ ->
|
_ ->
|
||||||
ok
|
ok
|
||||||
end
|
end
|
||||||
end, Rs).
|
end, Rs).
|
||||||
|
|
||||||
|
node_up(Node) ->
|
||||||
|
copy_rooms(mnesia:dirty_first(muc_online_room)).
|
||||||
|
|
||||||
|
copy_rooms('$end_of_table') ->
|
||||||
|
ok;
|
||||||
|
copy_rooms(Key) ->
|
||||||
|
case mnesia:dirty_read(muc_online_room, Key) of
|
||||||
|
[#muc_online_room{name_host = NameHost} = Room] ->
|
||||||
|
case ejabberd_cluster:get_node_new(NameHost) of
|
||||||
|
Node when node() /= Node ->
|
||||||
|
rpc:cast(Node, mnesia, dirty_write, [Room]);
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
end;
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
end,
|
||||||
|
copy_rooms(mnesia:dirty_next(muc_online_room, Key)).
|
||||||
|
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
%% gen_server callbacks
|
%% gen_server callbacks
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
@ -219,6 +239,7 @@ init([Host, Opts]) ->
|
|||||||
DefRoomOpts = gen_mod:get_opt(default_room_options, Opts, []),
|
DefRoomOpts = gen_mod:get_opt(default_room_options, Opts, []),
|
||||||
RoomShaper = gen_mod:get_opt(room_shaper, Opts, none),
|
RoomShaper = gen_mod:get_opt(room_shaper, Opts, none),
|
||||||
ejabberd_router:register_route(MyHost),
|
ejabberd_router:register_route(MyHost),
|
||||||
|
ejabberd_hooks:add(node_up, ?MODULE, node_up, 100),
|
||||||
ejabberd_hooks:add(node_hash_update, ?MODULE, migrate, 100),
|
ejabberd_hooks:add(node_hash_update, ?MODULE, migrate, 100),
|
||||||
load_permanent_rooms(MyHost, Host,
|
load_permanent_rooms(MyHost, Host,
|
||||||
{Access, AccessCreate, AccessAdmin, AccessPersistent},
|
{Access, AccessCreate, AccessAdmin, AccessPersistent},
|
||||||
@ -306,7 +327,15 @@ handle_info({room_destroyed, RoomHost, Pid}, State) ->
|
|||||||
mnesia:delete_object(#muc_online_room{name_host = RoomHost,
|
mnesia:delete_object(#muc_online_room{name_host = RoomHost,
|
||||||
pid = Pid})
|
pid = Pid})
|
||||||
end,
|
end,
|
||||||
mnesia:sync_dirty(F),
|
mnesia:async_dirty(F),
|
||||||
|
case ejabberd_cluster:get_node_new(RoomHost) of
|
||||||
|
Node when Node /= node() ->
|
||||||
|
rpc:cast(Node, mnesia, dirty_delete_object,
|
||||||
|
[#muc_online_room{name_host = RoomHost,
|
||||||
|
pid = Pid}]);
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
end,
|
||||||
{noreply, State};
|
{noreply, State};
|
||||||
handle_info(_Info, State) ->
|
handle_info(_Info, State) ->
|
||||||
{noreply, State}.
|
{noreply, State}.
|
||||||
@ -319,6 +348,7 @@ handle_info(_Info, State) ->
|
|||||||
%% The return value is ignored.
|
%% The return value is ignored.
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
terminate(_Reason, State) ->
|
terminate(_Reason, State) ->
|
||||||
|
ejabberd_hooks:delete(node_up, ?MODULE, node_up, 100),
|
||||||
ejabberd_hooks:delete(node_hash_update, ?MODULE, migrate, 100),
|
ejabberd_hooks:delete(node_hash_update, ?MODULE, migrate, 100),
|
||||||
ejabberd_router:unregister_route(State#state.host),
|
ejabberd_router:unregister_route(State#state.host),
|
||||||
ok.
|
ok.
|
||||||
@ -507,14 +537,20 @@ do_route1(Host, ServerHost, Access, HistorySize, RoomShaper,
|
|||||||
AccessCreate, From,
|
AccessCreate, From,
|
||||||
Room) of
|
Room) of
|
||||||
true ->
|
true ->
|
||||||
{ok, Pid} = start_new_room(
|
case start_new_room(
|
||||||
Host, ServerHost, Access,
|
Host, ServerHost, Access,
|
||||||
Room, HistorySize,
|
Room, HistorySize,
|
||||||
RoomShaper, From,
|
RoomShaper, From,
|
||||||
Nick, DefRoomOpts),
|
Nick, DefRoomOpts) of
|
||||||
register_room(Host, Room, Pid),
|
{ok, Pid} ->
|
||||||
mod_muc_room:route(Pid, From, Nick, Packet),
|
mod_muc_room:route(Pid, From, Nick, Packet),
|
||||||
ok;
|
register_room(Host, Room, Pid),
|
||||||
|
ok;
|
||||||
|
_Err ->
|
||||||
|
Err = jlib:make_error_reply(
|
||||||
|
Packet, ?ERR_INTERNAL_SERVER_ERROR),
|
||||||
|
ejabberd_router:route(To, From, Err)
|
||||||
|
end;
|
||||||
false ->
|
false ->
|
||||||
Lang = xml:get_attr_s("xml:lang", Attrs),
|
Lang = xml:get_attr_s("xml:lang", Attrs),
|
||||||
ErrText = "Room creation is denied by service policy",
|
ErrText = "Room creation is denied by service policy",
|
||||||
@ -603,7 +639,28 @@ register_room(Host, Room, Pid) ->
|
|||||||
mnesia:write(#muc_online_room{name_host = {Room, Host},
|
mnesia:write(#muc_online_room{name_host = {Room, Host},
|
||||||
pid = Pid})
|
pid = Pid})
|
||||||
end,
|
end,
|
||||||
mnesia:sync_dirty(F).
|
mnesia:async_dirty(F),
|
||||||
|
case ejabberd_cluster:get_node_new({Room, Host}) of
|
||||||
|
Node when Node /= node() ->
|
||||||
|
%% New node has just been added. But we may miss MUC records
|
||||||
|
%% copy procedure, so we copy the MUC record manually just
|
||||||
|
%% to make sure
|
||||||
|
rpc:cast(Node, mnesia, dirty_write,
|
||||||
|
[#muc_online_room{name_host = {Room, Host},
|
||||||
|
pid = Pid}]),
|
||||||
|
case ejabberd_cluster:get_node({Room, Host}) of
|
||||||
|
Node when node() /= Node ->
|
||||||
|
%% Migration to new node has completed, and seems like
|
||||||
|
%% we missed it, so we migrate the MUC room pid manually.
|
||||||
|
%% It is not a problem if we have already got migration
|
||||||
|
%% notification: dups are just ignored by the MUC room pid.
|
||||||
|
mod_muc_room:migrate(Pid, Node, 0);
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
end;
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
end.
|
||||||
|
|
||||||
iq_disco_info(Lang) ->
|
iq_disco_info(Lang) ->
|
||||||
[{xmlelement, "identity",
|
[{xmlelement, "identity",
|
||||||
|
@ -110,7 +110,7 @@ start_link(StateName, StateData) ->
|
|||||||
?GEN_FSM:start_link(?MODULE, [StateName, StateData], ?FSMOPTS).
|
?GEN_FSM:start_link(?MODULE, [StateName, StateData], ?FSMOPTS).
|
||||||
|
|
||||||
migrate(FsmRef, Node, After) ->
|
migrate(FsmRef, Node, After) ->
|
||||||
?GEN_FSM:send_all_state_event(FsmRef, {migrate, Node, After}).
|
erlang:send_after(After, FsmRef, {migrate, Node}).
|
||||||
|
|
||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
%%% Callback functions from gen_fsm
|
%%% Callback functions from gen_fsm
|
||||||
@ -597,9 +597,6 @@ handle_event(destroy, StateName, StateData) ->
|
|||||||
handle_event({set_affiliations, Affiliations}, StateName, StateData) ->
|
handle_event({set_affiliations, Affiliations}, StateName, StateData) ->
|
||||||
{next_state, StateName, StateData#state{affiliations = Affiliations}};
|
{next_state, StateName, StateData#state{affiliations = Affiliations}};
|
||||||
|
|
||||||
handle_event({migrate, Node, After}, StateName, StateData) when Node /= node() ->
|
|
||||||
{migrate, StateData,
|
|
||||||
{Node, ?MODULE, start, [StateName, StateData]}, After * 2};
|
|
||||||
handle_event(_Event, StateName, StateData) ->
|
handle_event(_Event, StateName, StateData) ->
|
||||||
{next_state, StateName, StateData}.
|
{next_state, StateName, StateData}.
|
||||||
|
|
||||||
@ -716,6 +713,13 @@ handle_info({captcha_failed, From}, normal_state, StateData) ->
|
|||||||
StateData
|
StateData
|
||||||
end,
|
end,
|
||||||
{next_state, normal_state, NewState};
|
{next_state, normal_state, NewState};
|
||||||
|
handle_info({migrate, Node}, StateName, StateData) ->
|
||||||
|
if Node /= node() ->
|
||||||
|
{migrate, StateData,
|
||||||
|
{Node, ?MODULE, start, [StateName, StateData]}, 0};
|
||||||
|
true ->
|
||||||
|
{next_state, StateName, StateData}
|
||||||
|
end;
|
||||||
handle_info(_Info, StateName, StateData) ->
|
handle_info(_Info, StateName, StateData) ->
|
||||||
{next_state, StateName, StateData}.
|
{next_state, StateName, StateData}.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user