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  * This is the MVCC test for XA.  It runs 3 tests, which are as follows:
9  * 1. No MVCC
10  * 2. MVCC enabled by DB_CONFIG
11  * 3. MVCC enabled by flags
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 "../utilities/bdb_xa_util.h"
30 
31 #define	HOME	"../data"
32 #define	TABLE1	"../data/table1.db"
33 #define	TABLE2	"../data/table2.db"
34 #define NUM_CLIENTS 2
35 #define NUM_TESTS 4
36 #define TIMEOUT 60
37 
38 static int error = 1;
39 
40 char *progname;					/* Client run-time name. */
41 
42 int
usage()43 usage()
44 {
45 	fprintf(stderr, "usage: %s [-v] -t[0|1|2] -n [name]\n", progname);
46 	return (EXIT_FAILURE);
47 }
48 
49 enum test_type{NO_MVCC, MVCC_DBCONFIG, MVCC_FLAG};
50 
51 void init_tests(char *ops[], int success[], int type, int client_num);
52 
53 /*
54  *
55  */
call_server(char * client_name,int ttype)56 int call_server(char *client_name, int ttype)
57 {
58 	char *ops[NUM_TESTS];
59 	int commit, j, success[NUM_TESTS], client_num, ret;
60 	TPINIT *initBuf = NULL;
61 	FBFR *replyBuf = NULL;
62 	long replyLen = 0;
63 
64 	client_num = atoi(client_name);
65 	init_tests(ops, success, ttype, client_num);
66 
67 	if (verbose)
68 		printf("%s:%s: starting client %i\n", progname, client_name,
69 		    client_num);
70 
71 	/* Allocate init buffer */
72 	if ((initBuf = (TPINIT *)tpalloc("TPINIT", NULL, TPINITNEED(0))) == 0)
73 		goto tuxedo_err;
74 
75 	if (tpinit(initBuf) == -1)
76 		goto tuxedo_err;
77 	if (verbose)
78 		printf("%s:%s: tpinit() OK\n", progname, client_name);
79 
80 	/* Allocate reply buffer. */
81 	replyLen = 1024;
82 	if ((replyBuf = (FBFR*)tpalloc("FML32", NULL, replyLen)) == NULL)
83 		goto tuxedo_err;
84 	if (verbose)
85 		printf("%s:%s: tpalloc(\"FML32\"), reply buffer OK\n",
86 		    progname, client_name);
87 
88 	for (j = 0; j < NUM_TESTS; j++) {
89 		commit = 1;
90 
91 		/* Sync Apps. */
92 		if ((ret = sync_clients(client_num, NUM_CLIENTS, 1, j)) != 0) {
93 			fprintf(stderr,
94 			    "%s:%s: Error syncing clients: %i \n",
95 			    progname, client_name, ret);
96 			goto end;
97 		}
98 
99 		/* Begin the XA transaction. */
100 		if (tpbegin(TIMEOUT, 0L) == -1)
101 			goto tuxedo_err;
102 		if (verbose)
103 			printf("%s:%s: tpbegin() OK\n", progname, client_name);
104 
105 		/* Force client 2 to wait till client 1 does its operation.*/
106 		if (client_num == 2) {
107 		  if ((ret = sync_clients(client_num, NUM_CLIENTS, 2, j)) != 0) {
108 				fprintf(stderr,
109 				    "%s:%s: Error syncing client 1: %i \n",
110 				    progname, client_name, ret);
111 				goto end;
112 			}
113 		}
114 		if (verbose)
115 			printf("%s:%s: calling server %s\n", progname,
116 			    client_name, ops[j]);
117 
118 		/* Read or insert into the database. */
119 		if (tpcall(ops[j], NULL, 0L, (char **)&replyBuf,
120 		    &replyLen, 0) == -1)
121 			goto tuxedo_err;
122 
123 		/* Wake up client 2.*/
124 		if (client_num == 1) {
125 		  if ((ret = sync_clients(client_num, NUM_CLIENTS, 2, j)) != 0) {
126 				fprintf(stderr,
127 				    "%s:%s: Error syncing client 1: %i \n",
128 				    progname, client_name, ret);
129 				goto end;
130 			}
131 		}
132 
133 		/* Sync both clients. */
134 		if ((ret = sync_clients(client_num, NUM_CLIENTS, 3, j)) != 0) {
135 			fprintf(stderr,
136 			    "%s:%s: Error syncing clients: %i \n",
137 			    progname, client_name, ret);
138 			goto end;
139 		}
140 
141 		/*
142 		 * Commit or abort the transaction depending the what the
143 		 * server returns. Check that it matched expectation
144 		 * (We abort on LOCK_NOTGRANTED and DEADLOCK errors, and
145 		 * commit otherwise.  Other errors result in returning
146 		 * without committing or aborting.
147 		 */
148 		commit = !tpurcode;
149 		if (commit != success[j]) {
150 			fprintf(stderr,
151 			    "%s:%s: Expected: %i Got: %i.\n",
152 			    progname, client_name, success[j], commit);
153 			if (verbose) {
154 				printf("%s:%s: Expected: %i Got: %i.\n",
155 				    progname, client_name, success[j], commit);
156 			}
157 		}
158 
159 		if (commit) {
160 			if (tpcommit(0L) == -1)
161 				goto tuxedo_err;
162 			if (verbose) {
163 				printf("%s:%s: tpcommit() OK\n", progname,
164 				    client_name);
165 			}
166 		} else {
167 			if (tpabort(0L) == -1) {
168 				goto tuxedo_err;
169 			}
170 			if (verbose) {
171 				printf("%s:%s: tpabort() OK\n", progname,
172 				    client_name);
173 			}
174 		}
175 	}
176 
177 	if (0) {
178 tuxedo_err:	fprintf(stderr, "%s:%s: TUXEDO ERROR: %s (code %d)\n",
179 		    progname, client_name, tpstrerror(tperrno), tperrno);
180 		ret = -1;
181 	}
182 end:	tpterm();
183 	if (verbose)
184 		printf("%s:%s: tpterm() OK\n", progname, client_name);
185 
186 	if (initBuf != NULL)
187 		tpfree((char *)initBuf);
188 
189 	if (replyBuf != NULL)
190 		tpfree((char *)replyBuf);
191 
192 	return(ret);
193 }
194 
195 /*
196  * Call the servers, and check that data in the two
197  * databases is identical.
198  */
199 int
main(int argc,char * argv[])200 main(int argc, char* argv[])
201 {
202 	int ch, i, ret, ttype;
203 	char *name;
204 
205 	progname = argv[0];
206 	i = 1;
207 	verbose = 0;
208 
209 	while ((ch = getopt(argc, argv, "vt:n:")) != EOF) {
210 		switch (ch) {
211 		case 'n':
212 			name = argv[++i];
213 			break;
214 		case 't':
215 			ttype = atoi(argv[++i]);
216 			break;
217 		case 'v':
218 			verbose = 1;
219 			break;
220 		case '?':
221 		default:
222 			return (usage());
223 		}
224 		i++;
225 	}
226 
227 	if (ttype > 2 || ttype < 0)
228 		return (usage());
229 
230 	if (verbose)
231 		printf("%s: called with type %i\n", progname, ttype);
232 
233 	if (call_server(name, ttype) != 0)
234 		goto err;
235 
236 	if (0) {
237 err:		ret = EXIT_FAILURE;
238 	}
239 
240 	return (ret);
241 }
242 
243 static char *rdb1 = "read_db1";
244 static char *wdb1 = "write_db1";
245 
246 /*
247  *	    Operation		    Success
248  * client 1	client 2	no MVCC		MVCC
249  * write    	write		no		no
250  * write    	read		no		yes
251  * read		read		yes		yes
252  * read		write		no		yes
253  */
init_tests(char * ops[],int success[],int type,int client_num)254 void init_tests(char *ops[], int success[], int type, int client_num)
255 {
256 	if (client_num == 1) {
257 		ops[0] = wdb1;
258 		ops[1] = wdb1;
259 		ops[2] = rdb1;
260 		ops[3] = rdb1;
261 		/* client 1 is always successful. */
262 		success[0] = 1;
263 		success[1] = 1;
264 		success[2] = 1;
265 		success[3] = 1;
266 	} else {
267 		ops[0] = wdb1;
268 		ops[1] = rdb1;
269 		ops[2] = rdb1;
270 		ops[3] = wdb1;
271 		if (type == NO_MVCC) {
272 			success[0] = 0;
273 			success[1] = 0;
274 			success[2] = 1;
275 			success[3] = 0;
276 		} else {
277 			success[0] = 0;
278 			success[1] = 1;
279 			success[2] = 1;
280 			success[3] = 1;
281 		}
282 	}
283 }
284