|
@@ -51,11 +51,11 @@
|
|
|
%% gen_server2 priorities
|
|
%% gen_server2 priorities
|
|
|
-export([prioritise_call/4, prioritise_cast/3, prioritise_info/3]).
|
|
-export([prioritise_call/4, prioritise_cast/3, prioritise_info/3]).
|
|
|
|
|
|
|
|
--record(state, {pool, id}).
|
|
|
|
|
|
|
+-record(state, {pool, id, monitors}).
|
|
|
|
|
|
|
|
-define(POOL, ?MODULE).
|
|
-define(POOL, ?MODULE).
|
|
|
|
|
|
|
|
--define(TIMEOUT, 60000).
|
|
|
|
|
|
|
+-define(TIMEOUT, 120000).
|
|
|
|
|
|
|
|
-define(LOG(Level, Format, Args, Session),
|
|
-define(LOG(Level, Format, Args, Session),
|
|
|
lager:Level("SM(~s): " ++ Format, [Session#mqtt_session.client_id | Args])).
|
|
lager:Level("SM(~s): " ++ Format, [Session#mqtt_session.client_id | Args])).
|
|
@@ -67,12 +67,11 @@
|
|
|
mnesia(boot) ->
|
|
mnesia(boot) ->
|
|
|
%% Global Session Table
|
|
%% Global Session Table
|
|
|
ok = emqttd_mnesia:create_table(session, [
|
|
ok = emqttd_mnesia:create_table(session, [
|
|
|
- {type, ordered_set},
|
|
|
|
|
|
|
+ {type, set},
|
|
|
{ram_copies, [node()]},
|
|
{ram_copies, [node()]},
|
|
|
{record_name, mqtt_session},
|
|
{record_name, mqtt_session},
|
|
|
- {attributes, record_info(fields, mqtt_session)},
|
|
|
|
|
- %% TODO: index_read is slow...
|
|
|
|
|
- {index, [sess_pid]}]);
|
|
|
|
|
|
|
+ {attributes, record_info(fields, mqtt_session)}]);
|
|
|
|
|
+
|
|
|
mnesia(copy) ->
|
|
mnesia(copy) ->
|
|
|
ok = emqttd_mnesia:copy_table(session).
|
|
ok = emqttd_mnesia:copy_table(session).
|
|
|
|
|
|
|
@@ -144,7 +143,8 @@ call(SM, Req) ->
|
|
|
|
|
|
|
|
init([Pool, Id]) ->
|
|
init([Pool, Id]) ->
|
|
|
?GPROC_POOL(join, Pool, Id),
|
|
?GPROC_POOL(join, Pool, Id),
|
|
|
- {ok, #state{pool = Pool, id = Id}}.
|
|
|
|
|
|
|
+ {ok, #state{pool = Pool, id = Id,
|
|
|
|
|
+ monitors = dict:new()}}.
|
|
|
|
|
|
|
|
prioritise_call(_Msg, _From, _Len, _State) ->
|
|
prioritise_call(_Msg, _From, _Len, _State) ->
|
|
|
1.
|
|
1.
|
|
@@ -155,43 +155,57 @@ prioritise_cast(_Msg, _Len, _State) ->
|
|
|
prioritise_info(_Msg, _Len, _State) ->
|
|
prioritise_info(_Msg, _Len, _State) ->
|
|
|
2.
|
|
2.
|
|
|
|
|
|
|
|
-%% persistent session
|
|
|
|
|
-handle_call({start_session, {false, ClientId, ClientPid}}, _From, State) ->
|
|
|
|
|
|
|
+%% Persistent Session
|
|
|
|
|
+handle_call({start_session, Client = {false, ClientId, ClientPid}}, _From, State) ->
|
|
|
case lookup_session(ClientId) of
|
|
case lookup_session(ClientId) of
|
|
|
undefined ->
|
|
undefined ->
|
|
|
- %% create session locally
|
|
|
|
|
- reply(create_session(false, ClientId, ClientPid), false, State);
|
|
|
|
|
|
|
+ %% Create session locally
|
|
|
|
|
+ create_session(Client, State);
|
|
|
Session ->
|
|
Session ->
|
|
|
- reply(resume_session(Session, ClientPid), true, State)
|
|
|
|
|
|
|
+ case resume_session(Session, ClientPid) of
|
|
|
|
|
+ {ok, SessPid} ->
|
|
|
|
|
+ {reply, {ok, SessPid, true}, State};
|
|
|
|
|
+ {error, Erorr} ->
|
|
|
|
|
+ {reply, {error, Erorr}, State}
|
|
|
|
|
+ end
|
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
-%% transient session
|
|
|
|
|
-handle_call({start_session, {true, ClientId, ClientPid}}, _From, State) ->
|
|
|
|
|
|
|
+%% Transient Session
|
|
|
|
|
+handle_call({start_session, Client = {true, ClientId, _ClientPid}}, _From, State) ->
|
|
|
case lookup_session(ClientId) of
|
|
case lookup_session(ClientId) of
|
|
|
undefined ->
|
|
undefined ->
|
|
|
- reply(create_session(true, ClientId, ClientPid), false, State);
|
|
|
|
|
|
|
+ create_session(Client, State);
|
|
|
Session ->
|
|
Session ->
|
|
|
case destroy_session(Session) of
|
|
case destroy_session(Session) of
|
|
|
ok ->
|
|
ok ->
|
|
|
- reply(create_session(true, ClientId, ClientPid), false, State);
|
|
|
|
|
|
|
+ create_session(Client, State);
|
|
|
{error, Error} ->
|
|
{error, Error} ->
|
|
|
{reply, {error, Error}, State}
|
|
{reply, {error, Error}, State}
|
|
|
end
|
|
end
|
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
-handle_call(_Request, _From, State) ->
|
|
|
|
|
- {reply, ok, State}.
|
|
|
|
|
|
|
+handle_call(Req, _From, State) ->
|
|
|
|
|
+ ?UNEXPECTED_REQ(Req, State).
|
|
|
|
|
|
|
|
handle_cast(Msg, State) ->
|
|
handle_cast(Msg, State) ->
|
|
|
?UNEXPECTED_MSG(Msg, State).
|
|
?UNEXPECTED_MSG(Msg, State).
|
|
|
|
|
|
|
|
-%%TODO: fix this issue that index_read is really slow...
|
|
|
|
|
-handle_info({'DOWN', _MRef, process, DownPid, _Reason}, State) ->
|
|
|
|
|
- mnesia:transaction(fun() ->
|
|
|
|
|
- [mnesia:delete_object(session, Sess, write) || Sess
|
|
|
|
|
- <- mnesia:index_read(session, DownPid, #mqtt_session.sess_pid)]
|
|
|
|
|
- end),
|
|
|
|
|
- {noreply, State};
|
|
|
|
|
|
|
+handle_info({'DOWN', MRef, process, DownPid, _Reason}, State) ->
|
|
|
|
|
+ case dict:find(MRef, State#state.monitors) of
|
|
|
|
|
+ {ok, ClientId} ->
|
|
|
|
|
+ mnesia:transaction(fun() ->
|
|
|
|
|
+ case mnesia:wread({session, ClientId}) of
|
|
|
|
|
+ [] -> ok;
|
|
|
|
|
+ [Sess = #mqtt_session{sess_pid = DownPid}] ->
|
|
|
|
|
+ mnesia:delete_object(session, Sess, write);
|
|
|
|
|
+ [_Sess] -> ok
|
|
|
|
|
+ end
|
|
|
|
|
+ end),
|
|
|
|
|
+ {noreply, erase_monitor(MRef, State)};
|
|
|
|
|
+ error ->
|
|
|
|
|
+ lager:error("MRef of session ~p not found", [DownPid]),
|
|
|
|
|
+ {noreply, State}
|
|
|
|
|
+ end;
|
|
|
|
|
|
|
|
handle_info(Info, State) ->
|
|
handle_info(Info, State) ->
|
|
|
?UNEXPECTED_INFO(Info, State).
|
|
?UNEXPECTED_INFO(Info, State).
|
|
@@ -206,6 +220,16 @@ code_change(_OldVsn, State, _Extra) ->
|
|
|
%%% Internal functions
|
|
%%% Internal functions
|
|
|
%%%=============================================================================
|
|
%%%=============================================================================
|
|
|
|
|
|
|
|
|
|
+%% Create Session Locally
|
|
|
|
|
+create_session({CleanSess, ClientId, ClientPid}, State) ->
|
|
|
|
|
+ case create_session(CleanSess, ClientId, ClientPid) of
|
|
|
|
|
+ {ok, SessPid} ->
|
|
|
|
|
+ {reply, {ok, SessPid, false},
|
|
|
|
|
+ monitor_session(ClientId, SessPid, State)};
|
|
|
|
|
+ {error, Error} ->
|
|
|
|
|
+ {reply, {error, Error}, State}
|
|
|
|
|
+ end.
|
|
|
|
|
+
|
|
|
create_session(CleanSess, ClientId, ClientPid) ->
|
|
create_session(CleanSess, ClientId, ClientPid) ->
|
|
|
case emqttd_session_sup:start_session(CleanSess, ClientId, ClientPid) of
|
|
case emqttd_session_sup:start_session(CleanSess, ClientId, ClientPid) of
|
|
|
{ok, SessPid} ->
|
|
{ok, SessPid} ->
|
|
@@ -218,7 +242,6 @@ create_session(CleanSess, ClientId, ClientPid) ->
|
|
|
lager:error("SM(~s): Conflict with ~p", [ClientId, ConflictPid]),
|
|
lager:error("SM(~s): Conflict with ~p", [ClientId, ConflictPid]),
|
|
|
{error, mnesia_conflict};
|
|
{error, mnesia_conflict};
|
|
|
{atomic, ok} ->
|
|
{atomic, ok} ->
|
|
|
- erlang:monitor(process, SessPid),
|
|
|
|
|
{ok, SessPid}
|
|
{ok, SessPid}
|
|
|
end;
|
|
end;
|
|
|
{error, Error} ->
|
|
{error, Error} ->
|
|
@@ -293,8 +316,10 @@ remove_session(Session) ->
|
|
|
{aborted, Error} -> {error, Error}
|
|
{aborted, Error} -> {error, Error}
|
|
|
end.
|
|
end.
|
|
|
|
|
|
|
|
-reply({ok, SessPid}, SP, State) ->
|
|
|
|
|
- {reply, {ok, SessPid, SP}, State};
|
|
|
|
|
-reply({error, Error}, _SP, State) ->
|
|
|
|
|
- {reply, {error, Error}, State}.
|
|
|
|
|
|
|
+monitor_session(ClientId, SessPid, State = #state{monitors = Monitors}) ->
|
|
|
|
|
+ MRef = erlang:monitor(process, SessPid),
|
|
|
|
|
+ State#state{monitors = dict:store(MRef, ClientId, Monitors)}.
|
|
|
|
|
+
|
|
|
|
|
+erase_monitor(MRef, State = #state{monitors = Monitors}) ->
|
|
|
|
|
+ State#state{monitors = dict:erase(MRef, Monitors)}.
|
|
|
|
|
|