diff options
-rw-r--r-- | src/mongo/db/s/collection_metadata_filtering_test.cpp | 5 | ||||
-rw-r--r-- | src/mongo/db/s/collection_metadata_test.cpp | 198 | ||||
-rw-r--r-- | src/mongo/db/s/collection_sharding_runtime_test.cpp | 61 | ||||
-rw-r--r-- | src/mongo/db/s/metadata_manager_test.cpp | 17 | ||||
-rw-r--r-- | src/mongo/db/s/migration_chunk_cloner_source_legacy_test.cpp | 11 | ||||
-rw-r--r-- | src/mongo/db/s/op_observer_sharding_test.cpp | 54 | ||||
-rw-r--r-- | src/mongo/db/s/range_deletion_util_test.cpp | 13 | ||||
-rw-r--r-- | src/mongo/s/catalog_cache.cpp | 22 | ||||
-rw-r--r-- | src/mongo/s/chunk_manager.cpp | 19 | ||||
-rw-r--r-- | src/mongo/s/chunk_manager.h | 6 | ||||
-rw-r--r-- | src/mongo/s/chunk_manager_query_test.cpp | 6 | ||||
-rw-r--r-- | src/mongo/s/chunk_manager_refresh_bm.cpp | 37 | ||||
-rw-r--r-- | src/mongo/s/routing_table_history_test.cpp | 152 | ||||
-rw-r--r-- | src/mongo/s/sharding_test_fixture_common.cpp | 5 | ||||
-rw-r--r-- | src/mongo/s/sharding_test_fixture_common.h | 10 |
15 files changed, 329 insertions, 287 deletions
diff --git a/src/mongo/db/s/collection_metadata_filtering_test.cpp b/src/mongo/db/s/collection_metadata_filtering_test.cpp index 0aa4438b5a8..ddeb8f1c7ba 100644 --- a/src/mongo/db/s/collection_metadata_filtering_test.cpp +++ b/src/mongo/db/s/collection_metadata_filtering_test.cpp @@ -103,7 +103,10 @@ protected: return std::vector<ChunkType>{chunk1, chunk2, chunk3, chunk4}; }()); - ChunkManager cm(ShardId("0"), DatabaseVersion(UUID::gen(), 1), rt, boost::none); + ChunkManager cm(ShardId("0"), + DatabaseVersion(UUID::gen(), 1), + makeStandaloneRoutingTableHistory(std::move(rt)), + boost::none); ASSERT_EQ(4, cm.numChunks()); { diff --git a/src/mongo/db/s/collection_metadata_test.cpp b/src/mongo/db/s/collection_metadata_test.cpp index c26be5b2795..0c343a5ed37 100644 --- a/src/mongo/db/s/collection_metadata_test.cpp +++ b/src/mongo/db/s/collection_metadata_test.cpp @@ -29,13 +29,12 @@ #include "mongo/platform/basic.h" -#include <memory> - #include "mongo/base/status.h" #include "mongo/db/range_arithmetic.h" #include "mongo/db/s/collection_metadata.h" #include "mongo/s/catalog/type_chunk.h" #include "mongo/s/chunk_version.h" +#include "mongo/s/sharding_test_fixture_common.h" #include "mongo/unittest/unittest.h" namespace mongo { @@ -43,7 +42,7 @@ namespace { using unittest::assertGet; -std::unique_ptr<CollectionMetadata> makeCollectionMetadataImpl( +CollectionMetadata makeCollectionMetadataImpl( const KeyPattern& shardKeyPattern, const std::vector<std::pair<BSONObj, BSONObj>>& thisShardsChunks, bool staleChunkManager) { @@ -73,17 +72,27 @@ std::unique_ptr<CollectionMetadata> makeCollectionMetadataImpl( version.incMajor(); nextMinKey = myNextChunk.second; } + if (SimpleBSONObjComparator::kInstance.evaluate(nextMinKey < shardKeyPattern.globalMax())) { allChunks.emplace_back( kNss, ChunkRange{nextMinKey, shardKeyPattern.globalMax()}, version, kOtherShard); allChunks.back().setHistory({ChunkHistory(kRouting, kOtherShard)}); } - UUID uuid(UUID::gen()); - auto rt = RoutingTableHistory::makeNew( - kNss, uuid, shardKeyPattern, nullptr, false, epoch, boost::none, allChunks); - return std::make_unique<CollectionMetadata>( - ChunkManager(kThisShard, DatabaseVersion(UUID::gen(), 1), rt, kChunkManager), kThisShard); + return CollectionMetadata( + ChunkManager(kThisShard, + DatabaseVersion(UUID::gen(), 1), + ShardingTestFixtureCommon::makeStandaloneRoutingTableHistory( + RoutingTableHistory::makeNew(kNss, + UUID::gen(), + shardKeyPattern, + nullptr, + false, + epoch, + boost::none, + allChunks)), + kChunkManager), + kThisShard); } struct ConstructedRangeMap : public RangeMap { @@ -93,38 +102,38 @@ struct ConstructedRangeMap : public RangeMap { class NoChunkFixture : public unittest::Test { protected: - std::unique_ptr<CollectionMetadata> makeCollectionMetadata() const { + CollectionMetadata makeCollectionMetadata() const { return makeCollectionMetadataImpl(KeyPattern(BSON("a" << 1)), {}, false); } }; TEST_F(NoChunkFixture, KeyBelongsToMe) { - ASSERT(!makeCollectionMetadata()->keyBelongsToMe(BSON("a" << MINKEY))); - ASSERT(!makeCollectionMetadata()->keyBelongsToMe(BSON("a" << 10))); - ASSERT(!makeCollectionMetadata()->keyBelongsToMe(BSON("a" << MINKEY))); + ASSERT(!makeCollectionMetadata().keyBelongsToMe(BSON("a" << MINKEY))); + ASSERT(!makeCollectionMetadata().keyBelongsToMe(BSON("a" << 10))); + ASSERT(!makeCollectionMetadata().keyBelongsToMe(BSON("a" << MINKEY))); - ASSERT(!makeCollectionMetadata()->keyBelongsToMe(BSONObj())); + ASSERT(!makeCollectionMetadata().keyBelongsToMe(BSONObj())); } TEST_F(NoChunkFixture, IsValidKey) { - ASSERT(makeCollectionMetadata()->isValidKey(BSON("a" + ASSERT(makeCollectionMetadata().isValidKey(BSON("a" + << "abcde"))); + ASSERT(makeCollectionMetadata().isValidKey(BSON("a" << 3))); + ASSERT(!makeCollectionMetadata().isValidKey(BSON("a" + << "abcde" + << "b" << 1))); + ASSERT(!makeCollectionMetadata().isValidKey(BSON("c" << "abcde"))); - ASSERT(makeCollectionMetadata()->isValidKey(BSON("a" << 3))); - ASSERT(!makeCollectionMetadata()->isValidKey(BSON("a" - << "abcde" - << "b" << 1))); - ASSERT(!makeCollectionMetadata()->isValidKey(BSON("c" - << "abcde"))); } TEST_F(NoChunkFixture, GetNextChunk) { ChunkType nextChunk; ASSERT( - !makeCollectionMetadata()->getNextChunk(makeCollectionMetadata()->getMinKey(), &nextChunk)); + !makeCollectionMetadata().getNextChunk(makeCollectionMetadata().getMinKey(), &nextChunk)); } TEST_F(NoChunkFixture, RangeOverlapsChunk) { - ASSERT(!makeCollectionMetadata()->rangeOverlapsChunk( + ASSERT(!makeCollectionMetadata().rangeOverlapsChunk( ChunkRange{BSON("a" << 100), BSON("a" << 200)})); } @@ -132,15 +141,15 @@ TEST_F(NoChunkFixture, OrphanedDataRangeBegin) { auto metadata(makeCollectionMetadata()); ConstructedRangeMap pending; - BSONObj lookupKey = metadata->getMinKey(); - auto keyRange = metadata->getNextOrphanRange(pending, lookupKey); + BSONObj lookupKey = metadata.getMinKey(); + auto keyRange = metadata.getNextOrphanRange(pending, lookupKey); ASSERT(keyRange); - ASSERT(keyRange->getMin().woCompare(metadata->getMinKey()) == 0); - ASSERT(keyRange->getMax().woCompare(metadata->getMaxKey()) == 0); + ASSERT(keyRange->getMin().woCompare(metadata.getMinKey()) == 0); + ASSERT(keyRange->getMax().woCompare(metadata.getMaxKey()) == 0); // Make sure we don't have any more ranges - ASSERT(!metadata->getNextOrphanRange(pending, keyRange->getMax())); + ASSERT(!metadata.getNextOrphanRange(pending, keyRange->getMax())); } TEST_F(NoChunkFixture, OrphanedDataRangeMiddle) { @@ -148,21 +157,21 @@ TEST_F(NoChunkFixture, OrphanedDataRangeMiddle) { ConstructedRangeMap pending; BSONObj lookupKey = BSON("a" << 20); - auto keyRange = metadata->getNextOrphanRange(pending, lookupKey); + auto keyRange = metadata.getNextOrphanRange(pending, lookupKey); ASSERT(keyRange); - ASSERT(keyRange->getMin().woCompare(metadata->getMinKey()) == 0); - ASSERT(keyRange->getMax().woCompare(metadata->getMaxKey()) == 0); + ASSERT(keyRange->getMin().woCompare(metadata.getMinKey()) == 0); + ASSERT(keyRange->getMax().woCompare(metadata.getMaxKey()) == 0); // Make sure we don't have any more ranges - ASSERT(!metadata->getNextOrphanRange(pending, keyRange->getMax())); + ASSERT(!metadata.getNextOrphanRange(pending, keyRange->getMax())); } TEST_F(NoChunkFixture, OrphanedDataRangeEnd) { auto metadata(makeCollectionMetadata()); ConstructedRangeMap pending; - ASSERT(!metadata->getNextOrphanRange(pending, metadata->getMaxKey())); + ASSERT(!metadata.getNextOrphanRange(pending, metadata.getMaxKey())); } /** @@ -171,31 +180,30 @@ TEST_F(NoChunkFixture, OrphanedDataRangeEnd) { */ class SingleChunkFixture : public unittest::Test { protected: - std::unique_ptr<CollectionMetadata> makeCollectionMetadata() const { + CollectionMetadata makeCollectionMetadata() const { return makeCollectionMetadataImpl( KeyPattern(BSON("a" << 1)), {std::make_pair(BSON("a" << 10), BSON("a" << 20))}, false); } }; TEST_F(SingleChunkFixture, KeyBelongsToMe) { - ASSERT(makeCollectionMetadata()->keyBelongsToMe(BSON("a" << 10))); - ASSERT(makeCollectionMetadata()->keyBelongsToMe(BSON("a" << 15))); - ASSERT(makeCollectionMetadata()->keyBelongsToMe(BSON("a" << 19))); - - ASSERT(!makeCollectionMetadata()->keyBelongsToMe(BSON("a" << 0))); - ASSERT(!makeCollectionMetadata()->keyBelongsToMe(BSON("a" << 9))); - ASSERT(!makeCollectionMetadata()->keyBelongsToMe(BSON("a" << 20))); - ASSERT(!makeCollectionMetadata()->keyBelongsToMe(BSON("a" << 1234))); - ASSERT(!makeCollectionMetadata()->keyBelongsToMe(BSON("a" << MINKEY))); - ASSERT(!makeCollectionMetadata()->keyBelongsToMe(BSON("a" << MAXKEY))); - - ASSERT(!makeCollectionMetadata()->keyBelongsToMe(BSONObj())); + ASSERT(makeCollectionMetadata().keyBelongsToMe(BSON("a" << 10))); + ASSERT(makeCollectionMetadata().keyBelongsToMe(BSON("a" << 15))); + ASSERT(makeCollectionMetadata().keyBelongsToMe(BSON("a" << 19))); + + ASSERT(!makeCollectionMetadata().keyBelongsToMe(BSON("a" << 0))); + ASSERT(!makeCollectionMetadata().keyBelongsToMe(BSON("a" << 9))); + ASSERT(!makeCollectionMetadata().keyBelongsToMe(BSON("a" << 20))); + ASSERT(!makeCollectionMetadata().keyBelongsToMe(BSON("a" << 1234))); + ASSERT(!makeCollectionMetadata().keyBelongsToMe(BSON("a" << MINKEY))); + ASSERT(!makeCollectionMetadata().keyBelongsToMe(BSON("a" << MAXKEY))); + + ASSERT(!makeCollectionMetadata().keyBelongsToMe(BSONObj())); } TEST_F(SingleChunkFixture, GetNextChunk) { ChunkType nextChunk; - ASSERT( - makeCollectionMetadata()->getNextChunk(makeCollectionMetadata()->getMinKey(), &nextChunk)); + ASSERT(makeCollectionMetadata().getNextChunk(makeCollectionMetadata().getMinKey(), &nextChunk)); ASSERT_EQUALS(0, nextChunk.getMin().woCompare(BSON("a" << 10))); ASSERT_EQUALS(0, nextChunk.getMax().woCompare(BSON("a" << 20))); } @@ -203,37 +211,37 @@ TEST_F(SingleChunkFixture, GetNextChunk) { TEST_F(SingleChunkFixture, GetNextChunkShouldFindNothing) { ChunkType nextChunk; ASSERT( - !makeCollectionMetadata()->getNextChunk(makeCollectionMetadata()->getMaxKey(), &nextChunk)); + !makeCollectionMetadata().getNextChunk(makeCollectionMetadata().getMaxKey(), &nextChunk)); } TEST_F(SingleChunkFixture, RangeOverlapsChunk) { - ASSERT(!makeCollectionMetadata()->rangeOverlapsChunk( - ChunkRange{BSON("a" << 20), BSON("a" << 30)})); - ASSERT(!makeCollectionMetadata()->rangeOverlapsChunk( + ASSERT( + !makeCollectionMetadata().rangeOverlapsChunk(ChunkRange{BSON("a" << 20), BSON("a" << 30)})); + ASSERT(!makeCollectionMetadata().rangeOverlapsChunk( ChunkRange{BSON("a" << 100), BSON("a" << 200)})); ASSERT( - !makeCollectionMetadata()->rangeOverlapsChunk(ChunkRange{BSON("a" << 0), BSON("a" << 10)})); + !makeCollectionMetadata().rangeOverlapsChunk(ChunkRange{BSON("a" << 0), BSON("a" << 10)})); ASSERT( - makeCollectionMetadata()->rangeOverlapsChunk(ChunkRange{BSON("a" << 11), BSON("a" << 19)})); + makeCollectionMetadata().rangeOverlapsChunk(ChunkRange{BSON("a" << 11), BSON("a" << 19)})); ASSERT( - makeCollectionMetadata()->rangeOverlapsChunk(ChunkRange{BSON("a" << 19), BSON("a" << 20)})); + makeCollectionMetadata().rangeOverlapsChunk(ChunkRange{BSON("a" << 19), BSON("a" << 20)})); } TEST_F(SingleChunkFixture, ChunkOrphanedDataRanges) { ConstructedRangeMap pending; - auto keyRange = makeCollectionMetadata()->getNextOrphanRange( - pending, makeCollectionMetadata()->getMinKey()); + auto keyRange = + makeCollectionMetadata().getNextOrphanRange(pending, makeCollectionMetadata().getMinKey()); ASSERT(keyRange); - ASSERT(keyRange->getMin().woCompare(makeCollectionMetadata()->getMinKey()) == 0); + ASSERT(keyRange->getMin().woCompare(makeCollectionMetadata().getMinKey()) == 0); ASSERT(keyRange->getMax().woCompare(BSON("a" << 10)) == 0); - keyRange = makeCollectionMetadata()->getNextOrphanRange(pending, keyRange->getMax()); + keyRange = makeCollectionMetadata().getNextOrphanRange(pending, keyRange->getMax()); ASSERT(keyRange); ASSERT(keyRange->getMin().woCompare(BSON("a" << 20)) == 0); - ASSERT(keyRange->getMax().woCompare(makeCollectionMetadata()->getMaxKey()) == 0); + ASSERT(keyRange->getMax().woCompare(makeCollectionMetadata().getMaxKey()) == 0); - ASSERT(!makeCollectionMetadata()->getNextOrphanRange(pending, keyRange->getMax())); + ASSERT(!makeCollectionMetadata().getNextOrphanRange(pending, keyRange->getMax())); } /** @@ -242,7 +250,7 @@ TEST_F(SingleChunkFixture, ChunkOrphanedDataRanges) { */ class SingleChunkMinMaxCompoundKeyFixture : public unittest::Test { protected: - std::unique_ptr<CollectionMetadata> makeCollectionMetadata() const { + CollectionMetadata makeCollectionMetadata() const { const KeyPattern shardKeyPattern(BSON("a" << 1 << "b" << 1)); return makeCollectionMetadataImpl( shardKeyPattern, @@ -252,13 +260,13 @@ protected: }; TEST_F(SingleChunkMinMaxCompoundKeyFixture, KeyBelongsToMe) { - ASSERT(makeCollectionMetadata()->keyBelongsToMe(BSON("a" << MINKEY << "b" << MINKEY))); - ASSERT(makeCollectionMetadata()->keyBelongsToMe(BSON("a" << MINKEY << "b" << 10))); - ASSERT(makeCollectionMetadata()->keyBelongsToMe(BSON("a" << 10 << "b" << 20))); + ASSERT(makeCollectionMetadata().keyBelongsToMe(BSON("a" << MINKEY << "b" << MINKEY))); + ASSERT(makeCollectionMetadata().keyBelongsToMe(BSON("a" << MINKEY << "b" << 10))); + ASSERT(makeCollectionMetadata().keyBelongsToMe(BSON("a" << 10 << "b" << 20))); - ASSERT(!makeCollectionMetadata()->keyBelongsToMe(BSON("a" << MAXKEY << "b" << MAXKEY))); + ASSERT(!makeCollectionMetadata().keyBelongsToMe(BSON("a" << MAXKEY << "b" << MAXKEY))); - ASSERT(!makeCollectionMetadata()->keyBelongsToMe(BSONObj())); + ASSERT(!makeCollectionMetadata().keyBelongsToMe(BSONObj())); } /** @@ -267,7 +275,7 @@ TEST_F(SingleChunkMinMaxCompoundKeyFixture, KeyBelongsToMe) { */ class TwoChunksWithGapCompoundKeyFixture : public unittest::Test { protected: - std::unique_ptr<CollectionMetadata> makeCollectionMetadata() const { + CollectionMetadata makeCollectionMetadata() const { return makeCollectionMetadataImpl( KeyPattern(BSON("a" << 1 << "b" << 1)), {std::make_pair(BSON("a" << 10 << "b" << 0), BSON("a" << 20 << "b" << 0)), @@ -279,23 +287,23 @@ protected: TEST_F(TwoChunksWithGapCompoundKeyFixture, ChunkGapOrphanedDataRanges) { ConstructedRangeMap pending; - auto keyRange = makeCollectionMetadata()->getNextOrphanRange( - pending, makeCollectionMetadata()->getMinKey()); + auto keyRange = + makeCollectionMetadata().getNextOrphanRange(pending, makeCollectionMetadata().getMinKey()); ASSERT(keyRange); - ASSERT(keyRange->getMin().woCompare(makeCollectionMetadata()->getMinKey()) == 0); + ASSERT(keyRange->getMin().woCompare(makeCollectionMetadata().getMinKey()) == 0); ASSERT(keyRange->getMax().woCompare(BSON("a" << 10 << "b" << 0)) == 0); - keyRange = makeCollectionMetadata()->getNextOrphanRange(pending, keyRange->getMax()); + keyRange = makeCollectionMetadata().getNextOrphanRange(pending, keyRange->getMax()); ASSERT(keyRange); ASSERT(keyRange->getMin().woCompare(BSON("a" << 20 << "b" << 0)) == 0); ASSERT(keyRange->getMax().woCompare(BSON("a" << 30 << "b" << 0)) == 0); - keyRange = makeCollectionMetadata()->getNextOrphanRange(pending, keyRange->getMax()); + keyRange = makeCollectionMetadata().getNextOrphanRange(pending, keyRange->getMax()); ASSERT(keyRange); ASSERT(keyRange->getMin().woCompare(BSON("a" << 40 << "b" << 0)) == 0); - ASSERT(keyRange->getMax().woCompare(makeCollectionMetadata()->getMaxKey()) == 0); + ASSERT(keyRange->getMax().woCompare(makeCollectionMetadata().getMaxKey()) == 0); - ASSERT(!makeCollectionMetadata()->getNextOrphanRange(pending, keyRange->getMax())); + ASSERT(!makeCollectionMetadata().getNextOrphanRange(pending, keyRange->getMax())); } /** @@ -304,8 +312,7 @@ TEST_F(TwoChunksWithGapCompoundKeyFixture, ChunkGapOrphanedDataRanges) { */ class ThreeChunkWithRangeGapFixture : public unittest::Test { protected: - std::unique_ptr<CollectionMetadata> makeCollectionMetadata() const { - + CollectionMetadata makeCollectionMetadata() const { return makeCollectionMetadataImpl(KeyPattern(BSON("a" << 1)), {std::make_pair(BSON("a" << MINKEY), BSON("a" << 10)), std::make_pair(BSON("a" << 10), BSON("a" << 20)), @@ -319,52 +326,51 @@ TEST_F(ThreeChunkWithRangeGapFixture, GetNextChunkMatch) { ChunkType chunk; - ASSERT(metadata->getNextChunk(BSON("a" << MINKEY), &chunk)); - ASSERT_BSONOBJ_EQ(metadata->getMinKey(), chunk.getMin()); + ASSERT(metadata.getNextChunk(BSON("a" << MINKEY), &chunk)); + ASSERT_BSONOBJ_EQ(metadata.getMinKey(), chunk.getMin()); ASSERT_BSONOBJ_EQ(BSON("a" << MINKEY), chunk.getMin()); ASSERT_BSONOBJ_EQ(BSON("a" << 10), chunk.getMax()); - ASSERT(metadata->getNextChunk(BSON("a" << 10), &chunk)); + ASSERT(metadata.getNextChunk(BSON("a" << 10), &chunk)); ASSERT_BSONOBJ_EQ(BSON("a" << 10), chunk.getMin()); ASSERT_BSONOBJ_EQ(BSON("a" << 20), chunk.getMax()); - ASSERT(metadata->getNextChunk(BSON("a" << 30), &chunk)); + ASSERT(metadata.getNextChunk(BSON("a" << 30), &chunk)); ASSERT_BSONOBJ_EQ(BSON("a" << 30), chunk.getMin()); - ASSERT_BSONOBJ_EQ(metadata->getMaxKey(), chunk.getMax()); + ASSERT_BSONOBJ_EQ(metadata.getMaxKey(), chunk.getMax()); ASSERT_BSONOBJ_EQ(BSON("a" << MAXKEY), chunk.getMax()); } TEST_F(ThreeChunkWithRangeGapFixture, KeyBelongsToMe) { - ASSERT(makeCollectionMetadata()->keyBelongsToMe(BSON("a" << 5))); - ASSERT(makeCollectionMetadata()->keyBelongsToMe(BSON("a" << 10))); - ASSERT(makeCollectionMetadata()->keyBelongsToMe(BSON("a" << 30))); - ASSERT(makeCollectionMetadata()->keyBelongsToMe(BSON("a" << 40))); + ASSERT(makeCollectionMetadata().keyBelongsToMe(BSON("a" << 5))); + ASSERT(makeCollectionMetadata().keyBelongsToMe(BSON("a" << 10))); + ASSERT(makeCollectionMetadata().keyBelongsToMe(BSON("a" << 30))); + ASSERT(makeCollectionMetadata().keyBelongsToMe(BSON("a" << 40))); - ASSERT(!makeCollectionMetadata()->keyBelongsToMe(BSON("a" << 20))); - ASSERT(!makeCollectionMetadata()->keyBelongsToMe(BSON("a" << 25))); - ASSERT(!makeCollectionMetadata()->keyBelongsToMe(BSON("a" << MAXKEY))); + ASSERT(!makeCollectionMetadata().keyBelongsToMe(BSON("a" << 20))); + ASSERT(!makeCollectionMetadata().keyBelongsToMe(BSON("a" << 25))); + ASSERT(!makeCollectionMetadata().keyBelongsToMe(BSON("a" << MAXKEY))); - ASSERT(!makeCollectionMetadata()->keyBelongsToMe(BSONObj())); + ASSERT(!makeCollectionMetadata().keyBelongsToMe(BSONObj())); } TEST_F(ThreeChunkWithRangeGapFixture, GetNextChunkFromBeginning) { ChunkType nextChunk; - ASSERT( - makeCollectionMetadata()->getNextChunk(makeCollectionMetadata()->getMinKey(), &nextChunk)); + ASSERT(makeCollectionMetadata().getNextChunk(makeCollectionMetadata().getMinKey(), &nextChunk)); ASSERT_EQUALS(0, nextChunk.getMin().woCompare(BSON("a" << MINKEY))); ASSERT_EQUALS(0, nextChunk.getMax().woCompare(BSON("a" << 10))); } TEST_F(ThreeChunkWithRangeGapFixture, GetNextChunkFromMiddle) { ChunkType nextChunk; - ASSERT(makeCollectionMetadata()->getNextChunk(BSON("a" << 20), &nextChunk)); + ASSERT(makeCollectionMetadata().getNextChunk(BSON("a" << 20), &nextChunk)); ASSERT_EQUALS(0, nextChunk.getMin().woCompare(BSON("a" << 30))); ASSERT_EQUALS(0, nextChunk.getMax().woCompare(BSON("a" << MAXKEY))); } TEST_F(ThreeChunkWithRangeGapFixture, GetNextChunkFromLast) { ChunkType nextChunk; - ASSERT(makeCollectionMetadata()->getNextChunk(BSON("a" << 30), &nextChunk)); + ASSERT(makeCollectionMetadata().getNextChunk(BSON("a" << 30), &nextChunk)); ASSERT_EQUALS(0, nextChunk.getMin().woCompare(BSON("a" << 30))); ASSERT_EQUALS(0, nextChunk.getMax().woCompare(BSON("a" << MAXKEY))); } @@ -375,18 +381,18 @@ TEST_F(ThreeChunkWithRangeGapFixture, GetNextChunkFromLast) { */ class StaleChunkFixture : public unittest::Test { protected: - std::unique_ptr<CollectionMetadata> makeCollectionMetadata() const { + CollectionMetadata makeCollectionMetadata() const { return makeCollectionMetadataImpl( KeyPattern(BSON("a" << 1)), {std::make_pair(BSON("a" << 10), BSON("a" << 20))}, true); } }; TEST_F(StaleChunkFixture, KeyBelongsToMe) { - ASSERT_THROWS_CODE(makeCollectionMetadata()->keyBelongsToMe(BSON("a" << 10)), + ASSERT_THROWS_CODE(makeCollectionMetadata().keyBelongsToMe(BSON("a" << 10)), AssertionException, ErrorCodes::StaleChunkHistory); - ASSERT_THROWS_CODE(makeCollectionMetadata()->keyBelongsToMe(BSON("a" << 0)), + ASSERT_THROWS_CODE(makeCollectionMetadata().keyBelongsToMe(BSON("a" << 0)), AssertionException, ErrorCodes::StaleChunkHistory); } diff --git a/src/mongo/db/s/collection_sharding_runtime_test.cpp b/src/mongo/db/s/collection_sharding_runtime_test.cpp index 0ea329db1b9..952924bf6f9 100644 --- a/src/mongo/db/s/collection_sharding_runtime_test.cpp +++ b/src/mongo/db/s/collection_sharding_runtime_test.cpp @@ -45,34 +45,39 @@ const NamespaceString kTestNss("TestDB", "TestColl"); const std::string kShardKey = "_id"; const BSONObj kShardKeyPattern = BSON(kShardKey << 1); -using CollectionShardingRuntimeTest = ShardServerTestFixture; - -CollectionMetadata makeShardedMetadata(OperationContext* opCtx, UUID uuid = UUID::gen()) { - const OID epoch = OID::gen(); - auto range = ChunkRange(BSON(kShardKey << MINKEY), BSON(kShardKey << MAXKEY)); - auto chunk = ChunkType(kTestNss, std::move(range), ChunkVersion(1, 0, epoch), ShardId("other")); - ChunkManager cm(ShardId("0"), - DatabaseVersion(UUID::gen(), 1), - RoutingTableHistory::makeNew(kTestNss, - uuid, - kShardKeyPattern, - nullptr, - false, - epoch, - boost::none, - {std::move(chunk)}), - boost::none); - - if (!OperationShardingState::isOperationVersioned(opCtx)) { - const auto version = cm.getVersion(ShardId("0")); - BSONObjBuilder builder; - version.appendToCommand(&builder); - - auto& oss = OperationShardingState::get(opCtx); - oss.initializeClientRoutingVersionsFromCommand(kTestNss, builder.obj()); +class CollectionShardingRuntimeTest : public ShardServerTestFixture { +protected: + static CollectionMetadata makeShardedMetadata(OperationContext* opCtx, + UUID uuid = UUID::gen()) { + const OID epoch = OID::gen(); + auto range = ChunkRange(BSON(kShardKey << MINKEY), BSON(kShardKey << MAXKEY)); + auto chunk = + ChunkType(kTestNss, std::move(range), ChunkVersion(1, 0, epoch), ShardId("other")); + ChunkManager cm( + ShardId("0"), + DatabaseVersion(UUID::gen(), 1), + makeStandaloneRoutingTableHistory(RoutingTableHistory::makeNew(kTestNss, + uuid, + kShardKeyPattern, + nullptr, + false, + epoch, + boost::none, + {std::move(chunk)})), + boost::none); + + if (!OperationShardingState::isOperationVersioned(opCtx)) { + const auto version = cm.getVersion(ShardId("0")); + BSONObjBuilder builder; + version.appendToCommand(&builder); + + auto& oss = OperationShardingState::get(opCtx); + oss.initializeClientRoutingVersionsFromCommand(kTestNss, builder.obj()); + } + + return CollectionMetadata(std::move(cm), ShardId("0")); } - return CollectionMetadata(std::move(cm), ShardId("0")); -} +}; TEST_F(CollectionShardingRuntimeTest, GetCollectionDescriptionThrowsStaleConfigBeforeSetFilteringMetadataIsCalledAndNoOSSSet) { @@ -175,7 +180,7 @@ TEST_F(CollectionShardingRuntimeTest, /** * Fixture for when range deletion functionality is required in CollectionShardingRuntime tests. */ -class CollectionShardingRuntimeWithRangeDeleterTest : public ShardServerTestFixture { +class CollectionShardingRuntimeWithRangeDeleterTest : public CollectionShardingRuntimeTest { public: void setUp() override { ShardServerTestFixture::setUp(); diff --git a/src/mongo/db/s/metadata_manager_test.cpp b/src/mongo/db/s/metadata_manager_test.cpp index ea40d8dcb61..71995b20b72 100644 --- a/src/mongo/db/s/metadata_manager_test.cpp +++ b/src/mongo/db/s/metadata_manager_test.cpp @@ -88,8 +88,11 @@ protected: boost::none, {ChunkType{kNss, range, ChunkVersion(1, 0, epoch), kOtherShard}}); - return CollectionMetadata( - ChunkManager(kThisShard, DatabaseVersion(UUID::gen(), 1), rt, boost::none), kThisShard); + return CollectionMetadata(ChunkManager(kThisShard, + DatabaseVersion(UUID::gen(), 1), + makeStandaloneRoutingTableHistory(std::move(rt)), + boost::none), + kThisShard); } /** @@ -131,7 +134,10 @@ protected: auto rt = cm->getRoutingTableHistory_ForTest().makeUpdated(boost::none, splitChunks); - return CollectionMetadata(ChunkManager(cm->dbPrimary(), cm->dbVersion(), rt, boost::none), + return CollectionMetadata(ChunkManager(cm->dbPrimary(), + cm->dbVersion(), + makeStandaloneRoutingTableHistory(std::move(rt)), + boost::none), kThisShard); } @@ -153,7 +159,10 @@ protected: auto rt = cm->getRoutingTableHistory_ForTest().makeUpdated( boost::none, {ChunkType(kNss, ChunkRange(minKey, maxKey), chunkVersion, kOtherShard)}); - return CollectionMetadata(ChunkManager(cm->dbPrimary(), cm->dbVersion(), rt, boost::none), + return CollectionMetadata(ChunkManager(cm->dbPrimary(), + cm->dbVersion(), + makeStandaloneRoutingTableHistory(std::move(rt)), + boost::none), kThisShard); } diff --git a/src/mongo/db/s/migration_chunk_cloner_source_legacy_test.cpp b/src/mongo/db/s/migration_chunk_cloner_source_legacy_test.cpp index 82426d039a1..3d87d74f94b 100644 --- a/src/mongo/db/s/migration_chunk_cloner_source_legacy_test.cpp +++ b/src/mongo/db/s/migration_chunk_cloner_source_legacy_test.cpp @@ -165,11 +165,12 @@ protected: CollectionShardingRuntime::get(operationContext(), kNss) ->setFilteringMetadata( operationContext(), - CollectionMetadata(ChunkManager(ShardId("dummyShardId"), - DatabaseVersion(UUID::gen(), 1), - rt, - boost::none), - ShardId("dummyShardId"))); + CollectionMetadata( + ChunkManager(ShardId("dummyShardId"), + DatabaseVersion(UUID::gen(), 1), + makeStandaloneRoutingTableHistory(std::move(rt)), + boost::none), + ShardId("dummyShardId"))); }(); _client->createIndex(kNss.ns(), kShardKeyPattern); diff --git a/src/mongo/db/s/op_observer_sharding_test.cpp b/src/mongo/db/s/op_observer_sharding_test.cpp index fd32555ba66..f1c78c2d9e9 100644 --- a/src/mongo/db/s/op_observer_sharding_test.cpp +++ b/src/mongo/db/s/op_observer_sharding_test.cpp @@ -53,31 +53,35 @@ void setCollectionFilteringMetadata(OperationContext* opCtx, CollectionMetadata oss.initializeClientRoutingVersionsFromCommand(kTestNss, builder.obj()); } -/** - * Constructs a CollectionMetadata suitable for refreshing a CollectionShardingState. The only - * salient detail is the argument `keyPattern` which, defining the shard key, selects the fields - * that DeleteState's constructor will extract from its `doc` argument into its member - * DeleteState::documentKey. - */ -CollectionMetadata makeAMetadata(BSONObj const& keyPattern) { - const OID epoch = OID::gen(); - auto range = ChunkRange(BSON("key" << MINKEY), BSON("key" << MAXKEY)); - auto chunk = ChunkType(kTestNss, std::move(range), ChunkVersion(1, 0, epoch), ShardId("other")); - auto rt = RoutingTableHistory::makeNew(kTestNss, - UUID::gen(), - KeyPattern(keyPattern), - nullptr, - false, - epoch, - boost::none, - {std::move(chunk)}); - - return CollectionMetadata( - ChunkManager(ShardId("this"), DatabaseVersion(UUID::gen(), 1), rt, Timestamp(100, 0)), - ShardId("this")); -} - -class DeleteStateTest : public ShardServerTestFixture {}; +class DeleteStateTest : public ShardServerTestFixture { +protected: + /** + * Constructs a CollectionMetadata suitable for refreshing a CollectionShardingState. The only + * salient detail is the argument `keyPattern` which, defining the shard key, selects the fields + * that DeleteState's constructor will extract from its `doc` argument into its member + * DeleteState::documentKey. + */ + static CollectionMetadata makeAMetadata(BSONObj const& keyPattern) { + const OID epoch = OID::gen(); + auto range = ChunkRange(BSON("key" << MINKEY), BSON("key" << MAXKEY)); + auto chunk = + ChunkType(kTestNss, std::move(range), ChunkVersion(1, 0, epoch), ShardId("other")); + auto rt = RoutingTableHistory::makeNew(kTestNss, + UUID::gen(), + KeyPattern(keyPattern), + nullptr, + false, + epoch, + boost::none, + {std::move(chunk)}); + + return CollectionMetadata(ChunkManager(ShardId("this"), + DatabaseVersion(UUID::gen(), 1), + makeStandaloneRoutingTableHistory(std::move(rt)), + Timestamp(100, 0)), + ShardId("this")); + } +}; TEST_F(DeleteStateTest, MakeDeleteStateUnsharded) { setCollectionFilteringMetadata(operationContext(), CollectionMetadata()); diff --git a/src/mongo/db/s/range_deletion_util_test.cpp b/src/mongo/db/s/range_deletion_util_test.cpp index d9874802768..b2de302ab59 100644 --- a/src/mongo/db/s/range_deletion_util_test.cpp +++ b/src/mongo/db/s/range_deletion_util_test.cpp @@ -105,12 +105,13 @@ public: AutoGetDb autoDb(operationContext(), kNss.db(), MODE_IX); Lock::CollectionLock collLock(operationContext(), kNss, MODE_IX); CollectionShardingRuntime::get(operationContext(), kNss) - ->setFilteringMetadata(operationContext(), - CollectionMetadata(ChunkManager(ShardId("dummyShardId"), - DatabaseVersion(UUID::gen(), 1), - rt, - boost::none), - ShardId("dummyShardId"))); + ->setFilteringMetadata( + operationContext(), + CollectionMetadata(ChunkManager(ShardId("dummyShardId"), + DatabaseVersion(UUID::gen(), 1), + makeStandaloneRoutingTableHistory(std::move(rt)), + boost::none), + ShardId("dummyShardId"))); } UUID uuid() const { diff --git a/src/mongo/s/catalog_cache.cpp b/src/mongo/s/catalog_cache.cpp index 52a83f2c371..19846e62b48 100644 --- a/src/mongo/s/catalog_cache.cpp +++ b/src/mongo/s/catalog_cache.cpp @@ -111,8 +111,9 @@ std::shared_ptr<RoutingTableHistory> refreshCollectionRoutingInfo( existingRoutingInfo->getVersion()) return existingRoutingInfo; - return existingRoutingInfo->makeUpdated(std::move(collectionAndChunks.reshardingFields), - collectionAndChunks.changedChunks); + return std::make_shared<RoutingTableHistory>( + existingRoutingInfo->makeUpdated(std::move(collectionAndChunks.reshardingFields), + collectionAndChunks.changedChunks)); } auto defaultCollator = [&]() -> std::unique_ptr<CollatorInterface> { @@ -124,14 +125,15 @@ std::shared_ptr<RoutingTableHistory> refreshCollectionRoutingInfo( return nullptr; }(); - return RoutingTableHistory::makeNew(nss, - collectionAndChunks.uuid, - KeyPattern(collectionAndChunks.shardKeyPattern), - std::move(defaultCollator), - collectionAndChunks.shardKeyIsUnique, - collectionAndChunks.epoch, - std::move(collectionAndChunks.reshardingFields), - collectionAndChunks.changedChunks); + return std::make_shared<RoutingTableHistory>( + RoutingTableHistory::makeNew(nss, + collectionAndChunks.uuid, + KeyPattern(collectionAndChunks.shardKeyPattern), + std::move(defaultCollator), + collectionAndChunks.shardKeyIsUnique, + collectionAndChunks.epoch, + std::move(collectionAndChunks.reshardingFields), + collectionAndChunks.changedChunks)); }(); std::set<ShardId> shardIds; diff --git a/src/mongo/s/chunk_manager.cpp b/src/mongo/s/chunk_manager.cpp index edf6c8fc91c..fece210d762 100644 --- a/src/mongo/s/chunk_manager.cpp +++ b/src/mongo/s/chunk_manager.cpp @@ -708,7 +708,7 @@ std::string RoutingTableHistory::toString() const { return sb.str(); } -std::shared_ptr<RoutingTableHistory> RoutingTableHistory::makeNew( +RoutingTableHistory RoutingTableHistory::makeNew( NamespaceString nss, boost::optional<UUID> uuid, KeyPattern shardKeyPattern, @@ -727,7 +727,7 @@ std::shared_ptr<RoutingTableHistory> RoutingTableHistory::makeNew( .makeUpdated(std::move(reshardingFields), chunks); } -std::shared_ptr<RoutingTableHistory> RoutingTableHistory::makeUpdated( +RoutingTableHistory RoutingTableHistory::makeUpdated( boost::optional<TypeCollectionReshardingFields> reshardingFields, const std::vector<ChunkType>& changedChunks) const { auto changedChunkInfos = flatten(changedChunks); @@ -737,14 +737,13 @@ std::shared_ptr<RoutingTableHistory> RoutingTableHistory::makeUpdated( invariant(getVersion().epoch() == chunkMap.getVersion().epoch()); invariant(getVersion().isOlderThan(chunkMap.getVersion())); - return std::shared_ptr<RoutingTableHistory>( - new RoutingTableHistory(_nss, - _uuid, - KeyPattern(getShardKeyPattern().getKeyPattern()), - CollatorInterface::cloneCollator(getDefaultCollator()), - isUnique(), - std::move(reshardingFields), - std::move(chunkMap))); + return RoutingTableHistory(_nss, + _uuid, + getShardKeyPattern().getKeyPattern(), + CollatorInterface::cloneCollator(getDefaultCollator()), + isUnique(), + std::move(reshardingFields), + std::move(chunkMap)); } } // namespace mongo diff --git a/src/mongo/s/chunk_manager.h b/src/mongo/s/chunk_manager.h index 22330aeecfb..7f25a810a4a 100644 --- a/src/mongo/s/chunk_manager.h +++ b/src/mongo/s/chunk_manager.h @@ -156,7 +156,7 @@ public: * The existence of "reshardingFields" inside the optional implies that this field was present * inside the config.collections entry when refreshing. */ - static std::shared_ptr<RoutingTableHistory> makeNew( + static RoutingTableHistory makeNew( NamespaceString nss, boost::optional<UUID>, KeyPattern shardKeyPattern, @@ -178,7 +178,7 @@ public: * parameter implies that the field was not present, and will clear any currently held * resharding fields inside the resulting RoutingTableHistory. */ - std::shared_ptr<RoutingTableHistory> makeUpdated( + RoutingTableHistory makeUpdated( boost::optional<TypeCollectionReshardingFields> reshardingFields, const std::vector<ChunkType>& changedChunks) const; @@ -310,7 +310,7 @@ private: // presence of the type inside the optional indicates that the collection is involved in a // resharding operation, and that these fields were present in the config.collections entry // for this collection. - const boost::optional<TypeCollectionReshardingFields> _reshardingFields; + boost::optional<TypeCollectionReshardingFields> _reshardingFields; // Map from the max for each chunk to an entry describing the chunk. The union of all chunks' // ranges must cover the complete space from [MinKey, MaxKey). diff --git a/src/mongo/s/chunk_manager_query_test.cpp b/src/mongo/s/chunk_manager_query_test.cpp index 772304ce006..c665e2c4f9f 100644 --- a/src/mongo/s/chunk_manager_query_test.cpp +++ b/src/mongo/s/chunk_manager_query_test.cpp @@ -522,9 +522,11 @@ TEST_F(ChunkManagerQueryTest, SnapshotQueryWithMoreShardsThanLatestMetadata) { chunk1.setHistory({ChunkHistory(Timestamp(20, 0), ShardId("0")), ChunkHistory(Timestamp(1, 0), ShardId("1"))}); - auto newRoutingTable = oldRoutingTable->makeUpdated(boost::none, {chunk1}); ChunkManager chunkManager( - ShardId("0"), DatabaseVersion(UUID::gen(), 1), newRoutingTable, Timestamp(5, 0)); + ShardId("0"), + DatabaseVersion(UUID::gen(), 1), + makeStandaloneRoutingTableHistory(oldRoutingTable.makeUpdated(boost::none, {chunk1})), + Timestamp(5, 0)); std::set<ShardId> shardIds; chunkManager.getShardIdsForRange(BSON("x" << MINKEY), BSON("x" << MAXKEY), &shardIds); diff --git a/src/mongo/s/chunk_manager_refresh_bm.cpp b/src/mongo/s/chunk_manager_refresh_bm.cpp index dbd0248f112..600196ea120 100644 --- a/src/mongo/s/chunk_manager_refresh_bm.cpp +++ b/src/mongo/s/chunk_manager_refresh_bm.cpp @@ -43,6 +43,10 @@ namespace { const NamespaceString kNss("test", "foo"); +std::shared_ptr<RoutingTableHistory> makeStandaloneRoutingTableHistory(RoutingTableHistory rt) { + return std::make_shared<RoutingTableHistory>(std::move(rt)); +} + ChunkRange getRangeForChunk(int i, int nChunks) { invariant(i >= 0); invariant(nChunks > 0); @@ -72,12 +76,13 @@ CollectionMetadata makeChunkManagerWithShardSelector(int nShards, selectShard(i, nShards, nChunks)); } - auto routingTableHistory = RoutingTableHistory::makeNew( + auto rt = RoutingTableHistory::makeNew( kNss, UUID::gen(), shardKeyPattern, nullptr, true, collEpoch, boost::none, chunks); - return CollectionMetadata( - ChunkManager( - ShardId("Shard0"), DatabaseVersion(UUID::gen(), 1), routingTableHistory, boost::none), - ShardId("shard0")); + return CollectionMetadata(ChunkManager(ShardId("Shard0"), + DatabaseVersion(UUID::gen(), 1), + makeStandaloneRoutingTableHistory(std::move(rt)), + boost::none), + ShardId("shard0")); } ShardId pessimalShardSelector(int i, int nShards, int nChunks) { @@ -104,10 +109,11 @@ MONGO_COMPILER_NOINLINE auto runIncrementalUpdate(const CollectionMetadata& cm, const std::vector<ChunkType>& newChunks) { auto rt = cm.getChunkManager()->getRoutingTableHistory_ForTest().makeUpdated(boost::none, newChunks); - - return std::make_unique<CollectionMetadata>( - ChunkManager(ShardId("shard0"), DatabaseVersion(UUID::gen(), 1), rt, boost::none), - ShardId("shard0")); + return CollectionMetadata(ChunkManager(ShardId("shard0"), + DatabaseVersion(UUID::gen(), 1), + makeStandaloneRoutingTableHistory(std::move(rt)), + boost::none), + ShardId("shard0")); } void BM_IncrementalRefreshWithNoChange(benchmark::State& state) { @@ -170,13 +176,14 @@ auto BM_FullBuildOfChunkManager(benchmark::State& state, ShardSelectorFn selectS } for (auto keepRunning : state) { - auto routingTableHistory = RoutingTableHistory::makeNew( + auto rt = RoutingTableHistory::makeNew( collName, UUID::gen(), shardKeyPattern, nullptr, true, collEpoch, boost::none, chunks); - benchmark::DoNotOptimize(CollectionMetadata(ChunkManager(ShardId("shard0"), - DatabaseVersion(UUID::gen(), 1), - routingTableHistory, - boost::none), - ShardId("shard0"))); + benchmark::DoNotOptimize( + CollectionMetadata(ChunkManager(ShardId("shard0"), + DatabaseVersion(UUID::gen(), 1), + makeStandaloneRoutingTableHistory(std::move(rt)), + boost::none), + ShardId("shard0"))); } } diff --git a/src/mongo/s/routing_table_history_test.cpp b/src/mongo/s/routing_table_history_test.cpp index 6e42767fc69..3d33cbce230 100644 --- a/src/mongo/s/routing_table_history_test.cpp +++ b/src/mongo/s/routing_table_history_test.cpp @@ -50,38 +50,39 @@ const NamespaceString kNss("TestDB", "TestColl"); * chunk boundaries to be inserted. As an example, if you want to split the range [0, 2] into chunks * [0, 1] and [1, 2], newChunkBoundaryPoints should be [0, 1, 2]. */ -std::shared_ptr<RoutingTableHistory> splitChunk( - const std::shared_ptr<RoutingTableHistory>& rt, - const std::vector<BSONObj>& newChunkBoundaryPoints) { +RoutingTableHistory splitChunk(const RoutingTableHistory& rt, + const std::vector<BSONObj>& newChunkBoundaryPoints) { + + invariant(newChunkBoundaryPoints.size() > 1); // Convert the boundary points into chunk range objects, e.g. {0, 1, 2} -> // {{ChunkRange{0, 1}, ChunkRange{1, 2}} std::vector<ChunkRange> newChunkRanges; - invariant(newChunkBoundaryPoints.size() > 1); for (size_t i = 0; i < newChunkBoundaryPoints.size() - 1; ++i) { newChunkRanges.emplace_back(newChunkBoundaryPoints[i], newChunkBoundaryPoints[i + 1]); } std::vector<ChunkType> newChunks; - auto curVersion = rt->getVersion(); + auto curVersion = rt.getVersion(); for (const auto& range : newChunkRanges) { // Chunks must be inserted ordered by version curVersion.incMajor(); newChunks.emplace_back(kNss, range, curVersion, kThisShard); } - return rt->makeUpdated(boost::none, newChunks); + + return rt.makeUpdated(boost::none, newChunks); } /** * Gets a set of raw pointers to ChunkInfo objects in the specified range, */ -std::set<ChunkInfo*> getChunksInRange(std::shared_ptr<RoutingTableHistory> rt, +std::set<ChunkInfo*> getChunksInRange(const RoutingTableHistory& rt, const BSONObj& min, const BSONObj& max) { std::set<ChunkInfo*> chunksFromSplit; - rt->forEachOverlappingChunk(min, max, false, [&](auto& chunk) { + rt.forEachOverlappingChunk(min, max, false, [&](auto& chunk) { chunksFromSplit.insert(chunk.get()); return true; }); @@ -89,21 +90,20 @@ std::set<ChunkInfo*> getChunksInRange(std::shared_ptr<RoutingTableHistory> rt, return chunksFromSplit; } -// Looks up a chunk that corresponds to or contains the range [min, max). There -// should only be one such chunk in the input RoutingTableHistory object. -std::shared_ptr<ChunkInfo> getChunkToSplit(std::shared_ptr<RoutingTableHistory> rt, - const BSONObj& min, - const BSONObj& max) { +/** + * Looks up a chunk that corresponds to or contains the range [min, max). There should only be one + * such chunk in the input RoutingTableHistory object. + */ +ChunkInfo* getChunkToSplit(const RoutingTableHistory& rt, const BSONObj& min, const BSONObj& max) { std::shared_ptr<ChunkInfo> firstOverlappingChunk; - rt->forEachOverlappingChunk(min, max, false, [&](auto& chunkInfo) { + rt.forEachOverlappingChunk(min, max, false, [&](auto& chunkInfo) { firstOverlappingChunk = chunkInfo; return false; // only need first chunk }); invariant(firstOverlappingChunk); - - return firstOverlappingChunk; + return firstOverlappingChunk.get(); } /** @@ -120,9 +120,8 @@ std::shared_ptr<ChunkInfo> getChunkToSplit(std::shared_ptr<RoutingTableHistory> * Else: * Make sure its bytes written have not been changed due to the split (e.g. it has * expectedBytesInChunksNotSplit in its writes tracker) - * */ -void assertCorrectBytesWritten(std::shared_ptr<RoutingTableHistory> rt, +void assertCorrectBytesWritten(const RoutingTableHistory& rt, const BSONObj& minSplitBoundary, const BSONObj& maxSplitBoundary, size_t expectedNumChunksFromSplit, @@ -131,7 +130,7 @@ void assertCorrectBytesWritten(std::shared_ptr<RoutingTableHistory> rt, auto chunksFromSplit = getChunksInRange(rt, minSplitBoundary, maxSplitBoundary); ASSERT_EQ(chunksFromSplit.size(), expectedNumChunksFromSplit); - rt->forEachChunk([&](const auto& chunkInfo) { + rt.forEachChunk([&](const auto& chunkInfo) { auto writesTracker = chunkInfo->getWritesTracker(); auto bytesWritten = writesTracker->getBytesWritten(); if (chunksFromSplit.count(chunkInfo.get()) > 0) { @@ -161,10 +160,10 @@ public: version, kThisShard}; - _rt = RoutingTableHistory::makeNew( - kNss, UUID::gen(), _shardKeyPattern, nullptr, false, epoch, boost::none, {initChunk}); - + _rt.emplace(RoutingTableHistory::makeNew( + kNss, UUID::gen(), _shardKeyPattern, nullptr, false, epoch, boost::none, {initChunk})); ASSERT_EQ(_rt->numChunks(), 1ull); + // Should only be one _rt->forEachChunk([&](const auto& chunkInfo) { auto writesTracker = chunkInfo->getWritesTracker(); @@ -173,21 +172,23 @@ public: }); } - virtual const KeyPattern& getShardKeyPattern() const { + const KeyPattern& getShardKeyPattern() const { return _shardKeyPattern; } - virtual uint64_t getBytesInOriginalChunk() const { + uint64_t getBytesInOriginalChunk() const { return _bytesInOriginalChunk; } - const std::shared_ptr<RoutingTableHistory>& getInitialRoutingTable() const { - return _rt; + const RoutingTableHistory& getInitialRoutingTable() const { + return *_rt; } private: uint64_t _bytesInOriginalChunk{4ull}; - std::shared_ptr<RoutingTableHistory> _rt; + + boost::optional<RoutingTableHistory> _rt; + KeyPattern _shardKeyPattern{BSON("a" << 1)}; }; @@ -203,13 +204,13 @@ public: BSON("a" << 10), BSON("a" << 20), getShardKeyPattern().globalMax()}; - _rt = splitChunk(RoutingTableHistoryTest::getInitialRoutingTable(), - _initialChunkBoundaryPoints); + _rt.emplace(splitChunk(RoutingTableHistoryTest::getInitialRoutingTable(), + _initialChunkBoundaryPoints)); ASSERT_EQ(_rt->numChunks(), 3ull); } - const std::shared_ptr<RoutingTableHistory>& getInitialRoutingTable() const { - return _rt; + const RoutingTableHistory& getInitialRoutingTable() const { + return *_rt; } std::vector<BSONObj> getInitialChunkBoundaryPoints() { @@ -217,7 +218,8 @@ public: } private: - std::shared_ptr<RoutingTableHistory> _rt; + boost::optional<RoutingTableHistory> _rt; + std::vector<BSONObj> _initialChunkBoundaryPoints; }; @@ -228,10 +230,9 @@ TEST_F(RoutingTableHistoryTest, SplittingOnlyChunkCopiesBytesWrittenToAllSubchun getShardKeyPattern().globalMin(), minKey, maxKey, getShardKeyPattern().globalMax()}; auto rt = splitChunk(getInitialRoutingTable(), newChunkBoundaryPoints); + ASSERT_EQ(rt.numChunks(), 3ull); - ASSERT_EQ(rt->numChunks(), 3ull); - - rt->forEachChunk([&](const auto& chunkInfo) { + rt.forEachChunk([&](const auto& chunkInfo) { auto writesTracker = chunkInfo->getWritesTracker(); auto bytesWritten = writesTracker->getBytesWritten(); ASSERT_EQ(bytesWritten, getBytesInOriginalChunk()); @@ -255,7 +256,7 @@ TEST_F(RoutingTableHistoryTestThreeInitialChunks, auto expectedNumChunksFromSplit = 2; auto expectedBytesInChunksFromSplit = getBytesInOriginalChunk() + bytesToWrite; auto expectedBytesInChunksNotSplit = getBytesInOriginalChunk(); - ASSERT_EQ(rt->numChunks(), 4ull); + ASSERT_EQ(rt.numChunks(), 4ull); assertCorrectBytesWritten(rt, minKey, maxKey, @@ -281,7 +282,7 @@ TEST_F(RoutingTableHistoryTestThreeInitialChunks, auto expectedNumChunksFromSplit = 3; auto expectedBytesInChunksFromSplit = getBytesInOriginalChunk() + bytesToWrite; auto expectedBytesInChunksNotSplit = getBytesInOriginalChunk(); - ASSERT_EQ(rt->numChunks(), 5ull); + ASSERT_EQ(rt.numChunks(), 5ull); assertCorrectBytesWritten(rt, minKey, maxKey, @@ -306,7 +307,7 @@ TEST_F(RoutingTableHistoryTestThreeInitialChunks, auto expectedNumChunksFromSplit = 2; auto expectedBytesInChunksFromSplit = getBytesInOriginalChunk() + bytesToWrite; auto expectedBytesInChunksNotSplit = getBytesInOriginalChunk(); - ASSERT_EQ(rt->numChunks(), 4ull); + ASSERT_EQ(rt.numChunks(), 4ull); assertCorrectBytesWritten(rt, minKey, maxKey, @@ -338,9 +339,9 @@ TEST_F(RoutingTableHistoryTest, TestSplits) { ChunkVersion{2, 2, epoch}, kThisShard}}; - auto rt1 = rt->makeUpdated(boost::none, chunks1); + auto rt1 = rt.makeUpdated(boost::none, chunks1); auto v1 = ChunkVersion{2, 2, epoch}; - ASSERT_EQ(v1, rt1->getVersion(kThisShard)); + ASSERT_EQ(v1, rt1.getVersion(kThisShard)); std::vector<ChunkType> chunks2 = { ChunkType{kNss, @@ -356,9 +357,9 @@ TEST_F(RoutingTableHistoryTest, TestSplits) { ChunkVersion{3, 2, epoch}, kThisShard}}; - auto rt2 = rt1->makeUpdated(boost::none, chunks2); + auto rt2 = rt1.makeUpdated(boost::none, chunks2); auto v2 = ChunkVersion{3, 2, epoch}; - ASSERT_EQ(v2, rt2->getVersion(kThisShard)); + ASSERT_EQ(v2, rt2.getVersion(kThisShard)); } TEST_F(RoutingTableHistoryTest, TestReplaceEmptyChunk) { @@ -372,8 +373,7 @@ TEST_F(RoutingTableHistoryTest, TestReplaceEmptyChunk) { auto rt = RoutingTableHistory::makeNew( kNss, UUID::gen(), getShardKeyPattern(), nullptr, false, epoch, boost::none, initialChunks); - - ASSERT_EQ(rt->numChunks(), 1); + ASSERT_EQ(rt.numChunks(), 1); std::vector<ChunkType> changedChunks = { ChunkType{kNss, @@ -385,15 +385,14 @@ TEST_F(RoutingTableHistoryTest, TestReplaceEmptyChunk) { ChunkVersion{2, 2, epoch}, kThisShard}}; - auto rt1 = rt->makeUpdated(boost::none, changedChunks); + auto rt1 = rt.makeUpdated(boost::none, changedChunks); auto v1 = ChunkVersion{2, 2, epoch}; - ASSERT_EQ(v1, rt1->getVersion(kThisShard)); - ASSERT_EQ(rt1->numChunks(), 2); - ASSERT_NE(rt.get(), rt1.get()); + ASSERT_EQ(v1, rt1.getVersion(kThisShard)); + ASSERT_EQ(rt1.numChunks(), 2); std::shared_ptr<ChunkInfo> found; - rt1->forEachChunk( + rt1.forEachChunk( [&](auto& chunkInfo) { if (chunkInfo->getShardIdAt(boost::none) == kThisShard) { found = chunkInfo; @@ -416,8 +415,7 @@ TEST_F(RoutingTableHistoryTest, TestUseLatestVersions) { auto rt = RoutingTableHistory::makeNew( kNss, UUID::gen(), getShardKeyPattern(), nullptr, false, epoch, boost::none, initialChunks); - - ASSERT_EQ(rt->numChunks(), 1); + ASSERT_EQ(rt.numChunks(), 1); std::vector<ChunkType> changedChunks = { ChunkType{kNss, @@ -433,11 +431,10 @@ TEST_F(RoutingTableHistoryTest, TestUseLatestVersions) { ChunkVersion{2, 2, epoch}, kThisShard}}; - auto rt1 = rt->makeUpdated(boost::none, changedChunks); + auto rt1 = rt.makeUpdated(boost::none, changedChunks); auto v1 = ChunkVersion{2, 2, epoch}; - ASSERT_EQ(v1, rt1->getVersion(kThisShard)); - ASSERT_EQ(rt1->numChunks(), 2); - ASSERT_NE(rt.get(), rt1.get()); + ASSERT_EQ(v1, rt1.getVersion(kThisShard)); + ASSERT_EQ(rt1.numChunks(), 2); } TEST_F(RoutingTableHistoryTest, TestOutOfOrderVersion) { @@ -455,8 +452,7 @@ TEST_F(RoutingTableHistoryTest, TestOutOfOrderVersion) { auto rt = RoutingTableHistory::makeNew( kNss, UUID::gen(), getShardKeyPattern(), nullptr, false, epoch, boost::none, initialChunks); - - ASSERT_EQ(rt->numChunks(), 2); + ASSERT_EQ(rt.numChunks(), 2); std::vector<ChunkType> changedChunks = { ChunkType{kNss, @@ -468,13 +464,12 @@ TEST_F(RoutingTableHistoryTest, TestOutOfOrderVersion) { ChunkVersion{3, 1, epoch}, kThisShard}}; - auto rt1 = rt->makeUpdated(boost::none, changedChunks); + auto rt1 = rt.makeUpdated(boost::none, changedChunks); auto v1 = ChunkVersion{3, 1, epoch}; - ASSERT_EQ(v1, rt1->getVersion(kThisShard)); - ASSERT_EQ(rt1->numChunks(), 2); - ASSERT_NE(rt.get(), rt1.get()); + ASSERT_EQ(v1, rt1.getVersion(kThisShard)); + ASSERT_EQ(rt1.numChunks(), 2); - auto chunk1 = rt1->findIntersectingChunk(BSON("a" << 0)); + auto chunk1 = rt1.findIntersectingChunk(BSON("a" << 0)); ASSERT_EQ(chunk1->getLastmod(), ChunkVersion(3, 0, epoch)); ASSERT_EQ(chunk1->getMin().woCompare(BSON("a" << 0)), 0); ASSERT_EQ(chunk1->getMax().woCompare(getShardKeyPattern().globalMax()), 0); @@ -499,9 +494,8 @@ TEST_F(RoutingTableHistoryTest, TestMergeChunks) { auto rt = RoutingTableHistory::makeNew( kNss, UUID::gen(), getShardKeyPattern(), nullptr, false, epoch, boost::none, initialChunks); - - ASSERT_EQ(rt->numChunks(), 3); - ASSERT_EQ(rt->getVersion(), ChunkVersion(2, 2, epoch)); + ASSERT_EQ(rt.numChunks(), 3); + ASSERT_EQ(rt.getVersion(), ChunkVersion(2, 2, epoch)); std::vector<ChunkType> changedChunks = { ChunkType{kNss, @@ -513,11 +507,10 @@ TEST_F(RoutingTableHistoryTest, TestMergeChunks) { ChunkVersion{3, 1, epoch}, kThisShard}}; - auto rt1 = rt->makeUpdated(boost::none, changedChunks); + auto rt1 = rt.makeUpdated(boost::none, changedChunks); auto v1 = ChunkVersion{3, 1, epoch}; - ASSERT_EQ(v1, rt1->getVersion(kThisShard)); - ASSERT_EQ(rt1->numChunks(), 2); - ASSERT_NE(rt.get(), rt1.get()); + ASSERT_EQ(v1, rt1.getVersion(kThisShard)); + ASSERT_EQ(rt1.numChunks(), 2); } TEST_F(RoutingTableHistoryTest, TestMergeChunksOrdering) { @@ -539,9 +532,8 @@ TEST_F(RoutingTableHistoryTest, TestMergeChunksOrdering) { auto rt = RoutingTableHistory::makeNew( kNss, UUID::gen(), getShardKeyPattern(), nullptr, false, epoch, boost::none, initialChunks); - - ASSERT_EQ(rt->numChunks(), 3); - ASSERT_EQ(rt->getVersion(), ChunkVersion(2, 2, epoch)); + ASSERT_EQ(rt.numChunks(), 3); + ASSERT_EQ(rt.getVersion(), ChunkVersion(2, 2, epoch)); std::vector<ChunkType> changedChunks = { ChunkType{kNss, @@ -553,13 +545,12 @@ TEST_F(RoutingTableHistoryTest, TestMergeChunksOrdering) { ChunkVersion{3, 1, epoch}, kThisShard}}; - auto rt1 = rt->makeUpdated(boost::none, changedChunks); + auto rt1 = rt.makeUpdated(boost::none, changedChunks); auto v1 = ChunkVersion{3, 1, epoch}; - ASSERT_EQ(v1, rt1->getVersion(kThisShard)); - ASSERT_EQ(rt1->numChunks(), 2); - ASSERT_NE(rt.get(), rt1.get()); + ASSERT_EQ(v1, rt1.getVersion(kThisShard)); + ASSERT_EQ(rt1.numChunks(), 2); - auto chunk1 = rt1->findIntersectingChunk(BSON("a" << -500)); + auto chunk1 = rt1.findIntersectingChunk(BSON("a" << -500)); ASSERT_EQ(chunk1->getLastmod(), ChunkVersion(3, 1, epoch)); ASSERT_EQ(chunk1->getMin().woCompare(getShardKeyPattern().globalMin()), 0); ASSERT_EQ(chunk1->getMax().woCompare(BSON("a" << -10)), 0); @@ -597,11 +588,10 @@ TEST_F(RoutingTableHistoryTest, TestFlatten) { auto rt = RoutingTableHistory::makeNew( kNss, UUID::gen(), getShardKeyPattern(), nullptr, false, epoch, boost::none, initialChunks); + ASSERT_EQ(rt.numChunks(), 2); + ASSERT_EQ(rt.getVersion(), ChunkVersion(4, 1, epoch)); - ASSERT_EQ(rt->numChunks(), 2); - ASSERT_EQ(rt->getVersion(), ChunkVersion(4, 1, epoch)); - - auto chunk1 = rt->findIntersectingChunk(BSON("a" << 0)); + auto chunk1 = rt.findIntersectingChunk(BSON("a" << 0)); ASSERT_EQ(chunk1->getLastmod(), ChunkVersion(4, 0, epoch)); ASSERT_EQ(chunk1->getMin().woCompare(getShardKeyPattern().globalMin()), 0); ASSERT_EQ(chunk1->getMax().woCompare(BSON("a" << 10)), 0); diff --git a/src/mongo/s/sharding_test_fixture_common.cpp b/src/mongo/s/sharding_test_fixture_common.cpp index ed1fbd2b043..95dd505687b 100644 --- a/src/mongo/s/sharding_test_fixture_common.cpp +++ b/src/mongo/s/sharding_test_fixture_common.cpp @@ -47,6 +47,11 @@ ShardingTestFixtureCommon::ShardingTestFixtureCommon() { ShardingTestFixtureCommon::~ShardingTestFixtureCommon() = default; +std::shared_ptr<RoutingTableHistory> ShardingTestFixtureCommon::makeStandaloneRoutingTableHistory( + RoutingTableHistory rt) { + return std::make_shared<RoutingTableHistory>(std::move(rt)); +} + void ShardingTestFixtureCommon::onCommand(NetworkTestEnv::OnCommandFunction func) { _networkTestEnv->onCommand(func); } diff --git a/src/mongo/s/sharding_test_fixture_common.h b/src/mongo/s/sharding_test_fixture_common.h index 317e7f03b50..0ecbbb30695 100644 --- a/src/mongo/s/sharding_test_fixture_common.h +++ b/src/mongo/s/sharding_test_fixture_common.h @@ -49,6 +49,15 @@ class TaskExecutor; * Contains common functionality and tools, which apply to both mongos and mongod unit-tests. */ class ShardingTestFixtureCommon : public virtual ServiceContextTest { +public: + /** + * Constructs a standalone RoutingTableHistory object (i.e., not linked to any CatalogCache), + * which can be used to pass to ChunkManager for tests, which specifically target the behaviour + * of the ChunkManager. + */ + static std::shared_ptr<RoutingTableHistory> makeStandaloneRoutingTableHistory( + RoutingTableHistory rt); + protected: ShardingTestFixtureCommon(); ~ShardingTestFixtureCommon(); @@ -115,7 +124,6 @@ protected: const std::string& ns, const BSONObj& detail); -protected: /** * Base class returns nullptr. * |