diff --git a/ChangeLog b/ChangeLog index cfba33ef8..fe15038c5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2007-08-07 Mickael Remond + + * src/mod_offline.erl: Started implementation of mod_offline + quota. For now, it require change in code. Will be turn into a + config file parameter soon. (EJAB-314). + * src/p1_mnesia.erl: Added memory efficient record count in + Mnesia. + 2007-08-03 Mickael Remond * src/mod_announce.erl: Added support to all the announce features diff --git a/src/mod_offline.erl b/src/mod_offline.erl index b9fde8833..96d963fa3 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -1,13 +1,13 @@ %%%---------------------------------------------------------------------- %%% File : mod_offline.erl -%%% Author : Alexey Shchepin -%%% Purpose : -%%% Created : 5 Jan 2003 by Alexey Shchepin +%%% Author : Alexey Shchepin +%%% Purpose : Store and manage offline messages in Mnesia database. +%%% Created : 5 Jan 2003 by Alexey Shchepin %%% Id : $Id$ %%%---------------------------------------------------------------------- -module(mod_offline). --author('alexey@sevcom.net'). +-author('alexey@process-one.net'). -behaviour(gen_mod). @@ -29,6 +29,10 @@ -define(PROCNAME, ejabberd_offline). -define(OFFLINE_TABLE_LOCK_THRESHOLD, 1000). +%% TODO: Move this part as a module config file parameter: +%% Can be an integer > 0 or infinity: +-define(MAX_OFFLINE_MSGS, infinity). + start(Host, _Opts) -> mnesia:create_table(offline_msg, [{disc_only_copies, [node()]}, @@ -51,19 +55,28 @@ init() -> loop() -> receive - #offline_msg{} = Msg -> - Msgs = receive_all([Msg]), + #offline_msg{us=US} = Msg -> + Msgs = receive_all(US, [Msg]), Len = length(Msgs), F = fun() -> + Count = Len + p1_mnesia:count_records( + offline_msg, + #offline_msg{us=US, _='_'}), if - Len >= ?OFFLINE_TABLE_LOCK_THRESHOLD -> - mnesia:write_lock_table(offline_msg); + Count > ?MAX_OFFLINE_MSGS -> + %% TODO: Warn that messages have been discarded + ok; true -> - ok - end, - lists:foreach(fun(M) -> - mnesia:write(M) - end, Msgs) + if + Len >= ?OFFLINE_TABLE_LOCK_THRESHOLD -> + mnesia:write_lock_table(offline_msg); + true -> + ok + end, + lists:foreach(fun(M) -> + mnesia:write(M) + end, Msgs) + end end, mnesia:transaction(F), loop(); @@ -71,10 +84,10 @@ loop() -> loop() end. -receive_all(Msgs) -> +receive_all(US, Msgs) -> receive - #offline_msg{} = Msg -> - receive_all([Msg | Msgs]) + #offline_msg{us=US} = Msg -> + receive_all(US, [Msg | Msgs]) after 0 -> Msgs end. @@ -387,4 +400,3 @@ update_table() -> ?INFO_MSG("Recreating offline_msg table", []), mnesia:transform_table(offline_msg, ignore, Fields) end. - diff --git a/src/p1_mnesia.erl b/src/p1_mnesia.erl new file mode 100644 index 000000000..2483a1b3f --- /dev/null +++ b/src/p1_mnesia.erl @@ -0,0 +1,45 @@ +%% ``The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved via the world wide web at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% The Initial Developer of the Original Code is Process-one. +%% Portions created by Process-one are Copyright 2007, Process-one +%% All Rights Reserved.'' +%% +%% $Id$ +%% +-module(p1_mnesia). +-author('mickael.remond@process-one.net'). + +-export([count_records/2]). + +%% Return the number of records matching a given match expression. +%% This function is intended to be used inside a Mnesia transaction. +%% The count has been written to use the fewest possible memory by +%% getting the record by small increment and by using continuation. +-define(BATCHSIZE, 100). +count_records(Tab, MatchExpression) -> + %% the result contains the atom a for each match: We do not need + %% actual values as we only count the data. + case mnesia:select(Tab, [{MatchExpression, [], [a]}], ?BATCHSIZE, read) of + {Result,Cont} -> + Count = length(Result), + count_records_cont(Cont, Count); + '$end_of_table' -> + 0 + end. +count_records_cont(Cont, Count) -> + case mnesia:select(Cont) of + {Result,Cont} -> + NewCount = Count + length(Result), + count_records_cont(Cont, NewCount); + '$end_of_table' -> + Count + end.