diff options
-rw-r--r-- | client/dbclient.h | 4 | ||||
-rw-r--r-- | db/commands.h | 6 | ||||
-rw-r--r-- | jstests/sharding/group_slaveok.js | 62 | ||||
-rw-r--r-- | s/commands_public.cpp | 26 | ||||
-rw-r--r-- | s/strategy_single.cpp | 4 | ||||
-rw-r--r-- | shell/mongo.js | 9 | ||||
-rwxr-xr-x | shell/servers.js | 22 | ||||
-rw-r--r-- | util/goodies.h | 2 |
8 files changed, 115 insertions, 20 deletions
diff --git a/client/dbclient.h b/client/dbclient.h index b27eab5c545..3f3b9441b6d 100644 --- a/client/dbclient.h +++ b/client/dbclient.h @@ -80,7 +80,9 @@ namespace mongo { */ QueryOption_PartialResults = 1 << 7 , - QueryOption_AllSupported = QueryOption_CursorTailable | QueryOption_SlaveOk | QueryOption_OplogReplay | QueryOption_NoCursorTimeout | QueryOption_AwaitData | QueryOption_Exhaust | QueryOption_PartialResults + QueryOption_NoOplog = 1 << 8 , + + QueryOption_AllSupported = QueryOption_CursorTailable | QueryOption_SlaveOk | QueryOption_OplogReplay | QueryOption_NoCursorTimeout | QueryOption_AwaitData | QueryOption_Exhaust | QueryOption_PartialResults | QueryOption_NoOplog }; diff --git a/db/commands.h b/db/commands.h index 454e2277e06..ff26d041817 100644 --- a/db/commands.h +++ b/db/commands.h @@ -20,6 +20,7 @@ #include "../pch.h" #include "jsobj.h" #include "../util/timer.h" +#include "../client/dbclient.h" namespace mongo { @@ -46,6 +47,9 @@ namespace mongo { return value is true if succeeded. if false, set errmsg text. */ virtual bool run(const string& db, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) = 0; + virtual bool run(const string& db, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, int options){ + return run( db, cmdObj, errmsg, result, ( options & QueryOption_NoOplog ) > 0 ); + } /* note: logTheTop() MUST be false if READ @@ -120,7 +124,7 @@ namespace mongo { static const map<string,Command*>* commandsByBestName() { return _commandsByBestName; } static const map<string,Command*>* webCommands() { return _webCommands; } /** @return if command was found and executed */ - static bool runAgainstRegistered(const char *ns, BSONObj& jsobj, BSONObjBuilder& anObjBuilder); + static bool runAgainstRegistered(const char *ns, BSONObj& jsobj, BSONObjBuilder& anObjBuilder, int queryOptions = 0); static LockType locktype( const string& name ); static Command * findCommand( const string& name ); }; diff --git a/jstests/sharding/group_slaveok.js b/jstests/sharding/group_slaveok.js new file mode 100644 index 00000000000..930ea095351 --- /dev/null +++ b/jstests/sharding/group_slaveok.js @@ -0,0 +1,62 @@ +// Tests group using slaveOk + +var st = new ShardingTest( testName = "groupSlaveOk", + numShards = 1, + verboseLevel = 0, + numMongos = 1, + { rs : true, + rs0 : { nodes : 2 } + }) + +var rst = st._rs[0].test + +// Insert data into replica set +var conn = new Mongo( st.s.host ) +conn.setLogLevel( 3 ) + +var coll = conn.getCollection( "test.groupSlaveOk" ) +coll.drop() + +for( var i = 0; i < 300; i++ ){ + coll.insert( { i : i % 10 } ) +} + +// Make sure the writes get through, otherwise we can continue to error these one-at-a-time +coll.getDB().getLastError() + +st.printShardingStatus() + +// Wait for client to update itself and replication to finish +rst.awaitReplication() + +// Data now inserted... stop the master, since only two in set, other will still be secondary +rst.stop( rst.getMaster(), undefined, true ) +printjson( rst.status() ) + +// Need to check slaveOk=true first, since slaveOk=false will destroy conn in pool when +// master is down +conn.setSlaveOk() + +// Should throw exception, since not slaveOk'd +assert.eq( 10, coll.group({ key : { i : true } , + reduce : function( obj, ctx ){ ctx.count += 1 } , + initial : { count : 0 } }).length ) + +try { + + conn.setSlaveOk( false ) + coll.group({ key : { i : true } , + reduce : function( obj, ctx ){ ctx.count += 1 } , + initial : { count : 0 } }) + + print( "Should not reach here!" ) + printjson( coll.getDB().getLastError() ) + assert( false ) + +} +catch( e ){ + print( "Non-slaveOk'd connection failed." ) +} + +// Finish +st.stop() diff --git a/s/commands_public.cpp b/s/commands_public.cpp index 713b9489fc2..890972b9ee6 100644 --- a/s/commands_public.cpp +++ b/s/commands_public.cpp @@ -57,18 +57,26 @@ namespace mongo { virtual LockType locktype() const { return NONE; } protected: + bool passthrough( DBConfigPtr conf, const BSONObj& cmdObj , BSONObjBuilder& result ) { - return _passthrough(conf->getName(), conf, cmdObj, result); + return _passthrough(conf->getName(), conf, cmdObj, 0, result); } bool adminPassthrough( DBConfigPtr conf, const BSONObj& cmdObj , BSONObjBuilder& result ) { - return _passthrough("admin", conf, cmdObj, result); + return _passthrough("admin", conf, cmdObj, 0, result); + } + + bool passthrough( DBConfigPtr conf, const BSONObj& cmdObj , int options, BSONObjBuilder& result ) { + return _passthrough(conf->getName(), conf, cmdObj, options, result); + } + bool adminPassthrough( DBConfigPtr conf, const BSONObj& cmdObj , int options, BSONObjBuilder& result ) { + return _passthrough("admin", conf, cmdObj, options, result); } private: - bool _passthrough(const string& db, DBConfigPtr conf, const BSONObj& cmdObj , BSONObjBuilder& result ) { + bool _passthrough(const string& db, DBConfigPtr conf, const BSONObj& cmdObj , int options , BSONObjBuilder& result ) { ShardConnection conn( conf->getPrimary() , "" ); BSONObj res; - bool ok = conn->runCommand( db , cmdObj , res ); + bool ok = conn->runCommand( db , cmdObj , res , options ); if ( ! ok && res["code"].numberInt() == StaleConfigInContextCode ) { conn.done(); throw StaleConfigException("foo","command failed because of stale config"); @@ -160,12 +168,16 @@ namespace mongo { virtual string getFullNS( const string& dbName , const BSONObj& cmdObj ) = 0; virtual bool run(const string& dbName , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool) { + return run( dbName, cmdObj, errmsg, result, 0); + } + + virtual bool run(const string& dbName , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, int options) { string fullns = getFullNS( dbName , cmdObj ); DBConfigPtr conf = grid.getDBConfig( dbName , false ); if ( ! conf || ! conf->isShardingEnabled() || ! conf->isSharded( fullns ) ) { - return passthrough( conf , cmdObj , result ); + return passthrough( conf , cmdObj , options, result ); } errmsg = "can't do command: " + name + " on sharded collection"; return false; @@ -1285,7 +1297,7 @@ namespace mongo { } - bool Command::runAgainstRegistered(const char *ns, BSONObj& jsobj, BSONObjBuilder& anObjBuilder) { + bool Command::runAgainstRegistered(const char *ns, BSONObj& jsobj, BSONObjBuilder& anObjBuilder, int queryOptions) { const char *p = strchr(ns, '.'); if ( !p ) return false; if ( strcmp(p, ".$cmd") != 0 ) return false; @@ -1326,7 +1338,7 @@ namespace mongo { anObjBuilder.append( "help" , help.str() ); } else { - ok = c->run( nsToDatabase( ns ) , jsobj, errmsg, anObjBuilder, false); + ok = c->run( nsToDatabase( ns ) , jsobj, errmsg, anObjBuilder, queryOptions); } BSONObj tmp = anObjBuilder.asTempObj(); diff --git a/s/strategy_single.cpp b/s/strategy_single.cpp index b3eef9dafa4..fac21895a4c 100644 --- a/s/strategy_single.cpp +++ b/s/strategy_single.cpp @@ -36,7 +36,7 @@ namespace mongo { virtual void queryOp( Request& r ) { QueryMessage q( r.d() ); - log(3) << "single query: " << q.ns << " " << q.query << " ntoreturn: " << q.ntoreturn << endl; + log(3) << "single query: " << q.ns << " " << q.query << " ntoreturn: " << q.ntoreturn << " options : " << q.queryOptions << endl; if ( r.isCommand() ) { @@ -55,7 +55,7 @@ namespace mongo { : str::equals("query", e.fieldName()))) cmdObj = e.embeddedObject(); } - bool ok = Command::runAgainstRegistered(q.ns, cmdObj, builder); + bool ok = Command::runAgainstRegistered(q.ns, cmdObj, builder, q.queryOptions); if ( ok ) { BSONObj x = builder.done(); replyToQuery(0, r.p(), r.m(), x); diff --git a/shell/mongo.js b/shell/mongo.js index e129784bf66..25357691c51 100644 --- a/shell/mongo.js +++ b/shell/mongo.js @@ -24,8 +24,9 @@ if ( typeof mongoInject == "function" ){ mongoInject( Mongo.prototype ); } -Mongo.prototype.setSlaveOk = function() { - this.slaveOk = true; +Mongo.prototype.setSlaveOk = function( value ) { + if( value == undefined ) value = true + this.slaveOk = value } Mongo.prototype.getDB = function( name ){ @@ -43,6 +44,10 @@ Mongo.prototype.adminCommand = function( cmd ){ return this.getDB( "admin" ).runCommand( cmd ); } +Mongo.prototype.setLogLevel = function( logLevel ){ + return this.adminCommand({ setParameter : 1, logLevel : logLevel }) +} + Mongo.prototype.getDBNames = function(){ return this.getDBs().databases.map( function(z){ diff --git a/shell/servers.js b/shell/servers.js index e8797ae1a5d..29d6f220ea1 100755 --- a/shell/servers.js +++ b/shell/servers.js @@ -170,8 +170,7 @@ ShardingTest = function( testName , numShards , verboseLevel , numMongos , other var localhost = otherParams.useHostname ? getHostName() : "localhost"; this._alldbpaths = [] - - + if ( otherParams.rs ){ localhost = getHostName(); // start replica sets @@ -179,16 +178,18 @@ ShardingTest = function( testName , numShards , verboseLevel , numMongos , other for ( var i=0; i<numShards; i++){ var setName = testName + "-rs" + i; - var rsDefaults = { oplogSize : 40 } + var rsDefaults = { oplogSize : 40, nodes : 3 } var rsParams = otherParams["rs" + i] for( var param in rsParams ){ rsDefaults[param] = rsParams[param] } - var numReplicas = otherParams.numReplicas || 3 + var numReplicas = rsDefaults.nodes || otherParams.numReplicas || 3 + delete rsDefaults.nodes + var rs = new ReplSetTest( { name : setName , nodes : numReplicas , startPort : 31100 + ( i * 100 ) } ); - this._rs[i] = { setName : setName , test : rs , nodes : rs.startSet( rsParams ) , url : rs.getURL() }; + this._rs[i] = { setName : setName , test : rs , nodes : rs.startSet( rsDefaults ) , url : rs.getURL() }; rs.initiate(); } @@ -1297,6 +1298,7 @@ ReplSetTest.prototype.getMaster = function( timeout ) { return master; } +ReplSetTest.prototype.getPrimary = ReplSetTest.prototype.getMaster ReplSetTest.prototype.getSecondaries = function( timeout ){ var master = this.getMaster( timeout ) @@ -1309,6 +1311,12 @@ ReplSetTest.prototype.getSecondaries = function( timeout ){ return secs } +ReplSetTest.prototype.status = function( timeout ){ + var master = this.callIsMaster() + if( ! master ) master = this.liveNodes.slaves[0] + return master.getDB("admin").runCommand({replSetGetStatus: 1}) +} + // Add a node to the test set ReplSetTest.prototype.add = function( config ) { if(this.ports.length == 0) { @@ -1719,10 +1727,10 @@ ReplSetTest.prototype.waitForIndicator = function( node, states, ind, timeout ){ var lastTime = null var currTime = new Date().getTime() var status = undefined - + this.attempt({context: this, timeout: timeout, desc: "waiting for state indicator " + ind + " for " + timeout + "ms" }, function() { - status = this.getMaster().getDB("admin").runCommand({ replSetGetStatus : 1 }) + status = this.status() if( lastTime == null || ( currTime = new Date().getTime() ) - (1000 * 5) > lastTime ){ if( lastTime == null ) print( "ReplSetTest waitForIndicator Initial status ( timeout : " + timeout + " ) :" ) diff --git a/util/goodies.h b/util/goodies.h index 51a80f6783c..65bfbaba982 100644 --- a/util/goodies.h +++ b/util/goodies.h @@ -109,6 +109,8 @@ namespace mongo { // PRINTFL; prints file:line #define MONGO_PRINTFL cout << __FILE__ ":" << __LINE__ << endl #define PRINTFL MONGO_PRINTFL +#define MONGO_FLOG log() << __FILE__ ":" << __LINE__ << endl +#define FLOG MONGO_FLOG #undef assert #define assert MONGO_assert |