1#include <sys/types.h>
2#include <sys/time.h>
3
4#include <ctype.h>
5#include <stdio.h>
6#include <stdlib.h>
7#include <string.h>
8#include <unistd.h>
9
10#include <tx.h>
11#include <atmi.h>
12#include <fml32.h>
13#include <fml1632.h>
14
15#include <db.h>
16
17#include "datafml.h"
18#include "hdbrec.h"
19#include "hcommonxa.h"
20#include "htimestampxa.h"
21
22#define	HOME	"../data"
23#define	TABLE1	"../data/table1.db"
24#define	TABLE3	"../data/table3.db"
25
26#ifdef VERBOSE
27static int verbose = 1;				/* Debugging output. */
28#else
29static int verbose = 0;
30#endif
31
32DB_ENV *dbenv;
33char *progname;					/* Client run-time name. */
34
35int   check_data(DB *);
36char *db_buf(DBT *);
37int   usage(void);
38
39int
40main(int argc, char* argv[])
41{
42	DB *dbp3;
43	DBT key, data;
44	FBFR *buf, *replyBuf;
45	HDbRec rec;
46	TPINIT *initBuf;
47	long len, replyLen, seqNo;
48	int ch, cnt, cnt_abort, cnt_commit, cnt_server1, i, ret;
49	char *target;
50
51	progname = argv[0];
52
53	dbp3 = NULL;
54	buf = replyBuf = NULL;
55	initBuf = NULL;
56	cnt = 1000;
57	cnt_abort = cnt_commit = cnt_server1 = 0;
58
59	while ((ch = getopt(argc, argv, "n:v")) != EOF)
60		switch (ch) {
61		case 'n':
62			cnt = atoi(optarg);
63			break;
64		case 'v':
65			verbose = 1;
66			break;
67		case '?':
68		default:
69			return (usage());
70		}
71	argc -= optind;
72	argv += optind;
73
74	if (verbose)
75		printf("%s: called\n", progname);
76
77	/* Seed random number generator. */
78	srand((u_int)(time(NULL) | getpid()));
79
80	if (tpinit((TPINIT *)NULL) == -1)
81		goto tuxedo_err;
82	if (verbose)
83		printf("%s: tpinit() OK\n", progname);
84
85	/* Allocate init buffer */
86	if ((initBuf = (TPINIT *)tpalloc("TPINIT", NULL, TPINITNEED(0))) == 0)
87		goto tuxedo_err;
88	if (verbose)
89		printf("%s: tpalloc(\"TPINIT\") OK\n", progname);
90
91	/* Join the DB environment. */
92	if ((ret = db_env_create(&dbenv, 0)) != 0 ||
93	    (ret = dbenv->open(dbenv, HOME, DB_JOINENV, 0)) != 0) {
94		fprintf(stderr,
95		    "%s: %s: %s\n", progname, HOME, db_strerror(ret));
96		goto err;
97	}
98	dbenv->set_errfile(dbenv, stderr);
99	if (verbose)
100		printf("%s: opened %s OK\n", progname, HOME);
101
102	/* Open table #3 -- truncate it for each new run. */
103	if ((ret = db_create(&dbp3, dbenv, 0)) != 0 ||
104	    (ret = dbp3->open(dbp3,
105	    NULL, TABLE3, NULL, DB_BTREE, DB_CREATE, 0660)) != 0) {
106		fprintf(stderr,
107		    "%s: %s %s\n", progname, TABLE3, db_strerror(ret));
108		goto err;
109	}
110	if (verbose)
111		printf("%s: opened/truncated %s OK\n", progname, TABLE3);
112
113	/* Allocate send buffer. */
114	len = Fneeded(1, 3 * sizeof(long));
115	if ((buf = (FBFR*)tpalloc("FML32", NULL, len)) == 0)
116		goto tuxedo_err;
117	if (verbose)
118		printf("%s: tpalloc(\"FML32\"), send buffer OK\n", progname);
119
120	/* Allocate reply buffer. */
121	replyLen = 1024;
122	if ((replyBuf = (FBFR*)tpalloc("FML32", NULL, replyLen)) == NULL)
123		goto tuxedo_err;
124	if (verbose)
125		printf("%s: tpalloc(\"FML32\"), reply buffer OK\n", progname);
126
127	memset(&key, 0, sizeof(key));
128	memset(&data, 0, sizeof(data));
129	for (rec.SeqNo = 1, i = 0; i < cnt; ++i, ++rec.SeqNo) {
130		GetTime(&rec.Ts);
131
132		if (Fchg(buf, SEQ_NO, 0, (char *)&rec.SeqNo, 0) == -1)
133			goto tuxedo_fml_err;
134		if (verbose)
135			printf("%s: Fchg(), sequence number OK\n", progname);
136		if (Fchg(buf, TS_SEC, 0, (char *)&rec.Ts.Sec, 0) == -1)
137			goto tuxedo_fml_err;
138		if (verbose)
139			printf("%s: Fchg(), seconds OK\n", progname);
140		if (Fchg(buf, TS_USEC, 0, (char *)&rec.Ts.Usec, 0) == -1)
141			goto tuxedo_fml_err;
142		if (verbose)
143			printf("%s: Fchg(), microseconds OK\n", progname);
144
145		if (tpbegin(60L, 0L) == -1)
146			goto tuxedo_err;
147		if (verbose)
148			printf("%s: tpbegin() OK\n", progname);
149
150		/* Randomly send half of our requests to each server. */
151		if (rand() % 2 > 0) {
152			++cnt_server1;
153			target = "TestTxn1";
154		} else
155			target = "TestTxn2";
156		if (tpcall(target, (char *)buf,
157		    0L, (char **)&replyBuf, &replyLen, TPSIGRSTRT) == -1)
158			goto tuxedo_err;
159
160		/* Commit for a return value of 0, otherwise abort. */
161		if (tpurcode == 0) {
162			++cnt_commit;
163			if (verbose)
164				printf("%s: txn success\n", progname);
165
166			if (tpcommit(0L) == -1)
167				goto tuxedo_err;
168			if (verbose)
169				printf("%s: tpcommit() OK\n", progname);
170
171			/*
172			 * Store a copy of the key/data pair into table #3
173			 * on success, we'll compare table #1 and table #3
174			 * after the run finishes.
175			 */
176			seqNo = rec.SeqNo;
177			key.data = &seqNo;
178			key.size = sizeof(seqNo);
179			data.data = &rec;
180			data.size = sizeof(rec);
181			if ((ret =
182			    dbp3->put(dbp3, NULL, &key, &data, 0)) != 0) {
183				fprintf(stderr, "%s: DB->put: %s %s\n",
184				    progname, TABLE3, db_strerror(ret));
185				goto err;
186			}
187		} else {
188			++cnt_abort;
189			if (verbose)
190				printf("%s: txn failure\n", progname);
191
192			if (tpabort(0L) == -1)
193				goto tuxedo_err;
194			if (verbose)
195				printf("%s: tpabort() OK\n", progname);
196		}
197	}
198
199	printf("%s: %d requests: %d committed, %d aborted\n",
200	    progname, cnt, cnt_commit, cnt_abort);
201	printf("%s: %d sent to server #1, %d sent to server #2\n",
202	    progname, cnt_server1, cnt - cnt_server1);
203
204	ret = check_data(dbp3);
205
206	if (0) {
207tuxedo_err:	fprintf(stderr, "%s: TUXEDO ERROR: %s (code %d)\n",
208		    progname, tpstrerror(tperrno), tperrno);
209		goto err;
210	}
211	if (0) {
212tuxedo_fml_err:	fprintf(stderr, "%s: FML ERROR: %s (code %d)\n",
213		    progname, Fstrerror(Ferror), Ferror);
214	}
215	if (0) {
216err:		ret = EXIT_FAILURE;
217	}
218
219	if (replyBuf != NULL)
220		tpfree((char *)replyBuf);
221	if (buf != NULL)
222		tpfree((char *)buf);
223	if (initBuf != NULL)
224		tpfree((char *)initBuf);
225	if (dbp3 != NULL)
226		(void)dbp3->close(dbp3, 0);
227	if (dbenv != NULL)
228		(void)dbenv->close(dbenv, 0);
229
230	tpterm();
231	if (verbose)
232		printf("%s: tpterm() OK\n", progname);
233
234	return (ret);
235}
236
237/*
238 * check_data --
239 *	Compare committed data with our local copy, stored in table3.
240 */
241int
242check_data(dbp3)
243	DB *dbp3;
244{
245	DB *dbp1;
246	DBC *dbc1, *dbc3;
247	DBT key1, data1, key3, data3;
248	int ret, ret1, ret3;
249
250	dbp1 = NULL;
251	dbc1 = dbc3 = NULL;
252
253	/* Open table #1. */
254	if ((ret = db_create(&dbp1, dbenv, 0)) != 0 ||
255	    (ret = dbp1->open(
256	    dbp1, NULL, TABLE1, NULL, DB_UNKNOWN, DB_RDONLY, 0)) != 0) {
257		fprintf(stderr,
258		    "%s: %s: %s\n", progname, TABLE1, db_strerror(ret));
259		goto err;
260	}
261	if (verbose)
262		printf("%s: opened %s OK\n", progname, TABLE1);
263
264	/* Open cursors. */
265	if ((ret = dbp1->cursor(dbp1, NULL, &dbc1, 0)) != 0 ||
266	    (ret = dbp3->cursor(dbp3, NULL, &dbc3, 0)) != 0) {
267		fprintf(stderr,
268		    "%s: DB->cursor: %s\n", progname, db_strerror(ret));
269		goto err;
270	}
271	if (verbose)
272		printf("%s: opened cursors OK\n", progname);
273
274	/* Compare the two databases. */
275	memset(&key1, 0, sizeof(key1));
276	memset(&data1, 0, sizeof(data1));
277	memset(&key3, 0, sizeof(key3));
278	memset(&data3, 0, sizeof(data3));
279	for (;;) {
280		ret1 = dbc1->c_get(dbc1, &key1, &data1, DB_NEXT);
281		ret3 = dbc3->c_get(dbc3, &key3, &data3, DB_NEXT);
282		if (verbose) {
283			printf("get: key1: %s\n", db_buf(&key1));
284			printf("get: key3: %s\n", db_buf(&key3));
285			printf("get: data1: %s\n", db_buf(&data1));
286			printf("get: data3: %s\n", db_buf(&data3));
287		}
288		if (ret1 != 0 || ret3 != 0)
289			break;
290		/*
291		 * Only compare the first N bytes, the saved message chunks
292		 * are different.
293		 */
294		if (key1.size != key3.size ||
295		    memcmp(key1.data, key3.data, key1.size) != 0 ||
296		    data1.size != data3.size ||
297		    memcmp(data1.data, data3.data,
298		    sizeof(long) + sizeof(HTimestampData)) != 0)
299			goto mismatch;
300	}
301	if (ret1 != DB_NOTFOUND || ret3 != DB_NOTFOUND) {
302mismatch:	fprintf(stderr,
303		    "%s: DB_ERROR: databases 1 and 3 weren't identical\n",
304		    progname);
305		ret = 1;
306	}
307
308err:	if (dbc1 != NULL)
309		(void)dbc1->c_close(dbc1);
310	if (dbc3 != NULL)
311		(void)dbc3->c_close(dbc3);
312	if (dbp1 != NULL)
313		(void)dbp1->close(dbp1, 0);
314
315	return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
316}
317
318char *
319db_buf(dbt)
320	DBT *dbt;
321{
322	static u_char buf[1024];
323	size_t len;
324	u_char *p, *b;
325
326	for (p = dbt->data, len = dbt->size, b = buf; len > 0; ++p, --len)
327		if (isprint(*p))
328			b += sprintf((char *)b, "%c", *p);
329		else
330			b += sprintf((char *)b, "%#o", *p);
331	return ((char *)buf);
332}
333
334int
335usage()
336{
337	fprintf(stderr, "usage: %s [-v] [-n txn]\n", progname);
338	return (EXIT_FAILURE);
339}
340