From c140945e2981f7db6193abde07c74e1aa2b086ff Mon Sep 17 00:00:00 2001 From: Evgeny Malygin Date: Mon, 28 Oct 2024 15:48:19 +0200 Subject: [PATCH 01/17] Perf[MQB]: remove unnecessary shared_ptr copy (#480) Signed-off-by: Evgeny Malygin --- src/groups/mqb/mqbblp/mqbblp_routers.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/groups/mqb/mqbblp/mqbblp_routers.cpp b/src/groups/mqb/mqbblp/mqbblp_routers.cpp index f31647ea8..8107b7a67 100644 --- a/src/groups/mqb/mqbblp/mqbblp_routers.cpp +++ b/src/groups/mqb/mqbblp/mqbblp_routers.cpp @@ -199,8 +199,8 @@ bool Routers::Expression::evaluate() bool Routers::PriorityGroup::evaluate( BSLS_ANNOTATION_UNUSED const bsl::shared_ptr& data) { - const Expressions::SharedItem it = d_itId->value().d_itExpression; - Expression& expression = it->value(); + const Expressions::SharedItem& it = d_itId->value().d_itExpression; + Expression& expression = it->value(); return expression.evaluate(); } From 9a9b79f6d8e21090eb9939dc7e05e32a5e5e5a7a Mon Sep 17 00:00:00 2001 From: Evgeny Malygin Date: Mon, 28 Oct 2024 15:53:37 +0200 Subject: [PATCH 02/17] Perf[MQB]: do not build temporary functors for every routed message (#477) Signed-off-by: Evgeny Malygin --- .../mqb/mqbblp/mqbblp_queueengineutil.cpp | 41 +++++++++++-------- .../mqb/mqbblp/mqbblp_queueengineutil.h | 19 ++++++++- 2 files changed, 42 insertions(+), 18 deletions(-) diff --git a/src/groups/mqb/mqbblp/mqbblp_queueengineutil.cpp b/src/groups/mqb/mqbblp/mqbblp_queueengineutil.cpp index 0dd4e3cb2..92c7876ff 100644 --- a/src/groups/mqb/mqbblp/mqbblp_queueengineutil.cpp +++ b/src/groups/mqb/mqbblp/mqbblp_queueengineutil.cpp @@ -637,6 +637,17 @@ QueueEngineUtil_AppsDeliveryContext::QueueEngineUtil_AppsDeliveryContext( , d_currentMessage(0) , d_queue_p(queue) , d_timeDelta() +, d_currentAppView_p(0) +, d_visitVisitor( + bdlf::BindUtil::bindS(allocator, + &QueueEngineUtil_AppsDeliveryContext::visit, + this, + bdlf::PlaceHolders::_1)) +, d_broadcastVisitor(bdlf::BindUtil::bindS( + allocator, + &QueueEngineUtil_AppsDeliveryContext::visitBroadcast, + this, + bdlf::PlaceHolders::_1)) { BSLS_ASSERT_SAFE(queue); } @@ -670,12 +681,7 @@ bool QueueEngineUtil_AppsDeliveryContext::processApp( if (d_queue_p->isDeliverAll()) { // collect all handles - app.routing()->iterateConsumers( - bdlf::BindUtil::bind( - &QueueEngineUtil_AppsDeliveryContext::visitBroadcast, - this, - bdlf::PlaceHolders::_1), - d_currentMessage); + app.routing()->iterateConsumers(d_broadcastVisitor, d_currentMessage); d_isReady = true; @@ -708,13 +714,14 @@ bool QueueEngineUtil_AppsDeliveryContext::processApp( // mapped file, which can delay the unmapping of files in case this // message has a huge TTL and there are no consumers for this message. - Routers::Result result = app.selectConsumer( - bdlf::BindUtil::bind(&QueueEngineUtil_AppsDeliveryContext::visit, - this, - bdlf::PlaceHolders::_1, - appView), - d_currentMessage, - ordinal); + d_currentAppView_p = &appView; + Routers::Result result = app.selectConsumer(d_visitVisitor, + d_currentMessage, + ordinal); + // We use this pointer only from `d_visitVisitor`, so not cleaning it is + // okay, but we clean it to keep contract that `d_currentAppView_p` only + // points at the actual AppView. + d_currentAppView_p = NULL; if (result == Routers::e_SUCCESS) { // RootQueueEngine makes stat reports @@ -749,14 +756,16 @@ bool QueueEngineUtil_AppsDeliveryContext::processApp( } bool QueueEngineUtil_AppsDeliveryContext::visit( - const Routers::Subscription* subscription, - const mqbi::AppMessage& appView) + const Routers::Subscription* subscription) { BSLS_ASSERT_SAFE(subscription); + BSLS_ASSERT_SAFE( + d_currentAppView_p && + "`d_currentAppView_p` must be assigned before calling this function"); d_consumers[subscription->handle()].push_back( bmqp::SubQueueInfo(subscription->d_downstreamSubscriptionId, - appView.d_rdaInfo)); + d_currentAppView_p->d_rdaInfo)); return true; } diff --git a/src/groups/mqb/mqbblp/mqbblp_queueengineutil.h b/src/groups/mqb/mqbblp/mqbblp_queueengineutil.h index 7496a9a37..c6b0f95c7 100644 --- a/src/groups/mqb/mqbblp/mqbblp_queueengineutil.h +++ b/src/groups/mqb/mqbblp/mqbblp_queueengineutil.h @@ -603,10 +603,26 @@ struct QueueEngineUtil_AppsDeliveryContext { mqbi::StorageIterator* d_currentMessage; mqbi::Queue* d_queue_p; bsl::optional d_timeDelta; + + /// Mutable additional argument used in `visit()`, when it is called from + /// `d_visitVisitor` functor. + const mqbi::AppMessage* d_currentAppView_p; + + /// Cached functor to `QueueEngineUtil_AppsDeliveryContext::visit` + const Routers::Visitor d_visitVisitor; + + /// Cached functor to `QueueEngineUtil_AppsDeliveryContext::visitBroadcast` + const Routers::Visitor d_broadcastVisitor; + // Avoid reading the attributes if not necessary. Get timeDelta on demand. // See comment in `QueueEngineUtil_AppsDeliveryContext::processApp`. public: + // TRAITS + BSLMF_NESTED_TRAIT_DECLARATION(QueueEngineUtil_AppsDeliveryContext, + bslma::UsesBslmaAllocator) + + // CREATORS QueueEngineUtil_AppsDeliveryContext(mqbi::Queue* queue, bslma::Allocator* allocator); @@ -637,8 +653,7 @@ struct QueueEngineUtil_AppsDeliveryContext { bool processApp(QueueEngineUtil_AppState& app, unsigned int ordina); /// Collect and prepare data for the subsequent `deliverMessage` call. - bool visit(const Routers::Subscription* subscription, - const mqbi::AppMessage& appView); + bool visit(const Routers::Subscription* subscription); bool visitBroadcast(const Routers::Subscription* subscription); /// Deliver message to the previously processed handles. From 6d3790f265efe824dd6fb6d8e6f5749c9a410030 Mon Sep 17 00:00:00 2001 From: Evgeny Malygin Date: Mon, 28 Oct 2024 16:23:45 +0200 Subject: [PATCH 03/17] Perf[MQB]: throttle logs critical for broadcast (#482) Signed-off-by: Evgeny Malygin --- src/groups/mqb/mqbblp/mqbblp_remotequeue.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/groups/mqb/mqbblp/mqbblp_remotequeue.cpp b/src/groups/mqb/mqbblp/mqbblp_remotequeue.cpp index c7849c837..bf411902a 100644 --- a/src/groups/mqb/mqbblp/mqbblp_remotequeue.cpp +++ b/src/groups/mqb/mqbblp/mqbblp_remotequeue.cpp @@ -1179,9 +1179,9 @@ void RemoteQueue::onAckMessageDispatched(const mqbi::DispatcherAckEvent& event) erasePendingMessage(it); - BALL_LOG_INFO << d_state_p->uri() << ": erased window of " << numErased - << " cached broadcasted PUTs upon " - << bmqt::AckResult::toAscii(ackResult); + BALL_LOG_DEBUG << d_state_p->uri() << ": erased window of " + << numErased << " cached broadcasted PUTs upon " + << bmqt::AckResult::toAscii(ackResult); return; // RETURN } @@ -1340,9 +1340,9 @@ void RemoteQueue::expirePendingMessagesDispatched() } else { d_pendingMessagesTimerEventHandle.release(); - BALL_LOG_INFO << d_state_p->uri() << ": " - << "no more timer scheduled to check expiration of " - << "pending PUSH messages"; + BALL_LOG_DEBUG << d_state_p->uri() << ": " + << "no more timer scheduled to check expiration of " + << "pending PUSH messages"; } } From 8550a818a1703a888ae10f97254e6ff12686dd47 Mon Sep 17 00:00:00 2001 From: Evgeny Malygin Date: Mon, 28 Oct 2024 17:55:00 +0200 Subject: [PATCH 04/17] Perf[BMQ]: do not create tmp functors in PutEventBuilder (#478) Signed-off-by: Evgeny Malygin --- .gitignore | 3 ++ src/groups/bmq/bmqp/bmqp_puteventbuilder.cpp | 42 ++++++++++++-------- src/groups/bmq/bmqp/bmqp_puteventbuilder.h | 22 ++++++---- 3 files changed, 43 insertions(+), 24 deletions(-) diff --git a/.gitignore b/.gitignore index be20d028e..9c69b16cb 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,9 @@ settings.json .cache/ .venv/ +# fuzz-test output folder +**/boofuzz-results + # Symlink from 'src/applications/bmqbrkr/run' src/applications/bmqbrkr/etc/etc diff --git a/src/groups/bmq/bmqp/bmqp_puteventbuilder.cpp b/src/groups/bmq/bmqp/bmqp_puteventbuilder.cpp index dfca9cd2c..f05701c1f 100644 --- a/src/groups/bmq/bmqp/bmqp_puteventbuilder.cpp +++ b/src/groups/bmq/bmqp/bmqp_puteventbuilder.cpp @@ -49,16 +49,31 @@ bool isWordAligned(const bdlbb::Blob& blob) #endif } // close unnamed namespace +// --------------------------------- +// class PutEventBuilder::ResetGuard +// --------------------------------- + +inline PutEventBuilder::ResetGuard::ResetGuard( + PutEventBuilder& putEventBuilder) +: d_putEventBuilder(putEventBuilder) +{ + // NOTHING +} + +inline PutEventBuilder::ResetGuard::~ResetGuard() +{ + d_putEventBuilder.resetFields(); +} + // --------------------- // class PutEventBuilder // --------------------- -void PutEventBuilder::resetFields(void* ptr) +void PutEventBuilder::resetFields() { - PutEventBuilder* builder = static_cast(ptr); - builder->d_flags = 0; - builder->d_messageGUID = bmqt::MessageGUID(); - builder->d_crc32c = 0; + d_flags = 0; + d_messageGUID = bmqt::MessageGUID(); + d_crc32c = 0; } bmqt::EventBuilderResult::Enum @@ -219,9 +234,7 @@ PutEventBuilder::packMessageInOldStyle(int queueId) // Guid and flags need to be reset after this method (irrespective of its // success or failure). Create a proctor to auto reset them. - const bsl::function f = - bdlf::BindUtil::bind(&PutEventBuilder::resetFields, this); - bdlb::ScopeExitAny resetter(f); + const ResetGuard guard(*this); // Calculate length of entire application data (includes payload, message // properties and padding, if any). @@ -304,12 +317,9 @@ bmqt::EventBuilderResult::Enum PutEventBuilder::packMessage(int queueId) typedef bmqt::EventBuilderResult Result; - // CorrelationId, guid and flags need to be reset after this method - // (irrespective of its success or failure). Create a proctor to auto - // reset them. - const bsl::function f = - bdlf::BindUtil::bind(&PutEventBuilder::resetFields, this); - bdlb::ScopeExitAny resetter(f); + // Guid and flags need to be reset after this method (irrespective of its + // success or failure). Create a proctor to auto reset them. + const ResetGuard guard(*this); // Calculate length of entire application data (includes payload, message // properties and padding, if any). @@ -398,9 +408,7 @@ bmqt::EventBuilderResult::Enum PutEventBuilder::packMessageRaw(int queueId) // Guid and flags need to be reset after this method (irrespective of its // success or failure). Create a proctor to auto reset them. - const bsl::function f = - bdlf::BindUtil::bind(&PutEventBuilder::resetFields, this); - bdlb::ScopeExitAny resetter(f); + const ResetGuard guard(*this); // Note that the 'd_blobPayload_p' has the entire application data. return packMessageInternal(*d_blobPayload_p, queueId); diff --git a/src/groups/bmq/bmqp/bmqp_puteventbuilder.h b/src/groups/bmq/bmqp/bmqp_puteventbuilder.h index 8ee9d3870..50675cf74 100644 --- a/src/groups/bmq/bmqp/bmqp_puteventbuilder.h +++ b/src/groups/bmq/bmqp/bmqp_puteventbuilder.h @@ -61,7 +61,6 @@ // // BMQ - #include #include #include @@ -92,6 +91,18 @@ class PutEventBuilder { typedef bdlb::NullableValue NullableMsgGroupId; private: + // TYPES + /// Mechanism to automatically reset PutEventBuilder on a built message + struct ResetGuard { + // DATA + PutEventBuilder& d_putEventBuilder; + + // CREATORS + explicit ResetGuard(PutEventBuilder& putEventBuilder); + + ~ResetGuard(); + }; + // DATA bdlbb::BlobBufferFactory* d_bufferFactory_p; @@ -169,13 +180,10 @@ class PutEventBuilder { PutEventBuilder& operator=(const PutEventBuilder&) BSLS_CPP11_DELETED; private: - // CLASS LEVEL METHODS - - /// Reset flags and message guid of PutEventBuilder instance pointed by - /// the specified `ptr`. - static void resetFields(void* ptr); - // PRIVATE MANIPULATORS + /// Reset flags and message guid of this object. + void resetFields(); + bmqt::EventBuilderResult::Enum packMessageInternal(const bdlbb::Blob& appData, int queueId); From afdbba251346fba5dd02ed131397fe822bcb3939 Mon Sep 17 00:00:00 2001 From: dorjesinpo <129227380+dorjesinpo@users.noreply.github.com> Date: Mon, 28 Oct 2024 13:05:41 -0400 Subject: [PATCH 05/17] fix: generate AppKey only once (#469) * fix: generate AppKey only once Signed-off-by: dorjesinpo <129227380+dorjesinpo@users.noreply.github.com> * switching to CSL app key gen everywhere Signed-off-by: dorjesinpo <129227380+dorjesinpo@users.noreply.github.com> * more fixes and an IT Signed-off-by: dorjesinpo <129227380+dorjesinpo@users.noreply.github.com> --------- Signed-off-by: dorjesinpo <129227380+dorjesinpo@users.noreply.github.com> --- src/groups/mqb/mqbblp/mqbblp_cluster.cpp | 49 ++-- src/groups/mqb/mqbblp/mqbblp_cluster.h | 4 +- .../mqb/mqbblp/mqbblp_clusterorchestrator.cpp | 2 +- .../mqb/mqbblp/mqbblp_clusterorchestrator.h | 4 +- .../mqb/mqbblp/mqbblp_clusterqueuehelper.cpp | 96 +++---- .../mqb/mqbblp/mqbblp_clusterqueuehelper.h | 8 +- .../mqb/mqbblp/mqbblp_clusterstatemanager.cpp | 40 +-- .../mqb/mqbblp/mqbblp_clusterstatemanager.h | 6 +- src/groups/mqb/mqbblp/mqbblp_domain.cpp | 40 ++- src/groups/mqb/mqbblp/mqbblp_domain.h | 13 +- src/groups/mqb/mqbblp/mqbblp_queuestate.cpp | 11 +- .../mqb/mqbblp/mqbblp_relayqueueengine.cpp | 10 +- .../mqb/mqbblp/mqbblp_rootqueueengine.cpp | 19 +- .../mqb/mqbblp/mqbblp_rootqueueengine.h | 4 +- .../mqb/mqbblp/mqbblp_storagemanager.cpp | 15 +- src/groups/mqb/mqbblp/mqbblp_storagemanager.h | 10 +- src/groups/mqb/mqbc/mqbc_clusterstate.cpp | 32 +-- src/groups/mqb/mqbc/mqbc_clusterstate.h | 53 ++-- .../mqb/mqbc/mqbc_clusterstatemanager.cpp | 10 +- .../mqb/mqbc/mqbc_clusterstatemanager.h | 4 +- .../mqb/mqbc/mqbc_clusterstatemanager.t.cpp | 3 +- src/groups/mqb/mqbc/mqbc_clusterutil.cpp | 195 +++++++------- src/groups/mqb/mqbc/mqbc_clusterutil.h | 25 +- src/groups/mqb/mqbc/mqbc_storagemanager.cpp | 23 +- src/groups/mqb/mqbc/mqbc_storagemanager.h | 19 +- src/groups/mqb/mqbc/mqbc_storagemanager.t.cpp | 4 +- src/groups/mqb/mqbc/mqbc_storageutil.cpp | 244 ++++++------------ src/groups/mqb/mqbc/mqbc_storageutil.h | 94 ++++--- .../mqb/mqbi/mqbi_clusterstatemanager.h | 8 +- src/groups/mqb/mqbi/mqbi_queueengine.cpp | 4 +- src/groups/mqb/mqbi/mqbi_queueengine.h | 4 +- src/groups/mqb/mqbi/mqbi_storage.h | 10 +- src/groups/mqb/mqbi/mqbi_storagemanager.h | 14 +- .../mqb/mqbmock/mqbmock_storagemanager.cpp | 8 +- .../mqb/mqbmock/mqbmock_storagemanager.h | 8 +- src/groups/mqb/mqbs/mqbs_datastore.h | 29 +-- src/groups/mqb/mqbs/mqbs_filebackedstorage.h | 10 +- .../mqb/mqbs/mqbs_filebackedstorage.t.cpp | 2 +- src/groups/mqb/mqbs/mqbs_filestore.cpp | 58 +++-- src/groups/mqb/mqbs/mqbs_filestore.h | 6 +- src/groups/mqb/mqbs/mqbs_filestore.t.cpp | 4 +- .../mqb/mqbs/mqbs_filestoreprotocolutil.cpp | 11 +- .../mqb/mqbs/mqbs_filestoreprotocolutil.h | 10 +- .../mqb/mqbs/mqbs_filestoreprotocolutil.t.cpp | 57 ++-- src/groups/mqb/mqbs/mqbs_inmemorystorage.h | 11 +- src/groups/mqb/mqbs/mqbs_storageprintutil.cpp | 4 +- src/groups/mqb/mqbs/mqbs_storageprintutil.h | 4 +- .../mqb/mqbs/mqbs_virtualstoragecatalog.cpp | 5 +- .../mqb/mqbs/mqbs_virtualstoragecatalog.h | 6 +- src/integration-tests/test_restart.py | 29 ++- 50 files changed, 622 insertions(+), 717 deletions(-) diff --git a/src/groups/mqb/mqbblp/mqbblp_cluster.cpp b/src/groups/mqb/mqbblp/mqbblp_cluster.cpp index a004855d0..f1f5d8d91 100644 --- a/src/groups/mqb/mqbblp/mqbblp_cluster.cpp +++ b/src/groups/mqb/mqbblp/mqbblp_cluster.cpp @@ -2209,27 +2209,16 @@ void Cluster::onRecoveryStatusDispatched( const bmqt::Uri uri(itMp->uri().canonical()); BSLS_ASSERT_SAFE(itMp->storage()->partitionId() == static_cast(pid)); - if (isCSLModeEnabled()) { - AppIdKeyPairs appIdKeyPairs; - itMp->storage()->loadVirtualStorageDetails(&appIdKeyPairs); - AppIdInfos appIdInfos(appIdKeyPairs.cbegin(), - appIdKeyPairs.cend()); - - d_clusterOrchestrator.registerQueueInfo( - uri, - pid, - itMp->storage()->queueKey(), - appIdInfos, - false); // Force-update? - } - else { - d_clusterOrchestrator.registerQueueInfo( - uri, - pid, - itMp->storage()->queueKey(), - AppIdInfos(), - false); // Force-update? - } + + AppInfos appIdInfos; + itMp->storage()->loadVirtualStorageDetails(&appIdInfos); + + d_clusterOrchestrator.registerQueueInfo( + uri, + pid, + itMp->storage()->queueKey(), + appIdInfos, + false); // Force-update? ++(*itMp); } @@ -2844,18 +2833,22 @@ void Cluster::onDomainReconfigured(const mqbi::Domain& domain, } // Compute list of added and removed App IDs. - bsl::vector oldCfgAppIds(oldDefn.mode().fanout().appIDs(), - d_allocator_p); - bsl::vector newCfgAppIds(newDefn.mode().fanout().appIDs(), - d_allocator_p); - - bsl::vector addedIds, removedIds; + bsl::unordered_set oldCfgAppIds( + oldDefn.mode().fanout().appIDs().cbegin(), + oldDefn.mode().fanout().appIDs().cend(), + d_allocator_p); + bsl::unordered_set newCfgAppIds( + newDefn.mode().fanout().appIDs().cbegin(), + newDefn.mode().fanout().appIDs().cend(), + d_allocator_p); + + bsl::unordered_set addedIds, removedIds; mqbc::StorageUtil::loadAddedAndRemovedEntries(&addedIds, &removedIds, oldCfgAppIds, newCfgAppIds); - bsl::vector::const_iterator it = addedIds.begin(); + bsl::unordered_set::const_iterator it = addedIds.cbegin(); for (; it != addedIds.cend(); ++it) { dispatcher()->execute( bdlf::BindUtil::bind(&ClusterOrchestrator::registerAppId, diff --git a/src/groups/mqb/mqbblp/mqbblp_cluster.h b/src/groups/mqb/mqbblp/mqbblp_cluster.h index de9c8f815..13fe60889 100644 --- a/src/groups/mqb/mqbblp/mqbblp_cluster.h +++ b/src/groups/mqb/mqbblp/mqbblp_cluster.h @@ -137,11 +137,9 @@ class Cluster : public mqbi::Cluster, private: // PRIVATE TYPES - typedef mqbi::Storage::AppIdKeyPairs AppIdKeyPairs; - typedef mqbc::ClusterStatePartitionInfo ClusterStatePartitionInfo; - typedef mqbc::ClusterStateQueueInfo::AppIdInfos AppIdInfos; + typedef mqbc::ClusterStateQueueInfo::AppInfos AppInfos; typedef mqbc::ClusterMembership::ClusterNodeSessionSp ClusterNodeSessionSp; diff --git a/src/groups/mqb/mqbblp/mqbblp_clusterorchestrator.cpp b/src/groups/mqb/mqbblp/mqbblp_clusterorchestrator.cpp index d368d1027..388544711 100644 --- a/src/groups/mqb/mqbblp/mqbblp_clusterorchestrator.cpp +++ b/src/groups/mqb/mqbblp/mqbblp_clusterorchestrator.cpp @@ -286,7 +286,7 @@ void ClusterOrchestrator::processBufferedQueueAdvisories() void ClusterOrchestrator::registerQueueInfo(const bmqt::Uri& uri, int partitionId, const mqbu::StorageKey& queueKey, - const AppIdInfos& appIdInfos, + const AppInfos& appIdInfos, bool forceUpdate) { // executed by the *DISPATCHER* thread diff --git a/src/groups/mqb/mqbblp/mqbblp_clusterorchestrator.h b/src/groups/mqb/mqbblp/mqbblp_clusterorchestrator.h index 9b9fe35e6..9d090a7f9 100644 --- a/src/groups/mqb/mqbblp/mqbblp_clusterorchestrator.h +++ b/src/groups/mqb/mqbblp/mqbblp_clusterorchestrator.h @@ -109,7 +109,7 @@ class ClusterOrchestrator { typedef bdlmt::EventScheduler::RecurringEventHandle RecurringEventHandle; - typedef mqbc::ClusterStateQueueInfo::AppIdInfos AppIdInfos; + typedef mqbc::ClusterStateQueueInfo::AppInfos AppInfos; private: // DATA @@ -515,7 +515,7 @@ class ClusterOrchestrator { void registerQueueInfo(const bmqt::Uri& uri, int partitionId, const mqbu::StorageKey& queueKey, - const AppIdInfos& appIdInfos, + const AppInfos& appIdInfos, bool forceUpdate); /// Executed by any thread. diff --git a/src/groups/mqb/mqbblp/mqbblp_clusterqueuehelper.cpp b/src/groups/mqb/mqbblp/mqbblp_clusterqueuehelper.cpp index ff24e36a0..8822876f4 100644 --- a/src/groups/mqb/mqbblp/mqbblp_clusterqueuehelper.cpp +++ b/src/groups/mqb/mqbblp/mqbblp_clusterqueuehelper.cpp @@ -139,8 +139,8 @@ void createQueueUriKey(bmqt::Uri* out, } void afterAppIdRegisteredDispatched( - mqbi::Queue* queue, - const mqbc::ClusterStateQueueInfo::AppIdInfo& appIdInfo) + mqbi::Queue* queue, + const mqbc::ClusterStateQueueInfo::AppInfo& appIdInfo) { // executed by the *QUEUE DISPATCHER* thread @@ -148,12 +148,12 @@ void afterAppIdRegisteredDispatched( BSLS_ASSERT_SAFE(queue->dispatcher()->inDispatcherThread(queue)); queue->queueEngine()->afterAppIdRegistered( - mqbi::Storage::AppIdKeyPair(appIdInfo.first, appIdInfo.second)); + mqbi::Storage::AppInfo(appIdInfo.first, appIdInfo.second)); } void afterAppIdUnregisteredDispatched( - mqbi::Queue* queue, - const mqbc::ClusterStateQueueInfo::AppIdInfo& appIdInfo) + mqbi::Queue* queue, + const mqbc::ClusterStateQueueInfo::AppInfo& appIdInfo) { // executed by the *QUEUE DISPATCHER* thread @@ -161,7 +161,7 @@ void afterAppIdUnregisteredDispatched( BSLS_ASSERT_SAFE(queue->dispatcher()->inDispatcherThread(queue)); queue->queueEngine()->afterAppIdUnregistered( - mqbi::Storage::AppIdKeyPair(appIdInfo.first, appIdInfo.second)); + mqbi::Storage::AppInfo(appIdInfo.first, appIdInfo.second)); } void handleHolderDummy(const bsl::shared_ptr& handle) @@ -2152,27 +2152,15 @@ bsl::shared_ptr ClusterQueueHelper::createQueueFactory( // queue but the queue is never opened, it will not be registered with // the StorageMgr. This is ok. - if (d_cluster_p->isCSLModeEnabled()) { - const AppIdInfos& appIdInfos = - context.d_queueContext_p->d_stateQInfo_sp->appIdInfos(); - const mqbi::Storage::AppIdKeyPairs appIdKeyPairs( - appIdInfos.cbegin(), - appIdInfos.cend()); - d_storageManager_p->registerQueue( - context.d_queueContext_p->uri(), - context.d_queueContext_p->key(), - context.d_queueContext_p->partitionId(), - appIdKeyPairs, - context.d_domain_p); - } - else { - d_storageManager_p->registerQueue( - context.d_queueContext_p->uri(), - context.d_queueContext_p->key(), - context.d_queueContext_p->partitionId(), - mqbi::Storage::AppIdKeyPairs(), - context.d_domain_p); - } + // Use keys in the CSL instead of generating new ones to keep CSL and + // non-CSL consistent. + + d_storageManager_p->registerQueue( + context.d_queueContext_p->uri(), + context.d_queueContext_p->key(), + context.d_queueContext_p->partitionId(), + context.d_queueContext_p->d_stateQInfo_sp->appInfos(), + context.d_domain_p); // Queue must have been registered with storage manager before // registering it with the domain, otherwise Queue.configure() will @@ -3698,28 +3686,12 @@ void ClusterQueueHelper::restoreStateCluster(int partitionId) // node creates a local queue instance (see // 'createQueueFactory'). - if (d_cluster_p->isCSLModeEnabled()) { - const AppIdInfos& appIdInfos = - queueContext->d_stateQInfo_sp->appIdInfos(); - const mqbi::Storage::AppIdKeyPairs appIdKeyPairs( - appIdInfos.cbegin(), - appIdInfos.cend()); - - d_storageManager_p->registerQueue( - queueContext->uri(), - queueContext->key(), - queueContext->partitionId(), - appIdKeyPairs, - qinfo.d_queue_sp->domain()); - } - else { - d_storageManager_p->registerQueue( - queueContext->uri(), - queueContext->key(), - queueContext->partitionId(), - mqbi::Storage::AppIdKeyPairs(), - qinfo.d_queue_sp->domain()); - } + d_storageManager_p->registerQueue( + queueContext->uri(), + queueContext->key(), + queueContext->partitionId(), + queueContext->d_stateQInfo_sp->appInfos(), + qinfo.d_queue_sp->domain()); // Convert the queue from remote to local instance. queueContext->d_liveQInfo.d_queue_sp->convertToLocal(); @@ -4109,6 +4081,7 @@ void ClusterQueueHelper::onQueueAssigned( BSLS_ASSERT_SAFE(!d_cluster_p->isRemote()); if (!d_cluster_p->isCSLModeEnabled()) { + // REVISIT return; // RETURN } @@ -4229,14 +4202,11 @@ void ClusterQueueHelper::onQueueAssigned( ->domain(), true); // allowDuplicate - const mqbi::Storage::AppIdKeyPairs appIdKeyPairs( - info.appIdInfos().cbegin(), - info.appIdInfos().cend()); d_storageManager_p->updateQueueReplica( info.partitionId(), info.uri(), info.key(), - appIdKeyPairs, + info.appInfos(), d_clusterState_p->domainStates() .at(info.uri().qualifiedDomain()) ->domain(), @@ -4395,8 +4365,8 @@ void ClusterQueueHelper::onQueueUnassigned( void ClusterQueueHelper::onQueueUpdated(const bmqt::Uri& uri, const bsl::string& domain, - const AppIdInfos& addedAppIds, - const AppIdInfos& removedAppIds) + const AppInfos& addedAppIds, + const AppInfos& removedAppIds) { // executed by the cluster *DISPATCHER* thread @@ -4424,19 +4394,21 @@ void ClusterQueueHelper::onQueueUpdated(const bmqt::Uri& uri, const int partitionId = qiter->second->partitionId(); BSLS_ASSERT_SAFE(partitionId != mqbs::DataStore::k_INVALID_PARTITION_ID); - for (AppIdInfosCIter cit = addedAppIds.cbegin(); cit != addedAppIds.cend(); + for (AppInfosCIter cit = addedAppIds.cbegin(); cit != addedAppIds.cend(); ++cit) { if (!d_clusterState_p->isSelfPrimary(partitionId) || queue == 0) { // Note: In non-CSL mode, the queue creation callback is // invoked at replica nodes when they receive a queue creation // record from the primary in the partition stream. - mqbi::Storage::AppIdKeyPair appIdKeyPair(cit->first, cit->second); - mqbi::Storage::AppIdKeyPairs appIdKeyPairs(1, appIdKeyPair); + + mqbi::Storage::AppInfos one(1, d_allocator_p); + one.emplace(*cit); + d_storageManager_p->updateQueueReplica( partitionId, uri, qiter->second->key(), - appIdKeyPairs, + one, d_clusterState_p->domainStates() .at(uri.qualifiedDomain()) ->domain()); @@ -4450,7 +4422,7 @@ void ClusterQueueHelper::onQueueUpdated(const bmqt::Uri& uri, } } - for (AppIdInfosCIter cit = removedAppIds.cbegin(); + for (AppInfosCIter cit = removedAppIds.cbegin(); cit != removedAppIds.cend(); ++cit) { if (!d_clusterState_p->isSelfPrimary(partitionId) || queue == 0) { @@ -4471,8 +4443,8 @@ void ClusterQueueHelper::onQueueUpdated(const bmqt::Uri& uri, } } - bmqu::Printer printer1(&addedAppIds); - bmqu::Printer printer2(&removedAppIds); + bmqu::Printer printer1(&addedAppIds); + bmqu::Printer printer2(&removedAppIds); BALL_LOG_INFO << d_cluster_p->description() << ": Updated queue: " << uri << ", addedAppIds: " << printer1 << ", removedAppIds: " << printer2; diff --git a/src/groups/mqb/mqbblp/mqbblp_clusterqueuehelper.h b/src/groups/mqb/mqbblp/mqbblp_clusterqueuehelper.h index 9a60251f2..5d448dca2 100644 --- a/src/groups/mqb/mqbblp/mqbblp_clusterqueuehelper.h +++ b/src/groups/mqb/mqbblp/mqbblp_clusterqueuehelper.h @@ -420,9 +420,9 @@ class ClusterQueueHelper : public mqbc::ClusterStateObserver, /// queue which have a proper valid unique queueId. typedef bsl::unordered_map QueueContextByIdMap; - typedef AppIdInfos::const_iterator AppIdInfosCIter; + typedef AppInfos::const_iterator AppInfosCIter; - typedef mqbc::ClusterStateQueueInfo::AppIdInfos AppIdInfos; + typedef mqbc::ClusterStateQueueInfo::AppInfos AppInfos; private: // DATA @@ -997,8 +997,8 @@ class ClusterQueueHelper : public mqbc::ClusterStateObserver, /// dispatcher thread. virtual void onQueueUpdated(const bmqt::Uri& uri, const bsl::string& domain, - const AppIdInfos& addedAppIds, - const AppIdInfos& removedAppIds = AppIdInfos()) + const AppInfos& addedAppIds, + const AppInfos& removedAppIds = AppInfos()) BSLS_KEYWORD_OVERRIDE; private: diff --git a/src/groups/mqb/mqbblp/mqbblp_clusterstatemanager.cpp b/src/groups/mqb/mqbblp/mqbblp_clusterstatemanager.cpp index a42bbdd30..d1137b0e5 100644 --- a/src/groups/mqb/mqbblp/mqbblp_clusterstatemanager.cpp +++ b/src/groups/mqb/mqbblp/mqbblp_clusterstatemanager.cpp @@ -617,17 +617,12 @@ void ClusterStateManager::onLeaderSyncDataQueryResponse( const mqbu::StorageKey receivedKey( mqbu::StorageKey::BinaryRepresentation(), queueInfo.key().data()); - AppIdInfos appIdInfos; - for (bsl::vector::const_iterator cit = - queueInfo.appIds().cbegin(); - cit != queueInfo.appIds().cend(); - ++cit) { - AppIdInfo appIdInfo; - appIdInfo.first = cit->appId(); - appIdInfo.second.fromBinary(cit->appKey().data()); - - appIdInfos.insert(appIdInfo); - } + + AppInfos appIdInfos(d_allocator_p); + + mqbc::ClusterUtil::parseQueueInfo(&appIdInfos, + queueInfo, + d_allocator_p); registerQueueInfo(queueUri, queueInfo.partitionId(), @@ -1180,7 +1175,7 @@ ClusterStateManager::assignQueue(const bmqt::Uri& uri, void ClusterStateManager::registerQueueInfo(const bmqt::Uri& uri, int partitionId, const mqbu::StorageKey& queueKey, - const AppIdInfos& appIdInfos, + const AppInfos& appIdInfos, bool forceUpdate) { // executed by the *DISPATCHER* thread @@ -1689,12 +1684,17 @@ void ClusterStateManager::processQueueAssignmentAdvisory( // no need to update d_state_p->domainStates() entry // , queue was already known and registered + AppInfos appIdInfos(d_allocator_p); + + mqbc::ClusterUtil::parseQueueInfo(&appIdInfos, + queueInfo, + d_allocator_p); BSLA_MAYBE_UNUSED const bool rc = d_state_p->assignQueue( uri, queueKey, queueInfo.partitionId(), - AppIdInfos()); + appIdInfos); BSLS_ASSERT_SAFE(rc == false); } else { @@ -1728,10 +1728,16 @@ void ClusterStateManager::processQueueAssignmentAdvisory( continue; // CONTINUE } + AppInfos appIdInfos(d_allocator_p); + + mqbc::ClusterUtil::parseQueueInfo(&appIdInfos, + queueInfo, + d_allocator_p); + d_state_p->assignQueue(uri, queueKey, queueInfo.partitionId(), - AppIdInfos()); + appIdInfos); d_state_p->domainStates() .at(uri.qualifiedDomain()) @@ -2027,10 +2033,8 @@ void ClusterStateManager::processLeaderSyncDataQuery( } // Populate queues info - mqbc::ClusterUtil::loadQueuesInfo( - &leaderAdvisory.queues(), - *d_state_p, - d_clusterConfig.clusterAttributes().isCSLModeEnabled()); + mqbc::ClusterUtil::loadQueuesInfo(&leaderAdvisory.queues(), + *d_state_p); } else { // Self is not available. diff --git a/src/groups/mqb/mqbblp/mqbblp_clusterstatemanager.h b/src/groups/mqb/mqbblp/mqbblp_clusterstatemanager.h index dfd6d38bf..25acc06fc 100644 --- a/src/groups/mqb/mqbblp/mqbblp_clusterstatemanager.h +++ b/src/groups/mqb/mqbblp/mqbblp_clusterstatemanager.h @@ -113,8 +113,8 @@ class ClusterStateManager : public mqbc::ClusterStateObserver, typedef bsl::vector QueueAdvisories; - typedef mqbc::ClusterStateQueueInfo::AppIdInfo AppIdInfo; - typedef mqbc::ClusterStateQueueInfo::AppIdInfos AppIdInfos; + typedef mqbc::ClusterStateQueueInfo::AppInfo AppInfo; + typedef mqbc::ClusterStateQueueInfo::AppInfos AppInfos; typedef mqbc::ClusterState::UriToQueueInfoMap UriToQueueInfoMap; typedef mqbc::ClusterState::UriToQueueInfoMapCIter UriToQueueInfoMapCIter; @@ -380,7 +380,7 @@ class ClusterStateManager : public mqbc::ClusterStateObserver, virtual void registerQueueInfo(const bmqt::Uri& uri, int partitionId, const mqbu::StorageKey& queueKey, - const AppIdInfos& appIdInfos, + const AppInfos& appIdInfos, bool forceUpdate) BSLS_KEYWORD_OVERRIDE; /// Unassign the queue in the specified `advisory` by applying the diff --git a/src/groups/mqb/mqbblp/mqbblp_domain.cpp b/src/groups/mqb/mqbblp/mqbblp_domain.cpp index 88bfd8d3c..10bcf80c7 100644 --- a/src/groups/mqb/mqbblp/mqbblp_domain.cpp +++ b/src/groups/mqb/mqbblp/mqbblp_domain.cpp @@ -77,7 +77,7 @@ void afterAppIdRegisteredDispatched(mqbi::Queue* queue, BSLS_ASSERT_SAFE(queue->dispatcher()->inDispatcherThread(queue)); queue->queueEngine()->afterAppIdRegistered( - mqbi::Storage::AppIdKeyPair(appId, mqbu::StorageKey())); + mqbi::Storage::AppInfo(appId, mqbu::StorageKey())); } void afterAppIdUnregisteredDispatched(mqbi::Queue* queue, @@ -91,7 +91,7 @@ void afterAppIdUnregisteredDispatched(mqbi::Queue* queue, // Note: Inputing nullKey here is okay since this routine will be removed // when we switch to CSL workflow. queue->queueEngine()->afterAppIdUnregistered( - mqbi::Storage::AppIdKeyPair(appId, mqbu::StorageKey())); + mqbi::Storage::AppInfo(appId, mqbu::StorageKey())); } /// Validates an application subscription. @@ -289,8 +289,8 @@ void Domain::onOpenQueueResponse( confirmationCookie)); } -void Domain::updateAuthorizedAppIds(const AppIdInfos& addedAppIds, - const AppIdInfos& removedAppIds) +void Domain::updateAuthorizedAppIds(const AppInfos& addedAppIds, + const AppInfos& removedAppIds) { mqbconfm::QueueMode& queueMode = d_config.value().mode(); if (!queueMode.isFanoutValue()) { @@ -298,10 +298,7 @@ void Domain::updateAuthorizedAppIds(const AppIdInfos& addedAppIds, } bsl::vector& authorizedAppIds = queueMode.fanout().appIDs(); - const AppIdKeyPairs addedIdKeyPairs(addedAppIds.cbegin(), - addedAppIds.cend()); - for (AppIdKeyPairsCIter cit = addedIdKeyPairs.cbegin(); - cit != addedIdKeyPairs.cend(); + for (AppInfosCIter cit = addedAppIds.cbegin(); cit != addedAppIds.cend(); ++cit) { if (bsl::find(authorizedAppIds.begin(), authorizedAppIds.end(), @@ -315,10 +312,8 @@ void Domain::updateAuthorizedAppIds(const AppIdInfos& addedAppIds, authorizedAppIds.push_back(cit->first); } - const AppIdKeyPairs removedIdKeyPairs(removedAppIds.cbegin(), - removedAppIds.cend()); - for (AppIdKeyPairsCIter cit = removedIdKeyPairs.cbegin(); - cit != removedIdKeyPairs.cend(); + for (AppInfosCIter cit = removedAppIds.cbegin(); + cit != removedAppIds.cend(); ++cit) { const bsl::vector::const_iterator it = bsl::find( authorizedAppIds.begin(), @@ -360,13 +355,13 @@ void Domain::onQueueAssigned(const mqbc::ClusterStateQueueInfo& info) return; // RETURN } - updateAuthorizedAppIds(info.appIdInfos()); + updateAuthorizedAppIds(info.appInfos()); } void Domain::onQueueUpdated(const bmqt::Uri& uri, const bsl::string& domain, - const AppIdInfos& addedAppIds, - const AppIdInfos& removedAppIds) + const AppInfos& addedAppIds, + const AppInfos& removedAppIds) { // executed by the associated CLUSTER's DISPATCHER thread @@ -500,14 +495,16 @@ int Domain::configure(bsl::ostream& errorDescription, if (!d_cluster_sp->isCSLModeEnabled() && d_config.value().mode().isFanoutValue()) { // Compute list of added and removed App IDs. - bsl::vector oldCfgAppIds( - oldConfig.value().mode().fanout().appIDs(), + bsl::unordered_set oldCfgAppIds( + oldConfig.value().mode().fanout().appIDs().cbegin(), + oldConfig.value().mode().fanout().appIDs().cend(), d_allocator_p); - bsl::vector newCfgAppIds( - d_config.value().mode().fanout().appIDs(), + bsl::unordered_set newCfgAppIds( + d_config.value().mode().fanout().appIDs().cbegin(), + d_config.value().mode().fanout().appIDs().cend(), d_allocator_p); - bsl::vector addedIds, removedIds; + bsl::unordered_set addedIds, removedIds; mqbc::StorageUtil::loadAddedAndRemovedEntries(&addedIds, &removedIds, oldCfgAppIds, @@ -516,7 +513,8 @@ int Domain::configure(bsl::ostream& errorDescription, bslmt::LockGuard guard(&d_mutex); // Invoke callbacks for each added and removed ID on each queue. - bsl::vector::const_iterator it = addedIds.cbegin(); + bsl::unordered_set::const_iterator it = + addedIds.cbegin(); QueueMap::const_iterator qIt; for (; it != addedIds.cend(); it++) { for (qIt = d_queues.cbegin(); qIt != d_queues.cend(); ++qIt) { diff --git a/src/groups/mqb/mqbblp/mqbblp_domain.h b/src/groups/mqb/mqbblp/mqbblp_domain.h index a8ef7ee14..af3af7172 100644 --- a/src/groups/mqb/mqbblp/mqbblp_domain.h +++ b/src/groups/mqb/mqbblp/mqbblp_domain.h @@ -104,8 +104,8 @@ class Domain : public mqbi::Domain, public mqbc::ClusterStateObserver { typedef QueueMap::iterator QueueMapIter; typedef QueueMap::const_iterator QueueMapCIter; - typedef mqbi::Storage::AppIdKeyPairs AppIdKeyPairs; - typedef AppIdKeyPairs::const_iterator AppIdKeyPairsCIter; + typedef mqbi::Storage::AppInfos AppInfos; + typedef AppInfos::const_iterator AppInfosCIter; enum DomainState { e_STARTED = 0, e_STOPPING = 1, e_STOPPED = 2 }; @@ -199,9 +199,8 @@ class Domain : public mqbi::Domain, public mqbc::ClusterStateObserver { /// Update the list of authorized appIds by adding the specified /// `addedAppIds` and removing the specified `removedAppIds`. - void - updateAuthorizedAppIds(const AppIdInfos& addedAppIds, - const AppIdInfos& removedAppIds = AppIdInfos()); + void updateAuthorizedAppIds(const AppInfos& addedAppIds, + const AppInfos& removedAppIds = AppInfos()); // PRIVATE MANIPULATORS // (virtual: mqbc::ClusterStateObserver) @@ -223,8 +222,8 @@ class Domain : public mqbi::Domain, public mqbc::ClusterStateObserver { /// which case this queue update is ignored. virtual void onQueueUpdated(const bmqt::Uri& uri, const bsl::string& domain, - const AppIdInfos& addedAppIds, - const AppIdInfos& removedAppIds = AppIdInfos()) + const AppInfos& addedAppIds, + const AppInfos& removedAppIds = AppInfos()) BSLS_KEYWORD_OVERRIDE; private: diff --git a/src/groups/mqb/mqbblp/mqbblp_queuestate.cpp b/src/groups/mqb/mqbblp/mqbblp_queuestate.cpp index e262b6f28..b37129837 100644 --- a/src/groups/mqb/mqbblp/mqbblp_queuestate.cpp +++ b/src/groups/mqb/mqbblp/mqbblp_queuestate.cpp @@ -224,7 +224,7 @@ void QueueState::loadInternals(mqbcmd::QueueState* out) const queueStorage.numBytes() = d_storage_mp->numBytes( mqbu::StorageKey::k_NULL_KEY); if (d_storage_mp->numVirtualStorages()) { - mqbi::Storage::AppIdKeyPairs appIdKeyPairs; + mqbi::Storage::AppInfos appIdKeyPairs; d_storage_mp->loadVirtualStorageDetails(&appIdKeyPairs); BSLS_ASSERT_SAFE( appIdKeyPairs.size() == @@ -233,8 +233,13 @@ void QueueState::loadInternals(mqbcmd::QueueState* out) const bsl::vector& virtualStorages = queueStorage.virtualStorages(); virtualStorages.resize(appIdKeyPairs.size()); - for (size_t i = 0; i < appIdKeyPairs.size(); ++i) { - const mqbi::Storage::AppIdKeyPair& p = appIdKeyPairs[i]; + + size_t i = 0; + for (mqbi::Storage::AppInfos::const_iterator cit = + appIdKeyPairs.cbegin(); + cit != appIdKeyPairs.cend(); + ++cit, ++i) { + const mqbi::Storage::AppInfo& p = *cit; virtualStorages[i].appId() = p.first; os.reset(); os << p.second; diff --git a/src/groups/mqb/mqbblp/mqbblp_relayqueueengine.cpp b/src/groups/mqb/mqbblp/mqbblp_relayqueueengine.cpp index 3b5ec9e8f..5796bed4a 100644 --- a/src/groups/mqb/mqbblp/mqbblp_relayqueueengine.cpp +++ b/src/groups/mqb/mqbblp/mqbblp_relayqueueengine.cpp @@ -1589,7 +1589,7 @@ void RelayQueueEngine::loadInternals(mqbcmd::QueueEngine* out) const mqbcmd::RelayQueueEngine& relayQueueEngine = out->makeRelay(); int numSubStreams = 0; - mqbi::Storage::AppIdKeyPairs appIdKeyPairs; + mqbi::Storage::AppInfos appIdKeyPairs; numSubStreams = storage()->numVirtualStorages(); storage()->loadVirtualStorageDetails(&appIdKeyPairs); @@ -1601,8 +1601,12 @@ void RelayQueueEngine::loadInternals(mqbcmd::QueueEngine* out) const bsl::vector& subStreams = relayQueueEngine.subStreams(); subStreams.reserve(appIdKeyPairs.size()); - for (size_t i = 0; i < appIdKeyPairs.size(); ++i) { - const mqbi::Storage::AppIdKeyPair& p = appIdKeyPairs[i]; + + for (mqbi::Storage::AppInfos::const_iterator cit = + appIdKeyPairs.cbegin(); + cit != appIdKeyPairs.cend(); + ++cit) { + const mqbi::Storage::AppInfo& p = *cit; subStreams.resize(subStreams.size() + 1); mqbcmd::RelayQueueEngineSubStream& subStream = subStreams.back(); diff --git a/src/groups/mqb/mqbblp/mqbblp_rootqueueengine.cpp b/src/groups/mqb/mqbblp/mqbblp_rootqueueengine.cpp index 57001d455..0bfaa6726 100644 --- a/src/groups/mqb/mqbblp/mqbblp_rootqueueengine.cpp +++ b/src/groups/mqb/mqbblp/mqbblp_rootqueueengine.cpp @@ -1821,7 +1821,7 @@ bool RootQueueEngine::logAlarmCb(const mqbu::StorageKey& appKey, } void RootQueueEngine::afterAppIdRegistered( - const mqbi::Storage::AppIdKeyPair& appIdKeyPair) + const mqbi::Storage::AppInfo& appIdKeyPair) { // executed by the *QUEUE DISPATCHER* thread @@ -1915,17 +1915,18 @@ void RootQueueEngine::afterAppIdRegistered( BSLS_ASSERT_SAFE(!key.isNull()); + mqbi::Storage::AppInfos one(1, d_allocator_p); + one.emplace(mqbi::Storage::AppInfo(appId, key)); d_queueState_p->storageManager()->updateQueuePrimary( d_queueState_p->uri(), d_queueState_p->key(), d_queueState_p->partitionId(), - mqbi::Storage::AppIdKeyPairs(1, - mqbi::Storage::AppIdKeyPair(appId, key)), - mqbi::Storage::AppIdKeyPairs()); + one, + mqbi::Storage::AppInfos()); } void RootQueueEngine::afterAppIdUnregistered( - const mqbi::Storage::AppIdKeyPair& appIdKeyPair) + const mqbi::Storage::AppInfo& appIdKeyPair) { // executed by the *QUEUE DISPATCHER* thread @@ -1967,15 +1968,15 @@ void RootQueueEngine::afterAppIdUnregistered( << "]"; } } + mqbi::Storage::AppInfos one(1, d_allocator_p); + one.emplace(mqbi::Storage::AppInfo(appId, appKey)); d_queueState_p->storageManager()->updateQueuePrimary( d_queueState_p->uri(), d_queueState_p->key(), d_queueState_p->partitionId(), - mqbi::Storage::AppIdKeyPairs(), - mqbi::Storage::AppIdKeyPairs(1, - mqbi::Storage::AppIdKeyPair(appId, - appKey))); + mqbi::Storage::AppInfos(), + one); // No need to log in case of failure because 'updateQueuePrimary' does it // (even in case of success FTM). diff --git a/src/groups/mqb/mqbblp/mqbblp_rootqueueengine.h b/src/groups/mqb/mqbblp/mqbblp_rootqueueengine.h index 818c71dfd..f8bd0b626 100644 --- a/src/groups/mqb/mqbblp/mqbblp_rootqueueengine.h +++ b/src/groups/mqb/mqbblp/mqbblp_rootqueueengine.h @@ -400,14 +400,14 @@ class RootQueueEngine BSLS_KEYWORD_FINAL : public mqbi::QueueEngine { /// /// THREAD: This method is called from the Queue's dispatcher thread. virtual void afterAppIdRegistered( - const mqbi::Storage::AppIdKeyPair& appIdKeyPair) BSLS_KEYWORD_OVERRIDE; + const mqbi::Storage::AppInfo& appIdKeyPair) BSLS_KEYWORD_OVERRIDE; /// Called after the specified `appIdKeyPair` has been dynamically /// unregistered. /// /// THREAD: This method is called from the Queue's dispatcher thread. virtual void afterAppIdUnregistered( - const mqbi::Storage::AppIdKeyPair& appIdKeyPair) BSLS_KEYWORD_OVERRIDE; + const mqbi::Storage::AppInfo& appIdKeyPair) BSLS_KEYWORD_OVERRIDE; /// Called after creation of a new storage for the specified /// `appIdKeyPair`. diff --git a/src/groups/mqb/mqbblp/mqbblp_storagemanager.cpp b/src/groups/mqb/mqbblp/mqbblp_storagemanager.cpp index c573e12f2..e319f48f3 100644 --- a/src/groups/mqb/mqbblp/mqbblp_storagemanager.cpp +++ b/src/groups/mqb/mqbblp/mqbblp_storagemanager.cpp @@ -367,7 +367,7 @@ void StorageManager::queueCreationCb(int* status, int partitionId, const bmqt::Uri& uri, const mqbu::StorageKey& queueKey, - const AppIdKeyPairs& appIdKeyPairs, + const AppInfos& appIdKeyPairs, bool isNewQueue) { // executed by *QUEUE_DISPATCHER* thread associated with 'partitionId' @@ -1049,7 +1049,7 @@ StorageManager::~StorageManager() void StorageManager::registerQueue(const bmqt::Uri& uri, const mqbu::StorageKey& queueKey, int partitionId, - const AppIdKeyPairs& appIdKeyPairs, + const AppInfos& appIdKeyPairs, mqbi::Domain* domain) { // executed by the *CLUSTER DISPATCHER* thread @@ -1060,9 +1060,6 @@ void StorageManager::registerQueue(const bmqt::Uri& uri, BSLS_ASSERT_SAFE(0 <= partitionId && partitionId < static_cast(d_fileStores.size())); BSLS_ASSERT_SAFE(domain); - if (!d_cluster_p->isCSLModeEnabled()) { - BSLS_ASSERT_SAFE(appIdKeyPairs.empty()); - } mqbc::StorageUtil::registerQueue(d_cluster_p, d_dispatcher_p, @@ -1112,8 +1109,8 @@ void StorageManager::unregisterQueue(const bmqt::Uri& uri, int partitionId) int StorageManager::updateQueuePrimary(const bmqt::Uri& uri, const mqbu::StorageKey& queueKey, int partitionId, - const AppIdKeyPairs& addedIdKeyPairs, - const AppIdKeyPairs& removedIdKeyPairs) + const AppInfos& addedIdKeyPairs, + const AppInfos& removedIdKeyPairs) { // executed by *QUEUE_DISPATCHER* thread with the specified 'partitionId' @@ -1229,7 +1226,7 @@ void StorageManager::unregisterQueueReplica(int partitionId, void StorageManager::updateQueueReplica(int partitionId, const bmqt::Uri& uri, const mqbu::StorageKey& queueKey, - const AppIdKeyPairs& appIdKeyPairs, + const AppInfos& appIdKeyPairs, mqbi::Domain* domain, bool allowDuplicate) { @@ -1410,7 +1407,7 @@ int StorageManager::start(bsl::ostream& errorDescription) bdlf::PlaceHolders::_2, // partitionId bdlf::PlaceHolders::_3, // QueueUri bdlf::PlaceHolders::_4, // QueueKey - bdlf::PlaceHolders::_5, // AppIdKeyPairs + bdlf::PlaceHolders::_5, // AppInfos bdlf::PlaceHolders::_6), // IsNewQueue) bdlf::BindUtil::bind(&StorageManager::queueDeletionCb, this, diff --git a/src/groups/mqb/mqbblp/mqbblp_storagemanager.h b/src/groups/mqb/mqbblp/mqbblp_storagemanager.h index 86ceb2fff..86a5a366c 100644 --- a/src/groups/mqb/mqbblp/mqbblp_storagemanager.h +++ b/src/groups/mqb/mqbblp/mqbblp_storagemanager.h @@ -398,7 +398,7 @@ class StorageManager : public mqbi::StorageManager { int partitionId, const bmqt::Uri& uri, const mqbu::StorageKey& queueKey, - const AppIdKeyPairs& appIdKeyPairs, + const AppInfos& appIdKeyPairs, bool isNewQueue); void queueDeletionCb(int* status, @@ -519,7 +519,7 @@ class StorageManager : public mqbi::StorageManager { virtual void registerQueue(const bmqt::Uri& uri, const mqbu::StorageKey& queueKey, int partitionId, - const AppIdKeyPairs& appIdKeyPairs, + const AppInfos& appIdKeyPairs, mqbi::Domain* domain) BSLS_KEYWORD_OVERRIDE; /// Synchronously unregister the queue with the specified `uri` from the @@ -542,8 +542,8 @@ class StorageManager : public mqbi::StorageManager { virtual int updateQueuePrimary(const bmqt::Uri& uri, const mqbu::StorageKey& queueKey, int partitionId, - const AppIdKeyPairs& addedIdKeyPairs, - const AppIdKeyPairs& removedIdKeyPairs) + const AppInfos& addedIdKeyPairs, + const AppInfos& removedIdKeyPairs) BSLS_KEYWORD_OVERRIDE; virtual void @@ -563,7 +563,7 @@ class StorageManager : public mqbi::StorageManager { updateQueueReplica(int partitionId, const bmqt::Uri& uri, const mqbu::StorageKey& queueKey, - const AppIdKeyPairs& appIdKeyPairs, + const AppInfos& appIdKeyPairs, mqbi::Domain* domain = 0, bool allowDuplicate = false) BSLS_KEYWORD_OVERRIDE; diff --git a/src/groups/mqb/mqbc/mqbc_clusterstate.cpp b/src/groups/mqb/mqbc/mqbc_clusterstate.cpp index 8bf7084f7..3f2ab1ed5 100644 --- a/src/groups/mqb/mqbc/mqbc_clusterstate.cpp +++ b/src/groups/mqb/mqbc/mqbc_clusterstate.cpp @@ -46,7 +46,7 @@ bsl::ostream& ClusterStateQueueInfo::print(bsl::ostream& stream, printer.printAttribute("uri", uri()); printer.printAttribute("queueKey", key()); printer.printAttribute("partitionId", partitionId()); - printer.printAttribute("appIdInfos", appIdInfos()); + printer.printAttribute("appIdInfos", appInfos()); printer.end(); return stream; @@ -87,8 +87,8 @@ void ClusterStateObserver::onQueueUnassigned( void ClusterStateObserver::onQueueUpdated( BSLS_ANNOTATION_UNUSED const bmqt::Uri& uri, BSLS_ANNOTATION_UNUSED const bsl::string& domain, - BSLS_ANNOTATION_UNUSED const AppIdInfos& addedAppIds, - BSLS_ANNOTATION_UNUSED const AppIdInfos& removedAppIds) + BSLS_ANNOTATION_UNUSED const AppInfos& addedAppIds, + BSLS_ANNOTATION_UNUSED const AppInfos& removedAppIds) { // NOTHING } @@ -315,7 +315,7 @@ ClusterState& ClusterState::updatePartitionNumActiveQueues(int partitionId, bool ClusterState::assignQueue(const bmqt::Uri& uri, const mqbu::StorageKey& key, int partitionId, - const AppIdInfos& appIdInfos) + const AppInfos& appIdInfos) { // executed by the cluster *DISPATCHER* thread @@ -353,14 +353,14 @@ bool ClusterState::assignQueue(const bmqt::Uri& uri, updatePartitionQueueMapped(iter->second->partitionId(), -1); iter->second->setKey(key).setPartitionId(partitionId); - iter->second->appIdInfos() = appIdInfos; + iter->second->appInfos() = appIdInfos; iter->second->setPendingUnassignment(false); } } updatePartitionQueueMapped(partitionId, 1); - bmqu::Printer printer(&appIdInfos); + bmqu::Printer printer(&appIdInfos); BALL_LOG_INFO << "Cluster [" << d_cluster_p->name() << "]: " << "Assigning queue [" << uri << "], queueKey: [" << key << "] to Partition [" << partitionId @@ -453,8 +453,8 @@ void ClusterState::clearQueues() int ClusterState::updateQueue(const bmqt::Uri& uri, const bsl::string& domain, - const AppIdInfos& addedAppIds, - const AppIdInfos& removedAppIds) + const AppInfos& addedAppIds, + const AppInfos& removedAppIds) { // executed by the cluster *DISPATCHER* thread @@ -484,8 +484,8 @@ int ClusterState::updateQueue(const bmqt::Uri& uri, return rc_QUEUE_NOT_FOUND; // RETURN } - AppIdInfos& appIdInfos = iter->second->appIdInfos(); - for (AppIdInfosCIter citer = addedAppIds.cbegin(); + AppInfos& appIdInfos = iter->second->appInfos(); + for (AppInfosCIter citer = addedAppIds.cbegin(); citer != addedAppIds.cend(); ++citer) { if (!appIdInfos.insert(*citer).second) { @@ -493,18 +493,18 @@ int ClusterState::updateQueue(const bmqt::Uri& uri, } } - for (AppIdInfosCIter citer = removedAppIds.begin(); + for (AppInfosCIter citer = removedAppIds.begin(); citer != removedAppIds.end(); ++citer) { - const AppIdInfosCIter appIdInfoCIter = appIdInfos.find(*citer); + const AppInfosCIter appIdInfoCIter = appIdInfos.find(*citer); if (appIdInfoCIter == appIdInfos.cend()) { return rc_APPID_NOT_FOUND; // RETURN } appIdInfos.erase(appIdInfoCIter); } - bmqu::Printer printer1(&addedAppIds); - bmqu::Printer printer2(&removedAppIds); + bmqu::Printer printer1(&addedAppIds); + bmqu::Printer printer2(&removedAppIds); BALL_LOG_INFO << "Cluster [" << d_cluster_p->name() << "]: " << "Updating queue [" << uri << "], queueKey: [" << iter->second->key() << "], partitionId: [" @@ -515,8 +515,8 @@ int ClusterState::updateQueue(const bmqt::Uri& uri, else { // This update is for an entire domain, instead of any individual // queue. - bmqu::Printer printer1(&addedAppIds); - bmqu::Printer printer2(&removedAppIds); + bmqu::Printer printer1(&addedAppIds); + bmqu::Printer printer2(&removedAppIds); BALL_LOG_INFO << "Cluster [" << d_cluster_p->name() << "]: " << "Updating domain: [" << domain << "], addedAppIds: " << printer1 diff --git a/src/groups/mqb/mqbc/mqbc_clusterstate.h b/src/groups/mqb/mqbc/mqbc_clusterstate.h index 82b996a08..e1c4a928c 100644 --- a/src/groups/mqb/mqbc/mqbc_clusterstate.h +++ b/src/groups/mqb/mqbc/mqbc_clusterstate.h @@ -161,9 +161,9 @@ class ClusterStatePartitionInfo { class ClusterStateQueueInfo { public: // TYPES - typedef mqbi::ClusterStateManager::AppIdInfo AppIdInfo; - typedef mqbi::ClusterStateManager::AppIdInfos AppIdInfos; - typedef mqbi::ClusterStateManager::AppIdInfosCIter AppIdInfosCIter; + typedef mqbi::ClusterStateManager::AppInfo AppInfo; + typedef mqbi::ClusterStateManager::AppInfos AppInfos; + typedef mqbi::ClusterStateManager::AppInfosCIter AppInfosCIter; private: // DATA @@ -178,7 +178,7 @@ class ClusterStateQueueInfo { // Assigned partitionId // (mqbs::DataStore::k_INVALID_PARTITION_ID if unassigned) - AppIdInfos d_appIdInfos; + AppInfos d_appInfos; // List of App id and key pairs // // TBD: Should also be added to mqbconfm::Domain @@ -210,7 +210,7 @@ class ClusterStateQueueInfo { ClusterStateQueueInfo(const bmqt::Uri& uri, const mqbu::StorageKey& key, int partitionId, - const AppIdInfos& appIdInfos, + const AppInfos& appIdInfos, bslma::Allocator* allocator); // MANIPULATORS @@ -222,7 +222,7 @@ class ClusterStateQueueInfo { ClusterStateQueueInfo& setPendingUnassignment(bool value); /// Get a modifiable reference to this object's appIdInfos. - AppIdInfos& appIdInfos(); + AppInfos& appInfos(); /// Reset the `key`, `partitionId`, `appIdInfos` members of this object. /// Note that `uri` is left untouched because it is an invariant member @@ -233,7 +233,7 @@ class ClusterStateQueueInfo { const bmqt::Uri& uri() const; const mqbu::StorageKey& key() const; int partitionId() const; - const AppIdInfos& appIdInfos() const; + const AppInfos& appInfos() const; /// Return the value of the corresponding member of this object. bool pendingUnassignment() const; @@ -271,7 +271,7 @@ bsl::ostream& operator<<(bsl::ostream& stream, class ClusterStateObserver { public: // TYPES - typedef ClusterStateQueueInfo::AppIdInfos AppIdInfos; + typedef ClusterStateQueueInfo::AppInfos AppInfos; public: // CREATORS @@ -318,11 +318,10 @@ class ClusterStateObserver { /// /// THREAD: This method is invoked in the associated cluster's /// dispatcher thread. - virtual void - onQueueUpdated(const bmqt::Uri& uri, - const bsl::string& domain, - const AppIdInfos& addedAppIds, - const AppIdInfos& removedAppIds = AppIdInfos()); + virtual void onQueueUpdated(const bmqt::Uri& uri, + const bsl::string& domain, + const AppInfos& addedAppIds, + const AppInfos& removedAppIds = AppInfos()); /// Callback invoked when a partition with the specified `partitionId` /// has been orphan above a certain threshold amount of time. @@ -366,8 +365,8 @@ class ClusterState { public: // TYPES - typedef ClusterStateQueueInfo::AppIdInfos AppIdInfos; - typedef ClusterStateQueueInfo::AppIdInfosCIter AppIdInfosCIter; + typedef ClusterStateQueueInfo::AppInfos AppInfos; + typedef ClusterStateQueueInfo::AppInfosCIter AppInfosCIter; typedef bsl::vector PartitionsInfo; @@ -567,7 +566,7 @@ class ClusterState { bool assignQueue(const bmqt::Uri& uri, const mqbu::StorageKey& key, int partitionId, - const AppIdInfos& appIdInfos); + const AppInfos& appIdInfos); /// Un-assign the queue with the specified `uri`. Return true if /// successful, or false if the queue does not exist. @@ -592,8 +591,8 @@ class ClusterState { /// cluster's dispatcher thread. int updateQueue(const bmqt::Uri& uri, const bsl::string& domain, - const AppIdInfos& addedAppIds, - const AppIdInfos& removedAppIds = AppIdInfos()); + const AppInfos& addedAppIds, + const AppInfos& removedAppIds = AppInfos()); /// Clear this cluster state object, without firing any observers. void clear(); @@ -767,7 +766,7 @@ inline ClusterStateQueueInfo::ClusterStateQueueInfo( : d_uri(uri, allocator) , d_key() , d_partitionId(mqbs::DataStore::k_INVALID_PARTITION_ID) -, d_appIdInfos(allocator) +, d_appInfos(allocator) , d_pendingUnassignment(false) { // NOTHING @@ -777,12 +776,12 @@ inline ClusterStateQueueInfo::ClusterStateQueueInfo( const bmqt::Uri& uri, const mqbu::StorageKey& key, int partitionId, - const AppIdInfos& appIdInfos, + const AppInfos& appIdInfos, bslma::Allocator* allocator) : d_uri(uri, allocator) , d_key(key) , d_partitionId(partitionId) -, d_appIdInfos(appIdInfos, allocator) +, d_appInfos(appIdInfos, allocator) , d_pendingUnassignment(false) { // NOTHING @@ -809,9 +808,9 @@ ClusterStateQueueInfo::setPendingUnassignment(bool value) return *this; } -inline ClusterStateQueueInfo::AppIdInfos& ClusterStateQueueInfo::appIdInfos() +inline ClusterStateQueueInfo::AppInfos& ClusterStateQueueInfo::appInfos() { - return d_appIdInfos; + return d_appInfos; } inline void ClusterStateQueueInfo::reset() @@ -821,7 +820,7 @@ inline void ClusterStateQueueInfo::reset() d_key.reset(); d_partitionId = mqbs::DataStore::k_INVALID_PARTITION_ID; - d_appIdInfos.clear(); + d_appInfos.clear(); } // ACCESSORS @@ -840,10 +839,10 @@ inline int ClusterStateQueueInfo::partitionId() const return d_partitionId; } -inline const ClusterStateQueueInfo::AppIdInfos& -ClusterStateQueueInfo::appIdInfos() const +inline const ClusterStateQueueInfo::AppInfos& +ClusterStateQueueInfo::appInfos() const { - return d_appIdInfos; + return d_appInfos; } inline bool ClusterStateQueueInfo::pendingUnassignment() const diff --git a/src/groups/mqb/mqbc/mqbc_clusterstatemanager.cpp b/src/groups/mqb/mqbc/mqbc_clusterstatemanager.cpp index 801b0ca1b..0316e7418 100644 --- a/src/groups/mqb/mqbc/mqbc_clusterstatemanager.cpp +++ b/src/groups/mqb/mqbc/mqbc_clusterstatemanager.cpp @@ -198,9 +198,7 @@ void ClusterStateManager::do_applyCSLSelf(const ClusterFSMArgsSp& args) return; // RETURN } - ClusterUtil::loadQueuesInfo(&clusterStateSnapshot.queues(), - tempState, - true); // includeAppIds + ClusterUtil::loadQueuesInfo(&clusterStateSnapshot.queues(), tempState); } else { // Verify that elector term in follower snapshot is less than the @@ -1120,9 +1118,7 @@ int ClusterStateManager::loadClusterStateSnapshot( } mqbc::ClusterUtil::loadPartitionsInfo(&out->partitions(), tempState); - mqbc::ClusterUtil::loadQueuesInfo(&out->queues(), - tempState, - true); // includeAppIds + mqbc::ClusterUtil::loadQueuesInfo(&out->queues(), tempState); return 0; } @@ -1513,7 +1509,7 @@ ClusterStateManager::assignQueue(const bmqt::Uri& uri, void ClusterStateManager::registerQueueInfo(const bmqt::Uri& uri, int partitionId, const mqbu::StorageKey& queueKey, - const AppIdInfos& appIdInfos, + const AppInfos& appIdInfos, bool forceUpdate) { // executed by the *DISPATCHER* thread diff --git a/src/groups/mqb/mqbc/mqbc_clusterstatemanager.h b/src/groups/mqb/mqbc/mqbc_clusterstatemanager.h index b2a8c2670..79af0a1c1 100644 --- a/src/groups/mqb/mqbc/mqbc_clusterstatemanager.h +++ b/src/groups/mqb/mqbc/mqbc_clusterstatemanager.h @@ -110,7 +110,7 @@ class ClusterStateManager typedef ClusterFSM::ClusterFSMArgs ClusterFSMArgs; typedef ClusterFSM::ClusterFSMArgsSp ClusterFSMArgsSp; - typedef mqbi::ClusterStateManager::AppIdInfos AppIdInfos; + typedef mqbi::ClusterStateManager::AppInfos AppInfos; public: // TYPES @@ -483,7 +483,7 @@ class ClusterStateManager virtual void registerQueueInfo(const bmqt::Uri& uri, int partitionId, const mqbu::StorageKey& queueKey, - const AppIdInfos& appIdInfos, + const AppInfos& appIdInfos, bool forceUpdate) BSLS_KEYWORD_OVERRIDE; /// Unassign the queue in the specified `advisory` by applying the diff --git a/src/groups/mqb/mqbc/mqbc_clusterstatemanager.t.cpp b/src/groups/mqb/mqbc/mqbc_clusterstatemanager.t.cpp index e8258298b..24d31a1a5 100644 --- a/src/groups/mqb/mqbc/mqbc_clusterstatemanager.t.cpp +++ b/src/groups/mqb/mqbc/mqbc_clusterstatemanager.t.cpp @@ -518,8 +518,7 @@ struct Tester { d_cluster_mp->_state()); mqbc::ClusterUtil::loadQueuesInfo( &response.clusterStateSnapshot().queues(), - d_cluster_mp->_state(), - true); // includeAppIds + d_cluster_mp->_state()); for (TestChannelMapCIter cit = d_cluster_mp->_channels().cbegin(); cit != d_cluster_mp->_channels().cend(); diff --git a/src/groups/mqb/mqbc/mqbc_clusterutil.cpp b/src/groups/mqb/mqbc/mqbc_clusterutil.cpp index 98be24bbe..0f09d5f34 100644 --- a/src/groups/mqb/mqbc/mqbc_clusterutil.cpp +++ b/src/groups/mqb/mqbc/mqbc_clusterutil.cpp @@ -66,9 +66,9 @@ const char k_SELF_NODE_IS_STOPPING[] = "self node is stopping"; const char k_DOMAIN_CREATION_FAILURE[] = "failed to create domain"; // TYPES -typedef ClusterUtil::AppIdInfo AppIdInfo; -typedef ClusterUtil::AppIdInfos AppIdInfos; -typedef ClusterUtil::AppIdInfosCIter AppIdInfosCIter; +typedef ClusterUtil::AppInfo AppInfo; +typedef ClusterUtil::AppInfos AppInfos; +typedef ClusterUtil::AppInfosCIter AppInfosCIter; typedef ClusterUtil::ClusterNodeSessionMapConstIter ClusterNodeSessionMapConstIter; @@ -97,31 +97,24 @@ void applyPartitionPrimary( void applyQueueAssignment(mqbc::ClusterState* clusterState, const bsl::vector& queues) { + // TODO: refactor to use allocator(s) + bslma::Allocator* allocator = 0; + for (bsl::vector::const_iterator it = queues.begin(); it != queues.end(); ++it) { const bmqp_ctrlmsg::QueueInfo& queueInfo = *it; - const bmqt::Uri uri(queueInfo.uri()); + const bmqt::Uri uri(queueInfo.uri(), allocator); const int partitionId(queueInfo.partitionId()); const mqbu::StorageKey queueKey( mqbu::StorageKey::BinaryRepresentation(), queueInfo.key().data()); - const bsl::vector& appIds = - queueInfo.appIds(); - AppIdInfos addedAppIds; - for (bsl::vector::const_iterator citer = - appIds.cbegin(); - citer != appIds.cend(); - ++citer) { - AppIdInfo appIdInfo; - appIdInfo.first = citer->appId(); - appIdInfo.second.fromBinary(citer->appKey().data()); - - addedAppIds.insert(appIdInfo); - } + AppInfos addedAppIds(allocator); + mqbc::ClusterUtil::parseQueueInfo(&addedAppIds, queueInfo, allocator); + // CSL commit clusterState->assignQueue(uri, queueKey, partitionId, addedAppIds); } } @@ -220,24 +213,24 @@ void applyQueueUpdate(mqbc::ClusterState* clusterState, mqbs::DataStore::k_INVALID_PARTITION_ID); } - AppIdInfos addedAppIds; + AppInfos addedAppIds; for (bsl::vector::const_iterator citer = queueUpdate.addedAppIds().cbegin(); citer != queueUpdate.addedAppIds().cend(); ++citer) { - AppIdInfo appIdInfo; + AppInfo appIdInfo; appIdInfo.first = citer->appId(); appIdInfo.second.fromBinary(citer->appKey().data()); addedAppIds.insert(appIdInfo); } - AppIdInfos removedAppIds; + AppInfos removedAppIds; for (bsl::vector::const_iterator citer = queueUpdate.removedAppIds().begin(); citer != queueUpdate.removedAppIds().end(); ++citer) { - AppIdInfo appIdInfo; + AppInfo appIdInfo; appIdInfo.first = citer->appId(); appIdInfo.second.fromBinary(citer->appKey().data()); @@ -808,7 +801,7 @@ void ClusterUtil::populateQueueAssignmentAdvisory( key->loadBinary(&queueInfo.key()); // Generate appIds and appKeys - populateAppIdInfos(&queueInfo.appIds(), domain->config().mode()); + populateAppInfos(&queueInfo.appIds(), domain->config().mode()); BALL_LOG_INFO << clusterData->identity().description() << ": Populated QueueAssignmentAdvisory: " << *advisory; @@ -900,6 +893,8 @@ ClusterUtil::assignQueue(ClusterState* clusterState, DomainStatesIter domIt = clusterState->domainStates().find( uri.qualifiedDomain()); if (domIt == clusterState->domainStates().end()) { + // REVISIT: This is also done in 'ClusterState::assignQueue' + clusterState->domainStates()[uri.qualifiedDomain()].createInplace( allocator, allocator); @@ -977,12 +972,13 @@ ClusterUtil::assignQueue(ClusterState* clusterState, } } - // Queue is no longer pending unassignment - const DomainStatesCIter cit = clusterState->domainStates().find( + // Set the queue as no longer pending unassignment + const DomainStatesCIter citDomainState = clusterState->domainStates().find( uri.qualifiedDomain()); - if (cit != clusterState->domainStates().cend()) { - UriToQueueInfoMapCIter qcit = cit->second->queuesInfo().find(uri); - if (qcit != cit->second->queuesInfo().cend()) { + if (citDomainState != clusterState->domainStates().cend()) { + UriToQueueInfoMapCIter qcit = + citDomainState->second->queuesInfo().find(uri); + if (qcit != citDomainState->second->queuesInfo().cend()) { BSLS_ASSERT_SAFE(cluster->isCSLModeEnabled() && qcit->second->pendingUnassignment()); qcit->second->setPendingUnassignment(false); @@ -1028,11 +1024,21 @@ ClusterUtil::assignQueue(ClusterState* clusterState, // In CSL mode, we assign the queue to ClusterState upon CSL commit // callback of QueueAssignmentAdvisory, so we don't assign it here. + // In non-CSL mode this is the shortcut to call Primary CQH instead of + // waiting for the quorum of acks in the ledger. + + BSLS_ASSERT_SAFE(queueAdvisory.queues().size() == 1); + + bmqp_ctrlmsg::QueueInfo& queueInfo = queueAdvisory.queues().back(); + + AppInfos appInfos(allocator); + mqbc::ClusterUtil::parseQueueInfo(&appInfos, queueInfo, allocator); + BSLA_MAYBE_UNUSED const bool assignRc = clusterState->assignQueue( uri, key, queueAdvisory.queues().back().partitionId(), - AppIdInfos()); + appInfos); BSLS_ASSERT_SAFE(assignRc); domIt->second->adjustQueueCount(1); @@ -1054,7 +1060,7 @@ void ClusterUtil::registerQueueInfo(ClusterState* clusterState, const bmqt::Uri& uri, int partitionId, const mqbu::StorageKey& queueKey, - const AppIdInfos& appIdInfos, + const AppInfos& appInfos, const QueueAssigningCb& queueAssigningCb, bool forceUpdate) { @@ -1096,40 +1102,39 @@ void ClusterUtil::registerQueueInfo(ClusterState* clusterState, BSLS_ASSERT_SAFE(qs->uri() == uri); if ((qs->partitionId() == partitionId) && - (qs->key() == queueKey) && (qs->appIdInfos() == appIdInfos)) { + (qs->key() == queueKey) && (qs->appInfos() == appInfos)) { // All good.. nothing to update. return; // RETURN } - bmqu::Printer stateAppIdInfos(&qs->appIdInfos()); - bmqu::Printer storageAppIdInfos(&appIdInfos); + bmqu::Printer stateAppInfos(&qs->appInfos()); + bmqu::Printer storageAppInfos(&appInfos); - // PartitionId and/or QueueKey and/or AppIdInfos mismatch. + // PartitionId and/or QueueKey and/or AppInfos mismatch. if (!forceUpdate) { BMQTSK_ALARMLOG_ALARM("CLUSTER_STATE") << cluster->description() << ": For queue [ " << uri - << "], different partitionId/queueKey/appIdInfos in " + << "], different partitionId/queueKey/appInfos in " << "cluster state and storage. " - << "PartitionId/QueueKey/AppIdInfos in cluster state [" + << "PartitionId/QueueKey/AppInfos in cluster state [" << qs->partitionId() << "], [" << qs->key() << "], [" - << stateAppIdInfos - << "]. PartitionId/QueueKey/AppIdInfos in storage [" + << stateAppInfos + << "]. PartitionId/QueueKey/AppInfos in storage [" << partitionId << "], [" << queueKey << "], [" - << storageAppIdInfos << "]." << BMQTSK_ALARMLOG_END; + << storageAppInfos << "]." << BMQTSK_ALARMLOG_END; return; // RETURN } BALL_LOG_WARN << cluster->description() << ": For queue [" << uri << "], force-updating " - << "partitionId/queueKey/appIdInfos from [" + << "partitionId/queueKey/appInfos from [" << qs->partitionId() << "], [" << qs->key() << "], [" - << stateAppIdInfos << "] to [" << partitionId - << "], [" << queueKey << "], [" << storageAppIdInfos - << "]."; + << stateAppInfos << "] to [" << partitionId << "], [" + << queueKey << "], [" << storageAppInfos << "]."; clusterState->queueKeys().erase(qs->key()); - clusterState->assignQueue(uri, queueKey, partitionId, appIdInfos); + clusterState->assignQueue(uri, queueKey, partitionId, appInfos); BALL_LOG_INFO << cluster->description() << ": Queue assigned: " << "[uri: " << uri << ", queueKey: " << queueKey @@ -1144,8 +1149,8 @@ void ClusterUtil::registerQueueInfo(ClusterState* clusterState, << ": re-registering a known queue with a stale view, " << "but queueKey is not unique. " << "QueueKey [" << queueKey << "], URI [" << uri << "], Partition [" - << partitionId << "], AppIdInfos [" - << storageAppIdInfos << "]." << BMQTSK_ALARMLOG_END; + << partitionId << "], AppInfos [" << storageAppInfos + << "]." << BMQTSK_ALARMLOG_END; return; // RETURN } @@ -1161,13 +1166,14 @@ void ClusterUtil::registerQueueInfo(ClusterState* clusterState, } // Queue is not known, so add it. - clusterState->assignQueue(uri, queueKey, partitionId, appIdInfos); + clusterState->assignQueue(uri, queueKey, partitionId, appInfos); - bmqu::Printer printer(&appIdInfos); - BALL_LOG_INFO << cluster->description() << ": Queue assigned: " - << "[uri: " << uri << ", queueKey: " << queueKey + bmqu::Printer printer(&appInfos); + BALL_LOG_INFO << cluster->description() + << ": Queue assigned: " << "[uri: " << uri + << ", queueKey: " << queueKey << ", partitionId: " << partitionId - << ", appIdInfos: " << printer << "]"; + << ", appInfos: " << printer << "]"; if (!cluster->isCSLModeEnabled()) { ClusterState::QueueKeysInsertRc insertRc = @@ -1191,11 +1197,11 @@ void ClusterUtil::registerQueueInfo(ClusterState* clusterState, queueAssigningCb(uri, false); // processingPendingRequests } -void ClusterUtil::populateAppIdInfos(AppIdInfos* appIdInfos, - const mqbconfm::QueueMode& domainConfig) +void ClusterUtil::populateAppInfos(AppInfos* appInfos, + const mqbconfm::QueueMode& domainConfig) { // PRECONDITIONS - BSLS_ASSERT_SAFE(appIdInfos && appIdInfos->empty()); + BSLS_ASSERT_SAFE(appInfos && appInfos->empty()); if (domainConfig.isFanoutValue()) { const bsl::vector& cfgAppIds = @@ -1208,21 +1214,21 @@ void ClusterUtil::populateAppIdInfos(AppIdInfos* appIdInfos, mqbu::StorageKey appKey; mqbs::StorageUtil::generateStorageKey(&appKey, &appKeys, *cit); - appIdInfos->insert(AppIdInfo(*cit, appKey)); + appInfos->insert(AppInfo(*cit, appKey)); } } else { - appIdInfos->insert(AppIdInfo(bmqp::ProtocolUtil::k_DEFAULT_APP_ID, - mqbi::QueueEngine::k_DEFAULT_APP_KEY)); + appInfos->insert(AppInfo(bmqp::ProtocolUtil::k_DEFAULT_APP_ID, + mqbi::QueueEngine::k_DEFAULT_APP_KEY)); } } -void ClusterUtil::populateAppIdInfos( - bsl::vector* appIdInfos, +void ClusterUtil::populateAppInfos( + bsl::vector* appInfos, const mqbconfm::QueueMode& domainConfig) { // PRECONDITIONS - BSLS_ASSERT_SAFE(appIdInfos && appIdInfos->empty()); + BSLS_ASSERT_SAFE(appInfos && appInfos->empty()); if (domainConfig.isFanoutValue()) { const bsl::vector& cfgAppIds = @@ -1237,9 +1243,13 @@ void ClusterUtil::populateAppIdInfos( mqbu::StorageKey appKey; mqbs::StorageUtil::generateStorageKey(&appKey, &appKeys, *cit); + // This is the only place generating keys upon queue assignment + // for both CSL (FSM) and non-CSL (non-FSM). The latter used to + // generate keys in 'StorageUtil::registerQueue'. + appKey.loadBinary(&appIdInfo.appKey()); - appIdInfos->push_back(appIdInfo); + appInfos->push_back(appIdInfo); } } else { @@ -1247,7 +1257,7 @@ void ClusterUtil::populateAppIdInfos( appIdInfo.appId() = bmqp::ProtocolUtil::k_DEFAULT_APP_ID; mqbi::QueueEngine::k_DEFAULT_APP_KEY.loadBinary(&appIdInfo.appKey()); - appIdInfos->push_back(appIdInfo); + appInfos->push_back(appIdInfo); } } @@ -1313,7 +1323,7 @@ void ClusterUtil::registerAppId(ClusterData* clusterData, mqbu::StorageKey::k_NULL_KEY.loadBinary((&queueUpdate.key())); queueUpdate.domain() = domain->name(); - // Populate AppIdInfo + // Populate AppInfo bmqp_ctrlmsg::AppIdInfo appIdInfo; appIdInfo.appId() = appId; mqbu::StorageKey::k_NULL_KEY.loadBinary(&appIdInfo.appKey()); @@ -1334,9 +1344,9 @@ void ClusterUtil::registerAppId(ClusterData* clusterData, BSLS_ASSERT_SAFE(queueUpdate.domain() == domain->name()); bsl::unordered_set appKeys; - const AppIdInfos& appIdInfos = qinfoCit->second->appIdInfos(); - for (AppIdInfosCIter appInfoCit = appIdInfos.cbegin(); - appInfoCit != appIdInfos.cend(); + const AppInfos& appInfos = qinfoCit->second->appInfos(); + for (AppInfosCIter appInfoCit = appInfos.cbegin(); + appInfoCit != appInfos.cend(); ++appInfoCit) { if (appInfoCit->first == appId) { BALL_LOG_ERROR << "Failed to register appId '" << appId @@ -1349,7 +1359,7 @@ void ClusterUtil::registerAppId(ClusterData* clusterData, appKeys.insert(appInfoCit->second); } - // Populate AppIdInfo + // Populate AppInfo bmqp_ctrlmsg::AppIdInfo appIdInfo; appIdInfo.appId() = appId; mqbu::StorageKey appKey; @@ -1441,7 +1451,7 @@ void ClusterUtil::unregisterAppId(ClusterData* clusterData, mqbu::StorageKey::k_NULL_KEY.loadBinary((&queueUpdate.key())); queueUpdate.domain() = domain->name(); - // Populate AppIdInfo + // Populate AppInfo bmqp_ctrlmsg::AppIdInfo appIdInfo; appIdInfo.appId() = appId; mqbu::StorageKey::k_NULL_KEY.loadBinary(&appIdInfo.appKey()); @@ -1462,12 +1472,12 @@ void ClusterUtil::unregisterAppId(ClusterData* clusterData, BSLS_ASSERT_SAFE(queueUpdate.domain() == domain->name()); bool appIdFound = false; - const AppIdInfos& appIdInfos = qinfoCit->second->appIdInfos(); - for (AppIdInfosCIter appInfoCit = appIdInfos.cbegin(); - appInfoCit != appIdInfos.cend(); + const AppInfos& appInfos = qinfoCit->second->appInfos(); + for (AppInfosCIter appInfoCit = appInfos.cbegin(); + appInfoCit != appInfos.cend(); ++appInfoCit) { if (appInfoCit->first == appId) { - // Populate AppIdInfo + // Populate AppInfo bmqp_ctrlmsg::AppIdInfo appIdInfo; appIdInfo.appId() = appId; appInfoCit->second.loadBinary(&appIdInfo.appKey()); @@ -1559,9 +1569,7 @@ void ClusterUtil::sendClusterState( &advisory.sequenceNumber()); advisory.partitions() = partitions; - loadQueuesInfo(&advisory.queues(), - clusterState, - clusterData->cluster().isCSLModeEnabled()); + loadQueuesInfo(&advisory.queues(), clusterState); } else if (sendPartitionPrimaryInfo) { bmqp_ctrlmsg::PartitionPrimaryAdvisory& advisory = @@ -1581,9 +1589,7 @@ void ClusterUtil::sendClusterState( clusterData->electorInfo().nextLeaderMessageSequence( &advisory.sequenceNumber()); - loadQueuesInfo(&advisory.queues(), - clusterState, - clusterData->cluster().isCSLModeEnabled()); + loadQueuesInfo(&advisory.queues(), clusterState); } if (!clusterData->cluster().isCSLModeEnabled()) { @@ -2190,8 +2196,7 @@ void ClusterUtil::loadPartitionsInfo( } void ClusterUtil::loadQueuesInfo(bsl::vector* out, - const ClusterState& state, - bool includeAppIds) + const ClusterState& state) { // PRECONDITIONS BSLS_ASSERT_SAFE(out); @@ -2212,17 +2217,14 @@ void ClusterUtil::loadQueuesInfo(bsl::vector* out, BSLS_ASSERT_SAFE(!qCit->second->key().isNull()); qCit->second->key().loadBinary(&queueInfo.key()); - if (includeAppIds) { - for (AppIdInfosCIter appIdCit = - qCit->second->appIdInfos().cbegin(); - appIdCit != qCit->second->appIdInfos().cend(); - ++appIdCit) { - bmqp_ctrlmsg::AppIdInfo appIdInfo; - appIdInfo.appId() = appIdCit->first; - appIdCit->second.loadBinary(&appIdInfo.appKey()); + for (AppInfosCIter appIdCit = qCit->second->appInfos().cbegin(); + appIdCit != qCit->second->appInfos().cend(); + ++appIdCit) { + bmqp_ctrlmsg::AppIdInfo appIdInfo; + appIdInfo.appId() = appIdCit->first; + appIdCit->second.loadBinary(&appIdInfo.appKey()); - queueInfo.appIds().push_back(appIdInfo); - } + queueInfo.appIds().push_back(appIdInfo); } out->push_back(queueInfo); @@ -2298,5 +2300,20 @@ int ClusterUtil::latestLedgerLSN(bmqp_ctrlmsg::LeaderMessageSequence* out, return rc_SUCCESS; } +void ClusterUtil::parseQueueInfo(mqbi::ClusterStateManager::AppInfos* out, + const bmqp_ctrlmsg::QueueInfo& queueInfo, + bslma::Allocator* allocator) +{ + for (bsl::vector::const_iterator cit = + queueInfo.appIds().cbegin(); + cit != queueInfo.appIds().cend(); + ++cit) { + out->emplace(mqbi::ClusterStateManager::AppInfo( + bsl::string(cit->appId(), allocator), + mqbu::StorageKey(mqbu::StorageKey::BinaryRepresentation(), + cit->appKey().data()))); + } +} + } // close package namespace } // close enterprise namespace diff --git a/src/groups/mqb/mqbc/mqbc_clusterutil.h b/src/groups/mqb/mqbc/mqbc_clusterutil.h index 5a54e8e49..970fdb3e0 100644 --- a/src/groups/mqb/mqbc/mqbc_clusterutil.h +++ b/src/groups/mqb/mqbc/mqbc_clusterutil.h @@ -88,9 +88,9 @@ struct ClusterUtil { public: // TYPES - typedef ClusterStateQueueInfo::AppIdInfo AppIdInfo; - typedef ClusterStateQueueInfo::AppIdInfos AppIdInfos; - typedef ClusterStateQueueInfo::AppIdInfosCIter AppIdInfosCIter; + typedef ClusterStateQueueInfo::AppInfo AppInfo; + typedef ClusterStateQueueInfo::AppInfos AppInfos; + typedef ClusterStateQueueInfo::AppInfosCIter AppInfosCIter; typedef mqbc::ClusterState::QueueInfoSp QueueInfoSp; typedef ClusterState::UriToQueueInfoMap UriToQueueInfoMap; @@ -270,17 +270,17 @@ struct ClusterUtil { const bmqt::Uri& uri, int partitionId, const mqbu::StorageKey& queueKey, - const AppIdInfos& appIdInfos, + const AppInfos& appIdInfos, const QueueAssigningCb& queueAssigningCb, bool forceUpdate); /// Generate appKeys based on the appIds in the specified `domainConfig` /// and populate them into the specified `appIdInfos`. - static void populateAppIdInfos(AppIdInfos* appIdInfos, - const mqbconfm::QueueMode& domainConfig); + static void populateAppInfos(AppInfos* appIdInfos, + const mqbconfm::QueueMode& domainConfig); static void - populateAppIdInfos(bsl::vector* appIdInfos, - const mqbconfm::QueueMode& domainConfig); + populateAppInfos(bsl::vector* appIdInfos, + const mqbconfm::QueueMode& domainConfig); /// Register the specified `appId` for all queues in the specified /// `domain`, using the specified `clusterData` and `clusterState`. @@ -392,8 +392,7 @@ struct ClusterUtil { /// `state`. If the specified `includeAppIds` is true, then the appId /// info for the queues will be loaded as well. static void loadQueuesInfo(bsl::vector* out, - const ClusterState& state, - bool includeAppIds); + const ClusterState& state); /// Load into the specified `out` the list of peer nodes using the /// specified `clusterData`. @@ -411,6 +410,12 @@ struct ClusterUtil { static int latestLedgerLSN(bmqp_ctrlmsg::LeaderMessageSequence* out, const ClusterStateLedger& ledger, const ClusterData& clusterData); + + /// Load into the specified `out` all `AppInfo` data from the specified + /// `queueInfo` using the specified `allocator`. + static void parseQueueInfo(mqbi::ClusterStateManager::AppInfos* out, + const bmqp_ctrlmsg::QueueInfo& queueInfo, + bslma::Allocator* allocator); }; // ============================================================================ diff --git a/src/groups/mqb/mqbc/mqbc_storagemanager.cpp b/src/groups/mqb/mqbc/mqbc_storagemanager.cpp index f7e4eefe7..d472aa809 100644 --- a/src/groups/mqb/mqbc/mqbc_storagemanager.cpp +++ b/src/groups/mqb/mqbc/mqbc_storagemanager.cpp @@ -3643,10 +3643,10 @@ void StorageManager::initializeQueueKeyInfoMap( mqbs::DataStoreConfigQueueInfo qinfo; qinfo.setCanonicalQueueUri(csQinfo.uri().asString()); qinfo.setPartitionId(csQinfo.partitionId()); - for (AppIdInfosCIter appIdCit = csQinfo.appIdInfos().cbegin(); - appIdCit != csQinfo.appIdInfos().cend(); + for (AppInfosCIter appIdCit = csQinfo.appInfos().cbegin(); + appIdCit != csQinfo.appInfos().cend(); ++appIdCit) { - qinfo.addAppIdKeyPair(*appIdCit); + qinfo.addAppInfo(*appIdCit); } d_queueKeyInfoMapVec.at(csQinfo.partitionId()) @@ -3657,11 +3657,12 @@ void StorageManager::initializeQueueKeyInfoMap( d_isQueueKeyInfoMapVecInitialized = true; } -void StorageManager::registerQueue(const bmqt::Uri& uri, - const mqbu::StorageKey& queueKey, - int partitionId, - const AppIdKeyPairs& appIdKeyPairs, - mqbi::Domain* domain) +void StorageManager::registerQueue( + const bmqt::Uri& uri, + const mqbu::StorageKey& queueKey, + int partitionId, + const bsl::unordered_set& appIdKeyPairs, + mqbi::Domain* domain) { // executed by the *CLUSTER DISPATCHER* thread @@ -3720,8 +3721,8 @@ void StorageManager::unregisterQueue(const bmqt::Uri& uri, int partitionId) int StorageManager::updateQueuePrimary(const bmqt::Uri& uri, const mqbu::StorageKey& queueKey, int partitionId, - const AppIdKeyPairs& addedIdKeyPairs, - const AppIdKeyPairs& removedIdKeyPairs) + const AppInfos& addedIdKeyPairs, + const AppInfos& removedIdKeyPairs) { // executed by *QUEUE_DISPATCHER* thread with the specified 'partitionId' @@ -3819,7 +3820,7 @@ void StorageManager::unregisterQueueReplica(int partitionId, void StorageManager::updateQueueReplica(int partitionId, const bmqt::Uri& uri, const mqbu::StorageKey& queueKey, - const AppIdKeyPairs& appIdKeyPairs, + const AppInfos& appIdKeyPairs, mqbi::Domain* domain, bool allowDuplicate) { diff --git a/src/groups/mqb/mqbc/mqbc_storagemanager.h b/src/groups/mqb/mqbc/mqbc_storagemanager.h index 25cfbd166..7fea414f3 100644 --- a/src/groups/mqb/mqbc/mqbc_storagemanager.h +++ b/src/groups/mqb/mqbc/mqbc_storagemanager.h @@ -155,7 +155,7 @@ class StorageManager typedef ClusterState::DomainStatesCIter DomainStatesCIter; typedef ClusterState::UriToQueueInfoMapCIter UriToQueueInfoMapCIter; - typedef ClusterStateQueueInfo::AppIdInfosCIter AppIdInfosCIter; + typedef ClusterStateQueueInfo::AppInfosCIter AppInfosCIter; /// Vector of pairs of buffered primary status advisories and their source typedef bsl::vector< @@ -853,11 +853,12 @@ class StorageManager /// associated queue storage created. /// /// THREAD: Executed by the Client's dispatcher thread. - virtual void registerQueue(const bmqt::Uri& uri, - const mqbu::StorageKey& queueKey, - int partitionId, - const AppIdKeyPairs& appIdKeyPairs, - mqbi::Domain* domain) BSLS_KEYWORD_OVERRIDE; + virtual void + registerQueue(const bmqt::Uri& uri, + const mqbu::StorageKey& queueKey, + int partitionId, + const bsl::unordered_set& appIdKeyPairs, + mqbi::Domain* domain) BSLS_KEYWORD_OVERRIDE; /// Synchronously unregister the queue with the specified `uri` from the /// specified `partitionId`. @@ -878,8 +879,8 @@ class StorageManager virtual int updateQueuePrimary(const bmqt::Uri& uri, const mqbu::StorageKey& queueKey, int partitionId, - const AppIdKeyPairs& addedIdKeyPairs, - const AppIdKeyPairs& removedIdKeyPairs) + const AppInfos& addedIdKeyPairs, + const AppInfos& removedIdKeyPairs) BSLS_KEYWORD_OVERRIDE; virtual void @@ -899,7 +900,7 @@ class StorageManager updateQueueReplica(int partitionId, const bmqt::Uri& uri, const mqbu::StorageKey& queueKey, - const AppIdKeyPairs& appIdKeyPairs, + const AppInfos& appIdKeyPairs, mqbi::Domain* domain = 0, bool allowDuplicate = false) BSLS_KEYWORD_OVERRIDE; diff --git a/src/groups/mqb/mqbc/mqbc_storagemanager.t.cpp b/src/groups/mqb/mqbc/mqbc_storagemanager.t.cpp index cb2055070..94916c3e4 100644 --- a/src/groups/mqb/mqbc/mqbc_storagemanager.t.cpp +++ b/src/groups/mqb/mqbc/mqbc_storagemanager.t.cpp @@ -767,14 +767,14 @@ struct TestHelper { handle, uri_t, rec.d_queueKey, - mqbs::DataStore::AppIdKeyPairs(), + mqbs::DataStore::AppInfos(), rec.d_timestamp, true); // isNewQueue d_cluster_mp->_state().assignQueue(uri_t, queueKey, partitionId, - mqbc::ClusterState::AppIdInfos()); + mqbc::ClusterState::AppInfos()); BSLS_ASSERT_OPT(rc == 0); return queueKey; diff --git a/src/groups/mqb/mqbc/mqbc_storageutil.cpp b/src/groups/mqb/mqbc/mqbc_storageutil.cpp index 21a3bf7a2..3bae89492 100644 --- a/src/groups/mqb/mqbc/mqbc_storageutil.cpp +++ b/src/groups/mqb/mqbc/mqbc_storageutil.cpp @@ -60,30 +60,6 @@ namespace mqbc { namespace { -/// Unary predicate used in certain `find` algorithms to match an element -/// having the specified AppId. -class AppIdMatcher { - private: - // TYPES - typedef bsl::pair AppIdKeyPair; - - // DATA - const bsl::string& d_expectedAppId; - - public: - // CREATORS - AppIdMatcher(const bsl::string& expectedAppId) - : d_expectedAppId(expectedAppId) - { - } - - // ACCESSORS - bool operator()(const AppIdKeyPair& appIdKeyPair) const - { - return d_expectedAppId == appIdKeyPair.first; - } -}; - /// Post on the optionally specified `semaphore`. void optionalSemaphorePost(bslmt::Semaphore* semaphore) { @@ -99,27 +75,17 @@ void optionalSemaphorePost(bslmt::Semaphore* semaphore) // ------------------ // PRIVATE FUNCTIONS -bool StorageUtil::loadUpdatedAppIdKeyPairs( - AppIdKeyPairs* addedAppIdKeyPairs, - AppIdKeyPairs* removedAppIdKeyPairs, - AppKeys* appKeys, - bslmt::Mutex* appKeysLock, - const mqbs::ReplicatedStorage& storage, - const AppIdKeyPairs& newAppIdKeyPairs, - const bsl::vector& cfgAppIds, - bool isCSLMode) +bool StorageUtil::loadUpdatedAppInfos(AppInfos* addedAppInfos, + AppInfos* removedAppInfos, + const mqbs::ReplicatedStorage& storage, + const AppInfos& newAppInfos) { // executed by the *CLUSTER DISPATCHER* thread // PRECONDITIONS - BSLS_ASSERT_SAFE(addedAppIdKeyPairs); - BSLS_ASSERT_SAFE(removedAppIdKeyPairs); - if (isCSLMode) { - BSLS_ASSERT_SAFE(cfgAppIds.empty()); - } - else { - BSLS_ASSERT_SAFE(newAppIdKeyPairs.empty()); - } + BSLS_ASSERT_SAFE(addedAppInfos); + BSLS_ASSERT_SAFE(removedAppInfos); + BSLS_ASSERT_SAFE(!newAppInfos.empty()); // This function is invoked by 'StorageManager::registerQueue' if the queue // with specified 'storage' is in fanout mode, in order to add or remove @@ -135,58 +101,17 @@ bool StorageUtil::loadUpdatedAppIdKeyPairs( // list of newly added and removed appIds, and then invoking 'updateQueue' // in the appropriate thread. - AppIdKeyPairs existingAppIdKeyPairs; - storage.loadVirtualStorageDetails(&existingAppIdKeyPairs); - - if (isCSLMode) { - loadAddedAndRemovedEntries(addedAppIdKeyPairs, - removedAppIdKeyPairs, - existingAppIdKeyPairs, - newAppIdKeyPairs); - - if (addedAppIdKeyPairs->empty() && removedAppIdKeyPairs->empty()) { - // No appIds to add or remove. - return false; // RETURN - } - } - else { - bsl::vector existingAppIds; - for (size_t i = 0; i < existingAppIdKeyPairs.size(); ++i) { - existingAppIds.push_back(existingAppIdKeyPairs[i].first); - } - - bsl::vector addedAppIds; - bsl::vector removedAppIds; - loadAddedAndRemovedEntries(&addedAppIds, - &removedAppIds, - existingAppIds, - cfgAppIds); - - if (addedAppIds.empty() && removedAppIds.empty()) { - // No appIds to add or remove. - return false; // RETURN - } + AppInfos existingAppInfos; + storage.loadVirtualStorageDetails(&existingAppInfos); - // Generate unique appKeys for the added appIds, and populate - // 'addedAppIdKeyPairs'. - for (size_t i = 0; i < addedAppIds.size(); ++i) { - mqbu::StorageKey appKey = generateAppKey(appKeys, - appKeysLock, - addedAppIds[i]); - addedAppIdKeyPairs->push_back( - bsl::make_pair(addedAppIds[i], appKey)); - } + loadAddedAndRemovedEntries(addedAppInfos, + removedAppInfos, + existingAppInfos, + newAppInfos); - // Populate 'removedAppIdKeyPairs'. - for (size_t i = 0; i < removedAppIds.size(); ++i) { - AppIdKeyPairsCIter it = bsl::find_if( - existingAppIdKeyPairs.begin(), - existingAppIdKeyPairs.end(), - AppIdMatcher(removedAppIds[i])); - BSLS_ASSERT_SAFE(it != existingAppIdKeyPairs.end()); - removedAppIdKeyPairs->push_back( - bsl::make_pair(it->first, it->second)); - } + if (addedAppInfos->empty() && removedAppInfos->empty()) { + // No appIds to add or remove. + return false; // RETURN } return true; @@ -196,9 +121,9 @@ void StorageUtil::registerQueueDispatched( BSLS_ANNOTATION_UNUSED const mqbi::Dispatcher::ProcessorHandle& processor, mqbs::FileStore* fs, mqbs::ReplicatedStorage* storage, - const bsl::string& clusterDescription, - int partitionId, - const AppIdKeyPairs& appIdKeyPairs) + const bsl::string& clusterDescription, + int partitionId, + const AppInfos& appIdKeyPairs) { // executed by *QUEUE_DISPATCHER* thread with the specified 'partitionId' @@ -255,16 +180,16 @@ void StorageUtil::registerQueueDispatched( void StorageUtil::updateQueuePrimaryDispatched( BSLS_ANNOTATION_UNUSED const mqbi::Dispatcher::ProcessorHandle& processor, mqbs::ReplicatedStorage* storage, - bslmt::Mutex* storagesLock, - mqbs::FileStore* fs, - AppKeys* appKeys, - bslmt::Mutex* appKeysLock, - const bsl::string& clusterDescription, - int partitionId, - const AppIdKeyPairs& addedIdKeyPairs, - const AppIdKeyPairs& removedIdKeyPairs, - bool isFanout, - bool isCSLMode) + bslmt::Mutex* storagesLock, + mqbs::FileStore* fs, + AppKeys* appKeys, + bslmt::Mutex* appKeysLock, + const bsl::string& clusterDescription, + int partitionId, + const AppInfos& addedIdKeyPairs, + const AppInfos& removedIdKeyPairs, + bool isFanout, + bool isCSLMode) { // executed by *QUEUE_DISPATCHER* thread with the specified 'partitionId' @@ -293,12 +218,12 @@ int StorageUtil::updateQueuePrimaryRaw(mqbs::ReplicatedStorage* storage, mqbs::FileStore* fs, AppKeys* appKeys, bslmt::Mutex* appKeysLock, - const bsl::string& clusterDescription, - int partitionId, - const AppIdKeyPairs& addedIdKeyPairs, - const AppIdKeyPairs& removedIdKeyPairs, - bool isFanout, - bool isCSLMode) + const bsl::string& clusterDescription, + int partitionId, + const AppInfos& addedIdKeyPairs, + const AppInfos& removedIdKeyPairs, + bool isFanout, + bool isCSLMode) { // executed by *QUEUE_DISPATCHER* thread with the specified 'partitionId' @@ -352,7 +277,7 @@ int StorageUtil::updateQueuePrimaryRaw(mqbs::ReplicatedStorage* storage, BALL_LOG_INFO_BLOCK { - bmqu::Printer printer(&addedIdKeyPairs); + bmqu::Printer printer(&addedIdKeyPairs); BALL_LOG_OUTPUT_STREAM << clusterDescription << ": Partition [" << partitionId @@ -364,7 +289,7 @@ int StorageUtil::updateQueuePrimaryRaw(mqbs::ReplicatedStorage* storage, } if (!removedIdKeyPairs.empty()) { - for (AppIdKeyPairsCIter cit = removedIdKeyPairs.begin(); + for (AppInfosCIter cit = removedIdKeyPairs.begin(); cit != removedIdKeyPairs.end(); ++cit) { // Write QueueDeletionRecord to data store for removed appIds. @@ -409,7 +334,7 @@ int StorageUtil::updateQueuePrimaryRaw(mqbs::ReplicatedStorage* storage, BALL_LOG_INFO_BLOCK { - bmqu::Printer printer(&removedIdKeyPairs); + bmqu::Printer printer(&removedIdKeyPairs); BALL_LOG_OUTPUT_STREAM << clusterDescription << ": Partition [" << partitionId @@ -424,8 +349,8 @@ int StorageUtil::updateQueuePrimaryRaw(mqbs::ReplicatedStorage* storage, // away. fs->dispatcherFlush(true, false); - bmqu::Printer printer1(&addedIdKeyPairs); - bmqu::Printer printer2(&removedIdKeyPairs); + bmqu::Printer printer1(&addedIdKeyPairs); + bmqu::Printer printer2(&removedIdKeyPairs); BALL_LOG_INFO << clusterDescription << ": Partition [" << partitionId << "] updated [" << storage->queueUri() << "], queueKey [" << storage->queueKey() << "] with the storage as primary: " @@ -439,7 +364,7 @@ int StorageUtil::addVirtualStoragesInternal( mqbs::ReplicatedStorage* storage, AppKeys* appKeys, bslmt::Mutex* appKeysLock, - const AppIdKeyPairs& appIdKeyPairs, + const AppInfos& appIdKeyPairs, const bsl::string& clusterDescription, int partitionId, bool isFanout, @@ -466,7 +391,7 @@ int StorageUtil::addVirtualStoragesInternal( // Register appKeys with 'appKeys' and then with the underlying // physical 'storage'. - for (AppIdKeyPairsCIter cit = appIdKeyPairs.begin(); + for (AppInfosCIter cit = appIdKeyPairs.begin(); cit != appIdKeyPairs.end(); ++cit) { AppKeysInsertRc irc = appKeys->insert(cit->second); @@ -1524,13 +1449,15 @@ void StorageUtil::recoveredQueuesCb( } if (qinfo.appIdKeyPairs().size() != 1 || - qinfo.appIdKeyPairs()[0].first != + qinfo.appIdKeyPairs().cbegin()->first != bmqp::ProtocolUtil::k_DEFAULT_APP_ID) { - // This ia a fanout queue + // This is a fanout queue AppIds appIds; - for (size_t n = 0; n < qinfo.appIdKeyPairs().size(); ++n) { - const AppIdKeyPair& p = qinfo.appIdKeyPairs()[n]; + for (AppInfos::const_iterator cit = qinfo.appIdKeyPairs().cbegin(); + cit != qinfo.appIdKeyPairs().cend(); + ++cit) { + const AppInfo& p = *cit; AppIdsInsertRc appIdsIrc = appIds.insert(p.first); if (false == appIdsIrc.second) { @@ -1662,7 +1589,7 @@ void StorageUtil::recoveredQueuesCb( ++qit) { const mqbu::StorageKey& queueKey = qit->first; const mqbs::DataStoreConfigQueueInfo& qinfo = qit->second; - const AppIdKeyPairs& appIdKeyPairs = qinfo.appIdKeyPairs(); + const AppInfos& appIdKeyPairs = qinfo.appIdKeyPairs(); const bmqt::Uri queueUri(qinfo.canonicalQueueUri()); BSLS_ASSERT_SAFE(queueUri.isValid()); @@ -1696,7 +1623,7 @@ void StorageUtil::recoveredQueuesCb( BSLS_ASSERT_SAFE(queueKey == rstorage->queueKey()); BSLS_ASSERT_SAFE(partitionId == rstorage->partitionId()); - for (AppIdKeyPairsCIter ait = appIdKeyPairs.begin(); + for (AppInfosCIter ait = appIdKeyPairs.begin(); ait != appIdKeyPairs.end(); ++ait) { BSLA_MAYBE_UNUSED const bsl::string& appId = ait->first; @@ -1830,7 +1757,7 @@ void StorageUtil::recoveredQueuesCb( bmqu::MemOutStream errorDesc; int rc; if (domain->config().mode().isFanoutValue()) { - for (AppIdKeyPairsCIter ait = appIdKeyPairs.begin(); + for (AppInfosCIter ait = appIdKeyPairs.begin(); ait != appIdKeyPairs.end(); ++ait) { const bsl::string& appId = ait->first; @@ -2338,7 +2265,7 @@ void StorageUtil::registerQueue( const mqbu::StorageKey& queueKey, const bsl::string& clusterDescription, int partitionId, - const AppIdKeyPairs& appIdKeyPairs, + const AppInfos& appIdKeyPairs, mqbi::Domain* domain) { // executed by the *CLUSTER DISPATCHER* thread @@ -2357,9 +2284,6 @@ void StorageUtil::registerQueue( partitionId < cluster->clusterConfig()->partitionConfig().numPartitions()); BSLS_ASSERT_SAFE(domain); - if (!cluster->isCSLModeEnabled()) { - BSLS_ASSERT_SAFE(appIdKeyPairs.empty()); - } // StorageMgr is either aware of the queue (the 'uri') or it isn't. If it // is already aware, either this queue was registered earlier or it was @@ -2374,7 +2298,7 @@ void StorageUtil::registerQueue( // and deployed before the node started (some appIds were added or removed // or both). We need to make sure that these appIds are handled correctly. // The logic to get a list of added and/or removed appId/key pairs is - // handled by invoking 'loadUpdatedAppIdKeyPairs' in this function if queue + // handled by invoking 'loadUpdatedAppInfos' in this function if queue // is in fanout mode. // If StorageMgr is not aware of the queue, then its a simpler process -- @@ -2438,34 +2362,12 @@ void StorageUtil::registerQueue( // to be added or removed (see comments at the beginning of this // routine for explanation). - AppIdKeyPairs addedAppIdKeyPairs, removedAppIdKeyPairs; + AppInfos addedAppInfos, removedAppInfos; - bool hasUpdate = false; - if (cluster->isCSLModeEnabled()) { - // In CSL mode, queue assignment procedure is split into queue - // assignment and queue update, so we simply remove all appIds - // here, and re-add them during queue update phase. - hasUpdate = loadUpdatedAppIdKeyPairs( - &addedAppIdKeyPairs, - &removedAppIdKeyPairs, - appKeys, - appKeysLock, - *storageSp.get(), - appIdKeyPairs, - bsl::vector(), - true); // isCSLMode - } - else { - hasUpdate = loadUpdatedAppIdKeyPairs( - &addedAppIdKeyPairs, - &removedAppIdKeyPairs, - appKeys, - appKeysLock, - *storageSp.get(), - AppIdKeyPairs(), - queueMode.fanout().appIDs(), - false); // isCSLMode - } + bool hasUpdate = loadUpdatedAppInfos(&addedAppInfos, + &removedAppInfos, + *storageSp.get(), + appIdKeyPairs); if (!hasUpdate) { // No update needed for AppId/Key pairs. return; // RETURN @@ -2490,8 +2392,8 @@ void StorageUtil::registerQueue( appKeysLock, clusterDescription, partitionId, - addedAppIdKeyPairs, - removedAppIdKeyPairs, + addedAppInfos, + removedAppInfos, domain->config().mode().isFanoutValue(), cluster->isCSLModeEnabled())); @@ -2501,7 +2403,7 @@ void StorageUtil::registerQueue( // Wait for 'updateQueuePrimaryDispatched' operation to complete. // We need to wait because 'updateQueuePrimaryDispatched' creates - // virtual storages corresponding to 'addedAppIdKeyPairs' (if any), + // virtual storages corresponding to 'addedAppInfos' (if any), // and the caller of 'registerQueue' expects these virtual storages // to be created this routine or its caller returns. Before // waiting, release the 'storagesLock' guard and unlock it to avoid @@ -2535,10 +2437,10 @@ void StorageUtil::registerQueue( bmqu::MemOutStream errorDesc; int rc = 0; - AppIdKeyPairs appIdKeyPairsToUse; + AppInfos appIdKeyPairsToUse; if (queueMode.isFanoutValue()) { - if (cluster->isCSLModeEnabled()) { - for (AppIdKeyPairsCIter citer = appIdKeyPairs.begin(); + if (cluster->isCSLModeEnabled() || !appIdKeyPairs.empty()) { + for (AppInfosCIter citer = appIdKeyPairs.begin(); citer != appIdKeyPairs.end(); ++citer) { rc = storageSp->addVirtualStorage(errorDesc, @@ -2566,7 +2468,7 @@ void StorageUtil::registerQueue( rc = storageSp->addVirtualStorage(errorDesc, *citer, appKey); - appIdKeyPairsToUse.push_back(bsl::make_pair(*citer, appKey)); + appIdKeyPairsToUse.emplace(bsl::make_pair(*citer, appKey)); } } } @@ -2762,8 +2664,8 @@ int StorageUtil::updateQueuePrimary(StorageSpMap* storageMap, const bmqt::Uri& uri, const mqbu::StorageKey& queueKey, int partitionId, - const AppIdKeyPairs& addedIdKeyPairs, - const AppIdKeyPairs& removedIdKeyPairs, + const AppInfos& addedIdKeyPairs, + const AppInfos& removedIdKeyPairs, bool isCSLMode) { // executed by *QUEUE_DISPATCHER* thread with the specified 'partitionId' @@ -2783,8 +2685,8 @@ int StorageUtil::updateQueuePrimary(StorageSpMap* storageMap, StorageSpMapIter it = storageMap->find(uri); if (storageMap->end() == it) { - bmqu::Printer printer1(&addedIdKeyPairs); - bmqu::Printer printer2(&removedIdKeyPairs); + bmqu::Printer printer1(&addedIdKeyPairs); + bmqu::Printer printer2(&removedIdKeyPairs); BALL_LOG_ERROR << clusterDescription << " Partition [" << partitionId << "]: Error when updating queue '" << uri << "' with addedAppIds: [" << printer1 @@ -3134,7 +3036,7 @@ void StorageUtil::updateQueueReplicaDispatched( int partitionId, const bmqt::Uri& uri, const mqbu::StorageKey& queueKey, - const AppIdKeyPairs& appIdKeyPairs, + const AppInfos& appIdKeyPairs, bool isCSLMode, mqbi::Domain* domain, bool allowDuplicate) @@ -3166,7 +3068,7 @@ void StorageUtil::updateQueueReplicaDispatched( if (it == storageMap->end()) { // Cluster state and/or partition are out of sync at this replica. - bmqu::Printer printer(&appIdKeyPairs); + bmqu::Printer printer(&appIdKeyPairs); BMQTSK_ALARMLOG_ALARM("REPLICATION") << "At partition [" << partitionId << "], failure while registering appIds [" << printer @@ -3198,7 +3100,7 @@ void StorageUtil::updateQueueReplicaDispatched( isCSLMode); if (rc != 0) { if (!allowDuplicate) { - bmqu::Printer printer(&appIdKeyPairs); + bmqu::Printer printer(&appIdKeyPairs); BMQTSK_ALARMLOG_ALARM("REPLICATION") << "At partition [" << partitionId << "], failure while registering appIds [" << printer @@ -3213,7 +3115,7 @@ void StorageUtil::updateQueueReplicaDispatched( return; // RETURN } - bmqu::Printer printer(&appIdKeyPairs); + bmqu::Printer printer(&appIdKeyPairs); BALL_LOG_INFO << clusterDescription << ": Partition [" << partitionId << "] updated [" << uri << "], queueKey [" << queueKey << "] with the storage as replica: " << "addedIdKeyPairs:" diff --git a/src/groups/mqb/mqbc/mqbc_storageutil.h b/src/groups/mqb/mqbc/mqbc_storageutil.h index 8db21fcfb..3f6e6cfe4 100644 --- a/src/groups/mqb/mqbc/mqbc_storageutil.h +++ b/src/groups/mqb/mqbc/mqbc_storageutil.h @@ -101,9 +101,9 @@ struct StorageUtil { private: // TYPES - typedef mqbi::StorageManager::AppIdKeyPair AppIdKeyPair; - typedef mqbi::StorageManager::AppIdKeyPairs AppIdKeyPairs; - typedef mqbi::StorageManager::AppIdKeyPairsCIter AppIdKeyPairsCIter; + typedef mqbi::StorageManager::AppInfo AppInfo; + typedef mqbi::StorageManager::AppInfos AppInfos; + typedef mqbi::StorageManager::AppInfosCIter AppInfosCIter; typedef mqbi::StorageManager::AppIds AppIds; typedef mqbi::StorageManager::AppIdsIter AppIdsIter; @@ -177,38 +177,33 @@ struct StorageUtil { /// Load into the specified `result` the list of elements present in /// `baseSet` which are not present in `subtractionSet`. template - static void loadDifference(bsl::vector* result, - const bsl::vector& baseSet, - const bsl::vector& subtractionSet); + static void loadDifference(bsl::unordered_set* result, + const bsl::unordered_set& baseSet, + const bsl::unordered_set& subtractionSet); - /// Load into the specified `addedAppIdKeyPairs` and - /// `removedAppIdKeyPairs` the appId/key pairs which have been added and + /// Load into the specified `addedAppInfos` and + /// `removedAppInfos` the appId/key pairs which have been added and /// removed respectively for the specified `storage` based on the - /// specified `newAppIdKeyPairs` or `cfgAppIds`, as well as the + /// specified `newAppInfos` or `cfgAppIds`, as well as the /// specified `isCSLMode` mode. If new app keys are generated, load /// them into the specified `appKeys`. If the optionally specified /// `appKeysLock` is provided, lock it. Return true if there are any /// added or removed appId/key pairs, false otherwise. /// /// THREAD: Executed by the cluster dispatcher thread. - static bool - loadUpdatedAppIdKeyPairs(AppIdKeyPairs* addedAppIdKeyPairs, - AppIdKeyPairs* removedAppIdKeyPairs, - AppKeys* appKeys, - bslmt::Mutex* appKeysLock, - const mqbs::ReplicatedStorage& storage, - const AppIdKeyPairs& newAppIdKeyPairs, - const bsl::vector& cfgAppIds, - bool isCSLMode); + static bool loadUpdatedAppInfos(AppInfos* addedAppInfos, + AppInfos* removedAppInfos, + const mqbs::ReplicatedStorage& storage, + const AppInfos& newAppInfos); /// THREAD: Executed by the Queue's dispatcher thread. static void registerQueueDispatched(const mqbi::Dispatcher::ProcessorHandle& processor, mqbs::FileStore* fs, mqbs::ReplicatedStorage* storage, - const bsl::string& clusterDescription, - int partitionId, - const AppIdKeyPairs& appIdKeyPairs); + const bsl::string& clusterDescription, + int partitionId, + const AppInfos& appIdKeyPairs); /// THREAD: This method is called from the Queue's dispatcher thread. static void updateQueuePrimaryDispatched( @@ -220,8 +215,8 @@ struct StorageUtil { bslmt::Mutex* appKeysLock, const bsl::string& clusterDescription, int partitionId, - const AppIdKeyPairs& addedIdKeyPairs, - const AppIdKeyPairs& removedIdKeyPairs, + const AppInfos& addedIdKeyPairs, + const AppInfos& removedIdKeyPairs, bool isFanout, bool isCSLMode); @@ -233,18 +228,18 @@ struct StorageUtil { mqbs::FileStore* fs, AppKeys* appKeys, bslmt::Mutex* appKeysLock, - const bsl::string& clusterDescription, - int partitionId, - const AppIdKeyPairs& addedIdKeyPairs, - const AppIdKeyPairs& removedIdKeyPairs, - bool isFanout, - bool isCSLMode); + const bsl::string& clusterDescription, + int partitionId, + const AppInfos& addedIdKeyPairs, + const AppInfos& removedIdKeyPairs, + bool isFanout, + bool isCSLMode); static int addVirtualStoragesInternal(mqbs::ReplicatedStorage* storage, AppKeys* appKeys, bslmt::Mutex* appKeysLock, - const AppIdKeyPairs& appIdKeyPairs, + const AppInfos& appIdKeyPairs, const bsl::string& clusterDescription, int partitionId, bool isFanout, @@ -387,10 +382,10 @@ struct StorageUtil { /// present in `existingEntries` but not in `newEntries`. template static void - loadAddedAndRemovedEntries(bsl::vector* addedEntries, - bsl::vector* removedEntries, - const bsl::vector& existingEntries, - const bsl::vector& newEntries); + loadAddedAndRemovedEntries(bsl::unordered_set* addedEntries, + bsl::unordered_set* removedEntries, + const bsl::unordered_set& existingEntries, + const bsl::unordered_set& newEntries); /// Return true if the queue having specified `uri` and assigned to the /// specified `partitionId` has no messages in the specified @@ -639,7 +634,7 @@ struct StorageUtil { const mqbu::StorageKey& queueKey, const bsl::string& clusterDescription, int partitionId, - const AppIdKeyPairs& appIdKeyPairs, + const AppInfos& appIdKeyPairs, mqbi::Domain* domain); /// THREAD: Executed by the Queue's dispatcher thread. @@ -671,8 +666,8 @@ struct StorageUtil { const bmqt::Uri& uri, const mqbu::StorageKey& queueKey, int partitionId, - const AppIdKeyPairs& addedIdKeyPairs, - const AppIdKeyPairs& removedIdKeyPairs, + const AppInfos& addedIdKeyPairs, + const AppInfos& removedIdKeyPairs, bool isCSLMode); static void @@ -714,7 +709,7 @@ struct StorageUtil { int partitionId, const bmqt::Uri& uri, const mqbu::StorageKey& queueKey, - const AppIdKeyPairs& addedIdKeyPairs, + const AppInfos& addedIdKeyPairs, bool isCSLMode, mqbi::Domain* domain = 0, bool allowDuplicate = false); @@ -822,29 +817,28 @@ unsigned int StorageUtil::extractPartitionId(const bmqp::Event& event); // ------------------ template -void StorageUtil::loadDifference(bsl::vector* result, - const bsl::vector& baseSet, - const bsl::vector& subtractionSet) +void StorageUtil::loadDifference(bsl::unordered_set* result, + const bsl::unordered_set& baseSet, + const bsl::unordered_set& subtractionSet) { // PRECONDITIONS BSLS_ASSERT_SAFE(result); - typedef typename bsl::vector::const_iterator CIter; + typedef typename bsl::unordered_set::const_iterator CIter; - for (CIter it = baseSet.begin(); it != baseSet.end(); ++it) { - if (subtractionSet.end() == - bsl::find(subtractionSet.begin(), subtractionSet.end(), *it)) { - result->push_back(*it); + for (CIter it = baseSet.cbegin(); it != baseSet.cend(); ++it) { + if (subtractionSet.end() == subtractionSet.find(*it)) { + result->emplace(*it); } } } template void StorageUtil::loadAddedAndRemovedEntries( - bsl::vector* addedEntries, - bsl::vector* removedEntries, - const bsl::vector& existingEntries, - const bsl::vector& newEntries) + bsl::unordered_set* addedEntries, + bsl::unordered_set* removedEntries, + const bsl::unordered_set& existingEntries, + const bsl::unordered_set& newEntries) { // PRECONDITIONS BSLS_ASSERT_SAFE(addedEntries); diff --git a/src/groups/mqb/mqbi/mqbi_clusterstatemanager.h b/src/groups/mqb/mqbi/mqbi_clusterstatemanager.h index 886589775..fa754df9c 100644 --- a/src/groups/mqb/mqbi/mqbi_clusterstatemanager.h +++ b/src/groups/mqb/mqbi/mqbi_clusterstatemanager.h @@ -102,9 +102,9 @@ class ClusterStateManager { AfterPartitionPrimaryAssignmentCb; /// Pair of (appId, appKey) - typedef bsl::pair AppIdInfo; - typedef bsl::unordered_set AppIdInfos; - typedef AppIdInfos::const_iterator AppIdInfosCIter; + typedef bsl::pair AppInfo; + typedef bsl::unordered_set AppInfos; + typedef AppInfos::const_iterator AppInfosCIter; struct QueueAssignmentResult { enum Enum { @@ -226,7 +226,7 @@ class ClusterStateManager { virtual void registerQueueInfo(const bmqt::Uri& uri, int partitionId, const mqbu::StorageKey& queueKey, - const AppIdInfos& appIdInfos, + const AppInfos& appIdInfos, bool forceUpdate) = 0; /// Unassign the queue in the specified `advisory` by applying the diff --git a/src/groups/mqb/mqbi/mqbi_queueengine.cpp b/src/groups/mqb/mqbi/mqbi_queueengine.cpp index 582956c6b..b26c4a293 100644 --- a/src/groups/mqb/mqbi/mqbi_queueengine.cpp +++ b/src/groups/mqb/mqbi/mqbi_queueengine.cpp @@ -36,13 +36,13 @@ QueueEngine::~QueueEngine() } void QueueEngine::afterAppIdRegistered( - BSLS_ANNOTATION_UNUSED const mqbi::Storage::AppIdKeyPair& appIdKeyPair) + BSLS_ANNOTATION_UNUSED const mqbi::Storage::AppInfo& appIdKeyPair) { // NOTHING } void QueueEngine::afterAppIdUnregistered( - BSLS_ANNOTATION_UNUSED const mqbi::Storage::AppIdKeyPair& appIdKeyPair) + BSLS_ANNOTATION_UNUSED const mqbi::Storage::AppInfo& appIdKeyPair) { // NOTHING } diff --git a/src/groups/mqb/mqbi/mqbi_queueengine.h b/src/groups/mqb/mqbi/mqbi_queueengine.h index cf6f27195..14a77e13a 100644 --- a/src/groups/mqb/mqbi/mqbi_queueengine.h +++ b/src/groups/mqb/mqbi/mqbi_queueengine.h @@ -198,14 +198,14 @@ class QueueEngine { /// /// THREAD: This method is called from the Queue's dispatcher thread. virtual void - afterAppIdRegistered(const mqbi::Storage::AppIdKeyPair& appIdKeyPair); + afterAppIdRegistered(const mqbi::Storage::AppInfo& appIdKeyPair); /// Called after the specified `appIdKeyPair` has been dynamically /// unregistered. /// /// THREAD: This method is called from the Queue's dispatcher thread. virtual void - afterAppIdUnregistered(const mqbi::Storage::AppIdKeyPair& appIdKeyPair); + afterAppIdUnregistered(const mqbi::Storage::AppInfo& appIdKeyPair); /// Called after creation of a new storage for the specified /// `appIdKeyPair`. diff --git a/src/groups/mqb/mqbi/mqbi_storage.h b/src/groups/mqb/mqbi/mqbi_storage.h index b05a42aa5..08b95c609 100644 --- a/src/groups/mqb/mqbi/mqbi_storage.h +++ b/src/groups/mqb/mqbi/mqbi_storage.h @@ -375,12 +375,12 @@ class Storage { public: // PUBLIC TYPES - /// `AppIdKeyPair` is an alias for an (appId, appKey) pairing + /// `AppInfo` is an alias for an (appId, appKey) pairing /// representing unique virtual storage identification. - typedef bsl::pair AppIdKeyPair; + typedef bsl::pair AppInfo; - /// `AppIdKeyPairs` is an alias for a list of pairs of appId and appKey - typedef bsl::vector AppIdKeyPairs; + /// `AppInfos` is an alias for a set of pairs of appId and appKey + typedef bsl::unordered_set AppInfos; typedef bmqc::Array @@ -648,7 +648,7 @@ class Storage { /// Load into the specified `buffer` the list of pairs of appId and /// appKey for all the virtual storages registered with this instance. - virtual void loadVirtualStorageDetails(AppIdKeyPairs* buffer) const = 0; + virtual void loadVirtualStorageDetails(AppInfos* buffer) const = 0; /// Return the number of auto confirmed Apps for the current message. virtual unsigned int numAutoConfirms() const = 0; diff --git a/src/groups/mqb/mqbi/mqbi_storagemanager.h b/src/groups/mqb/mqbi/mqbi_storagemanager.h index a157f66dc..e0397e582 100644 --- a/src/groups/mqb/mqbi/mqbi_storagemanager.h +++ b/src/groups/mqb/mqbi/mqbi_storagemanager.h @@ -168,9 +168,9 @@ class StorageManagerIterator { class StorageManager : public mqbi::AppKeyGenerator { public: // TYPES - typedef mqbi::Storage::AppIdKeyPair AppIdKeyPair; - typedef mqbi::Storage::AppIdKeyPairs AppIdKeyPairs; - typedef AppIdKeyPairs::const_iterator AppIdKeyPairsCIter; + typedef mqbi::Storage::AppInfo AppInfo; + typedef mqbi::Storage::AppInfos AppInfos; + typedef AppInfos::const_iterator AppInfosCIter; typedef bsl::unordered_set AppIds; typedef AppIds::iterator AppIdsIter; @@ -237,7 +237,7 @@ class StorageManager : public mqbi::AppKeyGenerator { virtual void registerQueue(const bmqt::Uri& uri, const mqbu::StorageKey& queueKey, int partitionId, - const AppIdKeyPairs& appIdKeyPairs, + const AppInfos& appIdKeyPairs, mqbi::Domain* domain) = 0; /// Synchronously unregister the queue with the specified `uri` from the @@ -259,8 +259,8 @@ class StorageManager : public mqbi::AppKeyGenerator { virtual int updateQueuePrimary(const bmqt::Uri& uri, const mqbu::StorageKey& queueKey, int partitionId, - const AppIdKeyPairs& addedIdKeyPairs, - const AppIdKeyPairs& removedIdKeyPairs) = 0; + const AppInfos& addedIdKeyPairs, + const AppInfos& removedIdKeyPairs) = 0; virtual void registerQueueReplica(int partitionId, const bmqt::Uri& uri, @@ -276,7 +276,7 @@ class StorageManager : public mqbi::AppKeyGenerator { virtual void updateQueueReplica(int partitionId, const bmqt::Uri& uri, const mqbu::StorageKey& queueKey, - const AppIdKeyPairs& appIdKeyPairs, + const AppInfos& appIdKeyPairs, mqbi::Domain* domain = 0, bool allowDuplicate = false) = 0; diff --git a/src/groups/mqb/mqbmock/mqbmock_storagemanager.cpp b/src/groups/mqb/mqbmock/mqbmock_storagemanager.cpp index 3264e0110..34ddd037d 100644 --- a/src/groups/mqb/mqbmock/mqbmock_storagemanager.cpp +++ b/src/groups/mqb/mqbmock/mqbmock_storagemanager.cpp @@ -60,7 +60,7 @@ void StorageManager::registerQueue( BSLS_ANNOTATION_UNUSED const bmqt::Uri& uri, BSLS_ANNOTATION_UNUSED const mqbu::StorageKey& queueKey, BSLS_ANNOTATION_UNUSED int partitionId, - BSLS_ANNOTATION_UNUSED const AppIdKeyPairs& appIdKeyPairs, + BSLS_ANNOTATION_UNUSED const AppInfos& appIdKeyPairs, BSLS_ANNOTATION_UNUSED mqbi::Domain* domain) { // NOTHING @@ -77,8 +77,8 @@ int StorageManager::updateQueuePrimary( BSLS_ANNOTATION_UNUSED const bmqt::Uri& uri, BSLS_ANNOTATION_UNUSED const mqbu::StorageKey& queueKey, BSLS_ANNOTATION_UNUSED int partitionId, - BSLS_ANNOTATION_UNUSED const AppIdKeyPairs& addedIdKeyPairs, - BSLS_ANNOTATION_UNUSED const AppIdKeyPairs& removedIdKeyPairs) + BSLS_ANNOTATION_UNUSED const AppInfos& addedIdKeyPairs, + BSLS_ANNOTATION_UNUSED const AppInfos& removedIdKeyPairs) { return 0; } @@ -106,7 +106,7 @@ void StorageManager::updateQueueReplica( BSLS_ANNOTATION_UNUSED int partitionId, BSLS_ANNOTATION_UNUSED const bmqt::Uri& uri, BSLS_ANNOTATION_UNUSED const mqbu::StorageKey& queueKey, - BSLS_ANNOTATION_UNUSED const AppIdKeyPairs& appIdKeyPairs, + BSLS_ANNOTATION_UNUSED const AppInfos& appIdKeyPairs, BSLS_ANNOTATION_UNUSED mqbi::Domain* domain, BSLS_ANNOTATION_UNUSED bool allowDuplicate) { diff --git a/src/groups/mqb/mqbmock/mqbmock_storagemanager.h b/src/groups/mqb/mqbmock/mqbmock_storagemanager.h index 028e17a3f..77e032778 100644 --- a/src/groups/mqb/mqbmock/mqbmock_storagemanager.h +++ b/src/groups/mqb/mqbmock/mqbmock_storagemanager.h @@ -80,7 +80,7 @@ class StorageManager : public mqbi::StorageManager { virtual void registerQueue(const bmqt::Uri& uri, const mqbu::StorageKey& queueKey, int partitionId, - const AppIdKeyPairs& appIdKeyPairs, + const AppInfos& appIdKeyPairs, mqbi::Domain* domain) BSLS_KEYWORD_OVERRIDE; /// Synchronously unregister the queue with the specified `uri` from the @@ -103,8 +103,8 @@ class StorageManager : public mqbi::StorageManager { virtual int updateQueuePrimary(const bmqt::Uri& uri, const mqbu::StorageKey& queueKey, int partitionId, - const AppIdKeyPairs& addedIdKeyPairs, - const AppIdKeyPairs& removedIdKeyPairs) + const AppInfos& addedIdKeyPairs, + const AppInfos& removedIdKeyPairs) BSLS_KEYWORD_OVERRIDE; virtual void @@ -124,7 +124,7 @@ class StorageManager : public mqbi::StorageManager { updateQueueReplica(int partitionId, const bmqt::Uri& uri, const mqbu::StorageKey& queueKey, - const AppIdKeyPairs& appIdKeyPairs, + const AppInfos& appIdKeyPairs, mqbi::Domain* domain = 0, bool allowDuplicate = false) BSLS_KEYWORD_OVERRIDE; diff --git a/src/groups/mqb/mqbs/mqbs_datastore.h b/src/groups/mqb/mqbs/mqbs_datastore.h index 7130a2fd0..67e7845a7 100644 --- a/src/groups/mqb/mqbs/mqbs_datastore.h +++ b/src/groups/mqb/mqbs/mqbs_datastore.h @@ -271,9 +271,9 @@ struct DataStoreRecordKeyLess { class DataStoreConfigQueueInfo { public: // TYPES - typedef mqbi::Storage::AppIdKeyPair AppIdKeyPair; + typedef mqbi::Storage::AppInfo AppInfo; - typedef mqbi::Storage::AppIdKeyPairs AppIdKeyPairs; + typedef mqbi::Storage::AppInfos AppInfos; private: // DATA @@ -281,7 +281,7 @@ class DataStoreConfigQueueInfo { int d_partitionId; - AppIdKeyPairs d_appIdKeyPairs; + AppInfos d_appIdKeyPairs; public: // TRAITS @@ -299,14 +299,14 @@ class DataStoreConfigQueueInfo { void setPartitionId(int value); - void addAppIdKeyPair(const AppIdKeyPair& value); + void addAppInfo(const AppInfo& value); // ACCESSORS const bsl::string& canonicalQueueUri() const; int partitionId() const; - const AppIdKeyPairs& appIdKeyPairs() const; + const AppInfos& appIdKeyPairs() const; }; // ===================== @@ -335,15 +335,15 @@ class DataStoreConfig { typedef Records::const_iterator RecordConstIterator; - typedef mqbi::Storage::AppIdKeyPair AppIdKeyPair; + typedef mqbi::Storage::AppInfo AppInfo; - typedef mqbi::Storage::AppIdKeyPairs AppIdKeyPairs; + typedef mqbi::Storage::AppInfos AppInfos; typedef bsl::function QueueCreationCb; @@ -541,9 +541,9 @@ class DataStore : public mqbi::DispatcherClient { public: // TYPES - typedef mqbi::Storage::AppIdKeyPair AppIdKeyPair; + typedef mqbi::Storage::AppInfo AppInfo; - typedef mqbi::Storage::AppIdKeyPairs AppIdKeyPairs; + typedef mqbi::Storage::AppInfos AppInfos; typedef DataStoreConfig::QueueKeyInfoMap QueueKeyInfoMap; @@ -596,7 +596,7 @@ class DataStore : public mqbi::DispatcherClient { virtual int writeQueueCreationRecord(DataStoreRecordHandle* handle, const bmqt::Uri& queueUri, const mqbu::StorageKey& queueKey, - const AppIdKeyPairs& appIdKeyPairs, + const AppInfos& appIdKeyPairs, bsls::Types::Uint64 timestamp, bool isNewQueue) = 0; @@ -889,10 +889,9 @@ inline void DataStoreConfigQueueInfo::setPartitionId(int value) d_partitionId = value; } -inline void -DataStoreConfigQueueInfo::addAppIdKeyPair(const AppIdKeyPair& value) +inline void DataStoreConfigQueueInfo::addAppInfo(const AppInfo& value) { - d_appIdKeyPairs.push_back(value); + d_appIdKeyPairs.insert(value); } // ACCESSORS @@ -906,7 +905,7 @@ inline int DataStoreConfigQueueInfo::partitionId() const return d_partitionId; } -inline const DataStoreConfigQueueInfo::AppIdKeyPairs& +inline const DataStoreConfigQueueInfo::AppInfos& DataStoreConfigQueueInfo::appIdKeyPairs() const { return d_appIdKeyPairs; diff --git a/src/groups/mqb/mqbs/mqbs_filebackedstorage.h b/src/groups/mqb/mqbs/mqbs_filebackedstorage.h index 1903536f3..091f4cfd2 100644 --- a/src/groups/mqb/mqbs/mqbs_filebackedstorage.h +++ b/src/groups/mqb/mqbs/mqbs_filebackedstorage.h @@ -131,9 +131,9 @@ class FileBackedStorage BSLS_KEYWORD_FINAL : public ReplicatedStorage { public: // TYPES - typedef mqbi::Storage::AppIdKeyPair AppIdKeyPair; + typedef mqbi::Storage::AppInfo AppInfo; - typedef mqbi::Storage::AppIdKeyPairs AppIdKeyPairs; + typedef mqbi::Storage::AppInfos AppInfos; typedef ReplicatedStorage::RecordHandles RecordHandles; @@ -334,8 +334,8 @@ class FileBackedStorage BSLS_KEYWORD_FINAL : public ReplicatedStorage { /// Load into the specified 'buffer' the list of pairs of appId and appKey // for all the virtual storages registered with this instance. - virtual void loadVirtualStorageDetails(AppIdKeyPairs* buffer) const - BSLS_KEYWORD_OVERRIDE; + virtual void + loadVirtualStorageDetails(AppInfos* buffer) const BSLS_KEYWORD_OVERRIDE; /// Store in the specified 'msgSize' the size, in bytes, of the message /// having the specified 'msgGUID' if found and return success, or return @@ -720,7 +720,7 @@ inline bool FileBackedStorage::hasVirtualStorage(const bsl::string& appId, } inline void -FileBackedStorage::loadVirtualStorageDetails(AppIdKeyPairs* buffer) const +FileBackedStorage::loadVirtualStorageDetails(AppInfos* buffer) const { return d_virtualStorageCatalog.loadVirtualStorageDetails(buffer); } diff --git a/src/groups/mqb/mqbs/mqbs_filebackedstorage.t.cpp b/src/groups/mqb/mqbs/mqbs_filebackedstorage.t.cpp index 8a865520d..9c99911e0 100644 --- a/src/groups/mqb/mqbs/mqbs_filebackedstorage.t.cpp +++ b/src/groups/mqb/mqbs/mqbs_filebackedstorage.t.cpp @@ -342,7 +342,7 @@ class MockDataStore : public mqbs::DataStore { int writeQueueCreationRecord(mqbs::DataStoreRecordHandle*, const bmqt::Uri&, const mqbu::StorageKey&, - const AppIdKeyPairs&, + const AppInfos&, bsls::Types::Uint64, bool) BSLS_KEYWORD_OVERRIDE { diff --git a/src/groups/mqb/mqbs/mqbs_filestore.cpp b/src/groups/mqb/mqbs/mqbs_filestore.cpp index 45d5b7b06..0b59ae95a 100644 --- a/src/groups/mqb/mqbs/mqbs_filestore.cpp +++ b/src/groups/mqb/mqbs/mqbs_filestore.cpp @@ -2019,13 +2019,15 @@ int FileStore::recoverMessages(QueueKeyInfoMap* queueKeyInfoMap, FileStoreProtocol::k_HASH_LENGTH, appIdsAreaLen); - AppIdKeyPairs appIdKeyPairs; - FileStoreProtocolUtil::loadAppIdKeyPairs(&appIdKeyPairs, - appIdsBlock, - numAppIds); - - for (size_t n = 0; n < appIdKeyPairs.size(); ++n) { - const AppIdKeyPair& p = appIdKeyPairs[n]; + AppInfos appIdKeyPairs; + FileStoreProtocolUtil::loadAppInfos(&appIdKeyPairs, + appIdsBlock, + numAppIds); + + for (AppInfos::const_iterator cit = appIdKeyPairs.cbegin(); + cit != appIdKeyPairs.cend(); + ++cit) { + const AppInfo& p = *cit; if (0 == deletedAppKeysOffsets.count(p.second)) { // This appKey is not deleted. Add it to the list // of 'alive' appId/appKey pairs for this queue. @@ -2034,7 +2036,7 @@ int FileStore::recoverMessages(QueueKeyInfoMap* queueKeyInfoMap, // StorageMgr because we have recovered all // appId/appKey pairs by that time. - qinfo.addAppIdKeyPair(p); + qinfo.addAppInfo(p); BALL_LOG_INFO << partitionDesc() @@ -4267,7 +4269,7 @@ int FileStore::writeQueueCreationRecord( } bmqt::Uri quri; - AppIdKeyPairs appIdKeyPairs; + AppInfos appIdKeyPairs; if (!d_isFSMWorkflow) { // Check qlist offset in the replicated journal record sent by the // primary vs qlist offset maintained by self. A mismatch means that @@ -4301,9 +4303,9 @@ int FileStore::writeQueueCreationRecord( queueRecHeaderLen + paddedUriLen + FileStoreProtocol::k_HASH_LENGTH, appIdsAreaSize); - FileStoreProtocolUtil::loadAppIdKeyPairs(&appIdKeyPairs, - appIdsBlock, - queueRecHeader->numAppIds()); + FileStoreProtocolUtil::loadAppInfos(&appIdKeyPairs, + appIdsBlock, + queueRecHeader->numAppIds()); } BALL_LOG_INFO_BLOCK @@ -4316,10 +4318,11 @@ int FileStore::writeQueueCreationRecord( BALL_LOG_OUTPUT_STREAM << ", queue [" << quri << "]" << ", with [" << appIdKeyPairs.size() << "] appId/appKey pairs "; - for (size_t n = 0; n < appIdKeyPairs.size(); ++n) { - BALL_LOG_OUTPUT_STREAM << " [" << appIdKeyPairs[n].first - << ", " << appIdKeyPairs[n].second - << "]"; + for (AppInfos::const_iterator cit = appIdKeyPairs.cbegin(); + cit != appIdKeyPairs.cend(); + ++cit) { + BALL_LOG_OUTPUT_STREAM << " [" << cit->first << ", " + << cit->second << "]"; } } } @@ -5593,7 +5596,7 @@ int FileStore::writeMessageRecord(mqbi::StorageMessageAttributes* attributes, int FileStore::writeQueueCreationRecord(DataStoreRecordHandle* handle, const bmqt::Uri& queueUri, const mqbu::StorageKey& queueKey, - const AppIdKeyPairs& appIdKeyPairs, + const AppInfos& appIdKeyPairs, bsls::Types::Uint64 timestamp, bool isNewQueue) { @@ -5654,9 +5657,11 @@ int FileStore::writeQueueCreationRecord(DataStoreRecordHandle* handle, totalLength = sizeof(QueueRecordHeader) + queueUri.asString().length() + queueUriPadding + FileStoreProtocol::k_HASH_LENGTH; - - for (size_t i = 0; i < appIdKeyPairs.size(); ++i) { - const AppIdKeyPair& appIdKeyPair = appIdKeyPairs[i]; + size_t i = 0; + for (AppInfos::const_iterator cit = appIdKeyPairs.cbegin(); + cit != appIdKeyPairs.cend(); + ++cit, ++i) { + const AppInfo& appIdKeyPair = *cit; BSLS_ASSERT_SAFE(!appIdKeyPair.first.empty()); BSLS_ASSERT_SAFE(!appIdKeyPair.second.isNull()); appIdWords[i] = bmqp::ProtocolUtil::calcNumWordsAndPadding( @@ -5761,7 +5766,10 @@ int FileStore::writeQueueCreationRecord(DataStoreRecordHandle* handle, qlistFilePos += FileStoreProtocol::k_HASH_LENGTH; // 3) Append AppIds and AppKeys - for (size_t i = 0; i < appIdKeyPairs.size(); ++i) { + size_t i = 0; + for (AppInfos::const_iterator cit = appIdKeyPairs.cbegin(); + cit != appIdKeyPairs.cend(); + ++cit, ++i) { // Append AppIdHeader. OffsetPtr appIdHeader(qlistFile.block(), @@ -5773,10 +5781,8 @@ int FileStore::writeQueueCreationRecord(DataStoreRecordHandle* handle, // Append AppId. OffsetPtr appId(qlistFile.block(), qlistFilePos); - bsl::memcpy(appId.get(), - appIdKeyPairs[i].first.c_str(), - appIdKeyPairs[i].first.length()); - qlistFilePos += appIdKeyPairs[i].first.length(); + bsl::memcpy(appId.get(), cit->first.c_str(), cit->first.length()); + qlistFilePos += cit->first.length(); // Append padding after AppId. @@ -5789,7 +5795,7 @@ int FileStore::writeQueueCreationRecord(DataStoreRecordHandle* handle, // above for explanation). char appIdHash[mqbs::FileStoreProtocol::k_HASH_LENGTH] = {0}; - bsl::memcpy(appIdHash, appIdKeyPairs[i].second.data(), k_KEY_LEN); + bsl::memcpy(appIdHash, cit->second.data(), k_KEY_LEN); OffsetPtr appHash(qlistFile.block(), qlistFilePos); bsl::memcpy(appHash.get(), appIdHash, diff --git a/src/groups/mqb/mqbs/mqbs_filestore.h b/src/groups/mqb/mqbs/mqbs_filestore.h index d2f1a2d23..1559d05d2 100644 --- a/src/groups/mqb/mqbs/mqbs_filestore.h +++ b/src/groups/mqb/mqbs/mqbs_filestore.h @@ -213,8 +213,8 @@ class FileStore : public DataStore { typedef DataStoreConfig::QueueKeyInfoMapConstIter QueueKeyInfoMapConstIter; typedef DataStoreConfig::QueueKeyInfoMapInsertRc QueueKeyInfoMapInsertRc; - typedef mqbi::Storage::AppIdKeyPair AppIdKeyPair; - typedef mqbi::Storage::AppIdKeyPairs AppIdKeyPairs; + typedef mqbi::Storage::AppInfo AppInfo; + typedef mqbi::Storage::AppInfos AppInfos; typedef StorageCollectionUtil::StoragesMap StoragesMap; typedef StorageCollectionUtil::StorageMapIter StorageMapIter; @@ -773,7 +773,7 @@ class FileStore : public DataStore { int writeQueueCreationRecord(DataStoreRecordHandle* handle, const bmqt::Uri& queueUri, const mqbu::StorageKey& queueKey, - const AppIdKeyPairs& appIdKeyPairs, + const AppInfos& appIdKeyPairs, bsls::Types::Uint64 timestamp, bool isNewQueue) BSLS_KEYWORD_OVERRIDE; diff --git a/src/groups/mqb/mqbs/mqbs_filestore.t.cpp b/src/groups/mqb/mqbs/mqbs_filestore.t.cpp index 6977a451b..0bddb7814 100644 --- a/src/groups/mqb/mqbs/mqbs_filestore.t.cpp +++ b/src/groups/mqb/mqbs/mqbs_filestore.t.cpp @@ -85,7 +85,7 @@ const int k_NODE_ID = 12345; // ALIASES typedef mqbs::FileStoreTestUtil_Record Record; -typedef mqbs::DataStore::AppIdKeyPairs AppIdKeyPairs; +typedef mqbs::DataStore::AppInfos AppInfos; typedef mqbs::FileStore::SyncPointOffsetPairs SyncPointOffsetPairs; typedef bsl::pair HandleRecordPair; @@ -368,7 +368,7 @@ struct Tester { bmqt::Uri(rec.d_uri, s_allocator_p), rec.d_queueKey, - AppIdKeyPairs(), + AppInfos(), rec.d_timestamp, true); // isNewQueue diff --git a/src/groups/mqb/mqbs/mqbs_filestoreprotocolutil.cpp b/src/groups/mqb/mqbs/mqbs_filestoreprotocolutil.cpp index 9a5856ea9..c6824b675 100644 --- a/src/groups/mqb/mqbs/mqbs_filestoreprotocolutil.cpp +++ b/src/groups/mqb/mqbs/mqbs_filestoreprotocolutil.cpp @@ -330,10 +330,11 @@ int FileStoreProtocolUtil::calculateMd5Digest( return 0; } -void FileStoreProtocolUtil::loadAppIdKeyPairs( - bsl::vector >* appIdKeyPairs, - const MemoryBlock& appIdsBlock, - unsigned int numAppIds) +void FileStoreProtocolUtil::loadAppInfos( + bsl::unordered_set >* + appIdKeyPairs, + const MemoryBlock& appIdsBlock, + unsigned int numAppIds) { // PRECONDITIONS BSLS_ASSERT_SAFE(appIdKeyPairs); @@ -351,7 +352,7 @@ void FileStoreProtocolUtil::loadAppIdKeyPairs( const char* appIdBegin = appIdsBlock.base() + offset + sizeof(AppIdHeader); - appIdKeyPairs->emplace_back( + appIdKeyPairs->emplace( bsl::string(appIdBegin, paddedLen - appIdBegin[paddedLen - 1], appIdKeyPairs->get_allocator()), diff --git a/src/groups/mqb/mqbs/mqbs_filestoreprotocolutil.h b/src/groups/mqb/mqbs/mqbs_filestoreprotocolutil.h index 9fbd417a0..d6789c841 100644 --- a/src/groups/mqb/mqbs/mqbs_filestoreprotocolutil.h +++ b/src/groups/mqb/mqbs/mqbs_filestoreprotocolutil.h @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -107,10 +108,11 @@ struct FileStoreProtocolUtil { const bmqu::BlobPosition& startPos, unsigned int length); - static void loadAppIdKeyPairs( - bsl::vector >* appIdKeyPairs, - const MemoryBlock& appIdsBlock, - unsigned int numAppIds); + static void + loadAppInfos(bsl::unordered_set >* + appIdKeyPairs, + const MemoryBlock& appIdsBlock, + unsigned int numAppIds); }; } // close package namespace diff --git a/src/groups/mqb/mqbs/mqbs_filestoreprotocolutil.t.cpp b/src/groups/mqb/mqbs/mqbs_filestoreprotocolutil.t.cpp index 5948826f7..3eb2b8072 100644 --- a/src/groups/mqb/mqbs/mqbs_filestoreprotocolutil.t.cpp +++ b/src/groups/mqb/mqbs/mqbs_filestoreprotocolutil.t.cpp @@ -495,25 +495,25 @@ static void test3_lastJournalSyncPoint() } } -static void test4_loadAppIdKeyPairs() +static void test4_loadAppInfos() // ------------------------------------------------------------------------ // Testing: -// loadAppIdKeyPairs() +// loadAppInfos() // ------------------------------------------------------------------------ { - typedef bsl::pair AppIdKeyPair; - typedef bsl::vector AppIdKeyPairs; + typedef bsl::pair AppInfo; + typedef bsl::unordered_set AppInfos; { // No appIds. char* p = static_cast(s_allocator_p->allocate(1)); mqbs::MemoryBlock mb(p, 1); - AppIdKeyPairs appIdKeyPairs(s_allocator_p); + AppInfos appIdKeyPairs(s_allocator_p); - mqbs::FileStoreProtocolUtil::loadAppIdKeyPairs(&appIdKeyPairs, - mb, - 0); // no appIds + mqbs::FileStoreProtocolUtil::loadAppInfos(&appIdKeyPairs, + mb, + 0); // no appIds ASSERT_EQ(0u, appIdKeyPairs.size()); @@ -563,15 +563,15 @@ static void test4_loadAppIdKeyPairs() // Test. mqbs::MemoryBlock mb(p, totalSize); - AppIdKeyPairs appIdKeyPairs(s_allocator_p); + AppInfos appIdKeyPairs(s_allocator_p); - mqbs::FileStoreProtocolUtil::loadAppIdKeyPairs(&appIdKeyPairs, - mb, - 1); // 1 appId + mqbs::FileStoreProtocolUtil::loadAppInfos(&appIdKeyPairs, + mb, + 1); // 1 appId ASSERT_EQ(1U, appIdKeyPairs.size()); - ASSERT_EQ(appId, appIdKeyPairs[0].first); - ASSERT_EQ(appKey, appIdKeyPairs[0].second); + ASSERT_EQ(appId, appIdKeyPairs.begin()->first); + ASSERT_EQ(appKey, appIdKeyPairs.begin()->second); s_allocator_p->deallocate(p); } @@ -601,10 +601,9 @@ static void test4_loadAppIdKeyPairs() mqbs::FileStoreProtocol::k_HASH_LENGTH; } - char* p = static_cast(s_allocator_p->allocate(totalSize)); - size_t offset = 0; - bsl::vector expectedAppIds(s_allocator_p); - bsl::vector expectedAppKeys(s_allocator_p); + char* p = static_cast(s_allocator_p->allocate(totalSize)); + size_t offset = 0; + AppInfos expectedAppInfos(s_allocator_p); for (int n = 0; n < numAppIds; ++n) { // Append AppIdHeader. @@ -624,7 +623,6 @@ static void test4_loadAppIdKeyPairs() s_allocator_p); bsl::memcpy(p + offset, appId.c_str(), appIdLenVec[n]); offset += appIdLenVec[n]; - expectedAppIds.push_back(appId); // Append AppId padding. bmqp::ProtocolUtil::appendPaddingRaw(p + offset, @@ -646,24 +644,21 @@ static void test4_loadAppIdKeyPairs() bsl::memcpy(p + offset, appHash, mqbs::FileStoreProtocol::k_HASH_LENGTH); - expectedAppKeys.push_back(appKey); + + expectedAppInfos.emplace( + AppInfo(bsl::string(appId, s_allocator_p), appKey)); offset += mqbs::FileStoreProtocol::k_HASH_LENGTH; } - // Test. mqbs::MemoryBlock mb(p, totalSize); - AppIdKeyPairs appIdKeyPairs(s_allocator_p); + AppInfos appIdKeyPairs(s_allocator_p); - mqbs::FileStoreProtocolUtil::loadAppIdKeyPairs(&appIdKeyPairs, - mb, - numAppIds); + mqbs::FileStoreProtocolUtil::loadAppInfos(&appIdKeyPairs, + mb, + numAppIds); ASSERT_EQ(static_cast(numAppIds), appIdKeyPairs.size()); - - for (size_t n = 0; n < appIdKeyPairs.size(); ++n) { - ASSERT_EQ_D(n, expectedAppIds[n], appIdKeyPairs[n].first); - ASSERT_EQ_D(n, expectedAppKeys[n], appIdKeyPairs[n].second); - } + ASSERT_EQ(appIdKeyPairs, expectedAppInfos); s_allocator_p->deallocate(p); } @@ -911,7 +906,7 @@ int main(int argc, char* argv[]) switch (_testCase) { case 0: case 5: test5_calculateMd5Digest(); break; - case 4: test4_loadAppIdKeyPairs(); break; + case 4: test4_loadAppInfos(); break; case 3: test3_lastJournalSyncPoint(); break; case 2: test2_lastJournalRecord(); break; case 1: test1_hasBmqHeader(); break; diff --git a/src/groups/mqb/mqbs/mqbs_inmemorystorage.h b/src/groups/mqb/mqbs/mqbs_inmemorystorage.h index caf70ae0f..4f4de320d 100644 --- a/src/groups/mqb/mqbs/mqbs_inmemorystorage.h +++ b/src/groups/mqb/mqbs/mqbs_inmemorystorage.h @@ -167,9 +167,9 @@ class InMemoryStorage BSLS_KEYWORD_FINAL : public ReplicatedStorage { public: // TYPES - typedef mqbi::Storage::AppIdKeyPair AppIdKeyPair; + typedef mqbi::Storage::AppInfo AppInfo; - typedef mqbi::Storage::AppIdKeyPairs AppIdKeyPairs; + typedef mqbi::Storage::AppInfos AppInfos; typedef ReplicatedStorage::RecordHandles RecordHandles; @@ -515,8 +515,8 @@ class InMemoryStorage BSLS_KEYWORD_FINAL : public ReplicatedStorage { /// Load into the specified 'buffer' the list of pairs of appId and /// appKey for all the virtual storages registered with this instance. - virtual void loadVirtualStorageDetails(AppIdKeyPairs* buffer) const - BSLS_KEYWORD_OVERRIDE; + virtual void + loadVirtualStorageDetails(AppInfos* buffer) const BSLS_KEYWORD_OVERRIDE; virtual unsigned int numAutoConfirms() const BSLS_KEYWORD_OVERRIDE; @@ -766,8 +766,7 @@ inline bool InMemoryStorage::hasReceipt(const bmqt::MessageGUID&) const return true; } -inline void -InMemoryStorage::loadVirtualStorageDetails(AppIdKeyPairs* buffer) const +inline void InMemoryStorage::loadVirtualStorageDetails(AppInfos* buffer) const { return d_virtualStorageCatalog.loadVirtualStorageDetails(buffer); diff --git a/src/groups/mqb/mqbs/mqbs_storageprintutil.cpp b/src/groups/mqb/mqbs/mqbs_storageprintutil.cpp index 53519711a..98ed74991 100644 --- a/src/groups/mqb/mqbs/mqbs_storageprintutil.cpp +++ b/src/groups/mqb/mqbs/mqbs_storageprintutil.cpp @@ -174,11 +174,11 @@ void StoragePrintUtil::printRecoveredStorages( out << " ["; } - AppIdKeyPairs appIdKeyPairs; + AppInfos appIdKeyPairs; rs->loadVirtualStorageDetails(&appIdKeyPairs); BSLS_ASSERT_SAFE(numVS == appIdKeyPairs.size()); - for (AppIdKeyPairsCIter vit = appIdKeyPairs.begin(); + for (AppInfosCIter vit = appIdKeyPairs.begin(); vit != appIdKeyPairs.end(); ++vit) { BSLS_ASSERT_SAFE(rs->hasVirtualStorage(vit->second)); diff --git a/src/groups/mqb/mqbs/mqbs_storageprintutil.h b/src/groups/mqb/mqbs/mqbs_storageprintutil.h index 0a20a02b5..6c420dba1 100644 --- a/src/groups/mqb/mqbs/mqbs_storageprintutil.h +++ b/src/groups/mqb/mqbs/mqbs_storageprintutil.h @@ -66,8 +66,8 @@ namespace mqbs { struct StoragePrintUtil { private: // PRIVATE TYPES - typedef mqbi::StorageManager::AppIdKeyPairs AppIdKeyPairs; - typedef AppIdKeyPairs::const_iterator AppIdKeyPairsCIter; + typedef mqbi::StorageManager::AppInfos AppInfos; + typedef AppInfos::const_iterator AppInfosCIter; public: // TYPES diff --git a/src/groups/mqb/mqbs/mqbs_virtualstoragecatalog.cpp b/src/groups/mqb/mqbs/mqbs_virtualstoragecatalog.cpp index 6ff76dc84..8cd24b5bf 100644 --- a/src/groups/mqb/mqbs/mqbs_virtualstoragecatalog.cpp +++ b/src/groups/mqb/mqbs/mqbs_virtualstoragecatalog.cpp @@ -565,8 +565,7 @@ bool VirtualStorageCatalog::hasVirtualStorage(const bsl::string& appId, return hasVs; } -void VirtualStorageCatalog::loadVirtualStorageDetails( - AppIdKeyPairs* buffer) const +void VirtualStorageCatalog::loadVirtualStorageDetails(AppInfos* buffer) const { // PRECONDITIONS BSLS_ASSERT_SAFE(buffer); @@ -575,7 +574,7 @@ void VirtualStorageCatalog::loadVirtualStorageDetails( cit != d_virtualStorages.end(); ++cit) { BSLS_ASSERT_SAFE(cit->key2() == cit->value()->appKey()); - buffer->push_back(bsl::make_pair(cit->key1(), cit->key2())); + buffer->emplace(bsl::make_pair(cit->key1(), cit->key2())); } } diff --git a/src/groups/mqb/mqbs/mqbs_virtualstoragecatalog.h b/src/groups/mqb/mqbs/mqbs_virtualstoragecatalog.h index 767887890..94f89762f 100644 --- a/src/groups/mqb/mqbs/mqbs_virtualstoragecatalog.h +++ b/src/groups/mqb/mqbs/mqbs_virtualstoragecatalog.h @@ -75,9 +75,9 @@ class VirtualStorageCatalog { public: // TYPES - typedef mqbi::Storage::AppIdKeyPair AppIdKeyPair; + typedef mqbi::Storage::AppInfo AppInfo; - typedef mqbi::Storage::AppIdKeyPairs AppIdKeyPairs; + typedef mqbi::Storage::AppInfos AppInfos; typedef unsigned int Ordinal; @@ -277,7 +277,7 @@ class VirtualStorageCatalog { /// Load into the specified 'buffer' the list of pairs of appId and /// appKey for all the virtual storages registered with this instance. - void loadVirtualStorageDetails(AppIdKeyPairs* buffer) const; + void loadVirtualStorageDetails(AppInfos* buffer) const; /// Return the number of messages in the virtual storage associated with /// the specified 'appKey'. Behavior is undefined unless a virtual diff --git a/src/integration-tests/test_restart.py b/src/integration-tests/test_restart.py index 064f0c076..102805e68 100644 --- a/src/integration-tests/test_restart.py +++ b/src/integration-tests/test_restart.py @@ -141,6 +141,18 @@ def test_restart_from_non_FSM_to_FSM(cluster: Cluster): ensureMessageAtStorageLayer(cluster) + # Consumer for fanout queue + consumer_foo = next(proxies).create_client("consumer_foo") + consumer_foo.open(tc.URI_FANOUT_FOO, flags=["read"], succeed=True) + consumer_foo.wait_push_event() + assert wait_until( + lambda: len(consumer_foo.list(tc.URI_FANOUT_FOO, block=True)) == 1, 2 + ) + + # Save one confirm to the storage + consumer_foo.confirm(tc.URI_FANOUT_FOO, "+1", succeed=True) + consumer_foo.close(tc.URI_FANOUT_FOO, succeed=True) + cluster.stop_nodes() # Reconfigure the cluster from non-FSM to FSM mode @@ -166,10 +178,17 @@ def test_restart_from_non_FSM_to_FSM(cluster: Cluster): consumer.wait_push_event() assert wait_until(lambda: len(consumer.list(tc.URI_PRIORITY, block=True)) == 2, 2) - # Consumer for fanout queue - consumer_fanout = next(proxies).create_client("consumer_fanout") - consumer_fanout.open(tc.URI_FANOUT_FOO, flags=["read"], succeed=True) - consumer_fanout.wait_push_event() + # Consumers for fanout queue + consumer_bar = next(proxies).create_client("consumer_bar") + consumer_bar.open(tc.URI_FANOUT_BAR, flags=["read"], succeed=True) + consumer_bar.wait_push_event() + assert wait_until( + lambda: len(consumer_bar.list(tc.URI_FANOUT_BAR, block=True)) == 2, 2 + ) + + # make sure the previously saved confirm is not lost + consumer_foo.open(tc.URI_FANOUT_FOO, flags=["read"], succeed=True) + consumer_foo.wait_push_event() assert wait_until( - lambda: len(consumer_fanout.list(tc.URI_FANOUT_FOO, block=True)) == 2, 2 + lambda: len(consumer_foo.list(tc.URI_FANOUT_FOO, block=True)) == 1, 2 ) From 7606a27c4827a170740b6f9e44e6eba702ced965 Mon Sep 17 00:00:00 2001 From: Evgeny Malygin Date: Mon, 28 Oct 2024 19:08:33 +0200 Subject: [PATCH 06/17] Perf[MQB]: make independent item pools for channels (#479) Signed-off-by: Evgeny Malygin --- src/groups/mqb/mqbmock/mqbmock_cluster.cpp | 2 -- src/groups/mqb/mqbmock/mqbmock_cluster.h | 11 ------- src/groups/mqb/mqbnet/mqbnet_channel.cpp | 27 +++++++++-------- src/groups/mqb/mqbnet/mqbnet_channel.h | 12 ++------ src/groups/mqb/mqbnet/mqbnet_channel.t.cpp | 24 ++++----------- src/groups/mqb/mqbnet/mqbnet_clusterimp.cpp | 12 ++++---- src/groups/mqb/mqbnet/mqbnet_clusterimp.h | 8 ++--- .../mqb/mqbnet/mqbnet_dummysession.t.cpp | 4 --- src/groups/mqb/mqbnet/mqbnet_mockcluster.cpp | 6 ++-- src/groups/mqb/mqbnet/mqbnet_mockcluster.h | 2 -- .../mqb/mqbnet/mqbnet_transportmanager.cpp | 30 +++++++++---------- .../mqb/mqbnet/mqbnet_transportmanager.h | 6 ++-- src/groups/mqb/mqbs/mqbs_filestore.t.cpp | 3 -- 13 files changed, 49 insertions(+), 98 deletions(-) diff --git a/src/groups/mqb/mqbmock/mqbmock_cluster.cpp b/src/groups/mqb/mqbmock/mqbmock_cluster.cpp index 0ffacdc1a..0d57dc8d7 100644 --- a/src/groups/mqb/mqbmock/mqbmock_cluster.cpp +++ b/src/groups/mqb/mqbmock/mqbmock_cluster.cpp @@ -136,7 +136,6 @@ void Cluster::_initializeNetcluster() d_netCluster_mp.load(new (*d_allocator_p) mqbnet::MockCluster(d_clusterDefinition, d_bufferFactory_p, - &d_itemPool, d_allocator_p), d_allocator_p); @@ -221,7 +220,6 @@ Cluster::Cluster(bdlbb::BlobBufferFactory* bufferFactory, , d_timeSource(&d_scheduler) , d_isStarted(false) , d_clusterDefinition(allocator) -, d_itemPool(mqbnet::Channel::k_ITEM_SIZE, allocator) , d_channels(allocator) , d_negotiator_mp() , d_transportManager(&d_scheduler, diff --git a/src/groups/mqb/mqbmock/mqbmock_cluster.h b/src/groups/mqb/mqbmock/mqbmock_cluster.h index e26421b3e..ed3885345 100644 --- a/src/groups/mqb/mqbmock/mqbmock_cluster.h +++ b/src/groups/mqb/mqbmock/mqbmock_cluster.h @@ -178,9 +178,6 @@ class Cluster : public mqbi::Cluster { mqbcfg::ClusterDefinition d_clusterDefinition; // Cluster definition - mqbnet::Channel::ItemPool d_itemPool; - // Item pool - TestChannelMap d_channels; // Test channels @@ -429,9 +426,6 @@ class Cluster : public mqbi::Cluster { /// Get a modifiable reference to this object's time source. bdlmt::EventSchedulerTestTimeSource& _timeSource(); - /// Get a modifiable reference to this object's item pool. - mqbnet::Channel::ItemPool& _itemPool(); - /// Get a modifiable reference to this object's cluster data. mqbc::ClusterData* _clusterData(); @@ -585,11 +579,6 @@ inline bdlmt::EventSchedulerTestTimeSource& Cluster::_timeSource() return d_timeSource; } -inline mqbnet::Channel::ItemPool& Cluster::_itemPool() -{ - return d_itemPool; -} - inline mqbc::ClusterData* Cluster::_clusterData() { return d_clusterData_mp.get(); diff --git a/src/groups/mqb/mqbnet/mqbnet_channel.cpp b/src/groups/mqb/mqbnet/mqbnet_channel.cpp index 9a53f0c0f..cf57b065f 100644 --- a/src/groups/mqb/mqbnet/mqbnet_channel.cpp +++ b/src/groups/mqb/mqbnet/mqbnet_channel.cpp @@ -63,17 +63,18 @@ void Channel::Stats::reset() // ------------- Channel::Channel(bdlbb::BlobBufferFactory* blobBufferFactory, - ItemPool* itemPool, const bsl::string& name, bslma::Allocator* allocator) : d_allocators(allocator) -, d_allocator_p(d_allocators.get(bsl::string("Channel-") + name)) +, d_allocator_p(d_allocators.get("Channel")) , d_putBuilder(blobBufferFactory, d_allocator_p) , d_pushBuilder(blobBufferFactory, d_allocator_p) , d_ackBuilder(blobBufferFactory, d_allocator_p) , d_confirmBuilder(blobBufferFactory, d_allocator_p) , d_rejectBuilder(blobBufferFactory, d_allocator_p) -, d_itemPool_p(itemPool) +, d_itemPool(sizeof(Item), + bsls::BlockGrowth::BSLS_CONSTANT, + d_allocators.get(bsl::string("ItemPool"))) , d_buffer(1024, allocator) , d_secondaryBuffer(1024, allocator) , d_doStop(false) @@ -108,7 +109,7 @@ Channel::~Channel() void Channel::deleteItem(void* item, void* cookie) { - static_cast(cookie)->d_itemPool_p->deleteObject( + static_cast(cookie)->d_itemPool.deleteObject( static_cast(item)); } @@ -119,7 +120,7 @@ Channel::writePut(const bmqp::PutHeader& ph, bool keepWeakPtr) { bslma::ManagedPtr item( - new (d_itemPool_p->allocate()) + new (d_itemPool.allocate()) Item(ph, data, keepWeakPtr, state, d_allocator_p), this, deleteItem); @@ -136,7 +137,7 @@ Channel::writePush(const bsl::shared_ptr& payload, const bmqp::Protocol::SubQueueInfosArray& subQueueInfos, const bsl::shared_ptr& state) { - bslma::ManagedPtr item(new (d_itemPool_p->allocate()) + bslma::ManagedPtr item(new (d_itemPool.allocate()) Item(queueId, msgId, flags, @@ -160,7 +161,7 @@ Channel::writePush(int queueId, const bmqp::Protocol::SubQueueInfosArray& subQueueInfos, const bsl::shared_ptr& state) { - bslma::ManagedPtr item(new (d_itemPool_p->allocate()) + bslma::ManagedPtr item(new (d_itemPool.allocate()) Item(queueId, msgId, flags, @@ -182,7 +183,7 @@ Channel::writeAck(int status, const bsl::shared_ptr& state) { bslma::ManagedPtr item( - new (d_itemPool_p->allocate()) + new (d_itemPool.allocate()) Item(status, correlationId, guid, queueId, state, d_allocator_p), this, deleteItem); @@ -195,7 +196,7 @@ Channel::writeConfirm(int queueId, const bmqt::MessageGUID& guid, const bsl::shared_ptr& state) { - bslma::ManagedPtr item(new (d_itemPool_p->allocate()) + bslma::ManagedPtr item(new (d_itemPool.allocate()) Item(queueId, subQueueId, guid, @@ -213,7 +214,7 @@ Channel::writeReject(int queueId, const bmqt::MessageGUID& guid, const bsl::shared_ptr& state) { - bslma::ManagedPtr item(new (d_itemPool_p->allocate()) + bslma::ManagedPtr item(new (d_itemPool.allocate()) Item(queueId, subQueueId, guid, @@ -230,7 +231,7 @@ Channel::writeBlob(const bdlbb::Blob& data, bmqp::EventType::Enum type, const bsl::shared_ptr& state) { - bslma::ManagedPtr item(new (d_itemPool_p->allocate()) + bslma::ManagedPtr item(new (d_itemPool.allocate()) Item(data, type, state, d_allocator_p), this, deleteItem); @@ -253,7 +254,7 @@ void Channel::resetChannel() d_stateCondition.signal(); } // Wake up the writing thread in case it is blocked by 'popFront' - bslma::ManagedPtr item(new (d_itemPool_p->allocate()) + bslma::ManagedPtr item(new (d_itemPool.allocate()) Item(d_allocator_p), this, deleteItem); @@ -336,7 +337,7 @@ void Channel::flush() return; // RETURN } - bslma::ManagedPtr item(new (d_itemPool_p->allocate()) + bslma::ManagedPtr item(new (d_itemPool.allocate()) Item(d_allocator_p), this, deleteItem); diff --git a/src/groups/mqb/mqbnet/mqbnet_channel.h b/src/groups/mqb/mqbnet/mqbnet_channel.h index 65a00a27f..66f1c104f 100644 --- a/src/groups/mqb/mqbnet/mqbnet_channel.h +++ b/src/groups/mqb/mqbnet/mqbnet_channel.h @@ -348,8 +348,6 @@ class Channel { public: // PUBLIC TYPES - - typedef bdlma::ConcurrentPool ItemPool; typedef bmqc::MonitoredQueue< bdlcc::SingleConsumerQueue > > ItemQueue; @@ -366,18 +364,15 @@ class Channel { e_HWM = 5 // HWM }; - public: - // CONSTANTS - static const int k_ITEM_SIZE = sizeof(Item); // for ItemPool - private: // CONSTANTS static const int k_NAGLE_PACKET_SIZE = 1024 * 1024; // 1MB; // DATA + /// Allocator store to spawn new allocators for sub-components bmqma::CountingAllocatorStore d_allocators; - // Counting allocator + /// Counting allocator bslma::Allocator* d_allocator_p; bmqp::PutEventBuilder d_putBuilder; @@ -390,7 +385,7 @@ class Channel { bmqp::RejectEventBuilder d_rejectBuilder; - ItemPool* d_itemPool_p; + bdlma::ConcurrentPool d_itemPool; // Pool of 'Item' objects. ItemQueue d_buffer; @@ -513,7 +508,6 @@ class Channel { /// Create a new object using the specified `allocator`. Channel(bdlbb::BlobBufferFactory* blobBufferFactory, - ItemPool* itemPool, const bsl::string& name, bslma::Allocator* allocator); diff --git a/src/groups/mqb/mqbnet/mqbnet_channel.t.cpp b/src/groups/mqb/mqbnet/mqbnet_channel.t.cpp index a667e1117..2af80dba0 100644 --- a/src/groups/mqb/mqbnet/mqbnet_channel.t.cpp +++ b/src/groups/mqb/mqbnet/mqbnet_channel.t.cpp @@ -725,9 +725,7 @@ static void test1_write() // ------------------------------------------------------------------------ { bdlbb::PooledBlobBufferFactory bufferFactory(k_BUFFER_SIZE, s_allocator_p); - mqbnet::Channel::ItemPool itemPool(mqbnet::Channel::k_ITEM_SIZE, - s_allocator_p); - mqbnet::Channel channel(&bufferFactory, &itemPool, "test", s_allocator_p); + mqbnet::Channel channel(&bufferFactory, "test", s_allocator_p); bsl::shared_ptr testChannel( new (*s_allocator_p) @@ -793,9 +791,7 @@ static void test2_highWatermark() // ------------------------------------------------------------------------ { bdlbb::PooledBlobBufferFactory bufferFactory(k_BUFFER_SIZE, s_allocator_p); - mqbnet::Channel::ItemPool itemPool(mqbnet::Channel::k_ITEM_SIZE, - s_allocator_p); - mqbnet::Channel channel(&bufferFactory, &itemPool, "test", s_allocator_p); + mqbnet::Channel channel(&bufferFactory, "test", s_allocator_p); bsl::shared_ptr testChannel( new (*s_allocator_p) @@ -885,9 +881,7 @@ static void test3_highWatermarkInWriteCb() // ------------------------------------------------------------------------ { bdlbb::PooledBlobBufferFactory bufferFactory(k_BUFFER_SIZE, s_allocator_p); - mqbnet::Channel::ItemPool itemPool(mqbnet::Channel::k_ITEM_SIZE, - s_allocator_p); - mqbnet::Channel channel(&bufferFactory, &itemPool, "test", s_allocator_p); + mqbnet::Channel channel(&bufferFactory, "test", s_allocator_p); bsl::shared_ptr testChannel( new (*s_allocator_p) @@ -977,9 +971,7 @@ static void test4_controlBlob() // ------------------------------------------------------------------------ { bdlbb::PooledBlobBufferFactory bufferFactory(k_BUFFER_SIZE, s_allocator_p); - mqbnet::Channel::ItemPool itemPool(mqbnet::Channel::k_ITEM_SIZE, - s_allocator_p); - mqbnet::Channel channel(&bufferFactory, &itemPool, "test", s_allocator_p); + mqbnet::Channel channel(&bufferFactory, "test", s_allocator_p); bsl::shared_ptr testChannel( new (*s_allocator_p) @@ -1048,9 +1040,7 @@ static void test5_reconnect() // ------------------------------------------------------------------------ { bdlbb::PooledBlobBufferFactory bufferFactory(k_BUFFER_SIZE, s_allocator_p); - mqbnet::Channel::ItemPool itemPool(mqbnet::Channel::k_ITEM_SIZE, - s_allocator_p); - mqbnet::Channel channel(&bufferFactory, &itemPool, "test", s_allocator_p); + mqbnet::Channel channel(&bufferFactory, "test", s_allocator_p); bsl::shared_ptr testChannel( new (*s_allocator_p) @@ -1129,9 +1119,7 @@ static void test6_weakData() // ------------------------------------------------------------------------ { bdlbb::PooledBlobBufferFactory bufferFactory(k_BUFFER_SIZE, s_allocator_p); - mqbnet::Channel::ItemPool itemPool(mqbnet::Channel::k_ITEM_SIZE, - s_allocator_p); - mqbnet::Channel channel(&bufferFactory, &itemPool, "test", s_allocator_p); + mqbnet::Channel channel(&bufferFactory, "test", s_allocator_p); bsl::shared_ptr testChannel( new (*s_allocator_p) diff --git a/src/groups/mqb/mqbnet/mqbnet_clusterimp.cpp b/src/groups/mqb/mqbnet/mqbnet_clusterimp.cpp index 091d9e5db..a5c4ccdb2 100644 --- a/src/groups/mqb/mqbnet/mqbnet_clusterimp.cpp +++ b/src/groups/mqb/mqbnet/mqbnet_clusterimp.cpp @@ -45,12 +45,12 @@ namespace mqbnet { ClusterNodeImp::ClusterNodeImp(ClusterImp* cluster, const mqbcfg::ClusterNode& config, bdlbb::BlobBufferFactory* blobBufferFactory, - Channel::ItemPool* itemPool, bslma::Allocator* allocator) -: d_cluster_p(cluster) +: d_allocators(allocator) +, d_cluster_p(cluster) , d_config(config, allocator) , d_description(allocator) -, d_channel(blobBufferFactory, itemPool, config.name(), allocator) +, d_channel(blobBufferFactory, config.name(), d_allocators.get(config.name())) , d_identity(allocator) , d_isReading(false) { @@ -181,10 +181,8 @@ ClusterImp::ClusterImp(const bsl::string& name, const bsl::vector& nodesConfig, int selfNodeId, bdlbb::BlobBufferFactory* blobBufferFactory, - Channel::ItemPool* itemPool, bslma::Allocator* allocator) -: d_allocator_p(allocator) -, d_name(name, allocator) +: d_name(name, allocator) , d_nodesConfig(nodesConfig, allocator) , d_selfNodeId(selfNodeId) , d_selfNode(0) // set below @@ -199,7 +197,7 @@ ClusterImp::ClusterImp(const bsl::string& name, bsl::vector::const_iterator nodeIt; for (nodeIt = d_nodesConfig.begin(); nodeIt != d_nodesConfig.end(); ++nodeIt) { - d_nodes.emplace_back(this, *nodeIt, blobBufferFactory, itemPool); + d_nodes.emplace_back(this, *nodeIt, blobBufferFactory); d_nodesList.emplace_back(&d_nodes.back()); if (nodeIt->id() == selfNodeId) { d_selfNode = d_nodesList.back(); diff --git a/src/groups/mqb/mqbnet/mqbnet_clusterimp.h b/src/groups/mqb/mqbnet/mqbnet_clusterimp.h index 3d53a69d6..ce23a0f8a 100644 --- a/src/groups/mqb/mqbnet/mqbnet_clusterimp.h +++ b/src/groups/mqb/mqbnet/mqbnet_clusterimp.h @@ -75,6 +75,9 @@ class ClusterNodeImp : public ClusterNode { private: // DATA + /// Allocator store to spawn new allocators for sub-components + bmqma::CountingAllocatorStore d_allocators; + ClusterImp* d_cluster_p; // Cluster this node belongs to @@ -113,7 +116,6 @@ class ClusterNodeImp : public ClusterNode { ClusterNodeImp(ClusterImp* cluster, const mqbcfg::ClusterNode& config, bdlbb::BlobBufferFactory* blobBufferFactory, - Channel::ItemPool* itemPool, bslma::Allocator* allocator); /// Destructor. @@ -196,9 +198,6 @@ class ClusterImp : public Cluster { private: // DATA - bslma::Allocator* d_allocator_p; - // Allocator to use - bsl::string d_name; // Name of this Cluster @@ -277,7 +276,6 @@ class ClusterImp : public Cluster { const bsl::vector& nodesConfig, int selfNodeId, bdlbb::BlobBufferFactory* blobBufferFactory, - Channel::ItemPool* itemPool, bslma::Allocator* allocator); /// Destructor diff --git a/src/groups/mqb/mqbnet/mqbnet_dummysession.t.cpp b/src/groups/mqb/mqbnet/mqbnet_dummysession.t.cpp index b4ca99870..e20a2e68d 100644 --- a/src/groups/mqb/mqbnet/mqbnet_dummysession.t.cpp +++ b/src/groups/mqb/mqbnet/mqbnet_dummysession.t.cpp @@ -52,18 +52,14 @@ static void test1_BreathingTest() mqbcfg::ClusterDefinition clusterConfig(s_allocator_p); bdlbb::PooledBlobBufferFactory bufferFactory(1024, s_allocator_p); - mqbnet::Channel::ItemPool itemPool(mqbnet::Channel::k_ITEM_SIZE, - s_allocator_p); mqbnet::MockCluster mockCluster(clusterConfig, &bufferFactory, - &itemPool, s_allocator_p); mqbcfg::ClusterNode clusterNodeConfig(s_allocator_p); mqbnet::MockClusterNode mockClusterNode(&mockCluster, clusterNodeConfig, &bufferFactory, - &itemPool, s_allocator_p); bsl::shared_ptr testChannel; diff --git a/src/groups/mqb/mqbnet/mqbnet_mockcluster.cpp b/src/groups/mqb/mqbnet/mqbnet_mockcluster.cpp index 842a6472f..7596f1066 100644 --- a/src/groups/mqb/mqbnet/mqbnet_mockcluster.cpp +++ b/src/groups/mqb/mqbnet/mqbnet_mockcluster.cpp @@ -41,12 +41,11 @@ namespace mqbnet { MockClusterNode::MockClusterNode(MockCluster* cluster, const mqbcfg::ClusterNode& config, bdlbb::BlobBufferFactory* blobBufferFactory, - Channel::ItemPool* itemPool, bslma::Allocator* allocator) : d_cluster_p(cluster) , d_config(config, allocator) , d_description(allocator) -, d_channel(blobBufferFactory, itemPool, config.name(), allocator) +, d_channel(blobBufferFactory, config.name(), allocator) , d_identity(allocator) , d_isReading(false) { @@ -156,7 +155,6 @@ void MockCluster::notifyObserversOfNodeStateChange(ClusterNode* node, MockCluster::MockCluster(const mqbcfg::ClusterDefinition& config, bdlbb::BlobBufferFactory* blobBufferFactory, - Channel::ItemPool* itemPool, bslma::Allocator* allocator) : d_allocator_p(allocator) , d_config(config, allocator) @@ -171,7 +169,7 @@ MockCluster::MockCluster(const mqbcfg::ClusterDefinition& config, bsl::vector::const_iterator nodeIt; for (nodeIt = d_config.nodes().begin(); nodeIt != d_config.nodes().end(); ++nodeIt) { - d_nodes.emplace_back(this, *nodeIt, blobBufferFactory, itemPool); + d_nodes.emplace_back(this, *nodeIt, blobBufferFactory); d_nodesList.emplace_back(&d_nodes.back()); } } diff --git a/src/groups/mqb/mqbnet/mqbnet_mockcluster.h b/src/groups/mqb/mqbnet/mqbnet_mockcluster.h index c68ca501c..44582d10e 100644 --- a/src/groups/mqb/mqbnet/mqbnet_mockcluster.h +++ b/src/groups/mqb/mqbnet/mqbnet_mockcluster.h @@ -100,7 +100,6 @@ class MockClusterNode : public ClusterNode { MockClusterNode(MockCluster* cluster, const mqbcfg::ClusterNode& config, bdlbb::BlobBufferFactory* blobBufferFactory, - Channel::ItemPool* itemPool, bslma::Allocator* allocator); /// Destructor. @@ -251,7 +250,6 @@ class MockCluster : public Cluster { /// `allocator`. MockCluster(const mqbcfg::ClusterDefinition& config, bdlbb::BlobBufferFactory* blobBufferFactory, - Channel::ItemPool* itemPool, bslma::Allocator* allocator); /// Destructor diff --git a/src/groups/mqb/mqbnet/mqbnet_transportmanager.cpp b/src/groups/mqb/mqbnet/mqbnet_transportmanager.cpp index b1f689745..5dab27780 100644 --- a/src/groups/mqb/mqbnet/mqbnet_transportmanager.cpp +++ b/src/groups/mqb/mqbnet/mqbnet_transportmanager.cpp @@ -103,7 +103,7 @@ void TransportManager::onClusterReleased(void* object, void* transportManager) cluster->closeChannels(); // And delete the cluster - self->d_allocator_p->deleteObject(cluster); + self->d_allocators.get(cluster->name())->deleteObject(cluster); } int TransportManager::createAndStartTcpInterface( @@ -112,14 +112,16 @@ int TransportManager::createAndStartTcpInterface( { // executed by the *MAIN* thread - d_tcpSessionFactory_mp.load(new (*d_allocator_p) + bslma::Allocator* alloc = d_allocators.get("Interface" + + bsl::to_string(config.port())); + d_tcpSessionFactory_mp.load(new (*alloc) TCPSessionFactory(config, d_scheduler_p, d_blobBufferFactory_p, d_negotiator_mp.get(), d_statController_p, - d_allocator_p), - d_allocator_p); + alloc), + alloc); return d_tcpSessionFactory_mp->start(errorDescription); } @@ -348,11 +350,10 @@ TransportManager::TransportManager(bdlmt::EventScheduler* scheduler, bslma::ManagedPtr& negotiator, mqbstat::StatController* statController, bslma::Allocator* allocator) -: d_allocator_p(allocator) +: d_allocators(allocator) , d_state(e_STOPPED) , d_scheduler_p(scheduler) , d_blobBufferFactory_p(blobBufferFactory) -, d_itemPool(Channel::k_ITEM_SIZE, bsls::BlockGrowth::BSLS_CONSTANT, allocator) , d_negotiator_mp(negotiator) , d_statController_p(statController) , d_tcpSessionFactory_mp(0) @@ -520,14 +521,11 @@ int TransportManager::createCluster( userDataSp = *userData; } - bslma::ManagedPtr cluster(new (*d_allocator_p) - ClusterImp(name, - nodes, - myNodeId, - d_blobBufferFactory_p, - &d_itemPool, - d_allocator_p), - d_allocator_p); + bslma::Allocator* alloc = d_allocators.get(name); + bslma::ManagedPtr cluster( + new (*alloc) + ClusterImp(name, nodes, myNodeId, d_blobBufferFactory_p, alloc), + alloc); // At the moment, only TCP is supported, validate that bsl::vector::const_iterator nodeIt; @@ -558,7 +556,7 @@ int TransportManager::createCluster( // config, the node must exist bsl::shared_ptr connectionState; - connectionState.createInplace(d_allocator_p); + connectionState.createInplace(d_allocators.get("ConnectionStates")); connectionState->d_endpoint = tcpConfig.endpoint(); connectionState->d_isClusterConnection = true; @@ -636,7 +634,7 @@ int TransportManager::connectOut(bsl::ostream& errorDescription, } bsl::shared_ptr state; - state.createInplace(d_allocator_p); + state.createInplace(d_allocators.get("ConnectionStates")); { bslmt::LockGuard guard(&d_mutex); // d_mutex LOCK diff --git a/src/groups/mqb/mqbnet/mqbnet_transportmanager.h b/src/groups/mqb/mqbnet/mqbnet_transportmanager.h index ccfb39da3..82ea9744f 100644 --- a/src/groups/mqb/mqbnet/mqbnet_transportmanager.h +++ b/src/groups/mqb/mqbnet/mqbnet_transportmanager.h @@ -181,8 +181,8 @@ class TransportManager { private: // DATA - bslma::Allocator* d_allocator_p; - // Allocator to use + /// Allocator store to spawn new allocators for sub-components + bmqma::CountingAllocatorStore d_allocators; bsls::AtomicInt d_state; // enum State. Always changed on @@ -195,8 +195,6 @@ class TransportManager { // BlobBufferFactory to use by the // sessions - Channel::ItemPool d_itemPool; - bslma::ManagedPtr d_negotiator_mp; // Negotiation to use diff --git a/src/groups/mqb/mqbs/mqbs_filestore.t.cpp b/src/groups/mqb/mqbs/mqbs_filestore.t.cpp index 0bddb7814..4acbbfe45 100644 --- a/src/groups/mqb/mqbs/mqbs_filestore.t.cpp +++ b/src/groups/mqb/mqbs/mqbs_filestore.t.cpp @@ -145,7 +145,6 @@ struct Tester { // DATA bdlmt::EventScheduler d_scheduler; bdlbb::PooledBlobBufferFactory d_bufferFactory; - mqbnet::Channel::ItemPool d_itemPool; bsl::string d_clusterLocation; bsl::string d_clusterArchiveLocation; BlobSpPool d_blobSpPool; @@ -170,7 +169,6 @@ struct Tester { Tester(const char* location) : d_scheduler(bsls::SystemClockType::e_MONOTONIC, s_allocator_p) , d_bufferFactory(1024, s_allocator_p) - , d_itemPool(mqbnet::Channel::k_ITEM_SIZE, s_allocator_p) , d_clusterLocation(location, s_allocator_p) , d_clusterArchiveLocation(location, s_allocator_p) , d_blobSpPool(bdlf::BindUtil::bind(&createBlob, @@ -225,7 +223,6 @@ struct Tester { d_cluster_mp.load(new (*s_allocator_p) mqbnet::MockCluster(d_clusterCfg, &d_bufferFactory, - &d_itemPool, s_allocator_p), s_allocator_p); d_node_p = d_cluster_mp->lookupNode(k_NODE_ID); From 0f582f02d4616373b7077930408b492d1a7d5a95 Mon Sep 17 00:00:00 2001 From: wlei29 Date: Mon, 28 Oct 2024 15:19:50 -0400 Subject: [PATCH 07/17] Fix[doc]: fix document bmqa example type Signed-off-by: wlei29 --- src/groups/bmq/bmqa/bmqa_messageeventbuilder.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/groups/bmq/bmqa/bmqa_messageeventbuilder.h b/src/groups/bmq/bmqa/bmqa_messageeventbuilder.h index 57c85aa41..3d46fe677 100644 --- a/src/groups/bmq/bmqa/bmqa_messageeventbuilder.h +++ b/src/groups/bmq/bmqa/bmqa_messageeventbuilder.h @@ -85,7 +85,7 @@ /// // Session start up logic omitted for brevity. /// /// // Obtain a valid instance of message properties. -/// bmqt::MessageProperties properties; +/// bmqa::MessageProperties properties; /// session.loadMessageProperties(&properties); /// /// // Set common properties that will be applicable to all messages sent by @@ -160,7 +160,7 @@ /// // Session start up logic omitted for brevity. /// /// // Obtain a valid instance of message properties. -/// bmqt::MessageProperties properties; +/// bmqa::MessageProperties properties; /// session.loadMessageProperties(&properties); /// /// // Set common properties that will be applicable to all messages sent by From 044fd8cd6e4337f354cb0a4a92ae98beaee79164 Mon Sep 17 00:00:00 2001 From: Taylor Foxhall Date: Tue, 29 Oct 2024 11:23:25 -0400 Subject: [PATCH 08/17] [BMQ]: Fix leaking internal headers in bmqa_mocksession Also fixes an incorrect change that marked bmqt as a private package Signed-off-by: Taylor Foxhall --- src/groups/bmq/CMakeLists.txt | 2 +- src/groups/bmq/bmqa/bmqa_mocksession.cpp | 13 ++++++++----- src/groups/bmq/bmqa/bmqa_mocksession.h | 6 ++++-- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/groups/bmq/CMakeLists.txt b/src/groups/bmq/CMakeLists.txt index 6e3ea38bb..09d000305 100644 --- a/src/groups/bmq/CMakeLists.txt +++ b/src/groups/bmq/CMakeLists.txt @@ -49,10 +49,10 @@ set(BMQ_PRIVATE_PACKAGES bmqst bmqstm bmqsys - bmqt bmqtsk bmqtst bmqu + bmqvt ) target_bmq_style_uor( bmq PRIVATE_PACKAGES ${BMQ_PRIVATE_PACKAGES} ) diff --git a/src/groups/bmq/bmqa/bmqa_mocksession.cpp b/src/groups/bmq/bmqa/bmqa_mocksession.cpp index 80f57c810..6ca08d409 100644 --- a/src/groups/bmq/bmqa/bmqa_mocksession.cpp +++ b/src/groups/bmq/bmqa/bmqa_mocksession.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -742,7 +743,7 @@ void MockSession::initializeStats() start.setLevel(0).setIndex(0); end.setLevel(0).setIndex(1); bmqimp::QueueStatsUtil::initializeStats(d_queuesStats_sp.get(), - &d_rootStatContext, + d_rootStatContext_mp.get(), start, end, d_allocator_p); @@ -961,8 +962,9 @@ MockSession::MockSession(const bmqt::SessionOptions& options, bslma::Default::allocator(allocator)), bslma::Default::allocator(allocator)) , d_postedEvents(bslma::Default::allocator(allocator)) -, d_rootStatContext(bmqst::StatContextConfiguration("MockSession", allocator), - allocator) +, d_rootStatContext_mp(bslma::ManagedPtrUtil::makeManaged( + bmqst::StatContextConfiguration("MockSession", allocator), + allocator)) , d_queuesStats_sp(new(*bslma::Default::allocator(allocator)) bmqimp::Stat(bslma::Default::allocator(allocator)), bslma::Default::allocator(allocator)) @@ -1004,8 +1006,9 @@ MockSession::MockSession(bslma::ManagedPtr eventHandler, bslma::Default::allocator(allocator)), bslma::Default::allocator(allocator)) , d_postedEvents(bslma::Default::allocator(allocator)) -, d_rootStatContext(bmqst::StatContextConfiguration("MockSession", allocator), - allocator) +, d_rootStatContext_mp(bslma::ManagedPtrUtil::makeManaged( + bmqst::StatContextConfiguration("MockSession", allocator), + allocator)) , d_queuesStats_sp(new(*bslma::Default::allocator(allocator)) bmqimp::Stat(bslma::Default::allocator(allocator)), bslma::Default::allocator(allocator)) diff --git a/src/groups/bmq/bmqa/bmqa_mocksession.h b/src/groups/bmq/bmqa/bmqa_mocksession.h index d4d095dc8..4f449b9fa 100644 --- a/src/groups/bmq/bmqa/bmqa_mocksession.h +++ b/src/groups/bmq/bmqa/bmqa_mocksession.h @@ -548,7 +548,6 @@ #include #include #include // for 'bmqa::SessionEventHandler' -#include #include #include @@ -586,6 +585,9 @@ class MessageCorrelationIdContainer; namespace bmqimp { struct Stat; } +namespace bmqst { +class StatContext; +} namespace bmqa { @@ -1040,7 +1042,7 @@ class MockSession : public AbstractSession { mutable bslmt::Mutex d_mutex; /// Top level stat context for this mocked Session. - bmqst::StatContext d_rootStatContext; + bslma::ManagedPtr d_rootStatContext_mp; /// Stats for all queues StatImplSp d_queuesStats_sp; From e4bf5f6bc28d6199ddb10a27c300387e7d1c3be3 Mon Sep 17 00:00:00 2001 From: Taylor Foxhall Date: Tue, 20 Feb 2024 17:56:22 +0000 Subject: [PATCH 09/17] Support listening on open ports - Add a new field for the broker config to list TCP interfaces with a port and name - Change how the port configuration is read to ignore the port field on the TCP interface when the new listeners are specified - Add a test fixture to support configuring clusters with multiple TCP interfaces open - Add an integration test to verify end-to-end connection on a cluster with multiple ports Signed-off-by: Taylor Foxhall --- src/groups/mqb/mqbcfg/doc/mqbcfg.txt | 5 +- src/groups/mqb/mqbcfg/mqbcfg.xsd | 25 + src/groups/mqb/mqbcfg/mqbcfg_messages.cpp | 905 ++-- src/groups/mqb/mqbcfg/mqbcfg_messages.h | 4020 +++++++++-------- .../mqbcfg_tcpinterfaceconfigvalidator.cpp | 109 + .../mqbcfg_tcpinterfaceconfigvalidator.h | 85 + .../mqbcfg_tcpinterfaceconfigvalidator.t.cpp | 125 + src/groups/mqb/mqbcfg/package/mqbcfg.mem | 1 + .../mqb/mqbnet/mqbnet_tcpsessionfactory.cpp | 138 +- .../mqb/mqbnet/mqbnet_tcpsessionfactory.h | 46 +- .../mqb/mqbnet/mqbnet_transportmanager.cpp | 4 + src/integration-tests/test_breathing.py | 53 + .../blazingmq/dev/configurator/__init__.py | 29 +- .../dev/configurator/configurator.py | 49 +- src/python/blazingmq/dev/it/cluster.py | 32 +- src/python/blazingmq/dev/it/fixtures.py | 91 +- src/python/blazingmq/dev/it/process/broker.py | 18 +- src/python/blazingmq/dev/it/process/client.py | 17 +- .../blazingmq/dev/it/tweaks/generated.py | 21 + src/python/blazingmq/dev/it/util.py | 15 +- src/python/blazingmq/schemas/mqbcfg.py | 235 +- 21 files changed, 3658 insertions(+), 2365 deletions(-) create mode 100644 src/groups/mqb/mqbcfg/mqbcfg_tcpinterfaceconfigvalidator.cpp create mode 100644 src/groups/mqb/mqbcfg/mqbcfg_tcpinterfaceconfigvalidator.h create mode 100644 src/groups/mqb/mqbcfg/mqbcfg_tcpinterfaceconfigvalidator.t.cpp diff --git a/src/groups/mqb/mqbcfg/doc/mqbcfg.txt b/src/groups/mqb/mqbcfg/doc/mqbcfg.txt index 52b1c8982..596eaff16 100644 --- a/src/groups/mqb/mqbcfg/doc/mqbcfg.txt +++ b/src/groups/mqb/mqbcfg/doc/mqbcfg.txt @@ -10,11 +10,12 @@ broker, as well as the generated corresponding messages component. /Hierarchical Synopsis /--------------------- - The 'mqbcfg' package currently has 2 components having 2 level of physical + The 'mqbcfg' package currently has 3 components having 2 levels of physical dependency. The list below shows the hierarchical ordering of the components. .. 1. mqbcfg_messages 2. mqbcfg_brokerconfig + 2. mqbcfg_tcpinterfaceconfigvalidator .. /Component Synopsis @@ -23,3 +24,5 @@ broker, as well as the generated corresponding messages component. : BMQBroker generated configuration messages. : 'mqbcfg_brokerconfig' : Provide global access to broker configuration. +: 'mqbcfg_tcpinterfaceconfigvalidator' +: Provide validation logic for `appConfig/networkInterfaces/tcpInterface/listeners` in the broker configuration. diff --git a/src/groups/mqb/mqbcfg/mqbcfg.xsd b/src/groups/mqb/mqbcfg/mqbcfg.xsd index aa38a39c9..c970f6b31 100644 --- a/src/groups/mqb/mqbcfg/mqbcfg.xsd +++ b/src/groups/mqb/mqbcfg/mqbcfg.xsd @@ -233,6 +233,10 @@ + name.................: + The name of the TCP session manager. + port.................: + (Deprecated) The port to receive connections. lowWatermark.........: highWatermark........: Watermarks used for channels with a client or proxy. @@ -243,6 +247,9 @@ heartbeatIntervalMs..: How often (in milliseconds) to check if the channel received data, and emit heartbeat. 0 to globally disable. + listeners: + A list of listener interfaces to receive TCP connections from. When non-empty + this option overrides the listener specified by port. @@ -255,6 +262,24 @@ + + + + + + + + This type describes the information needed for the broker to open a TCP listener. + + name.................: + A name to associate this listener to. + port.................: + The port this listener will accept connections on. + + + + + diff --git a/src/groups/mqb/mqbcfg/mqbcfg_messages.cpp b/src/groups/mqb/mqbcfg/mqbcfg_messages.cpp index 61585754c..42968e183 100644 --- a/src/groups/mqb/mqbcfg/mqbcfg_messages.cpp +++ b/src/groups/mqb/mqbcfg/mqbcfg_messages.cpp @@ -1,4 +1,4 @@ -// Copyright 2014-2024 Bloomberg Finance L.P. +// Copyright 2024 Bloomberg Finance L.P. // SPDX-License-Identifier: Apache-2.0 // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -12,7 +12,6 @@ // 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. - // mqbcfg_messages.cpp *DO NOT EDIT* @generated -*-C++-*- #include @@ -2261,25 +2260,15 @@ bsl::ostream& TcpClusterNodeConnection::print(bsl::ostream& stream, return stream; } -// ------------------------ -// class TcpInterfaceConfig -// ------------------------ +// -------------------------- +// class TcpInterfaceListener +// -------------------------- // CONSTANTS -const char TcpInterfaceConfig::CLASS_NAME[] = "TcpInterfaceConfig"; - -const int TcpInterfaceConfig::DEFAULT_INITIALIZER_MAX_CONNECTIONS = 10000; - -const bsls::Types::Int64 - TcpInterfaceConfig::DEFAULT_INITIALIZER_NODE_LOW_WATERMARK = 1024; - -const bsls::Types::Int64 - TcpInterfaceConfig::DEFAULT_INITIALIZER_NODE_HIGH_WATERMARK = 2048; - -const int TcpInterfaceConfig::DEFAULT_INITIALIZER_HEARTBEAT_INTERVAL_MS = 3000; +const char TcpInterfaceListener::CLASS_NAME[] = "TcpInterfaceListener"; -const bdlat_AttributeInfo TcpInterfaceConfig::ATTRIBUTE_INFO_ARRAY[] = { +const bdlat_AttributeInfo TcpInterfaceListener::ATTRIBUTE_INFO_ARRAY[] = { {ATTRIBUTE_ID_NAME, "name", sizeof("name") - 1, @@ -2289,51 +2278,16 @@ const bdlat_AttributeInfo TcpInterfaceConfig::ATTRIBUTE_INFO_ARRAY[] = { "port", sizeof("port") - 1, "", - bdlat_FormattingMode::e_DEC}, - {ATTRIBUTE_ID_IO_THREADS, - "ioThreads", - sizeof("ioThreads") - 1, - "", - bdlat_FormattingMode::e_DEC}, - {ATTRIBUTE_ID_MAX_CONNECTIONS, - "maxConnections", - sizeof("maxConnections") - 1, - "", - bdlat_FormattingMode::e_DEC}, - {ATTRIBUTE_ID_LOW_WATERMARK, - "lowWatermark", - sizeof("lowWatermark") - 1, - "", - bdlat_FormattingMode::e_DEC}, - {ATTRIBUTE_ID_HIGH_WATERMARK, - "highWatermark", - sizeof("highWatermark") - 1, - "", - bdlat_FormattingMode::e_DEC}, - {ATTRIBUTE_ID_NODE_LOW_WATERMARK, - "nodeLowWatermark", - sizeof("nodeLowWatermark") - 1, - "", - bdlat_FormattingMode::e_DEC}, - {ATTRIBUTE_ID_NODE_HIGH_WATERMARK, - "nodeHighWatermark", - sizeof("nodeHighWatermark") - 1, - "", - bdlat_FormattingMode::e_DEC}, - {ATTRIBUTE_ID_HEARTBEAT_INTERVAL_MS, - "heartbeatIntervalMs", - sizeof("heartbeatIntervalMs") - 1, - "", bdlat_FormattingMode::e_DEC}}; // CLASS METHODS const bdlat_AttributeInfo* -TcpInterfaceConfig::lookupAttributeInfo(const char* name, int nameLength) +TcpInterfaceListener::lookupAttributeInfo(const char* name, int nameLength) { - for (int i = 0; i < 9; ++i) { + for (int i = 0; i < 2; ++i) { const bdlat_AttributeInfo& attributeInfo = - TcpInterfaceConfig::ATTRIBUTE_INFO_ARRAY[i]; + TcpInterfaceListener::ATTRIBUTE_INFO_ARRAY[i]; if (nameLength == attributeInfo.d_nameLength && 0 == bsl::memcmp(attributeInfo.d_name_p, name, nameLength)) { @@ -2344,107 +2298,59 @@ TcpInterfaceConfig::lookupAttributeInfo(const char* name, int nameLength) return 0; } -const bdlat_AttributeInfo* TcpInterfaceConfig::lookupAttributeInfo(int id) +const bdlat_AttributeInfo* TcpInterfaceListener::lookupAttributeInfo(int id) { switch (id) { case ATTRIBUTE_ID_NAME: return &ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_NAME]; case ATTRIBUTE_ID_PORT: return &ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_PORT]; - case ATTRIBUTE_ID_IO_THREADS: - return &ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_IO_THREADS]; - case ATTRIBUTE_ID_MAX_CONNECTIONS: - return &ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_CONNECTIONS]; - case ATTRIBUTE_ID_LOW_WATERMARK: - return &ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_LOW_WATERMARK]; - case ATTRIBUTE_ID_HIGH_WATERMARK: - return &ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_HIGH_WATERMARK]; - case ATTRIBUTE_ID_NODE_LOW_WATERMARK: - return &ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_NODE_LOW_WATERMARK]; - case ATTRIBUTE_ID_NODE_HIGH_WATERMARK: - return &ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_NODE_HIGH_WATERMARK]; - case ATTRIBUTE_ID_HEARTBEAT_INTERVAL_MS: - return &ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_HEARTBEAT_INTERVAL_MS]; default: return 0; } } // CREATORS -TcpInterfaceConfig::TcpInterfaceConfig(bslma::Allocator* basicAllocator) -: d_lowWatermark() -, d_highWatermark() -, d_nodeLowWatermark(DEFAULT_INITIALIZER_NODE_LOW_WATERMARK) -, d_nodeHighWatermark(DEFAULT_INITIALIZER_NODE_HIGH_WATERMARK) -, d_name(basicAllocator) +TcpInterfaceListener::TcpInterfaceListener(bslma::Allocator* basicAllocator) +: d_name(basicAllocator) , d_port() -, d_ioThreads() -, d_maxConnections(DEFAULT_INITIALIZER_MAX_CONNECTIONS) -, d_heartbeatIntervalMs(DEFAULT_INITIALIZER_HEARTBEAT_INTERVAL_MS) { } -TcpInterfaceConfig::TcpInterfaceConfig(const TcpInterfaceConfig& original, - bslma::Allocator* basicAllocator) -: d_lowWatermark(original.d_lowWatermark) -, d_highWatermark(original.d_highWatermark) -, d_nodeLowWatermark(original.d_nodeLowWatermark) -, d_nodeHighWatermark(original.d_nodeHighWatermark) -, d_name(original.d_name, basicAllocator) +TcpInterfaceListener::TcpInterfaceListener( + const TcpInterfaceListener& original, + bslma::Allocator* basicAllocator) +: d_name(original.d_name, basicAllocator) , d_port(original.d_port) -, d_ioThreads(original.d_ioThreads) -, d_maxConnections(original.d_maxConnections) -, d_heartbeatIntervalMs(original.d_heartbeatIntervalMs) { } #if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) && \ defined(BSLS_COMPILERFEATURES_SUPPORT_NOEXCEPT) -TcpInterfaceConfig::TcpInterfaceConfig(TcpInterfaceConfig&& original) noexcept -: d_lowWatermark(bsl::move(original.d_lowWatermark)), - d_highWatermark(bsl::move(original.d_highWatermark)), - d_nodeLowWatermark(bsl::move(original.d_nodeLowWatermark)), - d_nodeHighWatermark(bsl::move(original.d_nodeHighWatermark)), - d_name(bsl::move(original.d_name)), - d_port(bsl::move(original.d_port)), - d_ioThreads(bsl::move(original.d_ioThreads)), - d_maxConnections(bsl::move(original.d_maxConnections)), - d_heartbeatIntervalMs(bsl::move(original.d_heartbeatIntervalMs)) +TcpInterfaceListener::TcpInterfaceListener(TcpInterfaceListener&& original) + noexcept : d_name(bsl::move(original.d_name)), + d_port(bsl::move(original.d_port)) { } -TcpInterfaceConfig::TcpInterfaceConfig(TcpInterfaceConfig&& original, - bslma::Allocator* basicAllocator) -: d_lowWatermark(bsl::move(original.d_lowWatermark)) -, d_highWatermark(bsl::move(original.d_highWatermark)) -, d_nodeLowWatermark(bsl::move(original.d_nodeLowWatermark)) -, d_nodeHighWatermark(bsl::move(original.d_nodeHighWatermark)) -, d_name(bsl::move(original.d_name), basicAllocator) +TcpInterfaceListener::TcpInterfaceListener(TcpInterfaceListener&& original, + bslma::Allocator* basicAllocator) +: d_name(bsl::move(original.d_name), basicAllocator) , d_port(bsl::move(original.d_port)) -, d_ioThreads(bsl::move(original.d_ioThreads)) -, d_maxConnections(bsl::move(original.d_maxConnections)) -, d_heartbeatIntervalMs(bsl::move(original.d_heartbeatIntervalMs)) { } #endif -TcpInterfaceConfig::~TcpInterfaceConfig() +TcpInterfaceListener::~TcpInterfaceListener() { } // MANIPULATORS -TcpInterfaceConfig& -TcpInterfaceConfig::operator=(const TcpInterfaceConfig& rhs) +TcpInterfaceListener& +TcpInterfaceListener::operator=(const TcpInterfaceListener& rhs) { if (this != &rhs) { - d_name = rhs.d_name; - d_port = rhs.d_port; - d_ioThreads = rhs.d_ioThreads; - d_maxConnections = rhs.d_maxConnections; - d_lowWatermark = rhs.d_lowWatermark; - d_highWatermark = rhs.d_highWatermark; - d_nodeLowWatermark = rhs.d_nodeLowWatermark; - d_nodeHighWatermark = rhs.d_nodeHighWatermark; - d_heartbeatIntervalMs = rhs.d_heartbeatIntervalMs; + d_name = rhs.d_name; + d_port = rhs.d_port; } return *this; @@ -2452,54 +2358,34 @@ TcpInterfaceConfig::operator=(const TcpInterfaceConfig& rhs) #if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) && \ defined(BSLS_COMPILERFEATURES_SUPPORT_NOEXCEPT) -TcpInterfaceConfig& TcpInterfaceConfig::operator=(TcpInterfaceConfig&& rhs) +TcpInterfaceListener& +TcpInterfaceListener::operator=(TcpInterfaceListener&& rhs) { if (this != &rhs) { - d_name = bsl::move(rhs.d_name); - d_port = bsl::move(rhs.d_port); - d_ioThreads = bsl::move(rhs.d_ioThreads); - d_maxConnections = bsl::move(rhs.d_maxConnections); - d_lowWatermark = bsl::move(rhs.d_lowWatermark); - d_highWatermark = bsl::move(rhs.d_highWatermark); - d_nodeLowWatermark = bsl::move(rhs.d_nodeLowWatermark); - d_nodeHighWatermark = bsl::move(rhs.d_nodeHighWatermark); - d_heartbeatIntervalMs = bsl::move(rhs.d_heartbeatIntervalMs); + d_name = bsl::move(rhs.d_name); + d_port = bsl::move(rhs.d_port); } return *this; } #endif -void TcpInterfaceConfig::reset() +void TcpInterfaceListener::reset() { bdlat_ValueTypeFunctions::reset(&d_name); bdlat_ValueTypeFunctions::reset(&d_port); - bdlat_ValueTypeFunctions::reset(&d_ioThreads); - d_maxConnections = DEFAULT_INITIALIZER_MAX_CONNECTIONS; - bdlat_ValueTypeFunctions::reset(&d_lowWatermark); - bdlat_ValueTypeFunctions::reset(&d_highWatermark); - d_nodeLowWatermark = DEFAULT_INITIALIZER_NODE_LOW_WATERMARK; - d_nodeHighWatermark = DEFAULT_INITIALIZER_NODE_HIGH_WATERMARK; - d_heartbeatIntervalMs = DEFAULT_INITIALIZER_HEARTBEAT_INTERVAL_MS; } // ACCESSORS -bsl::ostream& TcpInterfaceConfig::print(bsl::ostream& stream, - int level, - int spacesPerLevel) const +bsl::ostream& TcpInterfaceListener::print(bsl::ostream& stream, + int level, + int spacesPerLevel) const { bslim::Printer printer(&stream, level, spacesPerLevel); printer.start(); printer.printAttribute("name", this->name()); printer.printAttribute("port", this->port()); - printer.printAttribute("ioThreads", this->ioThreads()); - printer.printAttribute("maxConnections", this->maxConnections()); - printer.printAttribute("lowWatermark", this->lowWatermark()); - printer.printAttribute("highWatermark", this->highWatermark()); - printer.printAttribute("nodeLowWatermark", this->nodeLowWatermark()); - printer.printAttribute("nodeHighWatermark", this->nodeHighWatermark()); - printer.printAttribute("heartbeatIntervalMs", this->heartbeatIntervalMs()); printer.end(); return stream; } @@ -3227,34 +3113,85 @@ LogController::print(bsl::ostream& stream, int level, int spacesPerLevel) const return stream; } -// ----------------------- -// class NetworkInterfaces -// ----------------------- +// --------------------- +// class PartitionConfig +// --------------------- // CONSTANTS -const char NetworkInterfaces::CLASS_NAME[] = "NetworkInterfaces"; +const char PartitionConfig::CLASS_NAME[] = "PartitionConfig"; -const bdlat_AttributeInfo NetworkInterfaces::ATTRIBUTE_INFO_ARRAY[] = { - {ATTRIBUTE_ID_HEARTBEATS, - "heartbeats", - sizeof("heartbeats") - 1, +const bool PartitionConfig::DEFAULT_INITIALIZER_PREALLOCATE = false; + +const bool PartitionConfig::DEFAULT_INITIALIZER_PREFAULT_PAGES = false; + +const bool PartitionConfig::DEFAULT_INITIALIZER_FLUSH_AT_SHUTDOWN = true; + +const bdlat_AttributeInfo PartitionConfig::ATTRIBUTE_INFO_ARRAY[] = { + {ATTRIBUTE_ID_NUM_PARTITIONS, + "numPartitions", + sizeof("numPartitions") - 1, "", - bdlat_FormattingMode::e_DEFAULT}, - {ATTRIBUTE_ID_TCP_INTERFACE, - "tcpInterface", - sizeof("tcpInterface") - 1, + bdlat_FormattingMode::e_DEC}, + {ATTRIBUTE_ID_LOCATION, + "location", + sizeof("location") - 1, + "", + bdlat_FormattingMode::e_TEXT}, + {ATTRIBUTE_ID_ARCHIVE_LOCATION, + "archiveLocation", + sizeof("archiveLocation") - 1, + "", + bdlat_FormattingMode::e_TEXT}, + {ATTRIBUTE_ID_MAX_DATA_FILE_SIZE, + "maxDataFileSize", + sizeof("maxDataFileSize") - 1, + "", + bdlat_FormattingMode::e_DEC}, + {ATTRIBUTE_ID_MAX_JOURNAL_FILE_SIZE, + "maxJournalFileSize", + sizeof("maxJournalFileSize") - 1, + "", + bdlat_FormattingMode::e_DEC}, + {ATTRIBUTE_ID_MAX_QLIST_FILE_SIZE, + "maxQlistFileSize", + sizeof("maxQlistFileSize") - 1, + "", + bdlat_FormattingMode::e_DEC}, + {ATTRIBUTE_ID_PREALLOCATE, + "preallocate", + sizeof("preallocate") - 1, + "", + bdlat_FormattingMode::e_TEXT}, + {ATTRIBUTE_ID_MAX_ARCHIVED_FILE_SETS, + "maxArchivedFileSets", + sizeof("maxArchivedFileSets") - 1, + "", + bdlat_FormattingMode::e_DEC}, + {ATTRIBUTE_ID_PREFAULT_PAGES, + "prefaultPages", + sizeof("prefaultPages") - 1, + "", + bdlat_FormattingMode::e_TEXT}, + {ATTRIBUTE_ID_FLUSH_AT_SHUTDOWN, + "flushAtShutdown", + sizeof("flushAtShutdown") - 1, + "", + bdlat_FormattingMode::e_TEXT}, + {ATTRIBUTE_ID_SYNC_CONFIG, + "syncConfig", + sizeof("syncConfig") - 1, "", bdlat_FormattingMode::e_DEFAULT}}; // CLASS METHODS const bdlat_AttributeInfo* -NetworkInterfaces::lookupAttributeInfo(const char* name, int nameLength) +PartitionConfig::lookupAttributeInfo(const char* name, int nameLength) { - for (int i = 0; i < 2; ++i) { + for (int i = 0; i < 11; ++i) { const bdlat_AttributeInfo& attributeInfo = - NetworkInterfaces::ATTRIBUTE_INFO_ARRAY[i]; + PartitionConfig::ATTRIBUTE_INFO_ARRAY[i]; if (nameLength == attributeInfo.d_nameLength && 0 == bsl::memcmp(attributeInfo.d_name_p, name, nameLength)) { @@ -3265,187 +3202,7 @@ NetworkInterfaces::lookupAttributeInfo(const char* name, int nameLength) return 0; } -const bdlat_AttributeInfo* NetworkInterfaces::lookupAttributeInfo(int id) -{ - switch (id) { - case ATTRIBUTE_ID_HEARTBEATS: - return &ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_HEARTBEATS]; - case ATTRIBUTE_ID_TCP_INTERFACE: - return &ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_TCP_INTERFACE]; - default: return 0; - } -} - -// CREATORS - -NetworkInterfaces::NetworkInterfaces(bslma::Allocator* basicAllocator) -: d_tcpInterface(basicAllocator) -, d_heartbeats() -{ -} - -NetworkInterfaces::NetworkInterfaces(const NetworkInterfaces& original, - bslma::Allocator* basicAllocator) -: d_tcpInterface(original.d_tcpInterface, basicAllocator) -, d_heartbeats(original.d_heartbeats) -{ -} - -#if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) && \ - defined(BSLS_COMPILERFEATURES_SUPPORT_NOEXCEPT) -NetworkInterfaces::NetworkInterfaces(NetworkInterfaces&& original) noexcept -: d_tcpInterface(bsl::move(original.d_tcpInterface)), - d_heartbeats(bsl::move(original.d_heartbeats)) -{ -} - -NetworkInterfaces::NetworkInterfaces(NetworkInterfaces&& original, - bslma::Allocator* basicAllocator) -: d_tcpInterface(bsl::move(original.d_tcpInterface), basicAllocator) -, d_heartbeats(bsl::move(original.d_heartbeats)) -{ -} -#endif - -NetworkInterfaces::~NetworkInterfaces() -{ -} - -// MANIPULATORS - -NetworkInterfaces& NetworkInterfaces::operator=(const NetworkInterfaces& rhs) -{ - if (this != &rhs) { - d_heartbeats = rhs.d_heartbeats; - d_tcpInterface = rhs.d_tcpInterface; - } - - return *this; -} - -#if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) && \ - defined(BSLS_COMPILERFEATURES_SUPPORT_NOEXCEPT) -NetworkInterfaces& NetworkInterfaces::operator=(NetworkInterfaces&& rhs) -{ - if (this != &rhs) { - d_heartbeats = bsl::move(rhs.d_heartbeats); - d_tcpInterface = bsl::move(rhs.d_tcpInterface); - } - - return *this; -} -#endif - -void NetworkInterfaces::reset() -{ - bdlat_ValueTypeFunctions::reset(&d_heartbeats); - bdlat_ValueTypeFunctions::reset(&d_tcpInterface); -} - -// ACCESSORS - -bsl::ostream& NetworkInterfaces::print(bsl::ostream& stream, - int level, - int spacesPerLevel) const -{ - bslim::Printer printer(&stream, level, spacesPerLevel); - printer.start(); - printer.printAttribute("heartbeats", this->heartbeats()); - printer.printAttribute("tcpInterface", this->tcpInterface()); - printer.end(); - return stream; -} - -// --------------------- -// class PartitionConfig -// --------------------- - -// CONSTANTS - -const char PartitionConfig::CLASS_NAME[] = "PartitionConfig"; - -const bool PartitionConfig::DEFAULT_INITIALIZER_PREALLOCATE = false; - -const bool PartitionConfig::DEFAULT_INITIALIZER_PREFAULT_PAGES = false; - -const bool PartitionConfig::DEFAULT_INITIALIZER_FLUSH_AT_SHUTDOWN = true; - -const bdlat_AttributeInfo PartitionConfig::ATTRIBUTE_INFO_ARRAY[] = { - {ATTRIBUTE_ID_NUM_PARTITIONS, - "numPartitions", - sizeof("numPartitions") - 1, - "", - bdlat_FormattingMode::e_DEC}, - {ATTRIBUTE_ID_LOCATION, - "location", - sizeof("location") - 1, - "", - bdlat_FormattingMode::e_TEXT}, - {ATTRIBUTE_ID_ARCHIVE_LOCATION, - "archiveLocation", - sizeof("archiveLocation") - 1, - "", - bdlat_FormattingMode::e_TEXT}, - {ATTRIBUTE_ID_MAX_DATA_FILE_SIZE, - "maxDataFileSize", - sizeof("maxDataFileSize") - 1, - "", - bdlat_FormattingMode::e_DEC}, - {ATTRIBUTE_ID_MAX_JOURNAL_FILE_SIZE, - "maxJournalFileSize", - sizeof("maxJournalFileSize") - 1, - "", - bdlat_FormattingMode::e_DEC}, - {ATTRIBUTE_ID_MAX_QLIST_FILE_SIZE, - "maxQlistFileSize", - sizeof("maxQlistFileSize") - 1, - "", - bdlat_FormattingMode::e_DEC}, - {ATTRIBUTE_ID_PREALLOCATE, - "preallocate", - sizeof("preallocate") - 1, - "", - bdlat_FormattingMode::e_TEXT}, - {ATTRIBUTE_ID_MAX_ARCHIVED_FILE_SETS, - "maxArchivedFileSets", - sizeof("maxArchivedFileSets") - 1, - "", - bdlat_FormattingMode::e_DEC}, - {ATTRIBUTE_ID_PREFAULT_PAGES, - "prefaultPages", - sizeof("prefaultPages") - 1, - "", - bdlat_FormattingMode::e_TEXT}, - {ATTRIBUTE_ID_FLUSH_AT_SHUTDOWN, - "flushAtShutdown", - sizeof("flushAtShutdown") - 1, - "", - bdlat_FormattingMode::e_TEXT}, - {ATTRIBUTE_ID_SYNC_CONFIG, - "syncConfig", - sizeof("syncConfig") - 1, - "", - bdlat_FormattingMode::e_DEFAULT}}; - -// CLASS METHODS - -const bdlat_AttributeInfo* -PartitionConfig::lookupAttributeInfo(const char* name, int nameLength) -{ - for (int i = 0; i < 11; ++i) { - const bdlat_AttributeInfo& attributeInfo = - PartitionConfig::ATTRIBUTE_INFO_ARRAY[i]; - - if (nameLength == attributeInfo.d_nameLength && - 0 == bsl::memcmp(attributeInfo.d_name_p, name, nameLength)) { - return &attributeInfo; - } - } - - return 0; -} - -const bdlat_AttributeInfo* PartitionConfig::lookupAttributeInfo(int id) +const bdlat_AttributeInfo* PartitionConfig::lookupAttributeInfo(int id) { switch (id) { case ATTRIBUTE_ID_NUM_PARTITIONS: @@ -3784,40 +3541,84 @@ bsl::ostream& StatPluginConfigPrometheus::print(bsl::ostream& stream, return stream; } -// ----------------- -// class ClusterNode -// ----------------- +// ------------------------ +// class TcpInterfaceConfig +// ------------------------ // CONSTANTS -const char ClusterNode::CLASS_NAME[] = "ClusterNode"; +const char TcpInterfaceConfig::CLASS_NAME[] = "TcpInterfaceConfig"; -const bdlat_AttributeInfo ClusterNode::ATTRIBUTE_INFO_ARRAY[] = { - {ATTRIBUTE_ID_ID, "id", sizeof("id") - 1, "", bdlat_FormattingMode::e_DEC}, +const int TcpInterfaceConfig::DEFAULT_INITIALIZER_MAX_CONNECTIONS = 10000; + +const bsls::Types::Int64 + TcpInterfaceConfig::DEFAULT_INITIALIZER_NODE_LOW_WATERMARK = 1024; + +const bsls::Types::Int64 + TcpInterfaceConfig::DEFAULT_INITIALIZER_NODE_HIGH_WATERMARK = 2048; + +const int TcpInterfaceConfig::DEFAULT_INITIALIZER_HEARTBEAT_INTERVAL_MS = 3000; + +const bdlat_AttributeInfo TcpInterfaceConfig::ATTRIBUTE_INFO_ARRAY[] = { {ATTRIBUTE_ID_NAME, "name", sizeof("name") - 1, "", bdlat_FormattingMode::e_TEXT}, - {ATTRIBUTE_ID_DATA_CENTER, - "dataCenter", - sizeof("dataCenter") - 1, + {ATTRIBUTE_ID_PORT, + "port", + sizeof("port") - 1, "", - bdlat_FormattingMode::e_TEXT}, - {ATTRIBUTE_ID_TRANSPORT, - "transport", - sizeof("transport") - 1, + bdlat_FormattingMode::e_DEC}, + {ATTRIBUTE_ID_IO_THREADS, + "ioThreads", + sizeof("ioThreads") - 1, + "", + bdlat_FormattingMode::e_DEC}, + {ATTRIBUTE_ID_MAX_CONNECTIONS, + "maxConnections", + sizeof("maxConnections") - 1, + "", + bdlat_FormattingMode::e_DEC}, + {ATTRIBUTE_ID_LOW_WATERMARK, + "lowWatermark", + sizeof("lowWatermark") - 1, + "", + bdlat_FormattingMode::e_DEC}, + {ATTRIBUTE_ID_HIGH_WATERMARK, + "highWatermark", + sizeof("highWatermark") - 1, + "", + bdlat_FormattingMode::e_DEC}, + {ATTRIBUTE_ID_NODE_LOW_WATERMARK, + "nodeLowWatermark", + sizeof("nodeLowWatermark") - 1, + "", + bdlat_FormattingMode::e_DEC}, + {ATTRIBUTE_ID_NODE_HIGH_WATERMARK, + "nodeHighWatermark", + sizeof("nodeHighWatermark") - 1, + "", + bdlat_FormattingMode::e_DEC}, + {ATTRIBUTE_ID_HEARTBEAT_INTERVAL_MS, + "heartbeatIntervalMs", + sizeof("heartbeatIntervalMs") - 1, + "", + bdlat_FormattingMode::e_DEC}, + {ATTRIBUTE_ID_LISTENERS, + "listeners", + sizeof("listeners") - 1, "", bdlat_FormattingMode::e_DEFAULT}}; // CLASS METHODS -const bdlat_AttributeInfo* ClusterNode::lookupAttributeInfo(const char* name, - int nameLength) +const bdlat_AttributeInfo* +TcpInterfaceConfig::lookupAttributeInfo(const char* name, int nameLength) { - for (int i = 0; i < 4; ++i) { + for (int i = 0; i < 10; ++i) { const bdlat_AttributeInfo& attributeInfo = - ClusterNode::ATTRIBUTE_INFO_ARRAY[i]; + TcpInterfaceConfig::ATTRIBUTE_INFO_ARRAY[i]; if (nameLength == attributeInfo.d_nameLength && 0 == bsl::memcmp(attributeInfo.d_name_p, name, nameLength)) { @@ -3828,23 +3629,237 @@ const bdlat_AttributeInfo* ClusterNode::lookupAttributeInfo(const char* name, return 0; } -const bdlat_AttributeInfo* ClusterNode::lookupAttributeInfo(int id) +const bdlat_AttributeInfo* TcpInterfaceConfig::lookupAttributeInfo(int id) { switch (id) { - case ATTRIBUTE_ID_ID: return &ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_ID]; case ATTRIBUTE_ID_NAME: return &ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_NAME]; - case ATTRIBUTE_ID_DATA_CENTER: - return &ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_DATA_CENTER]; - case ATTRIBUTE_ID_TRANSPORT: - return &ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_TRANSPORT]; - default: return 0; - } -} - -// CREATORS - -ClusterNode::ClusterNode(bslma::Allocator* basicAllocator) -: d_name(basicAllocator) + case ATTRIBUTE_ID_PORT: return &ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_PORT]; + case ATTRIBUTE_ID_IO_THREADS: + return &ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_IO_THREADS]; + case ATTRIBUTE_ID_MAX_CONNECTIONS: + return &ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_CONNECTIONS]; + case ATTRIBUTE_ID_LOW_WATERMARK: + return &ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_LOW_WATERMARK]; + case ATTRIBUTE_ID_HIGH_WATERMARK: + return &ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_HIGH_WATERMARK]; + case ATTRIBUTE_ID_NODE_LOW_WATERMARK: + return &ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_NODE_LOW_WATERMARK]; + case ATTRIBUTE_ID_NODE_HIGH_WATERMARK: + return &ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_NODE_HIGH_WATERMARK]; + case ATTRIBUTE_ID_HEARTBEAT_INTERVAL_MS: + return &ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_HEARTBEAT_INTERVAL_MS]; + case ATTRIBUTE_ID_LISTENERS: + return &ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_LISTENERS]; + default: return 0; + } +} + +// CREATORS + +TcpInterfaceConfig::TcpInterfaceConfig(bslma::Allocator* basicAllocator) +: d_lowWatermark() +, d_highWatermark() +, d_nodeLowWatermark(DEFAULT_INITIALIZER_NODE_LOW_WATERMARK) +, d_nodeHighWatermark(DEFAULT_INITIALIZER_NODE_HIGH_WATERMARK) +, d_listeners(basicAllocator) +, d_name(basicAllocator) +, d_port() +, d_ioThreads() +, d_maxConnections(DEFAULT_INITIALIZER_MAX_CONNECTIONS) +, d_heartbeatIntervalMs(DEFAULT_INITIALIZER_HEARTBEAT_INTERVAL_MS) +{ +} + +TcpInterfaceConfig::TcpInterfaceConfig(const TcpInterfaceConfig& original, + bslma::Allocator* basicAllocator) +: d_lowWatermark(original.d_lowWatermark) +, d_highWatermark(original.d_highWatermark) +, d_nodeLowWatermark(original.d_nodeLowWatermark) +, d_nodeHighWatermark(original.d_nodeHighWatermark) +, d_listeners(original.d_listeners, basicAllocator) +, d_name(original.d_name, basicAllocator) +, d_port(original.d_port) +, d_ioThreads(original.d_ioThreads) +, d_maxConnections(original.d_maxConnections) +, d_heartbeatIntervalMs(original.d_heartbeatIntervalMs) +{ +} + +#if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) && \ + defined(BSLS_COMPILERFEATURES_SUPPORT_NOEXCEPT) +TcpInterfaceConfig::TcpInterfaceConfig(TcpInterfaceConfig&& original) noexcept +: d_lowWatermark(bsl::move(original.d_lowWatermark)), + d_highWatermark(bsl::move(original.d_highWatermark)), + d_nodeLowWatermark(bsl::move(original.d_nodeLowWatermark)), + d_nodeHighWatermark(bsl::move(original.d_nodeHighWatermark)), + d_listeners(bsl::move(original.d_listeners)), + d_name(bsl::move(original.d_name)), + d_port(bsl::move(original.d_port)), + d_ioThreads(bsl::move(original.d_ioThreads)), + d_maxConnections(bsl::move(original.d_maxConnections)), + d_heartbeatIntervalMs(bsl::move(original.d_heartbeatIntervalMs)) +{ +} + +TcpInterfaceConfig::TcpInterfaceConfig(TcpInterfaceConfig&& original, + bslma::Allocator* basicAllocator) +: d_lowWatermark(bsl::move(original.d_lowWatermark)) +, d_highWatermark(bsl::move(original.d_highWatermark)) +, d_nodeLowWatermark(bsl::move(original.d_nodeLowWatermark)) +, d_nodeHighWatermark(bsl::move(original.d_nodeHighWatermark)) +, d_listeners(bsl::move(original.d_listeners), basicAllocator) +, d_name(bsl::move(original.d_name), basicAllocator) +, d_port(bsl::move(original.d_port)) +, d_ioThreads(bsl::move(original.d_ioThreads)) +, d_maxConnections(bsl::move(original.d_maxConnections)) +, d_heartbeatIntervalMs(bsl::move(original.d_heartbeatIntervalMs)) +{ +} +#endif + +TcpInterfaceConfig::~TcpInterfaceConfig() +{ +} + +// MANIPULATORS + +TcpInterfaceConfig& +TcpInterfaceConfig::operator=(const TcpInterfaceConfig& rhs) +{ + if (this != &rhs) { + d_name = rhs.d_name; + d_port = rhs.d_port; + d_ioThreads = rhs.d_ioThreads; + d_maxConnections = rhs.d_maxConnections; + d_lowWatermark = rhs.d_lowWatermark; + d_highWatermark = rhs.d_highWatermark; + d_nodeLowWatermark = rhs.d_nodeLowWatermark; + d_nodeHighWatermark = rhs.d_nodeHighWatermark; + d_heartbeatIntervalMs = rhs.d_heartbeatIntervalMs; + d_listeners = rhs.d_listeners; + } + + return *this; +} + +#if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) && \ + defined(BSLS_COMPILERFEATURES_SUPPORT_NOEXCEPT) +TcpInterfaceConfig& TcpInterfaceConfig::operator=(TcpInterfaceConfig&& rhs) +{ + if (this != &rhs) { + d_name = bsl::move(rhs.d_name); + d_port = bsl::move(rhs.d_port); + d_ioThreads = bsl::move(rhs.d_ioThreads); + d_maxConnections = bsl::move(rhs.d_maxConnections); + d_lowWatermark = bsl::move(rhs.d_lowWatermark); + d_highWatermark = bsl::move(rhs.d_highWatermark); + d_nodeLowWatermark = bsl::move(rhs.d_nodeLowWatermark); + d_nodeHighWatermark = bsl::move(rhs.d_nodeHighWatermark); + d_heartbeatIntervalMs = bsl::move(rhs.d_heartbeatIntervalMs); + d_listeners = bsl::move(rhs.d_listeners); + } + + return *this; +} +#endif + +void TcpInterfaceConfig::reset() +{ + bdlat_ValueTypeFunctions::reset(&d_name); + bdlat_ValueTypeFunctions::reset(&d_port); + bdlat_ValueTypeFunctions::reset(&d_ioThreads); + d_maxConnections = DEFAULT_INITIALIZER_MAX_CONNECTIONS; + bdlat_ValueTypeFunctions::reset(&d_lowWatermark); + bdlat_ValueTypeFunctions::reset(&d_highWatermark); + d_nodeLowWatermark = DEFAULT_INITIALIZER_NODE_LOW_WATERMARK; + d_nodeHighWatermark = DEFAULT_INITIALIZER_NODE_HIGH_WATERMARK; + d_heartbeatIntervalMs = DEFAULT_INITIALIZER_HEARTBEAT_INTERVAL_MS; + bdlat_ValueTypeFunctions::reset(&d_listeners); +} + +// ACCESSORS + +bsl::ostream& TcpInterfaceConfig::print(bsl::ostream& stream, + int level, + int spacesPerLevel) const +{ + bslim::Printer printer(&stream, level, spacesPerLevel); + printer.start(); + printer.printAttribute("name", this->name()); + printer.printAttribute("port", this->port()); + printer.printAttribute("ioThreads", this->ioThreads()); + printer.printAttribute("maxConnections", this->maxConnections()); + printer.printAttribute("lowWatermark", this->lowWatermark()); + printer.printAttribute("highWatermark", this->highWatermark()); + printer.printAttribute("nodeLowWatermark", this->nodeLowWatermark()); + printer.printAttribute("nodeHighWatermark", this->nodeHighWatermark()); + printer.printAttribute("heartbeatIntervalMs", this->heartbeatIntervalMs()); + printer.printAttribute("listeners", this->listeners()); + printer.end(); + return stream; +} + +// ----------------- +// class ClusterNode +// ----------------- + +// CONSTANTS + +const char ClusterNode::CLASS_NAME[] = "ClusterNode"; + +const bdlat_AttributeInfo ClusterNode::ATTRIBUTE_INFO_ARRAY[] = { + {ATTRIBUTE_ID_ID, "id", sizeof("id") - 1, "", bdlat_FormattingMode::e_DEC}, + {ATTRIBUTE_ID_NAME, + "name", + sizeof("name") - 1, + "", + bdlat_FormattingMode::e_TEXT}, + {ATTRIBUTE_ID_DATA_CENTER, + "dataCenter", + sizeof("dataCenter") - 1, + "", + bdlat_FormattingMode::e_TEXT}, + {ATTRIBUTE_ID_TRANSPORT, + "transport", + sizeof("transport") - 1, + "", + bdlat_FormattingMode::e_DEFAULT}}; + +// CLASS METHODS + +const bdlat_AttributeInfo* ClusterNode::lookupAttributeInfo(const char* name, + int nameLength) +{ + for (int i = 0; i < 4; ++i) { + const bdlat_AttributeInfo& attributeInfo = + ClusterNode::ATTRIBUTE_INFO_ARRAY[i]; + + if (nameLength == attributeInfo.d_nameLength && + 0 == bsl::memcmp(attributeInfo.d_name_p, name, nameLength)) { + return &attributeInfo; + } + } + + return 0; +} + +const bdlat_AttributeInfo* ClusterNode::lookupAttributeInfo(int id) +{ + switch (id) { + case ATTRIBUTE_ID_ID: return &ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_ID]; + case ATTRIBUTE_ID_NAME: return &ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_NAME]; + case ATTRIBUTE_ID_DATA_CENTER: + return &ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_DATA_CENTER]; + case ATTRIBUTE_ID_TRANSPORT: + return &ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_TRANSPORT]; + default: return 0; + } +} + +// CREATORS + +ClusterNode::ClusterNode(bslma::Allocator* basicAllocator) +: d_name(basicAllocator) , d_dataCenter(basicAllocator) , d_transport(basicAllocator) , d_id() @@ -4025,6 +4040,135 @@ bsl::ostream& DispatcherConfig::print(bsl::ostream& stream, return stream; } +// ----------------------- +// class NetworkInterfaces +// ----------------------- + +// CONSTANTS + +const char NetworkInterfaces::CLASS_NAME[] = "NetworkInterfaces"; + +const bdlat_AttributeInfo NetworkInterfaces::ATTRIBUTE_INFO_ARRAY[] = { + {ATTRIBUTE_ID_HEARTBEATS, + "heartbeats", + sizeof("heartbeats") - 1, + "", + bdlat_FormattingMode::e_DEFAULT}, + {ATTRIBUTE_ID_TCP_INTERFACE, + "tcpInterface", + sizeof("tcpInterface") - 1, + "", + bdlat_FormattingMode::e_DEFAULT}}; + +// CLASS METHODS + +const bdlat_AttributeInfo* +NetworkInterfaces::lookupAttributeInfo(const char* name, int nameLength) +{ + for (int i = 0; i < 2; ++i) { + const bdlat_AttributeInfo& attributeInfo = + NetworkInterfaces::ATTRIBUTE_INFO_ARRAY[i]; + + if (nameLength == attributeInfo.d_nameLength && + 0 == bsl::memcmp(attributeInfo.d_name_p, name, nameLength)) { + return &attributeInfo; + } + } + + return 0; +} + +const bdlat_AttributeInfo* NetworkInterfaces::lookupAttributeInfo(int id) +{ + switch (id) { + case ATTRIBUTE_ID_HEARTBEATS: + return &ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_HEARTBEATS]; + case ATTRIBUTE_ID_TCP_INTERFACE: + return &ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_TCP_INTERFACE]; + default: return 0; + } +} + +// CREATORS + +NetworkInterfaces::NetworkInterfaces(bslma::Allocator* basicAllocator) +: d_tcpInterface(basicAllocator) +, d_heartbeats() +{ +} + +NetworkInterfaces::NetworkInterfaces(const NetworkInterfaces& original, + bslma::Allocator* basicAllocator) +: d_tcpInterface(original.d_tcpInterface, basicAllocator) +, d_heartbeats(original.d_heartbeats) +{ +} + +#if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) && \ + defined(BSLS_COMPILERFEATURES_SUPPORT_NOEXCEPT) +NetworkInterfaces::NetworkInterfaces(NetworkInterfaces&& original) noexcept +: d_tcpInterface(bsl::move(original.d_tcpInterface)), + d_heartbeats(bsl::move(original.d_heartbeats)) +{ +} + +NetworkInterfaces::NetworkInterfaces(NetworkInterfaces&& original, + bslma::Allocator* basicAllocator) +: d_tcpInterface(bsl::move(original.d_tcpInterface), basicAllocator) +, d_heartbeats(bsl::move(original.d_heartbeats)) +{ +} +#endif + +NetworkInterfaces::~NetworkInterfaces() +{ +} + +// MANIPULATORS + +NetworkInterfaces& NetworkInterfaces::operator=(const NetworkInterfaces& rhs) +{ + if (this != &rhs) { + d_heartbeats = rhs.d_heartbeats; + d_tcpInterface = rhs.d_tcpInterface; + } + + return *this; +} + +#if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) && \ + defined(BSLS_COMPILERFEATURES_SUPPORT_NOEXCEPT) +NetworkInterfaces& NetworkInterfaces::operator=(NetworkInterfaces&& rhs) +{ + if (this != &rhs) { + d_heartbeats = bsl::move(rhs.d_heartbeats); + d_tcpInterface = bsl::move(rhs.d_tcpInterface); + } + + return *this; +} +#endif + +void NetworkInterfaces::reset() +{ + bdlat_ValueTypeFunctions::reset(&d_heartbeats); + bdlat_ValueTypeFunctions::reset(&d_tcpInterface); +} + +// ACCESSORS + +bsl::ostream& NetworkInterfaces::print(bsl::ostream& stream, + int level, + int spacesPerLevel) const +{ + bslim::Printer printer(&stream, level, spacesPerLevel); + printer.start(); + printer.printAttribute("heartbeats", this->heartbeats()); + printer.printAttribute("tcpInterface", this->tcpInterface()); + printer.end(); + return stream; +} + // ------------------------------- // class ReversedClusterConnection // ------------------------------- @@ -5823,13 +5967,6 @@ Configuration::print(bsl::ostream& stream, int level, int spacesPerLevel) const } // close package namespace } // close enterprise namespace -// GENERATED BY @BLP_BAS_CODEGEN_VERSION@ +// GENERATED BY BLP_BAS_CODEGEN_2024.07.18 // USING bas_codegen.pl -m msg --noAggregateConversion --noExternalization // --noIdent --package mqbcfg --msgComponent messages mqbcfg.xsd -// ---------------------------------------------------------------------------- -// NOTICE: -// Copyright 2024 Bloomberg Finance L.P. All rights reserved. -// Property of Bloomberg Finance L.P. (BFLP) -// This software is made available solely pursuant to the -// terms of a BFLP license agreement which governs its use. -// ------------------------------- END-OF-FILE -------------------------------- diff --git a/src/groups/mqb/mqbcfg/mqbcfg_messages.h b/src/groups/mqb/mqbcfg/mqbcfg_messages.h index 9875c6ab2..99d95c47e 100644 --- a/src/groups/mqb/mqbcfg/mqbcfg_messages.h +++ b/src/groups/mqb/mqbcfg/mqbcfg_messages.h @@ -1,4 +1,4 @@ -// Copyright 2014-2024 Bloomberg Finance L.P. +// Copyright 2024 Bloomberg Finance L.P. // SPDX-License-Identifier: Apache-2.0 // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -12,7 +12,6 @@ // 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. - // mqbcfg_messages.h *DO NOT EDIT* @generated -*-C++-*- #ifndef INCLUDED_MQBCFG_MESSAGES #define INCLUDED_MQBCFG_MESSAGES @@ -102,7 +101,7 @@ namespace mqbcfg { class TcpClusterNodeConnection; } namespace mqbcfg { -class TcpInterfaceConfig; +class TcpInterfaceListener; } namespace mqbcfg { class VirtualClusterInformation; @@ -117,21 +116,24 @@ namespace mqbcfg { class LogController; } namespace mqbcfg { -class NetworkInterfaces; -} -namespace mqbcfg { class PartitionConfig; } namespace mqbcfg { class StatPluginConfigPrometheus; } namespace mqbcfg { +class TcpInterfaceConfig; +} +namespace mqbcfg { class ClusterNode; } namespace mqbcfg { class DispatcherConfig; } namespace mqbcfg { +class NetworkInterfaces; +} +namespace mqbcfg { class ReversedClusterConnection; } namespace mqbcfg { @@ -4020,74 +4022,32 @@ BDLAT_DECL_SEQUENCE_WITH_ALLOCATOR_BITWISEMOVEABLE_TRAITS( namespace mqbcfg { -// ======================== -// class TcpInterfaceConfig -// ======================== +// ========================== +// class TcpInterfaceListener +// ========================== -class TcpInterfaceConfig { - // lowWatermark.........: highWatermark........: Watermarks used for - // channels with a client or proxy. nodeLowWatermark.....: - // nodeHighWatermark....: Reduced watermarks for communication between - // cluster nodes where BlazingMQ maintains its own cache. - // heartbeatIntervalMs..: How often (in milliseconds) to check if the - // channel received data, and emit heartbeat. 0 to globally disable. +class TcpInterfaceListener { + // This type describes the information needed for the broker to open a TCP + // listener. + // name.................: A name to associate this listener to. + // port.................: The port this listener will accept connections + // on. // INSTANCE DATA - bsls::Types::Int64 d_lowWatermark; - bsls::Types::Int64 d_highWatermark; - bsls::Types::Int64 d_nodeLowWatermark; - bsls::Types::Int64 d_nodeHighWatermark; - bsl::string d_name; - int d_port; - int d_ioThreads; - int d_maxConnections; - int d_heartbeatIntervalMs; - - // PRIVATE ACCESSORS - template - void hashAppendImpl(t_HASH_ALGORITHM& hashAlgorithm) const; - - bool isEqualTo(const TcpInterfaceConfig& rhs) const; + bsl::string d_name; + int d_port; public: // TYPES - enum { - ATTRIBUTE_ID_NAME = 0, - ATTRIBUTE_ID_PORT = 1, - ATTRIBUTE_ID_IO_THREADS = 2, - ATTRIBUTE_ID_MAX_CONNECTIONS = 3, - ATTRIBUTE_ID_LOW_WATERMARK = 4, - ATTRIBUTE_ID_HIGH_WATERMARK = 5, - ATTRIBUTE_ID_NODE_LOW_WATERMARK = 6, - ATTRIBUTE_ID_NODE_HIGH_WATERMARK = 7, - ATTRIBUTE_ID_HEARTBEAT_INTERVAL_MS = 8 - }; + enum { ATTRIBUTE_ID_NAME = 0, ATTRIBUTE_ID_PORT = 1 }; - enum { NUM_ATTRIBUTES = 9 }; + enum { NUM_ATTRIBUTES = 2 }; - enum { - ATTRIBUTE_INDEX_NAME = 0, - ATTRIBUTE_INDEX_PORT = 1, - ATTRIBUTE_INDEX_IO_THREADS = 2, - ATTRIBUTE_INDEX_MAX_CONNECTIONS = 3, - ATTRIBUTE_INDEX_LOW_WATERMARK = 4, - ATTRIBUTE_INDEX_HIGH_WATERMARK = 5, - ATTRIBUTE_INDEX_NODE_LOW_WATERMARK = 6, - ATTRIBUTE_INDEX_NODE_HIGH_WATERMARK = 7, - ATTRIBUTE_INDEX_HEARTBEAT_INTERVAL_MS = 8 - }; + enum { ATTRIBUTE_INDEX_NAME = 0, ATTRIBUTE_INDEX_PORT = 1 }; // CONSTANTS static const char CLASS_NAME[]; - static const int DEFAULT_INITIALIZER_MAX_CONNECTIONS; - - static const bsls::Types::Int64 DEFAULT_INITIALIZER_NODE_LOW_WATERMARK; - - static const bsls::Types::Int64 DEFAULT_INITIALIZER_NODE_HIGH_WATERMARK; - - static const int DEFAULT_INITIALIZER_HEARTBEAT_INTERVAL_MS; - static const bdlat_AttributeInfo ATTRIBUTE_INFO_ARRAY[]; public: @@ -4103,29 +4063,29 @@ class TcpInterfaceConfig { // exists, and 0 otherwise. // CREATORS - explicit TcpInterfaceConfig(bslma::Allocator* basicAllocator = 0); - // Create an object of type 'TcpInterfaceConfig' having the default + explicit TcpInterfaceListener(bslma::Allocator* basicAllocator = 0); + // Create an object of type 'TcpInterfaceListener' having the default // value. Use the optionally specified 'basicAllocator' to supply // memory. If 'basicAllocator' is 0, the currently installed default // allocator is used. - TcpInterfaceConfig(const TcpInterfaceConfig& original, - bslma::Allocator* basicAllocator = 0); - // Create an object of type 'TcpInterfaceConfig' having the value of + TcpInterfaceListener(const TcpInterfaceListener& original, + bslma::Allocator* basicAllocator = 0); + // Create an object of type 'TcpInterfaceListener' having the value of // the specified 'original' object. Use the optionally specified // 'basicAllocator' to supply memory. If 'basicAllocator' is 0, the // currently installed default allocator is used. #if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) && \ defined(BSLS_COMPILERFEATURES_SUPPORT_NOEXCEPT) - TcpInterfaceConfig(TcpInterfaceConfig&& original) noexcept; - // Create an object of type 'TcpInterfaceConfig' having the value of + TcpInterfaceListener(TcpInterfaceListener&& original) noexcept; + // Create an object of type 'TcpInterfaceListener' having the value of // the specified 'original' object. After performing this action, the // 'original' object will be left in a valid, but unspecified state. - TcpInterfaceConfig(TcpInterfaceConfig&& original, - bslma::Allocator* basicAllocator); - // Create an object of type 'TcpInterfaceConfig' having the value of + TcpInterfaceListener(TcpInterfaceListener&& original, + bslma::Allocator* basicAllocator); + // Create an object of type 'TcpInterfaceListener' having the value of // the specified 'original' object. After performing this action, the // 'original' object will be left in a valid, but unspecified state. // Use the optionally specified 'basicAllocator' to supply memory. If @@ -4133,16 +4093,16 @@ class TcpInterfaceConfig { // used. #endif - ~TcpInterfaceConfig(); + ~TcpInterfaceListener(); // Destroy this object. // MANIPULATORS - TcpInterfaceConfig& operator=(const TcpInterfaceConfig& rhs); + TcpInterfaceListener& operator=(const TcpInterfaceListener& rhs); // Assign to this object the value of the specified 'rhs' object. #if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) && \ defined(BSLS_COMPILERFEATURES_SUPPORT_NOEXCEPT) - TcpInterfaceConfig& operator=(TcpInterfaceConfig&& rhs); + TcpInterfaceListener& operator=(TcpInterfaceListener&& rhs); // Assign to this object the value of the specified 'rhs' object. // After performing this action, the 'rhs' object will be left in a // valid, but unspecified state. @@ -4189,34 +4149,6 @@ class TcpInterfaceConfig { // Return a reference to the modifiable "Port" attribute of this // object. - int& ioThreads(); - // Return a reference to the modifiable "IoThreads" attribute of this - // object. - - int& maxConnections(); - // Return a reference to the modifiable "MaxConnections" attribute of - // this object. - - bsls::Types::Int64& lowWatermark(); - // Return a reference to the modifiable "LowWatermark" attribute of - // this object. - - bsls::Types::Int64& highWatermark(); - // Return a reference to the modifiable "HighWatermark" attribute of - // this object. - - bsls::Types::Int64& nodeLowWatermark(); - // Return a reference to the modifiable "NodeLowWatermark" attribute of - // this object. - - bsls::Types::Int64& nodeHighWatermark(); - // Return a reference to the modifiable "NodeHighWatermark" attribute - // of this object. - - int& heartbeatIntervalMs(); - // Return a reference to the modifiable "HeartbeatIntervalMs" attribute - // of this object. - // ACCESSORS bsl::ostream& print(bsl::ostream& stream, int level = 0, int spacesPerLevel = 4) const; @@ -4267,48 +4199,25 @@ class TcpInterfaceConfig { int port() const; // Return the value of the "Port" attribute of this object. - int ioThreads() const; - // Return the value of the "IoThreads" attribute of this object. - - int maxConnections() const; - // Return the value of the "MaxConnections" attribute of this object. - - bsls::Types::Int64 lowWatermark() const; - // Return the value of the "LowWatermark" attribute of this object. - - bsls::Types::Int64 highWatermark() const; - // Return the value of the "HighWatermark" attribute of this object. - - bsls::Types::Int64 nodeLowWatermark() const; - // Return the value of the "NodeLowWatermark" attribute of this object. - - bsls::Types::Int64 nodeHighWatermark() const; - // Return the value of the "NodeHighWatermark" attribute of this - // object. - - int heartbeatIntervalMs() const; - // Return the value of the "HeartbeatIntervalMs" attribute of this - // object. - // HIDDEN FRIENDS - friend bool operator==(const TcpInterfaceConfig& lhs, - const TcpInterfaceConfig& rhs) + friend bool operator==(const TcpInterfaceListener& lhs, + const TcpInterfaceListener& rhs) // Return 'true' if the specified 'lhs' and 'rhs' attribute objects // have the same value, and 'false' otherwise. Two attribute objects // have the same value if each respective attribute has the same value. { - return lhs.isEqualTo(rhs); + return lhs.name() == rhs.name() && lhs.port() == rhs.port(); } - friend bool operator!=(const TcpInterfaceConfig& lhs, - const TcpInterfaceConfig& rhs) + friend bool operator!=(const TcpInterfaceListener& lhs, + const TcpInterfaceListener& rhs) // Returns '!(lhs == rhs)' { return !(lhs == rhs); } - friend bsl::ostream& operator<<(bsl::ostream& stream, - const TcpInterfaceConfig& rhs) + friend bsl::ostream& operator<<(bsl::ostream& stream, + const TcpInterfaceListener& rhs) // Format the specified 'rhs' to the specified output 'stream' and // return a reference to the modifiable 'stream'. { @@ -4316,14 +4225,16 @@ class TcpInterfaceConfig { } template - friend void hashAppend(t_HASH_ALGORITHM& hashAlg, - const TcpInterfaceConfig& object) + friend void hashAppend(t_HASH_ALGORITHM& hashAlg, + const TcpInterfaceListener& object) // Pass the specified 'object' to the specified 'hashAlg'. This // function integrates with the 'bslh' modular hashing system and // effectively provides a 'bsl::hash' specialization for - // 'TcpInterfaceConfig'. + // 'TcpInterfaceListener'. { - object.hashAppendImpl(hashAlg); + using bslh::hashAppend; + hashAppend(hashAlg, object.name()); + hashAppend(hashAlg, object.port()); } }; @@ -4332,7 +4243,7 @@ class TcpInterfaceConfig { // TRAITS BDLAT_DECL_SEQUENCE_WITH_ALLOCATOR_BITWISEMOVEABLE_TRAITS( - mqbcfg::TcpInterfaceConfig) + mqbcfg::TcpInterfaceListener) namespace mqbcfg { @@ -5286,26 +5197,87 @@ BDLAT_DECL_SEQUENCE_WITH_ALLOCATOR_BITWISEMOVEABLE_TRAITS( namespace mqbcfg { -// ======================= -// class NetworkInterfaces -// ======================= +// ===================== +// class PartitionConfig +// ===================== + +class PartitionConfig { + // Type representing the configuration for the storage layer of a cluster. + // + // numPartitions........: number of partitions at each node in the cluster + // location.............: location of active files for a partition + // archiveLocation......: location of archive files for a partition + // maxDataFileSize......: maximum size of partitions' data file + // maxJournalFileSize...: maximum size of partitions' journal file + // maxQlistFileSize.....: maximum size of partitions' qlist file + // preallocate..........: flag to indicate whether files should be + // preallocated on disk maxArchivedFileSets..: maximum number of archived + // file sets per partition to keep prefaultPages........: flag to indicate + // whether to populate (prefault) page tables for a mapping. + // flushAtShutdown......: flag to indicate whether broker should flush + // storage files to disk at shutdown syncConfig...........: configuration + // for storage synchronization and recovery -class NetworkInterfaces { // INSTANCE DATA - bdlb::NullableValue d_tcpInterface; - Heartbeat d_heartbeats; + bsls::Types::Uint64 d_maxDataFileSize; + bsls::Types::Uint64 d_maxJournalFileSize; + bsls::Types::Uint64 d_maxQlistFileSize; + bsl::string d_location; + bsl::string d_archiveLocation; + StorageSyncConfig d_syncConfig; + int d_numPartitions; + int d_maxArchivedFileSets; + bool d_preallocate; + bool d_prefaultPages; + bool d_flushAtShutdown; + + // PRIVATE ACCESSORS + template + void hashAppendImpl(t_HASH_ALGORITHM& hashAlgorithm) const; + + bool isEqualTo(const PartitionConfig& rhs) const; public: // TYPES - enum { ATTRIBUTE_ID_HEARTBEATS = 0, ATTRIBUTE_ID_TCP_INTERFACE = 1 }; + enum { + ATTRIBUTE_ID_NUM_PARTITIONS = 0, + ATTRIBUTE_ID_LOCATION = 1, + ATTRIBUTE_ID_ARCHIVE_LOCATION = 2, + ATTRIBUTE_ID_MAX_DATA_FILE_SIZE = 3, + ATTRIBUTE_ID_MAX_JOURNAL_FILE_SIZE = 4, + ATTRIBUTE_ID_MAX_QLIST_FILE_SIZE = 5, + ATTRIBUTE_ID_PREALLOCATE = 6, + ATTRIBUTE_ID_MAX_ARCHIVED_FILE_SETS = 7, + ATTRIBUTE_ID_PREFAULT_PAGES = 8, + ATTRIBUTE_ID_FLUSH_AT_SHUTDOWN = 9, + ATTRIBUTE_ID_SYNC_CONFIG = 10 + }; - enum { NUM_ATTRIBUTES = 2 }; + enum { NUM_ATTRIBUTES = 11 }; - enum { ATTRIBUTE_INDEX_HEARTBEATS = 0, ATTRIBUTE_INDEX_TCP_INTERFACE = 1 }; + enum { + ATTRIBUTE_INDEX_NUM_PARTITIONS = 0, + ATTRIBUTE_INDEX_LOCATION = 1, + ATTRIBUTE_INDEX_ARCHIVE_LOCATION = 2, + ATTRIBUTE_INDEX_MAX_DATA_FILE_SIZE = 3, + ATTRIBUTE_INDEX_MAX_JOURNAL_FILE_SIZE = 4, + ATTRIBUTE_INDEX_MAX_QLIST_FILE_SIZE = 5, + ATTRIBUTE_INDEX_PREALLOCATE = 6, + ATTRIBUTE_INDEX_MAX_ARCHIVED_FILE_SETS = 7, + ATTRIBUTE_INDEX_PREFAULT_PAGES = 8, + ATTRIBUTE_INDEX_FLUSH_AT_SHUTDOWN = 9, + ATTRIBUTE_INDEX_SYNC_CONFIG = 10 + }; // CONSTANTS static const char CLASS_NAME[]; + static const bool DEFAULT_INITIALIZER_PREALLOCATE; + + static const bool DEFAULT_INITIALIZER_PREFAULT_PAGES; + + static const bool DEFAULT_INITIALIZER_FLUSH_AT_SHUTDOWN; + static const bdlat_AttributeInfo ATTRIBUTE_INFO_ARRAY[]; public: @@ -5321,29 +5293,29 @@ class NetworkInterfaces { // exists, and 0 otherwise. // CREATORS - explicit NetworkInterfaces(bslma::Allocator* basicAllocator = 0); - // Create an object of type 'NetworkInterfaces' having the default - // value. Use the optionally specified 'basicAllocator' to supply - // memory. If 'basicAllocator' is 0, the currently installed default - // allocator is used. + explicit PartitionConfig(bslma::Allocator* basicAllocator = 0); + // Create an object of type 'PartitionConfig' having the default value. + // Use the optionally specified 'basicAllocator' to supply memory. If + // 'basicAllocator' is 0, the currently installed default allocator is + // used. - NetworkInterfaces(const NetworkInterfaces& original, - bslma::Allocator* basicAllocator = 0); - // Create an object of type 'NetworkInterfaces' having the value of the + PartitionConfig(const PartitionConfig& original, + bslma::Allocator* basicAllocator = 0); + // Create an object of type 'PartitionConfig' having the value of the // specified 'original' object. Use the optionally specified // 'basicAllocator' to supply memory. If 'basicAllocator' is 0, the // currently installed default allocator is used. #if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) && \ defined(BSLS_COMPILERFEATURES_SUPPORT_NOEXCEPT) - NetworkInterfaces(NetworkInterfaces&& original) noexcept; - // Create an object of type 'NetworkInterfaces' having the value of the + PartitionConfig(PartitionConfig&& original) noexcept; + // Create an object of type 'PartitionConfig' having the value of the // specified 'original' object. After performing this action, the // 'original' object will be left in a valid, but unspecified state. - NetworkInterfaces(NetworkInterfaces&& original, - bslma::Allocator* basicAllocator); - // Create an object of type 'NetworkInterfaces' having the value of the + PartitionConfig(PartitionConfig&& original, + bslma::Allocator* basicAllocator); + // Create an object of type 'PartitionConfig' having the value of the // specified 'original' object. After performing this action, the // 'original' object will be left in a valid, but unspecified state. // Use the optionally specified 'basicAllocator' to supply memory. If @@ -5351,16 +5323,16 @@ class NetworkInterfaces { // used. #endif - ~NetworkInterfaces(); + ~PartitionConfig(); // Destroy this object. // MANIPULATORS - NetworkInterfaces& operator=(const NetworkInterfaces& rhs); + PartitionConfig& operator=(const PartitionConfig& rhs); // Assign to this object the value of the specified 'rhs' object. #if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) && \ defined(BSLS_COMPILERFEATURES_SUPPORT_NOEXCEPT) - NetworkInterfaces& operator=(NetworkInterfaces&& rhs); + PartitionConfig& operator=(PartitionConfig&& rhs); // Assign to this object the value of the specified 'rhs' object. // After performing this action, the 'rhs' object will be left in a // valid, but unspecified state. @@ -5399,14 +5371,50 @@ class NetworkInterfaces { // returned from the invocation of 'manipulator' if 'name' identifies // an attribute of this class, and -1 otherwise. - Heartbeat& heartbeats(); - // Return a reference to the modifiable "Heartbeats" attribute of this - // object. - - bdlb::NullableValue& tcpInterface(); - // Return a reference to the modifiable "TcpInterface" attribute of + int& numPartitions(); + // Return a reference to the modifiable "NumPartitions" attribute of + // this object. + + bsl::string& location(); + // Return a reference to the modifiable "Location" attribute of this + // object. + + bsl::string& archiveLocation(); + // Return a reference to the modifiable "ArchiveLocation" attribute of + // this object. + + bsls::Types::Uint64& maxDataFileSize(); + // Return a reference to the modifiable "MaxDataFileSize" attribute of + // this object. + + bsls::Types::Uint64& maxJournalFileSize(); + // Return a reference to the modifiable "MaxJournalFileSize" attribute + // of this object. + + bsls::Types::Uint64& maxQlistFileSize(); + // Return a reference to the modifiable "MaxQlistFileSize" attribute of + // this object. + + bool& preallocate(); + // Return a reference to the modifiable "Preallocate" attribute of this + // object. + + int& maxArchivedFileSets(); + // Return a reference to the modifiable "MaxArchivedFileSets" attribute + // of this object. + + bool& prefaultPages(); + // Return a reference to the modifiable "PrefaultPages" attribute of + // this object. + + bool& flushAtShutdown(); + // Return a reference to the modifiable "FlushAtShutdown" attribute of // this object. + StorageSyncConfig& syncConfig(); + // Return a reference to the modifiable "SyncConfig" attribute of this + // object. + // ACCESSORS bsl::ostream& print(bsl::ostream& stream, int level = 0, int spacesPerLevel = 4) const; @@ -5450,34 +5458,63 @@ class NetworkInterfaces { // invocation of 'accessor' if 'name' identifies an attribute of this // class, and -1 otherwise. - const Heartbeat& heartbeats() const; + int numPartitions() const; + // Return the value of the "NumPartitions" attribute of this object. + + const bsl::string& location() const; + // Return a reference offering non-modifiable access to the "Location" + // attribute of this object. + + const bsl::string& archiveLocation() const; // Return a reference offering non-modifiable access to the - // "Heartbeats" attribute of this object. + // "ArchiveLocation" attribute of this object. - const bdlb::NullableValue& tcpInterface() const; + bsls::Types::Uint64 maxDataFileSize() const; + // Return the value of the "MaxDataFileSize" attribute of this object. + + bsls::Types::Uint64 maxJournalFileSize() const; + // Return the value of the "MaxJournalFileSize" attribute of this + // object. + + bsls::Types::Uint64 maxQlistFileSize() const; + // Return the value of the "MaxQlistFileSize" attribute of this object. + + bool preallocate() const; + // Return the value of the "Preallocate" attribute of this object. + + int maxArchivedFileSets() const; + // Return the value of the "MaxArchivedFileSets" attribute of this + // object. + + bool prefaultPages() const; + // Return the value of the "PrefaultPages" attribute of this object. + + bool flushAtShutdown() const; + // Return the value of the "FlushAtShutdown" attribute of this object. + + const StorageSyncConfig& syncConfig() const; // Return a reference offering non-modifiable access to the - // "TcpInterface" attribute of this object. + // "SyncConfig" attribute of this object. // HIDDEN FRIENDS - friend bool operator==(const NetworkInterfaces& lhs, - const NetworkInterfaces& rhs) + friend bool operator==(const PartitionConfig& lhs, + const PartitionConfig& rhs) // Return 'true' if the specified 'lhs' and 'rhs' attribute objects // have the same value, and 'false' otherwise. Two attribute objects // have the same value if each respective attribute has the same value. { - return lhs.heartbeats() == rhs.heartbeats() && - lhs.tcpInterface() == rhs.tcpInterface(); + return lhs.isEqualTo(rhs); } - friend bool operator!=(const NetworkInterfaces& lhs, - const NetworkInterfaces& rhs) + friend bool operator!=(const PartitionConfig& lhs, + const PartitionConfig& rhs) // Returns '!(lhs == rhs)' { return !(lhs == rhs); } - friend bsl::ostream& operator<<(bsl::ostream& stream, - const NetworkInterfaces& rhs) + friend bsl::ostream& operator<<(bsl::ostream& stream, + const PartitionConfig& rhs) // Format the specified 'rhs' to the specified output 'stream' and // return a reference to the modifiable 'stream'. { @@ -5485,16 +5522,14 @@ class NetworkInterfaces { } template - friend void hashAppend(t_HASH_ALGORITHM& hashAlg, - const NetworkInterfaces& object) + friend void hashAppend(t_HASH_ALGORITHM& hashAlg, + const PartitionConfig& object) // Pass the specified 'object' to the specified 'hashAlg'. This // function integrates with the 'bslh' modular hashing system and // effectively provides a 'bsl::hash' specialization for - // 'NetworkInterfaces'. + // 'PartitionConfig'. { - using bslh::hashAppend; - hashAppend(hashAlg, object.heartbeats()); - hashAppend(hashAlg, object.tcpInterface()); + object.hashAppendImpl(hashAlg); } }; @@ -5503,90 +5538,48 @@ class NetworkInterfaces { // TRAITS BDLAT_DECL_SEQUENCE_WITH_ALLOCATOR_BITWISEMOVEABLE_TRAITS( - mqbcfg::NetworkInterfaces) + mqbcfg::PartitionConfig) namespace mqbcfg { -// ===================== -// class PartitionConfig -// ===================== - -class PartitionConfig { - // Type representing the configuration for the storage layer of a cluster. - // - // numPartitions........: number of partitions at each node in the cluster - // location.............: location of active files for a partition - // archiveLocation......: location of archive files for a partition - // maxDataFileSize......: maximum size of partitions' data file - // maxJournalFileSize...: maximum size of partitions' journal file - // maxQlistFileSize.....: maximum size of partitions' qlist file - // preallocate..........: flag to indicate whether files should be - // preallocated on disk maxArchivedFileSets..: maximum number of archived - // file sets per partition to keep prefaultPages........: flag to indicate - // whether to populate (prefault) page tables for a mapping. - // flushAtShutdown......: flag to indicate whether broker should flush - // storage files to disk at shutdown syncConfig...........: configuration - // for storage synchronization and recovery +// ================================ +// class StatPluginConfigPrometheus +// ================================ +class StatPluginConfigPrometheus { // INSTANCE DATA - bsls::Types::Uint64 d_maxDataFileSize; - bsls::Types::Uint64 d_maxJournalFileSize; - bsls::Types::Uint64 d_maxQlistFileSize; - bsl::string d_location; - bsl::string d_archiveLocation; - StorageSyncConfig d_syncConfig; - int d_numPartitions; - int d_maxArchivedFileSets; - bool d_preallocate; - bool d_prefaultPages; - bool d_flushAtShutdown; + bsl::string d_host; + int d_port; + ExportMode::Value d_mode; // PRIVATE ACCESSORS template void hashAppendImpl(t_HASH_ALGORITHM& hashAlgorithm) const; - bool isEqualTo(const PartitionConfig& rhs) const; - public: // TYPES enum { - ATTRIBUTE_ID_NUM_PARTITIONS = 0, - ATTRIBUTE_ID_LOCATION = 1, - ATTRIBUTE_ID_ARCHIVE_LOCATION = 2, - ATTRIBUTE_ID_MAX_DATA_FILE_SIZE = 3, - ATTRIBUTE_ID_MAX_JOURNAL_FILE_SIZE = 4, - ATTRIBUTE_ID_MAX_QLIST_FILE_SIZE = 5, - ATTRIBUTE_ID_PREALLOCATE = 6, - ATTRIBUTE_ID_MAX_ARCHIVED_FILE_SETS = 7, - ATTRIBUTE_ID_PREFAULT_PAGES = 8, - ATTRIBUTE_ID_FLUSH_AT_SHUTDOWN = 9, - ATTRIBUTE_ID_SYNC_CONFIG = 10 + ATTRIBUTE_ID_MODE = 0, + ATTRIBUTE_ID_HOST = 1, + ATTRIBUTE_ID_PORT = 2 }; - enum { NUM_ATTRIBUTES = 11 }; + enum { NUM_ATTRIBUTES = 3 }; enum { - ATTRIBUTE_INDEX_NUM_PARTITIONS = 0, - ATTRIBUTE_INDEX_LOCATION = 1, - ATTRIBUTE_INDEX_ARCHIVE_LOCATION = 2, - ATTRIBUTE_INDEX_MAX_DATA_FILE_SIZE = 3, - ATTRIBUTE_INDEX_MAX_JOURNAL_FILE_SIZE = 4, - ATTRIBUTE_INDEX_MAX_QLIST_FILE_SIZE = 5, - ATTRIBUTE_INDEX_PREALLOCATE = 6, - ATTRIBUTE_INDEX_MAX_ARCHIVED_FILE_SETS = 7, - ATTRIBUTE_INDEX_PREFAULT_PAGES = 8, - ATTRIBUTE_INDEX_FLUSH_AT_SHUTDOWN = 9, - ATTRIBUTE_INDEX_SYNC_CONFIG = 10 + ATTRIBUTE_INDEX_MODE = 0, + ATTRIBUTE_INDEX_HOST = 1, + ATTRIBUTE_INDEX_PORT = 2 }; // CONSTANTS static const char CLASS_NAME[]; - static const bool DEFAULT_INITIALIZER_PREALLOCATE; + static const ExportMode::Value DEFAULT_INITIALIZER_MODE; - static const bool DEFAULT_INITIALIZER_PREFAULT_PAGES; + static const char DEFAULT_INITIALIZER_HOST[]; - static const bool DEFAULT_INITIALIZER_FLUSH_AT_SHUTDOWN; + static const int DEFAULT_INITIALIZER_PORT; static const bdlat_AttributeInfo ATTRIBUTE_INFO_ARRAY[]; @@ -5603,46 +5596,48 @@ class PartitionConfig { // exists, and 0 otherwise. // CREATORS - explicit PartitionConfig(bslma::Allocator* basicAllocator = 0); - // Create an object of type 'PartitionConfig' having the default value. - // Use the optionally specified 'basicAllocator' to supply memory. If - // 'basicAllocator' is 0, the currently installed default allocator is - // used. + explicit StatPluginConfigPrometheus(bslma::Allocator* basicAllocator = 0); + // Create an object of type 'StatPluginConfigPrometheus' having the + // default value. Use the optionally specified 'basicAllocator' to + // supply memory. If 'basicAllocator' is 0, the currently installed + // default allocator is used. - PartitionConfig(const PartitionConfig& original, - bslma::Allocator* basicAllocator = 0); - // Create an object of type 'PartitionConfig' having the value of the - // specified 'original' object. Use the optionally specified - // 'basicAllocator' to supply memory. If 'basicAllocator' is 0, the - // currently installed default allocator is used. + StatPluginConfigPrometheus(const StatPluginConfigPrometheus& original, + bslma::Allocator* basicAllocator = 0); + // Create an object of type 'StatPluginConfigPrometheus' having the + // value of the specified 'original' object. Use the optionally + // specified 'basicAllocator' to supply memory. If 'basicAllocator' is + // 0, the currently installed default allocator is used. #if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) && \ defined(BSLS_COMPILERFEATURES_SUPPORT_NOEXCEPT) - PartitionConfig(PartitionConfig&& original) noexcept; - // Create an object of type 'PartitionConfig' having the value of the - // specified 'original' object. After performing this action, the - // 'original' object will be left in a valid, but unspecified state. + StatPluginConfigPrometheus(StatPluginConfigPrometheus&& original) noexcept; + // Create an object of type 'StatPluginConfigPrometheus' having the + // value of the specified 'original' object. After performing this + // action, the 'original' object will be left in a valid, but + // unspecified state. - PartitionConfig(PartitionConfig&& original, - bslma::Allocator* basicAllocator); - // Create an object of type 'PartitionConfig' having the value of the - // specified 'original' object. After performing this action, the - // 'original' object will be left in a valid, but unspecified state. - // Use the optionally specified 'basicAllocator' to supply memory. If - // 'basicAllocator' is 0, the currently installed default allocator is - // used. + StatPluginConfigPrometheus(StatPluginConfigPrometheus&& original, + bslma::Allocator* basicAllocator); + // Create an object of type 'StatPluginConfigPrometheus' having the + // value of the specified 'original' object. After performing this + // action, the 'original' object will be left in a valid, but + // unspecified state. Use the optionally specified 'basicAllocator' to + // supply memory. If 'basicAllocator' is 0, the currently installed + // default allocator is used. #endif - ~PartitionConfig(); + ~StatPluginConfigPrometheus(); // Destroy this object. // MANIPULATORS - PartitionConfig& operator=(const PartitionConfig& rhs); + StatPluginConfigPrometheus& + operator=(const StatPluginConfigPrometheus& rhs); // Assign to this object the value of the specified 'rhs' object. #if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) && \ defined(BSLS_COMPILERFEATURES_SUPPORT_NOEXCEPT) - PartitionConfig& operator=(PartitionConfig&& rhs); + StatPluginConfigPrometheus& operator=(StatPluginConfigPrometheus&& rhs); // Assign to this object the value of the specified 'rhs' object. // After performing this action, the 'rhs' object will be left in a // valid, but unspecified state. @@ -5681,49 +5676,17 @@ class PartitionConfig { // returned from the invocation of 'manipulator' if 'name' identifies // an attribute of this class, and -1 otherwise. - int& numPartitions(); - // Return a reference to the modifiable "NumPartitions" attribute of - // this object. + ExportMode::Value& mode(); + // Return a reference to the modifiable "Mode" attribute of this + // object. - bsl::string& location(); - // Return a reference to the modifiable "Location" attribute of this + bsl::string& host(); + // Return a reference to the modifiable "Host" attribute of this // object. - bsl::string& archiveLocation(); - // Return a reference to the modifiable "ArchiveLocation" attribute of - // this object. - - bsls::Types::Uint64& maxDataFileSize(); - // Return a reference to the modifiable "MaxDataFileSize" attribute of - // this object. - - bsls::Types::Uint64& maxJournalFileSize(); - // Return a reference to the modifiable "MaxJournalFileSize" attribute - // of this object. - - bsls::Types::Uint64& maxQlistFileSize(); - // Return a reference to the modifiable "MaxQlistFileSize" attribute of - // this object. - - bool& preallocate(); - // Return a reference to the modifiable "Preallocate" attribute of this - // object. - - int& maxArchivedFileSets(); - // Return a reference to the modifiable "MaxArchivedFileSets" attribute - // of this object. - - bool& prefaultPages(); - // Return a reference to the modifiable "PrefaultPages" attribute of - // this object. - - bool& flushAtShutdown(); - // Return a reference to the modifiable "FlushAtShutdown" attribute of - // this object. - - StorageSyncConfig& syncConfig(); - // Return a reference to the modifiable "SyncConfig" attribute of this - // object. + int& port(); + // Return a reference to the modifiable "Port" attribute of this + // object. // ACCESSORS bsl::ostream& @@ -5768,63 +5731,36 @@ class PartitionConfig { // invocation of 'accessor' if 'name' identifies an attribute of this // class, and -1 otherwise. - int numPartitions() const; - // Return the value of the "NumPartitions" attribute of this object. + ExportMode::Value mode() const; + // Return the value of the "Mode" attribute of this object. - const bsl::string& location() const; - // Return a reference offering non-modifiable access to the "Location" + const bsl::string& host() const; + // Return a reference offering non-modifiable access to the "Host" // attribute of this object. - const bsl::string& archiveLocation() const; - // Return a reference offering non-modifiable access to the - // "ArchiveLocation" attribute of this object. - - bsls::Types::Uint64 maxDataFileSize() const; - // Return the value of the "MaxDataFileSize" attribute of this object. - - bsls::Types::Uint64 maxJournalFileSize() const; - // Return the value of the "MaxJournalFileSize" attribute of this - // object. - - bsls::Types::Uint64 maxQlistFileSize() const; - // Return the value of the "MaxQlistFileSize" attribute of this object. - - bool preallocate() const; - // Return the value of the "Preallocate" attribute of this object. - - int maxArchivedFileSets() const; - // Return the value of the "MaxArchivedFileSets" attribute of this - // object. - - bool prefaultPages() const; - // Return the value of the "PrefaultPages" attribute of this object. - - bool flushAtShutdown() const; - // Return the value of the "FlushAtShutdown" attribute of this object. - - const StorageSyncConfig& syncConfig() const; - // Return a reference offering non-modifiable access to the - // "SyncConfig" attribute of this object. + int port() const; + // Return the value of the "Port" attribute of this object. // HIDDEN FRIENDS - friend bool operator==(const PartitionConfig& lhs, - const PartitionConfig& rhs) + friend bool operator==(const StatPluginConfigPrometheus& lhs, + const StatPluginConfigPrometheus& rhs) // Return 'true' if the specified 'lhs' and 'rhs' attribute objects // have the same value, and 'false' otherwise. Two attribute objects // have the same value if each respective attribute has the same value. { - return lhs.isEqualTo(rhs); + return lhs.mode() == rhs.mode() && lhs.host() == rhs.host() && + lhs.port() == rhs.port(); } - friend bool operator!=(const PartitionConfig& lhs, - const PartitionConfig& rhs) + friend bool operator!=(const StatPluginConfigPrometheus& lhs, + const StatPluginConfigPrometheus& rhs) // Returns '!(lhs == rhs)' { return !(lhs == rhs); } - friend bsl::ostream& operator<<(bsl::ostream& stream, - const PartitionConfig& rhs) + friend bsl::ostream& operator<<(bsl::ostream& stream, + const StatPluginConfigPrometheus& rhs) // Format the specified 'rhs' to the specified output 'stream' and // return a reference to the modifiable 'stream'. { @@ -5832,12 +5768,12 @@ class PartitionConfig { } template - friend void hashAppend(t_HASH_ALGORITHM& hashAlg, - const PartitionConfig& object) + friend void hashAppend(t_HASH_ALGORITHM& hashAlg, + const StatPluginConfigPrometheus& object) // Pass the specified 'object' to the specified 'hashAlg'. This // function integrates with the 'bslh' modular hashing system and // effectively provides a 'bsl::hash' specialization for - // 'PartitionConfig'. + // 'StatPluginConfigPrometheus'. { object.hashAppendImpl(hashAlg); } @@ -5848,48 +5784,85 @@ class PartitionConfig { // TRAITS BDLAT_DECL_SEQUENCE_WITH_ALLOCATOR_BITWISEMOVEABLE_TRAITS( - mqbcfg::PartitionConfig) + mqbcfg::StatPluginConfigPrometheus) namespace mqbcfg { -// ================================ -// class StatPluginConfigPrometheus -// ================================ +// ======================== +// class TcpInterfaceConfig +// ======================== + +class TcpInterfaceConfig { + // name.................: The name of the TCP session manager. + // port.................: (Deprecated) The port to receive connections. + // lowWatermark.........: highWatermark........: Watermarks used for + // channels with a client or proxy. nodeLowWatermark.....: + // nodeHighWatermark....: Reduced watermarks for communication between + // cluster nodes where BlazingMQ maintains its own cache. + // heartbeatIntervalMs..: How often (in milliseconds) to check if the + // channel received data, and emit heartbeat. 0 to globally disable. + // listeners: A list of listener interfaces to receive TCP connections + // from. When non-empty this option overrides the listener specified by + // port. -class StatPluginConfigPrometheus { // INSTANCE DATA - bsl::string d_host; - int d_port; - ExportMode::Value d_mode; + bsls::Types::Int64 d_lowWatermark; + bsls::Types::Int64 d_highWatermark; + bsls::Types::Int64 d_nodeLowWatermark; + bsls::Types::Int64 d_nodeHighWatermark; + bsl::vector d_listeners; + bsl::string d_name; + int d_port; + int d_ioThreads; + int d_maxConnections; + int d_heartbeatIntervalMs; // PRIVATE ACCESSORS template void hashAppendImpl(t_HASH_ALGORITHM& hashAlgorithm) const; + bool isEqualTo(const TcpInterfaceConfig& rhs) const; + public: // TYPES enum { - ATTRIBUTE_ID_MODE = 0, - ATTRIBUTE_ID_HOST = 1, - ATTRIBUTE_ID_PORT = 2 + ATTRIBUTE_ID_NAME = 0, + ATTRIBUTE_ID_PORT = 1, + ATTRIBUTE_ID_IO_THREADS = 2, + ATTRIBUTE_ID_MAX_CONNECTIONS = 3, + ATTRIBUTE_ID_LOW_WATERMARK = 4, + ATTRIBUTE_ID_HIGH_WATERMARK = 5, + ATTRIBUTE_ID_NODE_LOW_WATERMARK = 6, + ATTRIBUTE_ID_NODE_HIGH_WATERMARK = 7, + ATTRIBUTE_ID_HEARTBEAT_INTERVAL_MS = 8, + ATTRIBUTE_ID_LISTENERS = 9 }; - enum { NUM_ATTRIBUTES = 3 }; + enum { NUM_ATTRIBUTES = 10 }; enum { - ATTRIBUTE_INDEX_MODE = 0, - ATTRIBUTE_INDEX_HOST = 1, - ATTRIBUTE_INDEX_PORT = 2 + ATTRIBUTE_INDEX_NAME = 0, + ATTRIBUTE_INDEX_PORT = 1, + ATTRIBUTE_INDEX_IO_THREADS = 2, + ATTRIBUTE_INDEX_MAX_CONNECTIONS = 3, + ATTRIBUTE_INDEX_LOW_WATERMARK = 4, + ATTRIBUTE_INDEX_HIGH_WATERMARK = 5, + ATTRIBUTE_INDEX_NODE_LOW_WATERMARK = 6, + ATTRIBUTE_INDEX_NODE_HIGH_WATERMARK = 7, + ATTRIBUTE_INDEX_HEARTBEAT_INTERVAL_MS = 8, + ATTRIBUTE_INDEX_LISTENERS = 9 }; // CONSTANTS static const char CLASS_NAME[]; - static const ExportMode::Value DEFAULT_INITIALIZER_MODE; + static const int DEFAULT_INITIALIZER_MAX_CONNECTIONS; - static const char DEFAULT_INITIALIZER_HOST[]; + static const bsls::Types::Int64 DEFAULT_INITIALIZER_NODE_LOW_WATERMARK; - static const int DEFAULT_INITIALIZER_PORT; + static const bsls::Types::Int64 DEFAULT_INITIALIZER_NODE_HIGH_WATERMARK; + + static const int DEFAULT_INITIALIZER_HEARTBEAT_INTERVAL_MS; static const bdlat_AttributeInfo ATTRIBUTE_INFO_ARRAY[]; @@ -5906,48 +5879,46 @@ class StatPluginConfigPrometheus { // exists, and 0 otherwise. // CREATORS - explicit StatPluginConfigPrometheus(bslma::Allocator* basicAllocator = 0); - // Create an object of type 'StatPluginConfigPrometheus' having the - // default value. Use the optionally specified 'basicAllocator' to - // supply memory. If 'basicAllocator' is 0, the currently installed - // default allocator is used. + explicit TcpInterfaceConfig(bslma::Allocator* basicAllocator = 0); + // Create an object of type 'TcpInterfaceConfig' having the default + // value. Use the optionally specified 'basicAllocator' to supply + // memory. If 'basicAllocator' is 0, the currently installed default + // allocator is used. - StatPluginConfigPrometheus(const StatPluginConfigPrometheus& original, - bslma::Allocator* basicAllocator = 0); - // Create an object of type 'StatPluginConfigPrometheus' having the - // value of the specified 'original' object. Use the optionally - // specified 'basicAllocator' to supply memory. If 'basicAllocator' is - // 0, the currently installed default allocator is used. + TcpInterfaceConfig(const TcpInterfaceConfig& original, + bslma::Allocator* basicAllocator = 0); + // Create an object of type 'TcpInterfaceConfig' having the value of + // the specified 'original' object. Use the optionally specified + // 'basicAllocator' to supply memory. If 'basicAllocator' is 0, the + // currently installed default allocator is used. #if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) && \ defined(BSLS_COMPILERFEATURES_SUPPORT_NOEXCEPT) - StatPluginConfigPrometheus(StatPluginConfigPrometheus&& original) noexcept; - // Create an object of type 'StatPluginConfigPrometheus' having the - // value of the specified 'original' object. After performing this - // action, the 'original' object will be left in a valid, but - // unspecified state. + TcpInterfaceConfig(TcpInterfaceConfig&& original) noexcept; + // Create an object of type 'TcpInterfaceConfig' having the value of + // the specified 'original' object. After performing this action, the + // 'original' object will be left in a valid, but unspecified state. - StatPluginConfigPrometheus(StatPluginConfigPrometheus&& original, - bslma::Allocator* basicAllocator); - // Create an object of type 'StatPluginConfigPrometheus' having the - // value of the specified 'original' object. After performing this - // action, the 'original' object will be left in a valid, but - // unspecified state. Use the optionally specified 'basicAllocator' to - // supply memory. If 'basicAllocator' is 0, the currently installed - // default allocator is used. + TcpInterfaceConfig(TcpInterfaceConfig&& original, + bslma::Allocator* basicAllocator); + // Create an object of type 'TcpInterfaceConfig' having the value of + // the specified 'original' object. After performing this action, the + // 'original' object will be left in a valid, but unspecified state. + // Use the optionally specified 'basicAllocator' to supply memory. If + // 'basicAllocator' is 0, the currently installed default allocator is + // used. #endif - ~StatPluginConfigPrometheus(); + ~TcpInterfaceConfig(); // Destroy this object. // MANIPULATORS - StatPluginConfigPrometheus& - operator=(const StatPluginConfigPrometheus& rhs); + TcpInterfaceConfig& operator=(const TcpInterfaceConfig& rhs); // Assign to this object the value of the specified 'rhs' object. #if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) && \ defined(BSLS_COMPILERFEATURES_SUPPORT_NOEXCEPT) - StatPluginConfigPrometheus& operator=(StatPluginConfigPrometheus&& rhs); + TcpInterfaceConfig& operator=(TcpInterfaceConfig&& rhs); // Assign to this object the value of the specified 'rhs' object. // After performing this action, the 'rhs' object will be left in a // valid, but unspecified state. @@ -5986,18 +5957,46 @@ class StatPluginConfigPrometheus { // returned from the invocation of 'manipulator' if 'name' identifies // an attribute of this class, and -1 otherwise. - ExportMode::Value& mode(); - // Return a reference to the modifiable "Mode" attribute of this - // object. - - bsl::string& host(); - // Return a reference to the modifiable "Host" attribute of this + bsl::string& name(); + // Return a reference to the modifiable "Name" attribute of this // object. int& port(); // Return a reference to the modifiable "Port" attribute of this // object. + int& ioThreads(); + // Return a reference to the modifiable "IoThreads" attribute of this + // object. + + int& maxConnections(); + // Return a reference to the modifiable "MaxConnections" attribute of + // this object. + + bsls::Types::Int64& lowWatermark(); + // Return a reference to the modifiable "LowWatermark" attribute of + // this object. + + bsls::Types::Int64& highWatermark(); + // Return a reference to the modifiable "HighWatermark" attribute of + // this object. + + bsls::Types::Int64& nodeLowWatermark(); + // Return a reference to the modifiable "NodeLowWatermark" attribute of + // this object. + + bsls::Types::Int64& nodeHighWatermark(); + // Return a reference to the modifiable "NodeHighWatermark" attribute + // of this object. + + int& heartbeatIntervalMs(); + // Return a reference to the modifiable "HeartbeatIntervalMs" attribute + // of this object. + + bsl::vector& listeners(); + // Return a reference to the modifiable "Listeners" attribute of this + // object. + // ACCESSORS bsl::ostream& print(bsl::ostream& stream, int level = 0, int spacesPerLevel = 4) const; @@ -6041,36 +6040,59 @@ class StatPluginConfigPrometheus { // invocation of 'accessor' if 'name' identifies an attribute of this // class, and -1 otherwise. - ExportMode::Value mode() const; - // Return the value of the "Mode" attribute of this object. - - const bsl::string& host() const; - // Return a reference offering non-modifiable access to the "Host" + const bsl::string& name() const; + // Return a reference offering non-modifiable access to the "Name" // attribute of this object. int port() const; // Return the value of the "Port" attribute of this object. - // HIDDEN FRIENDS - friend bool operator==(const StatPluginConfigPrometheus& lhs, - const StatPluginConfigPrometheus& rhs) - // Return 'true' if the specified 'lhs' and 'rhs' attribute objects - // have the same value, and 'false' otherwise. Two attribute objects - // have the same value if each respective attribute has the same value. - { - return lhs.mode() == rhs.mode() && lhs.host() == rhs.host() && - lhs.port() == rhs.port(); - } + int ioThreads() const; + // Return the value of the "IoThreads" attribute of this object. - friend bool operator!=(const StatPluginConfigPrometheus& lhs, - const StatPluginConfigPrometheus& rhs) + int maxConnections() const; + // Return the value of the "MaxConnections" attribute of this object. + + bsls::Types::Int64 lowWatermark() const; + // Return the value of the "LowWatermark" attribute of this object. + + bsls::Types::Int64 highWatermark() const; + // Return the value of the "HighWatermark" attribute of this object. + + bsls::Types::Int64 nodeLowWatermark() const; + // Return the value of the "NodeLowWatermark" attribute of this object. + + bsls::Types::Int64 nodeHighWatermark() const; + // Return the value of the "NodeHighWatermark" attribute of this + // object. + + int heartbeatIntervalMs() const; + // Return the value of the "HeartbeatIntervalMs" attribute of this + // object. + + const bsl::vector& listeners() const; + // Return a reference offering non-modifiable access to the "Listeners" + // attribute of this object. + + // HIDDEN FRIENDS + friend bool operator==(const TcpInterfaceConfig& lhs, + const TcpInterfaceConfig& rhs) + // Return 'true' if the specified 'lhs' and 'rhs' attribute objects + // have the same value, and 'false' otherwise. Two attribute objects + // have the same value if each respective attribute has the same value. + { + return lhs.isEqualTo(rhs); + } + + friend bool operator!=(const TcpInterfaceConfig& lhs, + const TcpInterfaceConfig& rhs) // Returns '!(lhs == rhs)' { return !(lhs == rhs); } - friend bsl::ostream& operator<<(bsl::ostream& stream, - const StatPluginConfigPrometheus& rhs) + friend bsl::ostream& operator<<(bsl::ostream& stream, + const TcpInterfaceConfig& rhs) // Format the specified 'rhs' to the specified output 'stream' and // return a reference to the modifiable 'stream'. { @@ -6078,12 +6100,12 @@ class StatPluginConfigPrometheus { } template - friend void hashAppend(t_HASH_ALGORITHM& hashAlg, - const StatPluginConfigPrometheus& object) + friend void hashAppend(t_HASH_ALGORITHM& hashAlg, + const TcpInterfaceConfig& object) // Pass the specified 'object' to the specified 'hashAlg'. This // function integrates with the 'bslh' modular hashing system and // effectively provides a 'bsl::hash' specialization for - // 'StatPluginConfigPrometheus'. + // 'TcpInterfaceConfig'. { object.hashAppendImpl(hashAlg); } @@ -6094,7 +6116,7 @@ class StatPluginConfigPrometheus { // TRAITS BDLAT_DECL_SEQUENCE_WITH_ALLOCATOR_BITWISEMOVEABLE_TRAITS( - mqbcfg::StatPluginConfigPrometheus) + mqbcfg::TcpInterfaceConfig) namespace mqbcfg { @@ -6549,26 +6571,22 @@ BDLAT_DECL_SEQUENCE_WITH_BITWISEMOVEABLE_TRAITS(mqbcfg::DispatcherConfig) namespace mqbcfg { -// =============================== -// class ReversedClusterConnection -// =============================== - -class ReversedClusterConnection { - // Type representing the configuration for remote cluster connections.. - // name.............: name of the cluster connections......: list of - // connections to establish +// ======================= +// class NetworkInterfaces +// ======================= +class NetworkInterfaces { // INSTANCE DATA - bsl::vector d_connections; - bsl::string d_name; + bdlb::NullableValue d_tcpInterface; + Heartbeat d_heartbeats; public: // TYPES - enum { ATTRIBUTE_ID_NAME = 0, ATTRIBUTE_ID_CONNECTIONS = 1 }; + enum { ATTRIBUTE_ID_HEARTBEATS = 0, ATTRIBUTE_ID_TCP_INTERFACE = 1 }; enum { NUM_ATTRIBUTES = 2 }; - enum { ATTRIBUTE_INDEX_NAME = 0, ATTRIBUTE_INDEX_CONNECTIONS = 1 }; + enum { ATTRIBUTE_INDEX_HEARTBEATS = 0, ATTRIBUTE_INDEX_TCP_INTERFACE = 1 }; // CONSTANTS static const char CLASS_NAME[]; @@ -6588,47 +6606,46 @@ class ReversedClusterConnection { // exists, and 0 otherwise. // CREATORS - explicit ReversedClusterConnection(bslma::Allocator* basicAllocator = 0); - // Create an object of type 'ReversedClusterConnection' having the - // default value. Use the optionally specified 'basicAllocator' to - // supply memory. If 'basicAllocator' is 0, the currently installed - // default allocator is used. + explicit NetworkInterfaces(bslma::Allocator* basicAllocator = 0); + // Create an object of type 'NetworkInterfaces' having the default + // value. Use the optionally specified 'basicAllocator' to supply + // memory. If 'basicAllocator' is 0, the currently installed default + // allocator is used. - ReversedClusterConnection(const ReversedClusterConnection& original, - bslma::Allocator* basicAllocator = 0); - // Create an object of type 'ReversedClusterConnection' having the - // value of the specified 'original' object. Use the optionally - // specified 'basicAllocator' to supply memory. If 'basicAllocator' is - // 0, the currently installed default allocator is used. + NetworkInterfaces(const NetworkInterfaces& original, + bslma::Allocator* basicAllocator = 0); + // Create an object of type 'NetworkInterfaces' having the value of the + // specified 'original' object. Use the optionally specified + // 'basicAllocator' to supply memory. If 'basicAllocator' is 0, the + // currently installed default allocator is used. #if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) && \ defined(BSLS_COMPILERFEATURES_SUPPORT_NOEXCEPT) - ReversedClusterConnection(ReversedClusterConnection&& original) noexcept; - // Create an object of type 'ReversedClusterConnection' having the - // value of the specified 'original' object. After performing this - // action, the 'original' object will be left in a valid, but - // unspecified state. + NetworkInterfaces(NetworkInterfaces&& original) noexcept; + // Create an object of type 'NetworkInterfaces' having the value of the + // specified 'original' object. After performing this action, the + // 'original' object will be left in a valid, but unspecified state. - ReversedClusterConnection(ReversedClusterConnection&& original, - bslma::Allocator* basicAllocator); - // Create an object of type 'ReversedClusterConnection' having the - // value of the specified 'original' object. After performing this - // action, the 'original' object will be left in a valid, but - // unspecified state. Use the optionally specified 'basicAllocator' to - // supply memory. If 'basicAllocator' is 0, the currently installed - // default allocator is used. + NetworkInterfaces(NetworkInterfaces&& original, + bslma::Allocator* basicAllocator); + // Create an object of type 'NetworkInterfaces' having the value of the + // specified 'original' object. After performing this action, the + // 'original' object will be left in a valid, but unspecified state. + // Use the optionally specified 'basicAllocator' to supply memory. If + // 'basicAllocator' is 0, the currently installed default allocator is + // used. #endif - ~ReversedClusterConnection(); + ~NetworkInterfaces(); // Destroy this object. // MANIPULATORS - ReversedClusterConnection& operator=(const ReversedClusterConnection& rhs); + NetworkInterfaces& operator=(const NetworkInterfaces& rhs); // Assign to this object the value of the specified 'rhs' object. #if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) && \ defined(BSLS_COMPILERFEATURES_SUPPORT_NOEXCEPT) - ReversedClusterConnection& operator=(ReversedClusterConnection&& rhs); + NetworkInterfaces& operator=(NetworkInterfaces&& rhs); // Assign to this object the value of the specified 'rhs' object. // After performing this action, the 'rhs' object will be left in a // valid, but unspecified state. @@ -6667,13 +6684,13 @@ class ReversedClusterConnection { // returned from the invocation of 'manipulator' if 'name' identifies // an attribute of this class, and -1 otherwise. - bsl::string& name(); - // Return a reference to the modifiable "Name" attribute of this + Heartbeat& heartbeats(); + // Return a reference to the modifiable "Heartbeats" attribute of this // object. - bsl::vector& connections(); - // Return a reference to the modifiable "Connections" attribute of this - // object. + bdlb::NullableValue& tcpInterface(); + // Return a reference to the modifiable "TcpInterface" attribute of + // this object. // ACCESSORS bsl::ostream& @@ -6718,34 +6735,34 @@ class ReversedClusterConnection { // invocation of 'accessor' if 'name' identifies an attribute of this // class, and -1 otherwise. - const bsl::string& name() const; - // Return a reference offering non-modifiable access to the "Name" - // attribute of this object. + const Heartbeat& heartbeats() const; + // Return a reference offering non-modifiable access to the + // "Heartbeats" attribute of this object. - const bsl::vector& connections() const; + const bdlb::NullableValue& tcpInterface() const; // Return a reference offering non-modifiable access to the - // "Connections" attribute of this object. + // "TcpInterface" attribute of this object. // HIDDEN FRIENDS - friend bool operator==(const ReversedClusterConnection& lhs, - const ReversedClusterConnection& rhs) + friend bool operator==(const NetworkInterfaces& lhs, + const NetworkInterfaces& rhs) // Return 'true' if the specified 'lhs' and 'rhs' attribute objects // have the same value, and 'false' otherwise. Two attribute objects // have the same value if each respective attribute has the same value. { - return lhs.name() == rhs.name() && - lhs.connections() == rhs.connections(); + return lhs.heartbeats() == rhs.heartbeats() && + lhs.tcpInterface() == rhs.tcpInterface(); } - friend bool operator!=(const ReversedClusterConnection& lhs, - const ReversedClusterConnection& rhs) + friend bool operator!=(const NetworkInterfaces& lhs, + const NetworkInterfaces& rhs) // Returns '!(lhs == rhs)' { return !(lhs == rhs); } - friend bsl::ostream& operator<<(bsl::ostream& stream, - const ReversedClusterConnection& rhs) + friend bsl::ostream& operator<<(bsl::ostream& stream, + const NetworkInterfaces& rhs) // Format the specified 'rhs' to the specified output 'stream' and // return a reference to the modifiable 'stream'. { @@ -6753,16 +6770,16 @@ class ReversedClusterConnection { } template - friend void hashAppend(t_HASH_ALGORITHM& hashAlg, - const ReversedClusterConnection& object) + friend void hashAppend(t_HASH_ALGORITHM& hashAlg, + const NetworkInterfaces& object) // Pass the specified 'object' to the specified 'hashAlg'. This // function integrates with the 'bslh' modular hashing system and // effectively provides a 'bsl::hash' specialization for - // 'ReversedClusterConnection'. + // 'NetworkInterfaces'. { using bslh::hashAppend; - hashAppend(hashAlg, object.name()); - hashAppend(hashAlg, object.connections()); + hashAppend(hashAlg, object.heartbeats()); + hashAppend(hashAlg, object.tcpInterface()); } }; @@ -6771,77 +6788,34 @@ class ReversedClusterConnection { // TRAITS BDLAT_DECL_SEQUENCE_WITH_ALLOCATOR_BITWISEMOVEABLE_TRAITS( - mqbcfg::ReversedClusterConnection) + mqbcfg::NetworkInterfaces) namespace mqbcfg { -// ====================== -// class StatPluginConfig -// ====================== - -class StatPluginConfig { - // INSTANCE DATA - bsl::vector d_hosts; - bsl::string d_name; - bsl::string d_namespacePrefix; - bsl::string d_instanceId; - bdlb::NullableValue d_prometheusSpecific; - int d_queueSize; - int d_queueHighWatermark; - int d_queueLowWatermark; - int d_publishInterval; +// =============================== +// class ReversedClusterConnection +// =============================== - // PRIVATE ACCESSORS - template - void hashAppendImpl(t_HASH_ALGORITHM& hashAlgorithm) const; +class ReversedClusterConnection { + // Type representing the configuration for remote cluster connections.. + // name.............: name of the cluster connections......: list of + // connections to establish - bool isEqualTo(const StatPluginConfig& rhs) const; + // INSTANCE DATA + bsl::vector d_connections; + bsl::string d_name; public: // TYPES - enum { - ATTRIBUTE_ID_NAME = 0, - ATTRIBUTE_ID_QUEUE_SIZE = 1, - ATTRIBUTE_ID_QUEUE_HIGH_WATERMARK = 2, - ATTRIBUTE_ID_QUEUE_LOW_WATERMARK = 3, - ATTRIBUTE_ID_PUBLISH_INTERVAL = 4, - ATTRIBUTE_ID_NAMESPACE_PREFIX = 5, - ATTRIBUTE_ID_HOSTS = 6, - ATTRIBUTE_ID_INSTANCE_ID = 7, - ATTRIBUTE_ID_PROMETHEUS_SPECIFIC = 8 - }; + enum { ATTRIBUTE_ID_NAME = 0, ATTRIBUTE_ID_CONNECTIONS = 1 }; - enum { NUM_ATTRIBUTES = 9 }; + enum { NUM_ATTRIBUTES = 2 }; - enum { - ATTRIBUTE_INDEX_NAME = 0, - ATTRIBUTE_INDEX_QUEUE_SIZE = 1, - ATTRIBUTE_INDEX_QUEUE_HIGH_WATERMARK = 2, - ATTRIBUTE_INDEX_QUEUE_LOW_WATERMARK = 3, - ATTRIBUTE_INDEX_PUBLISH_INTERVAL = 4, - ATTRIBUTE_INDEX_NAMESPACE_PREFIX = 5, - ATTRIBUTE_INDEX_HOSTS = 6, - ATTRIBUTE_INDEX_INSTANCE_ID = 7, - ATTRIBUTE_INDEX_PROMETHEUS_SPECIFIC = 8 - }; + enum { ATTRIBUTE_INDEX_NAME = 0, ATTRIBUTE_INDEX_CONNECTIONS = 1 }; // CONSTANTS static const char CLASS_NAME[]; - static const char DEFAULT_INITIALIZER_NAME[]; - - static const int DEFAULT_INITIALIZER_QUEUE_SIZE; - - static const int DEFAULT_INITIALIZER_QUEUE_HIGH_WATERMARK; - - static const int DEFAULT_INITIALIZER_QUEUE_LOW_WATERMARK; - - static const int DEFAULT_INITIALIZER_PUBLISH_INTERVAL; - - static const char DEFAULT_INITIALIZER_NAMESPACE_PREFIX[]; - - static const char DEFAULT_INITIALIZER_INSTANCE_ID[]; - static const bdlat_AttributeInfo ATTRIBUTE_INFO_ARRAY[]; public: @@ -6857,46 +6831,47 @@ class StatPluginConfig { // exists, and 0 otherwise. // CREATORS - explicit StatPluginConfig(bslma::Allocator* basicAllocator = 0); - // Create an object of type 'StatPluginConfig' having the default - // value. Use the optionally specified 'basicAllocator' to supply - // memory. If 'basicAllocator' is 0, the currently installed default - // allocator is used. - - StatPluginConfig(const StatPluginConfig& original, - bslma::Allocator* basicAllocator = 0); - // Create an object of type 'StatPluginConfig' having the value of the - // specified 'original' object. Use the optionally specified - // 'basicAllocator' to supply memory. If 'basicAllocator' is 0, the - // currently installed default allocator is used. + explicit ReversedClusterConnection(bslma::Allocator* basicAllocator = 0); + // Create an object of type 'ReversedClusterConnection' having the + // default value. Use the optionally specified 'basicAllocator' to + // supply memory. If 'basicAllocator' is 0, the currently installed + // default allocator is used. -#if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) && \ + ReversedClusterConnection(const ReversedClusterConnection& original, + bslma::Allocator* basicAllocator = 0); + // Create an object of type 'ReversedClusterConnection' having the + // value of the specified 'original' object. Use the optionally + // specified 'basicAllocator' to supply memory. If 'basicAllocator' is + // 0, the currently installed default allocator is used. + +#if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) && \ defined(BSLS_COMPILERFEATURES_SUPPORT_NOEXCEPT) - StatPluginConfig(StatPluginConfig&& original) noexcept; - // Create an object of type 'StatPluginConfig' having the value of the - // specified 'original' object. After performing this action, the - // 'original' object will be left in a valid, but unspecified state. + ReversedClusterConnection(ReversedClusterConnection&& original) noexcept; + // Create an object of type 'ReversedClusterConnection' having the + // value of the specified 'original' object. After performing this + // action, the 'original' object will be left in a valid, but + // unspecified state. - StatPluginConfig(StatPluginConfig&& original, - bslma::Allocator* basicAllocator); - // Create an object of type 'StatPluginConfig' having the value of the - // specified 'original' object. After performing this action, the - // 'original' object will be left in a valid, but unspecified state. - // Use the optionally specified 'basicAllocator' to supply memory. If - // 'basicAllocator' is 0, the currently installed default allocator is - // used. + ReversedClusterConnection(ReversedClusterConnection&& original, + bslma::Allocator* basicAllocator); + // Create an object of type 'ReversedClusterConnection' having the + // value of the specified 'original' object. After performing this + // action, the 'original' object will be left in a valid, but + // unspecified state. Use the optionally specified 'basicAllocator' to + // supply memory. If 'basicAllocator' is 0, the currently installed + // default allocator is used. #endif - ~StatPluginConfig(); + ~ReversedClusterConnection(); // Destroy this object. // MANIPULATORS - StatPluginConfig& operator=(const StatPluginConfig& rhs); + ReversedClusterConnection& operator=(const ReversedClusterConnection& rhs); // Assign to this object the value of the specified 'rhs' object. #if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) && \ defined(BSLS_COMPILERFEATURES_SUPPORT_NOEXCEPT) - StatPluginConfig& operator=(StatPluginConfig&& rhs); + ReversedClusterConnection& operator=(ReversedClusterConnection&& rhs); // Assign to this object the value of the specified 'rhs' object. // After performing this action, the 'rhs' object will be left in a // valid, but unspecified state. @@ -6939,38 +6914,10 @@ class StatPluginConfig { // Return a reference to the modifiable "Name" attribute of this // object. - int& queueSize(); - // Return a reference to the modifiable "QueueSize" attribute of this - // object. - - int& queueHighWatermark(); - // Return a reference to the modifiable "QueueHighWatermark" attribute - // of this object. - - int& queueLowWatermark(); - // Return a reference to the modifiable "QueueLowWatermark" attribute - // of this object. - - int& publishInterval(); - // Return a reference to the modifiable "PublishInterval" attribute of - // this object. - - bsl::string& namespacePrefix(); - // Return a reference to the modifiable "NamespacePrefix" attribute of - // this object. - - bsl::vector& hosts(); - // Return a reference to the modifiable "Hosts" attribute of this - // object. - - bsl::string& instanceId(); - // Return a reference to the modifiable "InstanceId" attribute of this + bsl::vector& connections(); + // Return a reference to the modifiable "Connections" attribute of this // object. - bdlb::NullableValue& prometheusSpecific(); - // Return a reference to the modifiable "PrometheusSpecific" attribute - // of this object. - // ACCESSORS bsl::ostream& print(bsl::ostream& stream, int level = 0, int spacesPerLevel = 4) const; @@ -7018,56 +6965,30 @@ class StatPluginConfig { // Return a reference offering non-modifiable access to the "Name" // attribute of this object. - int queueSize() const; - // Return the value of the "QueueSize" attribute of this object. - - int queueHighWatermark() const; - // Return the value of the "QueueHighWatermark" attribute of this - // object. - - int queueLowWatermark() const; - // Return the value of the "QueueLowWatermark" attribute of this - // object. - - int publishInterval() const; - // Return the value of the "PublishInterval" attribute of this object. - - const bsl::string& namespacePrefix() const; - // Return a reference offering non-modifiable access to the - // "NamespacePrefix" attribute of this object. - - const bsl::vector& hosts() const; - // Return a reference offering non-modifiable access to the "Hosts" - // attribute of this object. - - const bsl::string& instanceId() const; - // Return a reference offering non-modifiable access to the - // "InstanceId" attribute of this object. - - const bdlb::NullableValue& - prometheusSpecific() const; + const bsl::vector& connections() const; // Return a reference offering non-modifiable access to the - // "PrometheusSpecific" attribute of this object. + // "Connections" attribute of this object. // HIDDEN FRIENDS - friend bool operator==(const StatPluginConfig& lhs, - const StatPluginConfig& rhs) + friend bool operator==(const ReversedClusterConnection& lhs, + const ReversedClusterConnection& rhs) // Return 'true' if the specified 'lhs' and 'rhs' attribute objects // have the same value, and 'false' otherwise. Two attribute objects // have the same value if each respective attribute has the same value. { - return lhs.isEqualTo(rhs); + return lhs.name() == rhs.name() && + lhs.connections() == rhs.connections(); } - friend bool operator!=(const StatPluginConfig& lhs, - const StatPluginConfig& rhs) + friend bool operator!=(const ReversedClusterConnection& lhs, + const ReversedClusterConnection& rhs) // Returns '!(lhs == rhs)' { return !(lhs == rhs); } - friend bsl::ostream& operator<<(bsl::ostream& stream, - const StatPluginConfig& rhs) + friend bsl::ostream& operator<<(bsl::ostream& stream, + const ReversedClusterConnection& rhs) // Format the specified 'rhs' to the specified output 'stream' and // return a reference to the modifiable 'stream'. { @@ -7075,14 +6996,16 @@ class StatPluginConfig { } template - friend void hashAppend(t_HASH_ALGORITHM& hashAlg, - const StatPluginConfig& object) + friend void hashAppend(t_HASH_ALGORITHM& hashAlg, + const ReversedClusterConnection& object) // Pass the specified 'object' to the specified 'hashAlg'. This // function integrates with the 'bslh' modular hashing system and // effectively provides a 'bsl::hash' specialization for - // 'StatPluginConfig'. + // 'ReversedClusterConnection'. { - object.hashAppendImpl(hashAlg); + using bslh::hashAppend; + hashAppend(hashAlg, object.name()); + hashAppend(hashAlg, object.connections()); } }; @@ -7091,43 +7014,77 @@ class StatPluginConfig { // TRAITS BDLAT_DECL_SEQUENCE_WITH_ALLOCATOR_BITWISEMOVEABLE_TRAITS( - mqbcfg::StatPluginConfig) + mqbcfg::ReversedClusterConnection) namespace mqbcfg { -// ================ -// class TaskConfig -// ================ +// ====================== +// class StatPluginConfig +// ====================== -class TaskConfig { +class StatPluginConfig { // INSTANCE DATA - bsls::Types::Uint64 d_allocationLimit; - LogController d_logController; - AllocatorType::Value d_allocatorType; + bsl::vector d_hosts; + bsl::string d_name; + bsl::string d_namespacePrefix; + bsl::string d_instanceId; + bdlb::NullableValue d_prometheusSpecific; + int d_queueSize; + int d_queueHighWatermark; + int d_queueLowWatermark; + int d_publishInterval; // PRIVATE ACCESSORS template void hashAppendImpl(t_HASH_ALGORITHM& hashAlgorithm) const; + bool isEqualTo(const StatPluginConfig& rhs) const; + public: // TYPES enum { - ATTRIBUTE_ID_ALLOCATOR_TYPE = 0, - ATTRIBUTE_ID_ALLOCATION_LIMIT = 1, - ATTRIBUTE_ID_LOG_CONTROLLER = 2 + ATTRIBUTE_ID_NAME = 0, + ATTRIBUTE_ID_QUEUE_SIZE = 1, + ATTRIBUTE_ID_QUEUE_HIGH_WATERMARK = 2, + ATTRIBUTE_ID_QUEUE_LOW_WATERMARK = 3, + ATTRIBUTE_ID_PUBLISH_INTERVAL = 4, + ATTRIBUTE_ID_NAMESPACE_PREFIX = 5, + ATTRIBUTE_ID_HOSTS = 6, + ATTRIBUTE_ID_INSTANCE_ID = 7, + ATTRIBUTE_ID_PROMETHEUS_SPECIFIC = 8 }; - enum { NUM_ATTRIBUTES = 3 }; + enum { NUM_ATTRIBUTES = 9 }; enum { - ATTRIBUTE_INDEX_ALLOCATOR_TYPE = 0, - ATTRIBUTE_INDEX_ALLOCATION_LIMIT = 1, - ATTRIBUTE_INDEX_LOG_CONTROLLER = 2 + ATTRIBUTE_INDEX_NAME = 0, + ATTRIBUTE_INDEX_QUEUE_SIZE = 1, + ATTRIBUTE_INDEX_QUEUE_HIGH_WATERMARK = 2, + ATTRIBUTE_INDEX_QUEUE_LOW_WATERMARK = 3, + ATTRIBUTE_INDEX_PUBLISH_INTERVAL = 4, + ATTRIBUTE_INDEX_NAMESPACE_PREFIX = 5, + ATTRIBUTE_INDEX_HOSTS = 6, + ATTRIBUTE_INDEX_INSTANCE_ID = 7, + ATTRIBUTE_INDEX_PROMETHEUS_SPECIFIC = 8 }; // CONSTANTS static const char CLASS_NAME[]; + static const char DEFAULT_INITIALIZER_NAME[]; + + static const int DEFAULT_INITIALIZER_QUEUE_SIZE; + + static const int DEFAULT_INITIALIZER_QUEUE_HIGH_WATERMARK; + + static const int DEFAULT_INITIALIZER_QUEUE_LOW_WATERMARK; + + static const int DEFAULT_INITIALIZER_PUBLISH_INTERVAL; + + static const char DEFAULT_INITIALIZER_NAMESPACE_PREFIX[]; + + static const char DEFAULT_INITIALIZER_INSTANCE_ID[]; + static const bdlat_AttributeInfo ATTRIBUTE_INFO_ARRAY[]; public: @@ -7143,28 +7100,29 @@ class TaskConfig { // exists, and 0 otherwise. // CREATORS - explicit TaskConfig(bslma::Allocator* basicAllocator = 0); - // Create an object of type 'TaskConfig' having the default value. Use - // the optionally specified 'basicAllocator' to supply memory. If - // 'basicAllocator' is 0, the currently installed default allocator is - // used. + explicit StatPluginConfig(bslma::Allocator* basicAllocator = 0); + // Create an object of type 'StatPluginConfig' having the default + // value. Use the optionally specified 'basicAllocator' to supply + // memory. If 'basicAllocator' is 0, the currently installed default + // allocator is used. - TaskConfig(const TaskConfig& original, - bslma::Allocator* basicAllocator = 0); - // Create an object of type 'TaskConfig' having the value of the + StatPluginConfig(const StatPluginConfig& original, + bslma::Allocator* basicAllocator = 0); + // Create an object of type 'StatPluginConfig' having the value of the // specified 'original' object. Use the optionally specified // 'basicAllocator' to supply memory. If 'basicAllocator' is 0, the // currently installed default allocator is used. #if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) && \ defined(BSLS_COMPILERFEATURES_SUPPORT_NOEXCEPT) - TaskConfig(TaskConfig&& original) noexcept; - // Create an object of type 'TaskConfig' having the value of the + StatPluginConfig(StatPluginConfig&& original) noexcept; + // Create an object of type 'StatPluginConfig' having the value of the // specified 'original' object. After performing this action, the // 'original' object will be left in a valid, but unspecified state. - TaskConfig(TaskConfig&& original, bslma::Allocator* basicAllocator); - // Create an object of type 'TaskConfig' having the value of the + StatPluginConfig(StatPluginConfig&& original, + bslma::Allocator* basicAllocator); + // Create an object of type 'StatPluginConfig' having the value of the // specified 'original' object. After performing this action, the // 'original' object will be left in a valid, but unspecified state. // Use the optionally specified 'basicAllocator' to supply memory. If @@ -7172,16 +7130,16 @@ class TaskConfig { // used. #endif - ~TaskConfig(); + ~StatPluginConfig(); // Destroy this object. // MANIPULATORS - TaskConfig& operator=(const TaskConfig& rhs); + StatPluginConfig& operator=(const StatPluginConfig& rhs); // Assign to this object the value of the specified 'rhs' object. #if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) && \ defined(BSLS_COMPILERFEATURES_SUPPORT_NOEXCEPT) - TaskConfig& operator=(TaskConfig&& rhs); + StatPluginConfig& operator=(StatPluginConfig&& rhs); // Assign to this object the value of the specified 'rhs' object. // After performing this action, the 'rhs' object will be left in a // valid, but unspecified state. @@ -7220,26 +7178,50 @@ class TaskConfig { // returned from the invocation of 'manipulator' if 'name' identifies // an attribute of this class, and -1 otherwise. - AllocatorType::Value& allocatorType(); - // Return a reference to the modifiable "AllocatorType" attribute of - // this object. + bsl::string& name(); + // Return a reference to the modifiable "Name" attribute of this + // object. - bsls::Types::Uint64& allocationLimit(); - // Return a reference to the modifiable "AllocationLimit" attribute of + int& queueSize(); + // Return a reference to the modifiable "QueueSize" attribute of this + // object. + + int& queueHighWatermark(); + // Return a reference to the modifiable "QueueHighWatermark" attribute + // of this object. + + int& queueLowWatermark(); + // Return a reference to the modifiable "QueueLowWatermark" attribute + // of this object. + + int& publishInterval(); + // Return a reference to the modifiable "PublishInterval" attribute of // this object. - LogController& logController(); - // Return a reference to the modifiable "LogController" attribute of + bsl::string& namespacePrefix(); + // Return a reference to the modifiable "NamespacePrefix" attribute of // this object. - // ACCESSORS - bsl::ostream& - print(bsl::ostream& stream, int level = 0, int spacesPerLevel = 4) const; - // Format this object to the specified output 'stream' at the - // optionally specified indentation 'level' and return a reference to - // the modifiable 'stream'. If 'level' is specified, optionally - // specify 'spacesPerLevel', the number of spaces per indentation level - // for this and all of its nested objects. Each line is indented by + bsl::vector& hosts(); + // Return a reference to the modifiable "Hosts" attribute of this + // object. + + bsl::string& instanceId(); + // Return a reference to the modifiable "InstanceId" attribute of this + // object. + + bdlb::NullableValue& prometheusSpecific(); + // Return a reference to the modifiable "PrometheusSpecific" attribute + // of this object. + + // ACCESSORS + bsl::ostream& + print(bsl::ostream& stream, int level = 0, int spacesPerLevel = 4) const; + // Format this object to the specified output 'stream' at the + // optionally specified indentation 'level' and return a reference to + // the modifiable 'stream'. If 'level' is specified, optionally + // specify 'spacesPerLevel', the number of spaces per indentation level + // for this and all of its nested objects. Each line is indented by // the absolute value of 'level * spacesPerLevel'. If 'level' is // negative, suppress indentation of the first line. If // 'spacesPerLevel' is negative, suppress line breaks and format the @@ -7275,35 +7257,60 @@ class TaskConfig { // invocation of 'accessor' if 'name' identifies an attribute of this // class, and -1 otherwise. - AllocatorType::Value allocatorType() const; - // Return the value of the "AllocatorType" attribute of this object. + const bsl::string& name() const; + // Return a reference offering non-modifiable access to the "Name" + // attribute of this object. - bsls::Types::Uint64 allocationLimit() const; - // Return the value of the "AllocationLimit" attribute of this object. + int queueSize() const; + // Return the value of the "QueueSize" attribute of this object. - const LogController& logController() const; + int queueHighWatermark() const; + // Return the value of the "QueueHighWatermark" attribute of this + // object. + + int queueLowWatermark() const; + // Return the value of the "QueueLowWatermark" attribute of this + // object. + + int publishInterval() const; + // Return the value of the "PublishInterval" attribute of this object. + + const bsl::string& namespacePrefix() const; // Return a reference offering non-modifiable access to the - // "LogController" attribute of this object. + // "NamespacePrefix" attribute of this object. + + const bsl::vector& hosts() const; + // Return a reference offering non-modifiable access to the "Hosts" + // attribute of this object. + + const bsl::string& instanceId() const; + // Return a reference offering non-modifiable access to the + // "InstanceId" attribute of this object. + + const bdlb::NullableValue& + prometheusSpecific() const; + // Return a reference offering non-modifiable access to the + // "PrometheusSpecific" attribute of this object. // HIDDEN FRIENDS - friend bool operator==(const TaskConfig& lhs, const TaskConfig& rhs) + friend bool operator==(const StatPluginConfig& lhs, + const StatPluginConfig& rhs) // Return 'true' if the specified 'lhs' and 'rhs' attribute objects // have the same value, and 'false' otherwise. Two attribute objects // have the same value if each respective attribute has the same value. { - return lhs.allocatorType() == rhs.allocatorType() && - lhs.allocationLimit() == rhs.allocationLimit() && - lhs.logController() == rhs.logController(); + return lhs.isEqualTo(rhs); } - friend bool operator!=(const TaskConfig& lhs, const TaskConfig& rhs) + friend bool operator!=(const StatPluginConfig& lhs, + const StatPluginConfig& rhs) // Returns '!(lhs == rhs)' { return !(lhs == rhs); } - friend bsl::ostream& operator<<(bsl::ostream& stream, - const TaskConfig& rhs) + friend bsl::ostream& operator<<(bsl::ostream& stream, + const StatPluginConfig& rhs) // Format the specified 'rhs' to the specified output 'stream' and // return a reference to the modifiable 'stream'. { @@ -7311,10 +7318,12 @@ class TaskConfig { } template - friend void hashAppend(t_HASH_ALGORITHM& hashAlg, const TaskConfig& object) + friend void hashAppend(t_HASH_ALGORITHM& hashAlg, + const StatPluginConfig& object) // Pass the specified 'object' to the specified 'hashAlg'. This // function integrates with the 'bslh' modular hashing system and - // effectively provides a 'bsl::hash' specialization for 'TaskConfig'. + // effectively provides a 'bsl::hash' specialization for + // 'StatPluginConfig'. { object.hashAppendImpl(hashAlg); } @@ -7324,69 +7333,39 @@ class TaskConfig { // TRAITS -BDLAT_DECL_SEQUENCE_WITH_ALLOCATOR_BITWISEMOVEABLE_TRAITS(mqbcfg::TaskConfig) +BDLAT_DECL_SEQUENCE_WITH_ALLOCATOR_BITWISEMOVEABLE_TRAITS( + mqbcfg::StatPluginConfig) namespace mqbcfg { -// ======================= -// class ClusterDefinition -// ======================= - -class ClusterDefinition { - // Type representing the configuration for a cluster. - // name..................: name of the cluster nodes.................: list - // of nodes in the cluster partitionConfig.......: configuration for the - // storage masterAssignment......: algorithm to use for partition's master - // assignment elector...............: configuration for leader election - // amongst the nodes queueOperations.......: configuration for queue - // operations on the cluster clusterAttributes.....: attributes specific to - // this cluster clusterMonitorConfig..: configuration for cluster state - // monitor messageThrottleConfig.: configuration for message throttling - // intervals and thresholds. +// ================ +// class TaskConfig +// ================ +class TaskConfig { // INSTANCE DATA - bsl::vector d_nodes; - bsl::string d_name; - QueueOperationsConfig d_queueOperations; - PartitionConfig d_partitionConfig; - MessageThrottleConfig d_messageThrottleConfig; - ElectorConfig d_elector; - ClusterMonitorConfig d_clusterMonitorConfig; - MasterAssignmentAlgorithm::Value d_masterAssignment; - ClusterAttributes d_clusterAttributes; + bsls::Types::Uint64 d_allocationLimit; + LogController d_logController; + AllocatorType::Value d_allocatorType; // PRIVATE ACCESSORS template void hashAppendImpl(t_HASH_ALGORITHM& hashAlgorithm) const; - bool isEqualTo(const ClusterDefinition& rhs) const; - public: // TYPES enum { - ATTRIBUTE_ID_NAME = 0, - ATTRIBUTE_ID_NODES = 1, - ATTRIBUTE_ID_PARTITION_CONFIG = 2, - ATTRIBUTE_ID_MASTER_ASSIGNMENT = 3, - ATTRIBUTE_ID_ELECTOR = 4, - ATTRIBUTE_ID_QUEUE_OPERATIONS = 5, - ATTRIBUTE_ID_CLUSTER_ATTRIBUTES = 6, - ATTRIBUTE_ID_CLUSTER_MONITOR_CONFIG = 7, - ATTRIBUTE_ID_MESSAGE_THROTTLE_CONFIG = 8 + ATTRIBUTE_ID_ALLOCATOR_TYPE = 0, + ATTRIBUTE_ID_ALLOCATION_LIMIT = 1, + ATTRIBUTE_ID_LOG_CONTROLLER = 2 }; - enum { NUM_ATTRIBUTES = 9 }; + enum { NUM_ATTRIBUTES = 3 }; enum { - ATTRIBUTE_INDEX_NAME = 0, - ATTRIBUTE_INDEX_NODES = 1, - ATTRIBUTE_INDEX_PARTITION_CONFIG = 2, - ATTRIBUTE_INDEX_MASTER_ASSIGNMENT = 3, - ATTRIBUTE_INDEX_ELECTOR = 4, - ATTRIBUTE_INDEX_QUEUE_OPERATIONS = 5, - ATTRIBUTE_INDEX_CLUSTER_ATTRIBUTES = 6, - ATTRIBUTE_INDEX_CLUSTER_MONITOR_CONFIG = 7, - ATTRIBUTE_INDEX_MESSAGE_THROTTLE_CONFIG = 8 + ATTRIBUTE_INDEX_ALLOCATOR_TYPE = 0, + ATTRIBUTE_INDEX_ALLOCATION_LIMIT = 1, + ATTRIBUTE_INDEX_LOG_CONTROLLER = 2 }; // CONSTANTS @@ -7407,29 +7386,28 @@ class ClusterDefinition { // exists, and 0 otherwise. // CREATORS - explicit ClusterDefinition(bslma::Allocator* basicAllocator = 0); - // Create an object of type 'ClusterDefinition' having the default - // value. Use the optionally specified 'basicAllocator' to supply - // memory. If 'basicAllocator' is 0, the currently installed default - // allocator is used. + explicit TaskConfig(bslma::Allocator* basicAllocator = 0); + // Create an object of type 'TaskConfig' having the default value. Use + // the optionally specified 'basicAllocator' to supply memory. If + // 'basicAllocator' is 0, the currently installed default allocator is + // used. - ClusterDefinition(const ClusterDefinition& original, - bslma::Allocator* basicAllocator = 0); - // Create an object of type 'ClusterDefinition' having the value of the + TaskConfig(const TaskConfig& original, + bslma::Allocator* basicAllocator = 0); + // Create an object of type 'TaskConfig' having the value of the // specified 'original' object. Use the optionally specified // 'basicAllocator' to supply memory. If 'basicAllocator' is 0, the // currently installed default allocator is used. #if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) && \ defined(BSLS_COMPILERFEATURES_SUPPORT_NOEXCEPT) - ClusterDefinition(ClusterDefinition&& original) noexcept; - // Create an object of type 'ClusterDefinition' having the value of the + TaskConfig(TaskConfig&& original) noexcept; + // Create an object of type 'TaskConfig' having the value of the // specified 'original' object. After performing this action, the // 'original' object will be left in a valid, but unspecified state. - ClusterDefinition(ClusterDefinition&& original, - bslma::Allocator* basicAllocator); - // Create an object of type 'ClusterDefinition' having the value of the + TaskConfig(TaskConfig&& original, bslma::Allocator* basicAllocator); + // Create an object of type 'TaskConfig' having the value of the // specified 'original' object. After performing this action, the // 'original' object will be left in a valid, but unspecified state. // Use the optionally specified 'basicAllocator' to supply memory. If @@ -7437,16 +7415,16 @@ class ClusterDefinition { // used. #endif - ~ClusterDefinition(); + ~TaskConfig(); // Destroy this object. // MANIPULATORS - ClusterDefinition& operator=(const ClusterDefinition& rhs); + TaskConfig& operator=(const TaskConfig& rhs); // Assign to this object the value of the specified 'rhs' object. #if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) && \ defined(BSLS_COMPILERFEATURES_SUPPORT_NOEXCEPT) - ClusterDefinition& operator=(ClusterDefinition&& rhs); + TaskConfig& operator=(TaskConfig&& rhs); // Assign to this object the value of the specified 'rhs' object. // After performing this action, the 'rhs' object will be left in a // valid, but unspecified state. @@ -7485,42 +7463,18 @@ class ClusterDefinition { // returned from the invocation of 'manipulator' if 'name' identifies // an attribute of this class, and -1 otherwise. - bsl::string& name(); - // Return a reference to the modifiable "Name" attribute of this - // object. - - bsl::vector& nodes(); - // Return a reference to the modifiable "Nodes" attribute of this - // object. - - PartitionConfig& partitionConfig(); - // Return a reference to the modifiable "PartitionConfig" attribute of + AllocatorType::Value& allocatorType(); + // Return a reference to the modifiable "AllocatorType" attribute of // this object. - MasterAssignmentAlgorithm::Value& masterAssignment(); - // Return a reference to the modifiable "MasterAssignment" attribute of + bsls::Types::Uint64& allocationLimit(); + // Return a reference to the modifiable "AllocationLimit" attribute of // this object. - ElectorConfig& elector(); - // Return a reference to the modifiable "Elector" attribute of this - // object. - - QueueOperationsConfig& queueOperations(); - // Return a reference to the modifiable "QueueOperations" attribute of + LogController& logController(); + // Return a reference to the modifiable "LogController" attribute of // this object. - ClusterAttributes& clusterAttributes(); - // Return a reference to the modifiable "ClusterAttributes" attribute - // of this object. - - ClusterMonitorConfig& clusterMonitorConfig(); - // Return a reference to the modifiable "ClusterMonitorConfig" - // attribute of this object. - - MessageThrottleConfig& messageThrottleConfig(); - // Return a reference to the modifiable "MessageThrottleConfig" - // attribute of this object. - // ACCESSORS bsl::ostream& print(bsl::ostream& stream, int level = 0, int spacesPerLevel = 4) const; @@ -7564,73 +7518,46 @@ class ClusterDefinition { // invocation of 'accessor' if 'name' identifies an attribute of this // class, and -1 otherwise. - const bsl::string& name() const; - // Return a reference offering non-modifiable access to the "Name" - // attribute of this object. - - const bsl::vector& nodes() const; - // Return a reference offering non-modifiable access to the "Nodes" - // attribute of this object. - - const PartitionConfig& partitionConfig() const; - // Return a reference offering non-modifiable access to the - // "PartitionConfig" attribute of this object. - - MasterAssignmentAlgorithm::Value masterAssignment() const; - // Return the value of the "MasterAssignment" attribute of this object. - - const ElectorConfig& elector() const; - // Return a reference offering non-modifiable access to the "Elector" - // attribute of this object. - - const QueueOperationsConfig& queueOperations() const; - // Return a reference offering non-modifiable access to the - // "QueueOperations" attribute of this object. - - const ClusterAttributes& clusterAttributes() const; - // Return a reference offering non-modifiable access to the - // "ClusterAttributes" attribute of this object. + AllocatorType::Value allocatorType() const; + // Return the value of the "AllocatorType" attribute of this object. - const ClusterMonitorConfig& clusterMonitorConfig() const; - // Return a reference offering non-modifiable access to the - // "ClusterMonitorConfig" attribute of this object. + bsls::Types::Uint64 allocationLimit() const; + // Return the value of the "AllocationLimit" attribute of this object. - const MessageThrottleConfig& messageThrottleConfig() const; + const LogController& logController() const; // Return a reference offering non-modifiable access to the - // "MessageThrottleConfig" attribute of this object. + // "LogController" attribute of this object. // HIDDEN FRIENDS - friend bool operator==(const ClusterDefinition& lhs, - const ClusterDefinition& rhs) + friend bool operator==(const TaskConfig& lhs, const TaskConfig& rhs) // Return 'true' if the specified 'lhs' and 'rhs' attribute objects // have the same value, and 'false' otherwise. Two attribute objects // have the same value if each respective attribute has the same value. { - return lhs.isEqualTo(rhs); + return lhs.allocatorType() == rhs.allocatorType() && + lhs.allocationLimit() == rhs.allocationLimit() && + lhs.logController() == rhs.logController(); } - friend bool operator!=(const ClusterDefinition& lhs, - const ClusterDefinition& rhs) + friend bool operator!=(const TaskConfig& lhs, const TaskConfig& rhs) // Returns '!(lhs == rhs)' { return !(lhs == rhs); } - friend bsl::ostream& operator<<(bsl::ostream& stream, - const ClusterDefinition& rhs) - // Format the specified 'rhs' to the specified output 'stream' and + friend bsl::ostream& operator<<(bsl::ostream& stream, + const TaskConfig& rhs) + // Format the specified 'rhs' to the specified output 'stream' and // return a reference to the modifiable 'stream'. { return rhs.print(stream, 0, -1); } template - friend void hashAppend(t_HASH_ALGORITHM& hashAlg, - const ClusterDefinition& object) + friend void hashAppend(t_HASH_ALGORITHM& hashAlg, const TaskConfig& object) // Pass the specified 'object' to the specified 'hashAlg'. This // function integrates with the 'bslh' modular hashing system and - // effectively provides a 'bsl::hash' specialization for - // 'ClusterDefinition'. + // effectively provides a 'bsl::hash' specialization for 'TaskConfig'. { object.hashAppendImpl(hashAlg); } @@ -7640,54 +7567,69 @@ class ClusterDefinition { // TRAITS -BDLAT_DECL_SEQUENCE_WITH_ALLOCATOR_BITWISEMOVEABLE_TRAITS( - mqbcfg::ClusterDefinition) +BDLAT_DECL_SEQUENCE_WITH_ALLOCATOR_BITWISEMOVEABLE_TRAITS(mqbcfg::TaskConfig) namespace mqbcfg { -// ============================ -// class ClusterProxyDefinition -// ============================ +// ======================= +// class ClusterDefinition +// ======================= -class ClusterProxyDefinition { - // Type representing the configuration for a cluster proxy. +class ClusterDefinition { + // Type representing the configuration for a cluster. // name..................: name of the cluster nodes.................: list - // of nodes in the cluster queueOperations.......: configuration for queue - // operations with the cluster clusterMonitorConfig..: configuration for - // cluster state monitor messageThrottleConfig.: configuration for message - // throttling intervals and thresholds. + // of nodes in the cluster partitionConfig.......: configuration for the + // storage masterAssignment......: algorithm to use for partition's master + // assignment elector...............: configuration for leader election + // amongst the nodes queueOperations.......: configuration for queue + // operations on the cluster clusterAttributes.....: attributes specific to + // this cluster clusterMonitorConfig..: configuration for cluster state + // monitor messageThrottleConfig.: configuration for message throttling + // intervals and thresholds. // INSTANCE DATA - bsl::vector d_nodes; - bsl::string d_name; - QueueOperationsConfig d_queueOperations; - MessageThrottleConfig d_messageThrottleConfig; - ClusterMonitorConfig d_clusterMonitorConfig; + bsl::vector d_nodes; + bsl::string d_name; + QueueOperationsConfig d_queueOperations; + PartitionConfig d_partitionConfig; + MessageThrottleConfig d_messageThrottleConfig; + ElectorConfig d_elector; + ClusterMonitorConfig d_clusterMonitorConfig; + MasterAssignmentAlgorithm::Value d_masterAssignment; + ClusterAttributes d_clusterAttributes; // PRIVATE ACCESSORS template void hashAppendImpl(t_HASH_ALGORITHM& hashAlgorithm) const; - bool isEqualTo(const ClusterProxyDefinition& rhs) const; + bool isEqualTo(const ClusterDefinition& rhs) const; public: // TYPES enum { ATTRIBUTE_ID_NAME = 0, ATTRIBUTE_ID_NODES = 1, - ATTRIBUTE_ID_QUEUE_OPERATIONS = 2, - ATTRIBUTE_ID_CLUSTER_MONITOR_CONFIG = 3, - ATTRIBUTE_ID_MESSAGE_THROTTLE_CONFIG = 4 + ATTRIBUTE_ID_PARTITION_CONFIG = 2, + ATTRIBUTE_ID_MASTER_ASSIGNMENT = 3, + ATTRIBUTE_ID_ELECTOR = 4, + ATTRIBUTE_ID_QUEUE_OPERATIONS = 5, + ATTRIBUTE_ID_CLUSTER_ATTRIBUTES = 6, + ATTRIBUTE_ID_CLUSTER_MONITOR_CONFIG = 7, + ATTRIBUTE_ID_MESSAGE_THROTTLE_CONFIG = 8 }; - enum { NUM_ATTRIBUTES = 5 }; + enum { NUM_ATTRIBUTES = 9 }; enum { ATTRIBUTE_INDEX_NAME = 0, ATTRIBUTE_INDEX_NODES = 1, - ATTRIBUTE_INDEX_QUEUE_OPERATIONS = 2, - ATTRIBUTE_INDEX_CLUSTER_MONITOR_CONFIG = 3, - ATTRIBUTE_INDEX_MESSAGE_THROTTLE_CONFIG = 4 + ATTRIBUTE_INDEX_PARTITION_CONFIG = 2, + ATTRIBUTE_INDEX_MASTER_ASSIGNMENT = 3, + ATTRIBUTE_INDEX_ELECTOR = 4, + ATTRIBUTE_INDEX_QUEUE_OPERATIONS = 5, + ATTRIBUTE_INDEX_CLUSTER_ATTRIBUTES = 6, + ATTRIBUTE_INDEX_CLUSTER_MONITOR_CONFIG = 7, + ATTRIBUTE_INDEX_MESSAGE_THROTTLE_CONFIG = 8 }; // CONSTANTS @@ -7708,47 +7650,46 @@ class ClusterProxyDefinition { // exists, and 0 otherwise. // CREATORS - explicit ClusterProxyDefinition(bslma::Allocator* basicAllocator = 0); - // Create an object of type 'ClusterProxyDefinition' having the default + explicit ClusterDefinition(bslma::Allocator* basicAllocator = 0); + // Create an object of type 'ClusterDefinition' having the default // value. Use the optionally specified 'basicAllocator' to supply // memory. If 'basicAllocator' is 0, the currently installed default // allocator is used. - ClusterProxyDefinition(const ClusterProxyDefinition& original, - bslma::Allocator* basicAllocator = 0); - // Create an object of type 'ClusterProxyDefinition' having the value - // of the specified 'original' object. Use the optionally specified + ClusterDefinition(const ClusterDefinition& original, + bslma::Allocator* basicAllocator = 0); + // Create an object of type 'ClusterDefinition' having the value of the + // specified 'original' object. Use the optionally specified // 'basicAllocator' to supply memory. If 'basicAllocator' is 0, the // currently installed default allocator is used. #if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) && \ defined(BSLS_COMPILERFEATURES_SUPPORT_NOEXCEPT) - ClusterProxyDefinition(ClusterProxyDefinition&& original) noexcept; - // Create an object of type 'ClusterProxyDefinition' having the value - // of the specified 'original' object. After performing this action, - // the 'original' object will be left in a valid, but unspecified - // state. + ClusterDefinition(ClusterDefinition&& original) noexcept; + // Create an object of type 'ClusterDefinition' having the value of the + // specified 'original' object. After performing this action, the + // 'original' object will be left in a valid, but unspecified state. - ClusterProxyDefinition(ClusterProxyDefinition&& original, - bslma::Allocator* basicAllocator); - // Create an object of type 'ClusterProxyDefinition' having the value - // of the specified 'original' object. After performing this action, - // the 'original' object will be left in a valid, but unspecified - // state. Use the optionally specified 'basicAllocator' to supply - // memory. If 'basicAllocator' is 0, the currently installed default - // allocator is used. + ClusterDefinition(ClusterDefinition&& original, + bslma::Allocator* basicAllocator); + // Create an object of type 'ClusterDefinition' having the value of the + // specified 'original' object. After performing this action, the + // 'original' object will be left in a valid, but unspecified state. + // Use the optionally specified 'basicAllocator' to supply memory. If + // 'basicAllocator' is 0, the currently installed default allocator is + // used. #endif - ~ClusterProxyDefinition(); + ~ClusterDefinition(); // Destroy this object. // MANIPULATORS - ClusterProxyDefinition& operator=(const ClusterProxyDefinition& rhs); + ClusterDefinition& operator=(const ClusterDefinition& rhs); // Assign to this object the value of the specified 'rhs' object. #if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) && \ defined(BSLS_COMPILERFEATURES_SUPPORT_NOEXCEPT) - ClusterProxyDefinition& operator=(ClusterProxyDefinition&& rhs); + ClusterDefinition& operator=(ClusterDefinition&& rhs); // Assign to this object the value of the specified 'rhs' object. // After performing this action, the 'rhs' object will be left in a // valid, but unspecified state. @@ -7795,10 +7736,26 @@ class ClusterProxyDefinition { // Return a reference to the modifiable "Nodes" attribute of this // object. + PartitionConfig& partitionConfig(); + // Return a reference to the modifiable "PartitionConfig" attribute of + // this object. + + MasterAssignmentAlgorithm::Value& masterAssignment(); + // Return a reference to the modifiable "MasterAssignment" attribute of + // this object. + + ElectorConfig& elector(); + // Return a reference to the modifiable "Elector" attribute of this + // object. + QueueOperationsConfig& queueOperations(); // Return a reference to the modifiable "QueueOperations" attribute of // this object. + ClusterAttributes& clusterAttributes(); + // Return a reference to the modifiable "ClusterAttributes" attribute + // of this object. + ClusterMonitorConfig& clusterMonitorConfig(); // Return a reference to the modifiable "ClusterMonitorConfig" // attribute of this object. @@ -7858,10 +7815,25 @@ class ClusterProxyDefinition { // Return a reference offering non-modifiable access to the "Nodes" // attribute of this object. + const PartitionConfig& partitionConfig() const; + // Return a reference offering non-modifiable access to the + // "PartitionConfig" attribute of this object. + + MasterAssignmentAlgorithm::Value masterAssignment() const; + // Return the value of the "MasterAssignment" attribute of this object. + + const ElectorConfig& elector() const; + // Return a reference offering non-modifiable access to the "Elector" + // attribute of this object. + const QueueOperationsConfig& queueOperations() const; // Return a reference offering non-modifiable access to the // "QueueOperations" attribute of this object. + const ClusterAttributes& clusterAttributes() const; + // Return a reference offering non-modifiable access to the + // "ClusterAttributes" attribute of this object. + const ClusterMonitorConfig& clusterMonitorConfig() const; // Return a reference offering non-modifiable access to the // "ClusterMonitorConfig" attribute of this object. @@ -7871,8 +7843,8 @@ class ClusterProxyDefinition { // "MessageThrottleConfig" attribute of this object. // HIDDEN FRIENDS - friend bool operator==(const ClusterProxyDefinition& lhs, - const ClusterProxyDefinition& rhs) + friend bool operator==(const ClusterDefinition& lhs, + const ClusterDefinition& rhs) // Return 'true' if the specified 'lhs' and 'rhs' attribute objects // have the same value, and 'false' otherwise. Two attribute objects // have the same value if each respective attribute has the same value. @@ -7880,15 +7852,15 @@ class ClusterProxyDefinition { return lhs.isEqualTo(rhs); } - friend bool operator!=(const ClusterProxyDefinition& lhs, - const ClusterProxyDefinition& rhs) + friend bool operator!=(const ClusterDefinition& lhs, + const ClusterDefinition& rhs) // Returns '!(lhs == rhs)' { return !(lhs == rhs); } - friend bsl::ostream& operator<<(bsl::ostream& stream, - const ClusterProxyDefinition& rhs) + friend bsl::ostream& operator<<(bsl::ostream& stream, + const ClusterDefinition& rhs) // Format the specified 'rhs' to the specified output 'stream' and // return a reference to the modifiable 'stream'. { @@ -7896,12 +7868,12 @@ class ClusterProxyDefinition { } template - friend void hashAppend(t_HASH_ALGORITHM& hashAlg, - const ClusterProxyDefinition& object) + friend void hashAppend(t_HASH_ALGORITHM& hashAlg, + const ClusterDefinition& object) // Pass the specified 'object' to the specified 'hashAlg'. This // function integrates with the 'bslh' modular hashing system and // effectively provides a 'bsl::hash' specialization for - // 'ClusterProxyDefinition'. + // 'ClusterDefinition'. { object.hashAppendImpl(hashAlg); } @@ -7912,45 +7884,58 @@ class ClusterProxyDefinition { // TRAITS BDLAT_DECL_SEQUENCE_WITH_ALLOCATOR_BITWISEMOVEABLE_TRAITS( - mqbcfg::ClusterProxyDefinition) + mqbcfg::ClusterDefinition) namespace mqbcfg { -// ================= -// class StatsConfig -// ================= +// ============================ +// class ClusterProxyDefinition +// ============================ + +class ClusterProxyDefinition { + // Type representing the configuration for a cluster proxy. + // name..................: name of the cluster nodes.................: list + // of nodes in the cluster queueOperations.......: configuration for queue + // operations with the cluster clusterMonitorConfig..: configuration for + // cluster state monitor messageThrottleConfig.: configuration for message + // throttling intervals and thresholds. -class StatsConfig { // INSTANCE DATA - bsl::vector d_plugins; - StatsPrinterConfig d_printer; - int d_snapshotInterval; + bsl::vector d_nodes; + bsl::string d_name; + QueueOperationsConfig d_queueOperations; + MessageThrottleConfig d_messageThrottleConfig; + ClusterMonitorConfig d_clusterMonitorConfig; // PRIVATE ACCESSORS template void hashAppendImpl(t_HASH_ALGORITHM& hashAlgorithm) const; + bool isEqualTo(const ClusterProxyDefinition& rhs) const; + public: // TYPES enum { - ATTRIBUTE_ID_SNAPSHOT_INTERVAL = 0, - ATTRIBUTE_ID_PLUGINS = 1, - ATTRIBUTE_ID_PRINTER = 2 + ATTRIBUTE_ID_NAME = 0, + ATTRIBUTE_ID_NODES = 1, + ATTRIBUTE_ID_QUEUE_OPERATIONS = 2, + ATTRIBUTE_ID_CLUSTER_MONITOR_CONFIG = 3, + ATTRIBUTE_ID_MESSAGE_THROTTLE_CONFIG = 4 }; - enum { NUM_ATTRIBUTES = 3 }; + enum { NUM_ATTRIBUTES = 5 }; enum { - ATTRIBUTE_INDEX_SNAPSHOT_INTERVAL = 0, - ATTRIBUTE_INDEX_PLUGINS = 1, - ATTRIBUTE_INDEX_PRINTER = 2 + ATTRIBUTE_INDEX_NAME = 0, + ATTRIBUTE_INDEX_NODES = 1, + ATTRIBUTE_INDEX_QUEUE_OPERATIONS = 2, + ATTRIBUTE_INDEX_CLUSTER_MONITOR_CONFIG = 3, + ATTRIBUTE_INDEX_MESSAGE_THROTTLE_CONFIG = 4 }; // CONSTANTS static const char CLASS_NAME[]; - static const int DEFAULT_INITIALIZER_SNAPSHOT_INTERVAL; - static const bdlat_AttributeInfo ATTRIBUTE_INFO_ARRAY[]; public: @@ -7966,45 +7951,47 @@ class StatsConfig { // exists, and 0 otherwise. // CREATORS - explicit StatsConfig(bslma::Allocator* basicAllocator = 0); - // Create an object of type 'StatsConfig' having the default value. - // Use the optionally specified 'basicAllocator' to supply memory. If - // 'basicAllocator' is 0, the currently installed default allocator is - // used. + explicit ClusterProxyDefinition(bslma::Allocator* basicAllocator = 0); + // Create an object of type 'ClusterProxyDefinition' having the default + // value. Use the optionally specified 'basicAllocator' to supply + // memory. If 'basicAllocator' is 0, the currently installed default + // allocator is used. - StatsConfig(const StatsConfig& original, - bslma::Allocator* basicAllocator = 0); - // Create an object of type 'StatsConfig' having the value of the - // specified 'original' object. Use the optionally specified + ClusterProxyDefinition(const ClusterProxyDefinition& original, + bslma::Allocator* basicAllocator = 0); + // Create an object of type 'ClusterProxyDefinition' having the value + // of the specified 'original' object. Use the optionally specified // 'basicAllocator' to supply memory. If 'basicAllocator' is 0, the // currently installed default allocator is used. #if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) && \ defined(BSLS_COMPILERFEATURES_SUPPORT_NOEXCEPT) - StatsConfig(StatsConfig&& original) noexcept; - // Create an object of type 'StatsConfig' having the value of the - // specified 'original' object. After performing this action, the - // 'original' object will be left in a valid, but unspecified state. + ClusterProxyDefinition(ClusterProxyDefinition&& original) noexcept; + // Create an object of type 'ClusterProxyDefinition' having the value + // of the specified 'original' object. After performing this action, + // the 'original' object will be left in a valid, but unspecified + // state. - StatsConfig(StatsConfig&& original, bslma::Allocator* basicAllocator); - // Create an object of type 'StatsConfig' having the value of the - // specified 'original' object. After performing this action, the - // 'original' object will be left in a valid, but unspecified state. - // Use the optionally specified 'basicAllocator' to supply memory. If - // 'basicAllocator' is 0, the currently installed default allocator is - // used. + ClusterProxyDefinition(ClusterProxyDefinition&& original, + bslma::Allocator* basicAllocator); + // Create an object of type 'ClusterProxyDefinition' having the value + // of the specified 'original' object. After performing this action, + // the 'original' object will be left in a valid, but unspecified + // state. Use the optionally specified 'basicAllocator' to supply + // memory. If 'basicAllocator' is 0, the currently installed default + // allocator is used. #endif - ~StatsConfig(); + ~ClusterProxyDefinition(); // Destroy this object. // MANIPULATORS - StatsConfig& operator=(const StatsConfig& rhs); + ClusterProxyDefinition& operator=(const ClusterProxyDefinition& rhs); // Assign to this object the value of the specified 'rhs' object. #if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) && \ defined(BSLS_COMPILERFEATURES_SUPPORT_NOEXCEPT) - StatsConfig& operator=(StatsConfig&& rhs); + ClusterProxyDefinition& operator=(ClusterProxyDefinition&& rhs); // Assign to this object the value of the specified 'rhs' object. // After performing this action, the 'rhs' object will be left in a // valid, but unspecified state. @@ -8043,18 +8030,26 @@ class StatsConfig { // returned from the invocation of 'manipulator' if 'name' identifies // an attribute of this class, and -1 otherwise. - int& snapshotInterval(); - // Return a reference to the modifiable "SnapshotInterval" attribute of - // this object. - - bsl::vector& plugins(); - // Return a reference to the modifiable "Plugins" attribute of this + bsl::string& name(); + // Return a reference to the modifiable "Name" attribute of this // object. - StatsPrinterConfig& printer(); - // Return a reference to the modifiable "Printer" attribute of this + bsl::vector& nodes(); + // Return a reference to the modifiable "Nodes" attribute of this // object. + QueueOperationsConfig& queueOperations(); + // Return a reference to the modifiable "QueueOperations" attribute of + // this object. + + ClusterMonitorConfig& clusterMonitorConfig(); + // Return a reference to the modifiable "ClusterMonitorConfig" + // attribute of this object. + + MessageThrottleConfig& messageThrottleConfig(); + // Return a reference to the modifiable "MessageThrottleConfig" + // attribute of this object. + // ACCESSORS bsl::ostream& print(bsl::ostream& stream, int level = 0, int spacesPerLevel = 4) const; @@ -8098,36 +8093,45 @@ class StatsConfig { // invocation of 'accessor' if 'name' identifies an attribute of this // class, and -1 otherwise. - int snapshotInterval() const; - // Return the value of the "SnapshotInterval" attribute of this object. - - const bsl::vector& plugins() const; - // Return a reference offering non-modifiable access to the "Plugins" + const bsl::string& name() const; + // Return a reference offering non-modifiable access to the "Name" // attribute of this object. - const StatsPrinterConfig& printer() const; - // Return a reference offering non-modifiable access to the "Printer" + const bsl::vector& nodes() const; + // Return a reference offering non-modifiable access to the "Nodes" // attribute of this object. + const QueueOperationsConfig& queueOperations() const; + // Return a reference offering non-modifiable access to the + // "QueueOperations" attribute of this object. + + const ClusterMonitorConfig& clusterMonitorConfig() const; + // Return a reference offering non-modifiable access to the + // "ClusterMonitorConfig" attribute of this object. + + const MessageThrottleConfig& messageThrottleConfig() const; + // Return a reference offering non-modifiable access to the + // "MessageThrottleConfig" attribute of this object. + // HIDDEN FRIENDS - friend bool operator==(const StatsConfig& lhs, const StatsConfig& rhs) + friend bool operator==(const ClusterProxyDefinition& lhs, + const ClusterProxyDefinition& rhs) // Return 'true' if the specified 'lhs' and 'rhs' attribute objects // have the same value, and 'false' otherwise. Two attribute objects // have the same value if each respective attribute has the same value. { - return lhs.snapshotInterval() == rhs.snapshotInterval() && - lhs.plugins() == rhs.plugins() && - lhs.printer() == rhs.printer(); + return lhs.isEqualTo(rhs); } - friend bool operator!=(const StatsConfig& lhs, const StatsConfig& rhs) + friend bool operator!=(const ClusterProxyDefinition& lhs, + const ClusterProxyDefinition& rhs) // Returns '!(lhs == rhs)' { return !(lhs == rhs); } - friend bsl::ostream& operator<<(bsl::ostream& stream, - const StatsConfig& rhs) + friend bsl::ostream& operator<<(bsl::ostream& stream, + const ClusterProxyDefinition& rhs) // Format the specified 'rhs' to the specified output 'stream' and // return a reference to the modifiable 'stream'. { @@ -8135,11 +8139,12 @@ class StatsConfig { } template - friend void hashAppend(t_HASH_ALGORITHM& hashAlg, - const StatsConfig& object) + friend void hashAppend(t_HASH_ALGORITHM& hashAlg, + const ClusterProxyDefinition& object) // Pass the specified 'object' to the specified 'hashAlg'. This // function integrates with the 'bslh' modular hashing system and - // effectively provides a 'bsl::hash' specialization for 'StatsConfig'. + // effectively provides a 'bsl::hash' specialization for + // 'ClusterProxyDefinition'. { object.hashAppendImpl(hashAlg); } @@ -8149,120 +8154,45 @@ class StatsConfig { // TRAITS -BDLAT_DECL_SEQUENCE_WITH_ALLOCATOR_BITWISEMOVEABLE_TRAITS(mqbcfg::StatsConfig) +BDLAT_DECL_SEQUENCE_WITH_ALLOCATOR_BITWISEMOVEABLE_TRAITS( + mqbcfg::ClusterProxyDefinition) namespace mqbcfg { -// =============== -// class AppConfig -// =============== - -class AppConfig { - // Top level type for the broker's configuration. - // brokerInstanceName...: name of the broker instance - // brokerVersion........: version of the broker configVersion........: - // version of the bmqbrkr.cfg config etcDir...............: directory - // containing the json config files hostName.............: name of the - // current host hostTags.............: tags of the current host - // hostDataCenter.......: datacenter the current host resides in - // isRunningOnDev.......: true if running on dev logsObserverMaxSize..: - // maximum number of log records to keep latencyMonitorDomain.: common part - // of all latemon domains dispatcherConfig.....: configuration for the - // dispatcher stats................: configuration for the stats - // networkInterfaces....: configuration for the network interfaces - // bmqconfConfig........: configuration for bmqconf plugins..............: - // configuration for the plugins msgPropertiesSupport.: information about - // if/how to advertise support for v2 message properties - // configureStream......: send new ConfigureStream instead of old - // ConfigureQueue advertiseSubscriptions.: temporarily control use of - // ConfigureStream in SDK routeCommandTimeoutMs: maximum amount of time to - // wait for a routed command's response +// ================= +// class StatsConfig +// ================= +class StatsConfig { // INSTANCE DATA - bsl::string d_brokerInstanceName; - bsl::string d_etcDir; - bsl::string d_hostName; - bsl::string d_hostTags; - bsl::string d_hostDataCenter; - bsl::string d_latencyMonitorDomain; - StatsConfig d_stats; - Plugins d_plugins; - NetworkInterfaces d_networkInterfaces; - MessagePropertiesV2 d_messagePropertiesV2; - DispatcherConfig d_dispatcherConfig; - BmqconfConfig d_bmqconfConfig; - int d_brokerVersion; - int d_configVersion; - int d_logsObserverMaxSize; - int d_routeCommandTimeoutMs; - bool d_isRunningOnDev; - bool d_configureStream; - bool d_advertiseSubscriptions; + bsl::vector d_plugins; + StatsPrinterConfig d_printer; + int d_snapshotInterval; // PRIVATE ACCESSORS template void hashAppendImpl(t_HASH_ALGORITHM& hashAlgorithm) const; - bool isEqualTo(const AppConfig& rhs) const; - public: // TYPES enum { - ATTRIBUTE_ID_BROKER_INSTANCE_NAME = 0, - ATTRIBUTE_ID_BROKER_VERSION = 1, - ATTRIBUTE_ID_CONFIG_VERSION = 2, - ATTRIBUTE_ID_ETC_DIR = 3, - ATTRIBUTE_ID_HOST_NAME = 4, - ATTRIBUTE_ID_HOST_TAGS = 5, - ATTRIBUTE_ID_HOST_DATA_CENTER = 6, - ATTRIBUTE_ID_IS_RUNNING_ON_DEV = 7, - ATTRIBUTE_ID_LOGS_OBSERVER_MAX_SIZE = 8, - ATTRIBUTE_ID_LATENCY_MONITOR_DOMAIN = 9, - ATTRIBUTE_ID_DISPATCHER_CONFIG = 10, - ATTRIBUTE_ID_STATS = 11, - ATTRIBUTE_ID_NETWORK_INTERFACES = 12, - ATTRIBUTE_ID_BMQCONF_CONFIG = 13, - ATTRIBUTE_ID_PLUGINS = 14, - ATTRIBUTE_ID_MESSAGE_PROPERTIES_V2 = 15, - ATTRIBUTE_ID_CONFIGURE_STREAM = 16, - ATTRIBUTE_ID_ADVERTISE_SUBSCRIPTIONS = 17, - ATTRIBUTE_ID_ROUTE_COMMAND_TIMEOUT_MS = 18 + ATTRIBUTE_ID_SNAPSHOT_INTERVAL = 0, + ATTRIBUTE_ID_PLUGINS = 1, + ATTRIBUTE_ID_PRINTER = 2 }; - enum { NUM_ATTRIBUTES = 19 }; + enum { NUM_ATTRIBUTES = 3 }; enum { - ATTRIBUTE_INDEX_BROKER_INSTANCE_NAME = 0, - ATTRIBUTE_INDEX_BROKER_VERSION = 1, - ATTRIBUTE_INDEX_CONFIG_VERSION = 2, - ATTRIBUTE_INDEX_ETC_DIR = 3, - ATTRIBUTE_INDEX_HOST_NAME = 4, - ATTRIBUTE_INDEX_HOST_TAGS = 5, - ATTRIBUTE_INDEX_HOST_DATA_CENTER = 6, - ATTRIBUTE_INDEX_IS_RUNNING_ON_DEV = 7, - ATTRIBUTE_INDEX_LOGS_OBSERVER_MAX_SIZE = 8, - ATTRIBUTE_INDEX_LATENCY_MONITOR_DOMAIN = 9, - ATTRIBUTE_INDEX_DISPATCHER_CONFIG = 10, - ATTRIBUTE_INDEX_STATS = 11, - ATTRIBUTE_INDEX_NETWORK_INTERFACES = 12, - ATTRIBUTE_INDEX_BMQCONF_CONFIG = 13, - ATTRIBUTE_INDEX_PLUGINS = 14, - ATTRIBUTE_INDEX_MESSAGE_PROPERTIES_V2 = 15, - ATTRIBUTE_INDEX_CONFIGURE_STREAM = 16, - ATTRIBUTE_INDEX_ADVERTISE_SUBSCRIPTIONS = 17, - ATTRIBUTE_INDEX_ROUTE_COMMAND_TIMEOUT_MS = 18 + ATTRIBUTE_INDEX_SNAPSHOT_INTERVAL = 0, + ATTRIBUTE_INDEX_PLUGINS = 1, + ATTRIBUTE_INDEX_PRINTER = 2 }; // CONSTANTS static const char CLASS_NAME[]; - static const char DEFAULT_INITIALIZER_LATENCY_MONITOR_DOMAIN[]; - - static const bool DEFAULT_INITIALIZER_CONFIGURE_STREAM; - - static const bool DEFAULT_INITIALIZER_ADVERTISE_SUBSCRIPTIONS; - - static const int DEFAULT_INITIALIZER_ROUTE_COMMAND_TIMEOUT_MS; + static const int DEFAULT_INITIALIZER_SNAPSHOT_INTERVAL; static const bdlat_AttributeInfo ATTRIBUTE_INFO_ARRAY[]; @@ -8279,27 +8209,28 @@ class AppConfig { // exists, and 0 otherwise. // CREATORS - explicit AppConfig(bslma::Allocator* basicAllocator = 0); - // Create an object of type 'AppConfig' having the default value. Use - // the optionally specified 'basicAllocator' to supply memory. If + explicit StatsConfig(bslma::Allocator* basicAllocator = 0); + // Create an object of type 'StatsConfig' having the default value. + // Use the optionally specified 'basicAllocator' to supply memory. If // 'basicAllocator' is 0, the currently installed default allocator is // used. - AppConfig(const AppConfig& original, bslma::Allocator* basicAllocator = 0); - // Create an object of type 'AppConfig' having the value of the + StatsConfig(const StatsConfig& original, + bslma::Allocator* basicAllocator = 0); + // Create an object of type 'StatsConfig' having the value of the // specified 'original' object. Use the optionally specified // 'basicAllocator' to supply memory. If 'basicAllocator' is 0, the // currently installed default allocator is used. #if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) && \ defined(BSLS_COMPILERFEATURES_SUPPORT_NOEXCEPT) - AppConfig(AppConfig&& original) noexcept; - // Create an object of type 'AppConfig' having the value of the + StatsConfig(StatsConfig&& original) noexcept; + // Create an object of type 'StatsConfig' having the value of the // specified 'original' object. After performing this action, the // 'original' object will be left in a valid, but unspecified state. - AppConfig(AppConfig&& original, bslma::Allocator* basicAllocator); - // Create an object of type 'AppConfig' having the value of the + StatsConfig(StatsConfig&& original, bslma::Allocator* basicAllocator); + // Create an object of type 'StatsConfig' having the value of the // specified 'original' object. After performing this action, the // 'original' object will be left in a valid, but unspecified state. // Use the optionally specified 'basicAllocator' to supply memory. If @@ -8307,16 +8238,16 @@ class AppConfig { // used. #endif - ~AppConfig(); + ~StatsConfig(); // Destroy this object. // MANIPULATORS - AppConfig& operator=(const AppConfig& rhs); + StatsConfig& operator=(const StatsConfig& rhs); // Assign to this object the value of the specified 'rhs' object. #if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) && \ defined(BSLS_COMPILERFEATURES_SUPPORT_NOEXCEPT) - AppConfig& operator=(AppConfig&& rhs); + StatsConfig& operator=(StatsConfig&& rhs); // Assign to this object the value of the specified 'rhs' object. // After performing this action, the 'rhs' object will be left in a // valid, but unspecified state. @@ -8355,37 +8286,349 @@ class AppConfig { // returned from the invocation of 'manipulator' if 'name' identifies // an attribute of this class, and -1 otherwise. - bsl::string& brokerInstanceName(); - // Return a reference to the modifiable "BrokerInstanceName" attribute - // of this object. - - int& brokerVersion(); - // Return a reference to the modifiable "BrokerVersion" attribute of - // this object. - - int& configVersion(); - // Return a reference to the modifiable "ConfigVersion" attribute of + int& snapshotInterval(); + // Return a reference to the modifiable "SnapshotInterval" attribute of // this object. - bsl::string& etcDir(); - // Return a reference to the modifiable "EtcDir" attribute of this + bsl::vector& plugins(); + // Return a reference to the modifiable "Plugins" attribute of this // object. - bsl::string& hostName(); - // Return a reference to the modifiable "HostName" attribute of this + StatsPrinterConfig& printer(); + // Return a reference to the modifiable "Printer" attribute of this // object. - bsl::string& hostTags(); - // Return a reference to the modifiable "HostTags" attribute of this - // object. + // ACCESSORS + bsl::ostream& + print(bsl::ostream& stream, int level = 0, int spacesPerLevel = 4) const; + // Format this object to the specified output 'stream' at the + // optionally specified indentation 'level' and return a reference to + // the modifiable 'stream'. If 'level' is specified, optionally + // specify 'spacesPerLevel', the number of spaces per indentation level + // for this and all of its nested objects. Each line is indented by + // the absolute value of 'level * spacesPerLevel'. If 'level' is + // negative, suppress indentation of the first line. If + // 'spacesPerLevel' is negative, suppress line breaks and format the + // entire output on one line. If 'stream' is initially invalid, this + // operation has no effect. Note that a trailing newline is provided + // in multiline mode only. - bsl::string& hostDataCenter(); - // Return a reference to the modifiable "HostDataCenter" attribute of - // this object. + template + int accessAttributes(t_ACCESSOR& accessor) const; + // Invoke the specified 'accessor' sequentially on each + // (non-modifiable) attribute of this object, supplying 'accessor' + // with the corresponding attribute information structure until such + // invocation returns a non-zero value. Return the value from the + // last invocation of 'accessor' (i.e., the invocation that terminated + // the sequence). - bool& isRunningOnDev(); - // Return a reference to the modifiable "IsRunningOnDev" attribute of - // this object. + template + int accessAttribute(t_ACCESSOR& accessor, int id) const; + // Invoke the specified 'accessor' on the (non-modifiable) attribute + // of this object indicated by the specified 'id', supplying 'accessor' + // with the corresponding attribute information structure. Return the + // value returned from the invocation of 'accessor' if 'id' identifies + // an attribute of this class, and -1 otherwise. + + template + int accessAttribute(t_ACCESSOR& accessor, + const char* name, + int nameLength) const; + // Invoke the specified 'accessor' on the (non-modifiable) attribute + // of this object indicated by the specified 'name' of the specified + // 'nameLength', supplying 'accessor' with the corresponding attribute + // information structure. Return the value returned from the + // invocation of 'accessor' if 'name' identifies an attribute of this + // class, and -1 otherwise. + + int snapshotInterval() const; + // Return the value of the "SnapshotInterval" attribute of this object. + + const bsl::vector& plugins() const; + // Return a reference offering non-modifiable access to the "Plugins" + // attribute of this object. + + const StatsPrinterConfig& printer() const; + // Return a reference offering non-modifiable access to the "Printer" + // attribute of this object. + + // HIDDEN FRIENDS + friend bool operator==(const StatsConfig& lhs, const StatsConfig& rhs) + // Return 'true' if the specified 'lhs' and 'rhs' attribute objects + // have the same value, and 'false' otherwise. Two attribute objects + // have the same value if each respective attribute has the same value. + { + return lhs.snapshotInterval() == rhs.snapshotInterval() && + lhs.plugins() == rhs.plugins() && + lhs.printer() == rhs.printer(); + } + + friend bool operator!=(const StatsConfig& lhs, const StatsConfig& rhs) + // Returns '!(lhs == rhs)' + { + return !(lhs == rhs); + } + + friend bsl::ostream& operator<<(bsl::ostream& stream, + const StatsConfig& rhs) + // Format the specified 'rhs' to the specified output 'stream' and + // return a reference to the modifiable 'stream'. + { + return rhs.print(stream, 0, -1); + } + + template + friend void hashAppend(t_HASH_ALGORITHM& hashAlg, + const StatsConfig& object) + // Pass the specified 'object' to the specified 'hashAlg'. This + // function integrates with the 'bslh' modular hashing system and + // effectively provides a 'bsl::hash' specialization for 'StatsConfig'. + { + object.hashAppendImpl(hashAlg); + } +}; + +} // close package namespace + +// TRAITS + +BDLAT_DECL_SEQUENCE_WITH_ALLOCATOR_BITWISEMOVEABLE_TRAITS(mqbcfg::StatsConfig) + +namespace mqbcfg { + +// =============== +// class AppConfig +// =============== + +class AppConfig { + // Top level type for the broker's configuration. + // brokerInstanceName...: name of the broker instance + // brokerVersion........: version of the broker configVersion........: + // version of the bmqbrkr.cfg config etcDir...............: directory + // containing the json config files hostName.............: name of the + // current host hostTags.............: tags of the current host + // hostDataCenter.......: datacenter the current host resides in + // isRunningOnDev.......: true if running on dev logsObserverMaxSize..: + // maximum number of log records to keep latencyMonitorDomain.: common part + // of all latemon domains dispatcherConfig.....: configuration for the + // dispatcher stats................: configuration for the stats + // networkInterfaces....: configuration for the network interfaces + // bmqconfConfig........: configuration for bmqconf plugins..............: + // configuration for the plugins msgPropertiesSupport.: information about + // if/how to advertise support for v2 message properties + // configureStream......: send new ConfigureStream instead of old + // ConfigureQueue advertiseSubscriptions.: temporarily control use of + // ConfigureStream in SDK routeCommandTimeoutMs: maximum amount of time to + // wait for a routed command's response + + // INSTANCE DATA + bsl::string d_brokerInstanceName; + bsl::string d_etcDir; + bsl::string d_hostName; + bsl::string d_hostTags; + bsl::string d_hostDataCenter; + bsl::string d_latencyMonitorDomain; + StatsConfig d_stats; + Plugins d_plugins; + NetworkInterfaces d_networkInterfaces; + MessagePropertiesV2 d_messagePropertiesV2; + DispatcherConfig d_dispatcherConfig; + BmqconfConfig d_bmqconfConfig; + int d_brokerVersion; + int d_configVersion; + int d_logsObserverMaxSize; + int d_routeCommandTimeoutMs; + bool d_isRunningOnDev; + bool d_configureStream; + bool d_advertiseSubscriptions; + + // PRIVATE ACCESSORS + template + void hashAppendImpl(t_HASH_ALGORITHM& hashAlgorithm) const; + + bool isEqualTo(const AppConfig& rhs) const; + + public: + // TYPES + enum { + ATTRIBUTE_ID_BROKER_INSTANCE_NAME = 0, + ATTRIBUTE_ID_BROKER_VERSION = 1, + ATTRIBUTE_ID_CONFIG_VERSION = 2, + ATTRIBUTE_ID_ETC_DIR = 3, + ATTRIBUTE_ID_HOST_NAME = 4, + ATTRIBUTE_ID_HOST_TAGS = 5, + ATTRIBUTE_ID_HOST_DATA_CENTER = 6, + ATTRIBUTE_ID_IS_RUNNING_ON_DEV = 7, + ATTRIBUTE_ID_LOGS_OBSERVER_MAX_SIZE = 8, + ATTRIBUTE_ID_LATENCY_MONITOR_DOMAIN = 9, + ATTRIBUTE_ID_DISPATCHER_CONFIG = 10, + ATTRIBUTE_ID_STATS = 11, + ATTRIBUTE_ID_NETWORK_INTERFACES = 12, + ATTRIBUTE_ID_BMQCONF_CONFIG = 13, + ATTRIBUTE_ID_PLUGINS = 14, + ATTRIBUTE_ID_MESSAGE_PROPERTIES_V2 = 15, + ATTRIBUTE_ID_CONFIGURE_STREAM = 16, + ATTRIBUTE_ID_ADVERTISE_SUBSCRIPTIONS = 17, + ATTRIBUTE_ID_ROUTE_COMMAND_TIMEOUT_MS = 18 + }; + + enum { NUM_ATTRIBUTES = 19 }; + + enum { + ATTRIBUTE_INDEX_BROKER_INSTANCE_NAME = 0, + ATTRIBUTE_INDEX_BROKER_VERSION = 1, + ATTRIBUTE_INDEX_CONFIG_VERSION = 2, + ATTRIBUTE_INDEX_ETC_DIR = 3, + ATTRIBUTE_INDEX_HOST_NAME = 4, + ATTRIBUTE_INDEX_HOST_TAGS = 5, + ATTRIBUTE_INDEX_HOST_DATA_CENTER = 6, + ATTRIBUTE_INDEX_IS_RUNNING_ON_DEV = 7, + ATTRIBUTE_INDEX_LOGS_OBSERVER_MAX_SIZE = 8, + ATTRIBUTE_INDEX_LATENCY_MONITOR_DOMAIN = 9, + ATTRIBUTE_INDEX_DISPATCHER_CONFIG = 10, + ATTRIBUTE_INDEX_STATS = 11, + ATTRIBUTE_INDEX_NETWORK_INTERFACES = 12, + ATTRIBUTE_INDEX_BMQCONF_CONFIG = 13, + ATTRIBUTE_INDEX_PLUGINS = 14, + ATTRIBUTE_INDEX_MESSAGE_PROPERTIES_V2 = 15, + ATTRIBUTE_INDEX_CONFIGURE_STREAM = 16, + ATTRIBUTE_INDEX_ADVERTISE_SUBSCRIPTIONS = 17, + ATTRIBUTE_INDEX_ROUTE_COMMAND_TIMEOUT_MS = 18 + }; + + // CONSTANTS + static const char CLASS_NAME[]; + + static const char DEFAULT_INITIALIZER_LATENCY_MONITOR_DOMAIN[]; + + static const bool DEFAULT_INITIALIZER_CONFIGURE_STREAM; + + static const bool DEFAULT_INITIALIZER_ADVERTISE_SUBSCRIPTIONS; + + static const int DEFAULT_INITIALIZER_ROUTE_COMMAND_TIMEOUT_MS; + + static const bdlat_AttributeInfo ATTRIBUTE_INFO_ARRAY[]; + + public: + // CLASS METHODS + static const bdlat_AttributeInfo* lookupAttributeInfo(int id); + // Return attribute information for the attribute indicated by the + // specified 'id' if the attribute exists, and 0 otherwise. + + static const bdlat_AttributeInfo* lookupAttributeInfo(const char* name, + int nameLength); + // Return attribute information for the attribute indicated by the + // specified 'name' of the specified 'nameLength' if the attribute + // exists, and 0 otherwise. + + // CREATORS + explicit AppConfig(bslma::Allocator* basicAllocator = 0); + // Create an object of type 'AppConfig' having the default value. Use + // the optionally specified 'basicAllocator' to supply memory. If + // 'basicAllocator' is 0, the currently installed default allocator is + // used. + + AppConfig(const AppConfig& original, bslma::Allocator* basicAllocator = 0); + // Create an object of type 'AppConfig' having the value of the + // specified 'original' object. Use the optionally specified + // 'basicAllocator' to supply memory. If 'basicAllocator' is 0, the + // currently installed default allocator is used. + +#if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) && \ + defined(BSLS_COMPILERFEATURES_SUPPORT_NOEXCEPT) + AppConfig(AppConfig&& original) noexcept; + // Create an object of type 'AppConfig' having the value of the + // specified 'original' object. After performing this action, the + // 'original' object will be left in a valid, but unspecified state. + + AppConfig(AppConfig&& original, bslma::Allocator* basicAllocator); + // Create an object of type 'AppConfig' having the value of the + // specified 'original' object. After performing this action, the + // 'original' object will be left in a valid, but unspecified state. + // Use the optionally specified 'basicAllocator' to supply memory. If + // 'basicAllocator' is 0, the currently installed default allocator is + // used. +#endif + + ~AppConfig(); + // Destroy this object. + + // MANIPULATORS + AppConfig& operator=(const AppConfig& rhs); + // Assign to this object the value of the specified 'rhs' object. + +#if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) && \ + defined(BSLS_COMPILERFEATURES_SUPPORT_NOEXCEPT) + AppConfig& operator=(AppConfig&& rhs); + // Assign to this object the value of the specified 'rhs' object. + // After performing this action, the 'rhs' object will be left in a + // valid, but unspecified state. +#endif + + void reset(); + // Reset this object to the default value (i.e., its value upon + // default construction). + + template + int manipulateAttributes(t_MANIPULATOR& manipulator); + // Invoke the specified 'manipulator' sequentially on the address of + // each (modifiable) attribute of this object, supplying 'manipulator' + // with the corresponding attribute information structure until such + // invocation returns a non-zero value. Return the value from the + // last invocation of 'manipulator' (i.e., the invocation that + // terminated the sequence). + + template + int manipulateAttribute(t_MANIPULATOR& manipulator, int id); + // Invoke the specified 'manipulator' on the address of + // the (modifiable) attribute indicated by the specified 'id', + // supplying 'manipulator' with the corresponding attribute + // information structure. Return the value returned from the + // invocation of 'manipulator' if 'id' identifies an attribute of this + // class, and -1 otherwise. + + template + int manipulateAttribute(t_MANIPULATOR& manipulator, + const char* name, + int nameLength); + // Invoke the specified 'manipulator' on the address of + // the (modifiable) attribute indicated by the specified 'name' of the + // specified 'nameLength', supplying 'manipulator' with the + // corresponding attribute information structure. Return the value + // returned from the invocation of 'manipulator' if 'name' identifies + // an attribute of this class, and -1 otherwise. + + bsl::string& brokerInstanceName(); + // Return a reference to the modifiable "BrokerInstanceName" attribute + // of this object. + + int& brokerVersion(); + // Return a reference to the modifiable "BrokerVersion" attribute of + // this object. + + int& configVersion(); + // Return a reference to the modifiable "ConfigVersion" attribute of + // this object. + + bsl::string& etcDir(); + // Return a reference to the modifiable "EtcDir" attribute of this + // object. + + bsl::string& hostName(); + // Return a reference to the modifiable "HostName" attribute of this + // object. + + bsl::string& hostTags(); + // Return a reference to the modifiable "HostTags" attribute of this + // object. + + bsl::string& hostDataCenter(); + // Return a reference to the modifiable "HostDataCenter" attribute of + // this object. + + bool& isRunningOnDev(); + // Return a reference to the modifiable "IsRunningOnDev" attribute of + // this object. int& logsObserverMaxSize(); // Return a reference to the modifiable "LogsObserverMaxSize" attribute @@ -12708,51 +12951,23 @@ int TcpClusterNodeConnection::accessAttribute(t_ACCESSOR& accessor, if (0 == attributeInfo) { return NOT_FOUND; } - - return accessAttribute(accessor, attributeInfo->d_id); -} - -inline const bsl::string& TcpClusterNodeConnection::endpoint() const -{ - return d_endpoint; -} - -// ------------------------ -// class TcpInterfaceConfig -// ------------------------ - -// PRIVATE ACCESSORS -template -void TcpInterfaceConfig::hashAppendImpl(t_HASH_ALGORITHM& hashAlgorithm) const -{ - using bslh::hashAppend; - hashAppend(hashAlgorithm, this->name()); - hashAppend(hashAlgorithm, this->port()); - hashAppend(hashAlgorithm, this->ioThreads()); - hashAppend(hashAlgorithm, this->maxConnections()); - hashAppend(hashAlgorithm, this->lowWatermark()); - hashAppend(hashAlgorithm, this->highWatermark()); - hashAppend(hashAlgorithm, this->nodeLowWatermark()); - hashAppend(hashAlgorithm, this->nodeHighWatermark()); - hashAppend(hashAlgorithm, this->heartbeatIntervalMs()); + + return accessAttribute(accessor, attributeInfo->d_id); } -inline bool TcpInterfaceConfig::isEqualTo(const TcpInterfaceConfig& rhs) const +inline const bsl::string& TcpClusterNodeConnection::endpoint() const { - return this->name() == rhs.name() && this->port() == rhs.port() && - this->ioThreads() == rhs.ioThreads() && - this->maxConnections() == rhs.maxConnections() && - this->lowWatermark() == rhs.lowWatermark() && - this->highWatermark() == rhs.highWatermark() && - this->nodeLowWatermark() == rhs.nodeLowWatermark() && - this->nodeHighWatermark() == rhs.nodeHighWatermark() && - this->heartbeatIntervalMs() == rhs.heartbeatIntervalMs(); + return d_endpoint; } +// -------------------------- +// class TcpInterfaceListener +// -------------------------- + // CLASS METHODS // MANIPULATORS template -int TcpInterfaceConfig::manipulateAttributes(t_MANIPULATOR& manipulator) +int TcpInterfaceListener::manipulateAttributes(t_MANIPULATOR& manipulator) { int ret; @@ -12766,56 +12981,12 @@ int TcpInterfaceConfig::manipulateAttributes(t_MANIPULATOR& manipulator) return ret; } - ret = manipulator(&d_ioThreads, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_IO_THREADS]); - if (ret) { - return ret; - } - - ret = manipulator(&d_maxConnections, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_CONNECTIONS]); - if (ret) { - return ret; - } - - ret = manipulator(&d_lowWatermark, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_LOW_WATERMARK]); - if (ret) { - return ret; - } - - ret = manipulator(&d_highWatermark, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_HIGH_WATERMARK]); - if (ret) { - return ret; - } - - ret = manipulator( - &d_nodeLowWatermark, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_NODE_LOW_WATERMARK]); - if (ret) { - return ret; - } - - ret = manipulator( - &d_nodeHighWatermark, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_NODE_HIGH_WATERMARK]); - if (ret) { - return ret; - } - - ret = manipulator( - &d_heartbeatIntervalMs, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_HEARTBEAT_INTERVAL_MS]); - if (ret) { - return ret; - } - return 0; } template -int TcpInterfaceConfig::manipulateAttribute(t_MANIPULATOR& manipulator, int id) +int TcpInterfaceListener::manipulateAttribute(t_MANIPULATOR& manipulator, + int id) { enum { NOT_FOUND = -1 }; @@ -12828,48 +12999,14 @@ int TcpInterfaceConfig::manipulateAttribute(t_MANIPULATOR& manipulator, int id) return manipulator(&d_port, ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_PORT]); } - case ATTRIBUTE_ID_IO_THREADS: { - return manipulator(&d_ioThreads, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_IO_THREADS]); - } - case ATTRIBUTE_ID_MAX_CONNECTIONS: { - return manipulator( - &d_maxConnections, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_CONNECTIONS]); - } - case ATTRIBUTE_ID_LOW_WATERMARK: { - return manipulator( - &d_lowWatermark, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_LOW_WATERMARK]); - } - case ATTRIBUTE_ID_HIGH_WATERMARK: { - return manipulator( - &d_highWatermark, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_HIGH_WATERMARK]); - } - case ATTRIBUTE_ID_NODE_LOW_WATERMARK: { - return manipulator( - &d_nodeLowWatermark, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_NODE_LOW_WATERMARK]); - } - case ATTRIBUTE_ID_NODE_HIGH_WATERMARK: { - return manipulator( - &d_nodeHighWatermark, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_NODE_HIGH_WATERMARK]); - } - case ATTRIBUTE_ID_HEARTBEAT_INTERVAL_MS: { - return manipulator( - &d_heartbeatIntervalMs, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_HEARTBEAT_INTERVAL_MS]); - } default: return NOT_FOUND; } } template -int TcpInterfaceConfig::manipulateAttribute(t_MANIPULATOR& manipulator, - const char* name, - int nameLength) +int TcpInterfaceListener::manipulateAttribute(t_MANIPULATOR& manipulator, + const char* name, + int nameLength) { enum { NOT_FOUND = -1 }; @@ -12882,54 +13019,19 @@ int TcpInterfaceConfig::manipulateAttribute(t_MANIPULATOR& manipulator, return manipulateAttribute(manipulator, attributeInfo->d_id); } -inline bsl::string& TcpInterfaceConfig::name() +inline bsl::string& TcpInterfaceListener::name() { return d_name; } -inline int& TcpInterfaceConfig::port() +inline int& TcpInterfaceListener::port() { return d_port; } -inline int& TcpInterfaceConfig::ioThreads() -{ - return d_ioThreads; -} - -inline int& TcpInterfaceConfig::maxConnections() -{ - return d_maxConnections; -} - -inline bsls::Types::Int64& TcpInterfaceConfig::lowWatermark() -{ - return d_lowWatermark; -} - -inline bsls::Types::Int64& TcpInterfaceConfig::highWatermark() -{ - return d_highWatermark; -} - -inline bsls::Types::Int64& TcpInterfaceConfig::nodeLowWatermark() -{ - return d_nodeLowWatermark; -} - -inline bsls::Types::Int64& TcpInterfaceConfig::nodeHighWatermark() -{ - return d_nodeHighWatermark; -} - -inline int& TcpInterfaceConfig::heartbeatIntervalMs() -{ - return d_heartbeatIntervalMs; -} - // ACCESSORS template -int TcpInterfaceConfig::accessAttributes(t_ACCESSOR& accessor) const +int TcpInterfaceListener::accessAttributes(t_ACCESSOR& accessor) const { int ret; @@ -12943,54 +13045,11 @@ int TcpInterfaceConfig::accessAttributes(t_ACCESSOR& accessor) const return ret; } - ret = accessor(d_ioThreads, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_IO_THREADS]); - if (ret) { - return ret; - } - - ret = accessor(d_maxConnections, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_CONNECTIONS]); - if (ret) { - return ret; - } - - ret = accessor(d_lowWatermark, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_LOW_WATERMARK]); - if (ret) { - return ret; - } - - ret = accessor(d_highWatermark, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_HIGH_WATERMARK]); - if (ret) { - return ret; - } - - ret = accessor(d_nodeLowWatermark, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_NODE_LOW_WATERMARK]); - if (ret) { - return ret; - } - - ret = accessor(d_nodeHighWatermark, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_NODE_HIGH_WATERMARK]); - if (ret) { - return ret; - } - - ret = accessor( - d_heartbeatIntervalMs, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_HEARTBEAT_INTERVAL_MS]); - if (ret) { - return ret; - } - return 0; } template -int TcpInterfaceConfig::accessAttribute(t_ACCESSOR& accessor, int id) const +int TcpInterfaceListener::accessAttribute(t_ACCESSOR& accessor, int id) const { enum { NOT_FOUND = -1 }; @@ -13001,45 +13060,14 @@ int TcpInterfaceConfig::accessAttribute(t_ACCESSOR& accessor, int id) const case ATTRIBUTE_ID_PORT: { return accessor(d_port, ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_PORT]); } - case ATTRIBUTE_ID_IO_THREADS: { - return accessor(d_ioThreads, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_IO_THREADS]); - } - case ATTRIBUTE_ID_MAX_CONNECTIONS: { - return accessor(d_maxConnections, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_CONNECTIONS]); - } - case ATTRIBUTE_ID_LOW_WATERMARK: { - return accessor(d_lowWatermark, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_LOW_WATERMARK]); - } - case ATTRIBUTE_ID_HIGH_WATERMARK: { - return accessor(d_highWatermark, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_HIGH_WATERMARK]); - } - case ATTRIBUTE_ID_NODE_LOW_WATERMARK: { - return accessor( - d_nodeLowWatermark, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_NODE_LOW_WATERMARK]); - } - case ATTRIBUTE_ID_NODE_HIGH_WATERMARK: { - return accessor( - d_nodeHighWatermark, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_NODE_HIGH_WATERMARK]); - } - case ATTRIBUTE_ID_HEARTBEAT_INTERVAL_MS: { - return accessor( - d_heartbeatIntervalMs, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_HEARTBEAT_INTERVAL_MS]); - } default: return NOT_FOUND; } } template -int TcpInterfaceConfig::accessAttribute(t_ACCESSOR& accessor, - const char* name, - int nameLength) const +int TcpInterfaceListener::accessAttribute(t_ACCESSOR& accessor, + const char* name, + int nameLength) const { enum { NOT_FOUND = -1 }; @@ -13052,49 +13080,14 @@ int TcpInterfaceConfig::accessAttribute(t_ACCESSOR& accessor, return accessAttribute(accessor, attributeInfo->d_id); } -inline const bsl::string& TcpInterfaceConfig::name() const -{ - return d_name; -} - -inline int TcpInterfaceConfig::port() const -{ - return d_port; -} - -inline int TcpInterfaceConfig::ioThreads() const -{ - return d_ioThreads; -} - -inline int TcpInterfaceConfig::maxConnections() const -{ - return d_maxConnections; -} - -inline bsls::Types::Int64 TcpInterfaceConfig::lowWatermark() const -{ - return d_lowWatermark; -} - -inline bsls::Types::Int64 TcpInterfaceConfig::highWatermark() const -{ - return d_highWatermark; -} - -inline bsls::Types::Int64 TcpInterfaceConfig::nodeLowWatermark() const -{ - return d_nodeLowWatermark; -} - -inline bsls::Types::Int64 TcpInterfaceConfig::nodeHighWatermark() const +inline const bsl::string& TcpInterfaceListener::name() const { - return d_nodeHighWatermark; + return d_name; } -inline int TcpInterfaceConfig::heartbeatIntervalMs() const +inline int TcpInterfaceListener::port() const { - return d_heartbeatIntervalMs; + return d_port; } // ------------------------------- @@ -13899,92 +13892,325 @@ inline const SyslogConfig& LogController::syslog() const return d_syslog; } -// ----------------------- -// class NetworkInterfaces -// ----------------------- +// --------------------- +// class PartitionConfig +// --------------------- + +// PRIVATE ACCESSORS +template +void PartitionConfig::hashAppendImpl(t_HASH_ALGORITHM& hashAlgorithm) const +{ + using bslh::hashAppend; + hashAppend(hashAlgorithm, this->numPartitions()); + hashAppend(hashAlgorithm, this->location()); + hashAppend(hashAlgorithm, this->archiveLocation()); + hashAppend(hashAlgorithm, this->maxDataFileSize()); + hashAppend(hashAlgorithm, this->maxJournalFileSize()); + hashAppend(hashAlgorithm, this->maxQlistFileSize()); + hashAppend(hashAlgorithm, this->preallocate()); + hashAppend(hashAlgorithm, this->maxArchivedFileSets()); + hashAppend(hashAlgorithm, this->prefaultPages()); + hashAppend(hashAlgorithm, this->flushAtShutdown()); + hashAppend(hashAlgorithm, this->syncConfig()); +} + +inline bool PartitionConfig::isEqualTo(const PartitionConfig& rhs) const +{ + return this->numPartitions() == rhs.numPartitions() && + this->location() == rhs.location() && + this->archiveLocation() == rhs.archiveLocation() && + this->maxDataFileSize() == rhs.maxDataFileSize() && + this->maxJournalFileSize() == rhs.maxJournalFileSize() && + this->maxQlistFileSize() == rhs.maxQlistFileSize() && + this->preallocate() == rhs.preallocate() && + this->maxArchivedFileSets() == rhs.maxArchivedFileSets() && + this->prefaultPages() == rhs.prefaultPages() && + this->flushAtShutdown() == rhs.flushAtShutdown() && + this->syncConfig() == rhs.syncConfig(); +} + +// CLASS METHODS +// MANIPULATORS +template +int PartitionConfig::manipulateAttributes(t_MANIPULATOR& manipulator) +{ + int ret; + + ret = manipulator(&d_numPartitions, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_NUM_PARTITIONS]); + if (ret) { + return ret; + } + + ret = manipulator(&d_location, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_LOCATION]); + if (ret) { + return ret; + } + + ret = manipulator(&d_archiveLocation, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_ARCHIVE_LOCATION]); + if (ret) { + return ret; + } + + ret = manipulator( + &d_maxDataFileSize, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_DATA_FILE_SIZE]); + if (ret) { + return ret; + } + + ret = manipulator( + &d_maxJournalFileSize, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_JOURNAL_FILE_SIZE]); + if (ret) { + return ret; + } + + ret = manipulator( + &d_maxQlistFileSize, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_QLIST_FILE_SIZE]); + if (ret) { + return ret; + } + + ret = manipulator(&d_preallocate, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_PREALLOCATE]); + if (ret) { + return ret; + } + + ret = manipulator( + &d_maxArchivedFileSets, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_ARCHIVED_FILE_SETS]); + if (ret) { + return ret; + } + + ret = manipulator(&d_prefaultPages, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_PREFAULT_PAGES]); + if (ret) { + return ret; + } + + ret = manipulator(&d_flushAtShutdown, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_FLUSH_AT_SHUTDOWN]); + if (ret) { + return ret; + } + + ret = manipulator(&d_syncConfig, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_SYNC_CONFIG]); + if (ret) { + return ret; + } + + return 0; +} + +template +int PartitionConfig::manipulateAttribute(t_MANIPULATOR& manipulator, int id) +{ + enum { NOT_FOUND = -1 }; + + switch (id) { + case ATTRIBUTE_ID_NUM_PARTITIONS: { + return manipulator( + &d_numPartitions, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_NUM_PARTITIONS]); + } + case ATTRIBUTE_ID_LOCATION: { + return manipulator(&d_location, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_LOCATION]); + } + case ATTRIBUTE_ID_ARCHIVE_LOCATION: { + return manipulator( + &d_archiveLocation, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_ARCHIVE_LOCATION]); + } + case ATTRIBUTE_ID_MAX_DATA_FILE_SIZE: { + return manipulator( + &d_maxDataFileSize, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_DATA_FILE_SIZE]); + } + case ATTRIBUTE_ID_MAX_JOURNAL_FILE_SIZE: { + return manipulator( + &d_maxJournalFileSize, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_JOURNAL_FILE_SIZE]); + } + case ATTRIBUTE_ID_MAX_QLIST_FILE_SIZE: { + return manipulator( + &d_maxQlistFileSize, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_QLIST_FILE_SIZE]); + } + case ATTRIBUTE_ID_PREALLOCATE: { + return manipulator(&d_preallocate, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_PREALLOCATE]); + } + case ATTRIBUTE_ID_MAX_ARCHIVED_FILE_SETS: { + return manipulator( + &d_maxArchivedFileSets, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_ARCHIVED_FILE_SETS]); + } + case ATTRIBUTE_ID_PREFAULT_PAGES: { + return manipulator( + &d_prefaultPages, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_PREFAULT_PAGES]); + } + case ATTRIBUTE_ID_FLUSH_AT_SHUTDOWN: { + return manipulator( + &d_flushAtShutdown, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_FLUSH_AT_SHUTDOWN]); + } + case ATTRIBUTE_ID_SYNC_CONFIG: { + return manipulator(&d_syncConfig, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_SYNC_CONFIG]); + } + default: return NOT_FOUND; + } +} + +template +int PartitionConfig::manipulateAttribute(t_MANIPULATOR& manipulator, + const char* name, + int nameLength) +{ + enum { NOT_FOUND = -1 }; + + const bdlat_AttributeInfo* attributeInfo = lookupAttributeInfo(name, + nameLength); + if (0 == attributeInfo) { + return NOT_FOUND; + } + + return manipulateAttribute(manipulator, attributeInfo->d_id); +} + +inline int& PartitionConfig::numPartitions() +{ + return d_numPartitions; +} + +inline bsl::string& PartitionConfig::location() +{ + return d_location; +} + +inline bsl::string& PartitionConfig::archiveLocation() +{ + return d_archiveLocation; +} + +inline bsls::Types::Uint64& PartitionConfig::maxDataFileSize() +{ + return d_maxDataFileSize; +} + +inline bsls::Types::Uint64& PartitionConfig::maxJournalFileSize() +{ + return d_maxJournalFileSize; +} + +inline bsls::Types::Uint64& PartitionConfig::maxQlistFileSize() +{ + return d_maxQlistFileSize; +} + +inline bool& PartitionConfig::preallocate() +{ + return d_preallocate; +} + +inline int& PartitionConfig::maxArchivedFileSets() +{ + return d_maxArchivedFileSets; +} + +inline bool& PartitionConfig::prefaultPages() +{ + return d_prefaultPages; +} + +inline bool& PartitionConfig::flushAtShutdown() +{ + return d_flushAtShutdown; +} + +inline StorageSyncConfig& PartitionConfig::syncConfig() +{ + return d_syncConfig; +} -// CLASS METHODS -// MANIPULATORS -template -int NetworkInterfaces::manipulateAttributes(t_MANIPULATOR& manipulator) +// ACCESSORS +template +int PartitionConfig::accessAttributes(t_ACCESSOR& accessor) const { int ret; - ret = manipulator(&d_heartbeats, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_HEARTBEATS]); + ret = accessor(d_numPartitions, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_NUM_PARTITIONS]); if (ret) { return ret; } - ret = manipulator(&d_tcpInterface, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_TCP_INTERFACE]); + ret = accessor(d_location, ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_LOCATION]); if (ret) { return ret; } - return 0; -} - -template -int NetworkInterfaces::manipulateAttribute(t_MANIPULATOR& manipulator, int id) -{ - enum { NOT_FOUND = -1 }; - - switch (id) { - case ATTRIBUTE_ID_HEARTBEATS: { - return manipulator(&d_heartbeats, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_HEARTBEATS]); - } - case ATTRIBUTE_ID_TCP_INTERFACE: { - return manipulator( - &d_tcpInterface, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_TCP_INTERFACE]); - } - default: return NOT_FOUND; + ret = accessor(d_archiveLocation, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_ARCHIVE_LOCATION]); + if (ret) { + return ret; } -} -template -int NetworkInterfaces::manipulateAttribute(t_MANIPULATOR& manipulator, - const char* name, - int nameLength) -{ - enum { NOT_FOUND = -1 }; + ret = accessor(d_maxDataFileSize, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_DATA_FILE_SIZE]); + if (ret) { + return ret; + } - const bdlat_AttributeInfo* attributeInfo = lookupAttributeInfo(name, - nameLength); - if (0 == attributeInfo) { - return NOT_FOUND; + ret = accessor( + d_maxJournalFileSize, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_JOURNAL_FILE_SIZE]); + if (ret) { + return ret; } - return manipulateAttribute(manipulator, attributeInfo->d_id); -} + ret = accessor(d_maxQlistFileSize, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_QLIST_FILE_SIZE]); + if (ret) { + return ret; + } -inline Heartbeat& NetworkInterfaces::heartbeats() -{ - return d_heartbeats; -} + ret = accessor(d_preallocate, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_PREALLOCATE]); + if (ret) { + return ret; + } -inline bdlb::NullableValue& -NetworkInterfaces::tcpInterface() -{ - return d_tcpInterface; -} + ret = accessor( + d_maxArchivedFileSets, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_ARCHIVED_FILE_SETS]); + if (ret) { + return ret; + } -// ACCESSORS -template -int NetworkInterfaces::accessAttributes(t_ACCESSOR& accessor) const -{ - int ret; + ret = accessor(d_prefaultPages, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_PREFAULT_PAGES]); + if (ret) { + return ret; + } - ret = accessor(d_heartbeats, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_HEARTBEATS]); + ret = accessor(d_flushAtShutdown, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_FLUSH_AT_SHUTDOWN]); if (ret) { return ret; } - ret = accessor(d_tcpInterface, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_TCP_INTERFACE]); + ret = accessor(d_syncConfig, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_SYNC_CONFIG]); if (ret) { return ret; } @@ -13993,27 +14219,69 @@ int NetworkInterfaces::accessAttributes(t_ACCESSOR& accessor) const } template -int NetworkInterfaces::accessAttribute(t_ACCESSOR& accessor, int id) const +int PartitionConfig::accessAttribute(t_ACCESSOR& accessor, int id) const { enum { NOT_FOUND = -1 }; switch (id) { - case ATTRIBUTE_ID_HEARTBEATS: { - return accessor(d_heartbeats, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_HEARTBEATS]); + case ATTRIBUTE_ID_NUM_PARTITIONS: { + return accessor(d_numPartitions, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_NUM_PARTITIONS]); } - case ATTRIBUTE_ID_TCP_INTERFACE: { - return accessor(d_tcpInterface, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_TCP_INTERFACE]); + case ATTRIBUTE_ID_LOCATION: { + return accessor(d_location, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_LOCATION]); + } + case ATTRIBUTE_ID_ARCHIVE_LOCATION: { + return accessor( + d_archiveLocation, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_ARCHIVE_LOCATION]); + } + case ATTRIBUTE_ID_MAX_DATA_FILE_SIZE: { + return accessor( + d_maxDataFileSize, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_DATA_FILE_SIZE]); + } + case ATTRIBUTE_ID_MAX_JOURNAL_FILE_SIZE: { + return accessor( + d_maxJournalFileSize, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_JOURNAL_FILE_SIZE]); + } + case ATTRIBUTE_ID_MAX_QLIST_FILE_SIZE: { + return accessor( + d_maxQlistFileSize, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_QLIST_FILE_SIZE]); + } + case ATTRIBUTE_ID_PREALLOCATE: { + return accessor(d_preallocate, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_PREALLOCATE]); + } + case ATTRIBUTE_ID_MAX_ARCHIVED_FILE_SETS: { + return accessor( + d_maxArchivedFileSets, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_ARCHIVED_FILE_SETS]); + } + case ATTRIBUTE_ID_PREFAULT_PAGES: { + return accessor(d_prefaultPages, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_PREFAULT_PAGES]); + } + case ATTRIBUTE_ID_FLUSH_AT_SHUTDOWN: { + return accessor( + d_flushAtShutdown, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_FLUSH_AT_SHUTDOWN]); + } + case ATTRIBUTE_ID_SYNC_CONFIG: { + return accessor(d_syncConfig, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_SYNC_CONFIG]); } default: return NOT_FOUND; } } template -int NetworkInterfaces::accessAttribute(t_ACCESSOR& accessor, - const char* name, - int nameLength) const +int PartitionConfig::accessAttribute(t_ACCESSOR& accessor, + const char* name, + int nameLength) const { enum { NOT_FOUND = -1 }; @@ -14026,127 +14294,95 @@ int NetworkInterfaces::accessAttribute(t_ACCESSOR& accessor, return accessAttribute(accessor, attributeInfo->d_id); } -inline const Heartbeat& NetworkInterfaces::heartbeats() const +inline int PartitionConfig::numPartitions() const { - return d_heartbeats; + return d_numPartitions; } -inline const bdlb::NullableValue& -NetworkInterfaces::tcpInterface() const +inline const bsl::string& PartitionConfig::location() const { - return d_tcpInterface; + return d_location; } -// --------------------- -// class PartitionConfig -// --------------------- +inline const bsl::string& PartitionConfig::archiveLocation() const +{ + return d_archiveLocation; +} -// PRIVATE ACCESSORS -template -void PartitionConfig::hashAppendImpl(t_HASH_ALGORITHM& hashAlgorithm) const +inline bsls::Types::Uint64 PartitionConfig::maxDataFileSize() const { - using bslh::hashAppend; - hashAppend(hashAlgorithm, this->numPartitions()); - hashAppend(hashAlgorithm, this->location()); - hashAppend(hashAlgorithm, this->archiveLocation()); - hashAppend(hashAlgorithm, this->maxDataFileSize()); - hashAppend(hashAlgorithm, this->maxJournalFileSize()); - hashAppend(hashAlgorithm, this->maxQlistFileSize()); - hashAppend(hashAlgorithm, this->preallocate()); - hashAppend(hashAlgorithm, this->maxArchivedFileSets()); - hashAppend(hashAlgorithm, this->prefaultPages()); - hashAppend(hashAlgorithm, this->flushAtShutdown()); - hashAppend(hashAlgorithm, this->syncConfig()); + return d_maxDataFileSize; } -inline bool PartitionConfig::isEqualTo(const PartitionConfig& rhs) const +inline bsls::Types::Uint64 PartitionConfig::maxJournalFileSize() const { - return this->numPartitions() == rhs.numPartitions() && - this->location() == rhs.location() && - this->archiveLocation() == rhs.archiveLocation() && - this->maxDataFileSize() == rhs.maxDataFileSize() && - this->maxJournalFileSize() == rhs.maxJournalFileSize() && - this->maxQlistFileSize() == rhs.maxQlistFileSize() && - this->preallocate() == rhs.preallocate() && - this->maxArchivedFileSets() == rhs.maxArchivedFileSets() && - this->prefaultPages() == rhs.prefaultPages() && - this->flushAtShutdown() == rhs.flushAtShutdown() && - this->syncConfig() == rhs.syncConfig(); + return d_maxJournalFileSize; } -// CLASS METHODS -// MANIPULATORS -template -int PartitionConfig::manipulateAttributes(t_MANIPULATOR& manipulator) +inline bsls::Types::Uint64 PartitionConfig::maxQlistFileSize() const { - int ret; + return d_maxQlistFileSize; +} - ret = manipulator(&d_numPartitions, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_NUM_PARTITIONS]); - if (ret) { - return ret; - } +inline bool PartitionConfig::preallocate() const +{ + return d_preallocate; +} - ret = manipulator(&d_location, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_LOCATION]); - if (ret) { - return ret; - } +inline int PartitionConfig::maxArchivedFileSets() const +{ + return d_maxArchivedFileSets; +} - ret = manipulator(&d_archiveLocation, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_ARCHIVE_LOCATION]); - if (ret) { - return ret; - } +inline bool PartitionConfig::prefaultPages() const +{ + return d_prefaultPages; +} - ret = manipulator( - &d_maxDataFileSize, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_DATA_FILE_SIZE]); - if (ret) { - return ret; - } +inline bool PartitionConfig::flushAtShutdown() const +{ + return d_flushAtShutdown; +} - ret = manipulator( - &d_maxJournalFileSize, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_JOURNAL_FILE_SIZE]); - if (ret) { - return ret; - } +inline const StorageSyncConfig& PartitionConfig::syncConfig() const +{ + return d_syncConfig; +} - ret = manipulator( - &d_maxQlistFileSize, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_QLIST_FILE_SIZE]); - if (ret) { - return ret; - } +// -------------------------------- +// class StatPluginConfigPrometheus +// -------------------------------- - ret = manipulator(&d_preallocate, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_PREALLOCATE]); - if (ret) { - return ret; - } +// PRIVATE ACCESSORS +template +void StatPluginConfigPrometheus::hashAppendImpl( + t_HASH_ALGORITHM& hashAlgorithm) const +{ + using bslh::hashAppend; + hashAppend(hashAlgorithm, this->mode()); + hashAppend(hashAlgorithm, this->host()); + hashAppend(hashAlgorithm, this->port()); +} - ret = manipulator( - &d_maxArchivedFileSets, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_ARCHIVED_FILE_SETS]); - if (ret) { - return ret; - } +// CLASS METHODS +// MANIPULATORS +template +int StatPluginConfigPrometheus::manipulateAttributes( + t_MANIPULATOR& manipulator) +{ + int ret; - ret = manipulator(&d_prefaultPages, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_PREFAULT_PAGES]); + ret = manipulator(&d_mode, ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MODE]); if (ret) { return ret; } - ret = manipulator(&d_flushAtShutdown, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_FLUSH_AT_SHUTDOWN]); + ret = manipulator(&d_host, ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_HOST]); if (ret) { return ret; } - ret = manipulator(&d_syncConfig, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_SYNC_CONFIG]); + ret = manipulator(&d_port, ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_PORT]); if (ret) { return ret; } @@ -14155,71 +14391,32 @@ int PartitionConfig::manipulateAttributes(t_MANIPULATOR& manipulator) } template -int PartitionConfig::manipulateAttribute(t_MANIPULATOR& manipulator, int id) +int StatPluginConfigPrometheus::manipulateAttribute(t_MANIPULATOR& manipulator, + int id) { enum { NOT_FOUND = -1 }; switch (id) { - case ATTRIBUTE_ID_NUM_PARTITIONS: { - return manipulator( - &d_numPartitions, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_NUM_PARTITIONS]); - } - case ATTRIBUTE_ID_LOCATION: { - return manipulator(&d_location, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_LOCATION]); - } - case ATTRIBUTE_ID_ARCHIVE_LOCATION: { - return manipulator( - &d_archiveLocation, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_ARCHIVE_LOCATION]); - } - case ATTRIBUTE_ID_MAX_DATA_FILE_SIZE: { - return manipulator( - &d_maxDataFileSize, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_DATA_FILE_SIZE]); - } - case ATTRIBUTE_ID_MAX_JOURNAL_FILE_SIZE: { - return manipulator( - &d_maxJournalFileSize, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_JOURNAL_FILE_SIZE]); - } - case ATTRIBUTE_ID_MAX_QLIST_FILE_SIZE: { - return manipulator( - &d_maxQlistFileSize, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_QLIST_FILE_SIZE]); - } - case ATTRIBUTE_ID_PREALLOCATE: { - return manipulator(&d_preallocate, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_PREALLOCATE]); - } - case ATTRIBUTE_ID_MAX_ARCHIVED_FILE_SETS: { - return manipulator( - &d_maxArchivedFileSets, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_ARCHIVED_FILE_SETS]); - } - case ATTRIBUTE_ID_PREFAULT_PAGES: { - return manipulator( - &d_prefaultPages, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_PREFAULT_PAGES]); + case ATTRIBUTE_ID_MODE: { + return manipulator(&d_mode, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MODE]); } - case ATTRIBUTE_ID_FLUSH_AT_SHUTDOWN: { - return manipulator( - &d_flushAtShutdown, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_FLUSH_AT_SHUTDOWN]); + case ATTRIBUTE_ID_HOST: { + return manipulator(&d_host, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_HOST]); } - case ATTRIBUTE_ID_SYNC_CONFIG: { - return manipulator(&d_syncConfig, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_SYNC_CONFIG]); + case ATTRIBUTE_ID_PORT: { + return manipulator(&d_port, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_PORT]); } default: return NOT_FOUND; } } template -int PartitionConfig::manipulateAttribute(t_MANIPULATOR& manipulator, - const char* name, - int nameLength) +int StatPluginConfigPrometheus::manipulateAttribute(t_MANIPULATOR& manipulator, + const char* name, + int nameLength) { enum { NOT_FOUND = -1 }; @@ -14232,130 +14429,194 @@ int PartitionConfig::manipulateAttribute(t_MANIPULATOR& manipulator, return manipulateAttribute(manipulator, attributeInfo->d_id); } -inline int& PartitionConfig::numPartitions() +inline ExportMode::Value& StatPluginConfigPrometheus::mode() { - return d_numPartitions; + return d_mode; } -inline bsl::string& PartitionConfig::location() +inline bsl::string& StatPluginConfigPrometheus::host() { - return d_location; + return d_host; } -inline bsl::string& PartitionConfig::archiveLocation() +inline int& StatPluginConfigPrometheus::port() { - return d_archiveLocation; + return d_port; } -inline bsls::Types::Uint64& PartitionConfig::maxDataFileSize() +// ACCESSORS +template +int StatPluginConfigPrometheus::accessAttributes(t_ACCESSOR& accessor) const { - return d_maxDataFileSize; + int ret; + + ret = accessor(d_mode, ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MODE]); + if (ret) { + return ret; + } + + ret = accessor(d_host, ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_HOST]); + if (ret) { + return ret; + } + + ret = accessor(d_port, ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_PORT]); + if (ret) { + return ret; + } + + return 0; } -inline bsls::Types::Uint64& PartitionConfig::maxJournalFileSize() +template +int StatPluginConfigPrometheus::accessAttribute(t_ACCESSOR& accessor, + int id) const { - return d_maxJournalFileSize; + enum { NOT_FOUND = -1 }; + + switch (id) { + case ATTRIBUTE_ID_MODE: { + return accessor(d_mode, ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MODE]); + } + case ATTRIBUTE_ID_HOST: { + return accessor(d_host, ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_HOST]); + } + case ATTRIBUTE_ID_PORT: { + return accessor(d_port, ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_PORT]); + } + default: return NOT_FOUND; + } } -inline bsls::Types::Uint64& PartitionConfig::maxQlistFileSize() +template +int StatPluginConfigPrometheus::accessAttribute(t_ACCESSOR& accessor, + const char* name, + int nameLength) const { - return d_maxQlistFileSize; + enum { NOT_FOUND = -1 }; + + const bdlat_AttributeInfo* attributeInfo = lookupAttributeInfo(name, + nameLength); + if (0 == attributeInfo) { + return NOT_FOUND; + } + + return accessAttribute(accessor, attributeInfo->d_id); } -inline bool& PartitionConfig::preallocate() +inline ExportMode::Value StatPluginConfigPrometheus::mode() const { - return d_preallocate; + return d_mode; } -inline int& PartitionConfig::maxArchivedFileSets() +inline const bsl::string& StatPluginConfigPrometheus::host() const { - return d_maxArchivedFileSets; + return d_host; } -inline bool& PartitionConfig::prefaultPages() +inline int StatPluginConfigPrometheus::port() const { - return d_prefaultPages; + return d_port; } -inline bool& PartitionConfig::flushAtShutdown() +// ------------------------ +// class TcpInterfaceConfig +// ------------------------ + +// PRIVATE ACCESSORS +template +void TcpInterfaceConfig::hashAppendImpl(t_HASH_ALGORITHM& hashAlgorithm) const { - return d_flushAtShutdown; + using bslh::hashAppend; + hashAppend(hashAlgorithm, this->name()); + hashAppend(hashAlgorithm, this->port()); + hashAppend(hashAlgorithm, this->ioThreads()); + hashAppend(hashAlgorithm, this->maxConnections()); + hashAppend(hashAlgorithm, this->lowWatermark()); + hashAppend(hashAlgorithm, this->highWatermark()); + hashAppend(hashAlgorithm, this->nodeLowWatermark()); + hashAppend(hashAlgorithm, this->nodeHighWatermark()); + hashAppend(hashAlgorithm, this->heartbeatIntervalMs()); + hashAppend(hashAlgorithm, this->listeners()); } -inline StorageSyncConfig& PartitionConfig::syncConfig() +inline bool TcpInterfaceConfig::isEqualTo(const TcpInterfaceConfig& rhs) const { - return d_syncConfig; + return this->name() == rhs.name() && this->port() == rhs.port() && + this->ioThreads() == rhs.ioThreads() && + this->maxConnections() == rhs.maxConnections() && + this->lowWatermark() == rhs.lowWatermark() && + this->highWatermark() == rhs.highWatermark() && + this->nodeLowWatermark() == rhs.nodeLowWatermark() && + this->nodeHighWatermark() == rhs.nodeHighWatermark() && + this->heartbeatIntervalMs() == rhs.heartbeatIntervalMs() && + this->listeners() == rhs.listeners(); } -// ACCESSORS -template -int PartitionConfig::accessAttributes(t_ACCESSOR& accessor) const +// CLASS METHODS +// MANIPULATORS +template +int TcpInterfaceConfig::manipulateAttributes(t_MANIPULATOR& manipulator) { int ret; - ret = accessor(d_numPartitions, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_NUM_PARTITIONS]); - if (ret) { - return ret; - } - - ret = accessor(d_location, ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_LOCATION]); + ret = manipulator(&d_name, ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_NAME]); if (ret) { return ret; } - ret = accessor(d_archiveLocation, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_ARCHIVE_LOCATION]); + ret = manipulator(&d_port, ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_PORT]); if (ret) { return ret; } - - ret = accessor(d_maxDataFileSize, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_DATA_FILE_SIZE]); + + ret = manipulator(&d_ioThreads, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_IO_THREADS]); if (ret) { return ret; } - ret = accessor( - d_maxJournalFileSize, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_JOURNAL_FILE_SIZE]); + ret = manipulator(&d_maxConnections, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_CONNECTIONS]); if (ret) { return ret; } - ret = accessor(d_maxQlistFileSize, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_QLIST_FILE_SIZE]); + ret = manipulator(&d_lowWatermark, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_LOW_WATERMARK]); if (ret) { return ret; } - ret = accessor(d_preallocate, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_PREALLOCATE]); + ret = manipulator(&d_highWatermark, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_HIGH_WATERMARK]); if (ret) { return ret; } - ret = accessor( - d_maxArchivedFileSets, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_ARCHIVED_FILE_SETS]); + ret = manipulator( + &d_nodeLowWatermark, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_NODE_LOW_WATERMARK]); if (ret) { return ret; } - ret = accessor(d_prefaultPages, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_PREFAULT_PAGES]); + ret = manipulator( + &d_nodeHighWatermark, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_NODE_HIGH_WATERMARK]); if (ret) { return ret; } - ret = accessor(d_flushAtShutdown, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_FLUSH_AT_SHUTDOWN]); + ret = manipulator( + &d_heartbeatIntervalMs, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_HEARTBEAT_INTERVAL_MS]); if (ret) { return ret; } - ret = accessor(d_syncConfig, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_SYNC_CONFIG]); + ret = manipulator(&d_listeners, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_LISTENERS]); if (ret) { return ret; } @@ -14363,70 +14624,66 @@ int PartitionConfig::accessAttributes(t_ACCESSOR& accessor) const return 0; } -template -int PartitionConfig::accessAttribute(t_ACCESSOR& accessor, int id) const +template +int TcpInterfaceConfig::manipulateAttribute(t_MANIPULATOR& manipulator, int id) { enum { NOT_FOUND = -1 }; switch (id) { - case ATTRIBUTE_ID_NUM_PARTITIONS: { - return accessor(d_numPartitions, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_NUM_PARTITIONS]); - } - case ATTRIBUTE_ID_LOCATION: { - return accessor(d_location, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_LOCATION]); + case ATTRIBUTE_ID_NAME: { + return manipulator(&d_name, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_NAME]); } - case ATTRIBUTE_ID_ARCHIVE_LOCATION: { - return accessor( - d_archiveLocation, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_ARCHIVE_LOCATION]); + case ATTRIBUTE_ID_PORT: { + return manipulator(&d_port, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_PORT]); } - case ATTRIBUTE_ID_MAX_DATA_FILE_SIZE: { - return accessor( - d_maxDataFileSize, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_DATA_FILE_SIZE]); + case ATTRIBUTE_ID_IO_THREADS: { + return manipulator(&d_ioThreads, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_IO_THREADS]); } - case ATTRIBUTE_ID_MAX_JOURNAL_FILE_SIZE: { - return accessor( - d_maxJournalFileSize, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_JOURNAL_FILE_SIZE]); + case ATTRIBUTE_ID_MAX_CONNECTIONS: { + return manipulator( + &d_maxConnections, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_CONNECTIONS]); } - case ATTRIBUTE_ID_MAX_QLIST_FILE_SIZE: { - return accessor( - d_maxQlistFileSize, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_QLIST_FILE_SIZE]); + case ATTRIBUTE_ID_LOW_WATERMARK: { + return manipulator( + &d_lowWatermark, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_LOW_WATERMARK]); } - case ATTRIBUTE_ID_PREALLOCATE: { - return accessor(d_preallocate, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_PREALLOCATE]); + case ATTRIBUTE_ID_HIGH_WATERMARK: { + return manipulator( + &d_highWatermark, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_HIGH_WATERMARK]); } - case ATTRIBUTE_ID_MAX_ARCHIVED_FILE_SETS: { - return accessor( - d_maxArchivedFileSets, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_ARCHIVED_FILE_SETS]); + case ATTRIBUTE_ID_NODE_LOW_WATERMARK: { + return manipulator( + &d_nodeLowWatermark, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_NODE_LOW_WATERMARK]); } - case ATTRIBUTE_ID_PREFAULT_PAGES: { - return accessor(d_prefaultPages, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_PREFAULT_PAGES]); + case ATTRIBUTE_ID_NODE_HIGH_WATERMARK: { + return manipulator( + &d_nodeHighWatermark, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_NODE_HIGH_WATERMARK]); } - case ATTRIBUTE_ID_FLUSH_AT_SHUTDOWN: { - return accessor( - d_flushAtShutdown, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_FLUSH_AT_SHUTDOWN]); + case ATTRIBUTE_ID_HEARTBEAT_INTERVAL_MS: { + return manipulator( + &d_heartbeatIntervalMs, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_HEARTBEAT_INTERVAL_MS]); } - case ATTRIBUTE_ID_SYNC_CONFIG: { - return accessor(d_syncConfig, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_SYNC_CONFIG]); + case ATTRIBUTE_ID_LISTENERS: { + return manipulator(&d_listeners, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_LISTENERS]); } default: return NOT_FOUND; } } -template -int PartitionConfig::accessAttribute(t_ACCESSOR& accessor, - const char* name, - int nameLength) const +template +int TcpInterfaceConfig::manipulateAttribute(t_MANIPULATOR& manipulator, + const char* name, + int nameLength) { enum { NOT_FOUND = -1 }; @@ -14436,176 +14693,120 @@ int PartitionConfig::accessAttribute(t_ACCESSOR& accessor, return NOT_FOUND; } - return accessAttribute(accessor, attributeInfo->d_id); -} - -inline int PartitionConfig::numPartitions() const -{ - return d_numPartitions; -} - -inline const bsl::string& PartitionConfig::location() const -{ - return d_location; + return manipulateAttribute(manipulator, attributeInfo->d_id); } -inline const bsl::string& PartitionConfig::archiveLocation() const +inline bsl::string& TcpInterfaceConfig::name() { - return d_archiveLocation; + return d_name; } -inline bsls::Types::Uint64 PartitionConfig::maxDataFileSize() const +inline int& TcpInterfaceConfig::port() { - return d_maxDataFileSize; + return d_port; } -inline bsls::Types::Uint64 PartitionConfig::maxJournalFileSize() const +inline int& TcpInterfaceConfig::ioThreads() { - return d_maxJournalFileSize; + return d_ioThreads; } -inline bsls::Types::Uint64 PartitionConfig::maxQlistFileSize() const +inline int& TcpInterfaceConfig::maxConnections() { - return d_maxQlistFileSize; + return d_maxConnections; } -inline bool PartitionConfig::preallocate() const +inline bsls::Types::Int64& TcpInterfaceConfig::lowWatermark() { - return d_preallocate; + return d_lowWatermark; } -inline int PartitionConfig::maxArchivedFileSets() const +inline bsls::Types::Int64& TcpInterfaceConfig::highWatermark() { - return d_maxArchivedFileSets; + return d_highWatermark; } -inline bool PartitionConfig::prefaultPages() const +inline bsls::Types::Int64& TcpInterfaceConfig::nodeLowWatermark() { - return d_prefaultPages; + return d_nodeLowWatermark; } -inline bool PartitionConfig::flushAtShutdown() const +inline bsls::Types::Int64& TcpInterfaceConfig::nodeHighWatermark() { - return d_flushAtShutdown; + return d_nodeHighWatermark; } -inline const StorageSyncConfig& PartitionConfig::syncConfig() const +inline int& TcpInterfaceConfig::heartbeatIntervalMs() { - return d_syncConfig; + return d_heartbeatIntervalMs; } -// -------------------------------- -// class StatPluginConfigPrometheus -// -------------------------------- - -// PRIVATE ACCESSORS -template -void StatPluginConfigPrometheus::hashAppendImpl( - t_HASH_ALGORITHM& hashAlgorithm) const +inline bsl::vector& TcpInterfaceConfig::listeners() { - using bslh::hashAppend; - hashAppend(hashAlgorithm, this->mode()); - hashAppend(hashAlgorithm, this->host()); - hashAppend(hashAlgorithm, this->port()); + return d_listeners; } -// CLASS METHODS -// MANIPULATORS -template -int StatPluginConfigPrometheus::manipulateAttributes( - t_MANIPULATOR& manipulator) +// ACCESSORS +template +int TcpInterfaceConfig::accessAttributes(t_ACCESSOR& accessor) const { int ret; - ret = manipulator(&d_mode, ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MODE]); + ret = accessor(d_name, ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_NAME]); if (ret) { return ret; } - ret = manipulator(&d_host, ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_HOST]); + ret = accessor(d_port, ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_PORT]); if (ret) { return ret; } - ret = manipulator(&d_port, ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_PORT]); + ret = accessor(d_ioThreads, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_IO_THREADS]); if (ret) { return ret; } - return 0; -} - -template -int StatPluginConfigPrometheus::manipulateAttribute(t_MANIPULATOR& manipulator, - int id) -{ - enum { NOT_FOUND = -1 }; - - switch (id) { - case ATTRIBUTE_ID_MODE: { - return manipulator(&d_mode, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MODE]); - } - case ATTRIBUTE_ID_HOST: { - return manipulator(&d_host, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_HOST]); - } - case ATTRIBUTE_ID_PORT: { - return manipulator(&d_port, - ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_PORT]); - } - default: return NOT_FOUND; - } -} - -template -int StatPluginConfigPrometheus::manipulateAttribute(t_MANIPULATOR& manipulator, - const char* name, - int nameLength) -{ - enum { NOT_FOUND = -1 }; - - const bdlat_AttributeInfo* attributeInfo = lookupAttributeInfo(name, - nameLength); - if (0 == attributeInfo) { - return NOT_FOUND; + ret = accessor(d_maxConnections, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_CONNECTIONS]); + if (ret) { + return ret; } - return manipulateAttribute(manipulator, attributeInfo->d_id); -} - -inline ExportMode::Value& StatPluginConfigPrometheus::mode() -{ - return d_mode; -} - -inline bsl::string& StatPluginConfigPrometheus::host() -{ - return d_host; -} - -inline int& StatPluginConfigPrometheus::port() -{ - return d_port; -} + ret = accessor(d_lowWatermark, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_LOW_WATERMARK]); + if (ret) { + return ret; + } -// ACCESSORS -template -int StatPluginConfigPrometheus::accessAttributes(t_ACCESSOR& accessor) const -{ - int ret; + ret = accessor(d_highWatermark, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_HIGH_WATERMARK]); + if (ret) { + return ret; + } - ret = accessor(d_mode, ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MODE]); + ret = accessor(d_nodeLowWatermark, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_NODE_LOW_WATERMARK]); if (ret) { return ret; } - ret = accessor(d_host, ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_HOST]); + ret = accessor(d_nodeHighWatermark, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_NODE_HIGH_WATERMARK]); if (ret) { return ret; } - ret = accessor(d_port, ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_PORT]); + ret = accessor( + d_heartbeatIntervalMs, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_HEARTBEAT_INTERVAL_MS]); + if (ret) { + return ret; + } + + ret = accessor(d_listeners, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_LISTENERS]); if (ret) { return ret; } @@ -14614,29 +14815,60 @@ int StatPluginConfigPrometheus::accessAttributes(t_ACCESSOR& accessor) const } template -int StatPluginConfigPrometheus::accessAttribute(t_ACCESSOR& accessor, - int id) const +int TcpInterfaceConfig::accessAttribute(t_ACCESSOR& accessor, int id) const { enum { NOT_FOUND = -1 }; switch (id) { - case ATTRIBUTE_ID_MODE: { - return accessor(d_mode, ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MODE]); - } - case ATTRIBUTE_ID_HOST: { - return accessor(d_host, ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_HOST]); + case ATTRIBUTE_ID_NAME: { + return accessor(d_name, ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_NAME]); } case ATTRIBUTE_ID_PORT: { return accessor(d_port, ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_PORT]); } + case ATTRIBUTE_ID_IO_THREADS: { + return accessor(d_ioThreads, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_IO_THREADS]); + } + case ATTRIBUTE_ID_MAX_CONNECTIONS: { + return accessor(d_maxConnections, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_MAX_CONNECTIONS]); + } + case ATTRIBUTE_ID_LOW_WATERMARK: { + return accessor(d_lowWatermark, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_LOW_WATERMARK]); + } + case ATTRIBUTE_ID_HIGH_WATERMARK: { + return accessor(d_highWatermark, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_HIGH_WATERMARK]); + } + case ATTRIBUTE_ID_NODE_LOW_WATERMARK: { + return accessor( + d_nodeLowWatermark, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_NODE_LOW_WATERMARK]); + } + case ATTRIBUTE_ID_NODE_HIGH_WATERMARK: { + return accessor( + d_nodeHighWatermark, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_NODE_HIGH_WATERMARK]); + } + case ATTRIBUTE_ID_HEARTBEAT_INTERVAL_MS: { + return accessor( + d_heartbeatIntervalMs, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_HEARTBEAT_INTERVAL_MS]); + } + case ATTRIBUTE_ID_LISTENERS: { + return accessor(d_listeners, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_LISTENERS]); + } default: return NOT_FOUND; } } template -int StatPluginConfigPrometheus::accessAttribute(t_ACCESSOR& accessor, - const char* name, - int nameLength) const +int TcpInterfaceConfig::accessAttribute(t_ACCESSOR& accessor, + const char* name, + int nameLength) const { enum { NOT_FOUND = -1 }; @@ -14649,19 +14881,55 @@ int StatPluginConfigPrometheus::accessAttribute(t_ACCESSOR& accessor, return accessAttribute(accessor, attributeInfo->d_id); } -inline ExportMode::Value StatPluginConfigPrometheus::mode() const +inline const bsl::string& TcpInterfaceConfig::name() const { - return d_mode; + return d_name; } -inline const bsl::string& StatPluginConfigPrometheus::host() const +inline int TcpInterfaceConfig::port() const { - return d_host; + return d_port; } -inline int StatPluginConfigPrometheus::port() const +inline int TcpInterfaceConfig::ioThreads() const { - return d_port; + return d_ioThreads; +} + +inline int TcpInterfaceConfig::maxConnections() const +{ + return d_maxConnections; +} + +inline bsls::Types::Int64 TcpInterfaceConfig::lowWatermark() const +{ + return d_lowWatermark; +} + +inline bsls::Types::Int64 TcpInterfaceConfig::highWatermark() const +{ + return d_highWatermark; +} + +inline bsls::Types::Int64 TcpInterfaceConfig::nodeLowWatermark() const +{ + return d_nodeLowWatermark; +} + +inline bsls::Types::Int64 TcpInterfaceConfig::nodeHighWatermark() const +{ + return d_nodeHighWatermark; +} + +inline int TcpInterfaceConfig::heartbeatIntervalMs() const +{ + return d_heartbeatIntervalMs; +} + +inline const bsl::vector& +TcpInterfaceConfig::listeners() const +{ + return d_listeners; } // ----------------- @@ -15041,6 +15309,144 @@ inline const DispatcherProcessorConfig& DispatcherConfig::clusters() const return d_clusters; } +// ----------------------- +// class NetworkInterfaces +// ----------------------- + +// CLASS METHODS +// MANIPULATORS +template +int NetworkInterfaces::manipulateAttributes(t_MANIPULATOR& manipulator) +{ + int ret; + + ret = manipulator(&d_heartbeats, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_HEARTBEATS]); + if (ret) { + return ret; + } + + ret = manipulator(&d_tcpInterface, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_TCP_INTERFACE]); + if (ret) { + return ret; + } + + return 0; +} + +template +int NetworkInterfaces::manipulateAttribute(t_MANIPULATOR& manipulator, int id) +{ + enum { NOT_FOUND = -1 }; + + switch (id) { + case ATTRIBUTE_ID_HEARTBEATS: { + return manipulator(&d_heartbeats, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_HEARTBEATS]); + } + case ATTRIBUTE_ID_TCP_INTERFACE: { + return manipulator( + &d_tcpInterface, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_TCP_INTERFACE]); + } + default: return NOT_FOUND; + } +} + +template +int NetworkInterfaces::manipulateAttribute(t_MANIPULATOR& manipulator, + const char* name, + int nameLength) +{ + enum { NOT_FOUND = -1 }; + + const bdlat_AttributeInfo* attributeInfo = lookupAttributeInfo(name, + nameLength); + if (0 == attributeInfo) { + return NOT_FOUND; + } + + return manipulateAttribute(manipulator, attributeInfo->d_id); +} + +inline Heartbeat& NetworkInterfaces::heartbeats() +{ + return d_heartbeats; +} + +inline bdlb::NullableValue& +NetworkInterfaces::tcpInterface() +{ + return d_tcpInterface; +} + +// ACCESSORS +template +int NetworkInterfaces::accessAttributes(t_ACCESSOR& accessor) const +{ + int ret; + + ret = accessor(d_heartbeats, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_HEARTBEATS]); + if (ret) { + return ret; + } + + ret = accessor(d_tcpInterface, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_TCP_INTERFACE]); + if (ret) { + return ret; + } + + return 0; +} + +template +int NetworkInterfaces::accessAttribute(t_ACCESSOR& accessor, int id) const +{ + enum { NOT_FOUND = -1 }; + + switch (id) { + case ATTRIBUTE_ID_HEARTBEATS: { + return accessor(d_heartbeats, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_HEARTBEATS]); + } + case ATTRIBUTE_ID_TCP_INTERFACE: { + return accessor(d_tcpInterface, + ATTRIBUTE_INFO_ARRAY[ATTRIBUTE_INDEX_TCP_INTERFACE]); + } + default: return NOT_FOUND; + } +} + +template +int NetworkInterfaces::accessAttribute(t_ACCESSOR& accessor, + const char* name, + int nameLength) const +{ + enum { NOT_FOUND = -1 }; + + const bdlat_AttributeInfo* attributeInfo = lookupAttributeInfo(name, + nameLength); + if (0 == attributeInfo) { + return NOT_FOUND; + } + + return accessAttribute(accessor, attributeInfo->d_id); +} + +inline const Heartbeat& NetworkInterfaces::heartbeats() const +{ + return d_heartbeats; +} + +inline const bdlb::NullableValue& +NetworkInterfaces::tcpInterface() const +{ + return d_tcpInterface; +} + // ------------------------------- // class ReversedClusterConnection // ------------------------------- @@ -17688,6 +18094,6 @@ inline const AppConfig& Configuration::appConfig() const } // close enterprise namespace #endif -// GENERATED BY @BLP_BAS_CODEGEN_VERSION@ +// GENERATED BY BLP_BAS_CODEGEN_2024.07.18 // USING bas_codegen.pl -m msg --noAggregateConversion --noExternalization // --noIdent --package mqbcfg --msgComponent messages mqbcfg.xsd diff --git a/src/groups/mqb/mqbcfg/mqbcfg_tcpinterfaceconfigvalidator.cpp b/src/groups/mqb/mqbcfg/mqbcfg_tcpinterfaceconfigvalidator.cpp new file mode 100644 index 000000000..e39b361c0 --- /dev/null +++ b/src/groups/mqb/mqbcfg/mqbcfg_tcpinterfaceconfigvalidator.cpp @@ -0,0 +1,109 @@ +// Copyright 2024 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. +// mqbcfg_tcpinterfaceconfigvalidator.cpp + +#include +BSLS_IDENT_RCSID(mqbcfg_tcpinterfaceconfigvalidator_h, "$Id$ $CSID$") + +#include + +#include +#include +#include +#include +#include + +namespace BloombergLP { +namespace mqbcfg { + +namespace { + +const char LOG_CATEGORY[] = "MQBCFG.TCPINTERFACECONFIGVALIDATOR"; +BALL_LOG_SET_NAMESPACE_CATEGORY(LOG_CATEGORY) + +/// @brief Transform the range that elements in the range [`begin`, `end`) and +/// then check if the result contains unique items. +template +bool uniqueWith(It begin, It end, F f) +{ + typedef typename bsl::iterator_traits::reference Reference; + typedef typename bsl::invoke_result::type Result; + bsl::vector sorted; + sorted.reserve(bsl::distance(begin, end)); + + bsl::transform(begin, end, bsl::back_inserter(sorted), f); + bsl::sort(sorted.begin(), sorted.end()); + typename bsl::vector::iterator newEnd = bsl::unique(sorted.begin(), + sorted.end()); + return sorted.end() == newEnd; +} + +} // close unnamed namespace + +// PRIVATE STATIC FUNCTIONS +int TcpInterfaceConfigValidator::port( + const mqbcfg::TcpInterfaceListener& listener) +{ + return listener.port(); +} + +bsl::string_view +TcpInterfaceConfigValidator::name(const mqbcfg::TcpInterfaceListener& listener) +{ + return listener.name(); +} + +bool TcpInterfaceConfigValidator::isValidPort( + const mqbcfg::TcpInterfaceListener& listener) +{ + return 0 <= listener.port() && listener.port() <= 65535; +} + +TcpInterfaceConfigValidator::ErrorCode TcpInterfaceConfigValidator::operator()( + const mqbcfg::TcpInterfaceConfig& config) const +{ + if (config.listeners().empty()) { + return k_OK; + } + + bsl::vector::const_iterator + first = config.listeners().cbegin(), + last = config.listeners().cend(); + // The names of each network interface is unique + if (!uniqueWith(first, last, TcpInterfaceConfigValidator::name)) { + BALL_LOG_ERROR << "TCP interface validation failed: Multiple " + "interfaces with the same name"; + return k_DUPLICATE_NAME; + } + + // The ports of each network interface is unqiue + if (!uniqueWith(first, last, TcpInterfaceConfigValidator::port)) { + BALL_LOG_ERROR << "TCP interface validation failed: Multiple " + "interfaces using the same port"; + return k_DUPLICATE_PORT; + } + + // Ports passed are possible port values + if (!bsl::all_of(first, last, TcpInterfaceConfigValidator::isValidPort)) { + BALL_LOG_ERROR << "TCP interface validation failed: Invalid port " + "specified"; + return k_PORT_RANGE; + } + + return k_OK; +} + +} // close namespace mqbcfg +} // close namespace BloombergLP diff --git a/src/groups/mqb/mqbcfg/mqbcfg_tcpinterfaceconfigvalidator.h b/src/groups/mqb/mqbcfg/mqbcfg_tcpinterfaceconfigvalidator.h new file mode 100644 index 000000000..6ec1da8e5 --- /dev/null +++ b/src/groups/mqb/mqbcfg/mqbcfg_tcpinterfaceconfigvalidator.h @@ -0,0 +1,85 @@ +// Copyright 2024 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. +// mqbcfg_tcpinterfaceconfigvalidator.h +#ifndef INCLUDED_MQBCFG_TCPINTERFACECONFIGVALIDATOR +#define INCLUDED_MQBCFG_TCPINTERFACECONFIGVALIDATOR + +#include +BSLS_IDENT_RCSID(mqbcfg_tcpinterfaceconfigvalidator_h, "$Id$ $CSID$") +BSLS_IDENT_PRAGMA_ONCE + +#include + +#include + +/// PURPOSE: This component provdies a class to validate TcpInterfaceConfig +/// settings in the broker config. +/// +/// CLASSES: +/// mqbcfg::TcpInterfaceConfigValidator: A predicate object that validates the +/// TCP interfaces in the broker config +/// +/// DESCRIPTION: + +namespace BloombergLP { +namespace mqbcfg { + +/// @brief This class is a functor that validates the +/// `appConfig/networkInterfaces/tcpInterface/listeners` property of the broker +/// config. +class TcpInterfaceConfigValidator { + private: + // PRIVATE STATIC FUNCTIONS + static int port(const mqbcfg::TcpInterfaceListener& listener); + + static bsl::string_view name(const mqbcfg::TcpInterfaceListener& listener); + + static bool isValidPort(const mqbcfg::TcpInterfaceListener& listener); + + public: + // TYPES + /// Codes to indicate the reason for a validation failure. + enum ErrorCode { + /// Indicates a config is valid. Guaranteed to equal zero. + k_OK = 0, + /// Indicates there were multiple interfaces with the same name. + k_DUPLICATE_NAME = -1, + /// Indicates there were multiple interfaces using the same ports. + k_DUPLICATE_PORT = -2, + /// Indicates a port number was passed outside of the valid port range. + k_PORT_RANGE = -3 + }; + + // ACCESSORS + + /// @brief Validate the TCP interface configuration. + /// + /// The TCP interface configuration is invalid unless: + /// 1. The names of each network interface is unique + /// 2. The ports of each network interface is unqiue + /// 3. Ports passed are possible port values + /// + /// @returns An error code indicating success (`k_OK`) or a non-zero code + /// indicating the cause of failure. + ErrorCode operator()(const mqbcfg::TcpInterfaceConfig& config) const; +}; + +// ============================================================================ +// INLINE FUNCTION DEFINITIONS +// ============================================================================ + +} // close namespace mqbcfg +} // close namespace BloombergLP +#endif \ No newline at end of file diff --git a/src/groups/mqb/mqbcfg/mqbcfg_tcpinterfaceconfigvalidator.t.cpp b/src/groups/mqb/mqbcfg/mqbcfg_tcpinterfaceconfigvalidator.t.cpp new file mode 100644 index 000000000..b8d417cae --- /dev/null +++ b/src/groups/mqb/mqbcfg/mqbcfg_tcpinterfaceconfigvalidator.t.cpp @@ -0,0 +1,125 @@ +// Copyright 2024 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. + +// mqbcfg_tcpinterfaceconfigvalidator.t.cpp -*-C++-*- +#include + +// MQB +#include + +// BMQ +#include + +// BDE +#include +#include +#include + +using namespace BloombergLP; + +struct TcpInterfaceConfigValidatorTest : bmqtst::Test {}; + +TEST_F(TcpInterfaceConfigValidatorTest, breathingTest) +{ + ASSERT_EQ(mqbcfg::TcpInterfaceConfigValidator::k_OK, 0); +} + +TEST_F(TcpInterfaceConfigValidatorTest, emptyConfigIsValid) +{ + mqbcfg::TcpInterfaceConfigValidator validator; + mqbcfg::TcpInterfaceConfig config; + + ASSERT_EQ(mqbcfg::TcpInterfaceConfigValidator::k_OK, validator(config)); +} + +TEST_F(TcpInterfaceConfigValidatorTest, nonUniqueNamesAreInvalid) +{ + mqbcfg::TcpInterfaceConfigValidator validator; + mqbcfg::TcpInterfaceConfig config; + + { + mqbcfg::TcpInterfaceListener& listener = + config.listeners().emplace_back(); + listener.name() = "Test"; + } + + { + mqbcfg::TcpInterfaceListener& listener = + config.listeners().emplace_back(); + listener.name() = "Test"; + } + + ASSERT_EQ(mqbcfg::TcpInterfaceConfigValidator::k_DUPLICATE_NAME, + validator(config)); +} + +TEST_F(TcpInterfaceConfigValidatorTest, nonUniquePortsAreInvalid) +{ + mqbcfg::TcpInterfaceConfigValidator validator; + mqbcfg::TcpInterfaceConfig config; + + { + mqbcfg::TcpInterfaceListener& listener = + config.listeners().emplace_back(); + listener.name() = "listener0"; + listener.port() = 8000; + } + + { + mqbcfg::TcpInterfaceListener& listener = + config.listeners().emplace_back(); + listener.name() = "listener1"; + listener.port() = 8000; + } + + ASSERT_EQ(mqbcfg::TcpInterfaceConfigValidator::k_DUPLICATE_PORT, + validator(config)); +} + +TEST_F(TcpInterfaceConfigValidatorTest, outOfRangePortsAreInvalid) +{ + mqbcfg::TcpInterfaceConfigValidator validator; + + { + mqbcfg::TcpInterfaceConfig config; + mqbcfg::TcpInterfaceListener& listener = + config.listeners().emplace_back(); + listener.port() = 0x10000; + ASSERT_EQ(mqbcfg::TcpInterfaceConfigValidator::k_PORT_RANGE, + validator(config)); + } + + { + mqbcfg::TcpInterfaceConfig config; + mqbcfg::TcpInterfaceListener& listener = + config.listeners().emplace_back(); + listener.port() = -1; + ASSERT_EQ(mqbcfg::TcpInterfaceConfigValidator::k_PORT_RANGE, + validator(config)); + } +} + +// ============================================================================ +// MAIN PROGRAM +// ---------------------------------------------------------------------------- + +int main(int argc, char* argv[]) +{ + TEST_PROLOG(bmqtst::TestHelper::e_DEFAULT); + + bmqtst::runTest(_testCase); + + TEST_EPILOG(bmqtst::TestHelper::e_CHECK_GBL_ALLOC); +} diff --git a/src/groups/mqb/mqbcfg/package/mqbcfg.mem b/src/groups/mqb/mqbcfg/package/mqbcfg.mem index f63a729ad..87a8f2eae 100644 --- a/src/groups/mqb/mqbcfg/package/mqbcfg.mem +++ b/src/groups/mqb/mqbcfg/package/mqbcfg.mem @@ -1,2 +1,3 @@ mqbcfg_brokerconfig mqbcfg_messages +mqbcfg_tcpinterfaceconfigvalidator \ No newline at end of file diff --git a/src/groups/mqb/mqbnet/mqbnet_tcpsessionfactory.cpp b/src/groups/mqb/mqbnet/mqbnet_tcpsessionfactory.cpp index 652321510..1ae238676 100644 --- a/src/groups/mqb/mqbnet/mqbnet_tcpsessionfactory.cpp +++ b/src/groups/mqb/mqbnet/mqbnet_tcpsessionfactory.cpp @@ -19,16 +19,18 @@ #include /// Implementation Notes ///==================== -// When a channel is being created, the following methods are always called, in -// order, regardless of the success or failure of the negotiation: -//: o !channelStateCallback! -//: o !negotiate! -//: o !negotiationComplete! -// -// When a channel goes down, 'onClose()' is the only method being invoked. +/// When a channel is being created, the following methods are always called, +/// in order, regardless of the success or failure of the negotiation: +/// - `channelStateCallback` +/// - `negotiate` +/// - `negotiationComplete` +/// +/// When a channel goes down, `onClose()` is the only method being invoked. // MQB #include +#include +#include #include #include @@ -705,7 +707,8 @@ void TCPSessionFactory::channelStateCallback( ++d_nbActiveChannels; // Register as observer of the channel to get the 'onClose' - channel->onClose(bdlf::BindUtil::bind( + channel->onClose(bdlf::BindUtil::bindS( + d_allocator_p, &TCPSessionFactory::onClose, this, channel, @@ -951,16 +954,16 @@ TCPSessionFactory::TCPSessionFactory( , d_heartbeatSchedulerActive(false) , d_heartbeatChannels(allocator) , d_initialMissedHeartbeatCounter(calculateInitialMissedHbCounter(config)) +, d_listeningHandles(allocator) , d_isListening(false) , d_timestampMap(allocator) +, d_listenContexts(allocator) , d_allocator_p(allocator) { // PRECONDITIONS BSLS_ASSERT_SAFE(scheduler->clockType() == bsls::SystemClockType::e_MONOTONIC); - BALL_LOG_INFO << "Creating TcpSessionFactory: " << config; - // Resolve the default address of this host bsl::string hostname; ntsa::Error error = bmqio::ResolveUtil::getHostname(&hostname); @@ -1001,6 +1004,27 @@ TCPSessionFactory::~TCPSessionFactory() d_self.invalidate(); } +int TCPSessionFactory::validateTcpInterfaces() const +{ + mqbcfg::TcpInterfaceConfigValidator validator; + return validator(d_config); +} + +void TCPSessionFactory::cancelListeners() +{ + for (ListeningHandleMap::iterator it = d_listeningHandles.begin(), + end = d_listeningHandles.end(); + it != end; + ++it) { + BSLS_ASSERT_SAFE(it->second); + it->second->cancel(); + it->second.reset(); + } + + d_listeningHandles.clear(); + d_listenContexts.clear(); +} + int TCPSessionFactory::start(bsl::ostream& errorDescription) { // PRECONDITIONS @@ -1011,6 +1035,15 @@ int TCPSessionFactory::start(bsl::ostream& errorDescription) int rc = 0; + rc = validateTcpInterfaces(); + + if (rc != 0) { + errorDescription << "Failed to validate the TCP interface config for " + << "TCPSessionFactory '" << d_config.name() + << "' [rc: " << rc << "]"; + return rc; // RETURN + } + ntca::InterfaceConfig interfaceConfig = ntcCreateInterfaceConfig(d_config); bslma::ManagedPtr channelFactory; @@ -1141,14 +1174,38 @@ int TCPSessionFactory::startListening(bsl::ostream& errorDescription, { BSLS_ASSERT_SAFE(d_isStarted && "TCPSessionFactory must be started first"); - int rc = listen(d_config.port(), resultCallback); - if (rc != 0) { - errorDescription << "Failed listening to port '" << d_config.port() - << "' for TCPSessionFactory '" << d_config.name() - << "' [rc: " << rc << "]"; - return rc; // RETURN + // Adapt a legacy listener configuration + if (d_config.listeners().empty()) { + mqbcfg::TcpInterfaceListener listener; + listener.name() = d_config.name(); + listener.port() = d_config.port(); + int rc = listen(listener, resultCallback); + if (rc != 0) { + errorDescription << "Failed listening to port '" << d_config.port() + << "' for TCPSessionFactory '" << d_config.name() + << "' [rc: " << rc << "]"; + cancelListeners(); + return rc; // RETURN + } + } + else { + for (bsl::vector::const_iterator + it = d_config.listeners().cbegin(), + end = d_config.listeners().cend(); + it != end; + ++it) { + int rc = listen(*it, resultCallback); + if (rc != 0) { + errorDescription << "Failed listening to port '" << it->port() + << "' for TCPSessionFactory '" + << d_config.name() << "' [rc: " << rc << "]"; + cancelListeners(); + return rc; // RETURN + } + } } + d_isListening = true; return 0; } @@ -1162,9 +1219,7 @@ void TCPSessionFactory::stopListening() } d_isListening = false; - BSLS_ASSERT_SAFE(d_listeningHandle_mp); - d_listeningHandle_mp->cancel(); - d_listeningHandle_mp.reset(); + cancelListeners(); // NOTE: This is done here as a temporary workaround until channels are // properly stopped (see 'mqba::Application::stop'), because in the @@ -1315,20 +1370,20 @@ void TCPSessionFactory::stop() BALL_LOG_INFO << "Stopped TCPSessionFactory '" << d_config.name() << "'"; } -int TCPSessionFactory::listen(int port, const ResultCallback& resultCallback) +int TCPSessionFactory::listen(const mqbcfg::TcpInterfaceListener& listener, + const ResultCallback& resultCallback) { - // Supporting only one 'listen' call. - BSLS_ASSERT_SAFE(!d_isListening); - BSLS_ASSERT_SAFE(!d_listenContext_mp); + const int port = listener.port(); + + BSLS_ASSERT_SAFE(d_listenContexts.find(port) == d_listenContexts.cend()); // Maintain ownership of 'OperationContext' instead of passing it to // 'ChannelFactory::listen' because it may delete the context // (on stopListening) while operation (readCallback / negotiation) is in // progress. - OperationContext* context = new (*d_allocator_p) OperationContext(); - d_listenContext_mp.load(context, d_allocator_p); - bsl::shared_ptr contextSp; - contextSp.reset(context, bslstl::SharedPtrNilDeleter()); + bsl::shared_ptr context = + bsl::allocate_shared(d_allocator_p); + d_listenContexts.emplace(port, context); context->d_resultCb = resultCallback; context->d_isIncoming = true; @@ -1340,19 +1395,19 @@ int TCPSessionFactory::listen(int port, const ResultCallback& resultCallback) bmqio::ListenOptions listenOptions; listenOptions.setEndpoint(endpoint.str()); - d_isListening = true; + OpHandleMp& listeningHandle = d_listeningHandles[port]; bmqio::Status status; d_statChannelFactory_mp->listen( &status, - &d_listeningHandle_mp, + &listeningHandle, listenOptions, bdlf::BindUtil::bind(&TCPSessionFactory::channelStateCallback, this, bdlf::PlaceHolders::_1, // event bdlf::PlaceHolders::_2, // status bdlf::PlaceHolders::_3, // channel - contextSp)); + context)); if (!status) { BALL_LOG_ERROR << "#TCP_LISTEN_FAILED " << "TCPSessionFactory '" << d_config.name() << "' " @@ -1362,7 +1417,7 @@ int TCPSessionFactory::listen(int port, const ResultCallback& resultCallback) return status.category(); // RETURN } - BSLS_ASSERT_SAFE(d_listeningHandle_mp); + BSLS_ASSERT_SAFE(listeningHandle); BALL_LOG_INFO << "TCPSessionFactory '" << d_config.name() << "' " << "successfully listening to '" << endpoint.str() << "'"; @@ -1468,8 +1523,25 @@ bool TCPSessionFactory::isEndpointLoopback(const bslstl::StringRef& uri) const { bmqio::TCPEndpoint endpoint(uri); - return (endpoint.port() == d_config.port()) && - bmqio::ChannelUtil::isLocalHost(endpoint.host()); + // Use the original port specification method + if (d_config.listeners().empty()) { + return (endpoint.port() == d_config.port()) && + bmqio::ChannelUtil::isLocalHost(endpoint.host()); + } + + struct PortMatcher { + int d_port; + + bool operator()(const mqbcfg::TcpInterfaceListener& listener) + { + return listener.port() == d_port; + } + }; + + PortMatcher portMatcher = {endpoint.port()}; + return bsl::any_of(d_config.listeners().cbegin(), + d_config.listeners().cend(), + portMatcher); } // ------------------------------------ diff --git a/src/groups/mqb/mqbnet/mqbnet_tcpsessionfactory.h b/src/groups/mqb/mqbnet/mqbnet_tcpsessionfactory.h index 14fb4501c..5d2c39da0 100644 --- a/src/groups/mqb/mqbnet/mqbnet_tcpsessionfactory.h +++ b/src/groups/mqb/mqbnet/mqbnet_tcpsessionfactory.h @@ -277,6 +277,8 @@ class TCPSessionFactory { typedef bsl::unordered_map TimestampMap; + typedef bsl::unordered_map ListeningHandleMap; + private: // DATA bmqu::SharedResource d_self; @@ -288,9 +290,8 @@ class TCPSessionFactory { // Has this component been // started ? + /// Config to use for setting up this SessionFactory mqbcfg::TcpInterfaceConfig d_config; - // Config to use for setting up - // this SessionFactory bdlmt::EventScheduler* d_scheduler_p; // Event scheduler held not owned @@ -387,10 +388,8 @@ class TCPSessionFactory { // See comments in // 'calculateInitialMissedHbCounter'. - OpHandleMp d_listeningHandle_mp; - // Handle which can be used to - // stop listening. Empty unless - // listening. + /// Handles that can be used to stop listening. Empty unless listening. + ListeningHandleMap d_listeningHandles; bsls::AtomicBool d_isListening; // Set to 'true' before calling @@ -401,15 +400,12 @@ class TCPSessionFactory { // Mutex for thread safety of // this component. - bslma::ManagedPtr d_listenContext_mp; - // Maintain ownership of - // 'OperationContext' instead of - // passing it to - // 'ChannelFactory::listen' - // because it may delete the - // context (on stopListening) - // while operation (readCallback/ - // negotiation) is in progress. + // Maintain ownership of 'OperationContext' instead of passing it to + // 'ChannelFactory::listen' because it may delete the context (on + // stopListening) while operation (readCallback/ negotiation) is in + // progress. + bsl::unordered_map > + d_listenContexts; TimestampMap d_timestampMap; // Map of HiRes timestamp of the session beginning per channel. @@ -522,6 +518,17 @@ class TCPSessionFactory { /// timestamps map. void logOpenSessionTime(const bsl::string& sessionDescription, const bsl::shared_ptr& channel); + /// @brief Check that the TCP interfaces are valid. + /// + /// We require the following: + /// - The name of each listener interface is unique + /// - The port of each listener interface is unqiue + /// + /// @returns 0 on success, nonzero on failure. + int validateTcpInterfaces() const; + + /// Cancel any open listener operations and clear them out. + void cancelListeners(); private: // NOT IMPLEMENTED @@ -580,10 +587,11 @@ class TCPSessionFactory { /// deleted. void closeClients(); - /// Listen to the specified `port` for incoming connection and invoke - /// the specified `resultCallback` when a connection has been - /// negotiated. Return 0 on success, or non-zero on error. - int listen(int port, const ResultCallback& resultCallback); + /// Create a new listener interface specified by `listener` for incoming + /// connections and invoke the specified `resultCallback` when a connection + /// has been negotiated. Return 0 on success, or non-zero on error. + int listen(const mqbcfg::TcpInterfaceListener& listener, + const ResultCallback& resultCallback); /// Initiate a connection to the specified `endpoint` and return 0 if /// the connection has successfully been started; with the result being diff --git a/src/groups/mqb/mqbnet/mqbnet_transportmanager.cpp b/src/groups/mqb/mqbnet/mqbnet_transportmanager.cpp index 5dab27780..7148e8a87 100644 --- a/src/groups/mqb/mqbnet/mqbnet_transportmanager.cpp +++ b/src/groups/mqb/mqbnet/mqbnet_transportmanager.cpp @@ -22,6 +22,7 @@ // MQB #include +#include #include #include #include @@ -389,6 +390,9 @@ int TransportManager::start(bsl::ostream& errorDescription) // Create and start the TCPInterface, if any const mqbcfg::AppConfig& brkrCfg = mqbcfg::BrokerConfig::get(); + + // If the new network interfaces exist, use them. Otherwise, fall back to + // the old network interface config. if (!brkrCfg.networkInterfaces().tcpInterface().isNull()) { rc = createAndStartTcpInterface( errorDescription, diff --git a/src/integration-tests/test_breathing.py b/src/integration-tests/test_breathing.py index 4679302e3..6f7486135 100644 --- a/src/integration-tests/test_breathing.py +++ b/src/integration-tests/test_breathing.py @@ -28,6 +28,7 @@ cluster, order, multi_node, + multi_interface, start_cluster, tweak, ) @@ -661,6 +662,58 @@ def test_verify_partial_close(multi_node: Cluster): _stop_clients([producer1, producer2]) +def test_multi_interface_connect(multi_interface: Cluster): + """Simple test to connect to a cluster with multiple ports listening.""" + cluster = multi_interface + brokers = cluster.nodes() + cluster.proxies() + for broker in brokers: + for i, listener in enumerate(broker.config.listeners): + port = listener.port + producer = broker.create_client(f"producer{i}", port=port) + consumer = broker.create_client(f"consumer{i}", port=port) + producer.open(tc.URI_PRIORITY, flags=["write", "ack"], succeed=True) + consumer.open( + tc.URI_PRIORITY, + flags=["read"], + consumer_priority=1, + max_unconfirmed_messages=1, + succeed=True, + ) + producer.post( + tc.URI_PRIORITY, payload=[f"{i}"], succeed=True, wait_ack=True + ) + assert consumer.wait_push_event() + msgs = consumer.list(block=True) + assert len(msgs) == 1 + assert msgs[0].payload == f"{i}" + consumer.confirm(tc.URI_PRIORITY, msgs[0].guid, succeed=True) + _stop_clients([producer, consumer]) + + +def test_multi_interface_share_queues(multi_interface: Cluster): + """Check that clients connecting on different ports still work together.""" + cluster = multi_interface + broker = next(cluster.proxy_cycle()) + [listener1, listener2] = broker.config.listeners + producer = broker.create_client("producer", port=listener1.port) + consumer = broker.create_client("consumer", port=listener2.port) + producer.open(tc.URI_PRIORITY, flags=["write", "ack"], succeed=True) + consumer.open( + tc.URI_PRIORITY, + flags=["read"], + consumer_priority=1, + max_unconfirmed_messages=1, + succeed=True, + ) + producer.post(tc.URI_PRIORITY, payload=["foo"], succeed=True, wait_ack=True) + assert consumer.wait_push_event() + msgs = consumer.list(block=True) + assert len(msgs) == 1 + assert msgs[0].payload == "foo" + consumer.confirm(tc.URI_PRIORITY, msgs[0].guid, succeed=True) + _stop_clients([producer, consumer]) + + @start_cluster(True, True, True) @tweak.cluster.queue_operations.open_timeout_ms(2) def test_command_timeout(multi_node: Cluster): diff --git a/src/python/blazingmq/dev/configurator/__init__.py b/src/python/blazingmq/dev/configurator/__init__.py index 6fa7835ad..a5508ccab 100644 --- a/src/python/blazingmq/dev/configurator/__init__.py +++ b/src/python/blazingmq/dev/configurator/__init__.py @@ -31,6 +31,10 @@ from decimal import Decimal from pathlib import Path from typing import Dict, Iterator, List, Optional, Set, Tuple, Union +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from blazingmq.dev.configurator import Configurator from blazingmq.dev.configurator.site import Site from blazingmq.dev.paths import required_paths as paths @@ -105,6 +109,10 @@ def port(self) -> str: def config_dir(self) -> Path: return Path(self.name) / "etc" + @property + def listeners(self) -> List[mqbcfg.TcpInterfaceListener]: + return self.config.app_config.network_interfaces.tcp_interface.listeners + def add_proxy_definition(self, cluster: "AbstractCluster"): self.proxy_clusters.add(cluster.name) self.clusters.proxy_clusters.append( @@ -166,13 +174,24 @@ def proxy(self, target: Union[Domain, "AbstractCluster"], reverse: bool = False) reversed_cluster_connections ) - reversed_cluster_connections.connections.append( - mqbcfg.ClusterNodeConnection( - mqbcfg.TcpClusterNodeConnection( - f"tcp://{self.host}:{self.port}" + if self.listeners: + for listener in self.listeners: + print(listener) + reversed_cluster_connections.connections.append( + mqbcfg.ClusterNodeConnection( + mqbcfg.TcpClusterNodeConnection( + f"tcp://{self.host}:{listener.port}" + ) + ) + ) + else: + reversed_cluster_connections.connections.append( + mqbcfg.ClusterNodeConnection( + mqbcfg.TcpClusterNodeConnection( + f"tcp://{self.host}:{self.port}" + ) ) ) - ) return self diff --git a/src/python/blazingmq/dev/configurator/configurator.py b/src/python/blazingmq/dev/configurator/configurator.py index f44ebae9c..cc698372c 100644 --- a/src/python/blazingmq/dev/configurator/configurator.py +++ b/src/python/blazingmq/dev/configurator/configurator.py @@ -129,7 +129,25 @@ def broker( name: str, instance: Optional[str] = None, data_center: str = "dc", + listeners: List[Tuple[str, int]] = [], ) -> Broker: + """Create a broker config and add it to the list of broker configs in + the current configs. + + Args: + tcp_host: config/app_config/network_interfaces/tcp_interface/name + tcp_port: config/app_config/network_interfaces/tcp_interface/port + name: The host name for this broker. + instance: The BlazingMQ instance this broker belongs to. + data_center: A name for the data center region this broker belongs + to. + listeners: A list of TCP interfaces the broker will listen on. The + option overrides tcp_host and tcp_port if non-empty. + + Returns: + A Broker object representing the fully configured broker + configuration. + """ config = self.broker_configuration() assert config.app_config is not None assert config.app_config.network_interfaces is not None @@ -139,6 +157,10 @@ def broker( config.app_config.broker_instance_name = instance config.app_config.network_interfaces.tcp_interface.name = tcp_host config.app_config.network_interfaces.tcp_interface.port = tcp_port + config.app_config.network_interfaces.tcp_interface.listeners = [ + mqbcfg.TcpInterfaceListener(name=host, port=port) + for (host, port) in listeners + ] broker = Broker(self, next(self.host_id_allocator), config) self.brokers[name] = broker @@ -150,6 +172,16 @@ def _prepare_cluster( if name in self.clusters: raise ConfiguratorError(f"cluster '{name}' already exists") + def port(tcp_interface: mqbcfg.TcpInterfaceConfig) -> int: + if tcp_interface.listeners: + return next( + listener.port + for listener in tcp_interface.listeners + if listener.name == "BROKER" + ) + else: + return tcp_interface.port + definition.name = name definition.nodes = [ mqbcfg.ClusterNode( @@ -160,7 +192,7 @@ def _prepare_cluster( mqbcfg.TcpClusterNodeConnection( "tcp://{host}:{port}".format( host=tcp_interface.name, # type: ignore - port=tcp_interface.port, # type: ignore + port=port(tcp_interface), # type: ignore ) ) ), @@ -172,6 +204,21 @@ def _prepare_cluster( ] def cluster(self, name: str, nodes: List[Broker]) -> Cluster: + """Create a cluster config and add it to the list of cluster configs in the + current configs. + + If a broker specifies listeners in its TCP interface config, the inter-broker + listener URI will be constructed as tcp://: where + is specified by the special listener named "BROKER". Otherwise, the port is + taken from the port field in the TCP interface config. + + Args: + name: The name of the cluster. + nodes: The broker members of the cluster. + + Returns: + A cluster config definition. + """ definition = self.cluster_definition() self._prepare_cluster(name, nodes, definition) diff --git a/src/python/blazingmq/dev/it/cluster.py b/src/python/blazingmq/dev/it/cluster.py index 0690bba37..804a1e082 100644 --- a/src/python/blazingmq/dev/it/cluster.py +++ b/src/python/blazingmq/dev/it/cluster.py @@ -377,7 +377,7 @@ def process(self, name): return self._processes[name] - def nodes(self, **kw): + def nodes(self, **kw) -> List[Broker]: """Return the nodes matching the conditions specified by 'kw'. Conditions @@ -408,7 +408,7 @@ def virtual_nodes(self, **kw): return [broker for broker in self._virtual_nodes if _match_broker(broker, **kw)] - def proxies(self, **kw): + def proxies(self, **kw) -> List[Broker]: """Return the proxies matching the conditions specified by 'kw'. Conditions can be any combination of: - datacenter: return the @@ -441,7 +441,9 @@ def proxy_cycle(self): following sub-sequence: o1, r1, o2, r2, o1, r3, o2, r1, o1, r2, o2, r3 """ - proxy_map = collections.defaultdict(list) + proxy_map: collections.defaultdict[str, List[Broker]] = collections.defaultdict( + list + ) for proxy in self._proxies: proxy_map[proxy.datacenter].append(proxy) @@ -465,17 +467,19 @@ def proxy_cycle(self): def create_client( self, prefix, - broker: cfg.Broker, + broker: Broker, start=True, dump_messages=True, options=None, + port=None, ) -> Client: """ Create a client with the specified name. Either 'proxyhostname' or 'proxy' must be specified; the client connects to the specified proxy. If 'options' is specified, its string - value is tacked at the end of the 'bmqtool.tsk' argument list. + value is tacked at the end of the 'bmqtool.tsk' argument list. If 'port' is not + specified, use either the first listener if it exists or 'broker.port'. """ if isinstance(options, str): @@ -483,9 +487,15 @@ def create_client( name = f"{prefix}@{broker.name}" + if port is None: + if broker.config.listeners: + port = broker.config.listeners[0] + else: + port = broker.config.port + client = Client( name, - ("localhost", broker.config.port), + ("localhost", port), tool_path="bin/bmqtool.tsk", cwd=(self.work_dir / broker.name), dump_messages=dump_messages, @@ -540,7 +550,9 @@ def wait_leader(self): return self.last_known_leader - def open_priority_queues(self, count, start=0, **kw): + def open_priority_queues( + self, count, start=0, port=None, **kw + ) -> ListContextManager[Queue]: """Open *distinct* priority queues with the options specified in 'kw'. While each queue uses a different URI, calling this method multiple @@ -556,7 +568,11 @@ def open_priority_queues(self, count, start=0, **kw): proxies = self.proxy_cycle() return ListContextManager( [ - Queue(next(proxies).create_client(), f"{tc.URI_PRIORITY}{i}", **kw) + Queue( + next(proxies).create_client(port=port), + f"{tc.URI_PRIORITY}{i}", + **kw, + ) for i in range(start, start + count) ] ) diff --git a/src/python/blazingmq/dev/it/fixtures.py b/src/python/blazingmq/dev/it/fixtures.py index de2c216d2..9d5d3fbd2 100644 --- a/src/python/blazingmq/dev/it/fixtures.py +++ b/src/python/blazingmq/dev/it/fixtures.py @@ -37,7 +37,8 @@ import tempfile from enum import IntEnum from pathlib import Path -from typing import Callable, Generator, Iterator, List, Optional, Tuple +from typing import Callable, List, Optional, Tuple +from collections.abc import Generator, Iterator import psutil import pytest @@ -197,7 +198,7 @@ def task_log_params(normalized_levels): return (broker_threshold, broker_category_levels, tool_threshold) -def cluster_fixture(request, configure) -> Generator: +def cluster_fixture(request, configure) -> Iterator[Cluster]: # Get a temporary directory and also add a unique suffix to the dir name to # further avoid name collision on a machine. @@ -605,6 +606,92 @@ def multi_node(request): yield from cluster_fixture(request, request.param) +############################################################################### +# multi_node cluster with multiple TCP listeners + + +def multi_interface_cluster_config( + configurator: cfg.Configurator, + port_allocator: Iterator[int], + mode: Mode, + listener_count: int, + reverse_proxy: bool = False, +) -> None: + """A factory for cluster configurations containing multiple open TCP interfaces. + + This function generates configuration for a 4-node BlazingMQ cluster, a proxy in + each data center region, and adds domains to the cluster to be used by tests. + + Cluster: east1, east2, west1, west2 + Proxies: eastp, westp + + Args: + configurator: The Configurator used to generate and manage cluster and broker + configuration definitions + port_allocator: An iterator providing port numbers for brokers + mode: The cluster operation mode + listener_count: The number of listeners that should be opened on a broker. The + minimum number of listeners is 1. + reverse_proxy: If True, configure reverse proxy brokers for the cluster. + Otherwise, configure regular proxies for the cluster. + """ + mode.tweak(configurator.proto.cluster) + + assert listener_count > 0 + + cluster = configurator.cluster( + name="itCluster", + nodes=[ + configurator.broker( + name=f"{data_center}{broker}", + tcp_host="localhost", + tcp_port=-1, + listeners=[("BROKER", next(port_allocator))] + + [ + (f"listener{i}", next(port_allocator)) + for i in range(listener_count - 1) + ], + data_center=data_center, + ) + for data_center in ("east", "west") + for broker in ("1", "2") + ], + ) + + add_test_domains(cluster) + + for data_center in ("east", "west"): + configurator.broker( + name=f"{data_center}p", + tcp_host="localhost", + tcp_port=-1, + listeners=[ + (f"listener{i}", next(port_allocator)) for i in range(listener_count) + ], + data_center=data_center, + ).proxy(cluster, reverse=reverse_proxy) + + +multi_interface_cluster_params = [ + pytest.param( + functools.partial(multi_interface_cluster_config, mode=mode, listener_count=2), + id=f"multi_interface{mode.suffix}", + marks=[ + pytest.mark.integrationtest, + pytest.mark.pr_integrationtest, + pytest.mark.multi, + *mode.marks, + ], + ) + for mode in Mode.__members__.values() +] + + +@pytest.fixture(params=multi_interface_cluster_params) +def multi_interface(request): + yield from cluster_fixture(request, request.param) + + ############################################################################### # single_node + multi_node cluster diff --git a/src/python/blazingmq/dev/it/process/broker.py b/src/python/blazingmq/dev/it/process/broker.py index 2edace70a..dff93e384 100644 --- a/src/python/blazingmq/dev/it/process/broker.py +++ b/src/python/blazingmq/dev/it/process/broker.py @@ -28,6 +28,12 @@ from pathlib import Path import signal +from typing import Optional, TypeVar +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from blazingmq.dev.it.cluster import Cluster + from blazingmq.dev.it.process import proc import blazingmq.dev.it.process.bmqproc import blazingmq.dev.it.testconstants as tc @@ -46,7 +52,17 @@ def open_non_blocking(path, flags): class Broker(blazingmq.dev.it.process.bmqproc.BMQProcess): - def __init__(self, config: cfg.Broker, cluster, **kwargs): + Self = TypeVar("Self", bound="Broker") + + config: cfg.Broker + cluster: "Cluster" + cluster_name: str + _pid: Optional[int] + _auto_id: itertools.count + last_known_leader: Optional[Self] + last_known_active: Optional[str] + + def __init__(self, config: cfg.Broker, cluster: "Cluster", **kwargs): cwd: Path = kwargs["cwd"] (cwd / "bmqbrkr.ctl").unlink(missing_ok=True) super().__init__( diff --git a/src/python/blazingmq/dev/it/process/client.py b/src/python/blazingmq/dev/it/process/client.py index abe0ef79a..abbf6190a 100644 --- a/src/python/blazingmq/dev/it/process/client.py +++ b/src/python/blazingmq/dev/it/process/client.py @@ -29,7 +29,7 @@ import re import subprocess from pathlib import Path -from typing import Any, Callable, Dict, Optional, List +from typing import Any, Callable, Dict, Optional, List, NamedTuple from blazingmq.dev.it.process import bmqproc from blazingmq.dev.it.process.bmqproc import BMQProcess @@ -38,7 +38,12 @@ from blazingmq.dev.it.util import internal_use, ListContextManager, Queue Message = namedtuple("Message", "guid, uri, correlationId, payload") -CommandResult = namedtuple("CommandResult", "error_code, matches") + + +class CommandResult(NamedTuple): + error_code: int | None + matches: List[re.Match | None] | None + blocktimeout = 15 @@ -335,7 +340,7 @@ def batch_post( ) return res.error_code - def list(self, uri=None, block=None): + def list(self, uri=None, block=None) -> List[Message]: """ Send the 'list' command with the 'uri' argument, if specified. If 'block' is specified and is True, wait for the command @@ -371,7 +376,9 @@ def list(self, uri=None, block=None): return msgs - def confirm(self, uri, guid, block=None, succeed=None, no_except=None): + def confirm( + self, uri, guid, block=None, succeed=None, no_except=None + ) -> int | None: command = _build_command(f'confirm uri="{uri}" guid="{guid}"', {}, {}) with internal_use(self): res = self._command_helper( @@ -424,7 +431,7 @@ def stop_session(self, block=None, **kw): ) return res.error_code - def wait_push_event(self, timeout=blocktimeout, quiet=False): + def wait_push_event(self, timeout=blocktimeout, quiet=False) -> bool: """ Wait until the client receives a 'PUSH' events. Return 'True' if the event was seen within the specified 'timeout'. diff --git a/src/python/blazingmq/dev/it/tweaks/generated.py b/src/python/blazingmq/dev/it/tweaks/generated.py index 7f635a042..26a0ff548 100644 --- a/src/python/blazingmq/dev/it/tweaks/generated.py +++ b/src/python/blazingmq/dev/it/tweaks/generated.py @@ -652,6 +652,27 @@ def __call__(self, value: int) -> Callable: ... heartbeat_interval_ms = HeartbeatIntervalMs() + class Listeners(metaclass=TweakMetaclass): + class Name(metaclass=TweakMetaclass): + + def __call__( + self, value: typing.Union[str, NoneType] + ) -> Callable: ... + + name = Name() + + class Port(metaclass=TweakMetaclass): + + def __call__( + self, value: typing.Union[int, NoneType] + ) -> Callable: ... + + port = Port() + + def __call__(self, value: None) -> Callable: ... + + listeners = Listeners() + def __call__( self, value: typing.Union[ diff --git a/src/python/blazingmq/dev/it/util.py b/src/python/blazingmq/dev/it/util.py index c4bc123cf..1aa37b798 100644 --- a/src/python/blazingmq/dev/it/util.py +++ b/src/python/blazingmq/dev/it/util.py @@ -26,6 +26,12 @@ import string import time +from typing import List, Generic, TypeVar +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from blazingmq.dev.it.process.client import Client + def random_string(len): letters = string.ascii_lowercase @@ -114,7 +120,7 @@ class Queue: action is to close the queue (if it has not yet been explicitly closed). """ - def __init__(self, client, uri, flags, **kw): + def __init__(self, client: "Client", uri: str, flags: List[str], **kw): """Open the queue specified by 'uri' via the specified 'client, using the specified 'flags'. """ @@ -139,7 +145,7 @@ def post(self, *args, **kwargs): def list(self, *args, **kwargs): return self.client.list(self.uri, *args, **kwargs) - def confirm(self, *args, **kwargs): + def confirm(self, *args, **kwargs) -> int | None: return self.client.confirm(self.uri, *args, **kwargs) def configure(self, *args, **kwargs): @@ -151,7 +157,10 @@ def close(self, *args, **kwargs): return rc -class ListContextManager(list): +_T = TypeVar("_T") + + +class ListContextManager(list[_T]): def __enter__(self): return self diff --git a/src/python/blazingmq/schemas/mqbcfg.py b/src/python/blazingmq/schemas/mqbcfg.py index 35d9b2c41..547c6cca0 100644 --- a/src/python/blazingmq/schemas/mqbcfg.py +++ b/src/python/blazingmq/schemas/mqbcfg.py @@ -971,18 +971,14 @@ class TcpClusterNodeConnection: @dataclass -class TcpInterfaceConfig: - """lowWatermark.........: - - highWatermark........: - Watermarks used for channels with a client or proxy. - nodeLowWatermark.....: - nodeHighWatermark....: - Reduced watermarks for communication between cluster nodes where - BlazingMQ maintains its own cache. - heartbeatIntervalMs..: - How often (in milliseconds) to check if the channel received data, - and emit heartbeat. 0 to globally disable. +class TcpInterfaceListener: + """This type describes the information needed for the broker to open a TCP + listener. + + name.................: + A name to associate this listener to. + port.................: + The port this listener will accept connections on. """ name: Optional[str] = field( @@ -1001,69 +997,6 @@ class TcpInterfaceConfig: "required": True, }, ) - io_threads: Optional[int] = field( - default=None, - metadata={ - "name": "ioThreads", - "type": "Element", - "namespace": "http://bloomberg.com/schemas/mqbcfg", - "required": True, - }, - ) - max_connections: int = field( - default=10000, - metadata={ - "name": "maxConnections", - "type": "Element", - "namespace": "http://bloomberg.com/schemas/mqbcfg", - "required": True, - }, - ) - low_watermark: Optional[int] = field( - default=None, - metadata={ - "name": "lowWatermark", - "type": "Element", - "namespace": "http://bloomberg.com/schemas/mqbcfg", - "required": True, - }, - ) - high_watermark: Optional[int] = field( - default=None, - metadata={ - "name": "highWatermark", - "type": "Element", - "namespace": "http://bloomberg.com/schemas/mqbcfg", - "required": True, - }, - ) - node_low_watermark: int = field( - default=1024, - metadata={ - "name": "nodeLowWatermark", - "type": "Element", - "namespace": "http://bloomberg.com/schemas/mqbcfg", - "required": True, - }, - ) - node_high_watermark: int = field( - default=2048, - metadata={ - "name": "nodeHighWatermark", - "type": "Element", - "namespace": "http://bloomberg.com/schemas/mqbcfg", - "required": True, - }, - ) - heartbeat_interval_ms: int = field( - default=3000, - metadata={ - "name": "heartbeatIntervalMs", - "type": "Element", - "namespace": "http://bloomberg.com/schemas/mqbcfg", - "required": True, - }, - ) @dataclass @@ -1226,26 +1159,6 @@ class LogController: ) -@dataclass -class NetworkInterfaces: - heartbeats: Optional[Heartbeat] = field( - default=None, - metadata={ - "type": "Element", - "namespace": "http://bloomberg.com/schemas/mqbcfg", - "required": True, - }, - ) - tcp_interface: Optional[TcpInterfaceConfig] = field( - default=None, - metadata={ - "name": "tcpInterface", - "type": "Element", - "namespace": "http://bloomberg.com/schemas/mqbcfg", - }, - ) - - @dataclass class PartitionConfig: """Type representing the configuration for the storage layer of a cluster. @@ -1395,6 +1308,116 @@ class StatPluginConfigPrometheus: ) +@dataclass +class TcpInterfaceConfig: + """name.................: + + The name of the TCP session manager. + port.................: + (Deprecated) The port to receive connections. + lowWatermark.........: + highWatermark........: + Watermarks used for channels with a client or proxy. + nodeLowWatermark.....: + nodeHighWatermark....: + Reduced watermarks for communication between cluster nodes where + BlazingMQ maintains its own cache. + heartbeatIntervalMs..: + How often (in milliseconds) to check if the channel received data, + and emit heartbeat. 0 to globally disable. + listeners: + A list of listener interfaces to receive TCP connections from. When non-empty + this option overrides the listener specified by port. + """ + + name: Optional[str] = field( + default=None, + metadata={ + "type": "Element", + "namespace": "http://bloomberg.com/schemas/mqbcfg", + "required": True, + }, + ) + port: Optional[int] = field( + default=None, + metadata={ + "type": "Element", + "namespace": "http://bloomberg.com/schemas/mqbcfg", + "required": True, + }, + ) + io_threads: Optional[int] = field( + default=None, + metadata={ + "name": "ioThreads", + "type": "Element", + "namespace": "http://bloomberg.com/schemas/mqbcfg", + "required": True, + }, + ) + max_connections: int = field( + default=10000, + metadata={ + "name": "maxConnections", + "type": "Element", + "namespace": "http://bloomberg.com/schemas/mqbcfg", + "required": True, + }, + ) + low_watermark: Optional[int] = field( + default=None, + metadata={ + "name": "lowWatermark", + "type": "Element", + "namespace": "http://bloomberg.com/schemas/mqbcfg", + "required": True, + }, + ) + high_watermark: Optional[int] = field( + default=None, + metadata={ + "name": "highWatermark", + "type": "Element", + "namespace": "http://bloomberg.com/schemas/mqbcfg", + "required": True, + }, + ) + node_low_watermark: int = field( + default=1024, + metadata={ + "name": "nodeLowWatermark", + "type": "Element", + "namespace": "http://bloomberg.com/schemas/mqbcfg", + "required": True, + }, + ) + node_high_watermark: int = field( + default=2048, + metadata={ + "name": "nodeHighWatermark", + "type": "Element", + "namespace": "http://bloomberg.com/schemas/mqbcfg", + "required": True, + }, + ) + heartbeat_interval_ms: int = field( + default=3000, + metadata={ + "name": "heartbeatIntervalMs", + "type": "Element", + "namespace": "http://bloomberg.com/schemas/mqbcfg", + "required": True, + }, + ) + listeners: List[TcpInterfaceListener] = field( + default_factory=list, + metadata={ + "type": "Element", + "namespace": "http://bloomberg.com/schemas/mqbcfg", + }, + ) + + @dataclass class ClusterNode: """Type representing the configuration of a node in a cluster. @@ -1470,6 +1493,26 @@ class DispatcherConfig: ) +@dataclass +class NetworkInterfaces: + heartbeats: Optional[Heartbeat] = field( + default=None, + metadata={ + "type": "Element", + "namespace": "http://bloomberg.com/schemas/mqbcfg", + "required": True, + }, + ) + tcp_interface: Optional[TcpInterfaceConfig] = field( + default=None, + metadata={ + "name": "tcpInterface", + "type": "Element", + "namespace": "http://bloomberg.com/schemas/mqbcfg", + }, + ) + + @dataclass class ReversedClusterConnection: """Type representing the configuration for remote cluster connections.. @@ -1793,7 +1836,7 @@ class StatsConfig: @dataclass class AppConfig: - """Top level typ for the broker's configuration. + """Top level type for the broker's configuration. brokerInstanceName...: name of the broker instance brokerVersion........: version of the broker From 8893588986fa357d85892aa8f459db15cad1f607 Mon Sep 17 00:00:00 2001 From: Dmitrii Petukhov Date: Wed, 30 Oct 2024 16:56:54 +0200 Subject: [PATCH 10/17] CI: Collect broker logs (#488) Signed-off-by: Dmitrii Petukhov --- .github/workflows/build.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 5c3b13913..7944ba810 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -221,6 +221,14 @@ jobs: --reruns=3 \ -n 4 -v + - name: Upload failure-logs as artifacts + if: failure() + uses: actions/upload-artifact@v4 + with: + name: failure_logs_${{ matrix.mode }}_${{ matrix.cluster }} + path: ${{ github.workspace }}/src/integration-tests/failure-logs + retention-days: 5 + fuzz_tests_ubuntu: name: Fuzz test [${{ matrix.request }}] strategy: From a41309d0b21bc412fd58451e84c13088a8fd34ee Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Wed, 30 Oct 2024 18:11:32 +0200 Subject: [PATCH 11/17] Feat[MQB]: Enhance filebackedstorage/inmemorystorage alarm log with app subscription info (#470) --- .../mqb/mqbblp/mqbblp_rootqueueengine.cpp | 203 +++++++++++------- .../mqb/mqbblp/mqbblp_rootqueueengine.h | 15 ++ src/groups/mqb/mqbi/mqbi_queueengine.cpp | 7 + src/groups/mqb/mqbi/mqbi_queueengine.h | 8 + .../mqb/mqbs/mqbs_filebackedstorage.cpp | 29 ++- src/groups/mqb/mqbs/mqbs_filebackedstorage.h | 6 + src/groups/mqb/mqbs/mqbs_inmemorystorage.cpp | 29 ++- src/groups/mqb/mqbs/mqbs_inmemorystorage.h | 6 + src/groups/mqb/mqbu/mqbu_capacitymeter.cpp | 18 +- src/groups/mqb/mqbu/mqbu_capacitymeter.h | 28 ++- src/groups/mqb/mqbu/mqbu_capacitymeter.t.cpp | 84 ++++++++ src/integration-tests/test_alarms.py | 45 ++++ 12 files changed, 383 insertions(+), 95 deletions(-) diff --git a/src/groups/mqb/mqbblp/mqbblp_rootqueueengine.cpp b/src/groups/mqb/mqbblp/mqbblp_rootqueueengine.cpp index 0bfaa6726..39b5d038a 100644 --- a/src/groups/mqb/mqbblp/mqbblp_rootqueueengine.cpp +++ b/src/groups/mqb/mqbblp/mqbblp_rootqueueengine.cpp @@ -1619,6 +1619,131 @@ void RootQueueEngine::onTimer(bsls::Types::Int64 currentTimer) d_consumptionMonitor.onTimer(currentTimer); } +bsl::ostream& +RootQueueEngine::logAppSubscriptionInfo(bsl::ostream& stream, + const mqbu::StorageKey& appKey) const +{ + // executed by the *QUEUE DISPATCHER* thread + + // PRECONDITIONS + BSLS_ASSERT_SAFE(d_queueState_p->queue()->dispatcher()->inDispatcherThread( + d_queueState_p->queue())); + + // Get AppState by appKey. + Apps::const_iterator cItApp = d_apps.findByKey2(AppKeyCount(appKey, 0)); + if (cItApp == d_apps.end()) { + BALL_LOG_WARN << "No app found for appKey: " << appKey; + stream << "\nSubscription info: no app found for appKey: " << appKey; + return stream; // RETURN + } + + const AppStateSp& app = cItApp->value(); + return logAppSubscriptionInfo(stream, app); +} + +bsl::ostream& +RootQueueEngine::logAppSubscriptionInfo(bsl::ostream& stream, + const AppStateSp& appState) const +{ + mqbi::Storage* const storage = d_queueState_p->storage(); + + // Log un-delivered messages info + stream << "\nFor appId: " << appState->appId() << "\n\n"; + stream << "Put aside list size: " + << bmqu::PrintUtil::prettyNumber(static_cast( + appState->putAsideListSize())) + << '\n'; + stream << "Redelivery list size: " + << bmqu::PrintUtil::prettyNumber(static_cast( + appState->redeliveryListSize())) + << '\n'; + stream << "Number of messages: " + << bmqu::PrintUtil::prettyNumber( + storage->numMessages(appState->appKey())) + << '\n'; + stream << "Number of bytes: " + << bmqu::PrintUtil::prettyBytes( + storage->numBytes(appState->appKey())) + << "\n\n"; + + // Log consumer subscriptions + mqbblp::Routers::QueueRoutingContext& routingContext = + appState->routing()->d_queue; + mqbcmd::Routing routing; + routingContext.loadInternals(&routing); + const bsl::vector& subscrGroups = + routing.subscriptionGroups(); + if (!subscrGroups.empty()) { + // Limit to log only k_EXPR_NUM_LIMIT expressions + static const size_t k_EXPR_NUM_LIMIT = 50; + if (subscrGroups.size() > k_EXPR_NUM_LIMIT) { + stream << "First " << k_EXPR_NUM_LIMIT + << " of consumer subscription expressions: \n"; + } + else { + stream << "Consumer subscription expressions: \n"; + } + + size_t exprNum = 0; + for (bsl::vector::const_iterator cIt = + subscrGroups.begin(); + cIt != subscrGroups.end() && exprNum < k_EXPR_NUM_LIMIT; + ++cIt, ++exprNum) { + if (cIt->expression().empty()) { + stream << "\n"; + } + else { + stream << cIt->expression() << '\n'; + } + } + stream << '\n'; + } + + // Log the first (oldest) message in a put aside list and its properties + if (!appState->putAsideList().empty()) { + bslma::ManagedPtr storageIt_mp; + mqbi::StorageResult::Enum rc = storage->getIterator( + &storageIt_mp, + appState->appKey(), + appState->putAsideList().first()); + if (rc == mqbi::StorageResult::e_SUCCESS) { + // Log timestamp + stream << "Oldest message in the 'Put aside' list:\n"; + mqbcmd::Result result; + mqbs::StoragePrintUtil::listMessage(&result.makeMessage(), + storage, + *storageIt_mp); + mqbcmd::HumanPrinter::print(stream, result); + stream << '\n'; + // Log message properties + const bsl::shared_ptr& appData = + storageIt_mp->appData(); + const bmqp::MessagePropertiesInfo& logic = + storageIt_mp->attributes().messagePropertiesInfo(); + bmqp::MessageProperties properties; + int ret = properties.streamIn(*appData, logic.isExtended()); + if (!ret) { + stream << "Message Properties: " << properties << '\n'; + } + else { + BALL_LOG_WARN << "Failed to streamIn MessageProperties, rc = " + << rc; + stream << "Message Properties: Failed to acquire [rc: " << rc + << "]\n"; + } + } + else { + BALL_LOG_WARN << "Failed to get storage iterator for GUID: " + << appState->putAsideList().first() + << ", rc = " << rc; + stream << "'Put aside' list: Failed to acquire [rc: " << rc + << "]\n"; + } + } + + return stream; +} + bool RootQueueEngine::logAlarmCb(const mqbu::StorageKey& appKey, bool enableLog) const { @@ -1711,83 +1836,7 @@ bool RootQueueEngine::logAlarmCb(const mqbu::StorageKey& appKey, << " consumers." << ss.str() << '\n'; // Log un-delivered messages info - out << "\nFor appId: " << app->appId() << '\n'; - out << "Put aside list size: " << app->putAsideListSize() << '\n'; - out << "Redelivery list size: " << app->redeliveryListSize() << '\n'; - out << "Number of messages: " << storage->numMessages(appKey) << '\n'; - out << "Number of bytes: " << storage->numBytes(appKey) << "\n\n"; - - // Log consumer subscriptions - mqbblp::Routers::QueueRoutingContext& routingContext = - app->routing()->d_queue; - mqbcmd::Routing routing; - routingContext.loadInternals(&routing); - const bsl::vector& subscrGroups = - routing.subscriptionGroups(); - - // Limit to log only k_EXPR_NUM_LIMIT expressions - static const size_t k_EXPR_NUM_LIMIT = 50; - ss.reset(); - size_t exprNum = 0; - for (bsl::vector::const_iterator cIt = - subscrGroups.begin(); - cIt != subscrGroups.end() && exprNum < k_EXPR_NUM_LIMIT; - ++cIt) { - if (!cIt->expression().empty()) { - ss << cIt->expression() << '\n'; - ++exprNum; - } - } - if (exprNum) { - if (exprNum == k_EXPR_NUM_LIMIT) { - out << "First " << k_EXPR_NUM_LIMIT - << " of consumer subscription expressions: "; - } - else { - out << "Consumer subscription expressions: "; - } - out << '\n' << ss.str() << '\n'; - } - - // Log the first (oldest) message in a put aside list and its properties - if (!app->putAsideList().empty()) { - bslma::ManagedPtr storageIt_mp; - mqbi::StorageResult::Enum rc = storage->getIterator( - &storageIt_mp, - appKey, - app->putAsideList().first()); - if (rc == mqbi::StorageResult::e_SUCCESS) { - // Log timestamp - out << "Oldest message in the 'Put aside' list:\n"; - mqbcmd::Result result; - mqbs::StoragePrintUtil::listMessage(&result.makeMessage(), - storage, - *storageIt_mp); - mqbcmd::HumanPrinter::print(out, result); - out << '\n'; - // Log message properties - const bsl::shared_ptr& appData = - storageIt_mp->appData(); - const bmqp::MessagePropertiesInfo& logic = - storageIt_mp->attributes().messagePropertiesInfo(); - bmqp::MessageProperties properties; - int ret = properties.streamIn(*appData, logic.isExtended()); - if (!ret) { - out << "Message Properties: " << properties << '\n'; - } - else { - BALL_LOG_WARN << "Failed to streamIn MessageProperties, rc = " - << rc; - out << "Message Properties: Failed to acquire [rc: " << rc - << "]\n"; - } - } - else { - BALL_LOG_WARN << "Failed to get storage iterator for GUID: " - << app->putAsideList().first() << ", rc = " << rc; - out << "'Put aside' list: Failed to acquire [rc: " << rc << "]\n"; - } - } + logAppSubscriptionInfo(out, app); // Print the 10 oldest messages in the queue static const int k_NUM_MSGS = 10; diff --git a/src/groups/mqb/mqbblp/mqbblp_rootqueueengine.h b/src/groups/mqb/mqbblp/mqbblp_rootqueueengine.h index f8bd0b626..7e1fd8fb6 100644 --- a/src/groups/mqb/mqbblp/mqbblp_rootqueueengine.h +++ b/src/groups/mqb/mqbblp/mqbblp_rootqueueengine.h @@ -458,6 +458,21 @@ class RootQueueEngine BSLS_KEYWORD_FINAL : public mqbi::QueueEngine { /// THREAD: This method is called from the Queue's dispatcher thread. virtual void loadInternals(mqbcmd::QueueEngine* out) const BSLS_KEYWORD_OVERRIDE; + + /// Log appllication subscription info for the specified `appKey` into the + /// specified `stream`. + /// + /// THREAD: This method is called from the Queue's + /// dispatcher thread. + virtual bsl::ostream& logAppSubscriptionInfo( + bsl::ostream& stream, + const mqbu::StorageKey& appKey) const BSLS_KEYWORD_OVERRIDE; + + private: + /// Log appllication subscription info for the specified `appState` into + /// the specified `stream`. + bsl::ostream& logAppSubscriptionInfo(bsl::ostream& stream, + const AppStateSp& appState) const; }; } // close package namespace diff --git a/src/groups/mqb/mqbi/mqbi_queueengine.cpp b/src/groups/mqb/mqbi/mqbi_queueengine.cpp index b26c4a293..aeb77a513 100644 --- a/src/groups/mqb/mqbi/mqbi_queueengine.cpp +++ b/src/groups/mqb/mqbi/mqbi_queueengine.cpp @@ -63,5 +63,12 @@ void QueueEngine::unregisterStorage( // NOTHING } +bsl::ostream& +QueueEngine::logAppSubscriptionInfo(bsl::ostream& stream, + const mqbu::StorageKey& appKey) const +{ + return stream; +}; + } // close package namespace } // close enterprise namespace diff --git a/src/groups/mqb/mqbi/mqbi_queueengine.h b/src/groups/mqb/mqbi/mqbi_queueengine.h index 14a77e13a..b2ad21082 100644 --- a/src/groups/mqb/mqbi/mqbi_queueengine.h +++ b/src/groups/mqb/mqbi/mqbi_queueengine.h @@ -246,6 +246,14 @@ class QueueEngine { /// Load into the specified `out` object the internal information about /// this queue engine and associated queue handles. virtual void loadInternals(mqbcmd::QueueEngine* out) const = 0; + + /// Log appllication subscription info for the specified `appKey` into the + /// specified `stream`. + /// + /// THREAD: This method is called from the Queue's dispatcher thread. + virtual bsl::ostream& + logAppSubscriptionInfo(bsl::ostream& stream, + const mqbu::StorageKey& appKey) const; }; } // close package namespace diff --git a/src/groups/mqb/mqbs/mqbs_filebackedstorage.cpp b/src/groups/mqb/mqbs/mqbs_filebackedstorage.cpp index c6c31923d..247b14031 100644 --- a/src/groups/mqb/mqbs/mqbs_filebackedstorage.cpp +++ b/src/groups/mqb/mqbs/mqbs_filebackedstorage.cpp @@ -118,9 +118,14 @@ FileBackedStorage::FileBackedStorage( this, allocatorStore ? allocatorStore->get("VirtualHandles") : d_allocator_p) , d_ttlSeconds(config.messageTtl()) -, d_capacityMeter("queue [" + queueUri.asString() + "]", - parentCapacityMeter, - allocator) +, d_capacityMeter( + "queue [" + queueUri.asString() + "]", + parentCapacityMeter, + allocator, + bdlf::BindUtil::bind(&FileBackedStorage::logAppsSubscriptionInfoCb, + this, + bdlf::PlaceHolders::_1) // stream + ) , d_handles(bsls::TimeInterval() .addMilliseconds(config.deduplicationTimeMs()) .totalNanoseconds(), @@ -1020,5 +1025,23 @@ void FileBackedStorage::clearSelection() d_currentlyAutoConfirming = bmqt::MessageGUID(); } +bsl::ostream& +FileBackedStorage::logAppsSubscriptionInfoCb(bsl::ostream& stream) const +{ + if (queue()) { + mqbi::Storage::AppInfos appInfos(d_allocator_p); + loadVirtualStorageDetails(&appInfos); + + for (mqbi::Storage::AppInfos::const_iterator cit = appInfos.begin(); + cit != appInfos.end(); + ++cit) { + queue()->queueEngine()->logAppSubscriptionInfo(stream, + cit->second); + } + } + + return stream; +} + } // close package namespace } // close enterprise namespace diff --git a/src/groups/mqb/mqbs/mqbs_filebackedstorage.h b/src/groups/mqb/mqbs/mqbs_filebackedstorage.h index 091f4cfd2..d652764dd 100644 --- a/src/groups/mqb/mqbs/mqbs_filebackedstorage.h +++ b/src/groups/mqb/mqbs/mqbs_filebackedstorage.h @@ -224,6 +224,12 @@ class FileBackedStorage BSLS_KEYWORD_FINAL : public ReplicatedStorage { /// Clear the state created by 'selectForAutoConfirming'. void clearSelection(); + // PRIVATE ACCESSORS + + /// Callback function called by `d_capacityMeter` to log appllications + /// subscription info into the specified `stream`. + bsl::ostream& logAppsSubscriptionInfoCb(bsl::ostream& stream) const; + public: // TRAITS BSLMF_NESTED_TRAIT_DECLARATION(FileBackedStorage, diff --git a/src/groups/mqb/mqbs/mqbs_inmemorystorage.cpp b/src/groups/mqb/mqbs/mqbs_inmemorystorage.cpp index 80e88031e..03f0c5988 100644 --- a/src/groups/mqb/mqbs/mqbs_inmemorystorage.cpp +++ b/src/groups/mqb/mqbs/mqbs_inmemorystorage.cpp @@ -60,9 +60,14 @@ InMemoryStorage::InMemoryStorage(const bmqt::Uri& uri, , d_uri(uri, allocator) , d_partitionId(partitionId) , d_config() -, d_capacityMeter("queue [" + uri.asString() + "]", - parentCapacityMeter, - allocator) +, d_capacityMeter( + "queue [" + uri.asString() + "]", + parentCapacityMeter, + allocator, + bdlf::BindUtil::bind(&InMemoryStorage::logAppsSubscriptionInfoCb, + this, + bdlf::PlaceHolders::_1) // stream + ) , d_items(bsls::TimeInterval() .addMilliseconds(config.deduplicationTimeMs()) .totalNanoseconds(), @@ -601,5 +606,23 @@ bool InMemoryStorage::isStrongConsistency() const return false; } +bsl::ostream& +InMemoryStorage::logAppsSubscriptionInfoCb(bsl::ostream& stream) const +{ + if (queue()) { + mqbi::Storage::AppInfos appInfos(d_allocator_p); + loadVirtualStorageDetails(&appInfos); + + for (mqbi::Storage::AppInfos::const_iterator cit = appInfos.begin(); + cit != appInfos.end(); + ++cit) { + queue()->queueEngine()->logAppSubscriptionInfo(stream, + cit->second); + } + } + + return stream; +} + } // close package namespace } // close enterprise namespace diff --git a/src/groups/mqb/mqbs/mqbs_inmemorystorage.h b/src/groups/mqb/mqbs/mqbs_inmemorystorage.h index 4f4de320d..4da76001a 100644 --- a/src/groups/mqb/mqbs/mqbs_inmemorystorage.h +++ b/src/groups/mqb/mqbs/mqbs_inmemorystorage.h @@ -229,6 +229,12 @@ class InMemoryStorage BSLS_KEYWORD_FINAL : public ReplicatedStorage { /// Not implemented InMemoryStorage& operator=(const InMemoryStorage&) BSLS_KEYWORD_DELETED; + // PRIVATE ACCESSORS + + /// Callback function called by `d_capacityMeter` to log appllications + /// subscription info into the specified `stream`. + bsl::ostream& logAppsSubscriptionInfoCb(bsl::ostream& stream) const; + public: // TRAITS BSLMF_NESTED_TRAIT_DECLARATION(InMemoryStorage, bslma::UsesBslmaAllocator) diff --git a/src/groups/mqb/mqbu/mqbu_capacitymeter.cpp b/src/groups/mqb/mqbu/mqbu_capacitymeter.cpp index f1251f213..b524cda00 100644 --- a/src/groups/mqb/mqbu/mqbu_capacitymeter.cpp +++ b/src/groups/mqb/mqbu/mqbu_capacitymeter.cpp @@ -83,6 +83,10 @@ void CapacityMeter::logOnMonitorStateTransition( switch (stateTransition) { case ResourceUsageMonitorStateTransition::e_HIGH_WATERMARK: case ResourceUsageMonitorStateTransition::e_FULL: { + if (d_logEnhancedStorageInfoCb) { + d_logEnhancedStorageInfoCb(stream); + } + BMQTSK_ALARMLOG_RAW_ALARM(categoryStream.str()) << stream.str() << BMQTSK_ALARMLOG_END; } break; @@ -100,8 +104,9 @@ void CapacityMeter::logOnMonitorStateTransition( } } -CapacityMeter::CapacityMeter(const bsl::string& name, - bslma::Allocator* allocator) +CapacityMeter::CapacityMeter(const bsl::string& name, + bslma::Allocator* allocator, + LogEnhancedStorageInfoCb logEnhancedStorageInfoCb) : d_name(name, allocator) , d_isDisabled(false) , d_parent_p(0) @@ -115,13 +120,15 @@ CapacityMeter::CapacityMeter(const bsl::string& name, , d_nbMessagesReserved(0) , d_nbBytesReserved(0) , d_lock(bsls::SpinLock::s_unlocked) +, d_logEnhancedStorageInfoCb(logEnhancedStorageInfoCb) { // NOTHING } -CapacityMeter::CapacityMeter(const bsl::string& name, - CapacityMeter* parent, - bslma::Allocator* allocator) +CapacityMeter::CapacityMeter(const bsl::string& name, + CapacityMeter* parent, + bslma::Allocator* allocator, + LogEnhancedStorageInfoCb logEnhancedStorageInfoCb) : d_name(name, allocator) , d_isDisabled(false) , d_parent_p(parent) @@ -135,6 +142,7 @@ CapacityMeter::CapacityMeter(const bsl::string& name, , d_nbMessagesReserved(0) , d_nbBytesReserved(0) , d_lock() +, d_logEnhancedStorageInfoCb(logEnhancedStorageInfoCb) { // NOTHING } diff --git a/src/groups/mqb/mqbu/mqbu_capacitymeter.h b/src/groups/mqb/mqbu/mqbu_capacitymeter.h index 0da20f1cb..1db19890c 100644 --- a/src/groups/mqb/mqbu/mqbu_capacitymeter.h +++ b/src/groups/mqb/mqbu/mqbu_capacitymeter.h @@ -151,6 +151,7 @@ #include #include +#include // BDE #include @@ -189,6 +190,11 @@ class CapacityMeter { e_LIMIT_BYTES = 2 // bytes limit was hit }; + // Callback function to log enhanced storage info into the + // specified `stream`. + typedef bsl::function + LogEnhancedStorageInfoCb; + private: // DATA bsl::string d_name; @@ -218,6 +224,10 @@ class CapacityMeter { // SpinLock for synchronization of this // component + LogEnhancedStorageInfoCb d_logEnhancedStorageInfoCb; + // Callback function to log enhanced storage info into the + // specified `stream`. + // FRIENDS friend struct CapacityMeterUtil; @@ -243,16 +253,20 @@ class CapacityMeter { // CREATORS - /// Create a new un-configured object having the specified `name` and - /// using the specified `allocator`. - CapacityMeter(const bsl::string& name, bslma::Allocator* allocator); + /// Create a new un-configured object having the specified `name`, + /// using the specified `allocator` and optionally specified + /// `logEnhancedStorageInfoCb`. + CapacityMeter(const bsl::string& name, + bslma::Allocator* allocator, + LogEnhancedStorageInfoCb logEnhancedStorageInfoCb = 0); /// Create a new un-configured object having the specified `name`, being /// a child of the specified `parent` meter and using the specified - /// `allocator`. - CapacityMeter(const bsl::string& name, - CapacityMeter* parent, - bslma::Allocator* allocator); + /// `allocator` and optionally specified `logEnhancedStorageInfoCb`. + CapacityMeter(const bsl::string& name, + CapacityMeter* parent, + bslma::Allocator* allocator, + LogEnhancedStorageInfoCb logEnhancedStorageInfoCb = 0); // MANIPULATORS diff --git a/src/groups/mqb/mqbu/mqbu_capacitymeter.t.cpp b/src/groups/mqb/mqbu/mqbu_capacitymeter.t.cpp index 58821bc2c..6ef20499b 100644 --- a/src/groups/mqb/mqbu/mqbu_capacitymeter.t.cpp +++ b/src/groups/mqb/mqbu/mqbu_capacitymeter.t.cpp @@ -32,6 +32,16 @@ using namespace BloombergLP; using namespace bsl; +// ============================================================================ +// HELPERS +// ---------------------------------------------------------------------------- + +bsl::ostream& logEnhancedStorageInfoCb(bsl::ostream& stream) +{ + stream << "Test enhanced storage Info"; + return stream; +} + // ============================================================================ // TESTS // ---------------------------------------------------------------------------- @@ -229,6 +239,79 @@ static void test2_logStateChange() } } +static void test3_enhancedLog() +// ------------------------------------------------------------------------ +// ENHANCED ALARM LOG +// +// Concerns: +// Ensure that enhanced alarm log is printed if callback is passed. +// +// Plan: +// 1. Pass LogEnhancedStorageInfoCb callback during initialization +// 2. Set resources to the high watermark and ensure the enhanced +// error message was logged. +// +// Testing: +// logging +// ------------------------------------------------------------------------ +{ + bmqtst::TestHelper::printTestName("ENHANCED ALARM LOG"); + + // Set resource to the high watermark, it should log one + PV("STATE - HIGH WATERMARK"); + + s_ignoreCheckDefAlloc = true; + // Logging infrastructure allocates using the default allocator, and + // that logging is beyond the control of this function. + + const bsls::Types::Int64 k_MSGS_LIMIT = 10; + const double k_MSGS_THRESHOLD = 0.5; + const bsls::Types::Int64 k_MSGS_HIGH_WATERMARK_VALUE = k_MSGS_LIMIT * + k_MSGS_THRESHOLD; + const bsls::Types::Int64 k_BYTES_LIMIT = 1024; + const double k_BYTES_THRESHOLD = 0.8; + const bsls::Types::Int64 k_BYTES_HIGH_WATERMARK_VALUE = k_BYTES_LIMIT * + k_BYTES_THRESHOLD; + + bmqtst::ScopedLogObserver observer(ball::Severity::WARN, s_allocator_p); + mqbu::CapacityMeter capacityMeter( + "dummy", + s_allocator_p, + bdlf::BindUtil::bind(&logEnhancedStorageInfoCb, + bdlf::PlaceHolders::_1) // stream + ); + capacityMeter.setLimits(k_MSGS_LIMIT, k_BYTES_LIMIT); + capacityMeter.setWatermarkThresholds(k_MSGS_THRESHOLD, k_BYTES_THRESHOLD); + + bsls::Types::Int64 nbMessagesAvailable; + bsls::Types::Int64 nbBytesAvailable; + capacityMeter.reserve(&nbMessagesAvailable, + &nbBytesAvailable, + k_MSGS_HIGH_WATERMARK_VALUE, + 10); + BSLS_ASSERT_OPT(nbMessagesAvailable == k_MSGS_HIGH_WATERMARK_VALUE); + BSLS_ASSERT_OPT(nbBytesAvailable == 10); + + ASSERT(observer.records().empty()); + + capacityMeter.commit(k_MSGS_HIGH_WATERMARK_VALUE, 10); + + ASSERT_EQ(observer.records().size(), 1U); + + const ball::Record& record = observer.records()[0]; + ASSERT_EQ(record.fixedFields().severity(), ball::Severity::ERROR); + + ASSERT(bmqtst::ScopedLogObserverUtil::recordMessageMatch( + record, + "ALARM \\[CAPACITY_STATE_HIGH_WATERMARK\\]", + s_allocator_p)); + // Check log from callback + ASSERT(bmqtst::ScopedLogObserverUtil::recordMessageMatch( + record, + "Test enhanced storage Info", + s_allocator_p)); +} + // ============================================================================ // MAIN PROGRAM // ---------------------------------------------------------------------------- @@ -241,6 +324,7 @@ int main(int argc, char* argv[]) case 0: case 2: test2_logStateChange(); break; case 1: test1_breathingTest(); break; + case 3: test3_enhancedLog(); break; default: { cerr << "WARNING: CASE '" << _testCase << "' NOT FOUND." << endl; s_testStatus = -1; diff --git a/src/integration-tests/test_alarms.py b/src/integration-tests/test_alarms.py index 3d296aa21..1b80b008f 100644 --- a/src/integration-tests/test_alarms.py +++ b/src/integration-tests/test_alarms.py @@ -115,3 +115,48 @@ def test_alarms_subscription_mismatch(cluster: Cluster): assert leader.capture(r"x == 1") assert leader.capture(r"Oldest message in the 'Put aside' list:") assert leader.capture(r"Message Properties: \[ x \(INT32\) = 0 \]") + + +@tweak.domain.storage.queue_limits.messages(2) +def test_capacity_alarm_subscription_mismatch(cluster: Cluster): + """ + Test broker capacity meter ALARM log content for producer/consumer subscription expression mismatch (put aside list is not empty). + """ + + leader = cluster.last_known_leader + proxy = next(cluster.proxy_cycle()) + + producer = proxy.create_client("producer") + producer.open(tc.URI_PRIORITY, flags=["write"], succeed=True) + + consumer = proxy.create_client("consumer") + consumer.open( + tc.URI_PRIORITY, + flags=["read"], + succeed=True, + subscriptions=[{"expression": "x == 1"}], + ) + + producer.post( + tc.URI_PRIORITY, + ["msg"], + succeed=True, + wait_ack=True, + messageProperties=[{"name": "x", "value": "0", "type": "E_INT"}], + ) + + producer.post( + tc.URI_PRIORITY, + ["msg"], + succeed=True, + wait_ack=True, + messageProperties=[{"name": "y", "value": "0", "type": "E_INT"}], + ) + + assert leader.alarms("CAPACITY_STATE_FULL", 1) + assert leader.capture(r"Put aside list size: 1") + assert leader.capture(r"Redelivery list size: 0") + assert leader.capture(r"Consumer subscription expressions:") + assert leader.capture(r"x == 1") + assert leader.capture(r"Oldest message in the 'Put aside' list:") + assert leader.capture(r"Message Properties: \[ x \(INT32\) = 0 \]") From 8d8a0e6019d14d15bebbd6023da533aa587c3835 Mon Sep 17 00:00:00 2001 From: Emelia Lei Date: Tue, 29 Oct 2024 13:09:41 -0400 Subject: [PATCH 12/17] add log for response message Signed-off-by: Emelia Lei --- src/groups/mqb/mqba/mqba_adminsession.cpp | 2 + src/integration-tests/test_admin_res_log.py | 154 ++++++++++++++++++++ 2 files changed, 156 insertions(+) create mode 100644 src/integration-tests/test_admin_res_log.py diff --git a/src/groups/mqb/mqba/mqba_adminsession.cpp b/src/groups/mqb/mqba/mqba_adminsession.cpp index 85e31ce28..2bf5caea2 100644 --- a/src/groups/mqb/mqba/mqba_adminsession.cpp +++ b/src/groups/mqb/mqba/mqba_adminsession.cpp @@ -206,6 +206,8 @@ void AdminSession::finalizeAdminCommand( response.choice().adminCommandResponse().text() = commandExecResults; + BALL_LOG_INFO << description() << ": Send response message: " << response; + int rc = d_state.d_schemaEventBuilder.setMessage( response, bmqp::EventType::e_CONTROL); diff --git a/src/integration-tests/test_admin_res_log.py b/src/integration-tests/test_admin_res_log.py new file mode 100644 index 000000000..57e9d71a8 --- /dev/null +++ b/src/integration-tests/test_admin_res_log.py @@ -0,0 +1,154 @@ +# Copyright 2024 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. + +""" +This suite of test cases verifies that only the node that the admin +connects to send the response back to the admin, and the corresponding +response is logged. +""" + +import blazingmq.dev.it.testconstants as tc +from blazingmq.dev.it.fixtures import ( + multi_node, + Cluster, +) +from blazingmq.dev.it.process.admin import AdminClient +from blazingmq.dev.it.process.client import Client + +TIMEOUT = 1 + + +def test_adminsession_res_log_stat(multi_node: Cluster): + """ + Test: STAT SHOW command: response message only generate on the node itself + """ + + admin = AdminClient() + + # find the first two nodes which are not the known leader + leader = multi_node.nodes()[0].last_known_leader + replicas = multi_node.nodes(exclude=leader) + member1 = replicas[0] + member2 = replicas[1] + + # connect and send request to primary + admin.connect(leader.config.host, int(leader.config.port)) + res = admin.send_admin(f"STAT SHOW") + + assert ":::::::::: :::::::::: DOMAINQUEUES >>" in res + + assert leader.capture("Send response message", TIMEOUT) + assert not member1.capture("Send response message", TIMEOUT) + assert not member2.capture("Send response message", TIMEOUT) + + admin.stop() + + # connect and send request to member1 + admin.connect(member1.config.host, int(member1.config.port)) + res = admin.send_admin(f"STAT SHOW") + + assert ":::::::::: :::::::::: DOMAINQUEUES >>" in res + + assert member1.capture("Send response message", TIMEOUT) + assert not leader.capture("Send response message", TIMEOUT) + assert not member2.capture("Send response message", TIMEOUT) + + admin.stop() + + +def test_adminsession_res_log_purge(multi_node: Cluster): + """ + Test: PURGE command: response message only generate on the node itself + """ + + admin = AdminClient() + + # find the first two nodes which are not the known leader + leader = multi_node.nodes()[0].last_known_leader + replicas = multi_node.nodes(exclude=leader) + member1 = replicas[0] + member2 = replicas[1] + + # open a domain + proxies = multi_node.proxy_cycle() + proxy = next(proxies) + producer: Client = proxy.create_client("producer") + producer.open(tc.URI_FANOUT, flags=["write,ack"], succeed=True) + + # connect and send request to primary + admin.connect(leader.config.host, int(leader.config.port)) + res = admin.send_admin(f"DOMAINS DOMAIN {tc.DOMAIN_FANOUT} PURGE") + + assert "Purged" in res + + assert leader.capture("Send response message", TIMEOUT) + assert not member1.capture("Send response message", TIMEOUT) + assert not member2.capture("Send response message", TIMEOUT) + + admin.stop() + + # connect and send request to member1 + admin.connect(member1.config.host, int(member1.config.port)) + res = admin.send_admin(f"DOMAINS DOMAIN {tc.DOMAIN_FANOUT} PURGE") + + assert "Purged" in res + + assert member1.capture("Send response message", TIMEOUT) + assert not leader.capture("Send response message", TIMEOUT) + assert not member2.capture("Send response message", TIMEOUT) + + admin.stop() + + +def test_adminsession_res_log_reconfigure(multi_node: Cluster): + """ + Test: RECONFIGURE command: response message only generate on the node itself + """ + + admin = AdminClient() + + # find the first two nodes which are not the known leader + leader = multi_node.nodes()[0].last_known_leader + replicas = multi_node.nodes(exclude=leader) + member1 = replicas[0] + member2 = replicas[1] + + num_nodes = len(multi_node.nodes()) + + # connect and send request to primary + admin.connect(leader.config.host, int(leader.config.port)) + res = admin.send_admin(f"DOMAINS RECONFIGURE {tc.DOMAIN_FANOUT}") + + success_count = res.split().count("SUCCESS") + assert success_count == num_nodes + + assert leader.capture("Send response message", TIMEOUT) + assert not member1.capture("Send response message", TIMEOUT) + assert not member2.capture("Send response message", TIMEOUT) + + admin.stop() + + # connect and send request to member1 + admin.connect(member1.config.host, int(member1.config.port)) + res = admin.send_admin(f"DOMAINS RECONFIGURE {tc.DOMAIN_FANOUT}") + + success_count = res.split().count("SUCCESS") + assert success_count == num_nodes + + assert member1.capture("Send response message", TIMEOUT) + assert not leader.capture("Send response message", TIMEOUT) + assert not member2.capture("Send response message", TIMEOUT) + + admin.stop() From 850b8d09211aed23ce0ce40e9bfd51e06bbec718 Mon Sep 17 00:00:00 2001 From: "Patrick M. Niedzielski" Date: Wed, 30 Oct 2024 15:06:50 -0400 Subject: [PATCH 13/17] Docs: Fix `bmqa_mocksession` doxygen failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `bqma_mocksession` component does not generate docs due to a Markdown syntax error: ``` /…/blazingmq/src/groups/bmq/bmqa/bmqa_mocksession.h:1520: warning: reached end of file while inside a '```' block! The command that should end the block seems to be missing! ``` The syntax error prevents any component-level documentation from being generated for this file. This patch fixes the syntax error, which then allows the component-level documentation to be built. Signed-off-by: Patrick M. Niedzielski --- src/groups/bmq/bmqa/bmqa_mocksession.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/groups/bmq/bmqa/bmqa_mocksession.h b/src/groups/bmq/bmqa/bmqa_mocksession.h index 4f449b9fa..0e1771c99 100644 --- a/src/groups/bmq/bmqa/bmqa_mocksession.h +++ b/src/groups/bmq/bmqa/bmqa_mocksession.h @@ -393,7 +393,7 @@ /// `emitting` on the @ref BMQA_EXPECT_CALL macro in synchronous mode is /// meaningless. /// -///``` +/// ``` /// void unitTest() /// { /// // MockSession created without an eventHandler. From 15cbaa576e23539809579a6231cd17ca0ca5a11d Mon Sep 17 00:00:00 2001 From: "Patrick M. Niedzielski" Date: Wed, 30 Oct 2024 12:31:31 -0400 Subject: [PATCH 14/17] CI: Add job to build API documentation on push to `main` Signed-off-by: Patrick M. Niedzielski --- .github/workflows/documentation.yaml | 51 ++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 .github/workflows/documentation.yaml diff --git a/.github/workflows/documentation.yaml b/.github/workflows/documentation.yaml new file mode 100644 index 000000000..17d41eccb --- /dev/null +++ b/.github/workflows/documentation.yaml @@ -0,0 +1,51 @@ +name: Generate documentation + +on: + push: + branches: + - main + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + documentation-main: + name: Build Doxygen documentation on `main` + + runs-on: ubuntu-latest + + permissions: + # Let the default GITHUB_TOKEN commit and push. + contents: write + + steps: + - name: Checkout `main` + uses: actions/checkout@v4 + + - name: Clear out `docs/` subdirectory + run: rm -rf docs + + - name: Checkout `gh-pages` into `docs/` + uses: actions/checkout@v4 + with: + path: docs + ref: gh-pages + + - name: Set up dependencies + run: | + sudo apt-get update + sudo apt-get install -qy doxygen + + - name: Build documentation + # Best way to pass Doxygen config overrides on the command line is + # using stdin. + run: | + ( cat Doxyfile ; echo "PROJECT_NUMBER=${{ github.sha }}" ) | doxygen - + + - name: Commit new API documentation to `gh-pages` + uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: Update docs for `main`@${{ github.sha }} + repository: docs From dcfa643ad273587e56240418b04ff3aa3c82c53d Mon Sep 17 00:00:00 2001 From: "Patrick M. Niedzielski" Date: Wed, 30 Oct 2024 14:48:13 -0400 Subject: [PATCH 15/17] CI: Use git CLI to push to `gh-pages` Signed-off-by: Patrick M. Niedzielski --- .github/workflows/documentation.yaml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/documentation.yaml b/.github/workflows/documentation.yaml index 17d41eccb..d625d543e 100644 --- a/.github/workflows/documentation.yaml +++ b/.github/workflows/documentation.yaml @@ -45,7 +45,9 @@ jobs: ( cat Doxyfile ; echo "PROJECT_NUMBER=${{ github.sha }}" ) | doxygen - - name: Commit new API documentation to `gh-pages` - uses: stefanzweifel/git-auto-commit-action@v5 - with: - commit_message: Update docs for `main`@${{ github.sha }} - repository: docs + run: | + cd docs/ + git config --global user.name "${{ github.actor }}" + git config --global user.email "${{ github.actor }}@users.noreply.github.com" + git commit -am "Update C++ API docs from commit ${{ github.sha }} on main" + git push From f10d75f08caa44a87e4d8117d1ab7de55accc0ad Mon Sep 17 00:00:00 2001 From: "Patrick M. Niedzielski" Date: Wed, 30 Oct 2024 17:55:04 -0400 Subject: [PATCH 16/17] Add DCO signoff Co-authored-by: Evgeny Malygin <678098@protonmail.com> Signed-off-by: Patrick M. Niedzielski --- .github/workflows/documentation.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/documentation.yaml b/.github/workflows/documentation.yaml index d625d543e..71ead65d8 100644 --- a/.github/workflows/documentation.yaml +++ b/.github/workflows/documentation.yaml @@ -49,5 +49,5 @@ jobs: cd docs/ git config --global user.name "${{ github.actor }}" git config --global user.email "${{ github.actor }}@users.noreply.github.com" - git commit -am "Update C++ API docs from commit ${{ github.sha }} on main" + git commit -s -am "Update C++ API docs from commit ${{ github.sha }} on main" git push From 844ba5c8d03b679f3838c0f69a68deb50c26d020 Mon Sep 17 00:00:00 2001 From: "Patrick M. Niedzielski" Date: Wed, 30 Oct 2024 18:17:16 -0400 Subject: [PATCH 17/17] CI: Add untracked generated documentation files when publishing If generating the documentation creates files that do not already exist on the `gh-pages` branch, the current GitHub Action to generate documentation will not add them. Instead, it will only update existing files. This may happen when a new component is added, or when the Doxygen version differs from prior runs. This bit us on our first run of the documentation-generation GitHub Action, because the version that GitHub Actions uses is different than the version that built our original documentation. This patch explicitly adds all files generated under the `docs/docs/apidocs/cpp_apidocs` directory, including both untracked files and tracked, modified files. Signed-off-by: Patrick M. Niedzielski --- .github/workflows/documentation.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/documentation.yaml b/.github/workflows/documentation.yaml index 71ead65d8..e3dcbb18f 100644 --- a/.github/workflows/documentation.yaml +++ b/.github/workflows/documentation.yaml @@ -49,5 +49,4 @@ jobs: cd docs/ git config --global user.name "${{ github.actor }}" git config --global user.email "${{ github.actor }}@users.noreply.github.com" - git commit -s -am "Update C++ API docs from commit ${{ github.sha }} on main" - git push + git add docs/apidocs/cpp_apidocs/ && git commit -s -am "Update C++ API docs from commit ${{ github.sha }} on main" && git push || true