ex_tpcb.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:19k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1997, 1998, 1999, 2000
  5.  * Sleepycat Software.  All rights reserved.
  6.  *
  7.  * $Id: ex_tpcb.c,v 11.21 2000/10/27 20:32:00 dda Exp $
  8.  */
  9. #include "db_config.h"
  10. #ifndef NO_SYSTEM_INCLUDES
  11. #include <sys/types.h>
  12. #if TIME_WITH_SYS_TIME
  13. #include <sys/time.h>
  14. #include <time.h>
  15. #else
  16. #if HAVE_SYS_TIME_H
  17. #include <sys/time.h>
  18. #else
  19. #include <time.h>
  20. #endif
  21. #endif
  22. #include <errno.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <unistd.h>
  26. #endif
  27. #ifdef DB_WIN32
  28. #include <sys/types.h>
  29. #include <sys/timeb.h>
  30. #endif
  31. #include <db.h>
  32. typedef enum { ACCOUNT, BRANCH, TELLER } FTYPE;
  33. DB_ENV  *db_init __P((char *, char *, int, int, int));
  34. int   hpopulate __P((DB *, int, int, int, int));
  35. int   populate __P((DB *, u_int32_t, u_int32_t, int, char *));
  36. u_int32_t random_id __P((FTYPE, int, int, int));
  37. u_int32_t random_int __P((u_int32_t, u_int32_t));
  38. int   tp_populate __P((DB_ENV *, int, int, int, int, int));
  39. int   tp_run __P((DB_ENV *, int, int, int, int, int));
  40. int   tp_txn __P((DB_ENV *, DB *, DB *, DB *, DB *, int, int, int, int));
  41. #ifdef HAVE_VXWORKS
  42. #define ERROR_RETURN ERROR
  43. #define HOME "/vxtmp/vxtmp/TESTDIR"
  44. #define VXSHM_KEY 13
  45. int   ex_tpcb_init __P(());
  46. int   ex_tpcb __P(());
  47. #else
  48. #define ERROR_RETURN 1
  49. void   invarg __P((char *, int, char *));
  50. int   main __P((int, char *[]));
  51. void   usage __P((char *));
  52. #endif
  53. /*
  54.  * This program implements a basic TPC/B driver program.  To create the
  55.  * TPC/B database, run with the -i (init) flag.  The number of records
  56.  * with which to populate the account, history, branch, and teller tables
  57.  * is specified by the a, s, b, and t flags respectively.  To run a TPC/B
  58.  * test, use the n flag to indicate a number of transactions to run (note
  59.  * that you can run many of these processes in parallel to simulate a
  60.  * multiuser test run).
  61.  */
  62. #define TELLERS_PER_BRANCH 10
  63. #define ACCOUNTS_PER_TELLER 10000
  64. #define HISTORY_PER_BRANCH 2592000
  65. /*
  66.  * The default configuration that adheres to TPCB scaling rules requires
  67.  * nearly 3 GB of space.  To avoid requiring that much space for testing,
  68.  * we set the parameters much lower.  If you want to run a valid 10 TPS
  69.  * configuration, define VALID_SCALING.
  70.  */
  71. #ifdef VALID_SCALING
  72. #define ACCOUNTS  1000000
  73. #define BRANCHES       10
  74. #define TELLERS      100
  75. #define HISTORY 25920000
  76. #endif
  77. #ifdef TINY
  78. #define ACCOUNTS     1000
  79. #define BRANCHES       10
  80. #define TELLERS      100
  81. #define HISTORY    10000
  82. #endif
  83. #ifdef VERY_TINY
  84. #define ACCOUNTS      500
  85. #define BRANCHES       10
  86. #define TELLERS       50
  87. #define HISTORY     5000
  88. #endif
  89. #if !defined(VALID_SCALING) && !defined(TINY) && !defined(VERY_TINY)
  90. #define ACCOUNTS   100000
  91. #define BRANCHES       10
  92. #define TELLERS      100
  93. #define HISTORY   259200
  94. #endif
  95. #define HISTORY_LEN     100
  96. #define RECLEN     100
  97. #define BEGID 1000000
  98. typedef struct _defrec {
  99. u_int32_t id;
  100. u_int32_t balance;
  101. u_int8_t pad[RECLEN - sizeof(u_int32_t) - sizeof(u_int32_t)];
  102. } defrec;
  103. typedef struct _histrec {
  104. u_int32_t aid;
  105. u_int32_t bid;
  106. u_int32_t tid;
  107. u_int32_t amount;
  108. u_int8_t pad[RECLEN - 4 * sizeof(u_int32_t)];
  109. } histrec;
  110. #ifdef HAVE_VXWORKS
  111. int
  112. ex_tpcb_init()
  113. {
  114. DB_ENV *dbenv;
  115. int accounts, branches, ret, seed, t_ret, tellers, history, verbose;
  116. char *home;
  117. char *progname = "ex_tpcb_init"; /* Program name. */
  118. verbose = 1;
  119. if ((dbenv = db_init(HOME, progname, 0, 1, 0)) == NULL)
  120. return (ERROR_RETURN);
  121. accounts = ACCOUNTS;
  122. branches = BRANCHES;
  123. tellers = TELLERS;
  124. history = HISTORY;
  125. if ((ret = tp_populate(dbenv, accounts, branches, history, tellers,
  126.     verbose)) != OK)
  127. fprintf(stderr, "%s: %sn", progname, db_strerror(ret));
  128. if ((t_ret = dbenv->close(dbenv, 0)) != 0) {
  129. fprintf(stderr, "%s: %sn", progname, db_strerror(ret));
  130. return (ERROR_RETURN);
  131. }
  132. return (ret == 0 ? t_ret : ret);
  133. }
  134. int
  135. ex_tpcb()
  136. {
  137. DB_ENV *dbenv;
  138. int accounts, branches, seed, tellers, history;
  139. int ch, mpool, ntxns, ret, t_ret, txn_no_sync, verbose;
  140. char *progname = "ex_tpcb"; /* Program name. */
  141. accounts = ACCOUNTS;
  142. branches = BRANCHES;
  143. tellers = TELLERS;
  144. history = HISTORY;
  145. txn_no_sync = 0;
  146. mpool = 0;
  147. ntxns = 20;
  148. verbose = 1;
  149. seed = (int)((u_int)getpid() | time(NULL));
  150. srand((u_int)seed);
  151. /* Initialize the database environment. */
  152. if ((dbenv = db_init(HOME, progname, mpool, 0,
  153.     txn_no_sync ? DB_TXN_NOSYNC : 0)) == NULL)
  154. return (ERROR_RETURN);
  155. if (verbose)
  156. printf("%ld Accounts, %ld Branches, %ld Tellers, %ld Historyn",
  157.     (long)accounts, (long)branches,
  158.     (long)tellers, (long)history);
  159. if ((ret = tp_run(dbenv, ntxns, accounts, branches, tellers, verbose))
  160.     != OK)
  161. fprintf(stderr, "tp_run failedn");
  162. if ((t_ret = dbenv->close(dbenv, 0)) != 0) {
  163. fprintf(stderr, "%s: %sn", progname, db_strerror(ret));
  164. return (ERROR_RETURN);
  165. }
  166. return (ret == 0 ? t_ret : ret);
  167. }
  168. #else
  169. int
  170. main(argc, argv)
  171. int argc;
  172. char *argv[];
  173. {
  174. extern char *optarg;
  175. extern int optind;
  176. DB_ENV *dbenv;
  177. int accounts, branches, seed, tellers, history;
  178. int ch, iflag, mpool, ntxns, ret, txn_no_sync, verbose;
  179. char *home, *progname;
  180. home = "TESTDIR";
  181. progname = "ex_tpcb";
  182. accounts = branches = history = tellers = 0;
  183. txn_no_sync = 0;
  184. mpool = ntxns = 0;
  185. verbose = 0;
  186. iflag = 0;
  187. seed = (int)((u_int)getpid() | time(NULL));
  188. while ((ch = getopt(argc, argv, "a:b:c:fh:in:S:s:t:v")) != EOF)
  189. switch (ch) {
  190. case 'a': /* Number of account records */
  191. if ((accounts = atoi(optarg)) <= 0)
  192. invarg(progname, ch, optarg);
  193. break;
  194. case 'b': /* Number of branch records */
  195. if ((branches = atoi(optarg)) <= 0)
  196. invarg(progname, ch, optarg);
  197. break;
  198. case 'c': /* Cachesize in bytes */
  199. if ((mpool = atoi(optarg)) <= 0)
  200. invarg(progname, ch, optarg);
  201. break;
  202. case 'f': /* Fast mode: no txn sync. */
  203. txn_no_sync = 1;
  204. break;
  205. case 'h': /* DB  home. */
  206. home = optarg;
  207. break;
  208. case 'i': /* Initialize the test. */
  209. iflag = 1;
  210. break;
  211. case 'n': /* Number of transactions */
  212. if ((ntxns = atoi(optarg)) <= 0)
  213. invarg(progname, ch, optarg);
  214. break;
  215. case 'S': /* Random number seed. */
  216. if ((seed = atoi(optarg)) <= 0)
  217. invarg(progname, ch, optarg);
  218. break;
  219. case 's': /* Number of history records */
  220. if ((history = atoi(optarg)) <= 0)
  221. invarg(progname, ch, optarg);
  222. break;
  223. case 't': /* Number of teller records */
  224. if ((tellers = atoi(optarg)) <= 0)
  225. invarg(progname, ch, optarg);
  226. break;
  227. case 'v': /* Verbose option. */
  228. verbose = 1;
  229. break;
  230. case '?':
  231. default:
  232. usage(progname);
  233. }
  234. argc -= optind;
  235. argv += optind;
  236. srand((u_int)seed);
  237. /* Initialize the database environment. */
  238. if ((dbenv = db_init(home,
  239.     progname, mpool, iflag, txn_no_sync ? DB_TXN_NOSYNC : 0)) == NULL)
  240. return (1);
  241. accounts = accounts == 0 ? ACCOUNTS : accounts;
  242. branches = branches == 0 ? BRANCHES : branches;
  243. tellers = tellers == 0 ? TELLERS : tellers;
  244. history = history == 0 ? HISTORY : history;
  245. if (verbose)
  246. printf("%ld Accounts, %ld Branches, %ld Tellers, %ld Historyn",
  247.     (long)accounts, (long)branches,
  248.     (long)tellers, (long)history);
  249. if (iflag) {
  250. if (ntxns != 0)
  251. usage(progname);
  252. tp_populate(dbenv,
  253.     accounts, branches, history, tellers, verbose);
  254. } else {
  255. if (ntxns == 0)
  256. usage(progname);
  257. tp_run(dbenv, ntxns, accounts, branches, tellers, verbose);
  258. }
  259. if ((ret = dbenv->close(dbenv, 0)) != 0) {
  260. fprintf(stderr, "%s: dbenv->close failed: %sn",
  261.     progname, db_strerror(ret));
  262. return (1);
  263. }
  264. return (0);
  265. }
  266. void
  267. invarg(progname, arg, str)
  268. char *progname;
  269. int arg;
  270. char *str;
  271. {
  272. (void)fprintf(stderr,
  273.     "%s: invalid argument for -%c: %sn", progname, arg, str);
  274. exit (1);
  275. }
  276. void
  277. usage(progname)
  278. char *progname;
  279. {
  280. char *a1, *a2;
  281. a1 = "[-fv] [-a accounts] [-b branches]n";
  282. a2 = "t[-c cache_size] [-h home] [-S seed] [-s history] [-t tellers]";
  283. (void)fprintf(stderr, "usage: %s -i %s %sn", progname, a1, a2);
  284. (void)fprintf(stderr,
  285.     "       %s -n transactions %s %sn", progname, a1, a2);
  286. exit(1);
  287. }
  288. #endif
  289. /*
  290.  * db_init --
  291.  * Initialize the environment.
  292.  */
  293. DB_ENV *
  294. db_init(home, prefix, cachesize, initializing, flags)
  295. char *home, *prefix;
  296. int cachesize, initializing, flags;
  297. {
  298. DB_ENV *dbenv;
  299. u_int32_t local_flags;
  300. int ret;
  301. if ((ret = db_env_create(&dbenv, 0)) != 0) {
  302. dbenv->err(dbenv, ret, "db_env_create");
  303. return (NULL);
  304. }
  305. dbenv->set_errfile(dbenv, stderr);
  306. dbenv->set_errpfx(dbenv, prefix);
  307. #ifdef HAVE_VXWORKS
  308. if ((ret = dbenv->set_shm_key(dbenv, VXSHM_KEY)) != 0) {
  309. dbenv->err(dbenv, ret, "set_shm_key");
  310. return (NULL);
  311. }
  312. #endif
  313. (void)dbenv->set_cachesize(dbenv, 0,
  314.     cachesize == 0 ? 4 * 1024 * 1024 : (u_int32_t)cachesize, 0);
  315. local_flags = flags | DB_CREATE | (initializing ? DB_INIT_MPOOL :
  316.     DB_INIT_TXN | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL);
  317. if ((ret = dbenv->open(dbenv, home, local_flags, 0)) != 0) {
  318. dbenv->err(dbenv, ret, "DBENV->open: %s", home);
  319. (void)dbenv->close(dbenv, 0);
  320. return (NULL);
  321. }
  322. return (dbenv);
  323. }
  324. /*
  325.  * Initialize the database to the specified number of accounts, branches,
  326.  * history records, and tellers.
  327.  */
  328. int
  329. tp_populate(env, accounts, branches, history, tellers, verbose)
  330. DB_ENV *env;
  331. int accounts, branches, history, tellers, verbose;
  332. {
  333. DB *dbp;
  334. char dbname[100];
  335. u_int32_t balance, idnum, oflags;
  336. u_int32_t end_anum, end_bnum, end_tnum;
  337. u_int32_t start_anum, start_bnum, start_tnum;
  338. int ret;
  339. idnum = BEGID;
  340. balance = 500000;
  341. #ifdef HAVE_VXWORKS
  342. oflags = DB_CREATE;
  343. #else
  344. oflags = DB_CREATE | DB_TRUNCATE;
  345. #endif
  346. if ((ret = db_create(&dbp, env, 0)) != 0) {
  347. env->err(env, ret, "db_create");
  348. return (ERROR_RETURN);
  349. }
  350. (void)dbp->set_h_nelem(dbp, (u_int32_t)accounts);
  351. snprintf(dbname, sizeof(dbname), "account");
  352. if ((ret = dbp->open(dbp, dbname, NULL,
  353.     DB_HASH, oflags, 0644)) != 0) {
  354. env->err(env, ret, "DB->open: account");
  355. return (ERROR_RETURN);
  356. }
  357. start_anum = idnum;
  358. populate(dbp, idnum, balance, accounts, "account");
  359. idnum += accounts;
  360. end_anum = idnum - 1;
  361. if ((ret = dbp->close(dbp, 0)) != 0) {
  362. env->err(env, ret, "DB->close: account");
  363. return (ERROR_RETURN);
  364. }
  365. if (verbose)
  366. printf("Populated accounts: %ld - %ldn",
  367.     (long)start_anum, (long)end_anum);
  368. /*
  369.  * Since the number of branches is very small, we want to use very
  370.  * small pages and only 1 key per page, i.e., key-locking instead
  371.  * of page locking.
  372.  */
  373. if ((ret = db_create(&dbp, env, 0)) != 0) {
  374. env->err(env, ret, "db_create");
  375. return (ERROR_RETURN);
  376. }
  377. (void)dbp->set_h_ffactor(dbp, 1);
  378. (void)dbp->set_h_nelem(dbp, (u_int32_t)branches);
  379. (void)dbp->set_pagesize(dbp, 512);
  380. snprintf(dbname, sizeof(dbname), "branch");
  381. if ((ret = dbp->open(dbp, dbname, NULL,
  382.     DB_HASH, oflags, 0644)) != 0) {
  383. env->err(env, ret, "DB->open: branch");
  384. return (ERROR_RETURN);
  385. }
  386. start_bnum = idnum;
  387. populate(dbp, idnum, balance, branches, "branch");
  388. idnum += branches;
  389. end_bnum = idnum - 1;
  390. if ((ret = dbp->close(dbp, 0)) != 0) {
  391. env->err(env, ret, "DB->close: branch");
  392. return (ERROR_RETURN);
  393. }
  394. if (verbose)
  395. printf("Populated branches: %ld - %ldn",
  396.     (long)start_bnum, (long)end_bnum);
  397. /*
  398.  * In the case of tellers, we also want small pages, but we'll let
  399.  * the fill factor dynamically adjust itself.
  400.  */
  401. if ((ret = db_create(&dbp, env, 0)) != 0) {
  402. env->err(env, ret, "db_create");
  403. return (ERROR_RETURN);
  404. }
  405. (void)dbp->set_h_ffactor(dbp, 0);
  406. (void)dbp->set_h_nelem(dbp, (u_int32_t)tellers);
  407. (void)dbp->set_pagesize(dbp, 512);
  408. snprintf(dbname, sizeof(dbname), "teller");
  409. if ((ret = dbp->open(dbp, dbname, NULL,
  410.     DB_HASH, oflags, 0644)) != 0) {
  411. env->err(env, ret, "DB->open: teller");
  412. return (ERROR_RETURN);
  413. }
  414. start_tnum = idnum;
  415. populate(dbp, idnum, balance, tellers, "teller");
  416. idnum += tellers;
  417. end_tnum = idnum - 1;
  418. if ((ret = dbp->close(dbp, 0)) != 0) {
  419. env->err(env, ret, "DB->close: teller");
  420. return (ERROR_RETURN);
  421. }
  422. if (verbose)
  423. printf("Populated tellers: %ld - %ldn",
  424.     (long)start_tnum, (long)end_tnum);
  425. if ((ret = db_create(&dbp, env, 0)) != 0) {
  426. env->err(env, ret, "db_create");
  427. return (ERROR_RETURN);
  428. }
  429. (void)dbp->set_re_len(dbp, HISTORY_LEN);
  430. snprintf(dbname, sizeof(dbname), "history");
  431. if ((ret = dbp->open(dbp, dbname, NULL,
  432.     DB_RECNO, oflags, 0644)) != 0) {
  433. env->err(env, ret, "DB->open: history");
  434. return (ERROR_RETURN);
  435. }
  436. hpopulate(dbp, history, accounts, branches, tellers);
  437. if ((ret = dbp->close(dbp, 0)) != 0) {
  438. env->err(env, ret, "DB->close: history");
  439. return (ERROR_RETURN);
  440. }
  441. return (0);
  442. }
  443. int
  444. populate(dbp, start_id, balance, nrecs, msg)
  445. DB *dbp;
  446. u_int32_t start_id, balance;
  447. int nrecs;
  448. char *msg;
  449. {
  450. DBT kdbt, ddbt;
  451. defrec drec;
  452. int i, ret;
  453. kdbt.flags = 0;
  454. kdbt.data = &drec.id;
  455. kdbt.size = sizeof(u_int32_t);
  456. ddbt.flags = 0;
  457. ddbt.data = &drec;
  458. ddbt.size = sizeof(drec);
  459. memset(&drec.pad[0], 1, sizeof(drec.pad));
  460. for (i = 0; i < nrecs; i++) {
  461. drec.id = start_id + (u_int32_t)i;
  462. drec.balance = balance;
  463. if ((ret =
  464.     (dbp->put)(dbp, NULL, &kdbt, &ddbt, DB_NOOVERWRITE)) != 0) {
  465. dbp->err(dbp,
  466.     ret, "Failure initializing %s filen", msg);
  467. return (ERROR_RETURN);
  468. }
  469. }
  470. return (0);
  471. }
  472. int
  473. hpopulate(dbp, history, accounts, branches, tellers)
  474. DB *dbp;
  475. int history, accounts, branches, tellers;
  476. {
  477. DBT kdbt, ddbt;
  478. histrec hrec;
  479. db_recno_t key;
  480. int i, ret;
  481. memset(&kdbt, 0, sizeof(kdbt));
  482. memset(&ddbt, 0, sizeof(ddbt));
  483. ddbt.data = &hrec;
  484. ddbt.size = sizeof(hrec);
  485. kdbt.data = &key;
  486. kdbt.size = sizeof(key);
  487. memset(&hrec.pad[0], 1, sizeof(hrec.pad));
  488. hrec.amount = 10;
  489. for (i = 1; i <= history; i++) {
  490. hrec.aid = random_id(ACCOUNT, accounts, branches, tellers);
  491. hrec.bid = random_id(BRANCH, accounts, branches, tellers);
  492. hrec.tid = random_id(TELLER, accounts, branches, tellers);
  493. if ((ret = dbp->put(dbp, NULL, &kdbt, &ddbt, DB_APPEND)) != 0) {
  494. dbp->err(dbp, ret, "dbp->put");
  495. return (ERROR_RETURN);
  496. }
  497. }
  498. return (0);
  499. }
  500. u_int32_t
  501. random_int(lo, hi)
  502. u_int32_t lo, hi;
  503. {
  504. u_int32_t ret;
  505. int t;
  506. #ifndef RAND_MAX
  507. #define RAND_MAX 0x7fffffff
  508. #endif
  509. t = rand();
  510. ret = (u_int32_t)(((double)t / ((double)(RAND_MAX) + 1)) *
  511.     (hi - lo + 1));
  512. ret += lo;
  513. return (ret);
  514. }
  515. u_int32_t
  516. random_id(type, accounts, branches, tellers)
  517. FTYPE type;
  518. int accounts, branches, tellers;
  519. {
  520. u_int32_t min, max, num;
  521. max = min = BEGID;
  522. num = accounts;
  523. switch(type) {
  524. case TELLER:
  525. min += branches;
  526. num = tellers;
  527. /* FALLTHROUGH */
  528. case BRANCH:
  529. if (type == BRANCH)
  530. num = branches;
  531. min += accounts;
  532. /* FALLTHROUGH */
  533. case ACCOUNT:
  534. max = min + num - 1;
  535. }
  536. return (random_int(min, max));
  537. }
  538. int
  539. tp_run(dbenv, n, accounts, branches, tellers, verbose)
  540. DB_ENV *dbenv;
  541. int n, accounts, branches, tellers, verbose;
  542. {
  543. DB *adb, *bdb, *hdb, *tdb;
  544. char dbname[100];
  545. double gtps, itps;
  546. int failed, ifailed, ret, txns;
  547. time_t starttime, curtime, lasttime;
  548. #ifndef DB_WIN32
  549. pid_t pid;
  550. pid = getpid();
  551. #else
  552. int pid;
  553. pid = 0;
  554. #endif
  555. /*
  556.  * Open the database files.
  557.  */
  558. if ((ret = db_create(&adb, dbenv, 0)) != 0) {
  559. dbenv->err(dbenv, ret, "db_create");
  560. return (ERROR_RETURN);
  561. }
  562. snprintf(dbname, sizeof(dbname), "account");
  563. if ((ret = adb->open(adb, dbname, NULL, DB_UNKNOWN, 0, 0)) != 0) {
  564. dbenv->err(dbenv, ret, "DB->open: account");
  565. return (ERROR_RETURN);
  566. }
  567. if ((ret = db_create(&bdb, dbenv, 0)) != 0) {
  568. dbenv->err(dbenv, ret, "db_create");
  569. return (ERROR_RETURN);
  570. }
  571. snprintf(dbname, sizeof(dbname), "branch");
  572. if ((ret = bdb->open(bdb, dbname, NULL, DB_UNKNOWN, 0, 0)) != 0) {
  573. dbenv->err(dbenv, ret, "DB->open: branch");
  574. return (ERROR_RETURN);
  575. }
  576. if ((ret = db_create(&tdb, dbenv, 0)) != 0) {
  577. dbenv->err(dbenv, ret, "db_create");
  578. return (ERROR_RETURN);
  579. }
  580. snprintf(dbname, sizeof(dbname), "teller");
  581. if ((ret = tdb->open(tdb, dbname, NULL, DB_UNKNOWN, 0, 0)) != 0) {
  582. dbenv->err(dbenv, ret, "DB->open: teller");
  583. return (ERROR_RETURN);
  584. }
  585. if ((ret = db_create(&hdb, dbenv, 0)) != 0) {
  586. dbenv->err(dbenv, ret, "db_create");
  587. return (ERROR_RETURN);
  588. }
  589. snprintf(dbname, sizeof(dbname), "history");
  590. if ((ret = hdb->open(hdb, dbname, NULL, DB_UNKNOWN, 0, 0)) != 0) {
  591. dbenv->err(dbenv, ret, "DB->open: history");
  592. return (ERROR_RETURN);
  593. }
  594. txns = failed = ifailed = 0;
  595. starttime = time(NULL);
  596. lasttime = starttime;
  597. while (n-- > 0) {
  598. txns++;
  599. ret = tp_txn(dbenv, adb, bdb, tdb, hdb,
  600.     accounts, branches, tellers, verbose);
  601. if (ret != 0) {
  602. failed++;
  603. ifailed++;
  604. }
  605. if (n % 5000 == 0) {
  606. curtime = time(NULL);
  607. gtps = (double)(txns - failed) / (curtime - starttime);
  608. itps = (double)(5000 - ifailed) / (curtime - lasttime);
  609. printf("[%d] %d txns %d failed ", (int)pid,
  610.     txns, failed);
  611. printf("%6.2f TPS (gross) %6.2f TPS (interval)n",
  612.    gtps, itps);
  613. lasttime = curtime;
  614. ifailed = 0;
  615. }
  616. }
  617. (void)adb->close(adb, 0);
  618. (void)bdb->close(bdb, 0);
  619. (void)tdb->close(tdb, 0);
  620. (void)hdb->close(hdb, 0);
  621. printf("%ld transactions begun %ld failedn", (long)txns, (long)failed);
  622. return (0);
  623. }
  624. /*
  625.  * XXX Figure out the appropriate way to pick out IDs.
  626.  */
  627. int
  628. tp_txn(dbenv, adb, bdb, tdb, hdb, accounts, branches, tellers, verbose)
  629. DB_ENV *dbenv;
  630. DB *adb, *bdb, *tdb, *hdb;
  631. int accounts, branches, tellers, verbose;
  632. {
  633. DBC *acurs, *bcurs, *tcurs;
  634. DBT d_dbt, d_histdbt, k_dbt, k_histdbt;
  635. DB_TXN *t;
  636. db_recno_t key;
  637. defrec rec;
  638. histrec hrec;
  639. int account, branch, teller;
  640. t = NULL;
  641. acurs = bcurs = tcurs = NULL;
  642. /*
  643.  * XXX We could move a lot of this into the driver to make this
  644.  * faster.
  645.  */
  646. account = random_id(ACCOUNT, accounts, branches, tellers);
  647. branch = random_id(BRANCH, accounts, branches, tellers);
  648. teller = random_id(TELLER, accounts, branches, tellers);
  649. memset(&d_histdbt, 0, sizeof(d_histdbt));
  650. memset(&k_histdbt, 0, sizeof(k_histdbt));
  651. k_histdbt.data = &key;
  652. k_histdbt.size = sizeof(key);
  653. memset(&k_dbt, 0, sizeof(k_dbt));
  654. k_dbt.size = sizeof(int);
  655. memset(&d_dbt, 0, sizeof(d_dbt));
  656. d_dbt.flags = DB_DBT_USERMEM;
  657. d_dbt.data = &rec;
  658. d_dbt.ulen = sizeof(rec);
  659. hrec.aid = account;
  660. hrec.bid = branch;
  661. hrec.tid = teller;
  662. hrec.amount = 10;
  663. /* Request 0 bytes since we're just positioning. */
  664. d_histdbt.flags = DB_DBT_PARTIAL;
  665. /* START TIMING */
  666. if (txn_begin(dbenv, NULL, &t, 0) != 0)
  667. goto err;
  668. if (adb->cursor(adb, t, &acurs, 0) != 0 ||
  669.     bdb->cursor(bdb, t, &bcurs, 0) != 0 ||
  670.     tdb->cursor(tdb, t, &tcurs, 0) != 0)
  671. goto err;
  672. /* Account record */
  673. k_dbt.data = &account;
  674. if (acurs->c_get(acurs, &k_dbt, &d_dbt, DB_SET) != 0)
  675. goto err;
  676. rec.balance += 10;
  677. if (acurs->c_put(acurs, &k_dbt, &d_dbt, DB_CURRENT) != 0)
  678. goto err;
  679. /* Branch record */
  680. k_dbt.data = &branch;
  681. if (bcurs->c_get(bcurs, &k_dbt, &d_dbt, DB_SET) != 0)
  682. goto err;
  683. rec.balance += 10;
  684. if (bcurs->c_put(bcurs, &k_dbt, &d_dbt, DB_CURRENT) != 0)
  685. goto err;
  686. /* Teller record */
  687. k_dbt.data = &teller;
  688. if (tcurs->c_get(tcurs, &k_dbt, &d_dbt, DB_SET) != 0)
  689. goto err;
  690. rec.balance += 10;
  691. if (tcurs->c_put(tcurs, &k_dbt, &d_dbt, DB_CURRENT) != 0)
  692. goto err;
  693. /* History record */
  694. d_histdbt.flags = 0;
  695. d_histdbt.data = &hrec;
  696. d_histdbt.ulen = sizeof(hrec);
  697. if (hdb->put(hdb, t, &k_histdbt, &d_histdbt, DB_APPEND) != 0)
  698. goto err;
  699. if (acurs->c_close(acurs) != 0 || bcurs->c_close(bcurs) != 0 ||
  700.     tcurs->c_close(tcurs) != 0)
  701. goto err;
  702. if (txn_commit(t, 0) != 0)
  703. goto err;
  704. /* END TIMING */
  705. return (0);
  706. err: if (acurs != NULL)
  707. (void)acurs->c_close(acurs);
  708. if (bcurs != NULL)
  709. (void)bcurs->c_close(bcurs);
  710. if (tcurs != NULL)
  711. (void)tcurs->c_close(tcurs);
  712. if (t != NULL)
  713. (void)txn_abort(t);
  714. if (verbose)
  715. printf("Transaction A=%ld B=%ld T=%ld failedn",
  716.     (long)account, (long)branch, (long)teller);
  717. return (-1);
  718. }