summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/db/commands/tenant_migration_donor_cmds.cpp49
-rw-r--r--src/mongo/db/repl/tenant_migration_donor_service.cpp48
-rw-r--r--src/mongo/db/repl/tenant_migration_donor_service.h15
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.