<div>I haven&#39;t really had a huge amount of time to work on it since I sent the first message message, with the holidays and starting up a new project at work.</div><div><br></div><div>Also I was hoping to get some input from the rabbitmq guys so that any changes I make would have a better chance of being accepted.</div>
<div><br></div><div>Taking a quick look at what I wrote a month ago, today my plan would be to implement having a amqp_pool_t associated with each amqp_channel_t and see how far I could get with that.</div><div><br></div>
<div>-Alan</div><div><br><div class="gmail_quote">On Thu, Jan 12, 2012 at 11:39 AM, Alexis Richardson <span dir="ltr">&lt;<a href="mailto:alexis@rabbitmq.com" target="_blank">alexis@rabbitmq.com</a>&gt;</span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Alan<br>
<br>
It appears that you stunned everyone into silence ;-)<br>
<br>
How are you getting on with this?<br>
<br>
alexis<br>
<div><div><br>
<br>
On Wed, Dec 14, 2011 at 8:15 PM, Alan Antonuk &lt;<a href="mailto:alan.antonuk@gmail.com" target="_blank">alan.antonuk@gmail.com</a>&gt; wrote:<br>
&gt; I&#39;ve been working on a c++ wrapper around rabbitmq-c that presents a<br>
&gt; &quot;humane&quot; API to the programmer heavily inspired by the Puka project.<br>
&gt; (see: <a href="https://github.com/alanxz/SimpleAmqpClient" target="_blank">https://github.com/alanxz/SimpleAmqpClient</a>).<br>
&gt;<br>
&gt; In developing this library I&#39;ve run across several limitations of the<br>
&gt; rabbitmq-c when working with multiple channels, the biggest issue being:<br>
&gt;<br>
&gt; - There is no way to wait for a list of methods on a channel.<br>
&gt; There is amqp_simple_wait_method() - however this suffers from some serious<br>
&gt; drawbacks:<br>
&gt; + you can only specify one method to listen for<br>
&gt; + it calls abort() if a different method, or a method on a different channel<br>
&gt; is received<br>
&gt; A use case for this might be: doing a basic.publish, and you want to want to<br>
&gt; wait for a basic.ack or a basic.return on a channel with confirms enabled<br>
&gt;<br>
&gt; The way I got around this in SimpleAmqpClient was to only use<br>
&gt; amqp_simple_wait_frame() and maintain queues of amqp_frame_t for each<br>
&gt; channel that I have open.<br>
&gt;<br>
&gt; However, this comes with one serious drawback: memory management. Each<br>
&gt; decoded frame is allocated in a connection-wide amqp_pool_t.  Because of<br>
&gt; this - it is impossible to recycle the pool and release memory unless you<br>
&gt; have dealt with all of your pending amqp_frame_t&#39;s.  This becomes a problem<br>
&gt; in pathological cases where you have two consumers sending simultaneously,<br>
&gt; you can get in the situation that even though the client program eventually<br>
&gt; deals with every consumed message, memory never gets released, because there<br>
&gt; is always at least one frame queued up.<br>
&gt;<br>
&gt; The above demonstrates the second biggest issue with the rabbitmq-c API:<br>
&gt; memory management when dealing with multiple channels.  There is no way to<br>
&gt; separate out memory allocation on, for example, a per-channel basis (with<br>
&gt; the library client keeping track of the memory pools used for example).<br>
&gt;<br>
&gt; Before I go on I&#39;d like to mention one feature that I find useful with the<br>
&gt; current API: it is possible to use something like select() before calling<br>
&gt; amqp_simple_wait_frame() to setup a timeout while waiting for a consumer,<br>
&gt; which is useful when developing single-threaded RPC apps.<br>
&gt;<br>
&gt;<br>
&gt; So now the interesting part: how could the API be improved?<br>
&gt;<br>
&gt; Some thoughts I&#39;ve had dealing with the memory management:<br>
&gt; 1. Create a amqp_simple_wait_frame() variant that as one of the parameters<br>
&gt; provides a callback to allocate memory, either something like a malloc()<br>
&gt; call, which the client would then be responsible for freeing, or perhaps<br>
&gt; something like get_amqp_pool(amqp_frame_t) which allows the client to return<br>
&gt; a memory pool which rabbitmq-c would use to allocate memory for that frame.<br>
&gt;  The amqp_frame_t would have to have some minimal amount of information<br>
&gt; filled in - such as frame type and channel to be useful.<br>
&gt;<br>
&gt; 2. amqp_channel_t becomes a struct containing both the the channel_id and a<br>
&gt; amqp_pool_t.  The amqp_pool would be used by the library to allocate frames<br>
&gt; received on that channel.  The client would then be responsible for calling<br>
&gt; amqp_pool_recycle at an appropriate point.<br>
&gt;<br>
&gt; Some thoughts on improving the API to deal with multiple channels:<br>
&gt; 1. Add the following to the API:<br>
&gt; amqp_simple_wait_frame_on_channel - wait for a frame on a specified channel<br>
&gt; amqp_simple_wait_methods - wait for multiple methods on a specified channel.<br>
&gt; Don&#39;t abort() if the wrong method, or channel is received, instead queue up<br>
&gt; the frame as is done in amqp_simple_rpc<br>
&gt; amqp_frames_enqueued_for_channel to add feature parity with<br>
&gt; amqp_frames_enqueued<br>
&gt; I started to code this up at one point but abandoned it as it didn&#39;t support<br>
&gt; the interesting property of being able to use select() to specify a timeout<br>
&gt; when calling amqp_simple_wait_frame_on_channel.  At least not without adding<br>
&gt; timeout to the rabbitmq-c api, which didn&#39;t fit with how the current<br>
&gt; rabbitmq-c api. Here&#39;s the implementation I came up with before I abandoned<br>
&gt; it. I can&#39;t guarantee is completely free of<br>
&gt; bugs. <a href="https://github.com/alanxz/rabbitmq-c/commits/simple_wait_frame/" target="_blank">https://github.com/alanxz/rabbitmq-c/commits/simple_wait_frame/</a><br>
&gt;<br>
&gt; 2. Continue to duck the issue and allow clients to write their own code to<br>
&gt; deal with multiple channels (fixing the memory management issue using one of<br>
&gt; the above techniques)<br>
&gt;<br>
&gt; 3. Something I haven&#39;t thought of yet.<br>
&gt;<br>
&gt; So anyone have any thoughts on all of this?<br>
&gt;<br>
&gt; -Alan<br>
&gt;<br>
</div></div>&gt; _______________________________________________<br>
&gt; rabbitmq-discuss mailing list<br>
&gt; <a href="mailto:rabbitmq-discuss@lists.rabbitmq.com" target="_blank">rabbitmq-discuss@lists.rabbitmq.com</a><br>
&gt; <a href="https://lists.rabbitmq.com/cgi-bin/mailman/listinfo/rabbitmq-discuss" target="_blank">https://lists.rabbitmq.com/cgi-bin/mailman/listinfo/rabbitmq-discuss</a><br>
&gt;<br>
</blockquote></div><br></div>