diff --git a/src/applications/bmqtool/m_bmqtool_application.cpp b/src/applications/bmqtool/m_bmqtool_application.cpp index 4b27be27b..d7094212a 100644 --- a/src/applications/bmqtool/m_bmqtool_application.cpp +++ b/src/applications/bmqtool/m_bmqtool_application.cpp @@ -71,6 +71,49 @@ namespace { BALL_LOG_SET_NAMESPACE_CATEGORY("BMQTOOL.APPLICATION"); +/// Stack-built functor to pass to `bmqp::ProtocolUtil::buildEvent` +struct BuildConfirmFunctor { + // DATA + bmqa::ConfirmEventBuilder& d_confirmBuilder; + const bmqa::Message& d_message; + + // CREATORS + inline explicit BuildConfirmFunctor( + bmqa::ConfirmEventBuilder& confirmBuilder, + const bmqa::Message& message) + : d_confirmBuilder(confirmBuilder) + , d_message(message) + { + // NOTHING + } + + // MANIPULATORS + inline bmqt::EventBuilderResult::Enum operator()() + { + return d_confirmBuilder.addMessageConfirmation(d_message); + } +}; + +/// Stack-built functor to pass to `bmqp::ProtocolUtil::buildEvent` +struct BuildConfirmOverflowFunctor { + // DATA + bmqa::Session& d_session; + bmqa::ConfirmEventBuilder& d_builder; + + // CREATORS + inline explicit BuildConfirmOverflowFunctor( + bmqa::Session& session, + bmqa::ConfirmEventBuilder& builder) + : d_session(session) + , d_builder(builder) + { + // NOTHING + } + + // MANIPULATORS + inline void operator()() { d_session.confirmMessages(&d_builder); } +}; + } // close unnamed namespace // ----------------- @@ -685,10 +728,9 @@ void Application::onMessageEvent(const bmqa::MessageEvent& event) bmqt::EventBuilderResult::Enum rc = bmqp::ProtocolUtil::buildEvent( - bdlf::BindUtil::bind(f, &confirmBuilder, message), - bdlf::BindUtil::bind(&bmqa::Session::confirmMessages, - d_session_mp.get(), - &confirmBuilder)); + BuildConfirmFunctor(confirmBuilder, message), + BuildConfirmOverflowFunctor(*d_session_mp.get(), + confirmBuilder)); BSLS_ASSERT_SAFE(rc == 0); (void)rc; // compiler happiness diff --git a/src/groups/bmq/bmqp/bmqp_protocolutil.h b/src/groups/bmq/bmqp/bmqp_protocolutil.h index b8c2af80f..0532c6e35 100644 --- a/src/groups/bmq/bmqp/bmqp_protocolutil.h +++ b/src/groups/bmq/bmqp/bmqp_protocolutil.h @@ -399,10 +399,20 @@ struct ProtocolUtil { /// Invoke the specified `action` and if it returns e_EVENT_TOO_BIG then /// invoke the specified `overflowCb` and call `action` again. Return /// result code returned from `action` + /// DEPRECATED: use `buildEvent` with functors instead, to avoid loss of + /// performance from `bsl::function` on critical paths. static bmqt::EventBuilderResult::Enum buildEvent( const bsl::function& action, const bsl::function& overflowCb); + /// Invoke the specified `actionCb` and if it returns e_EVENT_TOO_BIG then + /// invoke the specified `overflowCb` and call `actionCb` again. Return + /// result code returned from `action` + template + static bmqt::EventBuilderResult::Enum + buildEvent(ACTION_FUNCTOR_TYPE& actionCb, + OVERFLOW_FUNCTOR_TYPE& overflowCb); + /// Encode Receipt into the specified `blob` for the specified /// `partitionId`, `primaryLeaseId`, and `sequenceNumber`. static void buildReceipt(bdlbb::Blob* blob, @@ -708,6 +718,22 @@ inline bmqt::EventBuilderResult::Enum ProtocolUtil::buildEvent( return rc; }; +template +inline bmqt::EventBuilderResult::Enum +ProtocolUtil::buildEvent(ACTION_FUNCTOR_TYPE& actionCb, + OVERFLOW_FUNCTOR_TYPE& overflowCb) +{ + bmqt::EventBuilderResult::Enum rc = actionCb(); + if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY( + bmqt::EventBuilderResult::e_EVENT_TOO_BIG == rc)) { + BSLS_PERFORMANCEHINT_UNLIKELY_HINT; + + overflowCb(); + rc = actionCb(); + } + return rc; +}; + inline void ProtocolUtil::buildReceipt(bdlbb::Blob* blob, int partitionId, unsigned int primaryLeaseId, diff --git a/src/groups/mqb/mqba/mqba_clientsession.cpp b/src/groups/mqb/mqba/mqba_clientsession.cpp index 0d1d5674c..45bd278ee 100644 --- a/src/groups/mqb/mqba/mqba_clientsession.cpp +++ b/src/groups/mqb/mqba/mqba_clientsession.cpp @@ -287,6 +287,56 @@ void finalizeClosedHandle(bsl::string description, << handle->handleParameters(); } +/// Stack-built functor to pass to `bmqp::ProtocolUtil::buildEvent` +struct BuildAckFunctor { + // DATA + bmqp::AckEventBuilder& d_ackBuilder; + int d_status; + int d_correlationId; + const bmqt::MessageGUID& d_messageGUID; + int d_queueId; + + // CREATORS + inline explicit BuildAckFunctor(bmqp::AckEventBuilder& ackBuilder, + int status, + int correlationId, + const bmqt::MessageGUID& messageGUID, + int queueId) + : d_ackBuilder(ackBuilder) + , d_status(status) + , d_correlationId(correlationId) + , d_messageGUID(messageGUID) + , d_queueId(queueId) + { + // NOTHING + } + + // MANIPULATORS + inline bmqt::EventBuilderResult::Enum operator()() + { + return d_ackBuilder.appendMessage(d_status, + d_correlationId, + d_messageGUID, + d_queueId); + } +}; + +/// Stack-built functor to pass to `bmqp::ProtocolUtil::buildEvent` +struct BuildAckOverflowFunctor { + // DATA + mqba::ClientSession& d_session; + + // CREATORS + inline explicit BuildAckOverflowFunctor(mqba::ClientSession& session) + : d_session(session) + { + // NOTHING + } + + // MANIPULATORS + inline void operator()() { d_session.flush(); } +}; + } // close unnamed namespace // ------------------------- @@ -560,13 +610,12 @@ void ClientSession::sendAck(bmqt::AckResult::Enum status, // Append the ACK to the ackBuilder bmqt::EventBuilderResult::Enum rc = bmqp::ProtocolUtil::buildEvent( - bdlf::BindUtil::bind(&bmqp::AckEventBuilder::appendMessage, - &d_state.d_ackBuilder, - bmqp::ProtocolUtil::ackResultToCode(status), - correlationId, - messageGUID, - queueId), - bdlf::BindUtil::bind(&ClientSession::flush, this)); + BuildAckFunctor(d_state.d_ackBuilder, + bmqp::ProtocolUtil::ackResultToCode(status), + correlationId, + messageGUID, + queueId), + BuildAckOverflowFunctor(*this)); if (rc != bmqt::EventBuilderResult::e_SUCCESS) { BALL_LOG_ERROR << "Failed to append ACK [rc: " << rc << ", source: '"