1
// perftest.cpp : Run db performance tests.
5
* Copyright (C) 2009 10gen Inc.
7
* This program is free software: you can redistribute it and/or modify
8
* it under the terms of the GNU Affero General Public License, version 3,
9
* as published by the Free Software Foundation.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU Affero General Public License for more details.
16
* You should have received a copy of the GNU Affero General Public License
17
* along with this program. If not, see <http://www.gnu.org/licenses/>.
22
#include "../../client/dbclient.h"
23
#include "../../db/instance.h"
24
#include "../../db/query.h"
25
#include "../../db/queryoptimizer.h"
26
#include "../../util/file_allocator.h"
28
#include "../framework.h"
29
#include <boost/date_time/posix_time/posix_time.hpp>
36
using namespace mongo;
37
using namespace mongo::regression;
39
DBClientBase *client_;
41
// Each test runs with a separate db, so no test does any of the startup
42
// (ie allocation) work for another test.
44
string testDb( T *t = 0 ) {
45
string name = mongo::regression::demangleName( typeid( T ) );
46
// Make filesystem safe.
47
for( string::iterator i = name.begin(); i != name.end(); ++i )
54
string testNs( T *t ) {
56
ss << testDb( t ) << ".perftest";
65
string name = testDb( &test );
66
boost::posix_time::ptime start = boost::posix_time::microsec_clock::universal_time();
68
boost::posix_time::ptime end = boost::posix_time::microsec_clock::universal_time();
69
long long micro = ( end - start ).total_microseconds();
70
cout << "{'" << name << "': "
73
<< setw( 6 ) << setfill( '0' ) << micro % 1000000
77
theFileAllocator().waitUntilFinished();
78
client_->dropDatabase( testDb< T >().c_str() );
82
class RunnerSuite : public Suite {
84
RunnerSuite( string name ) : Suite( name ){}
88
Suite::add< Runner< T > >();
96
string ns = testNs( this );
97
for( int i = 0; i < 100000; ++i ) {
98
client_->insert( ns.c_str(), BSON( "_id" << i ) );
105
TwoIndex() : ns_( testNs( this ) ) {
106
client_->ensureIndex( ns_, BSON( "_id" << 1 ), "my_id" );
109
for( int i = 0; i < 100000; ++i )
110
client_->insert( ns_.c_str(), BSON( "_id" << i ) );
117
TenIndex() : ns_( testNs( this ) ) {
118
const char *names = "aaaaaaaaa";
119
for( int i = 0; i < 9; ++i ) {
120
client_->resetIndexCache();
121
client_->ensureIndex( ns_.c_str(), BSON( "_id" << 1 ), false, names + i );
125
for( int i = 0; i < 100000; ++i )
126
client_->insert( ns_.c_str(), BSON( "_id" << i ) );
133
Capped() : ns_( testNs( this ) ) {
134
client_->createCollection( ns_.c_str(), 100000, true );
137
for( int i = 0; i < 100000; ++i )
138
client_->insert( ns_.c_str(), BSON( "_id" << i ) );
143
class OneIndexReverse {
145
OneIndexReverse() : ns_( testNs( this ) ) {
146
client_->ensureIndex( ns_, BSON( "_id" << 1 ) );
149
for( int i = 0; i < 100000; ++i )
150
client_->insert( ns_.c_str(), BSON( "_id" << ( 100000 - 1 - i ) ) );
155
class OneIndexHighLow {
157
OneIndexHighLow() : ns_( testNs( this ) ) {
158
client_->ensureIndex( ns_, BSON( "_id" << 1 ) );
161
for( int i = 0; i < 100000; ++i ) {
162
int j = 50000 + ( ( i % 2 == 0 ) ? 1 : -1 ) * ( i / 2 + 1 );
163
client_->insert( ns_.c_str(), BSON( "_id" << j ) );
169
class All : public RunnerSuite {
171
All() : RunnerSuite( "insert" ){}
178
add< OneIndexReverse >();
179
add< OneIndexHighLow >();
182
} // namespace Insert
187
Smaller() : ns_( testNs( this ) ) {
188
for( int i = 0; i < 100000; ++i )
189
client_->insert( ns_.c_str(), BSON( "_id" << i << "b" << 2 ) );
192
for( int i = 0; i < 100000; ++i )
193
client_->update( ns_.c_str(), QUERY( "_id" << i ), BSON( "_id" << i ) );
200
Bigger() : ns_( testNs( this ) ) {
201
for( int i = 0; i < 100000; ++i )
202
client_->insert( ns_.c_str(), BSON( "_id" << i ) );
205
for( int i = 0; i < 100000; ++i )
206
client_->update( ns_.c_str(), QUERY( "_id" << i ), BSON( "_id" << i << "b" << 2 ) );
213
Inc() : ns_( testNs( this ) ) {
214
for( int i = 0; i < 10000; ++i )
215
client_->insert( ns_.c_str(), BSON( "_id" << i << "i" << 0 ) );
218
for( int j = 0; j < 10; ++j )
219
for( int i = 0; i < 10000; ++i )
220
client_->update( ns_.c_str(), QUERY( "_id" << i ), BSON( "$inc" << BSON( "i" << 1 ) ) );
227
Set() : ns_( testNs( this ) ) {
228
for( int i = 0; i < 10000; ++i )
229
client_->insert( ns_.c_str(), BSON( "_id" << i << "i" << 0 ) );
232
for( int j = 1; j < 11; ++j )
233
for( int i = 0; i < 10000; ++i )
234
client_->update( ns_.c_str(), QUERY( "_id" << i ), BSON( "$set" << BSON( "i" << j ) ) );
241
SetGrow() : ns_( testNs( this ) ) {
242
for( int i = 0; i < 10000; ++i )
243
client_->insert( ns_.c_str(), BSON( "_id" << i << "i" << "" ) );
246
for( int j = 9; j > -1; --j )
247
for( int i = 0; i < 10000; ++i )
248
client_->update( ns_.c_str(), QUERY( "_id" << i ), BSON( "$set" << BSON( "i" << "aaaaaaaaaa"[j] ) ) );
253
class All : public RunnerSuite {
255
All() : RunnerSuite( "update" ){}
264
} // namespace Update
269
"{\"one\":2, \"two\":5, \"three\": {},"
270
"\"four\": { \"five\": { \"six\" : 11 } },"
271
"\"seven\": [ \"a\", \"bb\", \"ccc\", 5 ],"
272
"\"eight\": Dbref( \"rrr\", \"01234567890123456789aaaa\" ),"
273
"\"_id\": ObjectId( \"deadbeefdeadbeefdeadbeef\" ),"
274
"\"nine\": { \"$binary\": \"abc=\", \"$type\": \"02\" },"
275
"\"ten\": Date( 44 ), \"eleven\": /foooooo/i }";
277
const char *shopwikiSample =
278
"{ '_id' : '289780-80f85380b5c1d4a0ad75d1217673a4a2' , 'site_id' : 289780 , 'title'"
279
": 'Jubilee - Margaret Walker' , 'image_url' : 'http://www.heartlanddigsandfinds.c"
280
"om/store/graphics/Product_Graphics/Product_8679.jpg' , 'url' : 'http://www.heartla"
281
"nddigsandfinds.com/store/store_product_detail.cfm?Product_ID=8679&Category_ID=2&Su"
282
"b_Category_ID=910' , 'url_hash' : 3450626119933116345 , 'last_update' : null , '"
283
"features' : { '$imagePrefetchDate' : '2008Aug30 22:39' , '$image.color.rgb' : '5a7"
284
"574' , 'Price' : '$10.99' , 'Description' : 'Author--s 1st Novel. A Houghton Miffl"
285
"in Literary Fellowship Award novel by the esteemed poet and novelist who has demon"
286
"strated a lifelong commitment to the heritage of black culture. An acclaimed story"
287
"of Vyry, a negro slave during the 19th Century, facing the biggest challenge of h"
288
"er lifetime - that of gaining her freedom, fighting for all the things she had nev"
289
"er known before. The author, great-granddaughter of Vyry, reveals what the Civil W"
290
"ar in America meant to the Negroes. Slavery W' , '$priceHistory-1' : '2008Dec03 $1"
291
"0.99' , 'Brand' : 'Walker' , '$brands_in_title' : 'Walker' , '--path' : '//HTML[1]"
292
"/BODY[1]/TABLE[1]/TR[1]/TD[1]/P[1]/TABLE[1]/TR[1]/TD[1]/TABLE[1]/TR[2]/TD[2]/TABLE"
293
"[1]/TR[1]/TD[1]/P[1]/TABLE[1]/TR[1]' , '~location' : 'en_US' , '$crawled' : '2009J"
294
"an11 03:22' , '$priceHistory-2' : '2008Nov15 $10.99' , '$priceHistory-0' : '2008De"
300
for( int i = 0; i < 10000; ++i )
305
class ShopwikiParse {
308
for( int i = 0; i < 10000; ++i )
309
fromjson( shopwikiSample );
315
Json() : o_( fromjson( sample ) ) {}
317
for( int i = 0; i < 10000; ++i )
325
ShopwikiJson() : o_( fromjson( shopwikiSample ) ) {}
327
for( int i = 0; i < 10000; ++i )
333
class All : public RunnerSuite {
335
All() : RunnerSuite( "bson" ){}
338
add< ShopwikiParse >();
340
add< ShopwikiJson >();
350
Int() : ns_( testNs( this ) ) {
351
for( int i = 0; i < 100000; ++i )
352
client_->insert( ns_.c_str(), BSON( "a" << i ) );
355
client_->ensureIndex( ns_, BSON( "a" << 1 ) );
362
ObjectId() : ns_( testNs( this ) ) {
364
for( int i = 0; i < 100000; ++i ) {
366
client_->insert( ns_.c_str(), BSON( "a" << id ) );
370
client_->ensureIndex( ns_, BSON( "a" << 1 ) );
377
String() : ns_( testNs( this ) ) {
378
for( int i = 0; i < 100000; ++i ) {
381
client_->insert( ns_.c_str(), BSON( "a" << ss.str() ) );
385
client_->ensureIndex( ns_, BSON( "a" << 1 ) );
392
Object() : ns_( testNs( this ) ) {
393
for( int i = 0; i < 100000; ++i ) {
394
client_->insert( ns_.c_str(), BSON( "a" << BSON( "a" << i ) ) );
398
client_->ensureIndex( ns_, BSON( "a" << 1 ) );
403
class All : public RunnerSuite {
405
All() : RunnerSuite( "index" ){}
416
namespace QueryTests {
420
NoMatch() : ns_( testNs( this ) ) {
421
for( int i = 0; i < 100000; ++i )
422
client_->insert( ns_.c_str(), BSON( "_id" << i ) );
425
client_->findOne( ns_.c_str(), QUERY( "_id" << 100000 ) );
432
NoMatchIndex() : ns_( testNs( this ) ) {
433
for( int i = 0; i < 100000; ++i )
434
client_->insert( ns_.c_str(), BSON( "_id" << i ) );
437
client_->findOne( ns_.c_str(),
438
QUERY( "a" << "b" ).hint( BSON( "_id" << 1 ) ) );
445
NoMatchLong() : ns_( testNs( this ) ) {
446
const char *names = "aaaaaaaaaa";
447
for( int i = 0; i < 100000; ++i ) {
449
for( int j = 0; j < 10; ++j )
450
b << ( names + j ) << i;
451
client_->insert( ns_.c_str(), b.obj() );
455
client_->findOne( ns_.c_str(), QUERY( "a" << 100000 ) );
462
SortOrdered() : ns_( testNs( this ) ) {
463
for( int i = 0; i < 50000; ++i )
464
client_->insert( ns_.c_str(), BSON( "_id" << i ) );
467
auto_ptr< DBClientCursor > c =
468
client_->query( ns_.c_str(), Query( BSONObj() ).sort( BSON( "_id" << 1 ) ) );
470
for( ; c->more(); c->nextSafe(), ++i );
471
ASSERT_EQUALS( 50000, i );
478
SortReverse() : ns_( testNs( this ) ) {
479
for( int i = 0; i < 50000; ++i )
480
client_->insert( ns_.c_str(), BSON( "_id" << ( 50000 - 1 - i ) ) );
483
auto_ptr< DBClientCursor > c =
484
client_->query( ns_.c_str(), Query( BSONObj() ).sort( BSON( "_id" << 1 ) ) );
486
for( ; c->more(); c->nextSafe(), ++i );
487
ASSERT_EQUALS( 50000, i );
494
GetMore() : ns_( testNs( this ) ) {
495
for( int i = 0; i < 100000; ++i )
496
client_->insert( ns_.c_str(), BSON( "a" << i ) );
497
c_ = client_->query( ns_.c_str(), Query() );
501
for( ; c_->more(); c_->nextSafe(), ++i );
502
ASSERT_EQUALS( 100000, i );
505
auto_ptr< DBClientCursor > c_;
510
GetMoreIndex() : ns_( testNs( this ) ) {
511
for( int i = 0; i < 100000; ++i )
512
client_->insert( ns_.c_str(), BSON( "a" << i ) );
513
client_->ensureIndex( ns_, BSON( "a" << 1 ) );
514
c_ = client_->query( ns_.c_str(), QUERY( "a" << GT << -1 ).hint( BSON( "a" << 1 ) ) );
518
for( ; c_->more(); c_->nextSafe(), ++i );
519
ASSERT_EQUALS( 100000, i );
522
auto_ptr< DBClientCursor > c_;
525
class GetMoreKeyMatchHelps {
527
GetMoreKeyMatchHelps() : ns_( testNs( this ) ) {
528
for( int i = 0; i < 1000000; ++i )
529
client_->insert( ns_.c_str(), BSON( "a" << i << "b" << i % 10 << "c" << "d" ) );
530
client_->ensureIndex( ns_, BSON( "a" << 1 << "b" << 1 ) );
531
c_ = client_->query( ns_.c_str(), QUERY( "a" << GT << -1 << "b" << 0 ).hint( BSON( "a" << 1 << "b" << 1 ) ) );
535
for( ; c_->more(); c_->nextSafe(), ++i );
536
ASSERT_EQUALS( 100000, i );
539
auto_ptr< DBClientCursor > c_;
542
class All : public RunnerSuite {
544
All() : RunnerSuite( "query" ){}
547
add< NoMatchIndex >();
548
add< NoMatchLong >();
549
add< SortOrdered >();
550
add< SortReverse >();
552
add< GetMoreIndex >();
553
add< GetMoreKeyMatchHelps >();
557
} // namespace QueryTests
563
Count() : ns_( testNs( this ) ) {
564
BSONObj obj = BSON( "a" << 1 );
565
for( int i = 0; i < 100000; ++i )
566
client_->insert( ns_, obj );
569
ASSERT_EQUALS( 100000U, client_->count( ns_, BSON( "a" << 1 ) ) );
576
CountIndex() : ns_( testNs( this ) ) {
577
BSONObj obj = BSON( "a" << 1 );
578
for( int i = 0; i < 100000; ++i )
579
client_->insert( ns_, obj );
580
client_->ensureIndex( ns_, obj );
583
// 'simple' match does not work for numbers
584
ASSERT_EQUALS( 100000U, client_->count( ns_, BSON( "a" << 1 ) ) );
589
class CountSimpleIndex {
591
CountSimpleIndex() : ns_( testNs( this ) ) {
592
BSONObj obj = BSON( "a" << "b" );
593
for( int i = 0; i < 100000; ++i )
594
client_->insert( ns_, obj );
595
client_->ensureIndex( ns_, obj );
598
ASSERT_EQUALS( 100000U, client_->count( ns_, BSON( "a" << "b" ) ) );
603
class All : public RunnerSuite {
605
All() : RunnerSuite( "count" ){}
609
add< CountSimpleIndex >();
619
Hint() : ns_( testNs( this ) ) {
620
const char *names = "aaaaaaaaa";
621
for( int i = 0; i < 9; ++i ) {
622
client_->resetIndexCache();
623
client_->ensureIndex( ns_.c_str(), BSON( ( names + i ) << 1 ), false, names + i );
625
lk_.reset( new dblock );
626
setClient( ns_.c_str() );
627
hint_ = BSON( "hint" << BSON( "a" << 1 ) );
628
hintElt_ = hint_.firstElement();
631
for( int i = 0; i < 10000; ++i )
632
QueryPlanSet s( ns_.c_str(), BSONObj(), BSONObj(), &hintElt_ );
635
auto_ptr< dblock > lk_;
637
BSONElement hintElt_;
642
Sort() : ns_( testNs( this ) ) {
643
const char *names = "aaaaaaaaaa";
644
for( int i = 0; i < 10; ++i ) {
645
client_->resetIndexCache();
646
client_->ensureIndex( ns_.c_str(), BSON( ( names + i ) << 1 ), false, names + i );
648
lk_.reset( new dblock );
649
setClient( ns_.c_str() );
652
for( int i = 0; i < 10000; ++i )
653
QueryPlanSet s( ns_.c_str(), BSONObj(), BSON( "a" << 1 ) );
656
auto_ptr< dblock > lk_;
661
Query() : ns_( testNs( this ) ) {
662
const char *names = "aaaaaaaaaa";
663
for( int i = 0; i < 10; ++i ) {
664
client_->resetIndexCache();
665
client_->ensureIndex( ns_.c_str(), BSON( ( names + i ) << 1 ), false, names + i );
667
lk_.reset( new dblock );
668
setClient( ns_.c_str() );
671
for( int i = 0; i < 10000; ++i )
672
QueryPlanSet s( ns_.c_str(), BSON( "a" << 1 ), BSONObj() );
675
auto_ptr< dblock > lk_;
678
class All : public RunnerSuite {
680
All() : RunnerSuite("plan" ){}
690
int main( int argc, char **argv ) {
692
client_ = new DBDirectClient();
694
return Suite::run(argc, argv, "/data/db/perftest");