-
Notifications
You must be signed in to change notification settings - Fork 145
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Perf[MQB]: use in-place callbacks in Dispatcher
Signed-off-by: Evgeny Malygin <emalygin@bloomberg.net>
- Loading branch information
Showing
25 changed files
with
955 additions
and
255 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
// Copyright 2025 Bloomberg Finance L.P. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
// Licensed 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. | ||
|
||
// bmqu_managedcallback.cpp -*-C++-*- | ||
#include <bmqu_managedcallback.h> | ||
|
||
#include <bmqscm_version.h> | ||
namespace BloombergLP { | ||
namespace bmqu { | ||
|
||
namespace { | ||
|
||
class VoidCallback : public bmqu::ManagedCallback::CallbackFunctor { | ||
private: | ||
// PRIVATE DATA | ||
bmqu::ManagedCallback::VoidFunctor d_callback; | ||
|
||
public: | ||
// CREATORS | ||
explicit VoidCallback(const bmqu::ManagedCallback::VoidFunctor& callback) | ||
: d_callback(callback) | ||
{ | ||
// NOTHING | ||
} | ||
|
||
explicit VoidCallback( | ||
bslmf::MovableRef<bmqu::ManagedCallback::VoidFunctor> callback) | ||
: d_callback(bslmf::MovableRefUtil::move(callback)) | ||
{ | ||
// NOTHING | ||
} | ||
|
||
~VoidCallback() BSLS_KEYWORD_OVERRIDE | ||
{ | ||
// NOTHING | ||
} | ||
|
||
// ACCESSORS | ||
void operator()() const BSLS_KEYWORD_OVERRIDE | ||
{ | ||
if (d_callback) { | ||
d_callback(); | ||
} | ||
} | ||
}; | ||
|
||
} // close unnamed namespace | ||
|
||
// --------------------------------------- | ||
// struct ManagedCallback::CallbackFunctor | ||
// --------------------------------------- | ||
|
||
ManagedCallback::CallbackFunctor::~CallbackFunctor() | ||
{ | ||
// NOTHING | ||
} | ||
|
||
void ManagedCallback::set(const VoidFunctor& callback) | ||
{ | ||
// Preconditions for placement are checked in `place`. | ||
// Destructor is called by `reset` of the holding DispatcherEvent. | ||
new (place<VoidCallback>()) VoidCallback(callback); | ||
} | ||
|
||
void ManagedCallback::set(bslmf::MovableRef<VoidFunctor> callback) | ||
{ | ||
// Preconditions for placement are checked in `place`. | ||
// Destructor is called by `reset` of the holding DispatcherEvent. | ||
new (place<VoidCallback>()) | ||
VoidCallback(bslmf::MovableRefUtil::move(callback)); | ||
} | ||
|
||
} // close package namespace | ||
} // close enterprise namespace |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,201 @@ | ||
// Copyright 2025 Bloomberg Finance L.P. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
// Licensed 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. | ||
|
||
// bmqu_managedcallback.h -*-C++-*- | ||
#ifndef INCLUDED_BMQU_JSONPRINTER | ||
#define INCLUDED_BMQU_JSONPRINTER | ||
|
||
//@PURPOSE: Provide a mechanism to print key-value pairs in JSON format. | ||
// | ||
//@CLASSES: | ||
// bmqu::JsonPrinter: Mechanism to print key-value pairs in JSON format. | ||
// | ||
//@DESCRIPTION: 'bmqu::JsonPrinter' provides a mechanism to print key-value | ||
// pairs in JSON format. | ||
// | ||
/// Usage | ||
///----- | ||
// First, specify field names for printer: | ||
//.. | ||
// bsl::vector<const char*> fields; | ||
// fields.push_back("Queue URI"); | ||
// fields.push_back("QueueKey"); | ||
// fields.push_back("Number of AppIds"); | ||
//.. | ||
// | ||
// Next, create an instance of bmqu::AlignedPrinter: | ||
//.. | ||
// bsl::stringstream output; | ||
// bmqu::JsonPrinter<true, 0, 4> printer(output, &fields); | ||
//.. | ||
// | ||
// Last, print field values accordingly: | ||
//.. | ||
// bsl::string uri = "bmq://bmq.tutorial.workqueue/sample-queue"; | ||
// bsl::string queueKey = "sample"; | ||
// const int num = 1; | ||
// printer << uri << queueKey << num; | ||
//.. | ||
// | ||
|
||
// BDE | ||
#include <bsl_functional.h> | ||
#include <bsl_vector.h> | ||
|
||
#include <bslmf_enableif.h> | ||
#include <bsls_assert.h> | ||
|
||
namespace BloombergLP { | ||
namespace bmqu { | ||
|
||
// =============== | ||
// ManagedCallback | ||
// =============== | ||
|
||
class ManagedCallback BSLS_KEYWORD_FINAL { | ||
/// The class useful for in-place construction and passing of functors | ||
/// between different actors. | ||
private: | ||
// DATA | ||
/// Reusable buffer holding the stored callback. | ||
bsl::vector<char> d_callbackBuffer; | ||
|
||
/// The flag indicating if `d_callbackBuffer` is empty now. | ||
bool d_empty; | ||
|
||
public: | ||
// TRAITS | ||
BSLMF_NESTED_TRAIT_DECLARATION(ManagedCallback, bslma::UsesBslmaAllocator) | ||
|
||
// PUBLIC TYPES | ||
/// Signature of a `void` functor method. | ||
typedef bsl::function<void(void)> VoidFunctor; | ||
|
||
// =============== | ||
// CallbackFunctor | ||
// =============== | ||
/// The interface for all callback functors passed to ManagedCallback. | ||
struct CallbackFunctor { | ||
// CREATORS | ||
virtual ~CallbackFunctor(); | ||
|
||
// ACCESSORS | ||
virtual void operator()() const = 0; | ||
}; | ||
|
||
// CREATORS | ||
/// Create a ManagedCallback object using the optionally specified | ||
/// `allocator`. | ||
explicit ManagedCallback(bslma::Allocator* allocator = 0); | ||
|
||
/// Destroy this object. | ||
~ManagedCallback(); | ||
|
||
// MANIPULATORS | ||
/// Reset the state of this object. If this object stores a callback, | ||
/// call a destructor for it and set this object empty. | ||
void reset(); | ||
|
||
/// Book and return the allocated memory to store the specified | ||
/// `CALLBACK_TYPE` that has to be inherited from `CallbackFunctor`. | ||
/// Note that it's the user's responsibility to construct a functor object | ||
/// at the provided address. | ||
/// The object must be `empty()` before calling `place()`. | ||
template <class CALLBACK_TYPE> | ||
char* place(); | ||
|
||
/// Store the specified `callback` in this object. | ||
/// Note: these setters are slow because they performs function copy, going | ||
/// against the basic idea of ManagedCallback. They exist solely for | ||
/// the compatibility with other code where this copy is acceptable. | ||
/// In performance-critical paths, `place` should always be used | ||
/// together with reusable ManagedCallback object(s). | ||
void set(const VoidFunctor& callback); | ||
void set(bslmf::MovableRef<VoidFunctor> callback); | ||
|
||
// ACCESSORS | ||
/// Is this object empty or not. | ||
bool empty() const; | ||
|
||
/// Call the stored callback. | ||
/// The object must be `!empty()` before calling `operator()`. | ||
void operator()() const; | ||
}; | ||
|
||
// ============================================================================ | ||
// INLINE DEFINITIONS | ||
// ============================================================================ | ||
|
||
// --------------- | ||
// ManagedCallback | ||
// --------------- | ||
|
||
inline ManagedCallback::ManagedCallback(bslma::Allocator* allocator) | ||
: d_callbackBuffer(allocator) | ||
, d_empty(true) | ||
{ | ||
// NOTHING | ||
} | ||
|
||
inline ManagedCallback::~ManagedCallback() | ||
{ | ||
reset(); | ||
} | ||
|
||
inline void ManagedCallback::reset() | ||
{ | ||
if (!d_empty) { | ||
// Not necessary to resize the vector or memset its elements to 0, | ||
// we just call the virtual destructor, and `d_empty` flag | ||
// prevents us from calling outdated callback. | ||
reinterpret_cast<CallbackFunctor*>(d_callbackBuffer.data()) | ||
->~CallbackFunctor(); | ||
d_empty = true; | ||
} | ||
} | ||
|
||
template <class CALLBACK_TYPE> | ||
inline char* ManagedCallback::place() | ||
{ | ||
// PRECONDITIONS | ||
BSLS_ASSERT_SAFE(d_empty); | ||
/// The compilation will fail here on the outer `static_cast` if we | ||
/// don't provide a type that is inherited from the base | ||
/// `CallbackFunctor` type. | ||
/// TODO: replace by static_assert on C++ standard update | ||
BSLS_ASSERT_SAFE(0 == static_cast<CALLBACK_TYPE*>( | ||
reinterpret_cast<CallbackFunctor*>(0))); | ||
d_callbackBuffer.resize(sizeof(CALLBACK_TYPE)); | ||
d_empty = false; | ||
return d_callbackBuffer.data(); | ||
} | ||
|
||
inline bool ManagedCallback::empty() const | ||
{ | ||
return d_empty; | ||
} | ||
|
||
inline void ManagedCallback::operator()() const | ||
{ | ||
// PRECONDITIONS | ||
BSLS_ASSERT_SAFE(!d_empty); | ||
|
||
(*reinterpret_cast<const CallbackFunctor*>(d_callbackBuffer.data()))(); | ||
} | ||
|
||
} // close package namespace | ||
} // close enterprise namespace | ||
|
||
#endif |
Oops, something went wrong.