diff options
author | Antonin Kral <a.kral@bobek.cz> | 2010-01-31 08:32:52 +0100 |
---|---|---|
committer | Antonin Kral <a.kral@bobek.cz> | 2010-01-31 08:32:52 +0100 |
commit | 4eefaf421bfeddf040d96a3dafb12e09673423d7 (patch) | |
tree | cb2e5ccc7f98158894f977ff131949da36673591 /dbtests/perf | |
download | mongodb-4eefaf421bfeddf040d96a3dafb12e09673423d7.tar.gz |
Imported Upstream version 1.3.1
Diffstat (limited to 'dbtests/perf')
-rw-r--r-- | dbtests/perf/perftest.cpp | 695 |
1 files changed, 695 insertions, 0 deletions
diff --git a/dbtests/perf/perftest.cpp b/dbtests/perf/perftest.cpp new file mode 100644 index 0000000..6fe9d6a --- /dev/null +++ b/dbtests/perf/perftest.cpp @@ -0,0 +1,695 @@ +// perftest.cpp : Run db performance tests. +// + +/** + * Copyright (C) 2009 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/>. + */ + +#include "stdafx.h" + +#include "../../client/dbclient.h" +#include "../../db/instance.h" +#include "../../db/query.h" +#include "../../db/queryoptimizer.h" +#include "../../util/file_allocator.h" + +#include "../framework.h" +#include <boost/date_time/posix_time/posix_time.hpp> + +namespace mongo { + extern string dbpath; +} // namespace mongo + + +using namespace mongo; +using namespace mongo::regression; + +DBClientBase *client_; + +// Each test runs with a separate db, so no test does any of the startup +// (ie allocation) work for another test. +template< class T > +string testDb( T *t = 0 ) { + string name = mongo::regression::demangleName( typeid( T ) ); + // Make filesystem safe. + for( string::iterator i = name.begin(); i != name.end(); ++i ) + if ( *i == ':' ) + *i = '_'; + return name; +} + +template< class T > +string testNs( T *t ) { + stringstream ss; + ss << testDb( t ) << ".perftest"; + return ss.str(); +} + +template <class T> +class Runner { +public: + void run() { + T test; + string name = testDb( &test ); + boost::posix_time::ptime start = boost::posix_time::microsec_clock::universal_time(); + test.run(); + boost::posix_time::ptime end = boost::posix_time::microsec_clock::universal_time(); + long long micro = ( end - start ).total_microseconds(); + cout << "{'" << name << "': " + << micro / 1000000 + << "." + << setw( 6 ) << setfill( '0' ) << micro % 1000000 + << "}" << endl; + } + ~Runner() { + theFileAllocator().waitUntilFinished(); + client_->dropDatabase( testDb< T >().c_str() ); + } +}; + +class RunnerSuite : public Suite { +public: + RunnerSuite( string name ) : Suite( name ){} +protected: + template< class T > + void add() { + Suite::add< Runner< T > >(); + } +}; + +namespace Insert { + class IdIndex { + public: + void run() { + string ns = testNs( this ); + for( int i = 0; i < 100000; ++i ) { + client_->insert( ns.c_str(), BSON( "_id" << i ) ); + } + } + }; + + class TwoIndex { + public: + TwoIndex() : ns_( testNs( this ) ) { + client_->ensureIndex( ns_, BSON( "_id" << 1 ), "my_id" ); + } + void run() { + for( int i = 0; i < 100000; ++i ) + client_->insert( ns_.c_str(), BSON( "_id" << i ) ); + } + string ns_; + }; + + class TenIndex { + public: + TenIndex() : ns_( testNs( this ) ) { + const char *names = "aaaaaaaaa"; + for( int i = 0; i < 9; ++i ) { + client_->resetIndexCache(); + client_->ensureIndex( ns_.c_str(), BSON( "_id" << 1 ), false, names + i ); + } + } + void run() { + for( int i = 0; i < 100000; ++i ) + client_->insert( ns_.c_str(), BSON( "_id" << i ) ); + } + string ns_; + }; + + class Capped { + public: + Capped() : ns_( testNs( this ) ) { + client_->createCollection( ns_.c_str(), 100000, true ); + } + void run() { + for( int i = 0; i < 100000; ++i ) + client_->insert( ns_.c_str(), BSON( "_id" << i ) ); + } + string ns_; + }; + + class OneIndexReverse { + public: + OneIndexReverse() : ns_( testNs( this ) ) { + client_->ensureIndex( ns_, BSON( "_id" << 1 ) ); + } + void run() { + for( int i = 0; i < 100000; ++i ) + client_->insert( ns_.c_str(), BSON( "_id" << ( 100000 - 1 - i ) ) ); + } + string ns_; + }; + + class OneIndexHighLow { + public: + OneIndexHighLow() : ns_( testNs( this ) ) { + client_->ensureIndex( ns_, BSON( "_id" << 1 ) ); + } + void run() { + for( int i = 0; i < 100000; ++i ) { + int j = 50000 + ( ( i % 2 == 0 ) ? 1 : -1 ) * ( i / 2 + 1 ); + client_->insert( ns_.c_str(), BSON( "_id" << j ) ); + } + } + string ns_; + }; + + class All : public RunnerSuite { + public: + All() : RunnerSuite( "insert" ){} + + void setupTests(){ + add< IdIndex >(); + add< TwoIndex >(); + add< TenIndex >(); + add< Capped >(); + add< OneIndexReverse >(); + add< OneIndexHighLow >(); + } + } all; +} // namespace Insert + +namespace Update { + class Smaller { + public: + Smaller() : ns_( testNs( this ) ) { + for( int i = 0; i < 100000; ++i ) + client_->insert( ns_.c_str(), BSON( "_id" << i << "b" << 2 ) ); + } + void run() { + for( int i = 0; i < 100000; ++i ) + client_->update( ns_.c_str(), QUERY( "_id" << i ), BSON( "_id" << i ) ); + } + string ns_; + }; + + class Bigger { + public: + Bigger() : ns_( testNs( this ) ) { + for( int i = 0; i < 100000; ++i ) + client_->insert( ns_.c_str(), BSON( "_id" << i ) ); + } + void run() { + for( int i = 0; i < 100000; ++i ) + client_->update( ns_.c_str(), QUERY( "_id" << i ), BSON( "_id" << i << "b" << 2 ) ); + } + string ns_; + }; + + class Inc { + public: + Inc() : ns_( testNs( this ) ) { + for( int i = 0; i < 10000; ++i ) + client_->insert( ns_.c_str(), BSON( "_id" << i << "i" << 0 ) ); + } + void run() { + for( int j = 0; j < 10; ++j ) + for( int i = 0; i < 10000; ++i ) + client_->update( ns_.c_str(), QUERY( "_id" << i ), BSON( "$inc" << BSON( "i" << 1 ) ) ); + } + string ns_; + }; + + class Set { + public: + Set() : ns_( testNs( this ) ) { + for( int i = 0; i < 10000; ++i ) + client_->insert( ns_.c_str(), BSON( "_id" << i << "i" << 0 ) ); + } + void run() { + for( int j = 1; j < 11; ++j ) + for( int i = 0; i < 10000; ++i ) + client_->update( ns_.c_str(), QUERY( "_id" << i ), BSON( "$set" << BSON( "i" << j ) ) ); + } + string ns_; + }; + + class SetGrow { + public: + SetGrow() : ns_( testNs( this ) ) { + for( int i = 0; i < 10000; ++i ) + client_->insert( ns_.c_str(), BSON( "_id" << i << "i" << "" ) ); + } + void run() { + for( int j = 9; j > -1; --j ) + for( int i = 0; i < 10000; ++i ) + client_->update( ns_.c_str(), QUERY( "_id" << i ), BSON( "$set" << BSON( "i" << "aaaaaaaaaa"[j] ) ) ); + } + string ns_; + }; + + class All : public RunnerSuite { + public: + All() : RunnerSuite( "update" ){} + void setupTests(){ + add< Smaller >(); + add< Bigger >(); + add< Inc >(); + add< Set >(); + add< SetGrow >(); + } + } all; +} // namespace Update + +namespace BSON { + + const char *sample = + "{\"one\":2, \"two\":5, \"three\": {}," + "\"four\": { \"five\": { \"six\" : 11 } }," + "\"seven\": [ \"a\", \"bb\", \"ccc\", 5 ]," + "\"eight\": Dbref( \"rrr\", \"01234567890123456789aaaa\" )," + "\"_id\": ObjectId( \"deadbeefdeadbeefdeadbeef\" )," + "\"nine\": { \"$binary\": \"abc=\", \"$type\": \"02\" }," + "\"ten\": Date( 44 ), \"eleven\": /foooooo/i }"; + + const char *shopwikiSample = + "{ '_id' : '289780-80f85380b5c1d4a0ad75d1217673a4a2' , 'site_id' : 289780 , 'title'" + ": 'Jubilee - Margaret Walker' , 'image_url' : 'http://www.heartlanddigsandfinds.c" + "om/store/graphics/Product_Graphics/Product_8679.jpg' , 'url' : 'http://www.heartla" + "nddigsandfinds.com/store/store_product_detail.cfm?Product_ID=8679&Category_ID=2&Su" + "b_Category_ID=910' , 'url_hash' : 3450626119933116345 , 'last_update' : null , '" + "features' : { '$imagePrefetchDate' : '2008Aug30 22:39' , '$image.color.rgb' : '5a7" + "574' , 'Price' : '$10.99' , 'Description' : 'Author--s 1st Novel. A Houghton Miffl" + "in Literary Fellowship Award novel by the esteemed poet and novelist who has demon" + "strated a lifelong commitment to the heritage of black culture. An acclaimed story" + "of Vyry, a negro slave during the 19th Century, facing the biggest challenge of h" + "er lifetime - that of gaining her freedom, fighting for all the things she had nev" + "er known before. The author, great-granddaughter of Vyry, reveals what the Civil W" + "ar in America meant to the Negroes. Slavery W' , '$priceHistory-1' : '2008Dec03 $1" + "0.99' , 'Brand' : 'Walker' , '$brands_in_title' : 'Walker' , '--path' : '//HTML[1]" + "/BODY[1]/TABLE[1]/TR[1]/TD[1]/P[1]/TABLE[1]/TR[1]/TD[1]/TABLE[1]/TR[2]/TD[2]/TABLE" + "[1]/TR[1]/TD[1]/P[1]/TABLE[1]/TR[1]' , '~location' : 'en_US' , '$crawled' : '2009J" + "an11 03:22' , '$priceHistory-2' : '2008Nov15 $10.99' , '$priceHistory-0' : '2008De" + "c24 $10.99'}}"; + + class Parse { + public: + void run() { + for( int i = 0; i < 10000; ++i ) + fromjson( sample ); + } + }; + + class ShopwikiParse { + public: + void run() { + for( int i = 0; i < 10000; ++i ) + fromjson( shopwikiSample ); + } + }; + + class Json { + public: + Json() : o_( fromjson( sample ) ) {} + void run() { + for( int i = 0; i < 10000; ++i ) + o_.jsonString(); + } + BSONObj o_; + }; + + class ShopwikiJson { + public: + ShopwikiJson() : o_( fromjson( shopwikiSample ) ) {} + void run() { + for( int i = 0; i < 10000; ++i ) + o_.jsonString(); + } + BSONObj o_; + }; + + class All : public RunnerSuite { + public: + All() : RunnerSuite( "bson" ){} + void setupTests(){ + add< Parse >(); + add< ShopwikiParse >(); + add< Json >(); + add< ShopwikiJson >(); + } + } all; + +} // namespace BSON + +namespace Index { + + class Int { + public: + Int() : ns_( testNs( this ) ) { + for( int i = 0; i < 100000; ++i ) + client_->insert( ns_.c_str(), BSON( "a" << i ) ); + } + void run() { + client_->ensureIndex( ns_, BSON( "a" << 1 ) ); + } + string ns_; + }; + + class ObjectId { + public: + ObjectId() : ns_( testNs( this ) ) { + OID id; + for( int i = 0; i < 100000; ++i ) { + id.init(); + client_->insert( ns_.c_str(), BSON( "a" << id ) ); + } + } + void run() { + client_->ensureIndex( ns_, BSON( "a" << 1 ) ); + } + string ns_; + }; + + class String { + public: + String() : ns_( testNs( this ) ) { + for( int i = 0; i < 100000; ++i ) { + stringstream ss; + ss << i; + client_->insert( ns_.c_str(), BSON( "a" << ss.str() ) ); + } + } + void run() { + client_->ensureIndex( ns_, BSON( "a" << 1 ) ); + } + string ns_; + }; + + class Object { + public: + Object() : ns_( testNs( this ) ) { + for( int i = 0; i < 100000; ++i ) { + client_->insert( ns_.c_str(), BSON( "a" << BSON( "a" << i ) ) ); + } + } + void run() { + client_->ensureIndex( ns_, BSON( "a" << 1 ) ); + } + string ns_; + }; + + class All : public RunnerSuite { + public: + All() : RunnerSuite( "index" ){} + void setupTests(){ + add< Int >(); + add< ObjectId >(); + add< String >(); + add< Object >(); + } + } all; + +} // namespace Index + +namespace QueryTests { + + class NoMatch { + public: + NoMatch() : ns_( testNs( this ) ) { + for( int i = 0; i < 100000; ++i ) + client_->insert( ns_.c_str(), BSON( "_id" << i ) ); + } + void run() { + client_->findOne( ns_.c_str(), QUERY( "_id" << 100000 ) ); + } + string ns_; + }; + + class NoMatchIndex { + public: + NoMatchIndex() : ns_( testNs( this ) ) { + for( int i = 0; i < 100000; ++i ) + client_->insert( ns_.c_str(), BSON( "_id" << i ) ); + } + void run() { + client_->findOne( ns_.c_str(), + QUERY( "a" << "b" ).hint( BSON( "_id" << 1 ) ) ); + } + string ns_; + }; + + class NoMatchLong { + public: + NoMatchLong() : ns_( testNs( this ) ) { + const char *names = "aaaaaaaaaa"; + for( int i = 0; i < 100000; ++i ) { + BSONObjBuilder b; + for( int j = 0; j < 10; ++j ) + b << ( names + j ) << i; + client_->insert( ns_.c_str(), b.obj() ); + } + } + void run() { + client_->findOne( ns_.c_str(), QUERY( "a" << 100000 ) ); + } + string ns_; + }; + + class SortOrdered { + public: + SortOrdered() : ns_( testNs( this ) ) { + for( int i = 0; i < 50000; ++i ) + client_->insert( ns_.c_str(), BSON( "_id" << i ) ); + } + void run() { + auto_ptr< DBClientCursor > c = + client_->query( ns_.c_str(), Query( BSONObj() ).sort( BSON( "_id" << 1 ) ) ); + int i = 0; + for( ; c->more(); c->nextSafe(), ++i ); + ASSERT_EQUALS( 50000, i ); + } + string ns_; + }; + + class SortReverse { + public: + SortReverse() : ns_( testNs( this ) ) { + for( int i = 0; i < 50000; ++i ) + client_->insert( ns_.c_str(), BSON( "_id" << ( 50000 - 1 - i ) ) ); + } + void run() { + auto_ptr< DBClientCursor > c = + client_->query( ns_.c_str(), Query( BSONObj() ).sort( BSON( "_id" << 1 ) ) ); + int i = 0; + for( ; c->more(); c->nextSafe(), ++i ); + ASSERT_EQUALS( 50000, i ); + } + string ns_; + }; + + class GetMore { + public: + GetMore() : ns_( testNs( this ) ) { + for( int i = 0; i < 100000; ++i ) + client_->insert( ns_.c_str(), BSON( "a" << i ) ); + c_ = client_->query( ns_.c_str(), Query() ); + } + void run() { + int i = 0; + for( ; c_->more(); c_->nextSafe(), ++i ); + ASSERT_EQUALS( 100000, i ); + } + string ns_; + auto_ptr< DBClientCursor > c_; + }; + + class GetMoreIndex { + public: + GetMoreIndex() : ns_( testNs( this ) ) { + for( int i = 0; i < 100000; ++i ) + client_->insert( ns_.c_str(), BSON( "a" << i ) ); + client_->ensureIndex( ns_, BSON( "a" << 1 ) ); + c_ = client_->query( ns_.c_str(), QUERY( "a" << GT << -1 ).hint( BSON( "a" << 1 ) ) ); + } + void run() { + int i = 0; + for( ; c_->more(); c_->nextSafe(), ++i ); + ASSERT_EQUALS( 100000, i ); + } + string ns_; + auto_ptr< DBClientCursor > c_; + }; + + class GetMoreKeyMatchHelps { + public: + GetMoreKeyMatchHelps() : ns_( testNs( this ) ) { + for( int i = 0; i < 1000000; ++i ) + client_->insert( ns_.c_str(), BSON( "a" << i << "b" << i % 10 << "c" << "d" ) ); + client_->ensureIndex( ns_, BSON( "a" << 1 << "b" << 1 ) ); + c_ = client_->query( ns_.c_str(), QUERY( "a" << GT << -1 << "b" << 0 ).hint( BSON( "a" << 1 << "b" << 1 ) ) ); + } + void run() { + int i = 0; + for( ; c_->more(); c_->nextSafe(), ++i ); + ASSERT_EQUALS( 100000, i ); + } + string ns_; + auto_ptr< DBClientCursor > c_; + }; + + class All : public RunnerSuite { + public: + All() : RunnerSuite( "query" ){} + void setupTests(){ + add< NoMatch >(); + add< NoMatchIndex >(); + add< NoMatchLong >(); + add< SortOrdered >(); + add< SortReverse >(); + add< GetMore >(); + add< GetMoreIndex >(); + add< GetMoreKeyMatchHelps >(); + } + } all; + +} // namespace QueryTests + +namespace Count { + + class Count { + public: + Count() : ns_( testNs( this ) ) { + BSONObj obj = BSON( "a" << 1 ); + for( int i = 0; i < 100000; ++i ) + client_->insert( ns_, obj ); + } + void run() { + ASSERT_EQUALS( 100000U, client_->count( ns_, BSON( "a" << 1 ) ) ); + } + string ns_; + }; + + class CountIndex { + public: + CountIndex() : ns_( testNs( this ) ) { + BSONObj obj = BSON( "a" << 1 ); + for( int i = 0; i < 100000; ++i ) + client_->insert( ns_, obj ); + client_->ensureIndex( ns_, obj ); + } + void run() { + // 'simple' match does not work for numbers + ASSERT_EQUALS( 100000U, client_->count( ns_, BSON( "a" << 1 ) ) ); + } + string ns_; + }; + + class CountSimpleIndex { + public: + CountSimpleIndex() : ns_( testNs( this ) ) { + BSONObj obj = BSON( "a" << "b" ); + for( int i = 0; i < 100000; ++i ) + client_->insert( ns_, obj ); + client_->ensureIndex( ns_, obj ); + } + void run() { + ASSERT_EQUALS( 100000U, client_->count( ns_, BSON( "a" << "b" ) ) ); + } + string ns_; + }; + + class All : public RunnerSuite { + public: + All() : RunnerSuite( "count" ){} + void setupTests(){ + add< Count >(); + add< CountIndex >(); + add< CountSimpleIndex >(); + } + } all; + +} // namespace Count + +namespace Plan { + + class Hint { + public: + Hint() : ns_( testNs( this ) ) { + const char *names = "aaaaaaaaa"; + for( int i = 0; i < 9; ++i ) { + client_->resetIndexCache(); + client_->ensureIndex( ns_.c_str(), BSON( ( names + i ) << 1 ), false, names + i ); + } + lk_.reset( new dblock ); + setClient( ns_.c_str() ); + hint_ = BSON( "hint" << BSON( "a" << 1 ) ); + hintElt_ = hint_.firstElement(); + } + void run() { + for( int i = 0; i < 10000; ++i ) + QueryPlanSet s( ns_.c_str(), BSONObj(), BSONObj(), &hintElt_ ); + } + string ns_; + auto_ptr< dblock > lk_; + BSONObj hint_; + BSONElement hintElt_; + }; + + class Sort { + public: + Sort() : ns_( testNs( this ) ) { + const char *names = "aaaaaaaaaa"; + for( int i = 0; i < 10; ++i ) { + client_->resetIndexCache(); + client_->ensureIndex( ns_.c_str(), BSON( ( names + i ) << 1 ), false, names + i ); + } + lk_.reset( new dblock ); + setClient( ns_.c_str() ); + } + void run() { + for( int i = 0; i < 10000; ++i ) + QueryPlanSet s( ns_.c_str(), BSONObj(), BSON( "a" << 1 ) ); + } + string ns_; + auto_ptr< dblock > lk_; + }; + + class Query { + public: + Query() : ns_( testNs( this ) ) { + const char *names = "aaaaaaaaaa"; + for( int i = 0; i < 10; ++i ) { + client_->resetIndexCache(); + client_->ensureIndex( ns_.c_str(), BSON( ( names + i ) << 1 ), false, names + i ); + } + lk_.reset( new dblock ); + setClient( ns_.c_str() ); + } + void run() { + for( int i = 0; i < 10000; ++i ) + QueryPlanSet s( ns_.c_str(), BSON( "a" << 1 ), BSONObj() ); + } + string ns_; + auto_ptr< dblock > lk_; + }; + + class All : public RunnerSuite { + public: + All() : RunnerSuite("plan" ){} + void setupTests(){ + add< Hint >(); + add< Sort >(); + add< Query >(); + } + } all; + +} // namespace Plan + +int main( int argc, char **argv ) { + logLevel = -1; + client_ = new DBDirectClient(); + + return Suite::run(argc, argv, "/data/db/perftest"); +} |