1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 2001,2008 Oracle. All rights reserved. 5 * 6 * $Id: bench_001.c,v 12.9 2008/01/08 20:58:23 bostic Exp $ 7 */ 8 9/* 10 * bench_001 - time bulk fetch interface. 11 * Without -R builds a btree acording to the arguments. 12 * With -R runs and times bulk fetches. If -d is specified 13 * during reads the DB_MULTIPLE interface is used 14 * otherwise the DB_MULTIPLE_KEY interface is used. 15 * 16 * ARGUMENTS: 17 * -c cachesize [1000 * pagesize] 18 * -d number of duplicates [none] 19 * -E don't use environment 20 * -I Just initialize the environment 21 * -i number of read iterations [1000000] 22 * -l length of data item [20] 23 * -n number of keys [1000000] 24 * -p pagesize [65536] 25 * -R perform read test. 26 * -T incorporate transactions. 27 * 28 * COMPILE: 29 * cc -I /usr/local/BerkeleyDB/include \ 30 * -o bench_001 -O2 bench_001.c /usr/local/BerkeleyDB/lib/libdb.so 31 */ 32#include <sys/types.h> 33#include <sys/time.h> 34 35#include <stdlib.h> 36#include <string.h> 37 38#ifdef _WIN32 39extern int getopt(int, char * const *, const char *); 40#else 41#include <unistd.h> 42#endif 43 44#include <db.h> 45 46#define DATABASE "bench_001.db" 47 48int compare_int(DB *, const DBT *, const DBT *); 49DB_ENV *db_init(char *, char *, u_int, int); 50int fill(DB_ENV *, DB *, int, u_int, int, int); 51int get(DB *, int, u_int, int, int, int, int *); 52int main(int, char *[]); 53void usage(void); 54 55const char 56 *progname = "bench_001"; /* Program name. */ 57/* 58 * db_init -- 59 * Initialize the environment. 60 */ 61DB_ENV * 62db_init(home, prefix, cachesize, txn) 63 char *home, *prefix; 64 u_int cachesize; 65 int txn; 66{ 67 DB_ENV *dbenv; 68 u_int32_t flags; 69 int ret; 70 71 if ((ret = db_env_create(&dbenv, 0)) != 0) { 72 dbenv->err(dbenv, ret, "db_env_create"); 73 return (NULL); 74 } 75 dbenv->set_errfile(dbenv, stderr); 76 dbenv->set_errpfx(dbenv, prefix); 77 (void)dbenv->set_cachesize(dbenv, 0, 78 cachesize == 0 ? 50 * 1024 * 1024 : (u_int32_t)cachesize, 0); 79 80 flags = DB_CREATE | DB_INIT_MPOOL; 81 if (txn) 82 flags |= DB_INIT_TXN | DB_INIT_LOCK; 83 if ((ret = dbenv->open(dbenv, home, flags, 0)) != 0) { 84 dbenv->err(dbenv, ret, "DB_ENV->open: %s", home); 85 (void)dbenv->close(dbenv, 0); 86 return (NULL); 87 } 88 return (dbenv); 89} 90 91/* 92 * get -- loop getting batches of records. 93 * 94 */ 95int 96get(dbp, txn, datalen, num, dups, iter, countp) 97 DB *dbp; 98 u_int datalen; 99 int txn, num, dups, iter, *countp; 100{ 101 DBC *dbcp; 102 DBT key, data; 103 DB_ENV *dbenv; 104 DB_TXN *txnp; 105 u_int32_t flags, len, klen; 106 int count, i, j, ret; 107 void *pointer, *dp, *kp; 108 109 dbenv = dbp->dbenv; 110 111 klen = 0; /* Lint. */ 112 klen = klen; 113 114 memset(&key, 0, sizeof(key)); 115 key.data = &j; 116 key.size = sizeof(j); 117 memset(&data, 0, sizeof(data)); 118 data.flags = DB_DBT_USERMEM; 119 data.data = malloc(datalen*1024*1024); 120 data.ulen = data.size = datalen*1024*1024; 121 122 count = 0; 123 flags = DB_SET; 124 if (!dups) 125 flags |= DB_MULTIPLE_KEY; 126 else 127 flags |= DB_MULTIPLE; 128 for (i = 0; i < iter; i++) { 129 txnp = NULL; 130 if (txn) 131 if ((ret = 132 dbenv->txn_begin(dbenv, NULL, &txnp, 0)) != 0) 133 goto err; 134 if ((ret = dbp->cursor(dbp, txnp, &dbcp, 0)) != 0) 135 goto err; 136 137 j = random() % num; 138 if ((ret = dbcp->get(dbcp, &key, &data, flags)) != 0) 139 goto err; 140 DB_MULTIPLE_INIT(pointer, &data); 141 if (dups) 142 while (pointer != NULL) { 143 DB_MULTIPLE_NEXT(pointer, &data, dp, len); 144 if (dp != NULL) 145 count++; 146 } 147 else 148 while (pointer != NULL) { 149 DB_MULTIPLE_KEY_NEXT(pointer, 150 &data, kp, klen, dp, len); 151 if (kp != NULL) 152 count++; 153 } 154 if ((ret = dbcp->close(dbcp)) != 0) 155 goto err; 156 if (txn) 157 if ((ret = txnp->commit(txnp, 0)) != 0) 158 goto err; 159 } 160 161 *countp = count; 162 return (0); 163 164err: dbp->err(dbp, ret, "get"); 165 return (ret); 166} 167 168/* 169 * fill - fill a db 170 * Since we open/created the db with transactions (potentially), 171 * we need to populate it with transactions. We'll bundle the puts 172 * 10 to a transaction. 173 */ 174#define PUTS_PER_TXN 10 175int 176fill(dbenv, dbp, txn, datalen, num, dups) 177 DB_ENV *dbenv; 178 DB *dbp; 179 u_int datalen; 180 int txn, num, dups; 181{ 182 DBT key, data; 183 DB_TXN *txnp; 184 struct data { 185 int id; 186 char str[1]; 187 } *data_val; 188 int count, i, ret; 189 190 /* 191 * Insert records into the database, where the key is the user 192 * input and the data is the user input in reverse order. 193 */ 194 txnp = NULL; 195 ret = 0; 196 count = 0; 197 memset(&key, 0, sizeof(DBT)); 198 memset(&data, 0, sizeof(DBT)); 199 key.data = &i; 200 key.size = sizeof(i); 201 data.data = data_val = malloc(datalen); 202 memcpy(data_val->str, "0123456789012345678901234567890123456789", 203 datalen - sizeof(data_val->id)); 204 data.size = datalen; 205 data.flags = DB_DBT_USERMEM; 206 207 for (i = 0; i < num; i++) { 208 if (txn != 0 && i % PUTS_PER_TXN == 0) { 209 if (txnp != NULL) { 210 ret = txnp->commit(txnp, 0); 211 txnp = NULL; 212 if (ret != 0) 213 goto err; 214 } 215 if ((ret = 216 dbenv->txn_begin(dbenv, NULL, &txnp, 0)) != 0) 217 goto err; 218 } 219 data_val->id = 0; 220 do { 221 switch (ret = dbp->put(dbp, txnp, &key, &data, 0)) { 222 case 0: 223 count++; 224 break; 225 default: 226 dbp->err(dbp, ret, "DB->put"); 227 goto err; 228 } 229 } while (++data_val->id < dups); 230 } 231 if (txnp != NULL) 232 ret = txnp->commit(txnp, 0); 233 234 printf("%d\n", count); 235 return (ret); 236 237err: if (txnp != NULL) 238 (void)txnp->abort(txnp); 239 return (ret); 240} 241 242int 243main(argc, argv) 244 int argc; 245 char *argv[]; 246{ 247 extern char *optarg; 248 extern int optind; 249 DB *dbp; 250 DB_ENV *dbenv; 251 DB_TXN *txnp; 252 struct timeval start_time, end_time; 253 double secs; 254 u_int cache, datalen, pagesize; 255 int ch, count, dups, env, init, iter, num; 256 int ret, rflag, txn; 257 258 txnp = NULL; 259 datalen = 20; 260 iter = num = 1000000; 261 env = 1; 262 dups = init = rflag = txn = 0; 263 264 pagesize = 65536; 265 cache = 1000 * pagesize; 266 267 while ((ch = getopt(argc, argv, "c:d:EIi:l:n:p:RT")) != EOF) 268 switch (ch) { 269 case 'c': 270 cache = (u_int)atoi(optarg); 271 break; 272 case 'd': 273 dups = atoi(optarg); 274 break; 275 case 'E': 276 env = 0; 277 break; 278 case 'I': 279 init = 1; 280 break; 281 case 'i': 282 iter = atoi(optarg); 283 break; 284 case 'l': 285 datalen = (u_int)atoi(optarg); 286 break; 287 case 'n': 288 num = atoi(optarg); 289 break; 290 case 'p': 291 pagesize = (u_int)atoi(optarg); 292 break; 293 case 'R': 294 rflag = 1; 295 break; 296 case 'T': 297 txn = 1; 298 break; 299 case '?': 300 default: 301 usage(); 302 } 303 argc -= optind; 304 argv += optind; 305 306 /* Remove the previous database. */ 307 if (!rflag) { 308 if (env) 309 (void)system("rm -rf BENCH_001; mkdir BENCH_001"); 310 else 311 (void)unlink(DATABASE); 312 } 313 314 dbenv = NULL; 315 if (env == 1 && 316 (dbenv = db_init("BENCH_001", "bench_001", cache, txn)) == NULL) 317 return (-1); 318 if (init) 319 exit(0); 320 /* Create and initialize database object, open the database. */ 321 if ((ret = db_create(&dbp, dbenv, 0)) != 0) { 322 fprintf(stderr, 323 "%s: db_create: %s\n", progname, db_strerror(ret)); 324 exit(EXIT_FAILURE); 325 } 326 dbp->set_errfile(dbp, stderr); 327 dbp->set_errpfx(dbp, progname); 328 if ((ret = dbp->set_bt_compare(dbp, compare_int)) != 0) { 329 dbp->err(dbp, ret, "set_bt_compare"); 330 goto err; 331 } 332 if ((ret = dbp->set_pagesize(dbp, pagesize)) != 0) { 333 dbp->err(dbp, ret, "set_pagesize"); 334 goto err; 335 } 336 if (dups && (ret = dbp->set_flags(dbp, DB_DUP)) != 0) { 337 dbp->err(dbp, ret, "set_flags"); 338 goto err; 339 } 340 341 if (env == 0 && (ret = dbp->set_cachesize(dbp, 0, cache, 0)) != 0) { 342 dbp->err(dbp, ret, "set_cachesize"); 343 goto err; 344 } 345 346 if ((ret = dbp->set_flags(dbp, DB_DUP)) != 0) { 347 dbp->err(dbp, ret, "set_flags"); 348 goto err; 349 } 350 351 if (txn != 0) 352 if ((ret = dbenv->txn_begin(dbenv, NULL, &txnp, 0)) != 0) 353 goto err; 354 355 if ((ret = dbp->open( 356 dbp, txnp, DATABASE, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) { 357 dbp->err(dbp, ret, "%s: open", DATABASE); 358 if (txnp != NULL) 359 (void)txnp->abort(txnp); 360 goto err; 361 } 362 363 if (txnp != NULL) 364 ret = txnp->commit(txnp, 0); 365 txnp = NULL; 366 if (ret != 0) 367 goto err; 368 369 if (rflag) { 370 /* If no environment, fill the cache. */ 371 if (!env && (ret = 372 get(dbp, txn, datalen, num, dups, iter, &count)) != 0) 373 goto err; 374 375 /* Time the get loop. */ 376 (void)gettimeofday(&start_time, NULL); 377 if ((ret = 378 get(dbp, txn, datalen, num, dups, iter, &count)) != 0) 379 goto err; 380 (void)gettimeofday(&end_time, NULL); 381 secs = 382 (((double)end_time.tv_sec * 1000000 + end_time.tv_usec) - 383 ((double)start_time.tv_sec * 1000000 + start_time.tv_usec)) 384 / 1000000; 385 printf("%d records read using %d batches in %.2f seconds: ", 386 count, iter, secs); 387 printf("%.0f records/second\n", (double)count / secs); 388 389 } else if ((ret = fill(dbenv, dbp, txn, datalen, num, dups)) != 0) 390 goto err; 391 392 /* Close everything down. */ 393 if ((ret = dbp->close(dbp, rflag ? DB_NOSYNC : 0)) != 0) { 394 fprintf(stderr, 395 "%s: DB->close: %s\n", progname, db_strerror(ret)); 396 return (1); 397 } 398 return (ret); 399 400err: (void)dbp->close(dbp, 0); 401 return (1); 402} 403 404int 405compare_int(dbp, a, b) 406 DB *dbp; 407 const DBT *a, *b; 408{ 409 int ai, bi; 410 411 dbp = dbp; /* Lint. */ 412 413 /* 414 * Returns: 415 * < 0 if a < b 416 * = 0 if a = b 417 * > 0 if a > b 418 */ 419 memcpy(&ai, a->data, sizeof(int)); 420 memcpy(&bi, b->data, sizeof(int)); 421 return (ai - bi); 422} 423 424void 425usage() 426{ 427 (void)fprintf(stderr, "usage: %s %s\n\t%s\n", 428 progname, "[-EIRT] [-c cachesize] [-d dups]", 429 "[-i iterations] [-l datalen] [-n keys] [-p pagesize]"); 430 exit(EXIT_FAILURE); 431} 432