<p>Den 25/07/2012 15.21 skrev "Richard Carlsson" <<a href="mailto:carlsson.richard@gmail.com">carlsson.richard@gmail.com</a>>:<br>
><br>
> On 07/25/2012 03:01 PM, Erik Søe Sørensen wrote:<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<br>
>> 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,<br>
>> counter_value=CV-Value}, TargetDate);<br>
>>  >         {{value, _}, _} -><br>
>>  >             % the currently removed entry is too young, so leave that<br>
>> 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<br>
>> the *spine* of a new list the length of the entire queue, but normally<br>
>> it does way less than that.<br>
>> The problem is that the way your code works, that worst-case is every<br>
>> time, and the throwing-away of old entries is also done from the start<br>
>> 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:<br>
>> because you keep a reference (apparently) to the original, unpruned<br>
>> queue, the memory will have to hold both list spines simultaneously.<br>
>> So I'd suggest you change the return value of get_value.<br>
><br>
><br>
> I might be a bit tired, but where does he still hold a reference to the original queue (unless somewhere outside the shown code)?<br>
And I may be assuming too much by thinking that get_value is called by a server loop which keeps holding on to the queue. Sorry I wasn't explicit about that; if it wasn't so, then what I said didn't make much sense.<br>

(It's vacation time and email-by-phone time, so my editing facilities are a bit limited...)</p>
<p>> 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.<br>

><br>
>     /Richard<br>
><br>
</p>