0
0
mirror of https://github.com/mongodb/mongo.git synced 2024-11-24 00:17:37 +01:00
mongodb/jstests/sharding/merge_chunk_hashed.js
Matt Broadstone 771dabd098 SERVER-81339 Convert ReplSetTest and ShardingTest to modules (#26332)
GitOrigin-RevId: 744aa110a53786b23c62ff53f87a1418b5991e8d
2024-08-20 22:00:49 +00:00

282 lines
11 KiB
JavaScript

/*
* Test that merging chunks for hashed sharding via mongos works/doesn't work with
* different chunk configurations.
*/
import {FeatureFlagUtil} from "jstests/libs/feature_flag_util.js";
import {ShardingTest} from "jstests/libs/shardingtest.js";
import {chunkBoundsUtil} from "jstests/sharding/libs/chunk_bounds_util.js";
import {findChunksUtil} from "jstests/sharding/libs/find_chunks_util.js";
let st = new ShardingTest({shards: 2, mongos: 2});
// , configOptions: {verbose: 3}
let mongos = st.s0;
let staleMongos = st.s1;
let dbName = "test";
let collName = "user";
let ns = dbName + "." + collName;
let configDB = mongos.getDB('config');
let admin = mongos.getDB("admin");
assert.commandWorked(admin.runCommand({enableSharding: dbName, primaryShard: st.shard0.shardName}));
let coll = mongos.getCollection(ns);
assert.commandWorked(admin.runCommand({shardCollection: ns, key: {x: 'hashed'}}));
// Setup predictable chunk distribution:
// shard0: MIN -> -4611686018427387902,
// -4611686018427387902 -> 0
// shard1: 0 -> 4611686018427387902
// 4611686018427387902 -> MAX
// TODO SERVER-81884: update once 8.0 becomes last LTS.
if (FeatureFlagUtil.isPresentAndEnabled(mongos.getDB(dbName),
"OneChunkPerShardEmptyCollectionWithHashedShardKey")) {
assert.commandWorked(
st.s.adminCommand({split: ns, middle: {x: NumberLong("-4611686018427387902")}}));
assert.commandWorked(
st.s.adminCommand({split: ns, middle: {x: NumberLong("4611686018427387902")}}));
}
assert.commandWorked(admin.runCommand({
moveChunk: ns,
bounds: [{x: MinKey}, {x: NumberLong("-4611686018427387902")}],
to: st.shard0.shardName,
_waitForDelete: true
}));
assert.commandWorked(admin.runCommand({
moveChunk: ns,
bounds: [{x: NumberLong("-4611686018427387902")}, {x: 0}],
to: st.shard0.shardName,
_waitForDelete: true
}));
assert.commandWorked(admin.runCommand({
moveChunk: ns,
bounds: [{x: 0}, {x: NumberLong("4611686018427387902")}],
to: st.shard1.shardName,
_waitForDelete: true
}));
assert.commandWorked(admin.runCommand({
moveChunk: ns,
bounds: [{x: NumberLong("4611686018427387902")}, {x: MaxKey}],
to: st.shard1.shardName,
_waitForDelete: true
}));
// Get the chunk -4611686018427387902 -> 0 on shard0.
let chunkToSplit = findChunksUtil.findOneChunkByNs(
configDB, ns, {min: {$ne: {x: MinKey}}, shard: st.shard0.shardName});
// Create chunks from that chunk and move some chunks to create holes.
// shard0: MIN -> chunkToSplit.min,
// chunkToSplit.min -> -4500000000000000000,
// (hole),
// -4000000000000000000 -> -3500000000000000000,
// -3500000000000000000 -> -3000000000000000000,
// -3000000000000000000 -> -2500000000000000000,
// (hole),
// -2000000000000000000 -> 0
// shard1: -4500000000000000000 -> -4000000000000000000
// -2500000000000000000 -> -2000000000000000000
// 0 -> 4611686018427387902
// 4611686018427387902 -> MAX
let splitPoints = [
{x: NumberLong(-4500000000000000000)},
{x: NumberLong(-4000000000000000000)},
{x: NumberLong(-3500000000000000000)},
{x: NumberLong(-3000000000000000000)},
{x: NumberLong(-2500000000000000000)},
{x: NumberLong(-2000000000000000000)},
];
assert.gt(0, bsonWoCompare(chunkToSplit.min, splitPoints[0]));
assert.lt(0, bsonWoCompare(chunkToSplit.max, splitPoints[splitPoints.length - 1]));
jsTest.log("Creating additional chunks and holes...");
for (let splitPoint of splitPoints) {
assert.commandWorked(admin.runCommand({split: ns, middle: splitPoint}));
}
assert.commandWorked(admin.runCommand({
moveChunk: ns,
bounds: [{x: NumberLong(-4500000000000000000)}, {x: NumberLong(-4000000000000000000)}],
to: st.shard1.shardName,
_waitForDelete: true
}));
assert.commandWorked(admin.runCommand({
moveChunk: ns,
bounds: [{x: NumberLong(-2500000000000000000)}, {x: NumberLong(-2000000000000000000)}],
to: st.shard1.shardName,
_waitForDelete: true
}));
let chunkDocs = findChunksUtil.findChunksByNs(configDB, ns).toArray();
let shardChunkBounds = chunkBoundsUtil.findShardChunkBounds(chunkDocs);
jsTest.log("Inserting docs...");
// Use docs that belong to different chunks and go on both shards.
let docs = [{x: -100}, {x: -60}, {x: -10}, {x: 10}];
let shards = [];
let docChunkBounds = [];
docs.forEach(function(doc) {
let hash = convertShardKeyToHashed(doc.x);
let {shard, bounds} =
chunkBoundsUtil.findShardAndChunkBoundsForShardKey(st, shardChunkBounds, {x: hash});
shards.push(shard);
docChunkBounds.push(bounds);
});
assert.eq(2, (new Set(shards)).size);
assert.eq(docs.length, (new Set(docChunkBounds)).size);
assert.commandWorked(coll.insert(docs));
var staleCollection = staleMongos.getCollection(ns);
jsTest.log("Trying merges that should fail...");
// Make sure merging non-exact chunks is invalid.
assert.commandFailed(admin.runCommand(
{mergeChunks: ns, bounds: [{x: MinKey}, {x: NumberLong(-5000000000000000000)}]}));
assert.commandFailed(admin.runCommand({
mergeChunks: ns,
bounds: [{x: NumberLong(-5500000000000000000)}, {x: NumberLong(-4500000000000000000)}]
}));
assert.commandFailed(admin.runCommand({
mergeChunks: ns,
bounds: [{x: NumberLong(4500000000000000000)}, {x: NumberLong(5500000000000000000)}]
}));
assert.commandFailed(admin.runCommand(
{mergeChunks: ns, bounds: [{x: NumberLong(-1500000000000000000)}, {x: MaxKey}]}));
// Make sure merging over holes is invalid.
assert.commandFailed(admin.runCommand(
{mergeChunks: ns, bounds: [{x: MinKey}, {x: NumberLong(-3500000000000000000)}]}));
assert.commandFailed(admin.runCommand(
{mergeChunks: ns, bounds: [{x: NumberLong(-3500000000000000000)}, {x: NumberLong(0)}]}));
assert.commandFailed(admin.runCommand(
{mergeChunks: ns, bounds: [{x: NumberLong(-3000000000000000000)}, {x: NumberLong(0)}]}));
// Make sure merging between shards is invalid.
assert.commandFailed(admin.runCommand(
{mergeChunks: ns, bounds: [{x: MinKey}, {x: NumberLong(-4000000000000000000)}]}));
assert.commandFailed(admin.runCommand({
mergeChunks: ns,
bounds: [{x: NumberLong(-3000000000000000000)}, {x: NumberLong(-2000000000000000000)}]
}));
assert.commandFailed(admin.runCommand(
{mergeChunks: ns, bounds: [{x: NumberLong(-2500000000000000000)}, {x: NumberLong(0)}]}));
assert.eq(4, staleCollection.find().itcount());
jsTest.log("Trying merges that should succeed...");
// Merging single chunks should be treated as a no-op
// (or fail because 'the range specifies one single chunk' in multiversion test environments)
try {
assert.commandWorked(
admin.runCommand({mergeChunks: ns, bounds: [{x: MinKey}, chunkToSplit.min]}));
} catch (e) {
if (!e.message.match(/could not merge chunks, collection .* already contains chunk for/)) {
throw e;
}
}
try {
assert.commandWorked(admin.runCommand({
mergeChunks: ns,
bounds: [{x: NumberLong(-4500000000000000000)}, {x: NumberLong(-4000000000000000000)}]
}));
} catch (e) {
if (!e.message.match(/could not merge chunks, collection .* already contains chunk for/)) {
throw e;
}
}
// Make sure merge including the MinKey works.
assert.commandWorked(admin.runCommand(
{mergeChunks: ns, bounds: [{x: MinKey}, {x: NumberLong(-4500000000000000000)}]}));
assert.eq(4, staleCollection.find().itcount());
// shard0: MIN -> -4500000000000000000,
// (hole),
// -4000000000000000000 -> -3500000000000000000,
// -3500000000000000000 -> -3000000000000000000,
// -3000000000000000000 -> -2500000000000000000,
// (hole),
// -2000000000000000000 -> 0
// shard1: -4500000000000000000 -> -4000000000000000000
// -2500000000000000000 -> -2000000000000000000
// 0 -> 4611686018427387902
// 4611686018427387902 -> MAX
// Make sure merging three chunks in the middle works.
assert.commandWorked(admin.runCommand({
mergeChunks: ns,
bounds: [{x: NumberLong(-4000000000000000000)}, {x: NumberLong(-2500000000000000000)}]
}));
assert.eq(4, staleCollection.find().itcount());
// shard0: MIN -> -4500000000000000000,
// (hole),
// -4000000000000000000 -> -2500000000000000000,
// (hole),
// -2000000000000000000 -> 0
// shard1: -4500000000000000000 -> -4000000000000000000
// -2500000000000000000 -> -2000000000000000000
// 0 -> 4611686018427387902
// 4611686018427387902 -> MAX
// Make sure merge including the MaxKey works.
assert.commandWorked(
admin.runCommand({mergeChunks: ns, bounds: [{x: NumberLong(0)}, {x: MaxKey}]}));
assert.eq(4, staleCollection.find().itcount());
// Make sure merging chunks after a chunk has been moved out of a shard succeeds
assert.commandWorked(admin.runCommand({
moveChunk: ns,
bounds: [{x: NumberLong(-2000000000000000000)}, {x: NumberLong(0)}],
to: st.shard1.shardName,
_waitForDelete: true
}));
assert.commandWorked(admin.runCommand({
moveChunk: ns,
bounds: [{x: NumberLong(-4500000000000000000)}, {x: NumberLong(-4000000000000000000)}],
to: st.shard0.shardName,
_waitForDelete: true
}));
assert.eq(4, staleCollection.find().itcount());
// shard0: MIN -> -4500000000000000000,
// -4500000000000000000 -> -4000000000000000000
// -4000000000000000000 -> -2500000000000000000,
// shard1: -2500000000000000000 -> -2000000000000000000
// -2000000000000000000 -> 0
// 0 -> 4611686018427387902
// 4611686018427387902 -> MAX
assert.commandWorked(admin.runCommand(
{mergeChunks: ns, bounds: [{x: NumberLong(-2500000000000000000)}, {x: MaxKey}]}));
assert.eq(4, staleCollection.find().itcount());
// shard0: MIN -> -4500000000000000000,
// -4500000000000000000 -> -4000000000000000000
// -4000000000000000000 -> -2500000000000000000,
// shard1: -2500000000000000000 -> MAX
// Make sure merge on the other shard after a chunk has been merged succeeds.
assert.commandWorked(admin.runCommand(
{mergeChunks: ns, bounds: [{x: MinKey}, {x: NumberLong(-2500000000000000000)}]}));
// shard0: MIN -> -2500000000000000000,
// shard1: -2500000000000000000 -> MAX
assert.eq(2, findChunksUtil.findChunksByNs(configDB, ns).itcount());
assert.eq(1,
findChunksUtil
.findChunksByNs(configDB, ns, {
min: {x: MinKey},
max: {x: NumberLong(-2500000000000000000)},
shard: st.shard0.shardName
})
.count());
assert.eq(1,
findChunksUtil
.findChunksByNs(configDB, ns, {
min: {x: NumberLong(-2500000000000000000)},
max: {x: MaxKey},
shard: st.shard1.shardName
})
.count());
st.stop();