Imported Upstream version 5.3.21
[platform/upstream/libdb.git] / test / xa / src1 / server.c
1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 2011, 2012 Oracle and/or its affiliates.  All rights reserved.
5  */
6
7 /*
8  * This is the code for the two servers used in the first XA test.  Server 1
9  * and Server 2 are both called by the client to insert data into table 1
10  * using XA transactions.  Server 1 also can forward requests to Server 2.
11  */
12 #include <sys/types.h>
13
14 #include <ctype.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <time.h>
19 #include <unistd.h>
20
21 #include <atmi.h>
22 #include <fml1632.h>
23 #include <fml32.h>
24 #include <tx.h>
25 #include <xa.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 /*
35  * The two servers are largely identical, #ifdef the source code.
36  */
37 #ifdef SERVER1
38 #define TXN_FUNC                TestTxn1
39 #define TXN_STRING              "TestTxn1"
40 #endif
41 #ifdef SERVER2
42 #define TXN_FUNC                TestTxn2
43 #define TXN_STRING              "TestTxn2"
44 #endif
45 void TXN_FUNC(TPSVCINFO *);
46
47 #define HOME    "../data"
48
49 #define NUMDB 2
50
51 int cnt_forward;                                /* Forwarded requests. */
52 int cnt_request;                                /* Total requests. */
53
54 char *progname;                         /* Server run-time name. */
55
56 /*
57  * Called when each server is started.  It creates and opens the
58  * two database handles.
59  */
60 int
61 tpsvrinit(int argc, char* argv[])
62 {
63         progname = argv[0];
64         return (init_xa_server(NUMDB, progname, 0));
65 }
66
67 /* Called when the servers are shutdown.  This closes the databases. */
68 void
69 tpsvrdone()
70 {
71         close_xa_server(NUMDB, progname);
72         printf("%s: %d requests, %d requests forwarded to the other server\n",
73             progname, cnt_request, cnt_forward);
74 }
75
76 /* 
77  * This function is called by the client.  Here Server 1 and Server 2 insert
78  * data into table 1 using XA transactions.  Server 1 can also forward its 
79  * request to Server 2.
80  */
81 void
82 TXN_FUNC(TPSVCINFO *msg)
83 {
84         DBT data;
85         DBT key;
86         FBFR *replyBuf;
87         HDbRec rcrd;
88         long replyLen, seqNo;
89         int ret, i;
90
91         ++cnt_request;
92
93 #ifdef SERVER1
94         /*
95          * Test that servers can forward to other servers.  Randomly forward
96          * half of server #1's requests to server #2.
97          */
98         if (rand() % 2 > 0) {
99                 ++cnt_forward;
100
101                 replyLen = 1024;
102                 if ((replyBuf =
103                     (FBFR*)tpalloc("FML32", NULL, replyLen)) == NULL ||
104                     tpcall("TestTxn2", msg->data,
105                     0, (char**)&replyBuf, &replyLen, TPSIGRSTRT) == -1) {
106                         fprintf(stderr, "%s: TUXEDO ERROR: %s (code %d)\n",
107                             progname, tpstrerror(tperrno), tperrno);
108                         tpfree((char*)replyBuf);
109                         tpreturn(TPFAIL, 0L, 0, 0L, 0);
110                 } else {
111                         tpfree((char*)replyBuf);
112                         tpreturn(TPSUCCESS, tpurcode, 0, 0L, 0);
113                 }
114                 return;
115         }
116 #endif
117                                                 /* Read the record. */
118         if (Fget((FBFR*)msg->data, SEQ_NO, 0, (char *)&rcrd.SeqNo, 0) == -1)
119                 goto fml_err;
120         if (Fget((FBFR*)msg->data, TS_SEC, 0, (char *)&rcrd.Ts.Sec, 0) == -1)
121                 goto fml_err;
122         if (Fget(
123             (FBFR*)msg->data, TS_USEC, 0, (char *)&rcrd.Ts.Usec, 0) == -1) {
124 fml_err:        fprintf(stderr, "%s: FML ERROR: %s (code %d)\n",
125                     progname, Fstrerror(Ferror), Ferror);
126                 goto err;
127         }
128
129         seqNo = rcrd.SeqNo;                     /* Update the record. */
130         memset(&key, 0, sizeof(key));
131         key.data = &seqNo;
132         key.size = sizeof(seqNo);
133         memset(&data, 0, sizeof(data));
134         data.data = &seqNo;
135         data.size = sizeof(seqNo);
136
137         if (verbose) {
138                  __db_prdbt(&key, 0, "put: key: %s\n", stdout, 
139                      pr_callback, 0, 0);
140                  __db_prdbt(&data, 0, "put: data: %s\n", stdout, 
141                      pr_callback, 0, 0);
142         }
143
144         for (i = 0; i < NUMDB; i++) {
145                 strcpy(rcrd.Msg, db_names[i]);  
146                 if ((ret = dbs[i]->put(dbs[i], NULL, &key, 
147                     &data, 0)) != 0) {
148                         if (ret == DB_LOCK_DEADLOCK)
149                                 goto abort;
150                         fprintf(stderr, "%s: %s: %s->put: %s\n",
151                             progname, TXN_STRING, db_names[i], 
152                             db_strerror(ret));
153                         goto err;
154                 }
155         }
156
157         /*
158          * Decide if the client is going to commit the global transaction or
159          * not, testing the return-value path back to the client; this is the
160          * path we'd use to resolve deadlock, for example.  Commit 80% of the
161          * time.  Returning 0 causes the client to commit, 1 to abort.
162          */
163         if (rand() % 10 > 7) {
164                 if (verbose)
165                         printf("%s: %s: commit\n", progname, TXN_STRING);
166                 tpreturn(TPSUCCESS, 0L, 0, 0L, 0);
167         } else {
168 abort:          if (verbose)
169                         printf("%s: %s: abort\n", progname, TXN_STRING);
170                 tpreturn(TPSUCCESS, 1L, 0, 0L, 0);
171         }
172         return;
173
174 err:    tpreturn(TPFAIL, 1L, 0, 0L, 0);
175 }
176