summaryrefslogtreecommitdiff
path: root/src/mongo/db/s/resharding
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/s/resharding')
-rw-r--r--src/mongo/db/s/resharding/document_source_resharding_iterate_transaction.cpp2
-rw-r--r--src/mongo/db/s/resharding/document_source_resharding_ownership_match.cpp2
-rw-r--r--src/mongo/db/s/resharding/recipient_document.idl5
-rw-r--r--src/mongo/db/s/resharding/resharding_collection_cloner.cpp5
-rw-r--r--src/mongo/db/s/resharding/resharding_coordinator_commit_monitor.cpp34
-rw-r--r--src/mongo/db/s/resharding/resharding_coordinator_commit_monitor_test.cpp41
-rw-r--r--src/mongo/db/s/resharding/resharding_coordinator_service.cpp259
-rw-r--r--src/mongo/db/s/resharding/resharding_coordinator_service.h21
-rw-r--r--src/mongo/db/s/resharding/resharding_coordinator_service_test.cpp11
-rw-r--r--src/mongo/db/s/resharding/resharding_coordinator_test.cpp2
-rw-r--r--src/mongo/db/s/resharding/resharding_data_copy_util.cpp29
-rw-r--r--src/mongo/db/s/resharding/resharding_data_copy_util.h14
-rw-r--r--src/mongo/db/s/resharding/resharding_destined_recipient_test.cpp10
-rw-r--r--src/mongo/db/s/resharding/resharding_donor_recipient_common.cpp57
-rw-r--r--src/mongo/db/s/resharding/resharding_donor_service.cpp8
-rw-r--r--src/mongo/db/s/resharding/resharding_donor_service_test.cpp8
-rw-r--r--src/mongo/db/s/resharding/resharding_future_util.cpp33
-rw-r--r--src/mongo/db/s/resharding/resharding_future_util.h3
-rw-r--r--src/mongo/db/s/resharding/resharding_future_util_test.cpp100
-rw-r--r--src/mongo/db/s/resharding/resharding_metrics.cpp77
-rw-r--r--src/mongo/db/s/resharding/resharding_metrics.h29
-rw-r--r--src/mongo/db/s/resharding/resharding_op_observer.h4
-rw-r--r--src/mongo/db/s/resharding/resharding_oplog_application.cpp8
-rw-r--r--src/mongo/db/s/resharding/resharding_oplog_batch_applier.cpp8
-rw-r--r--src/mongo/db/s/resharding/resharding_oplog_fetcher.cpp33
-rw-r--r--src/mongo/db/s/resharding/resharding_oplog_fetcher_test.cpp40
-rw-r--r--src/mongo/db/s/resharding/resharding_oplog_session_application.cpp2
-rw-r--r--src/mongo/db/s/resharding/resharding_recipient_service.cpp68
-rw-r--r--src/mongo/db/s/resharding/resharding_recipient_service.h2
-rw-r--r--src/mongo/db/s/resharding/resharding_recipient_service_test.cpp150
-rw-r--r--src/mongo/db/s/resharding/resharding_txn_cloner.cpp1
-rw-r--r--src/mongo/db/s/resharding/resharding_util.cpp2
32 files changed, 760 insertions, 308 deletions
diff --git a/src/mongo/db/s/resharding/document_source_resharding_iterate_transaction.cpp b/src/mongo/db/s/resharding/document_source_resharding_iterate_transaction.cpp
index 9d412147b7f..8075111e3af 100644
--- a/src/mongo/db/s/resharding/document_source_resharding_iterate_transaction.cpp
+++ b/src/mongo/db/s/resharding/document_source_resharding_iterate_transaction.cpp
@@ -134,7 +134,7 @@ DepsTracker::State DocumentSourceReshardingIterateTransaction::getDependencies(
DocumentSource::GetModPathsReturn DocumentSourceReshardingIterateTransaction::getModifiedPaths()
const {
- return {DocumentSource::GetModPathsReturn::Type::kAllPaths, std::set<std::string>{}, {}};
+ return {DocumentSource::GetModPathsReturn::Type::kAllPaths, OrderedPathSet{}, {}};
}
DocumentSource::GetNextResult DocumentSourceReshardingIterateTransaction::doGetNext() {
diff --git a/src/mongo/db/s/resharding/document_source_resharding_ownership_match.cpp b/src/mongo/db/s/resharding/document_source_resharding_ownership_match.cpp
index f8a186e3bcd..3144723bf2d 100644
--- a/src/mongo/db/s/resharding/document_source_resharding_ownership_match.cpp
+++ b/src/mongo/db/s/resharding/document_source_resharding_ownership_match.cpp
@@ -109,7 +109,7 @@ DepsTracker::State DocumentSourceReshardingOwnershipMatch::getDependencies(
DocumentSource::GetModPathsReturn DocumentSourceReshardingOwnershipMatch::getModifiedPaths() const {
// This stage does not modify or rename any paths.
- return {DocumentSource::GetModPathsReturn::Type::kFiniteSet, std::set<std::string>{}, {}};
+ return {DocumentSource::GetModPathsReturn::Type::kFiniteSet, OrderedPathSet{}, {}};
}
DocumentSource::GetNextResult DocumentSourceReshardingOwnershipMatch::doGetNext() {
diff --git a/src/mongo/db/s/resharding/recipient_document.idl b/src/mongo/db/s/resharding/recipient_document.idl
index e3128de0db5..1eda4620b8c 100644
--- a/src/mongo/db/s/resharding/recipient_document.idl
+++ b/src/mongo/db/s/resharding/recipient_document.idl
@@ -82,6 +82,11 @@ structs:
startConfigTxnCloneTime:
type: date
optional: true
+ approxBytesToCopy:
+ type: long
+ description: >-
+ Approximate number of bytes to copy during cloning
+ optional: true
metrics:
type: ReshardingRecipientMetrics
description: "Metrics related to this recipient."
diff --git a/src/mongo/db/s/resharding/resharding_collection_cloner.cpp b/src/mongo/db/s/resharding/resharding_collection_cloner.cpp
index 9132438053a..e51d2e2ed1f 100644
--- a/src/mongo/db/s/resharding/resharding_collection_cloner.cpp
+++ b/src/mongo/db/s/resharding/resharding_collection_cloner.cpp
@@ -29,8 +29,6 @@
#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kResharding
-#include "mongo/platform/basic.h"
-
#include "mongo/db/s/resharding/resharding_collection_cloner.h"
#include <utility>
@@ -39,7 +37,6 @@
#include "mongo/db/catalog/collection.h"
#include "mongo/db/catalog_raii.h"
#include "mongo/db/client.h"
-#include "mongo/db/concurrency/write_conflict_exception.h"
#include "mongo/db/curop.h"
#include "mongo/db/exec/document_value/document.h"
#include "mongo/db/logical_session_id_helpers.h"
@@ -277,7 +274,7 @@ bool ReshardingCollectionCloner::doOneBatch(OperationContext* opCtx, Pipeline& p
// ReshardingOpObserver depends on the collection metadata being known when processing writes to
// the temporary resharding collection. We attach shard version IGNORED to the insert operations
- // and retry once on a StaleConfig exception to allow the collection metadata information to be
+ // and retry once on a StaleConfig error to allow the collection metadata information to be
// recovered.
ScopedSetShardRole scopedSetShardRole(opCtx,
_outputNss,
diff --git a/src/mongo/db/s/resharding/resharding_coordinator_commit_monitor.cpp b/src/mongo/db/s/resharding/resharding_coordinator_commit_monitor.cpp
index 374dcd6538f..5700f0326ae 100644
--- a/src/mongo/db/s/resharding/resharding_coordinator_commit_monitor.cpp
+++ b/src/mongo/db/s/resharding/resharding_coordinator_commit_monitor.cpp
@@ -164,13 +164,21 @@ CoordinatorCommitMonitor::queryRemainingOperationTimeForRecipients() const {
uassertStatusOKWithContext(status, errorContext);
const auto remainingTime = extractOperationRemainingTime(shardResponse.data);
- // A recipient shard does not report the remaining operation time when there is no data
- // to copy and no oplog entry to apply.
- if (remainingTime && remainingTime.get() < minRemainingTime) {
- minRemainingTime = remainingTime.get();
+
+ // If any recipient omits the "remainingMillis" field of the response then
+ // we cannot conclude that it is safe to begin the critical section.
+ // It is possible that the recipient just had a failover and
+ // was not able to restore its metrics before it replied to the
+ // _shardsvrReshardingOperationTime command.
+ if (!remainingTime) {
+ maxRemainingTime = Milliseconds::max();
+ continue;
+ }
+ if (remainingTime.value() < minRemainingTime) {
+ minRemainingTime = remainingTime.value();
}
- if (remainingTime && remainingTime.get() > maxRemainingTime) {
- maxRemainingTime = remainingTime.get();
+ if (remainingTime.value() > maxRemainingTime) {
+ maxRemainingTime = remainingTime.value();
}
}
@@ -203,12 +211,20 @@ ExecutorFuture<void> CoordinatorCommitMonitor::_makeFuture() const {
"Encountered an error while querying recipients, will retry shortly",
"error"_attr = status);
- return RemainingOperationTimes{Milliseconds(0), Milliseconds::max()};
+ // On error we definitely cannot begin the critical section. Therefore,
+ // return Milliseconds::max for remainingTimes.max (remainingTimes.max is used
+ // for determining whether the critical section should begin).
+ return RemainingOperationTimes{Milliseconds(-1), Milliseconds::max()};
})
.then([this, anchor = shared_from_this()](RemainingOperationTimes remainingTimes) {
auto metrics = ReshardingMetrics::get(cc().getServiceContext());
- metrics->setMinRemainingOperationTime(remainingTimes.min);
- metrics->setMaxRemainingOperationTime(remainingTimes.max);
+ // If remainingTimes.max (or remainingTimes.min) is Milliseconds::max, then use -1 so
+ // that the scale of the y-axis is still useful when looking at FTDC metrics.
+ auto clampIfMax = [](Milliseconds t) {
+ return t != Milliseconds::max() ? t : Milliseconds(-1);
+ };
+ metrics->setMinRemainingOperationTime(clampIfMax(remainingTimes.min));
+ metrics->setMaxRemainingOperationTime(clampIfMax(remainingTimes.max));
// Check if all recipient shards are within the commit threshold.
if (remainingTimes.max <= _threshold)
diff --git a/src/mongo/db/s/resharding/resharding_coordinator_commit_monitor_test.cpp b/src/mongo/db/s/resharding/resharding_coordinator_commit_monitor_test.cpp
index e7f90cc41fa..2fe3075f1fc 100644
--- a/src/mongo/db/s/resharding/resharding_coordinator_commit_monitor_test.cpp
+++ b/src/mongo/db/s/resharding/resharding_coordinator_commit_monitor_test.cpp
@@ -92,6 +92,8 @@ protected:
void tearDown() override;
void mockCommandForRecipients(Milliseconds remainingOperationTime);
+ void mockOmitRemainingMillisForRecipients();
+ void mockOmitRemainingMillisForOneRecipient();
void mockRemaingOperationTimesCommandForRecipients(
CoordinatorCommitMonitor::RemainingOperationTimes remainingOperationTimes);
@@ -180,6 +182,31 @@ void CoordinatorCommitMonitorTest::mockCommandForRecipients(Milliseconds remaini
_recipientShards.begin(), _recipientShards.end(), [&](const ShardId&) { onCommand(func); });
}
+void CoordinatorCommitMonitorTest::mockOmitRemainingMillisForRecipients() {
+ // Omit remainingMillis from all shard responses.
+ std::for_each(_recipientShards.begin(), _recipientShards.end(), [this](const ShardId&) {
+ onCommand([](const executor::RemoteCommandRequest& request) -> StatusWith<BSONObj> {
+ // Return an empty BSON object.
+ return BSONObj();
+ });
+ });
+}
+
+void CoordinatorCommitMonitorTest::mockOmitRemainingMillisForOneRecipient() {
+ // Omit remainingMillis from a single recipient.
+ for (const auto& shard : _recipientShards) {
+ onCommand([&](const executor::RemoteCommandRequest&) -> StatusWith<BSONObj> {
+ if (shard == _recipientShards.front()) {
+ // Return an empty BSON object.
+ return BSONObj();
+ }
+ auto threshold = Milliseconds(gRemainingReshardingOperationTimeThresholdMillis.load());
+ return BSON("remainingMillis"
+ << durationCount<Milliseconds>(threshold - Milliseconds(1)));
+ });
+ }
+}
+
void CoordinatorCommitMonitorTest::mockRemaingOperationTimesCommandForRecipients(
CoordinatorCommitMonitor::RemainingOperationTimes remainingOperationTimes) {
bool useMin = true;
@@ -264,6 +291,20 @@ TEST_F(CoordinatorCommitMonitorTest, RetriesWhenEncountersErrorsWhileQueryingRec
future.get();
}
+TEST_F(CoordinatorCommitMonitorTest, BlocksWhenRemainingMillisIsOmitted) {
+ auto future = getCommitMonitor()->waitUntilRecipientsAreWithinCommitThreshold();
+
+ mockOmitRemainingMillisForRecipients();
+ ASSERT(!future.isReady());
+
+ // If even a single shard omits remainingMillis, we cannot begin the critical section.
+ mockOmitRemainingMillisForOneRecipient();
+ ASSERT(!future.isReady());
+
+ respondWithReadyToCommit();
+ future.get();
+}
+
} // namespace
} // namespace resharding
} // namespace mongo
diff --git a/src/mongo/db/s/resharding/resharding_coordinator_service.cpp b/src/mongo/db/s/resharding/resharding_coordinator_service.cpp
index 85c14b6478f..df90c6d718a 100644
--- a/src/mongo/db/s/resharding/resharding_coordinator_service.cpp
+++ b/src/mongo/db/s/resharding/resharding_coordinator_service.cpp
@@ -37,6 +37,7 @@
#include "mongo/bson/bsonobj.h"
#include "mongo/bson/json.h"
#include "mongo/db/auth/authorization_session_impl.h"
+#include "mongo/db/concurrency/exception_util.h"
#include "mongo/db/dbdirectclient.h"
#include "mongo/db/logical_session_cache.h"
#include "mongo/db/ops/write_ops.h"
@@ -94,6 +95,7 @@ MONGO_FAIL_POINT_DEFINE(reshardingPauseCoordinatorBeforeStartingErrorFlow);
MONGO_FAIL_POINT_DEFINE(reshardingPauseCoordinatorBeforePersistingStateTransition);
MONGO_FAIL_POINT_DEFINE(pauseBeforeTellDonorToRefresh);
MONGO_FAIL_POINT_DEFINE(pauseBeforeInsertCoordinatorDoc);
+MONGO_FAIL_POINT_DEFINE(pauseBeforeCTHolderInitialization);
const std::string kReshardingCoordinatorActiveIndexName = "ReshardingCoordinatorActiveIndex";
const Backoff kExponentialBackoff(Seconds(1), Milliseconds::max());
@@ -505,43 +507,33 @@ void insertChunkAndTagDocsForTempNss(OperationContext* opCtx,
ShardingCatalogManager::get(opCtx)->insertConfigDocuments(opCtx, TagsType::ConfigNS, newZones);
}
+void removeTagsDocs(OperationContext* opCtx, const BSONObj& tagsQuery, TxnNumber txnNumber) {
+ // Remove tag documents with the specified tagsQuery.
+ const auto tagDeleteOperationHint = BSON(TagsType::ns() << 1 << TagsType::min() << 1);
+ ShardingCatalogManager::get(opCtx)->writeToConfigDocumentInTxn(
+ opCtx,
+ TagsType::ConfigNS,
+ BatchedCommandRequest::buildDeleteOp(TagsType::ConfigNS,
+ tagsQuery, // query
+ true, // multi
+ tagDeleteOperationHint // hint
+ ),
+ txnNumber);
+}
+
// Requires that there be no session information on the opCtx.
void removeChunkAndTagsDocs(OperationContext* opCtx,
const BSONObj& tagsQuery,
const UUID& collUUID) {
- // Remove all chunk documents for the original nss. We do not know how many chunk docs
- // currently exist, so cannot pass a value for expectedNumModified
- const auto chunksQuery = BSON(ChunkType::collectionUUID() << collUUID);
- const auto tagDeleteOperationHint = BSON(TagsType::ns() << 1 << TagsType::min() << 1);
+ // Remove all chunk documents and specified tag documents.
+ resharding::removeChunkDocs(opCtx, collUUID);
+ const auto tagDeleteOperationHint = BSON(TagsType::ns() << 1 << TagsType::min() << 1);
const auto catalogClient = Grid::get(opCtx)->catalogClient();
-
- uassertStatusOK(catalogClient->removeConfigDocuments(
- opCtx, ChunkType::ConfigNS, chunksQuery, kMajorityWriteConcern));
uassertStatusOK(catalogClient->removeConfigDocuments(
opCtx, TagsType::ConfigNS, tagsQuery, kMajorityWriteConcern, tagDeleteOperationHint));
}
-void updateChunkAndTagsDocsForTempNss(OperationContext* opCtx,
- const ReshardingCoordinatorDocument& coordinatorDoc,
- OID newCollectionEpoch,
- TxnNumber txnNumber) {
- auto hint = BSON("ns" << 1 << "min" << 1);
- auto tagsRequest = BatchedCommandRequest::buildUpdateOp(
- TagsType::ConfigNS,
- BSON(TagsType::ns(coordinatorDoc.getTempReshardingNss().ns())), // query
- BSON("$set" << BSON("ns" << coordinatorDoc.getSourceNss().ns())), // update
- false, // upsert
- true, // multi
- hint // hint
- );
-
- // Update the 'ns' field to be the original collection namespace for all tags documents that
- // currently have 'ns' as the temporary collection namespace
- auto tagsRes = ShardingCatalogManager::get(opCtx)->writeToConfigDocumentInTxn(
- opCtx, TagsType::ConfigNS, tagsRequest, txnNumber);
-}
-
/**
* Executes metadata changes in a transaction without bumping the collection version.
*/
@@ -592,28 +584,14 @@ CollectionType createTempReshardingCollectionType(
return collType;
}
-void cleanupSourceConfigCollections(OperationContext* opCtx,
- const ReshardingCoordinatorDocument& coordinatorDoc) {
- using Doc = Document;
- using Arr = std::vector<Value>;
- using V = Value;
-
- auto createTagFilter = [](const V value) {
- return V{Doc{{"$map",
- V{Doc{{"input", V{Doc{{"$objectToArray", value}}}},
- {"in", V{StringData("$$this.k")}}}}}}};
- };
-
-
- auto skipNewTagsFilter = Doc{
- {"$ne",
- Arr{createTagFilter(V{StringData("$min")}),
- createTagFilter(V{Doc{{"$literal", coordinatorDoc.getReshardingKey().toBSON()}}})}}};
-
- const auto removeTagsQuery =
- BSON(TagsType::ns(coordinatorDoc.getSourceNss().ns()) << "$expr" << skipNewTagsFilter);
+void removeChunkDocs(OperationContext* opCtx, const UUID& collUUID) {
+ // Remove all chunk documents for the specified collUUID. We do not know how many chunk docs
+ // currently exist, so cannot pass a value for expectedNumModified
+ const auto chunksQuery = BSON(ChunkType::collectionUUID() << collUUID);
+ const auto catalogClient = Grid::get(opCtx)->catalogClient();
- removeChunkAndTagsDocs(opCtx, removeTagsQuery, coordinatorDoc.getSourceUUID());
+ uassertStatusOK(catalogClient->removeConfigDocuments(
+ opCtx, ChunkType::ConfigNS, chunksQuery, kMajorityWriteConcern));
}
void writeDecisionPersistedState(OperationContext* opCtx,
@@ -622,21 +600,49 @@ void writeDecisionPersistedState(OperationContext* opCtx,
Timestamp newCollectionTimestamp) {
// No need to bump originalNss version because its epoch will be changed.
- executeMetadataChangesInTxn(opCtx, [&](OperationContext* opCtx, TxnNumber txnNumber) {
- // Update the config.reshardingOperations entry
- writeToCoordinatorStateNss(opCtx, coordinatorDoc, txnNumber);
+ executeMetadataChangesInTxn(
+ opCtx,
+ [&coordinatorDoc, &newCollectionEpoch, &newCollectionTimestamp](OperationContext* opCtx,
+ TxnNumber txnNumber) {
+ // Update the config.reshardingOperations entry
+ writeToCoordinatorStateNss(opCtx, coordinatorDoc, txnNumber);
- // Remove the config.collections entry for the temporary collection
- writeToConfigCollectionsForTempNss(
- opCtx, coordinatorDoc, boost::none, boost::none, txnNumber);
+ // Remove the config.collections entry for the temporary collection
+ writeToConfigCollectionsForTempNss(
+ opCtx, coordinatorDoc, boost::none, boost::none, txnNumber);
- // Update the config.collections entry for the original namespace to reflect the new
- // shard key, new epoch, and new UUID
- updateConfigCollectionsForOriginalNss(
- opCtx, coordinatorDoc, newCollectionEpoch, newCollectionTimestamp, txnNumber);
+ // Update the config.collections entry for the original namespace to reflect the new
+ // shard key, new epoch, and new UUID
+ updateConfigCollectionsForOriginalNss(
+ opCtx, coordinatorDoc, newCollectionEpoch, newCollectionTimestamp, txnNumber);
+
+ // Delete all of the config.tags entries for the user collection namespace.
+ const auto removeTagsQuery = BSON(TagsType::ns(coordinatorDoc.getSourceNss().ns()));
+ removeTagsDocs(opCtx, removeTagsQuery, txnNumber);
- updateChunkAndTagsDocsForTempNss(opCtx, coordinatorDoc, newCollectionEpoch, txnNumber);
- });
+ // Update all of the config.tags entries for the temporary resharding namespace
+ // to refer to the user collection namespace.
+ updateTagsDocsForTempNss(opCtx, coordinatorDoc, txnNumber);
+ });
+}
+
+void updateTagsDocsForTempNss(OperationContext* opCtx,
+ const ReshardingCoordinatorDocument& coordinatorDoc,
+ TxnNumber txnNumber) {
+ auto hint = BSON("ns" << 1 << "min" << 1);
+ auto tagsRequest = BatchedCommandRequest::buildUpdateOp(
+ TagsType::ConfigNS,
+ BSON(TagsType::ns(coordinatorDoc.getTempReshardingNss().ns())), // query
+ BSON("$set" << BSON("ns" << coordinatorDoc.getSourceNss().ns())), // update
+ false, // upsert
+ true, // multi
+ hint // hint
+ );
+
+ // Update the 'ns' field to be the original collection namespace for all tags documents that
+ // currently have 'ns' as the temporary collection namespace.
+ auto tagsRes = ShardingCatalogManager::get(opCtx)->writeToConfigDocumentInTxn(
+ opCtx, TagsType::ConfigNS, tagsRequest, txnNumber);
}
void insertCoordDocAndChangeOrigCollEntry(OperationContext* opCtx,
@@ -1072,6 +1078,7 @@ ReshardingCoordinatorService::ReshardingCoordinator::_tellAllParticipantsReshard
_cancelableOpCtxFactory.emplace(_ctHolder->getStepdownToken(),
_markKilledExecutor);
})
+ .then([this] { return _waitForMajority(_ctHolder->getStepdownToken()); })
.then([this, executor]() {
pauseBeforeTellDonorToRefresh.pauseWhileSet();
_establishAllDonorsAsParticipants(executor);
@@ -1102,8 +1109,7 @@ ExecutorFuture<void> ReshardingCoordinatorService::ReshardingCoordinator::_initi
return resharding::WithAutomaticRetry([this, executor] {
return ExecutorFuture<void>(**executor)
.then([this, executor] { _insertCoordDocAndChangeOrigCollEntry(); })
- .then([this, executor] { _calculateParticipantsAndChunksThenWriteToDisk(); })
- .then([this] { return _waitForMajority(_ctHolder->getAbortToken()); });
+ .then([this, executor] { _calculateParticipantsAndChunksThenWriteToDisk(); });
})
.onTransientError([](const Status& status) {
LOGV2(5093703,
@@ -1242,33 +1248,11 @@ ReshardingCoordinatorService::ReshardingCoordinator::_commitAndFinishReshardOper
const ReshardingCoordinatorDocument& updatedCoordinatorDoc) noexcept {
return resharding::WithAutomaticRetry([this, executor, updatedCoordinatorDoc] {
return ExecutorFuture<void>(**executor)
- .then([this, executor, updatedCoordinatorDoc] {
- return _commit(updatedCoordinatorDoc);
- })
- .then([this] { return _waitForMajority(_ctHolder->getStepdownToken()); })
- .thenRunOn(**executor)
- .then([this, executor] {
- _tellAllParticipantsToCommit(_coordinatorDoc.getSourceNss(), executor);
- })
- .then([this] { _updateChunkImbalanceMetrics(_coordinatorDoc.getSourceNss()); })
- .then([this, updatedCoordinatorDoc] {
- auto opCtx = _cancelableOpCtxFactory->makeOperationContext(&cc());
- resharding::cleanupSourceConfigCollections(opCtx.get(),
- updatedCoordinatorDoc);
- return Status::OK();
- })
- .then([this, executor] { return _awaitAllParticipantShardsDone(executor); })
- .then([this, executor] {
- // Best-effort attempt to trigger a refresh on the participant shards so
- // they see the collection metadata without reshardingFields and no longer
- // throw ReshardCollectionInProgress. There is no guarantee this logic ever
- // runs if the config server primary steps down after having removed the
- // coordinator state document.
- return _tellAllRecipientsToRefresh(executor);
- });
+ .then(
+ [this, executor, updatedCoordinatorDoc] { _commit(updatedCoordinatorDoc); });
})
.onTransientError([](const Status& status) {
- LOGV2(5093705,
+ LOGV2(7698801,
"Resharding coordinator encountered transient error while committing",
"error"_attr = status);
})
@@ -1276,25 +1260,83 @@ ReshardingCoordinatorService::ReshardingCoordinator::_commitAndFinishReshardOper
.until<Status>([](const Status& status) { return status.isOK(); })
.on(**executor, _ctHolder->getStepdownToken())
.onError([this, executor](Status status) {
- {
- auto opCtx = _cancelableOpCtxFactory->makeOperationContext(&cc());
- reshardingPauseCoordinatorBeforeStartingErrorFlow.pauseWhileSet(opCtx.get());
+ if (status == ErrorCodes::TransactionTooLargeForCache) {
+ return _onAbortCoordinatorAndParticipants(executor, status);
}
+ return ExecutorFuture<void>(**executor, status);
+ })
+ .then([this, executor, updatedCoordinatorDoc] {
+ return resharding::WithAutomaticRetry([this, executor, updatedCoordinatorDoc] {
+ return ExecutorFuture<void>(**executor)
+ .then([this] { return _waitForMajority(_ctHolder->getStepdownToken()); })
+ .thenRunOn(**executor)
+ .then([this, executor] {
+ _tellAllParticipantsToCommit(_coordinatorDoc.getSourceNss(),
+ executor);
+ })
+ .then([this] {
+ _updateChunkImbalanceMetrics(_coordinatorDoc.getSourceNss());
+ })
+ .then([this, updatedCoordinatorDoc] {
+ auto opCtx = _cancelableOpCtxFactory->makeOperationContext(&cc());
+ resharding::removeChunkDocs(opCtx.get(),
+ updatedCoordinatorDoc.getSourceUUID());
+ return Status::OK();
+ })
+ .then([this, executor] {
+ return _awaitAllParticipantShardsDone(executor);
+ })
+ .then([this, executor] {
+ // Best-effort attempt to trigger a refresh on the participant shards
+ // so they see the collection metadata without reshardingFields and
+ // no longer throw ReshardCollectionInProgress. There is no guarantee
+ // this logic ever runs if the config server primary steps down after
+ // having removed the coordinator state document.
+ return _tellAllRecipientsToRefresh(executor);
+ });
+ })
+ .onTransientError([](const Status& status) {
+ LOGV2(5093705,
+ "Resharding coordinator encountered transient error while committing",
+ "error"_attr = status);
+ })
+ .onUnrecoverableError([](const Status& status) {})
+ .until<Status>([](const Status& status) { return status.isOK(); })
+ .on(**executor, _ctHolder->getStepdownToken())
+ .onError([this, executor](Status status) {
+ {
+ auto opCtx = _cancelableOpCtxFactory->makeOperationContext(&cc());
+ reshardingPauseCoordinatorBeforeStartingErrorFlow.pauseWhileSet(
+ opCtx.get());
+ }
- if (_ctHolder->isSteppingOrShuttingDown()) {
- return status;
- }
+ if (_ctHolder->isSteppingOrShuttingDown()) {
+ return status;
+ }
- LOGV2_FATAL(5277000,
+ LOGV2_FATAL(
+ 5277000,
"Unrecoverable error past the point resharding was guaranteed to succeed",
"error"_attr = redact(status));
+ });
});
}
SemiFuture<void> ReshardingCoordinatorService::ReshardingCoordinator::run(
std::shared_ptr<executor::ScopedTaskExecutor> executor,
const CancellationToken& stepdownToken) noexcept {
- _ctHolder = std::make_unique<CoordinatorCancellationTokenHolder>(stepdownToken);
+ pauseBeforeCTHolderInitialization.pauseWhileSet();
+
+ auto abortCalled = [&] {
+ stdx::lock_guard<Latch> lk(_abortCalledMutex);
+ _ctHolder = std::make_unique<CoordinatorCancellationTokenHolder>(stepdownToken);
+ return _abortCalled;
+ }();
+
+ if (abortCalled) {
+ _ctHolder->abort();
+ }
+
_markKilledExecutor->startup();
_cancelableOpCtxFactory.emplace(_ctHolder->getAbortToken(), _markKilledExecutor);
@@ -1305,8 +1347,15 @@ SemiFuture<void> ReshardingCoordinatorService::ReshardingCoordinator::run(
})
.onCompletion([this, executor](Status status) {
auto opCtx = _cancelableOpCtxFactory->makeOperationContext(&cc());
- reshardingPauseCoordinatorBeforeCompletion.pauseWhileSetAndNotCanceled(
- opCtx.get(), _ctHolder->getStepdownToken());
+ reshardingPauseCoordinatorBeforeCompletion.executeIf(
+ [&](const BSONObj&) {
+ reshardingPauseCoordinatorBeforeCompletion.pauseWhileSetAndNotCanceled(
+ opCtx.get(), _ctHolder->getStepdownToken());
+ },
+ [&](const BSONObj& data) {
+ auto ns = data.getStringField("sourceNamespace");
+ return ns.empty() ? true : ns.toString() == _coordinatorDoc.getSourceNss().ns();
+ });
{
auto lg = stdx::lock_guard(_fulfillmentMutex);
@@ -1443,7 +1492,15 @@ ReshardingCoordinatorService::ReshardingCoordinator::_onAbortCoordinatorAndParti
}
void ReshardingCoordinatorService::ReshardingCoordinator::abort() {
- _ctHolder->abort();
+ auto ctHolderInitialized = [&] {
+ stdx::lock_guard<Latch> lk(_abortCalledMutex);
+ _abortCalled = true;
+ return !(_ctHolder == nullptr);
+ }();
+
+ if (ctHolderInitialized) {
+ _ctHolder->abort();
+ }
}
boost::optional<BSONObj> ReshardingCoordinatorService::ReshardingCoordinator::reportForCurrentOp(
@@ -1739,11 +1796,11 @@ ReshardingCoordinatorService::ReshardingCoordinator::_awaitAllRecipientsInStrict
.thenRunOn(**executor);
}
-Future<void> ReshardingCoordinatorService::ReshardingCoordinator::_commit(
+void ReshardingCoordinatorService::ReshardingCoordinator::_commit(
const ReshardingCoordinatorDocument& coordinatorDoc) {
if (_coordinatorDoc.getState() > CoordinatorStateEnum::kBlockingWrites) {
invariant(_coordinatorDoc.getState() != CoordinatorStateEnum::kAborting);
- return Status::OK();
+ return;
}
ReshardingCoordinatorDocument updatedCoordinatorDoc = coordinatorDoc;
@@ -1769,8 +1826,6 @@ Future<void> ReshardingCoordinatorService::ReshardingCoordinator::_commit(
// Update the in memory state
installCoordinatorDoc(opCtx.get(), updatedCoordinatorDoc);
-
- return Status::OK();
}
ExecutorFuture<void>
diff --git a/src/mongo/db/s/resharding/resharding_coordinator_service.h b/src/mongo/db/s/resharding/resharding_coordinator_service.h
index a24569ecc44..3fdd0ae05c1 100644
--- a/src/mongo/db/s/resharding/resharding_coordinator_service.h
+++ b/src/mongo/db/s/resharding/resharding_coordinator_service.h
@@ -50,14 +50,17 @@ CollectionType createTempReshardingCollectionType(
const ChunkVersion& chunkVersion,
const BSONObj& collation);
-void cleanupSourceConfigCollections(OperationContext* opCtx,
- const ReshardingCoordinatorDocument& coordinatorDoc);
+void removeChunkDocs(OperationContext* opCtx, const UUID& collUUID);
void writeDecisionPersistedState(OperationContext* opCtx,
const ReshardingCoordinatorDocument& coordinatorDoc,
OID newCollectionEpoch,
Timestamp newCollectionTimestamp);
+void updateTagsDocsForTempNss(OperationContext* opCtx,
+ const ReshardingCoordinatorDocument& coordinatorDoc,
+ TxnNumber txnNumber);
+
void insertCoordDocAndChangeOrigCollEntry(OperationContext* opCtx,
const ReshardingCoordinatorDocument& coordinatorDoc);
@@ -404,11 +407,10 @@ private:
* Does the following writes:
* 1. Updates the config.collections entry for the new sharded collection
* 2. Updates config.chunks entries for the new sharded collection
- * 3. Updates config.tags for the new sharded collection
*
* Transitions to 'kCommitting'.
*/
- Future<void> _commit(const ReshardingCoordinatorDocument& updatedDoc);
+ void _commit(const ReshardingCoordinatorDocument& updatedDoc);
/**
* Waits on _reshardingCoordinatorObserver to notify that:
@@ -534,6 +536,13 @@ private:
MONGO_MAKE_LATCH("ReshardingCoordinatorService::_fulfillmentMutex");
/**
+ * Must be locked while the _abortCalled is being set to true.
+ */
+ mutable Mutex _abortCalledMutex =
+ MONGO_MAKE_LATCH("ReshardingCoordinatorService::_abortCalledMutex");
+
+
+ /**
* Coordinator does not enter the critical section until this is fulfilled.
* Can be set by "commitReshardCollection" command or by metrics determining
* that it's okay to proceed.
@@ -553,6 +562,10 @@ private:
std::shared_ptr<resharding::CoordinatorCommitMonitor> _commitMonitor;
std::shared_ptr<ReshardingCoordinatorExternalState> _reshardingCoordinatorExternalState;
+
+ // Used to catch the case when an abort() is called but the cancellation source (_ctHolder) has
+ // not been initialized.
+ bool _abortCalled{false};
};
} // namespace mongo
diff --git a/src/mongo/db/s/resharding/resharding_coordinator_service_test.cpp b/src/mongo/db/s/resharding/resharding_coordinator_service_test.cpp
index 6a5197b4c41..188fc400e29 100644
--- a/src/mongo/db/s/resharding/resharding_coordinator_service_test.cpp
+++ b/src/mongo/db/s/resharding/resharding_coordinator_service_test.cpp
@@ -923,5 +923,16 @@ TEST_F(ReshardingCoordinatorServiceTest, ReshardingCoordinatorFailsIfMigrationNo
}
}
+TEST_F(ReshardingCoordinatorServiceTest, SuccessfullyAbortReshardOperationImmediately) {
+ auto pauseBeforeCTHolderInitialization =
+ globalFailPointRegistry().find("pauseBeforeCTHolderInitialization");
+ auto timesEnteredFailPoint = pauseBeforeCTHolderInitialization->setMode(FailPoint::alwaysOn, 0);
+ auto coordinator = initializeAndGetCoordinator();
+ coordinator->abort();
+ pauseBeforeCTHolderInitialization->waitForTimesEntered(timesEnteredFailPoint + 1);
+ pauseBeforeCTHolderInitialization->setMode(FailPoint::off, 0);
+ coordinator->getCompletionFuture().wait();
+}
+
} // namespace
} // namespace mongo
diff --git a/src/mongo/db/s/resharding/resharding_coordinator_test.cpp b/src/mongo/db/s/resharding/resharding_coordinator_test.cpp
index a8fb4d83889..974879b2959 100644
--- a/src/mongo/db/s/resharding/resharding_coordinator_test.cpp
+++ b/src/mongo/db/s/resharding/resharding_coordinator_test.cpp
@@ -636,7 +636,7 @@ protected:
ReshardingCoordinatorDocument expectedCoordinatorDoc,
std::vector<ChunkType> expectedChunks,
std::vector<TagsType> expectedZones) {
- cleanupSourceConfigCollections(opCtx, expectedCoordinatorDoc);
+ removeChunkDocs(opCtx, expectedCoordinatorDoc.getSourceUUID());
// Check that chunks and tags entries previously under the temporary namespace have been
// correctly updated to the original namespace
diff --git a/src/mongo/db/s/resharding/resharding_data_copy_util.cpp b/src/mongo/db/s/resharding/resharding_data_copy_util.cpp
index 9893b2b0f2e..d0b27f00c3c 100644
--- a/src/mongo/db/s/resharding/resharding_data_copy_util.cpp
+++ b/src/mongo/db/s/resharding/resharding_data_copy_util.cpp
@@ -33,7 +33,7 @@
#include "mongo/db/catalog/rename_collection.h"
#include "mongo/db/catalog_raii.h"
-#include "mongo/db/concurrency/write_conflict_exception.h"
+#include "mongo/db/concurrency/exception_util.h"
#include "mongo/db/curop.h"
#include "mongo/db/dbhelpers.h"
#include "mongo/db/namespace_string.h"
@@ -44,6 +44,7 @@
#include "mongo/db/s/resharding/resharding_txn_cloner_progress_gen.h"
#include "mongo/db/s/resharding/resharding_util.h"
#include "mongo/db/s/session_catalog_migration.h"
+#include "mongo/db/s/sharding_ddl_util.h"
#include "mongo/db/session_catalog_mongod.h"
#include "mongo/db/session_txn_record_gen.h"
#include "mongo/db/storage/write_unit_of_work.h"
@@ -71,28 +72,6 @@ void ensureCollectionExists(OperationContext* opCtx,
});
}
-void ensureCollectionDropped(OperationContext* opCtx,
- const NamespaceString& nss,
- const boost::optional<UUID>& uuid) {
- invariant(!opCtx->lockState()->isLocked());
- invariant(!opCtx->lockState()->inAWriteUnitOfWork());
-
- writeConflictRetry(
- opCtx, "resharding::data_copy::ensureCollectionDropped", nss.toString(), [&] {
- AutoGetCollection coll(opCtx, nss, MODE_X);
- if (!coll || (uuid && coll->uuid() != uuid)) {
- // If the collection doesn't exist or exists with a different UUID, then the
- // requested collection has been dropped already.
- return;
- }
-
- WriteUnitOfWork wuow(opCtx);
- uassertStatusOK(coll.getDb()->dropCollectionEvenIfSystem(
- opCtx, nss, {} /* dropOpTime */, true /* markFromMigrate */));
- wuow.commit();
- });
-}
-
void ensureOplogCollectionsDropped(OperationContext* opCtx,
const UUID& reshardingUUID,
const UUID& sourceUUID,
@@ -119,11 +98,11 @@ void ensureOplogCollectionsDropped(OperationContext* opCtx,
// Drop the conflict stash collection for this donor.
auto stashNss = getLocalConflictStashNamespace(sourceUUID, donor.getShardId());
- ensureCollectionDropped(opCtx, stashNss);
+ mongo::sharding_ddl_util::ensureCollectionDroppedNoChangeEvent(opCtx, stashNss);
// Drop the oplog buffer collection for this donor.
auto oplogBufferNss = getLocalOplogBufferNamespace(sourceUUID, donor.getShardId());
- ensureCollectionDropped(opCtx, oplogBufferNss);
+ mongo::sharding_ddl_util::ensureCollectionDroppedNoChangeEvent(opCtx, oplogBufferNss);
}
}
diff --git a/src/mongo/db/s/resharding/resharding_data_copy_util.h b/src/mongo/db/s/resharding/resharding_data_copy_util.h
index 9f2a332ef6c..b51cfc250a5 100644
--- a/src/mongo/db/s/resharding/resharding_data_copy_util.h
+++ b/src/mongo/db/s/resharding/resharding_data_copy_util.h
@@ -60,16 +60,6 @@ void ensureCollectionExists(OperationContext* opCtx,
const CollectionOptions& options);
/**
- * Drops the specified collection or returns without error if the collection has already been
- * dropped. A particular incarnation of the collection can be dropped by specifying its UUID.
- *
- * This functions assumes the collection being dropped doesn't have any two-phase index builds
- * active on it.
- */
-void ensureCollectionDropped(OperationContext* opCtx,
- const NamespaceString& nss,
- const boost::optional<UUID>& uuid = boost::none);
-/**
* Removes documents from the oplog applier progress and transaction applier progress collections
* that are associated with an in-progress resharding operation. Also drops all oplog buffer
* collections and conflict stash collections that are associated with the in-progress resharding
@@ -159,8 +149,8 @@ void updateSessionRecord(OperationContext* opCtx,
/**
* Calls and returns the value from the supplied lambda function.
*
- * If a StaleConfig exception is thrown during its execution, then this function will attempt to
- * refresh the collection and invoke the supplied lambda function a second time.
+ * If a StaleConfig error is thrown during its execution, then this function will attempt to refresh
+ * the collection and invoke the supplied lambda function a second time.
*/
template <typename Callable>
auto withOneStaleConfigRetry(OperationContext* opCtx, Callable&& callable) {
diff --git a/src/mongo/db/s/resharding/resharding_destined_recipient_test.cpp b/src/mongo/db/s/resharding/resharding_destined_recipient_test.cpp
index e942dcd139f..28f10ae9143 100644
--- a/src/mongo/db/s/resharding/resharding_destined_recipient_test.cpp
+++ b/src/mongo/db/s/resharding/resharding_destined_recipient_test.cpp
@@ -135,10 +135,10 @@ public:
return repl::OpTimeWith<std::vector<ShardType>>(_shards);
}
- std::vector<CollectionType> getCollections(
- OperationContext* opCtx,
- StringData dbName,
- repl::ReadConcernLevel readConcernLevel) override {
+ std::vector<CollectionType> getCollections(OperationContext* opCtx,
+ StringData dbName,
+ repl::ReadConcernLevel readConcernLevel,
+ const BSONObj& sort) override {
return _colls;
}
@@ -237,7 +237,7 @@ protected:
createChunks(env.version.epoch(), env.sourceUuid, env.version.getTimestamp(), "y"),
boost::none);
- forceDatabaseRefresh(opCtx, kNss.db());
+ ASSERT_OK(onDbVersionMismatchNoExcept(opCtx, kNss.db(), boost::none));
forceShardFilteringMetadataRefresh(opCtx, kNss);
if (refreshTempNss)
diff --git a/src/mongo/db/s/resharding/resharding_donor_recipient_common.cpp b/src/mongo/db/s/resharding/resharding_donor_recipient_common.cpp
index e9a466a1cb6..99ab47fc11a 100644
--- a/src/mongo/db/s/resharding/resharding_donor_recipient_common.cpp
+++ b/src/mongo/db/s/resharding/resharding_donor_recipient_common.cpp
@@ -51,10 +51,35 @@ using DonorStateMachine = ReshardingDonorService::DonorStateMachine;
using RecipientStateMachine = ReshardingRecipientService::RecipientStateMachine;
namespace {
+MONGO_FAIL_POINT_DEFINE(reshardingInterruptAfterInsertStateMachineDocument);
+
using namespace fmt::literals;
const Backoff kExponentialBackoff(Seconds(1), Milliseconds::max());
+template <class StateMachine, class ReshardingDocument>
+void ensureStateDocumentInserted(OperationContext* opCtx, const ReshardingDocument& doc) {
+ try {
+ StateMachine::insertStateDocument(opCtx, doc);
+ } catch (const ExceptionFor<ErrorCodes::DuplicateKey>& ex) {
+ // It's possible that the state document was already previously inserted in the following
+ // cases:
+ // 1. The document was inserted previously, but the opCtx was interrupted before the
+ // state machine was started in-memory with getOrCreate(), e.g. due to a chunk migration
+ // (see SERVER-74647)
+ // 2. Similar to the ErrorCategory::NotPrimaryError clause below, it is
+ // theoretically possible for a series of stepdowns and step-ups to lead a scenario where a
+ // stale but now re-elected primary attempts to insert the state document when another node
+ // which was primary had already done so. Again, rather than attempt to prevent replica set
+ // member state transitions during the shard version refresh, we instead swallow the
+ // DuplicateKey exception. This is safe because PrimaryOnlyService::onStepUp() will have
+ // constructed a new instance of the resharding state machine.
+ auto dupeKeyInfo = ex.extraInfo<DuplicateKeyErrorInfo>();
+ invariant(dupeKeyInfo->getDuplicatedKeyValue().binaryEqual(
+ BSON("_id" << doc.getReshardingUUID())));
+ }
+}
+
/*
* Creates a ReshardingStateMachine if this node is primary and the ReshardingStateMachine doesn't
* already exist.
@@ -67,7 +92,10 @@ void createReshardingStateMachine(OperationContext* opCtx, const ReshardingDocum
// Inserting the resharding state document must happen synchronously with the shard version
// refresh for the w:majority wait from the resharding coordinator to mean that this replica
// set shard cannot forget about being a participant.
- StateMachine::insertStateDocument(opCtx, doc);
+ ensureStateDocumentInserted<StateMachine>(opCtx, doc);
+
+ reshardingInterruptAfterInsertStateMachineDocument.execute(
+ [&opCtx](const BSONObj& data) { opCtx->markKilled(); });
auto registry = repl::PrimaryOnlyServiceRegistry::get(opCtx->getServiceContext());
auto service = registry->lookupServiceByName(Service::kServiceName);
@@ -82,17 +110,6 @@ void createReshardingStateMachine(OperationContext* opCtx, const ReshardingDocum
// secondary (or primary which stepped down) must do for an active resharding operation upon
// refreshing its shard version. The primary is solely responsible for advancing the
// participant state as a result of the shard version refresh.
- } catch (const ExceptionFor<ErrorCodes::DuplicateKey>& ex) {
- // Similar to the ErrorCategory::NotPrimaryError clause above, it is theoretically possible
- // for a series of stepdowns and step-ups to lead a scenario where a stale but now
- // re-elected primary attempts to insert the state document when another node which was
- // primary had already done so. Again, rather than attempt to prevent replica set member
- // state transitions during the shard version refresh, we instead swallow the DuplicateKey
- // exception. This is safe because PrimaryOnlyService::onStepUp() will have constructed a
- // new instance of the resharding state machine.
- auto dupeKeyInfo = ex.extraInfo<DuplicateKeyErrorInfo>();
- invariant(dupeKeyInfo->getDuplicatedKeyValue().binaryEqual(
- BSON("_id" << doc.getReshardingUUID())));
}
}
@@ -138,6 +155,13 @@ void processReshardingFieldsForDonorCollection(OperationContext* opCtx,
return;
}
+ // We clear the routing information for the temporary resharding namespace to ensure this donor
+ // shard primary will refresh from the config server and see the chunk distribution for the new
+ // resharding operation.
+ auto* catalogCache = Grid::get(opCtx)->catalogCache();
+ catalogCache->invalidateCollectionEntry_LINEARIZABLE(
+ reshardingFields.getDonorFields()->getTempReshardingNss());
+
auto donorDoc = constructDonorDocumentFromReshardingFields(nss, metadata, reshardingFields);
createReshardingStateMachine<ReshardingDonorService,
DonorStateMachine,
@@ -328,7 +352,16 @@ void clearFilteringMetadata(OperationContext* opCtx, bool scheduleAsyncRefresh)
});
}
+ auto* catalogCache = Grid::get(opCtx)->catalogCache();
+
for (const auto& nss : namespacesToRefresh) {
+ if (nss.isTemporaryReshardingCollection()) {
+ // We clear the routing information for the temporary resharding namespace to ensure all
+ // new donor shard primaries will refresh from the config server and see the chunk
+ // distribution for the ongoing resharding operation.
+ catalogCache->invalidateCollectionEntry_LINEARIZABLE(nss);
+ }
+
AutoGetCollection autoColl(opCtx, nss, MODE_IX);
CollectionShardingRuntime::get(opCtx, nss)->clearFilteringMetadata(opCtx);
diff --git a/src/mongo/db/s/resharding/resharding_donor_service.cpp b/src/mongo/db/s/resharding/resharding_donor_service.cpp
index ce60e58f0e1..4594c4018a6 100644
--- a/src/mongo/db/s/resharding/resharding_donor_service.cpp
+++ b/src/mongo/db/s/resharding/resharding_donor_service.cpp
@@ -37,7 +37,7 @@
#include "mongo/db/catalog/drop_collection.h"
#include "mongo/db/catalog/rename_collection.h"
#include "mongo/db/catalog_raii.h"
-#include "mongo/db/concurrency/write_conflict_exception.h"
+#include "mongo/db/concurrency/exception_util.h"
#include "mongo/db/db_raii.h"
#include "mongo/db/dbdirectclient.h"
#include "mongo/db/dbhelpers.h"
@@ -55,6 +55,7 @@
#include "mongo/db/s/resharding/resharding_metrics.h"
#include "mongo/db/s/resharding/resharding_server_parameters_gen.h"
#include "mongo/db/s/resharding/resharding_util.h"
+#include "mongo/db/s/sharding_ddl_util.h"
#include "mongo/db/s/sharding_state.h"
#include "mongo/db/write_block_bypass.h"
#include "mongo/db/write_concern_options.h"
@@ -65,6 +66,7 @@
namespace mongo {
+MONGO_FAIL_POINT_DEFINE(reshardingPauseDonorBeforeCatalogCacheRefresh);
MONGO_FAIL_POINT_DEFINE(reshardingDonorFailsAfterTransitionToDonatingOplogEntries);
MONGO_FAIL_POINT_DEFINE(removeDonorDocFailpoint);
@@ -567,6 +569,8 @@ void ReshardingDonorService::DonorStateMachine::
// with a SnapshotUnavailable error response.
{
auto opCtx = _cancelableOpCtxFactory->makeOperationContext(&cc());
+ reshardingPauseDonorBeforeCatalogCacheRefresh.pauseWhileSet(opCtx.get());
+
_externalState->refreshCatalogCache(opCtx.get(), _metadata.getTempReshardingNss());
_externalState->waitForCollectionFlush(opCtx.get(), _metadata.getTempReshardingNss());
}
@@ -795,7 +799,7 @@ void ReshardingDonorService::DonorStateMachine::_dropOriginalCollectionThenTrans
// Allow bypassing user write blocking. The check has already been performed on the
// db-primary shard's ReshardCollectionCoordinator.
WriteBlockBypass::get(opCtx.get()).set(true);
- resharding::data_copy::ensureCollectionDropped(
+ mongo::sharding_ddl_util::ensureCollectionDroppedNoChangeEvent(
opCtx.get(), _metadata.getSourceNss(), _metadata.getSourceUUID());
}
diff --git a/src/mongo/db/s/resharding/resharding_donor_service_test.cpp b/src/mongo/db/s/resharding/resharding_donor_service_test.cpp
index 663b8c28136..6ff3c17fdcf 100644
--- a/src/mongo/db/s/resharding/resharding_donor_service_test.cpp
+++ b/src/mongo/db/s/resharding/resharding_donor_service_test.cpp
@@ -34,7 +34,6 @@
#include <boost/optional/optional_io.hpp>
#include <utility>
-#include "mongo/db/concurrency/write_conflict_exception.h"
#include "mongo/db/dbdirectclient.h"
#include "mongo/db/op_observer_noop.h"
#include "mongo/db/op_observer_registry.h"
@@ -53,6 +52,7 @@
#include "mongo/db/s/resharding/resharding_donor_service.h"
#include "mongo/db/s/resharding/resharding_service_test_helpers.h"
#include "mongo/db/s/resharding/resharding_util.h"
+#include "mongo/db/s/sharding_ddl_util.h"
#include "mongo/logv2/log.h"
#include "mongo/s/catalog/sharding_catalog_client.h"
#include "mongo/unittest/death_test.h"
@@ -161,7 +161,8 @@ public:
void createSourceCollection(OperationContext* opCtx, const ReshardingDonorDocument& donorDoc) {
CollectionOptions options;
options.uuid = donorDoc.getSourceUUID();
- resharding::data_copy::ensureCollectionDropped(opCtx, donorDoc.getSourceNss());
+ mongo::sharding_ddl_util::ensureCollectionDroppedNoChangeEvent(opCtx,
+ donorDoc.getSourceNss());
resharding::data_copy::ensureCollectionExists(opCtx, donorDoc.getSourceNss(), options);
}
@@ -169,7 +170,8 @@ public:
const ReshardingDonorDocument& donorDoc) {
CollectionOptions options;
options.uuid = donorDoc.getReshardingUUID();
- resharding::data_copy::ensureCollectionDropped(opCtx, donorDoc.getTempReshardingNss());
+ mongo::sharding_ddl_util::ensureCollectionDroppedNoChangeEvent(
+ opCtx, donorDoc.getTempReshardingNss());
resharding::data_copy::ensureCollectionExists(
opCtx, donorDoc.getTempReshardingNss(), options);
}
diff --git a/src/mongo/db/s/resharding/resharding_future_util.cpp b/src/mongo/db/s/resharding/resharding_future_util.cpp
index 849a14bd80e..62c95fbaf3f 100644
--- a/src/mongo/db/s/resharding/resharding_future_util.cpp
+++ b/src/mongo/db/s/resharding/resharding_future_util.cpp
@@ -51,19 +51,42 @@ ExecutorFuture<void> whenAllSucceedOn(const std::vector<SharedSemiFuture<void>>&
: ExecutorFuture(executor);
}
+std::vector<Future<void>> runAllInlineUnsafe(const std::vector<SharedSemiFuture<void>>& futures) {
+ std::vector<Future<void>> result;
+ result.reserve(futures.size());
+
+ for (const auto& future : futures) {
+ result.emplace_back(future.unsafeToInlineFuture());
+ }
+
+ return result;
+}
+
ExecutorFuture<void> cancelWhenAnyErrorThenQuiesce(
const std::vector<SharedSemiFuture<void>>& futures,
ExecutorPtr executor,
CancellationSource cancelSource) {
- return whenAllSucceedOn(futures, executor)
- .onError([futures, executor, cancelSource](Status originalError) mutable {
+ if (futures.empty()) {
+ return ExecutorFuture(executor);
+ }
+ // Run all futures inline so that the onError callback is called even if that error was caused
+ // by the executor shutting down. This causes the logic for whenAllSucceed, whenAll, and the
+ // onError callback to potentially run on the threads of the setters of the promises
+ // associated with the input futures. Since this logic is thread safe, not blocking, and does
+ // not acquire additional resources, this is safe, but beware if making further changes to this
+ // function.
+ return whenAllSucceed(runAllInlineUnsafe(futures))
+ .unsafeToInlineFuture()
+ .onError([futures, cancelSource](Status originalError) mutable {
cancelSource.cancel();
- return whenAll(thenRunAllOn(futures, executor))
+ return whenAll(runAllInlineUnsafe(futures))
.ignoreValue()
- .thenRunOn(executor)
+ .unsafeToInlineFuture()
.onCompletion([originalError](auto) { return originalError; });
- });
+ })
+ .thenRunOn(executor);
}
+
} // namespace mongo::resharding
diff --git a/src/mongo/db/s/resharding/resharding_future_util.h b/src/mongo/db/s/resharding/resharding_future_util.h
index 0bb858a963c..78847350d0c 100644
--- a/src/mongo/db/s/resharding/resharding_future_util.h
+++ b/src/mongo/db/s/resharding/resharding_future_util.h
@@ -131,7 +131,8 @@ public:
status.isA<ErrorCategory::CursorInvalidatedError>() ||
status == ErrorCodes::Interrupted ||
status.isA<ErrorCategory::CancellationError>() ||
- status.isA<ErrorCategory::NotPrimaryError>()) {
+ status.isA<ErrorCategory::NotPrimaryError>() ||
+ status.isA<ErrorCategory::NetworkTimeoutError>()) {
// Always attempt to retry on any type of retryable error. Also retry on errors
// from stray killCursors and killOp commands being run. Cancellation and
// NotPrimary errors may indicate the primary-only service Instance will be shut
diff --git a/src/mongo/db/s/resharding/resharding_future_util_test.cpp b/src/mongo/db/s/resharding/resharding_future_util_test.cpp
new file mode 100644
index 00000000000..e37a13a314b
--- /dev/null
+++ b/src/mongo/db/s/resharding/resharding_future_util_test.cpp
@@ -0,0 +1,100 @@
+/**
+ * Copyright (C) 2022-present MongoDB, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the Server Side Public License, version 1,
+ * as published by MongoDB, Inc.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Server Side Public License for more details.
+ *
+ * You should have received a copy of the Server Side Public License
+ * along with this program. If not, see
+ * <http://www.mongodb.com/licensing/server-side-public-license>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the Server Side Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#include "mongo/db/s/resharding/resharding_future_util.h"
+#include "mongo/unittest/unittest.h"
+#include "mongo/util/concurrency/thread_pool.h"
+
+namespace mongo {
+namespace {
+class ReshardingFutureUtilTest : public unittest::Test {
+protected:
+ void setUp() override {
+ _executor = std::make_shared<ThreadPool>([]() {
+ ThreadPool::Options options;
+ options.maxThreads = 2;
+ return options;
+ }());
+ _executor->startup();
+ }
+
+ void tearDown() override {
+ _executor->shutdown();
+ _executor->join();
+ }
+
+ std::shared_ptr<ThreadPool> getExecutor() const {
+ return _executor;
+ }
+
+private:
+ std::shared_ptr<ThreadPool> _executor;
+};
+
+TEST_F(ReshardingFutureUtilTest, CancelWhenAnyErrorThenQuiesceDuringExecutorShutdown) {
+ CancellationSource cancelSource;
+ auto token = cancelSource.token();
+ PromiseAndFuture<void> taskThreadsReady;
+ AtomicWord<int> tasksRunningCount{0};
+ AtomicWord<bool> taskWasCancelled{false};
+ auto checkSignalReady = [&]() {
+ auto running = tasksRunningCount.addAndFetch(1);
+ if (running == 2) {
+ taskThreadsReady.promise.emplaceValue();
+ }
+ };
+ PromiseAndFuture<void> executorShutDownTriggered;
+ auto quiesced = ExecutorFuture(getExecutor()).then([&]() {
+ return resharding::cancelWhenAnyErrorThenQuiesce(
+ {ExecutorFuture(getExecutor())
+ .then([&]() {
+ checkSignalReady();
+ executorShutDownTriggered.future.wait();
+ uasserted(6791600, "Executor shut down");
+ })
+ .share(),
+ ExecutorFuture(getExecutor())
+ .then([&]() {
+ checkSignalReady();
+ token.onCancel().wait();
+ taskWasCancelled.store(true);
+ })
+ .share()},
+ getExecutor(),
+ cancelSource);
+ });
+ taskThreadsReady.future.wait();
+ getExecutor()->shutdown();
+ executorShutDownTriggered.promise.emplaceValue();
+ auto status = quiesced.getNoThrow();
+ ASSERT_EQ(status.code(), 6791600);
+ ASSERT_TRUE(taskWasCancelled.load());
+}
+} // namespace
+} // namespace mongo
diff --git a/src/mongo/db/s/resharding/resharding_metrics.cpp b/src/mongo/db/s/resharding/resharding_metrics.cpp
index 6e4e4e041e9..b42c9df5c9e 100644
--- a/src/mongo/db/s/resharding/resharding_metrics.cpp
+++ b/src/mongo/db/s/resharding/resharding_metrics.cpp
@@ -406,6 +406,60 @@ void ReshardingMetrics::onStepUp(Role role) noexcept {
// instead of starting from the current time.
}
+void ReshardingMetrics::onStepUp(RecipientStateEnum state,
+ const ReshardingRecipientCountsAndMetrics& recipientMetrics) {
+ stdx::lock_guard<Latch> lk(_mutex);
+
+ _emplaceCurrentOpForRole(Role::kRecipient, boost::none);
+ _onStepUpCalled = true;
+
+ invariant(_currentOp, kNoOperationInProgress);
+ invariant(_currentOp->documentsCopied == 0, kMetricsSetBeforeRestore);
+ invariant(_currentOp->bytesCopied == 0, kMetricsSetBeforeRestore);
+ invariant(_currentOp->oplogEntriesFetched == 0, kMetricsSetBeforeRestore);
+ invariant(_currentOp->oplogEntriesApplied == 0, kMetricsSetBeforeRestore);
+
+ _currentOp->recipientState = state;
+ _currentOp->documentsCopied = recipientMetrics.documentCountCopied;
+ _currentOp->bytesCopied = recipientMetrics.documentBytesCopied;
+ _currentOp->oplogEntriesFetched = recipientMetrics.oplogEntriesFetched;
+ _currentOp->oplogEntriesApplied = recipientMetrics.oplogEntriesApplied;
+
+ if (recipientMetrics.approxBytesToCopy)
+ _currentOp->bytesToCopy = recipientMetrics.approxBytesToCopy.get();
+
+
+ const auto& timeIntervals = recipientMetrics.metrics;
+
+ // Restore in memory state of document copy metrics.
+ // Not calling startCopyingDocuments or endCopyingDocuments because they acquire a mutex that we
+ // already have.
+ //
+ // Also, note that it is possible for documentCopyInterval->getStart() to be none and for
+ // documentCopyInterval->getStop() to be not none. That can happen if the cluster is upgraded
+ // to include code for persisting time intervals during a resharding operation.
+ // In that case, restore neither the start nor stop time. The resharding coordinator will still
+ // treat this scenario as the recipient shard being completely caught up after a primary
+ // failover and engage the critical section too early.
+ const auto& documentCopyInterval = timeIntervals.getDocumentCopy();
+ if (documentCopyInterval && documentCopyInterval->getStart()) {
+ _currentOp->copyingDocuments.start(documentCopyInterval->getStart().get());
+ if (documentCopyInterval->getStop()) {
+ _currentOp->copyingDocuments.end(documentCopyInterval->getStop().get());
+ }
+ }
+ // Restore in memory state of oplog application metrics.
+ // Not calling startApplyingOplogEntries or endApplyingOplogEntries because they acquire a mutex
+ // that we already have.
+ const auto& oplogApplicationInterval = timeIntervals.getOplogApplication();
+ if (oplogApplicationInterval && oplogApplicationInterval->getStart()) {
+ _currentOp->applyingOplogEntries.start(oplogApplicationInterval->getStart().get());
+ if (oplogApplicationInterval->getStop()) {
+ _currentOp->applyingOplogEntries.end(oplogApplicationInterval->getStop().get());
+ }
+ }
+}
+
void ReshardingMetrics::onStepUp(DonorStateEnum state, ReshardingDonorMetrics donorMetrics) {
stdx::lock_guard<Latch> lk(_mutex);
auto operationRuntime = donorMetrics.getOperationRuntime();
@@ -484,6 +538,9 @@ void ReshardingMetrics::setDonorState(DonorStateEnum state) noexcept {
void ReshardingMetrics::setRecipientState(RecipientStateEnum state) noexcept {
stdx::lock_guard<Latch> lk(_mutex);
+ if (!_currentOp && state == RecipientStateEnum::kDone) {
+ return;
+ }
invariant(_currentOp, kNoOperationInProgress);
const auto oldState = std::exchange(_currentOp->recipientState, state);
@@ -634,6 +691,10 @@ void ReshardingMetrics::enterCriticalSection(Date_t start) {
void ReshardingMetrics::leaveCriticalSection(Date_t end) {
stdx::lock_guard<Latch> lk(_mutex);
+ if (!_currentOp) {
+ return;
+ }
+
_currentOp->inCriticalSection.forceEnd(end);
}
@@ -662,22 +723,6 @@ void ReshardingMetrics::onOplogEntriesApplied(int64_t entries) noexcept {
_cumulativeOp->oplogEntriesApplied += entries;
}
-void ReshardingMetrics::restoreForCurrentOp(int64_t documentCountCopied,
- int64_t documentBytesCopied,
- int64_t oplogEntriesFetched,
- int64_t oplogEntriesApplied) noexcept {
- invariant(_currentOp, kNoOperationInProgress);
- invariant(_currentOp->documentsCopied == 0, kMetricsSetBeforeRestore);
- invariant(_currentOp->bytesCopied == 0, kMetricsSetBeforeRestore);
- invariant(_currentOp->oplogEntriesFetched == 0, kMetricsSetBeforeRestore);
- invariant(_currentOp->oplogEntriesApplied == 0, kMetricsSetBeforeRestore);
-
- _currentOp->documentsCopied = documentCountCopied;
- _currentOp->bytesCopied = documentBytesCopied;
- _currentOp->oplogEntriesFetched = oplogEntriesFetched;
- _currentOp->oplogEntriesApplied = oplogEntriesApplied;
-}
-
void ReshardingMetrics::onWriteDuringCriticalSection(int64_t writes) noexcept {
stdx::lock_guard<Latch> lk(_mutex);
if (!_currentOp)
diff --git a/src/mongo/db/s/resharding/resharding_metrics.h b/src/mongo/db/s/resharding/resharding_metrics.h
index a6964c9d611..9ba80d35417 100644
--- a/src/mongo/db/s/resharding/resharding_metrics.h
+++ b/src/mongo/db/s/resharding/resharding_metrics.h
@@ -35,6 +35,7 @@
#include "mongo/bson/bsonobjbuilder.h"
#include "mongo/db/namespace_string.h"
#include "mongo/db/s/resharding/donor_document_gen.h"
+#include "mongo/db/s/resharding/recipient_document_gen.h"
#include "mongo/db/service_context.h"
#include "mongo/platform/mutex.h"
#include "mongo/s/resharding/common_types_gen.h"
@@ -71,6 +72,29 @@ public:
void onStepUp(DonorStateEnum state, ReshardingDonorMetrics donorMetrics);
+ struct ReshardingRecipientCountsAndMetrics {
+ ReshardingRecipientCountsAndMetrics(int64_t documentCountCopied,
+ int64_t documentBytesCopied,
+ int64_t oplogEntriesFetched,
+ int64_t oplogEntriesApplied,
+ boost::optional<int64_t> approxBytesToCopy,
+ ReshardingRecipientMetrics metrics)
+ : documentCountCopied{documentCountCopied},
+ documentBytesCopied{documentBytesCopied},
+ oplogEntriesFetched{oplogEntriesFetched},
+ oplogEntriesApplied{oplogEntriesApplied},
+ approxBytesToCopy{approxBytesToCopy},
+ metrics{metrics} {}
+ int64_t documentCountCopied;
+ int64_t documentBytesCopied;
+ int64_t oplogEntriesFetched;
+ int64_t oplogEntriesApplied;
+ boost::optional<int64_t> approxBytesToCopy;
+ ReshardingRecipientMetrics metrics;
+ };
+
+ void onStepUp(RecipientStateEnum, const ReshardingRecipientCountsAndMetrics&);
+
// So long as a resharding operation is in progress, the following may be used to update the
// state of a donor, a recipient, and a coordinator, respectively.
void setDonorState(DonorStateEnum) noexcept;
@@ -113,11 +137,6 @@ public:
// Allows restoring "oplog entries to apply" metrics.
void onOplogEntriesApplied(int64_t entries) noexcept;
- void restoreForCurrentOp(int64_t documentCountCopied,
- int64_t documentBytesCopied,
- int64_t oplogEntriesFetched,
- int64_t oplogEntriesApplied) noexcept;
-
// Allows tracking writes during a critical section when the donor's state is either of
// "donating-oplog-entries" or "blocking-writes".
void onWriteDuringCriticalSection(int64_t writes) noexcept;
diff --git a/src/mongo/db/s/resharding/resharding_op_observer.h b/src/mongo/db/s/resharding/resharding_op_observer.h
index 30d319a041d..e8affe3ef4a 100644
--- a/src/mongo/db/s/resharding/resharding_op_observer.h
+++ b/src/mongo/db/s/resharding/resharding_op_observer.h
@@ -228,6 +228,10 @@ public:
size_t numberOfPrePostImagesToWrite,
Date_t wallClockTime) override {}
+ void onTransactionPrepareNonPrimary(OperationContext* opCtx,
+ const std::vector<repl::OplogEntry>& statements,
+ const repl::OpTime& prepareOpTime) override {}
+
void onTransactionAbort(OperationContext* opCtx,
boost::optional<OplogSlot> abortOplogEntryOpTime) override {}
diff --git a/src/mongo/db/s/resharding/resharding_oplog_application.cpp b/src/mongo/db/s/resharding/resharding_oplog_application.cpp
index 9a2f6f2750e..42c5a1543e5 100644
--- a/src/mongo/db/s/resharding/resharding_oplog_application.cpp
+++ b/src/mongo/db/s/resharding/resharding_oplog_application.cpp
@@ -29,11 +29,9 @@
#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kResharding
-#include "mongo/platform/basic.h"
-
#include "mongo/db/s/resharding/resharding_oplog_application.h"
-#include "mongo/db/concurrency/write_conflict_exception.h"
+#include "mongo/db/concurrency/exception_util.h"
#include "mongo/db/dbhelpers.h"
#include "mongo/db/index/index_access_method.h"
#include "mongo/db/logical_session_cache.h"
@@ -79,8 +77,8 @@ void runWithTransaction(OperationContext* opCtx,
// ReshardingOpObserver depends on the collection metadata being known when processing writes to
// the temporary resharding collection. We attach shard version IGNORED to the write operations
- // and leave it to ReshardingOplogBatchApplier::applyBatch() to retry on a StaleConfig exception
- // to allow the collection metadata information to be recovered.
+ // and leave it to ReshardingOplogBatchApplier::applyBatch() to retry on a StaleConfig error to
+ // allow the collection metadata information to be recovered.
ScopedSetShardRole scopedSetShardRole(asr.opCtx(),
nss,
ChunkVersion::IGNORED() /* shardVersion */,
diff --git a/src/mongo/db/s/resharding/resharding_oplog_batch_applier.cpp b/src/mongo/db/s/resharding/resharding_oplog_batch_applier.cpp
index 4ff29b42d30..c7efa6d33e4 100644
--- a/src/mongo/db/s/resharding/resharding_oplog_batch_applier.cpp
+++ b/src/mongo/db/s/resharding/resharding_oplog_batch_applier.cpp
@@ -29,12 +29,8 @@
#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kResharding
-#include "mongo/platform/basic.h"
-
#include "mongo/db/s/resharding/resharding_oplog_batch_applier.h"
-#include <memory>
-
#include "mongo/db/s/operation_sharding_state.h"
#include "mongo/db/s/resharding/resharding_data_copy_util.h"
#include "mongo/db/s/resharding/resharding_future_util.h"
@@ -83,8 +79,8 @@ SemiFuture<void> ReshardingOplogBatchApplier::applyBatch(
// ReshardingOpObserver depends on the collection metadata being known
// when processing writes to the temporary resharding collection. We
// attach shard version IGNORED to the write operations and retry once
- // on a StaleConfig exception to allow the collection metadata
- // information to be recovered.
+ // on a StaleConfig error to allow the collection metadata information to
+ // be recovered.
ScopedSetShardRole scopedSetShardRole(
opCtx.get(),
_crudApplication.getOutputNss(),
diff --git a/src/mongo/db/s/resharding/resharding_oplog_fetcher.cpp b/src/mongo/db/s/resharding/resharding_oplog_fetcher.cpp
index 30811c8d2aa..064ca34c9fa 100644
--- a/src/mongo/db/s/resharding/resharding_oplog_fetcher.cpp
+++ b/src/mongo/db/s/resharding/resharding_oplog_fetcher.cpp
@@ -41,7 +41,7 @@
#include "mongo/client/dbclient_connection.h"
#include "mongo/client/remote_command_targeter.h"
#include "mongo/db/catalog_raii.h"
-#include "mongo/db/concurrency/write_conflict_exception.h"
+#include "mongo/db/concurrency/exception_util.h"
#include "mongo/db/pipeline/aggregate_command_gen.h"
#include "mongo/db/repl/read_concern_args.h"
#include "mongo/db/repl/read_concern_level.h"
@@ -194,23 +194,22 @@ ExecutorFuture<void> ReshardingOplogFetcher::_reschedule(
}
bool ReshardingOplogFetcher::iterate(Client* client, CancelableOperationContextFactory factory) {
- std::shared_ptr<Shard> targetShard;
- {
- auto opCtxRaii = factory.makeOperationContext(client);
- opCtxRaii->checkForInterrupt();
-
- StatusWith<std::shared_ptr<Shard>> swDonor =
- Grid::get(opCtxRaii.get())->shardRegistry()->getShard(opCtxRaii.get(), _donorShard);
- if (!swDonor.isOK()) {
- LOGV2_WARNING(5127203,
- "Error finding shard in registry, retrying.",
- "error"_attr = swDonor.getStatus());
- return true;
- }
- targetShard = swDonor.getValue();
- }
-
try {
+ std::shared_ptr<Shard> targetShard;
+ {
+ auto opCtxRaii = factory.makeOperationContext(client);
+ opCtxRaii->checkForInterrupt();
+
+ StatusWith<std::shared_ptr<Shard>> swDonor =
+ Grid::get(opCtxRaii.get())->shardRegistry()->getShard(opCtxRaii.get(), _donorShard);
+ if (!swDonor.isOK()) {
+ LOGV2_WARNING(5127203,
+ "Error finding shard in registry, retrying.",
+ "error"_attr = swDonor.getStatus());
+ return true;
+ }
+ targetShard = swDonor.getValue();
+ }
return consume(client, factory, targetShard.get());
} catch (const ExceptionForCat<ErrorCategory::Interruption>&) {
// Defer to the cancellation token for whether the Interruption exception should be retried
diff --git a/src/mongo/db/s/resharding/resharding_oplog_fetcher_test.cpp b/src/mongo/db/s/resharding/resharding_oplog_fetcher_test.cpp
index e7c512e2669..b3b85758e83 100644
--- a/src/mongo/db/s/resharding/resharding_oplog_fetcher_test.cpp
+++ b/src/mongo/db/s/resharding/resharding_oplog_fetcher_test.cpp
@@ -36,7 +36,7 @@
#include "mongo/bson/bsonobj.h"
#include "mongo/db/client.h"
-#include "mongo/db/concurrency/write_conflict_exception.h"
+#include "mongo/db/concurrency/exception_util.h"
#include "mongo/db/db_raii.h"
#include "mongo/db/dbdirectclient.h"
#include "mongo/db/dbhelpers.h"
@@ -666,6 +666,44 @@ TEST_F(ReshardingOplogFetcherTest, RetriesOnRemoteInterruptionError) {
ASSERT_TRUE(moreToCome);
}
+TEST_F(ReshardingOplogFetcherTest, RetriesOnNetworkTimeoutError) {
+ const NamespaceString outputCollectionNss("dbtests.outputCollection");
+ const NamespaceString dataCollectionNss("dbtests.runFetchIteration");
+
+ create(outputCollectionNss);
+ create(dataCollectionNss);
+ _fetchTimestamp = repl::StorageInterface::get(_svcCtx)->getLatestOplogTimestamp(_opCtx);
+
+ const auto& collectionUUID = [&] {
+ AutoGetCollection dataColl(_opCtx, dataCollectionNss, LockMode::MODE_IX);
+ return dataColl->uuid();
+ }();
+
+ auto fetcherJob = launchAsync([&, this] {
+ ThreadClient tc("RunnerForFetcher", _svcCtx, nullptr);
+
+ ReshardingDonorOplogId startAt{_fetchTimestamp, _fetchTimestamp};
+ ReshardingOplogFetcher fetcher(makeFetcherEnv(),
+ _reshardingUUID,
+ collectionUUID,
+ startAt,
+ _donorShard,
+ _destinationShard,
+ outputCollectionNss);
+
+ auto factory = makeCancelableOpCtx();
+ return fetcher.iterate(&cc(), factory);
+ });
+
+ onCommand([&](const executor::RemoteCommandRequest& request) -> StatusWith<BSONObj> {
+ // Inject network timeout error.
+ return {ErrorCodes::NetworkInterfaceExceededTimeLimit, "exceeded network time limit"};
+ });
+
+ auto moreToCome = fetcherJob.timed_get(Seconds(5));
+ ASSERT_TRUE(moreToCome);
+}
+
TEST_F(ReshardingOplogFetcherTest, ImmediatelyDoneWhenFinalOpHasAlreadyBeenFetched) {
const NamespaceString outputCollectionNss("dbtests.outputCollection");
const NamespaceString dataCollectionNss("dbtests.runFetchIteration");
diff --git a/src/mongo/db/s/resharding/resharding_oplog_session_application.cpp b/src/mongo/db/s/resharding/resharding_oplog_session_application.cpp
index 44251fa39dc..80338642587 100644
--- a/src/mongo/db/s/resharding/resharding_oplog_session_application.cpp
+++ b/src/mongo/db/s/resharding/resharding_oplog_session_application.cpp
@@ -32,7 +32,7 @@
#include "mongo/db/s/resharding/resharding_oplog_session_application.h"
#include "mongo/db/catalog_raii.h"
-#include "mongo/db/concurrency/write_conflict_exception.h"
+#include "mongo/db/concurrency/exception_util.h"
#include "mongo/db/dbdirectclient.h"
#include "mongo/db/operation_context.h"
#include "mongo/db/repl/oplog_entry.h"
diff --git a/src/mongo/db/s/resharding/resharding_recipient_service.cpp b/src/mongo/db/s/resharding/resharding_recipient_service.cpp
index 5d49e0cdb22..087e3cb603f 100644
--- a/src/mongo/db/s/resharding/resharding_recipient_service.cpp
+++ b/src/mongo/db/s/resharding/resharding_recipient_service.cpp
@@ -36,7 +36,7 @@
#include "mongo/db/cancelable_operation_context.h"
#include "mongo/db/catalog/rename_collection.h"
#include "mongo/db/catalog_raii.h"
-#include "mongo/db/concurrency/write_conflict_exception.h"
+#include "mongo/db/concurrency/exception_util.h"
#include "mongo/db/dbdirectclient.h"
#include "mongo/db/dbhelpers.h"
#include "mongo/db/ops/delete.h"
@@ -56,6 +56,7 @@
#include "mongo/db/s/resharding/resharding_recipient_service_external_state.h"
#include "mongo/db/s/resharding/resharding_server_parameters_gen.h"
#include "mongo/db/s/shard_key_util.h"
+#include "mongo/db/s/sharding_ddl_util.h"
#include "mongo/db/s/sharding_state.h"
#include "mongo/db/write_block_bypass.h"
#include "mongo/executor/network_interface_factory.h"
@@ -145,6 +146,8 @@ ReshardingRecipientService::RecipientStateMachine::RecipientStateMachine(
_recipientCtx{recipientDoc.getMutableState()},
_donorShards{recipientDoc.getDonorShards()},
_cloneTimestamp{recipientDoc.getCloneTimestamp()},
+ _timeIntervals{recipientDoc.getMetrics().get_value_or({})},
+ _approxBytesToCopy{recipientDoc.getApproxBytesToCopy()},
_externalState{std::move(externalState)},
_startConfigTxnCloneAt{recipientDoc.getStartConfigTxnCloneTime()},
_markKilledExecutor(std::make_shared<ThreadPool>([] {
@@ -166,6 +169,7 @@ ReshardingRecipientService::RecipientStateMachine::RecipientStateMachine(
return donor.getShardId() == myShardId;
}) != _donorShards.end();
}()) {
+
invariant(_externalState);
}
@@ -553,6 +557,11 @@ ReshardingRecipientService::RecipientStateMachine::_makeDataReplication(Operatio
bool cloningDone) {
invariant(_cloneTimestamp);
+ // We refresh the routing information for the source collection to ensure the
+ // ReshardingOplogApplier is making its decisions according to the chunk distribution after the
+ // sharding metadata was frozen.
+ _externalState->refreshCatalogCache(opCtx, _metadata.getSourceNss());
+
auto myShardId = _externalState->myShardId(opCtx->getServiceContext());
auto sourceChunkMgr =
_externalState->getShardedCollectionRoutingInfo(opCtx, _metadata.getSourceNss());
@@ -752,7 +761,7 @@ void ReshardingRecipientService::RecipientStateMachine::_cleanupReshardingCollec
opCtx.get(), _metadata.getReshardingUUID(), _metadata.getSourceUUID(), _donorShards);
if (aborted) {
- resharding::data_copy::ensureCollectionDropped(
+ mongo::sharding_ddl_util::ensureCollectionDroppedNoChangeEvent(
opCtx.get(), _metadata.getTempReshardingNss(), _metadata.getReshardingUUID());
}
}
@@ -808,27 +817,53 @@ void ReshardingRecipientService::RecipientStateMachine::_transitionToCloning(
const CancelableOperationContextFactory& factory) {
auto newRecipientCtx = _recipientCtx;
newRecipientCtx.setState(RecipientStateEnum::kCloning);
+ auto cloningStartTime = getCurrentTime();
+
+ // Record cloning start time.
+ ReshardingMetricsTimeInterval interval;
+ interval.setStart(cloningStartTime);
+ _timeIntervals.setDocumentCopy(interval);
+
_transitionState(std::move(newRecipientCtx), boost::none, boost::none, factory);
- _metrics()->startCopyingDocuments(getCurrentTime());
+ _metrics()->startCopyingDocuments(cloningStartTime);
}
void ReshardingRecipientService::RecipientStateMachine::_transitionToApplying(
const CancelableOperationContextFactory& factory) {
auto newRecipientCtx = _recipientCtx;
newRecipientCtx.setState(RecipientStateEnum::kApplying);
+ auto oplogApplicationStartTime = getCurrentTime();
+
+ // Record oplog application start time.
+ ReshardingMetricsTimeInterval interval;
+ interval.setStart(oplogApplicationStartTime);
+ _timeIntervals.setOplogApplication(interval);
+
+ // Record document copy stop time.
+ ReshardingMetricsTimeInterval documentCopy{_timeIntervals.getDocumentCopy().get_value_or({})};
+ documentCopy.setStop(oplogApplicationStartTime);
+ _timeIntervals.setDocumentCopy(documentCopy);
+
_transitionState(std::move(newRecipientCtx), boost::none, boost::none, factory);
- auto currentTime = getCurrentTime();
- _metrics()->endCopyingDocuments(currentTime);
- _metrics()->startApplyingOplogEntries(currentTime);
+ _metrics()->endCopyingDocuments(oplogApplicationStartTime);
+ _metrics()->startApplyingOplogEntries(oplogApplicationStartTime);
}
void ReshardingRecipientService::RecipientStateMachine::_transitionToStrictConsistency(
const CancelableOperationContextFactory& factory) {
auto newRecipientCtx = _recipientCtx;
newRecipientCtx.setState(RecipientStateEnum::kStrictConsistency);
+ auto oplogApplicationStopTime = getCurrentTime();
+
+ // Record oplog application stop time
+ ReshardingMetricsTimeInterval oplogApplication{
+ _timeIntervals.getOplogApplication().get_value_or({})};
+ oplogApplication.setStop(oplogApplicationStopTime);
+ _timeIntervals.setOplogApplication(oplogApplication);
+
+
_transitionState(std::move(newRecipientCtx), boost::none, boost::none, factory);
- auto currentTime = getCurrentTime();
- _metrics()->endApplyingOplogEntries(currentTime);
+ _metrics()->endApplyingOplogEntries(oplogApplicationStopTime);
}
void ReshardingRecipientService::RecipientStateMachine::_transitionToError(
@@ -980,6 +1015,9 @@ void ReshardingRecipientService::RecipientStateMachine::_updateRecipientDocument
setBuilder.append(ReshardingRecipientDocument::kDonorShardsFieldName,
donorShardsArrayBuilder.arr());
+
+ setBuilder.append(ReshardingRecipientDocument::kApproxBytesToCopyFieldName,
+ cloneDetails->approxBytesToCopy);
}
if (configStartTime) {
@@ -987,6 +1025,8 @@ void ReshardingRecipientService::RecipientStateMachine::_updateRecipientDocument
*configStartTime);
}
+ setBuilder.append(ReshardingRecipientDocument::kMetricsFieldName, _timeIntervals.toBSON());
+
setBuilder.doneFast();
}
@@ -1004,6 +1044,7 @@ void ReshardingRecipientService::RecipientStateMachine::_updateRecipientDocument
if (cloneDetails) {
_cloneTimestamp = cloneDetails->cloneTimestamp;
_donorShards = std::move(cloneDetails->donorShards);
+ _approxBytesToCopy = cloneDetails->approxBytesToCopy;
}
if (configStartTime) {
@@ -1063,7 +1104,6 @@ ExecutorFuture<void> ReshardingRecipientService::RecipientStateMachine::_startMe
const std::shared_ptr<executor::ScopedTaskExecutor>& executor,
const CancellationToken& abortToken) {
if (_recipientCtx.getState() > RecipientStateEnum::kAwaitingFetchTimestamp) {
- _metrics()->onStepUp(ReshardingMetrics::Role::kRecipient);
return _restoreMetricsWithRetry(executor, abortToken);
}
_metrics()->onStart(ReshardingMetrics::Role::kRecipient, getCurrentTime());
@@ -1073,7 +1113,6 @@ ExecutorFuture<void> ReshardingRecipientService::RecipientStateMachine::_startMe
ExecutorFuture<void> ReshardingRecipientService::RecipientStateMachine::_restoreMetricsWithRetry(
const std::shared_ptr<executor::ScopedTaskExecutor>& executor,
const CancellationToken& abortToken) {
- _metrics()->setRecipientState(_recipientCtx.getState());
return _retryingCancelableOpCtxFactory
->withAutomaticRetry(
[this, executor, abortToken](const auto& factory) { _restoreMetrics(factory); })
@@ -1139,8 +1178,13 @@ void ReshardingRecipientService::RecipientStateMachine::_restoreMetrics(
}
}
- _metrics()->restoreForCurrentOp(
- documentCountCopied, documentBytesCopied, oplogEntriesFetched, oplogEntriesApplied);
+ _metrics()->onStepUp(_recipientCtx.getState(),
+ ReshardingMetrics::ReshardingRecipientCountsAndMetrics{documentCountCopied,
+ documentBytesCopied,
+ oplogEntriesFetched,
+ oplogEntriesApplied,
+ _approxBytesToCopy,
+ _timeIntervals});
}
CancellationToken ReshardingRecipientService::RecipientStateMachine::_initAbortSource(
diff --git a/src/mongo/db/s/resharding/resharding_recipient_service.h b/src/mongo/db/s/resharding/resharding_recipient_service.h
index e1fe504a970..86d3236b9c9 100644
--- a/src/mongo/db/s/resharding/resharding_recipient_service.h
+++ b/src/mongo/db/s/resharding/resharding_recipient_service.h
@@ -288,6 +288,8 @@ private:
RecipientShardContext _recipientCtx;
std::vector<DonorShardFetchTimestamp> _donorShards;
boost::optional<Timestamp> _cloneTimestamp;
+ ReshardingRecipientMetrics _timeIntervals;
+ boost::optional<int64_t> _approxBytesToCopy;
const std::unique_ptr<RecipientStateMachineExternalState> _externalState;
diff --git a/src/mongo/db/s/resharding/resharding_recipient_service_test.cpp b/src/mongo/db/s/resharding/resharding_recipient_service_test.cpp
index 43ccab32bec..0b6c078603d 100644
--- a/src/mongo/db/s/resharding/resharding_recipient_service_test.cpp
+++ b/src/mongo/db/s/resharding/resharding_recipient_service_test.cpp
@@ -48,10 +48,13 @@
#include "mongo/db/s/resharding/resharding_recipient_service.h"
#include "mongo/db/s/resharding/resharding_recipient_service_external_state.h"
#include "mongo/db/s/resharding/resharding_service_test_helpers.h"
+#include "mongo/db/s/sharding_ddl_util.h"
#include "mongo/logv2/log.h"
#include "mongo/unittest/death_test.h"
+#include "mongo/util/clock_source_mock.h"
#include "mongo/util/fail_point.h"
+
namespace mongo {
namespace {
@@ -208,6 +211,8 @@ public:
*/
class ReshardingRecipientServiceTest : public repl::PrimaryOnlyServiceMongoDTest {
public:
+ ReshardingRecipientServiceTest() : PrimaryOnlyServiceMongoDTest(Options{}.useMockClock(true)) {}
+
using RecipientStateMachine = ReshardingRecipientService::RecipientStateMachine;
std::unique_ptr<repl::PrimaryOnlyService> makeService(ServiceContext* serviceContext) override {
@@ -222,7 +227,6 @@ public:
repl::DropPendingCollectionReaper::set(
serviceContext, std::make_unique<repl::DropPendingCollectionReaper>(storageMock.get()));
repl::StorageInterface::set(serviceContext, std::move(storageMock));
-
_controller = std::make_shared<RecipientStateTransitionController>();
_opObserverRegistry->addObserver(std::make_unique<RecipientOpObserverForTest>(_controller));
}
@@ -263,7 +267,8 @@ public:
const ReshardingRecipientDocument& recipientDoc) {
CollectionOptions options;
options.uuid = recipientDoc.getSourceUUID();
- resharding::data_copy::ensureCollectionDropped(opCtx, recipientDoc.getSourceNss());
+ mongo::sharding_ddl_util::ensureCollectionDroppedNoChangeEvent(opCtx,
+ recipientDoc.getSourceNss());
resharding::data_copy::ensureCollectionExists(opCtx, recipientDoc.getSourceNss(), options);
}
@@ -496,69 +501,87 @@ DEATH_TEST_REGEX_F(ReshardingRecipientServiceTest, CommitFn, "4457001.*tripwire"
TEST_F(ReshardingRecipientServiceTest, DropsTemporaryReshardingCollectionOnAbort) {
auto metrics = ReshardingRecipientServiceTest::metrics();
for (bool isAlsoDonor : {false, true}) {
- LOGV2(5551107,
- "Running case",
- "test"_attr = _agent.getTestName(),
- "isAlsoDonor"_attr = isAlsoDonor);
+ for (bool waitForMetricsInitialized : {false, true}) {
+ LOGV2(5551107,
+ "Running case",
+ "test"_attr = _agent.getTestName(),
+ "isAlsoDonor"_attr = isAlsoDonor,
+ "waitForMetricsInitialized"_attr = waitForMetricsInitialized);
+
+ boost::optional<PauseDuringStateTransitions> stateTransitionGuard;
+ if (waitForMetricsInitialized) {
+ std::vector<RecipientStateEnum> recipientStates{
+ RecipientStateEnum::kDone, RecipientStateEnum::kCreatingCollection};
+ stateTransitionGuard.emplace(controller(), recipientStates);
+ } else {
+ stateTransitionGuard.emplace(controller(), RecipientStateEnum::kDone);
+ }
- boost::optional<PauseDuringStateTransitions> doneTransitionGuard;
- doneTransitionGuard.emplace(controller(), RecipientStateEnum::kDone);
+ auto doc = makeStateDocument(isAlsoDonor);
+ auto instanceId = BSON(ReshardingRecipientDocument::kReshardingUUIDFieldName
+ << doc.getReshardingUUID());
- auto doc = makeStateDocument(isAlsoDonor);
- auto instanceId =
- BSON(ReshardingRecipientDocument::kReshardingUUIDFieldName << doc.getReshardingUUID());
+ auto opCtx = makeOperationContext();
- auto opCtx = makeOperationContext();
+ if (isAlsoDonor) {
+ // If the recipient is also a donor, the original collection should already exist on
+ // this shard.
+ createSourceCollection(opCtx.get(), doc);
+ }
- if (isAlsoDonor) {
- // If the recipient is also a donor, the original collection should already exist on
- // this shard.
- createSourceCollection(opCtx.get(), doc);
- }
+ RecipientStateMachine::insertStateDocument(opCtx.get(), doc);
+ auto recipient =
+ RecipientStateMachine::getOrCreate(opCtx.get(), _service, doc.toBSON());
- RecipientStateMachine::insertStateDocument(opCtx.get(), doc);
- auto recipient = RecipientStateMachine::getOrCreate(opCtx.get(), _service, doc.toBSON());
+ notifyToStartCloning(opCtx.get(), *recipient, doc);
+ if (waitForMetricsInitialized) {
+ // Waiting for the metrics to be initialized here causes the second abort to occur
+ // before the metrics are initialized after the step up, thereby testing a different
+ // code path.
+ stateTransitionGuard->wait(RecipientStateEnum::kCreatingCollection);
+ }
- notifyToStartCloning(opCtx.get(), *recipient, doc);
- recipient->abort(false);
+ recipient->abort(false);
- doneTransitionGuard->wait(RecipientStateEnum::kDone);
- stepDown();
+ stateTransitionGuard->wait(RecipientStateEnum::kDone);
- ASSERT_EQ(recipient->getCompletionFuture().getNoThrow(),
- ErrorCodes::InterruptedDueToReplStateChange);
+ stepDown();
- recipient.reset();
- stepUp(opCtx.get());
+ ASSERT_EQ(recipient->getCompletionFuture().getNoThrow(),
+ ErrorCodes::InterruptedDueToReplStateChange);
- auto maybeRecipient = RecipientStateMachine::lookup(opCtx.get(), _service, instanceId);
- ASSERT_TRUE(bool(maybeRecipient));
- recipient = *maybeRecipient;
+ recipient.reset();
+ stepUp(opCtx.get());
- doneTransitionGuard.reset();
- recipient->abort(false);
+ auto maybeRecipient = RecipientStateMachine::lookup(opCtx.get(), _service, instanceId);
+ ASSERT_TRUE(bool(maybeRecipient));
+ recipient = *maybeRecipient;
- ASSERT_OK(recipient->getCompletionFuture().getNoThrow());
- checkStateDocumentRemoved(opCtx.get());
+ stateTransitionGuard.reset();
+ recipient->abort(false);
- if (isAlsoDonor) {
- // Verify original collection still exists after aborting.
- AutoGetCollection coll(opCtx.get(), doc.getSourceNss(), MODE_IS);
- ASSERT_TRUE(bool(coll));
- ASSERT_EQ(coll->uuid(), doc.getSourceUUID());
- }
+ ASSERT_OK(recipient->getCompletionFuture().getNoThrow());
+ checkStateDocumentRemoved(opCtx.get());
- // Verify the temporary collection no longer exists.
- {
- AutoGetCollection coll(opCtx.get(), doc.getTempReshardingNss(), MODE_IS);
- ASSERT_FALSE(bool(coll));
+ if (isAlsoDonor) {
+ // Verify original collection still exists after aborting.
+ AutoGetCollection coll(opCtx.get(), doc.getSourceNss(), MODE_IS);
+ ASSERT_TRUE(bool(coll));
+ ASSERT_EQ(coll->uuid(), doc.getSourceUUID());
+ }
+
+ // Verify the temporary collection no longer exists.
+ {
+ AutoGetCollection coll(opCtx.get(), doc.getTempReshardingNss(), MODE_IS);
+ ASSERT_FALSE(bool(coll));
+ }
}
}
BSONObjBuilder result;
metrics->serializeCumulativeOpMetrics(&result);
- ASSERT_EQ(result.obj().getField("countReshardingFailures").numberLong(), 2);
+ ASSERT_LESS_THAN_OR_EQUALS(result.obj().getField("countReshardingFailures").numberLong(), 4);
}
TEST_F(ReshardingRecipientServiceTest, RenamesTemporaryReshardingCollectionWhenDone) {
@@ -816,22 +839,33 @@ TEST_F(ReshardingRecipientServiceTest, RestoreMetricsAfterStepUp) {
}
// Step down before the transition to state can complete.
stateTransitionsGuard.wait(state);
- if (state == RecipientStateEnum::kStrictConsistency) {
- auto currOp = recipient
- ->reportForCurrentOp(
- MongoProcessInterface::CurrentOpConnectionsMode::kExcludeIdle,
- MongoProcessInterface::CurrentOpSessionsMode::kExcludeIdle)
- .get();
+
+ dynamic_cast<ClockSourceMock*>(getServiceContext()->getFastClockSource())
+ ->advance(Seconds(1));
+ auto currOp =
+ recipient
+ ->reportForCurrentOp(MongoProcessInterface::CurrentOpConnectionsMode::kExcludeIdle,
+ MongoProcessInterface::CurrentOpSessionsMode::kExcludeIdle)
+ .get();
+
+
+ if (state == RecipientStateEnum::kApplying) {
+ ASSERT_EQ(currOp.getField("totalApplyTimeElapsedSecs").Long(), 0);
+ ASSERT_EQ(currOp.getStringField("recipientState"),
+ RecipientState_serializer(RecipientStateEnum::kCloning));
+ ASSERT_GT(currOp.getField("totalCopyTimeElapsedSecs").Long(), 0);
+ ASSERT_GT(currOp.getField("approxBytesToCopy").Long(), 0);
+
+ } else if (state == RecipientStateEnum::kStrictConsistency) {
ASSERT_EQ(currOp.getField("documentsCopied").Long(), 1L);
ASSERT_EQ(currOp.getField("bytesCopied").Long(), (long)reshardedDoc.objsize());
ASSERT_EQ(currOp.getStringField("recipientState"),
RecipientState_serializer(RecipientStateEnum::kApplying));
+ ASSERT_GT(currOp.getField("totalCopyTimeElapsedSecs").Long(), 0);
+ ASSERT_GT(currOp.getField("totalApplyTimeElapsedSecs").Long(), 0);
+ ASSERT_GT(currOp.getField("approxBytesToCopy").Long(), 0);
+
} else if (state == RecipientStateEnum::kDone) {
- auto currOp = recipient
- ->reportForCurrentOp(
- MongoProcessInterface::CurrentOpConnectionsMode::kExcludeIdle,
- MongoProcessInterface::CurrentOpSessionsMode::kExcludeIdle)
- .get();
ASSERT_EQ(currOp.getField("documentsCopied").Long(), 1L);
ASSERT_EQ(currOp.getField("bytesCopied").Long(), (long)reshardedDoc.objsize());
ASSERT_EQ(currOp.getField("oplogEntriesFetched").Long(),
@@ -840,7 +874,11 @@ TEST_F(ReshardingRecipientServiceTest, RestoreMetricsAfterStepUp) {
oplogEntriesAppliedOnEachDonor * doc.getDonorShards().size());
ASSERT_EQ(currOp.getStringField("recipientState"),
RecipientState_serializer(RecipientStateEnum::kStrictConsistency));
+ ASSERT_GT(currOp.getField("totalCopyTimeElapsedSecs").Long(), 0);
+ ASSERT_GT(currOp.getField("totalApplyTimeElapsedSecs").Long(), 0);
+ ASSERT_GT(currOp.getField("approxBytesToCopy").Long(), 0);
}
+
stepDown();
ASSERT_EQ(recipient->getCompletionFuture().getNoThrow(),
diff --git a/src/mongo/db/s/resharding/resharding_txn_cloner.cpp b/src/mongo/db/s/resharding/resharding_txn_cloner.cpp
index 7ab491286f3..764a32d68d5 100644
--- a/src/mongo/db/s/resharding/resharding_txn_cloner.cpp
+++ b/src/mongo/db/s/resharding/resharding_txn_cloner.cpp
@@ -40,7 +40,6 @@
#include "mongo/client/read_preference.h"
#include "mongo/db/client.h"
#include "mongo/db/concurrency/d_concurrency.h"
-#include "mongo/db/concurrency/write_conflict_exception.h"
#include "mongo/db/curop.h"
#include "mongo/db/logical_session_id.h"
#include "mongo/db/namespace_string.h"
diff --git a/src/mongo/db/s/resharding/resharding_util.cpp b/src/mongo/db/s/resharding/resharding_util.cpp
index 27d319264dd..3f06e12a291 100644
--- a/src/mongo/db/s/resharding/resharding_util.cpp
+++ b/src/mongo/db/s/resharding/resharding_util.cpp
@@ -38,7 +38,7 @@
#include "mongo/bson/bsonobj.h"
#include "mongo/bson/json.h"
#include "mongo/bson/util/bson_extract.h"
-#include "mongo/db/concurrency/write_conflict_exception.h"
+#include "mongo/db/concurrency/exception_util.h"
#include "mongo/db/exec/document_value/document.h"
#include "mongo/db/namespace_string.h"
#include "mongo/db/op_observer.h"