diff options
author | Jonathan Abrahams <jonathan@mongodb.com> | 2015-02-02 09:40:25 -0500 |
---|---|---|
committer | Benety Goh <benety@mongodb.com> | 2015-02-06 13:17:01 -0500 |
commit | 8c72cdbea2a3c15e67c4f53cd54ec38510e7080c (patch) | |
tree | a3f1496532d2520bb414f59f1ce16b6b927f7325 /jstests | |
parent | 7eb9c853416d123773e620cd16491856891d2ff0 (diff) | |
download | mongo-8c72cdbea2a3c15e67c4f53cd54ec38510e7080c.tar.gz |
SERVER-15831 Enhanced top chunk auto split tests
Closes #919
Signed-off-by: Benety Goh <benety@mongodb.com>
Diffstat (limited to 'jstests')
-rw-r--r-- | jstests/sharding/top_chunk_autosplit.js | 359 |
1 files changed, 296 insertions, 63 deletions
diff --git a/jstests/sharding/top_chunk_autosplit.js b/jstests/sharding/top_chunk_autosplit.js index 621bab10ee2..eae5be442c6 100644 --- a/jstests/sharding/top_chunk_autosplit.js +++ b/jstests/sharding/top_chunk_autosplit.js @@ -1,89 +1,322 @@ -var st = new ShardingTest({ shards: 3, chunksize: 1 }); +function shardSetup(shardConfig, dbName, collName) { + var st = new ShardingTest(shardConfig); + var db = st.getDB(dbName); + var coll = db[collName]; + var configDB = st.s.getDB('config'); -var testDB = st.s.getDB('test'); + // Disable the balancer to not interfere with the test, but keep the balancer settings on + // so the auto split logic will be able to move chunks around. + st.startBalancer(); + db.adminCommand({configureFailPoint: 'skipBalanceRound', mode: 'alwaysOn'}); + return st; +} -// Disable the balancer to not interfere with the test, but keep the balancer settings on -// so the auto split logic will be able to move chunks around. -st.startBalancer(); -var res = testDB.adminCommand({ configureFailPoint: 'skipBalanceRound', mode: 'alwaysOn' }); +function getShardWithTopChunk(configDB, lowOrHigh) { + // lowOrHigh: 1 low "top chunk", -1 high "top chunk" + return configDB.chunks.find({}).sort({min: lowOrHigh}).limit(1).next().shard; +} -testDB.adminCommand({ enableSharding: 'test' }); -testDB.adminCommand({ movePrimary: 'test', to: 'shard0001' }); +function getNumberOfChunks(configDB) { + return configDB.chunks.count(); +} -// Basic test with no tag, top chunk should move to shard with least chunks. -// -// Setup: -// s0: [0, inf) -> 10 chunks -// s1: [-100, 0) -> 10 chunks -// s2: [-inf, -100) -> 1 chunk +function runTest(test) { + jsTest.log(tojson(test)); -testDB.adminCommand({ shardCollection: 'test.user', key: { x: 1 }}); + // Setup + // Enable sharding, set primary shard and shard collection + db.adminCommand({enableSharding: dbName}); + db.adminCommand({movePrimary: dbName, to: 'shard0000'}); + db.adminCommand({shardCollection: coll + "", key: {x: 1}}); -testDB.adminCommand({ split: 'test.user', middle: { x: 0 }}); -assert.commandWorked( - testDB.adminCommand({ moveChunk: 'test.user', find: { x: 0 }, to: 'shard0000' })); + // Pre-split, move chunks & create tags + for (var i = 0; i < test.shards.length; i++) { + var startRange = test.shards[i].range.min; + var endRange = test.shards[i].range.max; + var chunkSize = Math.abs(endRange-startRange)/test.shards[i].chunks; + for (var j = startRange; j < endRange; j += chunkSize) { + // No split on highest chunk + if (j + chunkSize >= MAXVAL) { + continue; + } + db.adminCommand({split: coll + "", middle: {x: j+chunkSize}}); + db.adminCommand({moveChunk: coll + "", find: {x: j}, to: test.shards[i].name}); + } + // Make sure to move chunk when there's only 1 chunk in shard + db.adminCommand({moveChunk: coll + "", find: {x: startRange}, to: test.shards[i].name}); + // Make sure to move highest chunk + if (test.shards[i].range.max == MAXVAL) { + db.adminCommand({moveChunk: coll + "", find: {x: MAXVAL}, to: test.shards[i].name}); + } + // Add tags to each shard + var tags = test.shards[i].tags || []; + for (j = 0; j < tags.length; j++) { + sh.addShardTag(test.shards[i].name, tags[j]); + } + } -for (var x = -100; x < 100; x+= 10) { - testDB.adminCommand({ split: 'test.user', middle: { x: x }}); -} + // Add tag ranges associated to a tag + var tagRanges = test.tagRanges || []; + for (var j = 0; j < tagRanges.length; j++) { + sh.addTagRange(db + "." + collName, + {x: tagRanges[j].range.min}, + {x: tagRanges[j].range.max}, + tagRanges[j].tag); + } -assert.commandWorked( - testDB.adminCommand({ moveChunk: 'test.user', find: { x: -1000 }, to: 'shard0002' })); + // Number of chunks before auto-split + var numChunks = getNumberOfChunks(configDB); + // End of setup -var configDB = st.s.getDB('config'); -var largeStr = new Array(1024).join('x'); + // Insert on top chunk to force auto-split + var largeStr = new Array(1000).join('x'); -// The inserts should be bulked as one so the auto-split will only be triggered once. -var bulk = testDB.user.initializeUnorderedBulkOp(); -for (var x = 100; x < 2000; x++) { - bulk.insert({ x: x, val: largeStr }); + // Insert one doc at a time until first auto-split occurs on top chunk + var xval = test.inserts.value; + do { + var doc = {x: xval, val: largeStr}; + coll.insert(doc); + xval += test.inserts.inc; + } while (getNumberOfChunks(configDB) <= numChunks); + + // Test for where new top chunk should reside + assert.eq(getShardWithTopChunk(configDB, test.lowOrHigh), + test.movedToShard, + test.name + " chunk in the wrong shard"); + + // Cleanup: Drop collection, tags & tag ranges + coll.drop(); + for (var i = 0; i < test.shards.length; i++) { + var tags = test.shards[i].tags || []; + for (j = 0; j < tags.length; j++) { + sh.removeShardTag(test.shards[i].name, tags[j]); + } + } + configDB.tags.remove({ns: db + "." + collName}); + // End of test cleanup } -bulk.execute(); -var topChunkAfter = configDB.chunks.find({}).sort({ min: -1 }).next(); -assert.eq('shard0002', topChunkAfter.shard, 'chunk in the wrong shard: ' + tojson(topChunkAfter)); +// Main +var dbName = "test"; +var collName = "topchunk"; +var st = shardSetup({name: "topchunk", shards: 4, chunksize: 1}, dbName, collName); +var db = st.getDB(dbName); +var coll = db[collName]; +var configDB = st.s.getDB('config'); -testDB.user.drop(); +// Define shard key ranges for each of the shard nodes +var MINVAL = -500; +var MAXVAL = 1500; +var lowChunkRange = {min: MINVAL, max: 0}; +var midChunkRange1 = {min: 0, max: 500}; +var midChunkRange2 = {min: 500, max: 1000}; +var highChunkRange = {min: 1000, max: MAXVAL}; -// Basic test with tag, top chunk should move to the other shard with the right tag. -// -// Setup: -// s0: [0, inf) -> 10 chunks, tag: A -// s1: [-100, 0) -> 10 chunks, tag: A -// s2: [-inf, -100) -> 1 chunk, tag: B +var lowChunkTagRange = {min: MinKey, max: 0}; +var highChunkTagRange = {min: 1000, max: MaxKey}; -testDB.adminCommand({ shardCollection: 'test.user', key: { x: 1 }}); +var lowChunkInserts = {value: 0, inc: -1}; +var midChunkInserts = {value: 1, inc: 1}; +var highChunkInserts = {value: 1000, inc: 1}; -testDB.adminCommand({ split: 'test.user', middle: { x: 0 }}); -assert.commandWorked( - testDB.adminCommand({ moveChunk: 'test.user', find: { x: 0 }, to: 'shard0000' })); +var lowChunk = 1; +var highChunk = -1; -for (var x = -20; x < 100; x+= 10) { - testDB.adminCommand({ split: 'test.user', middle: { x: x }}); -} +// Test objects: +// name - name of test +// lowOrHigh - 1 for low top chunk, -1 for high top chunk +// movedToShard - name of shard the new top chunk should reside on +// shards - array of shard objects +// name - name of shard +// range - range object of shard key +// chunks - number of chunks to pre-split on this shard +// tags - array of tags associated to this shard +// tagRanges - array of objects defining the tag range +// range - range object of shard key +// tag - tag associated to this range +// inserts - object for inserting on shard key from low to high +// low - low shard key value +// high - high shard key value +var tests = [ + { + // Test auto-split on the "low" top chunk to another tagged shard + name: "low top chunk with tag move", + lowOrHigh: lowChunk, + movedToShard: "shard0002", + shards: [{name: "shard0000", range: lowChunkRange, chunks: 20, tags: ["NYC"]}, + {name: "shard0001", range: midChunkRange1, chunks: 20, tags: ["SF"]}, + {name: "shard0002", range: highChunkRange, chunks: 5, tags: ["NYC"]}, + {name: "shard0003", range: midChunkRange2, chunks: 1, tags: ["SF"]}, + ], + tagRanges: [{range: lowChunkTagRange, tag: "NYC"}, + {range: highChunkTagRange, tag: "NYC"}, + {range: midChunkRange1, tag: "SF"}, + {range: midChunkRange2, tag: "SF"}], + inserts: lowChunkInserts + }, + { + // Test auto-split on the "low" top chunk to same tagged shard + name: "low top chunk with tag no move", + lowOrHigh: lowChunk, + movedToShard: "shard0000", + shards: [{name: "shard0000", range: lowChunkRange, chunks: 5, tags: ["NYC"]}, + {name: "shard0001", range: midChunkRange1, chunks: 20, tags: ["SF"]}, + {name: "shard0002", range: highChunkRange, chunks: 20, tags: ["NYC"]}, + {name: "shard0003", range: midChunkRange2, chunks: 1, tags: ["SF"]}, + ], + tagRanges: [{range: lowChunkTagRange, tag: "NYC"}, + {range: highChunkTagRange, tag: "NYC"}, + {range: midChunkRange1, tag: "SF"}, + {range: midChunkRange2, tag: "SF"}], + inserts: lowChunkInserts + }, + { + // Test auto-split on the "low" top chunk to another shard + name: "low top chunk no tag move", + lowOrHigh: lowChunk, + movedToShard: "shard0003", + shards: [{name: "shard0000", range: lowChunkRange, chunks: 20}, + {name: "shard0001", range: midChunkRange1, chunks: 20}, + {name: "shard0002", range: highChunkRange, chunks: 5}, + {name: "shard0003", range: midChunkRange2, chunks: 1}], + inserts: lowChunkInserts + }, + { + // Test auto-split on the "high" top chunk to another tagged shard + name: "high top chunk with tag move", + lowOrHigh: highChunk, + movedToShard: "shard0000", + shards: [{name: "shard0000", range: lowChunkRange, chunks: 5, tags: ["NYC"]}, + {name: "shard0001", range: midChunkRange1, chunks: 20, tags: ["SF"]}, + {name: "shard0002", range: highChunkRange, chunks: 20, tags: ["NYC"]}, + {name: "shard0003", range: midChunkRange2, chunks: 1, tags: ["SF"]}], + tagRanges: [{range: lowChunkTagRange, tag: "NYC"}, + {range: highChunkTagRange, tag: "NYC"}, + {range: midChunkRange1, tag: "SF"}, + {range: midChunkRange2, tag: "SF"}], + inserts: highChunkInserts + }, + { + // Test auto-split on the "high" top chunk to another shard + name: "high top chunk no tag move", + lowOrHigh: highChunk, + movedToShard: "shard0003", + shards: [{name: "shard0000", range: lowChunkRange, chunks: 5}, + {name: "shard0001", range: midChunkRange1, chunks: 20}, + {name: "shard0002", range: highChunkRange, chunks: 20}, + {name: "shard0003", range: midChunkRange2, chunks: 1}], + inserts: highChunkInserts + }, + { + // Test auto-split on the "high" top chunk to same tagged shard + name: "high top chunk with tag no move", + lowOrHigh: highChunk, + movedToShard: "shard0002", + shards: [{name: "shard0000", range: lowChunkRange, chunks: 20, tags: ["NYC"]}, + {name: "shard0001", range: midChunkRange1, chunks: 20, tags: ["SF"]}, + {name: "shard0002", range: highChunkRange, chunks: 5, tags: ["NYC"]}, + {name: "shard0003", range: midChunkRange2, chunks: 1, tags: ["SF"]}], + tagRanges: [{range: lowChunkTagRange, tag: "NYC"}, + {range: highChunkTagRange, tag: "NYC"}, + {range: midChunkRange1, tag: "SF"}, + {range: midChunkRange2, tag: "SF"}], + inserts: highChunkInserts + }, + { + // Test auto-split on the "high" top chunk to same shard + name: "high top chunk no tag no move", + lowOrHigh: highChunk, + movedToShard: "shard0002", + shards: [{name: "shard0000", range: lowChunkRange, chunks: 20}, + {name: "shard0001", range: midChunkRange1, chunks: 20}, + {name: "shard0002", range: highChunkRange, chunks: 1}, + {name: "shard0003", range: midChunkRange2, chunks: 5}], + inserts: highChunkInserts + } +]; -assert.commandWorked( - testDB.adminCommand({ moveChunk: 'test.user', find: { x: -1000 }, to: 'shard0002' })); +// Execute all test objects +for (var i = 0; i < tests.length; i++) { + runTest(tests[i]); +} -// assign global db variable to make sh.addShardTag work correctly. -db = testDB; +st.stop(); -sh.addShardTag('shard0000', 'A'); -sh.addShardTag('shard0001', 'A'); -sh.addShardTag('shard0002', 'B'); +// Single node shard Tests +st = shardSetup({name: "singleNode", shards: 1, chunksize: 1}, dbName, collName); +db = st.getDB(dbName); +coll = db[collName]; +configDB = st.s.getDB('config'); -sh.addTagRange('test.user', { x: MinKey }, { x: -100 }, 'B'); -sh.addTagRange('test.user', { x: -100 }, { x: MaxKey }, 'A'); +var singleNodeTests = [ + { + // Test auto-split on the "low" top chunk on single node shard + name: "single node shard - low top chunk", + lowOrHigh: lowChunk, + movedToShard: "shard0000", + shards: [{name: "shard0000", range: lowChunkRange, chunks: 2}], + inserts: lowChunkInserts + }, + { + // Test auto-split on the "high" top chunk on single node shard + name: "single node shard - high top chunk", + lowOrHigh: highChunk, + movedToShard: "shard0000", + shards: [{name: "shard0000", range: highChunkRange, chunks: 2}], + inserts: highChunkInserts + } +]; -// The inserts should be bulked as one so the auto-split will only be triggered once. -bulk = testDB.user.initializeUnorderedBulkOp(); -for (var x = 100; x < 2000; x++) { - bulk.insert({ x: x, val: largeStr }); +// Execute all test objects +for (var i = 0; i < singleNodeTests.length; i++) { + runTest(singleNodeTests[i]); } -bulk.execute(); - -topChunkAfter = configDB.chunks.find({}).sort({ min: -1 }).next(); -assert.eq('shard0001', topChunkAfter.shard, 'chunk in the wrong shard: ' + tojson(topChunkAfter)); st.stop(); +// maxSize test +// To set maxSize, must manually add the shards +st = shardSetup({name: "maxSize", shards: 2, chunksize: 1, other: {manualAddShard: true}}, + dbName, + collName); +db = st.getDB(dbName); +coll = db[collName]; +configDB = st.s.getDB('config'); + +// maxSize on shard0000 - 5MB, on shard0001 - 1MB +st.adminCommand({addshard: st.getConnNames()[0], maxSize: 5}); +st.adminCommand({addshard: st.getConnNames()[1], maxSize: 1}); + +var maxSizeTests = [ + { + // Test auto-split on the "low" top chunk with maxSize on + // destination shard + name: "maxSize - low top chunk", + lowOrHigh: lowChunk, + movedToShard: "shard0000", + shards: [{name: "shard0000", range: lowChunkRange, chunks: 10}, + {name: "shard0001", range: highChunkRange, chunks: 1}], + inserts: lowChunkInserts + }, + { + // Test auto-split on the "high" top chunk with maxSize on + // destination shard + name: "maxSize - high top chunk", + lowOrHigh: highChunk, + movedToShard: "shard0000", + shards: [{name: "shard0000", range: highChunkRange, chunks: 10}, + {name: "shard0001", range: lowChunkRange, chunks: 1}], + inserts: highChunkInserts + } +]; + +// Execute all test objects +// SERVER-17070 Auto split moves to shard node running WiredTiger, if exceeding maxSize +if (st.d0.adminCommand({serverStatus: 1}).storageEngine.name != "wiredTiger" && + st.d1.adminCommand({serverStatus: 1}).storageEngine.name != "wiredTiger") { + for (var i = 0; i < maxSizeTests.length; i++) { + runTest(maxSizeTests[i]); + } +} + +st.stop(); |