Commit 6c578d51 authored by ram@mysql.r18.ru's avatar ram@mysql.r18.ru

bdb/ cleanup (SCRUM)

parent 7436e9ec
...@@ -71,7 +71,7 @@ head defonly _DB_INT_DEF_IN_ > $i_dfile ...@@ -71,7 +71,7 @@ head defonly _DB_INT_DEF_IN_ > $i_dfile
# Process the standard directories, creating per-directory prototype # Process the standard directories, creating per-directory prototype
# files and adding to the external prototype and #define files. # files and adding to the external prototype and #define files.
for i in db btree clib common crypto dbreg env fileops hash hmac \ for i in db btree clib common dbreg env fileops hash hmac \
lock log mp mutex os qam rep rpc_client rpc_server tcl txn xa; do lock log mp mutex os qam rep rpc_client rpc_server tcl txn xa; do
head "_${i}_ext_h_" > $i_pfile head "_${i}_ext_h_" > $i_pfile
......
...@@ -66,4 +66,4 @@ for i in db dbreg btree fileops hash qam txn; do ...@@ -66,4 +66,4 @@ for i in db dbreg btree fileops hash qam txn; do
done done
# Build the example application's recovery routines. # Build the example application's recovery routines.
(cd ../examples_c/ex_apprec && sh auto_rebuild) #(cd ../examples_c/ex_apprec && sh auto_rebuild)
...@@ -14,7 +14,7 @@ build btree/tags ../dist/tags ...@@ -14,7 +14,7 @@ build btree/tags ../dist/tags
build build_unix/tags ../dist/tags build build_unix/tags ../dist/tags
build clib/tags ../dist/tags build clib/tags ../dist/tags
build common/tags ../dist/tags build common/tags ../dist/tags
build crypto/tags ../dist/tags #build crypto/tags ../dist/tags
build cxx/tags ../dist/tags build cxx/tags ../dist/tags
build db/tags ../dist/tags build db/tags ../dist/tags
build db185/tags ../dist/tags build db185/tags ../dist/tags
...@@ -34,9 +34,9 @@ build dbinc_auto/tags ../dist/tags ...@@ -34,9 +34,9 @@ build dbinc_auto/tags ../dist/tags
build dbm/tags ../dist/tags build dbm/tags ../dist/tags
build dbreg/tags ../dist/tags build dbreg/tags ../dist/tags
build env/tags ../dist/tags build env/tags ../dist/tags
build examples_c/tags ../dist/tags #build examples_c/tags ../dist/tags
build examples_cxx/tags ../dist/tags #build examples_cxx/tags ../dist/tags
build examples_java java/src/com/sleepycat/examples #build examples_java java/src/com/sleepycat/examples
build fileops/tags ../dist/tags build fileops/tags ../dist/tags
build hash/tags ../dist/tags build hash/tags ../dist/tags
build hmac/tags ../dist/tags build hmac/tags ../dist/tags
......
# $Id: README,v 11.5 2002/02/26 16:22:45 krinsky Exp $
ex_access.c Using just the DB access methods.
ex_apprec Application-specific recovery.
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_repquote Replication. This creates a toy stock quote server
with DB's single-master, multiple-client replication,
with communication over TCP.
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.
/*-
* Copyright (c) 2001-2002
* Sleepycat Software. All rights reserved.
*
* $Id: bench_001.c,v 1.13 2002/08/15 02:45:39 bostic Exp $
*/
/*
* bench_001 - time bulk fetch interface.
* Without -R builds a btree acording to the arguments.
* With -R runs and times bulk fetches. If -d is specified
* during reads the DB_MULTIPLE interface is used
* otherwise the DB_MULTIPLE_KEY interface is used.
*
* ARGUMENTS:
* -c cachesize [1000 * pagesize]
* -d number of duplicates [none]
* -E don't use environment
* -I Just initialize the environment
* -i number of read iterations [1000000]
* -l length of data item [20]
* -n number of keys [1000000]
* -p pagesize [65536]
* -R perform read test.
* -T incorporate transactions.
*
* COMPILE:
* cc -I /usr/local/BerkeleyDB/include \
* -o bench_001 -O2 bench_001.c /usr/local/BerkeleyDB/lib/libdb.so
*/
#include <sys/types.h>
#include <sys/time.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <db.h>
#define DATABASE "bench_001.db"
int main(int, char *[]);
void usage(void);
const char
*progname = "bench_001"; /* Program name. */
/*
* db_init --
* Initialize the environment.
*/
DB_ENV *
db_init(home, prefix, cachesize, txn)
char *home, *prefix;
int cachesize, txn;
{
DB_ENV *dbenv;
int flags, 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);
(void)dbenv->set_cachesize(dbenv, 0,
cachesize == 0 ? 50 * 1024 * 1024 : (u_int32_t)cachesize, 0);
flags = DB_CREATE | DB_INIT_MPOOL;
if (txn)
flags |= DB_INIT_TXN | DB_INIT_LOCK;
if ((ret = dbenv->open(dbenv, home, flags, 0)) != 0) {
dbenv->err(dbenv, ret, "DB_ENV->open: %s", home);
(void)dbenv->close(dbenv, 0);
return (NULL);
}
return (dbenv);
}
/*
* get -- loop getting batches of records.
*
*/
int
get(dbp, txn, datalen, num, dups, iter, countp)
DB *dbp;
int txn, datalen, num, dups, iter, *countp;
{
DBC *dbcp;
DBT key, data;
DB_TXN *txnp;
u_int32_t len, klen;
int count, flags, i, j, ret;
void *pointer, *dp, *kp;
memset(&key, 0, sizeof(key));
key.data = &j;
key.size = sizeof(j);
memset(&data, 0, sizeof(data));
data.flags = DB_DBT_USERMEM;
data.data = malloc(datalen*1024*1024);
data.ulen = data.size = datalen*1024*1024;
count = 0;
flags = DB_SET;
if (!dups)
flags |= DB_MULTIPLE_KEY;
else
flags |= DB_MULTIPLE;
for (i = 0; i < iter; i++) {
txnp = NULL;
if (txn)
dbp->dbenv->txn_begin(dbp->dbenv, NULL, &txnp, 0);
dbp->cursor(dbp, txnp, &dbcp, 0);
j = random() % num;
switch (ret = dbcp->c_get(dbcp, &key, &data, flags)) {
case 0:
break;
default:
dbp->err(dbcp->dbp, ret, "DBC->c_get");
return (ret);
}
DB_MULTIPLE_INIT(pointer, &data);
if (dups)
while (pointer != NULL) {
DB_MULTIPLE_NEXT(pointer, &data, dp, len);
if (dp != NULL)
count++;
}
else
while (pointer != NULL) {
DB_MULTIPLE_KEY_NEXT(pointer,
&data, kp, klen, dp, len);
if (kp != NULL)
count++;
}
dbcp->c_close(dbcp);
if (txn)
txnp->commit(txnp, 0);
}
*countp = count;
return (0);
}
/*
* fill - fill a db
* Since we open/created the db with transactions (potentially),
* we need to populate it with transactions. We'll bundle the puts
* 10 to a transaction.
*/
#define PUTS_PER_TXN 10
int
fill(dbenv, dbp, txn, datalen, num, dups)
DB_ENV *dbenv;
DB *dbp;
int txn, datalen, num, dups;
{
DBT key, data;
DB_TXN *txnp;
struct data {
int id;
char str[1];
} *data_val;
int count, i, ret;
/*
* Insert records into the database, where the key is the user
* input and the data is the user input in reverse order.
*/
txnp = NULL;
ret = 0;
count = 0;
memset(&key, 0, sizeof(DBT));
memset(&data, 0, sizeof(DBT));
key.data = &i;
key.size = sizeof(i);
data.data = data_val = (struct data *) malloc(datalen);
memcpy(data_val->str, "0123456789012345678901234567890123456789",
datalen - sizeof (data_val->id));
data.size = datalen;
data.flags = DB_DBT_USERMEM;
for (i = 0; i < num; i++) {
if (txn != 0 && i % PUTS_PER_TXN == 0) {
if (txnp != NULL) {
ret = txnp->commit(txnp, 0);
txnp = NULL;
if (ret != 0)
goto err;
}
if ((ret =
dbenv->txn_begin(dbenv, NULL, &txnp, 0)) != 0)
goto err;
}
data_val->id = 0;
do {
switch (ret =
dbp->put(dbp, txnp, &key, &data, 0)) {
case 0:
count++;
break;
default:
dbp->err(dbp, ret, "DB->put");
goto err;
}
} while (++data_val->id < dups);
}
if (txnp != NULL)
ret = txnp->commit(txnp, 0);
printf("%d\n", count);
return (ret);
err: if (txnp != NULL)
(void)txnp->abort(txnp);
return (ret);
}
int
main(argc, argv)
int argc;
char *argv[];
{
extern char *optarg;
extern int optind;
DB *dbp;
DB_ENV *dbenv;
DB_TXN *txnp;
struct timeval start_time, end_time;
double secs;
int cache, ch, count, datalen, dups, env, init, iter, num, pagesize;
int ret, rflag, txn;
txnp = NULL;
datalen = 20;
iter = num = 1000000;
env = 1;
dups = init = rflag = txn = 0;
pagesize = 65536;
cache = 1000 * pagesize;
while ((ch = getopt(argc, argv, "c:d:EIi:l:n:p:RT")) != EOF)
switch (ch) {
case 'c':
cache = atoi(optarg);
break;
case 'd':
dups = atoi(optarg);
break;
case 'E':
env = 0;
break;
case 'I':
init = 1;
break;
case 'i':
iter = atoi(optarg);
break;
case 'l':
datalen = atoi(optarg);
break;
case 'n':
num = atoi(optarg);
break;
case 'p':
pagesize = atoi(optarg);
break;
case 'R':
rflag = 1;
break;
case 'T':
txn = 1;
break;
case '?':
default:
usage();
}
argc -= optind;
argv += optind;
/* Remove the previous database. */
if (!rflag) {
if (env)
system("rm -rf BENCH_001; mkdir BENCH_001");
else
(void)unlink(DATABASE);
}
dbenv = NULL;
if (env == 1 &&
(dbenv = db_init("BENCH_001", "bench_001", cache, txn)) == NULL)
return (-1);
if (init)
exit(0);
/* 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));
exit(EXIT_FAILURE);
}
dbp->set_errfile(dbp, stderr);
dbp->set_errpfx(dbp, progname);
if ((ret = dbp->set_pagesize(dbp, pagesize)) != 0) {
dbp->err(dbp, ret, "set_pagesize");
goto err1;
}
if (dups && (ret = dbp->set_flags(dbp, DB_DUP)) != 0) {
dbp->err(dbp, ret, "set_flags");
goto err1;
}
if (env == 0 && (ret = dbp->set_cachesize(dbp, 0, cache, 0)) != 0) {
dbp->err(dbp, ret, "set_cachesize");
goto err1;
}
if ((ret = dbp->set_flags(dbp, DB_DUP)) != 0) {
dbp->err(dbp, ret, "set_flags");
goto err1;
}
if (txn != 0)
if ((ret = dbenv->txn_begin(dbenv, NULL, &txnp, 0)) != 0)
goto err1;
if ((ret = dbp->open(
dbp, txnp, DATABASE, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) {
dbp->err(dbp, ret, "%s: open", DATABASE);
if (txnp != NULL)
(void)txnp->abort(txnp);
goto err1;
}
if (txnp != NULL)
ret = txnp->commit(txnp, 0);
txnp = NULL;
if (ret != 0)
goto err1;
if (rflag) {
/* If no environment, fill the cache. */
if (!env && (ret =
get(dbp, txn, datalen, num, dups, iter, &count)) != 0)
goto err1;
/* Time the get loop. */
gettimeofday(&start_time, NULL);
if ((ret =
get(dbp, txn, datalen, num, dups, iter, &count)) != 0)
goto err1;
gettimeofday(&end_time, NULL);
secs =
(((double)end_time.tv_sec * 1000000 + end_time.tv_usec) -
((double)start_time.tv_sec * 1000000 + start_time.tv_usec))
/ 1000000;
printf("%d records read using %d batches in %.2f seconds: ",
count, iter, secs);
printf("%.0f records/second\n", (double)count / secs);
} else if ((ret = fill(dbenv, dbp, txn, datalen, num, dups)) != 0)
goto err1;
/* Close everything down. */
if ((ret = dbp->close(dbp, rflag ? DB_NOSYNC : 0)) != 0) {
fprintf(stderr,
"%s: DB->close: %s\n", progname, db_strerror(ret));
return (1);
}
return (ret);
err1: (void)dbp->close(dbp, 0);
return (1);
}
void
usage()
{
(void)fprintf(stderr, "usage: %s %s\n\t%s\n",
progname, "[-EIRT] [-c cachesize] [-d dups]",
"[-i iterations] [-l datalen] [-n keys] [-p pagesize]");
exit(EXIT_FAILURE);
}
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Sleepycat Software. All rights reserved.
*
* $Id: ex_access.c,v 11.22 2002/09/03 12:54:26 bostic Exp $
*/
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
extern int getopt(int, char * const *, const char *);
#else
#include <unistd.h>
#endif
#include <db.h>
#define DATABASE "access.db"
int main __P((int, char *[]));
int usage __P((void));
int
main(argc, argv)
int argc;
char *argv[];
{
extern int optind;
DB *dbp;
DBC *dbcp;
DBT key, data;
u_int32_t len;
int ch, ret, rflag;
char *database, *p, *t, buf[1024], rbuf[1024];
const char *progname = "ex_access"; /* Program name. */
rflag = 0;
while ((ch = getopt(argc, argv, "r")) != EOF)
switch (ch) {
case 'r':
rflag = 1;
break;
case '?':
default:
return (usage());
}
argc -= optind;
argv += optind;
/* Accept optional database name. */
database = *argv == NULL ? DATABASE : argv[0];
/* Optionally discard the database. */
if (rflag)
(void)remove(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 (EXIT_FAILURE);
}
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,
NULL, 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 (strcmp(buf, "exit\n") == 0 || strcmp(buf, "quit\n") == 0)
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 (EXIT_FAILURE);
}
return (EXIT_SUCCESS);
err2: (void)dbcp->c_close(dbcp);
err1: (void)dbp->close(dbp, 0);
return (EXIT_FAILURE);
}
int
usage()
{
(void)fprintf(stderr, "usage: ex_access [-r] [database]\n");
return (EXIT_FAILURE);
}
# Script to rebuild automatically generated files for ex_apprec.
E=../examples_c/ex_apprec
cd ../../dist
awk -f gen_rec.awk \
-v source_file=$E/ex_apprec_auto.c \
-v header_file=$E/ex_apprec_auto.h \
-v template_file=$E/ex_apprec_template < $E/ex_apprec.src
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2002
* Sleepycat Software. All rights reserved.
*
* $Id: ex_apprec.c,v 1.2 2002/08/06 05:39:01 bostic Exp $
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <db.h>
#include "ex_apprec.h"
int apprec_dispatch __P((DB_ENV *, DBT *, DB_LSN *, db_recops));
int open_env __P((const char *, FILE *, const char *, DB_ENV **));
int verify_absence __P((DB_ENV *, const char *));
int verify_presence __P((DB_ENV *, const char *));
int
main(argc, argv)
int argc;
char *argv[];
{
extern char *optarg;
extern int optind;
DB_ENV *dbenv;
DB_LSN lsn;
DB_TXN *txn;
DBT dirnamedbt;
int ret;
const char *home;
char ch, dirname[256];
const char *progname = "ex_apprec"; /* Program name. */
/* Default home. */
home = "TESTDIR";
while ((ch = getopt(argc, argv, "h:")) != EOF)
switch (ch) {
case 'h':
home = optarg;
break;
default:
fprintf(stderr, "usage: %s [-h home]", progname);
exit(EXIT_FAILURE);
}
printf("Set up environment.\n");
if ((ret = open_env(home, stderr, progname, &dbenv)) != 0)
return (EXIT_FAILURE);
printf("Create a directory in a transaction.\n");
/*
* This application's convention is to log the full directory name,
* including trailing nul.
*/
memset(&dirnamedbt, 0, sizeof(dirnamedbt));
sprintf(dirname, "%s/MYDIRECTORY", home);
dirnamedbt.data = dirname;
dirnamedbt.size = strlen(dirname) + 1;
if ((ret = dbenv->txn_begin(dbenv, NULL, &txn, 0)) != 0) {
dbenv->err(dbenv, ret, "txn_begin");
return (EXIT_FAILURE);
}
/* Remember, always log actions before you execute them! */
memset(&lsn, 0, sizeof(lsn));
if ((ret =
ex_apprec_mkdir_log(dbenv, txn, &lsn, 0, &dirnamedbt)) != 0) {
dbenv->err(dbenv, ret, "mkdir_log");
return (EXIT_FAILURE);
}
if (mkdir(dirname, 0755) != 0) {
dbenv->err(dbenv, errno, "mkdir");
return (EXIT_FAILURE);
}
printf("Verify the directory's presence: ");
verify_presence(dbenv, dirname);
printf("check.\n");
/* Now abort the transaction and verify that the directory goes away. */
printf("Abort the transaction.\n");
if ((ret = txn->abort(txn)) != 0) {
dbenv->err(dbenv, ret, "txn_abort");
return (EXIT_FAILURE);
}
printf("Verify the directory's absence: ");
verify_absence(dbenv, dirname);
printf("check.\n");
/* Now do the same thing over again, only with a commit this time. */
printf("Create a directory in a transaction.\n");
memset(&dirnamedbt, 0, sizeof(dirnamedbt));
sprintf(dirname, "%s/MYDIRECTORY", home);
dirnamedbt.data = dirname;
dirnamedbt.size = strlen(dirname) + 1;
if ((ret = dbenv->txn_begin(dbenv, NULL, &txn, 0)) != 0) {
dbenv->err(dbenv, ret, "txn_begin");
return (EXIT_FAILURE);
}
memset(&lsn, 0, sizeof(lsn));
if ((ret =
ex_apprec_mkdir_log(dbenv, txn, &lsn, 0, &dirnamedbt)) != 0) {
dbenv->err(dbenv, ret, "mkdir_log");
return (EXIT_FAILURE);
}
if (mkdir(dirname, 0755) != 0) {
dbenv->err(dbenv, errno, "mkdir");
return (EXIT_FAILURE);
}
printf("Verify the directory's presence: ");
verify_presence(dbenv, dirname);
printf("check.\n");
/* Now abort the transaction and verify that the directory goes away. */
printf("Commit the transaction.\n");
if ((ret = txn->commit(txn, 0)) != 0) {
dbenv->err(dbenv, ret, "txn_commit");
return (EXIT_FAILURE);
}
printf("Verify the directory's presence: ");
verify_presence(dbenv, dirname);
printf("check.\n");
printf("Now remove the directory, then run recovery.\n");
if ((ret = dbenv->close(dbenv, 0)) != 0) {
fprintf(stderr, "DB_ENV->close: %s\n", db_strerror(ret));
return (EXIT_FAILURE);
}
if (rmdir(dirname) != 0) {
fprintf(stderr,
"%s: rmdir failed with error %s", progname,
strerror(errno));
}
verify_absence(dbenv, dirname);
/* Opening with DB_RECOVER runs recovery. */
if ((ret = open_env(home, stderr, progname, &dbenv)) != 0)
return (EXIT_FAILURE);
printf("Verify the directory's presence: ");
verify_presence(dbenv, dirname);
printf("check.\n");
/* Close the handle. */
if ((ret = dbenv->close(dbenv, 0)) != 0) {
fprintf(stderr, "DB_ENV->close: %s\n", db_strerror(ret));
return (EXIT_FAILURE);
}
return (EXIT_SUCCESS);
}
int
open_env(home, errfp, progname, dbenvp)
const char *home, *progname;
FILE *errfp;
DB_ENV **dbenvp;
{
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 (ret);
}
dbenv->set_errfile(dbenv, errfp);
dbenv->set_errpfx(dbenv, progname);
/* Set up our custom recovery dispatch function. */
if ((ret = dbenv->set_app_dispatch(dbenv, apprec_dispatch)) != 0) {
dbenv->err(dbenv, ret, "set_app_dispatch");
return (ret);
}
/*
* Open the environment with full transactional support, running
* recovery.
*/
if ((ret =
dbenv->open(dbenv, home, DB_CREATE | DB_RECOVER | 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 (ret);
}
*dbenvp = dbenv;
return (0);
}
/*
* Sample application dispatch function to handle user-specified log record
* types.
*/
int
apprec_dispatch(dbenv, dbt, lsn, op)
DB_ENV *dbenv;
DBT *dbt;
DB_LSN *lsn;
db_recops op;
{
u_int32_t rectype;
/* Pull the record type out of the log record. */
memcpy(&rectype, dbt->data, sizeof(rectype));
switch (rectype) {
case DB_ex_apprec_mkdir:
return (ex_apprec_mkdir_recover(dbenv, dbt, lsn, op, NULL));
default:
/*
* We've hit an unexpected, allegedly user-defined record
* type.
*/
dbenv->errx(dbenv, "Unexpected log record type encountered");
return (EINVAL);
}
}
int
verify_absence(dbenv, dirname)
DB_ENV *dbenv;
const char *dirname;
{
if (access(dirname, F_OK) == 0) {
dbenv->errx(dbenv, "Error--directory present!");
exit(EXIT_FAILURE);
}
return (0);
}
int
verify_presence(dbenv, dirname)
DB_ENV *dbenv;
const char *dirname;
{
if (access(dirname, F_OK) != 0) {
dbenv->errx(dbenv, "Error--directory not present!");
exit(EXIT_FAILURE);
}
return (0);
}
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002
* Sleepycat Software. All rights reserved.
*
* $Id: ex_apprec.h,v 1.2 2002/08/08 15:47:00 bostic Exp $
*/
#ifndef _EX_APPREC_H_
#define _EX_APPREC_H_
#include "ex_apprec_auto.h"
int ex_apprec_mkdir_log
__P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, const DBT *));
int ex_apprec_mkdir_print
__P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
int ex_apprec_mkdir_read
__P((DB_ENV *, void *, ex_apprec_mkdir_args **));
int ex_apprec_mkdir_recover
__P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
#endif /* !_EX_APPREC_H_ */
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002
* Sleepycat Software. All rights reserved.
*
* $Id: ex_apprec.src,v 1.3 2002/08/08 15:47:00 bostic Exp $
*/
PREFIX ex_apprec
/*
* This is the source file used to generate the application-specific recovery
* functions used by the ex_apprec example. It should be turned into usable
* source code (including a template for the recovery function itself) by
* invoking changing to the dist directory of the DB distribution and
* running the gen_rec.awk script there as follows:
*
* awk -f ./gen_rec.awk \
* -v source_file=../examples_c/ex_apprec/ex_apprec_auto.c \
* -v header_file=../examples_c/ex_apprec/ex_apprec_auto.h \
* -v template_file=../examples_c/ex_apprec/ex_apprec_template \
* < ../examples_c/ex_apprec/ex_apprec.src
INCLUDE #include <ctype.h>
INCLUDE #include <errno.h>
INCLUDE #include <stdlib.h>
INCLUDE #include <string.h>
INCLUDE
INCLUDE #include <db.h>
INCLUDE
INCLUDE #include "ex_apprec.h"
/*
* mkdir: used to create a directory
*
* dirname: relative or absolute pathname of the directory to be created
*/
BEGIN mkdir 10000
DBT dirname DBT s
END
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2002
* Sleepycat Software. All rights reserved.
*
* $Id: ex_apprec_rec.c,v 1.2 2002/08/06 05:39:02 bostic Exp $
*/
/*
* This file is based on the template file ex_apprec_template. Note that
* because ex_apprec_mkdir, like most application-specific recovery functions,
* does not make use of DB-private structures, it has actually been simplified
* significantly.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <db.h>
#include "ex_apprec.h"
/*
* ex_apprec_mkdir_recover --
* Recovery function for mkdir.
*
* PUBLIC: int ex_apprec_mkdir_recover
* PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
*/
int
ex_apprec_mkdir_recover(dbenv, dbtp, lsnp, op, info)
DB_ENV *dbenv;
DBT *dbtp;
DB_LSN *lsnp;
db_recops op;
void *info;
{
ex_apprec_mkdir_args *argp;
int ret;
argp = NULL;
/*
* Shut up the compiler--"info" is used for the recovery functions
* belonging to transaction meta-operations such as txn_create, and
* need not concern us here either.
*/
info = NULL;
if ((ret = ex_apprec_mkdir_read(dbenv, dbtp->data, &argp)) != 0)
goto out;
switch (op) {
case DB_TXN_ABORT:
case DB_TXN_BACKWARD_ROLL:
/*
* If we're aborting, we need to remove the directory if it
* exists. We log the trailing zero in pathnames, so we can
* simply pass the data part of the DBT into rmdir as a string.
* (Note that we don't have any alignment guarantees, but for
* a char * this doesn't matter.)
*
* Ignore all errors other than ENOENT; DB may attempt to undo
* or redo operations without knowing whether they have already
* been done or undone, so we should never assume in a recovery
* function that the task definitely needs doing or undoing.
*/
ret = rmdir(argp->dirname.data);
if (ret != 0 && errno != ENOENT)
dbenv->err(dbenv, ret, "Error in abort of mkdir");
else
ret = 0;
break;
case DB_TXN_FORWARD_ROLL:
/*
* The forward direction is just the opposite; here, we ignore
* EEXIST, because the directory may already exist.
*/
ret = mkdir(argp->dirname.data, 0755);
if (ret != 0 && errno != EEXIST)
dbenv->err(dbenv,
ret, "Error in roll-forward of mkdir");
else
ret = 0;
break;
default:
/*
* We might want to handle DB_TXN_PRINT or DB_TXN_APPLY here,
* too, but we don't try to print the log records and aren't
* using replication, so there's no need to in this example.
*/
dbenv->errx(dbenv, "Unexpected operation type\n");
return (EINVAL);
}
/*
* The recovery function is responsible for returning the LSN of the
* previous log record in this transaction, so that transaction aborts
* can follow the chain backwards.
*
* (If we'd wanted the LSN of this record earlier, we could have
* read it from lsnp, as well--but because we weren't working with
* pages or other objects that store their LSN and base recovery
* decisions on it, we didn't need to.)
*/
*lsnp = argp->prev_lsn;
out: if (argp != NULL)
free(argp);
return (ret);
}
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Sleepycat Software. All rights reserved.
*
* $Id: ex_btrec.c,v 11.18 2002/01/23 15:33:18 bostic Exp $
*/
#include <sys/types.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <db.h>
#define DATABASE "access.db"
#define WORDLIST "../test/wordlist"
int main __P((void));
int ex_btrec __P((void));
void show __P((const char *, DBT *, DBT *));
int
main()
{
return (ex_btrec() == 1 ? EXIT_FAILURE : EXIT_SUCCESS);
}
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 (1);
}
/* Remove the previous database. */
(void)remove(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 (1);
}
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 (1);
} /* Record numbers. */
if ((ret = dbp->set_flags(dbp, DB_RECNUM)) != 0) {
dbp->err(dbp, ret, "set_flags: DB_RECNUM");
return (1);
}
if ((ret = dbp->open(dbp,
NULL, DATABASE, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) {
dbp->err(dbp, ret, "open: %s", DATABASE);
return (1);
}
/*
* 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, 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 (1);
}
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)
const char *msg;
DBT *key, *data;
{
printf("%s%.*s : %.*s\n", msg,
(int)key->size, (char *)key->data,
(int)data->size, (char *)data->data);
}
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2002
* Sleepycat Software. All rights reserved.
*
* $Id: ex_dbclient.c,v 1.28 2002/08/06 06:11:24 bostic Exp $
*/
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <db.h>
#define DATABASE_HOME "database"
#define DATABASE "access.db"
int db_clientrun __P((DB_ENV *, const char *));
int ex_dbclient_run __P((const char *, FILE *, const char *, const char *));
int main __P((int, char *[]));
/*
* An example of a program creating/configuring a Berkeley DB environment.
*/
int
main(argc, argv)
int argc;
char *argv[];
{
const char *home;
if (argc != 2) {
fprintf(stderr, "Usage: %s hostname\n", argv[0]);
return (EXIT_FAILURE);
}
/*
* All of the shared database files live in DATABASE_HOME, but
* data files will live in CONFIG_DATA_DIR.
*/
home = DATABASE_HOME;
return (ex_dbclient_run(home,
stderr, argv[1], argv[0]) == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
int
ex_dbclient(host)
const char *host;
{
const char *home;
const 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)
const 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 (1);
}
retry = 0;
retry:
while (retry < 5) {
/*
* Set the server host we are talking to.
*/
if ((ret = dbenv->set_rpc_server(dbenv, NULL, host, 10000,
10000, 0)) != 0) {
fprintf(stderr, "Try %d: DB_ENV->set_rpc_server: %s\n",
retry, db_strerror(ret));
retry++;
sleep(15);
} else
break;
}
if (retry >= 5) {
fprintf(stderr,
"DB_ENV->set_rpc_server: %s\n", db_strerror(ret));
dbenv->close(dbenv, 0);
return (1);
}
/*
* 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 (1);
}
/*
* 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, 0)) != 0) {
dbenv->err(dbenv, ret, "environment open: %s", home);
dbenv->close(dbenv, 0);
if (ret == DB_NOSERVER)
goto retry;
return (1);
}
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, "DB_ENV->close: %s\n", db_strerror(ret));
return (1);
}
return (0);
}
int
db_clientrun(dbenv, progname)
DB_ENV *dbenv;
const 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,
NULL, 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);
}
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2002
* Sleepycat Software. All rights reserved.
*
* $Id: ex_env.c,v 11.27 2002/08/15 14:34:11 bostic Exp $
*/
#include <sys/types.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#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
#define DATABASE_HOME "/tmp/database"
#define CONFIG_DATA_DIR "/database/files"
#endif
#endif
int db_setup __P((const char *, const char *, FILE *, const char *));
int db_teardown __P((const char *, const char *, FILE *, const char *));
int main __P((void));
/*
* An example of a program creating/configuring a Berkeley DB environment.
*/
int
main()
{
const char *data_dir, *home;
const 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 (db_setup(home, data_dir, stderr, progname) != 0)
return (EXIT_FAILURE);
printf("Teardown env\n");
if (db_teardown(home, data_dir, stderr, progname) != 0)
return (EXIT_FAILURE);
return (EXIT_SUCCESS);
}
int
db_setup(home, data_dir, errfp, progname)
const 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 (1);
}
dbenv->set_errfile(dbenv, errfp);
dbenv->set_errpfx(dbenv, progname);
/*
* 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 (1);
}
/* 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 (1);
}
/* Do something interesting... */
/* Close the handle. */
if ((ret = dbenv->close(dbenv, 0)) != 0) {
fprintf(stderr, "DB_ENV->close: %s\n", db_strerror(ret));
return (1);
}
return (0);
}
int
db_teardown(home, data_dir, errfp, progname)
const 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 (1);
}
dbenv->set_errfile(dbenv, errfp);
dbenv->set_errpfx(dbenv, progname);
(void)dbenv->set_data_dir(dbenv, data_dir);
if ((ret = dbenv->remove(dbenv, home, 0)) != 0) {
fprintf(stderr, "DB_ENV->remove: %s\n", db_strerror(ret));
return (1);
}
return (0);
}
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Sleepycat Software. All rights reserved.
*
* $Id: ex_lock.c,v 11.18 2002/04/10 21:48:20 bostic Exp $
*/
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
extern int getopt(int, char * const *, const char *);
#else
#include <unistd.h>
#endif
#include <db.h>
int db_init __P((const char *, u_int32_t, int));
int main __P((int, char *[]));
int 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;
const char *home;
char 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)
return (usage());
maxlocks = (u_int32_t)i; /* XXX: possible overflow. */
break;
case 'u':
do_unlink = 1;
break;
case '?':
default:
return (usage());
}
argc -= optind;
argv += optind;
if (argc != 0)
return (usage());
/* Initialize the database environment. */
if ((ret = db_init(home, maxlocks, do_unlink)) != 0)
return (ret);
locks = 0;
lockcount = 0;
/*
* Accept lock requests.
*/
if ((ret = dbenv->lock_id(dbenv, &locker)) != 0) {
dbenv->err(dbenv, ret, "unable to get locker id");
(void)dbenv->close(dbenv, 0);
return (EXIT_FAILURE);
}
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 = dbenv->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 = dbenv->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);
return (EXIT_FAILURE);
}
}
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 (EXIT_FAILURE);
}
return (EXIT_SUCCESS);
}
/*
* db_init --
* Initialize the environment.
*/
int
db_init(home, maxlocks, do_unlink)
const 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));
return (EXIT_FAILURE);
}
if (do_unlink) {
if ((ret = dbenv->remove(dbenv, home, DB_FORCE)) != 0) {
fprintf(stderr, "%s: dbenv->remove: %s\n",
progname, db_strerror(ret));
return (EXIT_FAILURE);
}
if ((ret = db_env_create(&dbenv, 0)) != 0) {
fprintf(stderr, "%s: db_env_create: %s\n",
progname, db_strerror(ret));
return (EXIT_FAILURE);
}
}
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);
return (EXIT_FAILURE);
}
return (0);
}
int
usage()
{
(void)fprintf(stderr,
"usage: %s [-u] [-h home] [-m maxlocks]\n", progname);
return (EXIT_FAILURE);
}
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Sleepycat Software. All rights reserved.
*
* $Id: ex_mpool.c,v 11.26 2002/08/15 14:34:56 bostic Exp $
*/
#include <sys/types.h>
#include <errno.h>
#include <fcntl.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>
int init __P((const char *, int, int, const char *));
int run __P((int, int, int, int, const char *));
int run_mpool __P((int, int, int, int, const char *));
int main __P((int, char *[]));
int usage __P((const char *));
#define MPOOL "mpool" /* File. */
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)
return (usage(progname));
break;
case 'h':
if ((hits = atoi(optarg)) <= 0)
return (usage(progname));
break;
case 'n':
if ((npages = atoi(optarg)) <= 0)
return (usage(progname));
break;
case 'p':
if ((pagesize = atoi(optarg)) <= 0)
return (usage(progname));
break;
case '?':
default:
return (usage(progname));
}
argc -= optind;
argv += optind;
return (run_mpool(pagesize, cachesize,
hits, npages, progname) == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
int
usage(progname)
const char *progname;
{
(void)fprintf(stderr,
"usage: %s [-c cachesize] [-h hits] [-n npages] [-p pagesize]\n",
progname);
return (EXIT_FAILURE);
}
int
run_mpool(pagesize, cachesize, hits, npages, progname)
int pagesize, cachesize, hits, npages;
const 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)
const char *file, *progname;
int pagesize, npages;
{
FILE *fp;
int cnt;
char *p;
/*
* Create a file with the right number of pages, and store a page
* number on each page.
*/
if ((fp = fopen(file, "wb")) == NULL) {
fprintf(stderr,
"%s: %s: %s\n", progname, file, strerror(errno));
return (1);
}
if ((p = (char *)malloc(pagesize)) == NULL) {
fprintf(stderr, "%s: %s\n", progname, strerror(ENOMEM));
return (1);
}
/* The pages are numbered from 0. */
for (cnt = 0; cnt <= npages; ++cnt) {
*(int *)p = cnt;
if (fwrite(p, pagesize, 1, fp) != 1) {
fprintf(stderr,
"%s: %s: %s\n", progname, file, strerror(errno));
return (1);
}
}
(void)fclose(fp);
free(p);
return (0);
}
/*
* run --
* Get a set of pages.
*/
int
run(hits, cachesize, pagesize, npages, progname)
int hits, cachesize, pagesize, npages;
const char *progname;
{
DB_ENV *dbenv;
DB_MPOOLFILE *mfp;
db_pgno_t pageno;
int cnt, ret;
void *p;
dbenv = NULL;
mfp = NULL;
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 (1);
}
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 (1);
}
#endif
/* Set the cachesize. */
if ((ret = dbenv->set_cachesize(dbenv, 0, cachesize, 0)) != 0) {
dbenv->err(dbenv, ret, "set_cachesize");
goto err;
}
/* Open the environment. */
if ((ret = dbenv->open(
dbenv, NULL, DB_CREATE | DB_INIT_MPOOL, 0)) != 0) {
dbenv->err(dbenv, ret, "DB_ENV->open");
goto err;
}
/* Open the file in the environment. */
if ((ret = dbenv->memp_fcreate(dbenv, &mfp, 0)) != 0) {
dbenv->err(dbenv, ret, "DB_ENV->memp_fcreate: %s", MPOOL);
goto err;
}
if ((ret = mfp->open(mfp, MPOOL, 0, 0, pagesize)) != 0) {
dbenv->err(dbenv, ret, "DB_MPOOLFILE->open: %s", MPOOL);
goto err;
}
printf("retrieve %d random pages... ", hits);
srand((u_int)time(NULL));
for (cnt = 0; cnt < hits; ++cnt) {
pageno = (rand() % npages) + 1;
if ((ret = mfp->get(mfp, &pageno, 0, &p)) != 0) {
dbenv->err(dbenv, ret,
"unable to retrieve page %lu", (u_long)pageno);
goto err;
}
if (*(db_pgno_t *)p != pageno) {
dbenv->errx(dbenv,
"wrong page retrieved (%lu != %d)",
(u_long)pageno, *(int *)p);
goto err;
}
if ((ret = mfp->put(mfp, p, 0)) != 0) {
dbenv->err(dbenv, ret,
"unable to return page %lu", (u_long)pageno);
goto err;
}
}
printf("successful.\n");
/* Close the file. */
if ((ret = mfp->close(mfp, 0)) != 0) {
dbenv->err(dbenv, ret, "DB_MPOOLFILE->close");
goto err;
}
/* Close the pool. */
if ((ret = dbenv->close(dbenv, 0)) != 0) {
fprintf(stderr,
"%s: db_env_create: %s\n", progname, db_strerror(ret));
return (1);
}
return (0);
err: if (mfp != NULL)
(void)mfp->close(mfp, 0);
if (dbenv != NULL)
(void)dbenv->close(dbenv, 0);
return (1);
}
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2001-2002
* Sleepycat Software. All rights reserved.
*
* $Id: ex_repquote.h,v 1.27 2002/04/23 04:27:50 krinsky Exp $
*/
#ifndef _EX_REPQUOTE_H_
#define _EX_REPQUOTE_H_
#define SELF_EID 1
typedef struct {
char *host; /* Host name. */
u_int32_t port; /* Port on which to connect to this site. */
} repsite_t;
/* Globals */
extern int master_eid;
extern char *myaddr;
struct __member; typedef struct __member member_t;
struct __machtab; typedef struct __machtab machtab_t;
/* Arguments for the connect_all thread. */
typedef struct {
DB_ENV *dbenv;
const char *progname;
const char *home;
machtab_t *machtab;
repsite_t *sites;
int nsites;
} all_args;
/* Arguments for the connect_loop thread. */
typedef struct {
DB_ENV *dbenv;
const char * home;
const char * progname;
machtab_t *machtab;
int port;
} connect_args;
#define CACHESIZE (10 * 1024 * 1024)
#define DATABASE "quote.db"
#define SLEEPTIME 3
void *connect_all __P((void *args));
void *connect_thread __P((void *args));
int doclient __P((DB_ENV *, const char *, machtab_t *));
int domaster __P((DB_ENV *, const char *));
int get_accepted_socket __P((const char *, int));
int get_connected_socket __P((machtab_t *, const char *, const char *, int, int *, int *));
int get_next_message __P((int, DBT *, DBT *));
int listen_socket_init __P((const char *, int));
int listen_socket_accept __P((machtab_t *, const char *, int, int *));
int machtab_getinfo __P((machtab_t *, int, u_int32_t *, int *));
int machtab_init __P((machtab_t **, int, int));
void machtab_parm __P((machtab_t *, int *, int *, u_int32_t *));
int machtab_rem __P((machtab_t *, int, int));
int quote_send __P((DB_ENV *, const DBT *, const DBT *, int, u_int32_t));
#ifndef COMPQUIET
#define COMPQUIET(x,y) x = (y)
#endif
#endif /* !_EX_REPQUOTE_H_ */
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2001-2002
* Sleepycat Software. All rights reserved.
*
* $Id: ex_rq_client.c,v 1.29 2002/01/23 15:33:19 bostic Exp $
*/
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <db.h>
#include "ex_repquote.h"
static void *check_loop __P((void *));
static void *display_loop __P((void *));
static int print_stocks __P((DBC *));
typedef struct {
const char *progname;
DB_ENV *dbenv;
} disploop_args;
typedef struct {
DB_ENV *dbenv;
machtab_t *machtab;
} checkloop_args;
int
doclient(dbenv, progname, machtab)
DB_ENV *dbenv;
const char *progname;
machtab_t *machtab;
{
checkloop_args cargs;
disploop_args dargs;
pthread_t check_thr, disp_thr;
void *cstatus, *dstatus;
int rval, s;
rval = EXIT_SUCCESS;
s = -1;
memset(&dargs, 0, sizeof(dargs));
dstatus = (void *)EXIT_FAILURE;
dargs.progname = progname;
dargs.dbenv = dbenv;
if (pthread_create(&disp_thr, NULL, display_loop, (void *)&dargs)) {
dbenv->err(dbenv, errno, "display_loop pthread_create failed");
goto err;
}
cargs.dbenv = dbenv;
cargs.machtab = machtab;
if (pthread_create(&check_thr, NULL, check_loop, (void *)&cargs)) {
dbenv->err(dbenv, errno, "check_thread pthread_create failed");
goto err;
}
if (pthread_join(disp_thr, &dstatus) ||
pthread_join(check_thr, &cstatus)) {
dbenv->err(dbenv, errno, "pthread_join failed");
goto err;
}
if (0) {
err: rval = EXIT_FAILURE;
}
return (rval);
}
/*
* Our only job is to check that the master is valid and if it's not
* for an extended period, to trigger an election. We do two phases.
* If we do not have a master, first we send out a request for a master
* to identify itself (that would be a call to rep_start). If that fails,
* we trigger an election.
*/
static void *
check_loop(args)
void *args;
{
DB_ENV *dbenv;
DBT dbt;
checkloop_args *cargs;
int count, n, pri;
machtab_t *machtab;
u_int32_t timeout;
cargs = (checkloop_args *)args;
dbenv = cargs->dbenv;
machtab = cargs->machtab;
#define IDLE_INTERVAL 1
count = 0;
while (master_eid == DB_EID_INVALID) {
/*
* Call either rep_start or rep_elect depending on if
* count is 0 or 1.
*/
if (count == 0) {
memset(&dbt, 0, sizeof(dbt));
dbt.data = myaddr;
dbt.size = strlen(myaddr) + 1;
(void)dbenv->rep_start(dbenv, &dbt, DB_REP_CLIENT);
count = 1;
} else {
machtab_parm(machtab, &n, &pri, &timeout);
(void)dbenv->rep_elect(dbenv,
n, pri, timeout, &master_eid);
count = 0;
}
sleep(IDLE_INTERVAL);
}
return ((void *)EXIT_SUCCESS);
}
static void *
display_loop(args)
void *args;
{
DB *dbp;
DB_ENV *dbenv;
DBC *dbc;
const char *progname;
disploop_args *dargs;
int ret, rval;
dargs = (disploop_args *)args;
progname = dargs->progname;
dbenv = dargs->dbenv;
dbc = NULL;
dbp = NULL;
for (;;) {
/* If we become master, shut this loop off. */
if (master_eid == SELF_EID)
break;
if (dbp == NULL) {
if ((ret = db_create(&dbp, dbenv, 0)) != 0) {
dbenv->err(dbenv, ret, "db_create");
return ((void *)EXIT_FAILURE);
}
if ((ret = dbp->open(dbp, NULL,
DATABASE, NULL, DB_BTREE, DB_RDONLY, 0)) != 0) {
if (ret == ENOENT) {
printf(
"No stock database yet available.\n");
if ((ret = dbp->close(dbp, 0)) != 0) {
dbenv->err(dbenv,
ret, "DB->close");
goto err;
}
dbp = NULL;
sleep(SLEEPTIME);
continue;
}
dbenv->err(dbenv, ret, "DB->open");
goto err;
}
}
if ((ret = dbp->cursor(dbp, NULL, &dbc, 0)) != 0) {
dbenv->err(dbenv, ret, "DB->cursor");
goto err;
}
if ((ret = print_stocks(dbc)) != 0) {
dbenv->err(dbenv, ret, "database traversal failed");
goto err;
}
if ((ret = dbc->c_close(dbc)) != 0) {
dbenv->err(dbenv, ret, "DB->close");
goto err;
}
dbc = NULL;
sleep(SLEEPTIME);
}
rval = EXIT_SUCCESS;
if (0) {
err: rval = EXIT_FAILURE;
}
if (dbc != NULL && (ret = dbc->c_close(dbc)) != 0) {
dbenv->err(dbenv, ret, "DB->close");
rval = EXIT_FAILURE;
}
if (dbp != NULL && (ret = dbp->close(dbp, 0)) != 0) {
dbenv->err(dbenv, ret, "DB->close");
return ((void *)EXIT_FAILURE);
}
return ((void *)rval);
}
static int
print_stocks(dbc)
DBC *dbc;
{
DBT key, data;
#define MAXKEYSIZE 10
#define MAXDATASIZE 20
char keybuf[MAXKEYSIZE + 1], databuf[MAXDATASIZE + 1];
int ret;
u_int32_t keysize, datasize;
memset(&key, 0, sizeof(key));
memset(&data, 0, sizeof(data));
printf("\tSymbol\tPrice\n");
printf("\t======\t=====\n");
for (ret = dbc->c_get(dbc, &key, &data, DB_FIRST);
ret == 0;
ret = dbc->c_get(dbc, &key, &data, DB_NEXT)) {
keysize = key.size > MAXKEYSIZE ? MAXKEYSIZE : key.size;
memcpy(keybuf, key.data, keysize);
keybuf[keysize] = '\0';
datasize = data.size >= MAXDATASIZE ? MAXDATASIZE : data.size;
memcpy(databuf, data.data, datasize);
databuf[datasize] = '\0';
printf("\t%s\t%s\n", keybuf, databuf);
}
printf("\n");
return (ret == DB_NOTFOUND ? 0 : ret);
}
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2001-2002
* Sleepycat Software. All rights reserved.
*
* $Id: ex_rq_main.c,v 1.23 2002/08/06 05:39:03 bostic Exp $
*/
#include <sys/types.h>
#include <pthread.h>
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <db.h>
#include "ex_repquote.h"
/*
* Process globals (we could put these in the machtab I suppose.
*/
int master_eid;
char *myaddr;
static int env_init __P((const char *, const char *, DB_ENV **, machtab_t *,
u_int32_t));
static void usage __P((const char *));
int
main(argc, argv)
int argc;
char *argv[];
{
extern char *optarg;
extern int optind;
DB_ENV *dbenv;
DBT local;
enum { MASTER, CLIENT, UNKNOWN } whoami;
all_args aa;
connect_args ca;
machtab_t *machtab;
pthread_t all_thr, conn_thr;
repsite_t site, *sitep, self, *selfp;
struct sigaction sigact;
int maxsites, nsites, ret, priority, totalsites;
char *c, ch;
const char *home, *progname;
void *astatus, *cstatus;
master_eid = DB_EID_INVALID;
dbenv = NULL;
whoami = UNKNOWN;
machtab = NULL;
selfp = sitep = NULL;
maxsites = nsites = ret = totalsites = 0;
priority = 100;
home = "TESTDIR";
progname = "ex_repquote";
while ((ch = getopt(argc, argv, "Ch:Mm:n:o:p:")) != EOF)
switch (ch) {
case 'M':
whoami = MASTER;
master_eid = SELF_EID;
break;
case 'C':
whoami = CLIENT;
break;
case 'h':
home = optarg;
break;
case 'm':
if ((myaddr = strdup(optarg)) == NULL) {
fprintf(stderr,
"System error %s\n", strerror(errno));
goto err;
}
self.host = optarg;
self.host = strtok(self.host, ":");
if ((c = strtok(NULL, ":")) == NULL) {
fprintf(stderr, "Bad host specification.\n");
goto err;
}
self.port = atoi(c);
selfp = &self;
break;
case 'n':
totalsites = atoi(optarg);
break;
case 'o':
site.host = optarg;
site.host = strtok(site.host, ":");
if ((c = strtok(NULL, ":")) == NULL) {
fprintf(stderr, "Bad host specification.\n");
goto err;
}
site.port = atoi(c);
if (sitep == NULL || nsites >= maxsites) {
maxsites = maxsites == 0 ? 10 : 2 * maxsites;
if ((sitep = realloc(sitep,
maxsites * sizeof(repsite_t))) == NULL) {
fprintf(stderr, "System error %s\n",
strerror(errno));
goto err;
}
}
sitep[nsites++] = site;
break;
case 'p':
priority = atoi(optarg);
break;
case '?':
default:
usage(progname);
}
/* Error check command line. */
if (whoami == UNKNOWN) {
fprintf(stderr, "Must specify -M or -C.\n");
goto err;
}
if (selfp == NULL)
usage(progname);
if (home == NULL)
usage(progname);
/*
* Turn off SIGPIPE so that we don't kill processes when they
* happen to lose a connection at the wrong time.
*/
memset(&sigact, 0, sizeof(sigact));
sigact.sa_handler = SIG_IGN;
if ((ret = sigaction(SIGPIPE, &sigact, NULL)) != 0) {
fprintf(stderr,
"Unable to turn off SIGPIPE: %s\n", strerror(ret));
goto err;
}
/*
* We are hardcoding priorities here that all clients have the
* same priority except for a designated master who gets a higher
* priority.
*/
if ((ret =
machtab_init(&machtab, priority, totalsites)) != 0)
goto err;
/*
* We can know open our environment, although we're not ready to
* begin replicating. However, we want to have a dbenv around
* so that we can send it into any of our message handlers.
*/
if ((ret = env_init(progname, home, &dbenv, machtab, DB_RECOVER)) != 0)
goto err;
/*
* Now sets up comm infrastructure. There are two phases. First,
* we open our port for listening for incoming connections. Then
* we attempt to connect to every host we know about.
*/
ca.dbenv = dbenv;
ca.home = home;
ca.progname = progname;
ca.machtab = machtab;
ca.port = selfp->port;
if ((ret = pthread_create(&conn_thr, NULL, connect_thread, &ca)) != 0)
goto err;
aa.dbenv = dbenv;
aa.progname = progname;
aa.home = home;
aa.machtab = machtab;
aa.sites = sitep;
aa.nsites = nsites;
if ((ret = pthread_create(&all_thr, NULL, connect_all, &aa)) != 0)
goto err;
/*
* We have now got the entire communication infrastructure set up.
* It's time to declare ourselves to be a client or master.
*/
if (whoami == MASTER) {
if ((ret = dbenv->rep_start(dbenv, NULL, DB_REP_MASTER)) != 0) {
dbenv->err(dbenv, ret, "dbenv->rep_start failed");
goto err;
}
if ((ret = domaster(dbenv, progname)) != 0) {
dbenv->err(dbenv, ret, "Master failed");
goto err;
}
} else {
memset(&local, 0, sizeof(local));
local.data = myaddr;
local.size = strlen(myaddr) + 1;
if ((ret =
dbenv->rep_start(dbenv, &local, DB_REP_CLIENT)) != 0) {
dbenv->err(dbenv, ret, "dbenv->rep_start failed");
goto err;
}
/* Sleep to give ourselves a minute to find a master. */
sleep(5);
if ((ret = doclient(dbenv, progname, machtab)) != 0) {
dbenv->err(dbenv, ret, "Client failed");
goto err;
}
}
/* Wait on the connection threads. */
if (pthread_join(all_thr, &astatus) || pthread_join(conn_thr, &cstatus))
ret = errno;
if (ret == 0 &&
((int)astatus != EXIT_SUCCESS || (int)cstatus != EXIT_SUCCESS))
ret = -1;
err: if (machtab != NULL)
free(machtab);
if (dbenv != NULL)
(void)dbenv->close(dbenv, 0);
return (ret);
}
/*
* In this application, we specify all communication via the command line.
* In a real application, we would expect that information about the other
* sites in the system would be maintained in some sort of configuration
* file. The critical part of this interface is that we assume at startup
* that we can find out 1) what host/port we wish to listen on for connections,
* 2) a (possibly empty) list of other sites we should attempt to connect to.
* 3) whether we are a master or client (if we don't know, we should come up
* as a client and see if there is a master out there) and 4) what our
* Berkeley DB home environment is.
*
* These pieces of information are expressed by the following flags.
* -m host:port (required; m stands for me)
* -o host:port (optional; o stands for other; any number of these may be
* specified)
* -[MC] M for master/C for client
* -h home directory
* -n nsites (optional; number of sites in replication group; defaults to 0
* in which case we try to dynamically compute the number of sites in
* the replication group.)
* -p priority (optional: defaults to 100)
*/
static void
usage(progname)
const char *progname;
{
fprintf(stderr, "usage: %s ", progname);
fprintf(stderr, "[-CM][-h home][-o host:port][-m host:port]%s",
"[-n nsites][-p priority]\n");
exit(EXIT_FAILURE);
}
/* Open and configure an environment. */
int
env_init(progname, home, dbenvp, machtab, flags)
const char *progname, *home;
DB_ENV **dbenvp;
machtab_t *machtab;
u_int32_t flags;
{
DB_ENV *dbenv;
int ret;
char *prefix;
if ((prefix = malloc(strlen(progname) + 2)) == NULL) {
fprintf(stderr,
"%s: System error: %s\n", progname, strerror(errno));
return (errno);
}
sprintf(prefix, "%s:", progname);
if ((ret = db_env_create(&dbenv, 0)) != 0) {
fprintf(stderr, "%s: env create failed: %s\n",
progname, db_strerror(ret));
return (ret);
}
dbenv->set_errfile(dbenv, stderr);
dbenv->set_errpfx(dbenv, prefix);
/* (void)dbenv->set_verbose(dbenv, DB_VERB_REPLICATION, 1); */
(void)dbenv->set_cachesize(dbenv, 0, CACHESIZE, 0);
/* (void)dbenv->set_flags(dbenv, DB_TXN_NOSYNC, 1); */
dbenv->app_private = machtab;
(void)dbenv->set_rep_transport(dbenv, SELF_EID, quote_send);
flags |= DB_CREATE | DB_THREAD |
DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN;
ret = dbenv->open(dbenv, home, flags, 0);
*dbenvp = dbenv;
return (ret);
}
/*-
* #include <pthread.h>
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2001-2002
* Sleepycat Software. All rights reserved.
*
* $Id: ex_rq_master.c,v 1.22 2002/08/06 05:39:03 bostic Exp $
*/
#include <sys/types.h>
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <db.h>
#include "ex_repquote.h"
static void *master_loop __P((void *));
#define BUFSIZE 1024
int
domaster(dbenv, progname)
DB_ENV *dbenv;
const char *progname;
{
int ret, t_ret;
pthread_t interface_thr;
pthread_attr_t attr;
COMPQUIET(progname, NULL);
/* Spawn off a thread to handle the basic master interface. */
if ((ret = pthread_attr_init(&attr)) != 0 &&
(ret = pthread_attr_setdetachstate(&attr,
PTHREAD_CREATE_DETACHED)) != 0)
goto err;
if ((ret = pthread_create(&interface_thr,
&attr, master_loop, (void *)dbenv)) != 0)
goto err;
err: if ((t_ret = pthread_attr_destroy(&attr)) != 0 && ret == 0)
ret = t_ret;
return (ret);
}
static void *
master_loop(dbenvv)
void *dbenvv;
{
DB *dbp;
DB_ENV *dbenv;
DB_TXN *txn;
DBT key, data;
char buf[BUFSIZE], *rbuf;
int ret;
dbp = NULL;
txn = NULL;
dbenv = (DB_ENV *)dbenvv;
/*
* Check if the database exists and if it verifies cleanly.
* If it does, run with it; else recreate it and go. Note
* that we have to verify outside of the environment.
*/
#ifdef NOTDEF
if ((ret = db_create(&dbp, NULL, 0)) != 0)
return (ret);
if ((ret = dbp->verify(dbp, DATABASE, NULL, NULL, 0)) != 0) {
if ((ret = dbp->remove(dbp, DATABASE, NULL, 0)) != 0 &&
ret != DB_NOTFOUND && ret != ENOENT)
return (ret);
#endif
if ((ret = db_create(&dbp, dbenv, 0)) != 0)
return ((void *)ret);
if ((ret = dbenv->txn_begin(dbenv, NULL, &txn, 0)) != 0)
goto err;
if ((ret = dbp->open(dbp, txn, DATABASE,
NULL, DB_BTREE, DB_CREATE /* | DB_THREAD */, 0)) != 0)
goto err;
ret = txn->commit(txn, 0);
txn = NULL;
if (ret != 0) {
dbp = NULL;
goto err;
}
#ifdef NOTDEF
} else {
/* Reopen in the environment. */
if ((ret = dbp->close(dbp, 0)) != 0)
return (ret);
if ((ret = db_create(&dbp, dbenv, 0)) != 0)
return (ret);
if ((ret = dbp->open(dbp,
DATABASE, NULL, DB_UNKNOWN, DB_THREAD, 0)) != 0)
goto err;
}
#endif
/*
* XXX
* It would probably be kind of cool to do this in Tcl and
* have a nice GUI. It would also be cool to be independently
* wealthy.
*/
memset(&key, 0, sizeof(key));
memset(&data, 0, sizeof(data));
for (;;) {
printf("QUOTESERVER> ");
fflush(stdout);
if (fgets(buf, sizeof(buf), stdin) == NULL)
break;
(void)strtok(&buf[0], " \t\n");
rbuf = strtok(NULL, " \t\n");
if (rbuf == NULL || rbuf[0] == '\0') {
if (strncmp(buf, "exit", 4) == 0 ||
strncmp(buf, "quit", 4) == 0)
break;
dbenv->errx(dbenv, "Format: TICKER VALUE");
continue;
}
key.data = buf;
key.size = strlen(buf);
data.data = rbuf;
data.size = strlen(rbuf);
if ((ret = dbenv->txn_begin(dbenv, NULL, &txn, 0)) != 0)
goto err;
switch (ret =
dbp->put(dbp, txn, &key, &data, 0)) {
case 0:
break;
default:
dbp->err(dbp, ret, "DB->put");
if (ret != DB_KEYEXIST)
goto err;
break;
}
ret = txn->commit(txn, 0);
txn = NULL;
if (ret != 0)
goto err;
}
err: if (txn != NULL)
(void)txn->abort(txn);
if (dbp != NULL)
(void)dbp->close(dbp, DB_NOSYNC);
return ((void *)ret);
}
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2001-2002
* Sleepycat Software. All rights reserved.
*
* $Id: ex_rq_net.c,v 1.37 2002/08/06 05:39:04 bostic Exp $
*/
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <assert.h>
#include <errno.h>
#include <netdb.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <db.h>
#include <dbinc/queue.h> /* !!!: for the LIST_XXX macros. */
#include "ex_repquote.h"
int machtab_add __P((machtab_t *, int, u_int32_t, int, int *));
ssize_t readn __P((int, void *, size_t));
/*
* This file defines the communication infrastructure for the ex_repquote
* sample application.
*
* This application uses TCP/IP for its communication. In an N-site
* replication group, this means that there are N * N communication
* channels so that every site can communicate with every other site
* (this allows elections to be held when the master fails). We do
* not require that anyone know about all sites when the application
* starts up. In order to communicate, the application should know
* about someone, else it has no idea how to ever get in the game.
*
* Communication is handled via a number of different threads. These
* thread functions are implemented in rep_util.c In this file, we
* define the data structures that maintain the state that describes
* the comm infrastructure, the functions that manipulates this state
* and the routines used to actually send and receive data over the
* sockets.
*/
/*
* The communication infrastructure is represented by a machine table,
* machtab_t, which is essentially a mutex-protected linked list of members
* of the group. The machtab also contains the parameters that are needed
* to call for an election. We hardwire values for these parameters in the
* init function, but these could be set via some configuration setup in a
* real application. We reserve the machine-id 1 to refer to ourselves and
* make the machine-id 0 be invalid.
*/
#define MACHID_INVALID 0
#define MACHID_SELF 1
struct __machtab {
LIST_HEAD(__machlist, __member) machlist;
int nextid;
pthread_mutex_t mtmutex;
u_int32_t timeout_time;
int current;
int max;
int nsites;
int priority;
};
/* Data structure that describes each entry in the machtab. */
struct __member {
u_int32_t hostaddr; /* Host IP address. */
int port; /* Port number. */
int eid; /* Application-specific machine id. */
int fd; /* File descriptor for the socket. */
LIST_ENTRY(__member) links;
/* For linked list of all members we know of. */
};
static int quote_send_broadcast __P((machtab_t *,
const DBT *, const DBT *, u_int32_t));
static int quote_send_one __P((const DBT *, const DBT *, int, u_int32_t));
/*
* machtab_init --
* Initialize the machine ID table.
* XXX Right now we treat the number of sites as the maximum
* number we've ever had on the list at one time. We probably
* want to make that smarter.
*/
int
machtab_init(machtabp, pri, nsites)
machtab_t **machtabp;
int pri, nsites;
{
int ret;
machtab_t *machtab;
if ((machtab = malloc(sizeof(machtab_t))) == NULL)
return (ENOMEM);
LIST_INIT(&machtab->machlist);
/* Reserve eid's 0 and 1. */
machtab->nextid = 2;
machtab->timeout_time = 2 * 1000000; /* 2 seconds. */
machtab->current = machtab->max = 0;
machtab->priority = pri;
machtab->nsites = nsites;
ret = pthread_mutex_init(&machtab->mtmutex, NULL);
*machtabp = machtab;
return (ret);
}
/*
* machtab_add --
* Add a file descriptor to the table of machines, returning
* a new machine ID.
*/
int
machtab_add(machtab, fd, hostaddr, port, idp)
machtab_t *machtab;
int fd;
u_int32_t hostaddr;
int port, *idp;
{
int ret;
member_t *m, *member;
if ((member = malloc(sizeof(member_t))) == NULL)
return (ENOMEM);
member->fd = fd;
member->hostaddr = hostaddr;
member->port = port;
if ((ret = pthread_mutex_lock(&machtab->mtmutex)) != 0)
return (ret);
for (m = LIST_FIRST(&machtab->machlist);
m != NULL; m = LIST_NEXT(m, links))
if (m->hostaddr == hostaddr && m->port == port)
break;
if (m == NULL) {
member->eid = machtab->nextid++;
LIST_INSERT_HEAD(&machtab->machlist, member, links);
} else
member->eid = m->eid;
ret = pthread_mutex_unlock(&machtab->mtmutex);
if (idp != NULL)
*idp = member->eid;
if (m == NULL) {
if (++machtab->current > machtab->max)
machtab->max = machtab->current;
} else {
free(member);
ret = EEXIST;
}
return (ret);
}
/*
* machtab_getinfo --
* Return host and port information for a particular machine id.
*/
int
machtab_getinfo(machtab, eid, hostp, portp)
machtab_t *machtab;
int eid;
u_int32_t *hostp;
int *portp;
{
int ret;
member_t *member;
if ((ret = pthread_mutex_lock(&machtab->mtmutex)) != 0)
return (ret);
for (member = LIST_FIRST(&machtab->machlist);
member != NULL;
member = LIST_NEXT(member, links))
if (member->eid == eid) {
*hostp = member->hostaddr;
*portp = member->port;
break;
}
if ((ret = pthread_mutex_unlock(&machtab->mtmutex)) != 0)
return (ret);
return (member != NULL ? 0 : EINVAL);
}
/*
* machtab_rem --
* Remove a mapping from the table of machines. Lock indicates
* whether we need to lock the machtab or not (0 indicates we do not
* need to lock; non-zero indicates that we do need to lock).
*/
int
machtab_rem(machtab, eid, lock)
machtab_t *machtab;
int eid;
int lock;
{
int found, ret;
member_t *member;
ret = 0;
if (lock && (ret = pthread_mutex_lock(&machtab->mtmutex)) != 0)
return (ret);
for (found = 0, member = LIST_FIRST(&machtab->machlist);
member != NULL;
member = LIST_NEXT(member, links))
if (member->eid == eid) {
found = 1;
LIST_REMOVE(member, links);
(void)close(member->fd);
free(member);
machtab->current--;
break;
}
if (LIST_FIRST(&machtab->machlist) == NULL)
machtab->nextid = 2;
if (lock)
ret = pthread_mutex_unlock(&machtab->mtmutex);
return (ret);
}
void
machtab_parm(machtab, nump, prip, timeoutp)
machtab_t *machtab;
int *nump, *prip;
u_int32_t *timeoutp;
{
if (machtab->nsites == 0)
*nump = machtab->max;
else
*nump = machtab->nsites;
*prip = machtab->priority;
*timeoutp = machtab->timeout_time;
}
/*
* listen_socket_init --
* Initialize a socket for listening on the specified port. Returns
* a file descriptor for the socket, ready for an accept() call
* in a thread that we're happy to let block.
*/
int
listen_socket_init(progname, port)
const char *progname;
int port;
{
int s;
struct protoent *proto;
struct sockaddr_in si;
if ((proto = getprotobyname("tcp")) == NULL)
return (-1);
if ((s = socket(AF_INET, SOCK_STREAM, proto->p_proto)) < 0)
return (-1);
memset(&si, 0, sizeof(si));
si.sin_family = AF_INET;
si.sin_addr.s_addr = htonl(INADDR_ANY);
si.sin_port = htons(port);
if (bind(s, (struct sockaddr *)&si, sizeof(si)) != 0)
goto err;
if (listen(s, 5) != 0)
goto err;
return (s);
err: fprintf(stderr, "%s: %s", progname, strerror(errno));
close (s);
return (-1);
}
/*
* listen_socket_accept --
* Accept a connection on a socket. This is essentially just a wrapper
* for accept(3).
*/
int
listen_socket_accept(machtab, progname, s, eidp)
machtab_t *machtab;
const char *progname;
int s, *eidp;
{
struct sockaddr_in si;
int si_len;
int host, ns, port, ret;
COMPQUIET(progname, NULL);
wait: memset(&si, 0, sizeof(si));
si_len = sizeof(si);
ns = accept(s, (struct sockaddr *)&si, &si_len);
host = ntohl(si.sin_addr.s_addr);
port = ntohs(si.sin_port);
ret = machtab_add(machtab, ns, host, port, eidp);
if (ret == EEXIST) {
close(ns);
goto wait;
} else if (ret != 0)
goto err;
return (ns);
err: close(ns);
return (-1);
}
/*
* get_accepted_socket --
* Listen on the specified port, and return a file descriptor
* when we have accepted a connection on it.
*/
int
get_accepted_socket(progname, port)
const char *progname;
int port;
{
struct protoent *proto;
struct sockaddr_in si;
int si_len;
int s, ns;
if ((proto = getprotobyname("tcp")) == NULL)
return (-1);
if ((s = socket(AF_INET, SOCK_STREAM, proto->p_proto)) < 0)
return (-1);
memset(&si, 0, sizeof(si));
si.sin_family = AF_INET;
si.sin_addr.s_addr = htonl(INADDR_ANY);
si.sin_port = htons(port);
if (bind(s, (struct sockaddr *)&si, sizeof(si)) != 0)
goto err;
if (listen(s, 5) != 0)
goto err;
memset(&si, 0, sizeof(si));
si_len = sizeof(si);
ns = accept(s, (struct sockaddr *)&si, &si_len);
return (ns);
err: fprintf(stderr, "%s: %s", progname, strerror(errno));
close (s);
return (-1);
}
/*
* get_connected_socket --
* Connect to the specified port of the specified remote machine,
* and return a file descriptor when we have accepted a connection on it.
* Add this connection to the machtab. If we already have a connection
* open to this machine, then don't create another one, return the eid
* of the connection (in *eidp) and set is_open to 1. Return 0.
*/
int
get_connected_socket(machtab, progname, remotehost, port, is_open, eidp)
machtab_t *machtab;
const char *progname, *remotehost;
int port, *is_open, *eidp;
{
int ret, s;
struct hostent *hp;
struct protoent *proto;
struct sockaddr_in si;
u_int32_t addr;
*is_open = 0;
if ((proto = getprotobyname("tcp")) == NULL)
return (-1);
if ((hp = gethostbyname(remotehost)) == NULL) {
fprintf(stderr, "%s: host not found: %s\n", progname,
strerror(errno));
return (-1);
}
if ((s = socket(AF_INET, SOCK_STREAM, proto->p_proto)) < 0)
return (-1);
memset(&si, 0, sizeof(si));
memcpy((char *)&si.sin_addr, hp->h_addr, hp->h_length);
addr = ntohl(si.sin_addr.s_addr);
ret = machtab_add(machtab, s, addr, port, eidp);
if (ret == EEXIST) {
*is_open = 1;
close(s);
return (0);
} else if (ret != 0) {
close (s);
return (-1);
}
si.sin_family = AF_INET;
si.sin_port = htons(port);
if (connect(s, (struct sockaddr *)&si, sizeof(si)) < 0) {
fprintf(stderr, "%s: connection failed: %s",
progname, strerror(errno));
(void)machtab_rem(machtab, *eidp, 1);
return (-1);
}
return (s);
}
/*
* get_next_message --
* Read a single message from the specified file descriptor, and
* return it in the format used by rep functions (two DBTs and a type).
*
* This function is called in a loop by both clients and masters, and
* the resulting DBTs are manually dispatched to DB_ENV->rep_process_message().
*/
int
get_next_message(fd, rec, control)
int fd;
DBT *rec, *control;
{
size_t nr;
u_int32_t rsize, csize;
u_int8_t *recbuf, *controlbuf;
/*
* The protocol we use on the wire is dead simple:
*
* 4 bytes - rec->size
* (# read above) - rec->data
* 4 bytes - control->size
* (# read above) - control->data
*/
/* Read rec->size. */
nr = readn(fd, &rsize, 4);
if (nr != 4)
return (1);
/* Read the record itself. */
if (rsize > 0) {
if (rec->size < rsize)
rec->data = realloc(rec->data, rsize);
recbuf = rec->data;
nr = readn(fd, recbuf, rsize);
} else {
if (rec->data != NULL)
free(rec->data);
rec->data = NULL;
}
rec->size = rsize;
/* Read control->size. */
nr = readn(fd, &csize, 4);
if (nr != 4)
return (1);
/* Read the control struct itself. */
if (csize > 0) {
controlbuf = control->data;
if (control->size < csize)
controlbuf = realloc(controlbuf, csize);
nr = readn(fd, controlbuf, csize);
if (nr != csize)
return (1);
} else {
if (control->data != NULL)
free(control->data);
controlbuf = NULL;
}
control->data = controlbuf;
control->size = csize;
return (0);
}
/*
* readn --
* Read a full n characters from a file descriptor, unless we get an error
* or EOF.
*/
ssize_t
readn(fd, vptr, n)
int fd;
void *vptr;
size_t n;
{
size_t nleft;
ssize_t nread;
char *ptr;
ptr = vptr;
nleft = n;
while (nleft > 0) {
if ( (nread = read(fd, ptr, nleft)) < 0) {
/*
* Call read() again on interrupted system call;
* on other errors, bail.
*/
if (errno == EINTR)
nread = 0;
else
return (-1);
} else if (nread == 0)
break; /* EOF */
nleft -= nread;
ptr += nread;
}
return (n - nleft);
}
/*
* quote_send --
* The f_send function for DB_ENV->set_rep_transport.
*/
int
quote_send(dbenv, control, rec, eid, flags)
DB_ENV *dbenv;
const DBT *control, *rec;
int eid;
u_int32_t flags;
{
int fd, n, ret, t_ret;
machtab_t *machtab;
member_t *m;
machtab = (machtab_t *)dbenv->app_private;
if (eid == DB_EID_BROADCAST) {
/*
* Right now, we do not require successful transmission.
* I'd like to move this requiring at least one successful
* transmission on PERMANENT requests.
*/
n = quote_send_broadcast(machtab, rec, control, flags);
if (n < 0 /*|| (n == 0 && LF_ISSET(DB_REP_PERMANENT))*/)
return (DB_REP_UNAVAIL);
return (0);
}
if ((ret = pthread_mutex_lock(&machtab->mtmutex)) != 0)
return (ret);
fd = 0;
for (m = LIST_FIRST(&machtab->machlist); m != NULL;
m = LIST_NEXT(m, links)) {
if (m->eid == eid) {
fd = m->fd;
break;
}
}
if (fd == 0) {
dbenv->err(dbenv, DB_REP_UNAVAIL,
"quote_send: cannot find machine ID %d", eid);
return (DB_REP_UNAVAIL);
}
ret = quote_send_one(rec, control, fd, flags);
if ((t_ret = (pthread_mutex_unlock(&machtab->mtmutex))) != 0 &&
ret == 0)
ret = t_ret;
return (ret);
}
/*
* quote_send_broadcast --
* Send a message to everybody.
* Returns the number of sites to which this message was successfully
* communicated. A -1 indicates a fatal error.
*/
static int
quote_send_broadcast(machtab, rec, control, flags)
machtab_t *machtab;
const DBT *rec, *control;
u_int32_t flags;
{
int ret, sent;
member_t *m, *next;
if ((ret = pthread_mutex_lock(&machtab->mtmutex)) != 0)
return (0);
sent = 0;
for (m = LIST_FIRST(&machtab->machlist); m != NULL; m = next) {
next = LIST_NEXT(m, links);
if ((ret = quote_send_one(rec, control, m->fd, flags)) != 0) {
(void)machtab_rem(machtab, m->eid, 0);
} else
sent++;
}
if (pthread_mutex_unlock(&machtab->mtmutex) != 0)
return (-1);
return (sent);
}
/*
* quote_send_one --
* Send a message to a single machine, given that machine's file
* descriptor.
*
* !!!
* Note that the machtab mutex should be held through this call.
* It doubles as a synchronizer to make sure that two threads don't
* intersperse writes that are part of two single messages.
*/
static int
quote_send_one(rec, control, fd, flags)
const DBT *rec, *control;
int fd;
u_int32_t flags;
{
int retry;
ssize_t bytes_left, nw;
u_int8_t *wp;
COMPQUIET(flags, 0);
/*
* The protocol is simply: write rec->size, write rec->data,
* write control->size, write control->data.
*/
nw = write(fd, &rec->size, 4);
if (nw != 4)
return (DB_REP_UNAVAIL);
if (rec->size > 0) {
nw = write(fd, rec->data, rec->size);
if (nw < 0)
return (DB_REP_UNAVAIL);
if (nw != (ssize_t)rec->size) {
/* Try a couple of times to finish the write. */
wp = (u_int8_t *)rec->data + nw;
bytes_left = rec->size - nw;
for (retry = 0; bytes_left > 0 && retry < 3; retry++) {
nw = write(fd, wp, bytes_left);
if (nw < 0)
return (DB_REP_UNAVAIL);
bytes_left -= nw;
wp += nw;
}
if (bytes_left > 0)
return (DB_REP_UNAVAIL);
}
}
nw = write(fd, &control->size, 4);
if (nw != 4)
return (DB_REP_UNAVAIL);
if (control->size > 0) {
nw = write(fd, control->data, control->size);
if (nw != (ssize_t)control->size)
return (DB_REP_UNAVAIL);
}
return (0);
}
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2001-2002
* Sleepycat Software. All rights reserved.
*
* $Id: ex_rq_util.c,v 1.20 2002/08/06 05:39:04 bostic Exp $
*/
#include <sys/types.h>
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <db.h>
#include "ex_repquote.h"
static int connect_site __P((DB_ENV *, machtab_t *, const char *,
repsite_t *, int *, int *));
void * elect_thread __P((void *));
typedef struct {
DB_ENV *dbenv;
machtab_t *machtab;
} elect_args;
typedef struct {
DB_ENV *dbenv;
const char *progname;
const char *home;
int fd;
u_int32_t eid;
machtab_t *tab;
} hm_loop_args;
/*
* This is a generic message handling loop that is used both by the
* master to accept messages from a client as well as by clients
* to communicate with other clients.
*/
void *
hm_loop(args)
void *args;
{
DB_ENV *dbenv;
DBT rec, control;
const char *c, *home, *progname;
int fd, eid, n, newm;
int open, pri, r, ret, t_ret, tmpid;
elect_args *ea;
hm_loop_args *ha;
machtab_t *tab;
pthread_t elect_thr;
repsite_t self;
u_int32_t timeout;
void *status;
ea = NULL;
ha = (hm_loop_args *)args;
dbenv = ha->dbenv;
fd = ha->fd;
home = ha->home;
eid = ha->eid;
progname = ha->progname;
tab = ha->tab;
free(ha);
memset(&rec, 0, sizeof(DBT));
memset(&control, 0, sizeof(DBT));
for (ret = 0; ret == 0;) {
if ((ret = get_next_message(fd, &rec, &control)) != 0) {
/*
* Close this connection; if it's the master call
* for an election.
*/
close(fd);
if ((ret = machtab_rem(tab, eid, 1)) != 0)
break;
/*
* If I'm the master, I just lost a client and this
* thread is done.
*/
if (master_eid == SELF_EID)
break;
/*
* If I was talking with the master and the master
* went away, I need to call an election; else I'm
* done.
*/
if (master_eid != eid)
break;
master_eid = DB_EID_INVALID;
machtab_parm(tab, &n, &pri, &timeout);
if ((ret = dbenv->rep_elect(dbenv,
n, pri, timeout, &newm)) != 0)
continue;
/*
* Regardless of the results, the site I was talking
* to is gone, so I have nothing to do but exit.
*/
if (newm == SELF_EID && (ret =
dbenv->rep_start(dbenv, NULL, DB_REP_MASTER)) == 0)
ret = domaster(dbenv, progname);
break;
}
tmpid = eid;
switch(r = dbenv->rep_process_message(dbenv,
&control, &rec, &tmpid)) {
case DB_REP_NEWSITE:
/*
* Check if we got sent connect information and if we
* did, if this is me or if we already have a
* connection to this new site. If we don't,
* establish a new one.
*/
/* No connect info. */
if (rec.size == 0)
break;
/* It's me, do nothing. */
if (strncmp(myaddr, rec.data, rec.size) == 0)
break;
self.host = (char *)rec.data;
self.host = strtok(self.host, ":");
if ((c = strtok(NULL, ":")) == NULL) {
dbenv->errx(dbenv, "Bad host specification");
goto out;
}
self.port = atoi(c);
/*
* We try to connect to the new site. If we can't,
* we treat it as an error since we know that the site
* should be up if we got a message from it (even
* indirectly).
*/
if ((ret = connect_site(dbenv,
tab, progname, &self, &open, &eid)) != 0)
goto out;
break;
case DB_REP_HOLDELECTION:
if (master_eid == SELF_EID)
break;
/* Make sure that previous election has finished. */
if (ea != NULL) {
(void)pthread_join(elect_thr, &status);
ea = NULL;
}
if ((ea = calloc(sizeof(elect_args), 1)) == NULL) {
ret = errno;
goto out;
}
ea->dbenv = dbenv;
ea->machtab = tab;
ret = pthread_create(&elect_thr,
NULL, elect_thread, (void *)ea);
break;
case DB_REP_NEWMASTER:
/* Check if it's us. */
master_eid = tmpid;
if (tmpid == SELF_EID) {
if ((ret = dbenv->rep_start(dbenv,
NULL, DB_REP_MASTER)) != 0)
goto out;
ret = domaster(dbenv, progname);
}
break;
case 0:
break;
default:
dbenv->err(dbenv, r, "DB_ENV->rep_process_message");
break;
}
}
out: if ((t_ret = machtab_rem(tab, eid, 1)) != 0 && ret == 0)
ret = t_ret;
/* Don't close the environment before any children exit. */
if (ea != NULL)
(void)pthread_join(elect_thr, &status);
return ((void *)ret);
}
/*
* This is a generic thread that spawns a thread to listen for connections
* on a socket and then spawns off child threads to handle each new
* connection.
*/
void *
connect_thread(args)
void *args;
{
DB_ENV *dbenv;
const char *home, *progname;
int fd, i, eid, ns, port, ret;
hm_loop_args *ha;
connect_args *cargs;
machtab_t *machtab;
#define MAX_THREADS 25
pthread_t hm_thrs[MAX_THREADS];
pthread_attr_t attr;
ha = NULL;
cargs = (connect_args *)args;
dbenv = cargs->dbenv;
home = cargs->home;
progname = cargs->progname;
machtab = cargs->machtab;
port = cargs->port;
if ((ret = pthread_attr_init(&attr)) != 0)
return ((void *)EXIT_FAILURE);
if ((ret =
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) != 0)
goto err;
/*
* Loop forever, accepting connections from new machines,
* and forking off a thread to handle each.
*/
if ((fd = listen_socket_init(progname, port)) < 0) {
ret = errno;
goto err;
}
for (i = 0; i < MAX_THREADS; i++) {
if ((ns = listen_socket_accept(machtab,
progname, fd, &eid)) < 0) {
ret = errno;
goto err;
}
if ((ha = calloc(sizeof(hm_loop_args), 1)) == NULL)
goto err;
ha->progname = progname;
ha->home = home;
ha->fd = ns;
ha->eid = eid;
ha->tab = machtab;
ha->dbenv = dbenv;
if ((ret = pthread_create(&hm_thrs[i++], &attr,
hm_loop, (void *)ha)) != 0)
goto err;
ha = NULL;
}
/* If we fell out, we ended up with too many threads. */
dbenv->errx(dbenv, "Too many threads");
ret = ENOMEM;
err: pthread_attr_destroy(&attr);
return (ret == 0 ? (void *)EXIT_SUCCESS : (void *)EXIT_FAILURE);
}
/*
* Open a connection to everyone that we've been told about. If we
* cannot open some connections, keep trying.
*/
void *
connect_all(args)
void *args;
{
DB_ENV *dbenv;
all_args *aa;
const char *home, *progname;
hm_loop_args *ha;
int failed, i, eid, nsites, open, ret, *success;
machtab_t *machtab;
repsite_t *sites;
ha = NULL;
aa = (all_args *)args;
dbenv = aa->dbenv;
progname = aa->progname;
home = aa->home;
machtab = aa->machtab;
nsites = aa->nsites;
sites = aa->sites;
ret = 0;
/* Some implementations of calloc are sad about alloc'ing 0 things. */
if ((success = calloc(nsites > 0 ? nsites : 1, sizeof(int))) == NULL) {
dbenv->err(dbenv, errno, "connect_all");
ret = 1;
goto err;
}
for (failed = nsites; failed > 0;) {
for (i = 0; i < nsites; i++) {
if (success[i])
continue;
ret = connect_site(dbenv, machtab,
progname, &sites[i], &open, &eid);
/*
* If we couldn't make the connection, this isn't
* fatal to the loop, but we have nothing further
* to do on this machine at the moment.
*/
if (ret == DB_REP_UNAVAIL)
continue;
if (ret != 0)
goto err;
failed--;
success[i] = 1;
/* If the connection is already open, we're done. */
if (ret == 0 && open == 1)
continue;
}
sleep(1);
}
err: free(success);
return (ret ? (void *)EXIT_FAILURE : (void *)EXIT_SUCCESS);
}
int
connect_site(dbenv, machtab, progname, site, is_open, eidp)
DB_ENV *dbenv;
machtab_t *machtab;
const char *progname;
repsite_t *site;
int *is_open;
int *eidp;
{
int ret, s;
hm_loop_args *ha;
pthread_t hm_thr;
if ((s = get_connected_socket(machtab, progname,
site->host, site->port, is_open, eidp)) < 0)
return (DB_REP_UNAVAIL);
if (*is_open)
return (0);
if ((ha = calloc(sizeof(hm_loop_args), 1)) == NULL) {
ret = errno;
goto err;
}
ha->progname = progname;
ha->fd = s;
ha->eid = *eidp;
ha->tab = machtab;
ha->dbenv = dbenv;
if ((ret = pthread_create(&hm_thr, NULL,
hm_loop, (void *)ha)) != 0) {
dbenv->err(dbenv, ret, "connect site");
goto err1;
}
return (0);
err1: free(ha);
err:
return (ret);
}
/*
* We need to spawn off a new thread in which to hold an election in
* case we are the only thread listening on for messages.
*/
void *
elect_thread(args)
void *args;
{
DB_ENV *dbenv;
elect_args *eargs;
int n, ret, pri;
machtab_t *machtab;
u_int32_t timeout;
eargs = (elect_args *)args;
dbenv = eargs->dbenv;
machtab = eargs->machtab;
free(eargs);
machtab_parm(machtab, &n, &pri, &timeout);
while ((ret =
dbenv->rep_elect(dbenv, n, pri, timeout, &master_eid)) != 0)
sleep(2);
/* Check if it's us. */
if (master_eid == SELF_EID)
ret = dbenv->rep_start(dbenv, NULL, DB_REP_MASTER);
return ((void *)(ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE));
}
/*-
* 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;
}
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Sleepycat Software. All rights reserved.
*
* $Id: ex_tpcb.c,v 11.42 2002/08/06 05:39:00 bostic Exp $
*/
#include <sys/types.h>
#include <errno.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>
typedef enum { ACCOUNT, BRANCH, TELLER } FTYPE;
DB_ENV *db_init __P((const char *, const char *, int, int, u_int32_t));
int hpopulate __P((DB *, int, int, int, int));
int populate __P((DB *, u_int32_t, u_int32_t, int, const 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));
int invarg __P((const char *, int, const char *));
int main __P((int, char *[]));
int usage __P((const char *));
/*
* 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;
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;
const char *home, *progname;
home = "TESTDIR";
progname = "ex_tpcb";
accounts = branches = history = tellers = 0;
iflag = mpool = ntxns = txn_no_sync = verbose = 0;
seed = (int)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)
return (invarg(progname, ch, optarg));
break;
case 'b': /* Number of branch records */
if ((branches = atoi(optarg)) <= 0)
return (invarg(progname, ch, optarg));
break;
case 'c': /* Cachesize in bytes */
if ((mpool = atoi(optarg)) <= 0)
return (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)
return (invarg(progname, ch, optarg));
break;
case 'S': /* Random number seed. */
if ((seed = atoi(optarg)) <= 0)
return (invarg(progname, ch, optarg));
break;
case 's': /* Number of history records */
if ((history = atoi(optarg)) <= 0)
return (invarg(progname, ch, optarg));
break;
case 't': /* Number of teller records */
if ((tellers = atoi(optarg)) <= 0)
return (invarg(progname, ch, optarg));
break;
case 'v': /* Verbose option. */
verbose = 1;
break;
case '?':
default:
return (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 (EXIT_FAILURE);
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)
return (usage(progname));
tp_populate(dbenv,
accounts, branches, history, tellers, verbose);
} else {
if (ntxns == 0)
return (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 (EXIT_FAILURE);
}
return (EXIT_SUCCESS);
}
int
invarg(progname, arg, str)
const char *progname;
int arg;
const char *str;
{
(void)fprintf(stderr,
"%s: invalid argument for -%c: %s\n", progname, arg, str);
return (EXIT_FAILURE);
}
int
usage(progname)
const char *progname;
{
const 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);
return (EXIT_FAILURE);
}
/*
* db_init --
* Initialize the environment.
*/
DB_ENV *
db_init(home, prefix, cachesize, initializing, flags)
const char *home, *prefix;
int cachesize, initializing;
u_int32_t 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);
(void)dbenv->set_cachesize(dbenv, 0,
cachesize == 0 ? 4 * 1024 * 1024 : (u_int32_t)cachesize, 0);
if (flags & (DB_TXN_NOSYNC))
(void)dbenv->set_flags(dbenv, DB_TXN_NOSYNC, 1);
flags &= ~(DB_TXN_NOSYNC);
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, "DB_ENV->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;
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;
oflags = DB_CREATE | DB_TRUNCATE;
if ((ret = db_create(&dbp, env, 0)) != 0) {
env->err(env, ret, "db_create");
return (1);
}
(void)dbp->set_h_nelem(dbp, (u_int32_t)accounts);
if ((ret = dbp->open(dbp, NULL, "account", NULL,
DB_HASH, oflags, 0644)) != 0) {
env->err(env, ret, "DB->open: account");
return (1);
}
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 (1);
}
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 (1);
}
(void)dbp->set_h_ffactor(dbp, 1);
(void)dbp->set_h_nelem(dbp, (u_int32_t)branches);
(void)dbp->set_pagesize(dbp, 512);
if ((ret = dbp->open(dbp, NULL, "branch", NULL,
DB_HASH, oflags, 0644)) != 0) {
env->err(env, ret, "DB->open: branch");
return (1);
}
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 (1);
}
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 (1);
}
(void)dbp->set_h_ffactor(dbp, 0);
(void)dbp->set_h_nelem(dbp, (u_int32_t)tellers);
(void)dbp->set_pagesize(dbp, 512);
if ((ret = dbp->open(dbp, NULL, "teller", NULL,
DB_HASH, oflags, 0644)) != 0) {
env->err(env, ret, "DB->open: teller");
return (1);
}
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 (1);
}
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 (1);
}
(void)dbp->set_re_len(dbp, HISTORY_LEN);
if ((ret = dbp->open(dbp, NULL, "history", NULL,
DB_RECNO, oflags, 0644)) != 0) {
env->err(env, ret, "DB->open: history");
return (1);
}
hpopulate(dbp, history, accounts, branches, tellers);
if ((ret = dbp->close(dbp, 0)) != 0) {
env->err(env, ret, "DB->close: history");
return (1);
}
return (0);
}
int
populate(dbp, start_id, balance, nrecs, msg)
DB *dbp;
u_int32_t start_id, balance;
int nrecs;
const 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 (1);
}
}
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 (1);
}
}
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;
double gtps, itps;
int failed, ifailed, ret, txns;
time_t starttime, curtime, lasttime;
adb = bdb = hdb = tdb = NULL;
txns = failed = 0;
/*
* Open the database files.
*/
if ((ret = db_create(&adb, dbenv, 0)) != 0) {
dbenv->err(dbenv, ret, "db_create");
goto err;
}
if ((ret = adb->open(adb, NULL, "account", NULL, DB_UNKNOWN,
DB_AUTO_COMMIT, 0)) != 0) {
dbenv->err(dbenv, ret, "DB->open: account");
goto err;
}
if ((ret = db_create(&bdb, dbenv, 0)) != 0) {
dbenv->err(dbenv, ret, "db_create");
goto err;
}
if ((ret = bdb->open(bdb, NULL, "branch", NULL, DB_UNKNOWN,
DB_AUTO_COMMIT, 0)) != 0) {
dbenv->err(dbenv, ret, "DB->open: branch");
goto err;
}
if ((ret = db_create(&hdb, dbenv, 0)) != 0) {
dbenv->err(dbenv, ret, "db_create");
goto err;
}
if ((ret = hdb->open(hdb, NULL, "history", NULL, DB_UNKNOWN,
DB_AUTO_COMMIT, 0)) != 0) {
dbenv->err(dbenv, ret, "DB->open: history");
goto err;
}
if ((ret = db_create(&tdb, dbenv, 0)) != 0) {
dbenv->err(dbenv, ret, "db_create");
goto err;
}
if ((ret = tdb->open(tdb, NULL, "teller", NULL, DB_UNKNOWN,
DB_AUTO_COMMIT, 0)) != 0) {
dbenv->err(dbenv, ret, "DB->open: teller");
goto err;
}
starttime = time(NULL);
lasttime = starttime;
for (ifailed = 0; 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 txns %d failed ", txns, failed);
printf("%6.2f TPS (gross) %6.2f TPS (interval)\n",
gtps, itps);
lasttime = curtime;
ifailed = 0;
}
}
err: if (adb != NULL)
(void)adb->close(adb, 0);
if (bdb != NULL)
(void)bdb->close(bdb, 0);
if (tdb != NULL)
(void)tdb->close(tdb, 0);
if (hdb != NULL)
(void)hdb->close(hdb, 0);
printf("%ld transactions begun %ld failed\n", (long)txns, (long)failed);
return (ret == 0 ? 0 : 1);
}
/*
* 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, ret;
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 (dbenv->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;
ret = t->commit(t, 0);
t = NULL;
if (ret != 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)t->abort(t);
if (verbose)
printf("Transaction A=%ld B=%ld T=%ld failed\n",
(long)account, (long)branch, (long)teller);
return (-1);
}
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2002
* Sleepycat Software. All rights reserved.
*
* $Id: ex_tpcb.h,v 11.6 2002/01/11 15:52:06 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_ */
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Sleepycat Software. All rights reserved.
*
* $Id: AccessExample.cpp,v 11.18 2002/01/23 15:33:20 bostic Exp $
*/
#include <sys/types.h>
#include <iostream>
#include <iomanip>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <db_cxx.h>
using std::cin;
using std::cout;
using std::cerr;
class AccessExample
{
public:
AccessExample();
void run();
private:
static const char FileName[];
// no need for copy and assignment
AccessExample(const AccessExample &);
void operator = (const AccessExample &);
};
int main()
{
// 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 (EXIT_SUCCESS);
}
catch (DbException &dbe) {
cerr << "AccessExample: " << dbe.what() << "\n";
return (EXIT_FAILURE);
}
}
const char AccessExample::FileName[] = "access.db";
AccessExample::AccessExample()
{
}
void AccessExample::run()
{
// Remove the previous database.
(void)remove(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(NULL, 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);
}
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Sleepycat Software. All rights reserved.
*
* $Id: BtRecExample.cpp,v 11.21 2002/01/23 15:33:20 bostic Exp $
*/
#include <sys/types.h>
#include <errno.h>
#include <iostream>
#include <iomanip>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <db_cxx.h>
using std::cout;
using std::cerr;
#define DATABASE "access.db"
#define WORDLIST "../test/wordlist"
const char *progname = "BtRecExample"; // Program name.
class BtRecExample
{
public:
BtRecExample(FILE *fp);
~BtRecExample();
void run();
void stats();
void show(const 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)remove(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(NULL, 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, 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(const char *msg, Dbt *key, Dbt *data)
{
cout << msg << (char *)key->get_data()
<< " : " << (char *)data->get_data() << "\n";
}
int
main()
{
FILE *fp;
// Open the word database.
if ((fp = fopen(WORDLIST, "r")) == NULL) {
fprintf(stderr, "%s: open %s: %s\n",
progname, WORDLIST, db_strerror(errno));
return (EXIT_FAILURE);
}
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 (EXIT_FAILURE);
}
return (EXIT_SUCCESS);
}
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Sleepycat Software. All rights reserved.
*
* $Id: EnvExample.cpp,v 11.24 2002/01/11 15:52:15 bostic Exp $
*/
#include <sys/types.h>
#include <errno.h>
#include <iostream>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <db_cxx.h>
using std::ostream;
using std::cout;
using std::cerr;
#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(const char *, const char *, ostream&);
void db_teardown(const char *, const char *, ostream&);
const 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 {
const 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(home, data_dir, cerr);
cout << "Teardown env\n";
db_teardown(home, data_dir, cerr);
return (EXIT_SUCCESS);
}
catch (DbException &dbe) {
cerr << "EnvExample: " << dbe.what() << "\n";
return (EXIT_FAILURE);
}
}
// Note that any of the db calls can throw DbException
void
db_setup(const char *home, const 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(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(const char *home, const 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;
}
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Sleepycat Software. All rights reserved.
*
* $Id: LockExample.cpp,v 11.22 2002/01/11 15:52:15 bostic Exp $
*/
#include <sys/types.h>
#include <errno.h>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <db_cxx.h>
using std::cin;
using std::cout;
using std::cerr;
const char *progname = "LockExample"; // Program name.
//
// An example of a program using DBLock and related classes.
//
class LockExample : public DbEnv
{
public:
void run();
int error_code() { return (ecode); }
LockExample(const char *home, u_int32_t maxlocks, int do_unlink);
private:
static const char FileName[];
int ecode;
// no need for copy and assignment
LockExample(const LockExample &);
void operator = (const LockExample &);
};
static int 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)
return (usage());
home = argv[argnum];
}
else if (strcmp(argv[argnum], "-m") == 0) {
if (++argnum >= argc)
return (usage());
if ((i = atoi(argv[argnum])) <= 0)
return (usage());
maxlocks = (u_int32_t)i; /* XXX: possible overflow. */
}
else if (strcmp(argv[argnum], "-u") == 0) {
do_unlink = 1;
}
else {
return (usage());
}
}
try {
int ecode;
if (do_unlink) {
// Create an environment that immediately
// removes all files.
LockExample tmp(home, maxlocks, do_unlink);
if ((ecode = tmp.error_code()) != 0)
return (ecode);
}
LockExample app(home, maxlocks, do_unlink);
if ((ecode = app.error_code()) != 0)
return (ecode);
app.run();
app.close(0);
return (EXIT_SUCCESS);
}
catch (DbException &dbe) {
cerr << "LockExample: " << dbe.what() << "\n";
return (EXIT_FAILURE);
}
}
LockExample::LockExample(const char *home, u_int32_t maxlocks, int do_unlink)
: DbEnv(0)
, ecode(0)
{
int ret;
if (do_unlink) {
if ((ret = remove(home, DB_FORCE)) != 0) {
cerr << progname << ": DbEnv::remove: "
<< strerror(errno) << "\n";
ecode = EXIT_FAILURE;
}
}
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(&lock);
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 int
usage()
{
cerr << "usage: LockExample [-u] [-h home] [-m maxlocks]\n";
return (EXIT_FAILURE);
}
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Sleepycat Software. All rights reserved.
*
* $Id: MpoolExample.cpp,v 11.23 2002/01/11 15:52:15 bostic Exp $
*/
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <db_cxx.h>
using std::cout;
using std::cerr;
using std::ios;
using std::ofstream;
#define MPOOL "mpool"
int init(const char *, int, int);
int run(DB_ENV *, int, int, int);
static int usage();
const char *progname = "MpoolExample"; // Program name.
class MpoolExample : public DbEnv
{
public:
MpoolExample();
int initdb(const char *home, int cachesize);
int 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 ret;
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.
if ((ret = init(MPOOL, pagesize, npages)) != 0)
return (ret);
try {
MpoolExample app;
cout << progname
<< ": cachesize: " << cachesize
<< "; pagesize: " << pagesize
<< "; N pages: " << npages << "\n";
if ((ret = app.initdb(NULL, cachesize)) != 0)
return (ret);
if ((ret = app.run(hits, pagesize, npages)) != 0)
return (ret);
cout << "MpoolExample: completed\n";
return (EXIT_SUCCESS);
}
catch (DbException &dbe) {
cerr << "MpoolExample: " << dbe.what() << "\n";
return (EXIT_FAILURE);
}
}
//
// init --
// Create a backing file.
//
int
init(const char *file, int pagesize, int npages)
{
// Create a file with the right number of pages, and store a page
// number on each page.
ofstream of(file, ios::out | ios::binary);
if (of.fail()) {
cerr << "MpoolExample: " << file << ": open failed\n";
return (EXIT_FAILURE);
}
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;
of.write(p, pagesize);
if (of.fail()) {
cerr << "MpoolExample: " << file << ": write failed\n";
return (EXIT_FAILURE);
}
}
delete [] p;
return (EXIT_SUCCESS);
}
static int
usage()
{
cerr << "usage: MpoolExample [-c cachesize] "
<< "[-h hits] [-n npages] [-p pagesize]\n";
return (EXIT_FAILURE);
}
// 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)
{
}
int 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);
return (EXIT_SUCCESS);
}
//
// run --
// Get a set of pages.
//
int
MpoolExample::run(int hits, int pagesize, int npages)
{
db_pgno_t pageno;
int cnt, ret;
void *p;
// Open the file in the environment.
DbMpoolFile *mfp;
if ((ret = memp_fcreate(&mfp, 0)) != 0) {
cerr << "MpoolExample: memp_fcreate failed: "
<< strerror(ret) << "\n";
return (EXIT_FAILURE);
}
mfp->open(MPOOL, 0, 0, pagesize);
cout << "retrieve " << hits << " random pages... ";
srand((unsigned int)time(NULL));
for (cnt = 0; cnt < hits; ++cnt) {
pageno = (rand() % npages) + 1;
if ((ret = mfp->get(&pageno, 0, &p)) != 0) {
cerr << "MpoolExample: unable to retrieve page "
<< (unsigned long)pageno << ": "
<< strerror(ret) << "\n";
return (EXIT_FAILURE);
}
if (*(db_pgno_t *)p != pageno) {
cerr << "MpoolExample: wrong page retrieved ("
<< (unsigned long)pageno << " != "
<< *(int *)p << ")\n";
return (EXIT_FAILURE);
}
if ((ret = mfp->put(p, 0)) != 0) {
cerr << "MpoolExample: unable to return page "
<< (unsigned long)pageno << ": "
<< strerror(ret) << "\n";
return (EXIT_FAILURE);
}
}
cout << "successful.\n";
// Close the pool.
if ((ret = close(0)) != 0) {
cerr << "MpoolExample: " << strerror(ret) << "\n";
return (EXIT_FAILURE);
}
return (EXIT_SUCCESS);
}
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Sleepycat Software. All rights reserved.
*
* $Id: TpcbExample.cpp,v 11.30 2002/02/13 06:08:34 mjc Exp $
*/
#include <sys/types.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <iostream>
#include <iomanip>
#include <db_cxx.h>
using std::cout;
using std::cerr;
typedef enum { ACCOUNT, BRANCH, TELLER } FTYPE;
static int 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 int usage(void);
int verbose;
const 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, const 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;
const char *home;
char *endarg;
home = "TESTDIR";
accounts = branches = history = tellers = 0;
txn_no_sync = 0;
mpool = ntxns = 0;
verbose = 0;
iflag = 0;
seed = (unsigned long)time(NULL);
for (int i = 1; i < argc; ++i) {
if (strcmp(argv[i], "-a") == 0) {
// Number of account records
if ((accounts = atoi(argv[++i])) <= 0)
return (invarg('a', argv[i]));
}
else if (strcmp(argv[i], "-b") == 0) {
// Number of branch records
if ((branches = atoi(argv[++i])) <= 0)
return (invarg('b', argv[i]));
}
else if (strcmp(argv[i], "-c") == 0) {
// Cachesize in bytes
if ((mpool = atoi(argv[++i])) <= 0)
return (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)
return (invarg('n', argv[i]));
}
else if (strcmp(argv[i], "-S") == 0) {
// Random number seed.
seed = strtoul(argv[++i], &endarg, 0);
if (*endarg != '\0')
return (invarg('S', argv[i]));
}
else if (strcmp(argv[i], "-s") == 0) {
// Number of history records
if ((history = atoi(argv[++i])) <= 0)
return (invarg('s', argv[i]));
}
else if (strcmp(argv[i], "-t") == 0) {
// Number of teller records
if ((tellers = atoi(argv[++i])) <= 0)
return (invarg('t', argv[i]));
}
else if (strcmp(argv[i], "-v") == 0) {
// Verbose option.
verbose = 1;
}
else {
return (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)
return (usage());
app.populate(accounts, branches, history, tellers);
}
else {
if (ntxns == 0)
return (usage());
app.run(ntxns, accounts, branches, tellers);
}
app.close(0);
return (EXIT_SUCCESS);
}
catch (DbException &dbe) {
cerr << "TpcbExample: " << dbe.what() << "\n";
return (EXIT_FAILURE);
}
}
static int
invarg(int arg, char *str)
{
cerr << "TpcbExample: invalid argument for -"
<< (char)arg << ": " << str << "\n";
return (EXIT_FAILURE);
}
static int
usage()
{
cerr << "usage: TpcbExample [-fiv] [-a accounts] [-b branches]\n"
<< " [-c cachesize] [-h home] [-n transactions ]\n"
<< " [-S seed] [-s history] [-t tellers]\n";
return (EXIT_FAILURE);
}
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);
if (flags & (DB_TXN_NOSYNC))
set_flags(DB_TXN_NOSYNC, 1);
flags &= ~(DB_TXN_NOSYNC);
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(NULL, "account", NULL, DB_HASH,
DB_CREATE | DB_TRUNCATE, 0644)) != 0) {
DbException except("Account file create failed", err);
throw except;
}
start_anum = idnum;
populateTable(dbp, idnum, balance, accounts, "account");
idnum += accounts;
end_anum = idnum - 1;
if ((err = dbp->close(0)) != 0) {
DbException except("Account file close failed", err);
throw except;
}
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(NULL, "branch", NULL, DB_HASH,
DB_CREATE | DB_TRUNCATE, 0644)) != 0) {
DbException except("Branch file create failed", err);
throw except;
}
start_bnum = idnum;
populateTable(dbp, idnum, balance, branches, "branch");
idnum += branches;
end_bnum = idnum - 1;
if ((err = dbp->close(0)) != 0) {
DbException except("Close of branch file failed", err);
throw except;
}
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(NULL, "teller", NULL, DB_HASH,
DB_CREATE | DB_TRUNCATE, 0644)) != 0) {
DbException except("Teller file create failed", err);
throw except;
}
start_tnum = idnum;
populateTable(dbp, idnum, balance, tellers, "teller");
idnum += tellers;
end_tnum = idnum - 1;
if ((err = dbp->close(0)) != 0) {
DbException except("Close of teller file failed", err);
throw except;
}
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(NULL, "history", NULL, DB_RECNO,
DB_CREATE | DB_TRUNCATE, 0644)) != 0) {
DbException except("Create of history file failed", err);
throw except;
}
populateHistory(dbp, history, accounts, branches, tellers);
if ((err = dbp->close(0)) != 0) {
DbException except("Close of history file failed", err);
throw except;
}
delete dbp;
}
void
TpcbExample::populateTable(Db *dbp,
u_int32_t start_id, u_int32_t balance,
int nrecs, const 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";
DbException except("failure initializing file", err);
throw except;
}
}
}
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) {
DbException except("failure initializing history file",
err);
throw except;
}
}
}
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;
//
// Open the database files.
//
int err;
adb = new Db(this, 0);
if ((err = adb->open(NULL, "account", NULL, DB_UNKNOWN,
DB_AUTO_COMMIT, 0)) != 0) {
DbException except("Open of account file failed", err);
throw except;
}
bdb = new Db(this, 0);
if ((err = bdb->open(NULL, "branch", NULL, DB_UNKNOWN,
DB_AUTO_COMMIT, 0)) != 0) {
DbException except("Open of branch file failed", err);
throw except;
}
tdb = new Db(this, 0);
if ((err = tdb->open(NULL, "teller", NULL, DB_UNKNOWN,
DB_AUTO_COMMIT, 0)) != 0) {
DbException except("Open of teller file failed", err);
throw except;
}
hdb = new Db(this, 0);
if ((err = hdb->open(NULL, "history", NULL, DB_UNKNOWN,
DB_AUTO_COMMIT, 0)) != 0) {
DbException except("Open of history file failed", err);
throw except;
}
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 txns %d failed ", 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, ret;
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;
ret = t->commit(0);
t = NULL;
if (ret != 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);
}
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Sleepycat Software. All rights reserved.
*
* $Id: Db.java,v 11.110 2002/09/09 20:47:31 bostic Exp $
*/
package com.sleepycat.db;
import java.io.OutputStream;
import java.io.FileNotFoundException;
/**
*
* @author Donald D. Anderson
*/
public class Db
{
// BEGIN-JAVA-SPECIAL-CONSTANTS
/* DO NOT EDIT: automatically built by dist/s_java. */
public static final int DB_BTREE = 1;
public static final int DB_DONOTINDEX = -30999;
public static final int DB_HASH = 2;
public static final int DB_KEYEMPTY = -30998;
public static final int DB_KEYEXIST = -30997;
public static final int DB_LOCK_DEADLOCK = -30996;
public static final int DB_LOCK_NOTGRANTED = -30995;
public static final int DB_NOSERVER = -30994;
public static final int DB_NOSERVER_HOME = -30993;
public static final int DB_NOSERVER_ID = -30992;
public static final int DB_NOTFOUND = -30991;
public static final int DB_OLD_VERSION = -30990;
public static final int DB_PAGE_NOTFOUND = -30989;
public static final int DB_QUEUE = 4;
public static final int DB_RECNO = 3;
public static final int DB_REP_DUPMASTER = -30988;
public static final int DB_REP_HOLDELECTION = -30987;
public static final int DB_REP_NEWMASTER = -30986;
public static final int DB_REP_NEWSITE = -30985;
public static final int DB_REP_OUTDATED = -30984;
public static final int DB_RUNRECOVERY = -30982;
public static final int DB_SECONDARY_BAD = -30981;
public static final int DB_TXN_ABORT = 0;
public static final int DB_TXN_APPLY = 1;
public static final int DB_TXN_BACKWARD_ROLL = 3;
public static final int DB_TXN_FORWARD_ROLL = 4;
public static final int DB_TXN_PRINT = 8;
public static final int DB_UNKNOWN = 5;
public static final int DB_VERIFY_BAD = -30980;
public static final int DB_AFTER;
public static final int DB_AGGRESSIVE;
public static final int DB_APPEND;
public static final int DB_ARCH_ABS;
public static final int DB_ARCH_DATA;
public static final int DB_ARCH_LOG;
public static final int DB_AUTO_COMMIT;
public static final int DB_BEFORE;
public static final int DB_CACHED_COUNTS;
public static final int DB_CDB_ALLDB;
public static final int DB_CHKSUM_SHA1;
public static final int DB_CLIENT;
public static final int DB_CONSUME;
public static final int DB_CONSUME_WAIT;
public static final int DB_CREATE;
public static final int DB_CURRENT;
public static final int DB_CXX_NO_EXCEPTIONS;
public static final int DB_DBT_MALLOC;
public static final int DB_DBT_PARTIAL;
public static final int DB_DBT_REALLOC;
public static final int DB_DBT_USERMEM;
public static final int DB_DIRECT;
public static final int DB_DIRECT_DB;
public static final int DB_DIRECT_LOG;
public static final int DB_DIRTY_READ;
public static final int DB_DUP;
public static final int DB_DUPSORT;
public static final int DB_EID_BROADCAST;
public static final int DB_EID_INVALID;
public static final int DB_ENCRYPT;
public static final int DB_ENCRYPT_AES;
public static final int DB_EXCL;
public static final int DB_FAST_STAT;
public static final int DB_FIRST;
public static final int DB_FLUSH;
public static final int DB_FORCE;
public static final int DB_GET_BOTH;
public static final int DB_GET_BOTH_RANGE;
public static final int DB_GET_RECNO;
public static final int DB_INIT_CDB;
public static final int DB_INIT_LOCK;
public static final int DB_INIT_LOG;
public static final int DB_INIT_MPOOL;
public static final int DB_INIT_TXN;
public static final int DB_JOINENV;
public static final int DB_JOIN_ITEM;
public static final int DB_JOIN_NOSORT;
public static final int DB_KEYFIRST;
public static final int DB_KEYLAST;
public static final int DB_LAST;
public static final int DB_LOCKDOWN;
public static final int DB_LOCK_DEFAULT;
public static final int DB_LOCK_EXPIRE;
public static final int DB_LOCK_GET;
public static final int DB_LOCK_GET_TIMEOUT;
public static final int DB_LOCK_IREAD;
public static final int DB_LOCK_IWR;
public static final int DB_LOCK_IWRITE;
public static final int DB_LOCK_MAXLOCKS;
public static final int DB_LOCK_MINLOCKS;
public static final int DB_LOCK_MINWRITE;
public static final int DB_LOCK_NOWAIT;
public static final int DB_LOCK_OLDEST;
public static final int DB_LOCK_PUT;
public static final int DB_LOCK_PUT_ALL;
public static final int DB_LOCK_PUT_OBJ;
public static final int DB_LOCK_RANDOM;
public static final int DB_LOCK_READ;
public static final int DB_LOCK_TIMEOUT;
public static final int DB_LOCK_WRITE;
public static final int DB_LOCK_YOUNGEST;
public static final int DB_MULTIPLE;
public static final int DB_MULTIPLE_KEY;
public static final int DB_NEXT;
public static final int DB_NEXT_DUP;
public static final int DB_NEXT_NODUP;
public static final int DB_NODUPDATA;
public static final int DB_NOLOCKING;
public static final int DB_NOMMAP;
public static final int DB_NOORDERCHK;
public static final int DB_NOOVERWRITE;
public static final int DB_NOPANIC;
public static final int DB_NOSYNC;
public static final int DB_ODDFILESIZE;
public static final int DB_ORDERCHKONLY;
public static final int DB_OVERWRITE;
public static final int DB_PANIC_ENVIRONMENT;
public static final int DB_POSITION;
public static final int DB_PREV;
public static final int DB_PREV_NODUP;
public static final int DB_PRINTABLE;
public static final int DB_PRIORITY_DEFAULT;
public static final int DB_PRIORITY_HIGH;
public static final int DB_PRIORITY_LOW;
public static final int DB_PRIORITY_VERY_HIGH;
public static final int DB_PRIORITY_VERY_LOW;
public static final int DB_PRIVATE;
public static final int DB_RDONLY;
public static final int DB_RECNUM;
public static final int DB_RECORDCOUNT;
public static final int DB_RECOVER;
public static final int DB_RECOVER_FATAL;
public static final int DB_REGION_INIT;
public static final int DB_RENUMBER;
public static final int DB_REP_CLIENT;
public static final int DB_REP_LOGSONLY;
public static final int DB_REP_MASTER;
public static final int DB_REP_PERMANENT;
public static final int DB_REP_UNAVAIL;
public static final int DB_REVSPLITOFF;
public static final int DB_RMW;
public static final int DB_SALVAGE;
public static final int DB_SET;
public static final int DB_SET_LOCK_TIMEOUT;
public static final int DB_SET_RANGE;
public static final int DB_SET_RECNO;
public static final int DB_SET_TXN_TIMEOUT;
public static final int DB_SNAPSHOT;
public static final int DB_STAT_CLEAR;
public static final int DB_SYSTEM_MEM;
public static final int DB_THREAD;
public static final int DB_TRUNCATE;
public static final int DB_TXN_NOSYNC;
public static final int DB_TXN_NOWAIT;
public static final int DB_TXN_SYNC;
public static final int DB_TXN_WRITE_NOSYNC;
public static final int DB_UPGRADE;
public static final int DB_USE_ENVIRON;
public static final int DB_USE_ENVIRON_ROOT;
public static final int DB_VERB_CHKPOINT;
public static final int DB_VERB_DEADLOCK;
public static final int DB_VERB_RECOVERY;
public static final int DB_VERB_REPLICATION;
public static final int DB_VERB_WAITSFOR;
public static final int DB_VERIFY;
public static final int DB_VERSION_MAJOR;
public static final int DB_VERSION_MINOR;
public static final int DB_VERSION_PATCH;
public static final int DB_WRITECURSOR;
public static final int DB_XA_CREATE;
public static final int DB_XIDDATASIZE;
public static final int DB_YIELDCPU;
// END-JAVA-SPECIAL-CONSTANTS
// Note: the env can be null
//
public Db(DbEnv env, int flags)
throws DbException
{
constructor_env_ = env;
_init(env, flags);
if (env == null) {
dbenv_ = new DbEnv(this);
}
else {
dbenv_ = env;
}
dbenv_._add_db(this);
}
//
// Our parent DbEnv is notifying us that the environment is closing.
//
/*package*/ void _notify_dbenv_close()
{
dbenv_ = null;
_notify_internal();
}
private native void _init(DbEnv env, int flags)
throws DbException;
private native void _notify_internal();
// methods
//
public synchronized void associate(DbTxn txn, Db secondary,
DbSecondaryKeyCreate key_creator,
int flags)
throws DbException
{
secondary.secondary_key_create_ = key_creator;
_associate(txn, secondary, key_creator, flags);
}
public native void _associate(DbTxn txn, Db secondary,
DbSecondaryKeyCreate key_creator, int flags)
throws DbException;
public synchronized int close(int flags)
throws DbException
{
try {
dbenv_._remove_db(this);
return _close(flags);
}
finally {
if (constructor_env_ == null) {
dbenv_._notify_db_close();
}
dbenv_ = null;
}
}
public native int _close(int flags)
throws DbException;
public native Dbc cursor(DbTxn txnid, int flags)
throws DbException;
public native int del(DbTxn txnid, Dbt key, int flags)
throws DbException;
public native void err(int errcode, String message);
public native void errx(String message);
public native int fd()
throws DbException;
// overrides Object.finalize
protected void finalize()
throws Throwable
{
if (dbenv_ == null)
_finalize(null, null);
else
_finalize(dbenv_.errcall_, dbenv_.errpfx_);
}
protected native void _finalize(DbErrcall errcall, String errpfx)
throws Throwable;
// returns: 0, DB_NOTFOUND, or throws error
public native int get(DbTxn txnid, Dbt key, Dbt data, int flags)
throws DbException;
public native boolean get_byteswapped();
public native /*DBTYPE*/ int get_type();
public native Dbc join(Dbc curslist[], int flags)
throws DbException;
public native void key_range(DbTxn txnid, Dbt key,
DbKeyRange range, int flags)
throws DbException;
public synchronized void open(DbTxn txnid, String file,
String database, /*DBTYPE*/ int type,
int flags, int mode)
throws DbException, FileNotFoundException
{
_open(txnid, file, database, type, flags, mode);
}
// (Internal)
public native void _open(DbTxn txnid, String file,
String database, /*DBTYPE*/ int type,
int flags, int mode)
throws DbException, FileNotFoundException;
// returns: 0, DB_NOTFOUND, or throws error
public native int pget(DbTxn txnid, Dbt key, Dbt pkey, Dbt data, int flags)
throws DbException;
// returns: 0, DB_KEYEXIST, or throws error
public native int put(DbTxn txnid, Dbt key, Dbt data, int flags)
throws DbException;
public synchronized void rename(String file, String database,
String newname, int flags)
throws DbException, FileNotFoundException
{
try {
_rename(file, database, newname, flags);
}
finally {
if (constructor_env_ == null) {
dbenv_._notify_db_close();
}
dbenv_ = null;
}
}
public native void _rename(String file, String database,
String newname, int flags)
throws DbException, FileNotFoundException;
public synchronized void remove(String file,
String database, int flags)
throws DbException, FileNotFoundException
{
try {
_remove(file, database, flags);
}
finally {
if (constructor_env_ == null) {
dbenv_._notify_db_close();
}
dbenv_ = null;
}
}
public native void _remove(String file, String database,
int flags)
throws DbException, FileNotFoundException;
// Comparison function.
public void set_append_recno(DbAppendRecno append_recno)
throws DbException
{
append_recno_ = append_recno;
append_recno_changed(append_recno);
}
// (Internal)
private native void append_recno_changed(DbAppendRecno append_recno)
throws DbException;
// Comparison function.
public void set_bt_compare(DbBtreeCompare bt_compare)
throws DbException
{
bt_compare_ = bt_compare;
bt_compare_changed(bt_compare);
}
// (Internal)
private native void bt_compare_changed(DbBtreeCompare bt_compare)
throws DbException;
// Maximum keys per page.
public native void set_bt_maxkey(int maxkey)
throws DbException;
// Minimum keys per page.
public native void set_bt_minkey(int minkey)
throws DbException;
// Prefix function.
public void set_bt_prefix(DbBtreePrefix bt_prefix)
throws DbException
{
bt_prefix_ = bt_prefix;
bt_prefix_changed(bt_prefix);
}
// (Internal)
private native void bt_prefix_changed(DbBtreePrefix bt_prefix)
throws DbException;
// Set cache size
public native void set_cachesize(int gbytes, int bytes, int ncaches)
throws DbException;
// Set cache priority
public native void set_cache_priority(/* DB_CACHE_PRIORITY */ int priority)
throws DbException;
// Duplication resolution
public void set_dup_compare(DbDupCompare dup_compare)
throws DbException
{
dup_compare_ = dup_compare;
dup_compare_changed(dup_compare);
}
// (Internal)
private native void dup_compare_changed(DbDupCompare dup_compare)
throws DbException;
// Encryption
public native void set_encrypt(String passwd, /*u_int32_t*/ int flags)
throws DbException;
// Error message callback.
public void set_errcall(DbErrcall errcall)
{
if (dbenv_ != null)
dbenv_.set_errcall(errcall);
}
// Error stream.
public void set_error_stream(OutputStream s)
{
DbOutputStreamErrcall errcall = new DbOutputStreamErrcall(s);
set_errcall(errcall);
}
// Error message prefix.
public void set_errpfx(String errpfx)
{
if (dbenv_ != null)
dbenv_.set_errpfx(errpfx);
}
// Feedback
public void set_feedback(DbFeedback feedback)
throws DbException
{
feedback_ = feedback;
feedback_changed(feedback);
}
// (Internal)
private native void feedback_changed(DbFeedback feedback)
throws DbException;
// Flags.
public native void set_flags(/*u_int32_t*/ int flags)
throws DbException;
// Internal - only intended for testing purposes in the Java RPC server
public native int get_flags_raw()
throws DbException;
// Fill factor.
public native void set_h_ffactor(/*unsigned*/ int h_ffactor)
throws DbException;
// Hash function.
public void set_h_hash(DbHash h_hash)
throws DbException
{
h_hash_ = h_hash;
hash_changed(h_hash);
}
// (Internal)
private native void hash_changed(DbHash hash)
throws DbException;
// Number of elements.
public native void set_h_nelem(/*unsigned*/ int h_nelem)
throws DbException;
// Byte order.
public native void set_lorder(int lorder)
throws DbException;
// Underlying page size.
public native void set_pagesize(/*size_t*/ long pagesize)
throws DbException;
// Variable-length delimiting byte.
public native void set_re_delim(int re_delim)
throws DbException;
// Length for fixed-length records.
public native void set_re_len(/*u_int32_t*/ int re_len)
throws DbException;
// Fixed-length padding byte.
public native void set_re_pad(int re_pad)
throws DbException;
// Source file name.
public native void set_re_source(String re_source)
throws DbException;
// Extent size of Queue
public native void set_q_extentsize(/*u_int32_t*/ int extent_size)
throws DbException;
// returns a DbBtreeStat or DbHashStat
public native Object stat(int flags)
throws DbException;
public native void sync(int flags)
throws DbException;
public native int truncate(DbTxn txnid, int flags)
throws DbException;
public native void upgrade(String name, int flags)
throws DbException;
public native void verify(String name, String subdb,
OutputStream outstr, int flags)
throws DbException;
////////////////////////////////////////////////////////////////
//
// private data
//
private long private_dbobj_ = 0;
private long private_info_ = 0;
private DbEnv dbenv_ = null;
private DbEnv constructor_env_ = null;
private DbFeedback feedback_ = null;
private DbAppendRecno append_recno_ = null;
private DbBtreeCompare bt_compare_ = null;
private DbBtreePrefix bt_prefix_ = null;
private DbDupCompare dup_compare_ = null;
private DbHash h_hash_ = null;
private DbSecondaryKeyCreate secondary_key_create_ = null;
////////////////////////////////////////////////////////////////
//
// static methods and data that implement
// loading the native library and doing any
// extra sanity checks on startup.
//
private static boolean already_loaded_ = false;
public static void load_db()
{
if (already_loaded_)
return;
// An alternate library name can be specified via a property.
//
String override;
if ((override = System.getProperty("sleepycat.db.libfile")) != null) {
System.load(override);
}
else if ((override = System.getProperty("sleepycat.db.libname")) != null) {
System.loadLibrary(override);
}
else {
String os = System.getProperty("os.name");
if (os != null && os.startsWith("Windows")) {
// library name is "libdb_java30.dll" (for example) on Win/*
System.loadLibrary("libdb_java" +
DbConstants.DB_VERSION_MAJOR +
DbConstants.DB_VERSION_MINOR);
}
else {
// library name is "libdb_java-3.0.so" (for example) on UNIX
// Note: "db_java" isn't good enough;
// some Unixes require us to use the explicit SONAME.
System.loadLibrary("db_java-" +
DbConstants.DB_VERSION_MAJOR + "." +
DbConstants.DB_VERSION_MINOR);
}
}
already_loaded_ = true;
}
static private native void one_time_init();
static private void check_constant(int c1, int c2)
{
if (c1 != c2) {
System.err.println("Db: constant mismatch");
Thread.dumpStack();
System.exit(1);
}
}
static {
Db.load_db();
// BEGIN-JAVA-CONSTANT-INITIALIZATION
/* DO NOT EDIT: automatically built by dist/s_java. */
DB_AFTER = DbConstants.DB_AFTER;
DB_AGGRESSIVE = DbConstants.DB_AGGRESSIVE;
DB_APPEND = DbConstants.DB_APPEND;
DB_ARCH_ABS = DbConstants.DB_ARCH_ABS;
DB_ARCH_DATA = DbConstants.DB_ARCH_DATA;
DB_ARCH_LOG = DbConstants.DB_ARCH_LOG;
DB_AUTO_COMMIT = DbConstants.DB_AUTO_COMMIT;
DB_BEFORE = DbConstants.DB_BEFORE;
DB_CACHED_COUNTS = DbConstants.DB_CACHED_COUNTS;
DB_CDB_ALLDB = DbConstants.DB_CDB_ALLDB;
DB_CHKSUM_SHA1 = DbConstants.DB_CHKSUM_SHA1;
DB_CLIENT = DbConstants.DB_CLIENT;
DB_CONSUME = DbConstants.DB_CONSUME;
DB_CONSUME_WAIT = DbConstants.DB_CONSUME_WAIT;
DB_CREATE = DbConstants.DB_CREATE;
DB_CURRENT = DbConstants.DB_CURRENT;
DB_CXX_NO_EXCEPTIONS = DbConstants.DB_CXX_NO_EXCEPTIONS;
DB_DBT_MALLOC = DbConstants.DB_DBT_MALLOC;
DB_DBT_PARTIAL = DbConstants.DB_DBT_PARTIAL;
DB_DBT_REALLOC = DbConstants.DB_DBT_REALLOC;
DB_DBT_USERMEM = DbConstants.DB_DBT_USERMEM;
DB_DIRECT = DbConstants.DB_DIRECT;
DB_DIRECT_DB = DbConstants.DB_DIRECT_DB;
DB_DIRECT_LOG = DbConstants.DB_DIRECT_LOG;
DB_DIRTY_READ = DbConstants.DB_DIRTY_READ;
DB_DUP = DbConstants.DB_DUP;
DB_DUPSORT = DbConstants.DB_DUPSORT;
DB_EID_BROADCAST = DbConstants.DB_EID_BROADCAST;
DB_EID_INVALID = DbConstants.DB_EID_INVALID;
DB_ENCRYPT = DbConstants.DB_ENCRYPT;
DB_ENCRYPT_AES = DbConstants.DB_ENCRYPT_AES;
DB_EXCL = DbConstants.DB_EXCL;
DB_FAST_STAT = DbConstants.DB_FAST_STAT;
DB_FIRST = DbConstants.DB_FIRST;
DB_FLUSH = DbConstants.DB_FLUSH;
DB_FORCE = DbConstants.DB_FORCE;
DB_GET_BOTH = DbConstants.DB_GET_BOTH;
DB_GET_BOTH_RANGE = DbConstants.DB_GET_BOTH_RANGE;
DB_GET_RECNO = DbConstants.DB_GET_RECNO;
DB_INIT_CDB = DbConstants.DB_INIT_CDB;
DB_INIT_LOCK = DbConstants.DB_INIT_LOCK;
DB_INIT_LOG = DbConstants.DB_INIT_LOG;
DB_INIT_MPOOL = DbConstants.DB_INIT_MPOOL;
DB_INIT_TXN = DbConstants.DB_INIT_TXN;
DB_JOINENV = DbConstants.DB_JOINENV;
DB_JOIN_ITEM = DbConstants.DB_JOIN_ITEM;
DB_JOIN_NOSORT = DbConstants.DB_JOIN_NOSORT;
DB_KEYFIRST = DbConstants.DB_KEYFIRST;
DB_KEYLAST = DbConstants.DB_KEYLAST;
DB_LAST = DbConstants.DB_LAST;
DB_LOCKDOWN = DbConstants.DB_LOCKDOWN;
DB_LOCK_DEFAULT = DbConstants.DB_LOCK_DEFAULT;
DB_LOCK_EXPIRE = DbConstants.DB_LOCK_EXPIRE;
DB_LOCK_GET = DbConstants.DB_LOCK_GET;
DB_LOCK_GET_TIMEOUT = DbConstants.DB_LOCK_GET_TIMEOUT;
DB_LOCK_IREAD = DbConstants.DB_LOCK_IREAD;
DB_LOCK_IWR = DbConstants.DB_LOCK_IWR;
DB_LOCK_IWRITE = DbConstants.DB_LOCK_IWRITE;
DB_LOCK_MAXLOCKS = DbConstants.DB_LOCK_MAXLOCKS;
DB_LOCK_MINLOCKS = DbConstants.DB_LOCK_MINLOCKS;
DB_LOCK_MINWRITE = DbConstants.DB_LOCK_MINWRITE;
DB_LOCK_NOWAIT = DbConstants.DB_LOCK_NOWAIT;
DB_LOCK_OLDEST = DbConstants.DB_LOCK_OLDEST;
DB_LOCK_PUT = DbConstants.DB_LOCK_PUT;
DB_LOCK_PUT_ALL = DbConstants.DB_LOCK_PUT_ALL;
DB_LOCK_PUT_OBJ = DbConstants.DB_LOCK_PUT_OBJ;
DB_LOCK_RANDOM = DbConstants.DB_LOCK_RANDOM;
DB_LOCK_READ = DbConstants.DB_LOCK_READ;
DB_LOCK_TIMEOUT = DbConstants.DB_LOCK_TIMEOUT;
DB_LOCK_WRITE = DbConstants.DB_LOCK_WRITE;
DB_LOCK_YOUNGEST = DbConstants.DB_LOCK_YOUNGEST;
DB_MULTIPLE = DbConstants.DB_MULTIPLE;
DB_MULTIPLE_KEY = DbConstants.DB_MULTIPLE_KEY;
DB_NEXT = DbConstants.DB_NEXT;
DB_NEXT_DUP = DbConstants.DB_NEXT_DUP;
DB_NEXT_NODUP = DbConstants.DB_NEXT_NODUP;
DB_NODUPDATA = DbConstants.DB_NODUPDATA;
DB_NOLOCKING = DbConstants.DB_NOLOCKING;
DB_NOMMAP = DbConstants.DB_NOMMAP;
DB_NOORDERCHK = DbConstants.DB_NOORDERCHK;
DB_NOOVERWRITE = DbConstants.DB_NOOVERWRITE;
DB_NOPANIC = DbConstants.DB_NOPANIC;
DB_NOSYNC = DbConstants.DB_NOSYNC;
DB_ODDFILESIZE = DbConstants.DB_ODDFILESIZE;
DB_ORDERCHKONLY = DbConstants.DB_ORDERCHKONLY;
DB_OVERWRITE = DbConstants.DB_OVERWRITE;
DB_PANIC_ENVIRONMENT = DbConstants.DB_PANIC_ENVIRONMENT;
DB_POSITION = DbConstants.DB_POSITION;
DB_PREV = DbConstants.DB_PREV;
DB_PREV_NODUP = DbConstants.DB_PREV_NODUP;
DB_PRINTABLE = DbConstants.DB_PRINTABLE;
DB_PRIORITY_DEFAULT = DbConstants.DB_PRIORITY_DEFAULT;
DB_PRIORITY_HIGH = DbConstants.DB_PRIORITY_HIGH;
DB_PRIORITY_LOW = DbConstants.DB_PRIORITY_LOW;
DB_PRIORITY_VERY_HIGH = DbConstants.DB_PRIORITY_VERY_HIGH;
DB_PRIORITY_VERY_LOW = DbConstants.DB_PRIORITY_VERY_LOW;
DB_PRIVATE = DbConstants.DB_PRIVATE;
DB_RDONLY = DbConstants.DB_RDONLY;
DB_RECNUM = DbConstants.DB_RECNUM;
DB_RECORDCOUNT = DbConstants.DB_RECORDCOUNT;
DB_RECOVER = DbConstants.DB_RECOVER;
DB_RECOVER_FATAL = DbConstants.DB_RECOVER_FATAL;
DB_REGION_INIT = DbConstants.DB_REGION_INIT;
DB_RENUMBER = DbConstants.DB_RENUMBER;
DB_REP_CLIENT = DbConstants.DB_REP_CLIENT;
DB_REP_LOGSONLY = DbConstants.DB_REP_LOGSONLY;
DB_REP_MASTER = DbConstants.DB_REP_MASTER;
DB_REP_PERMANENT = DbConstants.DB_REP_PERMANENT;
DB_REP_UNAVAIL = DbConstants.DB_REP_UNAVAIL;
DB_REVSPLITOFF = DbConstants.DB_REVSPLITOFF;
DB_RMW = DbConstants.DB_RMW;
DB_SALVAGE = DbConstants.DB_SALVAGE;
DB_SET = DbConstants.DB_SET;
DB_SET_LOCK_TIMEOUT = DbConstants.DB_SET_LOCK_TIMEOUT;
DB_SET_RANGE = DbConstants.DB_SET_RANGE;
DB_SET_RECNO = DbConstants.DB_SET_RECNO;
DB_SET_TXN_TIMEOUT = DbConstants.DB_SET_TXN_TIMEOUT;
DB_SNAPSHOT = DbConstants.DB_SNAPSHOT;
DB_STAT_CLEAR = DbConstants.DB_STAT_CLEAR;
DB_SYSTEM_MEM = DbConstants.DB_SYSTEM_MEM;
DB_THREAD = DbConstants.DB_THREAD;
DB_TRUNCATE = DbConstants.DB_TRUNCATE;
DB_TXN_NOSYNC = DbConstants.DB_TXN_NOSYNC;
DB_TXN_NOWAIT = DbConstants.DB_TXN_NOWAIT;
DB_TXN_SYNC = DbConstants.DB_TXN_SYNC;
DB_TXN_WRITE_NOSYNC = DbConstants.DB_TXN_WRITE_NOSYNC;
DB_UPGRADE = DbConstants.DB_UPGRADE;
DB_USE_ENVIRON = DbConstants.DB_USE_ENVIRON;
DB_USE_ENVIRON_ROOT = DbConstants.DB_USE_ENVIRON_ROOT;
DB_VERB_CHKPOINT = DbConstants.DB_VERB_CHKPOINT;
DB_VERB_DEADLOCK = DbConstants.DB_VERB_DEADLOCK;
DB_VERB_RECOVERY = DbConstants.DB_VERB_RECOVERY;
DB_VERB_REPLICATION = DbConstants.DB_VERB_REPLICATION;
DB_VERB_WAITSFOR = DbConstants.DB_VERB_WAITSFOR;
DB_VERIFY = DbConstants.DB_VERIFY;
DB_VERSION_MAJOR = DbConstants.DB_VERSION_MAJOR;
DB_VERSION_MINOR = DbConstants.DB_VERSION_MINOR;
DB_VERSION_PATCH = DbConstants.DB_VERSION_PATCH;
DB_WRITECURSOR = DbConstants.DB_WRITECURSOR;
DB_XA_CREATE = DbConstants.DB_XA_CREATE;
DB_XIDDATASIZE = DbConstants.DB_XIDDATASIZE;
DB_YIELDCPU = DbConstants.DB_YIELDCPU;
// END-JAVA-CONSTANT-INITIALIZATION
one_time_init();
}
}
// end of Db.java
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2000-2002
* Sleepycat Software. All rights reserved.
*
* $Id: DbAppDispatch.java,v 11.6 2002/02/26 16:23:02 krinsky Exp $
*/
package com.sleepycat.db;
/*
* This interface is used by DbEnv.set_app_dispatch()
*
*/
public interface DbAppDispatch
{
// The value of recops is one of the Db.DB_TXN_* constants
public abstract int app_dispatch(DbEnv env, Dbt dbt, DbLsn lsn, int recops);
}
// end of DbAppDispatch.java
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2000-2002
* Sleepycat Software. All rights reserved.
*
* $Id: DbAppendRecno.java,v 11.5 2002/01/11 15:52:33 bostic Exp $
*/
package com.sleepycat.db;
/*
* This interface is used by Db.set_append_recno()
*
*/
public interface DbAppendRecno
{
public abstract void db_append_recno(Db db, Dbt data, int recno)
throws DbException;
}
// end of DbAppendRecno.java
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2000-2002
* Sleepycat Software. All rights reserved.
*
* $Id: DbBtreeCompare.java,v 11.6 2002/01/11 15:52:33 bostic Exp $
*/
package com.sleepycat.db;
/*
* This interface is used by DbEnv.set_bt_compare()
*
*/
public interface DbBtreeCompare
{
public abstract int bt_compare(Db db, Dbt dbt1, Dbt dbt2);
}
// end of DbBtreeCompare.java
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2000-2002
* Sleepycat Software. All rights reserved.
*
* $Id: DbBtreePrefix.java,v 11.6 2002/01/11 15:52:33 bostic Exp $
*/
package com.sleepycat.db;
/*
* This interface is used by DbEnv.set_bt_prefix()
*
*/
public interface DbBtreePrefix
{
public abstract int bt_prefix(Db db, Dbt dbt1, Dbt dbt2);
}
// end of DbBtreePrefix.java
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2000-2002
* Sleepycat Software. All rights reserved.
*
* $Id: DbClient.java,v 11.4 2002/01/11 15:52:33 bostic Exp $
*/
package com.sleepycat.db;
/*
* This interface is used by DbEnv.set_rpc_server().
* It is a placeholder for a future capability.
*
*/
public interface DbClient
{
}
// end of DbClient.java
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1999-2002
* Sleepycat Software. All rights reserved.
*
* $Id: DbDeadlockException.java,v 11.6 2002/01/11 15:52:33 bostic Exp $
*/
package com.sleepycat.db;
public class DbDeadlockException extends DbException
{
// methods
//
public DbDeadlockException(String s)
{
super(s);
}
public DbDeadlockException(String s, int errno)
{
super(s, errno);
}
}
// end of DbDeadlockException.java
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2000-2002
* Sleepycat Software. All rights reserved.
*
* $Id: DbDupCompare.java,v 11.6 2002/01/11 15:52:34 bostic Exp $
*/
package com.sleepycat.db;
/*
* This interface is used by DbEnv.set_dup_compare()
*
*/
public interface DbDupCompare
{
public abstract int dup_compare(Db db, Dbt dbt1, Dbt dbt2);
}
// end of DbDupCompare.java
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Sleepycat Software. All rights reserved.
*
* $Id: DbEnv.java,v 11.58 2002/08/29 14:22:22 margo Exp $
*/
package com.sleepycat.db;
import java.io.OutputStream;
import java.io.FileNotFoundException;
import java.util.Date;
import java.util.Enumeration;
import java.util.Vector;
/**
*
* @author Donald D. Anderson
*/
public class DbEnv
{
// methods
//
//
// After using this constructor, set any parameters via
// the set_* access methods below, and finally open
// the environment by calling open().
//
public DbEnv(int flags) throws DbException
{
constructor_flags_ = flags;
_init(errstream_, constructor_flags_);
}
//
// This constructor is purposely not public.
// It is used internally to create a DbEnv wrapper
// when an underlying environment already exists.
//
/*package*/ DbEnv(Db db)
{
_init_using_db(errstream_, db);
}
//
// When a Db is created, it is kept in a private list,
// so that Db's can be notified when the environment
// is closed. This allows us to detect and guard
// against the following situation:
// DbEnv env = new DbEnv(0);
// Db db = new Db(0);
// env.close();
// db.close();
//
// This *is* a programming error, but not protecting
// against it will crash the VM.
//
/*package*/ void _add_db(Db db)
{
dblist_.addElement(db);
}
//
// Remove from the private list of Db's.
//
/*package*/ void _remove_db(Db db)
{
dblist_.removeElement(db);
}
//
// Iterate all the Db's in the list, and
// notify them that the environment is closing,
// so they can clean up.
//
/*package*/ void _notify_dbs()
{
Enumeration enum = dblist_.elements();
while (enum.hasMoreElements()) {
Db db = (Db)enum.nextElement();
db._notify_dbenv_close();
}
dblist_.removeAllElements();
}
// close discards any internal memory.
// After using close, the DbEnv can be reopened.
//
public synchronized void close(int flags)
throws DbException
{
_notify_dbs();
_close(flags);
}
// (Internal)
private native void _close(int flags)
throws DbException;
public native void dbremove(DbTxn txn, String name, String subdb,
int flags)
throws DbException;
public native void dbrename(DbTxn txn, String name, String subdb,
String newname, int flags)
throws DbException;
public native void err(int errcode, String message);
public native void errx(String message);
// overrides Object.finalize
protected void finalize()
throws Throwable
{
_notify_dbs();
_finalize(errcall_, errpfx_);
}
// (Internal)
protected native void _finalize(DbErrcall errcall, String errpfx)
throws Throwable;
// (Internal)
// called during constructor
private native void _init(DbErrcall errcall, int flags) throws DbException;
// (Internal)
// called when DbEnv is constructed as part of Db constructor.
private native void _init_using_db(DbErrcall errcall, Db db);
/*package*/ native void _notify_db_close();
public native void open(String db_home, int flags, int mode)
throws DbException, FileNotFoundException;
// remove removes any files and discards any internal memory.
// (i.e. implicitly it does a close, if the environment is open).
// After using close, the DbEnv can no longer be used;
// create another one if needed.
//
public native synchronized void remove(String db_home, int flags)
throws DbException, FileNotFoundException;
////////////////////////////////////////////////////////////////
// simple get/set access methods
//
// If you are calling set_ methods, you need to
// use the constructor with one argument along with open().
public native void set_cachesize(int gbytes, int bytes, int ncaches)
throws DbException;
// Encryption
public native void set_encrypt(String passwd, /*u_int32_t*/ int flags)
throws DbException;
// Error message callback.
public void set_errcall(DbErrcall errcall)
{
errcall_ = errcall;
_set_errcall(errcall);
}
public native void _set_errcall(DbErrcall errcall);
// Error stream.
public void set_error_stream(OutputStream s)
{
DbOutputStreamErrcall errcall = new DbOutputStreamErrcall(s);
set_errcall(errcall);
}
// Error message prefix.
public void set_errpfx(String errpfx)
{
errpfx_ = errpfx;
_set_errpfx(errpfx);
}
private native void _set_errpfx(String errpfx);
// Feedback
public void set_feedback(DbEnvFeedback feedback)
throws DbException
{
feedback_ = feedback;
feedback_changed(feedback);
}
// (Internal)
private native void feedback_changed(DbEnvFeedback feedback)
throws DbException;
// Generate debugging messages.
public native void set_verbose(int which, boolean onoff)
throws DbException;
public native void set_data_dir(String data_dir)
throws DbException;
// Log buffer size.
public native void set_lg_bsize(/*u_int32_t*/ int lg_bsize)
throws DbException;
// Log directory.
public native void set_lg_dir(String lg_dir)
throws DbException;
// Maximum log file size.
public native void set_lg_max(/*u_int32_t*/ int lg_max)
throws DbException;
// Log region size.
public native void set_lg_regionmax(/*u_int32_t*/ int lg_regionmax)
throws DbException;
// Two dimensional conflict matrix.
public native void set_lk_conflicts(byte[][] lk_conflicts)
throws DbException;
// Deadlock detect on every conflict.
public native void set_lk_detect(/*u_int32_t*/ int lk_detect)
throws DbException;
/**
* @deprecated DB 3.2.6, see the online documentation.
*/
// Maximum number of locks.
public native void set_lk_max(/*unsigned*/ int lk_max)
throws DbException;
// Maximum number of lockers.
public native void set_lk_max_lockers(/*unsigned*/ int lk_max_lockers)
throws DbException;
// Maximum number of locks.
public native void set_lk_max_locks(/*unsigned*/ int lk_max_locks)
throws DbException;
// Maximum number of locked objects.
public native void set_lk_max_objects(/*unsigned*/ int lk_max_objects)
throws DbException;
// Maximum file size for mmap.
public native void set_mp_mmapsize(/*size_t*/ long mmapsize)
throws DbException;
public native void set_flags(int flags, boolean onoff)
throws DbException;
public native void set_rep_limit(int gbytes, int bytes) throws DbException;
public void set_rep_transport(int envid, DbRepTransport transport)
throws DbException
{
rep_transport_ = transport;
rep_transport_changed(envid, transport);
}
// (Internal)
private native void rep_transport_changed(int envid,
DbRepTransport transport)
throws DbException;
public native void set_rpc_server(DbClient client, String host,
long cl_timeout, long sv_timeout,
int flags)
throws DbException;
public native void set_shm_key(long shm_key)
throws DbException;
public native void set_tas_spins(int tas_spins)
throws DbException;
public native void set_timeout(/*db_timeout_t*/ long timeout,
/*u_int32_t*/ int flags)
throws DbException;
public native void set_tmp_dir(String tmp_dir)
throws DbException;
// Feedback
public void set_app_dispatch(DbAppDispatch app_dispatch)
throws DbException
{
app_dispatch_ = app_dispatch;
app_dispatch_changed(app_dispatch);
}
// (Internal)
private native void app_dispatch_changed(DbAppDispatch app_dispatch)
throws DbException;
// Maximum number of transactions.
public native void set_tx_max(/*unsigned*/ int tx_max)
throws DbException;
// Note: only the seconds (not milliseconds) of the timestamp
// are used in this API.
public void set_tx_timestamp(Date timestamp)
throws DbException
{
_set_tx_timestamp(timestamp.getTime()/1000);
}
// (Internal)
private native void _set_tx_timestamp(long seconds)
throws DbException;
// Versioning information
public native static int get_version_major();
public native static int get_version_minor();
public native static int get_version_patch();
public native static String get_version_string();
// Convert DB error codes to strings
public native static String strerror(int errcode);
public native int lock_detect(int flags, int atype)
throws DbException;
public native DbLock lock_get(/*u_int32_t*/ int locker,
int flags,
Dbt obj,
/*db_lockmode_t*/ int lock_mode)
throws DbException;
public native void lock_put(DbLock lock)
throws DbException;
public native /*u_int32_t*/ int lock_id()
throws DbException;
public native void lock_id_free(/*u_int32_t*/ int id)
throws DbException;
public native DbLockStat lock_stat(/*u_int32_t*/ int flags)
throws DbException;
public native void lock_vec(/*u_int32_t*/ int locker,
int flags,
DbLockRequest[] list,
int offset,
int count)
throws DbException;
public native String[] log_archive(int flags)
throws DbException;
public native static int log_compare(DbLsn lsn0, DbLsn lsn1);
public native DbLogc log_cursor(int flags)
throws DbException;
public native String log_file(DbLsn lsn)
throws DbException;
public native void log_flush(DbLsn lsn)
throws DbException;
public native void log_put(DbLsn lsn, Dbt data, int flags)
throws DbException;
public native DbLogStat log_stat(/*u_int32_t*/ int flags)
throws DbException;
public native DbMpoolStat memp_stat(/*u_int32_t*/ int flags)
throws DbException;
public native DbMpoolFStat[] memp_fstat(/*u_int32_t*/ int flags)
throws DbException;
public native int memp_trickle(int pct)
throws DbException;
public native int rep_elect(int nsites, int pri, int timeout)
throws DbException;
public static class RepProcessMessage {
public int envid;
}
public native int rep_process_message(Dbt control, Dbt rec,
RepProcessMessage result)
throws DbException;
public native void rep_start(Dbt cookie, int flags)
throws DbException;
public native DbRepStat rep_stat(/*u_int32_t*/ int flags)
throws DbException;
public native DbTxn txn_begin(DbTxn pid, int flags)
throws DbException;
public native void txn_checkpoint(int kbyte, int min, int flags)
throws DbException;
public native DbPreplist[] txn_recover(int count, int flags)
throws DbException;
public native DbTxnStat txn_stat(/*u_int32_t*/ int flags)
throws DbException;
////////////////////////////////////////////////////////////////
//
// private data
//
private long private_dbobj_ = 0;
private long private_info_ = 0;
private int constructor_flags_ = 0;
private Vector dblist_ = new Vector(); // Db's that are open
private DbEnvFeedback feedback_ = null;
private DbRepTransport rep_transport_ = null;
private DbAppDispatch app_dispatch_ = null;
private DbOutputStreamErrcall errstream_ =
new DbOutputStreamErrcall(System.err);
/*package*/ DbErrcall errcall_ = errstream_;
/*package*/ String errpfx_;
static {
Db.load_db();
}
}
// end of DbEnv.java
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1999-2002
* Sleepycat Software. All rights reserved.
*
* $Id: DbEnvFeedback.java,v 11.6 2002/01/11 15:52:34 bostic Exp $
*/
package com.sleepycat.db;
public interface DbEnvFeedback
{
// methods
//
public abstract void feedback(DbEnv env, int opcode, int pct);
}
// end of DbFeedback.java
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Sleepycat Software. All rights reserved.
*
* $Id: DbErrcall.java,v 11.6 2002/01/11 15:52:35 bostic Exp $
*/
package com.sleepycat.db;
/**
*
* @author Donald D. Anderson
*/
public interface DbErrcall
{
// methods
//
public abstract void errcall(String prefix, String buffer);
}
// end of DbErrcall.java
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Sleepycat Software. All rights reserved.
*
* $Id: DbException.java,v 11.7 2002/01/11 15:52:35 bostic Exp $
*/
package com.sleepycat.db;
/**
*
* @author Donald D. Anderson
*/
public class DbException extends Exception
{
// methods
//
public DbException(String s)
{
super(s);
}
public DbException(String s, int errno)
{
super(s);
this.errno_ = errno;
}
public String toString()
{
String s = super.toString();
if (errno_ == 0)
return s;
else
return s + ": " + DbEnv.strerror(errno_);
}
// get/set methods
//
public int get_errno()
{
return errno_;
}
// private data
//
private int errno_ = 0;
}
// end of DbException.java
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Sleepycat Software. All rights reserved.
*
* $Id: DbFeedback.java,v 11.7 2002/01/11 15:52:35 bostic Exp $
*/
package com.sleepycat.db;
/**
*
* @author Donald D. Anderson
*/
public interface DbFeedback
{
// methods
//
public abstract void feedback(Db db, int opcode, int pct);
}
// end of DbFeedback.java
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2000-2002
* Sleepycat Software. All rights reserved.
*
* $Id: DbHash.java,v 11.5 2002/01/11 15:52:36 bostic Exp $
*/
package com.sleepycat.db;
/*
* This interface is used by DbEnv.set_bt_compare()
*
*/
public interface DbHash
{
public abstract int hash(Db db, byte[] data, int len);
}
// end of DbHash.java
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Sleepycat Software. All rights reserved.
*
* $Id: DbKeyRange.java,v 1.4 2002/01/11 15:52:36 bostic Exp $
*/
package com.sleepycat.db;
/**
*
* @author Donald D. Anderson
*/
public class DbKeyRange
{
public double less;
public double equal;
public double greater;
}
// end of DbKeyRange.java
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Sleepycat Software. All rights reserved.
*
* $Id: DbLock.java,v 11.8 2002/01/11 15:52:36 bostic Exp $
*/
package com.sleepycat.db;
/**
*
* @author Donald D. Anderson
*/
public class DbLock
{
protected native void finalize()
throws Throwable;
// get/set methods
//
// private data
//
private long private_dbobj_ = 0;
static {
Db.load_db();
}
}
// end of DbLock.java
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Sleepycat Software. All rights reserved.
*
* $Id: DbLockNotGrantedException.java,v 11.3 2002/01/11 15:52:36 bostic Exp $
*/
package com.sleepycat.db;
public class DbLockNotGrantedException extends DbException {
public DbLockNotGrantedException(String message,
int op, int mode, Dbt obj,
DbLock lock, int index)
{
super(message, Db.DB_LOCK_NOTGRANTED);
this.op = op;
this.mode = mode;
this.obj = obj;
this.lock = lock;
this.index = index;
}
public int get_op()
{
return op;
}
public int get_mode()
{
return mode;
}
public Dbt get_obj()
{
return obj;
}
public DbLock get_lock()
{
return lock;
}
public int get_index()
{
return index;
}
private int op;
private int mode;
private Dbt obj;
private DbLock lock;
private int index;
}
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Sleepycat Software. All rights reserved.
*
* $Id: DbLockRequest.java,v 11.4 2002/01/16 07:45:24 mjc Exp $
*/
package com.sleepycat.db;
public class DbLockRequest
{
public DbLockRequest(int op, int mode, Dbt obj, DbLock lock)
{
this.op = op;
this.mode = mode;
this.obj = obj;
this.lock = lock;
}
public int get_op()
{
return op;
}
public void set_op(int op)
{
this.op = op;
}
public int get_mode()
{
return mode;
}
public void set_mode(int mode)
{
this.mode = mode;
}
public Dbt get_obj()
{
return obj;
}
public void set_obj(Dbt obj)
{
this.obj = obj;
}
public DbLock get_lock()
{
return lock;
}
public void set_lock(DbLock lock)
{
this.lock = lock;
}
private /* db_lockop_t */ int op;
private /* db_lockmode_t */ int mode;
private /* db_timeout_t */ int timeout;
private Dbt obj;
private DbLock lock;
}
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Sleepycat Software. All rights reserved.
*
* $Id: DbLogc.java,v 11.3 2002/01/11 15:52:37 bostic Exp $
*/
package com.sleepycat.db;
/**
*
* @author Donald D. Anderson
*/
public class DbLogc
{
// methods
//
public native void close(int flags)
throws DbException;
// returns: 0, DB_NOTFOUND, or throws error
public native int get(DbLsn lsn, Dbt data, int flags)
throws DbException;
protected native void finalize()
throws Throwable;
// private data
//
private long private_dbobj_ = 0;
static {
Db.load_db();
}
}
// end of DbLogc.java
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Sleepycat Software. All rights reserved.
*
* $Id: DbLsn.java,v 11.8 2002/01/11 15:52:37 bostic Exp $
*/
package com.sleepycat.db;
/**
*
* @author Donald D. Anderson
*/
public class DbLsn
{
// methods
//
public DbLsn()
{
init_lsn();
}
protected native void finalize()
throws Throwable;
private native void init_lsn();
// get/set methods
//
// private data
//
private long private_dbobj_ = 0;
static {
Db.load_db();
}
}
// end of DbLsn.java
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1999-2002
* Sleepycat Software. All rights reserved.
*
* $Id: DbMemoryException.java,v 11.7 2002/01/11 15:52:37 bostic Exp $
*/
package com.sleepycat.db;
public class DbMemoryException extends DbException
{
// methods
//
public DbMemoryException(String s)
{
super(s);
}
public DbMemoryException(String s, int errno)
{
super(s, errno);
}
public void set_dbt(Dbt dbt)
{
this.dbt = dbt;
}
public Dbt get_dbt()
{
return dbt;
}
/* Override of DbException.toString():
* the extra verbage that comes from DbEnv.strerror(ENOMEM)
* is not helpful.
*/
public String toString()
{
return getMessage();
}
Dbt dbt = null;
}
// end of DbMemoryException.java
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Sleepycat Software. All rights reserved.
*
* $Id: DbMpoolStat.java,v 11.7 2002/01/11 15:52:38 bostic Exp $
*/
package com.sleepycat.db;
/*
* This is filled in and returned by the
* DbMpool.stat() method.
*/
public class DbMpoolStat
{
public int st_cache_hit; // Pages found in the cache.
public int st_cache_miss; // Pages not found in the cache.
public int st_map; // Pages from mapped files.
public int st_page_create; // Pages created in the cache.
public int st_page_in; // Pages read in.
public int st_page_out; // Pages written out.
public int st_ro_evict; // Clean pages forced from the cache.
public int st_rw_evict; // Dirty pages forced from the cache.
public int st_hash_buckets; // Number of hash buckets.
public int st_hash_searches; // Total hash chain searches.
public int st_hash_longest; // Longest hash chain searched.
public int st_hash_examined; // Total hash entries searched.
public int st_page_clean; // Clean pages.
public int st_page_dirty; // Dirty pages.
public int st_page_trickle; // Pages written by memp_trickle.
public int st_region_wait; // Region lock granted after wait.
public int st_region_nowait; // Region lock granted without wait.
public int st_regsize; // Region size.
}
// end of DbMpoolStat.java
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2001-2002
* Sleepycat Software. All rights reserved.
*
* $Id: DbMultipleDataIterator.java,v 1.5 2002/01/11 15:52:38 bostic Exp $
*/
package com.sleepycat.db;
/**
*
* @author David M. Krinsky
*/
public class DbMultipleDataIterator extends DbMultipleIterator
{
// public methods
public DbMultipleDataIterator(Dbt data)
{
super(data);
}
public boolean next(Dbt data)
{
int dataoff = DbUtil.array2int(buf, pos);
// crack out the data offset and length.
if (dataoff < 0) {
return (false);
}
pos -= int32sz;
int datasz = DbUtil.array2int(buf, pos);
pos -= int32sz;
data.set_data(buf);
data.set_size(datasz);
data.set_offset(dataoff);
return (true);
}
}
// end of DbMultipleDataIterator.java
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2001-2002
* Sleepycat Software. All rights reserved.
*
* $Id: DbMultipleIterator.java,v 1.5 2002/01/11 15:52:38 bostic Exp $
*/
package com.sleepycat.db;
/**
*
* @author David M. Krinsky
*/
// DbMultipleIterator is a shared package-private base class for the three
// types of bulk-return Iterator; it should never be instantiated directly,
// but it handles the functionality shared by its subclasses.
class DbMultipleIterator
{
// Package-private methods and members: used by our subclasses.
// Called implicitly by the subclass
DbMultipleIterator(Dbt data)
{
buf = data.get_data();
size = data.get_ulen();
// The offset will always be zero from the front of the buffer
// DB returns, and the buffer is opaque, so don't bother
// handling an offset.
// The initial position is pointing at the last u_int32_t
// in the buffer.
pos = size - int32sz;
}
// The C macros use sizeof(u_int32_t). Fortunately, java ints
// are always four bytes. Make this a constant just for form's sake.
static final int int32sz = 4;
// Current position within the buffer; equivalent to "pointer"
// in the DB_MULTIPLE macros.
int pos;
// A reference to the encoded buffer returned from the original
// Db/Dbc.get call on the data Dbt, and its size.
byte[] buf;
int size;
}
// end of DbMultipleIterator.java
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2001-2002
* Sleepycat Software. All rights reserved.
*
* $Id: DbMultipleKeyDataIterator.java,v 1.5 2002/01/11 15:52:39 bostic Exp $
*/
package com.sleepycat.db;
/**
*
* @author David M. Krinsky
*/
public class DbMultipleKeyDataIterator extends DbMultipleIterator
{
// public methods
public DbMultipleKeyDataIterator(Dbt data)
{
super(data);
}
public boolean next(Dbt key, Dbt data)
{
int keyoff = DbUtil.array2int(buf, pos);
// crack out the key and data offsets and lengths.
if (keyoff < 0) {
return (false);
}
pos -= int32sz;
int keysz = DbUtil.array2int(buf, pos);
pos -= int32sz;
int dataoff = DbUtil.array2int(buf, pos);
pos -= int32sz;
int datasz = DbUtil.array2int(buf, pos);
pos -= int32sz;
key.set_data(buf);
key.set_size(keysz);
key.set_offset(keyoff);
data.set_data(buf);
data.set_size(datasz);
data.set_offset(dataoff);
return (true);
}
}
// end of DbMultipleKeyDataIterator.java
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2001-2002
* Sleepycat Software. All rights reserved.
*
* $Id: DbMultipleRecnoDataIterator.java,v 1.5 2002/01/11 15:52:39 bostic Exp $
*/
package com.sleepycat.db;
/**
*
* @author David M. Krinsky
*/
public class DbMultipleRecnoDataIterator extends DbMultipleIterator
{
// public methods
public DbMultipleRecnoDataIterator(Dbt data)
{
super(data);
}
public boolean next(Dbt key, Dbt data)
{
int keyoff = DbUtil.array2int(buf, pos);
// crack out the key offset and the data offset and length.
if (keyoff < 0) {
return (false);
}
pos -= int32sz;
int dataoff = DbUtil.array2int(buf, pos);
pos -= int32sz;
int datasz = DbUtil.array2int(buf, pos);
pos -= int32sz;
key.set_recno_key_from_buffer(buf, keyoff);
data.set_data(buf);
data.set_size(datasz);
data.set_offset(dataoff);
return (true);
}
}
// end of DbMultipleRecnoDataIterator.java
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Sleepycat Software. All rights reserved.
*
* $Id: DbOutputStreamErrcall.java,v 11.6 2002/01/11 15:52:39 bostic Exp $
*/
package com.sleepycat.db;
import java.io.OutputStream;
import java.io.IOException;
/**
*
* @author Donald D. Anderson
*
* This class is not public, as it is only used internally
* by Db to implement a default error handler.
*/
/*package*/ class DbOutputStreamErrcall implements DbErrcall
{
DbOutputStreamErrcall(OutputStream stream)
{
this.stream_ = stream;
}
// errcall implements DbErrcall
//
public void errcall(String prefix, String buffer)
{
try {
if (prefix != null) {
stream_.write(prefix.getBytes());
stream_.write((new String(": ")).getBytes());
}
stream_.write(buffer.getBytes());
stream_.write((new String("\n")).getBytes());
}
catch (IOException e) {
// well, we tried.
// Do our best to report the problem by other means.
//
System.err.println("DbOutputStreamErrcall Exception: " + e);
if (prefix != null)
System.err.print(prefix + ": ");
System.err.println(buffer + "\n");
}
}
// private data
//
private OutputStream stream_;
}
// end of DbOutputStreamErrcall.java
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1999-2002
* Sleepycat Software. All rights reserved.
*
* $Id: DbPreplist.java,v 11.3 2002/01/11 15:52:40 bostic Exp $
*/
package com.sleepycat.db;
/*
* This is filled in and returned by the
* DbEnv.txn_recover() method.
*/
public class DbPreplist
{
public DbTxn txn;
public byte gid[];
}
// end of DbPreplist.java
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2001-2002
* Sleepycat Software. All rights reserved.
*
* $Id: DbRepTransport.java,v 11.2 2002/01/11 15:52:40 bostic Exp $
*/
package com.sleepycat.db;
/*
* This is used as a callback by DbEnv.set_rep_transport.
*/
public interface DbRepTransport
{
public int send(DbEnv env, Dbt control, Dbt rec, int flags, int envid)
throws DbException;
}
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Sleepycat Software. All rights reserved.
*
* $Id: DbRunRecoveryException.java,v 11.6 2002/01/11 15:52:40 bostic Exp $
*/
package com.sleepycat.db;
/**
*
* @author Donald D. Anderson
*/
public class DbRunRecoveryException extends DbException
{
// methods
//
public DbRunRecoveryException(String s)
{
super(s);
}
public DbRunRecoveryException(String s, int errno)
{
super(s, errno);
}
}
// end of DbRunRecoveryException.java
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1999-2002
* Sleepycat Software. All rights reserved.
*
* $Id: DbSecondaryKeyCreate.java,v 11.3 2002/01/11 15:52:40 bostic Exp $
*/
package com.sleepycat.db;
/*
* This is used as a callback by Db.associate.
*/
public interface DbSecondaryKeyCreate
{
public int secondary_key_create(Db secondary, Dbt key,
Dbt data, Dbt result)
throws DbException;
}
// end of DbSecondaryKeyCreate.java
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Sleepycat Software. All rights reserved.
*
* $Id: DbTxn.java,v 11.17 2002/08/29 14:22:22 margo Exp $
*/
package com.sleepycat.db;
/**
*
* @author Donald D. Anderson
*/
public class DbTxn
{
// methods
//
public native void abort()
throws DbException;
public native void commit(int flags)
throws DbException;
public native void discard(int flags)
throws DbException;
public native /*u_int32_t*/ int id()
throws DbException;
public native void prepare(byte[] gid)
throws DbException;
public native void set_timeout(/*db_timeout_t*/ long timeout,
/*u_int32_t*/ int flags)
throws DbException;
// We override Object.equals because it is possible for
// the Java API to create multiple DbTxns that reference
// the same underlying object. This can happen for example
// during DbEnv.txn_recover().
//
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj != null && (obj instanceof DbTxn)) {
DbTxn that = (DbTxn)obj;
return (this.private_dbobj_ == that.private_dbobj_);
}
return false;
}
// We must override Object.hashCode whenever we override
// Object.equals() to enforce the maxim that equal objects
// have the same hashcode.
//
public int hashCode()
{
return ((int)private_dbobj_ ^ (int)(private_dbobj_ >> 32));
}
// get/set methods
//
// private data
//
private long private_dbobj_ = 0;
static {
Db.load_db();
}
}
// end of DbTxn.java
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2001-2002
* Sleepycat Software. All rights reserved.
*
* $Id: DbUtil.java,v 11.5 2002/01/11 15:52:41 bostic Exp $
*/
package com.sleepycat.db;
/**
*
* @author David M. Krinsky
*/
// DbUtil is a simple, package-private wrapper class that holds a few
// static utility functions other parts of the package share and that don't
// have a good home elsewhere. (For now, that's limited to byte-array-to-int
// conversion and back.)
class DbUtil
{
// Get the u_int32_t stored beginning at offset "offset" into
// array "arr". We have to do the conversion manually since it's
// a C-native int, and we're not really supposed to make this kind of
// cast in Java.
static int array2int(byte[] arr, int offset)
{
int b1, b2, b3, b4;
int pos = offset;
// Get the component bytes; b4 is most significant, b1 least.
if (big_endian) {
b4 = arr[pos++];
b3 = arr[pos++];
b2 = arr[pos++];
b1 = arr[pos];
} else {
b1 = arr[pos++];
b2 = arr[pos++];
b3 = arr[pos++];
b4 = arr[pos];
}
// Bytes are signed. Convert [-128, -1] to [128, 255].
if (b1 < 0) { b1 += 256; }
if (b2 < 0) { b2 += 256; }
if (b3 < 0) { b3 += 256; }
if (b4 < 0) { b4 += 256; }
// Put the bytes in their proper places in an int.
b2 <<= 8;
b3 <<= 16;
b4 <<= 24;
// Return their sum.
return (b1 + b2 + b3 + b4);
}
// Store the specified u_int32_t, with endianness appropriate
// to the platform we're running on, into four consecutive bytes of
// the specified byte array, starting from the specified offset.
static void int2array(int n, byte[] arr, int offset)
{
int b1, b2, b3, b4;
int pos = offset;
b1 = n & 0xff;
b2 = (n >> 8) & 0xff;
b3 = (n >> 16) & 0xff;
b4 = (n >> 24) & 0xff;
// Bytes are signed. Convert [128, 255] to [-128, -1].
if (b1 >= 128) { b1 -= 256; }
if (b2 >= 128) { b2 -= 256; }
if (b3 >= 128) { b3 -= 256; }
if (b4 >= 128) { b4 -= 256; }
// Put the bytes in the appropriate place in the array.
if (big_endian) {
arr[pos++] = (byte)b4;
arr[pos++] = (byte)b3;
arr[pos++] = (byte)b2;
arr[pos] = (byte)b1;
} else {
arr[pos++] = (byte)b1;
arr[pos++] = (byte)b2;
arr[pos++] = (byte)b3;
arr[pos] = (byte)b4;
}
}
private static final boolean big_endian = is_big_endian();
private static native boolean is_big_endian();
}
// end of DbUtil.java
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Sleepycat Software. All rights reserved.
*
* $Id: Dbc.java,v 11.9 2002/01/11 15:52:41 bostic Exp $
*/
package com.sleepycat.db;
/**
*
* @author Donald D. Anderson
*/
public class Dbc
{
// methods
//
public native void close()
throws DbException;
public native int count(int flags)
throws DbException;
// returns: 0, DB_KEYEMPTY, or throws error
public native int del(int flags)
throws DbException;
public native Dbc dup(int flags)
throws DbException;
// returns: 0, DB_NOTFOUND, or throws error
public native int get(Dbt key, Dbt data, int flags)
throws DbException;
// returns: 0, DB_NOTFOUND, or throws error
public native int pget(Dbt key, Dbt pkey, Dbt data, int flags)
throws DbException;
// returns: 0, DB_KEYEXIST, or throws error
public native int put(Dbt key, Dbt data, int flags)
throws DbException;
protected native void finalize()
throws Throwable;
// get/set methods
//
// private data
//
private long private_dbobj_ = 0;
static {
Db.load_db();
}
}
// end of Dbc.java
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Sleepycat Software. All rights reserved.
*
* $Id: Dbt.java,v 11.15 2002/09/04 00:37:25 mjc Exp $
*/
package com.sleepycat.db;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
/**
*
* @author Donald D. Anderson
*/
public class Dbt
{
// methods
//
public Dbt(byte[] data)
{
init();
this.data = data;
if (data != null) {
this.size = data.length;
}
}
public Dbt(byte[] data, int off, int len)
{
init();
this.data = data;
this.offset = off;
this.size = len;
}
public Dbt()
{
init();
}
public Dbt(Object serialobj) throws java.io.IOException
{
init();
this.set_object(serialobj);
}
protected native void finalize()
throws Throwable;
// get/set methods
//
// key/data
public byte[] get_data()
{
// In certain circumstances, like callbacks to
// user code that have Dbt args, we do not create
// data arrays until the user explicitly does a get_data.
// This saves us from needlessly creating objects
// (potentially large arrays) that may never be accessed.
//
if (must_create_data) {
data = create_data();
must_create_data = false;
}
return data;
}
public void set_data(byte[] data)
{
this.data = data;
this.must_create_data = false;
}
// get_offset/set_offset is unique to the Java portion
// of the DB APIs. They can be used to get/set the offset
// into the attached byte array.
//
public int get_offset()
{
return offset;
}
public void set_offset(int offset)
{
this.offset = offset;
}
// key/data length
public /*u_int32_t*/ int get_size()
{
return size;
}
public void set_size(/*u_int32_t*/ int size)
{
this.size = size;
}
// RO: length of user buffer.
public /*u_int32_t*/ int get_ulen()
{
return ulen;
}
public void set_ulen(/*u_int32_t*/ int ulen)
{
this.ulen = ulen;
}
// RO: get/put record length.
public /*u_int32_t*/ int get_dlen()
{
return dlen;
}
public void set_dlen(/*u_int32_t*/ int dlen)
{
this.dlen = dlen;
}
// RO: get/put record offset.
public /*u_int32_t*/ int get_doff()
{
return doff;
}
public void set_doff(/*u_int32_t*/ int doff)
{
this.doff = doff;
}
// flags
public /*u_int32_t*/ int get_flags()
{
return flags;
}
public void set_flags(/*u_int32_t*/ int flags)
{
this.flags = flags;
}
// Helper methods to get/set a Dbt from a serializable object.
public Object get_object() throws java.io.IOException,
java.lang.ClassNotFoundException
{
ByteArrayInputStream bytestream = new ByteArrayInputStream(get_data());
ObjectInputStream ois = new ObjectInputStream(bytestream);
Object serialobj = ois.readObject();
ois.close();
bytestream.close();
return (serialobj);
}
public void set_object(Object serialobj) throws java.io.IOException
{
ByteArrayOutputStream bytestream = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bytestream);
oos.writeObject(serialobj);
oos.close();
byte[] buf = bytestream.toByteArray();
bytestream.close();
set_data(buf);
set_offset(0);
set_size(buf.length);
}
// These are not in the original DB interface.
// They can be used to set the recno key for a Dbt.
// Note: if data is less than (offset + 4) bytes, these
// methods may throw an ArrayIndexException. get_recno_key_data()
// will additionally throw a NullPointerException if data is null.
public void set_recno_key_data(int recno)
{
if (data == null) {
data = new byte[4];
size = 4;
offset = 0;
}
DbUtil.int2array(recno, data, offset);
}
public int get_recno_key_data()
{
return (DbUtil.array2int(data, offset));
}
// Used internally by DbMultipleRecnoIterator
//
/*package*/ void set_recno_key_from_buffer(byte[] data, int offset)
{
this.data = data;
this.offset = offset;
this.size = 4;
}
static {
Db.load_db();
}
// private methods
//
private native void init();
private native byte[] create_data();
// private data
//
private long private_dbobj_ = 0;
private byte[] data = null;
private int offset = 0;
private int size = 0;
private int ulen = 0;
private int dlen = 0;
private int doff = 0;
private int flags = 0;
private boolean must_create_data = false;
}
// end of Dbt.java
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Sleepycat Software. All rights reserved.
*
* $Id: DbXAResource.java,v 1.2 2002/08/09 01:54:57 bostic Exp $
*/
package com.sleepycat.db.xa;
import com.sleepycat.db.Db;
import com.sleepycat.db.DbEnv;
import com.sleepycat.db.DbTxn;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.XAException;
import javax.transaction.xa.Xid;
public class DbXAResource implements XAResource
{
public DbXAResource(String home, int rmid, int flags)
throws XAException
{
this.home = home;
this.rmid = rmid;
// We force single-threading for calls to _init/_close.
// This makes our internal code much easier, and
// should not be a performance burden.
synchronized (DbXAResource.class) {
_init(home, rmid, flags);
}
}
//
// Alternate constructor for convenience.
// Uses an rmid that is unique within this JVM,
// numbered started at 0.
//
public DbXAResource(String home)
throws XAException
{
this(home, get_unique_rmid(), 0);
}
private native void _init(String home, int rmid, int flags);
public void close(int flags)
throws XAException
{
// We force single-threading for calls to _init/_close.
// This makes our internal code much easier, and
// should not be a performance burden.
synchronized (DbXAResource.class) {
_close(home, rmid, flags);
}
}
private native void _close(String home, int rmid, int flags);
public void commit(Xid xid, boolean onePhase)
throws XAException
{
_commit(xid, rmid, onePhase);
}
private native void _commit(Xid xid, int rmid, boolean onePhase);
public void end(Xid xid, int flags)
throws XAException
{
_end(xid, rmid, flags);
}
private native void _end(Xid xid, int rmid, int flags);
public void forget(Xid xid)
throws XAException
{
_forget(xid, rmid);
}
private native void _forget(Xid xid, int rmid);
public int getTransactionTimeout()
throws XAException
{
return transactionTimeout;
}
public boolean isSameRM(XAResource xares)
throws XAException
{
if (!(xares instanceof DbXAResource))
return false;
return (this.rmid == ((DbXAResource)xares).rmid);
}
public int prepare(Xid xid)
throws XAException
{
return _prepare(xid, rmid);
}
private native int _prepare(Xid xid, int rmid);
public Xid [] recover(int flag)
throws XAException
{
return _recover(rmid, flag);
}
private native Xid[] _recover(int rmid, int flags);
public void rollback(Xid xid)
throws XAException
{
_rollback(xid, rmid);
System.err.println("DbXAResource.rollback returned");
}
private native void _rollback(Xid xid, int rmid);
public boolean setTransactionTimeout(int seconds)
throws XAException
{
// XXX we are not using the transaction timeout.
transactionTimeout = seconds;
return true;
}
public void start(Xid xid, int flags)
throws XAException
{
_start(xid, rmid, flags);
}
private native void _start(Xid xid, int rmid, int flags);
private static synchronized int get_unique_rmid()
{
return unique_rmid++;
}
public interface DbAttach
{
public DbEnv get_env();
public DbTxn get_txn();
}
protected static class DbAttachImpl implements DbAttach
{
private DbEnv env;
private DbTxn txn;
DbAttachImpl(DbEnv env, DbTxn txn)
{
this.env = env;
this.txn = txn;
}
public DbTxn get_txn()
{
return txn;
}
public DbEnv get_env()
{
return env;
}
}
public static native DbAttach xa_attach(Xid xid, Integer rmid);
////////////////////////////////////////////////////////////////
//
// private data
//
private long private_dbobj_ = 0;
private int transactionTimeout = 0;
private String home;
private int rmid;
private static int unique_rmid = 0;
static
{
Db.load_db();
}
}
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Sleepycat Software. All rights reserved.
*
* $Id: DbXid.java,v 1.2 2002/08/09 01:54:58 bostic Exp $
*/
package com.sleepycat.db.xa;
import com.sleepycat.db.DbException;
import com.sleepycat.db.DbTxn;
import javax.transaction.xa.XAException;
import javax.transaction.xa.Xid;
public class DbXid implements Xid
{
public DbXid(int formatId, byte[] gtrid, byte[] bqual)
throws XAException
{
this.formatId = formatId;
this.gtrid = gtrid;
this.bqual = bqual;
}
public int getFormatId()
{
return formatId;
}
public byte[] getGlobalTransactionId()
{
return gtrid;
}
public byte[] getBranchQualifier()
{
return bqual;
}
////////////////////////////////////////////////////////////////
//
// private data
//
private byte[] gtrid;
private byte[] bqual;
private int formatId;
}
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Sleepycat Software. All rights reserved.
*
* $Id: AccessExample.java,v 11.12 2002/02/05 22:27:13 mjc Exp $
*/
package com.sleepycat.examples;
import com.sleepycat.db.*;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.PrintStream;
class AccessExample
{
private static final String FileName = "access.db";
public AccessExample()
{
}
public static void main(String argv[])
{
try
{
AccessExample app = new AccessExample();
app.run();
}
catch (DbException dbe)
{
System.err.println("AccessExample: " + dbe.toString());
System.exit(1);
}
catch (FileNotFoundException fnfe)
{
System.err.println("AccessExample: " + fnfe.toString());
System.exit(1);
}
System.exit(0);
}
// Prompts for a line, and keeps prompting until a non blank
// line is returned. Returns null on error.
//
static public String askForLine(InputStreamReader reader,
PrintStream out, String prompt)
{
String result = "";
while (result != null && result.length() == 0) {
out.print(prompt);
out.flush();
result = getLine(reader);
}
return result;
}
// Not terribly efficient, but does the job.
// Works for reading a line from stdin or a file.
// Returns null on EOF. If EOF appears in the middle
// of a line, returns that line, then null on next call.
//
static public String getLine(InputStreamReader reader)
{
StringBuffer b = new StringBuffer();
int c;
try {
while ((c = reader.read()) != -1 && c != '\n') {
if (c != '\r')
b.append((char)c);
}
}
catch (IOException ioe) {
c = -1;
}
if (c == -1 && b.length() == 0)
return null;
else
return b.toString();
}
public void run()
throws DbException, FileNotFoundException
{
// Remove the previous database.
new File(FileName).delete();
// Create the database object.
// There is no environment for this simple example.
Db table = new Db(null, 0);
table.set_error_stream(System.err);
table.set_errpfx("AccessExample");
table.open(null, FileName, null, Db.DB_BTREE, Db.DB_CREATE, 0644);
//
// Insert records into the database, where the key is the user
// input and the data is the user input in reverse order.
//
InputStreamReader reader = new InputStreamReader(System.in);
for (;;) {
String line = askForLine(reader, System.out, "input> ");
if (line == null)
break;
String reversed = (new StringBuffer(line)).reverse().toString();
// See definition of StringDbt below
//
StringDbt key = new StringDbt(line);
StringDbt data = new StringDbt(reversed);
try
{
int err;
if ((err = table.put(null,
key, data, Db.DB_NOOVERWRITE)) == Db.DB_KEYEXIST) {
System.out.println("Key " + line + " already exists.");
}
}
catch (DbException dbe)
{
System.out.println(dbe.toString());
}
System.out.println("");
}
// Acquire an iterator for the table.
Dbc iterator;
iterator = table.cursor(null, 0);
// Walk through the table, printing the key/data pairs.
// See class StringDbt defined below.
//
StringDbt key = new StringDbt();
StringDbt data = new StringDbt();
while (iterator.get(key, data, Db.DB_NEXT) == 0)
{
System.out.println(key.getString() + " : " + data.getString());
}
iterator.close();
table.close(0);
}
// Here's an example of how you can extend a Dbt in a straightforward
// way to allow easy storage/retrieval of strings, or whatever
// kind of data you wish. We've declared it as a static inner
// class, but it need not be.
//
static /*inner*/
class StringDbt extends Dbt
{
StringDbt()
{
set_flags(Db.DB_DBT_MALLOC); // tell Db to allocate on retrieval
}
StringDbt(String value)
{
setString(value);
set_flags(Db.DB_DBT_MALLOC); // tell Db to allocate on retrieval
}
void setString(String value)
{
byte[] data = value.getBytes();
set_data(data);
set_size(data.length);
}
String getString()
{
return new String(get_data(), 0, get_size());
}
}
}
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Sleepycat Software. All rights reserved.
*
* $Id: BtRecExample.java,v 11.11 2002/02/05 22:27:13 mjc Exp $
*/
package com.sleepycat.examples;
import com.sleepycat.db.*;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.PrintStream;
public class BtRecExample
{
static final String progname = "BtRecExample"; // Program name.
static final String database = "access.db";
static final String wordlist = "../test/wordlist";
BtRecExample(BufferedReader reader)
throws DbException, IOException, FileNotFoundException
{
int ret;
// Remove the previous database.
File f = new File(database);
f.delete();
dbp = new Db(null, 0);
dbp.set_error_stream(System.err);
dbp.set_errpfx(progname);
dbp.set_pagesize(1024); // 1K page sizes.
dbp.set_flags(Db.DB_RECNUM); // Record numbers.
dbp.open(null, database, null, Db.DB_BTREE, Db.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) {
String numstr = String.valueOf(cnt);
while (numstr.length() < 4)
numstr = "0" + numstr;
String buf = numstr + '_' + reader.readLine();
StringBuffer rbuf = new StringBuffer(buf).reverse();
StringDbt key = new StringDbt(buf);
StringDbt data = new StringDbt(rbuf.toString());
if ((ret = dbp.put(null, key, data, Db.DB_NOOVERWRITE)) != 0) {
if (ret != Db.DB_KEYEXIST)
throw new DbException("Db.put failed" + ret);
}
}
}
void run()
throws DbException
{
int recno;
int ret;
// Acquire a cursor for the database.
dbcp = dbp.cursor(null, 0);
//
// Prompt the user for a record number, then retrieve and display
// that record.
//
InputStreamReader reader = new InputStreamReader(System.in);
for (;;) {
// Get a record number.
String line = askForLine(reader, System.out, "recno #> ");
if (line == null)
break;
try {
recno = Integer.parseInt(line);
}
catch (NumberFormatException nfe) {
System.err.println("Bad record number: " + nfe);
continue;
}
//
// Start with a fresh key each time, the dbp.get() routine returns
// the key and data pair, not just the key!
//
RecnoStringDbt key = new RecnoStringDbt(recno, 100);
RecnoStringDbt data = new RecnoStringDbt(100);
if ((ret = dbcp.get(key, data, Db.DB_SET_RECNO)) != 0) {
throw new DbException("Dbc.get failed", 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.DB_NEXT)) != 0) {
throw new DbException("Dbc.get failed", ret);
}
// Display the key and data.
show("next\t", key, data);
RecnoStringDbt datano = new RecnoStringDbt(100);
//
// Retrieve the record number for the following record into
// local memory.
//
if ((ret = dbcp.get(key, datano, Db.DB_GET_RECNO)) != 0) {
if (ret != Db.DB_NOTFOUND && ret != Db.DB_KEYEMPTY) {
throw new DbException("Dbc.get failed", ret);
}
}
else {
recno = datano.getRecno();
System.out.println("retrieved recno: " + recno);
}
}
dbcp.close();
dbcp = null;
}
//
// Print out the number of records in the database.
//
void stats()
throws DbException
{
DbBtreeStat statp;
statp = (DbBtreeStat)dbp.stat(0);
System.out.println(progname + ": database contains " +
statp.bt_ndata + " records");
}
void show(String msg, RecnoStringDbt key, RecnoStringDbt data)
throws DbException
{
System.out.println(msg + key.getString() + ": " + data.getString());
}
public void shutdown()
throws DbException
{
if (dbcp != null) {
dbcp.close();
dbcp = null;
}
if (dbp != null) {
dbp.close(0);
dbp = null;
}
}
public static void main(String argv[])
{
try {
// Open the word database.
FileReader freader = new FileReader(wordlist);
BtRecExample app = new BtRecExample(new BufferedReader(freader));
// Close the word database.
freader.close();
freader = null;
app.stats();
app.run();
} catch (FileNotFoundException fnfe) {
System.err.println(progname + ": unexpected open error " + fnfe);
System.exit (1);
} catch (IOException ioe) {
System.err.println(progname + ": open " + wordlist + ": " + ioe);
System.exit (1);
} catch (DbException dbe) {
System.err.println("Exception: " + dbe);
System.exit(dbe.get_errno());
}
System.exit(0);
}
// Prompts for a line, and keeps prompting until a non blank
// line is returned. Returns null on error.
//
static public String askForLine(InputStreamReader reader,
PrintStream out, String prompt)
{
String result = "";
while (result != null && result.length() == 0) {
out.print(prompt);
out.flush();
result = getLine(reader);
}
return result;
}
// Not terribly efficient, but does the job.
// Works for reading a line from stdin or a file.
// Returns null on EOF. If EOF appears in the middle
// of a line, returns that line, then null on next call.
//
static public String getLine(InputStreamReader reader)
{
StringBuffer b = new StringBuffer();
int c;
try {
while ((c = reader.read()) != -1 && c != '\n') {
if (c != '\r')
b.append((char)c);
}
}
catch (IOException ioe) {
c = -1;
}
if (c == -1 && b.length() == 0)
return null;
else
return b.toString();
}
private Dbc dbcp;
private Db dbp;
// Here's an example of how you can extend a Dbt in a straightforward
// way to allow easy storage/retrieval of strings.
// We've declared it as a static inner class, but it need not be.
//
static /*inner*/
class StringDbt extends Dbt
{
StringDbt(byte[] arr)
{
set_flags(Db.DB_DBT_USERMEM);
set_data(arr);
set_size(arr.length);
}
StringDbt()
{
set_flags(Db.DB_DBT_MALLOC); // tell Db to allocate on retrieval
}
StringDbt(String value)
{
setString(value);
set_flags(Db.DB_DBT_MALLOC); // tell Db to allocate on retrieval
}
void setString(String value)
{
byte[] data = value.getBytes();
set_data(data);
set_size(data.length);
// must set ulen because sometimes a string is returned
set_ulen(data.length);
}
String getString()
{
return new String(get_data(), 0, get_size());
}
}
// Here's an example of how you can extend a Dbt to store
// (potentially) both recno's and strings in the same
// structure.
//
static /*inner*/
class RecnoStringDbt extends Dbt
{
RecnoStringDbt(int maxsize)
{
this(0, maxsize); // let other constructor do most of the work
}
RecnoStringDbt(int value, int maxsize)
{
set_flags(Db.DB_DBT_USERMEM); // do not allocate on retrieval
arr = new byte[maxsize];
set_data(arr); // use our local array for data
set_ulen(maxsize); // size of return storage
setRecno(value);
}
RecnoStringDbt(String value, int maxsize)
{
set_flags(Db.DB_DBT_USERMEM); // do not allocate on retrieval
arr = new byte[maxsize];
set_data(arr); // use our local array for data
set_ulen(maxsize); // size of return storage
setString(value);
}
void setRecno(int value)
{
set_recno_key_data(value);
set_size(arr.length);
}
void setString(String value)
{
byte[] data = value.getBytes();
set_data(data);
set_size(data.length);
}
int getRecno()
{
return get_recno_key_data();
}
String getString()
{
return new String(get_data(), 0, get_size());
}
byte arr[];
}
}
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Sleepycat Software. All rights reserved.
*
* $Id: BulkAccessExample.java,v 1.6 2002/02/05 22:27:13 mjc Exp $
*/
package com.sleepycat.examples;
import com.sleepycat.db.*;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.PrintStream;
class BulkAccessExample
{
private static final String FileName = "access.db";
public BulkAccessExample()
{
}
public static void main(String argv[])
{
try
{
BulkAccessExample app = new BulkAccessExample();
app.run();
}
catch (DbException dbe)
{
System.err.println("BulkAccessExample: " + dbe.toString());
System.exit(1);
}
catch (FileNotFoundException fnfe)
{
System.err.println("BulkAccessExample: " + fnfe.toString());
System.exit(1);
}
System.exit(0);
}
// Prompts for a line, and keeps prompting until a non blank
// line is returned. Returns null on error.
//
static public String askForLine(InputStreamReader reader,
PrintStream out, String prompt)
{
String result = "";
while (result != null && result.length() == 0) {
out.print(prompt);
out.flush();
result = getLine(reader);
}
return result;
}
// Not terribly efficient, but does the job.
// Works for reading a line from stdin or a file.
// Returns null on EOF. If EOF appears in the middle
// of a line, returns that line, then null on next call.
//
static public String getLine(InputStreamReader reader)
{
StringBuffer b = new StringBuffer();
int c;
try {
while ((c = reader.read()) != -1 && c != '\n') {
if (c != '\r')
b.append((char)c);
}
}
catch (IOException ioe) {
c = -1;
}
if (c == -1 && b.length() == 0)
return null;
else
return b.toString();
}
public void run()
throws DbException, FileNotFoundException
{
// Remove the previous database.
new File(FileName).delete();
// Create the database object.
// There is no environment for this simple example.
Db table = new Db(null, 0);
table.set_error_stream(System.err);
table.set_errpfx("BulkAccessExample");
table.open(null, FileName, null, Db.DB_BTREE, Db.DB_CREATE, 0644);
//
// Insert records into the database, where the key is the user
// input and the data is the user input in reverse order.
//
InputStreamReader reader = new InputStreamReader(System.in);
for (;;) {
String line = askForLine(reader, System.out, "input> ");
if (line == null)
break;
String reversed = (new StringBuffer(line)).reverse().toString();
// See definition of StringDbt below
//
StringDbt key = new StringDbt(line);
StringDbt data = new StringDbt(reversed);
try
{
int err;
if ((err = table.put(null,
key, data, Db.DB_NOOVERWRITE)) == Db.DB_KEYEXIST) {
System.out.println("Key " + line + " already exists.");
}
}
catch (DbException dbe)
{
System.out.println(dbe.toString());
}
System.out.println("");
}
// Acquire a cursor for the table and two Dbts.
Dbc dbc = table.cursor(null, 0);
Dbt foo = new Dbt();
foo.set_flags(Db.DB_DBT_MALLOC);
Dbt bulk_data = new Dbt();
// Set Db.DB_DBT_USERMEM on the data Dbt; Db.DB_MULTIPLE_KEY requires
// it. Then allocate a byte array of a reasonable size; we'll
// go through the database in chunks this big.
bulk_data.set_flags(Db.DB_DBT_USERMEM);
bulk_data.set_data(new byte[1000000]);
bulk_data.set_ulen(1000000);
// Walk through the table, printing the key/data pairs.
//
while (dbc.get(foo, bulk_data, Db.DB_NEXT | Db.DB_MULTIPLE_KEY) == 0)
{
DbMultipleKeyDataIterator iterator;
iterator = new DbMultipleKeyDataIterator(bulk_data);
StringDbt key, data;
key = new StringDbt();
data = new StringDbt();
while (iterator.next(key, data)) {
System.out.println(key.getString() + " : " + data.getString());
}
}
dbc.close();
table.close(0);
}
// Here's an example of how you can extend a Dbt in a straightforward
// way to allow easy storage/retrieval of strings, or whatever
// kind of data you wish. We've declared it as a static inner
// class, but it need not be.
//
static /*inner*/
class StringDbt extends Dbt
{
StringDbt()
{
set_flags(Db.DB_DBT_MALLOC); // tell Db to allocate on retrieval
}
StringDbt(String value)
{
setString(value);
set_flags(Db.DB_DBT_MALLOC); // tell Db to allocate on retrieval
}
void setString(String value)
{
byte[] data = value.getBytes();
set_data(data);
set_size(data.length);
}
String getString()
{
return new String(get_data(), get_offset(), get_size());
}
}
}
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Sleepycat Software. All rights reserved.
*
* $Id: EnvExample.java,v 11.9 2002/01/11 15:52:42 bostic Exp $
*/
package com.sleepycat.examples;
import com.sleepycat.db.*;
import java.io.FileNotFoundException;
import java.io.OutputStream;
/*
* An example of a program using DbEnv to configure its DB
* environment.
*
* For comparison purposes, this example uses a similar structure
* as examples/ex_env.c and examples_cxx/EnvExample.cpp.
*/
public class EnvExample
{
private static final String progname = "EnvExample";
private static final String DATABASE_HOME = "/tmp/database";
private static void db_application()
throws DbException
{
// Do something interesting...
// Your application goes here.
}
private static void db_setup(String home, String data_dir,
OutputStream errs)
throws DbException, FileNotFoundException
{
//
// Create an environment object and initialize it for error
// reporting.
//
DbEnv dbenv = new DbEnv(0);
dbenv.set_error_stream(errs);
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.
dbenv.set_data_dir(data_dir);
// Open the environment with full transactional support.
//
// open() will throw a DbException if there is an error.
//
// open is declared to throw a FileNotFoundException, which normally
// shouldn't occur with the DB_CREATE option.
//
dbenv.open(DATABASE_HOME,
Db.DB_CREATE | Db.DB_INIT_LOCK | Db.DB_INIT_LOG |
Db.DB_INIT_MPOOL | Db.DB_INIT_TXN, 0);
try {
// Start your application.
db_application();
}
finally {
// Close the environment. Doing this in the
// finally block ensures it is done, even if
// an error is thrown.
//
dbenv.close(0);
}
}
private static void db_teardown(String home, String data_dir,
OutputStream errs)
throws DbException, FileNotFoundException
{
// Remove the shared database regions.
DbEnv dbenv = new DbEnv(0);
dbenv.set_error_stream(errs);
dbenv.set_errpfx(progname);
dbenv.set_data_dir(data_dir);
dbenv.remove(home, 0);
}
public static void main(String[] args)
{
//
// All of the shared database files live in /tmp/database,
// but data files live in /database.
//
// Using Berkeley DB in C/C++, we need to allocate two elements
// in the array and set config[1] to NULL. This is not
// necessary in Java.
//
String home = DATABASE_HOME;
String config = "/database/files";
try {
System.out.println("Setup env");
db_setup(home, config, System.err);
System.out.println("Teardown env");
db_teardown(home, config, System.err);
}
catch (DbException dbe) {
System.err.println(progname + ": environment open: " + dbe.toString());
System.exit (1);
}
catch (FileNotFoundException fnfe) {
System.err.println(progname +
": unexpected open environment error " + fnfe);
System.exit (1);
}
}
}
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Sleepycat Software. All rights reserved.
*
* $Id: LockExample.java,v 11.8 2002/01/11 15:52:43 bostic Exp $
*/
package com.sleepycat.examples;
import com.sleepycat.db.*;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Vector;
//
// An example of a program using DbLock and related classes.
//
class LockExample extends DbEnv
{
private static final String progname = "LockExample";
private static final String LOCK_HOME = "TESTDIR";
public LockExample(String home, int maxlocks, boolean do_unlink)
throws DbException, FileNotFoundException
{
super(0);
if (do_unlink) {
remove(home, Db.DB_FORCE);
}
else {
set_error_stream(System.err);
set_errpfx("LockExample");
if (maxlocks != 0)
set_lk_max_locks(maxlocks);
open(home, Db.DB_CREATE|Db.DB_INIT_LOCK, 0);
}
}
// Prompts for a line, and keeps prompting until a non blank
// line is returned. Returns null on error.
//
static public String askForLine(InputStreamReader reader,
PrintStream out, String prompt)
{
String result = "";
while (result != null && result.length() == 0) {
out.print(prompt);
out.flush();
result = getLine(reader);
}
return result;
}
// Not terribly efficient, but does the job.
// Works for reading a line from stdin or a file.
// Returns null on EOF. If EOF appears in the middle
// of a line, returns that line, then null on next call.
//
static public String getLine(InputStreamReader reader)
{
StringBuffer b = new StringBuffer();
int c;
try {
while ((c = reader.read()) != -1 && c != '\n') {
if (c != '\r')
b.append((char)c);
}
}
catch (IOException ioe) {
c = -1;
}
if (c == -1 && b.length() == 0)
return null;
else
return b.toString();
}
public void run()
throws DbException
{
long held;
int len = 0, locker;
int ret;
boolean did_get = false;
int lockid = 0;
InputStreamReader in = new InputStreamReader(System.in);
Vector locks = new Vector();
//
// Accept lock requests.
//
locker = lock_id();
for (held = 0;;) {
String opbuf = askForLine(in, System.out,
"Operation get/release [get]> ");
if (opbuf == null)
break;
try {
if (opbuf.equals("get")) {
// Acquire a lock.
String objbuf = askForLine(in, System.out,
"input object (text string) to lock> ");
if (objbuf == null)
break;
String lockbuf;
do {
lockbuf = askForLine(in, System.out,
"lock type read/write [read]> ");
if (lockbuf == null)
break;
len = lockbuf.length();
} while (len >= 1 &&
!lockbuf.equals("read") &&
!lockbuf.equals("write"));
int lock_type;
if (len <= 1 || lockbuf.equals("read"))
lock_type = Db.DB_LOCK_READ;
else
lock_type = Db.DB_LOCK_WRITE;
Dbt dbt = new Dbt(objbuf.getBytes());
DbLock lock;
did_get = true;
lock = lock_get(locker, Db.DB_LOCK_NOWAIT,
dbt, lock_type);
lockid = locks.size();
locks.addElement(lock);
} else {
// Release a lock.
String objbuf;
objbuf = askForLine(in, System.out,
"input lock to release> ");
if (objbuf == null)
break;
lockid = Integer.parseInt(objbuf, 16);
if (lockid < 0 || lockid >= locks.size()) {
System.out.println("Lock #" + lockid + " out of range");
continue;
}
did_get = false;
DbLock lock = (DbLock)locks.elementAt(lockid);
lock_put(lock);
}
System.out.println("Lock #" + lockid + " " +
(did_get ? "granted" : "released"));
held += did_get ? 1 : -1;
}
catch (DbException dbe) {
switch (dbe.get_errno()) {
case Db.DB_LOCK_NOTGRANTED:
System.out.println("Lock not granted");
break;
case Db.DB_LOCK_DEADLOCK:
System.err.println("LockExample: lock_" +
(did_get ? "get" : "put") +
": returned DEADLOCK");
break;
default:
System.err.println("LockExample: lock_get: " + dbe.toString());
}
}
}
System.out.println();
System.out.println("Closing lock region " + String.valueOf(held) +
" locks held");
}
private static void usage()
{
System.err.println("usage: LockExample [-u] [-h home] [-m maxlocks]");
System.exit(1);
}
public static void main(String argv[])
{
String home = LOCK_HOME;
boolean do_unlink = false;
int maxlocks = 0;
for (int i = 0; i < argv.length; ++i) {
if (argv[i].equals("-h")) {
if (++i >= argv.length)
usage();
home = argv[i];
}
else if (argv[i].equals("-m")) {
if (++i >= argv.length)
usage();
try {
maxlocks = Integer.parseInt(argv[i]);
}
catch (NumberFormatException nfe) {
usage();
}
}
else if (argv[i].equals("-u")) {
do_unlink = true;
}
else {
usage();
}
}
try {
if (do_unlink) {
// Create an environment that immediately
// removes all files.
LockExample tmp = new LockExample(home, maxlocks, do_unlink);
}
LockExample app = new LockExample(home, maxlocks, do_unlink);
app.run();
app.close(0);
}
catch (DbException dbe) {
System.err.println(progname + ": " + dbe.toString());
}
catch (Throwable t) {
System.err.println(progname + ": " + t.toString());
}
System.out.println("LockExample completed");
}
}
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Sleepycat Software. All rights reserved.
*
* $Id: TpcbExample.java,v 11.16 2002/02/13 06:08:35 mjc Exp $
*/
package com.sleepycat.examples;
import com.sleepycat.db.*;
import java.io.FileNotFoundException;
import java.util.Calendar;
import java.util.Date;
import java.util.Random;
import java.util.GregorianCalendar;
import java.math.BigDecimal;
//
// 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).
//
class TpcbExample extends DbEnv
{
public static final int TELLERS_PER_BRANCH = 10;
public static final int ACCOUNTS_PER_TELLER = 10000;
public static final int 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, uncomment the VALID_SCALING configuration
//
// VALID_SCALING configuration
/*
public static final int ACCOUNTS = 1000000;
public static final int BRANCHES = 10;
public static final int TELLERS = 100;
public static final int HISTORY = 25920000;
*/
// TINY configuration
/*
public static final int ACCOUNTS = 1000;
public static final int BRANCHES = 10;
public static final int TELLERS = 100;
public static final int HISTORY = 10000;
*/
// Default configuration
public static final int ACCOUNTS = 100000;
public static final int BRANCHES = 10;
public static final int TELLERS = 100;
public static final int HISTORY = 259200;
public static final int HISTORY_LEN = 100;
public static final int RECLEN = 100;
public static final int BEGID = 1000000;
// used by random_id()
public static final int ACCOUNT = 0;
public static final int BRANCH = 1;
public static final int TELLER = 2;
private static boolean verbose = false;
private static final String progname = "TpcbExample"; // Program name.
public TpcbExample(String home, int cachesize,
boolean initializing, int flags)
throws DbException, FileNotFoundException
{
super(0);
set_error_stream(System.err);
set_errpfx(progname);
set_cachesize(0, cachesize == 0 ? 4 * 1024 * 1024 : cachesize, 0);
if ((flags & (Db.DB_TXN_NOSYNC)) != 0)
set_flags(Db.DB_TXN_NOSYNC, true);
flags &= ~(Db.DB_TXN_NOSYNC);
int local_flags = flags | Db.DB_CREATE;
if (initializing)
local_flags |= Db.DB_INIT_MPOOL;
else
local_flags |= Db.DB_INIT_TXN | Db.DB_INIT_LOCK |
Db.DB_INIT_LOG | Db.DB_INIT_MPOOL;
open(home, local_flags, 0); // may throw DbException
}
//
// Initialize the database to the specified number of accounts, branches,
// history records, and tellers.
//
// Note: num_h was unused in the original ex_tpcb.c example.
//
public void
populate(int num_a, int num_b, int num_h, int num_t)
{
Db dbp = null;
int err;
int balance, idnum;
int end_anum, end_bnum, end_tnum;
int start_anum, start_bnum, start_tnum;
int h_nelem;
idnum = BEGID;
balance = 500000;
h_nelem = num_a;
try {
dbp = new Db(this, 0);
dbp.set_h_nelem(h_nelem);
dbp.open(null, "account", null, Db.DB_HASH,
Db.DB_CREATE | Db.DB_TRUNCATE, 0644);
}
// can be DbException or FileNotFoundException
catch (Exception e1) {
errExit(e1, "Open of account file failed");
}
start_anum = idnum;
populateTable(dbp, idnum, balance, h_nelem, "account");
idnum += h_nelem;
end_anum = idnum - 1;
try {
dbp.close(0);
}
catch (DbException e2) {
errExit(e2, "Account file close failed");
}
if (verbose)
System.out.println("Populated accounts: "
+ String.valueOf(start_anum) + " - " + String.valueOf(end_anum));
//
// 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.
//
h_nelem = (int)num_b;
try {
dbp = new Db(this, 0);
dbp.set_h_nelem(h_nelem);
dbp.set_h_ffactor(1);
dbp.set_pagesize(512);
dbp.open(null, "branch", null, Db.DB_HASH,
Db.DB_CREATE | Db.DB_TRUNCATE, 0644);
}
// can be DbException or FileNotFoundException
catch (Exception e3) {
errExit(e3, "Branch file create failed");
}
start_bnum = idnum;
populateTable(dbp, idnum, balance, h_nelem, "branch");
idnum += h_nelem;
end_bnum = idnum - 1;
try {
dbp.close(0);
}
catch (DbException dbe4) {
errExit(dbe4, "Close of branch file failed");
}
if (verbose)
System.out.println("Populated branches: "
+ String.valueOf(start_bnum) + " - " + String.valueOf(end_bnum));
//
// In the case of tellers, we also want small pages, but we'll let
// the fill factor dynamically adjust itself.
//
h_nelem = (int)num_t;
try {
dbp = new Db(this, 0);
dbp.set_h_nelem(h_nelem);
dbp.set_h_ffactor(0);
dbp.set_pagesize(512);
dbp.open(null, "teller", null, Db.DB_HASH,
Db.DB_CREATE | Db.DB_TRUNCATE, 0644);
}
// can be DbException or FileNotFoundException
catch (Exception e5) {
errExit(e5, "Teller file create failed");
}
start_tnum = idnum;
populateTable(dbp, idnum, balance, h_nelem, "teller");
idnum += h_nelem;
end_tnum = idnum - 1;
try {
dbp.close(0);
}
catch (DbException e6) {
errExit(e6, "Close of teller file failed");
}
if (verbose)
System.out.println("Populated tellers: "
+ String.valueOf(start_tnum) + " - " + String.valueOf(end_tnum));
try {
dbp = new Db(this, 0);
dbp.set_re_len(HISTORY_LEN);
dbp.open(null, "history", null, Db.DB_RECNO,
Db.DB_CREATE | Db.DB_TRUNCATE, 0644);
}
// can be DbException or FileNotFoundException
catch (Exception e7) {
errExit(e7, "Create of history file failed");
}
populateHistory(dbp, num_h, num_a, num_b, num_t);
try {
dbp.close(0);
}
catch (DbException e8) {
errExit(e8, "Close of history file failed");
}
}
public void
populateTable(Db dbp,
int start_id, int balance,
int nrecs, String msg)
{
Defrec drec = new Defrec();
Dbt kdbt = new Dbt(drec.data);
kdbt.set_size(4); // sizeof(int)
Dbt ddbt = new Dbt(drec.data);
ddbt.set_size(drec.data.length); // uses whole array
try {
for (int i = 0; i < nrecs; i++) {
kdbt.set_recno_key_data(start_id + (int)i);
drec.set_balance(balance);
dbp.put(null, kdbt, ddbt, Db.DB_NOOVERWRITE);
}
}
catch (DbException dbe) {
System.err.println("Failure initializing " + msg + " file: " +
dbe.toString());
System.exit(1);
}
}
public void
populateHistory(Db dbp, int nrecs,
int anum, int bnum, int tnum)
{
Histrec hrec = new Histrec();
hrec.set_amount(10);
byte arr[] = new byte[4]; // sizeof(int)
int i;
Dbt kdbt = new Dbt(arr);
kdbt.set_size(arr.length);
Dbt ddbt = new Dbt(hrec.data);
ddbt.set_size(hrec.data.length);
try {
for (i = 1; i <= nrecs; i++) {
kdbt.set_recno_key_data(i);
hrec.set_aid(random_id(ACCOUNT, anum, bnum, tnum));
hrec.set_bid(random_id(BRANCH, anum, bnum, tnum));
hrec.set_tid(random_id(TELLER, anum, bnum, tnum));
dbp.put(null, kdbt, ddbt, Db.DB_APPEND);
}
}
catch (DbException dbe) {
errExit(dbe, "Failure initializing history file");
}
}
static Random rand = new Random();
public static int
random_int(int lo, int hi)
{
int ret;
int t;
t = rand.nextInt();
if (t < 0)
t = -t;
ret = (int)(((double)t / ((double)(Integer.MAX_VALUE) + 1)) *
(hi - lo + 1));
ret += lo;
return (ret);
}
public static int
random_id(int type, int accounts, int branches, int tellers)
{
int 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));
}
public void
run(int n, int accounts, int branches, int tellers)
{
Db adb = null;
Db bdb = null;
Db hdb = null;
Db tdb = null;
double gtps, itps;
int failed, ifailed, ret, txns;
long starttime, curtime, lasttime;
//
// Open the database files.
//
int err;
try {
adb = new Db(this, 0);
adb.open(null, "account", null, Db.DB_UNKNOWN,
Db.DB_AUTO_COMMIT, 0);
bdb = new Db(this, 0);
bdb.open(null, "branch", null, Db.DB_UNKNOWN,
Db.DB_AUTO_COMMIT, 0);
tdb = new Db(this, 0);
tdb.open(null, "teller", null, Db.DB_UNKNOWN,
Db.DB_AUTO_COMMIT, 0);
hdb = new Db(this, 0);
hdb.open(null, "history", null, Db.DB_UNKNOWN,
Db.DB_AUTO_COMMIT, 0);
}
catch (DbException dbe) {
errExit(dbe, "Open of db files failed");
}
catch (FileNotFoundException fnfe) {
errExit(fnfe, "Open of db files failed, missing file");
}
txns = failed = ifailed = 0;
starttime = (new Date()).getTime();
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 = (new Date()).getTime();
gtps = (double)(txns - failed) /
((curtime - starttime) / 1000.0);
itps = (double)(5000 - ifailed) /
((curtime - lasttime) / 1000.0);
System.out.print(String.valueOf(txns) + " txns " +
String.valueOf(failed) + " failed ");
System.out.println(showRounded(gtps, 2) + " TPS (gross) " +
showRounded(itps, 2) + " TPS (interval)");
lasttime = curtime;
ifailed = 0;
}
}
try {
adb.close(0);
bdb.close(0);
tdb.close(0);
hdb.close(0);
}
catch (DbException dbe2) {
errExit(dbe2, "Close of db files failed");
}
System.out.println((long)txns + " transactions begun "
+ String.valueOf(failed) + " failed");
}
//
// XXX Figure out the appropriate way to pick out IDs.
//
public int
txn(Db adb, Db bdb, Db tdb, Db hdb,
int anum, int bnum, int tnum)
{
Dbc acurs = null;
Dbc bcurs = null;
Dbc hcurs = null;
Dbc tcurs = null;
DbTxn t = null;
Defrec rec = new Defrec();
Histrec hrec = new Histrec();
int account, branch, teller;
Dbt d_dbt = new Dbt();
Dbt d_histdbt = new Dbt();
Dbt k_dbt = new Dbt();
Dbt k_histdbt = new Dbt();
account = random_id(ACCOUNT, anum, bnum, tnum);
branch = random_id(BRANCH, anum, bnum, tnum);
teller = random_id(TELLER, anum, bnum, tnum);
// The history key will not actually be retrieved,
// but it does need to be set to something.
byte hist_key[] = new byte[4];
k_histdbt.set_data(hist_key);
k_histdbt.set_size(4 /* == sizeof(int)*/);
byte key_bytes[] = new byte[4];
k_dbt.set_data(key_bytes);
k_dbt.set_size(4 /* == sizeof(int)*/);
d_dbt.set_flags(Db.DB_DBT_USERMEM);
d_dbt.set_data(rec.data);
d_dbt.set_ulen(rec.length());
hrec.set_aid(account);
hrec.set_bid(branch);
hrec.set_tid(teller);
hrec.set_amount(10);
// Request 0 bytes since we're just positioning.
d_histdbt.set_flags(Db.DB_DBT_PARTIAL);
// START TIMING
try {
t = txn_begin(null, 0);
acurs = adb.cursor(t, 0);
bcurs = bdb.cursor(t, 0);
tcurs = tdb.cursor(t, 0);
hcurs = hdb.cursor(t, 0);
// Account record
k_dbt.set_recno_key_data(account);
if (acurs.get(k_dbt, d_dbt, Db.DB_SET) != 0)
throw new TpcbException("acurs get failed");
rec.set_balance(rec.get_balance() + 10);
acurs.put(k_dbt, d_dbt, Db.DB_CURRENT);
// Branch record
k_dbt.set_recno_key_data(branch);
if (bcurs.get(k_dbt, d_dbt, Db.DB_SET) != 0)
throw new TpcbException("bcurs get failed");
rec.set_balance(rec.get_balance() + 10);
bcurs.put(k_dbt, d_dbt, Db.DB_CURRENT);
// Teller record
k_dbt.set_recno_key_data(teller);
if (tcurs.get(k_dbt, d_dbt, Db.DB_SET) != 0)
throw new TpcbException("ccurs get failed");
rec.set_balance(rec.get_balance() + 10);
tcurs.put(k_dbt, d_dbt, Db.DB_CURRENT);
// History record
d_histdbt.set_flags(0);
d_histdbt.set_data(hrec.data);
d_histdbt.set_ulen(hrec.length());
if (hdb.put(t, k_histdbt, d_histdbt, Db.DB_APPEND) != 0)
throw(new DbException("put failed"));
acurs.close();
bcurs.close();
tcurs.close();
hcurs.close();
// null out t in advance; if the commit fails,
// we don't want to abort it in the catch clause.
DbTxn tmptxn = t;
t = null;
tmptxn.commit(0);
// END TIMING
return (0);
}
catch (Exception e) {
try {
if (acurs != null)
acurs.close();
if (bcurs != null)
bcurs.close();
if (tcurs != null)
tcurs.close();
if (hcurs != null)
hcurs.close();
if (t != null)
t.abort();
}
catch (DbException dbe) {
// not much we can do here.
}
if (verbose) {
System.out.println("Transaction A=" + String.valueOf(account)
+ " B=" + String.valueOf(branch)
+ " T=" + String.valueOf(teller) + " failed");
System.out.println("Reason: " + e.toString());
}
return (-1);
}
}
static void errExit(Exception err, String s)
{
System.err.print(progname + ": ");
if (s != null) {
System.err.print(s + ": ");
}
System.err.println(err.toString());
System.exit(1);
}
public static void main(String argv[])
{
long seed;
int accounts, branches, tellers, history;
boolean iflag, txn_no_sync;
int mpool, ntxns;
String home, endarg;
home = "TESTDIR";
accounts = branches = history = tellers = 0;
txn_no_sync = false;
mpool = ntxns = 0;
verbose = false;
iflag = false;
seed = (new GregorianCalendar()).get(Calendar.SECOND);
for (int i = 0; i < argv.length; ++i)
{
if (argv[i].equals("-a")) {
// Number of account records
if ((accounts = Integer.parseInt(argv[++i])) <= 0)
invarg(argv[i]);
}
else if (argv[i].equals("-b")) {
// Number of branch records
if ((branches = Integer.parseInt(argv[++i])) <= 0)
invarg(argv[i]);
}
else if (argv[i].equals("-c")) {
// Cachesize in bytes
if ((mpool = Integer.parseInt(argv[++i])) <= 0)
invarg(argv[i]);
}
else if (argv[i].equals("-f")) {
// Fast mode: no txn sync.
txn_no_sync = true;
}
else if (argv[i].equals("-h")) {
// DB home.
home = argv[++i];
}
else if (argv[i].equals("-i")) {
// Initialize the test.
iflag = true;
}
else if (argv[i].equals("-n")) {
// Number of transactions
if ((ntxns = Integer.parseInt(argv[++i])) <= 0)
invarg(argv[i]);
}
else if (argv[i].equals("-S")) {
// Random number seed.
seed = Long.parseLong(argv[++i]);
if (seed <= 0)
invarg(argv[i]);
}
else if (argv[i].equals("-s")) {
// Number of history records
if ((history = Integer.parseInt(argv[++i])) <= 0)
invarg(argv[i]);
}
else if (argv[i].equals("-t")) {
// Number of teller records
if ((tellers = Integer.parseInt(argv[++i])) <= 0)
invarg(argv[i]);
}
else if (argv[i].equals("-v")) {
// Verbose option.
verbose = true;
}
else
{
usage();
}
}
rand.setSeed((int)seed);
TpcbExample app = null;
// Initialize the database environment.
// Must be done in within a try block.
//
try {
app = new TpcbExample(home, mpool, iflag,
txn_no_sync ? Db.DB_TXN_NOSYNC : 0);
}
catch (Exception e1) {
errExit(e1, "initializing environment failed");
}
accounts = accounts == 0 ? ACCOUNTS : accounts;
branches = branches == 0 ? BRANCHES : branches;
tellers = tellers == 0 ? TELLERS : tellers;
history = history == 0 ? HISTORY : history;
if (verbose)
System.out.println((long)accounts + " Accounts, "
+ String.valueOf(branches) + " Branches, "
+ String.valueOf(tellers) + " Tellers, "
+ String.valueOf(history) + " History");
if (iflag) {
if (ntxns != 0)
usage();
app.populate(accounts, branches, history, tellers);
}
else {
if (ntxns == 0)
usage();
app.run(ntxns, accounts, branches, tellers);
}
// Shut down the application.
try {
app.close(0);
}
catch (DbException dbe2) {
errExit(dbe2, "appexit failed");
}
System.exit(0);
}
private static void invarg(String str)
{
System.err.println("TpcbExample: invalid argument: " + str);
System.exit(1);
}
private static void usage()
{
System.err.println(
"usage: TpcbExample [-fiv] [-a accounts] [-b branches]\n" +
" [-c cachesize] [-h home] [-n transactions ]\n" +
" [-S seed] [-s history] [-t tellers]");
System.exit(1);
}
// round 'd' to 'scale' digits, and return result as string
private String showRounded(double d, int scale)
{
return new BigDecimal(d).
setScale(scale, BigDecimal.ROUND_HALF_DOWN).toString();
}
// The byte order is our choice.
//
static long get_int_in_array(byte[] array, int offset)
{
return
((0xff & array[offset+0]) << 0) |
((0xff & array[offset+1]) << 8) |
((0xff & array[offset+2]) << 16) |
((0xff & array[offset+3]) << 24);
}
// Note: Value needs to be long to avoid sign extension
static void set_int_in_array(byte[] array, int offset, long value)
{
array[offset+0] = (byte)((value >> 0) & 0x0ff);
array[offset+1] = (byte)((value >> 8) & 0x0ff);
array[offset+2] = (byte)((value >> 16) & 0x0ff);
array[offset+3] = (byte)((value >> 24) & 0x0ff);
}
};
// Simulate the following C struct:
// struct Defrec {
// u_int32_t id;
// u_int32_t balance;
// u_int8_t pad[RECLEN - sizeof(int) - sizeof(int)];
// };
class Defrec
{
public Defrec()
{
data = new byte[TpcbExample.RECLEN];
}
public int length()
{
return TpcbExample.RECLEN;
}
public long get_id()
{
return TpcbExample.get_int_in_array(data, 0);
}
public void set_id(long value)
{
TpcbExample.set_int_in_array(data, 0, value);
}
public long get_balance()
{
return TpcbExample.get_int_in_array(data, 4);
}
public void set_balance(long value)
{
TpcbExample.set_int_in_array(data, 4, value);
}
static {
Defrec d = new Defrec();
d.set_balance(500000);
}
public byte[] data;
}
// Simulate the following C struct:
// 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)];
// };
class Histrec
{
public Histrec()
{
data = new byte[TpcbExample.RECLEN];
}
public int length()
{
return TpcbExample.RECLEN;
}
public long get_aid()
{
return TpcbExample.get_int_in_array(data, 0);
}
public void set_aid(long value)
{
TpcbExample.set_int_in_array(data, 0, value);
}
public long get_bid()
{
return TpcbExample.get_int_in_array(data, 4);
}
public void set_bid(long value)
{
TpcbExample.set_int_in_array(data, 4, value);
}
public long get_tid()
{
return TpcbExample.get_int_in_array(data, 8);
}
public void set_tid(long value)
{
TpcbExample.set_int_in_array(data, 8, value);
}
public long get_amount()
{
return TpcbExample.get_int_in_array(data, 12);
}
public void set_amount(long value)
{
TpcbExample.set_int_in_array(data, 12, value);
}
public byte[] data;
}
class TpcbException extends Exception
{
TpcbException()
{
super();
}
TpcbException(String s)
{
super(s);
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment