Skip to content

Commit 7e91fcc

Browse files
authored
Perf[BMQ,MQB]: do not build tmp functions on ACKs (#497)
1 parent 96aba0c commit 7e91fcc

File tree

3 files changed

+128
-11
lines changed

3 files changed

+128
-11
lines changed

src/applications/bmqtool/m_bmqtool_application.cpp

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,49 @@ namespace {
7171

7272
BALL_LOG_SET_NAMESPACE_CATEGORY("BMQTOOL.APPLICATION");
7373

74+
/// Stack-built functor to pass to `bmqp::ProtocolUtil::buildEvent`
75+
struct BuildConfirmFunctor {
76+
// DATA
77+
bmqa::ConfirmEventBuilder& d_confirmBuilder;
78+
const bmqa::Message& d_message;
79+
80+
// CREATORS
81+
inline explicit BuildConfirmFunctor(
82+
bmqa::ConfirmEventBuilder& confirmBuilder,
83+
const bmqa::Message& message)
84+
: d_confirmBuilder(confirmBuilder)
85+
, d_message(message)
86+
{
87+
// NOTHING
88+
}
89+
90+
// MANIPULATORS
91+
inline bmqt::EventBuilderResult::Enum operator()()
92+
{
93+
return d_confirmBuilder.addMessageConfirmation(d_message);
94+
}
95+
};
96+
97+
/// Stack-built functor to pass to `bmqp::ProtocolUtil::buildEvent`
98+
struct BuildConfirmOverflowFunctor {
99+
// DATA
100+
bmqa::Session& d_session;
101+
bmqa::ConfirmEventBuilder& d_builder;
102+
103+
// CREATORS
104+
inline explicit BuildConfirmOverflowFunctor(
105+
bmqa::Session& session,
106+
bmqa::ConfirmEventBuilder& builder)
107+
: d_session(session)
108+
, d_builder(builder)
109+
{
110+
// NOTHING
111+
}
112+
113+
// MANIPULATORS
114+
inline void operator()() { d_session.confirmMessages(&d_builder); }
115+
};
116+
74117
} // close unnamed namespace
75118

76119
// -----------------
@@ -685,10 +728,9 @@ void Application::onMessageEvent(const bmqa::MessageEvent& event)
685728

686729
bmqt::EventBuilderResult::Enum rc =
687730
bmqp::ProtocolUtil::buildEvent(
688-
bdlf::BindUtil::bind(f, &confirmBuilder, message),
689-
bdlf::BindUtil::bind(&bmqa::Session::confirmMessages,
690-
d_session_mp.get(),
691-
&confirmBuilder));
731+
BuildConfirmFunctor(confirmBuilder, message),
732+
BuildConfirmOverflowFunctor(*d_session_mp.get(),
733+
confirmBuilder));
692734

693735
BSLS_ASSERT_SAFE(rc == 0);
694736
(void)rc; // compiler happiness

