summaryrefslogtreecommitdiff
path: root/db/examples_c
diff options
context:
space:
mode:
authorjbj <devnull@localhost>2001-03-21 18:33:35 +0000
committerjbj <devnull@localhost>2001-03-21 18:33:35 +0000
commit731946f4b90eb1173452dd30f1296dd825155d82 (patch)
tree67535f54ecb7e5463c06e62044e4efd84ae0291d /db/examples_c
parent7ed904da030dc4640ff9bce8458ba07cc09d830d (diff)
downloadlibrpm-tizen-731946f4b90eb1173452dd30f1296dd825155d82.tar.gz
librpm-tizen-731946f4b90eb1173452dd30f1296dd825155d82.tar.bz2
librpm-tizen-731946f4b90eb1173452dd30f1296dd825155d82.zip
Initial revision
CVS patchset: 4644 CVS date: 2001/03/21 18:33:35
Diffstat (limited to 'db/examples_c')
-rw-r--r--db/examples_c/README23
-rw-r--r--db/examples_c/ex_access.c171
-rw-r--r--db/examples_c/ex_btrec.c241
-rw-r--r--db/examples_c/ex_dbclient.c248
-rw-r--r--db/examples_c/ex_env.c170
-rw-r--r--db/examples_c/ex_lock.c235
-rw-r--r--db/examples_c/ex_mpool.c280
-rw-r--r--db/examples_c/ex_thread.c604
-rw-r--r--db/examples_c/ex_tpcb.c811
-rw-r--r--db/examples_c/ex_tpcb.h39
10 files changed, 2822 insertions, 0 deletions
diff --git a/db/examples_c/README b/db/examples_c/README
new file mode 100644
index 000000000..f59ae00a6
--- /dev/null
+++ b/db/examples_c/README
@@ -0,0 +1,23 @@
+# $Id: README,v 11.3 2000/12/13 06:32:29 krinsky Exp $
+
+ex_access.c Using just the DB access methods.
+
+ex_btrec.c Using the BTREE access method with record numbers.
+
+ex_env.c Setting up the DB environment.
+
+ex_lock.c Locking.
+
+ex_mpool.c Shared memory buffer pools.
+
+ex_tpcb.c TPC/B.
+ Ex_tpcb sets up a framework in which to run a TPC/B test.
+ Database initialization (the -i flag) and running the
+ benchmark (-n flag) must take place separately (i.e.,
+ first create the database, then run 1 or more copies of
+ the benchmark). Furthermore, when running more than one
+ TPCB process, it is necessary to run the deadlock detector
+ (db_deadlock), since it is possible for concurrent tpcb
+ processes to deadlock. For performance measurement, it
+ will also be beneficial to run the db_checkpoint process
+ as well.
diff --git a/db/examples_c/ex_access.c b/db/examples_c/ex_access.c
new file mode 100644
index 000000000..3448daf43
--- /dev/null
+++ b/db/examples_c/ex_access.c
@@ -0,0 +1,171 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1997, 1998, 1999, 2000
+ * Sleepycat Software. All rights reserved.
+ *
+ * $Id: ex_access.c,v 11.7 2000/05/22 15:17:03 sue Exp $
+ */
+
+#include "db_config.h"
+
+#ifndef NO_SYSTEM_INCLUDES
+#include <sys/types.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#endif
+
+#include <db.h>
+
+#ifdef HAVE_VXWORKS
+#include "stdio.h"
+#define DATABASE "/vxtmp/vxtmp/access.db"
+#define ERROR_RETURN ERROR
+#else
+#define DATABASE "access.db"
+#define ERROR_RETURN 1
+int main __P((int, char *[]));
+void usage __P((char *));
+#endif
+
+int ex_access __P((void));
+
+#ifndef HAVE_VXWORKS
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern char *optarg;
+ extern int optind;
+ int ch;
+
+ while ((ch = getopt(argc, argv, "")) != EOF)
+ switch (ch) {
+ case '?':
+ default:
+ usage(argv[0]);
+ }
+ argc -= optind;
+ argv += optind;
+
+ return (ex_access());
+}
+
+void
+usage(progname)
+ char *progname;
+{
+ (void)fprintf(stderr, "usage: %s\n", progname);
+ exit(1);
+}
+#endif
+
+int
+ex_access()
+{
+ DB *dbp;
+ DBC *dbcp;
+ DBT key, data;
+ u_int32_t len;
+ int ret;
+ char *p, *t, buf[1024], rbuf[1024];
+ const char *progname = "ex_access"; /* Program name. */
+
+ /* Remove the previous database. */
+ (void)unlink(DATABASE);
+
+ /* Create and initialize database object, open the database. */
+ if ((ret = db_create(&dbp, NULL, 0)) != 0) {
+ fprintf(stderr,
+ "%s: db_create: %s\n", progname, db_strerror(ret));
+ return (ERROR_RETURN);
+ }
+ dbp->set_errfile(dbp, stderr);
+ dbp->set_errpfx(dbp, progname);
+ if ((ret = dbp->set_pagesize(dbp, 1024)) != 0) {
+ dbp->err(dbp, ret, "set_pagesize");
+ goto err1;
+ }
+ if ((ret = dbp->set_cachesize(dbp, 0, 32 * 1024, 0)) != 0) {
+ dbp->err(dbp, ret, "set_cachesize");
+ goto err1;
+ }
+ if ((ret =
+ dbp->open(dbp, DATABASE, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) {
+ dbp->err(dbp, ret, "%s: open", DATABASE);
+ goto err1;
+ }
+
+ /*
+ * Insert records into the database, where the key is the user
+ * input and the data is the user input in reverse order.
+ */
+ memset(&key, 0, sizeof(DBT));
+ memset(&data, 0, sizeof(DBT));
+ for (;;) {
+ printf("input> ");
+ fflush(stdout);
+ if (fgets(buf, sizeof(buf), stdin) == NULL)
+ break;
+ if ((len = strlen(buf)) <= 1)
+ continue;
+ for (t = rbuf, p = buf + (len - 2); p >= buf;)
+ *t++ = *p--;
+ *t++ = '\0';
+
+ key.data = buf;
+ data.data = rbuf;
+ data.size = key.size = len - 1;
+
+ switch (ret =
+ dbp->put(dbp, NULL, &key, &data, DB_NOOVERWRITE)) {
+ case 0:
+ break;
+ default:
+ dbp->err(dbp, ret, "DB->put");
+ if (ret != DB_KEYEXIST)
+ goto err1;
+ break;
+ }
+ }
+ printf("\n");
+
+ /* Acquire a cursor for the database. */
+ if ((ret = dbp->cursor(dbp, NULL, &dbcp, 0)) != 0) {
+ dbp->err(dbp, ret, "DB->cursor");
+ goto err1;
+ }
+
+ /* Initialize the key/data pair so the flags aren't set. */
+ memset(&key, 0, sizeof(key));
+ memset(&data, 0, sizeof(data));
+
+ /* Walk through the database and print out the key/data pairs. */
+ while ((ret = dbcp->c_get(dbcp, &key, &data, DB_NEXT)) == 0)
+ printf("%.*s : %.*s\n",
+ (int)key.size, (char *)key.data,
+ (int)data.size, (char *)data.data);
+ if (ret != DB_NOTFOUND) {
+ dbp->err(dbp, ret, "DBcursor->get");
+ goto err2;
+ }
+
+ /* Close everything down. */
+ if ((ret = dbcp->c_close(dbcp)) != 0) {
+ dbp->err(dbp, ret, "DBcursor->close");
+ goto err1;
+ }
+ if ((ret = dbp->close(dbp, 0)) != 0) {
+ fprintf(stderr,
+ "%s: DB->close: %s\n", progname, db_strerror(ret));
+ return (ERROR_RETURN);
+ }
+ return (0);
+
+err2: (void)dbcp->c_close(dbcp);
+err1: (void)dbp->close(dbp, 0);
+ return (ERROR_RETURN);
+}
diff --git a/db/examples_c/ex_btrec.c b/db/examples_c/ex_btrec.c
new file mode 100644
index 000000000..b74f16b83
--- /dev/null
+++ b/db/examples_c/ex_btrec.c
@@ -0,0 +1,241 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1997, 1998, 1999, 2000
+ * Sleepycat Software. All rights reserved.
+ *
+ * $Id: ex_btrec.c,v 11.8 2000/05/22 15:17:03 sue Exp $
+ */
+
+#include "db_config.h"
+
+#ifndef NO_SYSTEM_INCLUDES
+#include <sys/types.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#endif
+
+#include <db.h>
+
+#ifdef HAVE_VXWORKS
+#define DATABASE "/vxtmp/vxtmp/access.db"
+#define WORDLIST "/vxtmp/vxtmp/wordlist"
+#define ERROR_RETURN ERROR
+#else
+#define DATABASE "access.db"
+#define WORDLIST "../test/wordlist"
+#define ERROR_RETURN 1
+int main __P((int, char *[]));
+void usage __P((char *));
+#endif
+
+int ex_btrec __P((void));
+void show __P((char *, DBT *, DBT *));
+
+#ifndef HAVE_VXWORKS
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern char *optarg;
+ extern int optind;
+ int ch;
+
+ while ((ch = getopt(argc, argv, "")) != EOF)
+ switch (ch) {
+ case '?':
+ default:
+ usage(argv[0]);
+ }
+ argc -= optind;
+ argv += optind;
+
+ return (ex_btrec());
+}
+
+void
+usage(progname)
+ char *progname;
+{
+ (void)fprintf(stderr, "usage: %s\n", progname);
+ exit(1);
+}
+#endif
+
+int
+ex_btrec()
+{
+ DB *dbp;
+ DBC *dbcp;
+ DBT key, data;
+ DB_BTREE_STAT *statp;
+ FILE *fp;
+ db_recno_t recno;
+ u_int32_t len;
+ int cnt, ret;
+ char *p, *t, buf[1024], rbuf[1024];
+ const char *progname = "ex_btrec"; /* Program name. */
+
+ /* Open the word database. */
+ if ((fp = fopen(WORDLIST, "r")) == NULL) {
+ fprintf(stderr, "%s: open %s: %s\n",
+ progname, WORDLIST, db_strerror(errno));
+ return (ERROR_RETURN);
+ }
+
+ /* Remove the previous database. */
+ (void)unlink(DATABASE);
+
+ /* Create and initialize database object, open the database. */
+ if ((ret = db_create(&dbp, NULL, 0)) != 0) {
+ fprintf(stderr,
+ "%s: db_create: %s\n", progname, db_strerror(ret));
+ return (ERROR_RETURN);
+ }
+ dbp->set_errfile(dbp, stderr);
+ dbp->set_errpfx(dbp, progname); /* 1K page sizes. */
+ if ((ret = dbp->set_pagesize(dbp, 1024)) != 0) {
+ dbp->err(dbp, ret, "set_pagesize");
+ return (ERROR_RETURN);
+ } /* Record numbers. */
+ if ((ret = dbp->set_flags(dbp, DB_RECNUM)) != 0) {
+ dbp->err(dbp, ret, "set_flags: DB_RECNUM");
+ return (ERROR_RETURN);
+ }
+ if ((ret =
+ dbp->open(dbp, DATABASE, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) {
+ dbp->err(dbp, ret, "open: %s", DATABASE);
+ return (ERROR_RETURN);
+ }
+
+ /*
+ * 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.
+ */
+ memset(&key, 0, sizeof(DBT));
+ memset(&data, 0, sizeof(DBT));
+ for (cnt = 1; cnt <= 1000; ++cnt) {
+ (void)sprintf(buf, "%04d_", cnt);
+ if (fgets(buf + 4, sizeof(buf) - 4, fp) == NULL)
+ break;
+ len = strlen(buf);
+ for (t = rbuf, p = buf + (len - 2); p >= buf;)
+ *t++ = *p--;
+ *t++ = '\0';
+
+ key.data = buf;
+ data.data = rbuf;
+ data.size = key.size = len - 1;
+
+ if ((ret =
+ dbp->put(dbp, NULL, &key, &data, DB_NOOVERWRITE)) != 0) {
+ dbp->err(dbp, ret, "DB->put");
+ if (ret != DB_KEYEXIST)
+ goto err1;
+ }
+ }
+
+ /* Close the word database. */
+ (void)fclose(fp);
+
+ /* Print out the number of records in the database. */
+ if ((ret = dbp->stat(dbp, &statp, NULL, 0)) != 0) {
+ dbp->err(dbp, ret, "DB->stat");
+ goto err1;
+ }
+ printf("%s: database contains %lu records\n",
+ progname, (u_long)statp->bt_ndata);
+ free(statp);
+
+ /* Acquire a cursor for the database. */
+ if ((ret = dbp->cursor(dbp, NULL, &dbcp, 0)) != 0) {
+ dbp->err(dbp, ret, "DB->cursor");
+ goto err1;
+ }
+
+ /*
+ * Prompt the user for a record number, then retrieve and display
+ * that record.
+ */
+ for (;;) {
+ /* Get a record number. */
+ printf("recno #> ");
+ fflush(stdout);
+ if (fgets(buf, sizeof(buf), stdin) == NULL)
+ break;
+ recno = atoi(buf);
+
+ /*
+ * Reset the key each time, the dbp->c_get() routine returns
+ * the key and data pair, not just the key!
+ */
+ key.data = &recno;
+ key.size = sizeof(recno);
+ if ((ret = dbcp->c_get(dbcp, &key, &data, DB_SET_RECNO)) != 0)
+ goto get_err;
+
+ /* Display the key and data. */
+ show("k/d\t", &key, &data);
+
+ /* Move the cursor a record forward. */
+ if ((ret = dbcp->c_get(dbcp, &key, &data, DB_NEXT)) != 0)
+ goto get_err;
+
+ /* Display the key and data. */
+ show("next\t", &key, &data);
+
+ /*
+ * Retrieve the record number for the following record into
+ * local memory.
+ */
+ data.data = &recno;
+ data.size = sizeof(recno);
+ data.ulen = sizeof(recno);
+ data.flags |= DB_DBT_USERMEM;
+ if ((ret = dbcp->c_get(dbcp, &key, &data, DB_GET_RECNO)) != 0) {
+get_err: dbp->err(dbp, ret, "DBcursor->get");
+ if (ret != DB_NOTFOUND && ret != DB_KEYEMPTY)
+ goto err2;
+ } else
+ printf("retrieved recno: %lu\n", (u_long)recno);
+
+ /* Reset the data DBT. */
+ memset(&data, 0, sizeof(data));
+ }
+
+ if ((ret = dbcp->c_close(dbcp)) != 0) {
+ dbp->err(dbp, ret, "DBcursor->close");
+ goto err1;
+ }
+ if ((ret = dbp->close(dbp, 0)) != 0) {
+ fprintf(stderr,
+ "%s: DB->close: %s\n", progname, db_strerror(ret));
+ return (ERROR_RETURN);
+ }
+
+ return (0);
+
+err2: (void)dbcp->c_close(dbcp);
+err1: (void)dbp->close(dbp, 0);
+ return (ret);
+
+}
+
+/*
+ * show --
+ * Display a key/data pair.
+ */
+void
+show(msg, key, data)
+ DBT *key, *data;
+ char *msg;
+{
+ printf("%s%.*s : %.*s\n", msg,
+ (int)key->size, (char *)key->data,
+ (int)data->size, (char *)data->data);
+}
diff --git a/db/examples_c/ex_dbclient.c b/db/examples_c/ex_dbclient.c
new file mode 100644
index 000000000..27461a892
--- /dev/null
+++ b/db/examples_c/ex_dbclient.c
@@ -0,0 +1,248 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1996, 1997, 1998, 1999, 2000
+ * Sleepycat Software. All rights reserved.
+ *
+ * $Id: ex_dbclient.c,v 1.12 2000/10/26 14:13:05 bostic Exp $
+ */
+
+#include "db_config.h"
+
+#ifndef NO_SYSTEM_INCLUDES
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#endif
+
+#include <db.h>
+
+#define DATABASE_HOME "database"
+
+#define DATABASE "access.db"
+
+int db_clientrun __P((DB_ENV *, char *));
+int ex_dbclient_run __P((char *, FILE *, char *, char *));
+#ifdef HAVE_VXWORKS
+int ex_dbclient __P((char *));
+#define ERROR_RETURN ERROR
+#define VXSHM_KEY 10
+#else
+int main __P((int, char *[]));
+#define ERROR_RETURN 1
+#endif
+
+/*
+ * An example of a program creating/configuring a Berkeley DB environment.
+ */
+#ifndef HAVE_VXWORKS
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ char *home;
+ int ret;
+
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s hostname\n",argv[0]);
+ exit(1);
+ }
+ /*
+ * All of the shared database files live in DATABASE_HOME, but
+ * data files will live in CONFIG_DATA_DIR.
+ */
+ home = DATABASE_HOME;
+
+ if ((ret = ex_dbclient_run(home, stderr, argv[1], argv[0])) != 0)
+ return (ret);
+
+ return (0);
+}
+#endif
+
+int
+ex_dbclient(host)
+ char *host;
+{
+ char *home;
+ char *progname = "ex_dbclient"; /* Program name. */
+ int ret;
+
+ /*
+ * All of the shared database files live in DATABASE_HOME, but
+ * data files will live in CONFIG_DATA_DIR.
+ */
+ home = DATABASE_HOME;
+
+ if ((ret = ex_dbclient_run(home, stderr, host, progname)) != 0)
+ return (ret);
+
+ return (0);
+}
+
+int
+ex_dbclient_run(home, errfp, host, progname)
+ char *home, *host, *progname;
+ FILE *errfp;
+{
+ DB_ENV *dbenv;
+ int ret, retry;
+
+ /*
+ * Create an environment object and initialize it for error
+ * reporting.
+ */
+ if ((ret = db_env_create(&dbenv, DB_CLIENT)) != 0) {
+ fprintf(errfp, "%s: %s\n", progname, db_strerror(ret));
+ return (ERROR_RETURN);
+ }
+#ifdef HAVE_VXWORKS
+ if ((ret = dbenv->set_shm_key(dbenv, VXSHM_KEY)) != 0) {
+ fprintf(errfp, "%s: %s\n", progname, db_strerror(ret));
+ return (ERROR_RETURN);
+ }
+#endif
+ retry = 0;
+retry:
+ while (retry < 5) {
+ /*
+ * Set the server host we are talking to.
+ */
+ if ((ret =
+ dbenv->set_server(dbenv, host, 10000, 10000, 0)) != 0) {
+ fprintf(stderr, "Try %d: DBENV->set_server: %s\n",
+ retry, db_strerror(ret));
+ retry++;
+ if ((ret = __os_sleep(dbenv, 15, 0)) != 0)
+ return (ret);
+ } else
+ break;
+ }
+
+ if (retry >= 5) {
+ fprintf(stderr, "DBENV->set_server: %s\n", db_strerror(ret));
+ dbenv->close(dbenv, 0);
+ return (ERROR_RETURN);
+ }
+ /*
+ * We want to specify the shared memory buffer pool cachesize,
+ * but everything else is the default.
+ */
+ if ((ret = dbenv->set_cachesize(dbenv, 0, 64 * 1024, 0)) != 0) {
+ dbenv->err(dbenv, ret, "set_cachesize");
+ dbenv->close(dbenv, 0);
+ return (ERROR_RETURN);
+ }
+ /*
+ * We have multiple processes reading/writing these files, so
+ * we need concurrency control and a shared buffer pool, but
+ * not logging or transactions.
+ */
+ if ((ret = dbenv->open(dbenv, home,
+ DB_CREATE | DB_INIT_LOCK | DB_INIT_MPOOL | DB_INIT_TXN, 0)) != 0) {
+ dbenv->err(dbenv, ret, "environment open: %s", home);
+ dbenv->close(dbenv, 0);
+ if (ret == DB_NOSERVER)
+ goto retry;
+ return (ERROR_RETURN);
+ }
+
+ ret = db_clientrun(dbenv, progname);
+ printf("db_clientrun returned %d\n", ret);
+ if (ret == DB_NOSERVER)
+ goto retry;
+
+ /* Close the handle. */
+ if ((ret = dbenv->close(dbenv, 0)) != 0) {
+ fprintf(stderr, "DBENV->close: %s\n", db_strerror(ret));
+ return (ERROR_RETURN);
+ }
+ return (0);
+}
+
+int
+db_clientrun(dbenv, progname)
+ DB_ENV *dbenv;
+ char *progname;
+{
+ DB *dbp;
+ DBT key, data;
+ u_int32_t len;
+ int ret;
+ char *p, *t, buf[1024], rbuf[1024];
+
+ /* Remove the previous database. */
+
+ /* Create and initialize database object, open the database. */
+ if ((ret = db_create(&dbp, dbenv, 0)) != 0) {
+ fprintf(stderr,
+ "%s: db_create: %s\n", progname, db_strerror(ret));
+ return (ret);
+ }
+ if ((ret = dbp->set_pagesize(dbp, 1024)) != 0) {
+ dbp->err(dbp, ret, "set_pagesize");
+ goto err1;
+ }
+ if ((ret =
+ dbp->open(dbp, DATABASE, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) {
+ dbp->err(dbp, ret, "%s: open", DATABASE);
+ goto err1;
+ }
+
+ /*
+ * Insert records into the database, where the key is the user
+ * input and the data is the user input in reverse order.
+ */
+ memset(&key, 0, sizeof(DBT));
+ memset(&data, 0, sizeof(DBT));
+ for (;;) {
+ printf("input> ");
+ fflush(stdout);
+ if (fgets(buf, sizeof(buf), stdin) == NULL)
+ break;
+ if ((len = strlen(buf)) <= 1)
+ continue;
+ for (t = rbuf, p = buf + (len - 2); p >= buf;)
+ *t++ = *p--;
+ *t++ = '\0';
+
+ key.data = buf;
+ data.data = rbuf;
+ data.size = key.size = len - 1;
+
+ switch (ret =
+ dbp->put(dbp, NULL, &key, &data, DB_NOOVERWRITE)) {
+ case 0:
+ break;
+ default:
+ dbp->err(dbp, ret, "DB->put");
+ if (ret != DB_KEYEXIST)
+ goto err1;
+ break;
+ }
+ memset(&data, 0, sizeof(DBT));
+ switch (ret = dbp->get(dbp, NULL, &key, &data, 0)) {
+ case 0:
+ printf("%.*s : %.*s\n",
+ (int)key.size, (char *)key.data,
+ (int)data.size, (char *)data.data);
+ break;
+ default:
+ dbp->err(dbp, ret, "DB->get");
+ break;
+ }
+ }
+ if ((ret = dbp->close(dbp, 0)) != 0) {
+ fprintf(stderr,
+ "%s: DB->close: %s\n", progname, db_strerror(ret));
+ return (1);
+ }
+ return (0);
+
+err1: (void)dbp->close(dbp, 0);
+ return (ret);
+}
diff --git a/db/examples_c/ex_env.c b/db/examples_c/ex_env.c
new file mode 100644
index 000000000..5490723a3
--- /dev/null
+++ b/db/examples_c/ex_env.c
@@ -0,0 +1,170 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1996, 1997, 1998, 1999, 2000
+ * Sleepycat Software. All rights reserved.
+ *
+ * $Id: ex_env.c,v 11.18 2000/10/27 20:32:00 dda Exp $
+ */
+
+#include "db_config.h"
+
+#ifndef NO_SYSTEM_INCLUDES
+#include <sys/types.h>
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#endif
+
+#include <db.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
+#ifdef HAVE_VXWORKS
+#define DATABASE_HOME "/ata0/vxtmp/database"
+#define CONFIG_DATA_DIR "/vxtmp/vxtmp/database/files"
+#else
+#define DATABASE_HOME "/tmp/database"
+#define CONFIG_DATA_DIR "/database/files"
+#endif
+#endif
+#endif
+
+int db_setup __P((char *, char *, FILE *, char *));
+int db_teardown __P((char *, char *, FILE *, char *));
+#ifdef HAVE_VXWORKS
+int ex_env __P((void));
+#define ERROR_RETURN ERROR
+#define VXSHM_KEY 11
+#else
+int main __P((void));
+#define ERROR_RETURN 1
+#endif
+
+/*
+ * An example of a program creating/configuring a Berkeley DB environment.
+ */
+int
+#ifdef HAVE_VXWORKS
+ex_env()
+#else
+main()
+#endif
+{
+ int ret;
+ char *data_dir, *home;
+ char *progname = "ex_env"; /* Program name. */
+
+ /*
+ * All of the shared database files live in DATABASE_HOME, but
+ * data files will live in CONFIG_DATA_DIR.
+ */
+ home = DATABASE_HOME;
+ data_dir = CONFIG_DATA_DIR;
+
+ printf("Setup env\n");
+ if ((ret = db_setup(home, data_dir, stderr, progname)) != 0)
+ return (ret);
+
+ printf("Teardown env\n");
+ if ((ret = db_teardown(home, data_dir, stderr, progname)) != 0)
+ return (ret);
+
+ return (0);
+}
+
+int
+db_setup(home, data_dir, errfp, progname)
+ char *home, *data_dir, *progname;
+ FILE *errfp;
+{
+ DB_ENV *dbenv;
+ int ret;
+
+ /*
+ * Create an environment object and initialize it for error
+ * reporting.
+ */
+ if ((ret = db_env_create(&dbenv, 0)) != 0) {
+ fprintf(errfp, "%s: %s\n", progname, db_strerror(ret));
+ return (ERROR_RETURN);
+ }
+ dbenv->set_errfile(dbenv, errfp);
+ dbenv->set_errpfx(dbenv, progname);
+
+#ifdef HAVE_VXWORKS
+ /* VxWorks needs to specify a base segment ID. */
+ if ((ret = dbenv->set_shm_key(dbenv, VXSHM_KEY)) != 0) {
+ fprintf(errfp, "%s: %s\n", progname, db_strerror(ret));
+ return (ERROR_RETURN);
+ }
+#endif
+
+ /*
+ * We want to specify the shared memory buffer pool cachesize,
+ * but everything else is the default.
+ */
+ if ((ret = dbenv->set_cachesize(dbenv, 0, 64 * 1024, 0)) != 0) {
+ dbenv->err(dbenv, ret, "set_cachesize");
+ dbenv->close(dbenv, 0);
+ return (ERROR_RETURN);
+ }
+
+ /* Databases are in a subdirectory. */
+ (void)dbenv->set_data_dir(dbenv, data_dir);
+
+ /* Open the environment with full transactional support. */
+ if ((ret = dbenv->open(dbenv, home,
+ DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN,
+ 0)) != 0) {
+ dbenv->err(dbenv, ret, "environment open: %s", home);
+ dbenv->close(dbenv, 0);
+ return (ERROR_RETURN);
+ }
+
+ /* Do something interesting... */
+
+ /* Close the handle. */
+ if ((ret = dbenv->close(dbenv, 0)) != 0) {
+ fprintf(stderr, "DBENV->close: %s\n", db_strerror(ret));
+ return (ERROR_RETURN);
+ }
+ return (0);
+}
+
+int
+db_teardown(home, data_dir, errfp, progname)
+ char *home, *data_dir, *progname;
+ FILE *errfp;
+{
+ DB_ENV *dbenv;
+ int ret;
+
+ /* Remove the shared database regions. */
+ if ((ret = db_env_create(&dbenv, 0)) != 0) {
+ fprintf(errfp, "%s: %s\n", progname, db_strerror(ret));
+ return (ERROR_RETURN);
+ }
+ dbenv->set_errfile(dbenv, errfp);
+ dbenv->set_errpfx(dbenv, progname);
+#ifdef HAVE_VXWORKS
+ if ((ret = dbenv->set_shm_key(dbenv, VXSHM_KEY)) != 0) {
+ fprintf(errfp, "%s: %s\n", progname, db_strerror(ret));
+ return (ERROR_RETURN);
+ }
+#endif
+
+ (void)dbenv->set_data_dir(dbenv, data_dir);
+ if ((ret = dbenv->remove(dbenv, home, 0)) != 0) {
+ fprintf(stderr, "DBENV->remove: %s\n", db_strerror(ret));
+ return (ERROR_RETURN);
+ }
+ return (0);
+}
diff --git a/db/examples_c/ex_lock.c b/db/examples_c/ex_lock.c
new file mode 100644
index 000000000..e858be6b3
--- /dev/null
+++ b/db/examples_c/ex_lock.c
@@ -0,0 +1,235 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1997, 1998, 1999, 2000
+ * Sleepycat Software. All rights reserved.
+ *
+ * $Id: ex_lock.c,v 11.6 2001/01/04 14:23:29 dda Exp $
+ */
+
+#include "db_config.h"
+
+#ifndef NO_SYSTEM_INCLUDES
+#include <sys/types.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#endif
+
+#include <db.h>
+
+void db_init __P((char *, u_int32_t, int));
+int main __P((int, char *[]));
+void usage __P((void));
+
+DB_ENV *dbenv;
+const char
+ *progname = "ex_lock"; /* Program name. */
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern char *optarg;
+ extern int optind;
+ DBT lock_dbt;
+ DB_LOCK lock;
+ DB_LOCK *locks;
+ db_lockmode_t lock_type;
+ long held;
+ u_int32_t len, locker, maxlocks;
+ int ch, do_unlink, did_get, i, lockid, lockcount, ret;
+ char *home, opbuf[16], objbuf[1024], lockbuf[16];
+
+ home = "TESTDIR";
+ maxlocks = 0;
+ do_unlink = 0;
+ while ((ch = getopt(argc, argv, "h:m:u")) != EOF)
+ switch (ch) {
+ case 'h':
+ home = optarg;
+ break;
+ case 'm':
+ if ((i = atoi(optarg)) <= 0)
+ usage();
+ maxlocks = (u_int32_t)i; /* XXX: possible overflow. */
+ break;
+ case 'u':
+ do_unlink = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 0)
+ usage();
+
+ /* Initialize the database environment. */
+ db_init(home, maxlocks, do_unlink);
+
+ locks = 0;
+ lockcount = 0;
+
+ /*
+ * Accept lock requests.
+ */
+ if ((ret = lock_id(dbenv, &locker)) != 0) {
+ dbenv->err(dbenv, ret, "unable to get locker id");
+ (void)dbenv->close(dbenv, 0);
+ exit (1);
+ }
+ lockid = -1;
+
+ memset(&lock_dbt, 0, sizeof(lock_dbt));
+ for (held = 0, did_get = 0;;) {
+ printf("Operation get/release [get]> ");
+ fflush(stdout);
+ if (fgets(opbuf, sizeof(opbuf), stdin) == NULL)
+ break;
+ if ((len = strlen(opbuf)) <= 1 || strcmp(opbuf, "get\n") == 0) {
+ /* Acquire a lock. */
+ printf("input object (text string) to lock> ");
+ fflush(stdout);
+ if (fgets(objbuf, sizeof(objbuf), stdin) == NULL)
+ break;
+ if ((len = strlen(objbuf)) <= 1)
+ continue;
+
+ do {
+ printf("lock type read/write [read]> ");
+ fflush(stdout);
+ if (fgets(lockbuf,
+ sizeof(lockbuf), stdin) == NULL)
+ break;
+ len = strlen(lockbuf);
+ } while (len > 1 &&
+ strcmp(lockbuf, "read\n") != 0 &&
+ strcmp(lockbuf, "write\n") != 0);
+ if (len == 1 || strcmp(lockbuf, "read\n") == 0)
+ lock_type = DB_LOCK_READ;
+ else
+ lock_type = DB_LOCK_WRITE;
+
+ lock_dbt.data = objbuf;
+ lock_dbt.size = strlen(objbuf);
+ ret = lock_get(dbenv, locker,
+ DB_LOCK_NOWAIT, &lock_dbt, lock_type, &lock);
+ if (ret == 0) {
+ did_get = 1;
+ lockid = lockcount++;
+ if (locks == NULL)
+ locks =
+ (DB_LOCK *)malloc(sizeof(DB_LOCK));
+ else
+ locks = (DB_LOCK *)realloc(locks,
+ lockcount * sizeof(DB_LOCK));
+ locks[lockid] = lock;
+ }
+ } else {
+ /* Release a lock. */
+ do {
+ printf("input lock to release> ");
+ fflush(stdout);
+ if (fgets(objbuf,
+ sizeof(objbuf), stdin) == NULL)
+ break;
+ } while ((len = strlen(objbuf)) <= 1);
+ lockid = strtol(objbuf, NULL, 16);
+ if (lockid < 0 || lockid >= lockcount) {
+ printf("Lock #%d out of range\n", lockid);
+ continue;
+ }
+ lock = locks[lockid];
+ ret = lock_put(dbenv, &lock);
+ did_get = 0;
+ }
+ switch (ret) {
+ case 0:
+ printf("Lock #%d %s\n", lockid,
+ did_get ? "granted" : "released");
+ held += did_get ? 1 : -1;
+ break;
+ case DB_LOCK_NOTGRANTED:
+ dbenv->err(dbenv, ret, NULL);
+ break;
+ case DB_LOCK_DEADLOCK:
+ dbenv->err(dbenv, ret,
+ "lock_%s", did_get ? "get" : "put");
+ break;
+ default:
+ dbenv->err(dbenv, ret,
+ "lock_%s", did_get ? "get" : "put");
+ (void)dbenv->close(dbenv, 0);
+ exit (1);
+ }
+ }
+
+ printf("\nClosing lock region %ld locks held\n", held);
+
+ if (locks != NULL)
+ free(locks);
+
+ if ((ret = dbenv->close(dbenv, 0)) != 0) {
+ fprintf(stderr,
+ "%s: dbenv->close: %s\n", progname, db_strerror(ret));
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * db_init --
+ * Initialize the environment.
+ */
+void
+db_init(home, maxlocks, do_unlink)
+ char *home;
+ u_int32_t maxlocks;
+ int do_unlink;
+{
+ int ret;
+
+ if ((ret = db_env_create(&dbenv, 0)) != 0) {
+ fprintf(stderr, "%s: db_env_create: %s\n",
+ progname, db_strerror(ret));
+ exit (1);
+ }
+
+ if (do_unlink) {
+ if ((ret = dbenv->remove(dbenv, home, DB_FORCE)) != 0) {
+ fprintf(stderr, "%s: dbenv->remove: %s\n",
+ progname, db_strerror(ret));
+ exit (1);
+ }
+ if ((ret = db_env_create(&dbenv, 0)) != 0) {
+ fprintf(stderr, "%s: db_env_create: %s\n",
+ progname, db_strerror(ret));
+ exit (1);
+ }
+ }
+
+ dbenv->set_errfile(dbenv, stderr);
+ dbenv->set_errpfx(dbenv, progname);
+ if (maxlocks != 0)
+ dbenv->set_lk_max_locks(dbenv, maxlocks);
+
+ if ((ret =
+ dbenv->open(dbenv, home, DB_CREATE | DB_INIT_LOCK, 0)) != 0) {
+ dbenv->err(dbenv, ret, NULL);
+ (void)dbenv->close(dbenv, 0);
+ exit(1);
+ }
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr,
+ "usage: %s [-u] [-h home] [-m maxlocks]\n", progname);
+ exit(1);
+}
diff --git a/db/examples_c/ex_mpool.c b/db/examples_c/ex_mpool.c
new file mode 100644
index 000000000..376c66478
--- /dev/null
+++ b/db/examples_c/ex_mpool.c
@@ -0,0 +1,280 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1997, 1998, 1999, 2000
+ * Sleepycat Software. All rights reserved.
+ *
+ * $Id: ex_mpool.c,v 11.13 2000/10/27 20:32:00 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 <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#endif
+
+#include <db.h>
+
+int init __P((char *, int, int, char *));
+int run __P((int, int, int, int, char *));
+int run_mpool __P((int, int, int, int, char *));
+#ifdef HAVE_VXWORKS
+int ex_mpool __P((void));
+#define MPOOL "/vxtmp/vxtmp/mpool" /* File. */
+#define ERROR_RETURN ERROR
+#define VXSHM_KEY 12
+#else
+int main __P((int, char *[]));
+void usage __P((char *));
+#define MPOOL "mpool" /* File. */
+#define ERROR_RETURN 1
+#endif
+
+#ifndef HAVE_VXWORKS
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern char *optarg;
+ extern int optind;
+ int cachesize, ch, hits, npages, pagesize;
+ char *progname;
+
+ cachesize = 20 * 1024;
+ hits = 1000;
+ npages = 50;
+ pagesize = 1024;
+ progname = argv[0];
+ while ((ch = getopt(argc, argv, "c:h:n:p:")) != EOF)
+ switch (ch) {
+ case 'c':
+ if ((cachesize = atoi(optarg)) < 20 * 1024)
+ usage(progname);
+ break;
+ case 'h':
+ if ((hits = atoi(optarg)) <= 0)
+ usage(progname);
+ break;
+ case 'n':
+ if ((npages = atoi(optarg)) <= 0)
+ usage(progname);
+ break;
+ case 'p':
+ if ((pagesize = atoi(optarg)) <= 0)
+ usage(progname);
+ break;
+ case '?':
+ default:
+ usage(progname);
+ }
+ argc -= optind;
+ argv += optind;
+
+ return (run_mpool(pagesize, cachesize, hits, npages, progname));
+}
+
+void
+usage(progname)
+ char *progname;
+{
+ (void)fprintf(stderr,
+ "usage: %s [-c cachesize] [-h hits] [-n npages] [-p pagesize]\n",
+ progname);
+ exit(1);
+}
+#else
+int
+ex_mpool()
+{
+ char *progname = "ex_mpool"; /* Program name. */
+ int cachesize, ch, hits, npages, pagesize;
+
+ cachesize = 20 * 1024;
+ hits = 1000;
+ npages = 50;
+ pagesize = 1024;
+
+ return (run_mpool(pagesize, cachesize, hits, npages, progname));
+}
+#endif
+
+int
+run_mpool(pagesize, cachesize, hits, npages, progname)
+ int pagesize, cachesize, hits, npages;
+ char *progname;
+{
+ int ret;
+
+ /* Initialize the file. */
+ if ((ret = init(MPOOL, pagesize, npages, progname)) != 0)
+ return (ret);
+
+ /* Get the pages. */
+ if ((ret = run(hits, cachesize, pagesize, npages, progname)) != 0)
+ return (ret);
+
+ return (0);
+}
+
+/*
+ * init --
+ * Create a backing file.
+ */
+int
+init(file, pagesize, npages, progname)
+ char *file, *progname;
+ int pagesize, npages;
+{
+ int cnt, flags, fd;
+ char *p;
+
+ /*
+ * Create a file with the right number of pages, and store a page
+ * number on each page.
+ */
+ flags = O_CREAT | O_RDWR | O_TRUNC;
+#ifdef DB_WIN32
+ flags |= O_BINARY;
+#endif
+ if ((fd = open(file, flags, 0666)) < 0) {
+ fprintf(stderr,
+ "%s: %s: %s\n", progname, file, strerror(errno));
+ return (ERROR_RETURN);
+ }
+ if ((p = (char *)malloc(pagesize)) == NULL) {
+ fprintf(stderr, "%s: %s\n", progname, strerror(ENOMEM));
+ return (ERROR_RETURN);
+ }
+
+ /* The pages are numbered from 0. */
+ for (cnt = 0; cnt <= npages; ++cnt) {
+ *(int *)p = cnt;
+ if (write(fd, p, pagesize) != pagesize) {
+ fprintf(stderr,
+ "%s: %s: %s\n", progname, file, strerror(errno));
+ return (ERROR_RETURN);
+ }
+ }
+
+ (void)close(fd);
+ free(p);
+ return (0);
+}
+
+/*
+ * run --
+ * Get a set of pages.
+ */
+int
+run(hits, cachesize, pagesize, npages, progname)
+ int hits, cachesize, pagesize, npages;
+ char *progname;
+{
+ DB_ENV *dbenv;
+ DB_MPOOLFILE *dbmfp;
+ db_pgno_t pageno;
+ int cnt, ret;
+ void *p;
+
+ printf("%s: cachesize: %d; pagesize: %d; N pages: %d\n",
+ progname, cachesize, pagesize, npages);
+
+ /*
+ * Open a memory pool, specify a cachesize, output error messages
+ * to stderr.
+ */
+ if ((ret = db_env_create(&dbenv, 0)) != 0) {
+ fprintf(stderr,
+ "%s: db_env_create: %s\n", progname, db_strerror(ret));
+ return (ERROR_RETURN);
+ }
+ dbenv->set_errfile(dbenv, stderr);
+ dbenv->set_errpfx(dbenv, progname);
+#ifdef HAVE_VXWORKS
+ if ((ret = dbenv->set_shm_key(dbenv, VXSHM_KEY)) != 0) {
+ dbenv->err(dbenv, ret, "set_shm_key");
+ return (ERROR_RETURN);
+ }
+#endif
+
+ /* Set the cachesize. */
+ if ((ret = dbenv->set_cachesize(dbenv, 0, cachesize, 0)) != 0) {
+ dbenv->err(dbenv, ret, "set_cachesize");
+ goto err1;
+ }
+
+ /* Open the environment. */
+ if ((ret = dbenv->open(
+ dbenv, NULL, DB_CREATE | DB_INIT_MPOOL, 0)) != 0) {
+ dbenv->err(dbenv, ret, "open");
+ goto err1;
+ }
+
+ /* Open the file in the environment. */
+ if ((ret =
+ memp_fopen(dbenv, MPOOL, 0, 0, pagesize, NULL, &dbmfp)) != 0) {
+ dbenv->err(dbenv, ret, "memp_fopen: %s", MPOOL);
+ goto err1;
+ }
+
+ printf("retrieve %d random pages... ", hits);
+
+ srand((u_int)time(NULL));
+ for (cnt = 0; cnt < hits; ++cnt) {
+ pageno = (rand() % npages) + 1;
+ if ((ret = memp_fget(dbmfp, &pageno, 0, &p)) != 0) {
+ dbenv->err(dbenv, ret,
+ "unable to retrieve page %lu", (u_long)pageno);
+ goto err2;
+ }
+ if (*(db_pgno_t *)p != pageno) {
+ dbenv->errx(dbenv,
+ "wrong page retrieved (%lu != %d)",
+ (u_long)pageno, *(int *)p);
+ goto err2;
+ }
+ if ((ret = memp_fput(dbmfp, p, 0)) != 0) {
+ dbenv->err(dbenv, ret,
+ "unable to return page %lu", (u_long)pageno);
+ goto err2;
+ }
+ }
+
+ printf("successful.\n");
+
+ /* Close the file. */
+ if ((ret = memp_fclose(dbmfp)) != 0) {
+ dbenv->err(dbenv, ret, "memp_fclose");
+ goto err1;
+ }
+
+ /* Close the pool. */
+ if ((ret = dbenv->close(dbenv, 0)) != 0) {
+ fprintf(stderr,
+ "%s: db_env_create: %s\n", progname, db_strerror(ret));
+ return (ERROR_RETURN);
+ }
+ return (0);
+
+err2: (void)memp_fclose(dbmfp);
+err1: (void)dbenv->close(dbenv, 0);
+ return (ERROR_RETURN);
+}
diff --git a/db/examples_c/ex_thread.c b/db/examples_c/ex_thread.c
new file mode 100644
index 000000000..93812ade7
--- /dev/null
+++ b/db/examples_c/ex_thread.c
@@ -0,0 +1,604 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1997, 1998, 1999, 2000
+ * Sleepycat Software. All rights reserved.
+ *
+ * $Id: ex_thread.c,v 11.9 2000/05/31 15:10:04 bostic 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 <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#endif
+
+#include <db.h>
+
+/*
+ * NB: This application is written using POSIX 1003.1b-1993 pthreads
+ * interfaces, which may not be portable to your system.
+ */
+extern int sched_yield __P((void)); /* Pthread yield function. */
+
+DB_ENV *db_init __P((char *));
+void *deadlock __P((void *));
+void fatal __P((char *, int, int));
+int main __P((int, char *[]));
+int reader __P((int));
+void stats __P((void));
+void *trickle __P((void *));
+void *tstart __P((void *));
+void usage __P((void));
+void word __P((void));
+int writer __P((int));
+
+struct _statistics {
+ int aborted; /* Write. */
+ int aborts; /* Read/write. */
+ int adds; /* Write. */
+ int deletes; /* Write. */
+ int txns; /* Write. */
+ int found; /* Read. */
+ int notfound; /* Read. */
+} *perf;
+
+const char
+ *progname = "ex_thread"; /* Program name. */
+
+#define DATABASE "access.db" /* Database name. */
+#define WORDLIST "../test/wordlist" /* Dictionary. */
+
+/*
+ * We can seriously increase the number of collisions and transaction
+ * aborts by yielding the scheduler after every DB call. Specify the
+ * -p option to do this.
+ */
+int punish; /* -p */
+int nlist; /* -n */
+int nreaders; /* -r */
+int verbose; /* -v */
+int nwriters; /* -w */
+
+DB *dbp; /* Database handle. */
+DB_ENV *dbenv; /* Database environment. */
+int nthreads; /* Total threads. */
+char **list; /* Word list. */
+
+/*
+ * ex_thread --
+ * Run a simple threaded application of some numbers of readers and
+ * writers competing for a set of words.
+ *
+ * Example UNIX shell script to run this program:
+ * % rm -rf TESTDIR
+ * % mkdir TESTDIR
+ * % ex_thread -h TESTDIR
+ */
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern char *optarg;
+ extern int errno, optind;
+ pthread_t *tids;
+ int ch, i, ret;
+ char *home;
+ void *retp;
+
+ nlist = 1000;
+ nreaders = nwriters = 4;
+ home = "TESTDIR";
+ while ((ch = getopt(argc, argv, "h:pn:r:vw:")) != EOF)
+ switch (ch) {
+ case 'h':
+ home = optarg;
+ break;
+ case 'p':
+ punish = 1;
+ break;
+ case 'n':
+ nlist = atoi(optarg);
+ break;
+ case 'r':
+ nreaders = atoi(optarg);
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 'w':
+ nwriters = atoi(optarg);
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ /* Initialize the random number generator. */
+ srand(getpid() | time(NULL));
+
+ /* Build the key list. */
+ word();
+
+ /* Remove the previous database. */
+ (void)unlink(DATABASE);
+
+ /* Initialize the database environment. */
+ dbenv = db_init(home);
+
+ /* Initialize the database. */
+ if ((ret = db_create(&dbp, dbenv, 0)) != 0) {
+ dbenv->err(dbenv, ret, "db_create");
+ (void)dbenv->close(dbenv, 0);
+ return (1);
+ }
+ if ((ret = dbp->set_pagesize(dbp, 1024)) != 0) {
+ dbp->err(dbp, ret, "set_pagesize");
+ goto err;
+ }
+ if ((ret = dbp->open(dbp,
+ DATABASE, NULL, DB_BTREE, DB_CREATE | DB_THREAD, 0664)) != 0) {
+ dbp->err(dbp, ret, "%s: open", DATABASE);
+ goto err;
+ }
+
+ nthreads = nreaders + nwriters + 2;
+ printf("Running: readers %d, writers %d\n", nreaders, nwriters);
+ fflush(stdout);
+
+ /* Create statistics structures, offset by 1. */
+ if ((perf = calloc(nreaders + nwriters + 1, sizeof(*perf))) == NULL)
+ fatal(NULL, errno, 1);
+
+ /* Create thread ID structures. */
+ if ((tids = malloc(nthreads * sizeof(pthread_t))) == NULL)
+ fatal(NULL, errno, 1);
+
+ /* Create reader/writer threads. */
+ for (i = 0; i < nreaders + nwriters; ++i)
+ if (pthread_create(&tids[i], NULL, tstart, (void *)i))
+ fatal("pthread_create", errno, 1);
+
+ /* Create buffer pool trickle thread. */
+ if (pthread_create(&tids[i], NULL, trickle, &i))
+ fatal("pthread_create", errno, 1);
+ ++i;
+
+ /* Create deadlock detector thread. */
+ if (pthread_create(&tids[i], NULL, deadlock, &i))
+ fatal("pthread_create", errno, 1);
+
+ /* Wait for the threads. */
+ for (i = 0; i < nthreads; ++i)
+ (void)pthread_join(tids[i], &retp);
+
+err: (void)dbp->close(dbp, 0);
+ (void)dbenv->close(dbenv, 0);
+
+ return (0);
+}
+
+int
+reader(id)
+ int id;
+{
+ DBT key, data;
+ int n, ret;
+ char buf[64];
+
+ /*
+ * DBT's must use local memory or malloc'd memory if the DB handle
+ * is accessed in a threaded fashion.
+ */
+ memset(&key, 0, sizeof(DBT));
+ memset(&data, 0, sizeof(DBT));
+ data.flags = DB_DBT_MALLOC;
+
+ /*
+ * Read-only threads do not require transaction protection, unless
+ * there's a need for repeatable reads.
+ */
+ for (;;) {
+ /* Pick a key at random, and look it up. */
+ n = rand() % nlist;
+ key.data = list[n];
+ key.size = strlen(key.data);
+
+ if (verbose) {
+ sprintf(buf, "reader: %d: list entry %d\n", id, n);
+ write(STDOUT_FILENO, buf, strlen(buf));
+ }
+
+ switch (ret = dbp->get(dbp, NULL, &key, &data, 0)) {
+ case DB_LOCK_DEADLOCK: /* Deadlock. */
+ ++perf[id].aborts;
+ break;
+ case 0: /* Success. */
+ ++perf[id].found;
+ free(data.data);
+ break;
+ case DB_NOTFOUND: /* Not found. */
+ ++perf[id].notfound;
+ break;
+ default:
+ sprintf(buf,
+ "reader %d: dbp->get: %s", id, (char *)key.data);
+ fatal(buf, ret, 0);
+ }
+ }
+ return (0);
+}
+
+int
+writer(id)
+ int id;
+{
+ DBT key, data;
+ DB_TXN *tid;
+ time_t now, then;
+ int n, ret;
+ char buf[256], dbuf[10000];
+
+ time(&now);
+ then = now;
+
+ /*
+ * DBT's must use local memory or malloc'd memory if the DB handle
+ * is accessed in a threaded fashion.
+ */
+ memset(&key, 0, sizeof(DBT));
+ memset(&data, 0, sizeof(DBT));
+ data.data = dbuf;
+ data.ulen = sizeof(dbuf);
+ data.flags = DB_DBT_USERMEM;
+
+ for (;;) {
+ /* Pick a random key. */
+ n = rand() % nlist;
+ key.data = list[n];
+ key.size = strlen(key.data);
+
+ if (verbose) {
+ sprintf(buf, "writer: %d: list entry %d\n", id, n);
+ write(STDOUT_FILENO, buf, strlen(buf));
+ }
+
+ /* Abort and retry. */
+ if (0) {
+retry: if ((ret = txn_abort(tid)) != 0)
+ fatal("txn_abort", ret, 1);
+ ++perf[id].aborts;
+ ++perf[id].aborted;
+ }
+
+ /* Thread #1 prints out the stats every 20 seconds. */
+ if (id == 1) {
+ time(&now);
+ if (now - then >= 20) {
+ stats();
+ then = now;
+ }
+ }
+
+ /* Begin the transaction. */
+ if ((ret = txn_begin(dbenv, NULL, &tid, 0)) != 0)
+ fatal("txn_begin", ret, 1);
+
+ /*
+ * Get the key. If it doesn't exist, add it. If it does
+ * exist, delete it.
+ */
+ switch (ret = dbp->get(dbp, tid, &key, &data, 0)) {
+ case DB_LOCK_DEADLOCK:
+ goto retry;
+ case 0:
+ goto delete;
+ case DB_NOTFOUND:
+ goto add;
+ }
+
+ sprintf(buf, "writer: %d: dbp->get", id);
+ fatal(buf, ret, 1);
+ /* NOTREACHED */
+
+delete: /* Delete the key. */
+ switch (ret = dbp->del(dbp, tid, &key, 0)) {
+ case DB_LOCK_DEADLOCK:
+ goto retry;
+ case 0:
+ ++perf[id].deletes;
+ goto commit;
+ }
+
+ sprintf(buf, "writer: %d: dbp->del", id);
+ fatal(buf, ret, 1);
+ /* NOTREACHED */
+
+add: /* Add the key. 1 data item in 30 is an overflow item. */
+ data.size = 20 + rand() % 128;
+ if (rand() % 30 == 0)
+ data.size += 8192;
+
+ switch (ret = dbp->put(dbp, tid, &key, &data, 0)) {
+ case DB_LOCK_DEADLOCK:
+ goto retry;
+ case 0:
+ ++perf[id].adds;
+ goto commit;
+ default:
+ sprintf(buf, "writer: %d: dbp->put", id);
+ fatal(buf, ret, 1);
+ }
+
+commit: /* The transaction finished, commit it. */
+ if ((ret = txn_commit(tid, 0)) != 0)
+ fatal("txn_commit", ret, 1);
+
+ /*
+ * Every time the thread completes 20 transactions, show
+ * our progress.
+ */
+ if (++perf[id].txns % 20 == 0) {
+ sprintf(buf,
+"writer: %2d: adds: %4d: deletes: %4d: aborts: %4d: txns: %4d\n",
+ id, perf[id].adds, perf[id].deletes,
+ perf[id].aborts, perf[id].txns);
+ write(STDOUT_FILENO, buf, strlen(buf));
+ }
+
+ /*
+ * If this thread was aborted more than 5 times before
+ * the transaction finished, complain.
+ */
+ if (perf[id].aborted > 5) {
+ sprintf(buf,
+"writer: %2d: adds: %4d: deletes: %4d: aborts: %4d: txns: %4d: ABORTED: %2d\n",
+ id, perf[id].adds, perf[id].deletes,
+ perf[id].aborts, perf[id].txns, perf[id].aborted);
+ write(STDOUT_FILENO, buf, strlen(buf));
+ }
+ perf[id].aborted = 0;
+ }
+ return (0);
+}
+
+/*
+ * stats --
+ * Display reader/writer thread statistics. To display the statistics
+ * for the mpool trickle or deadlock threads, use db_stat(1).
+ */
+void
+stats()
+{
+ int id;
+ char *p, buf[8192];
+
+ p = buf + sprintf(buf, "-------------\n");
+ for (id = 0; id < nreaders + nwriters;)
+ if (id++ < nwriters)
+ p += sprintf(p,
+ "writer: %2d: adds: %4d: deletes: %4d: aborts: %4d: txns: %4d\n",
+ id, perf[id].adds,
+ perf[id].deletes, perf[id].aborts, perf[id].txns);
+ else
+ p += sprintf(p,
+ "reader: %2d: found: %5d: notfound: %5d: aborts: %4d\n",
+ id, perf[id].found,
+ perf[id].notfound, perf[id].aborts);
+ p += sprintf(p, "-------------\n");
+
+ write(STDOUT_FILENO, buf, p - buf);
+}
+
+/*
+ * db_init --
+ * Initialize the environment.
+ */
+DB_ENV *
+db_init(home)
+ char *home;
+{
+ DB_ENV *dbenv;
+ int ret;
+
+ if (punish) {
+ (void)db_env_set_pageyield(1);
+ (void)db_env_set_func_yield(sched_yield);
+ }
+
+ if ((ret = db_env_create(&dbenv, 0)) != 0) {
+ fprintf(stderr,
+ "%s: db_env_create: %s\n", progname, db_strerror(ret));
+ exit (1);
+ }
+ dbenv->set_errfile(dbenv, stderr);
+ dbenv->set_errpfx(dbenv, progname);
+ (void)dbenv->set_cachesize(dbenv, 0, 100 * 1024, 0);
+ (void)dbenv->set_lg_max(dbenv, 200000);
+
+ if ((ret = dbenv->open(dbenv, home,
+ DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG |
+ DB_INIT_MPOOL | DB_INIT_TXN | DB_THREAD, 0)) != 0) {
+ dbenv->err(dbenv, ret, NULL);
+ (void)dbenv->close(dbenv, 0);
+ exit (1);
+ }
+ return (dbenv);
+}
+
+/*
+ * tstart --
+ * Thread start function for readers and writers.
+ */
+void *
+tstart(arg)
+ void *arg;
+{
+ pthread_t tid;
+ u_int id;
+
+ id = (u_int)arg + 1;
+
+ tid = pthread_self();
+
+ if (id <= (u_int)nwriters) {
+ printf("write thread %d starting: tid: %lu\n", id, (u_long)tid);
+ fflush(stdout);
+ writer(id);
+ } else {
+ printf("read thread %d starting: tid: %lu\n", id, (u_long)tid);
+ fflush(stdout);
+ reader(id);
+ }
+
+ /* NOTREACHED */
+ return (NULL);
+}
+
+/*
+ * deadlock --
+ * Thread start function for lock_detect().
+ */
+void *
+deadlock(arg)
+ void *arg;
+{
+ struct timeval t;
+ pthread_t tid;
+
+ arg = arg; /* XXX: shut the compiler up. */
+ tid = pthread_self();
+
+ printf("deadlock thread starting: tid: %lu\n", (u_long)tid);
+ fflush(stdout);
+
+ t.tv_sec = 0;
+ t.tv_usec = 100000;
+ for (;;) {
+ (void)lock_detect(dbenv,
+ DB_LOCK_CONFLICT, DB_LOCK_YOUNGEST, NULL);
+
+ /* Check every 100ms. */
+ (void)select(0, NULL, NULL, NULL, &t);
+ }
+
+ /* NOTREACHED */
+ return (NULL);
+}
+
+/*
+ * trickle --
+ * Thread start function for memp_trickle().
+ */
+void *
+trickle(arg)
+ void *arg;
+{
+ pthread_t tid;
+ int wrote;
+ char buf[64];
+
+ arg = arg; /* XXX: shut the compiler up. */
+ tid = pthread_self();
+
+ printf("trickle thread starting: tid: %lu\n", (u_long)tid);
+ fflush(stdout);
+
+ for (;;) {
+ (void)memp_trickle(dbenv, 10, &wrote);
+ if (verbose) {
+ sprintf(buf, "trickle: wrote %d\n", wrote);
+ write(STDOUT_FILENO, buf, strlen(buf));
+ }
+ if (wrote == 0) {
+ sleep(1);
+ sched_yield();
+ }
+ }
+
+ /* NOTREACHED */
+ return (NULL);
+}
+
+/*
+ * word --
+ * Build the dictionary word list.
+ */
+void
+word()
+{
+ FILE *fp;
+ int cnt;
+ char buf[256];
+
+ if ((fp = fopen(WORDLIST, "r")) == NULL)
+ fatal(WORDLIST, errno, 1);
+
+ if ((list = malloc(nlist * sizeof(char *))) == NULL)
+ fatal(NULL, errno, 1);
+
+ for (cnt = 0; cnt < nlist; ++cnt) {
+ if (fgets(buf, sizeof(buf), fp) == NULL)
+ break;
+ if ((list[cnt] = strdup(buf)) == NULL)
+ fatal(NULL, errno, 1);
+ }
+ nlist = cnt; /* In case nlist was larger than possible. */
+}
+
+/*
+ * fatal --
+ * Report a fatal error and quit.
+ */
+void
+fatal(msg, err, syserr)
+ char *msg;
+ int err, syserr;
+{
+ fprintf(stderr, "%s: ", progname);
+ if (msg != NULL) {
+ fprintf(stderr, "%s", msg);
+ if (syserr)
+ fprintf(stderr, ": ");
+ }
+ if (syserr)
+ fprintf(stderr, "%s", strerror(err));
+ fprintf(stderr, "\n");
+ exit (1);
+
+ /* NOTREACHED */
+}
+
+/*
+ * usage --
+ * Usage message.
+ */
+void
+usage()
+{
+ (void)fprintf(stderr,
+ "usage: %s [-pv] [-h home] [-n words] [-r readers] [-w writers]\n",
+ progname);
+ exit(1);
+}
diff --git a/db/examples_c/ex_tpcb.c b/db/examples_c/ex_tpcb.c
new file mode 100644
index 000000000..2fd11510a
--- /dev/null
+++ b/db/examples_c/ex_tpcb.c
@@ -0,0 +1,811 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1997, 1998, 1999, 2000
+ * Sleepycat Software. All rights reserved.
+ *
+ * $Id: ex_tpcb.c,v 11.21 2000/10/27 20:32:00 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 <db.h>
+
+typedef enum { ACCOUNT, BRANCH, TELLER } FTYPE;
+
+DB_ENV *db_init __P((char *, char *, int, int, int));
+int hpopulate __P((DB *, int, int, int, int));
+int populate __P((DB *, u_int32_t, u_int32_t, int, char *));
+u_int32_t random_id __P((FTYPE, int, int, int));
+u_int32_t random_int __P((u_int32_t, u_int32_t));
+int tp_populate __P((DB_ENV *, int, int, int, int, int));
+int tp_run __P((DB_ENV *, int, int, int, int, int));
+int tp_txn __P((DB_ENV *, DB *, DB *, DB *, DB *, int, int, int, int));
+
+#ifdef HAVE_VXWORKS
+#define ERROR_RETURN ERROR
+#define HOME "/vxtmp/vxtmp/TESTDIR"
+#define VXSHM_KEY 13
+int ex_tpcb_init __P(());
+int ex_tpcb __P(());
+#else
+#define ERROR_RETURN 1
+void invarg __P((char *, int, char *));
+int main __P((int, char *[]));
+void usage __P((char *));
+#endif
+
+/*
+ * 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 10
+#define ACCOUNTS_PER_TELLER 10000
+#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
+
+#ifdef VERY_TINY
+#define ACCOUNTS 500
+#define BRANCHES 10
+#define TELLERS 50
+#define HISTORY 5000
+#endif
+
+#if !defined(VALID_SCALING) && !defined(TINY) && !defined(VERY_TINY)
+#define ACCOUNTS 100000
+#define BRANCHES 10
+#define TELLERS 100
+#define HISTORY 259200
+#endif
+
+#define HISTORY_LEN 100
+#define RECLEN 100
+#define BEGID 1000000
+
+typedef struct _defrec {
+ u_int32_t id;
+ u_int32_t balance;
+ u_int8_t pad[RECLEN - sizeof(u_int32_t) - sizeof(u_int32_t)];
+} defrec;
+
+typedef 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)];
+} histrec;
+
+#ifdef HAVE_VXWORKS
+int
+ex_tpcb_init()
+{
+ DB_ENV *dbenv;
+ int accounts, branches, ret, seed, t_ret, tellers, history, verbose;
+ char *home;
+ char *progname = "ex_tpcb_init"; /* Program name. */
+
+ verbose = 1;
+ if ((dbenv = db_init(HOME, progname, 0, 1, 0)) == NULL)
+ return (ERROR_RETURN);
+
+ accounts = ACCOUNTS;
+ branches = BRANCHES;
+ tellers = TELLERS;
+ history = HISTORY;
+
+ if ((ret = tp_populate(dbenv, accounts, branches, history, tellers,
+ verbose)) != OK)
+ fprintf(stderr, "%s: %s\n", progname, db_strerror(ret));
+ if ((t_ret = dbenv->close(dbenv, 0)) != 0) {
+ fprintf(stderr, "%s: %s\n", progname, db_strerror(ret));
+ return (ERROR_RETURN);
+ }
+
+ return (ret == 0 ? t_ret : ret);
+}
+
+int
+ex_tpcb()
+{
+ DB_ENV *dbenv;
+ int accounts, branches, seed, tellers, history;
+ int ch, mpool, ntxns, ret, t_ret, txn_no_sync, verbose;
+ char *progname = "ex_tpcb"; /* Program name. */
+
+ accounts = ACCOUNTS;
+ branches = BRANCHES;
+ tellers = TELLERS;
+ history = HISTORY;
+
+ txn_no_sync = 0;
+ mpool = 0;
+ ntxns = 20;
+ verbose = 1;
+ seed = (int)((u_int)getpid() | time(NULL));
+
+ srand((u_int)seed);
+
+ /* Initialize the database environment. */
+ if ((dbenv = db_init(HOME, progname, mpool, 0,
+ txn_no_sync ? DB_TXN_NOSYNC : 0)) == NULL)
+ return (ERROR_RETURN);
+
+ if (verbose)
+ printf("%ld Accounts, %ld Branches, %ld Tellers, %ld History\n",
+ (long)accounts, (long)branches,
+ (long)tellers, (long)history);
+
+ if ((ret = tp_run(dbenv, ntxns, accounts, branches, tellers, verbose))
+ != OK)
+ fprintf(stderr, "tp_run failed\n");
+
+ if ((t_ret = dbenv->close(dbenv, 0)) != 0) {
+ fprintf(stderr, "%s: %s\n", progname, db_strerror(ret));
+ return (ERROR_RETURN);
+ }
+ return (ret == 0 ? t_ret : ret);
+}
+#else
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern char *optarg;
+ extern int optind;
+ DB_ENV *dbenv;
+ int accounts, branches, seed, tellers, history;
+ int ch, iflag, mpool, ntxns, ret, txn_no_sync, verbose;
+ char *home, *progname;
+
+ home = "TESTDIR";
+ progname = "ex_tpcb";
+ accounts = branches = history = tellers = 0;
+ txn_no_sync = 0;
+ mpool = ntxns = 0;
+ verbose = 0;
+ iflag = 0;
+ seed = (int)((u_int)getpid() | time(NULL));
+ while ((ch = getopt(argc, argv, "a:b:c:fh:in:S:s:t:v")) != EOF)
+ switch (ch) {
+ case 'a': /* Number of account records */
+ if ((accounts = atoi(optarg)) <= 0)
+ invarg(progname, ch, optarg);
+ break;
+ case 'b': /* Number of branch records */
+ if ((branches = atoi(optarg)) <= 0)
+ invarg(progname, ch, optarg);
+ break;
+ case 'c': /* Cachesize in bytes */
+ if ((mpool = atoi(optarg)) <= 0)
+ invarg(progname, ch, optarg);
+ break;
+ case 'f': /* Fast mode: no txn sync. */
+ txn_no_sync = 1;
+ break;
+ case 'h': /* DB home. */
+ home = optarg;
+ break;
+ case 'i': /* Initialize the test. */
+ iflag = 1;
+ break;
+ case 'n': /* Number of transactions */
+ if ((ntxns = atoi(optarg)) <= 0)
+ invarg(progname, ch, optarg);
+ break;
+ case 'S': /* Random number seed. */
+ if ((seed = atoi(optarg)) <= 0)
+ invarg(progname, ch, optarg);
+ break;
+ case 's': /* Number of history records */
+ if ((history = atoi(optarg)) <= 0)
+ invarg(progname, ch, optarg);
+ break;
+ case 't': /* Number of teller records */
+ if ((tellers = atoi(optarg)) <= 0)
+ invarg(progname, ch, optarg);
+ break;
+ case 'v': /* Verbose option. */
+ verbose = 1;
+ break;
+ case '?':
+ default:
+ usage(progname);
+ }
+ argc -= optind;
+ argv += optind;
+
+ srand((u_int)seed);
+
+ /* Initialize the database environment. */
+ if ((dbenv = db_init(home,
+ progname, mpool, iflag, txn_no_sync ? DB_TXN_NOSYNC : 0)) == NULL)
+ return (1);
+
+ accounts = accounts == 0 ? ACCOUNTS : accounts;
+ branches = branches == 0 ? BRANCHES : branches;
+ tellers = tellers == 0 ? TELLERS : tellers;
+ history = history == 0 ? HISTORY : history;
+
+ if (verbose)
+ printf("%ld Accounts, %ld Branches, %ld Tellers, %ld History\n",
+ (long)accounts, (long)branches,
+ (long)tellers, (long)history);
+
+ if (iflag) {
+ if (ntxns != 0)
+ usage(progname);
+ tp_populate(dbenv,
+ accounts, branches, history, tellers, verbose);
+ } else {
+ if (ntxns == 0)
+ usage(progname);
+ tp_run(dbenv, ntxns, accounts, branches, tellers, verbose);
+ }
+
+ if ((ret = dbenv->close(dbenv, 0)) != 0) {
+ fprintf(stderr, "%s: dbenv->close failed: %s\n",
+ progname, db_strerror(ret));
+ return (1);
+ }
+
+ return (0);
+}
+
+void
+invarg(progname, arg, str)
+ char *progname;
+ int arg;
+ char *str;
+{
+ (void)fprintf(stderr,
+ "%s: invalid argument for -%c: %s\n", progname, arg, str);
+ exit (1);
+}
+
+void
+usage(progname)
+ char *progname;
+{
+ char *a1, *a2;
+
+ a1 = "[-fv] [-a accounts] [-b branches]\n";
+ a2 = "\t[-c cache_size] [-h home] [-S seed] [-s history] [-t tellers]";
+ (void)fprintf(stderr, "usage: %s -i %s %s\n", progname, a1, a2);
+ (void)fprintf(stderr,
+ " %s -n transactions %s %s\n", progname, a1, a2);
+ exit(1);
+}
+#endif
+
+/*
+ * db_init --
+ * Initialize the environment.
+ */
+DB_ENV *
+db_init(home, prefix, cachesize, initializing, flags)
+ char *home, *prefix;
+ int cachesize, initializing, flags;
+{
+ DB_ENV *dbenv;
+ u_int32_t local_flags;
+ int ret;
+
+ if ((ret = db_env_create(&dbenv, 0)) != 0) {
+ dbenv->err(dbenv, ret, "db_env_create");
+ return (NULL);
+ }
+ dbenv->set_errfile(dbenv, stderr);
+ dbenv->set_errpfx(dbenv, prefix);
+#ifdef HAVE_VXWORKS
+ if ((ret = dbenv->set_shm_key(dbenv, VXSHM_KEY)) != 0) {
+ dbenv->err(dbenv, ret, "set_shm_key");
+ return (NULL);
+ }
+#endif
+ (void)dbenv->set_cachesize(dbenv, 0,
+ cachesize == 0 ? 4 * 1024 * 1024 : (u_int32_t)cachesize, 0);
+
+ local_flags = flags | DB_CREATE | (initializing ? DB_INIT_MPOOL :
+ DB_INIT_TXN | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL);
+ if ((ret = dbenv->open(dbenv, home, local_flags, 0)) != 0) {
+ dbenv->err(dbenv, ret, "DBENV->open: %s", home);
+ (void)dbenv->close(dbenv, 0);
+ return (NULL);
+ }
+ return (dbenv);
+}
+
+/*
+ * Initialize the database to the specified number of accounts, branches,
+ * history records, and tellers.
+ */
+int
+tp_populate(env, accounts, branches, history, tellers, verbose)
+ DB_ENV *env;
+ int accounts, branches, history, tellers, verbose;
+{
+ DB *dbp;
+ char dbname[100];
+ u_int32_t balance, idnum, oflags;
+ u_int32_t end_anum, end_bnum, end_tnum;
+ u_int32_t start_anum, start_bnum, start_tnum;
+ int ret;
+
+ idnum = BEGID;
+ balance = 500000;
+#ifdef HAVE_VXWORKS
+ oflags = DB_CREATE;
+#else
+ oflags = DB_CREATE | DB_TRUNCATE;
+#endif
+
+ if ((ret = db_create(&dbp, env, 0)) != 0) {
+ env->err(env, ret, "db_create");
+ return (ERROR_RETURN);
+ }
+ (void)dbp->set_h_nelem(dbp, (u_int32_t)accounts);
+
+ snprintf(dbname, sizeof(dbname), "account");
+ if ((ret = dbp->open(dbp, dbname, NULL,
+ DB_HASH, oflags, 0644)) != 0) {
+ env->err(env, ret, "DB->open: account");
+ return (ERROR_RETURN);
+ }
+
+ start_anum = idnum;
+ populate(dbp, idnum, balance, accounts, "account");
+ idnum += accounts;
+ end_anum = idnum - 1;
+ if ((ret = dbp->close(dbp, 0)) != 0) {
+ env->err(env, ret, "DB->close: account");
+ return (ERROR_RETURN);
+ }
+ if (verbose)
+ printf("Populated accounts: %ld - %ld\n",
+ (long)start_anum, (long)end_anum);
+
+ /*
+ * Since the number of branches is very small, we want to use very
+ * small pages and only 1 key per page, i.e., key-locking instead
+ * of page locking.
+ */
+ if ((ret = db_create(&dbp, env, 0)) != 0) {
+ env->err(env, ret, "db_create");
+ return (ERROR_RETURN);
+ }
+ (void)dbp->set_h_ffactor(dbp, 1);
+ (void)dbp->set_h_nelem(dbp, (u_int32_t)branches);
+ (void)dbp->set_pagesize(dbp, 512);
+ snprintf(dbname, sizeof(dbname), "branch");
+ if ((ret = dbp->open(dbp, dbname, NULL,
+ DB_HASH, oflags, 0644)) != 0) {
+ env->err(env, ret, "DB->open: branch");
+ return (ERROR_RETURN);
+ }
+ start_bnum = idnum;
+ populate(dbp, idnum, balance, branches, "branch");
+ idnum += branches;
+ end_bnum = idnum - 1;
+ if ((ret = dbp->close(dbp, 0)) != 0) {
+ env->err(env, ret, "DB->close: branch");
+ return (ERROR_RETURN);
+ }
+ if (verbose)
+ printf("Populated branches: %ld - %ld\n",
+ (long)start_bnum, (long)end_bnum);
+
+ /*
+ * In the case of tellers, we also want small pages, but we'll let
+ * the fill factor dynamically adjust itself.
+ */
+ if ((ret = db_create(&dbp, env, 0)) != 0) {
+ env->err(env, ret, "db_create");
+ return (ERROR_RETURN);
+ }
+ (void)dbp->set_h_ffactor(dbp, 0);
+ (void)dbp->set_h_nelem(dbp, (u_int32_t)tellers);
+ (void)dbp->set_pagesize(dbp, 512);
+ snprintf(dbname, sizeof(dbname), "teller");
+ if ((ret = dbp->open(dbp, dbname, NULL,
+ DB_HASH, oflags, 0644)) != 0) {
+ env->err(env, ret, "DB->open: teller");
+ return (ERROR_RETURN);
+ }
+
+ start_tnum = idnum;
+ populate(dbp, idnum, balance, tellers, "teller");
+ idnum += tellers;
+ end_tnum = idnum - 1;
+ if ((ret = dbp->close(dbp, 0)) != 0) {
+ env->err(env, ret, "DB->close: teller");
+ return (ERROR_RETURN);
+ }
+ if (verbose)
+ printf("Populated tellers: %ld - %ld\n",
+ (long)start_tnum, (long)end_tnum);
+
+ if ((ret = db_create(&dbp, env, 0)) != 0) {
+ env->err(env, ret, "db_create");
+ return (ERROR_RETURN);
+ }
+ (void)dbp->set_re_len(dbp, HISTORY_LEN);
+ snprintf(dbname, sizeof(dbname), "history");
+ if ((ret = dbp->open(dbp, dbname, NULL,
+ DB_RECNO, oflags, 0644)) != 0) {
+ env->err(env, ret, "DB->open: history");
+ return (ERROR_RETURN);
+ }
+
+ hpopulate(dbp, history, accounts, branches, tellers);
+ if ((ret = dbp->close(dbp, 0)) != 0) {
+ env->err(env, ret, "DB->close: history");
+ return (ERROR_RETURN);
+ }
+ return (0);
+}
+
+int
+populate(dbp, start_id, balance, nrecs, msg)
+ DB *dbp;
+ u_int32_t start_id, balance;
+ int nrecs;
+ char *msg;
+{
+ DBT kdbt, ddbt;
+ defrec drec;
+ int i, ret;
+
+ kdbt.flags = 0;
+ kdbt.data = &drec.id;
+ kdbt.size = sizeof(u_int32_t);
+ ddbt.flags = 0;
+ ddbt.data = &drec;
+ ddbt.size = sizeof(drec);
+ memset(&drec.pad[0], 1, sizeof(drec.pad));
+
+ for (i = 0; i < nrecs; i++) {
+ drec.id = start_id + (u_int32_t)i;
+ drec.balance = balance;
+ if ((ret =
+ (dbp->put)(dbp, NULL, &kdbt, &ddbt, DB_NOOVERWRITE)) != 0) {
+ dbp->err(dbp,
+ ret, "Failure initializing %s file\n", msg);
+ return (ERROR_RETURN);
+ }
+ }
+ return (0);
+}
+
+int
+hpopulate(dbp, history, accounts, branches, tellers)
+ DB *dbp;
+ int history, accounts, branches, tellers;
+{
+ DBT kdbt, ddbt;
+ histrec hrec;
+ db_recno_t key;
+ int i, ret;
+
+ memset(&kdbt, 0, sizeof(kdbt));
+ memset(&ddbt, 0, sizeof(ddbt));
+ ddbt.data = &hrec;
+ ddbt.size = sizeof(hrec);
+ kdbt.data = &key;
+ kdbt.size = sizeof(key);
+ memset(&hrec.pad[0], 1, sizeof(hrec.pad));
+ hrec.amount = 10;
+
+ for (i = 1; i <= history; 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);
+ if ((ret = dbp->put(dbp, NULL, &kdbt, &ddbt, DB_APPEND)) != 0) {
+ dbp->err(dbp, ret, "dbp->put");
+ return (ERROR_RETURN);
+ }
+ }
+ return (0);
+}
+
+u_int32_t
+random_int(lo, hi)
+ u_int32_t lo, hi;
+{
+ u_int32_t ret;
+ int t;
+
+#ifndef RAND_MAX
+#define RAND_MAX 0x7fffffff
+#endif
+ t = rand();
+ ret = (u_int32_t)(((double)t / ((double)(RAND_MAX) + 1)) *
+ (hi - lo + 1));
+ ret += lo;
+ return (ret);
+}
+
+u_int32_t
+random_id(type, accounts, branches, tellers)
+ FTYPE type;
+ int accounts, branches, 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));
+}
+
+int
+tp_run(dbenv, n, accounts, branches, tellers, verbose)
+ DB_ENV *dbenv;
+ int n, accounts, branches, tellers, verbose;
+{
+ DB *adb, *bdb, *hdb, *tdb;
+ char dbname[100];
+ 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.
+ */
+ if ((ret = db_create(&adb, dbenv, 0)) != 0) {
+ dbenv->err(dbenv, ret, "db_create");
+ return (ERROR_RETURN);
+ }
+ snprintf(dbname, sizeof(dbname), "account");
+ if ((ret = adb->open(adb, dbname, NULL, DB_UNKNOWN, 0, 0)) != 0) {
+ dbenv->err(dbenv, ret, "DB->open: account");
+ return (ERROR_RETURN);
+ }
+
+ if ((ret = db_create(&bdb, dbenv, 0)) != 0) {
+ dbenv->err(dbenv, ret, "db_create");
+ return (ERROR_RETURN);
+ }
+ snprintf(dbname, sizeof(dbname), "branch");
+ if ((ret = bdb->open(bdb, dbname, NULL, DB_UNKNOWN, 0, 0)) != 0) {
+ dbenv->err(dbenv, ret, "DB->open: branch");
+ return (ERROR_RETURN);
+ }
+
+ if ((ret = db_create(&tdb, dbenv, 0)) != 0) {
+ dbenv->err(dbenv, ret, "db_create");
+ return (ERROR_RETURN);
+ }
+ snprintf(dbname, sizeof(dbname), "teller");
+ if ((ret = tdb->open(tdb, dbname, NULL, DB_UNKNOWN, 0, 0)) != 0) {
+ dbenv->err(dbenv, ret, "DB->open: teller");
+ return (ERROR_RETURN);
+ }
+
+ if ((ret = db_create(&hdb, dbenv, 0)) != 0) {
+ dbenv->err(dbenv, ret, "db_create");
+ return (ERROR_RETURN);
+ }
+ snprintf(dbname, sizeof(dbname), "history");
+ if ((ret = hdb->open(hdb, dbname, NULL, DB_UNKNOWN, 0, 0)) != 0) {
+ dbenv->err(dbenv, ret, "DB->open: history");
+ return (ERROR_RETURN);
+ }
+
+ txns = failed = ifailed = 0;
+ starttime = time(NULL);
+ lasttime = starttime;
+ while (n-- > 0) {
+ txns++;
+ ret = tp_txn(dbenv, adb, bdb, tdb, hdb,
+ accounts, branches, tellers, verbose);
+ if (ret != 0) {
+ failed++;
+ ifailed++;
+ }
+ if (n % 5000 == 0) {
+ curtime = time(NULL);
+ gtps = (double)(txns - failed) / (curtime - starttime);
+ itps = (double)(5000 - ifailed) / (curtime - lasttime);
+ 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(adb, 0);
+ (void)bdb->close(bdb, 0);
+ (void)tdb->close(tdb, 0);
+ (void)hdb->close(hdb, 0);
+
+ printf("%ld transactions begun %ld failed\n", (long)txns, (long)failed);
+ return (0);
+}
+
+/*
+ * XXX Figure out the appropriate way to pick out IDs.
+ */
+int
+tp_txn(dbenv, adb, bdb, tdb, hdb, accounts, branches, tellers, verbose)
+ DB_ENV *dbenv;
+ DB *adb, *bdb, *tdb, *hdb;
+ int accounts, branches, tellers, verbose;
+{
+ DBC *acurs, *bcurs, *tcurs;
+ DBT d_dbt, d_histdbt, k_dbt, k_histdbt;
+ DB_TXN *t;
+ db_recno_t key;
+ defrec rec;
+ histrec hrec;
+ int account, branch, teller;
+
+ t = NULL;
+ acurs = bcurs = tcurs = NULL;
+
+ /*
+ * 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);
+
+ memset(&d_histdbt, 0, sizeof(d_histdbt));
+
+ memset(&k_histdbt, 0, sizeof(k_histdbt));
+ k_histdbt.data = &key;
+ k_histdbt.size = sizeof(key);
+
+ memset(&k_dbt, 0, sizeof(k_dbt));
+ k_dbt.size = sizeof(int);
+
+ memset(&d_dbt, 0, sizeof(d_dbt));
+ d_dbt.flags = DB_DBT_USERMEM;
+ d_dbt.data = &rec;
+ d_dbt.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.flags = DB_DBT_PARTIAL;
+
+ /* START TIMING */
+ if (txn_begin(dbenv, NULL, &t, 0) != 0)
+ goto err;
+
+ if (adb->cursor(adb, t, &acurs, 0) != 0 ||
+ bdb->cursor(bdb, t, &bcurs, 0) != 0 ||
+ tdb->cursor(tdb, t, &tcurs, 0) != 0)
+ goto err;
+
+ /* Account record */
+ k_dbt.data = &account;
+ if (acurs->c_get(acurs, &k_dbt, &d_dbt, DB_SET) != 0)
+ goto err;
+ rec.balance += 10;
+ if (acurs->c_put(acurs, &k_dbt, &d_dbt, DB_CURRENT) != 0)
+ goto err;
+
+ /* Branch record */
+ k_dbt.data = &branch;
+ if (bcurs->c_get(bcurs, &k_dbt, &d_dbt, DB_SET) != 0)
+ goto err;
+ rec.balance += 10;
+ if (bcurs->c_put(bcurs, &k_dbt, &d_dbt, DB_CURRENT) != 0)
+ goto err;
+
+ /* Teller record */
+ k_dbt.data = &teller;
+ if (tcurs->c_get(tcurs, &k_dbt, &d_dbt, DB_SET) != 0)
+ goto err;
+ rec.balance += 10;
+ if (tcurs->c_put(tcurs, &k_dbt, &d_dbt, DB_CURRENT) != 0)
+ goto err;
+
+ /* History record */
+ d_histdbt.flags = 0;
+ d_histdbt.data = &hrec;
+ d_histdbt.ulen = sizeof(hrec);
+ if (hdb->put(hdb, t, &k_histdbt, &d_histdbt, DB_APPEND) != 0)
+ goto err;
+
+ if (acurs->c_close(acurs) != 0 || bcurs->c_close(bcurs) != 0 ||
+ tcurs->c_close(tcurs) != 0)
+ goto err;
+
+ if (txn_commit(t, 0) != 0)
+ goto err;
+
+ /* END TIMING */
+ return (0);
+
+err: if (acurs != NULL)
+ (void)acurs->c_close(acurs);
+ if (bcurs != NULL)
+ (void)bcurs->c_close(bcurs);
+ if (tcurs != NULL)
+ (void)tcurs->c_close(tcurs);
+ if (t != NULL)
+ (void)txn_abort(t);
+
+ if (verbose)
+ printf("Transaction A=%ld B=%ld T=%ld failed\n",
+ (long)account, (long)branch, (long)teller);
+ return (-1);
+}
diff --git a/db/examples_c/ex_tpcb.h b/db/examples_c/ex_tpcb.h
new file mode 100644
index 000000000..ef90bc532
--- /dev/null
+++ b/db/examples_c/ex_tpcb.h
@@ -0,0 +1,39 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1996, 1997, 1998, 1999, 2000
+ * Sleepycat Software. All rights reserved.
+ *
+ * $Id: ex_tpcb.h,v 11.4 2000/05/17 19:21:02 bostic Exp $
+ */
+
+#ifndef _TPCB_H_
+#define _TPCB_H_
+
+typedef enum { ACCOUNT, BRANCH, TELLER } FTYPE;
+
+#define TELLERS_PER_BRANCH 100
+#define ACCOUNTS_PER_TELLER 1000
+
+#define ACCOUNTS 1000000
+#define BRANCHES 10
+#define TELLERS 1000
+#define HISTORY 1000000
+#define HISTORY_LEN 100
+#define RECLEN 100
+#define BEGID 1000000
+
+typedef struct _defrec {
+ u_int32_t id;
+ u_int32_t balance;
+ u_int8_t pad[RECLEN - sizeof(u_int32_t) - sizeof(u_int32_t)];
+} defrec;
+
+typedef 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)];
+} histrec;
+#endif /* _TPCB_H_ */