1 |
|
%%%------------------------------------------------------------------- |
2 |
|
%%% @author Michal Ptaszek <michal.ptaszek@erlang-solutions.com> |
3 |
|
%%% @copyright (C) 2011, Erlang Solutions Ltd. |
4 |
|
%%% @doc Implementation of Mnesia-based session manager |
5 |
|
%%% |
6 |
|
%%% @end |
7 |
|
%%% Created : 17 Nov 2011 by Michal Ptaszek <michal.ptaszek@erlang-solutions.com> |
8 |
|
%%%------------------------------------------------------------------- |
9 |
|
-module(ejabberd_sm_mnesia). |
10 |
|
|
11 |
|
-behavior(ejabberd_sm_backend). |
12 |
|
|
13 |
|
-include("mongoose.hrl"). |
14 |
|
-include("session.hrl"). |
15 |
|
|
16 |
|
-export([init/1, |
17 |
|
get_sessions/0, |
18 |
|
get_sessions/1, |
19 |
|
get_sessions/2, |
20 |
|
get_sessions/3, |
21 |
|
set_session/4, |
22 |
|
delete_session/4, |
23 |
|
cleanup/1, |
24 |
|
total_count/0, |
25 |
|
unique_count/0]). |
26 |
|
|
27 |
|
-spec init(map()) -> any(). |
28 |
|
init(_Opts) -> |
29 |
4 |
mongoose_mnesia:create_table(session, |
30 |
|
[{ram_copies, [node()]}, |
31 |
|
{attributes, record_info(fields, session)}]), |
32 |
4 |
mnesia:add_table_index(session, usr), |
33 |
4 |
mnesia:add_table_index(session, us). |
34 |
|
|
35 |
|
-spec get_sessions() -> [ejabberd_sm:session()]. |
36 |
|
get_sessions() -> |
37 |
5 |
mnesia:activity(transaction, |
38 |
|
fun() -> |
39 |
5 |
mnesia:foldl(fun(Session, AccIn) -> [Session | AccIn] end, |
40 |
|
[], session) |
41 |
|
end). |
42 |
|
|
43 |
|
-spec get_sessions(jid:lserver()) -> [ejabberd_sm:session()]. |
44 |
|
get_sessions(Server) -> |
45 |
:-( |
mnesia:dirty_select( |
46 |
|
session, |
47 |
|
[{#session{usr = '$1', sid='$2', priority='$3', info='$4', _ = '_' }, |
48 |
|
[{'==', {element, 2, '$1'}, Server}], |
49 |
|
['$_']}]). |
50 |
|
|
51 |
|
-spec get_sessions(jid:luser(), jid:lserver()) -> [ejabberd_sm:session()]. |
52 |
|
get_sessions(User, Server) -> |
53 |
3567 |
mnesia:dirty_index_read(session, {User, Server}, #session.us). |
54 |
|
|
55 |
|
-spec get_sessions(jid:luser(), jid:lserver(), jid:lresource() |
56 |
|
) -> [ejabberd_sm:session()]. |
57 |
|
get_sessions(User, Server, Resource) -> |
58 |
3387 |
mnesia:dirty_index_read(session, {User, Server, Resource}, #session.usr). |
59 |
|
|
60 |
|
-spec set_session(_User :: jid:luser(), |
61 |
|
_Server :: jid:lserver(), |
62 |
|
_Resource :: jid:lresource(), |
63 |
|
Session :: ejabberd_sm:session()) -> ok | {error, term()}. |
64 |
|
set_session(_User, _Server, _Resource, Session) -> |
65 |
1062 |
mnesia:sync_dirty(fun() -> mnesia:write(Session) end). |
66 |
|
|
67 |
|
-spec delete_session(ejabberd_sm:sid(), |
68 |
|
_User :: jid:luser(), |
69 |
|
_Server :: jid:lserver(), |
70 |
|
_Resource :: jid:lresource()) -> ok. |
71 |
|
delete_session(SID, _User, _Server, _Resource) -> |
72 |
615 |
mnesia:sync_dirty(fun() -> mnesia:delete({session, SID}) end). |
73 |
|
|
74 |
|
-spec cleanup(atom()) -> any(). |
75 |
|
cleanup(Node) -> |
76 |
:-( |
F = fun() -> |
77 |
:-( |
Es = mnesia:select( |
78 |
|
session, |
79 |
|
[{#session{sid = {'_', '$1'}, _ = '_'}, |
80 |
|
[{'==', {node, '$1'}, Node}], |
81 |
|
['$_']}]), |
82 |
:-( |
lists:foreach(fun(#session{sid = SID} = Session) -> |
83 |
:-( |
mnesia:delete({session, SID}), |
84 |
:-( |
ejabberd_sm:run_session_cleanup_hook(Session) |
85 |
|
end, Es) |
86 |
|
end, |
87 |
:-( |
mnesia:async_dirty(F). |
88 |
|
|
89 |
|
-spec total_count() -> integer(). |
90 |
|
total_count() -> |
91 |
15 |
mnesia:table_info(session, size). |
92 |
|
|
93 |
|
-spec unique_count() -> integer(). |
94 |
|
unique_count() -> |
95 |
15 |
compute_unique(mnesia:dirty_first(session), |
96 |
|
sets:new()). |
97 |
|
|
98 |
|
-spec compute_unique(term(), sets:set()) -> integer(). |
99 |
|
compute_unique('$end_of_table', Set) -> |
100 |
15 |
sets:size(Set); |
101 |
|
compute_unique(Key, Set) -> |
102 |
1 |
NewSet = case mnesia:dirty_read(session, Key) of |
103 |
|
[Session] -> |
104 |
1 |
sets:add_element(Session#session.us, Set); |
105 |
|
_ -> |
106 |
:-( |
Set |
107 |
|
end, |
108 |
1 |
compute_unique(mnesia:dirty_next(session, Key), NewSet). |