diff options
author | Siyuan Zhou <siyuan.zhou@mongodb.com> | 2014-04-23 16:17:17 -0400 |
---|---|---|
committer | Siyuan Zhou <siyuan.zhou@mongodb.com> | 2014-09-17 14:25:00 -0400 |
commit | 0cf60aa0af55a673786d4950c4b5524c1d671e6e (patch) | |
tree | 5f7f1fac0e66250afaf3b6091d95e2452ec8821a | |
parent | 7bca29e784b536e90387974bfa5a451ce15161a5 (diff) | |
download | mongo-0cf60aa0af55a673786d4950c4b5524c1d671e6e.tar.gz |
SERVER-13702 Commands without optional query may target to wrong shards on mongos
(cherry picked from commit bd1a02385378ee50a33db7c255217c050cc74192)
SERVER-13702 Add JS tests for shard targeting.
(cherry picked from commit e986b037f1301fae63938dc9bd933ff8ac25b7d6)
-rw-r--r-- | jstests/sharding/shard_targeting.js | 64 | ||||
-rw-r--r-- | src/mongo/client/parallel.cpp | 8 |
2 files changed, 67 insertions, 5 deletions
diff --git a/jstests/sharding/shard_targeting.js b/jstests/sharding/shard_targeting.js new file mode 100644 index 00000000000..7b47a2907cd --- /dev/null +++ b/jstests/sharding/shard_targeting.js @@ -0,0 +1,64 @@ +// SERVER-13702 +// Some commands allow optional query, e.g. count, mapreduce. +// If the optional query is not given, mongos will wrongly use the command +// BSONObj itself as the query to target shards, which could return wrong +// shards if the shard key happens to be one of the fields in the command object. + +var s = new ShardingTest("shard_targeting", 2, 0, 1); +s.adminCommand({ enablesharding : "test" }); +s.stopBalancer(); + +var db = s.getDB("test"); +var res; + +// +// Target count command +// + +// Shard key is the same with command name. +s.shardGo("foo", {count: 1}, { count: "" }) + +for (var i=0; i<50; i++) { + db.foo.insert({count: i}); // chunk [MinKey, ""), including numbers + db.foo.insert({count: "" + i}); // chunk ["", MaxKey] +} + +var theOtherShard = s.getOther( s.getServer( "test" ) ).name; +printShardingStatus(); + +// Count documents on both shards + +// "count" commnad with "query" option { }. +assert.eq(db.foo.count(), 100); +// Optional "query" option is not given. +res = db.foo.runCommand("count"); +assert.eq(res.n, 100); + +// +// Target mapreduce command +// +db.foo.drop(); +// Shard key is the same with command name. +s.shardGo("foo", {mapReduce: 1}, { mapReduce: "" }) + +for (var i=0; i<50; i++) { + db.foo.insert({mapReduce: i}); // to the chunk including number + db.foo.insert({mapReduce: "" + i}); // to the chunk including string +} + +printShardingStatus(); + +function m() { emit("total", 1); } +function r(k, v) { return Array.sum(v); } +res = db.foo.runCommand( +{ + mapReduce: "foo", + map: m, + reduce: r, + out: { inline: 1 } +}); + +// Count documents on both shards +assert.eq(res.results[0].value, 100); + +s.stop(); diff --git a/src/mongo/client/parallel.cpp b/src/mongo/client/parallel.cpp index 88ee0a35d1b..84066681059 100644 --- a/src/mongo/client/parallel.cpp +++ b/src/mongo/client/parallel.cpp @@ -624,10 +624,8 @@ namespace mongo { void ParallelSortClusteredCursor::startInit() { - bool returnPartial = ( _qSpec.options() & QueryOption_PartialResults ); - bool specialVersion = _cInfo.versionedNS.size() > 0; - bool specialFilter = ! _cInfo.cmdFilter.isEmpty(); - NamespaceString ns( specialVersion ? _cInfo.versionedNS : _qSpec.ns() ); + const bool returnPartial = ( _qSpec.options() & QueryOption_PartialResults ); + NamespaceString ns( !_cInfo.isEmpty() ? _cInfo.versionedNS : _qSpec.ns() ); ChunkManagerPtr manager; ShardPtr primary; @@ -666,7 +664,7 @@ namespace mongo { } } - if( manager ) manager->getShardsForQuery( todo, specialFilter ? _cInfo.cmdFilter : _qSpec.filter() ); + if( manager ) manager->getShardsForQuery( todo, !_cInfo.isEmpty() ? _cInfo.cmdFilter : _qSpec.filter() ); else if( primary ) todo.insert( *primary ); // Close all cursors on extra shards first, as these will be invalid |