summaryrefslogtreecommitdiff
path: root/bdb/examples_c/ex_thread.c
diff options
context:
space:
mode:
Diffstat (limited to 'bdb/examples_c/ex_thread.c')
-rw-r--r--bdb/examples_c/ex_thread.c629
1 files changed, 0 insertions, 629 deletions
diff --git a/bdb/examples_c/ex_thread.c b/bdb/examples_c/ex_thread.c
deleted file mode 100644
index 104de37ad38..00000000000
--- a/bdb/examples_c/ex_thread.c
+++ /dev/null
@@ -1,629 +0,0 @@
-/*-
- * See the file LICENSE for redistribution information.
- *
- * Copyright (c) 1997-2002
- * Sleepycat Software. All rights reserved.
- *
- * $Id: ex_thread.c,v 11.34 2002/08/15 14:37:13 bostic Exp $
- */
-
-#include <sys/types.h>
-#include <sys/time.h>
-
-#include <errno.h>
-#include <pthread.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-#ifdef _WIN32
-extern int getopt(int, char * const *, const char *);
-#else
-#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. */
-
-int db_init __P((const char *));
-void *deadlock __P((void *));
-void fatal __P((const char *, int, int));
-void onint __P((int));
-int main __P((int, char *[]));
-int reader __P((int));
-void stats __P((void));
-void *trickle __P((void *));
-void *tstart __P((void *));
-int usage __P((void));
-void word __P((void));
-int writer __P((int));
-
-int quit; /* Interrupt handling flag. */
-
-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;
- DB_TXN *txnp;
- pthread_t *tids;
- int ch, i, ret;
- const char *home;
- void *retp;
-
- txnp = NULL;
- 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:
- return (usage());
- }
- argc -= optind;
- argv += optind;
-
- /* Initialize the random number generator. */
- srand(getpid() | time(NULL));
-
- /* Register the signal handler. */
- (void)signal(SIGINT, onint);
-
- /* Build the key list. */
- word();
-
- /* Remove the previous database. */
- (void)remove(DATABASE);
-
- /* Initialize the database environment. */
- if ((ret = db_init(home)) != 0)
- return (ret);
-
- /* Initialize the database. */
- if ((ret = db_create(&dbp, dbenv, 0)) != 0) {
- dbenv->err(dbenv, ret, "db_create");
- (void)dbenv->close(dbenv, 0);
- return (EXIT_FAILURE);
- }
- if ((ret = dbp->set_pagesize(dbp, 1024)) != 0) {
- dbp->err(dbp, ret, "set_pagesize");
- goto err;
- }
-
- if ((ret = dbenv->txn_begin(dbenv, NULL, &txnp, 0)) != 0)
- fatal("txn_begin", ret, 1);
- if ((ret = dbp->open(dbp, txnp,
- DATABASE, NULL, DB_BTREE, DB_CREATE | DB_THREAD, 0664)) != 0) {
- dbp->err(dbp, ret, "%s: open", DATABASE);
- goto err;
- } else {
- ret = txnp->commit(txnp, 0);
- txnp = NULL;
- if (ret != 0)
- 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 ((ret =
- pthread_create(&tids[i], NULL, tstart, (void *)i)) != 0)
- fatal("pthread_create", ret > 0 ? ret : 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);
-
- printf("Exiting\n");
- stats();
-
-err: if (txnp != NULL)
- (void)txnp->abort(txnp);
- (void)dbp->close(dbp, 0);
- (void)dbenv->close(dbenv, 0);
-
- return (EXIT_SUCCESS);
-}
-
-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.
- */
- while (!quit) {
- /* 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;
-
- while (!quit) {
- /* 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 = tid->abort(tid)) != 0)
- fatal("DB_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 = dbenv->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 = tid->commit(tid, 0)) != 0)
- fatal("DB_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.
- */
-int
-db_init(home)
- const char *home;
-{
- int ret;
-
- if ((ret = db_env_create(&dbenv, 0)) != 0) {
- fprintf(stderr,
- "%s: db_env_create: %s\n", progname, db_strerror(ret));
- return (EXIT_FAILURE);
- }
- if (punish) {
- (void)dbenv->set_flags(dbenv, DB_YIELDCPU, 1);
- (void)db_env_set_func_yield(sched_yield);
- }
-
- 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);
- return (EXIT_FAILURE);
- }
-
- return (0);
-}
-
-/*
- * 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 DB_ENV->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;
- while (!quit) {
- (void)dbenv->lock_detect(dbenv, 0, DB_LOCK_YOUNGEST, NULL);
-
- /* Check every 100ms. */
- (void)select(0, NULL, NULL, NULL, &t);
- }
-
- 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);
-
- while (!quit) {
- (void)dbenv->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();
- }
- }
-
- 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)
- const 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(EXIT_FAILURE);
-
- /* NOTREACHED */
-}
-
-/*
- * usage --
- * Usage message.
- */
-int
-usage()
-{
- (void)fprintf(stderr,
- "usage: %s [-pv] [-h home] [-n words] [-r readers] [-w writers]\n",
- progname);
- return (EXIT_FAILURE);
-}
-
-/*
- * onint --
- * Interrupt signal handler.
- */
-void
-onint(signo)
- int signo;
-{
- signo = 0; /* Quiet compiler. */
- quit = 1;
-}