From 04eb16ef34caf3a28265d3ba912a5b5c1757fefd Mon Sep 17 00:00:00 2001 From: Andrew Stitcher Date: Wed, 22 May 2024 18:02:36 -0400 Subject: [PATCH 1/8] WIP: Python work for better transaction support * Added an extra handler to the python binding so that we can handle transactioned dispositions --- python/proton/_handlers.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/python/proton/_handlers.py b/python/proton/_handlers.py index b225dda34..1771e3ad2 100644 --- a/python/proton/_handlers.py +++ b/python/proton/_handlers.py @@ -75,6 +75,8 @@ def on_delivery(self, event: Event): self.on_rejected(event) elif dlv.remote_state == Delivery.RELEASED or dlv.remote_state == Delivery.MODIFIED: self.on_released(event) + else: + self.on_delivery_updated(event) if dlv.settled: self.on_settled(event) if self.auto_settle: @@ -123,6 +125,17 @@ def on_released(self, event: Event): if self.delegate is not None: _dispatch(self.delegate, 'on_released', event) + def on_delivery_updated(self, event: Event): + """ + Called when the remote peer updates the status of a delivery to any state that is not + 'ACCEPT', 'REJECT', 'RELEASE' or 'MODIFY' + + :param event: The underlying event object. Use this to obtain further + information on the event. + """ + if self.delegate is not None: + _dispatch(self.delegate, 'on_delivery_updated', event) + def on_settled(self, event: Event): """ Called when the remote peer has settled the outgoing From 33c306dc7d2619a9bc357529d7103ad1fdbc1ed9 Mon Sep 17 00:00:00 2001 From: Andrew Stitcher Date: Wed, 22 May 2024 18:02:36 -0400 Subject: [PATCH 2/8] WIP: Python example broker work for better transaction support * Modified the Python example broker so that it understands transaction requests, prints some useful output about what is happening, but doesn't honor the transaction semantics. It will queue up transactioned messages immediately and also doesn't correctly handle outgoing message releases (but it doesn't for non-transactioned messages either --- python/examples/broker.py | 120 +++++++++++++++++++++++++++++++++----- 1 file changed, 107 insertions(+), 13 deletions(-) diff --git a/python/examples/broker.py b/python/examples/broker.py index 753b7af3f..3f59c9d3a 100755 --- a/python/examples/broker.py +++ b/python/examples/broker.py @@ -22,7 +22,7 @@ import optparse import uuid -from proton import Endpoint +from proton import Condition, Described, Disposition, Endpoint, Terminus from proton.handlers import MessagingHandler from proton.reactor import Container @@ -70,9 +70,11 @@ def _deliver_to(self, consumers): class Broker(MessagingHandler): def __init__(self, url): - super(Broker, self).__init__() + super().__init__(auto_accept=False) self.url = url self.queues = {} + self.txns = set() + self.acceptor = None def on_start(self, event): self.acceptor = event.container.listen(self.url) @@ -86,23 +88,63 @@ def on_connection_opening(self, event): event.connection.offered_capabilities = 'ANONYMOUS-RELAY' def on_link_opening(self, event): - if event.link.is_sender: - if event.link.remote_source.dynamic: + link = event.link + if link.is_sender: + if link.remote_source.dynamic: address = str(uuid.uuid4()) - event.link.source.address = address + link.source.address = address q = Queue(True) self.queues[address] = q - q.subscribe(event.link) - elif event.link.remote_source.address: - event.link.source.address = event.link.remote_source.address - self._queue(event.link.source.address).subscribe(event.link) - elif event.link.remote_target.address: - event.link.target.address = event.link.remote_target.address + q.subscribe(link) + elif link.remote_source.address: + link.source.address = link.remote_source.address + self._queue(link.source.address).subscribe(link) + elif link.remote_target.type == Terminus.COORDINATOR: + # Set up transaction coordinator + # Should check for compatible capabilities + # requested = link.remote_target.capabilities.get_object() + link.target.type = Terminus.COORDINATOR + link.target.copy(link.remote_target) + elif link.remote_target.address: + link.target.address = link.remote_target.address def _unsubscribe(self, link): if link.source.address in self.queues and self.queues[link.source.address].unsubscribe(link): del self.queues[link.source.address] + def _allocate_txn(self): + tid = bytes(str(uuid.uuid4()), 'UTF8') + self.txns.add(tid) + return tid + + def _settle_txn(self, tid): + self.txns.remove(tid) + + def _coordinator_message(self, msg, delivery): + body = msg.body + if isinstance(body, Described): + d = body.descriptor + if d == "amqp:declare:list": + # Allocate transaction id + tid = self._allocate_txn() + print(f"Declare: txn-id={tid}") + delivery.local.data = [tid] + delivery.update(0x33) + elif d == "amqp:discharge:list": + # Always accept commit/abort! + value = body.value + tid = bytes(value[0]) + failed = bool(value[1]) + if tid in self.txns: + print(f"Discharge: txn-id={tid}, failed={failed}") + self._settle_txn(tid) + delivery.update(Disposition.ACCEPTED) + else: + print(f"Discharge unknown txn-id: txn-id={tid}, failed={failed}") + delivery.local.condition = Condition('amqp:transaction:unknown-id') + delivery.update(Disposition.REJECTED) + delivery.settle() + def on_link_closing(self, event): if event.link.is_sender: self._unsubscribe(event.link) @@ -124,10 +166,62 @@ def on_sendable(self, event): self._queue(event.link.source.address).dispatch(event.link) def on_message(self, event): - address = event.link.target.address + link = event.link + delivery = event.delivery + msg = event.message + if link.target.type == Terminus.COORDINATOR: + # Deal with special transaction messages + self._coordinator_message(msg, delivery) + return + + address = link.target.address if address is None: - address = event.message.address + address = msg.address + + # Is this a transactioned message? + disposition = delivery.remote + if disposition.type == 0x34: + tid = bytes(disposition.data[0]) + if tid in self.txns: + print(f"Message: txn-id={tid}") + else: + print(f"Message unknown txn-id: txn-id={tid}") + delivery.local.condition = Condition('amqp:transaction:unknown-id') + delivery.update(Disposition.REJECTED) + delivery.settle() + return + self._queue(address).publish(event.message) + delivery.update(Disposition.ACCEPTED) + delivery.settle() + + def on_accepted(self, event): + delivery = event.delivery + print(f"Accept: delivery={delivery}") + + def on_rejected(self, event): + delivery = event.delivery + print(f"Reject: delivery={delivery}") + + def on_released(self, event): + delivery = event.delivery + print(f"Released: delivery={delivery}") + + def on_delivery_updated(self, event): + # Is this a transactioned delivery update? + delivery = event.delivery + disposition = delivery.remote + if disposition.type == 0x34: + tid = bytes(disposition.data[0]) + outcome = disposition.data[1] + if tid in self.txns: + print(f"Delivery update: txn-id={tid} outcome={outcome}") + else: + print(f"Message unknown txn-id: txn-id={tid}") + delivery.local.condition = Condition('amqp:transaction:unknown-id') + delivery.update(Disposition.REJECTED) + delivery.settle() + return def main(): From baa68cee7828ab6023463b3a58b026486a7ad119 Mon Sep 17 00:00:00 2001 From: Rakhi Kumari Date: Thu, 30 May 2024 22:18:29 +0530 Subject: [PATCH 3/8] Implement local transactions --- cpp/examples/tx_send.cpp | 137 ++++++++++++++++++++++++++ cpp/include/proton/container.hpp | 1 + cpp/include/proton/target_options.hpp | 2 + cpp/include/proton/tracker.hpp | 9 ++ cpp/include/proton/transaction.hpp | 85 ++++++++++++++++ cpp/src/container.cpp | 42 ++++++++ cpp/src/handler.cpp | 1 + cpp/src/node_options.cpp | 5 + cpp/src/tracker.cpp | 3 + cpp/src/transaction.cpp | 83 ++++++++++++++++ 10 files changed, 368 insertions(+) create mode 100644 cpp/examples/tx_send.cpp create mode 100644 cpp/include/proton/transaction.hpp create mode 100644 cpp/src/transaction.cpp diff --git a/cpp/examples/tx_send.cpp b/cpp/examples/tx_send.cpp new file mode 100644 index 000000000..d756b32a5 --- /dev/null +++ b/cpp/examples/tx_send.cpp @@ -0,0 +1,137 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include "options.hpp" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +class tx_send : public proton::messaging_handler, proton::transaction_handler { + private: + proton::sender sender; + std::string url; + int total; + int batch_size; + int sent; + int current_batch = 0; + int committed = 0; + int confirmed = 0; + proton::container *container; + proton::transaction_handler transaction_handler; + proton::Transaction *transaction; + proton::connection connection; + public: + tx_send(const std::string &s, int c, int b): + url(s), total(c), batch_size(b), sent(0) {} + + void on_container_start(proton::container &c) override { + container = &c; // TODO: Fix error + sender = c.open_sender(url); + connection = sender.connection(); + transaction = NULL; + c.declare_transaction(connection, transaction_handler); + } + + void on_transaction_declared(proton::Transaction &t) override { + transaction = &t; + send(); + } + + void on_sendable(proton::sender &s) override { + send(); + } + + void send() { + // TODO: Add more condition in while loop + while (transaction && sender.credit() && (committed + current_batch) < total) + { + proton::message msg; + std::map m; + m["sequence"] = committed + current_batch; + + msg.id(committed + current_batch + 1); + msg.body(m); + current_batch += 1; + if(current_batch == batch_size) + { + transaction->commit(); + transaction = NULL; + } + } + + } + + void on_tracker_accept(proton::tracker &t) override { + confirmed += 1; + } + + void on_transaction_committed(proton::Transaction &t) override { + committed += current_batch; + if(committed == total) { + std::cout << "All messages committed"; + connection.close(); + } + else { + current_batch = 0; + container->declare_transaction(connection, transaction_handler); + } + } + + void on_sender_close(proton::sender &s) override { + current_batch = 0; + } + +}; + +int main(int argc, char **argv) { + std::string address("127.0.0.1:5672/examples"); + int message_count = 100; + int batch_size = 10; + example::options opts(argc, argv); + + opts.add_value(address, 'a', "address", "connect and send to URL", "URL"); + opts.add_value(message_count, 'm', "messages", "number of messages to send", "COUNT"); + opts.add_value(batch_size, 'b', "batch_size", "number of messages in each transaction", "BATCH_SIZE"); + + try { + opts.parse(); + + tx_send send(address, message_count, batch_size); + proton::container(send).run(); + + return 0; + } catch (const example::bad_option& e) { + std::cout << opts << std::endl << e.what() << std::endl; + } catch (const std::exception& e) { + std::cerr << e.what() << std::endl; + } + + return 1; +} diff --git a/cpp/include/proton/container.hpp b/cpp/include/proton/container.hpp index 839cf8137..4ba0a2b9d 100644 --- a/cpp/include/proton/container.hpp +++ b/cpp/include/proton/container.hpp @@ -312,6 +312,7 @@ class PN_CPP_CLASS_EXTERN container { /// Cancel task for the given work_handle. PN_CPP_EXTERN void cancel(work_handle); + PN_CPP_EXTERN Transaction declare_transaction(proton::connection conn, proton::transaction_handler &handler, bool settle_before_discharge = false); private: /// Declare both v03 and v11 if compiling with c++11 as the library contains both. /// A C++11 user should never call the v03 overload so it is private in this case diff --git a/cpp/include/proton/target_options.hpp b/cpp/include/proton/target_options.hpp index f5fe99177..d09f4094e 100644 --- a/cpp/include/proton/target_options.hpp +++ b/cpp/include/proton/target_options.hpp @@ -88,6 +88,8 @@ class target_options { /// **Unsettled API** Set the dynamic node properties. PN_CPP_EXTERN target_options& dynamic_properties(const target::dynamic_property_map&); + PN_CPP_EXTERN target_options& type(const int); + private: void apply(target&) const; diff --git a/cpp/include/proton/tracker.hpp b/cpp/include/proton/tracker.hpp index 3d8ad0aab..b579aac59 100644 --- a/cpp/include/proton/tracker.hpp +++ b/cpp/include/proton/tracker.hpp @@ -25,6 +25,8 @@ #include "./binary.hpp" #include "./internal/export.hpp" #include "./transfer.hpp" +#include "./messaging_handler.hpp" +#include "./transaction.hpp" /// @file /// @copybrief proton::tracker @@ -43,6 +45,7 @@ class tracker : public transfer { tracker(pn_delivery_t* d); /// @endcond + Transaction *transaction; public: /// Create an empty tracker. tracker() = default; @@ -53,6 +56,12 @@ class tracker : public transfer { /// Get the tag for this tracker. PN_CPP_EXTERN binary tag() const; + // set_transaction here is a problem. As evry time we call it will change + // the pointer in current object and update won' be reflected in any copies of this tracker. + PN_CPP_EXTERN void set_transaction(Transaction *t); + + PN_CPP_EXTERN Transaction* get_transaction() const; + /// @cond INTERNAL friend class internal::factory; /// @endcond diff --git a/cpp/include/proton/transaction.hpp b/cpp/include/proton/transaction.hpp new file mode 100644 index 000000000..b5422be61 --- /dev/null +++ b/cpp/include/proton/transaction.hpp @@ -0,0 +1,85 @@ +#ifndef PROTON_TRANSACTION_HPP +#define PROTON_TRANSACTION_HPP + + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + + +#include "./fwd.hpp" +#include "./internal/export.hpp" +#include "./sender.hpp" +#include "./tracker.hpp" + +/// @file +/// @copybrief proton::transaction + +namespace proton { + +class +PN_CPP_CLASS_EXTERN Transaction { + proton::sender txn_ctrl; + proton::transaction_handler handler; + // TODO int + int id = 0; + proton::tracker _declare; + proton::tracker _discharge; + bool failed = false; + std::vector pending; + public: + // TODO: + PN_CPP_EXTERN Transaction(proton::sender _txn_ctrl, proton::transaction_handler _handler, bool _settle_before_discharge = false); + PN_CPP_EXTERN virtual ~Transaction(); + PN_CPP_EXTERN virtual void commit(); + PN_CPP_EXTERN virtual void abort(); + PN_CPP_EXTERN virtual void declare(); + PN_CPP_EXTERN virtual void discharge(bool failed); + PN_CPP_EXTERN virtual proton::tracker send_ctrl(proton::symbol descriptor, proton::value _value); + PN_CPP_EXTERN virtual proton::tracker send(proton::sender s, proton::message msg); + PN_CPP_EXTERN virtual void handle_outcome(proton::tracker t); +}; + +class +PN_CPP_CLASS_EXTERN transaction_handler { + + public: + PN_CPP_EXTERN transaction_handler(); + PN_CPP_EXTERN virtual ~transaction_handler(); + + /// Called when a local transaction is declared. + PN_CPP_EXTERN virtual void on_transaction_declared(Transaction&); + + /// Called when a local transaction is discharged successfully. + PN_CPP_EXTERN virtual void on_transaction_committed(Transaction&); + + /// Called when a local transaction is discharged unsuccessfully (aborted). + PN_CPP_EXTERN virtual void on_transaction_aborted(Transaction&); + + /// Called when a local transaction declare fails. + PN_CPP_EXTERN virtual void on_transaction_declare_failed(Transaction&); + + /// Called when the commit of a local transaction fails. + PN_CPP_EXTERN virtual void on_transaction_commit_failed(Transaction&); +}; + +} // namespace proton + +#endif // PROTON_TRANSACTION_HPP diff --git a/cpp/src/container.cpp b/cpp/src/container.cpp index 8189539de..a12133ffe 100644 --- a/cpp/src/container.cpp +++ b/cpp/src/container.cpp @@ -26,8 +26,12 @@ #include "proton/listen_handler.hpp" #include "proton/listener.hpp" #include "proton/uuid.hpp" +#include "proton/target_options.hpp" +#include "proton/sender_options.hpp" +#include "proton/transaction.hpp" #include "proactor_container_impl.hpp" +#include namespace proton { @@ -45,6 +49,44 @@ returned container::connect(const std::string &url) { return connect(url, connection_options()); } +Transaction container::declare_transaction(proton::connection conn, proton::transaction_handler &handler, bool settle_before_discharge) { + + proton::target_options t; + class InternalTransactionHandler : public proton::messaging_handler { + // TODO: auto_settle + void on_tracker_settle(proton::tracker &t) override { + if(t.get_transaction()) { + t.get_transaction()->handle_outcome(t); + } + } + + // TODO: Add on_unhandled function + }; + + // TODO: Sender should be created only once. (May be use Singleton Class) + // proton::target_options t; + + std::vector cap = {proton::symbol("amqp:local-transactions")}; + t.capabilities(cap); + // Type PN_COORDINATOR value is 3. It is a special target identifying a transaction coordinator. + // TODO: Change the type from int to enum. + t.type(3); + + proton::sender_options so; + so.name("txn-ctrl"); + // Todo: Check the value, Or by deafult null? + //so.source() ? + so.target(t); + InternalTransactionHandler internal_handler; // internal_handler going out of scope. Fix it + so.handler(internal_handler); + proton::sender s = conn.open_sender("does not matter", so); + + settle_before_discharge = false; + + return Transaction(s, handler, settle_before_discharge); + +} + returned container::open_sender(const std::string &url) { return open_sender(url, proton::sender_options(), connection_options()); } diff --git a/cpp/src/handler.cpp b/cpp/src/handler.cpp index 1632efda6..d9bb34313 100644 --- a/cpp/src/handler.cpp +++ b/cpp/src/handler.cpp @@ -34,6 +34,7 @@ #include "proton/connection.h" #include "proton/session.h" +#include "proton/tracker.hpp" namespace proton { diff --git a/cpp/src/node_options.cpp b/cpp/src/node_options.cpp index fd489baf3..ad8293efc 100644 --- a/cpp/src/node_options.cpp +++ b/cpp/src/node_options.cpp @@ -162,6 +162,7 @@ class target_options::impl { option expiry_policy; option > capabilities; option dynamic_properties; + option type; void apply(target& t) { node_address(t, address, dynamic, anonymous); @@ -175,6 +176,9 @@ class target_options::impl { get(dynamic_properties.value, target_map); value(pn_terminus_properties(unwrap(t))) = target_map; } + if (type.set) { + pn_terminus_set_type(unwrap(t), pn_terminus_type_t(type.value)); + } } }; @@ -200,6 +204,7 @@ target_options& target_options::dynamic_properties(const target::dynamic_propert impl_->dynamic_properties = c; return *this; } +target_options& target_options::type(int t) { impl_->type = t; return *this;} void target_options::apply(target& s) const { impl_->apply(s); } diff --git a/cpp/src/tracker.cpp b/cpp/src/tracker.cpp index e703767ef..a1e04c7b1 100644 --- a/cpp/src/tracker.cpp +++ b/cpp/src/tracker.cpp @@ -26,6 +26,7 @@ #include "proton_bits.hpp" #include "types_internal.hpp" #include "proton/binary.hpp" +#include "proton/transaction.hpp" #include @@ -34,4 +35,6 @@ namespace proton { tracker::tracker(pn_delivery_t *d): transfer(make_wrapper(d)) {} sender tracker::sender() const { return make_wrapper(pn_delivery_link(pn_object())); } binary tracker::tag() const { return bin(pn_delivery_tag(pn_object())); } +void tracker::set_transaction(Transaction *t) { this->transaction=t; } +Transaction* tracker::get_transaction() const { return this->transaction; } } diff --git a/cpp/src/transaction.cpp b/cpp/src/transaction.cpp new file mode 100644 index 000000000..4ab9b673f --- /dev/null +++ b/cpp/src/transaction.cpp @@ -0,0 +1,83 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include "proton/message.hpp" +#include "proton/transaction.hpp" +#include "proton/tracker.hpp" + +namespace proton { + +void transaction_handler::on_transaction_declared(Transaction &) {} +void transaction_handler::on_transaction_committed(Transaction &) {} +void transaction_handler::on_transaction_aborted(Transaction &) {} +void transaction_handler::on_transaction_declare_failed(Transaction &) {} +void transaction_handler::on_transaction_commit_failed(Transaction &) {} + +Transaction::Transaction(proton::sender _txn_ctrl, proton::transaction_handler _handler, bool _settle_before_discharge) { + txn_ctrl = _txn_ctrl; + handler = _handler; + bool settle_before_discharge = _settle_before_discharge; + declare(); +} + +void Transaction::commit() { + discharge(false); +} + +void Transaction::abort() { + discharge(true); +} + +void Transaction::declare() { + proton::symbol descriptor("amqp:declare:list"); + // proton::value _value = vd; + // TODO: How to make list; + std::vector vd({NULL}); + proton::value _value; + // proton::get() + _declare = send_ctrl(descriptor, _value ); +} + +void Transaction::discharge(bool failed) { + this->failed = failed; + proton::symbol descriptor("amqp:declare:list");; + proton::value _value; + proton::tracker discharge = send_ctrl(descriptor, _value); +} + +proton::tracker Transaction::send_ctrl(proton::symbol descriptor, proton::value _value) { + proton::message msg = _value; // TODO + proton::tracker delivery = txn_ctrl.send(msg); + delivery.set_transaction(this); + return delivery; +} + +proton::tracker Transaction::send(proton::sender s, proton::message msg) { + proton::tracker tracker = s.send(msg); + return tracker; +} + +void Transaction::handle_outcome(proton::tracker t) { + // this->handler.on_transaction_declared(); + +} + +} From ea79f4782fc1fa028756da86a3483d440c429483 Mon Sep 17 00:00:00 2001 From: Andrew Stitcher Date: Wed, 2 Oct 2024 15:57:52 -0400 Subject: [PATCH 4/8] WIP: Fix up to transactions work: * Make it compile * Make it fit the existing software structure better --- cpp/CMakeLists.txt | 1 + cpp/examples/tx_send.cpp | 6 +-- cpp/include/proton/container.hpp | 2 +- cpp/include/proton/fwd.hpp | 2 + cpp/include/proton/tracker.hpp | 7 --- cpp/include/proton/transaction.hpp | 30 ++++-------- cpp/include/proton/transfer.hpp | 5 ++ cpp/src/container.cpp | 41 +--------------- cpp/src/contexts.hpp | 2 + cpp/src/proactor_container_impl.cpp | 41 ++++++++++++++++ cpp/src/proactor_container_impl.hpp | 1 + cpp/src/tracker.cpp | 2 - cpp/src/transaction.cpp | 75 +++++++++++++++++++++-------- cpp/src/transfer.cpp | 10 ++++ 14 files changed, 131 insertions(+), 94 deletions(-) diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index c65cc8723..33ceb3cf2 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -120,6 +120,7 @@ set(qpid-proton-cpp-source src/terminus.cpp src/timestamp.cpp src/tracker.cpp + src/transaction.cpp src/transfer.cpp src/transport.cpp src/type_id.cpp diff --git a/cpp/examples/tx_send.cpp b/cpp/examples/tx_send.cpp index d756b32a5..a79c9fe93 100644 --- a/cpp/examples/tx_send.cpp +++ b/cpp/examples/tx_send.cpp @@ -45,7 +45,7 @@ class tx_send : public proton::messaging_handler, proton::transaction_handler { int confirmed = 0; proton::container *container; proton::transaction_handler transaction_handler; - proton::Transaction *transaction; + proton::transaction *transaction; proton::connection connection; public: tx_send(const std::string &s, int c, int b): @@ -59,7 +59,7 @@ class tx_send : public proton::messaging_handler, proton::transaction_handler { c.declare_transaction(connection, transaction_handler); } - void on_transaction_declared(proton::Transaction &t) override { + void on_transaction_declared(proton::transaction &t) override { transaction = &t; send(); } @@ -92,7 +92,7 @@ class tx_send : public proton::messaging_handler, proton::transaction_handler { confirmed += 1; } - void on_transaction_committed(proton::Transaction &t) override { + void on_transaction_committed(proton::transaction &t) override { committed += current_batch; if(committed == total) { std::cout << "All messages committed"; diff --git a/cpp/include/proton/container.hpp b/cpp/include/proton/container.hpp index 4ba0a2b9d..0b0e16a41 100644 --- a/cpp/include/proton/container.hpp +++ b/cpp/include/proton/container.hpp @@ -312,7 +312,7 @@ class PN_CPP_CLASS_EXTERN container { /// Cancel task for the given work_handle. PN_CPP_EXTERN void cancel(work_handle); - PN_CPP_EXTERN Transaction declare_transaction(proton::connection conn, proton::transaction_handler &handler, bool settle_before_discharge = false); + PN_CPP_EXTERN transaction declare_transaction(proton::connection conn, proton::transaction_handler &handler, bool settle_before_discharge = false); private: /// Declare both v03 and v11 if compiling with c++11 as the library contains both. /// A C++11 user should never call the v03 overload so it is private in this case diff --git a/cpp/include/proton/fwd.hpp b/cpp/include/proton/fwd.hpp index 801d26932..9fe5fc303 100644 --- a/cpp/include/proton/fwd.hpp +++ b/cpp/include/proton/fwd.hpp @@ -55,6 +55,8 @@ class source_options; class ssl; class target_options; class tracker; +class transaction; +class transaction_handler; class transport; class url; class void_function0; diff --git a/cpp/include/proton/tracker.hpp b/cpp/include/proton/tracker.hpp index b579aac59..c6bf45721 100644 --- a/cpp/include/proton/tracker.hpp +++ b/cpp/include/proton/tracker.hpp @@ -45,7 +45,6 @@ class tracker : public transfer { tracker(pn_delivery_t* d); /// @endcond - Transaction *transaction; public: /// Create an empty tracker. tracker() = default; @@ -56,12 +55,6 @@ class tracker : public transfer { /// Get the tag for this tracker. PN_CPP_EXTERN binary tag() const; - // set_transaction here is a problem. As evry time we call it will change - // the pointer in current object and update won' be reflected in any copies of this tracker. - PN_CPP_EXTERN void set_transaction(Transaction *t); - - PN_CPP_EXTERN Transaction* get_transaction() const; - /// @cond INTERNAL friend class internal::factory; /// @endcond diff --git a/cpp/include/proton/transaction.hpp b/cpp/include/proton/transaction.hpp index b5422be61..5a74749ed 100644 --- a/cpp/include/proton/transaction.hpp +++ b/cpp/include/proton/transaction.hpp @@ -34,50 +34,38 @@ namespace proton { +class transaction_handler; + class -PN_CPP_CLASS_EXTERN Transaction { - proton::sender txn_ctrl; - proton::transaction_handler handler; - // TODO int - int id = 0; - proton::tracker _declare; - proton::tracker _discharge; - bool failed = false; - std::vector pending; +PN_CPP_CLASS_EXTERN transaction { public: // TODO: - PN_CPP_EXTERN Transaction(proton::sender _txn_ctrl, proton::transaction_handler _handler, bool _settle_before_discharge = false); - PN_CPP_EXTERN virtual ~Transaction(); + PN_CPP_EXTERN virtual ~transaction(); PN_CPP_EXTERN virtual void commit(); PN_CPP_EXTERN virtual void abort(); PN_CPP_EXTERN virtual void declare(); - PN_CPP_EXTERN virtual void discharge(bool failed); - PN_CPP_EXTERN virtual proton::tracker send_ctrl(proton::symbol descriptor, proton::value _value); PN_CPP_EXTERN virtual proton::tracker send(proton::sender s, proton::message msg); - PN_CPP_EXTERN virtual void handle_outcome(proton::tracker t); }; class PN_CPP_CLASS_EXTERN transaction_handler { - public: - PN_CPP_EXTERN transaction_handler(); PN_CPP_EXTERN virtual ~transaction_handler(); /// Called when a local transaction is declared. - PN_CPP_EXTERN virtual void on_transaction_declared(Transaction&); + PN_CPP_EXTERN virtual void on_transaction_declared(transaction&); /// Called when a local transaction is discharged successfully. - PN_CPP_EXTERN virtual void on_transaction_committed(Transaction&); + PN_CPP_EXTERN virtual void on_transaction_committed(transaction&); /// Called when a local transaction is discharged unsuccessfully (aborted). - PN_CPP_EXTERN virtual void on_transaction_aborted(Transaction&); + PN_CPP_EXTERN virtual void on_transaction_aborted(transaction&); /// Called when a local transaction declare fails. - PN_CPP_EXTERN virtual void on_transaction_declare_failed(Transaction&); + PN_CPP_EXTERN virtual void on_transaction_declare_failed(transaction&); /// Called when the commit of a local transaction fails. - PN_CPP_EXTERN virtual void on_transaction_commit_failed(Transaction&); + PN_CPP_EXTERN virtual void on_transaction_commit_failed(transaction&); }; } // namespace proton diff --git a/cpp/include/proton/transfer.hpp b/cpp/include/proton/transfer.hpp index cf0474a75..d74392f41 100644 --- a/cpp/include/proton/transfer.hpp +++ b/cpp/include/proton/transfer.hpp @@ -77,6 +77,11 @@ class transfer : public internal::object { /// Return true if the transfer has been settled. PN_CPP_EXTERN bool settled() const; + // Set transaction + PN_CPP_EXTERN void transaction(transaction& t); + + PN_CPP_EXTERN class transaction* transaction() const; + /// Set user data on this transfer. PN_CPP_EXTERN void user_data(void* user_data) const; diff --git a/cpp/src/container.cpp b/cpp/src/container.cpp index a12133ffe..427da590f 100644 --- a/cpp/src/container.cpp +++ b/cpp/src/container.cpp @@ -26,9 +26,6 @@ #include "proton/listen_handler.hpp" #include "proton/listener.hpp" #include "proton/uuid.hpp" -#include "proton/target_options.hpp" -#include "proton/sender_options.hpp" -#include "proton/transaction.hpp" #include "proactor_container_impl.hpp" #include @@ -49,42 +46,8 @@ returned container::connect(const std::string &url) { return connect(url, connection_options()); } -Transaction container::declare_transaction(proton::connection conn, proton::transaction_handler &handler, bool settle_before_discharge) { - - proton::target_options t; - class InternalTransactionHandler : public proton::messaging_handler { - // TODO: auto_settle - void on_tracker_settle(proton::tracker &t) override { - if(t.get_transaction()) { - t.get_transaction()->handle_outcome(t); - } - } - - // TODO: Add on_unhandled function - }; - - // TODO: Sender should be created only once. (May be use Singleton Class) - // proton::target_options t; - - std::vector cap = {proton::symbol("amqp:local-transactions")}; - t.capabilities(cap); - // Type PN_COORDINATOR value is 3. It is a special target identifying a transaction coordinator. - // TODO: Change the type from int to enum. - t.type(3); - - proton::sender_options so; - so.name("txn-ctrl"); - // Todo: Check the value, Or by deafult null? - //so.source() ? - so.target(t); - InternalTransactionHandler internal_handler; // internal_handler going out of scope. Fix it - so.handler(internal_handler); - proton::sender s = conn.open_sender("does not matter", so); - - settle_before_discharge = false; - - return Transaction(s, handler, settle_before_discharge); - +transaction container::declare_transaction(proton::connection conn, proton::transaction_handler &handler, bool settle_before_discharge) { + return impl_->declare_transaction(conn, handler, settle_before_discharge); } returned container::open_sender(const std::string &url) { diff --git a/cpp/src/contexts.hpp b/cpp/src/contexts.hpp index 7ebab1d7b..06a8c3f6e 100644 --- a/cpp/src/contexts.hpp +++ b/cpp/src/contexts.hpp @@ -41,6 +41,7 @@ namespace proton { class proton_handler; class connector; +class transaction; namespace io {class link_namer;} @@ -161,6 +162,7 @@ class transfer_context : public context { transfer_context() : user_data_(nullptr) {} static transfer_context& get(pn_delivery_t* s); + transaction* transaction_; void* user_data_; }; diff --git a/cpp/src/proactor_container_impl.cpp b/cpp/src/proactor_container_impl.cpp index 228002e38..290a4944b 100644 --- a/cpp/src/proactor_container_impl.cpp +++ b/cpp/src/proactor_container_impl.cpp @@ -26,6 +26,7 @@ #include "proton/listener.hpp" #include "proton/reconnect_options.hpp" #include "proton/ssl.hpp" +#include "proton/target_options.hpp" #include "proton/transport.hpp" #include "proton/url.hpp" @@ -860,4 +861,44 @@ void container::impl::stop(const proton::error_condition& err) { pn_condition_free(error_condition); } +// TODO: declare this in separate internal header file +extern transaction mk_transaction_impl(sender&, transaction_handler&, bool); + +transaction container::impl::declare_transaction(proton::connection conn, proton::transaction_handler &handler, bool settle_before_discharge) { + class InternalTransactionHandler : public proton::messaging_handler { + // TODO: auto_settle + void on_tracker_settle(proton::tracker &t) override { + if(t.transaction()) { + //t.transaction()->handle_outcome(t); + } + } + + // TODO: Add on_unhandled function + }; + + // TODO: Sender should be created only once. (May be use Singleton Class) + // proton::target_options t; + + proton::target_options t; + std::vector cap = {proton::symbol("amqp:local-transactions")}; + t.capabilities(cap); + // Type PN_COORDINATOR value is 3. It is a special target identifying a transaction coordinator. + // TODO: Change the type from int to enum. + t.type(3); + + proton::sender_options so; + so.name("txn-ctrl"); + // Todo: Check the value, Or by deafult null? + //so.source() ? + so.target(t); + InternalTransactionHandler internal_handler; // internal_handler going out of scope. Fix it + so.handler(internal_handler); + proton::sender s = conn.open_sender("does not matter", so); + + settle_before_discharge = false; + + return mk_transaction_impl(s, handler, settle_before_discharge); + +} + } diff --git a/cpp/src/proactor_container_impl.hpp b/cpp/src/proactor_container_impl.hpp index 1f87e7636..5d8b92a8b 100644 --- a/cpp/src/proactor_container_impl.hpp +++ b/cpp/src/proactor_container_impl.hpp @@ -91,6 +91,7 @@ class container::impl { template static messaging_handler* get_handler(T s); messaging_handler* get_handler(pn_event_t *event); static work_queue::impl* make_work_queue(container&); + transaction declare_transaction(proton::connection conn, proton::transaction_handler &handler, bool settle_before_discharge = false); private: class common_work_queue; diff --git a/cpp/src/tracker.cpp b/cpp/src/tracker.cpp index a1e04c7b1..f671764d1 100644 --- a/cpp/src/tracker.cpp +++ b/cpp/src/tracker.cpp @@ -35,6 +35,4 @@ namespace proton { tracker::tracker(pn_delivery_t *d): transfer(make_wrapper(d)) {} sender tracker::sender() const { return make_wrapper(pn_delivery_link(pn_object())); } binary tracker::tag() const { return bin(pn_delivery_tag(pn_object())); } -void tracker::set_transaction(Transaction *t) { this->transaction=t; } -Transaction* tracker::get_transaction() const { return this->transaction; } } diff --git a/cpp/src/transaction.cpp b/cpp/src/transaction.cpp index 4ab9b673f..7b4bd3104 100644 --- a/cpp/src/transaction.cpp +++ b/cpp/src/transaction.cpp @@ -25,59 +25,92 @@ namespace proton { -void transaction_handler::on_transaction_declared(Transaction &) {} -void transaction_handler::on_transaction_committed(Transaction &) {} -void transaction_handler::on_transaction_aborted(Transaction &) {} -void transaction_handler::on_transaction_declare_failed(Transaction &) {} -void transaction_handler::on_transaction_commit_failed(Transaction &) {} - -Transaction::Transaction(proton::sender _txn_ctrl, proton::transaction_handler _handler, bool _settle_before_discharge) { - txn_ctrl = _txn_ctrl; - handler = _handler; - bool settle_before_discharge = _settle_before_discharge; +void transaction_handler::on_transaction_declared(transaction &) {} +void transaction_handler::on_transaction_committed(transaction &) {} +void transaction_handler::on_transaction_aborted(transaction &) {} +void transaction_handler::on_transaction_declare_failed(transaction &) {} +void transaction_handler::on_transaction_commit_failed(transaction &) {} + +transaction::~transaction() = default; +void transaction::commit() {}; +void transaction::abort() {}; +void transaction::declare() {}; +proton::tracker transaction::send(proton::sender s, proton::message msg) { return {}; }; + +class transaction_impl : public transaction { + public: + proton::sender* txn_ctrl = nullptr; + proton::transaction_handler* handler = nullptr; + // TODO int + int id = 0; + proton::tracker _declare; + proton::tracker _discharge; + bool failed = false; + std::vector pending; + + transaction_impl(proton::sender& _txn_ctrl, proton::transaction_handler& _handler, bool _settle_before_discharge); + void commit() override; + void abort() override; + void declare() override; + proton::tracker send(proton::sender s, proton::message msg) override; + + void discharge(bool failed); + proton::tracker send_ctrl(proton::symbol descriptor, proton::value _value); + void handle_outcome(proton::tracker t); +}; + +transaction_impl::transaction_impl(proton::sender& _txn_ctrl, proton::transaction_handler& _handler, bool _settle_before_discharge): + txn_ctrl(&_txn_ctrl), + handler(&_handler) +{ + // bool settle_before_discharge = _settle_before_discharge; declare(); } -void Transaction::commit() { +void transaction_impl::commit() { discharge(false); } -void Transaction::abort() { +void transaction_impl::abort() { discharge(true); } -void Transaction::declare() { +void transaction_impl::declare() { proton::symbol descriptor("amqp:declare:list"); // proton::value _value = vd; // TODO: How to make list; - std::vector vd({NULL}); + std::vector vd; proton::value _value; // proton::get() _declare = send_ctrl(descriptor, _value ); } -void Transaction::discharge(bool failed) { - this->failed = failed; +void transaction_impl::discharge(bool failed) { + failed = failed; proton::symbol descriptor("amqp:declare:list");; proton::value _value; proton::tracker discharge = send_ctrl(descriptor, _value); } -proton::tracker Transaction::send_ctrl(proton::symbol descriptor, proton::value _value) { +proton::tracker transaction_impl::send_ctrl(proton::symbol descriptor, proton::value _value) { proton::message msg = _value; // TODO - proton::tracker delivery = txn_ctrl.send(msg); - delivery.set_transaction(this); + proton::tracker delivery = txn_ctrl->send(msg); + delivery.transaction(*this); return delivery; } -proton::tracker Transaction::send(proton::sender s, proton::message msg) { +proton::tracker transaction_impl::send(proton::sender s, proton::message msg) { proton::tracker tracker = s.send(msg); return tracker; } -void Transaction::handle_outcome(proton::tracker t) { +void transaction_impl::handle_outcome(proton::tracker t) { // this->handler.on_transaction_declared(); } +transaction mk_transaction_impl(sender& s, transaction_handler& h, bool f) { + return transaction_impl{s, h, f}; +} + } diff --git a/cpp/src/transfer.cpp b/cpp/src/transfer.cpp index 063254267..8a0cf096c 100644 --- a/cpp/src/transfer.cpp +++ b/cpp/src/transfer.cpp @@ -50,6 +50,16 @@ enum transfer::state transfer::state() const { return static_cast(pn std::string to_string(enum transfer::state s) { return pn_disposition_type_name(s); } std::ostream& operator<<(std::ostream& o, const enum transfer::state s) { return o << to_string(s); } +void transfer::transaction(class transaction& t) { + transfer_context& cc = transfer_context::get(pn_object()); + cc.transaction_ = &t; +} + +transaction* transfer::transaction() const { + transfer_context& cc = transfer_context::get(pn_object()); + return cc.transaction_; +} + void transfer::user_data(void* user_data) const { transfer_context& cc = transfer_context::get(pn_object()); cc.user_data_ = user_data; From ed624cd0d76c667bcfcf8a7dbda61c0aa3f09753 Mon Sep 17 00:00:00 2001 From: Rakhi Kumari Date: Mon, 21 Oct 2024 19:14:32 +0530 Subject: [PATCH 5/8] Make example compile --- cpp/examples/CMakeLists.txt | 3 +- cpp/examples/tx_send.cpp | 45 ++++++++++++------ cpp/include/proton/tracker.hpp | 1 - cpp/include/proton/transaction.hpp | 1 + cpp/include/proton/transfer.hpp | 8 ++-- cpp/src/contexts.hpp | 3 +- cpp/src/messaging_adapter.cpp | 72 +++++++++++++++++++++++++++-- cpp/src/proactor_container_impl.cpp | 26 +++++++---- cpp/src/transaction.cpp | 42 ++++++++++++++--- cpp/src/transfer.cpp | 10 ++-- 10 files changed, 165 insertions(+), 46 deletions(-) diff --git a/cpp/examples/CMakeLists.txt b/cpp/examples/CMakeLists.txt index 587edfc52..85b170377 100644 --- a/cpp/examples/CMakeLists.txt +++ b/cpp/examples/CMakeLists.txt @@ -60,7 +60,8 @@ foreach(example scheduled_send service_bus multithreaded_client - multithreaded_client_flow_control) + multithreaded_client_flow_control + tx_send) add_executable(${example} ${example}.cpp) target_link_libraries(${example} Proton::cpp Threads::Threads) endforeach() diff --git a/cpp/examples/tx_send.cpp b/cpp/examples/tx_send.cpp index a79c9fe93..55d247ecc 100644 --- a/cpp/examples/tx_send.cpp +++ b/cpp/examples/tx_send.cpp @@ -44,8 +44,8 @@ class tx_send : public proton::messaging_handler, proton::transaction_handler { int committed = 0; int confirmed = 0; proton::container *container; - proton::transaction_handler transaction_handler; - proton::transaction *transaction; + // proton::transaction_handler transaction_handler; + proton::transaction transaction; proton::connection connection; public: tx_send(const std::string &s, int c, int b): @@ -55,22 +55,34 @@ class tx_send : public proton::messaging_handler, proton::transaction_handler { container = &c; // TODO: Fix error sender = c.open_sender(url); connection = sender.connection(); - transaction = NULL; - c.declare_transaction(connection, transaction_handler); + std::cout << " [on_container_start] declare_txn started..." << std::endl; + transaction = c.declare_transaction(connection, *this); + std::cout << " [on_container_start] completed!! txn: " << &transaction << std::endl; } + void on_transaction_aborted(proton::transaction&) {} + void on_transaction_declare_failed(proton::transaction &) {} + void on_transaction_commit_failed(proton::transaction&) {} + + void on_transaction_declared(proton::transaction &t) override { - transaction = &t; - send(); + std::cout<<"[on_transaction_declared] txn: "<<(&transaction)<< " new_txn: "<<(&t)< m; @@ -78,11 +90,13 @@ class tx_send : public proton::messaging_handler, proton::transaction_handler { msg.id(committed + current_batch + 1); msg.body(m); + transaction.send(sender, msg); current_batch += 1; if(current_batch == batch_size) { - transaction->commit(); - transaction = NULL; + transaction.commit(); + // WE DON"T CARE ANY MORE FOR NOW + // transaction = NULL; } } @@ -94,13 +108,14 @@ class tx_send : public proton::messaging_handler, proton::transaction_handler { void on_transaction_committed(proton::transaction &t) override { committed += current_batch; + std::cout<<" [OnTxnCommitted] Committed:"<< committed<< std::endl; if(committed == total) { std::cout << "All messages committed"; - connection.close(); + // connection.close(); } else { - current_batch = 0; - container->declare_transaction(connection, transaction_handler); + // current_batch = 0; + // container->declare_transaction(connection, transaction_handler); } } @@ -112,7 +127,7 @@ class tx_send : public proton::messaging_handler, proton::transaction_handler { int main(int argc, char **argv) { std::string address("127.0.0.1:5672/examples"); - int message_count = 100; + int message_count = 10; int batch_size = 10; example::options opts(argc, argv); diff --git a/cpp/include/proton/tracker.hpp b/cpp/include/proton/tracker.hpp index c6bf45721..437a21289 100644 --- a/cpp/include/proton/tracker.hpp +++ b/cpp/include/proton/tracker.hpp @@ -26,7 +26,6 @@ #include "./internal/export.hpp" #include "./transfer.hpp" #include "./messaging_handler.hpp" -#include "./transaction.hpp" /// @file /// @copybrief proton::tracker diff --git a/cpp/include/proton/transaction.hpp b/cpp/include/proton/transaction.hpp index 5a74749ed..d2bc24be8 100644 --- a/cpp/include/proton/transaction.hpp +++ b/cpp/include/proton/transaction.hpp @@ -44,6 +44,7 @@ PN_CPP_CLASS_EXTERN transaction { PN_CPP_EXTERN virtual void commit(); PN_CPP_EXTERN virtual void abort(); PN_CPP_EXTERN virtual void declare(); + PN_CPP_EXTERN virtual void handle_outcome(proton::tracker); PN_CPP_EXTERN virtual proton::tracker send(proton::sender s, proton::message msg); }; diff --git a/cpp/include/proton/transfer.hpp b/cpp/include/proton/transfer.hpp index d74392f41..0e6de8cc9 100644 --- a/cpp/include/proton/transfer.hpp +++ b/cpp/include/proton/transfer.hpp @@ -78,9 +78,9 @@ class transfer : public internal::object { PN_CPP_EXTERN bool settled() const; // Set transaction - PN_CPP_EXTERN void transaction(transaction& t); + PN_CPP_EXTERN void transaction(transaction t); - PN_CPP_EXTERN class transaction* transaction() const; + PN_CPP_EXTERN class transaction transaction() const; /// Set user data on this transfer. PN_CPP_EXTERN void user_data(void* user_data) const; @@ -93,9 +93,9 @@ class transfer : public internal::object { /// @endcond }; -/// Human-readalbe name of the transfer::state +/// Human-readable name of the transfer::state PN_CPP_EXTERN std::string to_string(enum transfer::state); -/// Human-readalbe name of the transfer::state +/// Human-readable name of the transfer::state PN_CPP_EXTERN std::ostream& operator<<(std::ostream&, const enum transfer::state); } // proton diff --git a/cpp/src/contexts.hpp b/cpp/src/contexts.hpp index 06a8c3f6e..e496e7578 100644 --- a/cpp/src/contexts.hpp +++ b/cpp/src/contexts.hpp @@ -25,6 +25,7 @@ #include "reconnect_options_impl.hpp" #include "proton/work_queue.hpp" +#include "proton/transaction.hpp" #include "proton/message.hpp" #include "proton/object.h" @@ -162,7 +163,7 @@ class transfer_context : public context { transfer_context() : user_data_(nullptr) {} static transfer_context& get(pn_delivery_t* s); - transaction* transaction_; + std::unique_ptr transaction_; void* user_data_; }; diff --git a/cpp/src/messaging_adapter.cpp b/cpp/src/messaging_adapter.cpp index f90cd7613..8b51510c6 100644 --- a/cpp/src/messaging_adapter.cpp +++ b/cpp/src/messaging_adapter.cpp @@ -30,6 +30,7 @@ #include "proton/receiver_options.hpp" #include "proton/sender.hpp" #include "proton/sender_options.hpp" +#include "proton/target_options.hpp" #include "proton/session.hpp" #include "proton/tracker.hpp" #include "proton/transport.hpp" @@ -69,6 +70,11 @@ void on_link_flow(messaging_handler& handler, pn_event_t* event) { // TODO: process session flow data, if no link-specific data, just return. if (!lnk) return; int state = pn_link_state(lnk); + if (pn_terminus_get_type(pn_link_remote_target(lnk))==PN_COORDINATOR) { + std::cout << " on_link_flow, type: PN_COORDINATOR" << std::endl; + return; + + } if ((state&PN_LOCAL_ACTIVE) && (state&PN_REMOTE_ACTIVE)) { link_context& lctx = link_context::get(lnk); if (pn_link_is_sender(lnk)) { @@ -115,8 +121,14 @@ void on_delivery(messaging_handler& handler, pn_event_t* event) { pn_delivery_t *dlv = pn_event_delivery(event); link_context& lctx = link_context::get(lnk); Tracing& ot = Tracing::getTracing(); + if (pn_terminus_get_type(pn_link_remote_target(lnk))==PN_COORDINATOR) { + std::cout<< " on_delivery: COOORINDATOR.. " << &handler << std::endl; + tracker t(make_wrapper(dlv)); + std::cout<< " on_delivery: COOORINDATOR.. tracker" << &t << std::endl; + handler.on_tracker_settle(t); + } - if (pn_link_is_receiver(lnk)) { + else if (pn_link_is_receiver(lnk)) { delivery d(make_wrapper(dlv)); if (pn_delivery_aborted(dlv)) { pn_delivery_settle(dlv); @@ -274,23 +286,73 @@ void on_link_local_open(messaging_handler& handler, pn_event_t* event) { void on_link_remote_open(messaging_handler& handler, pn_event_t* event) { auto lnk = pn_event_link(event); - // Currently don't implement (transaction) coordinator + int type = pn_terminus_get_type(pn_link_remote_target(lnk)); + std::cout << " on_link_remote_open, type:" << type << std::endl; if (pn_terminus_get_type(pn_link_remote_target(lnk))==PN_COORDINATOR) { - auto error = pn_link_condition(lnk); - pn_condition_set_name(error, "amqp:not-implemented"); - pn_link_close(lnk); + auto cond = pn_link_condition(lnk); + if (pn_condition_is_set(cond)) { + std::cout<<" Got condition on_link_remote_open(.PN_COORDINATOR): " + << pn_event_type_name(pn_event_type(event)) << " " + << pn_condition_get_name(cond) << " " + << pn_condition_get_description(cond) << std::endl; + + pn_condition_set_name(cond, "amqp:on_link_remote_open:FAILED"); + pn_link_close(lnk); + return; + } + std::cout<<" IN on_link_remote_open(.PN_COORDINATOR) success " << std::endl; + + // WHY??? + // pn_terminus_copy(pn_link_source(lnk), pn_link_remote_source(lnk)); + // pn_terminus_copy(pn_link_target(lnk), pn_link_remote_target(lnk)); + + // We need a new class? + // auto coordinator = pn_link_remote_target(lnk); + + + // proton::target_options to; + // std::vector cap = {proton::symbol("amqp:local-transactions")}; + // to.capabilities(cap); + // to.type(PN_COORDINATOR); + + // proton::receiver_options ro; + // ro.name("txn-ctrl"); + // ro.target(to); + // ro.handler(handler); + // receiver r(make_wrapper(lnk)); + + // proton::receiver rcv = r.connection().open_receiver("does not matter", ro); + std::cout<<" IN on_link_remote_open(.PN_COORDINATOR) have handler " << &handler << std::endl; + + // handler.on_receiver_open(rcv); + // credit_topup(lnk); + + // pn_delivery_t *dlv = pn_event_delivery(event); + // tracker t(make_wrapper(dlv)); + + // // sender s(make_wrapper(lnk)); + // handler.on_tracker_settle(t); + // TODO: find what to do... + // HAHA.. treating coordinator like sender... + // sender s(make_wrapper(lnk)); + // handler.on_sender_open(s); + // pn_link_close(lnk); return; } if (pn_link_state(lnk) & PN_LOCAL_UNINIT) { // Incoming link // Copy source and target from remote end. + std::cout<<" Inside on_link_remote_open() .. PN_LOCAL_UNINIT " << std::endl; + pn_terminus_copy(pn_link_source(lnk), pn_link_remote_source(lnk)); pn_terminus_copy(pn_link_target(lnk), pn_link_remote_target(lnk)); } if (pn_link_is_receiver(lnk)) { + std::cout<<" Inside on_link_remote_open() .. pn_link_is_receiver " << std::endl; receiver r(make_wrapper(lnk)); handler.on_receiver_open(r); credit_topup(lnk); } else { + std::cout<<" Inside on_link_remote_open() .. sender " << std::endl; sender s(make_wrapper(lnk)); handler.on_sender_open(s); } diff --git a/cpp/src/proactor_container_impl.cpp b/cpp/src/proactor_container_impl.cpp index 290a4944b..bae2557ca 100644 --- a/cpp/src/proactor_container_impl.cpp +++ b/cpp/src/proactor_container_impl.cpp @@ -34,6 +34,7 @@ #include "proton/listener.h" #include "proton/proactor.h" #include "proton/transport.h" +#include "proton/transaction.hpp" #include "contexts.hpp" #include "messaging_adapter.hpp" @@ -49,7 +50,7 @@ #include // XXXX: Debug -//#include +#include namespace proton { @@ -868,9 +869,11 @@ transaction container::impl::declare_transaction(proton::connection conn, proton class InternalTransactionHandler : public proton::messaging_handler { // TODO: auto_settle void on_tracker_settle(proton::tracker &t) override { - if(t.transaction()) { - //t.transaction()->handle_outcome(t); - } + std::cout<<" [InternalTransactionHandler][on_tracker_settle] called with tracker.txn" + << std::endl; + // if(t.transaction()) { + t.transaction().handle_outcome(t); + // } } // TODO: Add on_unhandled function @@ -882,23 +885,28 @@ transaction container::impl::declare_transaction(proton::connection conn, proton proton::target_options t; std::vector cap = {proton::symbol("amqp:local-transactions")}; t.capabilities(cap); - // Type PN_COORDINATOR value is 3. It is a special target identifying a transaction coordinator. - // TODO: Change the type from int to enum. - t.type(3); + t.type(PN_COORDINATOR); proton::sender_options so; so.name("txn-ctrl"); // Todo: Check the value, Or by deafult null? //so.source() ? so.target(t); - InternalTransactionHandler internal_handler; // internal_handler going out of scope. Fix it + // TODO: FIX STATIC + static InternalTransactionHandler internal_handler; // internal_handler going out of scope. Fix it so.handler(internal_handler); + std::cout<<" [declare_transaction] txn-name sender open with handler: " << &internal_handler << std::endl; + proton::sender s = conn.open_sender("does not matter", so); settle_before_discharge = false; - return mk_transaction_impl(s, handler, settle_before_discharge); + std::cout<<" [declare_transaction] calling mk_transaction_impl" << std::endl; + + auto txn = mk_transaction_impl(s, handler, settle_before_discharge); + std::cout<<" [declare_transaction] txn address:" << &txn << std::endl; + return txn; } } diff --git a/cpp/src/transaction.cpp b/cpp/src/transaction.cpp index 7b4bd3104..0d9a15c5e 100644 --- a/cpp/src/transaction.cpp +++ b/cpp/src/transaction.cpp @@ -21,10 +21,16 @@ #include "proton/message.hpp" #include "proton/transaction.hpp" +#include "proton/target_options.hpp" #include "proton/tracker.hpp" +#include + +#include + namespace proton { +transaction_handler::~transaction_handler() = default; void transaction_handler::on_transaction_declared(transaction &) {} void transaction_handler::on_transaction_committed(transaction &) {} void transaction_handler::on_transaction_aborted(transaction &) {} @@ -36,6 +42,10 @@ void transaction::commit() {}; void transaction::abort() {}; void transaction::declare() {}; proton::tracker transaction::send(proton::sender s, proton::message msg) { return {}; }; +void transaction::handle_outcome(proton::tracker t) { + std::cout<<" transaction_impl::handle_outcome = NO OP base class " << std::endl; + +}; class transaction_impl : public transaction { public: @@ -76,26 +86,40 @@ void transaction_impl::abort() { } void transaction_impl::declare() { + std::cout<<" [transaction_impl][declare] staring it" << std::endl; + proton::symbol descriptor("amqp:declare:list"); // proton::value _value = vd; // TODO: How to make list; - std::vector vd; - proton::value _value; - // proton::get() + std::list vd; + proton::value i_am_null; + vd.push_back(i_am_null); + proton::value _value = vd; + std::cout<<" [transaction_impl::declare()] value to send_ctrl: " << _value<< std::endl; _declare = send_ctrl(descriptor, _value ); } void transaction_impl::discharge(bool failed) { failed = failed; - proton::symbol descriptor("amqp:declare:list");; + proton::symbol descriptor("amqp:declare:list"); proton::value _value; proton::tracker discharge = send_ctrl(descriptor, _value); } proton::tracker transaction_impl::send_ctrl(proton::symbol descriptor, proton::value _value) { - proton::message msg = _value; // TODO + proton::value msg_value; + proton::codec::encoder enc(msg_value); + enc << proton::codec::start::described() + << descriptor + << _value + << proton::codec::finish(); + + + proton::message msg = msg_value; + std::cout << " [transaction_impl::send_ctrl] sending " << msg << std::endl; proton::tracker delivery = txn_ctrl->send(msg); delivery.transaction(*this); + std::cout << " [transaction_impl::send_ctrl] sending done. I guess queued! " << std::endl; return delivery; } @@ -105,7 +129,13 @@ proton::tracker transaction_impl::send(proton::sender s, proton::message msg) { } void transaction_impl::handle_outcome(proton::tracker t) { - // this->handler.on_transaction_declared(); + // TODO: handle outcome + if(_declare == t) { + std::cout<<" transaction_impl::handle_outcome => got _declare" << std::endl; + + } + std::cout<<" transaction_impl::handle_outcome => calling txn declared. handler: " << handler << std::endl; + handler->on_transaction_declared(*this); } diff --git a/cpp/src/transfer.cpp b/cpp/src/transfer.cpp index 8a0cf096c..fa7cd126c 100644 --- a/cpp/src/transfer.cpp +++ b/cpp/src/transfer.cpp @@ -22,6 +22,7 @@ #include "proton/delivery.hpp" #include "proton/connection.hpp" +// #include "proton/transaction.hpp" #include "proton/link.hpp" #include "proton/session.hpp" @@ -50,14 +51,15 @@ enum transfer::state transfer::state() const { return static_cast(pn std::string to_string(enum transfer::state s) { return pn_disposition_type_name(s); } std::ostream& operator<<(std::ostream& o, const enum transfer::state s) { return o << to_string(s); } -void transfer::transaction(class transaction& t) { +void transfer::transaction(proton::transaction t) { transfer_context& cc = transfer_context::get(pn_object()); - cc.transaction_ = &t; + // FIX THIS + cc.transaction_ = std::make_unique(t); } -transaction* transfer::transaction() const { +transaction transfer::transaction() const { transfer_context& cc = transfer_context::get(pn_object()); - return cc.transaction_; + return *cc.transaction_; } void transfer::user_data(void* user_data) const { From 0e20334838d656dc7daea84926a4c1a60b492fed Mon Sep 17 00:00:00 2001 From: Rakhi Kumari Date: Tue, 19 Nov 2024 22:25:17 +0530 Subject: [PATCH 6/8] Add txn id in disposition frame bits --- cpp/examples/tx_send.cpp | 15 ++-- cpp/include/proton/container.hpp | 1 + cpp/include/proton/transaction.hpp | 64 ++++++++++++++--- cpp/include/proton/transfer.hpp | 20 ++++++ cpp/src/messaging_adapter.cpp | 25 +++++-- cpp/src/proactor_container_impl.cpp | 27 +++++++- cpp/src/proton_bits.hpp | 9 +++ cpp/src/tracker.cpp | 2 +- cpp/src/transaction.cpp | 104 ++++++++++++++++------------ cpp/src/transfer.cpp | 23 +++++- 10 files changed, 216 insertions(+), 74 deletions(-) diff --git a/cpp/examples/tx_send.cpp b/cpp/examples/tx_send.cpp index 55d247ecc..319ab3731 100644 --- a/cpp/examples/tx_send.cpp +++ b/cpp/examples/tx_send.cpp @@ -60,13 +60,13 @@ class tx_send : public proton::messaging_handler, proton::transaction_handler { std::cout << " [on_container_start] completed!! txn: " << &transaction << std::endl; } - void on_transaction_aborted(proton::transaction&) {} - void on_transaction_declare_failed(proton::transaction &) {} - void on_transaction_commit_failed(proton::transaction&) {} + void on_transaction_aborted(proton::transaction) {} + void on_transaction_declare_failed(proton::transaction) {} + void on_transaction_commit_failed(proton::transaction) {} - - void on_transaction_declared(proton::transaction &t) override { - std::cout<<"[on_transaction_declared] txn: "<<(&transaction)<< " new_txn: "<<(&t)<id) << std::endl; connection.close(); // transaction = &t; // ASSUME: THIS FUNCTION DOESN"T WORK @@ -95,7 +95,6 @@ class tx_send : public proton::messaging_handler, proton::transaction_handler { if(current_batch == batch_size) { transaction.commit(); - // WE DON"T CARE ANY MORE FOR NOW // transaction = NULL; } } @@ -106,7 +105,7 @@ class tx_send : public proton::messaging_handler, proton::transaction_handler { confirmed += 1; } - void on_transaction_committed(proton::transaction &t) override { + void on_transaction_committed(proton::transaction t) override { committed += current_batch; std::cout<<" [OnTxnCommitted] Committed:"<< committed<< std::endl; if(committed == total) { diff --git a/cpp/include/proton/container.hpp b/cpp/include/proton/container.hpp index 0b0e16a41..a6153fa69 100644 --- a/cpp/include/proton/container.hpp +++ b/cpp/include/proton/container.hpp @@ -327,6 +327,7 @@ class PN_CPP_CLASS_EXTERN container { friend class receiver_options; friend class sender_options; friend class work_queue; + friend class transaction; /// @endcond }; diff --git a/cpp/include/proton/transaction.hpp b/cpp/include/proton/transaction.hpp index d2bc24be8..a74f85d94 100644 --- a/cpp/include/proton/transaction.hpp +++ b/cpp/include/proton/transaction.hpp @@ -28,6 +28,7 @@ #include "./internal/export.hpp" #include "./sender.hpp" #include "./tracker.hpp" +#include "./container.hpp" /// @file /// @copybrief proton::transaction @@ -36,16 +37,57 @@ namespace proton { class transaction_handler; +// TODO: This should not be accessible to users. +class transaction_impl { + public: + proton::sender *txn_ctrl = nullptr; + proton::transaction_handler *handler = nullptr; + proton::binary id; + proton::tracker _declare; + proton::tracker _discharge; + bool failed = false; + std::vector pending; + + void commit(); + void abort(); + void declare(); + proton::tracker send(proton::sender s, proton::message msg); + + void discharge(bool failed); + proton::tracker send_ctrl(proton::symbol descriptor, proton::value _value); + void handle_outcome(proton::tracker t); + transaction_impl(proton::sender &_txn_ctrl, + proton::transaction_handler &_handler, + bool _settle_before_discharge); + + // delete copy and assignment operator to ensure no copy of this object is + // every made transaction_impl(const transaction_impl&) = delete; + // transaction_impl& operator=(const transaction_impl&) = delete; +}; + class PN_CPP_CLASS_EXTERN transaction { + // private: + // PN_CPP_EXTERN transaction(proton::sender& _txn_ctrl, + // proton::transaction_handler& _handler, bool _settle_before_discharge); + + static transaction mk_transaction_impl(sender &s, transaction_handler &h, + bool f); + PN_CPP_EXTERN transaction(transaction_impl* impl); public: + transaction_impl* _impl; // TODO: - PN_CPP_EXTERN virtual ~transaction(); - PN_CPP_EXTERN virtual void commit(); - PN_CPP_EXTERN virtual void abort(); - PN_CPP_EXTERN virtual void declare(); - PN_CPP_EXTERN virtual void handle_outcome(proton::tracker); - PN_CPP_EXTERN virtual proton::tracker send(proton::sender s, proton::message msg); + // PN_CPP_EXTERN transaction(transaction &o); + PN_CPP_EXTERN transaction(); + PN_CPP_EXTERN ~transaction(); + PN_CPP_EXTERN void commit(); + PN_CPP_EXTERN void abort(); + PN_CPP_EXTERN void declare(); + PN_CPP_EXTERN void handle_outcome(proton::tracker); + PN_CPP_EXTERN proton::tracker send(proton::sender s, proton::message msg); + + friend class transaction_impl; + friend class container::impl; }; class @@ -54,19 +96,19 @@ PN_CPP_CLASS_EXTERN transaction_handler { PN_CPP_EXTERN virtual ~transaction_handler(); /// Called when a local transaction is declared. - PN_CPP_EXTERN virtual void on_transaction_declared(transaction&); + PN_CPP_EXTERN virtual void on_transaction_declared(transaction); /// Called when a local transaction is discharged successfully. - PN_CPP_EXTERN virtual void on_transaction_committed(transaction&); + PN_CPP_EXTERN virtual void on_transaction_committed(transaction); /// Called when a local transaction is discharged unsuccessfully (aborted). - PN_CPP_EXTERN virtual void on_transaction_aborted(transaction&); + PN_CPP_EXTERN virtual void on_transaction_aborted(transaction); /// Called when a local transaction declare fails. - PN_CPP_EXTERN virtual void on_transaction_declare_failed(transaction&); + PN_CPP_EXTERN virtual void on_transaction_declare_failed(transaction); /// Called when the commit of a local transaction fails. - PN_CPP_EXTERN virtual void on_transaction_commit_failed(transaction&); + PN_CPP_EXTERN virtual void on_transaction_commit_failed(transaction); }; } // namespace proton diff --git a/cpp/include/proton/transfer.hpp b/cpp/include/proton/transfer.hpp index 0e6de8cc9..1e7995c06 100644 --- a/cpp/include/proton/transfer.hpp +++ b/cpp/include/proton/transfer.hpp @@ -33,9 +33,26 @@ /// @copybrief proton::transfer struct pn_delivery_t; +struct pn_disposition_t; namespace proton { +class disposition : public internal::object { + /// @cond INTERNAL + disposition(pn_disposition_t *d) : internal::object(d) {} + /// @endcond + + public: + /// Create an empty disposition. + disposition() : internal::object(0) {} + + proton::value data() const; + + /// @cond INTERNAL + friend class internal::factory; + /// @endcond +}; + /// The base class for delivery and tracker. class transfer : public internal::object { /// @cond INTERNAL @@ -88,6 +105,9 @@ class transfer : public internal::object { /// Get user data from this transfer. PN_CPP_EXTERN void* user_data() const; + PN_CPP_EXTERN disposition remote(); + PN_CPP_EXTERN disposition local(); + /// @cond INTERNAL friend class internal::factory; /// @endcond diff --git a/cpp/src/messaging_adapter.cpp b/cpp/src/messaging_adapter.cpp index 8b51510c6..9a9a048bf 100644 --- a/cpp/src/messaging_adapter.cpp +++ b/cpp/src/messaging_adapter.cpp @@ -41,6 +41,7 @@ #include #include +#include #include #include #include @@ -115,20 +116,32 @@ void message_decode(message& msg, proton::delivery delivery) { msg.decode(buf); pn_link_advance(unwrap(link)); } - void on_delivery(messaging_handler& handler, pn_event_t* event) { pn_link_t *lnk = pn_event_link(event); pn_delivery_t *dlv = pn_event_delivery(event); link_context& lctx = link_context::get(lnk); Tracing& ot = Tracing::getTracing(); if (pn_terminus_get_type(pn_link_remote_target(lnk))==PN_COORDINATOR) { - std::cout<< " on_delivery: COOORINDATOR.. " << &handler << std::endl; + // delivery d(make_wrapper(dlv)); + pn_disposition_t *disposition = pn_delivery_remote(dlv); + proton::value val(pn_disposition_data(disposition)); + std::cout << " on_delivery: COOORINDATOR.. tracker: " << val + << std::endl; tracker t(make_wrapper(dlv)); - std::cout<< " on_delivery: COOORINDATOR.. tracker" << &t << std::endl; - handler.on_tracker_settle(t); - } + std::cout << " on_delivery: COOORINDATOR.. TRACKER MADE: " + << std::endl; + // t.user_data = val; // not + + // proton::disposition _disposition = make_wrapper(disposition); // # + // t.remote(); - else if (pn_link_is_receiver(lnk)) { + // proton::value val2 = _disposition.data(); + + // std::cout<< " on_delivery: COOORINDATOR with TXN IN :" + // << val2 << std::endl; + + handler.on_tracker_settle(t); + } else if (pn_link_is_receiver(lnk)) { delivery d(make_wrapper(dlv)); if (pn_delivery_aborted(dlv)) { pn_delivery_settle(dlv); diff --git a/cpp/src/proactor_container_impl.cpp b/cpp/src/proactor_container_impl.cpp index bae2557ca..00ab38bef 100644 --- a/cpp/src/proactor_container_impl.cpp +++ b/cpp/src/proactor_container_impl.cpp @@ -36,11 +36,15 @@ #include "proton/transport.h" #include "proton/transaction.hpp" +#include "proton/delivery.h" + #include "contexts.hpp" #include "messaging_adapter.hpp" #include "reconnect_options_impl.hpp" #include "proton_bits.hpp" +#include + #include #include @@ -863,7 +867,7 @@ void container::impl::stop(const proton::error_condition& err) { } // TODO: declare this in separate internal header file -extern transaction mk_transaction_impl(sender&, transaction_handler&, bool); +// extern transaction mk_transaction_impl(sender&, transaction_handler&, bool); transaction container::impl::declare_transaction(proton::connection conn, proton::transaction_handler &handler, bool settle_before_discharge) { class InternalTransactionHandler : public proton::messaging_handler { @@ -871,8 +875,24 @@ transaction container::impl::declare_transaction(proton::connection conn, proton void on_tracker_settle(proton::tracker &t) override { std::cout<<" [InternalTransactionHandler][on_tracker_settle] called with tracker.txn" << std::endl; + t.transaction().handle_outcome(t); + + // t.user_data = val; // not + + // proton::disposition _disposition = make_wrapper(disposition); + // // # t.remote(); + + // proton::value val2 = _disposition.data(); + + // proton::disposition _disposition = t.remote(); + + // proton::value val = _disposition.data(); + + // std::cout<< " declare_transaction: on_tracker_settle with + // TXN IN :" << val << std::endl; + // if(t.transaction()) { - t.transaction().handle_outcome(t); + // t.transaction().handle_outcome(t); // } } @@ -903,7 +923,8 @@ transaction container::impl::declare_transaction(proton::connection conn, proton std::cout<<" [declare_transaction] calling mk_transaction_impl" << std::endl; - auto txn = mk_transaction_impl(s, handler, settle_before_discharge); + auto txn = + transaction::mk_transaction_impl(s, handler, settle_before_discharge); std::cout<<" [declare_transaction] txn address:" << &txn << std::endl; return txn; diff --git a/cpp/src/proton_bits.hpp b/cpp/src/proton_bits.hpp index 48b9f5fd8..b4350e0f6 100644 --- a/cpp/src/proton_bits.hpp +++ b/cpp/src/proton_bits.hpp @@ -20,6 +20,7 @@ */ #include #include +#include #include #include @@ -41,6 +42,7 @@ struct pn_connection_t; struct pn_session_t; struct pn_link_t; struct pn_delivery_t; +struct pn_disposition_t; struct pn_condition_t; struct pn_acceptor_t; struct pn_terminus_t; @@ -60,6 +62,7 @@ class sender; class receiver; class transfer; class tracker; +class disposition; class delivery; class error_condition; class acceptor; @@ -98,6 +101,9 @@ template <> struct wrapped { typedef pn_link_t type; }; template <> struct wrapped { typedef pn_link_t type; }; template <> struct wrapped { typedef pn_delivery_t type; }; template <> struct wrapped { typedef pn_delivery_t type; }; +template <> struct wrapped { + typedef pn_disposition_t type; +}; template <> struct wrapped { typedef pn_delivery_t type; }; template <> struct wrapped { typedef pn_condition_t type; }; template <> struct wrapped { typedef pn_terminus_t type; }; @@ -111,6 +117,9 @@ template <> struct wrapper { typedef connection type; }; template <> struct wrapper { typedef session type; }; template <> struct wrapper { typedef link type; }; template <> struct wrapper { typedef transfer type; }; +template <> struct wrapper { + typedef disposition type; +}; template <> struct wrapper { typedef error_condition type; }; template <> struct wrapper { typedef terminus type; }; diff --git a/cpp/src/tracker.cpp b/cpp/src/tracker.cpp index f671764d1..5715f12b8 100644 --- a/cpp/src/tracker.cpp +++ b/cpp/src/tracker.cpp @@ -32,7 +32,7 @@ namespace proton { -tracker::tracker(pn_delivery_t *d): transfer(make_wrapper(d)) {} +tracker::tracker(pn_delivery_t *d) : transfer(make_wrapper(d)) {} sender tracker::sender() const { return make_wrapper(pn_delivery_link(pn_object())); } binary tracker::tag() const { return bin(pn_delivery_tag(pn_object())); } } diff --git a/cpp/src/transaction.cpp b/cpp/src/transaction.cpp index 0d9a15c5e..b7865cf7b 100644 --- a/cpp/src/transaction.cpp +++ b/cpp/src/transaction.cpp @@ -19,11 +19,13 @@ * */ -#include "proton/message.hpp" #include "proton/transaction.hpp" +#include "proton/delivery.h" +#include "proton/message.hpp" #include "proton/target_options.hpp" #include "proton/tracker.hpp" +#include "proton_bits.hpp" #include #include @@ -31,43 +33,33 @@ namespace proton { transaction_handler::~transaction_handler() = default; -void transaction_handler::on_transaction_declared(transaction &) {} -void transaction_handler::on_transaction_committed(transaction &) {} -void transaction_handler::on_transaction_aborted(transaction &) {} -void transaction_handler::on_transaction_declare_failed(transaction &) {} -void transaction_handler::on_transaction_commit_failed(transaction &) {} - +void transaction_handler::on_transaction_declared(transaction) {} +void transaction_handler::on_transaction_committed(transaction) {} +void transaction_handler::on_transaction_aborted(transaction) {} +void transaction_handler::on_transaction_declare_failed(transaction) {} +void transaction_handler::on_transaction_commit_failed(transaction) {} + +transaction::transaction() : _impl(NULL) {} // empty transaction, not yet ready +// transaction::transaction(proton::sender& _txn_ctrl, +// proton::transaction_handler& _handler, bool _settle_before_discharge) : +// _impl(std::make_shared(_txn_ctrl, _handler, +// _settle_before_discharge)) {} +transaction::transaction(transaction_impl *impl) + : _impl(impl) {} +// transaction::transaction( transaction_impl* impl): _impl(impl){} transaction::~transaction() = default; -void transaction::commit() {}; -void transaction::abort() {}; -void transaction::declare() {}; -proton::tracker transaction::send(proton::sender s, proton::message msg) { return {}; }; +void transaction::commit() { _impl->commit(); }; +void transaction::abort() { _impl->abort(); }; +void transaction::declare() { _impl->declare(); }; +proton::tracker transaction::send(proton::sender s, proton::message msg) { + return _impl->send(s, msg); +}; void transaction::handle_outcome(proton::tracker t) { - std::cout<<" transaction_impl::handle_outcome = NO OP base class " << std::endl; - + std::cout << " transaction::handle_outcome = NO OP base class " + << std::endl; + _impl->handle_outcome(t); }; -class transaction_impl : public transaction { - public: - proton::sender* txn_ctrl = nullptr; - proton::transaction_handler* handler = nullptr; - // TODO int - int id = 0; - proton::tracker _declare; - proton::tracker _discharge; - bool failed = false; - std::vector pending; - - transaction_impl(proton::sender& _txn_ctrl, proton::transaction_handler& _handler, bool _settle_before_discharge); - void commit() override; - void abort() override; - void declare() override; - proton::tracker send(proton::sender s, proton::message msg) override; - - void discharge(bool failed); - proton::tracker send_ctrl(proton::symbol descriptor, proton::value _value); - void handle_outcome(proton::tracker t); -}; transaction_impl::transaction_impl(proton::sender& _txn_ctrl, proton::transaction_handler& _handler, bool _settle_before_discharge): txn_ctrl(&_txn_ctrl), @@ -97,6 +89,10 @@ void transaction_impl::declare() { proton::value _value = vd; std::cout<<" [transaction_impl::declare()] value to send_ctrl: " << _value<< std::endl; _declare = send_ctrl(descriptor, _value ); + std::cout << " transaction_impl::declare()... txn_impl i am is " << this + << std::endl; + std::cout << " [transaction_impl::declare()] _declare is : " << _declare + << std::endl; } void transaction_impl::discharge(bool failed) { @@ -118,8 +114,12 @@ proton::tracker transaction_impl::send_ctrl(proton::symbol descriptor, proton::v proton::message msg = msg_value; std::cout << " [transaction_impl::send_ctrl] sending " << msg << std::endl; proton::tracker delivery = txn_ctrl->send(msg); - delivery.transaction(*this); - std::cout << " [transaction_impl::send_ctrl] sending done. I guess queued! " << std::endl; + std::cout << " # declare, delivery as tracker: " << delivery + << std::endl; + delivery.transaction(transaction(this)); + std::cout + << " [transaction_impl::send_ctrl] sending done. I guess queued! " + << delivery << std::endl; return delivery; } @@ -129,18 +129,36 @@ proton::tracker transaction_impl::send(proton::sender s, proton::message msg) { } void transaction_impl::handle_outcome(proton::tracker t) { + + // std::vector _data = + // proton::get>(val); + auto txn = t.transaction(); + std::cout << " handle_outcome::txn_impl i am is " << this << std::endl; + std::cout << " handle_outcome::_declare is " << _declare << std::endl; + std::cout << " handle_outcome::tracker is " << t << std::endl; + // TODO: handle outcome if(_declare == t) { std::cout<<" transaction_impl::handle_outcome => got _declare" << std::endl; - + pn_disposition_t *disposition = pn_delivery_remote(unwrap(t)); + proton::value val(pn_disposition_data(disposition)); + auto vd = get>(val); + txn._impl->id = vd[0]; + std::cout << " transaction_impl: handle_outcome.. got txnid:: " + << vd[0] << std::endl; + handler->on_transaction_declared(txn); + } else if (_discharge == t) { + std::cout << " transaction_impl::handle_outcome => got _discharge" + << std::endl; + handler->on_transaction_committed(txn); + } else { + std::cout << " transaction_impl::handle_outcome => got NONE!" + << std::endl; } - std::cout<<" transaction_impl::handle_outcome => calling txn declared. handler: " << handler << std::endl; - handler->on_transaction_declared(*this); - } -transaction mk_transaction_impl(sender& s, transaction_handler& h, bool f) { - return transaction_impl{s, h, f}; +transaction transaction::mk_transaction_impl(sender &s, transaction_handler &h, + bool f) { + return transaction(new transaction_impl(s, h, f)); } - } diff --git a/cpp/src/transfer.cpp b/cpp/src/transfer.cpp index fa7cd126c..bdd17035d 100644 --- a/cpp/src/transfer.cpp +++ b/cpp/src/transfer.cpp @@ -32,6 +32,7 @@ #include "proton_bits.hpp" +#include #include namespace proton { @@ -52,8 +53,7 @@ std::string to_string(enum transfer::state s) { return pn_disposition_type_name( std::ostream& operator<<(std::ostream& o, const enum transfer::state s) { return o << to_string(s); } void transfer::transaction(proton::transaction t) { - transfer_context& cc = transfer_context::get(pn_object()); - // FIX THIS + transfer_context &cc = transfer_context::get(pn_object()); cc.transaction_ = std::make_unique(t); } @@ -72,4 +72,23 @@ void* transfer::user_data() const { return cc.user_data_; } +disposition transfer::remote() { + auto me = pn_object(); + std::cout << " transfer::remote ME => " << me << std::endl; + + auto dd = pn_delivery_remote(me); + std::cout << " transfer::remote dd => " << dd << std::endl; + std::cout << " transfer::remote.data dd => " + << proton::value(pn_disposition_data(dd)) << std::endl; + auto d2 = make_wrapper(dd); + std::cout << " transfer::remote d2 ready => " << std::endl; + return d2; +} +disposition transfer::local() { + return make_wrapper(pn_delivery_local(pn_object())); +} + +proton::value disposition::data() const { + return proton::value(pn_disposition_data(pn_object())); +} } From eb4514ba4e71865926f09d0ca94b50f7e0546044 Mon Sep 17 00:00:00 2001 From: Rakhi Kumari Date: Thu, 21 Nov 2024 23:55:27 +0530 Subject: [PATCH 7/8] Add transaction commit and abort functionalities --- cpp/examples/tx_send.cpp | 75 +++++++++++------ cpp/include/proton/transaction.hpp | 25 ++++-- cpp/src/messaging_adapter.cpp | 43 +++++++--- cpp/src/proactor_container_impl.cpp | 33 ++------ cpp/src/transaction.cpp | 125 +++++++++++++++++++++++----- 5 files changed, 205 insertions(+), 96 deletions(-) diff --git a/cpp/examples/tx_send.cpp b/cpp/examples/tx_send.cpp index 319ab3731..f2e8e4e21 100644 --- a/cpp/examples/tx_send.cpp +++ b/cpp/examples/tx_send.cpp @@ -33,6 +33,9 @@ #include #include +#include +#include + class tx_send : public proton::messaging_handler, proton::transaction_handler { private: proton::sender sender; @@ -40,9 +43,11 @@ class tx_send : public proton::messaging_handler, proton::transaction_handler { int total; int batch_size; int sent; + int batch_index = 0; int current_batch = 0; int committed = 0; int confirmed = 0; + proton::container *container; // proton::transaction_handler transaction_handler; proton::transaction transaction; @@ -56,68 +61,90 @@ class tx_send : public proton::messaging_handler, proton::transaction_handler { sender = c.open_sender(url); connection = sender.connection(); std::cout << " [on_container_start] declare_txn started..." << std::endl; - transaction = c.declare_transaction(connection, *this); - std::cout << " [on_container_start] completed!! txn: " << &transaction << std::endl; + c.declare_transaction(connection, *this); + std::cout << " [on_container_start] completed!!" << &transaction + << std::endl; } - void on_transaction_aborted(proton::transaction) {} void on_transaction_declare_failed(proton::transaction) {} - void on_transaction_commit_failed(proton::transaction) {} + void on_transaction_commit_failed(proton::transaction) { + std::cout << "Transaction Commit Failed" << std::endl; + connection.close(); + exit(-1); + } void on_transaction_declared(proton::transaction t) override { - std::cout << "[on_transaction_declared] txn: " << (&transaction) - << " new_txn: " << (t._impl->id) << std::endl; - connection.close(); - // transaction = &t; - // ASSUME: THIS FUNCTION DOESN"T WORK - // send(); + std::cout << "[on_transaction_declared] txn called " << (&t) + << std::endl; + // connection.close(); + std::cout << "[on_transaction_declared] txn is_empty " << (t.is_empty()) + << "\t" << transaction.is_empty() << std::endl; + transaction = t; + + send(sender); } void on_sendable(proton::sender &s) override { // send(); - // std::cout<<" [OnSendable] transaction: "<< &transaction << std::endl; - // send(s); + std::cout << " [OnSendable] transaction: " << &transaction + << std::endl; + send(s); } void send(proton::sender &s) { // TODO: Add more condition in while loop - // transaction != null - while ( sender.credit() && (committed + current_batch) < total) - { + while (!transaction.is_empty() && sender.credit() && + (committed + current_batch) < total) { proton::message msg; std::map m; m["sequence"] = committed + current_batch; msg.id(committed + current_batch + 1); msg.body(m); + std::cout << " [example] transaction send msg: " << msg + << std::endl; transaction.send(sender, msg); current_batch += 1; if(current_batch == batch_size) { - transaction.commit(); - // transaction = NULL; + std::cout << " >> Txn attempt commit" << std::endl; + if (batch_index % 2 == 0) { + transaction.commit(); + } else { + transaction.abort(); + } + + transaction = proton::transaction(); + batch_index++; } } - } void on_tracker_accept(proton::tracker &t) override { confirmed += 1; + std::cout << " [example] on_tracker_accept:" << confirmed + << std::endl; } void on_transaction_committed(proton::transaction t) override { committed += current_batch; + current_batch = 0; std::cout<<" [OnTxnCommitted] Committed:"<< committed<< std::endl; if(committed == total) { - std::cout << "All messages committed"; - // connection.close(); + std::cout << "All messages committed" << std::endl; + connection.close(); } else { - // current_batch = 0; - // container->declare_transaction(connection, transaction_handler); + container->declare_transaction(connection, *this); } } + void on_transaction_aborted(proton::transaction t) override { + std::cout << "Meesages Aborted ....." << std::endl; + current_batch = 0; + container->declare_transaction(connection, *this); + } + void on_sender_close(proton::sender &s) override { current_batch = 0; } @@ -126,8 +153,8 @@ class tx_send : public proton::messaging_handler, proton::transaction_handler { int main(int argc, char **argv) { std::string address("127.0.0.1:5672/examples"); - int message_count = 10; - int batch_size = 10; + int message_count = 6; + int batch_size = 3; example::options opts(argc, argv); opts.add_value(address, 'a', "address", "connect and send to URL", "URL"); diff --git a/cpp/include/proton/transaction.hpp b/cpp/include/proton/transaction.hpp index a74f85d94..51759f796 100644 --- a/cpp/include/proton/transaction.hpp +++ b/cpp/include/proton/transaction.hpp @@ -40,7 +40,7 @@ class transaction_handler; // TODO: This should not be accessible to users. class transaction_impl { public: - proton::sender *txn_ctrl = nullptr; + proton::sender txn_ctrl; proton::transaction_handler *handler = nullptr; proton::binary id; proton::tracker _declare; @@ -54,6 +54,11 @@ class transaction_impl { proton::tracker send(proton::sender s, proton::message msg); void discharge(bool failed); + void release_pending(); + void accept(tracker &d); + void update(tracker &d, uint64_t state); + void set_id(binary _id); + proton::tracker send_ctrl(proton::symbol descriptor, proton::value _value); void handle_outcome(proton::tracker t); transaction_impl(proton::sender &_txn_ctrl, @@ -67,19 +72,21 @@ class transaction_impl { class PN_CPP_CLASS_EXTERN transaction { - // private: - // PN_CPP_EXTERN transaction(proton::sender& _txn_ctrl, - // proton::transaction_handler& _handler, bool _settle_before_discharge); + private: + // PN_CPP_EXTERN transaction(proton::sender& _txn_ctrl, + // proton::transaction_handler& _handler, bool _settle_before_discharge); + + static transaction mk_transaction_impl(sender &s, transaction_handler &h, + bool f); + PN_CPP_EXTERN transaction(transaction_impl *impl); + transaction_impl *_impl; - static transaction mk_transaction_impl(sender &s, transaction_handler &h, - bool f); - PN_CPP_EXTERN transaction(transaction_impl* impl); public: - transaction_impl* _impl; - // TODO: + // TODO: // PN_CPP_EXTERN transaction(transaction &o); PN_CPP_EXTERN transaction(); PN_CPP_EXTERN ~transaction(); + PN_CPP_EXTERN bool is_empty(); PN_CPP_EXTERN void commit(); PN_CPP_EXTERN void abort(); PN_CPP_EXTERN void declare(); diff --git a/cpp/src/messaging_adapter.cpp b/cpp/src/messaging_adapter.cpp index 9a9a048bf..dcf79f777 100644 --- a/cpp/src/messaging_adapter.cpp +++ b/cpp/src/messaging_adapter.cpp @@ -71,12 +71,8 @@ void on_link_flow(messaging_handler& handler, pn_event_t* event) { // TODO: process session flow data, if no link-specific data, just return. if (!lnk) return; int state = pn_link_state(lnk); - if (pn_terminus_get_type(pn_link_remote_target(lnk))==PN_COORDINATOR) { - std::cout << " on_link_flow, type: PN_COORDINATOR" << std::endl; - return; - - } - if ((state&PN_LOCAL_ACTIVE) && (state&PN_REMOTE_ACTIVE)) { + if (pn_terminus_get_type(pn_link_remote_target(lnk)) == PN_COORDINATOR || + ((state & PN_LOCAL_ACTIVE) && (state & PN_REMOTE_ACTIVE))) { link_context& lctx = link_context::get(lnk); if (pn_link_is_sender(lnk)) { if (pn_link_credit(lnk) > 0) { @@ -123,13 +119,36 @@ void on_delivery(messaging_handler& handler, pn_event_t* event) { Tracing& ot = Tracing::getTracing(); if (pn_terminus_get_type(pn_link_remote_target(lnk))==PN_COORDINATOR) { // delivery d(make_wrapper(dlv)); - pn_disposition_t *disposition = pn_delivery_remote(dlv); - proton::value val(pn_disposition_data(disposition)); - std::cout << " on_delivery: COOORINDATOR.. tracker: " << val - << std::endl; - tracker t(make_wrapper(dlv)); + // pn_disposition_t *disposition = pn_delivery_remote(dlv); + // proton::value val(pn_disposition_data(disposition)); + // std::cout << " on_delivery: COOORINDATOR.. tracker: " << val + // << std::endl; + // tracker t(make_wrapper(dlv)); std::cout << " on_delivery: COOORINDATOR.. TRACKER MADE: " << std::endl; + + if (pn_delivery_updated(dlv)) { + tracker t(make_wrapper(dlv)); + ot.on_settled_span(t); + switch (pn_delivery_remote_state(dlv)) { + case PN_ACCEPTED: + handler.on_tracker_accept(t); + break; + case PN_REJECTED: + handler.on_tracker_reject(t); + break; + case PN_RELEASED: + case PN_MODIFIED: + handler.on_tracker_release(t); + break; + } + if (t.settled()) { + handler.on_tracker_settle(t); + if (lctx.auto_settle) + t.settle(); + } + } + // t.user_data = val; // not // proton::disposition _disposition = make_wrapper(disposition); // # @@ -140,7 +159,7 @@ void on_delivery(messaging_handler& handler, pn_event_t* event) { // std::cout<< " on_delivery: COOORINDATOR with TXN IN :" // << val2 << std::endl; - handler.on_tracker_settle(t); + // handler.on_tracker_settle(t); } else if (pn_link_is_receiver(lnk)) { delivery d(make_wrapper(dlv)); if (pn_delivery_aborted(dlv)) { diff --git a/cpp/src/proactor_container_impl.cpp b/cpp/src/proactor_container_impl.cpp index 00ab38bef..8fd238b40 100644 --- a/cpp/src/proactor_container_impl.cpp +++ b/cpp/src/proactor_container_impl.cpp @@ -872,36 +872,16 @@ void container::impl::stop(const proton::error_condition& err) { transaction container::impl::declare_transaction(proton::connection conn, proton::transaction_handler &handler, bool settle_before_discharge) { class InternalTransactionHandler : public proton::messaging_handler { // TODO: auto_settle + void on_tracker_settle(proton::tracker &t) override { std::cout<<" [InternalTransactionHandler][on_tracker_settle] called with tracker.txn" << std::endl; - t.transaction().handle_outcome(t); - - // t.user_data = val; // not - - // proton::disposition _disposition = make_wrapper(disposition); - // // # t.remote(); - - // proton::value val2 = _disposition.data(); - - // proton::disposition _disposition = t.remote(); - - // proton::value val = _disposition.data(); - - // std::cout<< " declare_transaction: on_tracker_settle with - // TXN IN :" << val << std::endl; - - // if(t.transaction()) { - // t.transaction().handle_outcome(t); - // } + if (!t.transaction().is_empty()) { + t.transaction().handle_outcome(t); + } } - - // TODO: Add on_unhandled function }; - // TODO: Sender should be created only once. (May be use Singleton Class) - // proton::target_options t; - proton::target_options t; std::vector cap = {proton::symbol("amqp:local-transactions")}; t.capabilities(cap); @@ -909,15 +889,12 @@ transaction container::impl::declare_transaction(proton::connection conn, proton proton::sender_options so; so.name("txn-ctrl"); - // Todo: Check the value, Or by deafult null? - //so.source() ? so.target(t); - // TODO: FIX STATIC static InternalTransactionHandler internal_handler; // internal_handler going out of scope. Fix it so.handler(internal_handler); std::cout<<" [declare_transaction] txn-name sender open with handler: " << &internal_handler << std::endl; - proton::sender s = conn.open_sender("does not matter", so); + static proton::sender s = conn.open_sender("does not matter", so); settle_before_discharge = false; diff --git a/cpp/src/transaction.cpp b/cpp/src/transaction.cpp index b7865cf7b..f67c08d9d 100644 --- a/cpp/src/transaction.cpp +++ b/cpp/src/transaction.cpp @@ -21,9 +21,11 @@ #include "proton/transaction.hpp" #include "proton/delivery.h" +#include "proton/delivery.hpp" #include "proton/message.hpp" #include "proton/target_options.hpp" #include "proton/tracker.hpp" +#include "proton/transfer.hpp" #include "proton_bits.hpp" #include @@ -51,6 +53,7 @@ transaction::~transaction() = default; void transaction::commit() { _impl->commit(); }; void transaction::abort() { _impl->abort(); }; void transaction::declare() { _impl->declare(); }; +bool transaction::is_empty() { return _impl == NULL; }; proton::tracker transaction::send(proton::sender s, proton::message msg) { return _impl->send(s, msg); }; @@ -60,11 +63,10 @@ void transaction::handle_outcome(proton::tracker t) { _impl->handle_outcome(t); }; - -transaction_impl::transaction_impl(proton::sender& _txn_ctrl, proton::transaction_handler& _handler, bool _settle_before_discharge): - txn_ctrl(&_txn_ctrl), - handler(&_handler) -{ +transaction_impl::transaction_impl(proton::sender &_txn_ctrl, + proton::transaction_handler &_handler, + bool _settle_before_discharge) + : txn_ctrl(_txn_ctrl), handler(&_handler) { // bool settle_before_discharge = _settle_before_discharge; declare(); } @@ -95,11 +97,19 @@ void transaction_impl::declare() { << std::endl; } -void transaction_impl::discharge(bool failed) { - failed = failed; - proton::symbol descriptor("amqp:declare:list"); - proton::value _value; - proton::tracker discharge = send_ctrl(descriptor, _value); +void transaction_impl::discharge(bool _failed) { + failed = _failed; + proton::symbol descriptor("amqp:discharge:list"); + std::list vd; + vd.push_back(id); + vd.push_back(failed); + proton::value _value = vd; + _discharge = send_ctrl(descriptor, _value); +} + +void transaction_impl::set_id(binary _id) { + std::cout << " TXN ID: " << _id << " from " << this << std::endl; + id = _id; } proton::tracker transaction_impl::send_ctrl(proton::symbol descriptor, proton::value _value) { @@ -113,7 +123,7 @@ proton::tracker transaction_impl::send_ctrl(proton::symbol descriptor, proton::v proton::message msg = msg_value; std::cout << " [transaction_impl::send_ctrl] sending " << msg << std::endl; - proton::tracker delivery = txn_ctrl->send(msg); + proton::tracker delivery = txn_ctrl.send(msg); std::cout << " # declare, delivery as tracker: " << delivery << std::endl; delivery.transaction(transaction(this)); @@ -125,32 +135,101 @@ proton::tracker transaction_impl::send_ctrl(proton::symbol descriptor, proton::v proton::tracker transaction_impl::send(proton::sender s, proton::message msg) { proton::tracker tracker = s.send(msg); + std::cout << " transaction_impl::send " << id << ", done: " << msg + << " tracker: " << tracker << std::endl; + update(tracker, 0x34); + std::cout << " transaction_impl::send, update" << std::endl; return tracker; } +void transaction_impl::accept(tracker &t) { + // TODO: settle-before-discharge + t.settle(); + // pending.push_back(d); +} + +// TODO: use enum transfer::state +void transaction_impl::update(tracker &t, uint64_t state) { + if (state) { + proton::value data(pn_disposition_data(pn_delivery_local(unwrap(t)))); + std::list data_to_send; + data_to_send.push_back(id); + data = data_to_send; + + pn_delivery_update(unwrap(t), state); + // pn_delivery_settle(o); + // delivery.update(0x34) + } +} + +void transaction_impl::release_pending() { + for (auto d : pending) { + // d.update(released); + // d.settle(); + // TODO: fix it + delivery d2(make_wrapper(unwrap(d))); + d2.release(); + } + pending.clear(); +} + void transaction_impl::handle_outcome(proton::tracker t) { // std::vector _data = // proton::get>(val); auto txn = t.transaction(); - std::cout << " handle_outcome::txn_impl i am is " << this << std::endl; - std::cout << " handle_outcome::_declare is " << _declare << std::endl; - std::cout << " handle_outcome::tracker is " << t << std::endl; + std::cout << " ## handle_outcome::txn_impl i am is " << this << std::endl; + std::cout << " ## handle_outcome::_declare is " << _declare << std::endl; + std::cout << " ## handle_outcome::tracker is " << t << std::endl; + pn_disposition_t *disposition = pn_delivery_remote(unwrap(t)); // TODO: handle outcome if(_declare == t) { - std::cout<<" transaction_impl::handle_outcome => got _declare" << std::endl; - pn_disposition_t *disposition = pn_delivery_remote(unwrap(t)); + std::cout << " transaction_impl::handle_outcome => got _declare" + << std::endl; proton::value val(pn_disposition_data(disposition)); auto vd = get>(val); - txn._impl->id = vd[0]; - std::cout << " transaction_impl: handle_outcome.. got txnid:: " - << vd[0] << std::endl; - handler->on_transaction_declared(txn); + if (vd.size() > 0) { + txn._impl->set_id(vd[0]); + std::cout << " transaction_impl: handle_outcome.. txn_declared " + "got txnid:: " + << vd[0] << std::endl; + handler->on_transaction_declared(txn); + } else if (pn_disposition_is_failed(disposition)) { + std::cout << " transaction_impl: handle_outcome.. " + "txn_declared_failed pn_disposition_is_failed " + << std::endl; + handler->on_transaction_declare_failed(txn); + } else { + std::cout + << " transaction_impl: handle_outcome.. txn_declared_failed " + << std::endl; + handler->on_transaction_declare_failed(txn); + } } else if (_discharge == t) { - std::cout << " transaction_impl::handle_outcome => got _discharge" - << std::endl; - handler->on_transaction_committed(txn); + if (pn_disposition_is_failed(disposition)) { + if (!failed) { + std::cout + << " transaction_impl: handle_outcome.. commit failed " + << std::endl; + handler->on_transaction_commit_failed(txn); + // release pending + } + } else { + if (failed) { + handler->on_transaction_aborted(txn); + std::cout + << " transaction_impl: handle_outcome.. txn aborted" + << std::endl; + // release pending + } else { + handler->on_transaction_committed(txn); + std::cout + << " transaction_impl: handle_outcome.. txn commited" + << std::endl; + } + } + pending.clear(); } else { std::cout << " transaction_impl::handle_outcome => got NONE!" << std::endl; From 347cf6e7efb2349fbd6b064ec18a997ee55b89d9 Mon Sep 17 00:00:00 2001 From: Rakhi Kumari Date: Tue, 26 Nov 2024 15:29:50 +0530 Subject: [PATCH 8/8] Add tx_recv file --- cpp/examples/CMakeLists.txt | 3 +- cpp/examples/tx_recv.cpp | 129 ++++++++++++++++++++++++++++ cpp/examples/tx_send.cpp | 35 ++++---- cpp/include/proton/container.hpp | 1 - cpp/include/proton/session.hpp | 2 + cpp/include/proton/tracker.hpp | 1 - cpp/include/proton/transaction.hpp | 6 +- cpp/include/proton/transfer.hpp | 30 +++---- cpp/src/container.cpp | 5 -- cpp/src/messaging_adapter.cpp | 54 +----------- cpp/src/proactor_container_impl.cpp | 74 ++++++++-------- cpp/src/session.cpp | 45 ++++++++++ cpp/src/transaction.cpp | 21 +++-- cpp/src/transfer.cpp | 38 ++++---- 14 files changed, 284 insertions(+), 160 deletions(-) create mode 100644 cpp/examples/tx_recv.cpp diff --git a/cpp/examples/CMakeLists.txt b/cpp/examples/CMakeLists.txt index 85b170377..766d34b2e 100644 --- a/cpp/examples/CMakeLists.txt +++ b/cpp/examples/CMakeLists.txt @@ -61,7 +61,8 @@ foreach(example service_bus multithreaded_client multithreaded_client_flow_control - tx_send) + tx_send + tx_recv) add_executable(${example} ${example}.cpp) target_link_libraries(${example} Proton::cpp Threads::Threads) endforeach() diff --git a/cpp/examples/tx_recv.cpp b/cpp/examples/tx_recv.cpp new file mode 100644 index 000000000..07d2061e4 --- /dev/null +++ b/cpp/examples/tx_recv.cpp @@ -0,0 +1,129 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include "options.hpp" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +class tx_recv : public proton::messaging_handler, proton::transaction_handler { + private: + proton::receiver receiver; + std::string url; + int expected; + int batch_size; + int current_batch = 0; + int committed = 0; + + proton::session session; + proton::transaction transaction; + public: + tx_recv(const std::string &s, int c, int b): + url(s), expected(c), batch_size(b) {} + + void on_container_start(proton::container &c) override { + receiver = c.open_receiver(url); + } + + void on_session_open(proton::session &s) override { + session = s; + std::cout << " [on_session_open] declare_txn started..." << std::endl; + s.declare_transaction(*this); + std::cout << " [on_session_open] declare_txn ended..." << std::endl; + } + + void on_transaction_declare_failed(proton::transaction) {} + void on_transaction_commit_failed(proton::transaction t) { + std::cout << "Transaction Commit Failed" << std::endl; + t.connection().close(); + exit(-1); + } + + void on_transaction_declared(proton::transaction t) override { + std::cout << "[on_transaction_declared] txn called " << (&t) + << std::endl; + std::cout << "[on_transaction_declared] txn is_empty " << (t.is_empty()) + << "\t" << transaction.is_empty() << std::endl; + receiver.add_credit(batch_size); + transaction = t; + } + + void on_message(proton::delivery &d, proton::message &msg) override { + std::cout<<"# MESSAGE: " << msg.id() <<": " << msg.body() << std::endl; + transaction.accept(d); + current_batch += 1; + if(current_batch == batch_size) { + transaction = proton::transaction(); // null + } + } + + void on_transaction_committed(proton::transaction t) override { + committed += current_batch; + current_batch = 0; + std::cout<<" [OnTxnCommitted] Committed:"<< committed<< std::endl; + if(committed == expected) { + std::cout << "All messages committed" << std::endl; + t.connection().close(); + } + else { + session.declare_transaction(*this); + } + } + +}; + +int main(int argc, char **argv) { + std::string address("127.0.0.1:5672/examples"); + int message_count = 9; + int batch_size = 3; + example::options opts(argc, argv); + + opts.add_value(address, 'a', "address", "connect and send to URL", "URL"); + opts.add_value(message_count, 'm', "messages", "number of messages to send", "COUNT"); + opts.add_value(batch_size, 'b', "batch_size", "number of messages in each transaction", "BATCH_SIZE"); + + try { + opts.parse(); + + tx_recv recv(address, message_count, batch_size); + proton::container(recv).run(); + + return 0; + } catch (const example::bad_option& e) { + std::cout << opts << std::endl << e.what() << std::endl; + } catch (const std::exception& e) { + std::cerr << e.what() << std::endl; + } + + return 1; +} diff --git a/cpp/examples/tx_send.cpp b/cpp/examples/tx_send.cpp index f2e8e4e21..6acee58fd 100644 --- a/cpp/examples/tx_send.cpp +++ b/cpp/examples/tx_send.cpp @@ -48,35 +48,33 @@ class tx_send : public proton::messaging_handler, proton::transaction_handler { int committed = 0; int confirmed = 0; - proton::container *container; - // proton::transaction_handler transaction_handler; + proton::session session; proton::transaction transaction; - proton::connection connection; public: tx_send(const std::string &s, int c, int b): url(s), total(c), batch_size(b), sent(0) {} void on_container_start(proton::container &c) override { - container = &c; // TODO: Fix error sender = c.open_sender(url); - connection = sender.connection(); - std::cout << " [on_container_start] declare_txn started..." << std::endl; - c.declare_transaction(connection, *this); - std::cout << " [on_container_start] completed!!" << &transaction - << std::endl; + } + + void on_session_open(proton::session &s) override { + session = s; + std::cout << " [on_session_open] declare_txn started..." << std::endl; + s.declare_transaction(*this); + std::cout << " [on_session_open] declare_txn ended..." << std::endl; } void on_transaction_declare_failed(proton::transaction) {} - void on_transaction_commit_failed(proton::transaction) { + void on_transaction_commit_failed(proton::transaction t) { std::cout << "Transaction Commit Failed" << std::endl; - connection.close(); + t.connection().close(); exit(-1); } void on_transaction_declared(proton::transaction t) override { std::cout << "[on_transaction_declared] txn called " << (&t) << std::endl; - // connection.close(); std::cout << "[on_transaction_declared] txn is_empty " << (t.is_empty()) << "\t" << transaction.is_empty() << std::endl; transaction = t; @@ -85,23 +83,22 @@ class tx_send : public proton::messaging_handler, proton::transaction_handler { } void on_sendable(proton::sender &s) override { - // send(); std::cout << " [OnSendable] transaction: " << &transaction << std::endl; send(s); } void send(proton::sender &s) { - // TODO: Add more condition in while loop + static int unique_id = 10000; while (!transaction.is_empty() && sender.credit() && (committed + current_batch) < total) { proton::message msg; std::map m; m["sequence"] = committed + current_batch; - msg.id(committed + current_batch + 1); + msg.id(unique_id++); msg.body(m); - std::cout << " [example] transaction send msg: " << msg + std::cout << "##### [example] transaction send msg: " << msg << std::endl; transaction.send(sender, msg); current_batch += 1; @@ -132,17 +129,17 @@ class tx_send : public proton::messaging_handler, proton::transaction_handler { std::cout<<" [OnTxnCommitted] Committed:"<< committed<< std::endl; if(committed == total) { std::cout << "All messages committed" << std::endl; - connection.close(); + t.connection().close(); } else { - container->declare_transaction(connection, *this); + session.declare_transaction(*this); } } void on_transaction_aborted(proton::transaction t) override { std::cout << "Meesages Aborted ....." << std::endl; current_batch = 0; - container->declare_transaction(connection, *this); + session.declare_transaction(*this); } void on_sender_close(proton::sender &s) override { diff --git a/cpp/include/proton/container.hpp b/cpp/include/proton/container.hpp index a6153fa69..c2c6d206e 100644 --- a/cpp/include/proton/container.hpp +++ b/cpp/include/proton/container.hpp @@ -312,7 +312,6 @@ class PN_CPP_CLASS_EXTERN container { /// Cancel task for the given work_handle. PN_CPP_EXTERN void cancel(work_handle); - PN_CPP_EXTERN transaction declare_transaction(proton::connection conn, proton::transaction_handler &handler, bool settle_before_discharge = false); private: /// Declare both v03 and v11 if compiling with c++11 as the library contains both. /// A C++11 user should never call the v03 overload so it is private in this case diff --git a/cpp/include/proton/session.hpp b/cpp/include/proton/session.hpp index 60522c817..702bd0db4 100644 --- a/cpp/include/proton/session.hpp +++ b/cpp/include/proton/session.hpp @@ -105,6 +105,8 @@ PN_CPP_CLASS_EXTERN session : public internal::object, public endp /// Get user data from this session. PN_CPP_EXTERN void* user_data() const; + PN_CPP_EXTERN transaction declare_transaction(proton::transaction_handler &handler, bool settle_before_discharge = false); + /// @cond INTERNAL friend class internal::factory; friend class session_iterator; diff --git a/cpp/include/proton/tracker.hpp b/cpp/include/proton/tracker.hpp index 437a21289..3d8ad0aab 100644 --- a/cpp/include/proton/tracker.hpp +++ b/cpp/include/proton/tracker.hpp @@ -25,7 +25,6 @@ #include "./binary.hpp" #include "./internal/export.hpp" #include "./transfer.hpp" -#include "./messaging_handler.hpp" /// @file /// @copybrief proton::tracker diff --git a/cpp/include/proton/transaction.hpp b/cpp/include/proton/transaction.hpp index 51759f796..6ca0fac96 100644 --- a/cpp/include/proton/transaction.hpp +++ b/cpp/include/proton/transaction.hpp @@ -55,7 +55,7 @@ class transaction_impl { void discharge(bool failed); void release_pending(); - void accept(tracker &d); + void accept(delivery &d); void update(tracker &d, uint64_t state); void set_id(binary _id); @@ -92,9 +92,11 @@ PN_CPP_CLASS_EXTERN transaction { PN_CPP_EXTERN void declare(); PN_CPP_EXTERN void handle_outcome(proton::tracker); PN_CPP_EXTERN proton::tracker send(proton::sender s, proton::message msg); + PN_CPP_EXTERN void accept(delivery &t); + PN_CPP_EXTERN proton::connection connection() const; friend class transaction_impl; - friend class container::impl; + friend class session; }; class diff --git a/cpp/include/proton/transfer.hpp b/cpp/include/proton/transfer.hpp index 1e7995c06..ada5305c5 100644 --- a/cpp/include/proton/transfer.hpp +++ b/cpp/include/proton/transfer.hpp @@ -33,25 +33,25 @@ /// @copybrief proton::transfer struct pn_delivery_t; -struct pn_disposition_t; +// struct pn_disposition_t; namespace proton { -class disposition : public internal::object { - /// @cond INTERNAL - disposition(pn_disposition_t *d) : internal::object(d) {} - /// @endcond +// class disposition : public internal::object { +// /// @cond INTERNAL +// disposition(pn_disposition_t *d) : internal::object(d) {} +// /// @endcond - public: - /// Create an empty disposition. - disposition() : internal::object(0) {} +// public: +// /// Create an empty disposition. +// disposition() : internal::object(0) {} - proton::value data() const; +// proton::value data() const; - /// @cond INTERNAL - friend class internal::factory; - /// @endcond -}; +// /// @cond INTERNAL +// friend class internal::factory; +// /// @endcond +// }; /// The base class for delivery and tracker. class transfer : public internal::object { @@ -105,8 +105,8 @@ class transfer : public internal::object { /// Get user data from this transfer. PN_CPP_EXTERN void* user_data() const; - PN_CPP_EXTERN disposition remote(); - PN_CPP_EXTERN disposition local(); + // PN_CPP_EXTERN disposition remote(); + // PN_CPP_EXTERN disposition local(); /// @cond INTERNAL friend class internal::factory; diff --git a/cpp/src/container.cpp b/cpp/src/container.cpp index 427da590f..8189539de 100644 --- a/cpp/src/container.cpp +++ b/cpp/src/container.cpp @@ -28,7 +28,6 @@ #include "proton/uuid.hpp" #include "proactor_container_impl.hpp" -#include namespace proton { @@ -46,10 +45,6 @@ returned container::connect(const std::string &url) { return connect(url, connection_options()); } -transaction container::declare_transaction(proton::connection conn, proton::transaction_handler &handler, bool settle_before_discharge) { - return impl_->declare_transaction(conn, handler, settle_before_discharge); -} - returned container::open_sender(const std::string &url) { return open_sender(url, proton::sender_options(), connection_options()); } diff --git a/cpp/src/messaging_adapter.cpp b/cpp/src/messaging_adapter.cpp index dcf79f777..3eb0c11f1 100644 --- a/cpp/src/messaging_adapter.cpp +++ b/cpp/src/messaging_adapter.cpp @@ -118,12 +118,6 @@ void on_delivery(messaging_handler& handler, pn_event_t* event) { link_context& lctx = link_context::get(lnk); Tracing& ot = Tracing::getTracing(); if (pn_terminus_get_type(pn_link_remote_target(lnk))==PN_COORDINATOR) { - // delivery d(make_wrapper(dlv)); - // pn_disposition_t *disposition = pn_delivery_remote(dlv); - // proton::value val(pn_disposition_data(disposition)); - // std::cout << " on_delivery: COOORINDATOR.. tracker: " << val - // << std::endl; - // tracker t(make_wrapper(dlv)); std::cout << " on_delivery: COOORINDATOR.. TRACKER MADE: " << std::endl; @@ -148,18 +142,6 @@ void on_delivery(messaging_handler& handler, pn_event_t* event) { t.settle(); } } - - // t.user_data = val; // not - - // proton::disposition _disposition = make_wrapper(disposition); // # - // t.remote(); - - // proton::value val2 = _disposition.data(); - - // std::cout<< " on_delivery: COOORINDATOR with TXN IN :" - // << val2 << std::endl; - - // handler.on_tracker_settle(t); } else if (pn_link_is_receiver(lnk)) { delivery d(make_wrapper(dlv)); if (pn_delivery_aborted(dlv)) { @@ -333,42 +315,8 @@ void on_link_remote_open(messaging_handler& handler, pn_event_t* event) { return; } std::cout<<" IN on_link_remote_open(.PN_COORDINATOR) success " << std::endl; + std::cout<<" IN on_link_remote_open(.PN_COORDINATOR) have handler " << &handler << std::endl; - // WHY??? - // pn_terminus_copy(pn_link_source(lnk), pn_link_remote_source(lnk)); - // pn_terminus_copy(pn_link_target(lnk), pn_link_remote_target(lnk)); - - // We need a new class? - // auto coordinator = pn_link_remote_target(lnk); - - - // proton::target_options to; - // std::vector cap = {proton::symbol("amqp:local-transactions")}; - // to.capabilities(cap); - // to.type(PN_COORDINATOR); - - // proton::receiver_options ro; - // ro.name("txn-ctrl"); - // ro.target(to); - // ro.handler(handler); - // receiver r(make_wrapper(lnk)); - - // proton::receiver rcv = r.connection().open_receiver("does not matter", ro); - std::cout<<" IN on_link_remote_open(.PN_COORDINATOR) have handler " << &handler << std::endl; - - // handler.on_receiver_open(rcv); - // credit_topup(lnk); - - // pn_delivery_t *dlv = pn_event_delivery(event); - // tracker t(make_wrapper(dlv)); - - // // sender s(make_wrapper(lnk)); - // handler.on_tracker_settle(t); - // TODO: find what to do... - // HAHA.. treating coordinator like sender... - // sender s(make_wrapper(lnk)); - // handler.on_sender_open(s); - // pn_link_close(lnk); return; } if (pn_link_state(lnk) & PN_LOCAL_UNINIT) { // Incoming link diff --git a/cpp/src/proactor_container_impl.cpp b/cpp/src/proactor_container_impl.cpp index 8fd238b40..34d1e19cc 100644 --- a/cpp/src/proactor_container_impl.cpp +++ b/cpp/src/proactor_container_impl.cpp @@ -869,42 +869,42 @@ void container::impl::stop(const proton::error_condition& err) { // TODO: declare this in separate internal header file // extern transaction mk_transaction_impl(sender&, transaction_handler&, bool); -transaction container::impl::declare_transaction(proton::connection conn, proton::transaction_handler &handler, bool settle_before_discharge) { - class InternalTransactionHandler : public proton::messaging_handler { - // TODO: auto_settle - - void on_tracker_settle(proton::tracker &t) override { - std::cout<<" [InternalTransactionHandler][on_tracker_settle] called with tracker.txn" - << std::endl; - if (!t.transaction().is_empty()) { - t.transaction().handle_outcome(t); - } - } - }; - - proton::target_options t; - std::vector cap = {proton::symbol("amqp:local-transactions")}; - t.capabilities(cap); - t.type(PN_COORDINATOR); - - proton::sender_options so; - so.name("txn-ctrl"); - so.target(t); - static InternalTransactionHandler internal_handler; // internal_handler going out of scope. Fix it - so.handler(internal_handler); - std::cout<<" [declare_transaction] txn-name sender open with handler: " << &internal_handler << std::endl; - - static proton::sender s = conn.open_sender("does not matter", so); - - settle_before_discharge = false; - - std::cout<<" [declare_transaction] calling mk_transaction_impl" << std::endl; - - auto txn = - transaction::mk_transaction_impl(s, handler, settle_before_discharge); - std::cout<<" [declare_transaction] txn address:" << &txn << std::endl; - - return txn; -} +// transaction container::impl::declare_transaction(proton::connection conn, proton::transaction_handler &handler, bool settle_before_discharge) { +// class InternalTransactionHandler : public proton::messaging_handler { +// // TODO: auto_settle + +// void on_tracker_settle(proton::tracker &t) override { +// std::cout<<" [InternalTransactionHandler][on_tracker_settle] called with tracker.txn" +// << std::endl; +// if (!t.transaction().is_empty()) { +// t.transaction().handle_outcome(t); +// } +// } +// }; + +// proton::target_options t; +// std::vector cap = {proton::symbol("amqp:local-transactions")}; +// t.capabilities(cap); +// t.type(PN_COORDINATOR); + +// proton::sender_options so; +// so.name("txn-ctrl"); +// so.target(t); +// static InternalTransactionHandler internal_handler; // internal_handler going out of scope. Fix it +// so.handler(internal_handler); +// std::cout<<" [declare_transaction] txn-name sender open with handler: " << &internal_handler << std::endl; + +// static proton::sender s = conn.open_sender("does not matter", so); + +// settle_before_discharge = false; + +// std::cout<<" [declare_transaction] calling mk_transaction_impl" << std::endl; + +// auto txn = +// transaction::mk_transaction_impl(s, handler, settle_before_discharge); +// std::cout<<" [declare_transaction] txn address:" << &txn << std::endl; + +// return txn; +// } } diff --git a/cpp/src/session.cpp b/cpp/src/session.cpp index b8f777a00..148d35993 100644 --- a/cpp/src/session.cpp +++ b/cpp/src/session.cpp @@ -24,6 +24,9 @@ #include "proton/receiver_options.hpp" #include "proton/sender_options.hpp" #include "proton/session_options.hpp" +#include "proton/target_options.hpp" +#include "proton/transaction.hpp" +#include "proton/messaging_handler.hpp" #include "contexts.hpp" #include "link_namer.hpp" @@ -34,6 +37,9 @@ #include +// XXXX: Debug +#include + namespace proton { session::~session() = default; @@ -148,4 +154,43 @@ void* session::user_data() const { return sctx.user_data_; } +transaction session::declare_transaction(proton::transaction_handler &handler, bool settle_before_discharge) { + proton::connection conn = this->connection(); + class InternalTransactionHandler : public proton::messaging_handler { + // TODO: auto_settle + + void on_tracker_settle(proton::tracker &t) override { + std::cout<<" [InternalTransactionHandler][on_tracker_settle] called with tracker.txn" + << std::endl; + if (!t.transaction().is_empty()) { + t.transaction().handle_outcome(t); + } + } + }; + + proton::target_options t; + std::vector cap = {proton::symbol("amqp:local-transactions")}; + t.capabilities(cap); + t.type(PN_COORDINATOR); + + proton::sender_options so; + so.name("txn-ctrl"); + so.target(t); + static InternalTransactionHandler internal_handler; // internal_handler going out of scope. Fix it + so.handler(internal_handler); + std::cout<<" [declare_transaction] txn-name sender open with handler: " << &internal_handler << std::endl; + + static proton::sender s = conn.open_sender("does not matter", so); + + settle_before_discharge = false; + + std::cout<<" [declare_transaction] calling mk_transaction_impl" << std::endl; + + auto txn = + transaction::mk_transaction_impl(s, handler, settle_before_discharge); + std::cout<<" [declare_transaction] txn address:" << &txn << std::endl; + + return txn; +} + } // namespace proton diff --git a/cpp/src/transaction.cpp b/cpp/src/transaction.cpp index f67c08d9d..d21568519 100644 --- a/cpp/src/transaction.cpp +++ b/cpp/src/transaction.cpp @@ -50,18 +50,19 @@ transaction::transaction(transaction_impl *impl) : _impl(impl) {} // transaction::transaction( transaction_impl* impl): _impl(impl){} transaction::~transaction() = default; -void transaction::commit() { _impl->commit(); }; -void transaction::abort() { _impl->abort(); }; -void transaction::declare() { _impl->declare(); }; -bool transaction::is_empty() { return _impl == NULL; }; +void transaction::commit() { _impl->commit(); } +void transaction::abort() { _impl->abort(); } +void transaction::declare() { _impl->declare(); } +bool transaction::is_empty() { return _impl == NULL; } +void transaction::accept(delivery &t) { return _impl->accept(t); } proton::tracker transaction::send(proton::sender s, proton::message msg) { return _impl->send(s, msg); -}; +} void transaction::handle_outcome(proton::tracker t) { std::cout << " transaction::handle_outcome = NO OP base class " << std::endl; _impl->handle_outcome(t); -}; +} transaction_impl::transaction_impl(proton::sender &_txn_ctrl, proton::transaction_handler &_handler, @@ -142,7 +143,7 @@ proton::tracker transaction_impl::send(proton::sender s, proton::message msg) { return tracker; } -void transaction_impl::accept(tracker &t) { +void transaction_impl::accept(delivery &t) { // TODO: settle-before-discharge t.settle(); // pending.push_back(d); @@ -236,8 +237,14 @@ void transaction_impl::handle_outcome(proton::tracker t) { } } + transaction transaction::mk_transaction_impl(sender &s, transaction_handler &h, bool f) { return transaction(new transaction_impl(s, h, f)); } + +proton::connection transaction::connection() const { + return _impl->txn_ctrl.connection(); +} + } diff --git a/cpp/src/transfer.cpp b/cpp/src/transfer.cpp index bdd17035d..ce3779dc2 100644 --- a/cpp/src/transfer.cpp +++ b/cpp/src/transfer.cpp @@ -72,23 +72,23 @@ void* transfer::user_data() const { return cc.user_data_; } -disposition transfer::remote() { - auto me = pn_object(); - std::cout << " transfer::remote ME => " << me << std::endl; - - auto dd = pn_delivery_remote(me); - std::cout << " transfer::remote dd => " << dd << std::endl; - std::cout << " transfer::remote.data dd => " - << proton::value(pn_disposition_data(dd)) << std::endl; - auto d2 = make_wrapper(dd); - std::cout << " transfer::remote d2 ready => " << std::endl; - return d2; -} -disposition transfer::local() { - return make_wrapper(pn_delivery_local(pn_object())); -} - -proton::value disposition::data() const { - return proton::value(pn_disposition_data(pn_object())); -} +// disposition transfer::remote() { +// auto me = pn_object(); +// std::cout << " transfer::remote ME => " << me << std::endl; + +// auto dd = pn_delivery_remote(me); +// std::cout << " transfer::remote dd => " << dd << std::endl; +// std::cout << " transfer::remote.data dd => " +// << proton::value(pn_disposition_data(dd)) << std::endl; +// auto d2 = make_wrapper(dd); +// std::cout << " transfer::remote d2 ready => " << std::endl; +// return d2; +// } +// disposition transfer::local() { +// return make_wrapper(pn_delivery_local(pn_object())); +// } + +// proton::value disposition::data() const { +// return proton::value(pn_disposition_data(pn_object())); +// } }