summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo')
-rw-r--r--src/mongo/db/s/collection_metadata.cpp33
-rw-r--r--src/mongo/db/s/collection_metadata.h6
-rw-r--r--src/mongo/db/s/collection_metadata_test.cpp60
-rw-r--r--src/mongo/db/s/resharding/resharding_donor_service.cpp57
-rw-r--r--src/mongo/db/s/resharding/resharding_donor_service.h4
-rw-r--r--src/mongo/db/s/scoped_collection_metadata.h6
6 files changed, 115 insertions, 51 deletions
diff --git a/src/mongo/db/s/collection_metadata.cpp b/src/mongo/db/s/collection_metadata.cpp
index d72b013b9ac..43233ae94ca 100644
--- a/src/mongo/db/s/collection_metadata.cpp
+++ b/src/mongo/db/s/collection_metadata.cpp
@@ -33,6 +33,8 @@
#include "mongo/db/s/collection_metadata.h"
+#include <fmt/format.h>
+
#include "mongo/bson/simple_bsonobj_comparator.h"
#include "mongo/bson/util/builder.h"
#include "mongo/db/bson/dotted_path_support.h"
@@ -41,6 +43,8 @@
namespace mongo {
+using namespace fmt::literals;
+
CollectionMetadata::CollectionMetadata(ChunkManager cm, const ShardId& thisShardId)
: _cm(std::move(cm)), _thisShardId(thisShardId) {}
@@ -90,8 +94,8 @@ boost::optional<ShardKeyPattern> CollectionMetadata::getReshardingKeyIfShouldFor
return ShardKeyPattern(donorFields->getReshardingKey());
}
-bool CollectionMetadata::writesShouldRunInDistributedTransaction(const OID& originalEpoch,
- const OID& reshardingEpoch) const {
+bool CollectionMetadata::writesShouldRunInDistributedTransaction(const UUID& originalUUID,
+ const UUID& reshardingUUID) const {
auto reshardingFields = getReshardingFields();
if (!reshardingFields)
return false;
@@ -114,23 +118,20 @@ bool CollectionMetadata::writesShouldRunInDistributedTransaction(const OID& orig
}
// Handle kRenaming:
- auto chunkVersion = getCollVersion();
- uassert(ErrorCodes::NamespaceNotSharded,
- str::stream() << "Collection is not sharded, original epoch: " << originalEpoch,
- chunkVersion != ChunkVersion::UNSHARDED());
+ auto currentCollectionUUID = *_cm->getUUID();
- const auto& collectionCurrentEpoch = chunkVersion.epoch();
-
- // Renaming has not completed:
- if (collectionCurrentEpoch == originalEpoch)
+ // Renaming has not completed
+ if (currentCollectionUUID == originalUUID) {
return true;
+ }
- // Else, renaming must have completed, and myEpoch must be equal to reshardingEpoch.
- uassert(5169400,
- str::stream() << "Invalid epoch; current epoch " << collectionCurrentEpoch
- << " does not match original epoch " << originalEpoch
- << " or resharding epoch " << reshardingEpoch,
- collectionCurrentEpoch == reshardingEpoch);
+ // Else, renaming must have completed, and the new UUID must be equal to the resharding UUID.
+ uassert(ErrorCodes::InvalidUUID,
+ "Expected collection to have either the original UUID {} or the resharding UUID {}, "
+ "but the collection instead has UUID {}"_format(originalUUID.toString(),
+ reshardingUUID.toString(),
+ currentCollectionUUID.toString()),
+ currentCollectionUUID == reshardingUUID);
return false;
}
diff --git a/src/mongo/db/s/collection_metadata.h b/src/mongo/db/s/collection_metadata.h
index a0b7d5cc6c7..e225dd570cd 100644
--- a/src/mongo/db/s/collection_metadata.h
+++ b/src/mongo/db/s/collection_metadata.h
@@ -80,10 +80,10 @@ public:
/**
* Writes should run in distributed transactions when
* 1. The coordinator is between the mirroring and committed states, OR
- * 2. The coordinator is in the renaming state, but the epoch is still the original epoch.
+ * 2. The coordinator is in the renaming state, but the UUID is still the original UUID.
*/
- bool writesShouldRunInDistributedTransaction(const OID& originalEpoch,
- const OID& reshardingEpoch) const;
+ bool writesShouldRunInDistributedTransaction(const UUID& originalUUID,
+ const UUID& reshardingUUID) const;
/**
* Returns the current shard version for the collection or UNSHARDED if it is not sharded.
diff --git a/src/mongo/db/s/collection_metadata_test.cpp b/src/mongo/db/s/collection_metadata_test.cpp
index fe0935fe41d..c42989221ef 100644
--- a/src/mongo/db/s/collection_metadata_test.cpp
+++ b/src/mongo/db/s/collection_metadata_test.cpp
@@ -46,6 +46,7 @@ CollectionMetadata makeCollectionMetadataImpl(
const KeyPattern& shardKeyPattern,
const std::vector<std::pair<BSONObj, BSONObj>>& thisShardsChunks,
bool staleChunkManager,
+ UUID uuid = UUID::gen(),
CoordinatorStateEnum state = CoordinatorStateEnum::kInitializing) {
const OID epoch = OID::gen();
@@ -85,10 +86,10 @@ CollectionMetadata makeCollectionMetadataImpl(
return CollectionMetadata(
ChunkManager(kThisShard,
- DatabaseVersion(UUID::gen()),
+ DatabaseVersion(uuid),
ShardingTestFixtureCommon::makeStandaloneRoutingTableHistory(
RoutingTableHistory::makeNew(kNss,
- UUID::gen(),
+ uuid,
shardKeyPattern,
nullptr,
false,
@@ -108,8 +109,9 @@ struct ConstructedRangeMap : public RangeMap {
class NoChunkFixture : public unittest::Test {
protected:
CollectionMetadata makeCollectionMetadata(
+ UUID uuid = UUID::gen(),
CoordinatorStateEnum state = CoordinatorStateEnum::kInitializing) const {
- return makeCollectionMetadataImpl(KeyPattern(BSON("a" << 1)), {}, false, state);
+ return makeCollectionMetadataImpl(KeyPattern(BSON("a" << 1)), {}, false, uuid, state);
}
};
@@ -180,28 +182,44 @@ TEST_F(NoChunkFixture, OrphanedDataRangeEnd) {
ASSERT(!metadata.getNextOrphanRange(pending, metadata.getMaxKey()));
}
+TEST_F(NoChunkFixture, WritesShouldRunInDistributedTxnRenamingOrigUUID) {
+ UUID originalUUID = UUID::gen();
+ UUID reshardingUUID = UUID::gen();
+
+ // kRenaming is the only state where UUIDs will be compared.
+ auto metadata(makeCollectionMetadata(originalUUID, CoordinatorStateEnum::kRenaming));
+
+ // Writes should run in a distributed txn if the collection metadata's UUID matches
+ // the original collection's UUID.
+ ASSERT(metadata.writesShouldRunInDistributedTransaction(originalUUID, reshardingUUID));
+}
+
+TEST_F(NoChunkFixture, WritesShouldRunInDistributedTxnRenamingCheckReshardingUUID) {
+ UUID originalUUID = UUID::gen();
+ UUID reshardingUUID = UUID::gen();
+
+ // kRenaming is the only state where UUIDs will be compared.
+ auto metadata(makeCollectionMetadata(reshardingUUID, CoordinatorStateEnum::kRenaming));
+
+ // Writes should NOT run in a distributed txn when the UUID matches the temp collection's
+ // UUID.
+ ASSERT(!metadata.writesShouldRunInDistributedTransaction(originalUUID, reshardingUUID));
+}
+
TEST_F(NoChunkFixture, WritesShouldRunInDistributedTxnRenamingCheck) {
- auto metadata(makeCollectionMetadata(CoordinatorStateEnum::kRenaming));
- // We are in kRenaming by default.
- OID originalEpoch = OID::gen();
- OID reshardingEpoch = OID::gen();
-
- // Writes should run in a distributed txn if the collection metadata's epoch matches
- // the original collection's epoch.
- ASSERT(metadata.writesShouldRunInDistributedTransaction(metadata.getCollVersion().epoch(),
- reshardingEpoch));
-
- // Writes should NOT run in a distributed txn when the epoch matches the temp collection's
- // epoch.
- ASSERT(!metadata.writesShouldRunInDistributedTransaction(originalEpoch,
- metadata.getCollVersion().epoch()));
-
- // If the collection's epoch matches neither the original epoch nor the resharding epoch,
+ UUID originalUUID = UUID::gen();
+ UUID reshardingUUID = UUID::gen();
+ UUID rogueUUID = UUID::gen();
+
+ // kRenaming is the only state where UUIDs will be compared.
+ auto metadata(makeCollectionMetadata(rogueUUID, CoordinatorStateEnum::kRenaming));
+
+ // If the collection's UUID matches neither the original UUID nor the resharding UUID,
// expect a throw.
ASSERT_THROWS_CODE(
- metadata.writesShouldRunInDistributedTransaction(originalEpoch, reshardingEpoch),
+ metadata.writesShouldRunInDistributedTransaction(originalUUID, reshardingUUID),
AssertionException,
- 5169400);
+ ErrorCodes::InvalidUUID);
}
/**
diff --git a/src/mongo/db/s/resharding/resharding_donor_service.cpp b/src/mongo/db/s/resharding/resharding_donor_service.cpp
index 62e7ecfd334..c2bc7ed409b 100644
--- a/src/mongo/db/s/resharding/resharding_donor_service.cpp
+++ b/src/mongo/db/s/resharding/resharding_donor_service.cpp
@@ -31,6 +31,9 @@
#include "mongo/db/s/resharding/resharding_donor_service.h"
+#include <fmt/format.h>
+
+#include "mongo/db/catalog/drop_collection.h"
#include "mongo/db/catalog_raii.h"
#include "mongo/db/concurrency/write_conflict_exception.h"
#include "mongo/db/dbdirectclient.h"
@@ -45,19 +48,27 @@
#include "mongo/s/grid.h"
namespace mongo {
+
+using namespace fmt::literals;
+
namespace {
-void refreshTemporaryReshardingCollection(const ReshardingDonorDocument& donorDoc) {
+ChunkManager getShardedCollectionRoutingInfoWithRefreshAndFlush(const NamespaceString& nss) {
auto opCtx = cc().makeOperationContext();
+ auto swRoutingInfo = Grid::get(opCtx.get())
+ ->catalogCache()
+ ->getShardedCollectionRoutingInfoWithRefresh(opCtx.get(), nss);
+ auto routingInfo = uassertStatusOK(swRoutingInfo);
+
+ CatalogCacheLoader::get(opCtx.get()).waitForCollectionFlush(opCtx.get(), nss);
+
+ return routingInfo;
+}
+
+void refreshTemporaryReshardingCollection(const ReshardingDonorDocument& donorDoc) {
auto tempNss =
constructTemporaryReshardingNss(donorDoc.getNss().db(), donorDoc.getExistingUUID());
-
- auto tempNssRoutingInfo =
- Grid::get(opCtx.get())
- ->catalogCache()
- ->getShardedCollectionRoutingInfoWithRefresh(opCtx.get(), tempNss);
- uassertStatusOK(tempNssRoutingInfo);
- CatalogCacheLoader::get(opCtx.get()).waitForCollectionFlush(opCtx.get(), tempNss);
+ std::ignore = getShardedCollectionRoutingInfoWithRefreshAndFlush(tempNss);
}
Timestamp generateMinFetchTimestamp(const ReshardingDonorDocument& donorDoc) {
@@ -269,9 +280,39 @@ void ReshardingDonorService::DonorStateMachine::_dropOriginalCollectionThenDelet
return;
}
+ auto origNssRoutingInfo =
+ getShardedCollectionRoutingInfoWithRefreshAndFlush(_donorDoc.getNss());
+ auto currentCollectionUUID =
+ getCollectionUUIDFromChunkManger(_donorDoc.getNss(), origNssRoutingInfo);
+
+ if (currentCollectionUUID == _donorDoc.getExistingUUID()) {
+ _dropOriginalCollection();
+ } else {
+ uassert(ErrorCodes::InvalidUUID,
+ "Expected collection {} to have either the original UUID {} or the resharding UUID"
+ " {}, but the collection instead has UUID {}"_format(
+ _donorDoc.getNss().toString(),
+ _donorDoc.getExistingUUID().toString(),
+ _donorDoc.get_id().toString(),
+ currentCollectionUUID.toString()),
+ currentCollectionUUID == _donorDoc.get_id());
+ }
+
_transitionStateAndUpdateCoordinator(DonorStateEnum::kDone);
}
+void ReshardingDonorService::DonorStateMachine::_dropOriginalCollection() {
+ DBDirectClient client(cc().makeOperationContext().get());
+ BSONObj dropResult;
+ if (!client.dropCollection(
+ _donorDoc.getNss().toString(), WriteConcerns::kMajorityWriteConcern, &dropResult)) {
+ auto dropStatus = getStatusFromCommandResult(dropResult);
+ if (dropStatus != ErrorCodes::NamespaceNotFound) {
+ uassertStatusOK(dropStatus);
+ }
+ }
+}
+
void ReshardingDonorService::DonorStateMachine::_transitionState(
DonorStateEnum endState, boost::optional<Timestamp> minFetchTimestamp) {
ReshardingDonorDocument replacementDoc(_donorDoc);
diff --git a/src/mongo/db/s/resharding/resharding_donor_service.h b/src/mongo/db/s/resharding/resharding_donor_service.h
index b1b837f5381..0a0d39c13cd 100644
--- a/src/mongo/db/s/resharding/resharding_donor_service.h
+++ b/src/mongo/db/s/resharding/resharding_donor_service.h
@@ -117,6 +117,10 @@ private:
void _dropOriginalCollectionThenDeleteLocalState();
+ // Drops the original collection and throws if the returned status is not either Status::OK()
+ // or NamespaceNotFound.
+ void _dropOriginalCollection();
+
// Transitions the state on-disk and in-memory to 'endState'.
void _transitionState(DonorStateEnum endState,
boost::optional<Timestamp> minFetchTimestamp = boost::none);
diff --git a/src/mongo/db/s/scoped_collection_metadata.h b/src/mongo/db/s/scoped_collection_metadata.h
index 40cef70599e..55252ba6bf9 100644
--- a/src/mongo/db/s/scoped_collection_metadata.h
+++ b/src/mongo/db/s/scoped_collection_metadata.h
@@ -57,9 +57,9 @@ public:
return _impl->get().isSharded();
}
- bool writesShouldRunInDistributedTransaction(const OID& originalEpoch,
- const OID& reshardingEpoch) const {
- return _impl->get().writesShouldRunInDistributedTransaction(originalEpoch, reshardingEpoch);
+ bool writesShouldRunInDistributedTransaction(const UUID& originalUUID,
+ const UUID& reshardingUUID) const {
+ return _impl->get().writesShouldRunInDistributedTransaction(originalUUID, reshardingUUID);
}
bool isValidKey(const BSONObj& key) const {