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