diff options
author | Kaloian Manassiev <kaloian.manassiev@mongodb.com> | 2014-07-08 04:48:23 -0400 |
---|---|---|
committer | Kaloian Manassiev <kaloian.manassiev@mongodb.com> | 2014-07-10 05:41:08 -0400 |
commit | af60b4d2d5c1547c6724a2f6437f4c29a74e1470 (patch) | |
tree | 841393563a1b0ace95e47db3fd923dd2d13ec0cd /src/mongo/scripting | |
parent | ac6619a626d96de740b196340e3aaeb99c6caadd (diff) | |
download | mongo-af60b4d2d5c1547c6724a2f6437f4c29a74e1470.tar.gz |
SERVER-13961 Move benchRunner to be in the shell only
Diffstat (limited to 'src/mongo/scripting')
-rw-r--r-- | src/mongo/scripting/bench.cpp | 931 | ||||
-rw-r--r-- | src/mongo/scripting/bench.h | 432 | ||||
-rw-r--r-- | src/mongo/scripting/engine.cpp | 9 | ||||
-rw-r--r-- | src/mongo/scripting/engine.h | 2 |
4 files changed, 0 insertions, 1374 deletions
diff --git a/src/mongo/scripting/bench.cpp b/src/mongo/scripting/bench.cpp deleted file mode 100644 index ed5d0f415fb..00000000000 --- a/src/mongo/scripting/bench.cpp +++ /dev/null @@ -1,931 +0,0 @@ -/** @file bench.cpp */ - -/* - * Copyright (C) 2010 10gen Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the GNU Affero General Public License in all respects - * for all of the code used other than as permitted herein. If you modify - * file(s) with this exception, you may extend this exception to your - * version of the file(s), but you are not obligated to do so. If you do not - * wish to do so, delete this exception statement from your version. If you - * delete this exception statement from all source files in the program, - * then also delete it in the license file. - */ - - - -#include "mongo/pch.h" - -#include "mongo/scripting/bench.h" - -#include <boost/thread/thread.hpp> - -#include "mongo/db/namespace_string.h" -#include "mongo/client/dbclientcursor.h" -#include "mongo/scripting/bson_template_evaluator.h" -#include "mongo/scripting/engine.h" -#include "mongo/util/md5.h" -#include "mongo/util/timer.h" -#include "mongo/util/version.h" - - -// --------------------------------- -// ---- benchmarking system -------- -// --------------------------------- - -// TODO: Maybe extract as library to avoid code duplication? -namespace { - inline pcrecpp::RE_Options flags2options(const char* flags) { - pcrecpp::RE_Options options; - options.set_utf8(true); - while ( flags && *flags ) { - if ( *flags == 'i' ) - options.set_caseless(true); - else if ( *flags == 'm' ) - options.set_multiline(true); - else if ( *flags == 'x' ) - options.set_extended(true); - flags++; - } - return options; - } -} - -namespace mongo { - - BenchRunEventCounter::BenchRunEventCounter() { - reset(); - } - - BenchRunEventCounter::~BenchRunEventCounter() {} - - void BenchRunEventCounter::reset() { - _numEvents = 0; - _totalTimeMicros = 0; - } - - void BenchRunEventCounter::updateFrom(const BenchRunEventCounter &other) { - _numEvents += other._numEvents; - _totalTimeMicros += other._totalTimeMicros; - } - - BenchRunStats::BenchRunStats() { - reset(); - } - - BenchRunStats::~BenchRunStats() {} - - void BenchRunStats::reset() { - error = false; - errCount = 0; - - findOneCounter.reset(); - updateCounter.reset(); - insertCounter.reset(); - deleteCounter.reset(); - queryCounter.reset(); - - trappedErrors.clear(); - } - - void BenchRunStats::updateFrom(const BenchRunStats &other) { - if (other.error) - error = true; - errCount += other.errCount; - - findOneCounter.updateFrom(other.findOneCounter); - updateCounter.updateFrom(other.updateCounter); - insertCounter.updateFrom(other.insertCounter); - deleteCounter.updateFrom(other.deleteCounter); - queryCounter.updateFrom(other.queryCounter); - - for (size_t i = 0; i < other.trappedErrors.size(); ++i) - trappedErrors.push_back(other.trappedErrors[i]); - } - - BenchRunConfig::BenchRunConfig() { - initializeToDefaults(); - } - - void BenchRunConfig::initializeToDefaults() { - host = "localhost"; - db = "test"; - username = ""; - password = ""; - - parallel = 1; - seconds = 1; - hideResults = true; - handleErrors = false; - hideErrors = false; - - trapPattern.reset(); - noTrapPattern.reset(); - watchPattern.reset(); - noWatchPattern.reset(); - - ops = BSONObj(); - - throwGLE = false; - breakOnTrap = true; - } - - BenchRunConfig *BenchRunConfig::createFromBson( const BSONObj &args ) { - BenchRunConfig *config = new BenchRunConfig(); - config->initializeFromBson( 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["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 = shared_ptr< pcrecpp::RE >( new pcrecpp::RE( regex, flags2options( flags ) ) ); - } - - if ( ! args["noTrapPattern"].eoo() ){ - const char* regex = args["noTrapPattern"].regex(); - const char* flags = args["noTrapPattern"].regexFlags(); - this->noTrapPattern = shared_ptr< pcrecpp::RE >( new pcrecpp::RE( regex, flags2options( flags ) ) ); - } - - if ( ! args["watchPattern"].eoo() ){ - const char* regex = args["watchPattern"].regex(); - const char* flags = args["watchPattern"].regexFlags(); - this->watchPattern = shared_ptr< pcrecpp::RE >( new pcrecpp::RE( regex, flags2options( flags ) ) ); - } - - if ( ! args["noWatchPattern"].eoo() ){ - const char* regex = args["noWatchPattern"].regex(); - const char* flags = args["noWatchPattern"].regexFlags(); - this->noWatchPattern = shared_ptr< pcrecpp::RE >( new pcrecpp::RE( regex, flags2options( flags ) ) ); - } - - this->ops = args["ops"].Obj().getOwned(); - } - - DBClientBase *BenchRunConfig::createConnection() const { - std::string errorMessage; - ConnectionString connectionString = ConnectionString::parse( host, errorMessage ); - uassert( 16157, errorMessage, connectionString.isValid() ); - DBClientBase *connection = connectionString.connect(errorMessage); - uassert( 16158, errorMessage, connection != NULL ); - return connection; - } - - BenchRunState::BenchRunState( unsigned numWorkers ) - : _mutex(), - _numUnstartedWorkers( numWorkers ), - _numActiveWorkers( 0 ), - _isShuttingDown( 0 ) { - } - - BenchRunState::~BenchRunState() { - wassert(_numActiveWorkers == 0 && _numUnstartedWorkers == 0); - } - - void BenchRunState::waitForState(State awaitedState) { - boost::mutex::scoped_lock lk(_mutex); - - switch ( awaitedState ) { - case BRS_RUNNING: - while ( _numUnstartedWorkers > 0 ) { - massert( 16147, "Already finished.", _numUnstartedWorkers + _numActiveWorkers > 0 ); - _stateChangeCondition.wait( _mutex ); - } - break; - case BRS_FINISHED: - while ( _numUnstartedWorkers + _numActiveWorkers > 0 ) { - _stateChangeCondition.wait( _mutex ); - } - break; - default: - msgasserted(16152, mongoutils::str::stream() << "Cannot wait for state " << awaitedState); - } - } - - void BenchRunState::tellWorkersToFinish() { - _isShuttingDown.set( 1 ); - } - - void BenchRunState::assertFinished() { - boost::mutex::scoped_lock lk(_mutex); - verify(0 == _numUnstartedWorkers + _numActiveWorkers); - } - - bool BenchRunState::shouldWorkerFinish() { - return bool(_isShuttingDown.get()); - } - - void BenchRunState::onWorkerStarted() { - boost::mutex::scoped_lock lk(_mutex); - verify( _numUnstartedWorkers > 0 ); - --_numUnstartedWorkers; - ++_numActiveWorkers; - if (_numUnstartedWorkers == 0) { - _stateChangeCondition.notify_all(); - } - } - - void BenchRunState::onWorkerFinished() { - boost::mutex::scoped_lock lk(_mutex); - verify( _numActiveWorkers > 0 ); - --_numActiveWorkers; - if (_numActiveWorkers + _numUnstartedWorkers == 0) { - _stateChangeCondition.notify_all(); - } - } - - BSONObj benchStart( const BSONObj& , void* ); - BSONObj benchFinish( const BSONObj& , void* ); - - static bool _hasSpecial( const BSONObj& obj ) { - BSONObjIterator i( obj ); - while ( i.more() ) { - BSONElement e = i.next(); - if ( e.fieldName()[0] == '#' ) - return true; - - if ( ! e.isABSONObj() ) - continue; - - if ( _hasSpecial( e.Obj() ) ) - return true; - } - return false; - } - - static BSONObj fixQuery( const BSONObj& obj, BsonTemplateEvaluator& btl ) { - if ( ! _hasSpecial( obj ) ) - return obj; - BSONObjBuilder b( obj.objsize() + 128 ); - - verify(BsonTemplateEvaluator::StatusSuccess == btl.evaluate(obj, b)); - return b.obj(); - } - - BenchRunWorker::BenchRunWorker(size_t id, const BenchRunConfig *config, BenchRunState *brState) - : _id(id), _config(config), _brState(brState) { - } - - BenchRunWorker::~BenchRunWorker() {} - - void BenchRunWorker::start() { - boost::thread(stdx::bind(&BenchRunWorker::run, this)); - } - - bool BenchRunWorker::shouldStop() const { - return _brState->shouldWorkerFinish(); - } - - void doNothing(const BSONObj&) { } - - void BenchRunWorker::generateLoadOnConnection( DBClientBase* conn ) { - verify( conn ); - long long count = 0; - mongo::Timer timer; - - BsonTemplateEvaluator bsonTemplateEvaluator; - invariant(bsonTemplateEvaluator.setId(_id) == BsonTemplateEvaluator::StatusSuccess); - - while ( !shouldStop() ) { - BSONObjIterator i( _config->ops ); - while ( i.more() ) { - - if ( shouldStop() ) break; - - BSONElement e = i.next(); - - string ns = e["ns"].String(); - string op = e["op"].String(); - - int delay = e["delay"].eoo() ? 0 : e["delay"].Int(); - - // Let's default to writeCmd == false. - bool useWriteCmd = e["writeCmd"].eoo() ? false : - e["writeCmd"].Bool(); - - BSONObj context = e["context"].eoo() ? BSONObj() : e["context"].Obj(); - - auto_ptr<Scope> scope; - ScriptingFunction scopeFunc = 0; - BSONObj scopeObj; - - if (_config->username != "") { - string errmsg; - if (!conn->auth("admin", _config->username, _config->password, errmsg)) { - uasserted(15931, "Authenticating to connection for _benchThread failed: " + errmsg); - } - } - - bool check = ! e["check"].eoo(); - if( check ){ - if ( e["check"].type() == CodeWScope || e["check"].type() == Code || e["check"].type() == String ) { - scope = globalScriptEngine->getPooledScope( 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 ); - verify( scopeFunc ); - } - else { - warning() << "Invalid check type detected in benchRun op : " << e << endl; - check = false; - } - } - - try { - if ( op == "findOne" ) { - - BSONObj result; - { - BenchRunEventTrace _bret(&_stats.findOneCounter); - result = conn->findOne( ns , fixQuery( e["query"].Obj(), - bsonTemplateEvaluator ) ); - } - - 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; - } - } - - if( ! _config->hideResults || e["showResult"].trueValue() ) log() << "Result from benchRun thread [findOne] : " << result << endl; - - } - else if ( op == "command" ) { - - BSONObj result; - conn->runCommand( ns, fixQuery( e["command"].Obj(), bsonTemplateEvaluator ), - result, e["options"].numberInt() ); - - 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; - - _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(); - BSONObj filter = e["filter"].eoo() ? BSONObj() : e["filter"].Obj(); - int expected = e["expected"].eoo() ? -1 : e["expected"].Int(); - - auto_ptr<DBClientCursor> cursor; - int count; - - BSONObj fixedQuery = fixQuery(e["query"].Obj(), bsonTemplateEvaluator); - - // 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, &filter, options); - } - else { - BenchRunEventTrace _bret(&_stats.queryCounter); - cursor = conn->query(ns, fixedQuery, limit, skip, &filter, options, - batchSize); - count = cursor->itcount(); - } - - if ( expected >= 0 && count != expected ) { - cout << "bench query on: " << ns << " expected: " << expected << " got: " << count << endl; - verify(false); - } - - 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++; - - return; - } - } - - 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 query = e["query"].eoo() ? BSONObj() : e["query"].Obj(); - BSONObj update = e["update"].Obj(); - BSONObj result; - bool safe = e["safe"].trueValue(); - - { - BenchRunEventTrace _bret(&_stats.updateCounter); - - if (useWriteCmd) { - // TODO: Replace after SERVER-11774. - BSONObjBuilder builder; - builder.append("update", - nsToCollectionSubstring(ns)); - BSONArrayBuilder docBuilder( - builder.subarrayStart("updates")); - docBuilder.append(BSON("q" << fixQuery(query, bsonTemplateEvaluator) << - "u" << update << - "multi" << multi << - "upsert" << upsert)); - docBuilder.done(); - conn->runCommand( - nsToDatabaseSubstring(ns).toString(), - builder.done(), result); - } - else { - conn->update(ns, fixQuery(query, - bsonTemplateEvaluator), update, - upsert , 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 [update]" << causedBy( scope->getError() ) << endl; - - _stats.errCount++; - - return; - } - } - - if( ! _config->hideResults || e["showResult"].trueValue() ) log() << "Result from benchRun thread [safe update] : " << 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 == "insert" ) { - bool safe = e["safe"].trueValue(); - BSONObj result; - - { - BenchRunEventTrace _bret(&_stats.insertCounter); - - BSONObjBuilder builder; - BSONObj insertDoc = fixQuery(e["doc"].Obj(), bsonTemplateEvaluator); - builder.append("insert", - nsToCollectionSubstring(ns)); - BSONArrayBuilder docBuilder( - builder.subarrayStart("documents")); - docBuilder.append(insertDoc); - docBuilder.done(); - - if (useWriteCmd) { - // TODO: Replace after SERVER-11774. - conn->runCommand( - nsToDatabaseSubstring(ns).toString(), - builder.done(), result); - } - else { - conn->insert(ns, insertDoc); - 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; - - _stats.errCount++; - - return; - } - } - - if( ! _config->hideResults || e["showResult"].trueValue() ) 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); - - 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" << fixQuery(query, bsonTemplateEvaluator) << - "limit" << limit)); - docBuilder.done(); - conn->runCommand( - nsToDatabaseSubstring(ns).toString(), - builder.done(), result); - } - else { - conn->remove(ns, fixQuery(query, - bsonTemplateEvaluator), !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; - - _stats.errCount++; - - return; - } - } - - if( ! _config->hideResults || e["showResult"].trueValue() ) 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 { - log() << "don't understand op: " << op << endl; - _stats.error = true; - return; - } - } - catch( DBException& ex ){ - if( ! _config->hideErrors || e["showError"].trueValue() ){ - - bool yesWatch = ( _config->watchPattern && _config->watchPattern->FullMatch( ex.what() ) ); - bool noWatch = ( _config->noWatchPattern && _config->noWatchPattern->FullMatch( ex.what() ) ); - - if( ( ! _config->watchPattern && _config->noWatchPattern && ! noWatch ) || // If we're just ignoring things - ( ! _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; - } - - bool yesTrap = ( _config->trapPattern && _config->trapPattern->FullMatch( ex.what() ) ); - bool noTrap = ( _config->noTrapPattern && _config->noTrapPattern->FullMatch( ex.what() ) ); - - if( ( ! _config->trapPattern && _config->noTrapPattern && ! noTrap ) || - ( ! _config->noTrapPattern && _config->trapPattern && yesTrap ) || - ( _config->trapPattern && _config->noTrapPattern && yesTrap && ! noTrap ) ){ - { - _stats.trappedErrors.push_back( BSON( "error" << ex.what() << "op" << e << "count" << count ) ); - } - if( _config->breakOnTrap ) return; - } - if( ! _config->handleErrors && ! e["handleError"].trueValue() ) 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() ) return; - - _stats.errCount++; - } - - if (++count % 100 == 0 && !useWriteCmd) { - conn->getLastError(); - } - - sleepmillis( delay ); - } - } - - conn->getLastError(); - } - - namespace { - class BenchRunWorkerStateGuard : private boost::noncopyable { - public: - explicit BenchRunWorkerStateGuard( BenchRunState *brState ) : _brState( brState ) { - _brState->onWorkerStarted(); - } - - ~BenchRunWorkerStateGuard() { - _brState->onWorkerFinished(); - } - - private: - BenchRunState *_brState; - }; - } // namespace - - void BenchRunWorker::run() { - BenchRunWorkerStateGuard _workerStateGuard( _brState ); - - boost::scoped_ptr<DBClientBase> conn( _config->createConnection() ); - - try { - if ( !_config->username.empty() ) { - string errmsg; - if (!conn->auth("admin", _config->username, _config->password, errmsg)) { - uasserted(15932, "Authenticating to connection for benchThread failed: " + errmsg); - } - } - generateLoadOnConnection( conn.get() ); - } - catch( DBException& e ){ - error() << "DBException not handled in benchRun thread" << causedBy( e ) << endl; - } - catch( std::exception& e ){ - error() << "std::exception not handled in benchRun thread" << causedBy( e ) << endl; - } - catch( ... ){ - error() << "Unknown exception not handled in benchRun thread." << endl; - } - } - - BenchRunner::BenchRunner( BenchRunConfig *config ) - : _brState(config->parallel), - _config(config) { - - _oid.init(); - boost::mutex::scoped_lock lk(_staticMutex); - _activeRuns[_oid] = this; - } - - BenchRunner::~BenchRunner() { - for (size_t i = 0; i < _workers.size(); ++i) - delete _workers[i]; - } - - void BenchRunner::start( ) { - - - { - boost::scoped_ptr<DBClientBase> conn( _config->createConnection() ); - // Must authenticate to admin db in order to run serverStatus command - if (_config->username != "") { - 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"); - } - } - // Get initial stats - conn->simpleCommand( "admin" , &before , "serverStatus" ); - before = before.getOwned(); - } - - // Start threads - for ( unsigned i = 0; i < _config->parallel; i++ ) { - BenchRunWorker *worker = new BenchRunWorker(i, _config.get(), &_brState); - worker->start(); - _workers.push_back(worker); - } - - _brState.waitForState(BenchRunState::BRS_RUNNING); - } - - void BenchRunner::stop() { - _brState.tellWorkersToFinish(); - _brState.waitForState(BenchRunState::BRS_FINISHED); - - { - boost::scoped_ptr<DBClientBase> conn( _config->createConnection() ); - if (_config->username != "") { - 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"); - } - } - // Get final stats - conn->simpleCommand( "admin" , &after , "serverStatus" ); - after = after.getOwned(); - } - - { - boost::mutex::scoped_lock lk(_staticMutex); - _activeRuns.erase( _oid ); - } - } - - BenchRunner* BenchRunner::createWithConfig( const BSONObj &configArgs ) { - BenchRunConfig *config = BenchRunConfig::createFromBson( configArgs ); - return new BenchRunner(config); - } - - BenchRunner* BenchRunner::get( OID oid ) { - boost::mutex::scoped_lock lk(_staticMutex); - return _activeRuns[ oid ]; - } - - void BenchRunner::populateStats( BenchRunStats *stats ) { - _brState.assertFinished(); - stats->reset(); - for ( size_t i = 0; i < _workers.size(); ++i ) - stats->updateFrom( _workers[i]->stats() ); - BSONObj before = this->before["opcounters"].Obj(); - BSONObj after = this->after["opcounters"].Obj(); - { - BSONObjIterator i( after ); - while ( i.more() ) { - BSONElement e = i.next(); - long long delta = e.numberLong(); - delta -= before[e.fieldName()].numberLong(); - stats->opcounters[e.fieldName()] = delta; - } - } - } - - static void appendAverageMicrosIfAvailable( - BSONObjBuilder &buf, const std::string &name, const BenchRunEventCounter &counter) { - - if (counter.getNumEvents() > 0) - buf.append(name, - static_cast<double>(counter.getTotalTimeMicros()) / counter.getNumEvents()); - } - - BSONObj BenchRunner::finish( BenchRunner* runner ) { - - runner->stop(); - - BenchRunStats stats; - runner->populateStats(&stats); - - // vector<BSONOBj> errors = runner->config.errors; - bool error = stats.error; - - if ( error ) - return BSON( "err" << 1 ); - - // compute actual ops/sec - BSONObj before = runner->before["opcounters"].Obj(); - BSONObj after = runner->after["opcounters"].Obj(); - - BSONObjBuilder buf; - buf.append( "note" , "values per second" ); - buf.append( "errCount", (long long) stats.errCount ); - buf.append( "trapped", "error: not implemented" ); - appendAverageMicrosIfAvailable(buf, "findOneLatencyAverageMicros", stats.findOneCounter); - appendAverageMicrosIfAvailable(buf, "insertLatencyAverageMicros", stats.insertCounter); - appendAverageMicrosIfAvailable(buf, "deleteLatencyAverageMicros", stats.deleteCounter); - appendAverageMicrosIfAvailable(buf, "updateLatencyAverageMicros", stats.updateCounter); - appendAverageMicrosIfAvailable(buf, "queryLatencyAverageMicros", stats.queryCounter); - - { - BSONObjIterator i( after ); - while ( i.more() ) { - BSONElement e = i.next(); - double x = e.number(); - x -= before[e.fieldName()].number(); - buf.append( e.fieldName() , x / runner->_config->seconds ); - } - } - - BSONObj zoo = buf.obj(); - - delete runner; - return zoo; - } - - boost::mutex BenchRunner::_staticMutex; - map< OID, BenchRunner* > BenchRunner::_activeRuns; - - /** - * benchRun( { ops : [] , host : XXX , db : XXXX , parallel : 5 , seconds : 5 } - */ - BSONObj BenchRunner::benchRunSync( const BSONObj& argsFake, void* data ) { - - BSONObj start = benchStart( argsFake, data ); - - OID oid = OID( start.firstElement().String() ); - BenchRunner* runner = BenchRunner::get( oid ); - sleepmillis( (int)(1000.0 * runner->config().seconds) ); - - return benchFinish( start, data ); - } - - /** - * benchRun( { ops : [] , host : XXX , db : XXXX , parallel : 5 , seconds : 5 } - */ - BSONObj BenchRunner::benchStart( const BSONObj& argsFake, void* data ) { - - verify( argsFake.firstElement().isABSONObj() ); - BSONObj args = argsFake.firstElement().Obj(); - - // Get new BenchRunner object - BenchRunner* runner = BenchRunner::createWithConfig( args ); - - runner->start(); - return BSON( "" << runner->oid().toString() ); - } - - /** - * benchRun( { ops : [] , host : XXX , db : XXXX , parallel : 5 , seconds : 5 } - */ - BSONObj BenchRunner::benchFinish( const BSONObj& argsFake, void* data ) { - - OID oid = OID( argsFake.firstElement().String() ); - - // Get new BenchRunner object - BenchRunner* runner = BenchRunner::get( oid ); - - BSONObj finalObj = BenchRunner::finish( runner ); - - return BSON( "" << finalObj ); - } - -} // namespace mongo diff --git a/src/mongo/scripting/bench.h b/src/mongo/scripting/bench.h deleted file mode 100644 index 83f674896bb..00000000000 --- a/src/mongo/scripting/bench.h +++ /dev/null @@ -1,432 +0,0 @@ -/* - * Copyright (C) 2010 10gen Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the GNU Affero General Public License in all respects - * for all of the code used other than as permitted herein. If you modify - * file(s) with this exception, you may extend this exception to your - * version of the file(s), but you are not obligated to do so. If you do not - * wish to do so, delete this exception statement from your version. If you - * delete this exception statement from all source files in the program, - * then also delete it in the license file. - */ - -#pragma once - -#include <string> - -#include <boost/shared_ptr.hpp> -#include <boost/thread/condition.hpp> -#include <boost/thread/mutex.hpp> -#include <pcrecpp.h> - -#include "mongo/bson/util/atomic_int.h" -#include "mongo/client/dbclientinterface.h" -#include "mongo/db/jsobj.h" -#include "mongo/util/timer.h" - -namespace mongo { - - /** - * Configuration object describing a bench run activity. - */ - class BenchRunConfig : private boost::noncopyable { - public: - - /** - * Create a new BenchRunConfig object, and initialize it from the BSON - * document, "args". - * - * Caller owns the returned object, and is responsible for its deletion. - */ - static BenchRunConfig *createFromBson( const BSONObj &args ); - - BenchRunConfig(); - - void initializeFromBson( const BSONObj &args ); - - // Create a new connection to the mongo instance specified by this configuration. - DBClientBase *createConnection() const; - - /** - * Connection std::string describing the host to which to connect. - */ - std::string host; - - /** - * Name of the database on which to operate. - */ - std::string db; - - /** - * Optional username for authenticating to the database. - */ - std::string username; - - /** - * Optional password for authenticating to the database. - * - * Only useful if username is non-empty. - */ - std::string password; - - /** - * Number of parallel threads to perform the bench run activity. - */ - unsigned parallel; - - /** - * Desired duration of the bench run activity, in seconds. - * - * NOTE: Only used by the javascript benchRun() and benchRunSync() functions. - */ - double seconds; - - bool hideResults; - bool handleErrors; - bool hideErrors; - - boost::shared_ptr< pcrecpp::RE > trapPattern; - boost::shared_ptr< pcrecpp::RE > noTrapPattern; - boost::shared_ptr< pcrecpp::RE > watchPattern; - boost::shared_ptr< pcrecpp::RE > noWatchPattern; - - /** - * Operation description. A BSON array of objects, 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; - - bool throwGLE; - bool breakOnTrap; - - private: - /// Initialize a config object to its default values. - void initializeToDefaults(); - }; - - /** - * An event counter for events that have an associated duration. - * - * Not thread safe. Expected use is one instance per thread during parallel execution. - */ - class BenchRunEventCounter : private boost::noncopyable { - public: - /// Constructs a zeroed out counter. - BenchRunEventCounter(); - ~BenchRunEventCounter(); - - /** - * Zero out the counter. - */ - void reset(); - - /** - * Conceptually the equivalent of "+=". Adds "other" into this. - */ - void updateFrom( const BenchRunEventCounter &other ); - - /** - * Count one instance of the event, which took "timeMicros" microseconds. - */ - void countOne(long long timeMicros) { - ++_numEvents; - _totalTimeMicros += timeMicros; - } - - /** - * Get the total number of microseconds ellapsed during all observed events. - */ - unsigned long long getTotalTimeMicros() const { return _totalTimeMicros; } - - /** - * Get the number of observed events. - */ - unsigned long long getNumEvents() const { return _numEvents; } - - private: - unsigned long long _numEvents; - long long _totalTimeMicros; - }; - - /** - * RAII object for tracing an event. - * - * Construct an instance of this at the beginning of an event, and have it go out of scope at - * the end, to facilitate tracking events. - * - * 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 - * event, and otherwise, the succes counter will. - * - * In all cases, the counter objects must outlive the trace object. - */ - class BenchRunEventTrace : private boost::noncopyable { - public: - explicit BenchRunEventTrace(BenchRunEventCounter *eventCounter) { - initialize(eventCounter, eventCounter, false); - } - - BenchRunEventTrace(BenchRunEventCounter *successCounter, - BenchRunEventCounter *failCounter, - bool defaultToFailure=true) { - initialize(successCounter, failCounter, defaultToFailure); - } - - ~BenchRunEventTrace() { - (_succeeded ? _successCounter : _failCounter)->countOne(_timer.micros()); - } - - void succeed() { _succeeded = true; } - void fail() { _succeeded = false; } - - private: - void initialize(BenchRunEventCounter *successCounter, - BenchRunEventCounter *failCounter, - bool defaultToFailure) { - _successCounter = successCounter; - _failCounter = failCounter; - _succeeded = !defaultToFailure; - } - - Timer _timer; - BenchRunEventCounter *_successCounter; - BenchRunEventCounter *_failCounter; - bool _succeeded; - }; - - /** - * Statistics object representing the result of a bench run activity. - */ - class BenchRunStats : private boost::noncopyable { - public: - BenchRunStats(); - ~BenchRunStats(); - - void reset(); - - void updateFrom( const BenchRunStats &other ); - - bool error; - unsigned long long errCount; - - BenchRunEventCounter findOneCounter; - BenchRunEventCounter updateCounter; - BenchRunEventCounter insertCounter; - BenchRunEventCounter deleteCounter; - BenchRunEventCounter queryCounter; - - std::map<std::string, long long> opcounters; - std::vector<BSONObj> trappedErrors; - }; - - /** - * State of a BenchRun activity. - * - * Logically, the states are "starting up", "running" and "finished." - */ - class BenchRunState : private boost::noncopyable { - public: - enum State { BRS_STARTING_UP, BRS_RUNNING, BRS_FINISHED }; - - explicit BenchRunState(unsigned numWorkers); - ~BenchRunState(); - - // - // Functions called by the job-controlling thread, through an instance of BenchRunner. - // - - /** - * Block until the current state is "awaitedState." - * - * massert() (uassert()?) if "awaitedState" is unreachable from - * the current state. - */ - void waitForState(State awaitedState); - - /** - * Notify the worker threads to wrap up. Does not block. - */ - void tellWorkersToFinish(); - - /// Check that the current state is BRS_FINISHED. - void assertFinished(); - - // - // Functions called by the worker threads, through instances of BenchRunWorker. - // - - /** - * Predicate that workers call to see if they should finish (as a result of a call - * to tellWorkersToFinish()). - */ - bool shouldWorkerFinish(); - - /** - * Called by each BenchRunWorker from within its thread context, immediately before it - * starts sending requests to the configured mongo instance. - */ - void onWorkerStarted(); - - /** - * Called by each BenchRunWorker from within its thread context, shortly after it finishes - * sending requests to the configured mongo instance. - */ - void onWorkerFinished(); - - private: - boost::mutex _mutex; - boost::condition _stateChangeCondition; - unsigned _numUnstartedWorkers; - unsigned _numActiveWorkers; - AtomicUInt _isShuttingDown; - }; - - /** - * A single worker in the bench run activity. - * - * Represents the behavior of one thread working in a bench run activity. - */ - class BenchRunWorker : private boost::noncopyable { - 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" - * and "brState" must exist for the life of this object. - * - * "id" is a positive integer which should uniquely identify the worker. - */ - BenchRunWorker(size_t id, const BenchRunConfig *config, BenchRunState *brState); - ~BenchRunWorker(); - - /** - * Start performing the "work" behavior in a new thread. - */ - void start(); - - /** - * Get the run statistics for a worker. - * - * Should only be observed _after_ the worker has signaled its completion by calling - * onWorkerFinished() on the BenchRunState passed into its constructor. - */ - const BenchRunStats &stats() const { return _stats; } - - private: - /// The main method of the worker, executed inside the thread launched by start(). - void run(); - - /// The function that actually sets about generating the load described in "_config". - void generateLoadOnConnection( DBClientBase *conn ); - - /// Predicate, used to decide whether or not it's time to terminate the worker. - bool shouldStop() const; - - size_t _id; - const BenchRunConfig *_config; - BenchRunState *_brState; - BenchRunStats _stats; - }; - - /** - * Object representing a "bench run" activity. - */ - class BenchRunner : private boost::noncopyable { - public: - /** - * Utility method to create a new bench runner from a BSONObj representation - * of a configuration. - * - * TODO: This is only really for the use of the javascript benchRun() methods, - * and should probably move out of the BenchRunner class. - */ - static BenchRunner* createWithConfig( const BSONObj &configArgs ); - - /** - * Look up a bench runner object by OID. - * - * TODO: Same todo as for "createWithConfig". - */ - static BenchRunner* get( OID oid ); - - /** - * Stop a running "runner", and return a BSON representation of its resultant - * BenchRunStats. - * - * TODO: Same as for "createWithConfig". - */ - static BSONObj finish( BenchRunner* runner ); - - /** - * Create a new bench runner, to perform the activity described by "*config." - * - * Takes ownership of "config", and will delete it. - */ - explicit BenchRunner( BenchRunConfig *config ); - ~BenchRunner(); - - /** - * Start the activity. Only call once per instance of BenchRunner. - */ - void start(); - - /** - * Stop the activity. Block until the activitiy has stopped. - */ - void stop(); - - /** - * Store the collected event data from a completed bench run activity into "stats." - * - * Illegal to call until after stop() returns. - */ - void populateStats(BenchRunStats *stats); - - OID oid() const { return _oid; } - - const BenchRunConfig &config() const { return *_config; } // TODO: Remove this function. - - // JS bindings - static BSONObj benchFinish(const BSONObj& argsFake, void* data); - static BSONObj benchStart(const BSONObj& argsFake, void* data); - static BSONObj benchRunSync(const BSONObj& argsFake, void* data); - - private: - // TODO: Same as for createWithConfig. - static boost::mutex _staticMutex; - static std::map< OID, BenchRunner* > _activeRuns; - - OID _oid; - BenchRunState _brState; - boost::scoped_ptr<BenchRunConfig> _config; - std::vector<BenchRunWorker *> _workers; - - BSONObj before; - BSONObj after; - }; - -} // namespace mongo diff --git a/src/mongo/scripting/engine.cpp b/src/mongo/scripting/engine.cpp index c0c6d30f577..820acd24eda 100644 --- a/src/mongo/scripting/engine.cpp +++ b/src/mongo/scripting/engine.cpp @@ -37,7 +37,6 @@ #include "mongo/client/dbclientcursor.h" #include "mongo/client/dbclientinterface.h" #include "mongo/platform/unordered_set.h" -#include "mongo/scripting/bench.h" #include "mongo/util/file.h" #include "mongo/util/text.h" @@ -279,14 +278,6 @@ namespace mongo { execSetup(JSFiles::upgrade_check); } - /** install BenchRunner suite */ - void Scope::installBenchRun() { - injectNative("benchRun", BenchRunner::benchRunSync); - injectNative("benchRunSync", BenchRunner::benchRunSync); - injectNative("benchStart", BenchRunner::benchStart); - injectNative("benchFinish", BenchRunner::benchFinish); - } - namespace { class ScopeCache { public: diff --git a/src/mongo/scripting/engine.h b/src/mongo/scripting/engine.h index 1fb512a6a44..ec4c1667481 100644 --- a/src/mongo/scripting/engine.h +++ b/src/mongo/scripting/engine.h @@ -85,8 +85,6 @@ namespace mongo { virtual bool hasOutOfMemoryException() = 0; - virtual void installBenchRun(); - virtual bool isKillPending() const = 0; virtual void gc() = 0; |