summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordalyd <david.daly@mongodb.com>2015-12-15 13:28:38 -0500
committerdalyd <david.daly@mongodb.com>2016-01-29 14:43:05 -0500
commitf72680615029f0d6ee7e2882e554f64d8ad1577f (patch)
tree72d5cbcb48ed5226c2f56d4277cecc860baa8265
parentd21109c7b3222088c0a382bbc02103c4d133f42f (diff)
downloadmongo-f72680615029f0d6ee7e2882e554f64d8ad1577f.tar.gz
SERVER-21427: benchRun should complain when passed invalid options
-rw-r--r--jstests/core/bench_test2.js1
-rw-r--r--jstests/core/bench_test3.js1
-rw-r--r--src/mongo/shell/bench.cpp1054
-rw-r--r--src/mongo/shell/bench.h76
4 files changed, 700 insertions, 432 deletions
diff --git a/jstests/core/bench_test2.js b/jstests/core/bench_test2.js
index 871b24ca051..ccf7ed20e67 100644
--- a/jstests/core/bench_test2.js
+++ b/jstests/core/bench_test2.js
@@ -11,7 +11,6 @@ benchArgs = { ops : [ { ns : t.getFullName() ,
update : { $inc : { x : 1 } } } ] ,
parallel : 2 ,
seconds : 1 ,
- totals : true ,
host : db.getMongo().host }
if (jsTest.options().auth) {
diff --git a/jstests/core/bench_test3.js b/jstests/core/bench_test3.js
index 34e033fe52a..1df22f05810 100644
--- a/jstests/core/bench_test3.js
+++ b/jstests/core/bench_test3.js
@@ -9,7 +9,6 @@ benchArgs = { ops : [ { ns : t.getFullName() ,
update : { $inc : { x : 1 } } } ] ,
parallel : 2 ,
seconds : 5 ,
- totals : true ,
host : db.getMongo().host }
if (jsTest.options().auth) {
diff --git a/src/mongo/shell/bench.cpp b/src/mongo/shell/bench.cpp
index 24edb8bcf62..a2a980d0f14 100644
--- a/src/mongo/shell/bench.cpp
+++ b/src/mongo/shell/bench.cpp
@@ -80,6 +80,18 @@ using std::cout;
using std::endl;
using std::map;
+const std::map<OpType, std::string> opTypeName{{OpType::NONE, "none"},
+ {OpType::NOP, "nop"},
+ {OpType::FINDONE, "findOne"},
+ {OpType::COMMAND, "command"},
+ {OpType::FIND, "find"},
+ {OpType::UPDATE, "update"},
+ {OpType::INSERT, "insert"},
+ {OpType::REMOVE, "remove"},
+ {OpType::CREATEINDEX, "createIndex"},
+ {OpType::DROPINDEX, "dropIndex"},
+ {OpType::LET, "let"}};
+
BenchRunEventCounter::BenchRunEventCounter() {
reset();
}
@@ -154,8 +166,6 @@ void BenchRunConfig::initializeToDefaults() {
watchPattern.reset();
noWatchPattern.reset();
- ops = BSONObj();
-
throwGLE = false;
breakOnTrap = true;
randomSeed = 1314159265358979323;
@@ -167,66 +177,308 @@ BenchRunConfig* BenchRunConfig::createFromBson(const BSONObj& args) {
return config;
}
-void BenchRunConfig::initializeFromBson(const BSONObj& args) {
- initializeToDefaults();
-
- if (args["host"].type() == String)
- this->host = args["host"].String();
- if (args["db"].type() == String)
- this->db = args["db"].String();
- if (args["username"].type() == String)
- this->username = args["username"].String();
- if (args["password"].type() == String)
- this->password = args["password"].String();
-
- if (args["parallel"].isNumber())
- this->parallel = args["parallel"].numberInt();
- if (args["randomSeed"].isNumber())
- this->randomSeed = args["randomSeed"].numberInt();
- if (args["seconds"].isNumber())
- this->seconds = args["seconds"].number();
- if (!args["hideResults"].eoo())
- this->hideResults = args["hideResults"].trueValue();
- if (!args["handleErrors"].eoo())
- this->handleErrors = args["handleErrors"].trueValue();
- if (!args["hideErrors"].eoo())
- this->hideErrors = args["hideErrors"].trueValue();
- if (!args["throwGLE"].eoo())
- this->throwGLE = args["throwGLE"].trueValue();
- if (!args["breakOnTrap"].eoo())
- this->breakOnTrap = args["breakOnTrap"].trueValue();
-
- uassert(16164, "loopCommands config not supported", args["loopCommands"].eoo());
-
- if (!args["trapPattern"].eoo()) {
- const char* regex = args["trapPattern"].regex();
- const char* flags = args["trapPattern"].regexFlags();
- this->trapPattern =
- std::shared_ptr<pcrecpp::RE>(new pcrecpp::RE(regex, flags2options(flags)));
+BenchRunOp opFromBson(const BSONObj& op) {
+ BenchRunOp myOp;
+ myOp.myBsonOp = op.getOwned(); // save an owned copy of the BSON obj
+ auto opType = myOp.myBsonOp["op"].valueStringData();
+ for (auto arg : myOp.myBsonOp) {
+ auto name = arg.fieldNameStringData();
+ if (name == "batchSize") {
+ uassert(34377,
+ str::stream() << "Field 'batchSize' should be a number, instead it's type: "
+ << typeName(arg.type()),
+ arg.isNumber());
+ uassert(34378,
+ str::stream() << "Field 'batchSize' only valid for find op types. Type is "
+ << opType,
+ (opType == "find") || (opType == "query"));
+ myOp.batchSize = arg.numberInt();
+ } else if (name == "check") {
+ // check function gets thrown into a scoped function. Leaving that parsing in main loop.
+ myOp.useCheck = true;
+ myOp.check = arg;
+ uassert(
+ 34403,
+ str::stream()
+ << "Check field requires type CodeWScoe, Code, or String, instead its type is: "
+ << typeName(myOp.check.type()),
+ (myOp.check.type() == CodeWScope || myOp.check.type() == Code ||
+ myOp.check.type() == String));
+
+ } else if (name == "command") {
+ // type needs to be command
+ uassert(34398,
+ str::stream() << "Field 'command' only valid for command op type. Type is "
+ << opType,
+ opType == "command");
+ myOp.command = arg.Obj();
+ } else if (name == "context") {
+ myOp.context = arg.Obj();
+ } else if (name == "delay") {
+ uassert(34379,
+ str::stream() << "Field 'delay' should be a number, instead it's type: "
+ << typeName(arg.type()),
+ arg.isNumber());
+ myOp.delay = arg.numberInt();
+ } else if (name == "doc") {
+ uassert(34399,
+ str::stream() << "Field 'doc' only valid for insert op type. Type is "
+ << opType,
+ (opType == "insert"));
+ myOp.isDocAnArray = arg.type() == Array;
+ myOp.doc = arg.Obj();
+ } else if (name == "expected") {
+ uassert(34380,
+ str::stream() << "Field 'Expected' should be a number, instead it's type: "
+ << typeName(arg.type()),
+ arg.isNumber());
+ uassert(34400,
+ str::stream() << "Field 'Expected' only valid for find op type. Type is "
+ << opType,
+ (opType == "find") || (opType == "query"));
+ myOp.expected = arg.numberInt();
+ } else if (name == "filter") {
+ uassert(
+ 34401,
+ str::stream()
+ << "Field 'Filter' (projection) only valid for find/findOne op type. Type is "
+ << opType,
+ (opType == "find") || (opType == "query") || (opType == "findOne"));
+ myOp.projection = arg.Obj(); // the name should be switched to projection
+ // also, but that will break things
+ } else if (name == "handleError") {
+ myOp.handleError = arg.trueValue();
+ } else if (name == "key") {
+ uassert(34402,
+ str::stream()
+ << "Field 'key' only valid for create or drop index op types. Type is "
+ << opType,
+ (opType == "createIndex") || (opType == "dropIndex"));
+ myOp.key = arg.Obj();
+ } else if (name == "limit") {
+ uassert(34381,
+ str::stream() << "Field 'limit' is only valid for find op types. Type is "
+ << opType,
+ (opType == "find") || (opType == "query"));
+ uassert(ErrorCodes::BadValue,
+ str::stream() << "Field 'limit' should be a number, instead it's type: "
+ << typeName(arg.type()),
+ arg.isNumber());
+ myOp.limit = arg.numberInt();
+ } else if (name == "multi") {
+ uassert(34383,
+ str::stream()
+ << "Field 'multi' is only valid for update/remove/delete types. Type is "
+ << opType,
+ (opType == "update") || (opType == "remove") || (opType == "delete"));
+ myOp.multi = arg.trueValue();
+ } else if (name == "ns") {
+ uassert(34385,
+ str::stream() << "Field 'ns' should be a string, instead it's type: "
+ << typeName(arg.type()),
+ arg.type() == String);
+ myOp.ns = arg.String();
+ } else if (name == "op") {
+ uassert(ErrorCodes::BadValue,
+ str::stream() << "Field 'op' is not a string, instead it's type: "
+ << typeName(arg.type()),
+ arg.type() == String);
+ auto type = arg.valueStringData();
+ if (type == "nop") {
+ myOp.op = OpType::NOP;
+ } else if (type == "findOne") {
+ myOp.op = OpType::FINDONE;
+ } else if (type == "command") {
+ myOp.op = OpType::COMMAND;
+ } else if (type == "find" || type == "query") {
+ myOp.op = OpType::FIND;
+ } else if (type == "update") {
+ myOp.op = OpType::UPDATE;
+ } else if (type == "insert") {
+ myOp.op = OpType::INSERT;
+ } else if (type == "delete" || type == "remove") {
+ myOp.op = OpType::REMOVE;
+ } else if (type == "createIndex") {
+ myOp.op = OpType::CREATEINDEX;
+ } else if (type == "dropIndex") {
+ myOp.op = OpType::DROPINDEX;
+ } else if (type == "let") {
+ myOp.op = OpType::LET;
+ } else {
+ uassert(34387,
+ str::stream() << "benchRun passed an unsupported op type: " << type,
+ false);
+ }
+ } else if (name == "options") {
+ uassert(ErrorCodes::BadValue,
+ str::stream() << "Field 'options' should be a number, instead it's type: "
+ << typeName(arg.type()),
+ arg.isNumber());
+ uassert(34388,
+ str::stream() << "Field 'options' but not a command or find type. Type is "
+ << opType,
+ (opType == "command") || (opType == "query") || (opType == "find"));
+ myOp.options = arg.numberInt();
+ } else if (name == "query") {
+ uassert(34389,
+ str::stream() << "Field 'query' is only valid for findOne, find, update, and "
+ "remove types. Type is " << opType,
+ (opType == "findOne") || (opType == "query") ||
+ (opType == "find" || (opType == "update") || (opType == "delete") ||
+ (opType == "remove")));
+ myOp.query = arg.Obj();
+ } else if (name == "safe") {
+ myOp.safe = arg.trueValue();
+ } else if (name == "skip") {
+ uassert(ErrorCodes::BadValue,
+ str::stream() << "Field 'skip' should be a number, instead it's type: "
+ << typeName(arg.type()),
+ arg.isNumber());
+ uassert(34390,
+ str::stream() << "Field 'skip' is only valid for find/query op types. Type is "
+ << opType,
+ (opType == "find") || (opType == "query"));
+ myOp.skip = arg.numberInt();
+ } else if (name == "showError") {
+ myOp.showError = arg.trueValue();
+ } else if (name == "showResult") {
+ myOp.showResult = arg.trueValue();
+ } else if (name == "target") {
+ uassert(ErrorCodes::BadValue,
+ str::stream() << "Field 'target' should be a string. It's type: "
+ << typeName(arg.type()),
+ arg.type() == String);
+ myOp.target = arg.String();
+ } else if (name == "throwGLE") {
+ myOp.throwGLE = arg.trueValue();
+ } else if (name == "update") {
+ uassert(34391,
+ str::stream() << "Field 'update' is only valid for update op type. Op type is "
+ << opType,
+ (opType == "update"));
+ myOp.update = arg.Obj();
+ } else if (name == "upsert") {
+ uassert(34392,
+ str::stream() << "Field 'upsert' is only valid for update op type. Op type is "
+ << opType,
+ (opType == "update"));
+ myOp.upsert = arg.trueValue();
+ } else if (name == "readCmd") {
+ myOp.useReadCmd = arg.trueValue();
+ } else if (name == "writeCmd") {
+ myOp.useWriteCmd = arg.trueValue();
+ } else if (name == "writeConcern") {
+ // Mongo-perf wants to pass the write concern into all calls. It is only used for
+ // update, insert, delete
+ myOp.writeConcern = arg.Obj();
+ } else if (name == "value") {
+ uassert(34403,
+ str::stream() << "Field 'value' is only valid for let op type. Op type is "
+ << opType,
+ opType == "let");
+ BSONObjBuilder valBuilder;
+ valBuilder.append(arg);
+ myOp.value = valBuilder.done();
+ } else {
+ uassert(34394, str::stream() << "Benchrun op has unsupported field: " << name, false);
+ }
}
- if (!args["noTrapPattern"].eoo()) {
- const char* regex = args["noTrapPattern"].regex();
- const char* flags = args["noTrapPattern"].regexFlags();
- this->noTrapPattern =
- std::shared_ptr<pcrecpp::RE>(new pcrecpp::RE(regex, flags2options(flags)));
- }
+ uassert(34395, "Benchrun op has an zero length ns", !myOp.ns.empty());
+ uassert(34396, "Benchrun op doesn't have an optype set", myOp.op != OpType::NONE);
+ return myOp;
+}
- if (!args["watchPattern"].eoo()) {
- const char* regex = args["watchPattern"].regex();
- const char* flags = args["watchPattern"].regexFlags();
- this->watchPattern =
- std::shared_ptr<pcrecpp::RE>(new pcrecpp::RE(regex, flags2options(flags)));
- }
+void BenchRunConfig::initializeFromBson(const BSONObj& args) {
+ initializeToDefaults();
- if (!args["noWatchPattern"].eoo()) {
- const char* regex = args["noWatchPattern"].regex();
- const char* flags = args["noWatchPattern"].regexFlags();
- this->noWatchPattern =
- std::shared_ptr<pcrecpp::RE>(new pcrecpp::RE(regex, flags2options(flags)));
+ for (auto arg : args) {
+ auto name = arg.fieldNameStringData();
+ if (name == "host") {
+ uassert(34404,
+ str::stream() << "Field '" << name << "' should be a string. . Type is "
+ << typeName(arg.type()),
+ arg.type() == String);
+ host = arg.String();
+ } else if (name == "db") {
+ uassert(34405,
+ str::stream() << "Field '" << name << "' should be a string. . Type is "
+ << typeName(arg.type()),
+ arg.type() == String);
+ db = arg.String();
+ } else if (name == "username") {
+ uassert(34406,
+ str::stream() << "Field '" << name << "' should be a string. . Type is "
+ << typeName(arg.type()),
+ arg.type() == String);
+ username = arg.String();
+ } else if (name == "password") {
+ uassert(34407,
+ str::stream() << "Field '" << name << "' should be a string. . Type is "
+ << typeName(arg.type()),
+ arg.type() == String);
+ password = arg.String();
+ } else if (name == "parallel") {
+ uassert(34409,
+ str::stream() << "Field '" << name << "' should be a number. . Type is "
+ << typeName(arg.type()),
+ arg.isNumber());
+ parallel = arg.numberInt();
+ } else if (name == "randomSeed") {
+ uassert(34365,
+ str::stream() << "Field '" << name << "' should be a number. . Type is "
+ << typeName(arg.type()),
+ arg.isNumber());
+ randomSeed = arg.numberInt();
+ } else if (name == "seconds") {
+ uassert(34408,
+ str::stream() << "Field '" << name << "' should be a number. . Type is "
+ << typeName(arg.type()),
+ arg.isNumber());
+ seconds = arg.number();
+ } else if (name == "hideResults") {
+ hideResults = arg.trueValue();
+ } else if (name == "handleErrors") {
+ handleErrors = arg.trueValue();
+ } else if (name == "hideErrors") {
+ hideErrors = arg.trueValue();
+ } else if (name == "throwGLE") {
+ throwGLE = arg.trueValue();
+ } else if (name == "breakOnTrap") {
+ breakOnTrap = arg.trueValue();
+ } else if (name == "trapPattern") {
+ const char* regex = arg.regex();
+ const char* flags = arg.regexFlags();
+ trapPattern =
+ std::shared_ptr<pcrecpp::RE>(new pcrecpp::RE(regex, flags2options(flags)));
+ } else if (name == "noTrapPattern") {
+ const char* regex = arg.regex();
+ const char* flags = arg.regexFlags();
+ noTrapPattern =
+ std::shared_ptr<pcrecpp::RE>(new pcrecpp::RE(regex, flags2options(flags)));
+ } else if (name == "watchPattern") {
+ const char* regex = arg.regex();
+ const char* flags = arg.regexFlags();
+ watchPattern =
+ std::shared_ptr<pcrecpp::RE>(new pcrecpp::RE(regex, flags2options(flags)));
+ } else if (name == "noWatchPattern") {
+ const char* regex = arg.regex();
+ const char* flags = arg.regexFlags();
+ noWatchPattern =
+ std::shared_ptr<pcrecpp::RE>(new pcrecpp::RE(regex, flags2options(flags)));
+ } else if (name == "ops") {
+ // iterate through the objects in ops
+ // create an BenchRunOp per
+ // put in ops vector.
+ BSONObjIterator i(arg.Obj());
+ while (i.more()) {
+ ops.push_back(opFromBson(i.next().Obj()));
+ }
+ } else {
+ log() << "benchRun passed an unsupported field: " << name;
+ uassert(34376, "benchRun passed an unsupported configuration field", false);
+ }
}
-
- this->ops = args["ops"].Obj().getOwned();
}
DBClientBase* BenchRunConfig::createConnection() const {
@@ -362,7 +614,7 @@ bool BenchRunWorker::shouldCollectStats() const {
void doNothing(const BSONObj&) {}
/**
- * Issues the query 'lpq' against 'conn' using read commands. Returns the size of the result set
+ * Issues the query 'lpq' against 'conn' using read commands. Returns the size of the result set
* returned by the query.
*
* If 'lpq' has the 'wantMore' flag set to false and the 'limit' option set to 1LL, then the caller
@@ -429,259 +681,189 @@ void BenchRunWorker::generateLoadOnConnection(DBClientBase* conn) {
}
while (!shouldStop()) {
- BSONObjIterator i(_config->ops);
- while (i.more()) {
+ for (auto op : _config->ops) {
if (shouldStop())
break;
auto& stats = shouldCollectStats() ? _stats : _statsBlackHole;
- BSONElement e = i.next();
-
- string ns = e["ns"].String();
- string op = e["op"].String();
-
- int delay = e["delay"].eoo() ? 0 : e["delay"].Int();
-
- bool useWriteCmd = false; // By default, don't use write commands.
- if (e["writeCmd"]) {
- useWriteCmd = e["writeCmd"].Bool();
- }
- bool useReadCmd = false; // By default, don't use read commands.
- if (e["readCmd"]) {
- useReadCmd = e["readCmd"].Bool();
- }
-
- BSONObj context = e["context"].eoo() ? BSONObj() : e["context"].Obj();
unique_ptr<Scope> scope;
ScriptingFunction scopeFunc = 0;
BSONObj scopeObj;
-
- bool check = !e["check"].eoo();
- if (check) {
- if (e["check"].type() == CodeWScope || e["check"].type() == Code ||
- e["check"].type() == String) {
- scope = globalScriptEngine->getPooledScope(NULL, ns, "benchrun");
- verify(scope.get());
-
- if (e.type() == CodeWScope) {
- scopeFunc = scope->createFunction(e["check"].codeWScopeCode());
- scopeObj = BSONObj(e.codeWScopeScopeDataUnsafe());
- } else {
- scopeFunc = scope->createFunction(e["check"].valuestr());
- }
-
- scope->init(&scopeObj);
- invariant(scopeFunc);
+ if (op.useCheck) {
+ auto check = op.check;
+ scope = globalScriptEngine->getPooledScope(NULL, op.ns, "benchrun");
+ verify(scope.get());
+
+ if (check.type() == CodeWScope) {
+ scopeFunc = scope->createFunction(check.codeWScopeCode());
+ scopeObj = BSONObj(check.codeWScopeScopeDataUnsafe());
} else {
- warning() << "Invalid check type detected in benchRun op : " << e << endl;
- check = false;
+ scopeFunc = scope->createFunction(check.valuestr());
}
+
+ scope->init(&scopeObj);
+ invariant(scopeFunc);
}
try {
- if (op == "nop") {
- // do nothing
- } else if (op == "findOne") {
- BSONObj fixedQuery = fixQuery(e["query"].Obj(), bsonTemplateEvaluator);
- BSONObj result;
- if (useReadCmd) {
- unique_ptr<LiteParsedQuery> lpq =
- LiteParsedQuery::makeAsFindCmd(NamespaceString(ns),
- fixedQuery,
- BSONObj(), // projection
- BSONObj(), // sort
- BSONObj(), // hint
- BSONObj(), // readConcern
- boost::none, // skip
- 1LL, // limit
- boost::none, // batchSize
- boost::none, // ntoreturn
- false); // wantMore
- BenchRunEventTrace _bret(&stats.findOneCounter);
- runQueryWithReadCommands(conn, std::move(lpq), &result);
- } else {
- BenchRunEventTrace _bret(&stats.findOneCounter);
- result = conn->findOne(ns, fixedQuery);
- }
-
- if (check) {
- int err = scope->invoke(scopeFunc, 0, &result, 1000 * 60, false);
- if (err) {
- log() << "Error checking in benchRun thread [findOne]"
- << causedBy(scope->getError()) << endl;
-
- stats.errCount++;
-
- return;
+ switch (op.op) {
+ case OpType::NOP:
+ break;
+ case OpType::FINDONE: {
+ BSONObj fixedQuery = fixQuery(op.query, bsonTemplateEvaluator);
+ BSONObj result;
+ if (op.useReadCmd) {
+ unique_ptr<LiteParsedQuery> lpq =
+ LiteParsedQuery::makeAsFindCmd(NamespaceString(op.ns),
+ fixedQuery,
+ op.projection, // projection
+ BSONObj(), // sort
+ BSONObj(), // hint
+ BSONObj(), // readConcern
+ boost::none, // skip
+ 1LL, // limit
+ boost::none, // batchSize
+ boost::none, // ntoreturn
+ false); // wantMore
+ BenchRunEventTrace _bret(&stats.findOneCounter);
+ runQueryWithReadCommands(conn, std::move(lpq), &result);
+ } else {
+ BenchRunEventTrace _bret(&stats.findOneCounter);
+ result = conn->findOne(op.ns, fixedQuery);
}
- }
- if (!_config->hideResults || e["showResult"].trueValue())
- log() << "Result from benchRun thread [findOne] : " << result << endl;
+ if (op.useCheck) {
+ int err = scope->invoke(scopeFunc, 0, &result, 1000 * 60, false);
+ if (err) {
+ log() << "Error checking in benchRun thread [findOne]"
+ << causedBy(scope->getError()) << endl;
- } else if (op == "command") {
- bool ok;
- BSONObj result;
- {
- BenchRunEventTrace _bret(&stats.commandCounter);
- ok = conn->runCommand(ns,
- fixQuery(e["command"].Obj(), bsonTemplateEvaluator),
- result,
- e["options"].numberInt());
- }
- if (!ok) {
- stats.errCount++;
- }
+ stats.errCount++;
- if (!result["cursor"].eoo()) {
- // The command returned a cursor, so iterate all results.
- auto cursorResponse =
- uassertStatusOK(CursorResponse::parseFromBSON(result));
- int count = cursorResponse.getBatch().size();
- while (cursorResponse.getCursorId() != 0) {
- GetMoreRequest getMoreRequest(cursorResponse.getNSS(),
- cursorResponse.getCursorId(),
- boost::none, // batchSize
- boost::none, // maxTimeMS
- boost::none, // term
- boost::none); // lastKnownCommittedOpTime
- BSONObj getMoreCommandResult;
- ok =
- conn->runCommand(ns, getMoreRequest.toBSON(), getMoreCommandResult);
- uassert(ErrorCodes::CommandFailed,
- str::stream() << "getMore command failed; reply was: "
- << getMoreCommandResult,
- ok);
- cursorResponse = uassertStatusOK(
- CursorResponse::parseFromBSON(getMoreCommandResult));
- count += cursorResponse.getBatch().size();
+ return;
+ }
}
- // Just give the count to the check function.
- result = BSON("count" << count << "context" << context);
- }
-
- if (check) {
- int err = scope->invoke(scopeFunc, 0, &result, 1000 * 60, false);
- if (err) {
- log() << "Error checking in benchRun thread [command]"
- << causedBy(scope->getError()) << endl;
+ if (!_config->hideResults || op.showResult)
+ log() << "Result from benchRun thread [findOne] : " << result << endl;
+ } break;
+ case OpType::COMMAND: {
+ bool ok;
+ BSONObj result;
+ {
+ BenchRunEventTrace _bret(&stats.commandCounter);
+ ok = conn->runCommand(op.ns,
+ fixQuery(op.command, bsonTemplateEvaluator),
+ result,
+ op.options);
+ }
+ if (!ok) {
stats.errCount++;
- return;
}
- }
- if (!_config->hideResults || e["showResult"].trueValue())
- log() << "Result from benchRun thread [command] : " << result << endl;
-
- } else if (op == "find" || op == "query") {
- int limit = e["limit"].eoo() ? 0 : e["limit"].numberInt();
- int skip = e["skip"].eoo() ? 0 : e["skip"].Int();
- int options = e["options"].eoo() ? 0 : e["options"].Int();
- int batchSize = e["batchSize"].eoo() ? 0 : e["batchSize"].Int();
- int expected = e["expected"].eoo() ? -1 : e["expected"].Int();
-
- // TODO: The following option should be named "projection". The work to rename
- // it is being tracked at SERVER-21013.
- BSONObj projection = e["filter"].eoo() ? BSONObj() : e["filter"].Obj();
-
- int count;
-
- BSONObj fixedQuery = fixQuery(e["query"].Obj(), bsonTemplateEvaluator);
-
- if (useReadCmd) {
- uassert(28824,
- "cannot use 'options' in combination with read commands",
- !options);
- unique_ptr<LiteParsedQuery> lpq = LiteParsedQuery::makeAsFindCmd(
- NamespaceString(ns),
- fixedQuery,
- projection,
- BSONObj(), // sort
- BSONObj(), // hint
- BSONObj(), // readConcern
- skip ? boost::optional<long long>(skip) : boost::none,
- limit ? boost::optional<long long>(limit) : boost::none,
- batchSize ? boost::optional<long long>(batchSize) : boost::none);
- BenchRunEventTrace _bret(&stats.queryCounter);
- count = runQueryWithReadCommands(conn, std::move(lpq));
- } else {
- // Use special query function for exhaust query option.
- if (options & QueryOption_Exhaust) {
- BenchRunEventTrace _bret(&stats.queryCounter);
- stdx::function<void(const BSONObj&)> castedDoNothing(doNothing);
- count =
- conn->query(castedDoNothing, ns, fixedQuery, &projection, options);
- } else {
- BenchRunEventTrace _bret(&stats.queryCounter);
- unique_ptr<DBClientCursor> cursor;
- cursor = conn->query(
- ns, fixedQuery, limit, skip, &projection, options, batchSize);
- count = cursor->itcount();
+ if (!result["cursor"].eoo()) {
+ // The command returned a cursor, so iterate all results.
+ auto cursorResponse =
+ uassertStatusOK(CursorResponse::parseFromBSON(result));
+ int count = cursorResponse.getBatch().size();
+ while (cursorResponse.getCursorId() != 0) {
+ GetMoreRequest getMoreRequest(
+ cursorResponse.getNSS(),
+ cursorResponse.getCursorId(),
+ boost::none, // batchSize
+ boost::none, // maxTimeMS
+ boost::none, // term
+ boost::none); // lastKnownCommittedOpTime
+ BSONObj getMoreCommandResult;
+ ok = conn->runCommand(
+ op.ns, getMoreRequest.toBSON(), getMoreCommandResult);
+ uassert(ErrorCodes::CommandFailed,
+ str::stream() << "getMore command failed; reply was: "
+ << getMoreCommandResult,
+ ok);
+ cursorResponse = uassertStatusOK(
+ CursorResponse::parseFromBSON(getMoreCommandResult));
+ count += cursorResponse.getBatch().size();
+ }
+ // Just give the count to the check function.
+ result = BSON("count" << count << "context" << op.context);
}
- }
- if (expected >= 0 && count != expected) {
- cout << "bench query on: " << ns << " expected: " << expected
- << " got: " << count << endl;
- verify(false);
- }
+ if (op.useCheck) {
+ int err = scope->invoke(scopeFunc, 0, &result, 1000 * 60, false);
+ if (err) {
+ log() << "Error checking in benchRun thread [command]"
+ << causedBy(scope->getError()) << endl;
+ int err = scope->invoke(scopeFunc, 0, &result, 1000 * 60, false);
+ if (err) {
+ log() << "Error checking in benchRun thread [command]"
+ << causedBy(scope->getError()) << endl;
- if (check) {
- BSONObj thisValue = BSON("count" << count << "context" << context);
- int err = scope->invoke(scopeFunc, 0, &thisValue, 1000 * 60, false);
- if (err) {
- log() << "Error checking in benchRun thread [find]"
- << causedBy(scope->getError()) << endl;
+ stats.errCount++;
- stats.errCount++;
+ return;
+ }
+ }
- return;
+ if (!_config->hideResults || op.showResult)
+ log() << "Result from benchRun thread [command] : " << result
+ << endl;
}
- }
-
- if (!_config->hideResults || e["showResult"].trueValue())
- log() << "Result from benchRun thread [query] : " << count << endl;
-
- } else if (op == "update") {
- bool multi = e["multi"].trueValue();
- bool upsert = e["upsert"].trueValue();
- BSONObj queryOrginal = e["query"].eoo() ? BSONObj() : e["query"].Obj();
- BSONObj updateOriginal = e["update"].Obj();
- BSONObj result;
- bool safe = e["safe"].trueValue();
-
- {
- BenchRunEventTrace _bret(&stats.updateCounter);
- BSONObj query = fixQuery(queryOrginal, bsonTemplateEvaluator);
- BSONObj update = fixQuery(updateOriginal, bsonTemplateEvaluator);
-
- if (useWriteCmd) {
- // TODO: Replace after SERVER-11774.
- BSONObjBuilder builder;
- builder.append("update", nsToCollectionSubstring(ns));
- BSONArrayBuilder docBuilder(builder.subarrayStart("updates"));
- docBuilder.append(BSON("q" << query << "u" << update << "multi" << multi
- << "upsert" << upsert));
- docBuilder.done();
- auto wcElem = e["writeConcern"];
- if (wcElem) {
- builder.append("writeConcern", wcElem.Obj());
- }
- conn->runCommand(
- nsToDatabaseSubstring(ns).toString(), builder.done(), result);
+ } break;
+ case OpType::FIND: {
+ int count;
+
+ BSONObj fixedQuery = fixQuery(op.query, bsonTemplateEvaluator);
+
+ if (op.useReadCmd) {
+ uassert(28824,
+ "cannot use 'options' in combination with read commands",
+ !op.options);
+ unique_ptr<LiteParsedQuery> lpq = LiteParsedQuery::makeAsFindCmd(
+ NamespaceString(op.ns),
+ fixedQuery,
+ op.projection,
+ BSONObj(), // sort
+ BSONObj(), // hint
+ BSONObj(), // readConcern
+ op.skip ? boost::optional<long long>(op.skip) : boost::none,
+ op.limit ? boost::optional<long long>(op.limit) : boost::none,
+ op.batchSize ? boost::optional<long long>(op.batchSize)
+ : boost::none);
+ BenchRunEventTrace _bret(&stats.queryCounter);
+ count = runQueryWithReadCommands(conn, std::move(lpq));
} else {
- conn->update(ns, query, update, upsert, multi);
- if (safe)
- result = conn->getLastErrorDetailed();
+ // Use special query function for exhaust query option.
+ if (op.options & QueryOption_Exhaust) {
+ BenchRunEventTrace _bret(&stats.queryCounter);
+ stdx::function<void(const BSONObj&)> castedDoNothing(doNothing);
+ count = conn->query(
+ castedDoNothing, op.ns, fixedQuery, &op.projection, op.options);
+ } else {
+ BenchRunEventTrace _bret(&stats.queryCounter);
+ unique_ptr<DBClientCursor> cursor;
+ cursor = conn->query(op.ns,
+ fixedQuery,
+ op.limit,
+ op.skip,
+ &op.projection,
+ op.options,
+ op.batchSize);
+ count = cursor->itcount();
+ }
}
- }
- if (safe) {
- if (check) {
- int err = scope->invoke(scopeFunc, 0, &result, 1000 * 60, false);
+ if (op.expected >= 0 && count != op.expected) {
+ cout << "bench query on: " << op.ns << " expected: " << op.expected
+ << " got: " << count << endl;
+ verify(false);
+ }
+
+ if (op.useCheck) {
+ BSONObj thisValue = BSON("count" << count << "context" << op.context);
+ int err = scope->invoke(scopeFunc, 0, &thisValue, 1000 * 60, false);
if (err) {
- log() << "Error checking in benchRun thread [update]"
+ log() << "Error checking in benchRun thread [find]"
<< causedBy(scope->getError()) << endl;
stats.errCount++;
@@ -690,159 +872,193 @@ void BenchRunWorker::generateLoadOnConnection(DBClientBase* conn) {
}
}
- if (!_config->hideResults || e["showResult"].trueValue())
- log() << "Result from benchRun thread [safe update] : " << result
- << endl;
+ if (!_config->hideResults || op.showResult)
+ log() << "Result from benchRun thread [query] : " << count << endl;
+ } break;
+ case OpType::UPDATE: {
+ BSONObj result;
+ {
+ BenchRunEventTrace _bret(&stats.updateCounter);
+ BSONObj query = fixQuery(op.query, bsonTemplateEvaluator);
+ BSONObj update = fixQuery(op.update, bsonTemplateEvaluator);
+
+ if (op.useWriteCmd) {
+ // TODO: Replace after SERVER-11774.
+ BSONObjBuilder builder;
+ builder.append("update", nsToCollectionSubstring(op.ns));
+ BSONArrayBuilder docBuilder(builder.subarrayStart("updates"));
+ docBuilder.append(BSON("q" << query << "u" << update << "multi"
+ << op.multi << "upsert" << op.upsert));
+ docBuilder.done();
+ builder.append("writeConcern", op.writeConcern);
+ conn->runCommand(nsToDatabaseSubstring(op.ns).toString(),
+ builder.done(),
+ result);
+ } else {
+ conn->update(op.ns, query, update, op.upsert, op.multi);
+ if (op.safe)
+ result = conn->getLastErrorDetailed();
+ }
+ }
- if (!result["err"].eoo() && result["err"].type() == String &&
- (_config->throwGLE || e["throwGLE"].trueValue()))
- throw DBException((string) "From benchRun GLE" +
- causedBy(result["err"].String()),
- result["code"].eoo() ? 0 : result["code"].Int());
- }
- } else if (op == "insert") {
- bool safe = e["safe"].trueValue();
- BSONObj result;
+ if (op.safe) {
+ if (op.useCheck) {
+ int err = scope->invoke(scopeFunc, 0, &result, 1000 * 60, false);
+ if (err) {
+ log() << "Error checking in benchRun thread [update]"
+ << causedBy(scope->getError()) << endl;
- {
- BenchRunEventTrace _bret(&stats.insertCounter);
-
- BSONObj insertDoc;
- if (useWriteCmd) {
- // TODO: Replace after SERVER-11774.
- BSONObjBuilder builder;
- builder.append("insert", nsToCollectionSubstring(ns));
- BSONArrayBuilder docBuilder(builder.subarrayStart("documents"));
- if (e["doc"].type() == Array) {
- for (auto& element : e["doc"].Array()) {
- insertDoc = fixQuery(element.Obj(), bsonTemplateEvaluator);
- docBuilder.append(insertDoc);
+ stats.errCount++;
+
+ return;
}
- } else {
- insertDoc = fixQuery(e["doc"].Obj(), bsonTemplateEvaluator);
- docBuilder.append(insertDoc);
}
- docBuilder.done();
- auto wcElem = e["writeConcern"];
- if (wcElem) {
- builder.append("writeConcern", wcElem.Obj());
- }
- conn->runCommand(
- nsToDatabaseSubstring(ns).toString(), builder.done(), result);
- } else {
- if (e["doc"].type() == Array) {
- std::vector<BSONObj> insertArray;
- for (auto& element : e["doc"].Array()) {
- BSONObj e = fixQuery(element.Obj(), bsonTemplateEvaluator);
- insertArray.push_back(e);
+
+ if (!_config->hideResults || op.showResult)
+ log() << "Result from benchRun thread [safe update] : " << result
+ << endl;
+
+ if (!result["err"].eoo() && result["err"].type() == String &&
+ (_config->throwGLE || op.throwGLE))
+ throw DBException((string) "From benchRun GLE" +
+ causedBy(result["err"].String()),
+ result["code"].eoo() ? 0 : result["code"].Int());
+ }
+ } break;
+ case OpType::INSERT: {
+ BSONObj result;
+
+ {
+ BenchRunEventTrace _bret(&stats.insertCounter);
+
+ BSONObj insertDoc;
+ if (op.useWriteCmd) {
+ // TODO: Replace after SERVER-11774.
+ BSONObjBuilder builder;
+ builder.append("insert", nsToCollectionSubstring(op.ns));
+ BSONArrayBuilder docBuilder(builder.subarrayStart("documents"));
+ if (op.isDocAnArray) {
+ for (const auto& element : op.doc) {
+ insertDoc = fixQuery(element.Obj(), bsonTemplateEvaluator);
+ docBuilder.append(insertDoc);
+ }
+ } else {
+ insertDoc = fixQuery(op.doc, bsonTemplateEvaluator);
+ docBuilder.append(insertDoc);
}
- conn->insert(ns, insertArray);
+ docBuilder.done();
+ builder.append("writeConcern", op.writeConcern);
+ conn->runCommand(nsToDatabaseSubstring(op.ns).toString(),
+ builder.done(),
+ result);
} else {
- insertDoc = fixQuery(e["doc"].Obj(), bsonTemplateEvaluator);
- conn->insert(ns, insertDoc);
+ if (op.isDocAnArray) {
+ std::vector<BSONObj> insertArray;
+ for (const auto& element : op.doc) {
+ BSONObj e = fixQuery(element.Obj(), bsonTemplateEvaluator);
+ insertArray.push_back(e);
+ }
+ conn->insert(op.ns, insertArray);
+ } else {
+ insertDoc = fixQuery(op.doc, bsonTemplateEvaluator);
+ conn->insert(op.ns, insertDoc);
+ }
+ if (op.safe)
+ result = conn->getLastErrorDetailed();
}
- if (safe)
- result = conn->getLastErrorDetailed();
}
- }
- if (safe) {
- if (check) {
- int err = scope->invoke(scopeFunc, 0, &result, 1000 * 60, false);
- if (err) {
- log() << "Error checking in benchRun thread [insert]"
- << causedBy(scope->getError()) << endl;
+ if (op.safe) {
+ if (op.useCheck) {
+ int err = scope->invoke(scopeFunc, 0, &result, 1000 * 60, false);
+ if (err) {
+ log() << "Error checking in benchRun thread [insert]"
+ << causedBy(scope->getError()) << endl;
- stats.errCount++;
+ stats.errCount++;
- return;
+ return;
+ }
}
- }
- if (!_config->hideResults || e["showResult"].trueValue())
- log() << "Result from benchRun thread [safe insert] : " << result
- << endl;
+ if (!_config->hideResults || op.showResult)
+ log() << "Result from benchRun thread [safe insert] : " << result
+ << endl;
- if (!result["err"].eoo() && result["err"].type() == String &&
- (_config->throwGLE || e["throwGLE"].trueValue()))
- throw DBException((string) "From benchRun GLE" +
- causedBy(result["err"].String()),
- result["code"].eoo() ? 0 : result["code"].Int());
- }
- } else if (op == "delete" || op == "remove") {
- bool multi = e["multi"].eoo() ? true : e["multi"].trueValue();
- BSONObj query = e["query"].eoo() ? BSONObj() : e["query"].Obj();
- bool safe = e["safe"].trueValue();
- BSONObj result;
- {
- BenchRunEventTrace _bret(&stats.deleteCounter);
- BSONObj predicate = fixQuery(query, bsonTemplateEvaluator);
- if (useWriteCmd) {
- // TODO: Replace after SERVER-11774.
- BSONObjBuilder builder;
- builder.append("delete", nsToCollectionSubstring(ns));
- BSONArrayBuilder docBuilder(builder.subarrayStart("deletes"));
- int limit = (multi == true) ? 0 : 1;
- docBuilder.append(BSON("q" << predicate << "limit" << limit));
- docBuilder.done();
- auto wcElem = e["writeConcern"];
- if (wcElem) {
- builder.append("writeConcern", wcElem.Obj());
+ if (!result["err"].eoo() && result["err"].type() == String &&
+ (_config->throwGLE || op.throwGLE))
+ throw DBException((string) "From benchRun GLE" +
+ causedBy(result["err"].String()),
+ result["code"].eoo() ? 0 : result["code"].Int());
+ }
+ } break;
+ case OpType::REMOVE: {
+ BSONObj result;
+ {
+ BenchRunEventTrace _bret(&stats.deleteCounter);
+ BSONObj predicate = fixQuery(op.query, bsonTemplateEvaluator);
+ if (op.useWriteCmd) {
+ // TODO: Replace after SERVER-11774.
+ BSONObjBuilder builder;
+ builder.append("delete", nsToCollectionSubstring(op.ns));
+ BSONArrayBuilder docBuilder(builder.subarrayStart("deletes"));
+ int limit = (op.multi == true) ? 0 : 1;
+ docBuilder.append(BSON("q" << predicate << "limit" << limit));
+ docBuilder.done();
+ builder.append("writeConcern", op.writeConcern);
+ conn->runCommand(nsToDatabaseSubstring(op.ns).toString(),
+ builder.done(),
+ result);
+ } else {
+ conn->remove(op.ns, predicate, !op.multi);
+ if (op.safe)
+ result = conn->getLastErrorDetailed();
}
- conn->runCommand(
- nsToDatabaseSubstring(ns).toString(), builder.done(), result);
- } else {
- conn->remove(ns, predicate, !multi);
- if (safe)
- result = conn->getLastErrorDetailed();
}
- }
- if (safe) {
- if (check) {
- int err = scope->invoke(scopeFunc, 0, &result, 1000 * 60, false);
- if (err) {
- log() << "Error checking in benchRun thread [delete]"
- << causedBy(scope->getError()) << endl;
+ if (op.safe) {
+ if (op.useCheck) {
+ int err = scope->invoke(scopeFunc, 0, &result, 1000 * 60, false);
+ if (err) {
+ log() << "Error checking in benchRun thread [delete]"
+ << causedBy(scope->getError()) << endl;
- stats.errCount++;
+ stats.errCount++;
- return;
+ return;
+ }
}
- }
- if (!_config->hideResults || e["showResult"].trueValue())
- log() << "Result from benchRun thread [safe remove] : " << result
- << endl;
+ if (!_config->hideResults || op.showResult)
+ log() << "Result from benchRun thread [safe remove] : " << result
+ << endl;
- if (!result["err"].eoo() && result["err"].type() == String &&
- (_config->throwGLE || e["throwGLE"].trueValue()))
- throw DBException((string) "From benchRun GLE " +
- causedBy(result["err"].String()),
- result["code"].eoo() ? 0 : result["code"].Int());
- }
- } else if (op == "createIndex") {
- conn->ensureIndex(ns, e["key"].Obj(), false, "", false);
- } else if (op == "dropIndex") {
- conn->dropIndex(ns, e["key"].Obj());
- } else if (op == "let") {
- string target = e["target"].eoo() ? string() : e["target"].String();
- BSONElement value = e["value"].eoo() ? BSONElement() : e["value"];
- BSONObjBuilder valBuilder;
- BSONObjBuilder templateBuilder;
- valBuilder.append(value);
- bsonTemplateEvaluator.evaluate(valBuilder.done(), templateBuilder);
- bsonTemplateEvaluator.setVariable(target,
- templateBuilder.done().firstElement());
- } else {
- log() << "don't understand op: " << op << endl;
- stats.error = true;
- return;
+ if (!result["err"].eoo() && result["err"].type() == String &&
+ (_config->throwGLE || op.throwGLE))
+ throw DBException((string) "From benchRun GLE " +
+ causedBy(result["err"].String()),
+ result["code"].eoo() ? 0 : result["code"].Int());
+ }
+ } break;
+ case OpType::CREATEINDEX:
+ conn->ensureIndex(op.ns, op.key, false, "", false);
+ break;
+ case OpType::DROPINDEX:
+ conn->dropIndex(op.ns, op.key);
+ break;
+ case OpType::LET: {
+ BSONObjBuilder templateBuilder;
+ bsonTemplateEvaluator.evaluate(op.value, templateBuilder);
+ bsonTemplateEvaluator.setVariable(op.target,
+ templateBuilder.done().firstElement());
+ } break;
+ default:
+ uassert(34397, "In benchRun loop and got unknown op type", false);
}
// Count 1 for total ops. Successfully got through the try phrase
stats.opCount++;
} catch (DBException& ex) {
- if (!_config->hideErrors || e["showError"].trueValue()) {
+ if (!_config->hideErrors || op.showError) {
bool yesWatch =
(_config->watchPattern && _config->watchPattern->FullMatch(ex.what()));
bool noWatch =
@@ -853,7 +1069,8 @@ void BenchRunWorker::generateLoadOnConnection(DBClientBase* conn) {
(!_config->noWatchPattern && _config->watchPattern &&
yesWatch) || // If we're just watching things
(_config->watchPattern && _config->noWatchPattern && yesWatch && !noWatch))
- log() << "Error in benchRun thread for op " << e << causedBy(ex) << endl;
+ log() << "Error in benchRun thread for op "
+ << opTypeName.find(op.op)->second << causedBy(ex) << endl;
}
bool yesTrap = (_config->trapPattern && _config->trapPattern->FullMatch(ex.what()));
@@ -864,32 +1081,33 @@ void BenchRunWorker::generateLoadOnConnection(DBClientBase* conn) {
(!_config->noTrapPattern && _config->trapPattern && yesTrap) ||
(_config->trapPattern && _config->noTrapPattern && yesTrap && !noTrap)) {
{
- stats.trappedErrors.push_back(
- BSON("error" << ex.what() << "op" << e << "count" << count));
+ stats.trappedErrors.push_back(BSON("error" << ex.what() << "op"
+ << opTypeName.find(op.op)->second
+ << "count" << count));
}
if (_config->breakOnTrap)
return;
}
- if (!_config->handleErrors && !e["handleError"].trueValue())
+ if (!_config->handleErrors && !op.handleError)
return;
stats.errCount++;
} catch (...) {
- if (!_config->hideErrors || e["showError"].trueValue())
- log() << "Error in benchRun thread caused by unknown error for op " << e
- << endl;
- if (!_config->handleErrors && !e["handleError"].trueValue())
+ if (!_config->hideErrors || op.showError)
+ log() << "Error in benchRun thread caused by unknown error for op "
+ << opTypeName.find(op.op)->second << endl;
+ if (!_config->handleErrors && !op.handleError)
return;
stats.errCount++;
}
- if (++count % 100 == 0 && !useWriteCmd) {
+ if (++count % 100 == 0 && !op.useWriteCmd) {
conn->getLastError();
}
- if (delay > 0)
- sleepmillis(delay);
+ if (op.delay > 0)
+ sleepmillis(op.delay);
}
}
diff --git a/src/mongo/shell/bench.h b/src/mongo/shell/bench.h
index 3fcb9e1db03..bda8ba9f896 100644
--- a/src/mongo/shell/bench.h
+++ b/src/mongo/shell/bench.h
@@ -43,6 +43,60 @@ class RE;
namespace mongo {
+enum class OpType {
+ NONE,
+ NOP,
+ FINDONE,
+ COMMAND,
+ FIND,
+ UPDATE,
+ INSERT,
+ REMOVE,
+ CREATEINDEX,
+ DROPINDEX,
+ LET
+};
+
+/**
+ * Object representing one operation passed to benchRun
+ */
+ struct BenchRunOp {
+ public:
+ int batchSize = 0;
+ BSONElement check;
+ BSONObj command;
+ BSONObj context;
+ int delay = 0;
+ BSONObj doc;
+ bool isDocAnArray = false;
+ int expected = -1;
+ bool handleError = false;
+ BSONObj key;
+ int limit = 0;
+ bool multi = false;
+ std::string ns;
+ OpType op = OpType::NONE;
+ int options = 0;
+ BSONObj projection;
+ BSONObj query;
+ bool safe = false;
+ int skip = 0;
+ bool showError = false;
+ bool showResult = false;
+ std::string target;
+ bool throwGLE = false;
+ BSONObj update;
+ bool upsert = false;
+ bool useCheck = false;
+ bool useReadCmd = false;
+ bool useWriteCmd = false;
+ BSONObj writeConcern;
+ BSONObj value;
+
+ // This is an owned copy of the raw operation. All unowned members point into this.
+ BSONObj myBsonOp;
+};
+
/**
* Configuration object describing a bench run activity.
*/
@@ -112,17 +166,15 @@ public:
std::shared_ptr<pcrecpp::RE> noWatchPattern;
/**
- * Operation description. A BSON array of objects, each describing a single
+ * Operation description. A list of BenchRunOps, each describing a single
* operation.
*
* Every thread in a benchRun job will perform these operations in sequence, restarting at
* the beginning when the end is reached, until the job is stopped.
*
- * TODO: Document the operation objects.
- *
* TODO: Introduce support for performing each operation exactly N times.
*/
- BSONObj ops;
+ std::vector<BenchRunOp> ops;
bool throwGLE;
bool breakOnTrap;
@@ -135,7 +187,7 @@ private:
/**
* An event counter for events that have an associated duration.
*
- * Not thread safe. Expected use is one instance per thread during parallel execution.
+ * Not thread safe. Expected use is one instance per thread during parallel execution.
*/
class BenchRunEventCounter {
MONGO_DISALLOW_COPYING(BenchRunEventCounter);
@@ -151,7 +203,7 @@ public:
void reset();
/**
- * Conceptually the equivalent of "+=". Adds "other" into this.
+ * Conceptually the equivalent of "+=". Adds "other" into this.
*/
void updateFrom(const BenchRunEventCounter& other);
@@ -190,7 +242,7 @@ private:
*
* This type can be used to separately count failures and successes by passing two event
* counters to the BenchRunEventCounter constructor, and calling "succeed()" on the object at
- * the end of a successful event. If an exception is thrown, the fail counter will receive the
+ * the end of a successful event. If an exception is thrown, the fail counter will receive the
* event, and otherwise, the succes counter will.
*
* In all cases, the counter objects must outlive the trace object.
@@ -291,12 +343,12 @@ public:
void waitForState(State awaitedState);
/**
- * Notify the worker threads to wrap up. Does not block.
+ * Notify the worker threads to wrap up. Does not block.
*/
void tellWorkersToFinish();
/**
- * Notify the worker threads to collect statistics. Does not block.
+ * Notify the worker threads to collect statistics. Does not block.
*/
void tellWorkersToCollectStats();
@@ -351,7 +403,7 @@ class BenchRunWorker {
public:
/**
* Create a new worker, performing one thread's worth of the activity described in
- * "config", and part of the larger activity with state "brState". Both "config"
+ * "config", and part of the larger activity with state "brState". Both "config"
* and "brState" must exist for the life of this object.
*
* "id" is a positive integer which should uniquely identify the worker.
@@ -438,12 +490,12 @@ public:
~BenchRunner();
/**
- * Start the activity. Only call once per instance of BenchRunner.
+ * Start the activity. Only call once per instance of BenchRunner.
*/
void start();
/**
- * Stop the activity. Block until the activitiy has stopped.
+ * Stop the activity. Block until the activitiy has stopped.
*/
void stop();