diff options
author | Scott Hernandez <scotthernandez@gmail.com> | 2014-02-26 11:25:50 -0500 |
---|---|---|
committer | Scott Hernandez <scotthernandez@gmail.com> | 2014-02-26 12:11:30 -0500 |
commit | a56653e1df978f68b887788b39d053e3f88bb0ea (patch) | |
tree | 4ba0d7d3114f6edc4a924a6ed40b42632bfe3736 /src/mongo/shell | |
parent | f4c7d400c8f938374474a37cde54e36168e60b26 (diff) | |
download | mongo-a56653e1df978f68b887788b39d053e3f88bb0ea.tar.gz |
SERVER-12786: add shell writeMode option
Diffstat (limited to 'src/mongo/shell')
-rw-r--r-- | src/mongo/shell/assert.js | 10 | ||||
-rw-r--r-- | src/mongo/shell/bulk_api.js | 3 | ||||
-rw-r--r-- | src/mongo/shell/collection.js | 24 | ||||
-rw-r--r-- | src/mongo/shell/mongo.js | 53 | ||||
-rw-r--r-- | src/mongo/shell/shell_options.cpp | 18 | ||||
-rw-r--r-- | src/mongo/shell/shell_options.h | 6 | ||||
-rw-r--r-- | src/mongo/shell/shell_utils.cpp | 5 | ||||
-rw-r--r-- | src/mongo/shell/utils.js | 9 |
8 files changed, 94 insertions, 34 deletions
diff --git a/src/mongo/shell/assert.js b/src/mongo/shell/assert.js index 97bb780f883..ac483bc8bb5 100644 --- a/src/mongo/shell/assert.js +++ b/src/mongo/shell/assert.js @@ -347,7 +347,7 @@ assert.writeOK = function(res, msg) { if (!res) errMsg = "missing first argument, no response to check" - if (!res.getWriteError) + else if (!res.getWriteError) assert.gleOK(res, msg) else { if (res.getWriteError()) { @@ -371,8 +371,7 @@ assert.gleOK = function(res, msg) { if (!res) errMsg = "missing first argument, no response to check" - - if (!res.ok) + else if (!res.ok) errMsg = "command failed: " + tojson(res); if ('code' in res || 'errMsg' in res || 'errInfo' in res || 'writeErrors' in res) @@ -387,11 +386,12 @@ assert.gleOK = function(res, msg) { return res; } - assert.writeError = function(res, msg) { var errMsg = ""; - if (!res.getWriteConcernError) { + if (!res) + errMsg = "The response arg was missing or undefined! -- " + res + else if (!res.getWriteConcernError) { if (!res.err) errMsg = "no error" + tojson(res); } else { diff --git a/src/mongo/shell/bulk_api.js b/src/mongo/shell/bulk_api.js index 21c5ce1e232..6418633954e 100644 --- a/src/mongo/shell/bulk_api.js +++ b/src/mongo/shell/bulk_api.js @@ -913,7 +913,8 @@ var _bulk_api_module = (function() { for(var i = 0; i < batches.length; i++) { // Execute the batch - if(useWriteCommands) { + if(collection.getMongo().hasWriteCommands() && + collection.getMongo().writeMode() == "commands") { executeBatch(batches[i]); } else { executeBatchWithLegacyOps(batches[i]); diff --git a/src/mongo/shell/collection.js b/src/mongo/shell/collection.js index 1023d8ce1ec..f57443ee85e 100644 --- a/src/mongo/shell/collection.js +++ b/src/mongo/shell/collection.js @@ -21,6 +21,7 @@ DBCollection.prototype.verify = function(){ assert.eq( this._fullName , this._db._name + "." + this._shortName , "name mismatch" ); assert( this._mongo , "no mongo in DBCollection" ); + assert( this.getMongo() , "no mongo from getMongo()" ); } DBCollection.prototype.getName = function(){ @@ -132,7 +133,7 @@ DBCollection.prototype._massageObject = function( q ){ DBCollection.prototype._validateObject = function( o ){ // Hidden property for testing purposes. - if (this._mongo._skipValidation) return; + if (this.getMongo()._skipValidation) return; if (typeof(o) != "object") throw "attempted to save a " + typeof(o) + " value. document expected."; @@ -145,7 +146,7 @@ DBCollection._allowedFields = { $id : 1 , $ref : 1 , $db : 1 }; DBCollection.prototype._validateForStorage = function( o ){ // Hidden property for testing purposes. - if (this._mongo._skipValidation) return; + if (this.getMongo()._skipValidation) return; this._validateObject( o ); for ( var k in o ){ @@ -225,7 +226,7 @@ DBCollection.prototype.insert = function( obj , options, _allow_dot ){ var startTime = (typeof(_verboseShell) === 'undefined' || !_verboseShell) ? 0 : new Date().getTime(); - if ( this._mongo.useWriteCommands() ) { + if ( this.getMongo().writeMode() != "legacy" ) { // Bit 1 of option flag is continueOnError. Bit 0 (stop on error) is the default. var batch = ordered ? this.initializeOrderedBulkOp() : this.initializeUnorderedBulkOp(); @@ -253,7 +254,7 @@ DBCollection.prototype.insert = function( obj , options, _allow_dot ){ } } - this._mongo.insert( this._fullName , obj, flags ); + this.getMongo().insert( this._fullName , obj, flags ); // enforce write concern, if required if (wc) @@ -267,7 +268,7 @@ DBCollection.prototype.insert = function( obj , options, _allow_dot ){ DBCollection.prototype._validateRemoveDoc = function(doc) { // Hidden property for testing purposes. - if (this._mongo._skipValidation) return; + if (this.getMongo()._skipValidation) return; for (var k in doc) { if (k == "_id" && typeof( doc[k] ) == "undefined") { @@ -292,7 +293,7 @@ DBCollection.prototype.remove = function( t , justOne ){ if (!wc) wc = this.getWriteConcern(); - if ( this._mongo.useWriteCommands() ) { + if ( this.getMongo().writeMode() != "legacy" ) { var query = (typeof(t) == 'undefined')? {} : this._massageObject(t); var batch = this.initializeOrderedBulkOp(); var removeOp = batch.find(query); @@ -308,7 +309,7 @@ DBCollection.prototype.remove = function( t , justOne ){ } else { this._validateRemoveDoc(t); - this._mongo.remove(this._fullName, this._massageObject(t), justOne ? true : false ); + this.getMongo().remove(this._fullName, this._massageObject(t), justOne ? true : false ); // enforce write concern, if required if (wc) @@ -322,7 +323,7 @@ DBCollection.prototype.remove = function( t , justOne ){ DBCollection.prototype._validateUpdateDoc = function(doc) { // Hidden property for testing purposes. - if (this._mongo._skipValidation) return; + if (this.getMongo()._skipValidation) return; var firstKey = null; for (var key in doc) { firstKey = key; break; } @@ -359,7 +360,7 @@ DBCollection.prototype.update = function( query , obj , upsert , multi ){ if (!wc) wc = this.getWriteConcern(); - if ( this._mongo.useWriteCommands() ) { + if ( this.getMongo().writeMode() != "legacy" ) { var batch = this.initializeOrderedBulkOp(); var updateOp = batch.find(query); @@ -378,7 +379,7 @@ DBCollection.prototype.update = function( query , obj , upsert , multi ){ } else { this._validateUpdateDoc(obj); - this._mongo.update(this._fullName, query, obj, + this.getMongo().update(this._fullName, query, obj, upsert ? true : false, multi ? true : false ); // enforce write concern, if required @@ -490,8 +491,7 @@ DBCollection.prototype._indexSpec = function( keys, options ) { DBCollection.prototype.createIndex = function( keys , options ){ var o = this._indexSpec( keys, options ); - if ( this._mongo.useWriteCommands() ) { - + if ( this.getMongo().writeMode() != "legacy" ) { // TODO: Use createIndexes command once fully supported by upgrade process var bulk = this.getDB().system.indexes.initializeOrderedBulkOp(); bulk.insert(o); diff --git a/src/mongo/shell/mongo.js b/src/mongo/shell/mongo.js index 6dc3d9da064..08764a7b87f 100644 --- a/src/mongo/shell/mongo.js +++ b/src/mongo/shell/mongo.js @@ -155,31 +155,60 @@ connect = function(url, user, pass) { return db; } +/** deprecated, use writeMode below + * + */ +Mongo.prototype.useWriteCommands = function() { + return (this.writeMode() != "legacy"); +} + +Mongo.prototype.forceWriteMode = function( mode ) { + this._writeMode = mode; +} + +Mongo.prototype.hasWriteCommands = function() { + if ( !('_hasWriteCommands' in this) ) { + var isMaster = this.getDB("admin").runCommand({ isMaster : 1 }); + this._hasWriteCommands = (isMaster.ok && + 'minWireVersion' in isMaster && + isMaster.minWireVersion <= 2 && + 2 <= isMaster.maxWireVersion ); + } + + return this._hasWriteCommands; +} + /** - * {Boolean} If true, uses the write commands instead of the legacy write ops. + * {String} Returns the current mode set. Will be commands/legacy/compatibility * * Sends isMaster to determine if the connection is capable of using bulk write operations, and * caches the result. */ -Mongo.prototype.useWriteCommands = function() { - if ( '_useWriteCommands' in this ) { - return this._useWriteCommands; +Mongo.prototype.writeMode = function() { + + if ( '_writeMode' in this ) { + return this._writeMode; } - // always use legacy write commands against old servers - var isMaster = this.getDB("admin").runCommand({ isMaster : 1 }); - if ( isMaster.ok && 'minWireVersion' in isMaster && - isMaster.minWireVersion <= 2 && 2 <= isMaster.maxWireVersion ) { - this._useWriteCommands = _useWriteCommandsDefault(); + // get default from shell params + if ( _writeMode ) + this._writeMode = _writeMode(); + + // can't use "commands" mode unless server version is good. + if ( this.hasWriteCommands() ) { + // good with whatever is already set } - else { - this._useWriteCommands = false; + else if ( this._writeMode == "commands" ) { + print("Cannot use commands write mode, degrading to compatability mode"); + this._writeMode = "compatibility"; } - return this._useWriteCommands; + return this._writeMode; }; + + // // Write Concern can be set at the connection level, and is used for all write operations unless // overridden at the collection level. diff --git a/src/mongo/shell/shell_options.cpp b/src/mongo/shell/shell_options.cpp index 08042fd2997..2832989ffe3 100644 --- a/src/mongo/shell/shell_options.cpp +++ b/src/mongo/shell/shell_options.cpp @@ -34,6 +34,7 @@ #include "mongo/bson/util/builder.h" #include "mongo/db/server_options.h" #include "mongo/shell/shell_utils.h" +#include "mongo/util/mongoutils/str.h" #include "mongo/util/net/sock.h" #include "mongo/util/net/ssl_options.h" #include "mongo/util/options_parser/startup_options.h" @@ -116,6 +117,12 @@ namespace mongo { moe::Switch, "use legacy write ops instead of write commands").hidden(); + options->addOptionChaining("writeMode", + "writeMode", + moe::String, + "mode to determine how writes are done:" + " commands, compatibility, legacy").hidden(); + return Status::OK(); } @@ -215,7 +222,16 @@ namespace mongo { shellGlobalParams.autoKillOp = true; } if (params.count("useLegacyWriteOps")) { - shellGlobalParams.useWriteCommandsDefault = false; + shellGlobalParams.writeMode = "legacy"; + } + if (params.count("writeMode")) { + std::string mode = params["writeMode"].as<string>(); + if (mode != "commands" && mode != "legacy" && mode != "compatibility") { + throw MsgAssertionException(17396, + mongoutils::str::stream() << + "Unknown writeMode option: " << mode); + } + shellGlobalParams.writeMode = mode; } /* This is a bit confusing, here are the rules: diff --git a/src/mongo/shell/shell_options.h b/src/mongo/shell/shell_options.h index 04f6f5222a2..12d0ed5c89c 100644 --- a/src/mongo/shell/shell_options.h +++ b/src/mongo/shell/shell_options.h @@ -62,8 +62,12 @@ namespace mongo { bool autoKillOp; bool useWriteCommandsDefault; + std::string writeMode; - ShellGlobalParams() : autoKillOp(false), useWriteCommandsDefault(true) { } + ShellGlobalParams() : autoKillOp(false), + useWriteCommandsDefault(true), + writeMode("commands") { + } }; extern ShellGlobalParams shellGlobalParams; diff --git a/src/mongo/shell/shell_utils.cpp b/src/mongo/shell/shell_utils.cpp index b9b256c1c7e..ce3cf42a7a0 100644 --- a/src/mongo/shell/shell_utils.cpp +++ b/src/mongo/shell/shell_utils.cpp @@ -178,6 +178,10 @@ namespace mongo { return BSON("" << shellGlobalParams.useWriteCommandsDefault); } + BSONObj writeMode(const BSONObj&, void*) { + return BSON("" << shellGlobalParams.writeMode); + } + BSONObj interpreterVersion(const BSONObj& a, void* data) { uassert( 16453, "interpreterVersion accepts no arguments", a.nFields() == 0 ); return BSON( "" << globalScriptEngine->getInterpreterVersionString() ); @@ -205,6 +209,7 @@ namespace mongo { void initScope( Scope &scope ) { // Need to define this method before JSFiles::utils is executed. scope.injectNative("_useWriteCommandsDefault", useWriteCommandsDefault); + scope.injectNative("_writeMode", writeMode); scope.externalSetup(); mongo::shell_utils::installShellUtils( scope ); scope.execSetup(JSFiles::servers); diff --git a/src/mongo/shell/utils.js b/src/mongo/shell/utils.js index 2c48a3c24d6..41735768dd8 100644 --- a/src/mongo/shell/utils.js +++ b/src/mongo/shell/utils.js @@ -594,16 +594,21 @@ if (typeof(_useWriteCommandsDefault) == 'undefined') { _useWriteCommandsDefault = function() { return false; }; }; +if (typeof(_writeMode) == 'undefined') { + // This is for cases when the v8 engine is used other than the mongo shell, like map reduce. + _writeMode = function() { return "commands"; }; +}; + shellPrintHelper = function (x) { if (typeof (x) == "undefined") { // Make sure that we have a db var before we use it // TODO: This implicit calling of GLE can cause subtle, hard to track issues - remove? if (__callLastError && typeof( db ) != "undefined" && db.getMongo && - !db.getMongo().useWriteCommands) { + db.getMongo().writeMode == "legacy") { __callLastError = false; - // explicit w:1 so that replset getLastErrorDefaults aren't used here which would be bad. + // explicit w:1 so that replset getLastErrorDefaults aren't used here which would be bad var err = db.getLastError(1); if (err != null) { print(err); |