summaryrefslogtreecommitdiff
path: root/src/mongo/tools/loadgenerator.cpp
diff options
context:
space:
mode:
authorApollon Oikonomopoulos <apoikos@debian.org>2016-01-14 00:10:06 +0200
committerApollon Oikonomopoulos <apollon@skroutz.gr>2016-01-14 00:10:06 +0200
commit374e1947abcd3e127a2a613aff73ecffdb9199ea (patch)
treed83973c3c9802450acd5b5e86fe0d4e8e60a3a1b /src/mongo/tools/loadgenerator.cpp
parent65585c90b12d6523bea75a2aebaae2a2fdf9e641 (diff)
Imported Upstream version 2.6.11upstream/2.6.11
Diffstat (limited to 'src/mongo/tools/loadgenerator.cpp')
-rw-r--r--src/mongo/tools/loadgenerator.cpp417
1 files changed, 0 insertions, 417 deletions
diff --git a/src/mongo/tools/loadgenerator.cpp b/src/mongo/tools/loadgenerator.cpp
deleted file mode 100644
index 42e7ad8029e..00000000000
--- a/src/mongo/tools/loadgenerator.cpp
+++ /dev/null
@@ -1,417 +0,0 @@
-/** @file loadgenerator.cpp */
-
-/**
- * Copyright (C) 2012 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/>.
- */
-
-/*
- * LoadGenerator drives a certain number (# threads) of simultaneous operation into a
- * specified number of databases as quickly as it can at a mongo instance,
- * continuously, for some number of seconds.
- *
- */
-
-/*
- * For internal reference:
- * Each document generated by the docgenerator.cpp is 176 bytes long
- * Number of documents per instance size :
- * small (500 MB) : 2978905 docs spread over 5 dbs (each db is 100 MB) Docs Per DB : 595781
- * medium (5 GB) : 30504030 docs spread over 5 dbs (each db is 1 GB) Docs Per DB : 6100806
- * large (25 GB) : 152520145 docs evenly spread over 5 dbs (each db is 5 GB) Docs Per DB : 30504029
- * vlarge (100 GB) : 621172954 docs evenly spread over 10 dbs (each db is 10 GB) Docs Per DB : 61008058
- *
- */
-
-#include <map>
-#include <string>
-
-#include <boost/program_options.hpp>
-#include <boost/scoped_ptr.hpp>
-
-#include "mongo/base/initializer.h"
-#include "mongo/util/assert_util.h"
-#include "mongo/scripting/bench.h"
-#include "mongo/client/dbclientinterface.h"
-#include "mongo/tools/docgenerator.h"
-#include "mongo/util/map_util.h"
-#include "mongo/util/md5.hpp"
-#include "mongo/util/mongoutils/str.h"
-
-using namespace std;
-
-using namespace mongo;
-
-namespace po = boost::program_options;
-
-namespace {
-
-struct LoadGeneratorOptions {
- LoadGeneratorOptions() :
- hostname("localhost"),
- type("query"),
- instanceSize( "large" ),
- numdbs( 5 ),
- resultNS( "" ),
- numOps( 60000 ),
- durationSeconds( 60 ),
- parallelThreads( 32 ),
- trials( 5 ),
- docsPerDB( 0 )
- { }
-
- string hostname;
- string type;
- string instanceSize;
- int numdbs;
- string resultNS;
- int numOps;
- double durationSeconds;
- int parallelThreads;
- int trials;
- unsigned long long docsPerDB;
-};
-
-
-struct OperationStats {
- OperationStats( const unsigned long long numEvents, const unsigned long long totalTimeMicros,
- const long long opcounter ) :
- numEvents( numEvents ),
- totalTimeMicros( totalTimeMicros ),
- opcounter( opcounter ) { }
- OperationStats() { }
-
- unsigned long long numEvents;
- unsigned long long totalTimeMicros;
- long long opcounter;
-};
-
-// ------Globals and typedefs----------
-LoadGeneratorOptions globalLoadGenOption;
-typedef std::map<std::string, OperationStats> OpStatsMap;
-
-double randomBetweenRange(const int& min, const int& max) {
- return rand() % (max - min) + min;
-}
-
-mongo::DBClientBase *getDBConnection() {
- string errmsg;
- mongo::ConnectionString connectionString = mongo::ConnectionString::parse(
- globalLoadGenOption.hostname, errmsg );
- mongo::fassert( 16265, connectionString.isValid() );
- mongo::DBClientBase *connection = connectionString.connect( errmsg );
- mongo::fassert( 16266, connection != NULL );
- return connection;
-}
-
-void dropNS(const string ns) {
- boost::scoped_ptr<mongo::DBClientBase> connection( getDBConnection() );
- connection->dropCollection( ns );
-}
-
-void dropDB(const string db) {
- boost::scoped_ptr<mongo::DBClientBase> connection( getDBConnection() );
- connection->dropDatabase( db );
-}
-
-void writeToNS(const string ns, const mongo::BSONObj bs) {
- boost::scoped_ptr<mongo::DBClientBase> connection( getDBConnection() );
- connection->insert( ns, bs );
- mongo::fassert( 16267, connection->getLastError().empty() );
-}
-
-// find the number of documents in a namespace
-void numDocsInNS(const string ns) {
- boost::scoped_ptr<mongo::DBClientBase> connection( getDBConnection() );
- globalLoadGenOption.docsPerDB = connection->count( ns );
-}
-
-
-mongo::BSONArray generateInsertOps() {
-
- //create a document config object
- BSONObj args = BSONObjBuilder()
- .append( "blob", "MongoDB is an open source document-oriented database system." )
- .append( "md5seed", "newyork" )
- .append( "counterUp", 0 )
- .append( "counterDown", numeric_limits<long long>::max() ).obj();
-
- scoped_ptr<DocumentGenerator> docGen( DocumentGenerator::makeDocumentGenerator(args) );
- mongo::BSONArrayBuilder insertOps;
- for (int i = 0; i < globalLoadGenOption.numOps; ++i) {
-
- //insert into databases
- string insertNS = mongoutils::str::stream() << globalLoadGenOption.instanceSize << "DB" <<
- i % globalLoadGenOption.numdbs << "I.sampledata";
- BSONObj doc = docGen->createDocument();
- insertOps.append( BSON( "ns" << insertNS <<
- "op" << "insert" <<
- "doc" << doc <<
- "safe" << true ) );
- }
- return insertOps.arr();
-}
-
-
-mongo::BSONArray generateFindOneOps() {
-
- mongo::BSONArrayBuilder queryOps;
-
- // query a namespace and find the number of docs in that ns. All benchmark namespaces should have
- // the same number of docs.
- string queryNS = mongoutils::str::stream() << globalLoadGenOption.instanceSize
- << "DB0.sampledata";
- numDocsInNS( queryNS );
-
- // Now fill the queryOps array. The findOne query operations will be evenly distributed
- // across all databases. Thus it tries to find a random document from db1, then db2,
- // and so on and so forth.
- for (int i = 0; i < globalLoadGenOption.numOps; ++i) {
-
- queryNS = mongoutils::str::stream() << globalLoadGenOption.instanceSize
- << "DB"
- << i % globalLoadGenOption.numdbs
- << ".sampledata";
-
- // select a random document among all the documents
- unsigned long long centerQueryKey =
- ( randomBetweenRange(0, 100 ) * globalLoadGenOption.docsPerDB ) / 100;
-
- // cast to long long from unsigned long long as BSON didn't have the overloaded method
- mongo::BSONObj query =
- BSON( "counterUp" << static_cast<long long>( floor(centerQueryKey) ) );
-
- queryOps.append( BSON( "ns" << queryNS <<
- "op" << "findOne" <<
- "query" << query) );
- }
-
- return queryOps.arr();
-}
-
-
-mongo::BenchRunConfig *createBenchRunConfig() {
-
- BSONArray ops;
-
- if ( globalLoadGenOption.type == "findOne" )
- ops = generateFindOneOps();
- else if ( globalLoadGenOption.type == "insert" )
- ops = generateInsertOps();
-
- return mongo::BenchRunConfig::createFromBson(
- BSON( "ops" << ops <<
- "parallel" << globalLoadGenOption.parallelThreads <<
- "seconds" << globalLoadGenOption.durationSeconds <<
- "host"<< globalLoadGenOption.hostname ) );
-}
-
-/*
- * The stats object from benchRun has two sub-objects : findOneCounter and opcounters
- * This function creates a single map data structure to store all the info.
- */
-
-void collectAllStats( const BenchRunStats& stats, OpStatsMap& allStats ) {
-
- allStats.clear();
- allStats.insert( std::make_pair("findOne",
- OperationStats(stats.findOneCounter.getNumEvents(),
- stats.findOneCounter.getTotalTimeMicros(),
- mapFindWithDefault(stats.opcounters, "query", 0)
- )) );
- allStats.insert( std::make_pair("insert",
- OperationStats(stats.insertCounter.getNumEvents(),
- stats.insertCounter.getTotalTimeMicros(),
- mapFindWithDefault(stats.opcounters, "insert", 0)
- )) );
-
-}
-
-// add the result of this trial to the trials array
-BSONObj makeTrialDocument( const OpStatsMap& allStats ) {
-
- BSONObjBuilder outerBuilder;
- for (OpStatsMap::const_iterator it = allStats.begin(); it != allStats.end(); ++it) {
-
- unsigned long long numEvents = it->second.numEvents;
- unsigned long long totalTimeMicros = it->second.totalTimeMicros;
-
- BSONObjBuilder innerDocBuilder;
- innerDocBuilder.append("numEvents", static_cast<long long>(numEvents));
- innerDocBuilder.append("totalTimeMicros", static_cast<long long>(totalTimeMicros));
-
- if (numEvents)
- innerDocBuilder.append("latencyMicros", static_cast<double>(totalTimeMicros/numEvents));
-
- outerBuilder.append(it->first, innerDocBuilder.obj());
- }
- return outerBuilder.obj();
-}
-
-BSONObj buildInformation() {
- boost::scoped_ptr<mongo::DBClientBase> connection( getDBConnection() );
- BSONObj info;
- connection->simpleCommand("admin", &info, "buildinfo");
- return info;
-}
-
-BSONObj createResultDoc(const BSONArray& trialsArray) {
-
- return BSON( "name" << globalLoadGenOption.type <<
- "config" << BSON ( "hostname" << globalLoadGenOption.hostname <<
- "instanceSize" << globalLoadGenOption.instanceSize <<
- "durationSeconds" << globalLoadGenOption.durationSeconds <<
- "parallelThreads" << globalLoadGenOption.parallelThreads <<
- "numOps" << globalLoadGenOption.numOps <<
- "Date" << 10 <<
- "buildInfo" << buildInformation()
- ) <<
- "trials" << trialsArray );
-}
-
-void runTest() {
- stringstream oss;
- BSONArrayBuilder trialsBuilder;
-
- // drop any previous dbs with the same name
- for (int j=0; j < globalLoadGenOption.numdbs; ++j) {
- string insertTestDB = mongoutils::str::stream() << globalLoadGenOption.instanceSize <<
- "DB" << j <<"I" ;
- dropDB(insertTestDB);
- }
-
- for (int i = 0; i<globalLoadGenOption.trials; ++i) {
-
- BenchRunner runner( createBenchRunConfig() );
- runner.start();
- sleepmillis( 1000 * globalLoadGenOption.durationSeconds );
- runner.stop();
- BenchRunStats stats;
- runner.populateStats(&stats);
-
- // collate all the stats (and save it in a local allstats map
- std::map<std::string, OperationStats> allStats;
- collectAllStats(stats, allStats);
-
- trialsBuilder.append(makeTrialDocument(allStats));
-
- // print for now -- this is temporary and will be removed
- oss << allStats.find("insert")->second.totalTimeMicros / allStats.find("insert")->second.numEvents <<
- " " <<
- allStats.find("insert")->second.opcounter / globalLoadGenOption.durationSeconds <<
- " ";
-
- //clean up the newly created dbs for next trial
- for (int j=0; j < globalLoadGenOption.numdbs; ++j) {
- string insertTestDB = mongoutils::str::stream() << globalLoadGenOption.instanceSize <<
- "DB" << j <<"I" ;
- dropDB(insertTestDB);
- }
- }
- // Write the experiment document to the result NS. If the user did not pass a resultNS cmdline
- // parameter then we won't write the results to the database.
- // This is useful in cases where we just want to drive a constant load from a client and are
- // not really interested in the statistics from it and so don't really care to save the stats
- // to a db.
-
- string resultNS = globalLoadGenOption.resultNS;
- if( !resultNS.empty() ) {
- BSONObj resultDoc = createResultDoc(trialsBuilder.arr());
- writeToNS( resultNS, resultDoc );
- }
-
- // temp line -- will be removed
- cout << oss.str() << endl;
-}
-
-
-int parseCmdLineOptions(int argc, char **argv) {
-
- try {
-
- po::options_description general_options("General options");
-
- general_options.add_options()
- ("help", "produce help message")
- ("hostname,H", po::value<string>() , "ip address of the host where mongod is running" )
- ("type", po::value<string>() , "findOne/insert" )
- ("instanceSize,I", po::value<string>(), "DB type (small/medium/large/vlarge)" )
- ("numdbs", po::value<int>(), " number of databases in this instance" )
- ("trials", po::value<int>(), "number of trials")
- ("durationSeconds,D", po::value<double>(), "how long should each trial run")
- ("parallelThreads,P",po::value<int>(), "number of threads")
- ("numOps", po::value<int>(), "number of ops per thread")
- ("resultNS", po::value<string>(), "result NS where you would like to save the results."
- "If this parameter is empty results will not be written")
- ;
-
- po::variables_map params;
- po::store(po::parse_command_line(argc, argv, general_options), params);
- po::notify(params);
-
- // Parse the values if supplied by the user. No data sanity check is performed
- // here so meaningless values (for eg. passing --numdbs 0) can crash the program.
- // TODO: Perform data sanity check
-
- if(params.count("help")) {
- cout << general_options << "\n";
- return 1;
- }
- if (params.count("hostname")) {
- globalLoadGenOption.hostname = params["hostname"].as<string>();
- }
- if (params.count("type")) {
- globalLoadGenOption.type = params["type"].as<string>();
- }
- if (params.count("instanceSize")) {
- globalLoadGenOption.instanceSize = params["instanceSize"].as<string>();
- }
- if (params.count("numdbs")) {
- globalLoadGenOption.numdbs = params["numdbs"].as<int>();
- }
- if (params.count("trials")) {
- globalLoadGenOption.trials = params["trials"].as<int>();
- }
- if (params.count("durationSeconds")) {
- globalLoadGenOption.durationSeconds = params["durationSeconds"].as<double>();
- }
- if (params.count("parallelThreads")) {
- globalLoadGenOption.parallelThreads = params["parallelThreads"].as<int>();
- }
- if (params.count("numOps")) {
- globalLoadGenOption.numOps = params["numOps"].as<int>();
- }
- if (params.count("resultNS")) {
- globalLoadGenOption.resultNS = params["resultNS"].as<string>();
- }
- }
- catch(exception& e) {
- cerr << "error: " << e.what() << "\n";
- return 1;
- }
- return 0;
-}
-
-} // namespace
-
-
-int main(int argc, char **argv, char** envp) {
- mongo::runGlobalInitializersOrDie(argc, argv, envp);
- if( parseCmdLineOptions(argc, argv) )
- return 1;
-
- runTest();
- return 0;
-}
-