summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSiyuan Zhou <siyuan.zhou@mongodb.com>2014-04-23 16:17:17 -0400
committerSiyuan Zhou <siyuan.zhou@mongodb.com>2014-09-17 14:25:00 -0400
commit0cf60aa0af55a673786d4950c4b5524c1d671e6e (patch)
tree5f7f1fac0e66250afaf3b6091d95e2452ec8821a
parent7bca29e784b536e90387974bfa5a451ce15161a5 (diff)
downloadmongo-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.js64
-rw-r--r--src/mongo/client/parallel.cpp8
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