diff options
author | clang-format-7.0.1 <adam.martin@10gen.com> | 2019-07-26 18:20:35 -0400 |
---|---|---|
committer | ADAM David Alan Martin <adam.martin@10gen.com> | 2019-07-27 11:02:23 -0400 |
commit | 134a4083953270e8a11430395357fb70a29047ad (patch) | |
tree | dd428e1230e31d92b20b393dfdc17ffe7fa79cb6 /src/mongo/shell | |
parent | 1e46b5049003f427047e723ea5fab15b5a9253ca (diff) | |
download | mongo-134a4083953270e8a11430395357fb70a29047ad.tar.gz |
SERVER-41772 Apply clang-format 7.0.1 to the codebase
Diffstat (limited to 'src/mongo/shell')
36 files changed, 3458 insertions, 3505 deletions
diff --git a/src/mongo/shell/assert.js b/src/mongo/shell/assert.js index ce2ec257763..20c8f2d481b 100644 --- a/src/mongo/shell/assert.js +++ b/src/mongo/shell/assert.js @@ -1,13 +1,13 @@ doassert = function(msg, obj) { // eval if msg is a function - if (typeof(msg) == "function") + if (typeof (msg) == "function") msg = msg(); - if (typeof(msg) == "object") + if (typeof (msg) == "object") msg = tojson(msg); if (jsTest.options().traceExceptions) { - if (typeof(msg) == "string" && msg.indexOf("assert") == 0) + if (typeof (msg) == "string" && msg.indexOf("assert") == 0) print(msg); else print("assert: " + msg); @@ -27,7 +27,6 @@ doassert = function(msg, obj) { // Sort doc/obj fields and return new sorted obj sortDoc = function(doc) { - // Helper to sort the elements of the array var sortElementsOfArray = function(arr) { var newArr = []; @@ -318,7 +317,7 @@ assert = (function() { var msgPrefix = "assert.soon failed: " + func; if (msg) { - if (typeof(msg) != "function") { + if (typeof (msg) != "function") { msgPrefix = "assert.soon failed, msg"; } } @@ -328,7 +327,7 @@ assert = (function() { interval = interval || 200; var last; while (1) { - if (typeof(func) == "string") { + if (typeof (func) == "string") { if (eval(func)) return; } else { @@ -418,7 +417,7 @@ assert = (function() { var start = new Date(); timeout = timeout || 30000; - if (typeof(f) == "string") { + if (typeof (f) == "string") { res = eval(f); } else { res = f(); @@ -929,7 +928,6 @@ assert = (function() { }; assert.gleOK = function(res, msg) { - var errMsg = null; if (!res) { @@ -950,7 +948,7 @@ assert = (function() { assert.gleSuccess = function(dbOrGLEDoc, msg) { var gle = dbOrGLEDoc instanceof DB ? dbOrGLEDoc.getLastErrorObj() : dbOrGLEDoc; if (gle.err) { - if (typeof(msg) == "function") + if (typeof (msg) == "function") msg = msg(gle); doassert(_buildAssertionMessage(msg, "getLastError not null: " + tojson(gle)), gle); } @@ -960,7 +958,7 @@ assert = (function() { assert.gleError = function(dbOrGLEDoc, msg) { var gle = dbOrGLEDoc instanceof DB ? dbOrGLEDoc.getLastErrorObj() : dbOrGLEDoc; if (!gle.err) { - if (typeof(msg) == "function") + if (typeof (msg) == "function") msg = msg(gle); doassert(_buildAssertionMessage(msg, "getLastError is null: " + tojson(gle))); } @@ -969,7 +967,7 @@ assert = (function() { assert.gleErrorCode = function(dbOrGLEDoc, code, msg) { var gle = dbOrGLEDoc instanceof DB ? dbOrGLEDoc.getLastErrorObj() : dbOrGLEDoc; if (!gle.err || gle.code != code) { - if (typeof(msg) == "function") + if (typeof (msg) == "function") msg = msg(gle); doassert(_buildAssertionMessage( msg, @@ -980,7 +978,7 @@ assert = (function() { assert.gleErrorRegex = function(dbOrGLEDoc, regex, msg) { var gle = dbOrGLEDoc instanceof DB ? dbOrGLEDoc.getLastErrorObj() : dbOrGLEDoc; if (!gle.err || !regex.test(gle.err)) { - if (typeof(msg) == "function") + if (typeof (msg) == "function") msg = msg(gle); doassert(_buildAssertionMessage( msg, diff --git a/src/mongo/shell/bench.cpp b/src/mongo/shell/bench.cpp index cc523d8ac77..f5ca0b2af04 100644 --- a/src/mongo/shell/bench.cpp +++ b/src/mongo/shell/bench.cpp @@ -924,8 +924,7 @@ void BenchRunWorker::generateLoadOnConnection(DBClientBase* conn) { { opState.stats->trappedErrors.push_back( BSON("error" << ex.what() << "op" << kOpTypeNames.find(op.op)->second - << "count" - << count)); + << "count" << count)); } if (_config->breakOnTrap) return; @@ -1040,8 +1039,8 @@ void BenchRunOp::executeOnce(DBClientBase* conn, boost::none); // lastKnownCommittedOpTime BSONObj getMoreCommandResult; uassert(ErrorCodes::CommandFailed, - str::stream() << "getMore command failed; reply was: " - << getMoreCommandResult, + str::stream() + << "getMore command failed; reply was: " << getMoreCommandResult, runCommandWithSession(conn, this->ns, getMoreRequest.toBSON(), @@ -1390,11 +1389,11 @@ void BenchRunner::start() { if (_config->username != "") { std::string errmsg; if (!conn->auth("admin", _config->username, _config->password, errmsg)) { - uasserted( - 16704, - str::stream() << "User " << _config->username - << " could not authenticate to admin db; admin db access is " - "required to use benchRun with auth enabled"); + uasserted(16704, + str::stream() + << "User " << _config->username + << " could not authenticate to admin db; admin db access is " + "required to use benchRun with auth enabled"); } } @@ -1429,11 +1428,11 @@ void BenchRunner::stop() { std::string errmsg; // this can only fail if admin access was revoked since start of run if (!conn->auth("admin", _config->username, _config->password, errmsg)) { - uasserted( - 16705, - str::stream() << "User " << _config->username - << " could not authenticate to admin db; admin db access is " - "still required to use benchRun with auth enabled"); + uasserted(16705, + str::stream() + << "User " << _config->username + << " could not authenticate to admin db; admin db access is " + "still required to use benchRun with auth enabled"); } } } diff --git a/src/mongo/shell/bench.h b/src/mongo/shell/bench.h index 527beecae49..f73d2149abe 100644 --- a/src/mongo/shell/bench.h +++ b/src/mongo/shell/bench.h @@ -45,7 +45,7 @@ namespace pcrecpp { class RE; -} // namespace pcrecpp; +} // namespace pcrecpp namespace mongo { @@ -431,9 +431,9 @@ public: bool shouldWorkerFinish() const; /** - * Predicate that workers call to see if they should start collecting stats (as a result - * of a call to tellWorkersToCollectStats()). - */ + * Predicate that workers call to see if they should start collecting stats (as a result + * of a call to tellWorkersToCollectStats()). + */ bool shouldWorkerCollectStats() const; /** diff --git a/src/mongo/shell/bulk_api.js b/src/mongo/shell/bulk_api.js index eac31f7a871..eac2c063374 100644 --- a/src/mongo/shell/bulk_api.js +++ b/src/mongo/shell/bulk_api.js @@ -2,7 +2,6 @@ // Scope for the function // var _bulk_api_module = (function() { - // Batch types var NONE = 0; var INSERT = 1; @@ -37,7 +36,6 @@ var _bulk_api_module = (function() { * Accepts { w : x, j : x, wtimeout : x, fsync: x } or w, wtimeout, j */ var WriteConcern = function(wValue, wTimeout, jValue) { - if (!(this instanceof WriteConcern)) { var writeConcern = Object.create(WriteConcern.prototype); WriteConcern.apply(writeConcern, arguments); @@ -97,7 +95,6 @@ var _bulk_api_module = (function() { this.shellPrint = function() { return this.toString(); }; - }; /** @@ -107,7 +104,6 @@ var _bulk_api_module = (function() { * are used to filter the WriteResult to only include relevant result fields. */ var WriteResult = function(bulkResult, singleBatchType, writeConcern) { - if (!(this instanceof WriteResult)) return new WriteResult(bulkResult, singleBatchType, writeConcern); @@ -217,7 +213,6 @@ var _bulk_api_module = (function() { * Wraps the result for the commands */ var BulkWriteResult = function(bulkResult, singleBatchType, writeConcern) { - if (!(this instanceof BulkWriteResult) && !(this instanceof BulkWriteError)) return new BulkWriteResult(bulkResult, singleBatchType, writeConcern); @@ -354,7 +349,6 @@ var _bulk_api_module = (function() { * Represents a bulk write error, identical to a BulkWriteResult but thrown */ var BulkWriteError = function(bulkResult, singleBatchType, writeConcern, message) { - if (!(this instanceof BulkWriteError)) return new BulkWriteError(bulkResult, singleBatchType, writeConcern, message); @@ -397,7 +391,6 @@ var _bulk_api_module = (function() { * Wraps a command error */ var WriteCommandError = function(commandError) { - if (!(this instanceof WriteCommandError)) return new WriteCommandError(commandError); @@ -607,7 +600,6 @@ var _bulk_api_module = (function() { // Add to internal list of documents var addToOperationsList = function(docType, document) { - if (Array.isArray(document)) throw Error("operation passed in cannot be an Array"); @@ -638,7 +630,7 @@ var _bulk_api_module = (function() { * Otherwise, returns the same object passed. */ var addIdIfNeeded = function(obj) { - if (typeof(obj._id) == "undefined" && !Array.isArray(obj)) { + if (typeof (obj._id) == "undefined" && !Array.isArray(obj)) { var tmp = obj; // don't want to modify input obj = {_id: new ObjectId()}; for (var key in tmp) { @@ -812,7 +804,6 @@ var _bulk_api_module = (function() { // // Merge write command result into aggregated results object var mergeBatchResults = function(batch, bulkResult, result) { - // If we have an insert Batch type if (batch.batchType == INSERT) { bulkResult.nInserted = bulkResult.nInserted + result.n; @@ -1009,8 +1000,8 @@ var _bulk_api_module = (function() { } else if (code == 19900 || // No longer primary code == 16805 || // replicatedToNum no longer primary code == 14330 || // gle wmode changed; invalid - code == NOT_MASTER || - code == UNKNOWN_REPL_WRITE_CONCERN || code == WRITE_CONCERN_FAILED) { + code == NOT_MASTER || code == UNKNOWN_REPL_WRITE_CONCERN || + code == WRITE_CONCERN_FAILED) { extractedErr.wcError = {code: code, errmsg: errMsg}; } else if (!isOK) { // This is a GLE failure we don't understand @@ -1037,7 +1028,6 @@ var _bulk_api_module = (function() { // Execute the operations, serially var executeBatchWithLegacyOps = function(batch) { - var batchResult = {n: 0, writeErrors: [], upserted: []}; var extractedErr = null; @@ -1113,10 +1103,11 @@ var _bulk_api_module = (function() { bsonWoCompare(writeConcern, {w: 0}) != 0; extractedErr = null; - if (needToEnforceWC && (batchResult.writeErrors.length == 0 || - (!ordered && - // not all errored. - batchResult.writeErrors.length < batch.operations.length))) { + if (needToEnforceWC && + (batchResult.writeErrors.length == 0 || + (!ordered && + // not all errored. + batchResult.writeErrors.length < batch.operations.length))) { // if last write errored if (batchResult.writeErrors.length > 0 && batchResult.writeErrors[batchResult.writeErrors.length - 1].index == @@ -1237,7 +1228,6 @@ var _bulk_api_module = (function() { }; return module; - })(); // Globals diff --git a/src/mongo/shell/collection.js b/src/mongo/shell/collection.js index c6c03b35e46..04aeddea965 100644 --- a/src/mongo/shell/collection.js +++ b/src/mongo/shell/collection.js @@ -167,7 +167,7 @@ DBCollection.prototype._makeCommand = function(cmd, params) { }; DBCollection.prototype._dbCommand = function(cmd, params) { - if (typeof(cmd) === "object") + if (typeof (cmd) === "object") return this._db._dbCommand(cmd, {}, this.getQueryOptions()); return this._db._dbCommand(this._makeCommand(cmd, params), {}, this.getQueryOptions()); @@ -175,7 +175,7 @@ DBCollection.prototype._dbCommand = function(cmd, params) { // Like _dbCommand, but applies $readPreference DBCollection.prototype._dbReadCommand = function(cmd, params) { - if (typeof(cmd) === "object") + if (typeof (cmd) === "object") return this._db._dbReadCommand(cmd, {}, this.getQueryOptions()); return this._db._dbReadCommand(this._makeCommand(cmd, params), {}, this.getQueryOptions()); @@ -210,7 +210,6 @@ DBCollection.prototype._massageObject = function(q) { } throw Error("don't know how to massage : " + type); - }; DBCollection.prototype.find = function(query, fields, limit, skip, batchSize, options) { @@ -276,7 +275,7 @@ DBCollection.prototype.insert = function(obj, options) { var allowDottedFields = false; if (options === undefined) { // do nothing - } else if (typeof(options) == 'object') { + } else if (typeof (options) == 'object') { if (options.ordered === undefined) { // do nothing, like above } else { @@ -299,7 +298,7 @@ DBCollection.prototype.insert = function(obj, options) { var result = undefined; var startTime = - (typeof(_verboseShell) === 'undefined' || !_verboseShell) ? 0 : new Date().getTime(); + (typeof (_verboseShell) === 'undefined' || !_verboseShell) ? 0 : new Date().getTime(); if (this.getMongo().writeMode() != "legacy") { // Bit 1 of option flag is continueOnError. Bit 0 (stop on error) is the default. @@ -329,7 +328,7 @@ DBCollection.prototype.insert = function(obj, options) { } } } else { - if (typeof(obj._id) == "undefined" && !Array.isArray(obj)) { + if (typeof (obj._id) == "undefined" && !Array.isArray(obj)) { var tmp = obj; // don't want to modify input obj = {_id: new ObjectId()}; for (var key in tmp) { @@ -361,7 +360,7 @@ DBCollection.prototype._parseRemove = function(t, justOne) { var wc = undefined; var collation = undefined; - if (typeof(justOne) === "object") { + if (typeof (justOne) === "object") { var opts = justOne; wc = opts.writeConcern; justOne = opts.justOne; @@ -390,7 +389,7 @@ DBCollection.prototype.remove = function(t, justOne) { var result = undefined; var startTime = - (typeof(_verboseShell) === 'undefined' || !_verboseShell) ? 0 : new Date().getTime(); + (typeof (_verboseShell) === 'undefined' || !_verboseShell) ? 0 : new Date().getTime(); if (this.getMongo().writeMode() != "legacy") { var bulk = this.initializeOrderedBulkOp(); @@ -452,7 +451,7 @@ DBCollection.prototype._parseUpdate = function(query, updateSpec, upsert, multi) let hint = undefined; // can pass options via object for improved readability - if (typeof(upsert) === "object") { + if (typeof (upsert) === "object") { if (multi) { throw Error("Fourth argument must be empty when specifying " + "upsert and multi with an object."); @@ -502,7 +501,7 @@ DBCollection.prototype.update = function(query, updateSpec, upsert, multi) { var result = undefined; var startTime = - (typeof(_verboseShell) === 'undefined' || !_verboseShell) ? 0 : new Date().getTime(); + (typeof (_verboseShell) === 'undefined' || !_verboseShell) ? 0 : new Date().getTime(); if (this.getMongo().writeMode() != "legacy") { var bulk = this.initializeOrderedBulkOp(); @@ -567,10 +566,10 @@ DBCollection.prototype.save = function(obj, opts) { if (obj == null) throw Error("can't save a null"); - if (typeof(obj) == "number" || typeof(obj) == "string") + if (typeof (obj) == "number" || typeof (obj) == "string") throw Error("can't save a number or string"); - if (typeof(obj._id) == "undefined") { + if (typeof (obj._id) == "undefined") { obj._id = new ObjectId(); return this.insert(obj, opts); } else { @@ -598,11 +597,11 @@ DBCollection.prototype._indexSpec = function(keys, options) { var ret = {ns: this._fullName, key: keys, name: this._genIndexName(keys)}; if (!options) { - } else if (typeof(options) == "string") + } else if (typeof (options) == "string") ret.name = options; - else if (typeof(options) == "boolean") + else if (typeof (options) == "boolean") ret.unique = true; - else if (typeof(options) == "object") { + else if (typeof (options) == "object") { if (Array.isArray(options)) { if (options.length > 3) { throw new Error("Index options that are supplied in array form may only specify" + @@ -610,9 +609,9 @@ DBCollection.prototype._indexSpec = function(keys, options) { } var nb = 0; for (var i = 0; i < options.length; i++) { - if (typeof(options[i]) == "string") + if (typeof (options[i]) == "string") ret.name = options[i]; - else if (typeof(options[i]) == "boolean") { + else if (typeof (options[i]) == "boolean") { if (options[i]) { if (nb == 0) ret.unique = true; @@ -626,7 +625,7 @@ DBCollection.prototype._indexSpec = function(keys, options) { Object.extend(ret, options); } } else { - throw Error("can't handle: " + typeof(options)); + throw Error("can't handle: " + typeof (options)); } return ret; @@ -780,14 +779,14 @@ DBCollection.prototype._printExtraInfo = function(action, startTime) { DBCollection.prototype.validate = function(full) { var cmd = {validate: this.getName()}; - if (typeof(full) == 'object') // support arbitrary options here + if (typeof (full) == 'object') // support arbitrary options here Object.extend(cmd, full); else cmd.full = full; var res = this._db.runCommand(cmd); - if (typeof(res.valid) == 'undefined') { + if (typeof (res.valid) == 'undefined') { // old-style format just put everything in a string. Now using proper fields res.valid = false; @@ -842,7 +841,7 @@ DBCollection.prototype.hashAllDocs = function() { var res = this._dbCommand(cmd); var hash = res.collections[this._shortName]; assert(hash); - assert(typeof(hash) == "string"); + assert(typeof (hash) == "string"); return hash; }; @@ -880,14 +879,14 @@ DBCollection.prototype.getCollection = function(subName) { }; /** - * scale: The scale at which to deliver results. Unless specified, this command returns all data - * in bytes. - * indexDetails: Includes indexDetails field in results. Default: false. - * indexDetailsKey: If indexDetails is true, filter contents in indexDetails by this index key. - * indexDetailsname: If indexDetails is true, filter contents in indexDetails by this index name. - * - * It is an error to provide both indexDetailsKey and indexDetailsName. - */ + * scale: The scale at which to deliver results. Unless specified, this command returns all data + * in bytes. + * indexDetails: Includes indexDetails field in results. Default: false. + * indexDetailsKey: If indexDetails is true, filter contents in indexDetails by this index key. + * indexDetailsname: If indexDetails is true, filter contents in indexDetails by this index name. + * + * It is an error to provide both indexDetailsKey and indexDetailsName. + */ DBCollection.prototype.stats = function(args) { 'use strict'; @@ -1040,8 +1039,8 @@ MapReduceResult.prototype.drop = function() { }; /** -* just for debugging really -*/ + * just for debugging really + */ MapReduceResult.prototype.convertToSingleObject = function() { var z = {}; var it = this.results != null ? this.results : this._coll.find(); @@ -1060,13 +1059,13 @@ DBCollection.prototype.convertToSingleObject = function(valueField) { }; /** -* @param optional object of optional fields; -*/ + * @param optional object of optional fields; + */ DBCollection.prototype.mapReduce = function(map, reduce, optionsOrOutString) { var c = {mapreduce: this._shortName, map: map, reduce: reduce}; assert(optionsOrOutString, "need to supply an optionsOrOutString"); - if (typeof(optionsOrOutString) == "string") + if (typeof (optionsOrOutString) == "string") c["out"] = optionsOrOutString; else Object.extend(c, optionsOrOutString); @@ -1086,7 +1085,6 @@ DBCollection.prototype.mapReduce = function(map, reduce, optionsOrOutString) { throw _getErrorWithCode(raw, "map reduce failed:" + tojson(raw)); } return new MapReduceResult(this._db, raw); - }; DBCollection.prototype.toString = function() { @@ -1142,7 +1140,6 @@ will actually */ DBCollection.prototype.getShardDistribution = function() { - var stats = this.stats(); if (!stats.sharded) { @@ -1175,8 +1172,8 @@ DBCollection.prototype.getShardDistribution = function() { } print("\nTotals"); - print(" data : " + sh._dataFormat(stats.size) + " docs : " + stats.count + " chunks : " + - numChunks); + print(" data : " + sh._dataFormat(stats.size) + " docs : " + stats.count + + " chunks : " + numChunks); for (var shard in stats.shards) { var shardStats = stats.shards[shard]; @@ -1186,16 +1183,14 @@ DBCollection.prototype.getShardDistribution = function() { (stats.count == 0) ? 0 : (Math.floor(shardStats.count / stats.count * 10000) / 100); print(" Shard " + shard + " contains " + estDataPercent + "% data, " + estDocPercent + - "% docs in cluster, " + "avg obj size on shard : " + - sh._dataFormat(stats.shards[shard].avgObjSize)); + "% docs in cluster, " + + "avg obj size on shard : " + sh._dataFormat(stats.shards[shard].avgObjSize)); } print("\n"); - }; DBCollection.prototype.getSplitKeysForChunks = function(chunkSize) { - var stats = this.stats(); if (!stats.sharded) { @@ -1263,7 +1258,6 @@ DBCollection.prototype.getSplitKeysForChunks = function(chunkSize) { var admin = this.getDB().getSiblingDB("admin"); var coll = this; var splitFunction = function() { - // Turn off the balancer, just to be safe print("Turning off balancer..."); config.settings.update({_id: "balancer"}, {$set: {stopped: true}}, true); @@ -1290,11 +1284,11 @@ DBCollection.prototype.getSplitKeysForChunks = function(chunkSize) { }; print("\nGenerated " + numSplits + " split keys, run output function to perform splits.\n" + - " ex : \n" + " > var splitter = <collection>.getSplitKeysForChunks()\n" + + " ex : \n" + + " > var splitter = <collection>.getSplitKeysForChunks()\n" + " > splitter() // Execute splits on cluster !\n"); return splitFunction; - }; DBCollection.prototype.setSlaveOk = function(value) { @@ -1352,21 +1346,21 @@ DBCollection.prototype.unsetWriteConcern = function() { // /** -* Count number of matching documents in the db to a query. -* -* @method -* @param {object} query The query for the count. -* @param {object} [options=null] Optional settings. -* @param {number} [options.limit=null] The limit of documents to count. -* @param {number} [options.skip=null] The number of documents to skip for the count. -* @param {string|object} [options.hint=null] An index name hint or specification for the query. -* @param {number} [options.maxTimeMS=null] The maximum amount of time to allow the query to run. -* @param {string} [options.readConcern=null] The level of readConcern passed to the count command -* @param {object} [options.collation=null] The collation that should be used for string comparisons -* for this count op. -* @return {number} -* -*/ + * Count number of matching documents in the db to a query. + * + * @method + * @param {object} query The query for the count. + * @param {object} [options=null] Optional settings. + * @param {number} [options.limit=null] The limit of documents to count. + * @param {number} [options.skip=null] The number of documents to skip for the count. + * @param {string|object} [options.hint=null] An index name hint or specification for the query. + * @param {number} [options.maxTimeMS=null] The maximum amount of time to allow the query to run. + * @param {string} [options.readConcern=null] The level of readConcern passed to the count command + * @param {object} [options.collation=null] The collation that should be used for string comparisons + * for this count op. + * @return {number} + * + */ DBCollection.prototype.count = function(query, options) { query = this.find(query); @@ -1375,19 +1369,19 @@ DBCollection.prototype.count = function(query, options) { }; /** -* Count number of matching documents in the db to a query using aggregation. -* -* @method -* @param {object} query The query for the count. -* @param {object} [options=null] Optional settings. -* @param {number} [options.limit=null] The limit of documents to count. -* @param {number} [options.skip=null] The number of documents to skip for the count. -* @param {string|object} [options.hint=null] An index name hint or specification for the query. -* @param {number} [options.maxTimeMS=null] The maximum amount of time to allow the query to run. -* @param {object} [options.collation=null] The collation that should be used for string comparisons -* for this count op. -* @return {number} -*/ + * Count number of matching documents in the db to a query using aggregation. + * + * @method + * @param {object} query The query for the count. + * @param {object} [options=null] Optional settings. + * @param {number} [options.limit=null] The limit of documents to count. + * @param {number} [options.skip=null] The number of documents to skip for the count. + * @param {string|object} [options.hint=null] An index name hint or specification for the query. + * @param {number} [options.maxTimeMS=null] The maximum amount of time to allow the query to run. + * @param {object} [options.collation=null] The collation that should be used for string comparisons + * for this count op. + * @return {number} + */ DBCollection.prototype.countDocuments = function(query, options) { "use strict"; let pipeline = [{"$match": query}]; @@ -1424,13 +1418,13 @@ DBCollection.prototype.countDocuments = function(query, options) { }; /** -* Estimates the count of documents in a collection using collection metadata. -* -* @method -* @param {object} [options=null] Optional settings. -* @param {number} [options.maxTimeMS=null] The maximum amount of time to allow the query to run. -* @return {number} -*/ + * Estimates the count of documents in a collection using collection metadata. + * + * @method + * @param {object} [options=null] Optional settings. + * @param {number} [options.maxTimeMS=null] The maximum amount of time to allow the query to run. + * @return {number} + */ DBCollection.prototype.estimatedDocumentCount = function(options) { "use strict"; let cmd = {count: this.getName()}; @@ -1452,17 +1446,17 @@ DBCollection.prototype.estimatedDocumentCount = function(options) { }; /** -* The distinct command returns returns a list of distinct values for the given key across a -*collection. -* -* @method -* @param {string} key Field of the document to find distinct values for. -* @param {object} query The query for filtering the set of documents to which we apply the distinct -*filter. -* @param {object} [options=null] Optional settings. -* @param {number} [options.maxTimeMS=null] The maximum amount of time to allow the query to run. -* @return {object} -*/ + * The distinct command returns returns a list of distinct values for the given key across a + *collection. + * + * @method + * @param {string} key Field of the document to find distinct values for. + * @param {object} query The query for filtering the set of documents to which we apply the distinct + *filter. + * @param {object} [options=null] Optional settings. + * @param {number} [options.maxTimeMS=null] The maximum amount of time to allow the query to run. + * @return {object} + */ DBCollection.prototype.distinct = function(keyString, query, options) { var opts = Object.extend({}, options || {}); var keyStringType = typeof keyString; @@ -1576,7 +1570,7 @@ PlanCache.prototype._parseQueryShape = function(query, projection, sort, collati // Accept query shape object as only argument. // Query shape must contain 'query', 'projection', and 'sort', and may optionally contain // 'collation'. 'collation' must be non-empty if present. - if (typeof(query) == 'object' && projection == undefined && sort == undefined && + if (typeof (query) == 'object' && projection == undefined && sort == undefined && collation == undefined) { var keysSorted = Object.keys(query).sort(); // Expected keys must be sorted for the comparison to work. diff --git a/src/mongo/shell/crud_api.js b/src/mongo/shell/crud_api.js index bcd245f4878..dd7d334291a 100644 --- a/src/mongo/shell/crud_api.js +++ b/src/mongo/shell/crud_api.js @@ -30,7 +30,7 @@ DBCollection.prototype.addIdIfNeeded = function(obj) { if (typeof obj !== "object") { throw new Error('argument passed to addIdIfNeeded is not an object'); } - if (typeof(obj._id) == "undefined" && !Array.isArray(obj)) { + if (typeof (obj._id) == "undefined" && !Array.isArray(obj)) { var tmp = obj; // don't want to modify input obj = {_id: new ObjectId()}; @@ -45,32 +45,32 @@ DBCollection.prototype.addIdIfNeeded = function(obj) { }; /** -* Perform a bulkWrite operation without a fluent API -* -* Legal operation types are -* -* { insertOne: { document: { a: 1 } } } -* -* { updateOne: { filter: {a:2}, update: {$set: {"a.$[i]":2}}, upsert:true, collation: {locale: -* "fr"}, arrayFilters: [{i: 0}] } } -* -* { updateMany: { filter: {a:2}, update: {$set: {"a.$[i]":2}}, upsert:true collation: {locale: -* "fr"}, arrayFilters: [{i: 0}] } } -* -* { deleteOne: { filter: {c:1}, collation: {locale: "fr"} } } -* -* { deleteMany: { filter: {c:1}, collation: {locale: "fr"} } } -* -* { replaceOne: { filter: {c:3}, replacement: {c:4}, upsert:true, collation: {locale: "fr"} } } -* -* @method -* @param {object[]} operations Bulk operations to perform. -* @param {object} [options=null] Optional settings. -* @param {(number|string)} [options.w=null] The write concern. -* @param {number} [options.wtimeout=null] The write concern timeout. -* @param {boolean} [options.j=false] Specify a journal write concern. -* @return {object} -*/ + * Perform a bulkWrite operation without a fluent API + * + * Legal operation types are + * + * { insertOne: { document: { a: 1 } } } + * + * { updateOne: { filter: {a:2}, update: {$set: {"a.$[i]":2}}, upsert:true, collation: {locale: + * "fr"}, arrayFilters: [{i: 0}] } } + * + * { updateMany: { filter: {a:2}, update: {$set: {"a.$[i]":2}}, upsert:true collation: {locale: + * "fr"}, arrayFilters: [{i: 0}] } } + * + * { deleteOne: { filter: {c:1}, collation: {locale: "fr"} } } + * + * { deleteMany: { filter: {c:1}, collation: {locale: "fr"} } } + * + * { replaceOne: { filter: {c:3}, replacement: {c:4}, upsert:true, collation: {locale: "fr"} } } + * + * @method + * @param {object[]} operations Bulk operations to perform. + * @param {object} [options=null] Optional settings. + * @param {(number|string)} [options.w=null] The write concern. + * @param {number} [options.wtimeout=null] The write concern timeout. + * @param {boolean} [options.j=false] Specify a journal write concern. + * @return {object} + */ DBCollection.prototype.bulkWrite = function(operations, options) { var opts = Object.extend({}, options || {}); opts.ordered = (typeof opts.ordered == 'boolean') ? opts.ordered : true; @@ -221,16 +221,16 @@ DBCollection.prototype.bulkWrite = function(operations, options) { }; /** -* Inserts a single document into MongoDB. -* -* @method -* @param {object} doc Document to insert. -* @param {object} [options=null] Optional settings. -* @param {(number|string)} [options.w=null] The write concern. -* @param {number} [options.wtimeout=null] The write concern timeout. -* @param {boolean} [options.j=false] Specify a journal write concern. -* @return {object} -*/ + * Inserts a single document into MongoDB. + * + * @method + * @param {object} doc Document to insert. + * @param {object} [options=null] Optional settings. + * @param {(number|string)} [options.w=null] The write concern. + * @param {number} [options.wtimeout=null] The write concern timeout. + * @param {boolean} [options.j=false] Specify a journal write concern. + * @return {object} + */ DBCollection.prototype.insertOne = function(document, options) { var opts = Object.extend({}, options || {}); @@ -276,17 +276,17 @@ DBCollection.prototype.insertOne = function(document, options) { }; /** -* Inserts an array of documents into MongoDB. -* -* @method -* @param {object[]} docs Documents to insert. -* @param {object} [options=null] Optional settings. -* @param {(number|string)} [options.w=null] The write concern. -* @param {number} [options.wtimeout=null] The write concern timeout. -* @param {boolean} [options.j=false] Specify a journal write concern. -* @param {boolean} [options.ordered=true] Execute inserts in ordered or unordered fashion. -* @return {object} -*/ + * Inserts an array of documents into MongoDB. + * + * @method + * @param {object[]} docs Documents to insert. + * @param {object} [options=null] Optional settings. + * @param {(number|string)} [options.w=null] The write concern. + * @param {number} [options.wtimeout=null] The write concern timeout. + * @param {boolean} [options.j=false] Specify a journal write concern. + * @param {boolean} [options.ordered=true] Execute inserts in ordered or unordered fashion. + * @return {object} + */ DBCollection.prototype.insertMany = function(documents, options) { var opts = Object.extend({}, options || {}); opts.ordered = (typeof opts.ordered == 'boolean') ? opts.ordered : true; @@ -327,16 +327,16 @@ DBCollection.prototype.insertMany = function(documents, options) { }; /** -* Delete a document on MongoDB -* -* @method -* @param {object} filter The filter used to select the document to remove -* @param {object} [options=null] Optional settings. -* @param {(number|string)} [options.w=null] The write concern. -* @param {number} [options.wtimeout=null] The write concern timeout. -* @param {boolean} [options.j=false] Specify a journal write concern. -* @return {object} -*/ + * Delete a document on MongoDB + * + * @method + * @param {object} filter The filter used to select the document to remove + * @param {object} [options=null] Optional settings. + * @param {(number|string)} [options.w=null] The write concern. + * @param {number} [options.wtimeout=null] The write concern timeout. + * @param {boolean} [options.j=false] Specify a journal write concern. + * @return {object} + */ DBCollection.prototype.deleteOne = function(filter, options) { var opts = Object.extend({}, options || {}); @@ -384,16 +384,16 @@ DBCollection.prototype.deleteOne = function(filter, options) { }; /** -* Delete multiple documents on MongoDB -* -* @method -* @param {object} filter The Filter used to select the documents to remove -* @param {object} [options=null] Optional settings. -* @param {(number|string)} [options.w=null] The write concern. -* @param {number} [options.wtimeout=null] The write concern timeout. -* @param {boolean} [options.j=false] Specify a journal write concern. -* @return {object} -*/ + * Delete multiple documents on MongoDB + * + * @method + * @param {object} filter The Filter used to select the documents to remove + * @param {object} [options=null] Optional settings. + * @param {(number|string)} [options.w=null] The write concern. + * @param {number} [options.wtimeout=null] The write concern timeout. + * @param {boolean} [options.j=false] Specify a journal write concern. + * @return {object} + */ DBCollection.prototype.deleteMany = function(filter, options) { var opts = Object.extend({}, options || {}); @@ -441,18 +441,18 @@ DBCollection.prototype.deleteMany = function(filter, options) { }; /** -* Replace a document on MongoDB -* -* @method -* @param {object} filter The Filter used to select the document to update -* @param {object} doc The Document that replaces the matching document -* @param {object} [options=null] Optional settings. -* @param {boolean} [options.upsert=false] Update operation is an upsert. -* @param {(number|string)} [options.w=null] The write concern. -* @param {number} [options.wtimeout=null] The write concern timeout. -* @param {boolean} [options.j=false] Specify a journal write concern. -* @return {object} -*/ + * Replace a document on MongoDB + * + * @method + * @param {object} filter The Filter used to select the document to update + * @param {object} doc The Document that replaces the matching document + * @param {object} [options=null] Optional settings. + * @param {boolean} [options.upsert=false] Update operation is an upsert. + * @param {(number|string)} [options.w=null] The write concern. + * @param {number} [options.wtimeout=null] The write concern timeout. + * @param {boolean} [options.j=false] Specify a journal write concern. + * @return {object} + */ DBCollection.prototype.replaceOne = function(filter, replacement, options) { var opts = Object.extend({}, options || {}); @@ -521,18 +521,18 @@ DBCollection.prototype.replaceOne = function(filter, replacement, options) { }; /** -* Update a single document on MongoDB -* -* @method -* @param {object} filter The Filter used to select the document to update -* @param {object} update The update operations to be applied to the document -* @param {object} [options=null] Optional settings. -* @param {boolean} [options.upsert=false] Update operation is an upsert. -* @param {(number|string)} [options.w=null] The write concern. -* @param {number} [options.wtimeout=null] The write concern timeout. -* @param {boolean} [options.j=false] Specify a journal write concern. -* @return {object} -*/ + * Update a single document on MongoDB + * + * @method + * @param {object} filter The Filter used to select the document to update + * @param {object} update The update operations to be applied to the document + * @param {object} [options=null] Optional settings. + * @param {boolean} [options.upsert=false] Update operation is an upsert. + * @param {(number|string)} [options.w=null] The write concern. + * @param {number} [options.wtimeout=null] The write concern timeout. + * @param {boolean} [options.j=false] Specify a journal write concern. + * @return {object} + */ DBCollection.prototype.updateOne = function(filter, update, options) { var opts = Object.extend({}, options || {}); @@ -607,18 +607,18 @@ DBCollection.prototype.updateOne = function(filter, update, options) { }; /** -* Update multiple documents on MongoDB -* -* @method -* @param {object} filter The Filter used to select the document to update -* @param {object} update The update operations to be applied to the document -* @param {object} [options=null] Optional settings. -* @param {boolean} [options.upsert=false] Update operation is an upsert. -* @param {(number|string)} [options.w=null] The write concern. -* @param {number} [options.wtimeout=null] The write concern timeout. -* @param {boolean} [options.j=false] Specify a journal write concern. -* @return {object} -*/ + * Update multiple documents on MongoDB + * + * @method + * @param {object} filter The Filter used to select the document to update + * @param {object} update The update operations to be applied to the document + * @param {object} [options=null] Optional settings. + * @param {boolean} [options.upsert=false] Update operation is an upsert. + * @param {(number|string)} [options.w=null] The write concern. + * @param {number} [options.wtimeout=null] The write concern timeout. + * @param {boolean} [options.j=false] Specify a journal write concern. + * @return {object} + */ DBCollection.prototype.updateMany = function(filter, update, options) { var opts = Object.extend({}, options || {}); @@ -693,18 +693,18 @@ DBCollection.prototype.updateMany = function(filter, update, options) { }; /** -* Find a document and delete it in one atomic operation, -* requires a write lock for the duration of the operation. -* -* @method -* @param {object} filter Document selection filter. -* @param {object} [options=null] Optional settings. -* @param {object} [options.projection=null] Limits the fields to return for all matching documents. -* @param {object} [options.sort=null] Determines which document the operation modifies if the query -*selects multiple documents. -* @param {number} [options.maxTimeMS=null] The maximum amount of time to allow the query to run. -* @return {object} -*/ + * Find a document and delete it in one atomic operation, + * requires a write lock for the duration of the operation. + * + * @method + * @param {object} filter Document selection filter. + * @param {object} [options=null] Optional settings. + * @param {object} [options.projection=null] Limits the fields to return for all matching documents. + * @param {object} [options.sort=null] Determines which document the operation modifies if the query + *selects multiple documents. + * @param {number} [options.maxTimeMS=null] The maximum amount of time to allow the query to run. + * @return {object} + */ DBCollection.prototype.findOneAndDelete = function(filter, options) { var opts = Object.extend({}, options || {}); // Set up the command @@ -739,22 +739,22 @@ DBCollection.prototype.findOneAndDelete = function(filter, options) { }; /** -* Find a document and replace it in one atomic operation, requires a write lock for the duration of -*the operation. -* -* @method -* @param {object} filter Document selection filter. -* @param {object} replacement Document replacing the matching document. -* @param {object} [options=null] Optional settings. -* @param {object} [options.projection=null] Limits the fields to return for all matching documents. -* @param {object} [options.sort=null] Determines which document the operation modifies if the query -*selects multiple documents. -* @param {number} [options.maxTimeMS=null] The maximum amount of time to allow the query to run. -* @param {boolean} [options.upsert=false] Upsert the document if it does not exist. -* @param {boolean} [options.returnNewDocument=false] When true, returns the updated document rather -*than the original. The default is false. -* @return {object} -*/ + * Find a document and replace it in one atomic operation, requires a write lock for the duration of + *the operation. + * + * @method + * @param {object} filter Document selection filter. + * @param {object} replacement Document replacing the matching document. + * @param {object} [options=null] Optional settings. + * @param {object} [options.projection=null] Limits the fields to return for all matching documents. + * @param {object} [options.sort=null] Determines which document the operation modifies if the query + *selects multiple documents. + * @param {number} [options.maxTimeMS=null] The maximum amount of time to allow the query to run. + * @param {boolean} [options.upsert=false] Upsert the document if it does not exist. + * @param {boolean} [options.returnNewDocument=false] When true, returns the updated document rather + *than the original. The default is false. + * @return {object} + */ DBCollection.prototype.findOneAndReplace = function(filter, replacement, options) { var opts = Object.extend({}, options || {}); @@ -805,22 +805,22 @@ DBCollection.prototype.findOneAndReplace = function(filter, replacement, options }; /** -* Find a document and update it in one atomic operation, requires a write lock for the duration of -*the operation. -* -* @method -* @param {object} filter Document selection filter. -* @param {object} update Update operations to be performed on the document -* @param {object} [options=null] Optional settings. -* @param {object} [options.projection=null] Limits the fields to return for all matching documents. -* @param {object} [options.sort=null] Determines which document the operation modifies if the query -*selects multiple documents. -* @param {number} [options.maxTimeMS=null] The maximum amount of time to allow the query to run. -* @param {boolean} [options.upsert=false] Upsert the document if it does not exist. -* @param {boolean} [options.returnNewDocument=false] When true, returns the updated document rather -*than the original. The default is false. -* @return {object} -*/ + * Find a document and update it in one atomic operation, requires a write lock for the duration of + *the operation. + * + * @method + * @param {object} filter Document selection filter. + * @param {object} update Update operations to be performed on the document + * @param {object} [options=null] Optional settings. + * @param {object} [options.projection=null] Limits the fields to return for all matching documents. + * @param {object} [options.sort=null] Determines which document the operation modifies if the query + *selects multiple documents. + * @param {number} [options.maxTimeMS=null] The maximum amount of time to allow the query to run. + * @param {boolean} [options.upsert=false] Upsert the document if it does not exist. + * @param {boolean} [options.returnNewDocument=false] When true, returns the updated document rather + *than the original. The default is false. + * @return {object} + */ DBCollection.prototype.findOneAndUpdate = function(filter, update, options) { var opts = Object.extend({}, options || {}); diff --git a/src/mongo/shell/db.js b/src/mongo/shell/db.js index a309bda09d2..afc6e5357ed 100644 --- a/src/mongo/shell/db.js +++ b/src/mongo/shell/db.js @@ -4,1854 +4,1838 @@ var DB; (function() { - var _defaultWriteConcern = {w: 'majority', wtimeout: 10 * 60 * 1000}; +var _defaultWriteConcern = {w: 'majority', wtimeout: 10 * 60 * 1000}; - if (DB === undefined) { - DB = function(mongo, name) { - this._mongo = mongo; - this._name = name; - }; - } - - DB.prototype.getMongo = function() { - assert(this._mongo, "why no mongo!"); - return this._mongo; +if (DB === undefined) { + DB = function(mongo, name) { + this._mongo = mongo; + this._name = name; }; +} - DB.prototype.getSiblingDB = function(name) { - return this.getSession().getDatabase(name); - }; +DB.prototype.getMongo = function() { + assert(this._mongo, "why no mongo!"); + return this._mongo; +}; - DB.prototype.getSisterDB = DB.prototype.getSiblingDB; +DB.prototype.getSiblingDB = function(name) { + return this.getSession().getDatabase(name); +}; - DB.prototype.getName = function() { - return this._name; - }; +DB.prototype.getSisterDB = DB.prototype.getSiblingDB; - DB.prototype.stats = function(scale) { - return this.runCommand({dbstats: 1, scale: scale}); - }; +DB.prototype.getName = function() { + return this._name; +}; - DB.prototype.getCollection = function(name) { - return new DBCollection(this._mongo, this, name, this._name + "." + name); - }; +DB.prototype.stats = function(scale) { + return this.runCommand({dbstats: 1, scale: scale}); +}; - DB.prototype.commandHelp = function(name) { - var c = {}; - c[name] = 1; - c.help = true; - var res = this.runCommand(c); - if (!res.ok) - throw _getErrorWithCode(res, res.errmsg); - return res.help; - }; +DB.prototype.getCollection = function(name) { + return new DBCollection(this._mongo, this, name, this._name + "." + name); +}; - // utility to attach readPreference if needed. - DB.prototype._attachReadPreferenceToCommand = function(cmdObj, readPref) { - "use strict"; - // if the user has not set a readpref, return the original cmdObj - if ((readPref === null) || typeof(readPref) !== "object") { - return cmdObj; - } - - // if user specifies $readPreference manually, then don't change it - if (cmdObj.hasOwnProperty("$readPreference")) { - return cmdObj; - } +DB.prototype.commandHelp = function(name) { + var c = {}; + c[name] = 1; + c.help = true; + var res = this.runCommand(c); + if (!res.ok) + throw _getErrorWithCode(res, res.errmsg); + return res.help; +}; + +// utility to attach readPreference if needed. +DB.prototype._attachReadPreferenceToCommand = function(cmdObj, readPref) { + "use strict"; + // if the user has not set a readpref, return the original cmdObj + if ((readPref === null) || typeof (readPref) !== "object") { + return cmdObj; + } - // copy object so we don't mutate the original - var clonedCmdObj = Object.extend({}, cmdObj); - // The server selection spec mandates that the key is '$query', but - // the shell has historically used 'query'. The server accepts both, - // so we maintain the existing behavior - var cmdObjWithReadPref = {query: clonedCmdObj, $readPreference: readPref}; - return cmdObjWithReadPref; - }; + // if user specifies $readPreference manually, then don't change it + if (cmdObj.hasOwnProperty("$readPreference")) { + return cmdObj; + } - /** - * If someone passes i.e. runCommand("foo", {bar: "baz"}), we merge it in to - * runCommand({foo: 1, bar: "baz"}). - * If we already have a command object in the first argument, we ensure that the second - * argument 'extraKeys' is either null or an empty object. This prevents users from accidentally - * calling runCommand({foo: 1}, {bar: 1}) and expecting the final command invocation to be - * runCommand({foo: 1, bar: 1}). - * This helper abstracts that logic. - */ - DB.prototype._mergeCommandOptions = function(obj, extraKeys) { - "use strict"; - - if (typeof(obj) === "object") { - if (Object.keys(extraKeys || {}).length > 0) { - throw Error("Unexpected second argument to DB.runCommand(): (type: " + - typeof(extraKeys) + "): " + tojson(extraKeys)); - } - return obj; - } else if (typeof(obj) !== "string") { - throw Error("First argument to DB.runCommand() must be either an object or a string: " + - "(type: " + typeof(obj) + "): " + tojson(obj)); - } + // copy object so we don't mutate the original + var clonedCmdObj = Object.extend({}, cmdObj); + // The server selection spec mandates that the key is '$query', but + // the shell has historically used 'query'. The server accepts both, + // so we maintain the existing behavior + var cmdObjWithReadPref = {query: clonedCmdObj, $readPreference: readPref}; + return cmdObjWithReadPref; +}; + +/** + * If someone passes i.e. runCommand("foo", {bar: "baz"}), we merge it in to + * runCommand({foo: 1, bar: "baz"}). + * If we already have a command object in the first argument, we ensure that the second + * argument 'extraKeys' is either null or an empty object. This prevents users from accidentally + * calling runCommand({foo: 1}, {bar: 1}) and expecting the final command invocation to be + * runCommand({foo: 1, bar: 1}). + * This helper abstracts that logic. + */ +DB.prototype._mergeCommandOptions = function(obj, extraKeys) { + "use strict"; + + if (typeof (obj) === "object") { + if (Object.keys(extraKeys || {}).length > 0) { + throw Error("Unexpected second argument to DB.runCommand(): (type: " + + typeof (extraKeys) + "): " + tojson(extraKeys)); + } + return obj; + } else if (typeof (obj) !== "string") { + throw Error("First argument to DB.runCommand() must be either an object or a string: " + + "(type: " + typeof (obj) + "): " + tojson(obj)); + } - var commandName = obj; - var mergedCmdObj = {}; - mergedCmdObj[commandName] = 1; - - if (!extraKeys) { - return mergedCmdObj; - } else if (typeof(extraKeys) === "object") { - // this will traverse the prototype chain of extra, but keeping - // to maintain legacy behavior - for (var key in extraKeys) { - mergedCmdObj[key] = extraKeys[key]; - } - } else { - throw Error("Second argument to DB.runCommand(" + commandName + - ") must be an object: (type: " + typeof(extraKeys) + "): " + - tojson(extraKeys)); - } + var commandName = obj; + var mergedCmdObj = {}; + mergedCmdObj[commandName] = 1; + if (!extraKeys) { return mergedCmdObj; - }; - - // Like runCommand but applies readPreference if one has been set - // on the connection. Also sets slaveOk if a (non-primary) readPref has been set. - DB.prototype.runReadCommand = function(obj, extra, queryOptions) { - "use strict"; - - // Support users who call this function with a string commandName, e.g. - // db.runReadCommand("commandName", {arg1: "value", arg2: "value"}). - obj = this._mergeCommandOptions(obj, extra); - queryOptions = queryOptions !== undefined ? queryOptions : this.getQueryOptions(); + } else if (typeof (extraKeys) === "object") { + // this will traverse the prototype chain of extra, but keeping + // to maintain legacy behavior + for (var key in extraKeys) { + mergedCmdObj[key] = extraKeys[key]; + } + } else { + throw Error("Second argument to DB.runCommand(" + commandName + + ") must be an object: (type: " + typeof (extraKeys) + + "): " + tojson(extraKeys)); + } - { - const session = this.getSession(); + return mergedCmdObj; +}; - const readPreference = session._getSessionAwareClient().getReadPreference(session); - if (readPreference !== null) { - obj = this._attachReadPreferenceToCommand(obj, readPreference); +// Like runCommand but applies readPreference if one has been set +// on the connection. Also sets slaveOk if a (non-primary) readPref has been set. +DB.prototype.runReadCommand = function(obj, extra, queryOptions) { + "use strict"; - if (readPreference.mode !== "primary") { - // Set slaveOk if readPrefMode has been explicitly set with a readPreference - // other than primary. - queryOptions |= 4; - } - } - } + // Support users who call this function with a string commandName, e.g. + // db.runReadCommand("commandName", {arg1: "value", arg2: "value"}). + obj = this._mergeCommandOptions(obj, extra); + queryOptions = queryOptions !== undefined ? queryOptions : this.getQueryOptions(); - // The 'extra' parameter is not used as we have already created a merged command object. - return this.runCommand(obj, null, queryOptions); - }; - - // runCommand uses this impl to actually execute the command - DB.prototype._runCommandImpl = function(name, obj, options) { + { const session = this.getSession(); - return session._getSessionAwareClient().runCommand(session, name, obj, options); - }; - DB.prototype.runCommand = function(obj, extra, queryOptions) { - "use strict"; + const readPreference = session._getSessionAwareClient().getReadPreference(session); + if (readPreference !== null) { + obj = this._attachReadPreferenceToCommand(obj, readPreference); - // Support users who call this function with a string commandName, e.g. - // db.runCommand("commandName", {arg1: "value", arg2: "value"}). - var mergedObj = this._mergeCommandOptions(obj, extra); - - // if options were passed (i.e. because they were overridden on a collection), use them. - // Otherwise use getQueryOptions. - var options = - (typeof(queryOptions) !== "undefined") ? queryOptions : this.getQueryOptions(); - - try { - return this._runCommandImpl(this._name, mergedObj, options); - } catch (ex) { - // When runCommand flowed through query, a connection error resulted in the message - // "error doing query: failed". Even though this message is arguably incorrect - // for a command failing due to a connection failure, we preserve it for backwards - // compatibility. See SERVER-18334 for details. - if (ex.message.indexOf("network error") >= 0) { - throw new Error("error doing query: failed: " + ex.message); + if (readPreference.mode !== "primary") { + // Set slaveOk if readPrefMode has been explicitly set with a readPreference + // other than primary. + queryOptions |= 4; } - throw ex; } - }; - - DB.prototype.runCommandWithMetadata = function(commandArgs, metadata) { - const session = this.getSession(); - return session._getSessionAwareClient().runCommandWithMetadata( - session, this._name, metadata, commandArgs); - }; + } - DB.prototype._dbCommand = DB.prototype.runCommand; - DB.prototype._dbReadCommand = DB.prototype.runReadCommand; + // The 'extra' parameter is not used as we have already created a merged command object. + return this.runCommand(obj, null, queryOptions); +}; + +// runCommand uses this impl to actually execute the command +DB.prototype._runCommandImpl = function(name, obj, options) { + const session = this.getSession(); + return session._getSessionAwareClient().runCommand(session, name, obj, options); +}; + +DB.prototype.runCommand = function(obj, extra, queryOptions) { + "use strict"; + + // Support users who call this function with a string commandName, e.g. + // db.runCommand("commandName", {arg1: "value", arg2: "value"}). + var mergedObj = this._mergeCommandOptions(obj, extra); + + // if options were passed (i.e. because they were overridden on a collection), use them. + // Otherwise use getQueryOptions. + var options = (typeof (queryOptions) !== "undefined") ? queryOptions : this.getQueryOptions(); + + try { + return this._runCommandImpl(this._name, mergedObj, options); + } catch (ex) { + // When runCommand flowed through query, a connection error resulted in the message + // "error doing query: failed". Even though this message is arguably incorrect + // for a command failing due to a connection failure, we preserve it for backwards + // compatibility. See SERVER-18334 for details. + if (ex.message.indexOf("network error") >= 0) { + throw new Error("error doing query: failed: " + ex.message); + } + throw ex; + } +}; - DB.prototype.adminCommand = function(obj, extra) { - if (this._name == "admin") - return this.runCommand(obj, extra); - return this.getSiblingDB("admin").runCommand(obj, extra); - }; +DB.prototype.runCommandWithMetadata = function(commandArgs, metadata) { + const session = this.getSession(); + return session._getSessionAwareClient().runCommandWithMetadata( + session, this._name, metadata, commandArgs); +}; - DB.prototype._adminCommand = DB.prototype.adminCommand; // alias old name +DB.prototype._dbCommand = DB.prototype.runCommand; +DB.prototype._dbReadCommand = DB.prototype.runReadCommand; - DB.prototype._runAggregate = function(cmdObj, aggregateOptions) { - assert(cmdObj.pipeline instanceof Array, "cmdObj must contain a 'pipeline' array"); - assert(cmdObj.aggregate !== undefined, "cmdObj must contain 'aggregate' field"); - assert(aggregateOptions === undefined || aggregateOptions instanceof Object, - "'aggregateOptions' argument must be an object"); +DB.prototype.adminCommand = function(obj, extra) { + if (this._name == "admin") + return this.runCommand(obj, extra); + return this.getSiblingDB("admin").runCommand(obj, extra); +}; - // Make a copy of the initial command object, i.e. {aggregate: x, pipeline: [...]}. - cmdObj = Object.extend({}, cmdObj); +DB.prototype._adminCommand = DB.prototype.adminCommand; // alias old name - // Make a copy of the aggregation options. - let optcpy = Object.extend({}, (aggregateOptions || {})); +DB.prototype._runAggregate = function(cmdObj, aggregateOptions) { + assert(cmdObj.pipeline instanceof Array, "cmdObj must contain a 'pipeline' array"); + assert(cmdObj.aggregate !== undefined, "cmdObj must contain 'aggregate' field"); + assert(aggregateOptions === undefined || aggregateOptions instanceof Object, + "'aggregateOptions' argument must be an object"); - if ('batchSize' in optcpy) { - if (optcpy.cursor == null) { - optcpy.cursor = {}; - } + // Make a copy of the initial command object, i.e. {aggregate: x, pipeline: [...]}. + cmdObj = Object.extend({}, cmdObj); - optcpy.cursor.batchSize = optcpy['batchSize']; - delete optcpy['batchSize']; - } else if ('useCursor' in optcpy) { - if (optcpy.cursor == null) { - optcpy.cursor = {}; - } + // Make a copy of the aggregation options. + let optcpy = Object.extend({}, (aggregateOptions || {})); - delete optcpy['useCursor']; + if ('batchSize' in optcpy) { + if (optcpy.cursor == null) { + optcpy.cursor = {}; } - const maxAwaitTimeMS = optcpy.maxAwaitTimeMS; - delete optcpy.maxAwaitTimeMS; - - // Reassign the cleaned-up options. - aggregateOptions = optcpy; - - // Add the options to the command object. - Object.extend(cmdObj, aggregateOptions); - - if (!('cursor' in cmdObj)) { - cmdObj.cursor = {}; + optcpy.cursor.batchSize = optcpy['batchSize']; + delete optcpy['batchSize']; + } else if ('useCursor' in optcpy) { + if (optcpy.cursor == null) { + optcpy.cursor = {}; } - const pipeline = cmdObj.pipeline; - - // Check whether the pipeline has a stage which performs writes like $out. If not, we may - // run on a Secondary and should attach a readPreference. - const hasWritingStage = (function() { - if (pipeline.length == 0) { - return false; - } - const lastStage = pipeline[pipeline.length - 1]; - return lastStage.hasOwnProperty("$out") || lastStage.hasOwnProperty("$merge"); - }()); - - const doAgg = function(cmdObj) { - return hasWritingStage ? this.runCommand(cmdObj) : this.runReadCommand(cmdObj); - }.bind(this); - - const res = doAgg(cmdObj); + delete optcpy['useCursor']; + } - if (!res.ok && (res.code == 17020 || res.errmsg == "unrecognized field \"cursor") && - !("cursor" in aggregateOptions)) { - // If the command failed because cursors aren't supported and the user didn't explicitly - // request a cursor, try again without requesting a cursor. - delete cmdObj.cursor; + const maxAwaitTimeMS = optcpy.maxAwaitTimeMS; + delete optcpy.maxAwaitTimeMS; - res = doAgg(cmdObj); + // Reassign the cleaned-up options. + aggregateOptions = optcpy; - if ('result' in res && !("cursor" in res)) { - // convert old-style output to cursor-style output - res.cursor = {ns: '', id: NumberLong(0)}; - res.cursor.firstBatch = res.result; - delete res.result; - } - } + // Add the options to the command object. + Object.extend(cmdObj, aggregateOptions); - assert.commandWorked(res, "aggregate failed"); - - if ("cursor" in res) { - let batchSizeValue = undefined; + if (!('cursor' in cmdObj)) { + cmdObj.cursor = {}; + } - if (cmdObj["cursor"]["batchSize"] > 0) { - batchSizeValue = cmdObj["cursor"]["batchSize"]; - } + const pipeline = cmdObj.pipeline; - return new DBCommandCursor(this, res, batchSizeValue, maxAwaitTimeMS); + // Check whether the pipeline has a stage which performs writes like $out. If not, we may + // run on a Secondary and should attach a readPreference. + const hasWritingStage = (function() { + if (pipeline.length == 0) { + return false; } + const lastStage = pipeline[pipeline.length - 1]; + return lastStage.hasOwnProperty("$out") || lastStage.hasOwnProperty("$merge"); + }()); - return res; - }; - - DB.prototype.aggregate = function(pipeline, aggregateOptions) { - assert(pipeline instanceof Array, "pipeline argument must be an array"); - const cmdObj = this._mergeCommandOptions("aggregate", {pipeline: pipeline}); - - return this._runAggregate(cmdObj, (aggregateOptions || {})); - }; - - /** - Create a new collection in the database. Normally, collection creation is automatic. You - would - use this function if you wish to specify special options on creation. - - If the collection already exists, no action occurs. - - <p>Options:</p> - <ul> - <li> - size: desired initial extent size for the collection. Must be <= 1000000000. - for fixed size (capped) collections, this size is the total/max size of the - collection. - </li> - <li> - capped: if true, this is a capped collection (where old data rolls out). - </li> - <li> max: maximum number of objects if capped (optional).</li> - <li> - storageEngine: BSON document containing storage engine specific options. Format: - { - storageEngine: { - storageEngine1: { - ... - }, - storageEngine2: { - ... - }, - ... - } - } - </li> - </ul> + const doAgg = function(cmdObj) { + return hasWritingStage ? this.runCommand(cmdObj) : this.runReadCommand(cmdObj); + }.bind(this); - <p>Example:</p> - <code>db.createCollection("movies", { size: 10 * 1024 * 1024, capped:true } );</code> + const res = doAgg(cmdObj); - * @param {String} name Name of new collection to create - * @param {Object} options Object with options for call. Options are listed above. - * @return {Object} returned has member ok set to true if operation succeeds, false otherwise. - */ - DB.prototype.createCollection = function(name, opt) { - var options = opt || {}; + if (!res.ok && (res.code == 17020 || res.errmsg == "unrecognized field \"cursor") && + !("cursor" in aggregateOptions)) { + // If the command failed because cursors aren't supported and the user didn't explicitly + // request a cursor, try again without requesting a cursor. + delete cmdObj.cursor; - var cmd = {create: name}; - Object.extend(cmd, options); - - return this._dbCommand(cmd); - }; + res = doAgg(cmdObj); - /** - * Command to create a view based on the specified aggregation pipeline. - * Usage: db.createView(name, viewOn, pipeline: [{ $operator: {...}}, ... ]) - * - * @param name String - name of the new view to create - * @param viewOn String - name of the backing view or collection - * @param pipeline [{ $operator: {...}}, ... ] - the aggregation pipeline that defines the view - * @param options { } - options on the view, e.g., collations - */ - DB.prototype.createView = function(name, viewOn, pipeline, opt) { - var options = opt || {}; - - var cmd = {create: name}; - - if (viewOn == undefined) { - throw Error("Must specify a backing view or collection"); + if ('result' in res && !("cursor" in res)) { + // convert old-style output to cursor-style output + res.cursor = {ns: '', id: NumberLong(0)}; + res.cursor.firstBatch = res.result; + delete res.result; } + } - // Since we allow a single stage pipeline to be specified as an object - // in aggregation, we need to account for that here for consistency. - if (pipeline != undefined) { - if (!Array.isArray(pipeline)) { - pipeline = [pipeline]; - } - } - options.pipeline = pipeline; - options.viewOn = viewOn; - - Object.extend(cmd, options); + assert.commandWorked(res, "aggregate failed"); - return this._dbCommand(cmd); - }; + if ("cursor" in res) { + let batchSizeValue = undefined; - /** - * @deprecated use getProfilingStatus - * Returns the current profiling level of this database - * @return SOMETHING_FIXME or null on error - */ - DB.prototype.getProfilingLevel = function() { - var res = assert.commandWorked(this._dbCommand({profile: -1})); - return res ? res.was : null; - }; + if (cmdObj["cursor"]["batchSize"] > 0) { + batchSizeValue = cmdObj["cursor"]["batchSize"]; + } - /** - * @return the current profiling status - * example { was : 0, slowms : 100 } - * @return SOMETHING_FIXME or null on error - */ - DB.prototype.getProfilingStatus = function() { - var res = this._dbCommand({profile: -1}); - if (!res.ok) - throw _getErrorWithCode(res, "profile command failed: " + tojson(res)); - delete res.ok; - return res; - }; + return new DBCommandCursor(this, res, batchSizeValue, maxAwaitTimeMS); + } - /** - * Erase the entire database. - * @params writeConcern: (document) expresses the write concern of the drop command. - * @return Object returned has member ok set to true if operation succeeds, false otherwise. - */ - DB.prototype.dropDatabase = function(writeConcern) { - return this._dbCommand( - {dropDatabase: 1, writeConcern: writeConcern ? writeConcern : _defaultWriteConcern}); - }; + return res; +}; + +DB.prototype.aggregate = function(pipeline, aggregateOptions) { + assert(pipeline instanceof Array, "pipeline argument must be an array"); + const cmdObj = this._mergeCommandOptions("aggregate", {pipeline: pipeline}); + + return this._runAggregate(cmdObj, (aggregateOptions || {})); +}; + +/** + Create a new collection in the database. Normally, collection creation is automatic. You + would + use this function if you wish to specify special options on creation. + + If the collection already exists, no action occurs. + + <p>Options:</p> + <ul> + <li> + size: desired initial extent size for the collection. Must be <= 1000000000. + for fixed size (capped) collections, this size is the total/max size of the + collection. + </li> + <li> + capped: if true, this is a capped collection (where old data rolls out). + </li> + <li> max: maximum number of objects if capped (optional).</li> + <li> + storageEngine: BSON document containing storage engine specific options. Format: + { + storageEngine: { + storageEngine1: { + ... + }, + storageEngine2: { + ... + }, + ... + } + } + </li> + </ul> + + <p>Example:</p> + <code>db.createCollection("movies", { size: 10 * 1024 * 1024, capped:true } );</code> + + * @param {String} name Name of new collection to create + * @param {Object} options Object with options for call. Options are listed above. + * @return {Object} returned has member ok set to true if operation succeeds, false otherwise. +*/ +DB.prototype.createCollection = function(name, opt) { + var options = opt || {}; + + var cmd = {create: name}; + Object.extend(cmd, options); + + return this._dbCommand(cmd); +}; + +/** + * Command to create a view based on the specified aggregation pipeline. + * Usage: db.createView(name, viewOn, pipeline: [{ $operator: {...}}, ... ]) + * + * @param name String - name of the new view to create + * @param viewOn String - name of the backing view or collection + * @param pipeline [{ $operator: {...}}, ... ] - the aggregation pipeline that defines the view + * @param options { } - options on the view, e.g., collations + */ +DB.prototype.createView = function(name, viewOn, pipeline, opt) { + var options = opt || {}; + + var cmd = {create: name}; + + if (viewOn == undefined) { + throw Error("Must specify a backing view or collection"); + } - /** - * Shuts down the database. Must be run while using the admin database. - * @param opts Options for shutdown. Possible options are: - * - force: (boolean) if the server should shut down, even if there is no - * up-to-date slave - * - timeoutSecs: (number) the server will continue checking over timeoutSecs - * if any other servers have caught up enough for it to shut down. - */ - DB.prototype.shutdownServer = function(opts) { - if ("admin" != this._name) { - return "shutdown command only works with the admin database; try 'use admin'"; + // Since we allow a single stage pipeline to be specified as an object + // in aggregation, we need to account for that here for consistency. + if (pipeline != undefined) { + if (!Array.isArray(pipeline)) { + pipeline = [pipeline]; } + } + options.pipeline = pipeline; + options.viewOn = viewOn; + + Object.extend(cmd, options); + + return this._dbCommand(cmd); +}; + +/** + * @deprecated use getProfilingStatus + * Returns the current profiling level of this database + * @return SOMETHING_FIXME or null on error + */ +DB.prototype.getProfilingLevel = function() { + var res = assert.commandWorked(this._dbCommand({profile: -1})); + return res ? res.was : null; +}; + +/** + * @return the current profiling status + * example { was : 0, slowms : 100 } + * @return SOMETHING_FIXME or null on error + */ +DB.prototype.getProfilingStatus = function() { + var res = this._dbCommand({profile: -1}); + if (!res.ok) + throw _getErrorWithCode(res, "profile command failed: " + tojson(res)); + delete res.ok; + return res; +}; + +/** + * Erase the entire database. + * @params writeConcern: (document) expresses the write concern of the drop command. + * @return Object returned has member ok set to true if operation succeeds, false otherwise. + */ +DB.prototype.dropDatabase = function(writeConcern) { + return this._dbCommand( + {dropDatabase: 1, writeConcern: writeConcern ? writeConcern : _defaultWriteConcern}); +}; + +/** + * Shuts down the database. Must be run while using the admin database. + * @param opts Options for shutdown. Possible options are: + * - force: (boolean) if the server should shut down, even if there is no + * up-to-date slave + * - timeoutSecs: (number) the server will continue checking over timeoutSecs + * if any other servers have caught up enough for it to shut down. + */ +DB.prototype.shutdownServer = function(opts) { + if ("admin" != this._name) { + return "shutdown command only works with the admin database; try 'use admin'"; + } - var cmd = {'shutdown': 1}; - opts = opts || {}; - for (var o in opts) { - cmd[o] = opts[o]; - } + var cmd = {'shutdown': 1}; + opts = opts || {}; + for (var o in opts) { + cmd[o] = opts[o]; + } - try { - var res = this.runCommand(cmd); - if (!res.ok) { - throw _getErrorWithCode(res, 'shutdownServer failed: ' + tojson(res)); - } - throw Error('shutdownServer failed: server is still up.'); - } catch (e) { - // we expect the command to not return a response, as the server will shut down - // immediately. - if (isNetworkError(e)) { - print('server should be down...'); - return; - } - throw e; + try { + var res = this.runCommand(cmd); + if (!res.ok) { + throw _getErrorWithCode(res, 'shutdownServer failed: ' + tojson(res)); + } + throw Error('shutdownServer failed: server is still up.'); + } catch (e) { + // we expect the command to not return a response, as the server will shut down + // immediately. + if (isNetworkError(e)) { + print('server should be down...'); + return; } - }; + throw e; + } +}; + +/** + Clone database on another server to here. This functionality was removed as of MongoDB 4.2. + The shell helper is kept to maintain compatibility with previous versions of MongoDB. + <p> + Generally, you should dropDatabase() first as otherwise the cloned information will MERGE + into whatever data is already present in this database. (That is however a valid way to use + clone if you are trying to do something intentionally, such as union three non-overlapping + databases into one.) + <p> + This is a low level administrative function will is not typically used. + + * @param {String} from Where to clone from (dbhostname[:port]). May not be this database + (self) as you cannot clone to yourself. + * @return Object returned has member ok set to true if operation succeeds, false otherwise. + * See also: db.copyDatabase() + */ +DB.prototype.cloneDatabase = function(from) { + print( + "WARNING: db.cloneDatabase will only function with MongoDB 4.0 and below. See http://dochub.mongodb.org/core/4.2-copydb-clone"); + assert(isString(from) && from.length); + return this._dbCommand({clone: from}); +}; + +/** + Copy database from one server or name to another server or name. This functionality was + removed as of MongoDB 4.2. The shell helper is kept to maintain compatibility with previous + versions of MongoDB. + + Generally, you should dropDatabase() first as otherwise the copied information will MERGE + into whatever data is already present in this database (and you will get duplicate objects + in collections potentially.) + + For security reasons this function only works when executed on the "admin" db. However, + if you have access to said db, you can copy any database from one place to another. + + This method provides a way to "rename" a database by copying it to a new db name and + location. Additionally, it effectively provides a repair facility. + + * @param {String} fromdb database name from which to copy. + * @param {String} todb database name to copy to. + * @param {String} fromhost hostname of the database (and optionally, ":port") from which to + copy the data. default if unspecified is to copy from self. + * @return Object returned has member ok set to true if operation succeeds, false otherwise. + * See also: db.clone() +*/ +DB.prototype.copyDatabase = function( + fromdb, todb, fromhost, username, password, mechanism, slaveOk) { + print( + "WARNING: db.copyDatabase will only function with MongoDB 4.0 and below. See http://dochub.mongodb.org/core/4.2-copydb-clone"); + assert(isString(fromdb) && fromdb.length); + assert(isString(todb) && todb.length); + fromhost = fromhost || ""; + if ((typeof username === "boolean") && (typeof password === "undefined") && + (typeof mechanism === "undefined") && (typeof slaveOk === "undefined")) { + slaveOk = username; + username = undefined; + } + if (typeof slaveOk !== "boolean") { + slaveOk = false; + } - /** - Clone database on another server to here. This functionality was removed as of MongoDB 4.2. - The shell helper is kept to maintain compatibility with previous versions of MongoDB. - <p> - Generally, you should dropDatabase() first as otherwise the cloned information will MERGE - into whatever data is already present in this database. (That is however a valid way to use - clone if you are trying to do something intentionally, such as union three non-overlapping - databases into one.) - <p> - This is a low level administrative function will is not typically used. - - * @param {String} from Where to clone from (dbhostname[:port]). May not be this database - (self) as you cannot clone to yourself. - * @return Object returned has member ok set to true if operation succeeds, false otherwise. - * See also: db.copyDatabase() - */ - DB.prototype.cloneDatabase = function(from) { - print( - "WARNING: db.cloneDatabase will only function with MongoDB 4.0 and below. See http://dochub.mongodb.org/core/4.2-copydb-clone"); - assert(isString(from) && from.length); - return this._dbCommand({clone: from}); - }; + if (!mechanism) { + mechanism = this._getDefaultAuthenticationMechanism(username, fromdb); + } + assert(mechanism == "SCRAM-SHA-1" || mechanism == "SCRAM-SHA-256" || mechanism == "MONGODB-CR"); - /** - Copy database from one server or name to another server or name. This functionality was - removed as of MongoDB 4.2. The shell helper is kept to maintain compatibility with previous - versions of MongoDB. - - Generally, you should dropDatabase() first as otherwise the copied information will MERGE - into whatever data is already present in this database (and you will get duplicate objects - in collections potentially.) - - For security reasons this function only works when executed on the "admin" db. However, - if you have access to said db, you can copy any database from one place to another. - - This method provides a way to "rename" a database by copying it to a new db name and - location. Additionally, it effectively provides a repair facility. - - * @param {String} fromdb database name from which to copy. - * @param {String} todb database name to copy to. - * @param {String} fromhost hostname of the database (and optionally, ":port") from which to - copy the data. default if unspecified is to copy from self. - * @return Object returned has member ok set to true if operation succeeds, false otherwise. - * See also: db.clone() - */ - DB.prototype.copyDatabase = function( - fromdb, todb, fromhost, username, password, mechanism, slaveOk) { - print( - "WARNING: db.copyDatabase will only function with MongoDB 4.0 and below. See http://dochub.mongodb.org/core/4.2-copydb-clone"); - assert(isString(fromdb) && fromdb.length); - assert(isString(todb) && todb.length); - fromhost = fromhost || ""; - if ((typeof username === "boolean") && (typeof password === "undefined") && - (typeof mechanism === "undefined") && (typeof slaveOk === "undefined")) { - slaveOk = username; - username = undefined; - } - if (typeof slaveOk !== "boolean") { - slaveOk = false; - } + // Check for no auth or copying from localhost + if (!username || !password || fromhost == "") { + return this._adminCommand( + {copydb: 1, fromhost: fromhost, fromdb: fromdb, todb: todb, slaveOk: slaveOk}); + } - if (!mechanism) { - mechanism = this._getDefaultAuthenticationMechanism(username, fromdb); - } - assert(mechanism == "SCRAM-SHA-1" || mechanism == "SCRAM-SHA-256" || - mechanism == "MONGODB-CR"); + // Use the copyDatabase native helper for SCRAM-SHA-1/256 + if (mechanism != "MONGODB-CR") { + // TODO SERVER-30886: Add session support for Mongo.prototype.copyDatabaseWithSCRAM(). + return this.getMongo().copyDatabaseWithSCRAM( + fromdb, todb, fromhost, username, password, slaveOk); + } - // Check for no auth or copying from localhost - if (!username || !password || fromhost == "") { - return this._adminCommand( - {copydb: 1, fromhost: fromhost, fromdb: fromdb, todb: todb, slaveOk: slaveOk}); + // Fall back to MONGODB-CR + var n = assert.commandWorked(this._adminCommand({copydbgetnonce: 1, fromhost: fromhost})); + return this._adminCommand({ + copydb: 1, + fromhost: fromhost, + fromdb: fromdb, + todb: todb, + username: username, + nonce: n.nonce, + key: this.__pwHash(n.nonce, username, password), + slaveOk: slaveOk, + }); +}; + +DB.prototype.help = function() { + print("DB methods:"); + print( + "\tdb.adminCommand(nameOrDocument) - switches to 'admin' db, and runs command [just calls db.runCommand(...)]"); + print( + "\tdb.aggregate([pipeline], {options}) - performs a collectionless aggregation on this database; returns a cursor"); + print("\tdb.auth(username, password)"); + print("\tdb.cloneDatabase(fromhost) - will only function with MongoDB 4.0 and below"); + print("\tdb.commandHelp(name) returns the help for the command"); + print( + "\tdb.copyDatabase(fromdb, todb, fromhost) - will only function with MongoDB 4.0 and below"); + print("\tdb.createCollection(name, {size: ..., capped: ..., max: ...})"); + print("\tdb.createUser(userDocument)"); + print("\tdb.createView(name, viewOn, [{$operator: {...}}, ...], {viewOptions})"); + print("\tdb.currentOp() displays currently executing operations in the db"); + print("\tdb.dropDatabase(writeConcern)"); + print("\tdb.dropUser(username)"); + print("\tdb.eval() - deprecated"); + print("\tdb.fsyncLock() flush data to disk and lock server for backups"); + print("\tdb.fsyncUnlock() unlocks server following a db.fsyncLock()"); + print("\tdb.getCollection(cname) same as db['cname'] or db.cname"); + print("\tdb.getCollectionInfos([filter]) - returns a list that contains the names and options" + + " of the db's collections"); + print("\tdb.getCollectionNames()"); + print("\tdb.getLastError() - just returns the err msg string"); + print("\tdb.getLastErrorObj() - return full status object"); + print("\tdb.getLogComponents()"); + print("\tdb.getMongo() get the server connection object"); + print("\tdb.getMongo().setSlaveOk() allow queries on a replication slave server"); + print("\tdb.getName()"); + print("\tdb.getProfilingLevel() - deprecated"); + print("\tdb.getProfilingStatus() - returns if profiling is on and slow threshold"); + print("\tdb.getReplicationInfo()"); + print("\tdb.getSiblingDB(name) get the db at the same server as this one"); + print( + "\tdb.getWriteConcern() - returns the write concern used for any operations on this db, inherited from server object if set"); + print("\tdb.hostInfo() get details about the server's host"); + print("\tdb.isMaster() check replica primary status"); + print("\tdb.killOp(opid) kills the current operation in the db"); + print("\tdb.listCommands() lists all the db commands"); + print("\tdb.loadServerScripts() loads all the scripts in db.system.js"); + print("\tdb.logout()"); + print("\tdb.printCollectionStats()"); + print("\tdb.printReplicationInfo()"); + print("\tdb.printShardingStatus()"); + print("\tdb.printSlaveReplicationInfo()"); + print("\tdb.resetError()"); + print( + "\tdb.runCommand(cmdObj) run a database command. if cmdObj is a string, turns it into {cmdObj: 1}"); + print("\tdb.serverStatus()"); + print("\tdb.setLogLevel(level,<component>)"); + print("\tdb.setProfilingLevel(level,slowms) 0=off 1=slow 2=all"); + print("\tdb.setVerboseShell(flag) display extra information in shell output"); + print( + "\tdb.setWriteConcern(<write concern doc>) - sets the write concern for writes to the db"); + print("\tdb.shutdownServer()"); + print("\tdb.stats()"); + print( + "\tdb.unsetWriteConcern(<write concern doc>) - unsets the write concern for writes to the db"); + print("\tdb.version() current version of the server"); + print("\tdb.watch() - opens a change stream cursor for a database to report on all " + + " changes to its non-system collections."); + return __magicNoPrint; +}; + +DB.prototype.printCollectionStats = function(scale) { + if (arguments.length > 1) { + print("printCollectionStats() has a single optional argument (scale)"); + return; + } + if (typeof scale != 'undefined') { + if (typeof scale != 'number') { + print("scale has to be a number >= 1"); + return; } - - // Use the copyDatabase native helper for SCRAM-SHA-1/256 - if (mechanism != "MONGODB-CR") { - // TODO SERVER-30886: Add session support for Mongo.prototype.copyDatabaseWithSCRAM(). - return this.getMongo().copyDatabaseWithSCRAM( - fromdb, todb, fromhost, username, password, slaveOk); + if (scale < 1) { + print("scale has to be >= 1"); + return; } + } + var mydb = this; + this.getCollectionNames().forEach(function(z) { + print(z); + printjson(mydb.getCollection(z).stats(scale)); + print("---"); + }); +}; + +/** + * Configures settings for capturing operations inside the system.profile collection and in the + * slow query log. + * + * The 'level' can be 0, 1, or 2: + * - 0 means that profiling is off and nothing will be written to system.profile. + * - 1 means that profiling is on for operations slower than the currently configured 'slowms' + * threshold (more on 'slowms' below). + * - 2 means that profiling is on for all operations, regardless of whether or not they are + * slower than 'slowms'. + * + * The 'options' parameter, if a number, is interpreted as the 'slowms' value to send to the + * server. 'slowms' determines the threshold, in milliseconds, above which slow operations get + * profiled at profiling level 1 or logged at logLevel 0. + * + * If 'options' is not a number, it is expected to be an object containing additional parameters + * to get passed to the server. For example, db.setProfilingLevel(2, {foo: "bar"}) will issue + * the command {profile: 2, foo: "bar"} to the server. + */ +DB.prototype.setProfilingLevel = function(level, options) { + if (level < 0 || level > 2) { + var errorText = "input level " + level + " is out of range [0..2]"; + var errorObject = new Error(errorText); + errorObject['dbSetProfilingException'] = errorText; + throw errorObject; + } - // Fall back to MONGODB-CR - var n = assert.commandWorked(this._adminCommand({copydbgetnonce: 1, fromhost: fromhost})); - return this._adminCommand({ - copydb: 1, - fromhost: fromhost, - fromdb: fromdb, - todb: todb, - username: username, - nonce: n.nonce, - key: this.__pwHash(n.nonce, username, password), - slaveOk: slaveOk, - }); - }; - - DB.prototype.help = function() { - print("DB methods:"); - print( - "\tdb.adminCommand(nameOrDocument) - switches to 'admin' db, and runs command [just calls db.runCommand(...)]"); - print( - "\tdb.aggregate([pipeline], {options}) - performs a collectionless aggregation on this database; returns a cursor"); - print("\tdb.auth(username, password)"); - print("\tdb.cloneDatabase(fromhost) - will only function with MongoDB 4.0 and below"); - print("\tdb.commandHelp(name) returns the help for the command"); - print( - "\tdb.copyDatabase(fromdb, todb, fromhost) - will only function with MongoDB 4.0 and below"); - print("\tdb.createCollection(name, {size: ..., capped: ..., max: ...})"); - print("\tdb.createUser(userDocument)"); - print("\tdb.createView(name, viewOn, [{$operator: {...}}, ...], {viewOptions})"); - print("\tdb.currentOp() displays currently executing operations in the db"); - print("\tdb.dropDatabase(writeConcern)"); - print("\tdb.dropUser(username)"); - print("\tdb.eval() - deprecated"); - print("\tdb.fsyncLock() flush data to disk and lock server for backups"); - print("\tdb.fsyncUnlock() unlocks server following a db.fsyncLock()"); - print("\tdb.getCollection(cname) same as db['cname'] or db.cname"); - print( - "\tdb.getCollectionInfos([filter]) - returns a list that contains the names and options" + - " of the db's collections"); - print("\tdb.getCollectionNames()"); - print("\tdb.getLastError() - just returns the err msg string"); - print("\tdb.getLastErrorObj() - return full status object"); - print("\tdb.getLogComponents()"); - print("\tdb.getMongo() get the server connection object"); - print("\tdb.getMongo().setSlaveOk() allow queries on a replication slave server"); - print("\tdb.getName()"); - print("\tdb.getProfilingLevel() - deprecated"); - print("\tdb.getProfilingStatus() - returns if profiling is on and slow threshold"); - print("\tdb.getReplicationInfo()"); - print("\tdb.getSiblingDB(name) get the db at the same server as this one"); - print( - "\tdb.getWriteConcern() - returns the write concern used for any operations on this db, inherited from server object if set"); - print("\tdb.hostInfo() get details about the server's host"); - print("\tdb.isMaster() check replica primary status"); - print("\tdb.killOp(opid) kills the current operation in the db"); - print("\tdb.listCommands() lists all the db commands"); - print("\tdb.loadServerScripts() loads all the scripts in db.system.js"); - print("\tdb.logout()"); - print("\tdb.printCollectionStats()"); - print("\tdb.printReplicationInfo()"); - print("\tdb.printShardingStatus()"); - print("\tdb.printSlaveReplicationInfo()"); - print("\tdb.resetError()"); - print( - "\tdb.runCommand(cmdObj) run a database command. if cmdObj is a string, turns it into {cmdObj: 1}"); - print("\tdb.serverStatus()"); - print("\tdb.setLogLevel(level,<component>)"); - print("\tdb.setProfilingLevel(level,slowms) 0=off 1=slow 2=all"); - print("\tdb.setVerboseShell(flag) display extra information in shell output"); - print( - "\tdb.setWriteConcern(<write concern doc>) - sets the write concern for writes to the db"); - print("\tdb.shutdownServer()"); - print("\tdb.stats()"); - print( - "\tdb.unsetWriteConcern(<write concern doc>) - unsets the write concern for writes to the db"); - print("\tdb.version() current version of the server"); - print("\tdb.watch() - opens a change stream cursor for a database to report on all " + - " changes to its non-system collections."); - return __magicNoPrint; - }; + var cmd = {profile: level}; + if (isNumber(options)) { + cmd.slowms = options; + } else { + cmd = Object.extend(cmd, options); + } + return assert.commandWorked(this._dbCommand(cmd)); +}; + +/** + * @deprecated + * <p> Evaluate a js expression at the database server.</p> + * + * <p>Useful if you need to touch a lot of data lightly; in such a scenario + * the network transfer of the data could be a bottleneck. A good example + * is "select count(*)" -- can be done server side via this mechanism. + * </p> + * + * <p> + * If the eval fails, an exception is thrown of the form: + * </p> + * <code>{ dbEvalException: { retval: functionReturnValue, ok: num [, errno: num] [, errmsg: + *str] } }</code> + * + * <p>Example: </p> + * <code>print( "mycount: " + db.eval( function(){db.mycoll.find({},{_id:ObjId()}).length();} + *);</code> + * + * @param {Function} jsfunction Javascript function to run on server. Note this it not a + *closure, but rather just "code". + * @return result of your function, or null if error + * + */ +DB.prototype.eval = function(jsfunction) { + print("WARNING: db.eval is deprecated"); + + var cmd = {$eval: jsfunction}; + if (arguments.length > 1) { + cmd.args = Array.from(arguments).slice(1); + } - DB.prototype.printCollectionStats = function(scale) { - if (arguments.length > 1) { - print("printCollectionStats() has a single optional argument (scale)"); - return; - } - if (typeof scale != 'undefined') { - if (typeof scale != 'number') { - print("scale has to be a number >= 1"); - return; - } - if (scale < 1) { - print("scale has to be >= 1"); - return; + var res = this._dbCommand(cmd); + + if (!res.ok) + throw _getErrorWithCode(res, tojson(res)); + + return res.retval; +}; + +DB.prototype.dbEval = DB.prototype.eval; + +/** + * <p> + * An array of grouped items is returned. The array must fit in RAM, thus this function is not + * suitable when the return set is extremely large. + * </p> + * <p> + * To order the grouped data, simply sort it client side upon return. + * <p> + Defaults + cond may be null if you want to run against all rows in the collection + keyf is a function which takes an object and returns the desired key. set either key or + keyf (not both). + * </p> + */ +DB.prototype.groupeval = function(parmsObj) { + var groupFunction = function() { + var parms = args[0]; + var c = db[parms.ns].find(parms.cond || {}); + var map = new Map(); + var pks = parms.key ? Object.keySet(parms.key) : null; + var pkl = pks ? pks.length : 0; + var key = {}; + + while (c.hasNext()) { + var obj = c.next(); + if (pks) { + for (var i = 0; i < pkl; i++) { + var k = pks[i]; + key[k] = obj[k]; + } + } else { + key = parms.$keyf(obj); } - } - var mydb = this; - this.getCollectionNames().forEach(function(z) { - print(z); - printjson(mydb.getCollection(z).stats(scale)); - print("---"); - }); - }; - /** - * Configures settings for capturing operations inside the system.profile collection and in the - * slow query log. - * - * The 'level' can be 0, 1, or 2: - * - 0 means that profiling is off and nothing will be written to system.profile. - * - 1 means that profiling is on for operations slower than the currently configured 'slowms' - * threshold (more on 'slowms' below). - * - 2 means that profiling is on for all operations, regardless of whether or not they are - * slower than 'slowms'. - * - * The 'options' parameter, if a number, is interpreted as the 'slowms' value to send to the - * server. 'slowms' determines the threshold, in milliseconds, above which slow operations get - * profiled at profiling level 1 or logged at logLevel 0. - * - * If 'options' is not a number, it is expected to be an object containing additional parameters - * to get passed to the server. For example, db.setProfilingLevel(2, {foo: "bar"}) will issue - * the command {profile: 2, foo: "bar"} to the server. - */ - DB.prototype.setProfilingLevel = function(level, options) { - if (level < 0 || level > 2) { - var errorText = "input level " + level + " is out of range [0..2]"; - var errorObject = new Error(errorText); - errorObject['dbSetProfilingException'] = errorText; - throw errorObject; + var aggObj = map.get(key); + if (aggObj == null) { + var newObj = Object.extend({}, key); // clone + aggObj = Object.extend(newObj, parms.initial); + map.put(key, aggObj); + } + parms.$reduce(obj, aggObj); } - var cmd = {profile: level}; - if (isNumber(options)) { - cmd.slowms = options; - } else { - cmd = Object.extend(cmd, options); - } - return assert.commandWorked(this._dbCommand(cmd)); + return map.values(); }; - /** - * @deprecated - * <p> Evaluate a js expression at the database server.</p> - * - * <p>Useful if you need to touch a lot of data lightly; in such a scenario - * the network transfer of the data could be a bottleneck. A good example - * is "select count(*)" -- can be done server side via this mechanism. - * </p> - * - * <p> - * If the eval fails, an exception is thrown of the form: - * </p> - * <code>{ dbEvalException: { retval: functionReturnValue, ok: num [, errno: num] [, errmsg: - *str] } }</code> - * - * <p>Example: </p> - * <code>print( "mycount: " + db.eval( function(){db.mycoll.find({},{_id:ObjId()}).length();} - *);</code> - * - * @param {Function} jsfunction Javascript function to run on server. Note this it not a - *closure, but rather just "code". - * @return result of your function, or null if error - * - */ - DB.prototype.eval = function(jsfunction) { - print("WARNING: db.eval is deprecated"); - - var cmd = {$eval: jsfunction}; - if (arguments.length > 1) { - cmd.args = Array.from(arguments).slice(1); - } + return this.eval(groupFunction, this._groupFixParms(parmsObj)); +}; - var res = this._dbCommand(cmd); +DB.prototype._groupFixParms = function(parmsObj) { + var parms = Object.extend({}, parmsObj); - if (!res.ok) - throw _getErrorWithCode(res, tojson(res)); + if (parms.reduce) { + parms.$reduce = parms.reduce; // must have $ to pass to db + delete parms.reduce; + } - return res.retval; - }; + if (parms.keyf) { + parms.$keyf = parms.keyf; + delete parms.keyf; + } - DB.prototype.dbEval = DB.prototype.eval; - - /** - * <p> - * An array of grouped items is returned. The array must fit in RAM, thus this function is not - * suitable when the return set is extremely large. - * </p> - * <p> - * To order the grouped data, simply sort it client side upon return. - * <p> - Defaults - cond may be null if you want to run against all rows in the collection - keyf is a function which takes an object and returns the desired key. set either key or - keyf (not both). - * </p> - */ - DB.prototype.groupeval = function(parmsObj) { - - var groupFunction = function() { - var parms = args[0]; - var c = db[parms.ns].find(parms.cond || {}); - var map = new Map(); - var pks = parms.key ? Object.keySet(parms.key) : null; - var pkl = pks ? pks.length : 0; - var key = {}; - - while (c.hasNext()) { - var obj = c.next(); - if (pks) { - for (var i = 0; i < pkl; i++) { - var k = pks[i]; - key[k] = obj[k]; - } - } else { - key = parms.$keyf(obj); - } + return parms; +}; + +DB.prototype.resetError = function() { + return this.runCommand({reseterror: 1}); +}; + +DB.prototype.forceError = function() { + return this.runCommand({forceerror: 1}); +}; + +DB.prototype.getLastError = function(w, wtimeout) { + var res = this.getLastErrorObj(w, wtimeout); + if (!res.ok) + throw _getErrorWithCode(ret, "getlasterror failed: " + tojson(res)); + return res.err; +}; +DB.prototype.getLastErrorObj = function(w, wtimeout, j) { + var cmd = {getlasterror: 1}; + if (w) { + cmd.w = w; + if (wtimeout) + cmd.wtimeout = wtimeout; + if (j != null) + cmd.j = j; + } + var res = this.runCommand(cmd); + + if (!res.ok) + throw _getErrorWithCode(res, "getlasterror failed: " + tojson(res)); + return res; +}; +DB.prototype.getLastErrorCmd = DB.prototype.getLastErrorObj; + +DB.prototype._getCollectionInfosCommand = function( + filter, nameOnly = false, authorizedCollections = false, options = {}) { + filter = filter || {}; + const cmd = { + listCollections: 1, + filter: filter, + nameOnly: nameOnly, + authorizedCollections: authorizedCollections + }; + + const res = this.runCommand(Object.merge(cmd, options)); + if (!res.ok) { + throw _getErrorWithCode(res, "listCollections failed: " + tojson(res)); + } - var aggObj = map.get(key); - if (aggObj == null) { - var newObj = Object.extend({}, key); // clone - aggObj = Object.extend(newObj, parms.initial); - map.put(key, aggObj); - } - parms.$reduce(obj, aggObj); - } + return new DBCommandCursor(this, res).toArray().sort(compareOn("name")); +}; - return map.values(); - }; +DB.prototype._getCollectionInfosFromPrivileges = function() { + let ret = this.runCommand({connectionStatus: 1, showPrivileges: 1}); + if (!ret.ok) { + throw _getErrorWithCode(res, "Failed to acquire collection information from privileges"); + } - return this.eval(groupFunction, this._groupFixParms(parmsObj)); - }; + // Parse apart collection information. + let result = []; - DB.prototype._groupFixParms = function(parmsObj) { - var parms = Object.extend({}, parmsObj); + let privileges = ret.authInfo.authenticatedUserPrivileges; + if (privileges === undefined) { + return result; + } - if (parms.reduce) { - parms.$reduce = parms.reduce; // must have $ to pass to db - delete parms.reduce; + privileges.forEach(privilege => { + let resource = privilege.resource; + if (resource === undefined) { + return; } - - if (parms.keyf) { - parms.$keyf = parms.keyf; - delete parms.keyf; + let db = resource.db; + if (db === undefined || db !== this.getName()) { + return; } - - return parms; - }; - - DB.prototype.resetError = function() { - return this.runCommand({reseterror: 1}); - }; - - DB.prototype.forceError = function() { - return this.runCommand({forceerror: 1}); - }; - - DB.prototype.getLastError = function(w, wtimeout) { - var res = this.getLastErrorObj(w, wtimeout); - if (!res.ok) - throw _getErrorWithCode(ret, "getlasterror failed: " + tojson(res)); - return res.err; - }; - DB.prototype.getLastErrorObj = function(w, wtimeout, j) { - var cmd = {getlasterror: 1}; - if (w) { - cmd.w = w; - if (wtimeout) - cmd.wtimeout = wtimeout; - if (j != null) - cmd.j = j; + let collection = resource.collection; + if (collection === undefined || typeof collection !== "string" || collection === "") { + return; } - var res = this.runCommand(cmd); - if (!res.ok) - throw _getErrorWithCode(res, "getlasterror failed: " + tojson(res)); - return res; - }; - DB.prototype.getLastErrorCmd = DB.prototype.getLastErrorObj; - - DB.prototype._getCollectionInfosCommand = function( - filter, nameOnly = false, authorizedCollections = false, options = {}) { - filter = filter || {}; - const cmd = { - listCollections: 1, - filter: filter, - nameOnly: nameOnly, - authorizedCollections: authorizedCollections - }; - - const res = this.runCommand(Object.merge(cmd, options)); - if (!res.ok) { - throw _getErrorWithCode(res, "listCollections failed: " + tojson(res)); + result.push({name: collection}); + }); + + return result.sort(compareOn("name")); +}; + +/** + * Returns a list that contains the names and options of this database's collections, sorted + * by collection name. An optional filter can be specified to match only collections with + * certain metadata. + */ +DB.prototype.getCollectionInfos = function( + filter, nameOnly = false, authorizedCollections = false) { + try { + return this._getCollectionInfosCommand(filter, nameOnly, authorizedCollections); + } catch (ex) { + if (ex.code !== ErrorCodes.Unauthorized) { + // We cannot recover from this error, propagate it. + throw ex; } - return new DBCommandCursor(this, res).toArray().sort(compareOn("name")); - }; + // We may be able to compute a set of *some* collections which exist and we have access + // to from our privileges. For this to work, the previous operation must have failed due + // to authorization, we must be attempting to recover the names of our own collections, + // and no filter can have been provided. - DB.prototype._getCollectionInfosFromPrivileges = function() { - let ret = this.runCommand({connectionStatus: 1, showPrivileges: 1}); - if (!ret.ok) { - throw _getErrorWithCode(res, - "Failed to acquire collection information from privileges"); + if (nameOnly && authorizedCollections && Object.getOwnPropertyNames(filter).length === 0 && + ex.code === ErrorCodes.Unauthorized) { + print( + "Warning: unable to run listCollections, attempting to approximate collection names by parsing connectionStatus"); + return this._getCollectionInfosFromPrivileges(); } - // Parse apart collection information. - let result = []; + throw ex; + } +}; + +DB.prototype._getCollectionNamesInternal = function(options) { + return this._getCollectionInfosCommand({}, true, true, options).map(function(infoObj) { + return infoObj.name; + }); +}; + +/** + * Returns this database's list of collection names in sorted order. + */ +DB.prototype.getCollectionNames = function() { + return this._getCollectionNamesInternal({}); +}; + +DB.prototype.tojson = function() { + return this._name; +}; + +DB.prototype.toString = function() { + return this._name; +}; + +DB.prototype.isMaster = function() { + return this.runCommand("isMaster"); +}; + +var commandUnsupported = function(res) { + return (!res.ok && + (res.errmsg.startsWith("no such cmd") || res.errmsg.startsWith("no such command") || + res.code === 59 /* CommandNotFound */)); +}; + +DB.prototype.currentOp = function(arg) { + var q = {}; + if (arg) { + if (typeof (arg) == "object") + Object.extend(q, arg); + else if (arg) + q["$all"] = true; + } - let privileges = ret.authInfo.authenticatedUserPrivileges; - if (privileges === undefined) { - return result; + var commandObj = {"currentOp": 1}; + Object.extend(commandObj, q); + var res = this.adminCommand(commandObj); + if (commandUnsupported(res)) { + // always send legacy currentOp with default (null) read preference (SERVER-17951) + const session = this.getSession(); + const readPreference = session.getOptions().getReadPreference(); + try { + session.getOptions().setReadPreference(null); + res = this.getSiblingDB("admin").$cmd.sys.inprog.findOne(q); + } finally { + session.getOptions().setReadPreference(readPreference); } - - privileges.forEach(privilege => { - let resource = privilege.resource; - if (resource === undefined) { - return; - } - let db = resource.db; - if (db === undefined || db !== this.getName()) { - return; - } - let collection = resource.collection; - if (collection === undefined || typeof collection !== "string" || collection === "") { - return; - } - - result.push({name: collection}); - }); - - return result.sort(compareOn("name")); - }; - - /** - * Returns a list that contains the names and options of this database's collections, sorted - * by collection name. An optional filter can be specified to match only collections with - * certain metadata. - */ - DB.prototype.getCollectionInfos = function( - filter, nameOnly = false, authorizedCollections = false) { + } + return res; +}; +DB.prototype.currentOP = DB.prototype.currentOp; + +DB.prototype.killOp = function(op) { + if (!op) + throw Error("no opNum to kill specified"); + var res = this.adminCommand({'killOp': 1, 'op': op}); + if (commandUnsupported(res)) { + // fall back for old servers + const session = this.getSession(); + const readPreference = session.getOptions().getReadPreference(); try { - return this._getCollectionInfosCommand(filter, nameOnly, authorizedCollections); - } catch (ex) { - if (ex.code !== ErrorCodes.Unauthorized) { - // We cannot recover from this error, propagate it. - throw ex; - } - - // We may be able to compute a set of *some* collections which exist and we have access - // to from our privileges. For this to work, the previous operation must have failed due - // to authorization, we must be attempting to recover the names of our own collections, - // and no filter can have been provided. - - if (nameOnly && authorizedCollections && - Object.getOwnPropertyNames(filter).length === 0 && - ex.code === ErrorCodes.Unauthorized) { - print( - "Warning: unable to run listCollections, attempting to approximate collection names by parsing connectionStatus"); - return this._getCollectionInfosFromPrivileges(); - } - - throw ex; + session.getOptions().setReadPreference(null); + res = this.getSiblingDB("admin").$cmd.sys.killop.findOne({'op': op}); + } finally { + session.getOptions().setReadPreference(readPreference); } - }; - - DB.prototype._getCollectionNamesInternal = function(options) { - return this._getCollectionInfosCommand({}, true, true, options).map(function(infoObj) { - return infoObj.name; - }); - }; - - /** - * Returns this database's list of collection names in sorted order. - */ - DB.prototype.getCollectionNames = function() { - return this._getCollectionNamesInternal({}); - }; + } + return res; +}; +DB.prototype.killOP = DB.prototype.killOp; + +DB.tsToSeconds = function(x) { + if (x.t && x.i) + return x.t; + return x / 4294967296; // low 32 bits are ordinal #s within a second +}; + +/** + Get a replication log information summary. + <p> + This command is for the database/cloud administer and not applicable to most databases. + It is only used with the local database. One might invoke from the JS shell: + <pre> + use local + db.getReplicationInfo(); + </pre> + * @return Object timeSpan: time span of the oplog from start to end if slave is more out + * of date than that, it can't recover without a complete resync +*/ +DB.prototype.getReplicationInfo = function() { + var localdb = this.getSiblingDB("local"); + + var result = {}; + var oplog; + var localCollections = localdb.getCollectionNames(); + if (localCollections.indexOf('oplog.rs') >= 0) { + oplog = 'oplog.rs'; + } else { + result.errmsg = "replication not detected"; + return result; + } - DB.prototype.tojson = function() { - return this._name; - }; + var ol = localdb.getCollection(oplog); + var ol_stats = ol.stats(); + if (ol_stats && ol_stats.maxSize) { + result.logSizeMB = ol_stats.maxSize / (1024 * 1024); + } else { + result.errmsg = "Could not get stats for local." + oplog + " collection. " + + "collstats returned: " + tojson(ol_stats); + return result; + } - DB.prototype.toString = function() { - return this._name; - }; + result.usedMB = ol_stats.size / (1024 * 1024); + result.usedMB = Math.ceil(result.usedMB * 100) / 100; - DB.prototype.isMaster = function() { - return this.runCommand("isMaster"); - }; + var firstc = ol.find().sort({$natural: 1}).limit(1); + var lastc = ol.find().sort({$natural: -1}).limit(1); + if (!firstc.hasNext() || !lastc.hasNext()) { + result.errmsg = + "objects not found in local.oplog.$main -- is this a new and empty db instance?"; + result.oplogMainRowCount = ol.count(); + return result; + } - var commandUnsupported = function(res) { - return (!res.ok && - (res.errmsg.startsWith("no such cmd") || res.errmsg.startsWith("no such command") || - res.code === 59 /* CommandNotFound */)); - }; + var first = firstc.next(); + var last = lastc.next(); + var tfirst = first.ts; + var tlast = last.ts; + + if (tfirst && tlast) { + tfirst = DB.tsToSeconds(tfirst); + tlast = DB.tsToSeconds(tlast); + result.timeDiff = tlast - tfirst; + result.timeDiffHours = Math.round(result.timeDiff / 36) / 100; + result.tFirst = (new Date(tfirst * 1000)).toString(); + result.tLast = (new Date(tlast * 1000)).toString(); + result.now = Date(); + } else { + result.errmsg = "ts element not found in oplog objects"; + } - DB.prototype.currentOp = function(arg) { - var q = {}; - if (arg) { - if (typeof(arg) == "object") - Object.extend(q, arg); - else if (arg) - q["$all"] = true; - } + return result; +}; - var commandObj = {"currentOp": 1}; - Object.extend(commandObj, q); - var res = this.adminCommand(commandObj); - if (commandUnsupported(res)) { - // always send legacy currentOp with default (null) read preference (SERVER-17951) - const session = this.getSession(); - const readPreference = session.getOptions().getReadPreference(); - try { - session.getOptions().setReadPreference(null); - res = this.getSiblingDB("admin").$cmd.sys.inprog.findOne(q); - } finally { - session.getOptions().setReadPreference(readPreference); - } - } - return res; - }; - DB.prototype.currentOP = DB.prototype.currentOp; - - DB.prototype.killOp = function(op) { - if (!op) - throw Error("no opNum to kill specified"); - var res = this.adminCommand({'killOp': 1, 'op': op}); - if (commandUnsupported(res)) { - // fall back for old servers - const session = this.getSession(); - const readPreference = session.getOptions().getReadPreference(); - try { - session.getOptions().setReadPreference(null); - res = this.getSiblingDB("admin").$cmd.sys.killop.findOne({'op': op}); - } finally { - session.getOptions().setReadPreference(readPreference); - } +DB.prototype.printReplicationInfo = function() { + var result = this.getReplicationInfo(); + if (result.errmsg) { + var isMaster = this.isMaster(); + if (isMaster.arbiterOnly) { + print("cannot provide replication status from an arbiter."); + return; + } else if (!isMaster.ismaster) { + print("this is a slave, printing slave replication info."); + this.printSlaveReplicationInfo(); + return; } - return res; - }; - DB.prototype.killOP = DB.prototype.killOp; - - DB.tsToSeconds = function(x) { - if (x.t && x.i) - return x.t; - return x / 4294967296; // low 32 bits are ordinal #s within a second - }; - - /** - Get a replication log information summary. - <p> - This command is for the database/cloud administer and not applicable to most databases. - It is only used with the local database. One might invoke from the JS shell: - <pre> - use local - db.getReplicationInfo(); - </pre> - * @return Object timeSpan: time span of the oplog from start to end if slave is more out - * of date than that, it can't recover without a complete resync - */ - DB.prototype.getReplicationInfo = function() { - var localdb = this.getSiblingDB("local"); - - var result = {}; - var oplog; - var localCollections = localdb.getCollectionNames(); - if (localCollections.indexOf('oplog.rs') >= 0) { - oplog = 'oplog.rs'; + print(tojson(result)); + return; + } + print("configured oplog size: " + result.logSizeMB + "MB"); + print("log length start to end: " + result.timeDiff + "secs (" + result.timeDiffHours + "hrs)"); + print("oplog first event time: " + result.tFirst); + print("oplog last event time: " + result.tLast); + print("now: " + result.now); +}; + +DB.prototype.printSlaveReplicationInfo = function() { + var startOptimeDate = null; + var primary = null; + + function getReplLag(st) { + assert(startOptimeDate, "how could this be null (getReplLag startOptimeDate)"); + print("\tsyncedTo: " + st.toString()); + var ago = (startOptimeDate - st) / 1000; + var hrs = Math.round(ago / 36) / 100; + var suffix = ""; + if (primary) { + suffix = "primary "; } else { - result.errmsg = "replication not detected"; - return result; + suffix = "freshest member (no primary available at the moment)"; } + print("\t" + Math.round(ago) + " secs (" + hrs + " hrs) behind the " + suffix); + } - var ol = localdb.getCollection(oplog); - var ol_stats = ol.stats(); - if (ol_stats && ol_stats.maxSize) { - result.logSizeMB = ol_stats.maxSize / (1024 * 1024); - } else { - result.errmsg = "Could not get stats for local." + oplog + " collection. " + - "collstats returned: " + tojson(ol_stats); - return result; + function getMaster(members) { + for (i in members) { + var row = members[i]; + if (row.state === 1) { + return row; + } } - result.usedMB = ol_stats.size / (1024 * 1024); - result.usedMB = Math.ceil(result.usedMB * 100) / 100; - - var firstc = ol.find().sort({$natural: 1}).limit(1); - var lastc = ol.find().sort({$natural: -1}).limit(1); - if (!firstc.hasNext() || !lastc.hasNext()) { - result.errmsg = - "objects not found in local.oplog.$main -- is this a new and empty db instance?"; - result.oplogMainRowCount = ol.count(); - return result; - } + return null; + } - var first = firstc.next(); - var last = lastc.next(); - var tfirst = first.ts; - var tlast = last.ts; - - if (tfirst && tlast) { - tfirst = DB.tsToSeconds(tfirst); - tlast = DB.tsToSeconds(tlast); - result.timeDiff = tlast - tfirst; - result.timeDiffHours = Math.round(result.timeDiff / 36) / 100; - result.tFirst = (new Date(tfirst * 1000)).toString(); - result.tLast = (new Date(tlast * 1000)).toString(); - result.now = Date(); + function g(x) { + assert(x, "how could this be null (printSlaveReplicationInfo gx)"); + print("source: " + x.host); + if (x.syncedTo) { + var st = new Date(DB.tsToSeconds(x.syncedTo) * 1000); + getReplLag(st); } else { - result.errmsg = "ts element not found in oplog objects"; + print("\tdoing initial sync"); } + } - return result; - }; - - DB.prototype.printReplicationInfo = function() { - var result = this.getReplicationInfo(); - if (result.errmsg) { - var isMaster = this.isMaster(); - if (isMaster.arbiterOnly) { - print("cannot provide replication status from an arbiter."); - return; - } else if (!isMaster.ismaster) { - print("this is a slave, printing slave replication info."); - this.printSlaveReplicationInfo(); - return; - } - print(tojson(result)); + function r(x) { + assert(x, "how could this be null (printSlaveReplicationInfo rx)"); + if (x.state == 1 || x.state == 7) { // ignore primaries (1) and arbiters (7) return; } - print("configured oplog size: " + result.logSizeMB + "MB"); - print("log length start to end: " + result.timeDiff + "secs (" + result.timeDiffHours + - "hrs)"); - print("oplog first event time: " + result.tFirst); - print("oplog last event time: " + result.tLast); - print("now: " + result.now); - }; - DB.prototype.printSlaveReplicationInfo = function() { - var startOptimeDate = null; - var primary = null; - - function getReplLag(st) { - assert(startOptimeDate, "how could this be null (getReplLag startOptimeDate)"); - print("\tsyncedTo: " + st.toString()); - var ago = (startOptimeDate - st) / 1000; - var hrs = Math.round(ago / 36) / 100; - var suffix = ""; - if (primary) { - suffix = "primary "; - } else { - suffix = "freshest member (no primary available at the moment)"; - } - print("\t" + Math.round(ago) + " secs (" + hrs + " hrs) behind the " + suffix); + print("source: " + x.name); + if (x.optime) { + getReplLag(x.optimeDate); + } else { + print("\tno replication info, yet. State: " + x.stateStr); } + } - function getMaster(members) { - for (i in members) { - var row = members[i]; - if (row.state === 1) { - return row; - } - } + var L = this.getSiblingDB("local"); - return null; + if (L.system.replset.count() != 0) { + var status = this.adminCommand({'replSetGetStatus': 1}); + primary = getMaster(status.members); + if (primary) { + startOptimeDate = primary.optimeDate; } - - function g(x) { - assert(x, "how could this be null (printSlaveReplicationInfo gx)"); - print("source: " + x.host); - if (x.syncedTo) { - var st = new Date(DB.tsToSeconds(x.syncedTo) * 1000); - getReplLag(st); - } else { - print("\tdoing initial sync"); + // no primary, find the most recent op among all members + else { + startOptimeDate = new Date(0, 0); + for (i in status.members) { + if (status.members[i].optimeDate > startOptimeDate) { + startOptimeDate = status.members[i].optimeDate; + } } } - function r(x) { - assert(x, "how could this be null (printSlaveReplicationInfo rx)"); - if (x.state == 1 || x.state == 7) { // ignore primaries (1) and arbiters (7) - return; - } - - print("source: " + x.name); - if (x.optime) { - getReplLag(x.optimeDate); - } else { - print("\tno replication info, yet. State: " + x.stateStr); - } + for (i in status.members) { + r(status.members[i]); } - - var L = this.getSiblingDB("local"); - - if (L.system.replset.count() != 0) { - var status = this.adminCommand({'replSetGetStatus': 1}); - primary = getMaster(status.members); - if (primary) { - startOptimeDate = primary.optimeDate; - } - // no primary, find the most recent op among all members - else { - startOptimeDate = new Date(0, 0); - for (i in status.members) { - if (status.members[i].optimeDate > startOptimeDate) { - startOptimeDate = status.members[i].optimeDate; - } - } - } - - for (i in status.members) { - r(status.members[i]); + } +}; + +DB.prototype.serverBuildInfo = function() { + return this._adminCommand("buildinfo"); +}; + +// Used to trim entries from the metrics.commands that have never been executed +getActiveCommands = function(tree) { + var result = {}; + for (var i in tree) { + if (!tree.hasOwnProperty(i)) + continue; + if (tree[i].hasOwnProperty("total")) { + if (tree[i].total > 0) { + result[i] = tree[i]; } + continue; } - }; - - DB.prototype.serverBuildInfo = function() { - return this._adminCommand("buildinfo"); - }; - - // Used to trim entries from the metrics.commands that have never been executed - getActiveCommands = function(tree) { - var result = {}; - for (var i in tree) { - if (!tree.hasOwnProperty(i)) - continue; - if (tree[i].hasOwnProperty("total")) { - if (tree[i].total > 0) { - result[i] = tree[i]; - } - continue; - } - if (i == "<UNKNOWN>") { - if (tree[i] > 0) { - result[i] = tree[i]; - } - continue; - } - // Handles nested commands - var subStatus = getActiveCommands(tree[i]); - if (Object.keys(subStatus).length > 0) { + if (i == "<UNKNOWN>") { + if (tree[i] > 0) { result[i] = tree[i]; } + continue; } - return result; - }; - - DB.prototype.serverStatus = function(options) { - var cmd = {serverStatus: 1}; - if (options) { - Object.extend(cmd, options); + // Handles nested commands + var subStatus = getActiveCommands(tree[i]); + if (Object.keys(subStatus).length > 0) { + result[i] = tree[i]; } - var res = this._adminCommand(cmd); - // Only prune if we have a metrics tree with commands. - if (res.metrics && res.metrics.commands) { - res.metrics.commands = getActiveCommands(res.metrics.commands); - } - return res; - }; + } + return result; +}; - DB.prototype.hostInfo = function() { - return this._adminCommand("hostInfo"); - }; +DB.prototype.serverStatus = function(options) { + var cmd = {serverStatus: 1}; + if (options) { + Object.extend(cmd, options); + } + var res = this._adminCommand(cmd); + // Only prune if we have a metrics tree with commands. + if (res.metrics && res.metrics.commands) { + res.metrics.commands = getActiveCommands(res.metrics.commands); + } + return res; +}; - DB.prototype.serverCmdLineOpts = function() { - return this._adminCommand("getCmdLineOpts"); - }; +DB.prototype.hostInfo = function() { + return this._adminCommand("hostInfo"); +}; - DB.prototype.version = function() { - return this.serverBuildInfo().version; - }; +DB.prototype.serverCmdLineOpts = function() { + return this._adminCommand("getCmdLineOpts"); +}; - DB.prototype.serverBits = function() { - return this.serverBuildInfo().bits; - }; +DB.prototype.version = function() { + return this.serverBuildInfo().version; +}; - DB.prototype.listCommands = function() { - var x = this.runCommand("listCommands"); - for (var name in x.commands) { - var c = x.commands[name]; +DB.prototype.serverBits = function() { + return this.serverBuildInfo().bits; +}; - var s = name + ": "; +DB.prototype.listCommands = function() { + var x = this.runCommand("listCommands"); + for (var name in x.commands) { + var c = x.commands[name]; - if (c.adminOnly) - s += " adminOnly "; - if (c.slaveOk) - s += " slaveOk "; + var s = name + ": "; - s += "\n "; - s += c.help.replace(/\n/g, '\n '); - s += "\n"; + if (c.adminOnly) + s += " adminOnly "; + if (c.slaveOk) + s += " slaveOk "; - print(s); - } - }; + s += "\n "; + s += c.help.replace(/\n/g, '\n '); + s += "\n"; - DB.prototype.printShardingStatus = function(verbose) { - printShardingStatus(this.getSiblingDB("config"), verbose); - }; + print(s); + } +}; - DB.prototype.fsyncLock = function() { - return this.adminCommand({fsync: 1, lock: true}); - }; +DB.prototype.printShardingStatus = function(verbose) { + printShardingStatus(this.getSiblingDB("config"), verbose); +}; - DB.prototype.fsyncUnlock = function() { - var res = this.adminCommand({fsyncUnlock: 1}); - if (commandUnsupported(res)) { - const session = this.getSession(); - const readPreference = session.getOptions().getReadPreference(); - try { - session.getOptions().setReadPreference(null); - res = this.getSiblingDB("admin").$cmd.sys.unlock.findOne(); - } finally { - session.getOptions().setReadPreference(readPreference); - } - } - return res; - }; +DB.prototype.fsyncLock = function() { + return this.adminCommand({fsync: 1, lock: true}); +}; - DB.autocomplete = function(obj) { - // Time out if a transaction or other op holds locks we need. Caller suppresses exceptions. - var colls = obj._getCollectionNamesInternal({maxTimeMS: 1000}); - var ret = []; - for (var i = 0; i < colls.length; i++) { - if (colls[i].match(/^[a-zA-Z0-9_.\$]+$/)) - ret.push(colls[i]); +DB.prototype.fsyncUnlock = function() { + var res = this.adminCommand({fsyncUnlock: 1}); + if (commandUnsupported(res)) { + const session = this.getSession(); + const readPreference = session.getOptions().getReadPreference(); + try { + session.getOptions().setReadPreference(null); + res = this.getSiblingDB("admin").$cmd.sys.unlock.findOne(); + } finally { + session.getOptions().setReadPreference(readPreference); } - return ret; - }; - - DB.prototype.setSlaveOk = function(value) { - if (value == undefined) - value = true; - this._slaveOk = value; - }; - - DB.prototype.getSlaveOk = function() { - if (this._slaveOk != undefined) - return this._slaveOk; - return this._mongo.getSlaveOk(); - }; - - DB.prototype.getQueryOptions = function() { - var options = 0; - if (this.getSlaveOk()) - options |= 4; - return options; - }; - - /* Loads any scripts contained in system.js into the client shell. - */ - DB.prototype.loadServerScripts = function() { - var global = Function('return this')(); - this.system.js.find().forEach(function(u) { - if (u.value.constructor === Code) { - global[u._id] = eval("(" + u.value.code + ")"); - } else { - global[u._id] = u.value; - } - }); - }; - - //////////////////////////////////////////////////////////////////////////////////////////////////// - //////////////////////////// Security shell helpers below - ///////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////////////////////////// - - function getUserObjString(userObj) { - var pwd = userObj.pwd; - delete userObj.pwd; - var toreturn = tojson(userObj); - userObj.pwd = pwd; - return toreturn; } - - DB.prototype._modifyCommandToDigestPasswordIfNecessary = function(cmdObj, username) { - if (!cmdObj["pwd"]) { - return; - } - if (cmdObj.hasOwnProperty("digestPassword")) { - throw Error( - "Cannot specify 'digestPassword' through the user management shell helpers, " + - "use 'passwordDigestor' instead"); - } - var passwordDigestor = cmdObj["passwordDigestor"] ? cmdObj["passwordDigestor"] : "server"; - if (passwordDigestor == "server") { - cmdObj["digestPassword"] = true; - } else if (passwordDigestor == "client") { - cmdObj["pwd"] = _hashPassword(username, cmdObj["pwd"]); - cmdObj["digestPassword"] = false; + return res; +}; + +DB.autocomplete = function(obj) { + // Time out if a transaction or other op holds locks we need. Caller suppresses exceptions. + var colls = obj._getCollectionNamesInternal({maxTimeMS: 1000}); + var ret = []; + for (var i = 0; i < colls.length; i++) { + if (colls[i].match(/^[a-zA-Z0-9_.\$]+$/)) + ret.push(colls[i]); + } + return ret; +}; + +DB.prototype.setSlaveOk = function(value) { + if (value == undefined) + value = true; + this._slaveOk = value; +}; + +DB.prototype.getSlaveOk = function() { + if (this._slaveOk != undefined) + return this._slaveOk; + return this._mongo.getSlaveOk(); +}; + +DB.prototype.getQueryOptions = function() { + var options = 0; + if (this.getSlaveOk()) + options |= 4; + return options; +}; + +/* Loads any scripts contained in system.js into the client shell. + */ +DB.prototype.loadServerScripts = function() { + var global = Function('return this')(); + this.system.js.find().forEach(function(u) { + if (u.value.constructor === Code) { + global[u._id] = eval("(" + u.value.code + ")"); } else { - throw Error("'passwordDigestor' must be either 'server' or 'client', got: '" + - passwordDigestor + "'"); - } - delete cmdObj["passwordDigestor"]; - }; + global[u._id] = u.value; + } + }); +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////// Security shell helpers below +///////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +function getUserObjString(userObj) { + var pwd = userObj.pwd; + delete userObj.pwd; + var toreturn = tojson(userObj); + userObj.pwd = pwd; + return toreturn; +} + +DB.prototype._modifyCommandToDigestPasswordIfNecessary = function(cmdObj, username) { + if (!cmdObj["pwd"]) { + return; + } + if (cmdObj.hasOwnProperty("digestPassword")) { + throw Error("Cannot specify 'digestPassword' through the user management shell helpers, " + + "use 'passwordDigestor' instead"); + } + var passwordDigestor = cmdObj["passwordDigestor"] ? cmdObj["passwordDigestor"] : "server"; + if (passwordDigestor == "server") { + cmdObj["digestPassword"] = true; + } else if (passwordDigestor == "client") { + cmdObj["pwd"] = _hashPassword(username, cmdObj["pwd"]); + cmdObj["digestPassword"] = false; + } else { + throw Error("'passwordDigestor' must be either 'server' or 'client', got: '" + + passwordDigestor + "'"); + } + delete cmdObj["passwordDigestor"]; +}; - DB.prototype.createUser = function(userObj, writeConcern) { - var name = userObj["user"]; - if (name === undefined) { - throw Error("no 'user' field provided to 'createUser' function"); - } +DB.prototype.createUser = function(userObj, writeConcern) { + var name = userObj["user"]; + if (name === undefined) { + throw Error("no 'user' field provided to 'createUser' function"); + } - if (userObj["createUser"] !== undefined) { - throw Error("calling 'createUser' function with 'createUser' field is disallowed"); - } + if (userObj["createUser"] !== undefined) { + throw Error("calling 'createUser' function with 'createUser' field is disallowed"); + } - var cmdObj = {createUser: name}; - cmdObj = Object.extend(cmdObj, userObj); - delete cmdObj["user"]; + var cmdObj = {createUser: name}; + cmdObj = Object.extend(cmdObj, userObj); + delete cmdObj["user"]; - this._modifyCommandToDigestPasswordIfNecessary(cmdObj, name); + this._modifyCommandToDigestPasswordIfNecessary(cmdObj, name); - cmdObj["writeConcern"] = writeConcern ? writeConcern : _defaultWriteConcern; + cmdObj["writeConcern"] = writeConcern ? writeConcern : _defaultWriteConcern; - var res = this.runCommand(cmdObj); + var res = this.runCommand(cmdObj); - if (res.ok) { - print("Successfully added user: " + getUserObjString(userObj)); - return; - } + if (res.ok) { + print("Successfully added user: " + getUserObjString(userObj)); + return; + } - if (res.errmsg == "no such cmd: createUser") { - throw Error("'createUser' command not found. This is most likely because you are " + - "talking to an old (pre v2.6) MongoDB server"); - } + if (res.errmsg == "no such cmd: createUser") { + throw Error("'createUser' command not found. This is most likely because you are " + + "talking to an old (pre v2.6) MongoDB server"); + } - if (res.errmsg == "timeout") { - throw Error("timed out while waiting for user authentication to replicate - " + - "database will not be fully secured until replication finishes"); - } + if (res.errmsg == "timeout") { + throw Error("timed out while waiting for user authentication to replicate - " + + "database will not be fully secured until replication finishes"); + } - throw _getErrorWithCode(res, "couldn't add user: " + res.errmsg); - }; + throw _getErrorWithCode(res, "couldn't add user: " + res.errmsg); +}; - function _hashPassword(username, password) { - if (typeof password != 'string') { - throw Error("User passwords must be of type string. Was given password with type: " + - typeof(password)); - } - return hex_md5(username + ":mongo:" + password); +function _hashPassword(username, password) { + if (typeof password != 'string') { + throw Error("User passwords must be of type string. Was given password with type: " + + typeof (password)); + } + return hex_md5(username + ":mongo:" + password); +} + +/** + * Used for updating users in systems with V1 style user information + * (ie MongoDB v2.4 and prior) + */ +DB.prototype._updateUserV1 = function(name, updateObject, writeConcern) { + var setObj = {}; + if (updateObject.pwd) { + setObj["pwd"] = _hashPassword(name, updateObject.pwd); + } + if (updateObject.extraData) { + setObj["extraData"] = updateObject.extraData; + } + if (updateObject.roles) { + setObj["roles"] = updateObject.roles; } - /** - * Used for updating users in systems with V1 style user information - * (ie MongoDB v2.4 and prior) - */ - DB.prototype._updateUserV1 = function(name, updateObject, writeConcern) { - var setObj = {}; - if (updateObject.pwd) { - setObj["pwd"] = _hashPassword(name, updateObject.pwd); - } - if (updateObject.extraData) { - setObj["extraData"] = updateObject.extraData; - } - if (updateObject.roles) { - setObj["roles"] = updateObject.roles; - } + this.system.users.update({user: name, userSource: null}, {$set: setObj}); + var errObj = this.getLastErrorObj(writeConcern['w'], writeConcern['wtimeout']); + if (errObj.err) { + throw _getErrorWithCode(errObj, "Updating user failed: " + errObj.err); + } +}; - this.system.users.update({user: name, userSource: null}, {$set: setObj}); - var errObj = this.getLastErrorObj(writeConcern['w'], writeConcern['wtimeout']); - if (errObj.err) { - throw _getErrorWithCode(errObj, "Updating user failed: " + errObj.err); - } - }; +DB.prototype.updateUser = function(name, updateObject, writeConcern) { + var cmdObj = {updateUser: name}; + cmdObj = Object.extend(cmdObj, updateObject); + cmdObj['writeConcern'] = writeConcern ? writeConcern : _defaultWriteConcern; + this._modifyCommandToDigestPasswordIfNecessary(cmdObj, name); - DB.prototype.updateUser = function(name, updateObject, writeConcern) { - var cmdObj = {updateUser: name}; - cmdObj = Object.extend(cmdObj, updateObject); - cmdObj['writeConcern'] = writeConcern ? writeConcern : _defaultWriteConcern; - this._modifyCommandToDigestPasswordIfNecessary(cmdObj, name); + var res = this.runCommand(cmdObj); + if (res.ok) { + return; + } - var res = this.runCommand(cmdObj); - if (res.ok) { - return; - } + if (res.errmsg == "no such cmd: updateUser") { + this._updateUserV1(name, updateObject, cmdObj['writeConcern']); + return; + } - if (res.errmsg == "no such cmd: updateUser") { - this._updateUserV1(name, updateObject, cmdObj['writeConcern']); - return; - } + throw _getErrorWithCode(res, "Updating user failed: " + res.errmsg); +}; - throw _getErrorWithCode(res, "Updating user failed: " + res.errmsg); - }; +DB.prototype.changeUserPassword = function(username, password, writeConcern) { + this.updateUser(username, {pwd: password}, writeConcern); +}; - DB.prototype.changeUserPassword = function(username, password, writeConcern) { - this.updateUser(username, {pwd: password}, writeConcern); - }; +DB.prototype.logout = function() { + // Logging out doesn't require a session since it manipulates connection state. + return this.getMongo().logout(this.getName()); +}; - DB.prototype.logout = function() { - // Logging out doesn't require a session since it manipulates connection state. - return this.getMongo().logout(this.getName()); - }; +// For backwards compatibility +DB.prototype.removeUser = function(username, writeConcern) { + print("WARNING: db.removeUser has been deprecated, please use db.dropUser instead"); + return this.dropUser(username, writeConcern); +}; - // For backwards compatibility - DB.prototype.removeUser = function(username, writeConcern) { - print("WARNING: db.removeUser has been deprecated, please use db.dropUser instead"); - return this.dropUser(username, writeConcern); +DB.prototype.dropUser = function(username, writeConcern) { + var cmdObj = { + dropUser: username, + writeConcern: writeConcern ? writeConcern : _defaultWriteConcern }; + var res = this.runCommand(cmdObj); - DB.prototype.dropUser = function(username, writeConcern) { - var cmdObj = { - dropUser: username, - writeConcern: writeConcern ? writeConcern : _defaultWriteConcern - }; - var res = this.runCommand(cmdObj); - - if (res.ok) { - return true; - } + if (res.ok) { + return true; + } - if (res.code == 11) { // Code 11 = UserNotFound - return false; - } + if (res.code == 11) { // Code 11 = UserNotFound + return false; + } - if (res.errmsg == "no such cmd: dropUsers") { - return this._removeUserV1(username, cmdObj['writeConcern']); - } + if (res.errmsg == "no such cmd: dropUsers") { + return this._removeUserV1(username, cmdObj['writeConcern']); + } - throw _getErrorWithCode(res, res.errmsg); - }; + throw _getErrorWithCode(res, res.errmsg); +}; - /** - * Used for removing users in systems with V1 style user information - * (ie MongoDB v2.4 and prior) - */ - DB.prototype._removeUserV1 = function(username, writeConcern) { - this.getCollection("system.users").remove({user: username}); +/** + * Used for removing users in systems with V1 style user information + * (ie MongoDB v2.4 and prior) + */ +DB.prototype._removeUserV1 = function(username, writeConcern) { + this.getCollection("system.users").remove({user: username}); - var le = this.getLastErrorObj(writeConcern['w'], writeConcern['wtimeout']); + var le = this.getLastErrorObj(writeConcern['w'], writeConcern['wtimeout']); - if (le.err) { - throw _getErrorWithCode(le, "Couldn't remove user: " + le.err); - } + if (le.err) { + throw _getErrorWithCode(le, "Couldn't remove user: " + le.err); + } - if (le.n == 1) { - return true; - } else { - return false; - } - }; + if (le.n == 1) { + return true; + } else { + return false; + } +}; - DB.prototype.dropAllUsers = function(writeConcern) { - var res = this.runCommand({ - dropAllUsersFromDatabase: 1, - writeConcern: writeConcern ? writeConcern : _defaultWriteConcern - }); +DB.prototype.dropAllUsers = function(writeConcern) { + var res = this.runCommand({ + dropAllUsersFromDatabase: 1, + writeConcern: writeConcern ? writeConcern : _defaultWriteConcern + }); - if (!res.ok) { - throw _getErrorWithCode(res, res.errmsg); - } + if (!res.ok) { + throw _getErrorWithCode(res, res.errmsg); + } - return res.n; - }; + return res.n; +}; - DB.prototype.__pwHash = function(nonce, username, pass) { - return hex_md5(nonce + username + _hashPassword(username, pass)); - }; +DB.prototype.__pwHash = function(nonce, username, pass) { + return hex_md5(nonce + username + _hashPassword(username, pass)); +}; - DB.prototype._defaultAuthenticationMechanism = null; +DB.prototype._defaultAuthenticationMechanism = null; - DB.prototype._getDefaultAuthenticationMechanism = function(username, database) { - if (username !== undefined) { - const userid = database + "." + username; - const result = this.runCommand({isMaster: 1, saslSupportedMechs: userid}); - if (result.ok && (result.saslSupportedMechs !== undefined)) { - const mechs = result.saslSupportedMechs; - if (!Array.isArray(mechs)) { - throw Error("Server replied with invalid saslSupportedMechs response"); - } +DB.prototype._getDefaultAuthenticationMechanism = function(username, database) { + if (username !== undefined) { + const userid = database + "." + username; + const result = this.runCommand({isMaster: 1, saslSupportedMechs: userid}); + if (result.ok && (result.saslSupportedMechs !== undefined)) { + const mechs = result.saslSupportedMechs; + if (!Array.isArray(mechs)) { + throw Error("Server replied with invalid saslSupportedMechs response"); + } - if ((this._defaultAuthenticationMechanism != null) && - mechs.includes(this._defaultAuthenticationMechanism)) { - return this._defaultAuthenticationMechanism; - } + if ((this._defaultAuthenticationMechanism != null) && + mechs.includes(this._defaultAuthenticationMechanism)) { + return this._defaultAuthenticationMechanism; + } - // Never include PLAIN in auto-negotiation. - const priority = ["GSSAPI", "SCRAM-SHA-256", "SCRAM-SHA-1"]; - for (var i = 0; i < priority.length; ++i) { - if (mechs.includes(priority[i])) { - return priority[i]; - } + // Never include PLAIN in auto-negotiation. + const priority = ["GSSAPI", "SCRAM-SHA-256", "SCRAM-SHA-1"]; + for (var i = 0; i < priority.length; ++i) { + if (mechs.includes(priority[i])) { + return priority[i]; } } - // If isMaster doesn't support saslSupportedMechs, - // or if we couldn't agree on a mechanism, - // then fallthrough to configured default or SCRAM-SHA-1. - } - - // Use the default auth mechanism if set on the command line. - if (this._defaultAuthenticationMechanism != null) - return this._defaultAuthenticationMechanism; - - return "SCRAM-SHA-1"; - }; - - DB.prototype._defaultGssapiServiceName = null; - - DB.prototype._authOrThrow = function() { - var params; - if (arguments.length == 2) { - params = {user: arguments[0], pwd: arguments[1]}; - } else if (arguments.length == 1) { - if (typeof(arguments[0]) != "object") - throw Error("Single-argument form of auth expects a parameter object"); - params = Object.extend({}, arguments[0]); - } else { - throw Error( - "auth expects either (username, password) or ({ user: username, pwd: password })"); - } - - if (params.mechanism === undefined) { - params.mechanism = this._getDefaultAuthenticationMechanism(params.user, this.getName()); - } - - if (params.db !== undefined) { - throw Error("Do not override db field on db.auth(). Use getMongo().auth(), instead."); } + // If isMaster doesn't support saslSupportedMechs, + // or if we couldn't agree on a mechanism, + // then fallthrough to configured default or SCRAM-SHA-1. + } - if (params.mechanism == "GSSAPI" && params.serviceName == null && - this._defaultGssapiServiceName != null) { - params.serviceName = this._defaultGssapiServiceName; - } - - // Logging in doesn't require a session since it manipulates connection state. - params.db = this.getName(); - var good = this.getMongo().auth(params); - if (good) { - // auth enabled, and should try to use isMaster and replSetGetStatus to build prompt - this.getMongo().authStatus = { - authRequired: true, - isMaster: true, - replSetGetStatus: true - }; - } - - return good; - }; - - DB.prototype.auth = function() { - var ex; - try { - this._authOrThrow.apply(this, arguments); - } catch (ex) { - print(ex); - return 0; - } - return 1; - }; - - DB.prototype.grantRolesToUser = function(username, roles, writeConcern) { - var cmdObj = { - grantRolesToUser: username, - roles: roles, - writeConcern: writeConcern ? writeConcern : _defaultWriteConcern - }; - var res = this.runCommand(cmdObj); - if (!res.ok) { - throw _getErrorWithCode(res, res.errmsg); - } - }; + // Use the default auth mechanism if set on the command line. + if (this._defaultAuthenticationMechanism != null) + return this._defaultAuthenticationMechanism; + + return "SCRAM-SHA-1"; +}; + +DB.prototype._defaultGssapiServiceName = null; + +DB.prototype._authOrThrow = function() { + var params; + if (arguments.length == 2) { + params = {user: arguments[0], pwd: arguments[1]}; + } else if (arguments.length == 1) { + if (typeof (arguments[0]) != "object") + throw Error("Single-argument form of auth expects a parameter object"); + params = Object.extend({}, arguments[0]); + } else { + throw Error( + "auth expects either (username, password) or ({ user: username, pwd: password })"); + } - DB.prototype.revokeRolesFromUser = function(username, roles, writeConcern) { - var cmdObj = { - revokeRolesFromUser: username, - roles: roles, - writeConcern: writeConcern ? writeConcern : _defaultWriteConcern - }; - var res = this.runCommand(cmdObj); - if (!res.ok) { - throw _getErrorWithCode(res, res.errmsg); - } - }; + if (params.mechanism === undefined) { + params.mechanism = this._getDefaultAuthenticationMechanism(params.user, this.getName()); + } - DB.prototype.getUser = function(username, args) { - if (typeof username != "string") { - throw Error("User name for getUser shell helper must be a string"); - } - var cmdObj = {usersInfo: username}; - Object.extend(cmdObj, args); + if (params.db !== undefined) { + throw Error("Do not override db field on db.auth(). Use getMongo().auth(), instead."); + } - var res = this.runCommand(cmdObj); - if (!res.ok) { - throw _getErrorWithCode(res, res.errmsg); - } + if (params.mechanism == "GSSAPI" && params.serviceName == null && + this._defaultGssapiServiceName != null) { + params.serviceName = this._defaultGssapiServiceName; + } - if (res.users.length == 0) { - return null; - } - return res.users[0]; - }; + // Logging in doesn't require a session since it manipulates connection state. + params.db = this.getName(); + var good = this.getMongo().auth(params); + if (good) { + // auth enabled, and should try to use isMaster and replSetGetStatus to build prompt + this.getMongo().authStatus = {authRequired: true, isMaster: true, replSetGetStatus: true}; + } - DB.prototype.getUsers = function(args) { - var cmdObj = {usersInfo: 1}; - Object.extend(cmdObj, args); - var res = this.runCommand(cmdObj); - if (!res.ok) { - var authSchemaIncompatibleCode = 69; - if (res.code == authSchemaIncompatibleCode || - (res.code == null && res.errmsg == "no such cmd: usersInfo")) { - // Working with 2.4 schema user data - return this.system.users.find({}).toArray(); - } + return good; +}; - throw _getErrorWithCode(res, res.errmsg); - } +DB.prototype.auth = function() { + var ex; + try { + this._authOrThrow.apply(this, arguments); + } catch (ex) { + print(ex); + return 0; + } + return 1; +}; - return res.users; +DB.prototype.grantRolesToUser = function(username, roles, writeConcern) { + var cmdObj = { + grantRolesToUser: username, + roles: roles, + writeConcern: writeConcern ? writeConcern : _defaultWriteConcern }; + var res = this.runCommand(cmdObj); + if (!res.ok) { + throw _getErrorWithCode(res, res.errmsg); + } +}; - DB.prototype.createRole = function(roleObj, writeConcern) { - var name = roleObj["role"]; - var cmdObj = {createRole: name}; - cmdObj = Object.extend(cmdObj, roleObj); - delete cmdObj["role"]; - cmdObj["writeConcern"] = writeConcern ? writeConcern : _defaultWriteConcern; - - var res = this.runCommand(cmdObj); - - if (!res.ok) { - throw _getErrorWithCode(res, res.errmsg); - } - printjson(roleObj); +DB.prototype.revokeRolesFromUser = function(username, roles, writeConcern) { + var cmdObj = { + revokeRolesFromUser: username, + roles: roles, + writeConcern: writeConcern ? writeConcern : _defaultWriteConcern }; + var res = this.runCommand(cmdObj); + if (!res.ok) { + throw _getErrorWithCode(res, res.errmsg); + } +}; - DB.prototype.updateRole = function(name, updateObject, writeConcern) { - var cmdObj = {updateRole: name}; - cmdObj = Object.extend(cmdObj, updateObject); - cmdObj['writeConcern'] = writeConcern ? writeConcern : _defaultWriteConcern; - var res = this.runCommand(cmdObj); - if (!res.ok) { - throw _getErrorWithCode(res, res.errmsg); - } - }; +DB.prototype.getUser = function(username, args) { + if (typeof username != "string") { + throw Error("User name for getUser shell helper must be a string"); + } + var cmdObj = {usersInfo: username}; + Object.extend(cmdObj, args); - DB.prototype.dropRole = function(name, writeConcern) { - var cmdObj = { - dropRole: name, - writeConcern: writeConcern ? writeConcern : _defaultWriteConcern - }; - var res = this.runCommand(cmdObj); + var res = this.runCommand(cmdObj); + if (!res.ok) { + throw _getErrorWithCode(res, res.errmsg); + } - if (res.ok) { - return true; - } + if (res.users.length == 0) { + return null; + } + return res.users[0]; +}; - if (res.code == 31) { // Code 31 = RoleNotFound - return false; +DB.prototype.getUsers = function(args) { + var cmdObj = {usersInfo: 1}; + Object.extend(cmdObj, args); + var res = this.runCommand(cmdObj); + if (!res.ok) { + var authSchemaIncompatibleCode = 69; + if (res.code == authSchemaIncompatibleCode || + (res.code == null && res.errmsg == "no such cmd: usersInfo")) { + // Working with 2.4 schema user data + return this.system.users.find({}).toArray(); } throw _getErrorWithCode(res, res.errmsg); - }; - - DB.prototype.dropAllRoles = function(writeConcern) { - var res = this.runCommand({ - dropAllRolesFromDatabase: 1, - writeConcern: writeConcern ? writeConcern : _defaultWriteConcern - }); - - if (!res.ok) { - throw _getErrorWithCode(res, res.errmsg); - } + } - return res.n; - }; + return res.users; +}; - DB.prototype.grantRolesToRole = function(rolename, roles, writeConcern) { - var cmdObj = { - grantRolesToRole: rolename, - roles: roles, - writeConcern: writeConcern ? writeConcern : _defaultWriteConcern - }; - var res = this.runCommand(cmdObj); - if (!res.ok) { - throw _getErrorWithCode(res, res.errmsg); - } - }; +DB.prototype.createRole = function(roleObj, writeConcern) { + var name = roleObj["role"]; + var cmdObj = {createRole: name}; + cmdObj = Object.extend(cmdObj, roleObj); + delete cmdObj["role"]; + cmdObj["writeConcern"] = writeConcern ? writeConcern : _defaultWriteConcern; - DB.prototype.revokeRolesFromRole = function(rolename, roles, writeConcern) { - var cmdObj = { - revokeRolesFromRole: rolename, - roles: roles, - writeConcern: writeConcern ? writeConcern : _defaultWriteConcern - }; - var res = this.runCommand(cmdObj); - if (!res.ok) { - throw _getErrorWithCode(res, res.errmsg); - } - }; + var res = this.runCommand(cmdObj); - DB.prototype.grantPrivilegesToRole = function(rolename, privileges, writeConcern) { - var cmdObj = { - grantPrivilegesToRole: rolename, - privileges: privileges, - writeConcern: writeConcern ? writeConcern : _defaultWriteConcern - }; - var res = this.runCommand(cmdObj); - if (!res.ok) { - throw _getErrorWithCode(res, res.errmsg); - } - }; + if (!res.ok) { + throw _getErrorWithCode(res, res.errmsg); + } + printjson(roleObj); +}; + +DB.prototype.updateRole = function(name, updateObject, writeConcern) { + var cmdObj = {updateRole: name}; + cmdObj = Object.extend(cmdObj, updateObject); + cmdObj['writeConcern'] = writeConcern ? writeConcern : _defaultWriteConcern; + var res = this.runCommand(cmdObj); + if (!res.ok) { + throw _getErrorWithCode(res, res.errmsg); + } +}; - DB.prototype.revokePrivilegesFromRole = function(rolename, privileges, writeConcern) { - var cmdObj = { - revokePrivilegesFromRole: rolename, - privileges: privileges, - writeConcern: writeConcern ? writeConcern : _defaultWriteConcern - }; - var res = this.runCommand(cmdObj); - if (!res.ok) { - throw _getErrorWithCode(res, res.errmsg); - } - }; +DB.prototype.dropRole = function(name, writeConcern) { + var cmdObj = {dropRole: name, writeConcern: writeConcern ? writeConcern : _defaultWriteConcern}; + var res = this.runCommand(cmdObj); - DB.prototype.getRole = function(rolename, args) { - if (typeof rolename != "string") { - throw Error("Role name for getRole shell helper must be a string"); - } - var cmdObj = {rolesInfo: rolename}; - Object.extend(cmdObj, args); - var res = this.runCommand(cmdObj); - if (!res.ok) { - throw _getErrorWithCode(res, res.errmsg); - } + if (res.ok) { + return true; + } - if (res.roles.length == 0) { - return null; - } - return res.roles[0]; - }; + if (res.code == 31) { // Code 31 = RoleNotFound + return false; + } - DB.prototype.getRoles = function(args) { - var cmdObj = {rolesInfo: 1}; - Object.extend(cmdObj, args); - var res = this.runCommand(cmdObj); - if (!res.ok) { - throw _getErrorWithCode(res, res.errmsg); - } + throw _getErrorWithCode(res, res.errmsg); +}; - return res.roles; - }; +DB.prototype.dropAllRoles = function(writeConcern) { + var res = this.runCommand({ + dropAllRolesFromDatabase: 1, + writeConcern: writeConcern ? writeConcern : _defaultWriteConcern + }); - DB.prototype.setWriteConcern = function(wc) { - if (wc instanceof WriteConcern) { - this._writeConcern = wc; - } else { - this._writeConcern = new WriteConcern(wc); - } - }; + if (!res.ok) { + throw _getErrorWithCode(res, res.errmsg); + } - DB.prototype.getWriteConcern = function() { - if (this._writeConcern) - return this._writeConcern; + return res.n; +}; - { - const session = this.getSession(); - return session._getSessionAwareClient().getWriteConcern(session); - } +DB.prototype.grantRolesToRole = function(rolename, roles, writeConcern) { + var cmdObj = { + grantRolesToRole: rolename, + roles: roles, + writeConcern: writeConcern ? writeConcern : _defaultWriteConcern }; + var res = this.runCommand(cmdObj); + if (!res.ok) { + throw _getErrorWithCode(res, res.errmsg); + } +}; - DB.prototype.unsetWriteConcern = function() { - delete this._writeConcern; +DB.prototype.revokeRolesFromRole = function(rolename, roles, writeConcern) { + var cmdObj = { + revokeRolesFromRole: rolename, + roles: roles, + writeConcern: writeConcern ? writeConcern : _defaultWriteConcern }; + var res = this.runCommand(cmdObj); + if (!res.ok) { + throw _getErrorWithCode(res, res.errmsg); + } +}; - DB.prototype.getLogComponents = function() { - return this.getMongo().getLogComponents(this.getSession()); +DB.prototype.grantPrivilegesToRole = function(rolename, privileges, writeConcern) { + var cmdObj = { + grantPrivilegesToRole: rolename, + privileges: privileges, + writeConcern: writeConcern ? writeConcern : _defaultWriteConcern }; + var res = this.runCommand(cmdObj); + if (!res.ok) { + throw _getErrorWithCode(res, res.errmsg); + } +}; - DB.prototype.setLogLevel = function(logLevel, component) { - return this.getMongo().setLogLevel(logLevel, component, this.getSession()); +DB.prototype.revokePrivilegesFromRole = function(rolename, privileges, writeConcern) { + var cmdObj = { + revokePrivilegesFromRole: rolename, + privileges: privileges, + writeConcern: writeConcern ? writeConcern : _defaultWriteConcern }; + var res = this.runCommand(cmdObj); + if (!res.ok) { + throw _getErrorWithCode(res, res.errmsg); + } +}; - DB.prototype.watch = function(pipeline, options) { - pipeline = pipeline || []; - assert(pipeline instanceof Array, "'pipeline' argument must be an array"); - - let changeStreamStage; - [changeStreamStage, aggOptions] = this.getMongo()._extractChangeStreamOptions(options); - pipeline.unshift(changeStreamStage); - return this._runAggregate({aggregate: 1, pipeline: pipeline}, aggOptions); - }; +DB.prototype.getRole = function(rolename, args) { + if (typeof rolename != "string") { + throw Error("Role name for getRole shell helper must be a string"); + } + var cmdObj = {rolesInfo: rolename}; + Object.extend(cmdObj, args); + var res = this.runCommand(cmdObj); + if (!res.ok) { + throw _getErrorWithCode(res, res.errmsg); + } - DB.prototype.getFreeMonitoringStatus = function() { - 'use strict'; - return assert.commandWorked(this.adminCommand({getFreeMonitoringStatus: 1})); - }; + if (res.roles.length == 0) { + return null; + } + return res.roles[0]; +}; + +DB.prototype.getRoles = function(args) { + var cmdObj = {rolesInfo: 1}; + Object.extend(cmdObj, args); + var res = this.runCommand(cmdObj); + if (!res.ok) { + throw _getErrorWithCode(res, res.errmsg); + } - DB.prototype.enableFreeMonitoring = function() { - 'use strict'; - const isMaster = this.isMaster(); - if (isMaster.ismaster == false) { - print("ERROR: db.enableFreeMonitoring() may only be run on a primary"); - return; - } + return res.roles; +}; - assert.commandWorked(this.adminCommand({setFreeMonitoring: 1, action: 'enable'})); +DB.prototype.setWriteConcern = function(wc) { + if (wc instanceof WriteConcern) { + this._writeConcern = wc; + } else { + this._writeConcern = new WriteConcern(wc); + } +}; - const cmd = this.adminCommand({getFreeMonitoringStatus: 1}); - if (!cmd.ok && (cmd.code == ErrorCode.Unauthorized)) { - // Edge case: It's technically possible that a user can change free-mon state, - // but is not allowed to inspect it. - print("Successfully initiated free monitoring, but unable to determine status " + - "as you lack the 'checkFreeMonitoringStatus' privilege."); - return; - } - assert.commandWorked(cmd); +DB.prototype.getWriteConcern = function() { + if (this._writeConcern) + return this._writeConcern; - if (cmd.state !== 'enabled') { - const url = this.adminCommand({'getParameter': 1, 'cloudFreeMonitoringEndpointURL': 1}) - .cloudFreeMonitoringEndpointURL; + { + const session = this.getSession(); + return session._getSessionAwareClient().getWriteConcern(session); + } +}; + +DB.prototype.unsetWriteConcern = function() { + delete this._writeConcern; +}; + +DB.prototype.getLogComponents = function() { + return this.getMongo().getLogComponents(this.getSession()); +}; + +DB.prototype.setLogLevel = function(logLevel, component) { + return this.getMongo().setLogLevel(logLevel, component, this.getSession()); +}; + +DB.prototype.watch = function(pipeline, options) { + pipeline = pipeline || []; + assert(pipeline instanceof Array, "'pipeline' argument must be an array"); + + let changeStreamStage; + [changeStreamStage, aggOptions] = this.getMongo()._extractChangeStreamOptions(options); + pipeline.unshift(changeStreamStage); + return this._runAggregate({aggregate: 1, pipeline: pipeline}, aggOptions); +}; + +DB.prototype.getFreeMonitoringStatus = function() { + 'use strict'; + return assert.commandWorked(this.adminCommand({getFreeMonitoringStatus: 1})); +}; + +DB.prototype.enableFreeMonitoring = function() { + 'use strict'; + const isMaster = this.isMaster(); + if (isMaster.ismaster == false) { + print("ERROR: db.enableFreeMonitoring() may only be run on a primary"); + return; + } - print("Unable to get immediate response from the Cloud Monitoring service. We will" + - "continue to retry in the background. Please check your firewall " + - "settings to ensure that mongod can communicate with \"" + url + "\""); - return; - } + assert.commandWorked(this.adminCommand({setFreeMonitoring: 1, action: 'enable'})); - print(tojson(cmd)); - }; + const cmd = this.adminCommand({getFreeMonitoringStatus: 1}); + if (!cmd.ok && (cmd.code == ErrorCode.Unauthorized)) { + // Edge case: It's technically possible that a user can change free-mon state, + // but is not allowed to inspect it. + print("Successfully initiated free monitoring, but unable to determine status " + + "as you lack the 'checkFreeMonitoringStatus' privilege."); + return; + } + assert.commandWorked(cmd); - DB.prototype.disableFreeMonitoring = function() { - 'use strict'; - assert.commandWorked(this.adminCommand({setFreeMonitoring: 1, action: 'disable'})); - }; + if (cmd.state !== 'enabled') { + const url = this.adminCommand({'getParameter': 1, 'cloudFreeMonitoringEndpointURL': 1}) + .cloudFreeMonitoringEndpointURL; - // Writing `this.hasOwnProperty` would cause DB.prototype.getCollection() to be called since the - // DB's getProperty() handler in C++ takes precedence when a property isn't defined on the DB - // instance directly. The "hasOwnProperty" property is defined on Object.prototype, so we must - // resort to using the function explicitly ourselves. - (function(hasOwnProperty) { - DB.prototype.getSession = function() { - if (!hasOwnProperty.call(this, "_session")) { - this._session = this.getMongo()._getDefaultSession(); - } - return this._session; - }; - })(Object.prototype.hasOwnProperty); + print("Unable to get immediate response from the Cloud Monitoring service. We will" + + "continue to retry in the background. Please check your firewall " + + "settings to ensure that mongod can communicate with \"" + url + "\""); + return; + } + print(tojson(cmd)); +}; + +DB.prototype.disableFreeMonitoring = function() { + 'use strict'; + assert.commandWorked(this.adminCommand({setFreeMonitoring: 1, action: 'disable'})); +}; + +// Writing `this.hasOwnProperty` would cause DB.prototype.getCollection() to be called since the +// DB's getProperty() handler in C++ takes precedence when a property isn't defined on the DB +// instance directly. The "hasOwnProperty" property is defined on Object.prototype, so we must +// resort to using the function explicitly ourselves. +(function(hasOwnProperty) { +DB.prototype.getSession = function() { + if (!hasOwnProperty.call(this, "_session")) { + this._session = this.getMongo()._getDefaultSession(); + } + return this._session; +}; +})(Object.prototype.hasOwnProperty); }()); diff --git a/src/mongo/shell/dbshell.cpp b/src/mongo/shell/dbshell.cpp index 4f4e55669e5..12911840cb9 100644 --- a/src/mongo/shell/dbshell.cpp +++ b/src/mongo/shell/dbshell.cpp @@ -175,7 +175,7 @@ enum ShellExitCode : int { }; Scope* shellMainScope; -} +} // namespace mongo bool isSessionTimedOut() { static Date_t previousCommandTime = Date_t::now(); @@ -794,8 +794,8 @@ int _main(int argc, char* argv[], char** envp) { #else wchar_t programDataPath[MAX_PATH]; if (S_OK == SHGetFolderPathW(nullptr, CSIDL_COMMON_APPDATA, nullptr, 0, programDataPath)) { - rcGlobalLocation = str::stream() << toUtf8String(programDataPath) - << "\\MongoDB\\mongorc.js"; + rcGlobalLocation = str::stream() + << toUtf8String(programDataPath) << "\\MongoDB\\mongorc.js"; } #endif if (!rcGlobalLocation.empty() && ::mongo::shell_utils::fileExists(rcGlobalLocation)) { @@ -875,9 +875,9 @@ int _main(int argc, char* argv[], char** envp) { rcLocation = str::stream() << getenv("HOME") << "/.mongorc.js"; #else if (getenv("HOMEDRIVE") != nullptr && getenv("HOMEPATH") != nullptr) - rcLocation = str::stream() << toUtf8String(_wgetenv(L"HOMEDRIVE")) - << toUtf8String(_wgetenv(L"HOMEPATH")) - << "\\.mongorc.js"; + rcLocation = str::stream() + << toUtf8String(_wgetenv(L"HOMEDRIVE")) << toUtf8String(_wgetenv(L"HOMEPATH")) + << "\\.mongorc.js"; #endif if (!rcLocation.empty() && ::mongo::shell_utils::fileExists(rcLocation)) { hasMongoRC = true; diff --git a/src/mongo/shell/encrypted_dbclient_base.cpp b/src/mongo/shell/encrypted_dbclient_base.cpp index bec5bb8ae5e..be82f6b97bb 100644 --- a/src/mongo/shell/encrypted_dbclient_base.cpp +++ b/src/mongo/shell/encrypted_dbclient_base.cpp @@ -138,7 +138,7 @@ BSONObj EncryptedDBClientBase::encryptDecryptCommand(const BSONObj& object, uassert(31096, "Object too deep to be encrypted. Exceeded stack depth.", frameStack.size() < BSONDepth::kDefaultMaxAllowableDepth); - auto & [ iterator, builder ] = frameStack.top(); + auto& [iterator, builder] = frameStack.top(); if (iterator.more()) { BSONElement elem = iterator.next(); if (elem.type() == BSONType::Object) { @@ -609,7 +609,7 @@ std::shared_ptr<SymmetricKey> EncryptedDBClientBase::getDataKey(const UUID& uuid auto ts_new = Date_t::now(); if (_datakeyCache.hasKey(uuid)) { - auto[key, ts] = _datakeyCache.find(uuid)->second; + auto [key, ts] = _datakeyCache.find(uuid)->second; if (ts_new - ts < kCacheInvalidationTime) { return key; } else { diff --git a/src/mongo/shell/encrypted_shell_options.h b/src/mongo/shell/encrypted_shell_options.h index f839c637d9a..b4b30aba2fe 100644 --- a/src/mongo/shell/encrypted_shell_options.h +++ b/src/mongo/shell/encrypted_shell_options.h @@ -42,4 +42,4 @@ struct EncryptedShellGlobalParams { }; extern EncryptedShellGlobalParams encryptedShellGlobalParams; -} +} // namespace mongo diff --git a/src/mongo/shell/explain_query.js b/src/mongo/shell/explain_query.js index 78e57c86e69..89a922e225a 100644 --- a/src/mongo/shell/explain_query.js +++ b/src/mongo/shell/explain_query.js @@ -4,7 +4,6 @@ // var DBExplainQuery = (function() { - // // Private methods. // @@ -15,7 +14,7 @@ var DBExplainQuery = (function() { * is implemented here for backwards compatibility. */ function removeVerboseFields(obj) { - if (typeof(obj) !== "object") { + if (typeof (obj) !== "object") { return; } @@ -23,7 +22,7 @@ var DBExplainQuery = (function() { delete obj.oldPlan; delete obj.stats; - if (typeof(obj.length) === "number") { + if (typeof (obj.length) === "number") { for (var i = 0; i < obj.length; i++) { removeVerboseFields(obj[i]); } diff --git a/src/mongo/shell/explainable.js b/src/mongo/shell/explainable.js index 637d19d2bf7..4f32af22221 100644 --- a/src/mongo/shell/explainable.js +++ b/src/mongo/shell/explainable.js @@ -4,7 +4,6 @@ // var Explainable = (function() { - var parseVerbosity = function(verbosity) { // Truthy non-strings are interpreted as "allPlansExecution" verbosity. if (verbosity && (typeof verbosity !== "string")) { @@ -19,8 +18,10 @@ var Explainable = (function() { // If we're here, then the verbosity is a string. We reject invalid strings. if (verbosity !== "queryPlanner" && verbosity !== "executionStats" && verbosity !== "allPlansExecution") { - throw Error("explain verbosity must be one of {" + "'queryPlanner'," + - "'executionStats'," + "'allPlansExecution'}"); + throw Error("explain verbosity must be one of {" + + "'queryPlanner'," + + "'executionStats'," + + "'allPlansExecution'}"); } return verbosity; diff --git a/src/mongo/shell/kms_aws.cpp b/src/mongo/shell/kms_aws.cpp index a0c3ecffe06..b923a59355c 100644 --- a/src/mongo/shell/kms_aws.cpp +++ b/src/mongo/shell/kms_aws.cpp @@ -449,7 +449,7 @@ public: } }; -} // namspace +} // namespace MONGO_INITIALIZER(KMSRegister)(::mongo::InitializerContext* context) { kms_message_init(); diff --git a/src/mongo/shell/kms_local.cpp b/src/mongo/shell/kms_local.cpp index 628ea9ed9c2..32d5f760383 100644 --- a/src/mongo/shell/kms_local.cpp +++ b/src/mongo/shell/kms_local.cpp @@ -143,7 +143,7 @@ public: } }; -} // namspace +} // namespace MONGO_INITIALIZER(LocalKMSRegister)(::mongo::InitializerContext* context) { KMSServiceController::registerFactory(KMSProviderEnum::local, diff --git a/src/mongo/shell/linenoise.cpp b/src/mongo/shell/linenoise.cpp index 501103aae4a..ed8910ac73c 100644 --- a/src/mongo/shell/linenoise.cpp +++ b/src/mongo/shell/linenoise.cpp @@ -126,16 +126,16 @@ using std::vector; using std::unique_ptr; -using linenoise_utf8::UChar8; -using linenoise_utf8::UChar32; -using linenoise_utf8::copyString8to32; using linenoise_utf8::copyString32; using linenoise_utf8::copyString32to8; +using linenoise_utf8::copyString8to32; using linenoise_utf8::strlen32; using linenoise_utf8::strncmp32; -using linenoise_utf8::write32; -using linenoise_utf8::Utf8String; +using linenoise_utf8::UChar32; +using linenoise_utf8::UChar8; using linenoise_utf8::Utf32String; +using linenoise_utf8::Utf8String; +using linenoise_utf8::write32; struct linenoiseCompletions { vector<Utf32String> completionStrings; @@ -1234,7 +1234,7 @@ static UChar32 setMetaRoutine(UChar32 c) { return doDispatch(c, initialDispatch); } -} // namespace EscapeSequenceProcessing // move these out of global namespace +} // namespace EscapeSequenceProcessing #endif // #ifndef _WIN32 diff --git a/src/mongo/shell/linenoise_utf8.h b/src/mongo/shell/linenoise_utf8.h index d5d4c6db7d9..dca7a8b0ef4 100644 --- a/src/mongo/shell/linenoise_utf8.h +++ b/src/mongo/shell/linenoise_utf8.h @@ -141,10 +141,7 @@ struct UtfStringMixin { UtfStringMixin() : _len(0), _cap(0), _chars(0) {} UtfStringMixin(const UtfStringMixin& other) // copies like std::string - : _len(other._len), - _cap(other._len + 1), - _chars(other._chars), - _str(new char_t[_cap]) { + : _len(other._len), _cap(other._len + 1), _chars(other._chars), _str(new char_t[_cap]) { memcpy(_str.get(), other._str.get(), _cap * sizeof(char_t)); } diff --git a/src/mongo/shell/mk_wcwidth.cpp b/src/mongo/shell/mk_wcwidth.cpp index cb4674344f5..1a09cc2e874 100644 --- a/src/mongo/shell/mk_wcwidth.cpp +++ b/src/mongo/shell/mk_wcwidth.cpp @@ -177,15 +177,15 @@ int mk_wcwidth(int ucs) { return 1 + (ucs >= 0x1100 && (ucs <= 0x115f || /* Hangul Jamo init. consonants */ - ucs == 0x2329 || - ucs == 0x232a || (ucs >= 0x2e80 && ucs <= 0xa4cf && ucs != 0x303f) || /* CJK ... Yi */ - (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */ - (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */ - (ucs >= 0xfe10 && ucs <= 0xfe19) || /* Vertical forms */ - (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */ - (ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */ - (ucs >= 0xffe0 && ucs <= 0xffe6) || - (ucs >= 0x20000 && ucs <= 0x2fffd) || (ucs >= 0x30000 && ucs <= 0x3fffd))); + ucs == 0x2329 || ucs == 0x232a || + (ucs >= 0x2e80 && ucs <= 0xa4cf && ucs != 0x303f) || /* CJK ... Yi */ + (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */ + (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */ + (ucs >= 0xfe10 && ucs <= 0xfe19) || /* Vertical forms */ + (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */ + (ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */ + (ucs >= 0xffe0 && ucs <= 0xffe6) || (ucs >= 0x20000 && ucs <= 0x2fffd) || + (ucs >= 0x30000 && ucs <= 0x3fffd))); } diff --git a/src/mongo/shell/mongo.js b/src/mongo/shell/mongo.js index 39dbd402f7d..481aff7c6ad 100644 --- a/src/mongo/shell/mongo.js +++ b/src/mongo/shell/mongo.js @@ -45,7 +45,7 @@ Mongo.prototype.getDB = function(name) { // There is a weird issue where typeof(db._name) !== "string" when the db name // is created from objects returned from native C++ methods. // This hack ensures that the db._name is always a string. - if (typeof(name) === "object") { + if (typeof (name) === "object") { name = name.toString(); } return new DB(this, name); @@ -84,7 +84,6 @@ Mongo.prototype.getDBs = function(driverSession = this._getDefaultSession(), filter = undefined, nameOnly = undefined, authorizedDatabases = undefined) { - return function(driverSession, filter, nameOnly, authorizedDatabases) { 'use strict'; @@ -227,7 +226,7 @@ Mongo.prototype.tojson = Mongo.prototype.toString; * Note that this object only keeps a shallow copy of this array. */ Mongo.prototype.setReadPref = function(mode, tagSet) { - if ((this._readPrefMode === "primary") && (typeof(tagSet) !== "undefined") && + if ((this._readPrefMode === "primary") && (typeof (tagSet) !== "undefined") && (Object.keys(tagSet).length > 0)) { // we allow empty arrays/objects or no tagSet for compatibility reasons throw Error("Can not supply tagSet with readPref mode primary"); @@ -252,7 +251,7 @@ Mongo.prototype.getReadPrefTagSet = function() { // Returns a readPreference object of the type expected by mongos. Mongo.prototype.getReadPref = function() { var obj = {}, mode, tagSet; - if (typeof(mode = this.getReadPrefMode()) === "string") { + if (typeof (mode = this.getReadPrefMode()) === "string") { obj.mode = mode; } else { return null; @@ -381,7 +380,8 @@ connect = function(url, user, pass) { return db; }; -/** deprecated, use writeMode below +/** + * deprecated, use writeMode below * */ Mongo.prototype.useWriteCommands = function() { @@ -410,7 +410,6 @@ Mongo.prototype.hasExplainCommand = function() { */ Mongo.prototype.writeMode = function() { - if ('_writeMode' in this) { return this._writeMode; } @@ -539,8 +538,8 @@ Mongo.prototype.startSession = function startSession(options = {}) { // Only log this message if we are running a test if (typeof TestData === "object" && TestData.testName) { jsTest.log("New session started with sessionID: " + - tojsononeline(newDriverSession.getSessionId()) + " and options: " + - tojsononeline(options)); + tojsononeline(newDriverSession.getSessionId()) + + " and options: " + tojsononeline(options)); } return newDriverSession; @@ -560,7 +559,7 @@ Mongo.prototype._getDefaultSession = function getDefaultSession() { this._setDummyDefaultSession(); } else { print("ERROR: Implicit session failed: " + e.message); - throw(e); + throw (e); } } } else { diff --git a/src/mongo/shell/query.js b/src/mongo/shell/query.js index 7bd167b5437..bd451166e9d 100644 --- a/src/mongo/shell/query.js +++ b/src/mongo/shell/query.js @@ -2,7 +2,6 @@ if (typeof DBQuery == "undefined") { DBQuery = function(mongo, db, collection, ns, query, fields, limit, skip, batchSize, options) { - this._mongo = mongo; // 0 this._db = db; // 1 this._collection = collection; // 2 @@ -399,8 +398,8 @@ DBQuery.prototype.countReturn = function() { }; /** -* iterative count - only for testing -*/ + * iterative count - only for testing + */ DBQuery.prototype.itcount = function() { var num = 0; @@ -555,7 +554,6 @@ DBQuery.prototype.shellPrint = function() { } catch (e) { print(e); } - }; DBQuery.prototype.toString = function() { @@ -567,12 +565,12 @@ DBQuery.prototype.toString = function() { // /** -* Get partial results from a mongos if some shards are down (instead of throwing an error). -* -* @method -* @see http://docs.mongodb.org/meta-driver/latest/legacy/mongodb-wire-protocol/#op-query -* @return {DBQuery} -*/ + * Get partial results from a mongos if some shards are down (instead of throwing an error). + * + * @method + * @see http://docs.mongodb.org/meta-driver/latest/legacy/mongodb-wire-protocol/#op-query + * @return {DBQuery} + */ DBQuery.prototype.allowPartialResults = function() { this._checkModify(); this.addOption(DBQuery.Option.partial); @@ -580,13 +578,13 @@ DBQuery.prototype.allowPartialResults = function() { }; /** -* The server normally times out idle cursors after an inactivity period (10 minutes) -* to prevent excess memory use. Set this option to prevent that. -* -* @method -* @see http://docs.mongodb.org/meta-driver/latest/legacy/mongodb-wire-protocol/#op-query -* @return {DBQuery} -*/ + * The server normally times out idle cursors after an inactivity period (10 minutes) + * to prevent excess memory use. Set this option to prevent that. + * + * @method + * @see http://docs.mongodb.org/meta-driver/latest/legacy/mongodb-wire-protocol/#op-query + * @return {DBQuery} + */ DBQuery.prototype.noCursorTimeout = function() { this._checkModify(); this.addOption(DBQuery.Option.noTimeout); @@ -594,13 +592,13 @@ DBQuery.prototype.noCursorTimeout = function() { }; /** -* Limits the fields to return for all matching documents. -* -* @method -* @see http://docs.mongodb.org/manual/tutorial/project-fields-from-query-results/ -* @param {object} document Document specifying the projection of the resulting documents. -* @return {DBQuery} -*/ + * Limits the fields to return for all matching documents. + * + * @method + * @see http://docs.mongodb.org/manual/tutorial/project-fields-from-query-results/ + * @param {object} document Document specifying the projection of the resulting documents. + * @return {DBQuery} + */ DBQuery.prototype.projection = function(document) { this._checkModify(); this._fields = document; @@ -608,14 +606,14 @@ DBQuery.prototype.projection = function(document) { }; /** -* Specify cursor as a tailable cursor, allowing to specify if it will use awaitData -* -* @method -* @see http://docs.mongodb.org/manual/tutorial/create-tailable-cursor/ -* @param {boolean} [awaitData=true] cursor blocks for a few seconds to wait for data if no documents -*found. -* @return {DBQuery} -*/ + * Specify cursor as a tailable cursor, allowing to specify if it will use awaitData + * + * @method + * @see http://docs.mongodb.org/manual/tutorial/create-tailable-cursor/ + * @param {boolean} [awaitData=true] cursor blocks for a few seconds to wait for data if no + *documents found. + * @return {DBQuery} + */ DBQuery.prototype.tailable = function(awaitData) { this._checkModify(); this.addOption(DBQuery.Option.tailable); @@ -629,13 +627,13 @@ DBQuery.prototype.tailable = function(awaitData) { }; /** -* Specify a document containing modifiers for the query. -* -* @method -* @see http://docs.mongodb.org/manual/reference/operator/query-modifier/ -* @param {object} document A document containing modifers to apply to the cursor. -* @return {DBQuery} -*/ + * Specify a document containing modifiers for the query. + * + * @method + * @see http://docs.mongodb.org/manual/reference/operator/query-modifier/ + * @param {object} document A document containing modifers to apply to the cursor. + * @return {DBQuery} + */ DBQuery.prototype.modifiers = function(document) { this._checkModify(); @@ -802,16 +800,16 @@ DBCommandCursor.prototype._runGetMoreCommand = function() { assert.commandWorked(cmdRes, () => "getMore command failed: " + tojson(cmdRes)); if (this._ns !== cmdRes.cursor.ns) { - throw Error("unexpected collection in getMore response: " + this._ns + " != " + - cmdRes.cursor.ns); + throw Error("unexpected collection in getMore response: " + this._ns + + " != " + cmdRes.cursor.ns); } if (!cmdRes.cursor.id.compare(NumberLong("0"))) { this._cursorHandle.zeroCursorId(); this._cursorid = NumberLong("0"); } else if (this._cursorid.compare(cmdRes.cursor.id)) { - throw Error("unexpected cursor id: " + this._cursorid.toString() + " != " + - cmdRes.cursor.id.toString()); + throw Error("unexpected cursor id: " + this._cursorid.toString() + + " != " + cmdRes.cursor.id.toString()); } // If the command result represents a change stream cursor, update our postBatchResumeToken. diff --git a/src/mongo/shell/replsettest.js b/src/mongo/shell/replsettest.js index 525be55a6fc..5e8a14f7d3c 100644 --- a/src/mongo/shell/replsettest.js +++ b/src/mongo/shell/replsettest.js @@ -282,13 +282,14 @@ var ReplSetTest = function(opts) { if (status.members[i].name == node.host || status.members[i].name == node.name) { for (var j = 0; j < states.length; j++) { if (printStatus) { - print("Status -- " + " current state: " + status.members[i][ind] + + print("Status -- " + + " current state: " + status.members[i][ind] + ", target state : " + states[j]); } - if (typeof(states[j]) != "number") { - throw new Error("State was not an number -- type:" + typeof(states[j]) + - ", value:" + states[j]); + if (typeof (states[j]) != "number") { + throw new Error("State was not an number -- type:" + + typeof (states[j]) + ", value:" + states[j]); } if (status.members[i][ind] == states[j]) { foundState = states[j]; @@ -299,7 +300,6 @@ var ReplSetTest = function(opts) { } return false; - }, "waiting for state indicator " + ind + " for " + timeout + "ms", timeout); // If we were waiting for the node to step down, wait until we can connect to it again, @@ -894,7 +894,6 @@ var ReplSetTest = function(opts) { * and returns the 'config' object unchanged. Does not affect 'config' when running CSRS. */ this._updateConfigIfNotDurable = function(config) { - // Get a replica set node (check for use of bridge). var replNode = _useBridge ? _unbridgedNodes[0] : this.nodes[0]; @@ -936,9 +935,9 @@ var ReplSetTest = function(opts) { const result = assert.commandWorkedOrFailedWithCode( master.runCommand(cmd), [ - ErrorCodes.NodeNotFound, - ErrorCodes.NewReplicaSetConfigurationIncompatible, - ErrorCodes.InterruptedDueToReplStateChange + ErrorCodes.NodeNotFound, + ErrorCodes.NewReplicaSetConfigurationIncompatible, + ErrorCodes.InterruptedDueToReplStateChange ], errorMsg); return result.ok; @@ -1032,7 +1031,7 @@ var ReplSetTest = function(opts) { } else { Object.keys(self.nodeOptions).forEach(function(key, index) { let val = self.nodeOptions[key]; - if (typeof(val) === "object" && + if (typeof (val) === "object" && (val.hasOwnProperty("shardsvr") || val.hasOwnProperty("binVersion") && // Should not wait for keys if version is less than 3.6 @@ -1043,7 +1042,7 @@ var ReplSetTest = function(opts) { }); if (self.startOptions != undefined) { let val = self.startOptions; - if (typeof(val) === "object" && + if (typeof (val) === "object" && (val.hasOwnProperty("shardsvr") || val.hasOwnProperty("binVersion") && // Should not wait for keys if version is less than 3.6 @@ -1564,7 +1563,8 @@ var ReplSetTest = function(opts) { this.getHashesUsingSessions = function(sessions, dbName, { filterCapped: filterCapped = true, - filterMapReduce: filterMapReduce = true, readAtClusterTime, + filterMapReduce: filterMapReduce = true, + readAtClusterTime, } = {}) { return sessions.map(session => { const commandObj = {dbHash: 1}; @@ -1896,7 +1896,8 @@ var ReplSetTest = function(opts) { primarySession, secondarySession, dbName, collName); for (let { - primary: primaryDoc, secondary: secondaryDoc, + primary: primaryDoc, + secondary: secondaryDoc, } of diff.docsWithDifferentContents) { print(`Mismatching documents between the primary ${primary.host}` + ` and the secondary ${secondary.host}:`); @@ -1994,7 +1995,6 @@ var ReplSetTest = function(opts) { dumpCollectionDiff(primary, secondary, dbName, collName); success = false; } - }); // Check that collection information is consistent on the primary and @@ -2363,7 +2363,7 @@ var ReplSetTest = function(opts) { // Turn off periodic noop writes for replica sets by default. options.setParameter = options.setParameter || {}; - if (typeof(options.setParameter) === "string") { + if (typeof (options.setParameter) === "string") { var eqIdx = options.setParameter.indexOf("="); if (eqIdx != -1) { var param = options.setParameter.substring(0, eqIdx); diff --git a/src/mongo/shell/servers.js b/src/mongo/shell/servers.js index 4ebf51ec693..e4633c42a7e 100644 --- a/src/mongo/shell/servers.js +++ b/src/mongo/shell/servers.js @@ -2,1112 +2,1192 @@ var MongoRunner, _startMongod, startMongoProgram, runMongoProgram, startMongoPro myPort; (function() { - "use strict"; +"use strict"; - var shellVersion = version; +var shellVersion = version; - // Record the exit codes of mongod and mongos processes that crashed during startup keyed by - // port. This map is cleared when MongoRunner._startWithArgs and MongoRunner.stopMongod/s are - // called. - var serverExitCodeMap = {}; +// Record the exit codes of mongod and mongos processes that crashed during startup keyed by +// port. This map is cleared when MongoRunner._startWithArgs and MongoRunner.stopMongod/s are +// called. +var serverExitCodeMap = {}; - var _parsePath = function() { - var dbpath = ""; - for (var i = 0; i < arguments.length; ++i) - if (arguments[i] == "--dbpath") - dbpath = arguments[i + 1]; +var _parsePath = function() { + var dbpath = ""; + for (var i = 0; i < arguments.length; ++i) + if (arguments[i] == "--dbpath") + dbpath = arguments[i + 1]; - if (dbpath == "") - throw Error("No dbpath specified"); + if (dbpath == "") + throw Error("No dbpath specified"); - return dbpath; - }; + return dbpath; +}; - var _parsePort = function() { - var port = ""; - for (var i = 0; i < arguments.length; ++i) - if (arguments[i] == "--port") - port = arguments[i + 1]; +var _parsePort = function() { + var port = ""; + for (var i = 0; i < arguments.length; ++i) + if (arguments[i] == "--port") + port = arguments[i + 1]; - if (port == "") - throw Error("No port specified"); - return port; - }; + if (port == "") + throw Error("No port specified"); + return port; +}; - var createMongoArgs = function(binaryName, args) { - if (!Array.isArray(args)) { - throw new Error("The second argument to createMongoArgs must be an array"); - } +var createMongoArgs = function(binaryName, args) { + if (!Array.isArray(args)) { + throw new Error("The second argument to createMongoArgs must be an array"); + } - var fullArgs = [binaryName]; - - if (args.length == 1 && isObject(args[0])) { - var o = args[0]; - for (var k in o) { - if (o.hasOwnProperty(k)) { - if (k == "v" && isNumber(o[k])) { - var n = o[k]; - if (n > 0) { - if (n > 10) - n = 10; - var temp = "-"; - while (n-- > 0) - temp += "v"; - fullArgs.push(temp); - } - } else { - fullArgs.push("--" + k); - if (o[k] != "") - fullArgs.push("" + o[k]); + var fullArgs = [binaryName]; + + if (args.length == 1 && isObject(args[0])) { + var o = args[0]; + for (var k in o) { + if (o.hasOwnProperty(k)) { + if (k == "v" && isNumber(o[k])) { + var n = o[k]; + if (n > 0) { + if (n > 10) + n = 10; + var temp = "-"; + while (n-- > 0) + temp += "v"; + fullArgs.push(temp); } + } else { + fullArgs.push("--" + k); + if (o[k] != "") + fullArgs.push("" + o[k]); } } - } else { - for (var i = 0; i < args.length; i++) - fullArgs.push(args[i]); } + } else { + for (var i = 0; i < args.length; i++) + fullArgs.push(args[i]); + } - return fullArgs; - }; - - MongoRunner = function() {}; - - MongoRunner.dataDir = "/data/db"; - MongoRunner.dataPath = "/data/db/"; - - MongoRunner.mongodPath = "mongod"; - MongoRunner.mongosPath = "mongos"; - MongoRunner.mongoShellPath = "mongo"; - - MongoRunner.VersionSub = function(pattern, version) { - this.pattern = pattern; - this.version = version; - }; - - /** - * Returns an array of version elements from a version string. - * - * "3.3.4-fade3783" -> ["3", "3", "4-fade3783" ] - * "3.2" -> [ "3", "2" ] - * 3 -> exception: versions must have at least two components. - */ - var convertVersionStringToArray = function(versionString) { - assert("" !== versionString, "Version strings must not be empty"); - var versionArray = versionString.split('.'); - - assert.gt(versionArray.length, - 1, - "MongoDB versions must have at least two components to compare, but \"" + - versionString + "\" has " + versionArray.length); - return versionArray; - }; - - /** - * Returns the major version string from a version string. - * - * 3.3.4-fade3783 -> 3.3 - * 3.2 -> 3.2 - * 3 -> exception: versions must have at least two components. - */ - var extractMajorVersionFromVersionString = function(versionString) { - return convertVersionStringToArray(versionString).slice(0, 2).join('.'); - }; - - // These patterns allow substituting the binary versions used for each version string to support - // the - // dev/stable MongoDB release cycle. - // - // If you add a new version substitution to this list, you should add it to the lists of - // versions being checked in 'verify_versions_test.js' to verify it is susbstituted correctly. - MongoRunner.binVersionSubs = [ - new MongoRunner.VersionSub("latest", shellVersion()), - new MongoRunner.VersionSub(extractMajorVersionFromVersionString(shellVersion()), - shellVersion()), - // To-be-updated when we branch for the next release. - new MongoRunner.VersionSub("last-stable", "4.2") - ]; - - MongoRunner.getBinVersionFor = function(version) { - if (version instanceof MongoRunner.versionIterator.iterator) { - version = version.current(); - } - - if (version == null) - version = ""; - version = version.trim(); - if (version === "") - version = "latest"; - - // See if this version is affected by version substitutions - for (var i = 0; i < MongoRunner.binVersionSubs.length; i++) { - var sub = MongoRunner.binVersionSubs[i]; - if (sub.pattern == version) { - return sub.version; - } - } - - return version; - }; - - /** - * Returns true if two version strings could represent the same version. This is true - * if, after passing the versions through getBinVersionFor, the versions have the - * same value for each version component up through the length of the shorter version. - * - * That is, 3.2.4 compares equal to 3.2, but 3.2.4 does not compare equal to 3.2.3. - */ - MongoRunner.areBinVersionsTheSame = function(versionA, versionB) { + return fullArgs; +}; + +MongoRunner = function() {}; + +MongoRunner.dataDir = "/data/db"; +MongoRunner.dataPath = "/data/db/"; + +MongoRunner.mongodPath = "mongod"; +MongoRunner.mongosPath = "mongos"; +MongoRunner.mongoShellPath = "mongo"; + +MongoRunner.VersionSub = function(pattern, version) { + this.pattern = pattern; + this.version = version; +}; + +/** + * Returns an array of version elements from a version string. + * + * "3.3.4-fade3783" -> ["3", "3", "4-fade3783" ] + * "3.2" -> [ "3", "2" ] + * 3 -> exception: versions must have at least two components. + */ +var convertVersionStringToArray = function(versionString) { + assert("" !== versionString, "Version strings must not be empty"); + var versionArray = versionString.split('.'); + + assert.gt(versionArray.length, + 1, + "MongoDB versions must have at least two components to compare, but \"" + + versionString + "\" has " + versionArray.length); + return versionArray; +}; + +/** + * Returns the major version string from a version string. + * + * 3.3.4-fade3783 -> 3.3 + * 3.2 -> 3.2 + * 3 -> exception: versions must have at least two components. + */ +var extractMajorVersionFromVersionString = function(versionString) { + return convertVersionStringToArray(versionString).slice(0, 2).join('.'); +}; + +// These patterns allow substituting the binary versions used for each version string to support +// the +// dev/stable MongoDB release cycle. +// +// If you add a new version substitution to this list, you should add it to the lists of +// versions being checked in 'verify_versions_test.js' to verify it is susbstituted correctly. +MongoRunner.binVersionSubs = [ + new MongoRunner.VersionSub("latest", shellVersion()), + new MongoRunner.VersionSub(extractMajorVersionFromVersionString(shellVersion()), + shellVersion()), + // To-be-updated when we branch for the next release. + new MongoRunner.VersionSub("last-stable", "4.2") +]; + +MongoRunner.getBinVersionFor = function(version) { + if (version instanceof MongoRunner.versionIterator.iterator) { + version = version.current(); + } - // Check for invalid version strings first. - convertVersionStringToArray(MongoRunner.getBinVersionFor(versionA)); - convertVersionStringToArray(MongoRunner.getBinVersionFor(versionB)); + if (version == null) + version = ""; + version = version.trim(); + if (version === "") + version = "latest"; - try { - return (0 === MongoRunner.compareBinVersions(versionA, versionB)); - } catch (err) { - // compareBinVersions() throws an error if two versions differ only by the git hash. - return false; + // See if this version is affected by version substitutions + for (var i = 0; i < MongoRunner.binVersionSubs.length; i++) { + var sub = MongoRunner.binVersionSubs[i]; + if (sub.pattern == version) { + return sub.version; } - }; - - /** - * Compares two version strings and returns: - * 1, if the first is more recent - * 0, if they are equal - * -1, if the first is older - * - * Note that this function only compares up to the length of the shorter version. - * Because of this, minor versions will compare equal to the major versions they stem - * from, but major-major and minor-minor version pairs will undergo strict comparison. - */ - MongoRunner.compareBinVersions = function(versionA, versionB) { - - let stringA = versionA; - let stringB = versionB; - - versionA = convertVersionStringToArray(MongoRunner.getBinVersionFor(versionA)); - versionB = convertVersionStringToArray(MongoRunner.getBinVersionFor(versionB)); - - // Treat the githash as a separate element, if it's present. - versionA.push(...versionA.pop().split("-")); - versionB.push(...versionB.pop().split("-")); + } - var elementsToCompare = Math.min(versionA.length, versionB.length); + return version; +}; + +/** + * Returns true if two version strings could represent the same version. This is true + * if, after passing the versions through getBinVersionFor, the versions have the + * same value for each version component up through the length of the shorter version. + * + * That is, 3.2.4 compares equal to 3.2, but 3.2.4 does not compare equal to 3.2.3. + */ +MongoRunner.areBinVersionsTheSame = function(versionA, versionB) { + // Check for invalid version strings first. + convertVersionStringToArray(MongoRunner.getBinVersionFor(versionA)); + convertVersionStringToArray(MongoRunner.getBinVersionFor(versionB)); + + try { + return (0 === MongoRunner.compareBinVersions(versionA, versionB)); + } catch (err) { + // compareBinVersions() throws an error if two versions differ only by the git hash. + return false; + } +}; - for (var i = 0; i < elementsToCompare; ++i) { - var elementA = versionA[i]; - var elementB = versionB[i]; +/** + * Compares two version strings and returns: + * 1, if the first is more recent + * 0, if they are equal + * -1, if the first is older + * + * Note that this function only compares up to the length of the shorter version. + * Because of this, minor versions will compare equal to the major versions they stem + * from, but major-major and minor-minor version pairs will undergo strict comparison. + */ +MongoRunner.compareBinVersions = function(versionA, versionB) { + let stringA = versionA; + let stringB = versionB; - if (elementA === elementB) { - continue; - } + versionA = convertVersionStringToArray(MongoRunner.getBinVersionFor(versionA)); + versionB = convertVersionStringToArray(MongoRunner.getBinVersionFor(versionB)); - var numA = parseInt(elementA); - var numB = parseInt(elementB); + // Treat the githash as a separate element, if it's present. + versionA.push(...versionA.pop().split("-")); + versionB.push(...versionB.pop().split("-")); - assert(!isNaN(numA) && !isNaN(numB), "Cannot compare non-equal non-numeric versions."); + var elementsToCompare = Math.min(versionA.length, versionB.length); - if (numA > numB) { - return 1; - } else if (numA < numB) { - return -1; - } + for (var i = 0; i < elementsToCompare; ++i) { + var elementA = versionA[i]; + var elementB = versionB[i]; - assert(false, `Unreachable case. Provided versions: {${stringA}, ${stringB}}`); + if (elementA === elementB) { + continue; } - return 0; - }; - - MongoRunner.logicalOptions = { - runId: true, - env: true, - pathOpts: true, - remember: true, - noRemember: true, - appendOptions: true, - restart: true, - noCleanData: true, - cleanData: true, - startClean: true, - forceLock: true, - useLogFiles: true, - logFile: true, - useHostName: true, - useHostname: true, - noReplSet: true, - forgetPort: true, - arbiter: true, - noJournal: true, - binVersion: true, - waitForConnect: true, - bridgeOptions: true, - skipValidation: true, - }; + var numA = parseInt(elementA); + var numB = parseInt(elementB); - MongoRunner.toRealPath = function(path, pathOpts) { + assert(!isNaN(numA) && !isNaN(numB), "Cannot compare non-equal non-numeric versions."); - // Replace all $pathOptions with actual values - pathOpts = pathOpts || {}; - path = path.replace(/\$dataPath/g, MongoRunner.dataPath); - path = path.replace(/\$dataDir/g, MongoRunner.dataDir); - for (var key in pathOpts) { - path = path.replace(RegExp("\\$" + RegExp.escape(key), "g"), pathOpts[key]); + if (numA > numB) { + return 1; + } else if (numA < numB) { + return -1; } - // Relative path - // Detect Unix and Windows absolute paths - // as well as Windows drive letters - // Also captures Windows UNC paths + assert(false, `Unreachable case. Provided versions: {${stringA}, ${stringB}}`); + } - if (!path.match(/^(\/|\\|[A-Za-z]:)/)) { - if (path != "" && !path.endsWith("/")) - path += "/"; + return 0; +}; + +MongoRunner.logicalOptions = { + runId: true, + env: true, + pathOpts: true, + remember: true, + noRemember: true, + appendOptions: true, + restart: true, + noCleanData: true, + cleanData: true, + startClean: true, + forceLock: true, + useLogFiles: true, + logFile: true, + useHostName: true, + useHostname: true, + noReplSet: true, + forgetPort: true, + arbiter: true, + noJournal: true, + binVersion: true, + waitForConnect: true, + bridgeOptions: true, + skipValidation: true, +}; + +MongoRunner.toRealPath = function(path, pathOpts) { + // Replace all $pathOptions with actual values + pathOpts = pathOpts || {}; + path = path.replace(/\$dataPath/g, MongoRunner.dataPath); + path = path.replace(/\$dataDir/g, MongoRunner.dataDir); + for (var key in pathOpts) { + path = path.replace(RegExp("\\$" + RegExp.escape(key), "g"), pathOpts[key]); + } - path = MongoRunner.dataPath + path; - } + // Relative path + // Detect Unix and Windows absolute paths + // as well as Windows drive letters + // Also captures Windows UNC paths - return path; + if (!path.match(/^(\/|\\|[A-Za-z]:)/)) { + if (path != "" && !path.endsWith("/")) + path += "/"; - }; + path = MongoRunner.dataPath + path; + } - MongoRunner.toRealDir = function(path, pathOpts) { + return path; +}; - path = MongoRunner.toRealPath(path, pathOpts); +MongoRunner.toRealDir = function(path, pathOpts) { + path = MongoRunner.toRealPath(path, pathOpts); - if (path.endsWith("/")) - path = path.substring(0, path.length - 1); + if (path.endsWith("/")) + path = path.substring(0, path.length - 1); - return path; - }; + return path; +}; - MongoRunner.toRealFile = MongoRunner.toRealDir; +MongoRunner.toRealFile = MongoRunner.toRealDir; - /** - * Returns an iterator object which yields successive versions on calls to advance(), starting - * from a random initial position, from an array of versions. - * - * If passed a single version string or an already-existing version iterator, just returns the - * object itself, since it will yield correctly on calls to advance(). - * - * @param {Array.<String>}|{String}|{versionIterator} - */ - MongoRunner.versionIterator = function(arr, isRandom) { +/** + * Returns an iterator object which yields successive versions on calls to advance(), starting + * from a random initial position, from an array of versions. + * + * If passed a single version string or an already-existing version iterator, just returns the + * object itself, since it will yield correctly on calls to advance(). + * + * @param {Array.<String>}|{String}|{versionIterator} + */ +MongoRunner.versionIterator = function(arr, isRandom) { + // If this isn't an array of versions, or is already an iterator, just use it + if (typeof arr == "string") + return arr; + if (arr.isVersionIterator) + return arr; - // If this isn't an array of versions, or is already an iterator, just use it - if (typeof arr == "string") - return arr; - if (arr.isVersionIterator) - return arr; + if (isRandom == undefined) + isRandom = false; - if (isRandom == undefined) - isRandom = false; + // Starting pos + var i = isRandom ? parseInt(Random.rand() * arr.length) : 0; - // Starting pos - var i = isRandom ? parseInt(Random.rand() * arr.length) : 0; + return new MongoRunner.versionIterator.iterator(i, arr); +}; - return new MongoRunner.versionIterator.iterator(i, arr); +MongoRunner.versionIterator.iterator = function(i, arr) { + if (!Array.isArray(arr)) { + throw new Error("Expected an array for the second argument, but got: " + tojson(arr)); + } + + this.current = function current() { + return arr[i]; }; - MongoRunner.versionIterator.iterator = function(i, arr) { - if (!Array.isArray(arr)) { - throw new Error("Expected an array for the second argument, but got: " + tojson(arr)); - } + // We define the toString() method as an alias for current() so that concatenating a version + // iterator with a string returns the next version in the list without introducing any + // side-effects. + this.toString = this.current; - this.current = function current() { - return arr[i]; - }; + this.advance = function advance() { + i = (i + 1) % arr.length; + }; - // We define the toString() method as an alias for current() so that concatenating a version - // iterator with a string returns the next version in the list without introducing any - // side-effects. - this.toString = this.current; + this.isVersionIterator = true; +}; + +/** + * Converts the args object by pairing all keys with their value and appending + * dash-dash (--) to the keys. The only exception to this rule are keys that + * are defined in MongoRunner.logicalOptions, of which they will be ignored. + * + * @param {string} binaryName + * @param {Object} args + * + * @return {Array.<String>} an array of parameter strings that can be passed + * to the binary. + */ +MongoRunner.arrOptions = function(binaryName, args) { + var fullArgs = [""]; + + // isObject returns true even if "args" is an array, so the else branch of this statement is + // dead code. See SERVER-14220. + if (isObject(args) || (args.length == 1 && isObject(args[0]))) { + var o = isObject(args) ? args : args[0]; + + // If we've specified a particular binary version, use that + if (o.binVersion && o.binVersion != "" && o.binVersion != shellVersion()) { + binaryName += "-" + o.binVersion; + } + + // Manage legacy options + var isValidOptionForBinary = function(option, value) { + if (!o.binVersion) + return true; - this.advance = function advance() { - i = (i + 1) % arr.length; + return true; }; - this.isVersionIterator = true; + var addOptionsToFullArgs = function(k, v) { + if (v === undefined || v === null) + return; - }; + fullArgs.push("--" + k); - /** - * Converts the args object by pairing all keys with their value and appending - * dash-dash (--) to the keys. The only exception to this rule are keys that - * are defined in MongoRunner.logicalOptions, of which they will be ignored. - * - * @param {string} binaryName - * @param {Object} args - * - * @return {Array.<String>} an array of parameter strings that can be passed - * to the binary. - */ - MongoRunner.arrOptions = function(binaryName, args) { - - var fullArgs = [""]; - - // isObject returns true even if "args" is an array, so the else branch of this statement is - // dead code. See SERVER-14220. - if (isObject(args) || (args.length == 1 && isObject(args[0]))) { - var o = isObject(args) ? args : args[0]; - - // If we've specified a particular binary version, use that - if (o.binVersion && o.binVersion != "" && o.binVersion != shellVersion()) { - binaryName += "-" + o.binVersion; + if (v != "") { + fullArgs.push("" + v); } + }; - // Manage legacy options - var isValidOptionForBinary = function(option, value) { - - if (!o.binVersion) - return true; - - return true; - }; - - var addOptionsToFullArgs = function(k, v) { - if (v === undefined || v === null) - return; - - fullArgs.push("--" + k); - - if (v != "") { - fullArgs.push("" + v); - } - }; - - for (var k in o) { - // Make sure our logical option should be added to the array of options - if (!o.hasOwnProperty(k) || k in MongoRunner.logicalOptions || - !isValidOptionForBinary(k, o[k])) - continue; + for (var k in o) { + // Make sure our logical option should be added to the array of options + if (!o.hasOwnProperty(k) || k in MongoRunner.logicalOptions || + !isValidOptionForBinary(k, o[k])) + continue; - if ((k == "v" || k == "verbose") && isNumber(o[k])) { - var n = o[k]; - if (n > 0) { - if (n > 10) - n = 10; - var temp = "-"; - while (n-- > 0) - temp += "v"; - fullArgs.push(temp); - } - } else if (k === "setParameter" && isObject(o[k])) { - // If the value associated with the setParameter option is an object, we want - // to add all key-value pairs in that object as separate --setParameters. - Object.keys(o[k]).forEach(function(paramKey) { - addOptionsToFullArgs(k, "" + paramKey + "=" + o[k][paramKey]); - }); - } else { - addOptionsToFullArgs(k, o[k]); + if ((k == "v" || k == "verbose") && isNumber(o[k])) { + var n = o[k]; + if (n > 0) { + if (n > 10) + n = 10; + var temp = "-"; + while (n-- > 0) + temp += "v"; + fullArgs.push(temp); } + } else if (k === "setParameter" && isObject(o[k])) { + // If the value associated with the setParameter option is an object, we want + // to add all key-value pairs in that object as separate --setParameters. + Object.keys(o[k]).forEach(function(paramKey) { + addOptionsToFullArgs(k, "" + paramKey + "=" + o[k][paramKey]); + }); + } else { + addOptionsToFullArgs(k, o[k]); } - } else { - for (var i = 0; i < args.length; i++) - fullArgs.push(args[i]); } + } else { + for (var i = 0; i < args.length; i++) + fullArgs.push(args[i]); + } - fullArgs[0] = binaryName; - return fullArgs; - }; - - MongoRunner.arrToOpts = function(arr) { + fullArgs[0] = binaryName; + return fullArgs; +}; - var opts = {}; - for (var i = 1; i < arr.length; i++) { - if (arr[i].startsWith("-")) { - var opt = arr[i].replace(/^-/, "").replace(/^-/, ""); +MongoRunner.arrToOpts = function(arr) { + var opts = {}; + for (var i = 1; i < arr.length; i++) { + if (arr[i].startsWith("-")) { + var opt = arr[i].replace(/^-/, "").replace(/^-/, ""); - if (arr.length > i + 1 && !arr[i + 1].startsWith("-")) { - opts[opt] = arr[i + 1]; - i++; - } else { - opts[opt] = ""; - } + if (arr.length > i + 1 && !arr[i + 1].startsWith("-")) { + opts[opt] = arr[i + 1]; + i++; + } else { + opts[opt] = ""; + } - if (opt.replace(/v/g, "") == "") { - opts["verbose"] = opt.length; - } + if (opt.replace(/v/g, "") == "") { + opts["verbose"] = opt.length; } } + } - return opts; - }; + return opts; +}; - MongoRunner.savedOptions = {}; +MongoRunner.savedOptions = {}; - MongoRunner.mongoOptions = function(opts) { - // Don't remember waitForConnect - var waitForConnect = opts.waitForConnect; - delete opts.waitForConnect; +MongoRunner.mongoOptions = function(opts) { + // Don't remember waitForConnect + var waitForConnect = opts.waitForConnect; + delete opts.waitForConnect; - // If we're a mongo object - if (opts.getDB) { - opts = {restart: opts.runId}; - } + // If we're a mongo object + if (opts.getDB) { + opts = {restart: opts.runId}; + } - // Initialize and create a copy of the opts - opts = Object.merge(opts || {}, {}); + // Initialize and create a copy of the opts + opts = Object.merge(opts || {}, {}); - if (!opts.restart) - opts.restart = false; + if (!opts.restart) + opts.restart = false; - // RunId can come from a number of places - // If restart is passed as an old connection - if (opts.restart && opts.restart.getDB) { - opts.runId = opts.restart.runId; - opts.restart = true; - } - // If it's the runId itself - else if (isObject(opts.restart)) { - opts.runId = opts.restart; - opts.restart = true; - } + // RunId can come from a number of places + // If restart is passed as an old connection + if (opts.restart && opts.restart.getDB) { + opts.runId = opts.restart.runId; + opts.restart = true; + } + // If it's the runId itself + else if (isObject(opts.restart)) { + opts.runId = opts.restart; + opts.restart = true; + } - if (isObject(opts.remember)) { - opts.runId = opts.remember; - opts.remember = true; - } else if (opts.remember == undefined) { - // Remember by default if we're restarting - opts.remember = opts.restart; - } + if (isObject(opts.remember)) { + opts.runId = opts.remember; + opts.remember = true; + } else if (opts.remember == undefined) { + // Remember by default if we're restarting + opts.remember = opts.restart; + } - // If we passed in restart : <conn> or runId : <conn> - if (isObject(opts.runId) && opts.runId.runId) - opts.runId = opts.runId.runId; + // If we passed in restart : <conn> or runId : <conn> + if (isObject(opts.runId) && opts.runId.runId) + opts.runId = opts.runId.runId; - if (opts.restart && opts.remember) { - opts = Object.merge(MongoRunner.savedOptions[opts.runId], opts); - } + if (opts.restart && opts.remember) { + opts = Object.merge(MongoRunner.savedOptions[opts.runId], opts); + } - // Create a new runId - opts.runId = opts.runId || ObjectId(); + // Create a new runId + opts.runId = opts.runId || ObjectId(); - if (opts.forgetPort) { - delete opts.port; - } + if (opts.forgetPort) { + delete opts.port; + } - // Normalize and get the binary version to use - if (opts.hasOwnProperty('binVersion')) { - if (opts.binVersion instanceof MongoRunner.versionIterator.iterator) { - // Advance the version iterator so that subsequent calls to - // MongoRunner.mongoOptions() use the next version in the list. - const iterator = opts.binVersion; - opts.binVersion = iterator.current(); - iterator.advance(); - } - opts.binVersion = MongoRunner.getBinVersionFor(opts.binVersion); + // Normalize and get the binary version to use + if (opts.hasOwnProperty('binVersion')) { + if (opts.binVersion instanceof MongoRunner.versionIterator.iterator) { + // Advance the version iterator so that subsequent calls to + // MongoRunner.mongoOptions() use the next version in the list. + const iterator = opts.binVersion; + opts.binVersion = iterator.current(); + iterator.advance(); } + opts.binVersion = MongoRunner.getBinVersionFor(opts.binVersion); + } - // Default for waitForConnect is true - opts.waitForConnect = - (waitForConnect == undefined || waitForConnect == null) ? true : waitForConnect; + // Default for waitForConnect is true + opts.waitForConnect = + (waitForConnect == undefined || waitForConnect == null) ? true : waitForConnect; - opts.port = opts.port || allocatePort(); + opts.port = opts.port || allocatePort(); - opts.pathOpts = - Object.merge(opts.pathOpts || {}, {port: "" + opts.port, runId: "" + opts.runId}); + opts.pathOpts = + Object.merge(opts.pathOpts || {}, {port: "" + opts.port, runId: "" + opts.runId}); - var shouldRemember = - (!opts.restart && !opts.noRemember) || (opts.restart && opts.appendOptions); - if (shouldRemember) { - MongoRunner.savedOptions[opts.runId] = Object.merge(opts, {}); - } + var shouldRemember = + (!opts.restart && !opts.noRemember) || (opts.restart && opts.appendOptions); + if (shouldRemember) { + MongoRunner.savedOptions[opts.runId] = Object.merge(opts, {}); + } - if (jsTestOptions().networkMessageCompressors) { - opts.networkMessageCompressors = jsTestOptions().networkMessageCompressors; - } + if (jsTestOptions().networkMessageCompressors) { + opts.networkMessageCompressors = jsTestOptions().networkMessageCompressors; + } - if (!opts.hasOwnProperty('bind_ip')) { - opts.bind_ip = "0.0.0.0"; - } + if (!opts.hasOwnProperty('bind_ip')) { + opts.bind_ip = "0.0.0.0"; + } - return opts; - }; + return opts; +}; - // Returns an array of integers representing the version provided. - // Ex: "3.3.12" => [3, 3, 12] - var _convertVersionToIntegerArray = function(version) { - var versionParts = - convertVersionStringToArray(version).slice(0, 3).map(part => parseInt(part, 10)); - if (versionParts.length === 2) { - versionParts.push(Infinity); - } - return versionParts; - }; +// Returns an array of integers representing the version provided. +// Ex: "3.3.12" => [3, 3, 12] +var _convertVersionToIntegerArray = function(version) { + var versionParts = + convertVersionStringToArray(version).slice(0, 3).map(part => parseInt(part, 10)); + if (versionParts.length === 2) { + versionParts.push(Infinity); + } + return versionParts; +}; - // Returns if version2 is equal to, or came after, version 1. - var _isMongodVersionEqualOrAfter = function(version1, version2) { - if (version2 === "latest") { - return true; - } +// Returns if version2 is equal to, or came after, version 1. +var _isMongodVersionEqualOrAfter = function(version1, version2) { + if (version2 === "latest") { + return true; + } - var versionParts1 = _convertVersionToIntegerArray(version1); - var versionParts2 = _convertVersionToIntegerArray(version2); - if (versionParts2[0] > versionParts1[0] || - (versionParts2[0] === versionParts1[0] && versionParts2[1] > versionParts1[1]) || - (versionParts2[0] === versionParts1[0] && versionParts2[1] === versionParts1[1] && - versionParts2[2] >= versionParts1[2])) { - return true; - } + var versionParts1 = _convertVersionToIntegerArray(version1); + var versionParts2 = _convertVersionToIntegerArray(version2); + if (versionParts2[0] > versionParts1[0] || + (versionParts2[0] === versionParts1[0] && versionParts2[1] > versionParts1[1]) || + (versionParts2[0] === versionParts1[0] && versionParts2[1] === versionParts1[1] && + versionParts2[2] >= versionParts1[2])) { + return true; + } - return false; - }; + return false; +}; + +// Removes a setParameter parameter from mongods running a version that won't recognize them. +var _removeSetParameterIfBeforeVersion = function(opts, parameterName, requiredVersion) { + var versionCompatible = (opts.binVersion === "" || opts.binVersion === undefined || + _isMongodVersionEqualOrAfter(requiredVersion, opts.binVersion)); + if (!versionCompatible && opts.setParameter && opts.setParameter[parameterName] != undefined) { + print("Removing '" + parameterName + "' setParameter with value " + + opts.setParameter[parameterName] + + " because it isn't compatibile with mongod running version " + opts.binVersion); + delete opts.setParameter[parameterName]; + } +}; + +/** + * @option {object} opts + * + * { + * dbpath {string} + * useLogFiles {boolean}: use with logFile option. + * logFile {string}: path to the log file. If not specified and useLogFiles + * is true, automatically creates a log file inside dbpath. + * noJournal {boolean} + * keyFile + * replSet + * oplogSize + * } + */ +MongoRunner.mongodOptions = function(opts) { + opts = MongoRunner.mongoOptions(opts); + + opts.dbpath = MongoRunner.toRealDir(opts.dbpath || "$dataDir/mongod-$port", opts.pathOpts); + + opts.pathOpts = Object.merge(opts.pathOpts, {dbpath: opts.dbpath}); + + _removeSetParameterIfBeforeVersion(opts, "writePeriodicNoops", "3.3.12"); + _removeSetParameterIfBeforeVersion(opts, "numInitialSyncAttempts", "3.3.12"); + _removeSetParameterIfBeforeVersion(opts, "numInitialSyncConnectAttempts", "3.3.12"); + _removeSetParameterIfBeforeVersion(opts, "migrationLockAcquisitionMaxWaitMS", "4.1.7"); + + if (!opts.logFile && opts.useLogFiles) { + opts.logFile = opts.dbpath + "/mongod.log"; + } else if (opts.logFile) { + opts.logFile = MongoRunner.toRealFile(opts.logFile, opts.pathOpts); + } - // Removes a setParameter parameter from mongods running a version that won't recognize them. - var _removeSetParameterIfBeforeVersion = function(opts, parameterName, requiredVersion) { - var versionCompatible = (opts.binVersion === "" || opts.binVersion === undefined || - _isMongodVersionEqualOrAfter(requiredVersion, opts.binVersion)); - if (!versionCompatible && opts.setParameter && - opts.setParameter[parameterName] != undefined) { - print("Removing '" + parameterName + "' setParameter with value " + - opts.setParameter[parameterName] + - " because it isn't compatibile with mongod running version " + opts.binVersion); - delete opts.setParameter[parameterName]; - } - }; + if (opts.logFile !== undefined) { + opts.logpath = opts.logFile; + } - /** - * @option {object} opts - * - * { - * dbpath {string} - * useLogFiles {boolean}: use with logFile option. - * logFile {string}: path to the log file. If not specified and useLogFiles - * is true, automatically creates a log file inside dbpath. - * noJournal {boolean} - * keyFile - * replSet - * oplogSize - * } - */ - MongoRunner.mongodOptions = function(opts) { - - opts = MongoRunner.mongoOptions(opts); - - opts.dbpath = MongoRunner.toRealDir(opts.dbpath || "$dataDir/mongod-$port", opts.pathOpts); - - opts.pathOpts = Object.merge(opts.pathOpts, {dbpath: opts.dbpath}); - - _removeSetParameterIfBeforeVersion(opts, "writePeriodicNoops", "3.3.12"); - _removeSetParameterIfBeforeVersion(opts, "numInitialSyncAttempts", "3.3.12"); - _removeSetParameterIfBeforeVersion(opts, "numInitialSyncConnectAttempts", "3.3.12"); - _removeSetParameterIfBeforeVersion(opts, "migrationLockAcquisitionMaxWaitMS", "4.1.7"); - - if (!opts.logFile && opts.useLogFiles) { - opts.logFile = opts.dbpath + "/mongod.log"; - } else if (opts.logFile) { - opts.logFile = MongoRunner.toRealFile(opts.logFile, opts.pathOpts); - } + if ((jsTestOptions().noJournal || opts.noJournal) && !('journal' in opts) && + !('configsvr' in opts)) { + opts.nojournal = ""; + } - if (opts.logFile !== undefined) { - opts.logpath = opts.logFile; - } + if (jsTestOptions().keyFile && !opts.keyFile) { + opts.keyFile = jsTestOptions().keyFile; + } - if ((jsTestOptions().noJournal || opts.noJournal) && !('journal' in opts) && - !('configsvr' in opts)) { - opts.nojournal = ""; + if (opts.hasOwnProperty("enableEncryption")) { + // opts.enableEncryption, if set, must be an empty string + if (opts.enableEncryption !== "") { + throw new Error("The enableEncryption option must be an empty string if it is " + + "specified"); } - - if (jsTestOptions().keyFile && !opts.keyFile) { - opts.keyFile = jsTestOptions().keyFile; + } else if (jsTestOptions().enableEncryption !== undefined) { + if (jsTestOptions().enableEncryption !== "") { + throw new Error("The enableEncryption option must be an empty string if it is " + + "specified"); } + opts.enableEncryption = ""; + } - if (opts.hasOwnProperty("enableEncryption")) { - // opts.enableEncryption, if set, must be an empty string - if (opts.enableEncryption !== "") { - throw new Error("The enableEncryption option must be an empty string if it is " + - "specified"); - } - } else if (jsTestOptions().enableEncryption !== undefined) { - if (jsTestOptions().enableEncryption !== "") { - throw new Error("The enableEncryption option must be an empty string if it is " + - "specified"); - } - opts.enableEncryption = ""; + if (opts.hasOwnProperty("encryptionKeyFile")) { + // opts.encryptionKeyFile, if set, must be a string + if (typeof opts.encryptionKeyFile !== "string") { + throw new Error("The encryptionKeyFile option must be a string if it is specified"); } - - if (opts.hasOwnProperty("encryptionKeyFile")) { - // opts.encryptionKeyFile, if set, must be a string - if (typeof opts.encryptionKeyFile !== "string") { - throw new Error("The encryptionKeyFile option must be a string if it is specified"); - } - } else if (jsTestOptions().encryptionKeyFile !== undefined) { - if (typeof(jsTestOptions().encryptionKeyFile) !== "string") { - throw new Error("The encryptionKeyFile option must be a string if it is specified"); - } - opts.encryptionKeyFile = jsTestOptions().encryptionKeyFile; + } else if (jsTestOptions().encryptionKeyFile !== undefined) { + if (typeof (jsTestOptions().encryptionKeyFile) !== "string") { + throw new Error("The encryptionKeyFile option must be a string if it is specified"); } + opts.encryptionKeyFile = jsTestOptions().encryptionKeyFile; + } - if (opts.hasOwnProperty("auditDestination")) { - // opts.auditDestination, if set, must be a string - if (typeof opts.auditDestination !== "string") { - throw new Error("The auditDestination option must be a string if it is specified"); - } - } else if (jsTestOptions().auditDestination !== undefined) { - if (typeof(jsTestOptions().auditDestination) !== "string") { - throw new Error("The auditDestination option must be a string if it is specified"); - } - opts.auditDestination = jsTestOptions().auditDestination; + if (opts.hasOwnProperty("auditDestination")) { + // opts.auditDestination, if set, must be a string + if (typeof opts.auditDestination !== "string") { + throw new Error("The auditDestination option must be a string if it is specified"); } - - if (opts.noReplSet) - opts.replSet = null; - if (opts.arbiter) - opts.oplogSize = 1; - - return opts; - }; - - MongoRunner.mongosOptions = function(opts) { - opts = MongoRunner.mongoOptions(opts); - - // Normalize configdb option to be host string if currently a host - if (opts.configdb && opts.configdb.getDB) { - opts.configdb = opts.configdb.host; + } else if (jsTestOptions().auditDestination !== undefined) { + if (typeof (jsTestOptions().auditDestination) !== "string") { + throw new Error("The auditDestination option must be a string if it is specified"); } + opts.auditDestination = jsTestOptions().auditDestination; + } - opts.pathOpts = - Object.merge(opts.pathOpts, {configdb: opts.configdb.replace(/:|\/|,/g, "-")}); + if (opts.noReplSet) + opts.replSet = null; + if (opts.arbiter) + opts.oplogSize = 1; - if (!opts.logFile && opts.useLogFiles) { - opts.logFile = - MongoRunner.toRealFile("$dataDir/mongos-$configdb-$port.log", opts.pathOpts); - } else if (opts.logFile) { - opts.logFile = MongoRunner.toRealFile(opts.logFile, opts.pathOpts); - } + return opts; +}; - if (opts.logFile !== undefined) { - opts.logpath = opts.logFile; - } +MongoRunner.mongosOptions = function(opts) { + opts = MongoRunner.mongoOptions(opts); - var testOptions = jsTestOptions(); - if (testOptions.keyFile && !opts.keyFile) { - opts.keyFile = testOptions.keyFile; - } + // Normalize configdb option to be host string if currently a host + if (opts.configdb && opts.configdb.getDB) { + opts.configdb = opts.configdb.host; + } - if (opts.hasOwnProperty("auditDestination")) { - // opts.auditDestination, if set, must be a string - if (typeof opts.auditDestination !== "string") { - throw new Error("The auditDestination option must be a string if it is specified"); - } - } else if (testOptions.auditDestination !== undefined) { - if (typeof(testOptions.auditDestination) !== "string") { - throw new Error("The auditDestination option must be a string if it is specified"); - } - opts.auditDestination = testOptions.auditDestination; - } + opts.pathOpts = Object.merge(opts.pathOpts, {configdb: opts.configdb.replace(/:|\/|,/g, "-")}); - if (!opts.hasOwnProperty('binVersion') && testOptions.mongosBinVersion) { - opts.binVersion = MongoRunner.getBinVersionFor(testOptions.mongosBinVersion); - } - - // If the mongos is being restarted with a newer version, make sure we remove any options - // that no longer exist in the newer version. - if (opts.restart && MongoRunner.areBinVersionsTheSame('latest', opts.binVersion)) { - delete opts.noAutoSplit; - } + if (!opts.logFile && opts.useLogFiles) { + opts.logFile = MongoRunner.toRealFile("$dataDir/mongos-$configdb-$port.log", opts.pathOpts); + } else if (opts.logFile) { + opts.logFile = MongoRunner.toRealFile(opts.logFile, opts.pathOpts); + } - return opts; - }; + if (opts.logFile !== undefined) { + opts.logpath = opts.logFile; + } - /** - * Starts a mongod instance. - * - * @param {Object} opts - * - * { - * useHostName {boolean}: Uses hostname of machine if true. - * forceLock {boolean}: Deletes the lock file if set to true. - * dbpath {string}: location of db files. - * cleanData {boolean}: Removes all files in dbpath if true. - * startClean {boolean}: same as cleanData. - * noCleanData {boolean}: Do not clean files (cleanData takes priority). - * binVersion {string}: version for binary (also see MongoRunner.binVersionSubs). - * - * @see MongoRunner.mongodOptions for other options - * } - * - * @return {Mongo} connection object to the started mongod instance. - * - * @see MongoRunner.arrOptions - */ - MongoRunner.runMongod = function(opts) { - - opts = opts || {}; - var env = undefined; - var useHostName = true; - var runId = null; - var waitForConnect = true; - var fullOptions = opts; - - if (isObject(opts)) { - opts = MongoRunner.mongodOptions(opts); - fullOptions = opts; - - if (opts.useHostName != undefined) { - useHostName = opts.useHostName; - } else if (opts.useHostname != undefined) { - useHostName = opts.useHostname; - } else { - useHostName = true; // Default to true - } - env = opts.env; - runId = opts.runId; - waitForConnect = opts.waitForConnect; - - if (opts.forceLock) - removeFile(opts.dbpath + "/mongod.lock"); - if ((opts.cleanData || opts.startClean) || (!opts.restart && !opts.noCleanData)) { - print("Resetting db path '" + opts.dbpath + "'"); - resetDbpath(opts.dbpath); - } + var testOptions = jsTestOptions(); + if (testOptions.keyFile && !opts.keyFile) { + opts.keyFile = testOptions.keyFile; + } - var mongodProgram = MongoRunner.mongodPath; - opts = MongoRunner.arrOptions(mongodProgram, opts); + if (opts.hasOwnProperty("auditDestination")) { + // opts.auditDestination, if set, must be a string + if (typeof opts.auditDestination !== "string") { + throw new Error("The auditDestination option must be a string if it is specified"); } - - var mongod = MongoRunner._startWithArgs(opts, env, waitForConnect); - if (!mongod) { - return null; + } else if (testOptions.auditDestination !== undefined) { + if (typeof (testOptions.auditDestination) !== "string") { + throw new Error("The auditDestination option must be a string if it is specified"); } + opts.auditDestination = testOptions.auditDestination; + } - mongod.commandLine = MongoRunner.arrToOpts(opts); - mongod.name = (useHostName ? getHostName() : "localhost") + ":" + mongod.commandLine.port; - mongod.host = mongod.name; - mongod.port = parseInt(mongod.commandLine.port); - mongod.runId = runId || ObjectId(); - mongod.dbpath = fullOptions.dbpath; - mongod.savedOptions = MongoRunner.savedOptions[mongod.runId]; - mongod.fullOptions = fullOptions; + if (!opts.hasOwnProperty('binVersion') && testOptions.mongosBinVersion) { + opts.binVersion = MongoRunner.getBinVersionFor(testOptions.mongosBinVersion); + } - return mongod; - }; + // If the mongos is being restarted with a newer version, make sure we remove any options + // that no longer exist in the newer version. + if (opts.restart && MongoRunner.areBinVersionsTheSame('latest', opts.binVersion)) { + delete opts.noAutoSplit; + } - MongoRunner.runMongos = function(opts) { - opts = opts || {}; - - var env = undefined; - var useHostName = false; - var runId = null; - var waitForConnect = true; - var fullOptions = opts; - - if (isObject(opts)) { - opts = MongoRunner.mongosOptions(opts); - fullOptions = opts; - - useHostName = opts.useHostName || opts.useHostname; - runId = opts.runId; - waitForConnect = opts.waitForConnect; - env = opts.env; - var mongosProgram = MongoRunner.mongosPath; - opts = MongoRunner.arrOptions(mongosProgram, opts); + return opts; +}; + +/** + * Starts a mongod instance. + * + * @param {Object} opts + * + * { + * useHostName {boolean}: Uses hostname of machine if true. + * forceLock {boolean}: Deletes the lock file if set to true. + * dbpath {string}: location of db files. + * cleanData {boolean}: Removes all files in dbpath if true. + * startClean {boolean}: same as cleanData. + * noCleanData {boolean}: Do not clean files (cleanData takes priority). + * binVersion {string}: version for binary (also see MongoRunner.binVersionSubs). + * + * @see MongoRunner.mongodOptions for other options + * } + * + * @return {Mongo} connection object to the started mongod instance. + * + * @see MongoRunner.arrOptions + */ +MongoRunner.runMongod = function(opts) { + opts = opts || {}; + var env = undefined; + var useHostName = true; + var runId = null; + var waitForConnect = true; + var fullOptions = opts; + + if (isObject(opts)) { + opts = MongoRunner.mongodOptions(opts); + fullOptions = opts; + + if (opts.useHostName != undefined) { + useHostName = opts.useHostName; + } else if (opts.useHostname != undefined) { + useHostName = opts.useHostname; + } else { + useHostName = true; // Default to true } + env = opts.env; + runId = opts.runId; + waitForConnect = opts.waitForConnect; - var mongos = MongoRunner._startWithArgs(opts, env, waitForConnect); - if (!mongos) { - return null; + if (opts.forceLock) + removeFile(opts.dbpath + "/mongod.lock"); + if ((opts.cleanData || opts.startClean) || (!opts.restart && !opts.noCleanData)) { + print("Resetting db path '" + opts.dbpath + "'"); + resetDbpath(opts.dbpath); } - mongos.commandLine = MongoRunner.arrToOpts(opts); - mongos.name = (useHostName ? getHostName() : "localhost") + ":" + mongos.commandLine.port; - mongos.host = mongos.name; - mongos.port = parseInt(mongos.commandLine.port); - mongos.runId = runId || ObjectId(); - mongos.savedOptions = MongoRunner.savedOptions[mongos.runId]; - mongos.fullOptions = fullOptions; - - return mongos; - }; + var mongodProgram = MongoRunner.mongodPath; + opts = MongoRunner.arrOptions(mongodProgram, opts); + } - MongoRunner.StopError = function(returnCode) { - this.name = "StopError"; - this.returnCode = returnCode; - this.message = "MongoDB process stopped with exit code: " + this.returnCode; - this.stack = this.toString() + "\n" + (new Error()).stack; - }; + var mongod = MongoRunner._startWithArgs(opts, env, waitForConnect); + if (!mongod) { + return null; + } - MongoRunner.StopError.prototype = Object.create(Error.prototype); - MongoRunner.StopError.prototype.constructor = MongoRunner.StopError; - - // Constants for exit codes of MongoDB processes - MongoRunner.EXIT_ABORT = -6; - MongoRunner.EXIT_CLEAN = 0; - MongoRunner.EXIT_BADOPTIONS = 2; - MongoRunner.EXIT_REPLICATION_ERROR = 3; - MongoRunner.EXIT_NEED_UPGRADE = 4; - MongoRunner.EXIT_SHARDING_ERROR = 5; - // SIGKILL is translated to TerminateProcess() on Windows, which causes the program to - // terminate with exit code 1. - MongoRunner.EXIT_SIGKILL = _isWindows() ? 1 : -9; - MongoRunner.EXIT_KILL = 12; - MongoRunner.EXIT_ABRUPT = 14; - MongoRunner.EXIT_NTSERVICE_ERROR = 20; - MongoRunner.EXIT_JAVA = 21; - MongoRunner.EXIT_OOM_MALLOC = 42; - MongoRunner.EXIT_OOM_REALLOC = 43; - MongoRunner.EXIT_FS = 45; - MongoRunner.EXIT_CLOCK_SKEW = 47; // OpTime clock skew; deprecated - MongoRunner.EXIT_NET_ERROR = 48; - MongoRunner.EXIT_WINDOWS_SERVICE_STOP = 49; - MongoRunner.EXIT_POSSIBLE_CORRUPTION = 60; - MongoRunner.EXIT_NEED_DOWNGRADE = 62; - MongoRunner.EXIT_UNCAUGHT = 100; // top level exception that wasn't caught - MongoRunner.EXIT_TEST = 101; - - MongoRunner.validateCollectionsCallback = function(port) {}; - - /** - * Kills a mongod process. - * - * @param {Mongo} conn the connection object to the process to kill - * @param {number} signal The signal number to use for killing - * @param {Object} opts Additional options. Format: - * { - * auth: { - * user {string}: admin user name - * pwd {string}: admin password - * }, - * skipValidation: <bool>, - * allowedExitCode: <int> - * } - * - * Note: The auth option is required in a authenticated mongod running in Windows since - * it uses the shutdown command, which requires admin credentials. - */ - MongoRunner.stopMongod = function(conn, signal, opts) { - if (!conn.pid) { - throw new Error("first arg must have a `pid` property; " + - "it is usually the object returned from MongoRunner.runMongod/s"); - } + mongod.commandLine = MongoRunner.arrToOpts(opts); + mongod.name = (useHostName ? getHostName() : "localhost") + ":" + mongod.commandLine.port; + mongod.host = mongod.name; + mongod.port = parseInt(mongod.commandLine.port); + mongod.runId = runId || ObjectId(); + mongod.dbpath = fullOptions.dbpath; + mongod.savedOptions = MongoRunner.savedOptions[mongod.runId]; + mongod.fullOptions = fullOptions; + + return mongod; +}; + +MongoRunner.runMongos = function(opts) { + opts = opts || {}; + + var env = undefined; + var useHostName = false; + var runId = null; + var waitForConnect = true; + var fullOptions = opts; + + if (isObject(opts)) { + opts = MongoRunner.mongosOptions(opts); + fullOptions = opts; + + useHostName = opts.useHostName || opts.useHostname; + runId = opts.runId; + waitForConnect = opts.waitForConnect; + env = opts.env; + var mongosProgram = MongoRunner.mongosPath; + opts = MongoRunner.arrOptions(mongosProgram, opts); + } - if (!conn.port) { - throw new Error("first arg must have a `port` property; " + - "it is usually the object returned from MongoRunner.runMongod/s"); - } + var mongos = MongoRunner._startWithArgs(opts, env, waitForConnect); + if (!mongos) { + return null; + } - signal = parseInt(signal) || 15; - opts = opts || {}; + mongos.commandLine = MongoRunner.arrToOpts(opts); + mongos.name = (useHostName ? getHostName() : "localhost") + ":" + mongos.commandLine.port; + mongos.host = mongos.name; + mongos.port = parseInt(mongos.commandLine.port); + mongos.runId = runId || ObjectId(); + mongos.savedOptions = MongoRunner.savedOptions[mongos.runId]; + mongos.fullOptions = fullOptions; + + return mongos; +}; + +MongoRunner.StopError = function(returnCode) { + this.name = "StopError"; + this.returnCode = returnCode; + this.message = "MongoDB process stopped with exit code: " + this.returnCode; + this.stack = this.toString() + "\n" + (new Error()).stack; +}; + +MongoRunner.StopError.prototype = Object.create(Error.prototype); +MongoRunner.StopError.prototype.constructor = MongoRunner.StopError; + +// Constants for exit codes of MongoDB processes +MongoRunner.EXIT_ABORT = -6; +MongoRunner.EXIT_CLEAN = 0; +MongoRunner.EXIT_BADOPTIONS = 2; +MongoRunner.EXIT_REPLICATION_ERROR = 3; +MongoRunner.EXIT_NEED_UPGRADE = 4; +MongoRunner.EXIT_SHARDING_ERROR = 5; +// SIGKILL is translated to TerminateProcess() on Windows, which causes the program to +// terminate with exit code 1. +MongoRunner.EXIT_SIGKILL = _isWindows() ? 1 : -9; +MongoRunner.EXIT_KILL = 12; +MongoRunner.EXIT_ABRUPT = 14; +MongoRunner.EXIT_NTSERVICE_ERROR = 20; +MongoRunner.EXIT_JAVA = 21; +MongoRunner.EXIT_OOM_MALLOC = 42; +MongoRunner.EXIT_OOM_REALLOC = 43; +MongoRunner.EXIT_FS = 45; +MongoRunner.EXIT_CLOCK_SKEW = 47; // OpTime clock skew; deprecated +MongoRunner.EXIT_NET_ERROR = 48; +MongoRunner.EXIT_WINDOWS_SERVICE_STOP = 49; +MongoRunner.EXIT_POSSIBLE_CORRUPTION = 60; +MongoRunner.EXIT_NEED_DOWNGRADE = 62; +MongoRunner.EXIT_UNCAUGHT = 100; // top level exception that wasn't caught +MongoRunner.EXIT_TEST = 101; + +MongoRunner.validateCollectionsCallback = function(port) {}; + +/** + * Kills a mongod process. + * + * @param {Mongo} conn the connection object to the process to kill + * @param {number} signal The signal number to use for killing + * @param {Object} opts Additional options. Format: + * { + * auth: { + * user {string}: admin user name + * pwd {string}: admin password + * }, + * skipValidation: <bool>, + * allowedExitCode: <int> + * } + * + * Note: The auth option is required in a authenticated mongod running in Windows since + * it uses the shutdown command, which requires admin credentials. + */ +MongoRunner.stopMongod = function(conn, signal, opts) { + if (!conn.pid) { + throw new Error("first arg must have a `pid` property; " + + "it is usually the object returned from MongoRunner.runMongod/s"); + } - var allowedExitCode = MongoRunner.EXIT_CLEAN; + if (!conn.port) { + throw new Error("first arg must have a `port` property; " + + "it is usually the object returned from MongoRunner.runMongod/s"); + } - if (opts.allowedExitCode) { - allowedExitCode = opts.allowedExitCode; - } + signal = parseInt(signal) || 15; + opts = opts || {}; - var port = parseInt(conn.port); + var allowedExitCode = MongoRunner.EXIT_CLEAN; - var pid = conn.pid; - // If the return code is in the serverExitCodeMap, it means the server crashed on startup. - // We just use the recorded return code instead of stopping the program. - var returnCode; - if (serverExitCodeMap.hasOwnProperty(port)) { - returnCode = serverExitCodeMap[port]; - delete serverExitCodeMap[port]; - } else { - // Invoke callback to validate collections and indexes before shutting down mongod. - // We skip calling the callback function when the expected return code of - // the mongod process is non-zero since it's likely the process has already exited. + if (opts.allowedExitCode) { + allowedExitCode = opts.allowedExitCode; + } - var skipValidation = false; - if (opts.skipValidation) { - skipValidation = true; - } + var port = parseInt(conn.port); - if (allowedExitCode === MongoRunner.EXIT_CLEAN && !skipValidation) { - MongoRunner.validateCollectionsCallback(port); - } + var pid = conn.pid; + // If the return code is in the serverExitCodeMap, it means the server crashed on startup. + // We just use the recorded return code instead of stopping the program. + var returnCode; + if (serverExitCodeMap.hasOwnProperty(port)) { + returnCode = serverExitCodeMap[port]; + delete serverExitCodeMap[port]; + } else { + // Invoke callback to validate collections and indexes before shutting down mongod. + // We skip calling the callback function when the expected return code of + // the mongod process is non-zero since it's likely the process has already exited. - returnCode = _stopMongoProgram(port, signal, opts); + var skipValidation = false; + if (opts.skipValidation) { + skipValidation = true; } - if (allowedExitCode !== returnCode) { - throw new MongoRunner.StopError(returnCode); - } else if (returnCode !== MongoRunner.EXIT_CLEAN) { - print("MongoDB process on port " + port + " intentionally exited with error code ", - returnCode); + + if (allowedExitCode === MongoRunner.EXIT_CLEAN && !skipValidation) { + MongoRunner.validateCollectionsCallback(port); } - return returnCode; - }; + returnCode = _stopMongoProgram(port, signal, opts); + } + if (allowedExitCode !== returnCode) { + throw new MongoRunner.StopError(returnCode); + } else if (returnCode !== MongoRunner.EXIT_CLEAN) { + print("MongoDB process on port " + port + " intentionally exited with error code ", + returnCode); + } - MongoRunner.stopMongos = MongoRunner.stopMongod; - - /** - * Starts an instance of the specified mongo tool - * - * @param {String} binaryName - The name of the tool to run. - * @param {Object} [opts={}] - Options of the form --flag or --key=value to pass to the tool. - * @param {string} [opts.binVersion] - The version of the tool to run. - * - * @param {...string} positionalArgs - Positional arguments to pass to the tool after all - * options have been specified. For example, - * MongoRunner.runMongoTool("executable", {key: value}, arg1, arg2) would invoke - * ./executable --key value arg1 arg2. - * - * @see MongoRunner.arrOptions - */ - MongoRunner.runMongoTool = function(binaryName, opts, ...positionalArgs) { - - var opts = opts || {}; - - // Normalize and get the binary version to use - if (opts.binVersion instanceof MongoRunner.versionIterator.iterator) { - // Advance the version iterator so that subsequent calls to MongoRunner.runMongoTool() - // use the next version in the list. - const iterator = opts.binVersion; - opts.binVersion = iterator.current(); - iterator.advance(); - } - opts.binVersion = MongoRunner.getBinVersionFor(opts.binVersion); + return returnCode; +}; + +MongoRunner.stopMongos = MongoRunner.stopMongod; + +/** + * Starts an instance of the specified mongo tool + * + * @param {String} binaryName - The name of the tool to run. + * @param {Object} [opts={}] - Options of the form --flag or --key=value to pass to the tool. + * @param {string} [opts.binVersion] - The version of the tool to run. + * + * @param {...string} positionalArgs - Positional arguments to pass to the tool after all + * options have been specified. For example, + * MongoRunner.runMongoTool("executable", {key: value}, arg1, arg2) would invoke + * ./executable --key value arg1 arg2. + * + * @see MongoRunner.arrOptions + */ +MongoRunner.runMongoTool = function(binaryName, opts, ...positionalArgs) { + var opts = opts || {}; + + // Normalize and get the binary version to use + if (opts.binVersion instanceof MongoRunner.versionIterator.iterator) { + // Advance the version iterator so that subsequent calls to MongoRunner.runMongoTool() + // use the next version in the list. + const iterator = opts.binVersion; + opts.binVersion = iterator.current(); + iterator.advance(); + } + opts.binVersion = MongoRunner.getBinVersionFor(opts.binVersion); - // Recent versions of the mongo tools support a --dialTimeout flag to set for how - // long they retry connecting to a mongod or mongos process. We have them retry - // connecting for up to 30 seconds to handle when the tests are run on a - // resource-constrained host machine. - // - // The bsondump tool doesn't accept the --dialTimeout flag because it doesn't connect to a - // mongod or mongos process. - if (!opts.hasOwnProperty('dialTimeout') && binaryName !== 'bsondump' && - _toolVersionSupportsDialTimeout(opts.binVersion)) { - opts['dialTimeout'] = '30'; - } + // Recent versions of the mongo tools support a --dialTimeout flag to set for how + // long they retry connecting to a mongod or mongos process. We have them retry + // connecting for up to 30 seconds to handle when the tests are run on a + // resource-constrained host machine. + // + // The bsondump tool doesn't accept the --dialTimeout flag because it doesn't connect to a + // mongod or mongos process. + if (!opts.hasOwnProperty('dialTimeout') && binaryName !== 'bsondump' && + _toolVersionSupportsDialTimeout(opts.binVersion)) { + opts['dialTimeout'] = '30'; + } - // Convert 'opts' into an array of arguments. - var argsArray = MongoRunner.arrOptions(binaryName, opts); + // Convert 'opts' into an array of arguments. + var argsArray = MongoRunner.arrOptions(binaryName, opts); - // Append any positional arguments that were specified. - argsArray.push(...positionalArgs); + // Append any positional arguments that were specified. + argsArray.push(...positionalArgs); - return runMongoProgram.apply(null, argsArray); + return runMongoProgram.apply(null, argsArray); +}; - }; +var _toolVersionSupportsDialTimeout = function(version) { + if (version === "latest" || version === "") { + return true; + } + var versionParts = + convertVersionStringToArray(version).slice(0, 3).map(part => parseInt(part, 10)); + if (versionParts.length === 2) { + versionParts.push(Infinity); + } - var _toolVersionSupportsDialTimeout = function(version) { - if (version === "latest" || version === "") { - return true; - } - var versionParts = - convertVersionStringToArray(version).slice(0, 3).map(part => parseInt(part, 10)); - if (versionParts.length === 2) { - versionParts.push(Infinity); - } + if (versionParts[0] > 3 || (versionParts[0] === 3 && versionParts[1] > 3)) { + // The --dialTimeout command line option is supported by the tools + // with a major version newer than 3.3. + return true; + } - if (versionParts[0] > 3 || (versionParts[0] === 3 && versionParts[1] > 3)) { - // The --dialTimeout command line option is supported by the tools - // with a major version newer than 3.3. + for (var supportedVersion of ["3.3.4", "3.2.5", "3.0.12"]) { + var supportedVersionParts = convertVersionStringToArray(supportedVersion) + .slice(0, 3) + .map(part => parseInt(part, 10)); + if (versionParts[0] === supportedVersionParts[0] && + versionParts[1] === supportedVersionParts[1] && + versionParts[2] >= supportedVersionParts[2]) { return true; } + } + return false; +}; + +// Given a test name figures out a directory for that test to use for dump files and makes sure +// that directory exists and is empty. +MongoRunner.getAndPrepareDumpDirectory = function(testName) { + var dir = MongoRunner.dataPath + testName + "_external/"; + resetDbpath(dir); + return dir; +}; + +// Start a mongod instance and return a 'Mongo' object connected to it. +// This function's arguments are passed as command line arguments to mongod. +// The specified 'dbpath' is cleared if it exists, created if not. +// var conn = _startMongodEmpty("--port", 30000, "--dbpath", "asdf"); +var _startMongodEmpty = function() { + var args = createMongoArgs("mongod", Array.from(arguments)); + + var dbpath = _parsePath.apply(null, args); + resetDbpath(dbpath); + + return startMongoProgram.apply(null, args); +}; + +_startMongod = function() { + print("startMongod WARNING DELETES DATA DIRECTORY THIS IS FOR TESTING ONLY"); + return _startMongodEmpty.apply(null, arguments); +}; + +/** + * Returns a new argArray with any test-specific arguments added. + */ +function appendSetParameterArgs(argArray) { + function argArrayContains(key) { + return (argArray + .filter((val) => { + return typeof val === "string" && val.indexOf(key) === 0; + }) + .length > 0); + } - for (var supportedVersion of["3.3.4", "3.2.5", "3.0.12"]) { - var supportedVersionParts = convertVersionStringToArray(supportedVersion) - .slice(0, 3) - .map(part => parseInt(part, 10)); - if (versionParts[0] === supportedVersionParts[0] && - versionParts[1] === supportedVersionParts[1] && - versionParts[2] >= supportedVersionParts[2]) { - return true; - } - } - return false; - }; - - // Given a test name figures out a directory for that test to use for dump files and makes sure - // that directory exists and is empty. - MongoRunner.getAndPrepareDumpDirectory = function(testName) { - var dir = MongoRunner.dataPath + testName + "_external/"; - resetDbpath(dir); - return dir; - }; - - // Start a mongod instance and return a 'Mongo' object connected to it. - // This function's arguments are passed as command line arguments to mongod. - // The specified 'dbpath' is cleared if it exists, created if not. - // var conn = _startMongodEmpty("--port", 30000, "--dbpath", "asdf"); - var _startMongodEmpty = function() { - var args = createMongoArgs("mongod", Array.from(arguments)); - - var dbpath = _parsePath.apply(null, args); - resetDbpath(dbpath); + function argArrayContainsSetParameterValue(value) { + assert(value.endsWith("="), "Expected value argument to be of the form <parameterName>="); + return argArray.some(function(el) { + return typeof el === "string" && el.startsWith(value); + }); + } - return startMongoProgram.apply(null, args); - }; + // programName includes the version, e.g., mongod-3.2. + // baseProgramName is the program name without any version information, e.g., mongod. + let programName = argArray[0]; - _startMongod = function() { - print("startMongod WARNING DELETES DATA DIRECTORY THIS IS FOR TESTING ONLY"); - return _startMongodEmpty.apply(null, arguments); - }; + let [baseProgramName, programVersion] = programName.split("-"); + let programMajorMinorVersion = 0; + if (programVersion) { + let [major, minor, point] = programVersion.split("."); + programMajorMinorVersion = parseInt(major) * 100 + parseInt(minor); + } - /** - * Returns a new argArray with any test-specific arguments added. - */ - function appendSetParameterArgs(argArray) { - function argArrayContains(key) { - return (argArray - .filter((val) => { - return typeof val === "string" && val.indexOf(key) === 0; - }) - .length > 0); + if (baseProgramName === 'mongod' || baseProgramName === 'mongos') { + if (jsTest.options().enableTestCommands) { + argArray.push(...['--setParameter', "enableTestCommands=1"]); } - - function argArrayContainsSetParameterValue(value) { - assert(value.endsWith("="), - "Expected value argument to be of the form <parameterName>="); - return argArray.some(function(el) { - return typeof el === "string" && el.startsWith(value); - }); + if (jsTest.options().authMechanism && jsTest.options().authMechanism != "SCRAM-SHA-1") { + if (!argArrayContainsSetParameterValue('authenticationMechanisms=')) { + argArray.push(...['--setParameter', + "authenticationMechanisms=" + jsTest.options().authMechanism]); + } } - - // programName includes the version, e.g., mongod-3.2. - // baseProgramName is the program name without any version information, e.g., mongod. - let programName = argArray[0]; - - let [baseProgramName, programVersion] = programName.split("-"); - let programMajorMinorVersion = 0; - if (programVersion) { - let [major, minor, point] = programVersion.split("."); - programMajorMinorVersion = parseInt(major) * 100 + parseInt(minor); + if (jsTest.options().auth) { + argArray.push(...['--setParameter', "enableLocalhostAuthBypass=false"]); } - if (baseProgramName === 'mongod' || baseProgramName === 'mongos') { - if (jsTest.options().enableTestCommands) { - argArray.push(...['--setParameter', "enableTestCommands=1"]); - } - if (jsTest.options().authMechanism && jsTest.options().authMechanism != "SCRAM-SHA-1") { - if (!argArrayContainsSetParameterValue('authenticationMechanisms=')) { - argArray.push( - ...['--setParameter', - "authenticationMechanisms=" + jsTest.options().authMechanism]); + // New options in 3.5.x + if (!programMajorMinorVersion || programMajorMinorVersion >= 305) { + if (jsTest.options().serviceExecutor) { + if (!argArrayContains("--serviceExecutor")) { + argArray.push(...["--serviceExecutor", jsTest.options().serviceExecutor]); } } - if (jsTest.options().auth) { - argArray.push(...['--setParameter', "enableLocalhostAuthBypass=false"]); + + if (jsTest.options().transportLayer) { + if (!argArrayContains("--transportLayer")) { + argArray.push(...["--transportLayer", jsTest.options().transportLayer]); + } } - // New options in 3.5.x - if (!programMajorMinorVersion || programMajorMinorVersion >= 305) { - if (jsTest.options().serviceExecutor) { - if (!argArrayContains("--serviceExecutor")) { - argArray.push(...["--serviceExecutor", jsTest.options().serviceExecutor]); + // Disable background cache refreshing to avoid races in tests + argArray.push(...['--setParameter', "disableLogicalSessionCacheRefresh=true"]); + } + + // Since options may not be backward compatible, mongos options are not + // set on older versions, e.g., mongos-3.0. + if (programName.endsWith('mongos')) { + // apply setParameters for mongos + if (jsTest.options().setParametersMongos) { + let params = jsTest.options().setParametersMongos; + for (let paramName of Object.keys(params)) { + // Only set the 'logComponentVerbosity' parameter if it has not already + // been specified in the given argument array. This means that any + // 'logComponentVerbosity' settings passed through via TestData will + // always be overridden by settings passed directly to MongoRunner from + // within the shell. + if (paramName === "logComponentVerbosity" && + argArrayContains("logComponentVerbosity")) { + continue; } + const paramVal = ((param) => { + if (typeof param === "object") { + return JSON.stringify(param); + } + + return param; + })(params[paramName]); + const setParamStr = paramName + "=" + paramVal; + argArray.push(...['--setParameter', setParamStr]); + } + } + } else if (baseProgramName === 'mongod') { + if (jsTestOptions().roleGraphInvalidationIsFatal) { + argArray.push(...['--setParameter', "roleGraphInvalidationIsFatal=true"]); + } + + // Set storageEngine for mongod. There was no storageEngine parameter before 3.0. + if (jsTest.options().storageEngine && + (!programVersion || programMajorMinorVersion >= 300)) { + if (!argArrayContains("--storageEngine")) { + argArray.push(...['--storageEngine', jsTest.options().storageEngine]); } + } - if (jsTest.options().transportLayer) { - if (!argArrayContains("--transportLayer")) { - argArray.push(...["--transportLayer", jsTest.options().transportLayer]); + // New mongod-specific options in 4.0.x + if (!programMajorMinorVersion || programMajorMinorVersion >= 400) { + if (jsTest.options().transactionLifetimeLimitSeconds !== undefined) { + if (!argArrayContainsSetParameterValue("transactionLifetimeLimitSeconds=")) { + argArray.push(...["--setParameter", + "transactionLifetimeLimitSeconds=" + + jsTest.options().transactionLifetimeLimitSeconds]); } } + } - // Disable background cache refreshing to avoid races in tests - argArray.push(...['--setParameter', "disableLogicalSessionCacheRefresh=true"]); + // TODO: Make this unconditional in 3.8. + if (!programMajorMinorVersion || programMajorMinorVersion > 304) { + if (!argArrayContainsSetParameterValue('orphanCleanupDelaySecs=')) { + argArray.push(...['--setParameter', 'orphanCleanupDelaySecs=1']); + } } - // Since options may not be backward compatible, mongos options are not - // set on older versions, e.g., mongos-3.0. - if (programName.endsWith('mongos')) { - // apply setParameters for mongos - if (jsTest.options().setParametersMongos) { - let params = jsTest.options().setParametersMongos; + // Since options may not be backward compatible, mongod options are not + // set on older versions, e.g., mongod-3.0. + if (programName.endsWith('mongod')) { + if (jsTest.options().storageEngine === "wiredTiger" || + !jsTest.options().storageEngine) { + if (jsTest.options().enableMajorityReadConcern !== undefined && + !argArrayContains("--enableMajorityReadConcern")) { + argArray.push(...['--enableMajorityReadConcern', + jsTest.options().enableMajorityReadConcern.toString()]); + } + if (jsTest.options().storageEngineCacheSizeGB && + !argArrayContains('--wiredTigerCacheSizeGB')) { + argArray.push(...['--wiredTigerCacheSizeGB', + jsTest.options().storageEngineCacheSizeGB]); + } + if (jsTest.options().wiredTigerEngineConfigString && + !argArrayContains('--wiredTigerEngineConfigString')) { + argArray.push(...['--wiredTigerEngineConfigString', + jsTest.options().wiredTigerEngineConfigString]); + } + if (jsTest.options().wiredTigerCollectionConfigString && + !argArrayContains('--wiredTigerCollectionConfigString')) { + argArray.push(...['--wiredTigerCollectionConfigString', + jsTest.options().wiredTigerCollectionConfigString]); + } + if (jsTest.options().wiredTigerIndexConfigString && + !argArrayContains('--wiredTigerIndexConfigString')) { + argArray.push(...['--wiredTigerIndexConfigString', + jsTest.options().wiredTigerIndexConfigString]); + } + } else if (jsTest.options().storageEngine === "rocksdb") { + if (jsTest.options().storageEngineCacheSizeGB) { + argArray.push( + ...['--rocksdbCacheSizeGB', jsTest.options().storageEngineCacheSizeGB]); + } + } else if (jsTest.options().storageEngine === "inMemory") { + if (jsTest.options().storageEngineCacheSizeGB && + !argArrayContains("--inMemorySizeGB")) { + argArray.push( + ...["--inMemorySizeGB", jsTest.options().storageEngineCacheSizeGB]); + } + } + // apply setParameters for mongod. The 'setParameters' field should be given as + // a plain JavaScript object, where each key is a parameter name and the value + // is the value to set for that parameter. + if (jsTest.options().setParameters) { + let params = jsTest.options().setParameters; for (let paramName of Object.keys(params)) { // Only set the 'logComponentVerbosity' parameter if it has not already // been specified in the given argument array. This means that any @@ -1118,6 +1198,7 @@ var MongoRunner, _startMongod, startMongoProgram, runMongoProgram, startMongoPro argArrayContains("logComponentVerbosity")) { continue; } + const paramVal = ((param) => { if (typeof param === "object") { return JSON.stringify(param); @@ -1129,261 +1210,157 @@ var MongoRunner, _startMongod, startMongoProgram, runMongoProgram, startMongoPro argArray.push(...['--setParameter', setParamStr]); } } - } else if (baseProgramName === 'mongod') { - if (jsTestOptions().roleGraphInvalidationIsFatal) { - argArray.push(...['--setParameter', "roleGraphInvalidationIsFatal=true"]); - } - - // Set storageEngine for mongod. There was no storageEngine parameter before 3.0. - if (jsTest.options().storageEngine && - (!programVersion || programMajorMinorVersion >= 300)) { - if (!argArrayContains("--storageEngine")) { - argArray.push(...['--storageEngine', jsTest.options().storageEngine]); - } - } - - // New mongod-specific options in 4.0.x - if (!programMajorMinorVersion || programMajorMinorVersion >= 400) { - if (jsTest.options().transactionLifetimeLimitSeconds !== undefined) { - if (!argArrayContainsSetParameterValue( - "transactionLifetimeLimitSeconds=")) { - argArray.push( - ...["--setParameter", - "transactionLifetimeLimitSeconds=" + - jsTest.options().transactionLifetimeLimitSeconds]); - } - } - } - - // TODO: Make this unconditional in 3.8. - if (!programMajorMinorVersion || programMajorMinorVersion > 304) { - if (!argArrayContainsSetParameterValue('orphanCleanupDelaySecs=')) { - argArray.push(...['--setParameter', 'orphanCleanupDelaySecs=1']); - } - } - - // Since options may not be backward compatible, mongod options are not - // set on older versions, e.g., mongod-3.0. - if (programName.endsWith('mongod')) { - if (jsTest.options().storageEngine === "wiredTiger" || - !jsTest.options().storageEngine) { - if (jsTest.options().enableMajorityReadConcern !== undefined && - !argArrayContains("--enableMajorityReadConcern")) { - argArray.push( - ...['--enableMajorityReadConcern', - jsTest.options().enableMajorityReadConcern.toString()]); - } - if (jsTest.options().storageEngineCacheSizeGB && - !argArrayContains('--wiredTigerCacheSizeGB')) { - argArray.push(...['--wiredTigerCacheSizeGB', - jsTest.options().storageEngineCacheSizeGB]); - } - if (jsTest.options().wiredTigerEngineConfigString && - !argArrayContains('--wiredTigerEngineConfigString')) { - argArray.push(...['--wiredTigerEngineConfigString', - jsTest.options().wiredTigerEngineConfigString]); - } - if (jsTest.options().wiredTigerCollectionConfigString && - !argArrayContains('--wiredTigerCollectionConfigString')) { - argArray.push(...['--wiredTigerCollectionConfigString', - jsTest.options().wiredTigerCollectionConfigString]); - } - if (jsTest.options().wiredTigerIndexConfigString && - !argArrayContains('--wiredTigerIndexConfigString')) { - argArray.push(...['--wiredTigerIndexConfigString', - jsTest.options().wiredTigerIndexConfigString]); - } - } else if (jsTest.options().storageEngine === "rocksdb") { - if (jsTest.options().storageEngineCacheSizeGB) { - argArray.push(...['--rocksdbCacheSizeGB', - jsTest.options().storageEngineCacheSizeGB]); - } - } else if (jsTest.options().storageEngine === "inMemory") { - if (jsTest.options().storageEngineCacheSizeGB && - !argArrayContains("--inMemorySizeGB")) { - argArray.push( - ...["--inMemorySizeGB", jsTest.options().storageEngineCacheSizeGB]); - } - } - // apply setParameters for mongod. The 'setParameters' field should be given as - // a plain JavaScript object, where each key is a parameter name and the value - // is the value to set for that parameter. - if (jsTest.options().setParameters) { - let params = jsTest.options().setParameters; - for (let paramName of Object.keys(params)) { - // Only set the 'logComponentVerbosity' parameter if it has not already - // been specified in the given argument array. This means that any - // 'logComponentVerbosity' settings passed through via TestData will - // always be overridden by settings passed directly to MongoRunner from - // within the shell. - if (paramName === "logComponentVerbosity" && - argArrayContains("logComponentVerbosity")) { - continue; - } - - const paramVal = ((param) => { - if (typeof param === "object") { - return JSON.stringify(param); - } - - return param; - })(params[paramName]); - const setParamStr = paramName + "=" + paramVal; - argArray.push(...['--setParameter', setParamStr]); - } - } - } } } - - return argArray; } - /** - * Start a mongo process with a particular argument array. - * If we aren't waiting for connect, return {pid: <pid>}. - * If we are waiting for connect: - * returns connection to process on success; - * otherwise returns null if we fail to connect. - */ - MongoRunner._startWithArgs = function(argArray, env, waitForConnect) { - // TODO: Make there only be one codepath for starting mongo processes - - argArray = appendSetParameterArgs(argArray); - var port = _parsePort.apply(null, argArray); - var pid = -1; - if (env === undefined) { - pid = _startMongoProgram.apply(null, argArray); - } else { - pid = _startMongoProgram({args: argArray, env: env}); - } + return argArray; +} + +/** + * Start a mongo process with a particular argument array. + * If we aren't waiting for connect, return {pid: <pid>}. + * If we are waiting for connect: + * returns connection to process on success; + * otherwise returns null if we fail to connect. + */ +MongoRunner._startWithArgs = function(argArray, env, waitForConnect) { + // TODO: Make there only be one codepath for starting mongo processes + + argArray = appendSetParameterArgs(argArray); + var port = _parsePort.apply(null, argArray); + var pid = -1; + if (env === undefined) { + pid = _startMongoProgram.apply(null, argArray); + } else { + pid = _startMongoProgram({args: argArray, env: env}); + } - delete serverExitCodeMap[port]; - if (!waitForConnect) { - return { - pid: pid, - port: port, - }; - } + delete serverExitCodeMap[port]; + if (!waitForConnect) { + return { + pid: pid, + port: port, + }; + } - var conn = null; - assert.soon(function() { - try { - conn = new Mongo("127.0.0.1:" + port); - conn.pid = pid; + var conn = null; + assert.soon(function() { + try { + conn = new Mongo("127.0.0.1:" + port); + conn.pid = pid; + return true; + } catch (e) { + var res = checkProgram(pid); + if (!res.alive) { + print("Could not start mongo program at " + port + + ", process ended with exit code: " + res.exitCode); + serverExitCodeMap[port] = res.exitCode; return true; - } catch (e) { - var res = checkProgram(pid); - if (!res.alive) { - print("Could not start mongo program at " + port + - ", process ended with exit code: " + res.exitCode); - serverExitCodeMap[port] = res.exitCode; - return true; - } } - return false; - }, "unable to connect to mongo program on port " + port, 600 * 1000); - - return conn; - }; - - /** - * DEPRECATED - * - * Start mongod or mongos and return a Mongo() object connected to there. - * This function's first argument is "mongod" or "mongos" program name, \ - * and subsequent arguments to this function are passed as - * command line arguments to the program. - */ - startMongoProgram = function() { - var port = _parsePort.apply(null, arguments); - - // Enable test commands. - // TODO: Make this work better with multi-version testing so that we can support - // enabling this on 2.4 when testing 2.6 - var args = Array.from(arguments); - args = appendSetParameterArgs(args); - var pid = _startMongoProgram.apply(null, args); - - var m; - assert.soon(function() { - try { - m = new Mongo("127.0.0.1:" + port); - m.pid = pid; + } + return false; + }, "unable to connect to mongo program on port " + port, 600 * 1000); + + return conn; +}; + +/** + * DEPRECATED + * + * Start mongod or mongos and return a Mongo() object connected to there. + * This function's first argument is "mongod" or "mongos" program name, \ + * and subsequent arguments to this function are passed as + * command line arguments to the program. + */ +startMongoProgram = function() { + var port = _parsePort.apply(null, arguments); + + // Enable test commands. + // TODO: Make this work better with multi-version testing so that we can support + // enabling this on 2.4 when testing 2.6 + var args = Array.from(arguments); + args = appendSetParameterArgs(args); + var pid = _startMongoProgram.apply(null, args); + + var m; + assert.soon(function() { + try { + m = new Mongo("127.0.0.1:" + port); + m.pid = pid; + return true; + } catch (e) { + var res = checkProgram(pid); + if (!res.alive) { + print("Could not start mongo program at " + port + + ", process ended with exit code: " + res.exitCode); + // Break out + m = null; return true; - } catch (e) { - var res = checkProgram(pid); - if (!res.alive) { - print("Could not start mongo program at " + port + - ", process ended with exit code: " + res.exitCode); - // Break out - m = null; - return true; - } } - return false; - }, "unable to connect to mongo program on port " + port, 600 * 1000); - - return m; - }; - - runMongoProgram = function() { - var args = Array.from(arguments); - args = appendSetParameterArgs(args); - var progName = args[0]; - - // The bsondump tool doesn't support these auth related command line flags. - if (jsTestOptions().auth && progName != 'mongod' && progName != 'bsondump') { - args = args.slice(1); - args.unshift(progName, - '-u', - jsTestOptions().authUser, - '-p', - jsTestOptions().authPassword, - '--authenticationDatabase=admin'); } + return false; + }, "unable to connect to mongo program on port " + port, 600 * 1000); + + return m; +}; + +runMongoProgram = function() { + var args = Array.from(arguments); + args = appendSetParameterArgs(args); + var progName = args[0]; + + // The bsondump tool doesn't support these auth related command line flags. + if (jsTestOptions().auth && progName != 'mongod' && progName != 'bsondump') { + args = args.slice(1); + args.unshift(progName, + '-u', + jsTestOptions().authUser, + '-p', + jsTestOptions().authPassword, + '--authenticationDatabase=admin'); + } - if (progName == 'mongo' && !_useWriteCommandsDefault()) { - progName = args[0]; - args = args.slice(1); - args.unshift(progName, '--useLegacyWriteOps'); - } - - return _runMongoProgram.apply(null, args); - }; - - // Start a mongo program instance. This function's first argument is the - // program name, and subsequent arguments to this function are passed as - // command line arguments to the program. Returns pid of the spawned program. - startMongoProgramNoConnect = function() { - var args = Array.from(arguments); - args = appendSetParameterArgs(args); - var progName = args[0]; - - if (jsTestOptions().auth) { - args = args.slice(1); - args.unshift(progName, - '-u', - jsTestOptions().authUser, - '-p', - jsTestOptions().authPassword, - '--authenticationDatabase=admin'); - } + if (progName == 'mongo' && !_useWriteCommandsDefault()) { + progName = args[0]; + args = args.slice(1); + args.unshift(progName, '--useLegacyWriteOps'); + } - if (progName == 'mongo' && !_useWriteCommandsDefault()) { - args = args.slice(1); - args.unshift(progName, '--useLegacyWriteOps'); - } + return _runMongoProgram.apply(null, args); +}; + +// Start a mongo program instance. This function's first argument is the +// program name, and subsequent arguments to this function are passed as +// command line arguments to the program. Returns pid of the spawned program. +startMongoProgramNoConnect = function() { + var args = Array.from(arguments); + args = appendSetParameterArgs(args); + var progName = args[0]; + + if (jsTestOptions().auth) { + args = args.slice(1); + args.unshift(progName, + '-u', + jsTestOptions().authUser, + '-p', + jsTestOptions().authPassword, + '--authenticationDatabase=admin'); + } - return _startMongoProgram.apply(null, args); - }; + if (progName == 'mongo' && !_useWriteCommandsDefault()) { + args = args.slice(1); + args.unshift(progName, '--useLegacyWriteOps'); + } - myPort = function() { - var m = db.getMongo(); - if (m.host.match(/:/)) - return m.host.match(/:(.*)/)[1]; - else - return 27017; - }; + return _startMongoProgram.apply(null, args); +}; +myPort = function() { + var m = db.getMongo(); + if (m.host.match(/:/)) + return m.host.match(/:(.*)/)[1]; + else + return 27017; +}; }()); diff --git a/src/mongo/shell/servers_misc.js b/src/mongo/shell/servers_misc.js index 825bca3d689..4edda039549 100644 --- a/src/mongo/shell/servers_misc.js +++ b/src/mongo/shell/servers_misc.js @@ -78,28 +78,28 @@ var allocatePort; var resetAllocatedPorts; (function() { - // Defer initializing these variables until the first call, as TestData attributes may be - // initialized as part of the --eval argument (e.g. by resmoke.py), which will not be evaluated - // until after this has loaded. - var maxPort; - var nextPort; - - allocatePort = function() { - // The default port was chosen in an attempt to have a large number of unassigned ports that - // are also outside the ephemeral port range. - nextPort = nextPort || jsTestOptions().minPort || 20000; - maxPort = maxPort || jsTestOptions().maxPort || Math.pow(2, 16) - 1; - - if (nextPort === maxPort) { - throw new Error("Exceeded maximum port range in allocatePort()"); - } - return nextPort++; - }; +// Defer initializing these variables until the first call, as TestData attributes may be +// initialized as part of the --eval argument (e.g. by resmoke.py), which will not be evaluated +// until after this has loaded. +var maxPort; +var nextPort; + +allocatePort = function() { + // The default port was chosen in an attempt to have a large number of unassigned ports that + // are also outside the ephemeral port range. + nextPort = nextPort || jsTestOptions().minPort || 20000; + maxPort = maxPort || jsTestOptions().maxPort || Math.pow(2, 16) - 1; + + if (nextPort === maxPort) { + throw new Error("Exceeded maximum port range in allocatePort()"); + } + return nextPort++; +}; - resetAllocatedPorts = function() { - jsTest.log("Resetting the range of allocated ports"); - maxPort = nextPort = undefined; - }; +resetAllocatedPorts = function() { + jsTest.log("Resetting the range of allocated ports"); + maxPort = nextPort = undefined; +}; })(); /** @@ -142,9 +142,9 @@ function startParallelShell(jsCode, port, noConnect) { } // Convert function into call-string - if (typeof(jsCode) == "function") { + if (typeof (jsCode) == "function") { jsCode = "(" + jsCode.toString() + ")();"; - } else if (typeof(jsCode) == "string") { + } else if (typeof (jsCode) == "string") { } // do nothing else { @@ -153,7 +153,7 @@ function startParallelShell(jsCode, port, noConnect) { if (noConnect) { args.push("--nodb"); - } else if (typeof(db) == "object") { + } else if (typeof (db) == "object") { jsCode = "db = db.getSiblingDB('" + db.getName() + "');" + jsCode; } diff --git a/src/mongo/shell/session.js b/src/mongo/shell/session.js index 0313f46fc0e..0f6eb11323a 100644 --- a/src/mongo/shell/session.js +++ b/src/mongo/shell/session.js @@ -5,7 +5,11 @@ * https://github.com/mongodb/specifications/blob/master/source/sessions/driver-sessions.rst#abstract */ var { - DriverSession, SessionOptions, _DummyDriverSession, _DelegatingDriverSession, _ServerSession, + DriverSession, + SessionOptions, + _DummyDriverSession, + _DelegatingDriverSession, + _ServerSession, } = (function() { "use strict"; @@ -416,10 +420,10 @@ var { if (writeError !== undefined) { if (jsTest.options().logRetryAttempts) { - jsTest.log("Retrying " + cmdName + - " due to retryable write error (code=" + - writeError.code + "), subsequent retries remaining: " + - numRetries); + jsTest.log( + "Retrying " + cmdName + + " due to retryable write error (code=" + writeError.code + + "), subsequent retries remaining: " + numRetries); } if (client.isReplicaSetConnection()) { client._markNodeAsFailed( @@ -1035,54 +1039,54 @@ var { const DummyDriverSession = makeDriverSessionConstructor( // Force clang-format to break this line. { - createServerSession: function createServerSession(client) { - return { - injectSessionId: function injectSessionId(cmdObj) { - return cmdObj; - }, - - assignTransactionNumber: function assignTransactionNumber(cmdObj) { - return cmdObj; - }, - - canRetryWrites: function canRetryWrites(cmdObj) { - return false; - }, - - assignTxnInfo: function assignTxnInfo(cmdObj) { - return cmdObj; - }, - - isTxnActive: function isTxnActive() { - return false; - }, - - isFirstStatement: function isFirstStatement() { - return false; - }, - - getTxnOptions: function getTxnOptions() { - return {}; - }, - - startTransaction: function startTransaction() { - throw new Error("Must call startSession() on the Mongo connection " + - "object before starting a transaction."); - }, - - commitTransaction: function commitTransaction() { - throw new Error("Must call startSession() on the Mongo connection " + - "object before committing a transaction."); - }, - - abortTransaction: function abortTransaction() { - throw new Error("Must call startSession() on the Mongo connection " + - "object before aborting a transaction."); - }, - }; - }, - - endSession: function endSession(serverSession) {}, + createServerSession: function createServerSession(client) { + return { + injectSessionId: function injectSessionId(cmdObj) { + return cmdObj; + }, + + assignTransactionNumber: function assignTransactionNumber(cmdObj) { + return cmdObj; + }, + + canRetryWrites: function canRetryWrites(cmdObj) { + return false; + }, + + assignTxnInfo: function assignTxnInfo(cmdObj) { + return cmdObj; + }, + + isTxnActive: function isTxnActive() { + return false; + }, + + isFirstStatement: function isFirstStatement() { + return false; + }, + + getTxnOptions: function getTxnOptions() { + return {}; + }, + + startTransaction: function startTransaction() { + throw new Error("Must call startSession() on the Mongo connection " + + "object before starting a transaction."); + }, + + commitTransaction: function commitTransaction() { + throw new Error("Must call startSession() on the Mongo connection " + + "object before committing a transaction."); + }, + + abortTransaction: function abortTransaction() { + throw new Error("Must call startSession() on the Mongo connection " + + "object before aborting a transaction."); + }, + }; + }, + + endSession: function endSession(serverSession) {}, }, {causalConsistency: false, retryWrites: false}); diff --git a/src/mongo/shell/shardingtest.js b/src/mongo/shell/shardingtest.js index f814a02cbf4..6008c769202 100644 --- a/src/mongo/shell/shardingtest.js +++ b/src/mongo/shell/shardingtest.js @@ -102,7 +102,6 @@ * configRS - If the config servers are a replset, this will contain the config ReplSetTest object */ var ShardingTest = function(params) { - if (!(this instanceof ShardingTest)) { return new ShardingTest(params); } @@ -292,16 +291,16 @@ var ShardingTest = function(params) { countDBsFound++; printjson(db); }); - throw Error("couldn't find dbname: " + dbname + " in config.databases. Total DBs: " + - countDBsFound); + throw Error("couldn't find dbname: " + dbname + + " in config.databases. Total DBs: " + countDBsFound); }; this.getNonPrimaries = function(dbname) { var x = this.config.databases.findOne({_id: dbname}); if (!x) { this.config.databases.find().forEach(printjson); - throw Error("couldn't find dbname: " + dbname + " total: " + - this.config.databases.count()); + throw Error("couldn't find dbname: " + dbname + + " total: " + this.config.databases.count()); } return this.config.shards.find({_id: {$ne: x.primary}}).map(z => z._id); @@ -334,8 +333,8 @@ var ShardingTest = function(params) { } } - throw Error("can't find server connection for db '" + dbname + "'s primary shard: " + - tojson(primaryShard)); + throw Error("can't find server connection for db '" + dbname + + "'s primary shard: " + tojson(primaryShard)); }; this.normalize = function(x) { @@ -859,9 +858,9 @@ var ShardingTest = function(params) { } if (arguments.length >= 3) { - if (typeof(beforeRestartCallback) !== "function") { + if (typeof (beforeRestartCallback) !== "function") { throw new Error("beforeRestartCallback must be a function but was of type " + - typeof(beforeRestartCallback)); + typeof (beforeRestartCallback)); } beforeRestartCallback(); } @@ -1621,7 +1620,6 @@ var ShardingTest = function(params) { MongoRunner.getBinVersionFor(otherParams.configOptions.binVersion)))) { this.configRS.getPrimary().getDB("admin").runCommand({refreshLogicalSessionCacheNow: 1}); } - }; // Stub for a hook to check that collection UUIDs are consistent across shards and the config diff --git a/src/mongo/shell/shell_options.cpp b/src/mongo/shell/shell_options.cpp index 026cb9af45b..5181719de4f 100644 --- a/src/mongo/shell/shell_options.cpp +++ b/src/mongo/shell/shell_options.cpp @@ -61,7 +61,8 @@ using std::vector; // SERVER-36807: Limit --setShellParameter to SetParameters we know we want to expose. const std::set<std::string> kSetShellParameterWhitelist = { - "disabledSecureAllocatorDomains", "newLineAfterPasswordPromptForTest", + "disabledSecureAllocatorDomains", + "newLineAfterPasswordPromptForTest", }; std::string getMongoShellHelp(StringData name, const moe::OptionSection& options) { @@ -321,14 +322,14 @@ Status storeMongoShellOptions(const moe::Environment& params, auto* param = paramIt->second; if (!param->allowedToChangeAtStartup()) { return {ErrorCodes::BadValue, - str::stream() << "Cannot use --setShellParameter to set '" << name - << "' at startup"}; + str::stream() + << "Cannot use --setShellParameter to set '" << name << "' at startup"}; } auto status = param->setFromString(it.second); if (!status.isOK()) { return {ErrorCodes::BadValue, - str::stream() << "Bad value for parameter '" << name << "': " - << status.reason()}; + str::stream() + << "Bad value for parameter '" << name << "': " << status.reason()}; } } } diff --git a/src/mongo/shell/shell_options.h b/src/mongo/shell/shell_options.h index aad972d0dc1..45ac4e55455 100644 --- a/src/mongo/shell/shell_options.h +++ b/src/mongo/shell/shell_options.h @@ -98,4 +98,4 @@ bool handlePreValidationMongoShellOptions(const moe::Environment& params, Status storeMongoShellOptions(const moe::Environment& params, const std::vector<std::string>& args); void redactPasswordOptions(int argc, char** argv); -} +} // namespace mongo diff --git a/src/mongo/shell/shell_options_init.cpp b/src/mongo/shell/shell_options_init.cpp index 98cf02f5c53..2ea64570bc8 100644 --- a/src/mongo/shell/shell_options_init.cpp +++ b/src/mongo/shell/shell_options_init.cpp @@ -59,4 +59,4 @@ MONGO_STARTUP_OPTIONS_STORE(MongoShellOptions)(InitializerContext* context) { } return Status::OK(); } -} +} // namespace mongo diff --git a/src/mongo/shell/shell_utils.cpp b/src/mongo/shell/shell_utils.cpp index b97e6358b14..09b5335117e 100644 --- a/src/mongo/shell/shell_utils.cpp +++ b/src/mongo/shell/shell_utils.cpp @@ -164,10 +164,9 @@ size_t skipOverString(const std::string& code, size_t start, char quote) { // that the escaping backslash is not itself escaped. Comparisons of start and pos // are to keep us from reading beyond the beginning of the quoted string. // - if (start == pos || code[pos - 1] != '\\' || // previous char was backslash - start == pos - 1 || - code[pos - 2] == '\\' // char before backslash was not another - ) { + if (start == pos || code[pos - 1] != '\\' || // previous char was backslash + start == pos - 1 || code[pos - 2] == '\\' // char before backslash was not another + ) { break; // The quote we found was not preceded by an unescaped backslash; it is real } ++pos; // The quote we found was escaped with backslash, so it doesn't count diff --git a/src/mongo/shell/shell_utils.h b/src/mongo/shell/shell_utils.h index 0c856c37ed3..a5b8a0ce50c 100644 --- a/src/mongo/shell/shell_utils.h +++ b/src/mongo/shell/shell_utils.h @@ -96,5 +96,5 @@ extern stdx::mutex& mongoProgramOutputMutex; // Helper to tell if a file exists cross platform // TODO: Remove this when we have a cross platform file utility library bool fileExists(const std::string& file); -} -} +} // namespace shell_utils +} // namespace mongo diff --git a/src/mongo/shell/shell_utils_extended.cpp b/src/mongo/shell/shell_utils_extended.cpp index 6a756911f3d..df5444670dd 100644 --- a/src/mongo/shell/shell_utils_extended.cpp +++ b/src/mongo/shell/shell_utils_extended.cpp @@ -365,8 +365,8 @@ BSONObj getFileMode(const BSONObj& a, void* data) { auto fileStatus = boost::filesystem::status(path, ec); if (ec) { uasserted(50974, - str::stream() << "Unable to get status for file \"" << pathStr << "\": " - << ec.message()); + str::stream() << "Unable to get status for file \"" << pathStr + << "\": " << ec.message()); } return BSON("" << fileStatus.permissions()); @@ -389,5 +389,5 @@ void installShellUtilsExtended(Scope& scope) { scope.injectNative("umask", changeUmask); scope.injectNative("getFileMode", getFileMode); } -} -} +} // namespace shell_utils +} // namespace mongo diff --git a/src/mongo/shell/shell_utils_extended.h b/src/mongo/shell/shell_utils_extended.h index 0fb83c4d7a0..543095d1187 100644 --- a/src/mongo/shell/shell_utils_extended.h +++ b/src/mongo/shell/shell_utils_extended.h @@ -37,4 +37,4 @@ class Scope; namespace shell_utils { void installShellUtilsExtended(Scope& scope); } -} +} // namespace mongo diff --git a/src/mongo/shell/shell_utils_launcher.cpp b/src/mongo/shell/shell_utils_launcher.cpp index 5b7c68d5363..752c7724e42 100644 --- a/src/mongo/shell/shell_utils_launcher.cpp +++ b/src/mongo/shell/shell_utils_launcher.cpp @@ -275,11 +275,13 @@ ProgramRunner::ProgramRunner(const BSONObj& args, const BSONObj& env, bool isMon _port = -1; string prefix("mongod-"); - bool isMongodProgram = isMongo && (string("mongod") == programName || - programName.string().compare(0, prefix.size(), prefix) == 0); + bool isMongodProgram = isMongo && + (string("mongod") == programName || + programName.string().compare(0, prefix.size(), prefix) == 0); prefix = "mongos-"; - bool isMongosProgram = isMongo && (string("mongos") == programName || - programName.string().compare(0, prefix.size(), prefix) == 0); + bool isMongosProgram = isMongo && + (string("mongos") == programName || + programName.string().compare(0, prefix.size(), prefix) == 0); if (!isMongo) { _name = "sh"; diff --git a/src/mongo/shell/types.js b/src/mongo/shell/types.js index 19c1fb272f3..faaa5d00499 100644 --- a/src/mongo/shell/types.js +++ b/src/mongo/shell/types.js @@ -1,5 +1,5 @@ // Date and time types -if (typeof(Timestamp) != "undefined") { +if (typeof (Timestamp) != "undefined") { Timestamp.prototype.tojson = function() { return this.toString(); }; @@ -265,13 +265,13 @@ Array.stdDev = function(arr) { Object.extend = function(dst, src, deep) { for (var k in src) { var v = src[k]; - if (deep && typeof(v) == "object" && v !== null) { + if (deep && typeof (v) == "object" && v !== null) { if (v.constructor === ObjectId) { // convert ObjectId properly eval("v = " + tojson(v)); } else if ("floatApprox" in v) { // convert NumberLong properly eval("v = " + tojson(v)); } else { - v = Object.extend(typeof(v.length) == "number" ? [] : {}, v, true); + v = Object.extend(typeof (v.length) == "number" ? [] : {}, v, true); } } dst[k] = v; @@ -433,7 +433,7 @@ ObjectId.fromDate = function(source) { if (source instanceof Date) { sourceDate = source; } else { - throw Error("Cannot create ObjectId from " + typeof(source) + ": " + tojson(source)); + throw Error("Cannot create ObjectId from " + typeof (source) + ": " + tojson(source)); } // Convert date object to seconds since Unix epoch. @@ -449,7 +449,7 @@ ObjectId.fromDate = function(source) { }; // DBPointer -if (typeof(DBPointer) != "undefined") { +if (typeof (DBPointer) != "undefined") { DBPointer.prototype.fetch = function() { assert(this.ns, "need a ns"); assert(this.id, "need an id"); @@ -476,7 +476,7 @@ if (typeof(DBPointer) != "undefined") { } // DBRef -if (typeof(DBRef) != "undefined") { +if (typeof (DBRef) != "undefined") { DBRef.prototype.fetch = function() { assert(this.$ref, "need a ns"); assert(this.$id, "need an id"); @@ -513,7 +513,7 @@ if (typeof(DBRef) != "undefined") { } // BinData -if (typeof(BinData) != "undefined") { +if (typeof (BinData) != "undefined") { BinData.prototype.tojson = function() { return this.toString(); }; @@ -529,7 +529,7 @@ if (typeof(BinData) != "undefined") { } // Map -if (typeof(Map) == "undefined") { +if (typeof (Map) == "undefined") { Map = function() { this._data = {}; }; @@ -539,7 +539,7 @@ Map.hash = function(val) { if (!val) return val; - switch (typeof(val)) { + switch (typeof (val)) { case 'string': case 'number': case 'date': @@ -553,7 +553,7 @@ Map.hash = function(val) { return s; } - throw Error("can't hash : " + typeof(val)); + throw Error("can't hash : " + typeof (val)); }; Map.prototype.put = function(key, value) { @@ -594,7 +594,7 @@ Map.prototype.values = function() { return all; }; -if (typeof(gc) == "undefined") { +if (typeof (gc) == "undefined") { gc = function() { print("warning: using noop gc()"); }; @@ -640,7 +640,6 @@ tojson = function(x, indent, nolint, depth) { default: throw Error("tojson can't handle type " + (typeof x)); } - }; tojson.MAX_DEPTH = 100; @@ -655,11 +654,11 @@ tojsonObject = function(x, indent, nolint, depth) { if (!indent) indent = ""; - if (typeof(x.tojson) == "function" && x.tojson != tojson) { + if (typeof (x.tojson) == "function" && x.tojson != tojson) { return x.tojson(indent, nolint, depth); } - if (x.constructor && typeof(x.constructor.tojson) == "function" && + if (x.constructor && typeof (x.constructor.tojson) == "function" && x.constructor.tojson != tojson) { return x.constructor.tojson(x, indent, nolint, depth); } @@ -685,7 +684,7 @@ tojsonObject = function(x, indent, nolint, depth) { indent += tabSpace; var keys = x; - if (typeof(x._simpleKeys) == "function") + if (typeof (x._simpleKeys) == "function") keys = x._simpleKeys(); var fieldStrings = []; for (var k in keys) { @@ -721,14 +720,14 @@ printjsononeline = function(x) { }; isString = function(x) { - return typeof(x) == "string"; + return typeof (x) == "string"; }; isNumber = function(x) { - return typeof(x) == "number"; + return typeof (x) == "number"; }; // This function returns true even if the argument is an array. See SERVER-14220. isObject = function(x) { - return typeof(x) == "object"; + return typeof (x) == "object"; }; diff --git a/src/mongo/shell/utils.js b/src/mongo/shell/utils.js index 11e6cde6902..1201e800eeb 100644 --- a/src/mongo/shell/utils.js +++ b/src/mongo/shell/utils.js @@ -213,7 +213,7 @@ print.captureAllOutput = function(fn, args) { }; var indentStr = function(indent, s) { - if (typeof(s) === "undefined") { + if (typeof (s) === "undefined") { s = indent; indent = 0; } @@ -350,7 +350,7 @@ jsTestLog = function(msg) { if (typeof msg === "object") { msg = tojson(msg); } - assert.eq(typeof(msg), "string", "Received: " + msg); + assert.eq(typeof (msg), "string", "Received: " + msg); const msgs = ["----", ...msg.split("\n"), "----"].map(s => `[jsTest] ${s}`); print(`\n\n${msgs.join("\n")}\n\n`); }; @@ -596,10 +596,10 @@ if (typeof _shouldUseImplicitSessions === 'undefined') { } shellPrintHelper = function(x) { - if (typeof(x) == "undefined") { + 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 && + if (__callLastError && typeof (db) != "undefined" && db.getMongo && db.getMongo().writeMode() == "legacy") { __callLastError = false; // explicit w:1 so that replset getLastErrorDefaults aren't used here which would be bad @@ -638,7 +638,6 @@ shellPrintHelper = function(x) { shellAutocomplete = function( /*prefix*/) { // outer scope function called on init. Actual function at end - var universalMethods = "constructor prototype toString valueOf toLocaleString hasOwnProperty propertyIsEnumerable" .split(' '); @@ -743,7 +742,7 @@ shellAutocomplete = function( {}; // see http://dreaminginjavascript.wordpress.com/2008/08/22/eliminating-duplicates/ for (var i = 0; i < possibilities.length; i++) { var p = possibilities[i]; - if (typeof(curObj[p]) == "undefined" && curObj != global) + if (typeof (curObj[p]) == "undefined" && curObj != global) continue; // extraGlobals aren't in the global object if (p.length == 0 || p.length < lastPrefix.length) continue; @@ -829,7 +828,7 @@ shellHelper.set = function(str) { }; shellHelper.it = function() { - if (typeof(___it___) == "undefined" || ___it___ == null) { + if (typeof (___it___) == "undefined" || ___it___ == null) { print("no cursor"); return; } @@ -862,7 +861,7 @@ shellHelper.show = function(what) { continue; var val = x[z]; - var mytype = typeof(val); + var mytype = typeof (val); if (mytype == "string" || mytype == "number") l += z + ":" + val + " "; @@ -1120,7 +1119,8 @@ shellHelper.show = function(what) { } if (matchesKnownImposterSignature) { - print("\n" + "Warning: Non-Genuine MongoDB Detected\n\n" + + print("\n" + + "Warning: Non-Genuine MongoDB Detected\n\n" + "This server or service appears to be an emulation of MongoDB " + "rather than an official MongoDB product.\n\n" + @@ -1137,7 +1137,6 @@ shellHelper.show = function(what) { } throw Error("don't know how to show [" + what + "]"); - }; __promptWrapper__ = function(promptFunction) { @@ -1173,8 +1172,8 @@ Math.sigFig = function(x, N) { var Random = (function() { var initialized = false; - var errorMsg = - "The random number generator hasn't been seeded yet; " + "call Random.setRandomSeed()"; + var errorMsg = "The random number generator hasn't been seeded yet; " + + "call Random.setRandomSeed()"; // Set the random generator seed. function srand(s) { @@ -1248,7 +1247,6 @@ var Random = (function() { setRandomSeed: setRandomSeed, srand: srand, }; - })(); /** @@ -1351,7 +1349,8 @@ _awaitRSHostViaRSMonitor = function(hostAddr, desiredState, rsName, timeout) { desiredState = {ok: true}; } - print("Awaiting " + hostAddr + " to be " + tojson(desiredState) + " in " + " rs " + rsName); + print("Awaiting " + hostAddr + " to be " + tojson(desiredState) + " in " + + " rs " + rsName); var tests = 0; assert.soon( @@ -1387,8 +1386,8 @@ _awaitRSHostViaRSMonitor = function(hostAddr, desiredState, rsName, timeout) { } return false; }, - "timed out waiting for replica set member: " + hostAddr + " to reach state: " + - tojson(desiredState), + "timed out waiting for replica set member: " + hostAddr + + " to reach state: " + tojson(desiredState), timeout); }; @@ -1700,35 +1699,52 @@ help = shellHelper.help = function(x) { print("\t returns a connection to the new server"); return; } else if (x == "") { - print("\t" + "db.help() help on db methods"); - print("\t" + "db.mycoll.help() help on collection methods"); - print("\t" + "sh.help() sharding helpers"); - print("\t" + "rs.help() replica set helpers"); - print("\t" + "help admin administrative help"); - print("\t" + "help connect connecting to a db help"); - print("\t" + "help keys key shortcuts"); - print("\t" + "help misc misc things to know"); - print("\t" + "help mr mapreduce"); + print("\t" + + "db.help() help on db methods"); + print("\t" + + "db.mycoll.help() help on collection methods"); + print("\t" + + "sh.help() sharding helpers"); + print("\t" + + "rs.help() replica set helpers"); + print("\t" + + "help admin administrative help"); + print("\t" + + "help connect connecting to a db help"); + print("\t" + + "help keys key shortcuts"); + print("\t" + + "help misc misc things to know"); + print("\t" + + "help mr mapreduce"); print(); - print("\t" + "show dbs show database names"); - print("\t" + "show collections show collections in current database"); - print("\t" + "show users show users in current database"); + print("\t" + + "show dbs show database names"); + print("\t" + + "show collections show collections in current database"); + print("\t" + + "show users show users in current database"); print( "\t" + "show profile show most recent system.profile entries with time >= 1ms"); - print("\t" + "show logs show the accessible logger names"); + print("\t" + + "show logs show the accessible logger names"); print( "\t" + "show log [name] prints out the last segment of log in memory, 'global' is default"); - print("\t" + "use <db_name> set current database"); - print("\t" + "db.foo.find() list objects in collection foo"); - print("\t" + "db.foo.find( { a : 1 } ) list objects in foo where a == 1"); + print("\t" + + "use <db_name> set current database"); + print("\t" + + "db.foo.find() list objects in collection foo"); + print("\t" + + "db.foo.find( { a : 1 } ) list objects in foo where a == 1"); print( "\t" + "it result of the last line evaluated; use to further iterate"); print("\t" + "DBQuery.shellBatchSize = x set default number of items to display on shell"); - print("\t" + "exit quit the mongo shell"); + print("\t" + + "exit quit the mongo shell"); } else print("unknown help option"); }; diff --git a/src/mongo/shell/utils_auth.js b/src/mongo/shell/utils_auth.js index 0343a81ceef..9beb08db940 100644 --- a/src/mongo/shell/utils_auth.js +++ b/src/mongo/shell/utils_auth.js @@ -1,146 +1,146 @@ var authutil; (function() { - assert(!authutil); - authutil = {}; +assert(!authutil); +authutil = {}; - /** - * Logs out all connections "conn" from database "dbname". - */ - authutil.logout = function(conn, dbname) { - var i; - if (null == conn.length) { - conn = [conn]; - } - for (i = 0; i < conn.length; ++i) { - var curDB = new DB(conn[i], dbname); - curDB.logout(); - } - }; - - /** - * Authenticates all connections in "conns" using "authParams" on database "dbName". - * - * Raises an exception if any authentication fails, and tries to leave all connnections - * in "conns" in the logged-out-of-dbName state. - */ - authutil.assertAuthenticate = function(conns, dbName, authParams) { - var conn, i, ex, ex2; - if (conns.length == null) - conns = [conns]; - - try { - for (i = 0; i < conns.length; ++i) { - conn = conns[i]; - // Bypass the implicit auth call in getDB(); - var db = new DB(conn, dbName); - try { - retryOnNetworkError(db._authOrThrow.bind(db, authParams)); - } catch (ex3) { - doassert("assert failed : " + "Failed to authenticate " + conn + " to " + - dbName + " using parameters " + tojson(authParams) + " : " + ex3); - } - } - } catch (ex) { - try { - authutil.logout(conns, dbName); - } catch (ex2) { - } - throw ex; - } - }; +/** + * Logs out all connections "conn" from database "dbname". + */ +authutil.logout = function(conn, dbname) { + var i; + if (null == conn.length) { + conn = [conn]; + } + for (i = 0; i < conn.length; ++i) { + var curDB = new DB(conn[i], dbname); + curDB.logout(); + } +}; - /** - * Authenticates all connections in "conns" using "authParams" on database "dbName". - * Raises in exception if any of the authentications succeed. - */ - authutil.assertAuthenticateFails = function(conns, dbName, authParams) { - var conn, i; - if (conns.length == null) - conns = [conns]; +/** + * Authenticates all connections in "conns" using "authParams" on database "dbName". + * + * Raises an exception if any authentication fails, and tries to leave all connnections + * in "conns" in the logged-out-of-dbName state. + */ +authutil.assertAuthenticate = function(conns, dbName, authParams) { + var conn, i, ex, ex2; + if (conns.length == null) + conns = [conns]; + try { for (i = 0; i < conns.length; ++i) { conn = conns[i]; // Bypass the implicit auth call in getDB(); var db = new DB(conn, dbName); - const ex = assert.throws(retryOnNetworkError, - [db._authOrThrow.bind(db, authParams)], - "Unexpectedly authenticated " + conn + " to " + dbName + - " using parameters " + tojson(authParams)); - if (isNetworkError(ex)) { - throw ex; + try { + retryOnNetworkError(db._authOrThrow.bind(db, authParams)); + } catch (ex3) { + doassert("assert failed : " + + "Failed to authenticate " + conn + " to " + dbName + " using parameters " + + tojson(authParams) + " : " + ex3); } } - }; + } catch (ex) { + try { + authutil.logout(conns, dbName); + } catch (ex2) { + } + throw ex; + } +}; - /** - * Executes action() after authenticating the keyfile user on "conn", then logs out the keyfile - * user. - */ - authutil.asCluster = function(conn, keyfile, action) { - var ex; - const authMode = jsTest.options().clusterAuthMode; +/** + * Authenticates all connections in "conns" using "authParams" on database "dbName". + * Raises in exception if any of the authentications succeed. + */ +authutil.assertAuthenticateFails = function(conns, dbName, authParams) { + var conn, i; + if (conns.length == null) + conns = [conns]; - // put a connection in an array for uniform processing. - let connArray = conn; - if (conn.length == null) - connArray = [conn]; + for (i = 0; i < conns.length; ++i) { + conn = conns[i]; + // Bypass the implicit auth call in getDB(); + var db = new DB(conn, dbName); + const ex = assert.throws(retryOnNetworkError, + [db._authOrThrow.bind(db, authParams)], + "Unexpectedly authenticated " + conn + " to " + dbName + + " using parameters " + tojson(authParams)); + if (isNetworkError(ex)) { + throw ex; + } + } +}; - let clusterTimes = connArray.map(connElem => { - const connClusterTime = connElem.getClusterTime(); - const sessionClusterTime = connElem._getDefaultSession().getClusterTime(); - const operationTime = connElem._getDefaultSession().getOperationTime(); +/** + * Executes action() after authenticating the keyfile user on "conn", then logs out the keyfile + * user. + */ +authutil.asCluster = function(conn, keyfile, action) { + var ex; + const authMode = jsTest.options().clusterAuthMode; - connElem.resetClusterTime_forTesting(); - connElem._getDefaultSession().resetClusterTime_forTesting(); - connElem._getDefaultSession().resetOperationTime_forTesting(); + // put a connection in an array for uniform processing. + let connArray = conn; + if (conn.length == null) + connArray = [conn]; - return {connClusterTime, sessionClusterTime, operationTime}; - }); + let clusterTimes = connArray.map(connElem => { + const connClusterTime = connElem.getClusterTime(); + const sessionClusterTime = connElem._getDefaultSession().getClusterTime(); + const operationTime = connElem._getDefaultSession().getOperationTime(); - if (authMode === 'keyFile') { - authutil.assertAuthenticate(conn, 'admin', { - user: '__system', - mechanism: 'SCRAM-SHA-1', - pwd: cat(keyfile).replace(/[\011-\015\040]/g, '') - }); - } else if (authMode === 'x509') { - authutil.assertAuthenticate(conn, '$external', { - mechanism: 'MONGODB-X509', - }); - } else { - throw new Error('clusterAuthMode ' + authMode + ' is currently unsupported'); - } + connElem.resetClusterTime_forTesting(); + connElem._getDefaultSession().resetClusterTime_forTesting(); + connElem._getDefaultSession().resetOperationTime_forTesting(); + + return {connClusterTime, sessionClusterTime, operationTime}; + }); + + if (authMode === 'keyFile') { + authutil.assertAuthenticate(conn, 'admin', { + user: '__system', + mechanism: 'SCRAM-SHA-1', + pwd: cat(keyfile).replace(/[\011-\015\040]/g, '') + }); + } else if (authMode === 'x509') { + authutil.assertAuthenticate(conn, '$external', { + mechanism: 'MONGODB-X509', + }); + } else { + throw new Error('clusterAuthMode ' + authMode + ' is currently unsupported'); + } + try { + return action(); + } finally { try { - return action(); - } finally { - try { - authutil.logout(conn, 'admin'); - let connArray = conn; - if (conn.length == null) - connArray = [conn]; + authutil.logout(conn, 'admin'); + let connArray = conn; + if (conn.length == null) + connArray = [conn]; - for (let i = 0; i < connArray.length; i++) { - let connElem = connArray[i]; - connElem.resetClusterTime_forTesting(); - connElem._getDefaultSession().resetClusterTime_forTesting(); - connElem._getDefaultSession().resetOperationTime_forTesting(); - if (clusterTimes[i].connClusterTime) { - connElem.advanceClusterTime(clusterTimes[i].connClusterTime); - } - if (clusterTimes[i].sessionClusterTime) { - connElem._getDefaultSession().advanceClusterTime( - clusterTimes[i].sessionClusterTime); - } - if (clusterTimes[i].operationTime) { - connElem._getDefaultSession().advanceOperationTime( - clusterTimes[i].operationTime); - } + for (let i = 0; i < connArray.length; i++) { + let connElem = connArray[i]; + connElem.resetClusterTime_forTesting(); + connElem._getDefaultSession().resetClusterTime_forTesting(); + connElem._getDefaultSession().resetOperationTime_forTesting(); + if (clusterTimes[i].connClusterTime) { + connElem.advanceClusterTime(clusterTimes[i].connClusterTime); + } + if (clusterTimes[i].sessionClusterTime) { + connElem._getDefaultSession().advanceClusterTime( + clusterTimes[i].sessionClusterTime); + } + if (clusterTimes[i].operationTime) { + connElem._getDefaultSession().advanceOperationTime( + clusterTimes[i].operationTime); } - } catch (ex) { } + } catch (ex) { } - }; - + } +}; }()); diff --git a/src/mongo/shell/utils_sh.js b/src/mongo/shell/utils_sh.js index 3c62675db7b..2ada654ce55 100644 --- a/src/mongo/shell/utils_sh.js +++ b/src/mongo/shell/utils_sh.js @@ -109,13 +109,13 @@ sh.enableSharding = function(dbname) { sh.shardCollection = function(fullName, key, unique, options) { sh._checkFullName(fullName); assert(key, "need a key"); - assert(typeof(key) == "object", "key needs to be an object"); + assert(typeof (key) == "object", "key needs to be an object"); var cmd = {shardCollection: fullName, key: key}; if (unique) cmd.unique = true; if (options) { - if (typeof(options) !== "object") { + if (typeof (options) !== "object") { throw new Error("options must be an object"); } Object.extend(cmd, options); @@ -140,7 +140,7 @@ sh.moveChunk = function(fullName, find, to) { }; sh.setBalancerState = function(isOn) { - assert(typeof(isOn) == "boolean", "Must pass boolean to setBalancerState"); + assert(typeof (isOn) == "boolean", "Must pass boolean to setBalancerState"); if (isOn) { return sh.startBalancer(); } else { @@ -243,7 +243,7 @@ sh.waitForPingChange = function(activePings, timeout, interval) { }; sh.waitForBalancer = function(wait, timeout, interval) { - if (typeof(wait) === 'undefined') { + if (typeof (wait) === 'undefined') { wait = false; } var initialStatus = sh._getBalancerStatus(); @@ -296,7 +296,6 @@ sh.enableBalancing = function(coll) { * mongos ) */ sh._lastMigration = function(ns) { - var coll = null; var dbase = null; var config = null; @@ -480,12 +479,12 @@ sh.getRecentMigrations = function(configDB) { var result = configDB.changelog .aggregate([ { - $match: { - time: {$gt: yesterday}, - what: "moveChunk.from", - 'details.errmsg': {$exists: false}, - 'details.note': 'success' - } + $match: { + time: {$gt: yesterday}, + what: "moveChunk.from", + 'details.errmsg': {$exists: false}, + 'details.note': 'success' + } }, {$group: {_id: {msg: "$details.errmsg"}, count: {$sum: 1}}}, {$project: {_id: {$ifNull: ["$_id.msg", "Success"]}, count: "$count"}} @@ -497,28 +496,28 @@ sh.getRecentMigrations = function(configDB) { configDB.changelog .aggregate([ { - $match: { - time: {$gt: yesterday}, - what: "moveChunk.from", - $or: [ - {'details.errmsg': {$exists: true}}, - {'details.note': {$ne: 'success'}} - ] - } + $match: { + time: {$gt: yesterday}, + what: "moveChunk.from", + $or: [ + {'details.errmsg': {$exists: true}}, + {'details.note': {$ne: 'success'}} + ] + } }, { - $group: { - _id: {msg: "$details.errmsg", from: "$details.from", to: "$details.to"}, - count: {$sum: 1} - } + $group: { + _id: {msg: "$details.errmsg", from: "$details.from", to: "$details.to"}, + count: {$sum: 1} + } }, { - $project: { - _id: {$ifNull: ['$_id.msg', 'aborted']}, - from: "$_id.from", - to: "$_id.to", - count: "$count" - } + $project: { + _id: {$ifNull: ['$_id.msg', 'aborted']}, + from: "$_id.from", + to: "$_id.to", + count: "$count" + } } ]) .toArray()); @@ -703,7 +702,7 @@ function printShardingStatus(configDB, verbose) { var nonBooleanNote = function(name, value) { // If the given value is not a boolean, return a string of the // form " (<name>: <value>)", where <value> is converted to JSON. - var t = typeof(value); + var t = typeof (value); var s = ""; if (t != "boolean" && t != "undefined") { s = " (" + name + ": " + tojson(value) + ")"; @@ -814,9 +813,8 @@ function printShardingSizes(configDB) { delete out.ok; output(4, - tojson(chunk.min) + " -->> " + tojson(chunk.max) + " on : " + - chunk.shard + " " + tojson(out)); - + tojson(chunk.min) + " -->> " + tojson(chunk.max) + + " on : " + chunk.shard + " " + tojson(out)); }); }); } |