[ 
https://issues.apache.org/jira/browse/QPID-8538?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17360343#comment-17360343
 ] 

Peter Moran commented on QPID-8538:
-----------------------------------

Citation from AMQP:
" If the sender's drain flag is set and there are no available messages, the 
sender MUST advance its delivery-count until link-credit is zero, and send its 
updated flow state to the receiver.

(1) If a message is available within the timeout, it will
       arrive at this point.
 (2) If a message is not available within the timeout, the
       drain flag will ensure that the sender promptly advances the 
delivery-count until link-credit is consumed.  
"

The AMQP documentation is bit unclear how receiver should replenish the credit 
or should understand the delivery_count.  I understand that subsequent get 
should increase the credit if there are messages delivered. But what about the 
case above, message were not delivered (just the flow message from broker with 
updated deliveries +credit) and credit is depleted and queue is e.g 1 message. 
There is just a gap in the fetch which ignores the possibility that broker 
cannot deliver messages in given time and just updates the delivery count. I 
would any way expect the fetch must therefore always replenish the credit 
consider amount of returned messages (obtained by get) and then replenish the 
credit immediately, if it does not the the link credit will stay very low and 
never returns to capacity. I have tested the code above and I will retest one 
more alternative

remove the pn link flow after drain and move it after get ( if (lnk->capacity 
&& pn_link_queued(lnk->receiver) == 0) {)
{code:java}

    auto res = get(ssn, lnk, message, qpid::messaging::Duration::IMMEDIATE);

    {
        if (lnk->capacity)
        {
            sys::Monitor::ScopedLock l(lock);
            pn_link_flow(lnk->receiver, lnk->capacity - 
pn_link_queued(lnk->receiver));
            wakeupDriver();
        }
    }
    return res;
{code}


Alternative consequence if you believe the qpid-cpp is correct then there is a 
bug in proton:

{code:java}
if (delta > 0) {
        link->state.delivery_count += delta;
        link->state.link_credit -= delta;
        link->credit -= delta;
        link->drained += delta;
{code}

if there are 0 message available then broker delivers and sets delivery count 
to maximum possible (current + granted credit) this code in pn_do_flow decrease 
the credit by delta but also sets drained to + delta, which does not match any 
documentation expectation, from the documentation of pn_link_drained:
 
_When invoked on a receiving link, this operation will return and reset the 
number of credits the sender has released back to the receiver._

which is just returns link->drained, but this is not traded as execs in 
pn_do_flow, 

Is the documentation of proton wrong? if it is not excess and it is amount of 
messages drained from the queue it cannot be calculated from delivery count. 
This code does not make any sense to me. delivery count is not counter as you 
said yet proton treats it like it is. And consequence of all this is that the 
receiver must top up its credit to (capacity - link->queued) after it drains 
regardless if the receiver read messages and incremented credit by itself and 
then numbers should match, or got nothing because the credit was consumed by 
sender because there are no messages. 








> Receiver fetch method depletes credit and slows down receiver
> -------------------------------------------------------------
>
>                 Key: QPID-8538
>                 URL: https://issues.apache.org/jira/browse/QPID-8538
>             Project: Qpid
>          Issue Type: Bug
>          Components: C++ Client
>    Affects Versions: qpid-cpp-1.39.0
>            Reporter: Peter Moran
>            Priority: Major
>
> As remote broker java broker is used.
> e.g 
>  capacity of link is 10
>  credit is 10
> When calling Method ConnectionContext::fetch and there are no data available 
> inside receiver (get returns false) it
>  # Enables drain mode  pn_link_drain(lnk->receiver, 0);
>  # Tries to process all queued messages (while 
> (pn_link_draining(lnk->receiver) && !pn_link_queued(lnk->receiver)))
>  # Credit is being drained by broker pn_do_flow in proton ( pn_sequence_t 
> delta = delivery_count - link->state.delivery_count;) -> delta is 10 and 
> credit is cleared to 0, yet no messages arrived from broker at all
>  if there are queued messages and credit is 0 then pn_link_draining returns 
> false and while stops
>  # however if (lnk->capacity && pn_link_queued(lnk->receiver) == 0) replenish 
> credit only if there are no outstanding queued messages to the maximum 
> capacity, this should be rather capacity - credit, but also the condition 
> seems to be wrong, it should not check the queued messages.
> the code should look like this
> {code:java}
> if (lnk->capacity) {
>     pn_link_flow(lnk->receiver, lnk->capacity - 
> pn_link_credit(lnk->receiver));
> }
> or
> if (lnk->capacity) { 
> pn_link_flow(lnk->receiver, pn_link_drained(lnk->receiver));
> }{code}
> this would much more look like what is inside proton c++ api
> {code:java}
> void credit_topup(pn_link_t *link) {
>     assert(pn_link_is_receiver(link));
>     int window = link_context::get(link).credit_window;
>     if (window) {
>         int delta = window - pn_link_credit(link);
>         pn_link_flow(link, delta);
>     }
> }
>       // receiver
>             if (!pn_link_credit(lnk) && lctx.draining) {
>                 lctx.draining = false;
>                 pn_link_set_drain(lnk, false);
>                 receiver r(make_wrapper<receiver>(lnk));
>                 handler.on_receiver_drain_finish(r);
>             }
>             credit_topup(lnk);
> {code}
> there is no condition about queued and also the resulting credit is set to 
> the link capacity 
>  (e.g 10 - delta) delta is delivery count reduced from by pn_do_flow,
> However this to me looks like some incompatibility between client and broker, 
> as one would not expect that delta is 10 if no messages are received from 
> broker. is this some kind of message sequencing problem?
>  
> fyi pn_link_queued messages does not mean they they are locally available 
> they might be still on broker and also getAvaialable implementation is wrong.
>  
>  
>  



--
This message was sent by Atlassian Jira
(v8.3.4#803005)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to