summaryrefslogtreecommitdiff
path: root/db/test/scr031/src/server.c
diff options
context:
space:
mode:
Diffstat (limited to 'db/test/scr031/src/server.c')
-rw-r--r--db/test/scr031/src/server.c287
1 files changed, 287 insertions, 0 deletions
diff --git a/db/test/scr031/src/server.c b/db/test/scr031/src/server.c
new file mode 100644
index 000000000..4353ee926
--- /dev/null
+++ b/db/test/scr031/src/server.c
@@ -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);
+}