summaryrefslogtreecommitdiff
path: root/src/mongo/s/routing_table_history_test.cpp
diff options
context:
space:
mode:
authorLucas de Castro Borges <lucas@gnuabordo.com.br>2025-02-14 14:26:38 -0300
committerLucas de Castro Borges <lucas@gnuabordo.com.br>2025-02-14 14:26:38 -0300
commit294bc6ecabf14c09c9bc8644704921dcf97cb44e (patch)
tree279b1e0bab53901a1647ac63c1c724f0f789a663 /src/mongo/s/routing_table_history_test.cpp
parent70be7c27a251621187a1de533462ae2bb1e3bd39 (diff)
parent1e917fd798aa25b7066d4b414b51184f13d5a092 (diff)
Update upstream source from tag 'upstream/6.0.10'debian/6.0.10-1
Update to upstream version '6.0.10' with Debian dir 2d176fa254eee97b139f712fec5709641335a8c3
Diffstat (limited to 'src/mongo/s/routing_table_history_test.cpp')
-rw-r--r--src/mongo/s/routing_table_history_test.cpp826
1 files changed, 579 insertions, 247 deletions
diff --git a/src/mongo/s/routing_table_history_test.cpp b/src/mongo/s/routing_table_history_test.cpp
index 9651911ee64..008c15f26ed 100644
--- a/src/mongo/s/routing_table_history_test.cpp
+++ b/src/mongo/s/routing_table_history_test.cpp
@@ -27,20 +27,38 @@
* it in the license file.
*/
+#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kTest
+
#include "mongo/platform/basic.h"
#include "mongo/bson/bsonobjbuilder.h"
#include "mongo/db/namespace_string.h"
#include "mongo/db/service_context.h"
+#include "mongo/idl/server_parameter_test_util.h"
+#include "mongo/logv2/log.h"
#include "mongo/s/catalog/type_chunk.h"
#include "mongo/s/chunk_manager.h"
#include "mongo/s/chunk_writes_tracker.h"
+#include "mongo/s/chunks_test_util.h"
#include "mongo/unittest/death_test.h"
#include "mongo/unittest/unittest.h"
+
namespace mongo {
+
+using chunks_test_util::assertEqualChunkInfo;
+using chunks_test_util::calculateCollVersion;
+using chunks_test_util::calculateIntermediateShardKey;
+using chunks_test_util::calculateShardVersions;
+using chunks_test_util::genChunkVector;
+using chunks_test_util::genRandomChunkVector;
+using chunks_test_util::getShardId;
+using chunks_test_util::performRandomChunkOperations;
+
namespace {
+PseudoRandom _random{SecureRandom().nextInt64()};
+
const ShardId kThisShard("thisShard");
const NamespaceString kNss("TestDB", "TestColl");
@@ -144,64 +162,57 @@ void assertCorrectBytesWritten(const RoutingTableHistory& rt,
});
}
-/**
- * Test fixture for tests that need to start with a fresh routing table with
- * only a single chunk in it, with bytes already written to that chunk object.
- */
class RoutingTableHistoryTest : public unittest::Test {
public:
- void setUp() override {
- const UUID uuid = UUID::gen();
- const OID epoch = OID::gen();
- const Timestamp timestamp(1);
- ChunkVersion version{1, 0, epoch, timestamp};
-
- auto initChunk =
- ChunkType{uuid,
- ChunkRange{_shardKeyPattern.globalMin(), _shardKeyPattern.globalMax()},
- version,
- kThisShard};
-
- _rt.emplace(RoutingTableHistory::makeNew(kNss,
- uuid,
- _shardKeyPattern,
- nullptr,
- false,
- epoch,
- timestamp,
- boost::none /* timeseriesFields */,
- boost::none,
- boost::none /* chunkSizeBytes */,
- true,
- {initChunk}));
- ASSERT_EQ(_rt->numChunks(), 1ull);
-
- // Should only be one
- _rt->forEachChunk([&](const auto& chunkInfo) {
- auto writesTracker = chunkInfo->getWritesTracker();
- writesTracker->addBytesWritten(_bytesInOriginalChunk);
- return true;
- });
- }
-
const KeyPattern& getShardKeyPattern() const {
return _shardKeyPattern;
}
- uint64_t getBytesInOriginalChunk() const {
- return _bytesInOriginalChunk;
+ const OID& collEpoch() const {
+ return _epoch;
}
- const RoutingTableHistory& getInitialRoutingTable() const {
- return *_rt;
+ const Timestamp& collTimestamp() const {
+ return _collTimestamp;
}
-private:
- uint64_t _bytesInOriginalChunk{4ull};
+ const UUID& collUUID() const {
+ return _collUUID;
+ }
- boost::optional<RoutingTableHistory> _rt;
+ std::vector<ChunkType> genRandomChunkVector(size_t minNumChunks = 1,
+ size_t maxNumChunks = 30) const {
+ return chunks_test_util::genRandomChunkVector(
+ _collUUID, _epoch, _collTimestamp, maxNumChunks, minNumChunks);
+ }
- KeyPattern _shardKeyPattern{BSON("a" << 1)};
+ RoutingTableHistory makeNewRt(const std::vector<ChunkType>& chunks) const {
+ const auto chunkBucketSize = llround(_random.nextInt64(chunks.size() * 1.2)) + 1;
+ LOGV2(7162710,
+ "Creating new RoutingTable",
+ "chunkBucketSize"_attr = chunkBucketSize,
+ "numChunks"_attr = chunks.size());
+ RAIIServerParameterControllerForTest chunkBucketSizeParameter(
+ "routingTableCacheChunkBucketSize", chunkBucketSize);
+ return RoutingTableHistory::makeNew(kNss,
+ _collUUID,
+ _shardKeyPattern,
+ nullptr,
+ false,
+ _epoch,
+ _collTimestamp,
+ boost::none /* timeseriesFields */,
+ boost::none /* reshardingFields */,
+ boost::none /* maxChunkSizeBytes */,
+ true,
+ chunks);
+ }
+
+protected:
+ KeyPattern _shardKeyPattern{chunks_test_util::kShardKeyPattern};
+ const OID _epoch{OID::gen()};
+ const Timestamp _collTimestamp{1, 1};
+ const UUID _collUUID{UUID::gen()};
};
/**
@@ -212,13 +223,28 @@ class RoutingTableHistoryTestThreeInitialChunks : public RoutingTableHistoryTest
public:
void setUp() override {
RoutingTableHistoryTest::setUp();
+
_initialChunkBoundaryPoints = {getShardKeyPattern().globalMin(),
BSON("a" << 10),
BSON("a" << 20),
getShardKeyPattern().globalMax()};
- _rt.emplace(splitChunk(RoutingTableHistoryTest::getInitialRoutingTable(),
- _initialChunkBoundaryPoints));
+ ChunkVersion version{1, 0, collEpoch(), collTimestamp()};
+ auto chunks =
+ genChunkVector(collUUID(), _initialChunkBoundaryPoints, version, 1 /* numShards */);
+
+ _rt.emplace(makeNewRt(chunks));
+
ASSERT_EQ(_rt->numChunks(), 3ull);
+
+ _rt->forEachChunk([&](const auto& chunkInfo) {
+ auto writesTracker = chunkInfo->getWritesTracker();
+ writesTracker->addBytesWritten(_bytesInOriginalChunk);
+ return true;
+ });
+ }
+
+ uint64_t getBytesInOriginalChunk() const {
+ return _bytesInOriginalChunk;
}
const RoutingTableHistory& getInitialRoutingTable() const {
@@ -230,24 +256,384 @@ public:
}
private:
+ uint64_t _bytesInOriginalChunk{4ull};
+
boost::optional<RoutingTableHistory> _rt;
std::vector<BSONObj> _initialChunkBoundaryPoints;
};
+/*
+ * Test creation of a Routing Table with randomly generated chunks
+ */
+TEST_F(RoutingTableHistoryTest, RandomCreateBasic) {
+ const auto chunks = genRandomChunkVector();
+ const auto expectedShardVersions = calculateShardVersions(chunks);
+ const auto expectedCollVersion = calculateCollVersion(expectedShardVersions);
+
+ // Create a new routing table from the randomly generated chunks
+ auto rt = makeNewRt(chunks);
+
+ // Checks basic getter of routing table return correct values
+ ASSERT_EQ(kNss, rt.nss());
+ ASSERT_EQ(ShardKeyPattern(getShardKeyPattern()).toString(), rt.getShardKeyPattern().toString());
+ ASSERT_EQ(chunks.size(), rt.numChunks());
+
+ // Check that chunks have correct info
+ size_t i = 0;
+ rt.forEachChunk([&](const auto& chunkInfo) {
+ assertEqualChunkInfo(ChunkInfo{chunks[i++]}, *chunkInfo);
+ return true;
+ });
+ ASSERT_EQ(i, chunks.size());
+
+ // Checks collection version is correct
+ ASSERT_EQ(expectedCollVersion, rt.getVersion());
+
+ // Checks version for each chunk
+ for (const auto& [shardId, shardVersion] : expectedShardVersions) {
+ ASSERT_EQ(shardVersion, rt.getVersion(shardId));
+ }
+
+ ASSERT_EQ(expectedShardVersions.size(), rt.getNShardsOwningChunks());
+
+ std::set<ShardId> expectedShardIds;
+ for (const auto& [shardId, shardVersion] : expectedShardVersions) {
+ expectedShardIds.insert(shardId);
+ }
+ std::set<ShardId> shardIds;
+ rt.getAllShardIds(&shardIds);
+ ASSERT(expectedShardIds == shardIds);
+}
+
+/*
+ * Test that creation of Routing Table with chunks that do not cover the entire shard key space
+ * fails.
+ *
+ * The gap is produced by removing a random chunks from the randomly generated chunk list. Thus it
+ * also cover the case for which min/max key is missing.
+ */
+TEST_F(RoutingTableHistoryTest, RandomCreateWithMissingChunkFail) {
+ auto chunks = genRandomChunkVector(2 /*minNumChunks*/);
+
+ // Remove one random chunk to simulate a gap in the shardkey
+ chunks.erase(chunks.begin() + _random.nextInt64(chunks.size()));
+
+ // Create a new routing table from the randomly generated chunks
+ ASSERT_THROWS_CODE(makeNewRt(chunks), DBException, ErrorCodes::ConflictingOperationInProgress);
+}
+
+/*
+ * Test that creation of Routing Table with chunks that do not cover the entire shard key space
+ * fails.
+ *
+ * The gap is produced by shrinking the range of a random chunk.
+ */
+TEST_F(RoutingTableHistoryTest, RandomCreateWithChunkGapFail) {
+ auto chunks = genRandomChunkVector(2 /*minNumChunks*/);
+
+ auto& shrinkedChunk = chunks.at(_random.nextInt64(chunks.size()));
+ auto intermediateKey =
+ calculateIntermediateShardKey(shrinkedChunk.getMin(), shrinkedChunk.getMax());
+ if (_random.nextInt64(2)) {
+ // Shrink right bound
+ shrinkedChunk.setMax(intermediateKey);
+ } else {
+ // Shrink left bound
+ shrinkedChunk.setMin(intermediateKey);
+ }
+
+ // Create a new routing table from the randomly generated chunks
+ ASSERT_THROWS_CODE(makeNewRt(chunks), DBException, ErrorCodes::ConflictingOperationInProgress);
+}
+
+/*
+ * Updating ChunkMap with gaps must fail
+ */
+TEST_F(RoutingTableHistoryTest, RandomUpdateWithChunkGapFail) {
+ auto chunks = genRandomChunkVector();
+
+ // Create a new routing table from the randomly generated chunks
+ auto rt = makeNewRt(chunks);
+ auto collVersion = rt.getVersion();
+
+ auto shrinkedChunk = chunks.at(_random.nextInt64(chunks.size()));
+ auto intermediateKey =
+ calculateIntermediateShardKey(shrinkedChunk.getMin(), shrinkedChunk.getMax());
+ if (_random.nextInt64(2)) {
+ // Shrink right bound
+ shrinkedChunk.setMax(intermediateKey);
+ } else {
+ // Shrink left bound
+ shrinkedChunk.setMin(intermediateKey);
+ }
+
+ // Bump chunk version
+ collVersion.incMajor();
+ shrinkedChunk.setVersion(collVersion);
+
+ ASSERT_THROWS_CODE(rt.makeUpdated(boost::none /* timeseriesFields */,
+ boost::none /* reshardingFields */,
+ boost::none /* maxChunkSizeBytes */,
+ true,
+ {std::move(shrinkedChunk)}),
+ AssertionException,
+ ErrorCodes::ConflictingOperationInProgress);
+}
+
+/*
+ * Creating a Routing Table with overlapping chunks must fail.
+ */
+TEST_F(RoutingTableHistoryTest, RandomCreateWithChunkOverlapFail) {
+ auto chunks = genRandomChunkVector(2 /* minNumChunks */);
+
+ auto chunkToExtendIt = chunks.begin() + _random.nextInt64(chunks.size());
+
+ const auto canExtendLeft = chunkToExtendIt > chunks.begin();
+ const auto extendRight =
+ !canExtendLeft || ((chunkToExtendIt < std::prev(chunks.end())) && _random.nextInt64(2));
+ const auto extendLeft = !extendRight;
+ if (extendRight) {
+ // extend right bound
+ chunkToExtendIt->setMax(calculateIntermediateShardKey(chunkToExtendIt->getMax(),
+ std::next(chunkToExtendIt)->getMax(),
+ 0.0 /* minKeyProb */,
+ 0.1 /* maxKeyProb */));
+ auto newVersion = chunkToExtendIt->getVersion();
+ newVersion.incMajor();
+ std::next(chunkToExtendIt)->setVersion(newVersion);
+ }
+
+ if (extendLeft) {
+ invariant(canExtendLeft);
+ // extend left bound
+ chunkToExtendIt->setMin(calculateIntermediateShardKey(std::prev(chunkToExtendIt)->getMin(),
+ chunkToExtendIt->getMin(),
+ 0.1 /* minKeyProb */,
+ 0.0 /* maxKeyProb */));
+ auto newVersion = chunkToExtendIt->getVersion();
+ newVersion.incMajor();
+ std::prev(chunkToExtendIt)->setVersion(newVersion);
+ }
+
+ // Create a new routing table from the randomly generated chunks
+ ASSERT_THROWS_CODE(makeNewRt(chunks), DBException, ErrorCodes::ConflictingOperationInProgress);
+}
+
+/*
+ * Updating a ChunkMap with overlapping chunks must fail.
+ */
+TEST_F(RoutingTableHistoryTest, RandomUpdateWithChunkOverlapFail) {
+ auto chunks = genRandomChunkVector(2 /* minNumChunks */);
+
+ // Create a new routing table from the randomly generated chunks
+ auto rt = makeNewRt(chunks);
+ auto collVersion = rt.getVersion();
+
+ auto chunkToExtendIt = chunks.begin() + _random.nextInt64(chunks.size());
+
+ const auto canExtendLeft = chunkToExtendIt > chunks.begin();
+ const auto extendRight =
+ !canExtendLeft || (chunkToExtendIt < std::prev(chunks.end()) && _random.nextInt64(2));
+ const auto extendLeft = !extendRight;
+ if (extendRight) {
+ // extend right bound
+ chunkToExtendIt->setMax(calculateIntermediateShardKey(
+ chunkToExtendIt->getMax(), std::next(chunkToExtendIt)->getMax()));
+ }
+
+ if (extendLeft) {
+ invariant(canExtendLeft);
+ // extend left bound
+ chunkToExtendIt->setMin(calculateIntermediateShardKey(std::prev(chunkToExtendIt)->getMin(),
+ chunkToExtendIt->getMin()));
+ }
+
+ // Bump chunk version
+ collVersion.incMajor();
+ chunkToExtendIt->setVersion(collVersion);
+
+ ASSERT_THROWS_CODE(rt.makeUpdated(boost::none /* timeseriesFields */,
+ boost::none /* reshardingFields */,
+ boost::none /* maxChunkSizeBytes */,
+ true,
+ {*chunkToExtendIt}),
+ AssertionException,
+ ErrorCodes::ConflictingOperationInProgress);
+}
+
+/*
+ * Creating a Routing Table with wrong min key must fail.
+ */
+TEST_F(RoutingTableHistoryTest, RandomCreateWrongMinFail) {
+ auto chunks = genRandomChunkVector();
+
+ chunks.begin()->setMin(BSON("a" << std::numeric_limits<int64_t>::min()));
+
+ // Create a new routing table from the randomly generated chunks
+ ASSERT_THROWS_CODE(makeNewRt(chunks), DBException, ErrorCodes::ConflictingOperationInProgress);
+}
+
+/*
+ * Creating a Routing Table with wrong max key must fail.
+ */
+TEST_F(RoutingTableHistoryTest, RandomCreateWrongMaxFail) {
+ auto chunks = genRandomChunkVector();
+
+ chunks.begin()->setMax(BSON("a" << std::numeric_limits<int64_t>::max()));
+
+ // Create a new routing table from the randomly generated chunks
+ ASSERT_THROWS_CODE(makeNewRt(chunks), DBException, ErrorCodes::ConflictingOperationInProgress);
+}
+
+/*
+ * Creating a Routing Table with mismatching epoch must fail.
+ */
+TEST_F(RoutingTableHistoryTest, RandomCreateMismatchingTimestampFail) {
+ auto chunks = genRandomChunkVector();
+
+ // Change epoch on a random chunk
+ auto chunkIt = chunks.begin() + _random.nextInt64(chunks.size());
+ const auto& oldVersion = chunkIt->getVersion();
+
+ const Timestamp wrongTimestamp{Date_t::now()};
+ ChunkVersion newVersion{
+ oldVersion.majorVersion(), oldVersion.minorVersion(), collEpoch(), wrongTimestamp};
+ chunkIt->setVersion(newVersion);
+
+ // Create a new routing table from the randomly generated chunks
+ ASSERT_THROWS_CODE(makeNewRt(chunks), DBException, ErrorCodes::ConflictingOperationInProgress);
+}
+
+/*
+ * Updating a Routing Table with mismatching Timestamp must fail.
+ */
+TEST_F(RoutingTableHistoryTest, RandomUpdateMismatchingTimestampFail) {
+ auto chunks = genRandomChunkVector();
+
+ // Create a new routing table from the randomly generated chunks
+ auto rt = makeNewRt(chunks);
+
+ // Change epoch on a random chunk
+ auto chunkIt = chunks.begin() + _random.nextInt64(chunks.size());
+ const auto& oldVersion = chunkIt->getVersion();
+ const Timestamp wrongTimestamp{Date_t::now()};
+ ChunkVersion newVersion{
+ oldVersion.majorVersion(), oldVersion.minorVersion(), collEpoch(), wrongTimestamp};
+ chunkIt->setVersion(newVersion);
+
+ ASSERT_THROWS_CODE(rt.makeUpdated(boost::none /* timeseriesFields */,
+ boost::none /* reshardingFields */,
+ boost::none /* maxChunkSizeBytes */,
+ true,
+ {*chunkIt}),
+ AssertionException,
+ ErrorCodes::ConflictingOperationInProgress);
+}
+
+
+/*
+ * Test update of the Routing Table with randomly generated changed chunks.
+ */
+TEST_F(RoutingTableHistoryTest, RandomUpdate) {
+ auto initialChunks = genRandomChunkVector();
+
+ const auto initialShardVersions = calculateShardVersions(initialChunks);
+ const auto initialCollVersion = calculateCollVersion(initialShardVersions);
+
+ // Create a new routing table from the randomly generated initialChunks
+ auto initialRt = makeNewRt(initialChunks);
+
+ auto chunks = initialChunks;
+ const auto maxNumChunkOps = 2 * initialChunks.size();
+ const auto numChunkOps = _random.nextInt32(maxNumChunkOps);
+
+ performRandomChunkOperations(&chunks, numChunkOps);
+
+ std::vector<ChunkType> updatedChunks;
+ for (const auto& chunk : chunks) {
+ if (!chunk.getVersion().isOlderOrEqualThan(initialCollVersion)) {
+ updatedChunks.push_back(chunk);
+ }
+ }
+
+ const auto expectedShardVersions = calculateShardVersions(chunks);
+ const auto expectedCollVersion = calculateCollVersion(expectedShardVersions);
+
+ auto rt = initialRt.makeUpdated(boost::none /* timeseriesFields */,
+ boost::none /* reshardingFields */,
+ boost::none /* maxChunkSizeBytes */,
+ true,
+ updatedChunks);
+
+ // Checks basic getter of routing table return correct values
+ ASSERT_EQ(kNss, rt.nss());
+ ASSERT_EQ(ShardKeyPattern(getShardKeyPattern()).toString(), rt.getShardKeyPattern().toString());
+ ASSERT_EQ(chunks.size(), rt.numChunks());
+
+ // Check that chunks have correct info
+ size_t i = 0;
+ rt.forEachChunk([&](const auto& chunkInfo) {
+ assertEqualChunkInfo(ChunkInfo{chunks[i++]}, *chunkInfo);
+ return true;
+ });
+ ASSERT_EQ(i, chunks.size());
+
+ // Checks collection version is correct
+ ASSERT_EQ(expectedCollVersion, rt.getVersion());
+
+ // Checks version for each shard
+ for (const auto& [shardId, shardVersion] : expectedShardVersions) {
+ ASSERT_EQ(shardVersion, rt.getVersion(shardId));
+ }
+
+ ASSERT_EQ(expectedShardVersions.size(), rt.getNShardsOwningChunks());
+
+ std::set<ShardId> expectedShardIds;
+ for (const auto& [shardId, shardVersion] : expectedShardVersions) {
+ expectedShardIds.insert(shardId);
+ }
+ std::set<ShardId> shardIds;
+ rt.getAllShardIds(&shardIds);
+ ASSERT(expectedShardIds == shardIds);
+}
+
TEST_F(RoutingTableHistoryTest, SplittingOnlyChunkCopiesBytesWrittenToAllSubchunks) {
- auto minKey = BSON("a" << 10);
- auto maxKey = BSON("a" << 20);
- auto newChunkBoundaryPoints = {
- getShardKeyPattern().globalMin(), minKey, maxKey, getShardKeyPattern().globalMax()};
+ ChunkVersion version{1, 0, collEpoch(), collTimestamp()};
- auto rt = splitChunk(getInitialRoutingTable(), newChunkBoundaryPoints);
- ASSERT_EQ(rt.numChunks(), 3ull);
+ const ChunkType initialChunk{
+ collUUID(),
+ ChunkRange{getShardKeyPattern().globalMin(), getShardKeyPattern().globalMax()},
+ version,
+ kThisShard};
+ auto rt = makeNewRt({initialChunk});
+ ASSERT_EQ(1, rt.numChunks());
+
+ // Set the 4 written bytes in each chunk
+ const size_t bytesInOriginalChunk{4};
rt.forEachChunk([&](const auto& chunkInfo) {
- auto writesTracker = chunkInfo->getWritesTracker();
- auto bytesWritten = writesTracker->getBytesWritten();
- ASSERT_EQ(bytesWritten, getBytesInOriginalChunk());
+ chunkInfo->getWritesTracker()->addBytesWritten(bytesInOriginalChunk);
+ return true;
+ });
+
+ version.incMinor();
+ auto newChunks = genChunkVector(collUUID(),
+ {getShardKeyPattern().globalMin(),
+ BSON("a" << 10),
+ BSON("a" << 20),
+ getShardKeyPattern().globalMax()},
+ version,
+ 1 /*numShards*/);
+ auto newRt = rt.makeUpdated(boost::none /* timeseriesFields */,
+ boost::none /* reshardingFields */,
+ boost::none /* maxChunkSizeBytes */,
+ true,
+ newChunks);
+ ASSERT_EQ(3, newRt.numChunks());
+
+ rt.forEachChunk([&](const auto& chunkInfo) {
+ ASSERT_EQ(bytesInOriginalChunk, chunkInfo->getWritesTracker()->getBytesWritten());
return true;
});
}
@@ -328,104 +714,124 @@ TEST_F(RoutingTableHistoryTestThreeInitialChunks,
expectedBytesInChunksNotSplit);
}
+TEST_F(RoutingTableHistoryTest, AllowMigrationFlag) {
+ auto chunks = genRandomChunkVector();
+
+ auto makeUpdatedChunk = [&](const ChunkVersion& oldVersion) {
+ auto updatedChunk = chunks[_random.nextInt64(chunks.size())];
+ updatedChunk.setVersion({oldVersion.majorVersion() + 1,
+ oldVersion.minorVersion(),
+ collEpoch(),
+ collTimestamp()});
+ return updatedChunk;
+ };
+
+ for (auto initialAllowMigrationsValue : std::vector<bool>{false, true}) {
+
+ auto allowMigrationsValue = initialAllowMigrationsValue;
+ auto rt = RoutingTableHistory::makeNew(kNss,
+ collUUID(),
+ getShardKeyPattern(),
+ nullptr,
+ false,
+ collEpoch(),
+ collTimestamp(),
+ boost::none /* timeseriesFields */,
+ boost::none /* reshardingFields */,
+ boost::none /* maxChunkSizeBytes */,
+ allowMigrationsValue,
+ chunks);
+ ASSERT_EQ(allowMigrationsValue, rt.allowMigrations());
+
+ // Create an updated routing table with flipped allowMigration flag
+ allowMigrationsValue = !allowMigrationsValue;
+ rt = rt.makeUpdated(boost::none /* timeseriesFields */,
+ boost::none /* reshardingFields */,
+ boost::none /* maxChunkSizeBytes */,
+ allowMigrationsValue,
+ {makeUpdatedChunk(rt.getVersion())});
+ ASSERT_EQ(allowMigrationsValue, rt.allowMigrations());
+
+ // Change back the allow migration flag to the original value
+ allowMigrationsValue = !allowMigrationsValue;
+ rt = rt.makeUpdated(boost::none /* timeseriesFields */,
+ boost::none /* reshardingFields */,
+ boost::none /* maxChunkSizeBytes */,
+ allowMigrationsValue,
+ {makeUpdatedChunk(rt.getVersion())});
+ ASSERT_EQ(allowMigrationsValue, rt.allowMigrations());
+ }
+}
+
TEST_F(RoutingTableHistoryTest, TestSplits) {
- const UUID uuid = UUID::gen();
- const OID epoch = OID::gen();
- const Timestamp timestamp(1);
- ChunkVersion version{1, 0, epoch, timestamp};
+ ChunkVersion version{1, 0, collEpoch(), collTimestamp()};
auto chunkAll =
- ChunkType{uuid,
+ ChunkType{collUUID(),
ChunkRange{getShardKeyPattern().globalMin(), getShardKeyPattern().globalMax()},
version,
kThisShard};
- auto rt = RoutingTableHistory::makeNew(kNss,
- uuid,
- getShardKeyPattern(),
- nullptr,
- false,
- epoch,
- timestamp,
- boost::none /* timeseriesFields */,
- boost::none,
- boost::none /* chunkSizeBytes */,
- true,
- {chunkAll});
+ auto rt = makeNewRt({chunkAll});
std::vector<ChunkType> chunks1 = {
- ChunkType{uuid,
+ ChunkType{collUUID(),
ChunkRange{getShardKeyPattern().globalMin(), BSON("a" << 0)},
- ChunkVersion{2, 1, epoch, timestamp},
+ ChunkVersion{2, 1, collEpoch(), collTimestamp()},
kThisShard},
- ChunkType{uuid,
+ ChunkType{collUUID(),
ChunkRange{BSON("a" << 0), getShardKeyPattern().globalMax()},
- ChunkVersion{2, 2, epoch, timestamp},
+ ChunkVersion{2, 2, collEpoch(), collTimestamp()},
kThisShard}};
auto rt1 =
rt.makeUpdated(boost::none /* timeseriesFields */, boost::none, boost::none, true, chunks1);
- auto v1 = ChunkVersion{2, 2, epoch, timestamp};
+ auto v1 = ChunkVersion{2, 2, collEpoch(), collTimestamp()};
ASSERT_EQ(v1, rt1.getVersion(kThisShard));
std::vector<ChunkType> chunks2 = {
- ChunkType{uuid,
+ ChunkType{collUUID(),
ChunkRange{BSON("a" << 0), getShardKeyPattern().globalMax()},
- ChunkVersion{2, 2, epoch, timestamp},
+ ChunkVersion{2, 2, collEpoch(), collTimestamp()},
kThisShard},
- ChunkType{uuid,
+ ChunkType{collUUID(),
ChunkRange{getShardKeyPattern().globalMin(), BSON("a" << -1)},
- ChunkVersion{3, 1, epoch, timestamp},
+ ChunkVersion{3, 1, collEpoch(), collTimestamp()},
kThisShard},
- ChunkType{uuid,
+ ChunkType{collUUID(),
ChunkRange{BSON("a" << -1), BSON("a" << 0)},
- ChunkVersion{3, 2, epoch, timestamp},
+ ChunkVersion{3, 2, collEpoch(), collTimestamp()},
kThisShard}};
auto rt2 = rt1.makeUpdated(
boost::none /* timeseriesFields */, boost::none, boost::none, true, chunks2);
- auto v2 = ChunkVersion{3, 2, epoch, timestamp};
+ auto v2 = ChunkVersion{3, 2, collEpoch(), collTimestamp()};
ASSERT_EQ(v2, rt2.getVersion(kThisShard));
}
TEST_F(RoutingTableHistoryTest, TestReplaceEmptyChunk) {
- const UUID uuid = UUID::gen();
- const OID epoch = OID::gen();
- const Timestamp timestamp(1);
-
std::vector<ChunkType> initialChunks = {
- ChunkType{uuid,
+ ChunkType{collUUID(),
ChunkRange{getShardKeyPattern().globalMin(), getShardKeyPattern().globalMax()},
- ChunkVersion{1, 0, epoch, timestamp},
+ ChunkVersion{1, 0, collEpoch(), collTimestamp()},
kThisShard}};
- auto rt = RoutingTableHistory::makeNew(kNss,
- uuid,
- getShardKeyPattern(),
- nullptr,
- false,
- epoch,
- timestamp,
- boost::none /* timeseriesFields */,
- boost::none,
- boost::none /* chunkSizeBytes */,
- true,
- initialChunks);
+ auto rt = makeNewRt(initialChunks);
ASSERT_EQ(rt.numChunks(), 1);
std::vector<ChunkType> changedChunks = {
- ChunkType{uuid,
+ ChunkType{collUUID(),
ChunkRange{getShardKeyPattern().globalMin(), BSON("a" << 0)},
- ChunkVersion{2, 1, epoch, timestamp},
+ ChunkVersion{2, 1, collEpoch(), collTimestamp()},
kThisShard},
- ChunkType{uuid,
+ ChunkType{collUUID(),
ChunkRange{BSON("a" << 0), getShardKeyPattern().globalMax()},
- ChunkVersion{2, 2, epoch, timestamp},
+ ChunkVersion{2, 2, collEpoch(), collTimestamp()},
kThisShard}};
auto rt1 = rt.makeUpdated(
boost::none /* timeseriesFields */, boost::none, boost::none, true, changedChunks);
- auto v1 = ChunkVersion{2, 2, epoch, timestamp};
+ auto v1 = ChunkVersion{2, 2, collEpoch(), collTimestamp()};
ASSERT_EQ(v1, rt1.getVersion(kThisShard));
ASSERT_EQ(rt1.numChunks(), 2);
@@ -444,258 +850,184 @@ TEST_F(RoutingTableHistoryTest, TestReplaceEmptyChunk) {
}
TEST_F(RoutingTableHistoryTest, TestUseLatestVersions) {
- const UUID uuid = UUID::gen();
- const OID epoch = OID::gen();
- const Timestamp timestamp(1);
-
std::vector<ChunkType> initialChunks = {
- ChunkType{uuid,
+ ChunkType{collUUID(),
ChunkRange{getShardKeyPattern().globalMin(), getShardKeyPattern().globalMax()},
- ChunkVersion{1, 0, epoch, timestamp},
+ ChunkVersion{1, 0, collEpoch(), collTimestamp()},
kThisShard}};
- auto rt = RoutingTableHistory::makeNew(kNss,
- uuid,
- getShardKeyPattern(),
- nullptr,
- false,
- epoch,
- timestamp,
- boost::none /* timeseriesFields */,
- boost::none,
- boost::none /* chunkSizeBytes */,
- true,
- initialChunks);
+ auto rt = makeNewRt(initialChunks);
ASSERT_EQ(rt.numChunks(), 1);
std::vector<ChunkType> changedChunks = {
- ChunkType{uuid,
+ ChunkType{collUUID(),
ChunkRange{getShardKeyPattern().globalMin(), getShardKeyPattern().globalMax()},
- ChunkVersion{1, 0, epoch, timestamp},
+ ChunkVersion{1, 0, collEpoch(), collTimestamp()},
kThisShard},
- ChunkType{uuid,
+ ChunkType{collUUID(),
ChunkRange{getShardKeyPattern().globalMin(), BSON("a" << 0)},
- ChunkVersion{2, 1, epoch, timestamp},
+ ChunkVersion{2, 1, collEpoch(), collTimestamp()},
kThisShard},
- ChunkType{uuid,
+ ChunkType{collUUID(),
ChunkRange{BSON("a" << 0), getShardKeyPattern().globalMax()},
- ChunkVersion{2, 2, epoch, timestamp},
+ ChunkVersion{2, 2, collEpoch(), collTimestamp()},
kThisShard}};
auto rt1 = rt.makeUpdated(
boost::none /* timeseriesFields */, boost::none, boost::none, true, changedChunks);
- auto v1 = ChunkVersion{2, 2, epoch, timestamp};
+ auto v1 = ChunkVersion{2, 2, collEpoch(), collTimestamp()};
ASSERT_EQ(v1, rt1.getVersion(kThisShard));
ASSERT_EQ(rt1.numChunks(), 2);
}
TEST_F(RoutingTableHistoryTest, TestOutOfOrderVersion) {
- const UUID uuid = UUID::gen();
- const OID epoch = OID::gen();
- const Timestamp timestamp(1);
-
std::vector<ChunkType> initialChunks = {
- ChunkType{uuid,
+ ChunkType{collUUID(),
ChunkRange{getShardKeyPattern().globalMin(), BSON("a" << 0)},
- ChunkVersion{2, 1, epoch, timestamp},
+ ChunkVersion{2, 1, collEpoch(), collTimestamp()},
kThisShard},
- ChunkType{uuid,
+ ChunkType{collUUID(),
ChunkRange{BSON("a" << 0), getShardKeyPattern().globalMax()},
- ChunkVersion{2, 2, epoch, timestamp},
+ ChunkVersion{2, 2, collEpoch(), collTimestamp()},
kThisShard}};
- auto rt = RoutingTableHistory::makeNew(kNss,
- uuid,
- getShardKeyPattern(),
- nullptr,
- false,
- epoch,
- timestamp,
- boost::none /* timeseriesFields */,
- boost::none,
- boost::none /* chunkSizeBytes */,
- true,
- initialChunks);
+ auto rt = makeNewRt(initialChunks);
ASSERT_EQ(rt.numChunks(), 2);
std::vector<ChunkType> changedChunks = {
- ChunkType{uuid,
+ ChunkType{collUUID(),
ChunkRange{BSON("a" << 0), getShardKeyPattern().globalMax()},
- ChunkVersion{3, 0, epoch, timestamp},
+ ChunkVersion{3, 0, collEpoch(), collTimestamp()},
kThisShard},
- ChunkType{uuid,
+ ChunkType{collUUID(),
ChunkRange{getShardKeyPattern().globalMin(), BSON("a" << 0)},
- ChunkVersion{3, 1, epoch, timestamp},
+ ChunkVersion{3, 1, collEpoch(), collTimestamp()},
kThisShard}};
auto rt1 = rt.makeUpdated(
boost::none /* timeseriesFields */, boost::none, boost::none, true, changedChunks);
- auto v1 = ChunkVersion{3, 1, epoch, timestamp};
+ auto v1 = ChunkVersion{3, 1, collEpoch(), collTimestamp()};
ASSERT_EQ(v1, rt1.getVersion(kThisShard));
ASSERT_EQ(rt1.numChunks(), 2);
auto chunk1 = rt1.findIntersectingChunk(BSON("a" << 0));
- ASSERT_EQ(chunk1->getLastmod(), ChunkVersion(3, 0, epoch, timestamp));
+ ASSERT_EQ(chunk1->getLastmod(), ChunkVersion(3, 0, collEpoch(), collTimestamp()));
ASSERT_EQ(chunk1->getMin().woCompare(BSON("a" << 0)), 0);
ASSERT_EQ(chunk1->getMax().woCompare(getShardKeyPattern().globalMax()), 0);
}
TEST_F(RoutingTableHistoryTest, TestMergeChunks) {
- const UUID uuid = UUID::gen();
- const OID epoch = OID::gen();
- const Timestamp timestamp(1);
-
std::vector<ChunkType> initialChunks = {
- ChunkType{uuid,
+ ChunkType{collUUID(),
ChunkRange{BSON("a" << 0), BSON("a" << 10)},
- ChunkVersion{2, 0, epoch, timestamp},
+ ChunkVersion{2, 0, collEpoch(), collTimestamp()},
kThisShard},
- ChunkType{uuid,
+ ChunkType{collUUID(),
ChunkRange{getShardKeyPattern().globalMin(), BSON("a" << 0)},
- ChunkVersion{2, 1, epoch, timestamp},
+ ChunkVersion{2, 1, collEpoch(), collTimestamp()},
kThisShard},
- ChunkType{uuid,
+ ChunkType{collUUID(),
ChunkRange{BSON("a" << 10), getShardKeyPattern().globalMax()},
- ChunkVersion{2, 2, epoch, timestamp},
+ ChunkVersion{2, 2, collEpoch(), collTimestamp()},
kThisShard}};
- auto rt = RoutingTableHistory::makeNew(kNss,
- uuid,
- getShardKeyPattern(),
- nullptr,
- false,
- epoch,
- timestamp,
- boost::none,
- boost::none /* timeseriesFields */,
- boost::none /* chunkSizeBytes */,
- true,
- initialChunks);
+ auto rt = makeNewRt(initialChunks);
+
ASSERT_EQ(rt.numChunks(), 3);
- ASSERT_EQ(rt.getVersion(), ChunkVersion(2, 2, epoch, timestamp));
+ ASSERT_EQ(rt.getVersion(), ChunkVersion(2, 2, collEpoch(), collTimestamp()));
std::vector<ChunkType> changedChunks = {
- ChunkType{uuid,
+ ChunkType{collUUID(),
ChunkRange{BSON("a" << 10), getShardKeyPattern().globalMax()},
- ChunkVersion{3, 0, epoch, timestamp},
+ ChunkVersion{3, 0, collEpoch(), collTimestamp()},
kThisShard},
- ChunkType{uuid,
+ ChunkType{collUUID(),
ChunkRange{getShardKeyPattern().globalMin(), BSON("a" << 10)},
- ChunkVersion{3, 1, epoch, timestamp},
+ ChunkVersion{3, 1, collEpoch(), collTimestamp()},
kThisShard}};
auto rt1 = rt.makeUpdated(
boost::none /* timeseriesFields */, boost::none, boost::none, true, changedChunks);
- auto v1 = ChunkVersion{3, 1, epoch, timestamp};
+ auto v1 = ChunkVersion{3, 1, collEpoch(), collTimestamp()};
ASSERT_EQ(v1, rt1.getVersion(kThisShard));
ASSERT_EQ(rt1.numChunks(), 2);
}
TEST_F(RoutingTableHistoryTest, TestMergeChunksOrdering) {
- const UUID uuid = UUID::gen();
- const OID epoch = OID::gen();
- const Timestamp timestamp(1);
-
std::vector<ChunkType> initialChunks = {
- ChunkType{uuid,
+ ChunkType{collUUID(),
ChunkRange{BSON("a" << -10), getShardKeyPattern().globalMax()},
- ChunkVersion{2, 0, epoch, timestamp},
+ ChunkVersion{2, 0, collEpoch(), collTimestamp()},
kThisShard},
- ChunkType{uuid,
+ ChunkType{collUUID(),
ChunkRange{getShardKeyPattern().globalMin(), BSON("a" << -500)},
- ChunkVersion{2, 1, epoch, timestamp},
+ ChunkVersion{2, 1, collEpoch(), collTimestamp()},
kThisShard},
- ChunkType{uuid,
+ ChunkType{collUUID(),
ChunkRange{BSON("a" << -500), BSON("a" << -10)},
- ChunkVersion{2, 2, epoch, timestamp},
+ ChunkVersion{2, 2, collEpoch(), collTimestamp()},
kThisShard}};
- auto rt = RoutingTableHistory::makeNew(kNss,
- uuid,
- getShardKeyPattern(),
- nullptr,
- false,
- epoch,
- timestamp,
- boost::none /* timeseriesFields */,
- boost::none,
- boost::none /* chunkSizeBytes */,
- true,
- initialChunks);
+ auto rt = makeNewRt(initialChunks);
ASSERT_EQ(rt.numChunks(), 3);
- ASSERT_EQ(rt.getVersion(), ChunkVersion(2, 2, epoch, timestamp));
+ ASSERT_EQ(rt.getVersion(), ChunkVersion(2, 2, collEpoch(), collTimestamp()));
std::vector<ChunkType> changedChunks = {
- ChunkType{uuid,
+ ChunkType{collUUID(),
ChunkRange{BSON("a" << -500), BSON("a" << -10)},
- ChunkVersion{2, 2, epoch, timestamp},
+ ChunkVersion{2, 2, collEpoch(), collTimestamp()},
kThisShard},
- ChunkType{uuid,
+ ChunkType{collUUID(),
ChunkRange{getShardKeyPattern().globalMin(), BSON("a" << -10)},
- ChunkVersion{3, 1, epoch, timestamp},
+ ChunkVersion{3, 1, collEpoch(), collTimestamp()},
kThisShard}};
auto rt1 = rt.makeUpdated(
boost::none /* timeseriesFields */, boost::none, boost::none, true, changedChunks);
- auto v1 = ChunkVersion{3, 1, epoch, timestamp};
+ auto v1 = ChunkVersion{3, 1, collEpoch(), collTimestamp()};
ASSERT_EQ(v1, rt1.getVersion(kThisShard));
ASSERT_EQ(rt1.numChunks(), 2);
auto chunk1 = rt1.findIntersectingChunk(BSON("a" << -500));
- ASSERT_EQ(chunk1->getLastmod(), ChunkVersion(3, 1, epoch, timestamp));
+ ASSERT_EQ(chunk1->getLastmod(), ChunkVersion(3, 1, collEpoch(), collTimestamp()));
ASSERT_EQ(chunk1->getMin().woCompare(getShardKeyPattern().globalMin()), 0);
ASSERT_EQ(chunk1->getMax().woCompare(BSON("a" << -10)), 0);
}
TEST_F(RoutingTableHistoryTest, TestFlatten) {
- const UUID uuid = UUID::gen();
- const OID epoch = OID::gen();
- const Timestamp timestamp(1);
-
std::vector<ChunkType> initialChunks = {
- ChunkType{uuid,
+ ChunkType{collUUID(),
ChunkRange{getShardKeyPattern().globalMin(), BSON("a" << 10)},
- ChunkVersion{2, 0, epoch, timestamp},
+ ChunkVersion{2, 0, collEpoch(), collTimestamp()},
kThisShard},
- ChunkType{uuid,
+ ChunkType{collUUID(),
ChunkRange{BSON("a" << 10), BSON("a" << 20)},
- ChunkVersion{2, 1, epoch, timestamp},
+ ChunkVersion{2, 1, collEpoch(), collTimestamp()},
kThisShard},
- ChunkType{uuid,
+ ChunkType{collUUID(),
ChunkRange{BSON("a" << 20), getShardKeyPattern().globalMax()},
- ChunkVersion{2, 2, epoch, timestamp},
+ ChunkVersion{2, 2, collEpoch(), collTimestamp()},
kThisShard},
- ChunkType{uuid,
+ ChunkType{collUUID(),
ChunkRange{getShardKeyPattern().globalMin(), getShardKeyPattern().globalMax()},
- ChunkVersion{3, 0, epoch, timestamp},
+ ChunkVersion{3, 0, collEpoch(), collTimestamp()},
kThisShard},
- ChunkType{uuid,
+ ChunkType{collUUID(),
ChunkRange{getShardKeyPattern().globalMin(), BSON("a" << 10)},
- ChunkVersion{4, 0, epoch, timestamp},
+ ChunkVersion{4, 0, collEpoch(), collTimestamp()},
kThisShard},
- ChunkType{uuid,
+ ChunkType{collUUID(),
ChunkRange{BSON("a" << 10), getShardKeyPattern().globalMax()},
- ChunkVersion{4, 1, epoch, timestamp},
+ ChunkVersion{4, 1, collEpoch(), collTimestamp()},
kThisShard},
};
- auto rt = RoutingTableHistory::makeNew(kNss,
- UUID::gen(),
- getShardKeyPattern(),
- nullptr,
- false,
- epoch,
- timestamp,
- boost::none /* timeseriesFields */,
- boost::none,
- boost::none /* chunkSizeBytes */,
- true,
- initialChunks);
+ auto rt = makeNewRt(initialChunks);
ASSERT_EQ(rt.numChunks(), 2);
- ASSERT_EQ(rt.getVersion(), ChunkVersion(4, 1, epoch, timestamp));
+ ASSERT_EQ(rt.getVersion(), ChunkVersion(4, 1, collEpoch(), collTimestamp()));
auto chunk1 = rt.findIntersectingChunk(BSON("a" << 0));
- ASSERT_EQ(chunk1->getLastmod(), ChunkVersion(4, 0, epoch, timestamp));
+ ASSERT_EQ(chunk1->getLastmod(), ChunkVersion(4, 0, collEpoch(), collTimestamp()));
ASSERT_EQ(chunk1->getMin().woCompare(getShardKeyPattern().globalMin()), 0);
ASSERT_EQ(chunk1->getMax().woCompare(BSON("a" << 10)), 0);
}