// // Tests during chunk migration that the recipient does not receive out of range deletes from // the donor. // // Pauses the migration on the recipient shard after the initial data chunk cloning is finished. // This allows time for the donor shard to perform deletes, half of which are on the migrating // chunk. The recipient is then set to continue, collecting the delete mods from the donor, and // finishes the migration. A failpoint is set prior to resuming in the recipient shard to fail // if it receives an out of chunk range delete from the donor's delete mods log. // // The idea is that the recipient shard should not be collecting deletes from the donor shard // that are not in range and that will unnecessarily prevent the migration from finishing: the // migration can only end when donor's log of delete mods for the migrating chunk is empty. // load('./jstests/libs/chunk_manipulation_util.js'); (function() { "use strict"; var staticMongod = MongoRunner.runMongod({}); // For startParallelOps. /** * Start up new sharded cluster, stop balancer that would interfere in manual chunk management. */ var st = new ShardingTest({shards: 2, mongos: 1}); st.stopBalancer(); var mongos = st.s0, admin = mongos.getDB('admin'), shards = mongos.getCollection('config.shards').find().toArray(), dbName = "testDB", ns = dbName + ".foo", coll = mongos.getCollection(ns), donor = st.shard0, recipient = st.shard1, donorColl = donor.getCollection(ns), recipientColl = recipient.getCollection(ns); /** * Exable sharding, and split collection into two chunks. */ // Two chunks // Donor: [0, 10) [10, 20) // Recipient: jsTest.log('Enable sharding of the collection and pre-split into two chunks....'); assert.commandWorked(admin.runCommand({enableSharding: dbName})); st.ensurePrimaryShard(dbName, shards[0]._id); assert.commandWorked(admin.runCommand({shardCollection: ns, key: {a: 1}})); assert.commandWorked(admin.runCommand({split: ns, middle: {a: 10}})); /** * Insert data into collection */ // 10 documents in each chunk on the donor jsTest.log('Inserting 20 docs into donor shard, 10 in each chunk....'); for (var i = 0; i < 20; ++i) donorColl.insert({a: i}); assert.eq(null, donorColl.getDB().getLastError()); assert.eq(20, donorColl.count()); /** * Set failpoints. Recipient will crash if an out of chunk range data delete is * received from donor. Recipient will pause migration after cloning chunk data from donor, * before checking delete mods log on donor. */ jsTest.log('setting failpoint failMigrationReceivedOutOfRangeDelete'); assert.commandWorked(recipient.getDB('admin').runCommand( {configureFailPoint: 'failMigrationReceivedOutOfRangeDelete', mode: 'alwaysOn'})); jsTest.log('setting recipient failpoint cloned'); pauseMigrateAtStep(recipient, migrateStepNames.cloned); /** * Start a moveChunk in the background. Move chunk [10, 20), which has 10 docs, * from shard 0 (donor) to shard 1 (recipient). Migration will pause after cloning * (when it reaches the recipient failpoint). */ // Donor: [0, 10) // Recipient: [10, 20) jsTest.log('starting migration, pause after cloning...'); var joinMoveChunk = moveChunkParallel( staticMongod, st.s0.host, {a: 10}, null, coll.getFullName(), shards[1]._id); /** * Wait for recipient to finish cloning. * THEN delete 10 documents on donor, 5 in the migrating chunk and the 5 in the remaining chunk. */ jsTest.log('Delete 5 docs from each chunk, migrating chunk and remaining chunk...'); waitForMigrateStep(recipient, migrateStepNames.cloned); donorColl.remove({$and: [{a: {$gte: 5}}, {a: {$lt: 15}}]}); /** * Finish migration. Unpause recipient migration, wait for it to collect * the delete diffs from donor and finish. */ jsTest.log('Continuing and finishing migration...'); unpauseMigrateAtStep(recipient, migrateStepNames.cloned); joinMoveChunk(); /** * Check documents are where they should be: 5 docs in each shard's chunk. */ jsTest.log('Checking that documents are on the shards they should be...'); assert.eq(5, donorColl.count()); assert.eq(5, recipientColl.count()); assert.eq(10, coll.count()); jsTest.log('DONE!'); st.stop(); })();