@@ -3778,44 +3778,14 @@ void ClusterQueueHelper::restoreStateCluster(int partitionId)
37783778 const ClusterStatePartitionInfo* pinfo = 0 ;
37793779
37803780 if (!allPartitions) {
3781- pinfo = &(d_clusterState_p->partition (partitionId));
3782- BSLS_ASSERT_SAFE (pinfo);
3783- if (!hasActiveAvailablePrimary (partitionId)) {
3784- BALL_LOG_INFO << d_cluster_p->description () << " Partition ["
3785- << partitionId
3786- << " ]: Not restoring partition state because there "
3787- << " is no primary or primary isn't ACTIVE. Current "
3788- << " primary: "
3789- << (pinfo->primaryNode ()
3790- ? pinfo->primaryNode ()->nodeDescription ()
3791- : " ** null **" )
3792- << " , primary status: " << pinfo->primaryStatus ();
3781+ pinfo = activeAvailablePrimaryPartition (&isSelfPrimaryAndLeader,
3782+ partitionId);
3783+
3784+ if (!pinfo) {
37933785 return ; // RETURN
37943786 }
3795-
3796- // Primary for this partitionId is ACTIVE. Check if self is the
3797- // primary and leader. If self is primary but not leader, this is
3798- // primary-leader divergence and we should not proceed with state
3799- // restore.
3800-
3801- isSelfPrimaryAndLeader =
3802- pinfo->primaryNode () == d_clusterData_p->membership ().selfNode () &&
3803- d_clusterData_p->electorInfo ().isSelfLeader ();
38043787 }
38053788
3806- // / TODO (FSM); remove after switching to FSM
3807- if (!d_cluster_p->isFSMWorkflow () && isSelfPrimaryAndLeader) {
3808- // Note that this fails if there are data
3809- mqbc::ClusterState::AssignmentVisitor doubleAssignmentVisitor =
3810- bdlf::BindUtil::bindS (d_allocator_p,
3811- &mqbi::StorageManager::unregisterQueue,
3812- d_storageManager_p,
3813- bdlf::PlaceHolders::_1, // uri
3814- bdlf::PlaceHolders::_2); // partitionId),
3815-
3816- d_clusterState_p->iterateDoubleAssignments (partitionId,
3817- doubleAssignmentVisitor);
3818- }
38193789 ConditionalAdvance<QueueContextMapConstIter> conditional;
38203790 for (QueueContextMapConstIter cit = d_queues.cbegin ();
38213791 cit != d_queues.cend ();
@@ -3850,134 +3820,139 @@ void ClusterQueueHelper::restoreStateCluster(int partitionId)
38503820
38513821 continue ; // CONTINUE
38523822 }
3853- }
3854- else {
3855- // A specific partitionId is specified. Attempt to re-issue
3856- // open-queue requests for all appropriate queues assigned to that
3857- // partition.
38583823
3859- if (queueContext->partitionId () != partitionId) {
3860- // Skip the queue as its assigned to a different partitionId.
3861- continue ; // CONTINUE;
3824+ // Proceed as if a specific partitionId is specified.
3825+
3826+ pinfo = activeAvailablePrimaryPartition (
3827+ &isSelfPrimaryAndLeader,
3828+ queueContext->partitionId ());
3829+ if (!pinfo) {
3830+ continue ;
38623831 }
3832+ }
3833+ else if (queueContext->partitionId () != partitionId) {
3834+ // Skip the queue as its assigned to a different partitionId.
3835+ continue ; // CONTINUE;
3836+ }
3837+
3838+ // Attempt to re-issue open-queue requests for all appropriate queues
3839+ // assigned to that partition.
38633840
3864- BSLS_ASSERT_SAFE (isQueueAssigned (*queueContext));
3865- BSLS_ASSERT_SAFE (isQueuePrimaryAvailable (*queueContext));
3841+ BSLS_ASSERT_SAFE (isQueueAssigned (*queueContext));
3842+ BSLS_ASSERT_SAFE (isQueuePrimaryAvailable (*queueContext));
38663843
38673844 // Start restore cycle
38683845 bsl::shared_ptr<PartitionReopenCycle> cycle =
38693846 startPartitionReopen (partitionId, pinfo->primaryLeaseId ());
38703847
3871- // Verify the CSL if needed by comparing it with the Domain config
3872- if (liveQInfo.d_queue_sp ) {
3873- if (isSelfPrimaryAndLeader) {
3874- // We are assuming that it is not possible for a node to be
3875- // primary, lose primary-ship and regain primary-ship;
3876- // unless eventually the node went down in which case it
3877- // will start from fresh.
3878-
3879- // Moreover, since self node is now the primary, it is
3880- // important for it to register the queue with the
3881- // StorageManager. This is logically equivalent to
3882- // registering the queue with StorageManager when a primary
3883- // node creates a local queue instance (see
3884- // 'createQueueFactory').
3885-
3886- bsl::vector<bsl::string> added (d_allocator_p);
3887- bsl::vector<bsl::string> removed (d_allocator_p);
3888- mqbi::Domain* domain = liveQInfo.d_queue_sp ->domain ();
3889-
3890- match (&added,
3891- &removed,
3892- *queueContext->d_stateQInfo_sp ,
3893- domain->config ().mode ());
3894-
3895- if (!removed.empty () || !added.empty ()) {
3896- VoidFunctor park = bdlf::BindUtil::bindS (
3897- d_allocator_p,
3898- &ClusterQueueHelper::convertToLocal,
3899- this ,
3900- queueContext,
3901- domain);
3902-
3903- // Add to 'd_pendingUpdates' before calling
3904- // 'updateAppIds' which is asynchronous (CSL commit)
3905- liveQInfo.d_pendingUpdates .push_back (park);
3906-
3907- mqbi::ClusterErrorCode::Enum result =
3908- d_clusterStateManager_p->updateAppIds (
3909- added,
3910- removed,
3911- domain->name (),
3912- " " );
3913-
3914- if (mqbi::ClusterErrorCode::e_OK == result) {
3915- // Cannot continue until 'onQueueUpdated'
3916- // Send QueueUpdateAdvisory and _wait_ for commit
3917-
3918- continue ; // CONTINUE
3919- }
3920-
3921- // An update error is CSL error (in
3922- // 'ClusterStateLedger::apply'). This queue cannot
3923- // convertToLocal
3924- // ('RootQueueEngine::initializeAppId' would assert
3925- // if there is no storage for some app).
3926-
3927- BSLS_ASSERT_SAFE (
3928- false &&
3929- " Failure to update Apps before convertToLocal" );
3930- }
3931- else {
3932- convertToLocal (queueContext, domain);
3848+ // Verify the CSL if needed by comparing it with the Domain config
3849+ if (liveQInfo.d_queue_sp ) {
3850+ if (isSelfPrimaryAndLeader) {
3851+ // We are assuming that it is not possible for a node to be
3852+ // primary, lose primary-ship and regain primary-ship;
3853+ // unless eventually the node went down in which case it
3854+ // will start from fresh.
3855+
3856+ // Moreover, since self node is now the primary, it is
3857+ // important for it to register the queue with the
3858+ // StorageManager. This is logically equivalent to
3859+ // registering the queue with StorageManager when a primary
3860+ // node creates a local queue instance (see
3861+ // 'createQueueFactory').
3862+
3863+ bsl::vector<bsl::string> added (d_allocator_p);
3864+ bsl::vector<bsl::string> removed (d_allocator_p);
3865+ mqbi::Domain* domain = liveQInfo.d_queue_sp ->domain ();
3866+
3867+ match (&added,
3868+ &removed,
3869+ *queueContext->d_stateQInfo_sp ,
3870+ domain->config ().mode ());
3871+
3872+ if (!removed.empty () || !added.empty ()) {
3873+ VoidFunctor park = bdlf::BindUtil::bindS (
3874+ d_allocator_p,
3875+ &ClusterQueueHelper::convertToLocal,
3876+ this ,
3877+ queueContext,
3878+ domain);
3879+
3880+ // Add to 'd_pendingUpdates' before calling
3881+ // 'updateAppIds' which is asynchronous (CSL commit)
3882+ liveQInfo.d_pendingUpdates .push_back (park);
3883+
3884+ mqbi::ClusterErrorCode::Enum result =
3885+ d_clusterStateManager_p->updateAppIds (added,
3886+ removed,
3887+ domain->name (),
3888+ " " );
3889+
3890+ if (mqbi::ClusterErrorCode::e_OK == result) {
3891+ // Cannot continue until 'onQueueUpdated'
3892+ // Send QueueUpdateAdvisory and _wait_ for commit
3893+
3894+ continue ; // CONTINUE
39333895 }
3896+
3897+ // An update error is CSL error (in
3898+ // 'ClusterStateLedger::apply'). This queue cannot
3899+ // convertToLocal
3900+ // ('RootQueueEngine::initializeAppId' would assert
3901+ // if there is no storage for some app).
3902+
3903+ BSLS_ASSERT_SAFE (
3904+ false &&
3905+ " Failure to update Apps before convertToLocal" );
39343906 }
39353907 else {
3936- if (queueContext->d_liveQInfo .d_numQueueHandles != 0 ) {
3937- // In the case of a cluster member, queues are deleted
3938- // 'lazily' when receiving a notification from the
3939- // primary. This replica may have fully closed the
3940- // queue, but the queue has not been deleted by the
3941- // primary if another replica still uses it; however
3942- // from this replica's perspective, we don't want to
3943- // reopen the queue.
3944- const bmqt::GenericResult::Enum rc =
3945- restoreStateHelper (queueContext.get (),
3946- pinfo->primaryNode (),
3908+ convertToLocal (queueContext, domain);
3909+ }
3910+ }
3911+ else {
3912+ if (queueContext->d_liveQInfo .d_numQueueHandles != 0 ) {
3913+ const bmqt::GenericResult::Enum rc = restoreStateHelper (
3914+ queueContext.get (),
3915+ pinfo->primaryNode (),
39473916 cycle);
39483917
3949- if (rc == bmqt::GenericResult::e_NOT_CONNECTED) {
3950- // Abort restore of the state: the channel is no
3951- // longer valid or we hit high water mark. For the
3952- // case of invalid channel, we'll wait for a new
3953- // one to be active and will restart restoring the
3954- // state from the beginning.
3955- return ; // RETURN
3956- }
3957- // In case of other type of failure, just continue
3958- // processing other queues instead of stopping the
3959- // 'state restore' sequence.
3960-
3961- // REVISIT: this code sends pending Open Queue requests
3962- // without waiting for the Reopen Queue Response.
3963- }
3964- else {
3965- BMQ_LOGTHROTTLE_INFO
3966- << d_cluster_p->description ()
3967- << " : Skipping restore of " << queueContext->uri ()
3968- << " because it has no active queue handles" ;
3918+ if (rc == bmqt::GenericResult::e_NOT_CONNECTED) {
3919+ // Abort restore of the state: the channel is no
3920+ // longer valid or we hit high water mark. For the
3921+ // case of invalid channel, we'll wait for a new
3922+ // one to be active and will restart restoring the
3923+ // state from the beginning.
3924+ return ; // RETURN
39693925 }
3926+ // In case of other type of failure, just continue
3927+ // processing other queues instead of stopping the
3928+ // 'state restore' sequence.
39703929
3971- // We also need to issue requests for any pending contexts:
3972- // when a primary fails over, the queue may have been
3973- // already open on this node, and all clients which were
3974- // connected to the old primary will immediately reconnect,
3975- // some might connect to this node and will issue an open
3976- // queue. Because primary just got lost, those open queue
3977- // requests were not processed, but appended to the pending
3978- // context list, so once we have an active primary, we
3979- // should process them.
3930+ // REVISIT: this code sends pending Open Queue requests
3931+ // without waiting for the Reopen Queue Response.
39803932 }
3933+ else {
3934+ // In the case of a cluster member, queues are deleted
3935+ // 'lazily' when receiving a notification from the
3936+ // primary. This replica may have fully closed the
3937+ // queue, but the queue has not been deleted by the
3938+ // primary if another replica still uses it; however
3939+ // from this replica's perspective, we don't want to
3940+ // reopen the queue.
3941+ BMQ_LOGTHROTTLE_INFO
3942+ << d_cluster_p->description ()
3943+ << " : Skipping restore of " << queueContext->uri ()
3944+ << " because it has no active queue handles" ;
3945+ }
3946+
3947+ // We also need to issue requests for any pending contexts:
3948+ // when a primary fails over, the queue may have been
3949+ // already open on this node, and all clients which were
3950+ // connected to the old primary will immediately reconnect,
3951+ // some might connect to this node and will issue an open
3952+ // queue. Because primary just got lost, those open queue
3953+ // requests were not processed, but appended to the pending
3954+ // context list, so once we have an active primary, we
3955+ // should process them.
39813956 }
39823957 // else, Queue instance is not created, but the queue is assigned.
39833958 // Proceed ahead.
@@ -6265,5 +6240,54 @@ void ClusterQueueHelper::match(bsl::vector<bsl::string>* added,
62656240 }
62666241}
62676242
6243+ const mqbc::ClusterStatePartitionInfo*
6244+ ClusterQueueHelper::activeAvailablePrimaryPartition (
6245+ bool * isSelfPrimaryAndLeader,
6246+ int partitionId)
6247+ {
6248+ BSLS_ASSERT_SAFE (isSelfPrimaryAndLeader);
6249+
6250+ const ClusterStatePartitionInfo* pinfo = &(
6251+ d_clusterState_p->partition (partitionId));
6252+ BSLS_ASSERT_SAFE (pinfo);
6253+ if (!hasActiveAvailablePrimary (partitionId)) {
6254+ BALL_LOG_INFO << d_cluster_p->description () << " Partition ["
6255+ << partitionId
6256+ << " ]: Not restoring partition state because there "
6257+ << " is no primary or primary isn't ACTIVE. Current "
6258+ << " primary: "
6259+ << (pinfo->primaryNode ()
6260+ ? pinfo->primaryNode ()->nodeDescription ()
6261+ : " ** null **" )
6262+ << " , primary status: " << pinfo->primaryStatus ();
6263+ return 0 ; // RETURN
6264+ }
6265+
6266+ // Primary for this partitionId is ACTIVE. Check if self is the
6267+ // primary and leader. If self is primary but not leader, this is
6268+ // primary-leader divergence and we should not proceed with state
6269+ // restore.
6270+
6271+ *isSelfPrimaryAndLeader = pinfo->primaryNode () ==
6272+ d_clusterData_p->membership ().selfNode () &&
6273+ d_clusterData_p->electorInfo ().isSelfLeader ();
6274+
6275+ // / TODO (FSM); remove after switching to FSM
6276+ if (!d_cluster_p->isFSMWorkflow () && *isSelfPrimaryAndLeader) {
6277+ // Note that this fails if there are data
6278+ mqbc::ClusterState::AssignmentVisitor doubleAssignmentVisitor =
6279+ bdlf::BindUtil::bindS (d_allocator_p,
6280+ &mqbi::StorageManager::unregisterQueue,
6281+ d_storageManager_p,
6282+ bdlf::PlaceHolders::_1, // uri
6283+ bdlf::PlaceHolders::_2); // partitionId),
6284+
6285+ d_clusterState_p->iterateDoubleAssignments (partitionId,
6286+ doubleAssignmentVisitor);
6287+ }
6288+
6289+ return pinfo;
6290+ }
6291+
62686292} // close package namespace
62696293} // close enterprise namespace
0 commit comments