Import BSDDB 4.7.25 (as of svn r89086)
This commit is contained in:
301
test/scr031/chk.xa
Normal file
301
test/scr031/chk.xa
Normal file
@@ -0,0 +1,301 @@
|
||||
#! /bin/sh
|
||||
#
|
||||
# Smoke test XA support.
|
||||
|
||||
msg()
|
||||
{
|
||||
echo "========"
|
||||
echo "======== $1"
|
||||
echo "========"
|
||||
}
|
||||
|
||||
func_clean()
|
||||
{
|
||||
rm -rf run
|
||||
}
|
||||
|
||||
# Build the configuration file --
|
||||
# We do this work in the shell script because we have to fill in
|
||||
# lots of shell variables.
|
||||
func_ubbinit()
|
||||
{
|
||||
MACHINE_NAME=`uname -n`
|
||||
cat > $RUN/config/ubb.cfg << END_OF_UBB_FILE
|
||||
*RESOURCES
|
||||
IPCKEY 200103
|
||||
DOMAINID domain3
|
||||
MASTER cluster3
|
||||
MAXACCESSERS 10
|
||||
MAXSERVERS 5
|
||||
MAXSERVICES 10
|
||||
MODEL SHM
|
||||
LDBAL N
|
||||
|
||||
*MACHINES
|
||||
DEFAULT:
|
||||
APPDIR="$RUN/bin"
|
||||
TUXCONFIG="$TUXCONFIG"
|
||||
TLOGDEVICE="$TLOGDEVICE"
|
||||
TUXDIR="$TUXDIR"
|
||||
# Machine name is 30 characters max
|
||||
$MACHINE_NAME LMID=cluster3
|
||||
|
||||
*GROUPS
|
||||
# Group name is 30 characters max
|
||||
group_tm LMID=cluster3 GRPNO=1 TMSNAME=DBRM TMSCOUNT=2 OPENINFO="BERKELEY-DB:$RUN/data"
|
||||
|
||||
*SERVERS
|
||||
DEFAULT:
|
||||
CLOPT="-A"
|
||||
|
||||
# Server name is 78 characters max (same for any pathname)
|
||||
server1 SRVGRP=group_tm SRVID=1 MAXGEN=3 RESTART=Y
|
||||
server2 SRVGRP=group_tm SRVID=2 MAXGEN=3 RESTART=Y
|
||||
|
||||
*SERVICES
|
||||
# Service name is 15 characters max
|
||||
# server1
|
||||
TestTxn1
|
||||
# server2
|
||||
TestTxn2
|
||||
END_OF_UBB_FILE
|
||||
tmloadcf -y $RUN/config/ubb.cfg
|
||||
}
|
||||
|
||||
init_tmadmin()
|
||||
{
|
||||
tmadmin << END_OF_TMADMIN
|
||||
crdl -z $TLOGDEVICE -b 500
|
||||
crlog -m cluster3
|
||||
END_OF_TMADMIN
|
||||
}
|
||||
|
||||
# Run a test.
|
||||
run()
|
||||
{
|
||||
msg "CLEANING UP FROM THE LAST RUN."
|
||||
rm -rf run
|
||||
mkdir -p run/bin run/config run/data
|
||||
|
||||
msg "BUILDING THE CONFIGURATION FILE."
|
||||
func_ubbinit
|
||||
|
||||
# Everything else is done in run/bin.
|
||||
cd $RUN/bin
|
||||
|
||||
# The CFLAGS variable defines the pre-processor defines -- start with
|
||||
# whatever the user set, and add our own stuff.
|
||||
#
|
||||
# For debugging output, add -DVERBOSE to COMPILE_FLAGS, by uncommenting
|
||||
# the following line.
|
||||
#
|
||||
# Verbose output from the client appears in this script's stdout,
|
||||
# (which you can re-direct below, when the client is run).
|
||||
# Verbose output from the server appears in the file run/bin/stdout.
|
||||
#
|
||||
# COMPILE_FLAGS="-DVERBOSE"
|
||||
COMPILE_FLAGS="$CFLAGS $COMPILE_FLAGS -g -I../../.."
|
||||
|
||||
msg "BUILDING CLIENT"
|
||||
CFLAGS="$COMPILE_FLAGS"; export CFLAGS
|
||||
buildclient -v -r BERKELEY-DB -o client \
|
||||
-f ../../src/htimestampxa.c -f ../../src/client.c
|
||||
test "$?" -eq 0 || {
|
||||
echo "FAIL: buildclient failed."
|
||||
exit 1
|
||||
}
|
||||
|
||||
msg "BUILDING SERVER #1"
|
||||
CFLAGS="$COMPILE_FLAGS -DSERVER1"; export CFLAGS
|
||||
buildserver -v -r BERKELEY-DB -o server1 \
|
||||
-s TestTxn1:TestTxn1 \
|
||||
-f ../../src/htimestampxa.c -f ../../src/server.c
|
||||
test "$?" -eq 0 || {
|
||||
echo "FAIL: buildserver failed."
|
||||
exit 1
|
||||
}
|
||||
|
||||
msg "BUILDING SERVER #2"
|
||||
CFLAGS="$COMPILE_FLAGS -DSERVER2"; export CFLAGS
|
||||
buildserver -v -r BERKELEY-DB -o server2 \
|
||||
-s TestTxn2:TestTxn2 \
|
||||
-f ../../src/htimestampxa.c -f ../../src/server.c
|
||||
test "$?" -eq 0 || {
|
||||
echo "FAIL: buildserver failed."
|
||||
exit 1
|
||||
}
|
||||
|
||||
msg "BUILDING THE RESOURCE MANAGER."
|
||||
buildtms -v -o DBRM -r BERKELEY-DB
|
||||
|
||||
msg "BUILDING THE LOG DEVICE."
|
||||
init_tmadmin
|
||||
|
||||
# Boot Tuxedo.
|
||||
# You should see something like:
|
||||
#
|
||||
# INFO: BEA Tuxedo, Version 8.1
|
||||
# INFO: Serial #: 650522264138-1510597376252,
|
||||
# Expiration 2005-02-15, Maxusers 100
|
||||
# INFO: Licensed to: BEA Evaluation Customer
|
||||
#
|
||||
# Booting admin processes ...
|
||||
#
|
||||
# exec BBL -A :
|
||||
# process id=13845 ... Started.
|
||||
#
|
||||
# Booting server processes ...
|
||||
#
|
||||
# exec DBRM -A :
|
||||
# process id=13846 ... Started.
|
||||
# exec DBRM -A :
|
||||
# process id=13847 ... Started.
|
||||
# exec server1 -A :
|
||||
# process id=13848 ... Started.
|
||||
# exec server2 -A :
|
||||
# process id=13849 ... Started.
|
||||
# 5 processes started.
|
||||
msg "BOOTING TUXEDO."
|
||||
tmboot -y
|
||||
|
||||
# Run the client with 10, 100 and 1000 transactions.
|
||||
exitval=0
|
||||
for i in 10 100 1000; do
|
||||
msg "RUN THE CLIENT WITH $i TRANSACTIONS."
|
||||
# You can get debugging output on just the client by
|
||||
# adding -v to the command line.
|
||||
#
|
||||
# ./client -v -n $i
|
||||
./client -n $i
|
||||
test "$?" -ne 0 && {
|
||||
echo "FAIL: client failed"
|
||||
exitval=1
|
||||
break;
|
||||
}
|
||||
done
|
||||
|
||||
msg "SHUTTING DOWN THE TRANSACTION MANAGER."
|
||||
echo 'y' | tmshutdown
|
||||
|
||||
# Copy out Tuxedo's logging.
|
||||
msg "ULOG FILES:"
|
||||
cat ULOG*
|
||||
|
||||
# Copy out any server output.
|
||||
msg "STDOUT:"
|
||||
cat stdout
|
||||
|
||||
# Copy out any server errors.
|
||||
msg "STDERR:"
|
||||
cat stderr
|
||||
test -s stderr && {
|
||||
echo "FAIL: stderr file not empty"
|
||||
exitval=1
|
||||
}
|
||||
|
||||
# We never checkpointed, run recovery to make sure it all works.
|
||||
msg "RECOVERY:"
|
||||
../../../db_recover -h ../data -v
|
||||
test "$?" -ne 0 && {
|
||||
echo "FAIL: recovery failed"
|
||||
exitval=1
|
||||
}
|
||||
|
||||
return $exitval
|
||||
}
|
||||
|
||||
# Debug the shell script.
|
||||
# set -x
|
||||
|
||||
# Check to make sure we have a Tuxedo build we understand.
|
||||
test -z "$TUXDIR" && {
|
||||
echo "FAIL: the TUXDIR environment variable NOT set"
|
||||
echo \
|
||||
"FAIL: TUXDIR must be set to the absolute path of the Tuxedo install"
|
||||
echo "FAIL: immediately above the subdirectories bin, include and lib"
|
||||
exit 1
|
||||
}
|
||||
dlist="include lib"
|
||||
for i in $dlist; do
|
||||
test -d $TUXDIR/$i || {
|
||||
echo "FAIL: check the Tuxedo install"
|
||||
echo "FAIL: the required directory $TUXDIR/$i does not exist"
|
||||
exit 1
|
||||
}
|
||||
done
|
||||
flist="bin/buildclient bin/buildserver bin/buildtms bin/tmadmin bin/tmboot
|
||||
bin/tmloadcf bin/tmshutdown udataobj/RM"
|
||||
for i in $flist; do
|
||||
test -f $TUXDIR/$i || {
|
||||
echo "FAIL: check the Tuxedo install"
|
||||
echo "FAIL: the required file $TUXDIR/$i does not exist"
|
||||
exit 1
|
||||
}
|
||||
done
|
||||
msg "Using Tuxedo $TUXDIR installation"
|
||||
|
||||
# Set the location of the Berkeley DB libraries -- allow the user to override.
|
||||
# Check to make sure we have a Berkeley DB installation. (I'd like to use the
|
||||
# local DB installation, but I've never been able to make Tuxedo load shared
|
||||
# libraries from the .libs directory.)
|
||||
REL=../../dist/RELEASE
|
||||
test -z "$DB_INSTALL" && test -f $REL && {
|
||||
. $REL
|
||||
DB_INSTALL=/usr/local/BerkeleyDB.${DB_VERSION_MAJOR}.${DB_VERSION_MINOR}
|
||||
export DB_INSTALL
|
||||
}
|
||||
if test -f "$DB_INSTALL/lib/libdb.so"; then
|
||||
msg "Using Berkeley DB $DB_INSTALL/lib/ installation"
|
||||
else
|
||||
echo "FAIL: $DB_INSTALL/lib/libdb.so not found"
|
||||
echo \
|
||||
"FAIL: DB_INSTALL must be set to the absolute path of the Berkeley DB install"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# You may need to update the Tuxedo resource manager file. It should be in:
|
||||
#
|
||||
# $TUXDIR/udataobj/RM
|
||||
#
|
||||
# Solaris requires a line something like the following:
|
||||
#
|
||||
# BERKELEY-DB:db_xa_switch:-L${DB_INSTALL}/lib -ldb
|
||||
#
|
||||
# where DB_INSTALL is a Berkeley DB install, and /lib contains DB libraries.
|
||||
egrep "^BERKELEY-DB:db_xa_switch:" $TUXDIR/udataobj/RM > /dev/null || {
|
||||
echo "FAIL: $TUXDIR/udataobj/RM does not list DB as one of its RMs"
|
||||
echo "FAIL: Try adding:"
|
||||
echo "FAIL: BERKELEY-DB:db_xa_switch:-L\${DB_INSTALL}/lib -ldb"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Everything is built in and run from the "run" subdirectory.
|
||||
RUN=`pwd`/run; export RUN
|
||||
|
||||
FIELDTBLS32=datafml.fml; export FIELDTBLS32
|
||||
FLDTBLDIR32=$RUN/config; export FLDTBLDIR32
|
||||
TLOGDEVICE=$RUN/data/dlog; export TLOGDEVICE
|
||||
TUXCONFIG=$RUN/config/tuxconfig;export TUXCONFIG
|
||||
|
||||
PATH="$PATH:$RUN/bin:$TUXDIR/bin"
|
||||
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$DB_INSTALL/lib:$TUXDIR/lib;
|
||||
export LD_LIBRARY_PATH PATH
|
||||
|
||||
if test $# -eq 1; then
|
||||
case "$1" in
|
||||
clean) # Clean up from previous runs.
|
||||
func_clean;;
|
||||
shutdown) # Shutdown Tuxedo from previous runs.
|
||||
echo 'y' | tmshutdown -w 5;;
|
||||
*)
|
||||
echo 'usage: chk.xa [clean | shutdown]'
|
||||
exit 1;;
|
||||
esac
|
||||
else
|
||||
run # Run the XA test.
|
||||
if test "$?" -ne 0; then
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
exit 0
|
||||
339
test/scr031/src/client.c
Normal file
339
test/scr031/src/client.c
Normal file
@@ -0,0 +1,339 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <tx.h>
|
||||
#include <atmi.h>
|
||||
#include <fml32.h>
|
||||
#include <fml1632.h>
|
||||
|
||||
#include <db.h>
|
||||
|
||||
#include "datafml.h"
|
||||
#include "hdbrec.h"
|
||||
#include "hcommonxa.h"
|
||||
#include "htimestampxa.h"
|
||||
|
||||
#define HOME "../data"
|
||||
#define TABLE1 "../data/table1.db"
|
||||
#define TABLE3 "../data/table3.db"
|
||||
|
||||
#ifdef VERBOSE
|
||||
static int verbose = 1; /* Debugging output. */
|
||||
#else
|
||||
static int verbose = 0;
|
||||
#endif
|
||||
|
||||
DB_ENV *dbenv;
|
||||
char *progname; /* Client run-time name. */
|
||||
|
||||
int check_data(DB *);
|
||||
char *db_buf(DBT *);
|
||||
int usage(void);
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
DB *dbp3;
|
||||
DBT key, data;
|
||||
FBFR *buf, *replyBuf;
|
||||
HDbRec rec;
|
||||
TPINIT *initBuf;
|
||||
long len, replyLen, seqNo;
|
||||
int ch, cnt, cnt_abort, cnt_commit, cnt_server1, i, ret;
|
||||
char *target;
|
||||
|
||||
progname = argv[0];
|
||||
|
||||
dbp3 = NULL;
|
||||
buf = replyBuf = NULL;
|
||||
initBuf = NULL;
|
||||
cnt = 1000;
|
||||
cnt_abort = cnt_commit = cnt_server1 = 0;
|
||||
|
||||
while ((ch = getopt(argc, argv, "n:v")) != EOF)
|
||||
switch (ch) {
|
||||
case 'n':
|
||||
cnt = atoi(optarg);
|
||||
break;
|
||||
case 'v':
|
||||
verbose = 1;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
return (usage());
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (verbose)
|
||||
printf("%s: called\n", progname);
|
||||
|
||||
/* Seed random number generator. */
|
||||
srand((u_int)(time(NULL) | getpid()));
|
||||
|
||||
if (tpinit((TPINIT *)NULL) == -1)
|
||||
goto tuxedo_err;
|
||||
if (verbose)
|
||||
printf("%s: tpinit() OK\n", progname);
|
||||
|
||||
/* Allocate init buffer */
|
||||
if ((initBuf = (TPINIT *)tpalloc("TPINIT", NULL, TPINITNEED(0))) == 0)
|
||||
goto tuxedo_err;
|
||||
if (verbose)
|
||||
printf("%s: tpalloc(\"TPINIT\") OK\n", progname);
|
||||
|
||||
/* Join the DB environment. */
|
||||
if ((ret = db_env_create(&dbenv, 0)) != 0 ||
|
||||
(ret = dbenv->open(dbenv, HOME, DB_JOINENV, 0)) != 0) {
|
||||
fprintf(stderr,
|
||||
"%s: %s: %s\n", progname, HOME, db_strerror(ret));
|
||||
goto err;
|
||||
}
|
||||
dbenv->set_errfile(dbenv, stderr);
|
||||
if (verbose)
|
||||
printf("%s: opened %s OK\n", progname, HOME);
|
||||
|
||||
/* Open table #3 -- truncate it for each new run. */
|
||||
if ((ret = db_create(&dbp3, dbenv, 0)) != 0 ||
|
||||
(ret = dbp3->open(dbp3,
|
||||
NULL, TABLE3, NULL, DB_BTREE, DB_CREATE, 0660)) != 0) {
|
||||
fprintf(stderr,
|
||||
"%s: %s %s\n", progname, TABLE3, db_strerror(ret));
|
||||
goto err;
|
||||
}
|
||||
if (verbose)
|
||||
printf("%s: opened/truncated %s OK\n", progname, TABLE3);
|
||||
|
||||
/* Allocate send buffer. */
|
||||
len = Fneeded(1, 3 * sizeof(long));
|
||||
if ((buf = (FBFR*)tpalloc("FML32", NULL, len)) == 0)
|
||||
goto tuxedo_err;
|
||||
if (verbose)
|
||||
printf("%s: tpalloc(\"FML32\"), send buffer OK\n", progname);
|
||||
|
||||
/* Allocate reply buffer. */
|
||||
replyLen = 1024;
|
||||
if ((replyBuf = (FBFR*)tpalloc("FML32", NULL, replyLen)) == NULL)
|
||||
goto tuxedo_err;
|
||||
if (verbose)
|
||||
printf("%s: tpalloc(\"FML32\"), reply buffer OK\n", progname);
|
||||
|
||||
memset(&key, 0, sizeof(key));
|
||||
memset(&data, 0, sizeof(data));
|
||||
for (rec.SeqNo = 1, i = 0; i < cnt; ++i, ++rec.SeqNo) {
|
||||
GetTime(&rec.Ts);
|
||||
|
||||
if (Fchg(buf, SEQ_NO, 0, (char *)&rec.SeqNo, 0) == -1)
|
||||
goto tuxedo_fml_err;
|
||||
if (verbose)
|
||||
printf("%s: Fchg(), sequence number OK\n", progname);
|
||||
if (Fchg(buf, TS_SEC, 0, (char *)&rec.Ts.Sec, 0) == -1)
|
||||
goto tuxedo_fml_err;
|
||||
if (verbose)
|
||||
printf("%s: Fchg(), seconds OK\n", progname);
|
||||
if (Fchg(buf, TS_USEC, 0, (char *)&rec.Ts.Usec, 0) == -1)
|
||||
goto tuxedo_fml_err;
|
||||
if (verbose)
|
||||
printf("%s: Fchg(), microseconds OK\n", progname);
|
||||
|
||||
if (tpbegin(60L, 0L) == -1)
|
||||
goto tuxedo_err;
|
||||
if (verbose)
|
||||
printf("%s: tpbegin() OK\n", progname);
|
||||
|
||||
/* Randomly send half of our requests to each server. */
|
||||
if (rand() % 2 > 0) {
|
||||
++cnt_server1;
|
||||
target = "TestTxn1";
|
||||
} else
|
||||
target = "TestTxn2";
|
||||
if (tpcall(target, (char *)buf,
|
||||
0L, (char **)&replyBuf, &replyLen, TPSIGRSTRT) == -1)
|
||||
goto tuxedo_err;
|
||||
|
||||
/* Commit for a return value of 0, otherwise abort. */
|
||||
if (tpurcode == 0) {
|
||||
++cnt_commit;
|
||||
if (verbose)
|
||||
printf("%s: txn success\n", progname);
|
||||
|
||||
if (tpcommit(0L) == -1)
|
||||
goto tuxedo_err;
|
||||
if (verbose)
|
||||
printf("%s: tpcommit() OK\n", progname);
|
||||
|
||||
/*
|
||||
* Store a copy of the key/data pair into table #3
|
||||
* on success, we'll compare table #1 and table #3
|
||||
* after the run finishes.
|
||||
*/
|
||||
seqNo = rec.SeqNo;
|
||||
key.data = &seqNo;
|
||||
key.size = sizeof(seqNo);
|
||||
data.data = &rec;
|
||||
data.size = sizeof(rec);
|
||||
if ((ret =
|
||||
dbp3->put(dbp3, NULL, &key, &data, 0)) != 0) {
|
||||
fprintf(stderr, "%s: DB->put: %s %s\n",
|
||||
progname, TABLE3, db_strerror(ret));
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
++cnt_abort;
|
||||
if (verbose)
|
||||
printf("%s: txn failure\n", progname);
|
||||
|
||||
if (tpabort(0L) == -1)
|
||||
goto tuxedo_err;
|
||||
if (verbose)
|
||||
printf("%s: tpabort() OK\n", progname);
|
||||
}
|
||||
}
|
||||
|
||||
printf("%s: %d requests: %d committed, %d aborted\n",
|
||||
progname, cnt, cnt_commit, cnt_abort);
|
||||
printf("%s: %d sent to server #1, %d sent to server #2\n",
|
||||
progname, cnt_server1, cnt - cnt_server1);
|
||||
|
||||
ret = check_data(dbp3);
|
||||
|
||||
if (0) {
|
||||
tuxedo_err: fprintf(stderr, "%s: TUXEDO ERROR: %s (code %d)\n",
|
||||
progname, tpstrerror(tperrno), tperrno);
|
||||
goto err;
|
||||
}
|
||||
if (0) {
|
||||
tuxedo_fml_err: fprintf(stderr, "%s: FML ERROR: %s (code %d)\n",
|
||||
progname, Fstrerror(Ferror), Ferror);
|
||||
}
|
||||
if (0) {
|
||||
err: ret = EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (replyBuf != NULL)
|
||||
tpfree((char *)replyBuf);
|
||||
if (buf != NULL)
|
||||
tpfree((char *)buf);
|
||||
if (initBuf != NULL)
|
||||
tpfree((char *)initBuf);
|
||||
if (dbp3 != NULL)
|
||||
(void)dbp3->close(dbp3, 0);
|
||||
if (dbenv != NULL)
|
||||
(void)dbenv->close(dbenv, 0);
|
||||
|
||||
tpterm();
|
||||
if (verbose)
|
||||
printf("%s: tpterm() OK\n", progname);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* check_data --
|
||||
* Compare committed data with our local copy, stored in table3.
|
||||
*/
|
||||
int
|
||||
check_data(dbp3)
|
||||
DB *dbp3;
|
||||
{
|
||||
DB *dbp1;
|
||||
DBC *dbc1, *dbc3;
|
||||
DBT key1, data1, key3, data3;
|
||||
int ret, ret1, ret3;
|
||||
|
||||
dbp1 = NULL;
|
||||
dbc1 = dbc3 = NULL;
|
||||
|
||||
/* Open table #1. */
|
||||
if ((ret = db_create(&dbp1, dbenv, 0)) != 0 ||
|
||||
(ret = dbp1->open(
|
||||
dbp1, NULL, TABLE1, NULL, DB_UNKNOWN, DB_RDONLY, 0)) != 0) {
|
||||
fprintf(stderr,
|
||||
"%s: %s: %s\n", progname, TABLE1, db_strerror(ret));
|
||||
goto err;
|
||||
}
|
||||
if (verbose)
|
||||
printf("%s: opened %s OK\n", progname, TABLE1);
|
||||
|
||||
/* Open cursors. */
|
||||
if ((ret = dbp1->cursor(dbp1, NULL, &dbc1, 0)) != 0 ||
|
||||
(ret = dbp3->cursor(dbp3, NULL, &dbc3, 0)) != 0) {
|
||||
fprintf(stderr,
|
||||
"%s: DB->cursor: %s\n", progname, db_strerror(ret));
|
||||
goto err;
|
||||
}
|
||||
if (verbose)
|
||||
printf("%s: opened cursors OK\n", progname);
|
||||
|
||||
/* Compare the two databases. */
|
||||
memset(&key1, 0, sizeof(key1));
|
||||
memset(&data1, 0, sizeof(data1));
|
||||
memset(&key3, 0, sizeof(key3));
|
||||
memset(&data3, 0, sizeof(data3));
|
||||
for (;;) {
|
||||
ret1 = dbc1->c_get(dbc1, &key1, &data1, DB_NEXT);
|
||||
ret3 = dbc3->c_get(dbc3, &key3, &data3, DB_NEXT);
|
||||
if (verbose) {
|
||||
printf("get: key1: %s\n", db_buf(&key1));
|
||||
printf("get: key3: %s\n", db_buf(&key3));
|
||||
printf("get: data1: %s\n", db_buf(&data1));
|
||||
printf("get: data3: %s\n", db_buf(&data3));
|
||||
}
|
||||
if (ret1 != 0 || ret3 != 0)
|
||||
break;
|
||||
/*
|
||||
* Only compare the first N bytes, the saved message chunks
|
||||
* are different.
|
||||
*/
|
||||
if (key1.size != key3.size ||
|
||||
memcmp(key1.data, key3.data, key1.size) != 0 ||
|
||||
data1.size != data3.size ||
|
||||
memcmp(data1.data, data3.data,
|
||||
sizeof(long) + sizeof(HTimestampData)) != 0)
|
||||
goto mismatch;
|
||||
}
|
||||
if (ret1 != DB_NOTFOUND || ret3 != DB_NOTFOUND) {
|
||||
mismatch: fprintf(stderr,
|
||||
"%s: DB_ERROR: databases 1 and 3 weren't identical\n",
|
||||
progname);
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
err: if (dbc1 != NULL)
|
||||
(void)dbc1->c_close(dbc1);
|
||||
if (dbc3 != NULL)
|
||||
(void)dbc3->c_close(dbc3);
|
||||
if (dbp1 != NULL)
|
||||
(void)dbp1->close(dbp1, 0);
|
||||
|
||||
return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
}
|
||||
|
||||
char *
|
||||
db_buf(dbt)
|
||||
DBT *dbt;
|
||||
{
|
||||
static u_char buf[1024];
|
||||
size_t len;
|
||||
u_char *p, *b;
|
||||
|
||||
for (p = dbt->data, len = dbt->size, b = buf; len > 0; ++p, --len)
|
||||
if (isprint(*p))
|
||||
b += sprintf((char *)b, "%c", *p);
|
||||
else
|
||||
b += sprintf((char *)b, "%#o", *p);
|
||||
return ((char *)buf);
|
||||
}
|
||||
|
||||
int
|
||||
usage()
|
||||
{
|
||||
fprintf(stderr, "usage: %s [-v] [-n txn]\n", progname);
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
5
test/scr031/src/datafml.fml
Normal file
5
test/scr031/src/datafml.fml
Normal file
@@ -0,0 +1,5 @@
|
||||
# datafml.fml was generated by tuxdev on 12/18/98 @ 12:15:33 ***** DO NOT EDIT *****
|
||||
|
||||
SEQ_NO 401 long -
|
||||
TS_SEC 402 long -
|
||||
TS_USEC 403 long -
|
||||
5
test/scr031/src/datafml.h
Normal file
5
test/scr031/src/datafml.h
Normal file
@@ -0,0 +1,5 @@
|
||||
/* fname fldid */
|
||||
/* ----- ----- */
|
||||
#define SEQ_NO ((FLDID32)33554833) /* number: 401 type: long */
|
||||
#define TS_SEC ((FLDID32)33554834) /* number: 402 type: long */
|
||||
#define TS_USEC ((FLDID32)33554835) /* number: 403 type: long */
|
||||
8
test/scr031/src/hcommonxa.h
Normal file
8
test/scr031/src/hcommonxa.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef HCOMMONXA_H
|
||||
#define HCOMMONXA_H
|
||||
|
||||
#define HERR_SYS_CUR 102
|
||||
#define HERR_TUX_CUR 103
|
||||
#define HERR_FML_CUR 104
|
||||
|
||||
#endif
|
||||
14
test/scr031/src/hdbrec.h
Normal file
14
test/scr031/src/hdbrec.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef HDBREC_H
|
||||
#define HDBREC_H
|
||||
|
||||
#include "htimestampxa.h"
|
||||
|
||||
/*
|
||||
* DB record
|
||||
*/
|
||||
typedef struct __HDbRec {
|
||||
long SeqNo;
|
||||
HTimestampData Ts;
|
||||
char Msg[10];
|
||||
} HDbRec;
|
||||
#endif
|
||||
14
test/scr031/src/htimestampxa.c
Normal file
14
test/scr031/src/htimestampxa.c
Normal file
@@ -0,0 +1,14 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "htimestampxa.h"
|
||||
|
||||
void
|
||||
GetTime(HTimestampData *ts)
|
||||
{
|
||||
struct timeval timeNow;
|
||||
|
||||
(void)gettimeofday(&timeNow, 0);
|
||||
ts->Sec = timeNow.tv_sec;
|
||||
ts->Usec = timeNow.tv_usec;
|
||||
}
|
||||
13
test/scr031/src/htimestampxa.h
Normal file
13
test/scr031/src/htimestampxa.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#ifndef HTIMESTAMPXA_H
|
||||
#define HTIMESTAMPXA_H
|
||||
|
||||
/*
|
||||
* Timestamp with microseconds precision
|
||||
*/
|
||||
typedef struct __HTimestampData {
|
||||
time_t Sec;
|
||||
time_t Usec;
|
||||
} HTimestampData;
|
||||
|
||||
void GetTime(HTimestampData *);
|
||||
#endif
|
||||
287
test/scr031/src/server.c
Normal file
287
test/scr031/src/server.c
Normal file
@@ -0,0 +1,287 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <atmi.h>
|
||||
#include <fml1632.h>
|
||||
#include <fml32.h>
|
||||
#include <tx.h>
|
||||
#include <xa.h>
|
||||
|
||||
#include <db.h>
|
||||
|
||||
#include "datafml.h"
|
||||
#include "hdbrec.h"
|
||||
#include "hcommonxa.h"
|
||||
#include "htimestampxa.h"
|
||||
|
||||
/*
|
||||
* The two servers are largely identical, #ifdef the source code.
|
||||
*/
|
||||
#ifdef SERVER1
|
||||
#define TXN_FUNC TestTxn1
|
||||
#define TXN_STRING "TestTxn1"
|
||||
#endif
|
||||
#ifdef SERVER2
|
||||
#define TXN_FUNC TestTxn2
|
||||
#define TXN_STRING "TestTxn2"
|
||||
#endif
|
||||
void TXN_FUNC(TPSVCINFO *);
|
||||
|
||||
#define HOME "../data"
|
||||
#define TABLE1 "table1.db"
|
||||
#define TABLE2 "table2.db"
|
||||
|
||||
#ifdef VERBOSE
|
||||
static int verbose = 1; /* Debugging output. */
|
||||
#else
|
||||
static int verbose = 0;
|
||||
#endif
|
||||
|
||||
DB *db1, *db2; /* Table handles. */
|
||||
|
||||
int cnt_forward; /* Forwarded requests. */
|
||||
int cnt_request; /* Total requests. */
|
||||
|
||||
char *progname; /* Server run-time name. */
|
||||
|
||||
char *db_buf(DBT *);
|
||||
|
||||
int
|
||||
tpsvrinit(int argc, char* argv[])
|
||||
{
|
||||
DB_ENV *dbenv;
|
||||
int ret;
|
||||
|
||||
progname = argv[0];
|
||||
if (verbose)
|
||||
printf("%s: called\n", progname);
|
||||
|
||||
/*
|
||||
* This is all Berkeley DB specific.
|
||||
*
|
||||
* Open the environment and clear tables #1 and #2. We do this with
|
||||
* our own DB_ENV handle -- Berkeley DB doesn't require servers know
|
||||
* where the database environment is, but it's pretty much necessary
|
||||
* if you want to do anything tricky.
|
||||
*/
|
||||
if ((ret = db_env_create(&dbenv, 0)) != 0) {
|
||||
fprintf(stderr, "db_env_create: %s\n", db_strerror(ret));
|
||||
return (-1);
|
||||
}
|
||||
if ((ret = dbenv->open(dbenv, HOME, DB_JOINENV, 0)) != 0) {
|
||||
fprintf(stderr,
|
||||
"DB_ENV->open: %s: %s\n", HOME, db_strerror(ret));
|
||||
return (-1);
|
||||
}
|
||||
if ((ret = db_create(&db1, dbenv, 0)) != 0) {
|
||||
fprintf(stderr, "db_create: %s\n", db_strerror(ret));
|
||||
return (-1);
|
||||
}
|
||||
db1->set_errfile(db1, stderr);
|
||||
if ((ret = db1->open(db1, NULL,
|
||||
TABLE1, NULL, DB_BTREE, DB_AUTO_COMMIT | DB_CREATE, 0660)) != 0 ||
|
||||
(ret = db1->truncate(db1, NULL, NULL, 0)) != 0) {
|
||||
fprintf(stderr,
|
||||
"DB open/truncate: %s: %s\n", TABLE1, db_strerror(ret));
|
||||
return (-1);
|
||||
}
|
||||
if ((ret = db_create(&db2, dbenv, 0)) != 0) {
|
||||
fprintf(stderr, "db_create: %s\n", db_strerror(ret));
|
||||
return (-1);
|
||||
}
|
||||
db2->set_errfile(db2, stderr);
|
||||
if ((ret = db2->open(db2, NULL,
|
||||
TABLE2, NULL, DB_BTREE, DB_AUTO_COMMIT | DB_CREATE, 0660)) != 0 ||
|
||||
(ret = db2->truncate(db2, NULL, NULL, 0)) != 0) {
|
||||
fprintf(stderr,
|
||||
"DB open/truncate: %s: %s\n", TABLE2, db_strerror(ret));
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* We're done -- discard our handles. */
|
||||
if ((ret = db1->close(db1, 0)) != 0) {
|
||||
fprintf(stderr,
|
||||
"DB->close: %s: %s\n", TABLE1, db_strerror(ret));
|
||||
return (-1);
|
||||
}
|
||||
if ((ret = db2->close(db2, 0)) != 0) {
|
||||
fprintf(stderr,
|
||||
"DB->close: %s: %s\n", TABLE2, db_strerror(ret));
|
||||
return (-1);
|
||||
}
|
||||
if ((ret = dbenv->close(dbenv, 0)) != 0) {
|
||||
fprintf(stderr,
|
||||
"DB_ENV->close: %s: %s\n", HOME, db_strerror(ret));
|
||||
return (-1);
|
||||
}
|
||||
/* End Berkeley DB specific setup. */
|
||||
|
||||
/* Open resource managers. */
|
||||
if (tx_open() == TX_ERROR) {
|
||||
fprintf(stderr, "tx_open: TX_ERROR\n");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Seed random number generator. */
|
||||
srand((u_int)(time(NULL) | getpid()));
|
||||
|
||||
/* Open permanent XA handles. */
|
||||
if ((ret = db_create(&db1, NULL, DB_XA_CREATE)) != 0) {
|
||||
fprintf(stderr, "db_create: %s\n", db_strerror(ret));
|
||||
return (-1);
|
||||
}
|
||||
db1->set_errfile(db1, stderr);
|
||||
if ((ret = db1->open(db1, NULL,
|
||||
TABLE1, NULL, DB_BTREE, DB_AUTO_COMMIT | DB_CREATE, 0660)) != 0) {
|
||||
fprintf(stderr, "DB open: %s: %s\n", TABLE1, db_strerror(ret));
|
||||
return (-1);
|
||||
}
|
||||
if ((ret = db_create(&db2, NULL, DB_XA_CREATE)) != 0) {
|
||||
fprintf(stderr, "db_create: %s\n", db_strerror(ret));
|
||||
return (-1);
|
||||
}
|
||||
db2->set_errfile(db2, stderr);
|
||||
if ((ret = db2->open(db2, NULL,
|
||||
TABLE2, NULL, DB_BTREE, DB_AUTO_COMMIT | DB_CREATE, 0660)) != 0) {
|
||||
fprintf(stderr, "DB open: %s: %s\n", TABLE2, db_strerror(ret));
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
printf("%s: tpsvrinit: initialization done\n", progname);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
tpsvrdone()
|
||||
{
|
||||
if (db1 != NULL)
|
||||
(void)db1->close(db1, 0);
|
||||
if (db2 != NULL)
|
||||
(void)db2->close(db2, 0);
|
||||
|
||||
tx_close();
|
||||
|
||||
if (verbose)
|
||||
printf("%s: tpsvrdone: shutdown done\n", progname);
|
||||
|
||||
printf("%s: %d requests, %d requests forwarded to the other server\n",
|
||||
progname, cnt_request, cnt_forward);
|
||||
}
|
||||
|
||||
void
|
||||
TXN_FUNC(TPSVCINFO *msg)
|
||||
{
|
||||
DBT data;
|
||||
DBT key;
|
||||
FBFR *replyBuf;
|
||||
HDbRec rcrd;
|
||||
long replyLen, seqNo;
|
||||
int ret;
|
||||
|
||||
++cnt_request;
|
||||
|
||||
#ifdef SERVER1
|
||||
/*
|
||||
* Test that servers can forward to other servers. Randomly forward
|
||||
* half of server #1's requests to server #2.
|
||||
*/
|
||||
if (rand() % 2 > 0) {
|
||||
++cnt_forward;
|
||||
|
||||
replyLen = 1024;
|
||||
if ((replyBuf =
|
||||
(FBFR*)tpalloc("FML32", NULL, replyLen)) == NULL ||
|
||||
tpcall("TestTxn2", msg->data,
|
||||
0, (char**)&replyBuf, &replyLen, TPSIGRSTRT) == -1) {
|
||||
fprintf(stderr, "%s: TUXEDO ERROR: %s (code %d)\n",
|
||||
progname, tpstrerror(tperrno), tperrno);
|
||||
tpfree((char*)replyBuf);
|
||||
tpreturn(TPFAIL, 0L, 0, 0L, 0);
|
||||
} else {
|
||||
tpfree((char*)replyBuf);
|
||||
tpreturn(TPSUCCESS, tpurcode, 0, 0L, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
/* Read the record. */
|
||||
if (Fget((FBFR*)msg->data, SEQ_NO, 0, (char *)&rcrd.SeqNo, 0) == -1)
|
||||
goto fml_err;
|
||||
if (Fget((FBFR*)msg->data, TS_SEC, 0, (char *)&rcrd.Ts.Sec, 0) == -1)
|
||||
goto fml_err;
|
||||
if (Fget(
|
||||
(FBFR*)msg->data, TS_USEC, 0, (char *)&rcrd.Ts.Usec, 0) == -1) {
|
||||
fml_err: fprintf(stderr, "%s: FML ERROR: %s (code %d)\n",
|
||||
progname, Fstrerror(Ferror), Ferror);
|
||||
goto err;
|
||||
}
|
||||
|
||||
seqNo = rcrd.SeqNo; /* Update the record. */
|
||||
memset(&key, 0, sizeof(key));
|
||||
key.data = &seqNo;
|
||||
key.size = sizeof(seqNo);
|
||||
memset(&data, 0, sizeof(data));
|
||||
data.data = &rcrd;
|
||||
data.size = sizeof(rcrd);
|
||||
|
||||
strcpy(rcrd.Msg, "Table1"); /* Table 1. */
|
||||
if (verbose) {
|
||||
printf("put1: key: %s\n", db_buf(&key));
|
||||
printf("put1: data: %s\n", db_buf(&data));
|
||||
}
|
||||
if ((ret = db1->put(db1, NULL, &key, &data, 0)) != 0) {
|
||||
fprintf(stderr, "%s: %s: Table1->put: %s\n",
|
||||
progname, TXN_STRING, db_strerror(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
strcpy(rcrd.Msg, "Table2"); /* Table 2. */
|
||||
if ((ret = db2->put(db2, NULL, &key, &data, 0)) != 0) {
|
||||
fprintf(stderr, "%s: %s: Table2->put: %s\n",
|
||||
progname, TXN_STRING, db_strerror(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decide if the client is going to commit the global transaction or
|
||||
* not, testing the return-value path back to the client; this is the
|
||||
* path we'd use to resolve deadlock, for example. Commit 80% of the
|
||||
* time. Returning 0 causes the client to commit, 1 to abort.
|
||||
*/
|
||||
if (rand() % 10 > 7) {
|
||||
if (verbose)
|
||||
printf("%s: %s: commit\n", progname, TXN_STRING);
|
||||
tpreturn(TPSUCCESS, 0L, 0, 0L, 0);
|
||||
} else {
|
||||
if (verbose)
|
||||
printf("%s: %s: abort\n", progname, TXN_STRING);
|
||||
tpreturn(TPSUCCESS, 1L, 0, 0L, 0);
|
||||
}
|
||||
return;
|
||||
|
||||
err: tpreturn(TPFAIL, 1L, 0, 0L, 0);
|
||||
}
|
||||
|
||||
char *
|
||||
db_buf(dbt)
|
||||
DBT *dbt;
|
||||
{
|
||||
static u_char buf[1024];
|
||||
size_t len;
|
||||
u_char *p, *b;
|
||||
|
||||
for (p = dbt->data, len = dbt->size, b = buf; len > 0; ++p, --len)
|
||||
if (isprint(*p))
|
||||
b += sprintf((char *)b, "%c", *p);
|
||||
else
|
||||
b += sprintf((char *)b, "%#o", *p);
|
||||
return ((char *)buf);
|
||||
}
|
||||
Reference in New Issue
Block a user