summaryrefslogtreecommitdiff
path: root/bdb/examples_cxx
diff options
context:
space:
mode:
authortim@threads.polyesthetic.msg <>2001-03-04 19:42:05 -0500
committertim@threads.polyesthetic.msg <>2001-03-04 19:42:05 -0500
commit89dad52004ecba5a380aeebb0e2a9beaae88eb86 (patch)
tree9dd732e08dba156ee3d7635caedc0dc3107ecac6 /bdb/examples_cxx
parent639a1069d313843288ba6d9cb54b290073a748a7 (diff)
downloadmariadb-git-89dad52004ecba5a380aeebb0e2a9beaae88eb86.tar.gz
Import changeset
Diffstat (limited to 'bdb/examples_cxx')
-rw-r--r--bdb/examples_cxx/AccessExample.cpp151
-rw-r--r--bdb/examples_cxx/BtRecExample.cpp247
-rw-r--r--bdb/examples_cxx/EnvExample.cpp122
-rw-r--r--bdb/examples_cxx/LockExample.cpp236
-rw-r--r--bdb/examples_cxx/MpoolExample.cpp210
-rw-r--r--bdb/examples_cxx/TpcbExample.cpp666
6 files changed, 1632 insertions, 0 deletions
diff --git a/bdb/examples_cxx/AccessExample.cpp b/bdb/examples_cxx/AccessExample.cpp
new file mode 100644
index 00000000000..ae885aa8388
--- /dev/null
+++ b/bdb/examples_cxx/AccessExample.cpp
@@ -0,0 +1,151 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1997, 1998, 1999, 2000
+ * Sleepycat Software. All rights reserved.
+ *
+ * $Id: AccessExample.cpp,v 11.7 2000/12/06 18:58:23 bostic Exp $
+ */
+
+#include "db_config.h"
+
+#ifndef NO_SYSTEM_INCLUDES
+#include <sys/types.h>
+
+#include <iostream.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#ifndef _MSC_VER
+#include <unistd.h>
+#endif
+#endif
+
+#include <iomanip.h>
+#include <db_cxx.h>
+
+class AccessExample
+{
+public:
+ AccessExample();
+ void run();
+
+private:
+ static const char FileName[];
+
+ // no need for copy and assignment
+ AccessExample(const AccessExample &);
+ void operator = (const AccessExample &);
+};
+
+static void usage(); // forward
+
+int main(int argc, char *argv[])
+{
+ if (argc > 1) {
+ usage();
+ }
+
+ // Use a try block just to report any errors.
+ // An alternate approach to using exceptions is to
+ // use error models (see DbEnv::set_error_model()) so
+ // that error codes are returned for all Berkeley DB methods.
+ //
+ try {
+ AccessExample app;
+ app.run();
+ return 0;
+ }
+ catch (DbException &dbe) {
+ cerr << "AccessExample: " << dbe.what() << "\n";
+ return 1;
+ }
+}
+
+static void usage()
+{
+ cerr << "usage: AccessExample\n";
+ exit(1);
+}
+
+const char AccessExample::FileName[] = "access.db";
+
+AccessExample::AccessExample()
+{
+}
+
+void AccessExample::run()
+{
+ // Remove the previous database.
+ (void)unlink(FileName);
+
+ // Create the database object.
+ // There is no environment for this simple example.
+ Db db(0, 0);
+
+ db.set_error_stream(&cerr);
+ db.set_errpfx("AccessExample");
+ db.set_pagesize(1024); /* Page size: 1K. */
+ db.set_cachesize(0, 32 * 1024, 0);
+ db.open(FileName, NULL, DB_BTREE, DB_CREATE, 0664);
+
+ //
+ // Insert records into the database, where the key is the user
+ // input and the data is the user input in reverse order.
+ //
+ char buf[1024];
+ char rbuf[1024];
+ char *t;
+ char *p;
+ int ret;
+ int len;
+
+ for (;;) {
+ cout << "input> ";
+ cout.flush();
+
+ cin.getline(buf, sizeof(buf));
+ if (cin.eof())
+ break;
+
+ if ((len = strlen(buf)) <= 0)
+ continue;
+ for (t = rbuf, p = buf + (len - 1); p >= buf;)
+ *t++ = *p--;
+ *t++ = '\0';
+
+ Dbt key(buf, len + 1);
+ Dbt data(rbuf, len + 1);
+
+ ret = db.put(0, &key, &data, DB_NOOVERWRITE);
+ if (ret == DB_KEYEXIST) {
+ cout << "Key " << buf << " already exists.\n";
+ }
+ }
+ cout << "\n";
+
+ // We put a try block around this section of code
+ // to ensure that our database is properly closed
+ // in the event of an error.
+ //
+ try {
+ // Acquire a cursor for the table.
+ Dbc *dbcp;
+ db.cursor(NULL, &dbcp, 0);
+
+ // Walk through the table, printing the key/data pairs.
+ Dbt key;
+ Dbt data;
+ while (dbcp->get(&key, &data, DB_NEXT) == 0) {
+ char *key_string = (char *)key.get_data();
+ char *data_string = (char *)data.get_data();
+ cout << key_string << " : " << data_string << "\n";
+ }
+ dbcp->close();
+ }
+ catch (DbException &dbe) {
+ cerr << "AccessExample: " << dbe.what() << "\n";
+ }
+
+ db.close(0);
+}
diff --git a/bdb/examples_cxx/BtRecExample.cpp b/bdb/examples_cxx/BtRecExample.cpp
new file mode 100644
index 00000000000..98d9626b969
--- /dev/null
+++ b/bdb/examples_cxx/BtRecExample.cpp
@@ -0,0 +1,247 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1997, 1998, 1999, 2000
+ * Sleepycat Software. All rights reserved.
+ *
+ * $Id: BtRecExample.cpp,v 11.6 2000/02/19 20:57:59 bostic Exp $
+ */
+
+#include "db_config.h"
+
+#ifndef NO_SYSTEM_INCLUDES
+#include <sys/types.h>
+#include <errno.h>
+#include <iostream.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#endif
+
+#include <iomanip.h>
+#include <db_cxx.h>
+
+#define DATABASE "access.db"
+#define WORDLIST "../test/wordlist"
+
+void usage();
+extern "C" int getopt(int, char * const *, const char *);
+
+char *progname = "BtRecExample"; // Program name.
+
+class BtRecExample
+{
+public:
+ BtRecExample(FILE *fp);
+ ~BtRecExample();
+ void run();
+ void stats();
+ void show(char *msg, Dbt *key, Dbt *data);
+
+private:
+ Db *dbp;
+ Dbc *dbcp;
+};
+
+BtRecExample::BtRecExample(FILE *fp)
+{
+ char *p, *t, buf[1024], rbuf[1024];
+ int ret;
+
+ // Remove the previous database.
+ (void)unlink(DATABASE);
+
+ dbp = new Db(NULL, 0);
+
+ dbp->set_error_stream(&cerr);
+ dbp->set_errpfx(progname);
+ dbp->set_pagesize(1024); // 1K page sizes.
+
+ dbp->set_flags(DB_RECNUM); // Record numbers.
+ dbp->open(DATABASE, NULL, DB_BTREE, DB_CREATE, 0664);
+
+ //
+ // Insert records into the database, where the key is the word
+ // preceded by its record number, and the data is the same, but
+ // in reverse order.
+ //
+
+ for (int cnt = 1; cnt <= 1000; ++cnt) {
+ (void)sprintf(buf, "%04d_", cnt);
+ if (fgets(buf + 4, sizeof(buf) - 4, fp) == NULL)
+ break;
+ u_int32_t len = strlen(buf);
+ buf[len - 1] = '\0';
+ for (t = rbuf, p = buf + (len - 2); p >= buf;)
+ *t++ = *p--;
+ *t++ = '\0';
+
+ // As a convenience for printing, we include the null terminator
+ // in the stored data.
+ //
+ Dbt key(buf, len);
+ Dbt data(rbuf, len);
+
+ if ((ret = dbp->put(NULL, &key, &data, DB_NOOVERWRITE)) != 0) {
+ dbp->err(ret, "Db::put");
+ if (ret != DB_KEYEXIST)
+ throw DbException(ret);
+ }
+ }
+}
+
+BtRecExample::~BtRecExample()
+{
+ if (dbcp != 0)
+ dbcp->close();
+ dbp->close(0);
+ delete dbp;
+}
+
+//
+// Print out the number of records in the database.
+//
+void BtRecExample::stats()
+{
+ DB_BTREE_STAT *statp;
+
+ dbp->stat(&statp, NULL, 0);
+ cout << progname << ": database contains "
+ << (u_long)statp->bt_ndata << " records\n";
+
+ // Note: must use free, not delete.
+ // This struct is allocated by C.
+ //
+ free(statp);
+}
+
+void BtRecExample::run()
+{
+ db_recno_t recno;
+ int ret;
+ char buf[1024];
+
+ // Acquire a cursor for the database.
+ dbp->cursor(NULL, &dbcp, 0);
+
+ //
+ // Prompt the user for a record number, then retrieve and display
+ // that record.
+ //
+ for (;;) {
+ // Get a record number.
+ cout << "recno #> ";
+ cout.flush();
+ if (fgets(buf, sizeof(buf), stdin) == NULL)
+ break;
+ recno = atoi(buf);
+
+ //
+ // Start with a fresh key each time,
+ // the dbp->get() routine returns
+ // the key and data pair, not just the key!
+ //
+ Dbt key(&recno, sizeof(recno));
+ Dbt data;
+
+ if ((ret = dbcp->get(&key, &data, DB_SET_RECNO)) != 0) {
+ dbp->err(ret, "DBcursor->get");
+ throw DbException(ret);
+ }
+
+ // Display the key and data.
+ show("k/d\t", &key, &data);
+
+ // Move the cursor a record forward.
+ if ((ret = dbcp->get(&key, &data, DB_NEXT)) != 0) {
+ dbp->err(ret, "DBcursor->get");
+ throw DbException(ret);
+ }
+
+ // Display the key and data.
+ show("next\t", &key, &data);
+
+ //
+ // Retrieve the record number for the following record into
+ // local memory.
+ //
+ data.set_data(&recno);
+ data.set_size(sizeof(recno));
+ data.set_ulen(sizeof(recno));
+ data.set_flags(data.get_flags() | DB_DBT_USERMEM);
+
+ if ((ret = dbcp->get(&key, &data, DB_GET_RECNO)) != 0) {
+ if (ret != DB_NOTFOUND && ret != DB_KEYEMPTY) {
+ dbp->err(ret, "DBcursor->get");
+ throw DbException(ret);
+ }
+ }
+ else {
+ cout << "retrieved recno: " << (u_long)recno << "\n";
+ }
+ }
+
+ dbcp->close();
+ dbcp = NULL;
+}
+
+//
+// show --
+// Display a key/data pair.
+//
+void BtRecExample::show(char *msg, Dbt *key, Dbt *data)
+{
+ cout << msg << (char *)key->get_data()
+ << " : " << (char *)data->get_data() << "\n";
+}
+
+int
+main(int argc, char *argv[])
+{
+ extern char *optarg;
+ extern int optind;
+ FILE *fp;
+ int ch;
+
+ while ((ch = getopt(argc, argv, "")) != EOF)
+ switch (ch) {
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ // Open the word database.
+ if ((fp = fopen(WORDLIST, "r")) == NULL) {
+ fprintf(stderr, "%s: open %s: %s\n",
+ progname, WORDLIST, db_strerror(errno));
+ exit (1);
+ }
+
+ try {
+ BtRecExample app(fp);
+
+ // Close the word database.
+ (void)fclose(fp);
+ fp = NULL;
+
+ app.stats();
+ app.run();
+ }
+ catch (DbException &dbe) {
+ cerr << "Exception: " << dbe.what() << "\n";
+ return dbe.get_errno();
+ }
+
+ return (0);
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr, "usage: %s\n", progname);
+ exit(1);
+}
diff --git a/bdb/examples_cxx/EnvExample.cpp b/bdb/examples_cxx/EnvExample.cpp
new file mode 100644
index 00000000000..bef1f3d1ace
--- /dev/null
+++ b/bdb/examples_cxx/EnvExample.cpp
@@ -0,0 +1,122 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1997, 1998, 1999, 2000
+ * Sleepycat Software. All rights reserved.
+ *
+ * $Id: EnvExample.cpp,v 11.12 2000/10/27 20:32:00 dda Exp $
+ */
+
+#include "db_config.h"
+
+#ifndef NO_SYSTEM_INCLUDES
+#include <sys/types.h>
+
+#include <errno.h>
+#include <iostream.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#endif
+
+#include <db_cxx.h>
+
+#ifdef macintosh
+#define DATABASE_HOME ":database"
+#define CONFIG_DATA_DIR ":database"
+#else
+#ifdef DB_WIN32
+#define DATABASE_HOME "\\tmp\\database"
+#define CONFIG_DATA_DIR "\\database\\files"
+#else
+#define DATABASE_HOME "/tmp/database"
+#define CONFIG_DATA_DIR "/database/files"
+#endif
+#endif
+
+void db_setup(char *, char *, ostream&);
+void db_teardown(char *, char *, ostream&);
+
+char *progname = "EnvExample"; /* Program name. */
+
+//
+// An example of a program creating/configuring a Berkeley DB environment.
+//
+int
+main(int, char **)
+{
+ //
+ // Note: it may be easiest to put all Berkeley DB operations in a
+ // try block, as seen here. Alternatively, you can change the
+ // ErrorModel in the DbEnv so that exceptions are never thrown
+ // and check error returns from all methods.
+ //
+ try {
+ char *data_dir, *home;
+
+ //
+ // All of the shared database files live in /home/database,
+ // but data files live in /database.
+ //
+ home = DATABASE_HOME;
+ data_dir = CONFIG_DATA_DIR;
+
+ cout << "Setup env\n";
+ db_setup(DATABASE_HOME, data_dir, cerr);
+
+ cout << "Teardown env\n";
+ db_teardown(DATABASE_HOME, data_dir, cerr);
+ return 0;
+ }
+ catch (DbException &dbe) {
+ cerr << "AccessExample: " << dbe.what() << "\n";
+ return 1;
+ }
+}
+
+// Note that any of the db calls can throw DbException
+void
+db_setup(char *home, char *data_dir, ostream& err_stream)
+{
+ //
+ // Create an environment object and initialize it for error
+ // reporting.
+ //
+ DbEnv *dbenv = new DbEnv(0);
+ dbenv->set_error_stream(&err_stream);
+ dbenv->set_errpfx(progname);
+
+ //
+ // We want to specify the shared memory buffer pool cachesize,
+ // but everything else is the default.
+ //
+ dbenv->set_cachesize(0, 64 * 1024, 0);
+
+ // Databases are in a subdirectory.
+ (void)dbenv->set_data_dir(data_dir);
+
+ // Open the environment with full transactional support.
+ dbenv->open(DATABASE_HOME,
+ DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN, 0);
+
+ // Do something interesting...
+
+ // Close the handle.
+ dbenv->close(0);
+}
+
+void
+db_teardown(char *home, char *data_dir, ostream& err_stream)
+{
+ // Remove the shared database regions.
+ DbEnv *dbenv = new DbEnv(0);
+
+ dbenv->set_error_stream(&err_stream);
+ dbenv->set_errpfx(progname);
+
+ (void)dbenv->set_data_dir(data_dir);
+ dbenv->remove(home, 0);
+ delete dbenv;
+}
diff --git a/bdb/examples_cxx/LockExample.cpp b/bdb/examples_cxx/LockExample.cpp
new file mode 100644
index 00000000000..cfab2868098
--- /dev/null
+++ b/bdb/examples_cxx/LockExample.cpp
@@ -0,0 +1,236 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1997, 1998, 1999, 2000
+ * Sleepycat Software. All rights reserved.
+ *
+ * $Id: LockExample.cpp,v 11.8 2001/01/04 14:23:30 dda Exp $
+ */
+
+#include "db_config.h"
+
+#ifndef NO_SYSTEM_INCLUDES
+#include <sys/types.h>
+
+#include <errno.h>
+#include <iostream.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#endif
+
+#include <db_cxx.h>
+
+char *progname = "LockExample"; // Program name.
+
+//
+// An example of a program using DBLock and related classes.
+//
+class LockExample : public DbEnv
+{
+public:
+ void run();
+
+ LockExample(const char *home, u_int32_t maxlocks, int do_unlink);
+
+private:
+ static const char FileName[];
+
+ // no need for copy and assignment
+ LockExample(const LockExample &);
+ void operator = (const LockExample &);
+};
+
+static void usage(); // forward
+
+int
+main(int argc, char *argv[])
+{
+ const char *home;
+ int do_unlink;
+ u_int32_t maxlocks;
+ int i;
+
+ home = "TESTDIR";
+ maxlocks = 0;
+ do_unlink = 0;
+ for (int argnum = 1; argnum < argc; ++argnum) {
+ if (strcmp(argv[argnum], "-h") == 0) {
+ if (++argnum >= argc)
+ usage();
+ home = argv[argnum];
+ }
+ else if (strcmp(argv[argnum], "-m") == 0) {
+ if (++argnum >= argc)
+ usage();
+ if ((i = atoi(argv[argnum])) <= 0)
+ usage();
+ maxlocks = (u_int32_t)i; /* XXX: possible overflow. */
+ }
+ else if (strcmp(argv[argnum], "-u") == 0) {
+ do_unlink = 1;
+ }
+ else {
+ usage();
+ }
+ }
+
+ try {
+ if (do_unlink) {
+ // Create an environment that immediately
+ // removes all files.
+ LockExample tmp(home, maxlocks, do_unlink);
+ }
+
+ LockExample app(home, maxlocks, do_unlink);
+ app.run();
+ app.close(0);
+ return 0;
+ }
+ catch (DbException &dbe) {
+ cerr << "LockExample: " << dbe.what() << "\n";
+ return 1;
+ }
+}
+
+LockExample::LockExample(const char *home, u_int32_t maxlocks, int do_unlink)
+: DbEnv(0)
+{
+ int ret;
+
+ if (do_unlink) {
+ if ((ret = remove(home, DB_FORCE)) != 0) {
+ cerr << progname << ": DbEnv::remove: "
+ << strerror(errno) << "\n";
+ exit (1);
+ }
+ }
+ else {
+ set_error_stream(&cerr);
+ set_errpfx("LockExample");
+ if (maxlocks != 0)
+ set_lk_max_locks(maxlocks);
+ open(home, DB_CREATE | DB_INIT_LOCK, 0);
+ }
+}
+
+void LockExample::run()
+{
+ long held;
+ u_int32_t len, locker;
+ int did_get, ret;
+ DbLock *locks = 0;
+ int lockcount = 0;
+ char objbuf[1024];
+ int lockid = 0;
+
+ //
+ // Accept lock requests.
+ //
+ lock_id(&locker);
+ for (held = 0;;) {
+ cout << "Operation get/release [get]> ";
+ cout.flush();
+
+ char opbuf[16];
+ cin.getline(opbuf, sizeof(opbuf));
+ if (cin.eof())
+ break;
+ if ((len = strlen(opbuf)) <= 1 || strcmp(opbuf, "get") == 0) {
+ // Acquire a lock.
+ cout << "input object (text string) to lock> ";
+ cout.flush();
+ cin.getline(objbuf, sizeof(objbuf));
+ if (cin.eof())
+ break;
+ if ((len = strlen(objbuf)) <= 0)
+ continue;
+
+ char lockbuf[16];
+ do {
+ cout << "lock type read/write [read]> ";
+ cout.flush();
+ cin.getline(lockbuf, sizeof(lockbuf));
+ if (cin.eof())
+ break;
+ len = strlen(lockbuf);
+ } while (len >= 1 &&
+ strcmp(lockbuf, "read") != 0 &&
+ strcmp(lockbuf, "write") != 0);
+
+ db_lockmode_t lock_type;
+ if (len <= 1 || strcmp(lockbuf, "read") == 0)
+ lock_type = DB_LOCK_READ;
+ else
+ lock_type = DB_LOCK_WRITE;
+
+ Dbt dbt(objbuf, strlen(objbuf));
+
+ DbLock lock;
+ ret = lock_get(locker, DB_LOCK_NOWAIT, &dbt,
+ lock_type, &lock);
+ did_get = 1;
+ lockid = lockcount++;
+ if (locks == NULL) {
+ locks = new DbLock[1];
+ }
+ else {
+ DbLock *newlocks = new DbLock[lockcount];
+ for (int lockno = 0; lockno < lockid; lockno++) {
+ newlocks[lockno] = locks[lockno];
+ }
+ delete locks;
+ locks = newlocks;
+ }
+ locks[lockid] = lock;
+ } else {
+ // Release a lock.
+ do {
+ cout << "input lock to release> ";
+ cout.flush();
+ cin.getline(objbuf, sizeof(objbuf));
+ if (cin.eof())
+ break;
+ } while ((len = strlen(objbuf)) <= 0);
+ lockid = strtol(objbuf, NULL, 16);
+ if (lockid < 0 || lockid >= lockcount) {
+ cout << "Lock #" << lockid << " out of range\n";
+ continue;
+ }
+ DbLock lock = locks[lockid];
+ ret = lock.put(this);
+ did_get = 0;
+ }
+
+ switch (ret) {
+ case 0:
+ cout << "Lock #" << lockid << " "
+ << (did_get ? "granted" : "released")
+ << "\n";
+ held += did_get ? 1 : -1;
+ break;
+ case DB_LOCK_NOTGRANTED:
+ cout << "Lock not granted\n";
+ break;
+ case DB_LOCK_DEADLOCK:
+ cerr << "LockExample: lock_"
+ << (did_get ? "get" : "put")
+ << ": " << "returned DEADLOCK";
+ break;
+ default:
+ cerr << "LockExample: lock_get: %s",
+ strerror(errno);
+ }
+ }
+ cout << "\n";
+ cout << "Closing lock region " << held << " locks held\n";
+ if (locks != 0)
+ delete locks;
+}
+
+static void
+usage()
+{
+ cerr << "usage: LockExample [-u] [-h home] [-m maxlocks]\n";
+ exit(1);
+}
diff --git a/bdb/examples_cxx/MpoolExample.cpp b/bdb/examples_cxx/MpoolExample.cpp
new file mode 100644
index 00000000000..cf0f5f7e6a4
--- /dev/null
+++ b/bdb/examples_cxx/MpoolExample.cpp
@@ -0,0 +1,210 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1997, 1998, 1999, 2000
+ * Sleepycat Software. All rights reserved.
+ *
+ * $Id: MpoolExample.cpp,v 11.9 2000/10/27 20:32:01 dda Exp $
+ */
+
+#include "db_config.h"
+
+#ifndef NO_SYSTEM_INCLUDES
+#include <sys/types.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <iostream.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#endif
+
+#include <db_cxx.h>
+
+#define MPOOL "mpool"
+
+void init(char *, int, int);
+void run(DB_ENV *, int, int, int);
+
+static void usage();
+
+char *progname = "MpoolExample"; // Program name.
+
+class MpoolExample : public DbEnv
+{
+public:
+ MpoolExample();
+ void initdb(const char *home, int cachesize);
+ void run(int hits, int pagesize, int npages);
+
+private:
+ static const char FileName[];
+
+ // no need for copy and assignment
+ MpoolExample(const MpoolExample &);
+ void operator = (const MpoolExample &);
+};
+
+int main(int argc, char *argv[])
+{
+ int cachesize = 20 * 1024;
+ int hits = 1000;
+ int npages = 50;
+ int pagesize = 1024;
+
+ for (int i = 1; i < argc; ++i) {
+ if (strcmp(argv[i], "-c") == 0) {
+ if ((cachesize = atoi(argv[++i])) < 20 * 1024)
+ usage();
+ }
+ else if (strcmp(argv[i], "-h") == 0) {
+ if ((hits = atoi(argv[++i])) <= 0)
+ usage();
+ }
+ else if (strcmp(argv[i], "-n") == 0) {
+ if ((npages = atoi(argv[++i])) <= 0)
+ usage();
+ }
+ else if (strcmp(argv[i], "-p") == 0) {
+ if ((pagesize = atoi(argv[++i])) <= 0)
+ usage();
+ }
+ else {
+ usage();
+ }
+ }
+
+ // Initialize the file.
+ init(MPOOL, pagesize, npages);
+
+ try {
+ MpoolExample app;
+
+ cout << progname
+ << ": cachesize: " << cachesize
+ << "; pagesize: " << pagesize
+ << "; N pages: " << npages << "\n";
+
+ app.initdb(NULL, cachesize);
+ app.run(hits, pagesize, npages);
+ cout << "MpoolExample: completed\n";
+ return 0;
+ }
+ catch (DbException &dbe) {
+ cerr << "MpoolExample: " << dbe.what() << "\n";
+ return 1;
+ }
+}
+
+//
+// init --
+// Create a backing file.
+//
+void
+init(char *file, int pagesize, int npages)
+{
+ //
+ // Create a file with the right number of pages, and store a page
+ // number on each page.
+ //
+ int fd;
+ int flags = O_CREAT | O_RDWR | O_TRUNC;
+#ifdef DB_WIN32
+ flags |= O_BINARY;
+#endif
+ if ((fd = open(file, flags, 0666)) < 0) {
+ cerr << "MpoolExample: " << file << ": " << strerror(errno) << "\n";
+ exit(1);
+ }
+ char *p = new char[pagesize];
+ memset(p, 0, pagesize);
+
+ // The pages are numbered from 0.
+ for (int cnt = 0; cnt <= npages; ++cnt) {
+ *(db_pgno_t *)p = cnt;
+ if (write(fd, p, pagesize) != pagesize) {
+ cerr << "MpoolExample: " << file
+ << ": " << strerror(errno) << "\n";
+ exit(1);
+ }
+ }
+ delete [] p;
+}
+
+static void
+usage()
+{
+ cerr << "usage: MpoolExample [-c cachesize] "
+ << "[-h hits] [-n npages] [-p pagesize]\n";
+ exit(1);
+}
+
+// Note: by using DB_CXX_NO_EXCEPTIONS, we get explicit error returns
+// from various methods rather than exceptions so we can report more
+// information with each error.
+//
+MpoolExample::MpoolExample()
+: DbEnv(DB_CXX_NO_EXCEPTIONS)
+{
+}
+
+void MpoolExample::initdb(const char *home, int cachesize)
+{
+ set_error_stream(&cerr);
+ set_errpfx("MpoolExample");
+ set_cachesize(0, cachesize, 0);
+
+ open(home, DB_CREATE | DB_INIT_MPOOL, 0);
+}
+
+//
+// run --
+// Get a set of pages.
+//
+void
+MpoolExample::run(int hits, int pagesize, int npages)
+{
+ db_pgno_t pageno;
+ int cnt;
+ void *p;
+
+ // Open the file in the pool.
+ DbMpoolFile *dbmfp;
+
+ DbMpoolFile::open(this, MPOOL, 0, 0, pagesize, NULL, &dbmfp);
+
+ cout << "retrieve " << hits << " random pages... ";
+
+ srand((unsigned int)time(NULL));
+ for (cnt = 0; cnt < hits; ++cnt) {
+ pageno = (rand() % npages) + 1;
+ if ((errno = dbmfp->get(&pageno, 0, &p)) != 0) {
+ cerr << "MpoolExample: unable to retrieve page "
+ << (unsigned long)pageno << ": "
+ << strerror(errno) << "\n";
+ exit(1);
+ }
+ if (*(db_pgno_t *)p != pageno) {
+ cerr << "MpoolExample: wrong page retrieved ("
+ << (unsigned long)pageno << " != "
+ << *(int *)p << ")\n";
+ exit(1);
+ }
+ if ((errno = dbmfp->put(p, 0)) != 0) {
+ cerr << "MpoolExample: unable to return page "
+ << (unsigned long)pageno << ": "
+ << strerror(errno) << "\n";
+ exit(1);
+ }
+ }
+
+ cout << "successful.\n";
+
+ // Close the pool.
+ if ((errno = close(0)) != 0) {
+ cerr << "MpoolExample: " << strerror(errno) << "\n";
+ exit(1);
+ }
+}
diff --git a/bdb/examples_cxx/TpcbExample.cpp b/bdb/examples_cxx/TpcbExample.cpp
new file mode 100644
index 00000000000..f4ca72df8e3
--- /dev/null
+++ b/bdb/examples_cxx/TpcbExample.cpp
@@ -0,0 +1,666 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1997, 1998, 1999, 2000
+ * Sleepycat Software. All rights reserved.
+ *
+ * $Id: TpcbExample.cpp,v 11.14 2000/10/27 20:32:01 dda Exp $
+ */
+
+#include "db_config.h"
+
+#ifndef NO_SYSTEM_INCLUDES
+#include <sys/types.h>
+
+#if TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#else
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#endif
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#endif
+
+#ifdef DB_WIN32
+#include <sys/types.h>
+#include <sys/timeb.h>
+#endif
+
+#include <iostream.h>
+#include <iomanip.h>
+#include <db_cxx.h>
+
+typedef enum { ACCOUNT, BRANCH, TELLER } FTYPE;
+
+void errExit(int err, const char *); // show err as errno and exit
+
+void invarg(int, char *);
+u_int32_t random_id(FTYPE, u_int32_t, u_int32_t, u_int32_t);
+u_int32_t random_int(u_int32_t, u_int32_t);
+static void usage(void);
+
+int verbose;
+char *progname = "TpcbExample"; // Program name.
+
+class TpcbExample : public DbEnv
+{
+public:
+ void populate(int, int, int, int);
+ void run(int, int, int, int);
+ int txn(Db *, Db *, Db *, Db *,
+ int, int, int);
+ void populateHistory(Db *, int, u_int32_t, u_int32_t, u_int32_t);
+ void populateTable(Db *, u_int32_t, u_int32_t, int, char *);
+
+ // Note: the constructor creates a DbEnv(), which is
+ // not fully initialized until the DbEnv::open() method
+ // is called.
+ //
+ TpcbExample(const char *home, int cachesize,
+ int initializing, int flags);
+
+private:
+ static const char FileName[];
+
+ // no need for copy and assignment
+ TpcbExample(const TpcbExample &);
+ void operator = (const TpcbExample &);
+};
+
+//
+// This program implements a basic TPC/B driver program. To create the
+// TPC/B database, run with the -i (init) flag. The number of records
+// with which to populate the account, history, branch, and teller tables
+// is specified by the a, s, b, and t flags respectively. To run a TPC/B
+// test, use the n flag to indicate a number of transactions to run (note
+// that you can run many of these processes in parallel to simulate a
+// multiuser test run).
+//
+#define TELLERS_PER_BRANCH 100
+#define ACCOUNTS_PER_TELLER 1000
+#define HISTORY_PER_BRANCH 2592000
+
+/*
+ * The default configuration that adheres to TPCB scaling rules requires
+ * nearly 3 GB of space. To avoid requiring that much space for testing,
+ * we set the parameters much lower. If you want to run a valid 10 TPS
+ * configuration, define VALID_SCALING.
+ */
+#ifdef VALID_SCALING
+#define ACCOUNTS 1000000
+#define BRANCHES 10
+#define TELLERS 100
+#define HISTORY 25920000
+#endif
+
+#ifdef TINY
+#define ACCOUNTS 1000
+#define BRANCHES 10
+#define TELLERS 100
+#define HISTORY 10000
+#endif
+
+#if !defined(VALID_SCALING) && !defined(TINY)
+#define ACCOUNTS 100000
+#define BRANCHES 10
+#define TELLERS 100
+#define HISTORY 259200
+#endif
+
+#define HISTORY_LEN 100
+#define RECLEN 100
+#define BEGID 1000000
+
+struct Defrec {
+ u_int32_t id;
+ u_int32_t balance;
+ u_int8_t pad[RECLEN - sizeof(u_int32_t) - sizeof(u_int32_t)];
+};
+
+struct Histrec {
+ u_int32_t aid;
+ u_int32_t bid;
+ u_int32_t tid;
+ u_int32_t amount;
+ u_int8_t pad[RECLEN - 4 * sizeof(u_int32_t)];
+};
+
+int
+main(int argc, char *argv[])
+{
+ unsigned long seed;
+ int accounts, branches, tellers, history;
+ int iflag, mpool, ntxns, txn_no_sync;
+ char *home, *endarg;
+
+ home = "TESTDIR";
+ accounts = branches = history = tellers = 0;
+ txn_no_sync = 0;
+ mpool = ntxns = 0;
+ verbose = 0;
+ iflag = 0;
+ seed = (unsigned long)getpid();
+
+ for (int i = 1; i < argc; ++i) {
+
+ if (strcmp(argv[i], "-a") == 0) {
+ // Number of account records
+ if ((accounts = atoi(argv[++i])) <= 0)
+ invarg('a', argv[i]);
+ }
+ else if (strcmp(argv[i], "-b") == 0) {
+ // Number of branch records
+ if ((branches = atoi(argv[++i])) <= 0)
+ invarg('b', argv[i]);
+ }
+ else if (strcmp(argv[i], "-c") == 0) {
+ // Cachesize in bytes
+ if ((mpool = atoi(argv[++i])) <= 0)
+ invarg('c', argv[i]);
+ }
+ else if (strcmp(argv[i], "-f") == 0) {
+ // Fast mode: no txn sync.
+ txn_no_sync = 1;
+ }
+ else if (strcmp(argv[i], "-h") == 0) {
+ // DB home.
+ home = argv[++i];
+ }
+ else if (strcmp(argv[i], "-i") == 0) {
+ // Initialize the test.
+ iflag = 1;
+ }
+ else if (strcmp(argv[i], "-n") == 0) {
+ // Number of transactions
+ if ((ntxns = atoi(argv[++i])) <= 0)
+ invarg('n', argv[i]);
+ }
+ else if (strcmp(argv[i], "-S") == 0) {
+ // Random number seed.
+ seed = strtoul(argv[++i], &endarg, 0);
+ if (*endarg != '\0')
+ invarg('S', argv[i]);
+ }
+ else if (strcmp(argv[i], "-s") == 0) {
+ // Number of history records
+ if ((history = atoi(argv[++i])) <= 0)
+ invarg('s', argv[i]);
+ }
+ else if (strcmp(argv[i], "-t") == 0) {
+ // Number of teller records
+ if ((tellers = atoi(argv[++i])) <= 0)
+ invarg('t', argv[i]);
+ }
+ else if (strcmp(argv[i], "-v") == 0) {
+ // Verbose option.
+ verbose = 1;
+ }
+ else {
+ usage();
+ }
+ }
+
+ srand((unsigned int)seed);
+
+ accounts = accounts == 0 ? ACCOUNTS : accounts;
+ branches = branches == 0 ? BRANCHES : branches;
+ tellers = tellers == 0 ? TELLERS : tellers;
+ history = history == 0 ? HISTORY : history;
+
+ if (verbose)
+ cout << (long)accounts << " Accounts "
+ << (long)branches << " Branches "
+ << (long)tellers << " Tellers "
+ << (long)history << " History\n";
+
+ try {
+ // Initialize the database environment.
+ // Must be done in within a try block, unless you
+ // change the error model in the environment options.
+ //
+ TpcbExample app(home, mpool, iflag, txn_no_sync ? DB_TXN_NOSYNC : 0);
+
+ if (iflag) {
+ if (ntxns != 0)
+ usage();
+ app.populate(accounts, branches, history, tellers);
+ }
+ else {
+ if (ntxns == 0)
+ usage();
+ app.run(ntxns, accounts, branches, tellers);
+ }
+
+ app.close(0);
+ return 0;
+ }
+ catch (DbException &dbe) {
+ cerr << "TpcbExample: " << dbe.what() << "\n";
+ return 1;
+ }
+}
+
+void
+invarg(int arg, char *str)
+{
+ cerr << "TpcbExample: invalid argument for -"
+ << (char)arg << ": " << str << "\n";
+ exit(1);
+}
+
+static void
+usage()
+{
+ cerr << "usage: TpcbExample [-fiv] [-a accounts] [-b branches]\n"
+ << " [-c cachesize] [-h home] [-n transactions ]\n"
+ << " [-S seed] [-s history] [-t tellers]\n";
+ exit(1);
+}
+
+TpcbExample::TpcbExample(const char *home, int cachesize,
+ int initializing, int flags)
+: DbEnv(0)
+{
+ u_int32_t local_flags;
+
+ set_error_stream(&cerr);
+ set_errpfx("TpcbExample");
+ (void)set_cachesize(0, cachesize == 0 ?
+ 4 * 1024 * 1024 : (u_int32_t)cachesize, 0);
+
+ local_flags = flags | DB_CREATE | DB_INIT_MPOOL;
+ if (!initializing)
+ local_flags |= DB_INIT_TXN | DB_INIT_LOCK | DB_INIT_LOG;
+ open(home, local_flags, 0);
+}
+
+//
+// Initialize the database to the specified number of accounts, branches,
+// history records, and tellers.
+//
+void
+TpcbExample::populate(int accounts, int branches, int history, int tellers)
+{
+ Db *dbp;
+
+ int err;
+ u_int32_t balance, idnum;
+ u_int32_t end_anum, end_bnum, end_tnum;
+ u_int32_t start_anum, start_bnum, start_tnum;
+
+ idnum = BEGID;
+ balance = 500000;
+
+ dbp = new Db(this, 0);
+ dbp->set_h_nelem((unsigned int)accounts);
+
+ if ((err = dbp->open("account", NULL, DB_HASH,
+ DB_CREATE | DB_TRUNCATE, 0644)) != 0) {
+ errExit(err, "Open of account file failed");
+ }
+
+ start_anum = idnum;
+ populateTable(dbp, idnum, balance, accounts, "account");
+ idnum += accounts;
+ end_anum = idnum - 1;
+ if ((err = dbp->close(0)) != 0) {
+ errExit(err, "Account file close failed");
+ }
+ delete dbp;
+ if (verbose)
+ cout << "Populated accounts: "
+ << (long)start_anum << " - " << (long)end_anum << "\n";
+
+ dbp = new Db(this, 0);
+ //
+ // Since the number of branches is very small, we want to use very
+ // small pages and only 1 key per page. This is the poor-man's way
+ // of getting key locking instead of page locking.
+ //
+ dbp->set_h_ffactor(1);
+ dbp->set_h_nelem((unsigned int)branches);
+ dbp->set_pagesize(512);
+
+ if ((err = dbp->open("branch", NULL, DB_HASH,
+ DB_CREATE | DB_TRUNCATE, 0644)) != 0) {
+ errExit(err, "Branch file create failed");
+ }
+ start_bnum = idnum;
+ populateTable(dbp, idnum, balance, branches, "branch");
+ idnum += branches;
+ end_bnum = idnum - 1;
+ if ((err = dbp->close(0)) != 0) {
+ errExit(err, "Close of branch file failed");
+ }
+ delete dbp;
+
+ if (verbose)
+ cout << "Populated branches: "
+ << (long)start_bnum << " - " << (long)end_bnum << "\n";
+
+ dbp = new Db(this, 0);
+ //
+ // In the case of tellers, we also want small pages, but we'll let
+ // the fill factor dynamically adjust itself.
+ //
+ dbp->set_h_ffactor(0);
+ dbp->set_h_nelem((unsigned int)tellers);
+ dbp->set_pagesize(512);
+
+ if ((err = dbp->open("teller", NULL, DB_HASH,
+ DB_CREATE | DB_TRUNCATE, 0644)) != 0) {
+ errExit(err, "Teller file create failed");
+ }
+
+ start_tnum = idnum;
+ populateTable(dbp, idnum, balance, tellers, "teller");
+ idnum += tellers;
+ end_tnum = idnum - 1;
+ if ((err = dbp->close(0)) != 0) {
+ errExit(err, "Close of teller file failed");
+ }
+ delete dbp;
+ if (verbose)
+ cout << "Populated tellers: "
+ << (long)start_tnum << " - " << (long)end_tnum << "\n";
+
+ dbp = new Db(this, 0);
+ dbp->set_re_len(HISTORY_LEN);
+ if ((err = dbp->open("history", NULL, DB_RECNO,
+ DB_CREATE | DB_TRUNCATE, 0644)) != 0) {
+ errExit(err, "Create of history file failed");
+ }
+
+ populateHistory(dbp, history, accounts, branches, tellers);
+ if ((err = dbp->close(0)) != 0) {
+ errExit(err, "Close of history file failed");
+ }
+ delete dbp;
+}
+
+void
+TpcbExample::populateTable(Db *dbp,
+ u_int32_t start_id, u_int32_t balance,
+ int nrecs, char *msg)
+{
+ Defrec drec;
+ memset(&drec.pad[0], 1, sizeof(drec.pad));
+
+ Dbt kdbt(&drec.id, sizeof(u_int32_t));
+ Dbt ddbt(&drec, sizeof(drec));
+
+ for (int i = 0; i < nrecs; i++) {
+ drec.id = start_id + (u_int32_t)i;
+ drec.balance = balance;
+ int err;
+ if ((err =
+ dbp->put(NULL, &kdbt, &ddbt, DB_NOOVERWRITE)) != 0) {
+ cerr << "Failure initializing " << msg << " file: "
+ << strerror(err) << "\n";
+ exit(1);
+ }
+ }
+}
+
+void
+TpcbExample::populateHistory(Db *dbp, int nrecs,
+ u_int32_t accounts, u_int32_t branches, u_int32_t tellers)
+{
+ Histrec hrec;
+ memset(&hrec.pad[0], 1, sizeof(hrec.pad));
+ hrec.amount = 10;
+ db_recno_t key;
+
+ Dbt kdbt(&key, sizeof(u_int32_t));
+ Dbt ddbt(&hrec, sizeof(hrec));
+
+ for (int i = 1; i <= nrecs; i++) {
+ hrec.aid = random_id(ACCOUNT, accounts, branches, tellers);
+ hrec.bid = random_id(BRANCH, accounts, branches, tellers);
+ hrec.tid = random_id(TELLER, accounts, branches, tellers);
+
+ int err;
+ key = (db_recno_t)i;
+ if ((err = dbp->put(NULL, &kdbt, &ddbt, DB_APPEND)) != 0) {
+ errExit(err, "Failure initializing history file");
+ }
+ }
+}
+
+u_int32_t
+random_int(u_int32_t lo, u_int32_t hi)
+{
+ u_int32_t ret;
+ int t;
+
+ t = rand();
+ ret = (u_int32_t)(((double)t / ((double)(RAND_MAX) + 1)) *
+ (hi - lo + 1));
+ ret += lo;
+ return (ret);
+}
+
+u_int32_t
+random_id(FTYPE type, u_int32_t accounts, u_int32_t branches, u_int32_t tellers)
+{
+ u_int32_t min, max, num;
+
+ max = min = BEGID;
+ num = accounts;
+ switch(type) {
+ case TELLER:
+ min += branches;
+ num = tellers;
+ // Fallthrough
+ case BRANCH:
+ if (type == BRANCH)
+ num = branches;
+ min += accounts;
+ // Fallthrough
+ case ACCOUNT:
+ max = min + num - 1;
+ }
+ return (random_int(min, max));
+}
+
+void
+TpcbExample::run(int n, int accounts, int branches, int tellers)
+{
+ Db *adb, *bdb, *hdb, *tdb;
+ double gtps, itps;
+ int failed, ifailed, ret, txns;
+ time_t starttime, curtime, lasttime;
+#ifndef DB_WIN32
+ pid_t pid;
+
+ pid = getpid();
+#else
+ int pid;
+
+ pid = 0;
+#endif
+
+ //
+ // Open the database files.
+ //
+
+ int err;
+ adb = new Db(this, 0);
+ if ((err = adb->open("account", NULL, DB_UNKNOWN, 0, 0)) != 0)
+ errExit(err, "Open of account file failed");
+
+ bdb = new Db(this, 0);
+ if ((err = bdb->open("branch", NULL, DB_UNKNOWN, 0, 0)) != 0)
+ errExit(err, "Open of branch file failed");
+
+ tdb = new Db(this, 0);
+ if ((err = tdb->open("teller", NULL, DB_UNKNOWN, 0, 0)) != 0)
+ errExit(err, "Open of teller file failed");
+
+ hdb = new Db(this, 0);
+ if ((err = hdb->open("history", NULL, DB_UNKNOWN, 0, 0)) != 0)
+ errExit(err, "Open of history file failed");
+
+ txns = failed = ifailed = 0;
+ starttime = time(NULL);
+ lasttime = starttime;
+ while (n-- > 0) {
+ txns++;
+ ret = txn(adb, bdb, tdb, hdb, accounts, branches, tellers);
+ if (ret != 0) {
+ failed++;
+ ifailed++;
+ }
+ if (n % 5000 == 0) {
+ curtime = time(NULL);
+ gtps = (double)(txns - failed) / (curtime - starttime);
+ itps = (double)(5000 - ifailed) / (curtime - lasttime);
+
+ // We use printf because it provides much simpler
+ // formatting than iostreams.
+ //
+ printf("[%d] %d txns %d failed ", (int)pid,
+ txns, failed);
+ printf("%6.2f TPS (gross) %6.2f TPS (interval)\n",
+ gtps, itps);
+ lasttime = curtime;
+ ifailed = 0;
+ }
+ }
+
+ (void)adb->close(0);
+ (void)bdb->close(0);
+ (void)tdb->close(0);
+ (void)hdb->close(0);
+
+ cout << (long)txns << " transactions begun "
+ << (long)failed << " failed\n";
+}
+
+//
+// XXX Figure out the appropriate way to pick out IDs.
+//
+int
+TpcbExample::txn(Db *adb, Db *bdb, Db *tdb, Db *hdb,
+ int accounts, int branches, int tellers)
+{
+ Dbc *acurs = NULL;
+ Dbc *bcurs = NULL;
+ Dbc *tcurs = NULL;
+ DbTxn *t = NULL;
+
+ db_recno_t key;
+ Defrec rec;
+ Histrec hrec;
+ int account, branch, teller;
+
+ Dbt d_dbt;
+ Dbt d_histdbt;
+ Dbt k_dbt;
+ Dbt k_histdbt(&key, sizeof(key));
+
+ //
+ // XXX We could move a lot of this into the driver to make this
+ // faster.
+ //
+ account = random_id(ACCOUNT, accounts, branches, tellers);
+ branch = random_id(BRANCH, accounts, branches, tellers);
+ teller = random_id(TELLER, accounts, branches, tellers);
+
+ k_dbt.set_size(sizeof(int));
+
+ d_dbt.set_flags(DB_DBT_USERMEM);
+ d_dbt.set_data(&rec);
+ d_dbt.set_ulen(sizeof(rec));
+
+ hrec.aid = account;
+ hrec.bid = branch;
+ hrec.tid = teller;
+ hrec.amount = 10;
+ // Request 0 bytes since we're just positioning.
+ d_histdbt.set_flags(DB_DBT_PARTIAL);
+
+ // START TIMING
+ if (txn_begin(NULL, &t, 0) != 0)
+ goto err;
+
+ if (adb->cursor(t, &acurs, 0) != 0 ||
+ bdb->cursor(t, &bcurs, 0) != 0 ||
+ tdb->cursor(t, &tcurs, 0) != 0)
+ goto err;
+
+ // Account record
+ k_dbt.set_data(&account);
+ if (acurs->get(&k_dbt, &d_dbt, DB_SET) != 0)
+ goto err;
+ rec.balance += 10;
+ if (acurs->put(&k_dbt, &d_dbt, DB_CURRENT) != 0)
+ goto err;
+
+ // Branch record
+ k_dbt.set_data(&branch);
+ if (bcurs->get(&k_dbt, &d_dbt, DB_SET) != 0)
+ goto err;
+ rec.balance += 10;
+ if (bcurs->put(&k_dbt, &d_dbt, DB_CURRENT) != 0)
+ goto err;
+
+ // Teller record
+ k_dbt.set_data(&teller);
+ if (tcurs->get(&k_dbt, &d_dbt, DB_SET) != 0)
+ goto err;
+ rec.balance += 10;
+ if (tcurs->put(&k_dbt, &d_dbt, DB_CURRENT) != 0)
+ goto err;
+
+ // History record
+ d_histdbt.set_flags(0);
+ d_histdbt.set_data(&hrec);
+ d_histdbt.set_ulen(sizeof(hrec));
+ if (hdb->put(t, &k_histdbt, &d_histdbt, DB_APPEND) != 0)
+ goto err;
+
+ if (acurs->close() != 0 || bcurs->close() != 0 ||
+ tcurs->close() != 0)
+ goto err;
+
+ if (t->commit(0) != 0)
+ goto err;
+
+ // END TIMING
+ return (0);
+
+err:
+ if (acurs != NULL)
+ (void)acurs->close();
+ if (bcurs != NULL)
+ (void)bcurs->close();
+ if (tcurs != NULL)
+ (void)tcurs->close();
+ if (t != NULL)
+ (void)t->abort();
+
+ if (verbose)
+ cout << "Transaction A=" << (long)account
+ << " B=" << (long)branch
+ << " T=" << (long)teller << " failed\n";
+ return (-1);
+}
+
+void errExit(int err, const char *s)
+{
+ cerr << progname << ": ";
+ if (s != NULL) {
+ cerr << s << ": ";
+ }
+ cerr << strerror(err) << "\n";
+ exit(1);
+}