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 #include "../utilities/bdb_xa_util.h"
8 
9 #include <time.h>
10 #include <atmi.h>
11 #include <fml1632.h>
12 #include <fml32.h>
13 #include <tx.h>
14 #include <db.h>
15 #include <stdlib.h>
16 #include <errno.h>
17 
itoc(int num)18 static char itoc(int num)
19 {
20 	char vals[] = {'0', '1', '2', '3', '4',
21 		'5', '6', '7', '8', '9'};
22 	if (num > 9 || num < 0)
23 		return '0';
24 	return vals[num];
25 }
26 
27 /*
28  * This function syncs all clients by having each one create
29  * a file called [num]_[test_num]_[call], and attempting to read the files
30  * the other clients create until it succeeds.
31  */
sync_clients(num,num_clients,call,test_num)32 int sync_clients(num, num_clients, call, test_num)
33 	int num;
34 	int num_clients;
35 	int call;
36 	int test_num;
37 {
38 	FILE *fp;
39 	int i, ret;
40 	char name[6];
41 
42 	name[5] = 0;
43 	name[0] = itoc(num);
44 	name[1] = '_';
45 	name[2] = itoc(test_num);
46 	name[3] = '_';
47 	name[4] = itoc(call);
48 
49 	//printf("client %d waiting in call %d\n", num, call);
50 
51 	fp = fopen(name, "w");
52 	if (fp == NULL)
53 		return ENOENT;
54 	fprintf(fp, "success");
55 	if ((ret = fclose(fp)) != 0)
56 		return (ret);
57 	for (i = 1; i < (num_clients + 1); i++) {
58 		if (i == num)
59 			continue;
60 		name[0] = itoc(i);
61 		while ((fp = fopen(name, "r")) == NULL) {
62 			sleep(1);
63 		}
64 	}
65 	//printf ("client %d continuing in call %d\n", num, call);
66 	return (0);
67 }
68 
69 /*
70  * Print callback for __db_prdbt.
71  */
72 int
pr_callback(handle,str_arg)73 pr_callback(handle, str_arg)
74 	void *handle;
75 	const void *str_arg;
76 {
77 	char *str;
78 	FILE *f;
79 
80 	str = (char *)str_arg;
81 	f = (FILE *)handle;
82 
83 	if (fprintf(f, "%s", str) != (int)strlen(str))
84 		return (-1);
85 
86 	return (0);
87 }
88 
89 /*
90  * Initialize an XA server and allocate and open its database handles
91  */
92 int
init_xa_server(num_db,progname,use_mvcc)93 init_xa_server(num_db, progname, use_mvcc)
94 	int num_db;
95 	const char *progname;
96 	int use_mvcc;
97 {
98 	int ret, i, j;
99 	u_int32_t temp;
100 	u_int32_t flags = DB_AUTO_COMMIT|DB_CREATE|DB_THREAD;
101 
102 	if (use_mvcc)
103 		 flags |= DB_MULTIVERSION;
104 
105 	if (verbose)
106 		printf("%s: called\n", progname);
107 
108 	/* Open resource managers. */
109 	if (tx_open() == TX_ERROR) {
110 		fprintf(stderr, "tx_open: TX_ERROR\n");
111 		return (-1);
112 	}
113 
114 	/* Seed random number generator. */
115 	srand((u_int)(time(NULL) | getpid()));
116 
117 	for (i = 0; i < MAX_NUMDB; i++)
118 		dbs[i] = NULL;
119 
120 	/*
121 	 * Open XA database handles.  Databases must be opened
122 	 * outside of a global transaction
123 	 * because the open event is held in process local memory.
124 	 */
125 	for (i = 0; i < num_db; i++) {
126 		if ((ret = db_create(&dbs[i], NULL, DB_XA_CREATE)) != 0) {
127 			fprintf(stderr, "db_create: %s\n", db_strerror(ret));
128 			goto err;
129 		}
130 
131 		dbs[i]->set_errfile(dbs[i], stderr);
132 		if ((ret = dbs[i]->open(dbs[i], NULL,
133 		    db_names[i], NULL, DB_BTREE, flags, 0664)) != 0) {
134 			fprintf(stderr, "DB open: %s: %s\n", db_names[i],
135 			    db_strerror(ret));
136 			goto err;
137 		}
138 	}
139 
140 	if (verbose)
141 		printf("%s: tpsvrinit: initialization done\n", progname);
142 
143 	return (0);
144 
145 	/* Clean up on error. */
146 err:	for (i = 0; i < num_db; i++) {
147 		if (dbs[i] != NULL)
148 			(void) dbs[i]->close(dbs[i], 0);
149 		dbs[i] = NULL;
150 	}
151 	return (-1);
152 }
153 
154 /*
155  * Called when the servers are shutdown.  This closes all open
156  * database handles.
157  */
158 void
close_xa_server(num_db,progname)159 close_xa_server(num_db, progname)
160 	int num_db;
161 	const char *progname;
162 {
163 	int i;
164 
165 	for (i = 0; i < num_db; i++) {
166 		if (dbs[i] != NULL)
167 			(void) dbs[i]->close(dbs[i], 0);
168 		dbs[i] = NULL;
169 	}
170 
171 	tx_close();
172 
173 	if (verbose)
174 		printf("%s: tpsvrdone: shutdown done\n", progname);
175 }
176 
177 /*
178  * check_data --
179  *	Compare data between two databases to ensure that they are identical.
180  */
check_data(dbenv1,name1,dbenv2,name2,progname)181 int check_data(dbenv1, name1, dbenv2, name2, progname)
182      DB_ENV *dbenv1;
183      const char *name1;
184      DB_ENV *dbenv2;
185      const char *name2;
186      const char * progname;
187 {
188 	DB *dbp1, *dbp2;
189 	DBC *dbc1, *dbc2;
190 	DBT key1, data1, key2, data2;
191 	int ret, ret1, ret2;
192 	u_int32_t flags = DB_INIT_MPOOL | DB_INIT_LOG | DB_INIT_TXN |
193 	  DB_INIT_LOCK | DB_THREAD;
194 
195 	dbp1 = dbp2 = NULL;
196 	dbc1 = dbc2 = NULL;
197 
198 	/* Open table #1. */
199 	if ((ret = db_create(&dbp1, dbenv1, 0)) != 0 ||
200 	    (ret = dbp1->open(
201 	    dbp1, NULL, name1, NULL, DB_UNKNOWN, DB_RDONLY, 0)) != 0) {
202 		fprintf(stderr,
203 		    "%s: %s: %s\n", progname, name1, db_strerror(ret));
204 		goto err;
205 	}
206 	if (verbose)
207 		printf("%s: opened %s OK\n", progname, name1);
208 
209 	/* Open table #2. */
210 	if ((ret = db_create(&dbp2, dbenv2, 0)) != 0 ||
211 	    (ret = dbp2->open(
212 	    dbp2, NULL, name2, NULL, DB_UNKNOWN, DB_RDONLY, 0)) != 0) {
213 		fprintf(stderr,
214 		    "%s: %s: %s\n", progname, name2, db_strerror(ret));
215 		goto err;
216 	}
217 	if (verbose)
218 		printf("%s: opened %s OK\n", progname, name2);
219 
220 	/* Open cursors. */
221 	if ((ret = dbp1->cursor(dbp1, NULL, &dbc1, 0)) != 0 ||
222 	    (ret = dbp2->cursor(dbp2, NULL, &dbc2, 0)) != 0) {
223 		fprintf(stderr,
224 		    "%s: DB->cursor: %s\n", progname, db_strerror(ret));
225 		goto err;
226 	}
227 	if (verbose)
228 		printf("%s: opened cursors OK\n", progname);
229 
230 	/* Compare the two databases. */
231 	memset(&key1, 0, sizeof(key1));
232 	memset(&data1, 0, sizeof(data1));
233 	memset(&key2, 0, sizeof(key2));
234 	memset(&data2, 0, sizeof(data2));
235 	for (;;) {
236 		ret1 = dbc1->get(dbc1, &key1, &data1, DB_NEXT);
237 		ret2 = dbc2->get(dbc2, &key2, &data2, DB_NEXT);
238 		if (ret1 != 0 || ret2 != 0)
239 			break;
240 		if (verbose) {
241 			__db_prdbt(&key1, 0, "get: key1: %s\n", stdout,
242 			   pr_callback , 0, 0);
243 			__db_prdbt(&key2, 0, "get: key2: %s\n", stdout,
244 			    pr_callback, 0, 0);
245 			__db_prdbt(&data1, 0, "get: data1: %s\n", stdout,
246 			   pr_callback, 0, 0);
247 			__db_prdbt(&data2, 0, "get: data2: %s\n", stdout,
248 			    pr_callback, 0, 0);
249 		}
250 		/* Compare the key and data.  */
251 		if (key1.size != key2.size ||
252 		    memcmp(key1.data, key2.data, key1.size) != 0 ||
253 		    data1.size != data2.size ||
254 		    memcmp(data1.data, data2.data,
255 		    data1.size) != 0)
256 			goto mismatch;
257 	}
258 	if (ret1 != ret2) {
259 mismatch:	fprintf(stderr,
260 		    "%s: DB_ERROR: databases 1 and 2 weren't identical\n",
261 		    progname);
262 		ret = 1;
263 	}
264 
265 err:	if (dbc1 != NULL)
266 		(void)dbc1->close(dbc1);
267 	if (dbc2 != NULL)
268 		(void)dbc2->close(dbc2);
269 	if (dbp1 != NULL)
270 		(void)dbp1->close(dbp1, 0);
271 	if (dbp2 != NULL)
272 		(void)dbp2->close(dbp2, 0);
273 
274 	if (verbose) {
275 		if (ret == 0)
276 			printf("Data check succeeded.\n", progname);
277 		else
278 			printf("Data check failed.\n", progname);
279 	}
280 
281 	return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
282 }
283