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