/* 07.11.2004 M. Spiekermann This is a simple test of the Berkeley-Db C++ API. It was programmed in order to test the performance of Berkeley-DB B-Trees. It was observed that the PrefetchingIterator implemented in Secondos SMI is much slower than the bulk retrieval, but it does call the same bulk-retrieval APIs as in this code. */ #include "DbVersion.h" #include #include #include #include #include #include #include #include "StopWatch.h" #include using namespace std; void check_bdb_error(const int rc, DbEnv& bdb) { if ( (rc == DB_SECONDARY_BAD) || (rc == EINVAL) || (rc == ENOMEM) ) { bdb.err(rc, "cursor.get()"); } } int main( int argc, char** argv ) { if ( argc == 1 ) { cout << endl; cout << "Usage: " << argv[0] << " -mode [NUM_INSERT | NUM_FIND | BUFFER]" << endl << "Operational modes are listed below: " << endl << " -1 : Create B-Tree with key integer and insert NUM_INSERT data" << " records of size 100 b" << endl << " -2 : Retrieve randomly NUM_FIND of NUM_INSERT integers." << endl << " -3 : Scan database with cursor." << endl << " -4 : Scan BTREE database using bulk retrieval with buffer " << "size BUFFER kb" << endl << " -5 : Create a DB_RECNO database with NUM_INSERT entries" << " of size 100 b" << endl << " -6 : Scan RECNO database using bulk retrieval with buffer" << " size BUFFER kb." << endl; cout << endl; exit(1); } int param1 = 0; int param2 = 0; const int mode = -1 * atoi(argv[1]); if ( (mode == 1) || (mode == 4) || (mode == 5) || (mode == 6) ) { if (!(argc == 3)) { cout << "Arguments not correct!" << endl; exit(2); } param1 = atoi(argv[2]); } if ( mode == 2 ) { if (!(argc == 4)) { cout << "Arguments not correct!" << endl; exit(2); } param1 = atoi(argv[2]); param2 = atoi(argv[3]); } const int pageSize = 4096; DbEnv bdb(DB_CXX_NO_EXCEPTIONS); const int CACHE_SIZE = 300 * pageSize; int SetCachesizeSuccess = bdb.set_cachesize( 0 ,CACHE_SIZE, 0 ); assert( !SetCachesizeSuccess ); //assert( !bdb.set_flags(DB_DIRECT_DB | DB_REGION_INIT, 1) ); int BDBopened = bdb.open( 0, DB_CREATE | DB_INIT_MPOOL, 0); assert( !BDBopened ); cout << "Environment opened. Cache size: " << CACHE_SIZE << " bytes." << endl; string HOME("bdb-performance-test"); string DATABASE("access-btree.db"); string DATABASE2("access-recno.db"); Db db1(&bdb, 0); Db db2(&bdb, 0); int DBsetPagesizeSuccess = db1.set_pagesize(4096); assert( !DBsetPagesizeSuccess ); u_int32_t openFlags; if ( mode==1 || mode==5 ) { openFlags = DB_CREATE; } else { openFlags = DB_RDONLY; } int DBopenSuccess = db1.open( 0, (DATABASE).c_str(), 0, DB_BTREE, openFlags, 0664); assert( !DBopenSuccess ); cout << "Database " << DATABASE << " opened." << endl; DBopenSuccess = db2.open( 0, (DATABASE2).c_str(), 0, DB_RECNO, openFlags, 0664); assert( !DBopenSuccess ); cout << "Database " << DATABASE << " opened." << endl; const int recSize = 100; char dummyRec[recSize]; StopWatch runTime; const int TEST_MAX = param1; if ( mode == 1 ) { cout << "Inserting " << TEST_MAX << " integer values into DB_BTREE ..." << endl; for ( int j=1 ; j < TEST_MAX; j++ ) { Dbt key( (void*) &j, sizeof(int) ); Dbt data( (void*) dummyRec, recSize ); int DBputSuccess = db1.put(0, &key, &data, 0); assert( !DBputSuccess ); } // end of for j ... } if ( mode == 5 ) { cout << "Inserting " << TEST_MAX << " records of size " << recSize <<" into DB_RECNO ..." << endl; for ( int j=1 ; j < TEST_MAX; j++ ) { Dbt key( (void*) &j, sizeof(int) ); Dbt data( (void*) dummyRec, recSize ); int DBputSuccess = db2.put(0, &key, &data, 0); assert( !DBputSuccess ); } // end of for j ... } if ( mode == 2 ) { const int READ_MAX = param2; cout << "Random access of " << READ_MAX << " items ..." << endl; for ( int j=1 ; j < READ_MAX; j++ ) { int keyval = (int)(TEST_MAX * 1.0 * rand() / (RAND_MAX + 1.0)) + 1; //cout << keyval << ", "; Dbt key( (void *) &(keyval), sizeof(int) ); Dbt data; int DBgetSuccess = db1.get(0, &key, &data, 0); assert( !DBgetSuccess ); } } if ( mode == 3 ) { Dbc* cursor = 0; int DBcursorSuccess = !db1.cursor(0, &cursor, 0); assert( !DBcursorSuccess ); Dbt key; Dbt data; int rc = 0; cout << "Scanning database " << DATABASE << "..." << endl; while ( (rc = cursor->get(&key, &data, DB_NEXT)) == 0 ) { } check_bdb_error(rc, bdb); cursor->close(); } Dbc* cursor = 0; int DBcursorSuccess = db1.cursor(0, &cursor, 0); assert( !DBcursorSuccess ); Dbt key; int rc = 0; Dbt retdata; Dbt buf; size_t cBufLength = 1; if ( mode==4 || mode==6 ) { cBufLength = param1 * 1024; cout << "Buffer for bulk retrieval set to " << cBufLength << " bytes." << endl; } char cBuf[cBufLength]; buf.set_data(cBuf); buf.set_ulen(cBufLength); buf.set_dlen(cBufLength); buf.set_doff(0); buf.set_flags(DB_DBT_USERMEM); /* if ( mode == 4 ) { DBcursorSuccess = db1.cursor(0, &cursor, 0); assert( !DBcursorSuccess ); cout << "Bulk retrieval of " << DATABASE << "..." << endl; for (;;) { //cerr << "Getting next bulk of data ..." << endl; rc = cursor->get(&key, &buf, DB_MULTIPLE_KEY | DB_NEXT); if ( rc != 0) { //cerr << "finished!" << endl; check_bdb_error(rc, bdb); break; } int ctr = 0; for ( DB_MULTIPLE_INIT( bufptr, &buf );; ) { DB_MULTIPLE_KEY_NEXT( bufptr, &buf, retkey, retklen, retdata, retdlen ); if (bufptr == 0) { //cerr << "Iterating buffer finished!" << endl; break; } //cout << ctr << " - key, data: " << *((int*)retkey) // << ", " << *((int*)retdata)<< endl; //ctr++; } } cursor->close(); } */ if ( mode == 6 ) { DBcursorSuccess = !db2.cursor(0, &cursor, 0); assert( DBcursorSuccess ); db_recno_t recno = 0; cout << "Bulk retrieval of " << DATABASE2 << "..." << endl; #if (DB_VERSION_REQUIRED(4,2)) for (;;) { //cerr << "Getting next bulk of data ..." << endl; rc = cursor->get(&key, &buf, DB_MULTIPLE_KEY | DB_NEXT); if ( rc != 0) { //cerr << "finished!" << endl; check_bdb_error(rc, bdb); break; } DbMultipleRecnoDataIterator it(buf); while ( it.next(recno, retdata) ) {}; } cursor->close(); #else cout << "Not supported below version 4.2!" << endl; #endif } bool t1 = db1.close(DB_NOSYNC); assert (!t1); t1 = db2.close(DB_NOSYNC); assert ( !t1); cout << "Time: " << runTime.diffTimes() << endl; int BDBclosed = bdb.close(0); assert( !BDBclosed ); }