src/groups/bmq/bmqp/bmqp_protocolutil.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,10 +399,20 @@ struct ProtocolUtil {
399399
/// Invoke the specified `action` and if it returns e_EVENT_TOO_BIG then
400400
/// invoke the specified `overflowCb` and call `action` again. Return
401401
/// result code returned from `action`
402+
/// DEPRECATED: use `buildEvent` with functors instead, to avoid loss of
403+
/// performance from `bsl::function` on critical paths.
402404
static bmqt::EventBuilderResult::Enum buildEvent(
403405
const bsl::function<bmqt::EventBuilderResult::Enum(void)>& action,
404406
const bsl::function<void(void)>& overflowCb);
405407

408+
/// Invoke the specified `actionCb` and if it returns e_EVENT_TOO_BIG then
409+
/// invoke the specified `overflowCb` and call `actionCb` again. Return
410+
/// result code returned from `action`
411+
template <class ACTION_FUNCTOR_TYPE, class OVERFLOW_FUNCTOR_TYPE>
412+
static bmqt::EventBuilderResult::Enum
413+
buildEvent(ACTION_FUNCTOR_TYPE& actionCb,
414+
OVERFLOW_FUNCTOR_TYPE& overflowCb);
415+
406416
/// Encode Receipt into the specified `blob` for the specified
407417
/// `partitionId`, `primaryLeaseId`, and `sequenceNumber`.
408418
static void buildReceipt(bdlbb::Blob* blob,
@@ -708,6 +718,22 @@ inline bmqt::EventBuilderResult::Enum ProtocolUtil::buildEvent(
708718
return rc;
709719
};
710720

721+
template <class ACTION_FUNCTOR_TYPE, class OVERFLOW_FUNCTOR_TYPE>
722+
inline bmqt::EventBuilderResult::Enum
723+
ProtocolUtil::buildEvent(ACTION_FUNCTOR_TYPE& actionCb,
724+
OVERFLOW_FUNCTOR_TYPE& overflowCb)
725+
{
726+
bmqt::EventBuilderResult::Enum rc = actionCb();
727+
if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(
728+
bmqt::EventBuilderResult::e_EVENT_TOO_BIG == rc)) {
729+
BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
730+
731+
overflowCb();
732+
rc = actionCb();
733+
}
734+
return rc;
735+
};
736+
711737
inline void ProtocolUtil::buildReceipt(bdlbb::Blob* blob,
712738
int partitionId,
713739
unsigned int primaryLeaseId,

src/groups/mqb/mqba/mqba_clientsession.cpp

Lines changed: 56 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,56 @@ void finalizeClosedHandle(bsl::string description,
287287
<< handle->handleParameters();
288288
}
289289

290+
/// Stack-built functor to pass to `bmqp::ProtocolUtil::buildEvent`
291+
struct BuildAckFunctor {
292+
// DATA
293+
bmqp::AckEventBuilder& d_ackBuilder;
294+
int d_status;
295+
int d_correlationId;
296+
const bmqt::MessageGUID& d_messageGUID;
297+
int d_queueId;
298+
299+
// CREATORS
300+
inline explicit BuildAckFunctor(bmqp::AckEventBuilder& ackBuilder,
301+
int status,
302+
int correlationId,
303+
const bmqt::MessageGUID& messageGUID,
304+
int queueId)
305+
: d_ackBuilder(ackBuilder)
306+
, d_status(status)
307+
, d_correlationId(correlationId)
308+
, d_messageGUID(messageGUID)
309+
, d_queueId(queueId)
310+
{
311+
// NOTHING
312+
}
313+
314+
// MANIPULATORS
315+
inline bmqt::EventBuilderResult::Enum operator()()
316+
{
317+
return d_ackBuilder.appendMessage(d_status,
318+
d_correlationId,
319+
d_messageGUID,
320+
d_queueId);
321+
}
322+
};
323+
324+
/// Stack-built functor to pass to `bmqp::ProtocolUtil::buildEvent`
325+
struct BuildAckOverflowFunctor {
326+
// DATA
327+
mqba::ClientSession& d_session;
328+
329+
// CREATORS
330+
inline explicit BuildAckOverflowFunctor(mqba::ClientSession& session)
331+
: d_session(session)
332+
{
333+
// NOTHING
334+
}
335+
336+
// MANIPULATORS
337+
inline void operator()() { d_session.flush(); }
338+
};
339+
290340
} // close unnamed namespace
291341

292342
// -------------------------
@@ -560,13 +610,12 @@ void ClientSession::sendAck(bmqt::AckResult::Enum status,
560610

561611
// Append the ACK to the ackBuilder
562612
bmqt::EventBuilderResult::Enum rc = bmqp::ProtocolUtil::buildEvent(
563-
bdlf::BindUtil::bind(&bmqp::AckEventBuilder::appendMessage,
564-
&d_state.d_ackBuilder,
565-
bmqp::ProtocolUtil::ackResultToCode(status),
566-
correlationId,
567-
messageGUID,
568-
queueId),
569-
bdlf::BindUtil::bind(&ClientSession::flush, this));
613+
BuildAckFunctor(d_state.d_ackBuilder,
614+
bmqp::ProtocolUtil::ackResultToCode(status),
615+
correlationId,
616+
messageGUID,
617+
queueId),
618+
BuildAckOverflowFunctor(*this));
570619

571620
if (rc != bmqt::EventBuilderResult::e_SUCCESS) {
572621
BALL_LOG_ERROR << "Failed to append ACK [rc: " << rc << ", source: '"

0 commit comments

Comments
 (0)