Main Page | Class Hierarchy | Data Structures | Directories | File List | Data Fields | Related Pages

ex_tpcb.c

00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 1997-2005
00005  *      Sleepycat Software.  All rights reserved.
00006  *
00007  * $Id: ex_tpcb.c,v 12.2 2005/09/22 03:53:45 mjc Exp $
00008  */
00009 
00010 #include <sys/types.h>
00011 
00012 #include <errno.h>
00013 #include <stdlib.h>
00014 #include <string.h>
00015 #include <time.h>
00016 
00017 #ifdef _WIN32
00018 extern int getopt(int, char * const *, const char *);
00019 #else
00020 #include <unistd.h>
00021 #endif
00022 
00023 #include <db.h>
00024 
00025 typedef enum { ACCOUNT, BRANCH, TELLER } FTYPE;
00026 
00027 DB_ENV   *db_init __P((const char *, const char *, int, u_int32_t));
00028 int       hpopulate __P((DB *, int, int, int, int));
00029 int       populate __P((DB *, u_int32_t, u_int32_t, int, const char *));
00030 u_int32_t random_id __P((FTYPE, int, int, int));
00031 u_int32_t random_int __P((u_int32_t, u_int32_t));
00032 int       tp_populate __P((DB_ENV *, int, int, int, int, int));
00033 int       tp_run __P((DB_ENV *, int, int, int, int, int));
00034 int       tp_txn __P((DB_ENV *, DB *, DB *, DB *, DB *, int, int, int, int));
00035 
00036 int       invarg __P((const char *, int, const char *));
00037 int       main __P((int, char *[]));
00038 int       usage __P((const char *));
00039 
00040 /*
00041  * This program implements a basic TPC/B driver program.  To create the
00042  * TPC/B database, run with the -i (init) flag.  The number of records
00043  * with which to populate the account, history, branch, and teller tables
00044  * is specified by the a, s, b, and t flags respectively.  To run a TPC/B
00045  * test, use the n flag to indicate a number of transactions to run (note
00046  * that you can run many of these processes in parallel to simulate a
00047  * multiuser test run).
00048  */
00049 #define TELLERS_PER_BRANCH      10
00050 #define ACCOUNTS_PER_TELLER     10000
00051 #define HISTORY_PER_BRANCH      2592000
00052 
00053 /*
00054  * The default configuration that adheres to TPCB scaling rules requires
00055  * nearly 3 GB of space.  To avoid requiring that much space for testing,
00056  * we set the parameters much lower.  If you want to run a valid 10 TPS
00057  * configuration, define VALID_SCALING.
00058  */
00059 #ifdef  VALID_SCALING
00060 #define ACCOUNTS         1000000
00061 #define BRANCHES              10
00062 #define TELLERS              100
00063 #define HISTORY         25920000
00064 #endif
00065 
00066 #ifdef  TINY
00067 #define ACCOUNTS            1000
00068 #define BRANCHES              10
00069 #define TELLERS              100
00070 #define HISTORY            10000
00071 #endif
00072 
00073 #ifdef  VERY_TINY
00074 #define ACCOUNTS             500
00075 #define BRANCHES              10
00076 #define TELLERS               50
00077 #define HISTORY             5000
00078 #endif
00079 
00080 #if !defined(VALID_SCALING) && !defined(TINY) && !defined(VERY_TINY)
00081 #define ACCOUNTS          100000
00082 #define BRANCHES              10
00083 #define TELLERS              100
00084 #define HISTORY           259200
00085 #endif
00086 
00087 #define HISTORY_LEN         100
00088 #define RECLEN              100
00089 #define BEGID           1000000
00090 
00091 typedef struct _defrec {
00092         u_int32_t       id;
00093         u_int32_t       balance;
00094         u_int8_t        pad[RECLEN - sizeof(u_int32_t) - sizeof(u_int32_t)];
00095 } defrec;
00096 
00097 typedef struct _histrec {
00098         u_int32_t       aid;
00099         u_int32_t       bid;
00100         u_int32_t       tid;
00101         u_int32_t       amount;
00102         u_int8_t        pad[RECLEN - 4 * sizeof(u_int32_t)];
00103 } histrec;
00104 
00105 char *progname = "ex_tpcb";                     /* Program name. */
00106 
00107 int
00108 main(argc, argv)
00109         int argc;
00110         char *argv[];
00111 {
00112         extern char *optarg;
00113         extern int optind;
00114         DB_ENV *dbenv;
00115         int accounts, branches, seed, tellers, history;
00116         int ch, iflag, mpool, ntxns, ret, txn_no_sync, verbose;
00117         const char *home;
00118 
00119         home = "TESTDIR";
00120         accounts = branches = history = tellers = 0;
00121         iflag = mpool = ntxns = txn_no_sync = verbose = 0;
00122         seed = (int)time(NULL);
00123 
00124         while ((ch = getopt(argc, argv, "a:b:c:fh:in:S:s:t:v")) != EOF)
00125                 switch (ch) {
00126                 case 'a':                       /* Number of account records */
00127                         if ((accounts = atoi(optarg)) <= 0)
00128                                 return (invarg(progname, ch, optarg));
00129                         break;
00130                 case 'b':                       /* Number of branch records */
00131                         if ((branches = atoi(optarg)) <= 0)
00132                                 return (invarg(progname, ch, optarg));
00133                         break;
00134                 case 'c':                       /* Cachesize in bytes */
00135                         if ((mpool = atoi(optarg)) <= 0)
00136                                 return (invarg(progname, ch, optarg));
00137                         break;
00138                 case 'f':                       /* Fast mode: no txn sync. */
00139                         txn_no_sync = 1;
00140                         break;
00141                 case 'h':                       /* DB  home. */
00142                         home = optarg;
00143                         break;
00144                 case 'i':                       /* Initialize the test. */
00145                         iflag = 1;
00146                         break;
00147                 case 'n':                       /* Number of transactions */
00148                         if ((ntxns = atoi(optarg)) <= 0)
00149                                 return (invarg(progname, ch, optarg));
00150                         break;
00151                 case 'S':                       /* Random number seed. */
00152                         if ((seed = atoi(optarg)) <= 0)
00153                                 return (invarg(progname, ch, optarg));
00154                         break;
00155                 case 's':                       /* Number of history records */
00156                         if ((history = atoi(optarg)) <= 0)
00157                                 return (invarg(progname, ch, optarg));
00158                         break;
00159                 case 't':                       /* Number of teller records */
00160                         if ((tellers = atoi(optarg)) <= 0)
00161                                 return (invarg(progname, ch, optarg));
00162                         break;
00163                 case 'v':                       /* Verbose option. */
00164                         verbose = 1;
00165                         break;
00166                 case '?':
00167                 default:
00168                         return (usage(progname));
00169                 }
00170         argc -= optind;
00171         argv += optind;
00172 
00173         srand((u_int)seed);
00174 
00175         /* Initialize the database environment. */
00176         if ((dbenv = db_init(home,
00177             progname, mpool, txn_no_sync ? DB_TXN_NOSYNC : 0)) == NULL)
00178                 return (EXIT_FAILURE);
00179 
00180         accounts = accounts == 0 ? ACCOUNTS : accounts;
00181         branches = branches == 0 ? BRANCHES : branches;
00182         tellers = tellers == 0 ? TELLERS : tellers;
00183         history = history == 0 ? HISTORY : history;
00184 
00185         if (verbose)
00186                 printf("%ld Accounts, %ld Branches, %ld Tellers, %ld History\n",
00187                     (long)accounts, (long)branches,
00188                     (long)tellers, (long)history);
00189 
00190         if (iflag) {
00191                 if (ntxns != 0)
00192                         return (usage(progname));
00193                 tp_populate(dbenv,
00194                     accounts, branches, history, tellers, verbose);
00195         } else {
00196                 if (ntxns == 0)
00197                         return (usage(progname));
00198                 tp_run(dbenv, ntxns, accounts, branches, tellers, verbose);
00199         }
00200 
00201         if ((ret = dbenv->close(dbenv, 0)) != 0) {
00202                 fprintf(stderr, "%s: dbenv->close failed: %s\n",
00203                     progname, db_strerror(ret));
00204                 return (EXIT_FAILURE);
00205         }
00206 
00207         return (EXIT_SUCCESS);
00208 }
00209 
00210 int
00211 invarg(progname, arg, str)
00212         const char *progname;
00213         int arg;
00214         const char *str;
00215 {
00216         (void)fprintf(stderr,
00217             "%s: invalid argument for -%c: %s\n", progname, arg, str);
00218         return (EXIT_FAILURE);
00219 }
00220 
00221 int
00222 usage(progname)
00223         const char *progname;
00224 {
00225         const char *a1, *a2;
00226 
00227         a1 = "[-fv] [-a accounts] [-b branches]\n";
00228         a2 = "\t[-c cache_size] [-h home] [-S seed] [-s history] [-t tellers]";
00229         (void)fprintf(stderr, "usage: %s -i %s %s\n", progname, a1, a2);
00230         (void)fprintf(stderr,
00231             "       %s -n transactions %s %s\n", progname, a1, a2);
00232         return (EXIT_FAILURE);
00233 }
00234 
00235 /*
00236  * db_init --
00237  *      Initialize the environment.
00238  */
00239 DB_ENV *
00240 db_init(home, prefix, cachesize, flags)
00241         const char *home, *prefix;
00242         int cachesize;
00243         u_int32_t flags;
00244 {
00245         DB_ENV *dbenv;
00246         u_int32_t local_flags;
00247         int ret;
00248 
00249         if ((ret = db_env_create(&dbenv, 0)) != 0) {
00250                 dbenv->err(dbenv, ret, "db_env_create");
00251                 return (NULL);
00252         }
00253         dbenv->set_errfile(dbenv, stderr);
00254         dbenv->set_errpfx(dbenv, prefix);
00255         (void)dbenv->set_cachesize(dbenv, 0,
00256             cachesize == 0 ? 4 * 1024 * 1024 : (u_int32_t)cachesize, 0);
00257 
00258         if (flags & (DB_TXN_NOSYNC))
00259                 (void)dbenv->set_flags(dbenv, DB_TXN_NOSYNC, 1);
00260         flags &= ~(DB_TXN_NOSYNC);
00261 
00262         local_flags = flags | DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG |
00263             DB_INIT_MPOOL | DB_INIT_TXN;
00264         if ((ret = dbenv->open(dbenv, home, local_flags, 0)) != 0) {
00265                 dbenv->err(dbenv, ret, "DB_ENV->open: %s", home);
00266                 (void)dbenv->close(dbenv, 0);
00267                 return (NULL);
00268         }
00269         return (dbenv);
00270 }
00271 
00272 /*
00273  * Initialize the database to the specified number of accounts, branches,
00274  * history records, and tellers.
00275  */
00276 int
00277 tp_populate(env, accounts, branches, history, tellers, verbose)
00278         DB_ENV *env;
00279         int accounts, branches, history, tellers, verbose;
00280 {
00281         DB *dbp;
00282         u_int32_t balance, idnum, oflags;
00283         u_int32_t end_anum, end_bnum, end_tnum;
00284         u_int32_t start_anum, start_bnum, start_tnum;
00285         int ret;
00286 
00287         idnum = BEGID;
00288         balance = 500000;
00289         oflags = DB_CREATE;
00290 
00291         if ((ret = db_create(&dbp, env, 0)) != 0) {
00292                 env->err(env, ret, "db_create");
00293                 return (1);
00294         }
00295         (void)dbp->set_h_nelem(dbp, (u_int32_t)accounts);
00296 
00297         if ((ret = dbp->open(dbp, NULL, "account", NULL,
00298             DB_HASH, oflags, 0644)) != 0) {
00299                 env->err(env, ret, "DB->open: account");
00300                 return (1);
00301         }
00302 
00303         start_anum = idnum;
00304         populate(dbp, idnum, balance, accounts, "account");
00305         idnum += accounts;
00306         end_anum = idnum - 1;
00307         if ((ret = dbp->close(dbp, 0)) != 0) {
00308                 env->err(env, ret, "DB->close: account");
00309                 return (1);
00310         }
00311         if (verbose)
00312                 printf("Populated accounts: %ld - %ld\n",
00313                     (long)start_anum, (long)end_anum);
00314 
00315         /*
00316          * Since the number of branches is very small, we want to use very
00317          * small pages and only 1 key per page, i.e., key-locking instead
00318          * of page locking.
00319          */
00320         if ((ret = db_create(&dbp, env, 0)) != 0) {
00321                 env->err(env, ret, "db_create");
00322                 return (1);
00323         }
00324         (void)dbp->set_h_ffactor(dbp, 1);
00325         (void)dbp->set_h_nelem(dbp, (u_int32_t)branches);
00326         (void)dbp->set_pagesize(dbp, 512);
00327         if ((ret = dbp->open(dbp, NULL, "branch", NULL,
00328             DB_HASH, oflags, 0644)) != 0) {
00329                 env->err(env, ret, "DB->open: branch");
00330                 return (1);
00331         }
00332         start_bnum = idnum;
00333         populate(dbp, idnum, balance, branches, "branch");
00334         idnum += branches;
00335         end_bnum = idnum - 1;
00336         if ((ret = dbp->close(dbp, 0)) != 0) {
00337                 env->err(env, ret, "DB->close: branch");
00338                 return (1);
00339         }
00340         if (verbose)
00341                 printf("Populated branches: %ld - %ld\n",
00342                     (long)start_bnum, (long)end_bnum);
00343 
00344         /*
00345          * In the case of tellers, we also want small pages, but we'll let
00346          * the fill factor dynamically adjust itself.
00347          */
00348         if ((ret = db_create(&dbp, env, 0)) != 0) {
00349                 env->err(env, ret, "db_create");
00350                 return (1);
00351         }
00352         (void)dbp->set_h_ffactor(dbp, 0);
00353         (void)dbp->set_h_nelem(dbp, (u_int32_t)tellers);
00354         (void)dbp->set_pagesize(dbp, 512);
00355         if ((ret = dbp->open(dbp, NULL, "teller", NULL,
00356             DB_HASH, oflags, 0644)) != 0) {
00357                 env->err(env, ret, "DB->open: teller");
00358                 return (1);
00359         }
00360 
00361         start_tnum = idnum;
00362         populate(dbp, idnum, balance, tellers, "teller");
00363         idnum += tellers;
00364         end_tnum = idnum - 1;
00365         if ((ret = dbp->close(dbp, 0)) != 0) {
00366                 env->err(env, ret, "DB->close: teller");
00367                 return (1);
00368         }
00369         if (verbose)
00370                 printf("Populated tellers: %ld - %ld\n",
00371                     (long)start_tnum, (long)end_tnum);
00372 
00373         if ((ret = db_create(&dbp, env, 0)) != 0) {
00374                 env->err(env, ret, "db_create");
00375                 return (1);
00376         }
00377         (void)dbp->set_re_len(dbp, HISTORY_LEN);
00378         if ((ret = dbp->open(dbp, NULL, "history", NULL,
00379             DB_RECNO, oflags, 0644)) != 0) {
00380                 env->err(env, ret, "DB->open: history");
00381                 return (1);
00382         }
00383 
00384         hpopulate(dbp, history, accounts, branches, tellers);
00385         if ((ret = dbp->close(dbp, 0)) != 0) {
00386                 env->err(env, ret, "DB->close: history");
00387                 return (1);
00388         }
00389         return (0);
00390 }
00391 
00392 int
00393 populate(dbp, start_id, balance, nrecs, msg)
00394         DB *dbp;
00395         u_int32_t start_id, balance;
00396         int nrecs;
00397         const char *msg;
00398 {
00399         DBT kdbt, ddbt;
00400         defrec drec;
00401         int i, ret;
00402 
00403         kdbt.flags = 0;
00404         kdbt.data = &drec.id;
00405         kdbt.size = sizeof(u_int32_t);
00406         ddbt.flags = 0;
00407         ddbt.data = &drec;
00408         ddbt.size = sizeof(drec);
00409         memset(&drec.pad[0], 1, sizeof(drec.pad));
00410 
00411         for (i = 0; i < nrecs; i++) {
00412                 drec.id = start_id + (u_int32_t)i;
00413                 drec.balance = balance;
00414                 if ((ret =
00415                     (dbp->put)(dbp, NULL, &kdbt, &ddbt, DB_NOOVERWRITE)) != 0) {
00416                         dbp->err(dbp,
00417                             ret, "Failure initializing %s file\n", msg);
00418                         return (1);
00419                 }
00420         }
00421         return (0);
00422 }
00423 
00424 int
00425 hpopulate(dbp, history, accounts, branches, tellers)
00426         DB *dbp;
00427         int history, accounts, branches, tellers;
00428 {
00429         DBT kdbt, ddbt;
00430         histrec hrec;
00431         db_recno_t key;
00432         int i, ret;
00433 
00434         memset(&kdbt, 0, sizeof(kdbt));
00435         memset(&ddbt, 0, sizeof(ddbt));
00436         ddbt.data = &hrec;
00437         ddbt.size = sizeof(hrec);
00438         kdbt.data = &key;
00439         kdbt.size = sizeof(key);
00440         memset(&hrec.pad[0], 1, sizeof(hrec.pad));
00441         hrec.amount = 10;
00442 
00443         for (i = 1; i <= history; i++) {
00444                 hrec.aid = random_id(ACCOUNT, accounts, branches, tellers);
00445                 hrec.bid = random_id(BRANCH, accounts, branches, tellers);
00446                 hrec.tid = random_id(TELLER, accounts, branches, tellers);
00447                 if ((ret = dbp->put(dbp, NULL, &kdbt, &ddbt, DB_APPEND)) != 0) {
00448                         dbp->err(dbp, ret, "dbp->put");
00449                         return (1);
00450                 }
00451         }
00452         return (0);
00453 }
00454 
00455 u_int32_t
00456 random_int(lo, hi)
00457         u_int32_t lo, hi;
00458 {
00459         u_int32_t ret;
00460         int t;
00461 
00462 #ifndef RAND_MAX
00463 #define RAND_MAX        0x7fffffff
00464 #endif
00465         t = rand();
00466         ret = (u_int32_t)(((double)t / ((double)(RAND_MAX) + 1)) *
00467             (hi - lo + 1));
00468         ret += lo;
00469         return (ret);
00470 }
00471 
00472 u_int32_t
00473 random_id(type, accounts, branches, tellers)
00474         FTYPE type;
00475         int accounts, branches, tellers;
00476 {
00477         u_int32_t min, max, num;
00478 
00479         max = min = BEGID;
00480         num = accounts;
00481         switch (type) {
00482         case TELLER:
00483                 min += branches;
00484                 num = tellers;
00485                 /* FALLTHROUGH */
00486         case BRANCH:
00487                 if (type == BRANCH)
00488                         num = branches;
00489                 min += accounts;
00490                 /* FALLTHROUGH */
00491         case ACCOUNT:
00492                 max = min + num - 1;
00493         }
00494         return (random_int(min, max));
00495 }
00496 
00497 int
00498 tp_run(dbenv, n, accounts, branches, tellers, verbose)
00499         DB_ENV *dbenv;
00500         int n, accounts, branches, tellers, verbose;
00501 {
00502         DB *adb, *bdb, *hdb, *tdb;
00503         int failed, ret, txns;
00504         time_t start_time, end_time;
00505 
00506         adb = bdb = hdb = tdb = NULL;
00507 
00508         /*
00509          * Open the database files.
00510          */
00511         if ((ret = db_create(&adb, dbenv, 0)) != 0) {
00512                 dbenv->err(dbenv, ret, "db_create");
00513                 goto err;
00514         }
00515         if ((ret = adb->open(adb, NULL, "account", NULL, DB_UNKNOWN,
00516             DB_AUTO_COMMIT, 0)) != 0) {
00517                 dbenv->err(dbenv, ret, "DB->open: account");
00518                 goto err;
00519         }
00520         if ((ret = db_create(&bdb, dbenv, 0)) != 0) {
00521                 dbenv->err(dbenv, ret, "db_create");
00522                 goto err;
00523         }
00524         if ((ret = bdb->open(bdb, NULL, "branch", NULL, DB_UNKNOWN,
00525             DB_AUTO_COMMIT, 0)) != 0) {
00526                 dbenv->err(dbenv, ret, "DB->open: branch");
00527                 goto err;
00528         }
00529         if ((ret = db_create(&hdb, dbenv, 0)) != 0) {
00530                 dbenv->err(dbenv, ret, "db_create");
00531                 goto err;
00532         }
00533         if ((ret = hdb->open(hdb, NULL, "history", NULL, DB_UNKNOWN,
00534             DB_AUTO_COMMIT, 0)) != 0) {
00535                 dbenv->err(dbenv, ret, "DB->open: history");
00536                 goto err;
00537         }
00538         if ((ret = db_create(&tdb, dbenv, 0)) != 0) {
00539                 dbenv->err(dbenv, ret, "db_create");
00540                 goto err;
00541         }
00542         if ((ret = tdb->open(tdb, NULL, "teller", NULL, DB_UNKNOWN,
00543             DB_AUTO_COMMIT, 0)) != 0) {
00544                 dbenv->err(dbenv, ret, "DB->open: teller");
00545                 goto err;
00546         }
00547 
00548         (void)time(&start_time);
00549         for (txns = n, failed = 0; n-- > 0;)
00550                 if ((ret = tp_txn(dbenv, adb, bdb, tdb, hdb,
00551                     accounts, branches, tellers, verbose)) != 0)
00552                         ++failed;
00553         (void)time(&end_time);
00554         if (end_time == start_time)
00555                 ++end_time;
00556         printf("%s: %d txns: %d failed, %.2f TPS\n", progname,
00557             txns, failed, (txns - failed) / (double)(end_time - start_time));
00558 
00559 err:    if (adb != NULL)
00560                 (void)adb->close(adb, 0);
00561         if (bdb != NULL)
00562                 (void)bdb->close(bdb, 0);
00563         if (tdb != NULL)
00564                 (void)tdb->close(tdb, 0);
00565         if (hdb != NULL)
00566                 (void)hdb->close(hdb, 0);
00567         return (ret == 0 ? 0 : 1);
00568 }
00569 
00570 /*
00571  * XXX Figure out the appropriate way to pick out IDs.
00572  */
00573 int
00574 tp_txn(dbenv, adb, bdb, tdb, hdb, accounts, branches, tellers, verbose)
00575         DB_ENV *dbenv;
00576         DB *adb, *bdb, *tdb, *hdb;
00577         int accounts, branches, tellers, verbose;
00578 {
00579         DBC *acurs, *bcurs, *tcurs;
00580         DBT d_dbt, d_histdbt, k_dbt, k_histdbt;
00581         DB_TXN *t;
00582         db_recno_t key;
00583         defrec rec;
00584         histrec hrec;
00585         int account, branch, teller, ret;
00586 
00587         t = NULL;
00588         acurs = bcurs = tcurs = NULL;
00589 
00590         /*
00591          * !!!
00592          * This is sample code -- we could move a lot of this into the driver
00593          * to make it faster.
00594          */
00595         account = random_id(ACCOUNT, accounts, branches, tellers);
00596         branch = random_id(BRANCH, accounts, branches, tellers);
00597         teller = random_id(TELLER, accounts, branches, tellers);
00598 
00599         memset(&d_histdbt, 0, sizeof(d_histdbt));
00600 
00601         memset(&k_histdbt, 0, sizeof(k_histdbt));
00602         k_histdbt.data = &key;
00603         k_histdbt.size = sizeof(key);
00604 
00605         memset(&k_dbt, 0, sizeof(k_dbt));
00606         k_dbt.size = sizeof(int);
00607 
00608         memset(&d_dbt, 0, sizeof(d_dbt));
00609         d_dbt.flags = DB_DBT_USERMEM;
00610         d_dbt.data = &rec;
00611         d_dbt.ulen = sizeof(rec);
00612 
00613         hrec.aid = account;
00614         hrec.bid = branch;
00615         hrec.tid = teller;
00616         hrec.amount = 10;
00617         /* Request 0 bytes since we're just positioning. */
00618         d_histdbt.flags = DB_DBT_PARTIAL;
00619 
00620         /*
00621          * START PER-TRANSACTION TIMING.
00622          *
00623          * Technically, TPCB requires a limit on response time, you only get
00624          * to count transactions that complete within 2 seconds.  That's not
00625          * an issue for this sample application -- regardless, here's where
00626          * the transaction begins.
00627          */
00628         if (dbenv->txn_begin(dbenv, NULL, &t, 0) != 0)
00629                 goto err;
00630 
00631         if (adb->cursor(adb, t, &acurs, 0) != 0 ||
00632             bdb->cursor(bdb, t, &bcurs, 0) != 0 ||
00633             tdb->cursor(tdb, t, &tcurs, 0) != 0)
00634                 goto err;
00635 
00636         /* Account record */
00637         k_dbt.data = &account;
00638         if (acurs->c_get(acurs, &k_dbt, &d_dbt, DB_SET) != 0)
00639                 goto err;
00640         rec.balance += 10;
00641         if (acurs->c_put(acurs, &k_dbt, &d_dbt, DB_CURRENT) != 0)
00642                 goto err;
00643 
00644         /* Branch record */
00645         k_dbt.data = &branch;
00646         if (bcurs->c_get(bcurs, &k_dbt, &d_dbt, DB_SET) != 0)
00647                 goto err;
00648         rec.balance += 10;
00649         if (bcurs->c_put(bcurs, &k_dbt, &d_dbt, DB_CURRENT) != 0)
00650                 goto err;
00651 
00652         /* Teller record */
00653         k_dbt.data = &teller;
00654         if (tcurs->c_get(tcurs, &k_dbt, &d_dbt, DB_SET) != 0)
00655                 goto err;
00656         rec.balance += 10;
00657         if (tcurs->c_put(tcurs, &k_dbt, &d_dbt, DB_CURRENT) != 0)
00658                 goto err;
00659 
00660         /* History record */
00661         d_histdbt.flags = 0;
00662         d_histdbt.data = &hrec;
00663         d_histdbt.ulen = sizeof(hrec);
00664         if (hdb->put(hdb, t, &k_histdbt, &d_histdbt, DB_APPEND) != 0)
00665                 goto err;
00666 
00667         if (acurs->c_close(acurs) != 0 || bcurs->c_close(bcurs) != 0 ||
00668             tcurs->c_close(tcurs) != 0)
00669                 goto err;
00670 
00671         ret = t->commit(t, 0);
00672         t = NULL;
00673         if (ret != 0)
00674                 goto err;
00675         /* END PER-TRANSACTION TIMING. */
00676 
00677         return (0);
00678 
00679 err:    if (acurs != NULL)
00680                 (void)acurs->c_close(acurs);
00681         if (bcurs != NULL)
00682                 (void)bcurs->c_close(bcurs);
00683         if (tcurs != NULL)
00684                 (void)tcurs->c_close(tcurs);
00685         if (t != NULL)
00686                 (void)t->abort(t);
00687 
00688         if (verbose)
00689                 printf("Transaction A=%ld B=%ld T=%ld failed\n",
00690                     (long)account, (long)branch, (long)teller);
00691         return (-1);
00692 }

Generated on Sun Dec 25 12:14:25 2005 for Berkeley DB 4.4.16 by  doxygen 1.4.2