diff options
author | Didier Nadeau <didier.nadeau@mongodb.com> | 2021-11-15 19:12:56 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-11-15 19:48:03 +0000 |
commit | 7d7ffa22ea8d3979d7a5c1623c8a1683424393c4 (patch) | |
tree | 6b38e18789f3a1cf6bcba9d64fed3c4b08a371f4 /src | |
parent | 4cd66c0f2fe2912a5261d26bbc9608873fc22303 (diff) | |
download | mongo-7d7ffa22ea8d3979d7a5c1623c8a1683424393c4.tar.gz |
SERVER-60953 Return an optional when getDurableState is called
Diffstat (limited to 'src')
-rw-r--r-- | src/mongo/db/commands/tenant_migration_donor_cmds.cpp | 49 | ||||
-rw-r--r-- | src/mongo/db/repl/tenant_migration_donor_service.cpp | 48 | ||||
-rw-r--r-- | src/mongo/db/repl/tenant_migration_donor_service.h | 15 |
3 files changed, 69 insertions, 43 deletions
diff --git a/src/mongo/db/commands/tenant_migration_donor_cmds.cpp b/src/mongo/db/commands/tenant_migration_donor_cmds.cpp index 4e37821036f..eaae37b5c3a 100644 --- a/src/mongo/db/commands/tenant_migration_donor_cmds.cpp +++ b/src/mongo/db/commands/tenant_migration_donor_cmds.cpp @@ -117,11 +117,16 @@ public: // with the same migrationId but different options (e.g. tenantId or // recipientConnectionString or readPreference). uassertStatusOK(donor->checkIfOptionsConflict(stateDoc)); - auto durableState = donor->getDurableState(opCtx); - auto response = Response(durableState.state); - if (durableState.abortReason) { + + + // always ensure we wait for the initial state document to be inserted. + donor->getInitialStateDocumentDurableFuture().get(opCtx); + auto durableState = donor->getDurableState(); + + auto response = Response(durableState->state); + if (durableState->abortReason) { BSONObjBuilder bob; - durableState.abortReason.get().serializeErrorToBSON(&bob); + durableState->abortReason->serializeErrorToBSON(&bob); response.setAbortReason(bob.obj()); } @@ -180,22 +185,28 @@ public: auto donorService = repl::PrimaryOnlyServiceRegistry::get(opCtx->getServiceContext()) ->lookupServiceByName(TenantMigrationDonorService::kServiceName); - auto donor = TenantMigrationDonorService::Instance::lookup( + auto optionalDonor = TenantMigrationDonorService::Instance::lookup( opCtx, donorService, BSON("_id" << cmd.getMigrationId())); uassert(ErrorCodes::NoSuchTenantMigration, str::stream() << "Could not find tenant migration with id " << cmd.getMigrationId(), - donor); + optionalDonor); - auto durableState = donor.get()->getDurableState(opCtx); + // Retrieve the shared_ptr from boost::optional to improve readability + auto donorPtr = optionalDonor.get(); + + // always ensure we wait for the initial state document to be inserted. + donorPtr->getInitialStateDocumentDurableFuture().get(opCtx); + + auto durableState = donorPtr->getDurableState(); uassert(ErrorCodes::TenantMigrationInProgress, str::stream() << "Could not forget migration with id " << cmd.getMigrationId() << " since no decision has been made yet", - durableState.state == TenantMigrationDonorStateEnum::kCommitted || - durableState.state == TenantMigrationDonorStateEnum::kAborted); + durableState->state == TenantMigrationDonorStateEnum::kCommitted || + durableState->state == TenantMigrationDonorStateEnum::kAborted); - donor.get().get()->onReceiveDonorForgetMigration(); - donor.get().get()->getCompletionFuture().get(opCtx); + donorPtr->onReceiveDonorForgetMigration(); + donorPtr->getCompletionFuture().get(opCtx); } private: @@ -248,13 +259,13 @@ public: auto donorService = repl::PrimaryOnlyServiceRegistry::get(opCtx->getServiceContext()) ->lookupServiceByName(TenantMigrationDonorService::kServiceName); - auto donorPtr = TenantMigrationDonorService::Instance::lookup( + auto optionalDonor = TenantMigrationDonorService::Instance::lookup( opCtx, donorService, BSON("_id" << cmd.getMigrationId())); // If there is NoSuchTenantMigration, perform a noop write and wait for it to be // majority committed to verify that any durable data read up to this point is majority // committed. - if (!donorPtr) { + if (!optionalDonor) { tenant_migration_access_blocker::performNoopWrite(opCtx, "NoSuchTenantMigration error"); @@ -271,16 +282,16 @@ public: << cmd.getMigrationId()); } - const auto& donor = donorPtr.get().get(); - - donor->onReceiveDonorAbortMigration(); - donor->getDecisionFuture().get(opCtx); + // Retrieve the shared_ptr from boost::optional to improve readability + auto donorPtr = optionalDonor.get(); - auto durableState = donor->getDurableState(opCtx); + donorPtr->onReceiveDonorAbortMigration(); + donorPtr->getDecisionFuture().get(opCtx); + auto durableState = donorPtr->getDurableState(); uassert(ErrorCodes::TenantMigrationCommitted, "Tenant migration already committed", - durableState.state == TenantMigrationDonorStateEnum::kAborted); + durableState->state == TenantMigrationDonorStateEnum::kAborted); } private: diff --git a/src/mongo/db/repl/tenant_migration_donor_service.cpp b/src/mongo/db/repl/tenant_migration_donor_service.cpp index c9c15368105..32ca14a35e2 100644 --- a/src/mongo/db/repl/tenant_migration_donor_service.cpp +++ b/src/mongo/db/repl/tenant_migration_donor_service.cpp @@ -156,12 +156,17 @@ void TenantMigrationDonorService::checkIfConflictsWithOtherInstances( // Any existing migration for this tenant must be aborted and garbage-collectable. for (auto& instance : existingInstances) { auto typedInstance = checked_cast<const TenantMigrationDonorService::Instance*>(instance); - auto durableState = typedInstance->getDurableState(opCtx); - uassert(ErrorCodes::ConflictingOperationInProgress, - str::stream() << "tenant " << tenantId << " is already migrating", - typedInstance->getTenantId() != tenantId || - (durableState.state == TenantMigrationDonorStateEnum::kAborted && - durableState.expireAt)); + auto durableState = typedInstance->getDurableState(); + + if (typedInstance->getTenantId() == tenantId) { + // If a migration with the same tenantId exists, it needs to be already in kAborted + // state + uassert(ErrorCodes::ConflictingOperationInProgress, + str::stream() << "tenant " << tenantId << " is already migrating", + durableState && + durableState->state == TenantMigrationDonorStateEnum::kAborted && + durableState->expireAt); + } } } @@ -170,7 +175,7 @@ std::shared_ptr<repl::PrimaryOnlyService::Instance> TenantMigrationDonorService: return std::make_shared<TenantMigrationDonorService::Instance>( _serviceContext, this, initialState); -} +} // namespace mongo void TenantMigrationDonorService::abortAllMigrations(OperationContext* opCtx) { LOGV2(5356301, "Aborting all tenant migrations on donor"); @@ -272,15 +277,13 @@ TenantMigrationDonorService::Instance::Instance(ServiceContext* const serviceCon if (_stateDoc.getState() > TenantMigrationDonorStateEnum::kUninitialized) { // The migration was resumed on stepup. - _durableState.state = _stateDoc.getState(); - _durableState.expireAt = _stateDoc.getExpireAt(); if (_stateDoc.getAbortReason()) { auto abortReasonBson = _stateDoc.getAbortReason().get(); auto code = abortReasonBson["code"].Int(); auto errmsg = abortReasonBson["errmsg"].String(); - _durableState.abortReason = Status(ErrorCodes::Error(code), errmsg); - _abortReason = _durableState.abortReason; + _abortReason = Status(ErrorCodes::Error(code), errmsg); } + _durableState = DurableState{_stateDoc.getState(), _abortReason, _stateDoc.getExpireAt()}; _initialDonorStateDurablePromise.emplaceValue(); @@ -377,7 +380,11 @@ boost::optional<BSONObj> TenantMigrationDonorService::Instance::reportForCurrent bob.append("recipientConnectionString", _recipientConnectionString); bob.append("readPreference", _readPreference.toInnerBSON()); bob.append("receivedCancellation", _abortRequested); - bob.append("lastDurableState", _durableState.state); + if (_durableState) { + bob.append("lastDurableState", _durableState.get().state); + } else { + bob.appendUndefined("lastDurableState"); + } if (_stateDoc.getMigrationStart()) { bob.appendDate("migrationStart", *_stateDoc.getMigrationStart()); } @@ -419,11 +426,8 @@ Status TenantMigrationDonorService::Instance::checkIfOptionsConflict( << tenant_migration_util::redactStateDoc(_stateDoc.toBSON())); } -TenantMigrationDonorService::Instance::DurableState -TenantMigrationDonorService::Instance::getDurableState(OperationContext* opCtx) const { - // Wait for the insert of the state doc to become majority-committed. - _initialDonorStateDurablePromise.getFuture().get(opCtx); - +boost::optional<TenantMigrationDonorService::Instance::DurableState> +TenantMigrationDonorService::Instance::getDurableState() const { stdx::lock_guard<Latch> lg(_mutex); return _durableState; } @@ -657,9 +661,8 @@ ExecutorFuture<void> TenantMigrationDonorService::Instance::_waitForMajorityWrit .thenRunOn(**executor) .then([this, self = shared_from_this()] { stdx::lock_guard<Latch> lg(_mutex); - _durableState.state = _stateDoc.getState(); - _durableState.expireAt = _stateDoc.getExpireAt(); - switch (_durableState.state) { + boost::optional<Status> abortReason; + switch (_stateDoc.getState()) { case TenantMigrationDonorStateEnum::kAbortingIndexBuilds: setPromiseOkIfNotReady(lg, _initialDonorStateDurablePromise); break; @@ -669,11 +672,14 @@ ExecutorFuture<void> TenantMigrationDonorService::Instance::_waitForMajorityWrit break; case TenantMigrationDonorStateEnum::kAborted: invariant(_abortReason); - _durableState.abortReason = _abortReason; + abortReason = _abortReason; break; default: MONGO_UNREACHABLE; } + + _durableState = + DurableState{_stateDoc.getState(), std::move(abortReason), _stateDoc.getExpireAt()}; }); } diff --git a/src/mongo/db/repl/tenant_migration_donor_service.h b/src/mongo/db/repl/tenant_migration_donor_service.h index 5ead7300d17..87931e03343 100644 --- a/src/mongo/db/repl/tenant_migration_donor_service.h +++ b/src/mongo/db/repl/tenant_migration_donor_service.h @@ -108,9 +108,18 @@ public: Status checkIfOptionsConflict(const TenantMigrationDonorDocument& stateDoc); /** - * Returns the latest durable migration state. + * Returns the latest durable migration state, or boost::none if no state document has been + * inserted yet. The state document exists once getInitialStateDocumentDurableFuture() is + * resolved. */ - DurableState getDurableState(OperationContext* opCtx) const; + boost::optional<DurableState> getDurableState() const; + + /** + * Returns a Future that will be resolved once the initial state document has been inserted. + */ + SharedSemiFuture<void> getInitialStateDocumentDurableFuture() const { + return _initialDonorStateDurablePromise.getFuture(); + } /** * Returns a Future that will be resolved when all work associated with this Instance has @@ -309,7 +318,7 @@ public: mutable Mutex _mutex = MONGO_MAKE_LATCH("TenantMigrationDonorService::_mutex"); // The latest majority-committed migration state. - DurableState _durableState; + boost::optional<DurableState> _durableState; // Promise that is resolved when the donor has majority-committed the write to insert the // donor state doc for the migration. |