<p><br>
Den 25/07/2012 11.57 skrev "Attila Rajmund Nohl" <<a href="mailto:attila.r.nohl@gmail.com">attila.r.nohl@gmail.com</a>>:<br>
><br>
> 2012/7/24 Erik Søe Sørensen <<a href="mailto:eriksoe@gmail.com">eriksoe@gmail.com</a>>:<br>
> ><br>
> > Den 24/07/2012 17.11 skrev "Attila Rajmund Nohl" <<a href="mailto:attila.r.nohl@gmail.com">attila.r.nohl@gmail.com</a>>:<br>
> ><br>
> ><br>
> >><br>
> >> Hello!<br>
> >><br>
> >> I have a data structure where I manage "historical data": a list of<br>
> >> timestamps when events happened. I only need to know how many events<br>
> >> happened in the last 24 hours. When an event happens, I put the<br>
> >> timestamp into the queue (I use the queue module in OTP). When I check<br>
> >> how many values are in the queue, I also remove the entries that are<br>
> >> older than 24 hours. My problem is: when I remove the old elements, I<br>
> >> can do it one by one and at each step the (possibly big) queue gets<br>
> >> copied and I run out of memory.<br>
> > I am curious: how do you manage to do this? Can we see the code?<br>
> > (Certainly it shouldn't be the case that much copying should be done at each<br>
> > step.)<br>
><br>
> I can show an excerpt from the code:<br>
><br>
> increase_counter(#ch{queue=Q, counter_value=CV}=CH, Value) -><br>
> Date = ?MODULE:get_date(),<br>
> NewQueue=queue:in({Date, Value}, Q),<br>
> CH#ch{queue=NewQueue, counter_value=CV+Value}.<br>
><br>
> get_value(#ch{hist_len=HL}=CH) -><br>
> % get the values from the queue until we reach a first element in the queue<br>
> % which is not older then the hist_len (e.g. not older than 15 mins)<br>
> Date = ?MODULE:get_date(),<br>
> get_younger_than(CH, Date-HL).<br>
><br>
> get_younger_than(#ch{queue=Q, counter_value=CV}=CH, TargetDate) -><br>
> case queue:out(Q) of<br>
> {empty, _} -><br>
> 0 = CV, % this is an assert, the value shall be 0<br>
> {CH, 0};<br>
> {{value, {Date, Value}}, NewQ} when Date < TargetDate -><br>
> get_younger_than(CH#ch{queue=NewQ, counter_value=CV-Value}, TargetDate);<br>
> {{value, _}, _} -><br>
> % the currently removed entry is too young, so leave that in the<br>
> % queue (i.e. use the parameter queue).<br>
> {CH, CV}<br>
> end.<br>
><br>
> The copying is done in the queue:out call, because it returns not just<br>
> the first value, but the rest of the queu (newQ) too.<br>
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.<br>
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.<br>
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.<br>
So I'd suggest you change the return value of get_value.</p>