Qpid
  1. Qpid
  2. QPID-3232

fetch(timeout=0) does not behave as expected on receiver with capacity=1

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 0.10
    • Fix Version/s: 0.11
    • Component/s: Python Client
    • Labels:
      None

      Description

      Fill a queue up with some messages (some > 1). Create a receiver with capacity=1. Call fetch() in a loop with timeout=0.

      Expect to get all the messages that were on the queue to start with. Only get the first message.

      It appears to be a result of the client not restoring its credit correctly after the first flush.

        Activity

        Hide
        Rafael H. Schloming added a comment -

        This looks correct to me, I think at one point previously the driver didn't use returned in calculating the delta, so the ordering wouldn't be important, but I recall changing that at one point, and your reasoning makes sense now.

        Show
        Rafael H. Schloming added a comment - This looks correct to me, I think at one point previously the driver didn't use returned in calculating the delta, so the ordering wouldn't be important, but I recall changing that at one point, and your reasoning makes sense now.
        Hide
        Gordon Sim added a comment - - edited

        Suggested fix:

        Index: qpid/messaging/endpoints.py
        ===================================================================
        --- qpid/messaging/endpoints.py	(revision 1096729)
        +++ qpid/messaging/endpoints.py	(working copy)
        @@ -1007,9 +1007,9 @@
               self.draining = True
               self._wakeup()
               self._ecwait(lambda: not self.draining)
        +      msg = self.session._get(self, timeout=0)
               self._grant()
               self._wakeup()
        -      msg = self.session._get(self, timeout=0)
               if msg is None:
                 raise Empty()
             elif self._capacity not in (0, UNLIMITED.value):
        

        I.e. move the _grant() call (and associated wakeup()) after the _get() call on the session that updates the returned count.

        Show
        Gordon Sim added a comment - - edited Suggested fix: Index: qpid/messaging/endpoints.py =================================================================== --- qpid/messaging/endpoints.py (revision 1096729) +++ qpid/messaging/endpoints.py (working copy) @@ -1007,9 +1007,9 @@ self.draining = True self._wakeup() self._ecwait(lambda: not self.draining) + msg = self.session._get(self, timeout=0) self._grant() self._wakeup() - msg = self.session._get(self, timeout=0) if msg is None: raise Empty() elif self._capacity not in (0, UNLIMITED.value): I.e. move the _grant() call (and associated wakeup()) after the _get() call on the session that updates the returned count.
        Hide
        Gordon Sim added a comment -

        In the receivers fetch() implementation, after waiting for draining to complete a call to _grant() is made - I assume to replenish the drained credit. However that call will not actually result in any more credit being issued when made during the first fetch() call in the above example. The returned count has not yet been updated, so granted remains at 1. In the drivers grant() call for the receiver, the delta is computed to be 0 (granted, received and impending are all 1). Only during the second fetch() call, after draining, is the _grant() call on the receiver reissued and at that point the returned counter has been updated so a message-flow is triggered - however this happens after the flush and so the fetch() will usually not return it.

        Show
        Gordon Sim added a comment - In the receivers fetch() implementation, after waiting for draining to complete a call to _grant() is made - I assume to replenish the drained credit. However that call will not actually result in any more credit being issued when made during the first fetch() call in the above example. The returned count has not yet been updated, so granted remains at 1. In the drivers grant() call for the receiver, the delta is computed to be 0 (granted, received and impending are all 1). Only during the second fetch() call, after draining, is the _grant() call on the receiver reissued and at that point the returned counter has been updated so a message-flow is triggered - however this happens after the flush and so the fetch() will usually not return it.

          People

          • Assignee:
            Gordon Sim
            Reporter:
            Gordon Sim
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development