1 /*-
2 * Copyright (c) 2011, 2020 Oracle and/or its affiliates. All rights reserved.
3 *
4 * See the file LICENSE for license information.
5 */
6
7 /*
8 * Basic smoke test for XA transactions. The client randomly sends requests
9 * to each of the servers to insert data into table 1, and inserts the
10 * same data into table 2 using regular transactions.
11 */
12
13 #include <sys/types.h>
14 #include <sys/time.h>
15
16 #include <ctype.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21
22 #include <tx.h>
23 #include <atmi.h>
24 #include <fml32.h>
25 #include <fml1632.h>
26
27 #include <db.h>
28
29 #include "datafml.h"
30 #include "hdbrec.h"
31 #include "htimestampxa.h"
32 #include "../utilities/bdb_xa_util.h"
33
34 #define HOME "../data2"
35 #define TABLE1 "../data/table1.db"
36 #define TABLE2 "../data2/table2.db"
37
38 char *progname; /* Client run-time name. */
39
40 int usage(void);
41
42 int
main(int argc,char * argv[])43 main(int argc, char* argv[])
44 {
45 DB *dbp2;
46 DBT key, data;
47 FBFR *buf, *replyBuf;
48 HDbRec rec;
49 TPINIT *initBuf;
50 DB_ENV *dbenv2, *dbenv1;
51 long len, replyLen, seqNo;
52 int ch, cnt, cnt_abort, cnt_commit, cnt_server1, i, ret;
53 char *target;
54 char *home = HOME;
55 u_int32_t flags = DB_INIT_MPOOL | DB_INIT_LOG | DB_INIT_TXN |
56 DB_INIT_LOCK | DB_CREATE | DB_RECOVER | DB_REGISTER;
57 u_int32_t dbflags = DB_CREATE;
58
59 progname = argv[0];
60
61 dbenv2 = dbenv1 = NULL;
62 dbp2 = NULL;
63 buf = replyBuf = NULL;
64 initBuf = NULL;
65 cnt = 1000;
66 cnt_abort = cnt_commit = cnt_server1 = 0;
67
68 while ((ch = getopt(argc, argv, "n:v")) != EOF)
69 switch (ch) {
70 case 'n':
71 cnt = atoi(optarg);
72 break;
73 case 'v':
74 verbose = 1;
75 break;
76 case '?':
77 default:
78 return (usage());
79 }
80 argc -= optind;
81 argv += optind;
82
83 if (verbose)
84 printf("%s: called\n", progname);
85
86 /* Seed random number generator. */
87 srand((u_int)(time(NULL) | getpid()));
88
89 if (tpinit((TPINIT *)NULL) == -1)
90 goto tuxedo_err;
91 if (verbose)
92 printf("%s: tpinit() OK\n", progname);
93
94 /* Allocate init buffer */
95 if ((initBuf = (TPINIT *)tpalloc("TPINIT", NULL, TPINITNEED(0))) == 0)
96 goto tuxedo_err;
97 if (verbose)
98 printf("%s: tpalloc(\"TPINIT\") OK\n", progname);
99
100 /* Create the DB environment. */
101 if ((ret = db_env_create(&dbenv2, 0)) != 0 ||
102 (ret = dbenv2->open(dbenv2, home, flags, 0)) != 0) {
103 fprintf(stderr,
104 "%s: %s: %s\n", progname, home, db_strerror(ret));
105 goto err;
106 }
107 dbenv2->set_errfile(dbenv2, stderr);
108 if (verbose)
109 printf("%s: opened %s OK\n", progname, home);
110
111 /*
112 * Open table #2 -- Data is inserted into table 1 using XA
113 * transactions, and inserted into table 2 using regular transactions.
114 */
115 if ((ret = db_create(&dbp2, dbenv2, 0)) != 0 ||
116 (ret = dbp2->open(dbp2,
117 NULL, TABLE2, NULL, DB_BTREE, dbflags, 0660)) != 0) {
118 fprintf(stderr,
119 "%s: %s %s\n", progname, TABLE2, db_strerror(ret));
120 goto err;
121 }
122 if (verbose)
123 printf("%s: opened %s OK\n", progname, TABLE2);
124
125 /* Allocate send buffer. */
126 len = Fneeded(1, 3 * sizeof(long));
127 if ((buf = (FBFR*)tpalloc("FML32", NULL, len)) == 0)
128 goto tuxedo_err;
129 if (verbose)
130 printf("%s: tpalloc(\"FML32\"), send buffer OK\n", progname);
131
132 /* Allocate reply buffer. */
133 replyLen = 1024;
134 if ((replyBuf = (FBFR*)tpalloc("FML32", NULL, replyLen)) == NULL)
135 goto tuxedo_err;
136 if (verbose)
137 printf("%s: tpalloc(\"FML32\"), reply buffer OK\n", progname);
138
139 memset(&key, 0, sizeof(key));
140 memset(&data, 0, sizeof(data));
141 for (rec.SeqNo = 1, i = 0; i < cnt; ++i, ++rec.SeqNo) {
142 GetTime(&rec.Ts);
143
144 if (Fchg(buf, SEQ_NO, 0, (char *)&rec.SeqNo, 0) == -1)
145 goto tuxedo_fml_err;
146 if (verbose)
147 printf("%s: Fchg(), sequence number OK\n", progname);
148 if (Fchg(buf, TS_SEC, 0, (char *)&rec.Ts.Sec, 0) == -1)
149 goto tuxedo_fml_err;
150 if (verbose)
151 printf("%s: Fchg(), seconds OK\n", progname);
152 if (Fchg(buf, TS_USEC, 0, (char *)&rec.Ts.Usec, 0) == -1)
153 goto tuxedo_fml_err;
154 if (verbose)
155 printf("%s: Fchg(), microseconds OK\n", progname);
156
157 if (tpbegin(60L, 0L) == -1)
158 goto tuxedo_err;
159 if (verbose)
160 printf("%s: tpbegin() OK\n", progname);
161
162 /* Randomly send half of our requests to each server. */
163 if (rand() % 2 > 0) {
164 ++cnt_server1;
165 target = "TestTxn1";
166 } else
167 target = "TestTxn2";
168 if (tpcall(target, (char *)buf,
169 0L, (char **)&replyBuf, &replyLen, TPSIGRSTRT) == -1)
170 goto tuxedo_err;
171 /* Commit for a return value of 0, otherwise abort. */
172 if (tpurcode == 0) {
173 ++cnt_commit;
174 if (verbose)
175 printf("%s: txn success\n", progname);
176
177 if (tpcommit(0L) == -1)
178 goto abort;
179 if (verbose)
180 printf("%s: tpcommit() OK\n", progname);
181
182 /*
183 * Store a copy of the key/data pair into table #2
184 * on success, we'll compare table #1 and table #2
185 * after the run finishes.
186 */
187 seqNo = rec.SeqNo;
188 key.data = &seqNo;
189 key.size = sizeof(seqNo);
190 data.data = &seqNo;
191 data.size = sizeof(seqNo);
192 if ((ret =
193 dbp2->put(dbp2, NULL, &key, &data, 0)) != 0) {
194 fprintf(stderr, "%s: DB->put: %s %s\n",
195 progname, TABLE2, db_strerror(ret));
196 goto err;
197 }
198 } else {
199 abort: ++cnt_abort;
200 if (verbose)
201 printf("%s: txn failure\n", progname);
202
203 if (tpabort(0L) == -1)
204 goto tuxedo_err;
205 if (verbose)
206 printf("%s: tpabort() OK\n", progname);
207 }
208 }
209
210 printf("%s: %d requests: %d committed, %d aborted\n",
211 progname, cnt, cnt_commit, cnt_abort);
212 printf("%s: %d sent to server #1, %d sent to server #2\n",
213 progname, cnt_server1, cnt - cnt_server1);
214
215 /* Check that database 1 and database 2 are identical. */
216 if (dbp2 != NULL)
217 (void)dbp2->close(dbp2, 0);
218 dbp2 = NULL;
219 if ((ret = db_env_create(&dbenv1, 0)) != 0 ||
220 (ret = dbenv1->open(dbenv1, "../data", flags, 0)) != 0)
221 goto err;
222 ret = check_data(dbenv1, TABLE1, dbenv2, TABLE2, progname);
223
224 if (0) {
225 tuxedo_err: fprintf(stderr, "%s: TUXEDO ERROR: %s (code %d)\n",
226 progname, tpstrerror(tperrno), tperrno);
227 goto err;
228 }
229 if (0) {
230 tuxedo_fml_err: fprintf(stderr, "%s: FML ERROR: %s (code %d)\n",
231 progname, Fstrerror(Ferror), Ferror);
232 }
233 if (0) {
234 err: ret = EXIT_FAILURE;
235 }
236
237 if (replyBuf != NULL)
238 tpfree((char *)replyBuf);
239 if (buf != NULL)
240 tpfree((char *)buf);
241 if (initBuf != NULL)
242 tpfree((char *)initBuf);
243 if (dbp2 != NULL)
244 (void)dbp2->close(dbp2, 0);
245 if (dbenv1 != NULL)
246 (void)dbenv1->close(dbenv1, 0);
247 if (dbenv2 != NULL)
248 (void)dbenv2->close(dbenv2, 0);
249
250 tpterm();
251 if (verbose)
252 printf("%s: tpterm() OK\n", progname);
253
254 return (ret);
255 }
256
257 int
usage()258 usage()
259 {
260 fprintf(stderr, "usage: %s [-v] [-n txn]\n", progname);
261 return (EXIT_FAILURE);
262 }
263