diff options
Diffstat (limited to 'src/mod_mam_mnesia.erl')
-rw-r--r-- | src/mod_mam_mnesia.erl | 86 |
1 files changed, 60 insertions, 26 deletions
diff --git a/src/mod_mam_mnesia.erl b/src/mod_mam_mnesia.erl index 007ef5eba..10b98daf7 100644 --- a/src/mod_mam_mnesia.erl +++ b/src/mod_mam_mnesia.erl @@ -16,6 +16,7 @@ -include_lib("stdlib/include/ms_transform.hrl"). -include("jlib.hrl"). +-include("logger.hrl"). -include("mod_mam.hrl"). -define(BIN_GREATER_THAN(A, B), @@ -25,6 +26,8 @@ ((A < B andalso byte_size(A) == byte_size(B)) orelse byte_size(A) < byte_size(B))). +-define(TABLE_SIZE_LIMIT, 2000000000). % A bit less than 2 GiB. + %%%=================================================================== %%% API %%%=================================================================== @@ -49,37 +52,68 @@ remove_room(_LServer, LName, LHost) -> remove_user(LName, LHost). delete_old_messages(global, TimeStamp, Type) -> - MS = ets:fun2ms(fun(#archive_msg{timestamp = MsgTS, - type = MsgType} = Msg) - when MsgTS < TimeStamp, - MsgType == Type orelse Type == all -> - Msg - end), - OldMsgs = mnesia:dirty_select(archive_msg, MS), - lists:foreach(fun(Rec) -> - ok = mnesia:dirty_delete_object(Rec) - end, OldMsgs). + delete_old_user_messages(mnesia:dirty_first(archive_msg), TimeStamp, Type). + +delete_old_user_messages('$end_of_table', _TimeStamp, _Type) -> + ok; +delete_old_user_messages(User, TimeStamp, Type) -> + F = fun() -> + Msgs = mnesia:read(archive_msg, User), + Keep = lists:filter( + fun(#archive_msg{timestamp = MsgTS, + type = MsgType}) -> + MsgTS >= TimeStamp orelse (Type /= all andalso + Type /= MsgType) + end, Msgs), + if length(Keep) < length(Msgs) -> + mnesia:delete({archive_msg, User}), + lists:foreach(fun(Msg) -> mnesia:write(Msg) end, Keep); + true -> + ok + end + end, + case mnesia:transaction(F) of + {atomic, ok} -> + delete_old_user_messages(mnesia:dirty_next(archive_msg, User), + TimeStamp, Type); + {aborted, Err} -> + ?ERROR_MSG("Cannot delete old MAM messages: ~s", [Err]), + Err + end. extended_fields() -> []. store(Pkt, _, {LUser, LServer}, Type, Peer, Nick, _Dir) -> - LPeer = {PUser, PServer, _} = jid:tolower(Peer), - TS = p1_time_compat:timestamp(), - ID = jlib:integer_to_binary(now_to_usec(TS)), - case mnesia:dirty_write( - #archive_msg{us = {LUser, LServer}, - id = ID, - timestamp = TS, - peer = LPeer, - bare_peer = {PUser, PServer, <<>>}, - type = Type, - nick = Nick, - packet = Pkt}) of - ok -> - {ok, ID}; - Err -> - Err + case {mnesia:table_info(archive_msg, disc_only_copies), + mnesia:table_info(archive_msg, memory)} of + {[_|_], TableSize} when TableSize > ?TABLE_SIZE_LIMIT -> + ?ERROR_MSG("MAM archives too large, won't store message for ~s@~s", + [LUser, LServer]), + {error, overflow}; + _ -> + LPeer = {PUser, PServer, _} = jid:tolower(Peer), + TS = p1_time_compat:timestamp(), + ID = jlib:integer_to_binary(now_to_usec(TS)), + F = fun() -> + mnesia:write( + #archive_msg{us = {LUser, LServer}, + id = ID, + timestamp = TS, + peer = LPeer, + bare_peer = {PUser, PServer, <<>>}, + type = Type, + nick = Nick, + packet = Pkt}) + end, + case mnesia:transaction(F) of + {atomic, ok} -> + {ok, ID}; + {aborted, Err} -> + ?ERROR_MSG("Cannot add message to MAM archive of ~s@~s: ~s", + [LUser, LServer, Err]), + Err + end end. write_prefs(_LUser, _LServer, Prefs, _ServerHost) -> |