[erlang-questions] Memory-effective queue handling
Richard Carlsson
carlsson.richard@REDACTED
Wed Jul 25 15:21:00 CEST 2012
On 07/25/2012 03:01 PM, Erik Søe Sørensen wrote:
> > increase_counter(#ch{queue=Q, counter_value=CV}=CH, Value) ->
> > Date = ?MODULE:get_date(),
> > NewQueue=queue:in({Date, Value}, Q),
> > CH#ch{queue=NewQueue, counter_value=CV+Value}.
> >
> > get_value(#ch{hist_len=HL}=CH) ->
> > % get the values from the queue until we reach a first element in
> the queue
> > % which is not older then the hist_len (e.g. not older than 15 mins)
> > Date = ?MODULE:get_date(),
> > get_younger_than(CH, Date-HL).
> >
> > get_younger_than(#ch{queue=Q, counter_value=CV}=CH, TargetDate) ->
> > case queue:out(Q) of
> > {empty, _} ->
> > 0 = CV, % this is an assert, the value shall be 0
> > {CH, 0};
> > {{value, {Date, Value}}, NewQ} when Date < TargetDate ->
> > get_younger_than(CH#ch{queue=NewQ,
> counter_value=CV-Value}, TargetDate);
> > {{value, _}, _} ->
> > % the currently removed entry is too young, so leave that
> in the
> > % queue (i.e. use the parameter queue).
> > {CH, CV}
> > end.
> >
> > The copying is done in the queue:out call, because it returns not just
> > the first value, but the rest of the queu (newQ) too.
> That doesn't copy the entire queue. That is, occasionally it recreates
> the *spine* of a new list the length of the entire queue, but normally
> it does way less than that.
> The problem is that the way your code works, that worst-case is every
> time, and the throwing-away of old entries is also done from the start
> each time: your get_value() does not return the pruned queue.
> A further consequence of that is that Richard's statement doesn't hold:
> because you keep a reference (apparently) to the original, unpruned
> queue, the memory will have to hold both list spines simultaneously.
> So I'd suggest you change the return value of get_value.
I might be a bit tired, but where does he still hold a reference to the
original queue (unless somewhere outside the shown code)? And if so, is
the problem really that he can't hold 2 copies of the queue at the same
time? - In that case he's pushing the limits anyway. As far as I can
see, get_value() tail calls to get_younger_than(), so no references are
kept there, and get_younger_than() keeps tailcalling itself with the
updated queue in its #ch-record, dropping the previous queue. The final
#ch-record gets returned to the caller. Only the result of the last call
to queue:out() does any wasted rewriting.
/Richard
More information about the erlang-questions
mailing list