You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@qpid.apache.org by jeremy <je...@gmail.com> on 2019/04/25 13:42:26 UTC

Managing the lifetime of a proton::delivery object

Hello,

In the client API we're writing, we let a consumer consume messages
asynchronously, receiving a future of a delivery. In the receiver handler,
we keep track of deliveries in a list, as such:
https://github.com/rabih-mourad/qpid-imperative-proton/blob/master/include/proton/imperative/Receiver.hpp#L59
The user can then get the delivery and accept/reject/release it:
https://github.com/rabih-mourad/qpid-imperative-proton/blob/master/src/Delivery.cpp#L7

The proton delivery operations (accept/reject/release) are asynchronous
(added on the work queue:
https://github.com/apache/qpid-proton/blob/7c0a3387a5096d86541dbddfeb55f36eb0b85dd8/c/src/core/engine.c#L732)
unless I'm mistaken. In the above delivery code, removing the delivery
object from the list as soon as we go out of scope
(https://github.com/rabih-mourad/qpid-imperative-proton/blob/master/src/Delivery.cpp#L11)
results in a random segfault, since at the time the accept is called on the
delivery in the work queue, the delivery would have been already removed
from the list.
As a solution, we thought of implementing on_delivery_settle on the
receiver's side, and removing the delivery there. However, we noticed that
on_delivery_settle is never called (delivery mode set to none on both sender
and receiver sides, sender auto_settle set to false, receiver auto ack set
to false). I tested with all delivery modes on both sides, and the
on_delivery_settle was never called. I attached the corresponding code. 

Got the following log:

broker on_container_start
[0x1021a70]:  -> AMQP
[0x1021a70]:0 -> @open(16)
[container-id="b7cdef05-f195-4760-b262-655d538f0419", hostname="127.0.0.1",
channel-max=32767]
[0x7f719c0032d0]:  <- AMQP
[0x7f719c0032d0]:0 <- @open(16)
[container-id="b7cdef05-f195-4760-b262-655d538f0419", hostname="127.0.0.1",
channel-max=32767]
broker on_connection_open
[0x7f719c0032d0]:  -> AMQP
[0x7f719c0032d0]:0 -> @open(16)
[container-id="64a68948-0d32-4c19-89c7-9d62c408e248", channel-max=32767]
[0x1021a70]:  <- AMQP
[0x1021a70]:0 <- @open(16)
[container-id="64a68948-0d32-4c19-89c7-9d62c408e248", channel-max=32767]
[0x1021a70]:0 -> @begin(17) [next-outgoing-id=0, incoming-window=2147483647,
outgoing-window=2147483647]
[0x1021a70]:0 -> @attach(18) [name="aacbdc5d-0b8e-474c-a9e7-bf0c5a1bbd25",
handle=0, role=true, snd-settle-mode=2, rcv-settle-mode=0,
source=@source(40) [address="examples", durable=0, timeout=0,
dynamic=false], target=@target(41) [durable=0, timeout=0, dynamic=false],
initial-delivery-count=0, max-message-size=0]
[0x1021a70]:0 -> @flow(19) [incoming-window=2147483647, next-outgoing-id=0,
outgoing-window=2147483647, handle=0, delivery-count=0, link-credit=10,
drain=false]
[0x7f719c0032d0]:0 <- @begin(17) [next-outgoing-id=0,
incoming-window=2147483647, outgoing-window=2147483647]
[0x7f719c0032d0]:0 <- @attach(18)
[name="aacbdc5d-0b8e-474c-a9e7-bf0c5a1bbd25", handle=0, role=true,
snd-settle-mode=2, rcv-settle-mode=0, source=@source(40)
[address="examples", durable=0, timeout=0, dynamic=false],
target=@target(41) [durable=0, timeout=0, dynamic=false],
initial-delivery-count=0, max-message-size=0]
[0x7f719c0032d0]:0 <- @flow(19) [incoming-window=2147483647,
next-outgoing-id=0, outgoing-window=2147483647, handle=0, delivery-count=0,
link-credit=10, drain=false]
broker on_sendable
broker on_sendable
[0x7f719c0032d0]:0 -> @begin(17) [remote-channel=0, next-outgoing-id=0,
incoming-window=2147483647, outgoing-window=2147483647]
[0x7f719c0032d0]:0 -> @attach(18)
[name="aacbdc5d-0b8e-474c-a9e7-bf0c5a1bbd25", handle=0, role=false,
snd-settle-mode=2, rcv-settle-mode=0, source=@source(40)
[address="examples", durable=0, timeout=0, dynamic=false],
target=@target(41) [durable=0, timeout=0, dynamic=false],
initial-delivery-count=0, max-message-size=0]
[0x7f719c0032d0]:0 -> @transfer(20) [handle=0, delivery-id=0,
delivery-tag=b"\x01\x00\x00\x00\x00\x00\x00\x00", message-format=0] (23)
"\x00SpE\x00SsE\x00Sw\xa1\x0amy message"
broker on_sendable
[0x1021a70]:0 <- @begin(17) [remote-channel=0, next-outgoing-id=0,
incoming-window=2147483647, outgoing-window=2147483647]
[0x1021a70]:0 <- @attach(18) [name="aacbdc5d-0b8e-474c-a9e7-bf0c5a1bbd25",
handle=0, role=false, snd-settle-mode=2, rcv-settle-mode=0,
source=@source(40) [address="examples", durable=0, timeout=0,
dynamic=false], target=@target(41) [durable=0, timeout=0, dynamic=false],
initial-delivery-count=0, max-message-size=0]
[0x1021a70]:0 <- @transfer(20) [handle=0, delivery-id=0,
delivery-tag=b"\x01\x00\x00\x00\x00\x00\x00\x00", message-format=0] (23)
"\x00SpE\x00SsE\x00Sw\xa1\x0amy message"
my message
on_message settled:0
[0x1021a70]:0 -> @flow(19) [next-incoming-id=1, incoming-window=2147483647,
next-outgoing-id=0, outgoing-window=2147483647, handle=0, delivery-count=1,
link-credit=10, drain=false]
[0x1021a70]:0 -> @disposition(21) [role=true, first=0, settled=true,
state=@accepted(36) []]
[0x7f719c0032d0]:0 <- @flow(19) [next-incoming-id=1,
incoming-window=2147483647, next-outgoing-id=0, outgoing-window=2147483647,
handle=0, delivery-count=1, link-credit=10, drain=false]
[0x7f719c0032d0]:0 <- @disposition(21) [role=true, first=0, settled=true,
state=@accepted(36) []]
broker on_sendable
broker on_tracker_accept
broker on_tracker_settle


DeliverySettleTest.cpp
<http://qpid.2158936.n2.nabble.com/file/t396337/DeliverySettleTest.cpp>  
Broker.hpp <http://qpid.2158936.n2.nabble.com/file/t396337/Broker.hpp>  

Thanks,
Jeremy



-----
Cheers,
Jeremy
--
Sent from: http://qpid.2158936.n2.nabble.com/Apache-Qpid-users-f2158936.html

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@qpid.apache.org
For additional commands, e-mail: users-help@qpid.apache.org


Re: Managing the lifetime of a proton::delivery object

Posted by Cliff Jansen <cl...@gmail.com>.
Hi Rabih,

Thank you for the concise test case.

I believe the problem is that you are using

  proton::delivery::work_queue()

from the exterior thread, and that call is not thread safe.

If you look at the multithreaded client examples, you will see that
the work_queue is acquired and saved into a member variable called
"work_queue_".  This is done in the Proton callback thread, where it
is thread safe.  The fact that the example is using an accessor also
called "work_queue()" perhaps distracts from its message that

  proton::work_queue::add()

is the thread safety mechanism.

I would also note that proton::connection::work_queue() has less
thread-unsafe moving parts, and perhaps very difficult to go awry in
the manner that you use it (as a counterexample in Main.cpp), but it
is thread-unsafe too.

Cliff

On Tue, Apr 30, 2019 at 4:55 AM Rabih M <ra...@gmail.com> wrote:
>
> Hello Cliff,
>
> After spending more time debugging, I think we found where the real problem comes from:
> I attached a simplified use case in the Main.cpp, Broker.hpp.
> When we call delivery.work_queue().add() line 35 of Main.cpp, we get an random segfault and if we replace it instead by a connection.work_queue().add() everything comes back to normal.
>
> I tried to think about what might be the source of the problem but i can't find any ideas yet...
>
> Best regards,
> Rabih
>
>
>
> On Fri, Apr 26, 2019 at 9:38 AM Cliff Jansen <cl...@gmail.com> wrote:
>>
>> Hi Jeremy,
>>
>> I haven't had a chance to parse your overall description to arrive at
>> a reproducer of your segfault problem.
>>
>> However, the DeliverySettleTest.cpp code you provided runs correctly.
>> The client view of the delivery is settled via
>>
>>   d.accept();  // line 34
>>
>> which results in the disposition frame including "settled=true" sent
>> to the server (class Broker).  This also means that the client locally
>> has determined that (in AMQP terminology) it is now "safe to forget"
>> the disposition.  No changes to the disposition are legal after that,
>> and no callbacks about the disposition would be expected either.
>>
>> On the server side, in both on_tracker_accept() and
>> on_tracker_settle() you would find that t.settled() is true, as you
>> would expect.  The call to
>>
>>   t.settle();  // line 147 Broker.hpp
>>
>> is important to release memory since auto_settle has been turned off.
>> But proton knows that the peer has settled and forgotten the delivery.
>> So it sensibly declines to send a disposition frame (about a forgotten
>> entity) that would be ignored by the client as per the AMQP spec.
>>
>> Note that the above explanation is C++ specific.  If you use lower
>> level C primitives, it is possible to accept a delivery without
>> settling it until later and get closer to what you appear to be
>> striving for in this test.
>>
>> However, I can't help thinking that relying on two wire transfers,
>> which could be arbitrarily slow, is the mechanism you want to pursue
>> to avoid the (lifecycle?) segfault you are trying to address.
>>
>> Perhaps you could post the actual code with the segfault problem for
>> me to look at.
>>
>> On Thu, Apr 25, 2019 at 6:42 AM jeremy <je...@gmail.com> wrote:
>>
>> > Hello,
>> >
>> > In the client API we're writing, we let a consumer consume messages
>> > asynchronously, receiving a future of a delivery. In the receiver handler,
>> > we keep track of deliveries in a list, as such:
>> >
>> > https://github.com/rabih-mourad/qpid-imperative-proton/blob/master/include/proton/imperative/Receiver.hpp#L59
>> > The user can then get the delivery and accept/reject/release it:
>> >
>> > https://github.com/rabih-mourad/qpid-imperative-proton/blob/master/src/Delivery.cpp#L7
>> >
>> > The proton delivery operations (accept/reject/release) are asynchronous
>> > (added on the work queue:
>> >
>> > https://github.com/apache/qpid-proton/blob/7c0a3387a5096d86541dbddfeb55f36eb0b85dd8/c/src/core/engine.c#L732
>> > )
>> > unless I'm mistaken. In the above delivery code, removing the delivery
>> > object from the list as soon as we go out of scope
>> > (
>> > https://github.com/rabih-mourad/qpid-imperative-proton/blob/master/src/Delivery.cpp#L11
>> > )
>> > results in a random segfault, since at the time the accept is called on the
>> > delivery in the work queue, the delivery would have been already removed
>> > from the list.
>> > As a solution, we thought of implementing on_delivery_settle on the
>> > receiver's side, and removing the delivery there. However, we noticed that
>> > on_delivery_settle is never called (delivery mode set to none on both
>> > sender
>> > and receiver sides, sender auto_settle set to false, receiver auto ack set
>> > to false). I tested with all delivery modes on both sides, and the
>> > on_delivery_settle was never called. I attached the corresponding code.
>> >
>> > Got the following log:
>> >
>> > broker on_container_start
>> > [0x1021a70]:  -> AMQP
>> > [0x1021a70]:0 -> @open(16)
>> > [container-id="b7cdef05-f195-4760-b262-655d538f0419", hostname="127.0.0.1",
>> > channel-max=32767]
>> > [0x7f719c0032d0]:  <- AMQP
>> > [0x7f719c0032d0]:0 <- @open(16)
>> > [container-id="b7cdef05-f195-4760-b262-655d538f0419", hostname="127.0.0.1",
>> > channel-max=32767]
>> > broker on_connection_open
>> > [0x7f719c0032d0]:  -> AMQP
>> > [0x7f719c0032d0]:0 -> @open(16)
>> > [container-id="64a68948-0d32-4c19-89c7-9d62c408e248", channel-max=32767]
>> > [0x1021a70]:  <- AMQP
>> > [0x1021a70]:0 <- @open(16)
>> > [container-id="64a68948-0d32-4c19-89c7-9d62c408e248", channel-max=32767]
>> > [0x1021a70]:0 -> @begin(17) [next-outgoing-id=0,
>> > incoming-window=2147483647,
>> > outgoing-window=2147483647]
>> > [0x1021a70]:0 -> @attach(18) [name="aacbdc5d-0b8e-474c-a9e7-bf0c5a1bbd25",
>> > handle=0, role=true, snd-settle-mode=2, rcv-settle-mode=0,
>> > source=@source(40) [address="examples", durable=0, timeout=0,
>> > dynamic=false], target=@target(41) [durable=0, timeout=0, dynamic=false],
>> > initial-delivery-count=0, max-message-size=0]
>> > [0x1021a70]:0 -> @flow(19) [incoming-window=2147483647, next-outgoing-id=0,
>> > outgoing-window=2147483647, handle=0, delivery-count=0, link-credit=10,
>> > drain=false]
>> > [0x7f719c0032d0]:0 <- @begin(17) [next-outgoing-id=0,
>> > incoming-window=2147483647, outgoing-window=2147483647]
>> > [0x7f719c0032d0]:0 <- @attach(18)
>> > [name="aacbdc5d-0b8e-474c-a9e7-bf0c5a1bbd25", handle=0, role=true,
>> > snd-settle-mode=2, rcv-settle-mode=0, source=@source(40)
>> > [address="examples", durable=0, timeout=0, dynamic=false],
>> > target=@target(41) [durable=0, timeout=0, dynamic=false],
>> > initial-delivery-count=0, max-message-size=0]
>> > [0x7f719c0032d0]:0 <- @flow(19) [incoming-window=2147483647,
>> > next-outgoing-id=0, outgoing-window=2147483647, handle=0, delivery-count=0,
>> > link-credit=10, drain=false]
>> > broker on_sendable
>> > broker on_sendable
>> > [0x7f719c0032d0]:0 -> @begin(17) [remote-channel=0, next-outgoing-id=0,
>> > incoming-window=2147483647, outgoing-window=2147483647]
>> > [0x7f719c0032d0]:0 -> @attach(18)
>> > [name="aacbdc5d-0b8e-474c-a9e7-bf0c5a1bbd25", handle=0, role=false,
>> > snd-settle-mode=2, rcv-settle-mode=0, source=@source(40)
>> > [address="examples", durable=0, timeout=0, dynamic=false],
>> > target=@target(41) [durable=0, timeout=0, dynamic=false],
>> > initial-delivery-count=0, max-message-size=0]
>> > [0x7f719c0032d0]:0 -> @transfer(20) [handle=0, delivery-id=0,
>> > delivery-tag=b"\x01\x00\x00\x00\x00\x00\x00\x00", message-format=0] (23)
>> > "\x00SpE\x00SsE\x00Sw\xa1\x0amy message"
>> > broker on_sendable
>> > [0x1021a70]:0 <- @begin(17) [remote-channel=0, next-outgoing-id=0,
>> > incoming-window=2147483647, outgoing-window=2147483647]
>> > [0x1021a70]:0 <- @attach(18) [name="aacbdc5d-0b8e-474c-a9e7-bf0c5a1bbd25",
>> > handle=0, role=false, snd-settle-mode=2, rcv-settle-mode=0,
>> > source=@source(40) [address="examples", durable=0, timeout=0,
>> > dynamic=false], target=@target(41) [durable=0, timeout=0, dynamic=false],
>> > initial-delivery-count=0, max-message-size=0]
>> > [0x1021a70]:0 <- @transfer(20) [handle=0, delivery-id=0,
>> > delivery-tag=b"\x01\x00\x00\x00\x00\x00\x00\x00", message-format=0] (23)
>> > "\x00SpE\x00SsE\x00Sw\xa1\x0amy message"
>> > my message
>> > on_message settled:0
>> > [0x1021a70]:0 -> @flow(19) [next-incoming-id=1, incoming-window=2147483647,
>> > next-outgoing-id=0, outgoing-window=2147483647, handle=0, delivery-count=1,
>> > link-credit=10, drain=false]
>> > [0x1021a70]:0 -> @disposition(21) [role=true, first=0, settled=true,
>> > state=@accepted(36) []]
>> > [0x7f719c0032d0]:0 <- @flow(19) [next-incoming-id=1,
>> > incoming-window=2147483647, next-outgoing-id=0, outgoing-window=2147483647,
>> > handle=0, delivery-count=1, link-credit=10, drain=false]
>> > [0x7f719c0032d0]:0 <- @disposition(21) [role=true, first=0, settled=true,
>> > state=@accepted(36) []]
>> > broker on_sendable
>> > broker on_tracker_accept
>> > broker on_tracker_settle
>> >
>> >
>> > DeliverySettleTest.cpp
>> > <http://qpid.2158936.n2.nabble.com/file/t396337/DeliverySettleTest.cpp>
>> > Broker.hpp <http://qpid.2158936.n2.nabble.com/file/t396337/Broker.hpp>
>> >
>> > Thanks,
>> > Jeremy
>> >
>> >
>> >
>> > -----
>> > Cheers,
>> > Jeremy
>> > --
>> > Sent from:
>> > http://qpid.2158936.n2.nabble.com/Apache-Qpid-users-f2158936.html
>> >
>> > ---------------------------------------------------------------------
>> > To unsubscribe, e-mail: users-unsubscribe@qpid.apache.org
>> > For additional commands, e-mail: users-help@qpid.apache.org
>> >
>> >
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@qpid.apache.org
> For additional commands, e-mail: users-help@qpid.apache.org

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@qpid.apache.org
For additional commands, e-mail: users-help@qpid.apache.org


Re: Managing the lifetime of a proton::delivery object

Posted by Rabih M <ra...@gmail.com>.
Hello Cliff,

After spending more time debugging, I think we found where the real problem
comes from:
I attached a simplified use case in the Main.cpp, Broker.hpp.
When we call delivery.work_queue().add() line 35 of Main.cpp, we get an
random segfault and if we replace it instead by a
connection.work_queue().add() everything comes back to normal.

I tried to think about what might be the source of the problem but i can't
find any ideas yet...

Best regards,
Rabih



On Fri, Apr 26, 2019 at 9:38 AM Cliff Jansen <cl...@gmail.com> wrote:

> Hi Jeremy,
>
> I haven't had a chance to parse your overall description to arrive at
> a reproducer of your segfault problem.
>
> However, the DeliverySettleTest.cpp code you provided runs correctly.
> The client view of the delivery is settled via
>
>   d.accept();  // line 34
>
> which results in the disposition frame including "settled=true" sent
> to the server (class Broker).  This also means that the client locally
> has determined that (in AMQP terminology) it is now "safe to forget"
> the disposition.  No changes to the disposition are legal after that,
> and no callbacks about the disposition would be expected either.
>
> On the server side, in both on_tracker_accept() and
> on_tracker_settle() you would find that t.settled() is true, as you
> would expect.  The call to
>
>   t.settle();  // line 147 Broker.hpp
>
> is important to release memory since auto_settle has been turned off.
> But proton knows that the peer has settled and forgotten the delivery.
> So it sensibly declines to send a disposition frame (about a forgotten
> entity) that would be ignored by the client as per the AMQP spec.
>
> Note that the above explanation is C++ specific.  If you use lower
> level C primitives, it is possible to accept a delivery without
> settling it until later and get closer to what you appear to be
> striving for in this test.
>
> However, I can't help thinking that relying on two wire transfers,
> which could be arbitrarily slow, is the mechanism you want to pursue
> to avoid the (lifecycle?) segfault you are trying to address.
>
> Perhaps you could post the actual code with the segfault problem for
> me to look at.
>
> On Thu, Apr 25, 2019 at 6:42 AM jeremy <je...@gmail.com> wrote:
>
> > Hello,
> >
> > In the client API we're writing, we let a consumer consume messages
> > asynchronously, receiving a future of a delivery. In the receiver
> handler,
> > we keep track of deliveries in a list, as such:
> >
> >
> https://github.com/rabih-mourad/qpid-imperative-proton/blob/master/include/proton/imperative/Receiver.hpp#L59
> > The user can then get the delivery and accept/reject/release it:
> >
> >
> https://github.com/rabih-mourad/qpid-imperative-proton/blob/master/src/Delivery.cpp#L7
> >
> > The proton delivery operations (accept/reject/release) are asynchronous
> > (added on the work queue:
> >
> >
> https://github.com/apache/qpid-proton/blob/7c0a3387a5096d86541dbddfeb55f36eb0b85dd8/c/src/core/engine.c#L732
> > )
> > unless I'm mistaken. In the above delivery code, removing the delivery
> > object from the list as soon as we go out of scope
> > (
> >
> https://github.com/rabih-mourad/qpid-imperative-proton/blob/master/src/Delivery.cpp#L11
> > )
> > results in a random segfault, since at the time the accept is called on
> the
> > delivery in the work queue, the delivery would have been already removed
> > from the list.
> > As a solution, we thought of implementing on_delivery_settle on the
> > receiver's side, and removing the delivery there. However, we noticed
> that
> > on_delivery_settle is never called (delivery mode set to none on both
> > sender
> > and receiver sides, sender auto_settle set to false, receiver auto ack
> set
> > to false). I tested with all delivery modes on both sides, and the
> > on_delivery_settle was never called. I attached the corresponding code.
> >
> > Got the following log:
> >
> > broker on_container_start
> > [0x1021a70]:  -> AMQP
> > [0x1021a70]:0 -> @open(16)
> > [container-id="b7cdef05-f195-4760-b262-655d538f0419",
> hostname="127.0.0.1",
> > channel-max=32767]
> > [0x7f719c0032d0]:  <- AMQP
> > [0x7f719c0032d0]:0 <- @open(16)
> > [container-id="b7cdef05-f195-4760-b262-655d538f0419",
> hostname="127.0.0.1",
> > channel-max=32767]
> > broker on_connection_open
> > [0x7f719c0032d0]:  -> AMQP
> > [0x7f719c0032d0]:0 -> @open(16)
> > [container-id="64a68948-0d32-4c19-89c7-9d62c408e248", channel-max=32767]
> > [0x1021a70]:  <- AMQP
> > [0x1021a70]:0 <- @open(16)
> > [container-id="64a68948-0d32-4c19-89c7-9d62c408e248", channel-max=32767]
> > [0x1021a70]:0 -> @begin(17) [next-outgoing-id=0,
> > incoming-window=2147483647,
> > outgoing-window=2147483647]
> > [0x1021a70]:0 -> @attach(18)
> [name="aacbdc5d-0b8e-474c-a9e7-bf0c5a1bbd25",
> > handle=0, role=true, snd-settle-mode=2, rcv-settle-mode=0,
> > source=@source(40) [address="examples", durable=0, timeout=0,
> > dynamic=false], target=@target(41) [durable=0, timeout=0, dynamic=false],
> > initial-delivery-count=0, max-message-size=0]
> > [0x1021a70]:0 -> @flow(19) [incoming-window=2147483647,
> next-outgoing-id=0,
> > outgoing-window=2147483647, handle=0, delivery-count=0, link-credit=10,
> > drain=false]
> > [0x7f719c0032d0]:0 <- @begin(17) [next-outgoing-id=0,
> > incoming-window=2147483647, outgoing-window=2147483647]
> > [0x7f719c0032d0]:0 <- @attach(18)
> > [name="aacbdc5d-0b8e-474c-a9e7-bf0c5a1bbd25", handle=0, role=true,
> > snd-settle-mode=2, rcv-settle-mode=0, source=@source(40)
> > [address="examples", durable=0, timeout=0, dynamic=false],
> > target=@target(41) [durable=0, timeout=0, dynamic=false],
> > initial-delivery-count=0, max-message-size=0]
> > [0x7f719c0032d0]:0 <- @flow(19) [incoming-window=2147483647,
> > next-outgoing-id=0, outgoing-window=2147483647, handle=0,
> delivery-count=0,
> > link-credit=10, drain=false]
> > broker on_sendable
> > broker on_sendable
> > [0x7f719c0032d0]:0 -> @begin(17) [remote-channel=0, next-outgoing-id=0,
> > incoming-window=2147483647, outgoing-window=2147483647]
> > [0x7f719c0032d0]:0 -> @attach(18)
> > [name="aacbdc5d-0b8e-474c-a9e7-bf0c5a1bbd25", handle=0, role=false,
> > snd-settle-mode=2, rcv-settle-mode=0, source=@source(40)
> > [address="examples", durable=0, timeout=0, dynamic=false],
> > target=@target(41) [durable=0, timeout=0, dynamic=false],
> > initial-delivery-count=0, max-message-size=0]
> > [0x7f719c0032d0]:0 -> @transfer(20) [handle=0, delivery-id=0,
> > delivery-tag=b"\x01\x00\x00\x00\x00\x00\x00\x00", message-format=0] (23)
> > "\x00SpE\x00SsE\x00Sw\xa1\x0amy message"
> > broker on_sendable
> > [0x1021a70]:0 <- @begin(17) [remote-channel=0, next-outgoing-id=0,
> > incoming-window=2147483647, outgoing-window=2147483647]
> > [0x1021a70]:0 <- @attach(18)
> [name="aacbdc5d-0b8e-474c-a9e7-bf0c5a1bbd25",
> > handle=0, role=false, snd-settle-mode=2, rcv-settle-mode=0,
> > source=@source(40) [address="examples", durable=0, timeout=0,
> > dynamic=false], target=@target(41) [durable=0, timeout=0, dynamic=false],
> > initial-delivery-count=0, max-message-size=0]
> > [0x1021a70]:0 <- @transfer(20) [handle=0, delivery-id=0,
> > delivery-tag=b"\x01\x00\x00\x00\x00\x00\x00\x00", message-format=0] (23)
> > "\x00SpE\x00SsE\x00Sw\xa1\x0amy message"
> > my message
> > on_message settled:0
> > [0x1021a70]:0 -> @flow(19) [next-incoming-id=1,
> incoming-window=2147483647,
> > next-outgoing-id=0, outgoing-window=2147483647, handle=0,
> delivery-count=1,
> > link-credit=10, drain=false]
> > [0x1021a70]:0 -> @disposition(21) [role=true, first=0, settled=true,
> > state=@accepted(36) []]
> > [0x7f719c0032d0]:0 <- @flow(19) [next-incoming-id=1,
> > incoming-window=2147483647, next-outgoing-id=0,
> outgoing-window=2147483647,
> > handle=0, delivery-count=1, link-credit=10, drain=false]
> > [0x7f719c0032d0]:0 <- @disposition(21) [role=true, first=0, settled=true,
> > state=@accepted(36) []]
> > broker on_sendable
> > broker on_tracker_accept
> > broker on_tracker_settle
> >
> >
> > DeliverySettleTest.cpp
> > <http://qpid.2158936.n2.nabble.com/file/t396337/DeliverySettleTest.cpp>
> > Broker.hpp <http://qpid.2158936.n2.nabble.com/file/t396337/Broker.hpp>
> >
> > Thanks,
> > Jeremy
> >
> >
> >
> > -----
> > Cheers,
> > Jeremy
> > --
> > Sent from:
> > http://qpid.2158936.n2.nabble.com/Apache-Qpid-users-f2158936.html
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: users-unsubscribe@qpid.apache.org
> > For additional commands, e-mail: users-help@qpid.apache.org
> >
> >
>

Re: Managing the lifetime of a proton::delivery object

Posted by Cliff Jansen <cl...@gmail.com>.
Hi Jeremy,

I haven't had a chance to parse your overall description to arrive at
a reproducer of your segfault problem.

However, the DeliverySettleTest.cpp code you provided runs correctly.
The client view of the delivery is settled via

  d.accept();  // line 34

which results in the disposition frame including "settled=true" sent
to the server (class Broker).  This also means that the client locally
has determined that (in AMQP terminology) it is now "safe to forget"
the disposition.  No changes to the disposition are legal after that,
and no callbacks about the disposition would be expected either.

On the server side, in both on_tracker_accept() and
on_tracker_settle() you would find that t.settled() is true, as you
would expect.  The call to

  t.settle();  // line 147 Broker.hpp

is important to release memory since auto_settle has been turned off.
But proton knows that the peer has settled and forgotten the delivery.
So it sensibly declines to send a disposition frame (about a forgotten
entity) that would be ignored by the client as per the AMQP spec.

Note that the above explanation is C++ specific.  If you use lower
level C primitives, it is possible to accept a delivery without
settling it until later and get closer to what you appear to be
striving for in this test.

However, I can't help thinking that relying on two wire transfers,
which could be arbitrarily slow, is the mechanism you want to pursue
to avoid the (lifecycle?) segfault you are trying to address.

Perhaps you could post the actual code with the segfault problem for
me to look at.

On Thu, Apr 25, 2019 at 6:42 AM jeremy <je...@gmail.com> wrote:

> Hello,
>
> In the client API we're writing, we let a consumer consume messages
> asynchronously, receiving a future of a delivery. In the receiver handler,
> we keep track of deliveries in a list, as such:
>
> https://github.com/rabih-mourad/qpid-imperative-proton/blob/master/include/proton/imperative/Receiver.hpp#L59
> The user can then get the delivery and accept/reject/release it:
>
> https://github.com/rabih-mourad/qpid-imperative-proton/blob/master/src/Delivery.cpp#L7
>
> The proton delivery operations (accept/reject/release) are asynchronous
> (added on the work queue:
>
> https://github.com/apache/qpid-proton/blob/7c0a3387a5096d86541dbddfeb55f36eb0b85dd8/c/src/core/engine.c#L732
> )
> unless I'm mistaken. In the above delivery code, removing the delivery
> object from the list as soon as we go out of scope
> (
> https://github.com/rabih-mourad/qpid-imperative-proton/blob/master/src/Delivery.cpp#L11
> )
> results in a random segfault, since at the time the accept is called on the
> delivery in the work queue, the delivery would have been already removed
> from the list.
> As a solution, we thought of implementing on_delivery_settle on the
> receiver's side, and removing the delivery there. However, we noticed that
> on_delivery_settle is never called (delivery mode set to none on both
> sender
> and receiver sides, sender auto_settle set to false, receiver auto ack set
> to false). I tested with all delivery modes on both sides, and the
> on_delivery_settle was never called. I attached the corresponding code.
>
> Got the following log:
>
> broker on_container_start
> [0x1021a70]:  -> AMQP
> [0x1021a70]:0 -> @open(16)
> [container-id="b7cdef05-f195-4760-b262-655d538f0419", hostname="127.0.0.1",
> channel-max=32767]
> [0x7f719c0032d0]:  <- AMQP
> [0x7f719c0032d0]:0 <- @open(16)
> [container-id="b7cdef05-f195-4760-b262-655d538f0419", hostname="127.0.0.1",
> channel-max=32767]
> broker on_connection_open
> [0x7f719c0032d0]:  -> AMQP
> [0x7f719c0032d0]:0 -> @open(16)
> [container-id="64a68948-0d32-4c19-89c7-9d62c408e248", channel-max=32767]
> [0x1021a70]:  <- AMQP
> [0x1021a70]:0 <- @open(16)
> [container-id="64a68948-0d32-4c19-89c7-9d62c408e248", channel-max=32767]
> [0x1021a70]:0 -> @begin(17) [next-outgoing-id=0,
> incoming-window=2147483647,
> outgoing-window=2147483647]
> [0x1021a70]:0 -> @attach(18) [name="aacbdc5d-0b8e-474c-a9e7-bf0c5a1bbd25",
> handle=0, role=true, snd-settle-mode=2, rcv-settle-mode=0,
> source=@source(40) [address="examples", durable=0, timeout=0,
> dynamic=false], target=@target(41) [durable=0, timeout=0, dynamic=false],
> initial-delivery-count=0, max-message-size=0]
> [0x1021a70]:0 -> @flow(19) [incoming-window=2147483647, next-outgoing-id=0,
> outgoing-window=2147483647, handle=0, delivery-count=0, link-credit=10,
> drain=false]
> [0x7f719c0032d0]:0 <- @begin(17) [next-outgoing-id=0,
> incoming-window=2147483647, outgoing-window=2147483647]
> [0x7f719c0032d0]:0 <- @attach(18)
> [name="aacbdc5d-0b8e-474c-a9e7-bf0c5a1bbd25", handle=0, role=true,
> snd-settle-mode=2, rcv-settle-mode=0, source=@source(40)
> [address="examples", durable=0, timeout=0, dynamic=false],
> target=@target(41) [durable=0, timeout=0, dynamic=false],
> initial-delivery-count=0, max-message-size=0]
> [0x7f719c0032d0]:0 <- @flow(19) [incoming-window=2147483647,
> next-outgoing-id=0, outgoing-window=2147483647, handle=0, delivery-count=0,
> link-credit=10, drain=false]
> broker on_sendable
> broker on_sendable
> [0x7f719c0032d0]:0 -> @begin(17) [remote-channel=0, next-outgoing-id=0,
> incoming-window=2147483647, outgoing-window=2147483647]
> [0x7f719c0032d0]:0 -> @attach(18)
> [name="aacbdc5d-0b8e-474c-a9e7-bf0c5a1bbd25", handle=0, role=false,
> snd-settle-mode=2, rcv-settle-mode=0, source=@source(40)
> [address="examples", durable=0, timeout=0, dynamic=false],
> target=@target(41) [durable=0, timeout=0, dynamic=false],
> initial-delivery-count=0, max-message-size=0]
> [0x7f719c0032d0]:0 -> @transfer(20) [handle=0, delivery-id=0,
> delivery-tag=b"\x01\x00\x00\x00\x00\x00\x00\x00", message-format=0] (23)
> "\x00SpE\x00SsE\x00Sw\xa1\x0amy message"
> broker on_sendable
> [0x1021a70]:0 <- @begin(17) [remote-channel=0, next-outgoing-id=0,
> incoming-window=2147483647, outgoing-window=2147483647]
> [0x1021a70]:0 <- @attach(18) [name="aacbdc5d-0b8e-474c-a9e7-bf0c5a1bbd25",
> handle=0, role=false, snd-settle-mode=2, rcv-settle-mode=0,
> source=@source(40) [address="examples", durable=0, timeout=0,
> dynamic=false], target=@target(41) [durable=0, timeout=0, dynamic=false],
> initial-delivery-count=0, max-message-size=0]
> [0x1021a70]:0 <- @transfer(20) [handle=0, delivery-id=0,
> delivery-tag=b"\x01\x00\x00\x00\x00\x00\x00\x00", message-format=0] (23)
> "\x00SpE\x00SsE\x00Sw\xa1\x0amy message"
> my message
> on_message settled:0
> [0x1021a70]:0 -> @flow(19) [next-incoming-id=1, incoming-window=2147483647,
> next-outgoing-id=0, outgoing-window=2147483647, handle=0, delivery-count=1,
> link-credit=10, drain=false]
> [0x1021a70]:0 -> @disposition(21) [role=true, first=0, settled=true,
> state=@accepted(36) []]
> [0x7f719c0032d0]:0 <- @flow(19) [next-incoming-id=1,
> incoming-window=2147483647, next-outgoing-id=0, outgoing-window=2147483647,
> handle=0, delivery-count=1, link-credit=10, drain=false]
> [0x7f719c0032d0]:0 <- @disposition(21) [role=true, first=0, settled=true,
> state=@accepted(36) []]
> broker on_sendable
> broker on_tracker_accept
> broker on_tracker_settle
>
>
> DeliverySettleTest.cpp
> <http://qpid.2158936.n2.nabble.com/file/t396337/DeliverySettleTest.cpp>
> Broker.hpp <http://qpid.2158936.n2.nabble.com/file/t396337/Broker.hpp>
>
> Thanks,
> Jeremy
>
>
>
> -----
> Cheers,
> Jeremy
> --
> Sent from:
> http://qpid.2158936.n2.nabble.com/Apache-Qpid-users-f2158936.html
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@qpid.apache.org
> For additional commands, e-mail: users-help@qpid.apache.org
>
>