// // Basic tests for reshardCollection. // @tags: [ // uses_atclustertime, // ] // load("jstests/libs/fail_point_util.js"); load("jstests/sharding/libs/find_chunks_util.js"); load("jstests/libs/discover_topology.js"); load("jstests/sharding/libs/reshard_collection_util.js"); (function() { 'use strict'; const st = new ShardingTest({mongos: 1, shards: 2}); const kDbName = 'db'; const collName = 'foo'; const ns = kDbName + '.' + collName; const mongos = st.s0; const kNumInitialDocs = 500; const reshardCmdTest = new ReshardCollectionCmdTest({st, dbName: kDbName, collName, numInitialDocs: kNumInitialDocs}); const criticalSectionTimeoutMS = 24 * 60 * 60 * 1000; /* 1 day */ const topology = DiscoverTopology.findConnectedNodes(mongos); const coordinator = new Mongo(topology.configsvr.nodes[0]); assert.commandWorked(coordinator.getDB("admin").adminCommand( {setParameter: 1, reshardingCriticalSectionTimeoutMillis: criticalSectionTimeoutMS})); let presetReshardedChunks = [{recipientShardId: st.shard1.shardName, min: {newKey: MinKey}, max: {newKey: MaxKey}}]; /** * Fail cases */ jsTest.log('Fail if sharding is disabled.'); assert.commandFailedWithCode(mongos.adminCommand({reshardCollection: ns, key: {newKey: 1}}), ErrorCodes.NamespaceNotFound); assert.commandWorked(mongos.adminCommand({enableSharding: kDbName})); jsTest.log("Fail if collection is unsharded."); assert.commandFailedWithCode(mongos.adminCommand({reshardCollection: ns, key: {newKey: 1}}), ErrorCodes.NamespaceNotSharded); assert.commandWorked(mongos.adminCommand({shardCollection: ns, key: {oldKey: 1}})); jsTest.log("Fail if missing required key."); assert.commandFailedWithCode(mongos.adminCommand({reshardCollection: ns}), 40414); jsTest.log("Fail if unique is specified and is true."); assert.commandFailedWithCode( mongos.adminCommand({reshardCollection: ns, key: {newKey: 1}, unique: true}), ErrorCodes.BadValue); jsTest.log("Fail if collation is specified and is not {locale: 'simple'}."); assert.commandFailedWithCode( mongos.adminCommand({reshardCollection: ns, key: {newKey: 1}, collation: {locale: 'en_US'}}), ErrorCodes.BadValue); jsTest.log("Fail if both numInitialChunks and _presetReshardedChunks are provided."); assert.commandFailedWithCode(mongos.adminCommand({ reshardCollection: ns, key: {newKey: 1}, unique: false, collation: {locale: 'simple'}, numInitialChunks: 2, _presetReshardedChunks: presetReshardedChunks }), ErrorCodes.BadValue); jsTest.log("Fail if the zone provided is not assigned to a shard."); const nonExistingZoneName = 'x0'; assert.commandFailedWithCode(mongos.adminCommand({ reshardCollection: ns, key: {newKey: 1}, unique: false, collation: {locale: 'simple'}, zones: [{zone: nonExistingZoneName, min: {newKey: 5}, max: {newKey: 10}}], numInitialChunks: 2, }), 4952607); jsTestLog("Fail if splitting collection into multiple chunks while it is still empty."); assert.commandFailedWithCode( mongos.adminCommand({reshardCollection: ns, key: {b: 1}, numInitialChunks: 2}), 4952606); assert.commandFailedWithCode( st.s.adminCommand({reshardCollection: ns, key: {b: "hashed"}, numInitialChunks: 2}), 4952606); jsTest.log( "Fail if authoritative tags exist in config.tags collection and zones are not provided."); const existingZoneName = 'x1'; assert.commandWorked( st.s.adminCommand({addShardToZone: st.shard1.shardName, zone: existingZoneName})); assert.commandWorked(st.s.adminCommand( {updateZoneKeyRange: ns, min: {oldKey: 0}, max: {oldKey: 5}, zone: existingZoneName})); assert.commandFailedWithCode(mongos.adminCommand({ reshardCollection: ns, key: {newKey: 1}, unique: false, collation: {locale: 'simple'}, numInitialChunks: 2, }), ErrorCodes.BadValue); jsTestLog("Fail if attempting insert to an unsharded 'system.resharding.' collection"); assert.commandFailedWithCode(mongos.getDB('test').system.resharding.mycoll.insert({_id: 1, a: 1}), ErrorCodes.NamespaceNotSharded); /** * Success cases */ mongos.getDB(kDbName)[collName].drop(); jsTest.log("Succeed when correct locale is provided."); reshardCmdTest.assertReshardCollOk( {reshardCollection: ns, key: {newKey: 1}, collation: {locale: 'simple'}}, 1); jsTest.log("Succeed base case."); reshardCmdTest.assertReshardCollOk({reshardCollection: ns, key: {newKey: 1}}, 1); jsTest.log("Succeed if unique is specified and is false."); reshardCmdTest.assertReshardCollOk({reshardCollection: ns, key: {newKey: 1}, unique: false}, 1); jsTest.log( "Succeed if _presetReshardedChunks is provided and test commands are enabled (default)."); reshardCmdTest.assertReshardCollOkWithPreset({reshardCollection: ns, key: {newKey: 1}}, presetReshardedChunks); presetReshardedChunks = [ {recipientShardId: st.shard0.shardName, min: {newKey: MinKey}, max: {newKey: 0}}, {recipientShardId: st.shard1.shardName, min: {newKey: 0}, max: {newKey: MaxKey}} ]; jsTest.log("Succeed if all optional fields and numInitialChunks are provided with correct values."); reshardCmdTest.assertReshardCollOk({ reshardCollection: ns, key: {newKey: 1}, unique: false, collation: {locale: 'simple'}, numInitialChunks: 2, }, 2); jsTest.log( "Succeed if all optional fields and _presetReshardedChunks are provided with correct values" + " and test commands are enabled (default)."); reshardCmdTest.assertReshardCollOkWithPreset( {reshardCollection: ns, key: {newKey: 1}, unique: false, collation: {locale: 'simple'}}, presetReshardedChunks); jsTest.log("Succeed if the zone provided is assigned to a shard but not a range for the source" + " collection."); const newZoneName = 'x2'; assert.commandWorked(st.s.adminCommand({addShardToZone: st.shard1.shardName, zone: newZoneName})); reshardCmdTest.assertReshardCollOk({ reshardCollection: ns, key: {newKey: 1}, unique: false, collation: {locale: 'simple'}, zones: [{zone: newZoneName, min: {newKey: 5}, max: {newKey: 10}}] }, 3); jsTest.log("Succeed if resulting chunks all end up in one shard."); reshardCmdTest.assertReshardCollOk({ reshardCollection: ns, key: {newKey: 1}, unique: false, numInitialChunks: 1, collation: {locale: 'simple'}, zones: [{zone: newZoneName, min: {newKey: MinKey}, max: {newKey: MaxKey}}] }, 1); jsTest.log("Succeed if zones are empty"); reshardCmdTest.assertReshardCollOk({ reshardCollection: ns, key: {newKey: 1}, unique: false, numInitialChunks: 1, collation: {locale: 'simple'}, zones: [] }, 1); jsTest.log("Succeed if zones are not empty."); assert.commandWorked( mongos.adminCommand({addShardToZone: st.shard1.shardName, zone: existingZoneName})); assert.commandWorked(st.s.adminCommand( {updateZoneKeyRange: ns, min: {oldKey: 0}, max: {oldKey: 5}, zone: existingZoneName})); reshardCmdTest.assertReshardCollOk({ reshardCollection: ns, key: {oldKey: 1, newKey: 1}, unique: false, collation: {locale: 'simple'}, zones: [{zone: existingZoneName, min: {oldKey: 0}, max: {oldKey: 5}}] }, 3); jsTest.log("Succeed with hashed shard key that provides enough cardinality."); assert.commandWorked( mongos.adminCommand({shardCollection: ns, key: {a: "hashed"}, numInitialChunks: 5})); assert.commandWorked(mongos.getCollection(ns).insert( Array.from({length: 10000}, (_, i) => ({a: new ObjectId(), b: new ObjectId()})))); assert.commandWorked( st.s.adminCommand({reshardCollection: ns, key: {b: "hashed"}, numInitialChunks: 5})); mongos.getDB(kDbName)[collName].drop(); st.stop(); })();