cc43e4a50c5deb4fd5a8380d77ad256fb4fd591b
[openafs.git] / src / ubik / utst_server.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12
13
14 #include <afs/stds.h>
15 #include <sys/types.h>
16 #ifdef AFS_NT40_ENV
17 #include <winsock2.h>
18 #include <afsutil.h>
19 #else
20 #include <sys/file.h>
21 #include <netdb.h>
22 #include <netinet/in.h>
23 #endif
24 #include <time.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <rx/xdr.h>
28 #include <rx/rx.h>
29 #include <lock.h>
30 #include <afs/afsutil.h>
31 #include "ubik.h"
32 #include "utst_int.h"
33
34
35 /*! \name useful globals */
36 struct ubik_dbase *dbase;
37 afs_int32 sleepTime;
38 /*\}*/
39
40 int
41 SAMPLE_Inc(struct rx_connection *rxconn)
42 {
43     afs_int32 code, temp;
44     struct ubik_trans *tt;
45     struct timeval tv;
46
47     code = ubik_BeginTrans(dbase, UBIK_WRITETRANS, &tt);
48     if (code)
49         return code;
50     printf("about to set lock\n");
51     /* now set database locks.  Must do this or people may read uncommitted
52      * data.  Note that we're just setting a lock at position 1, which is
53      * this program's convention for locking the whole database */
54     code = ubik_SetLock(tt, 1, 1, LOCKWRITE);
55     printf("now have lock\n");
56     if (code) {
57         ubik_AbortTrans(tt);
58         return code;
59     }
60     /* sleep for a little while to make it possible for us to test for some
61      * race conditions */
62     if (sleepTime) {
63         tv.tv_sec = sleepTime;
64         tv.tv_usec = 0;
65 #ifdef AFS_PTHREAD_ENV
66         select(0, 0, 0, 0, &tv);
67 #else
68         IOMGR_Select(0, 0, 0, 0, &tv);
69 #endif
70     }
71     /* read the original value */
72     code = ubik_Read(tt, &temp, sizeof(afs_int32));
73     if (code == UEOF) {
74         /* short read */
75         temp = 0;
76     } else if (code) {
77         ubik_AbortTrans(tt);
78         return code;
79     }
80     temp++;                     /* bump the value here */
81     /* reset the file pointer back to where it was before the read */
82     code = ubik_Seek(tt, 0, 0);
83     if (code) {
84         ubik_AbortTrans(tt);
85         return code;
86     }
87     /* write the data back */
88     code = ubik_Write(tt, &temp, sizeof(afs_int32));
89     if (code) {
90         ubik_AbortTrans(tt);
91         return code;
92     }
93     /* finally, we commit the transaction */
94     code = ubik_EndTrans(tt);
95     temp = 0;
96     return code;
97 }
98
99 int
100 SAMPLE_Get(struct rx_connection *rxconn, afs_int32 *gnumber)
101 {
102     afs_int32 code, temp;
103     struct ubik_trans *tt;
104     struct timeval tv;
105
106     /* start with a read transaction, since we're only going to do read
107      * operations in this transaction. */
108     code = ubik_BeginTrans(dbase, UBIK_READTRANS, &tt);
109     if (code)
110         return code;
111     printf("about to set lock\n");
112     /* obtain a read lock, so we don't read data the other guy is writing */
113     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
114     printf("now have lock\n");
115     if (code) {
116         ubik_AbortTrans(tt);
117         return code;
118     }
119     /* sleep to allow races */
120     if (sleepTime) {
121         tv.tv_sec = sleepTime;
122         tv.tv_usec = 0;
123 #ifdef AFS_PTHREAD_ENV
124         select(0, 0, 0, 0, &tv);
125 #else
126         IOMGR_Select(0, 0, 0, 0, &tv);
127 #endif
128     }
129     /* read the value */
130     code = ubik_Read(tt, &temp, sizeof(afs_int32));
131     if (code == UEOF) {
132         /* premature eof, use 0 */
133         temp = 0;
134     } else if (code) {
135         ubik_AbortTrans(tt);
136         return code;
137     }
138     *gnumber = temp;
139     /* end the transaction, automatically releasing locks */
140     code = ubik_EndTrans(tt);
141     return code;
142 }
143
144 int
145 SAMPLE_QGet(struct rx_connection *rxconn, afs_int32 *gnumber)
146 {
147     afs_int32 code, temp;
148     struct ubik_trans *tt;
149     struct timeval tv;
150
151     /* start with a read transaction, since we're only going to do read
152      * operations in this transaction. */
153     code = ubik_BeginTransReadAny(dbase, UBIK_READTRANS, &tt);
154     if (code)
155         return code;
156     printf("about to set lock\n");
157     /* obtain a read lock, so we don't read data the other guy is writing */
158     code = ubik_SetLock(tt, 1, 1, LOCKREAD);
159     printf("now have lock\n");
160     if (code) {
161         ubik_AbortTrans(tt);
162         return code;
163     }
164     /* sleep to allow races */
165     if (sleepTime) {
166         tv.tv_sec = sleepTime;
167         tv.tv_usec = 0;
168 #ifdef AFS_PTHREAD_ENV
169         select(0, 0, 0, 0, &tv);
170 #else
171         IOMGR_Select(0, 0, 0, 0, &tv);
172 #endif
173     }
174     /* read the value */
175     code = ubik_Read(tt, &temp, sizeof(afs_int32));
176     if (code == UEOF) {
177         /* premature eof, use 0 */
178         temp = 0;
179     } else if (code) {
180         ubik_AbortTrans(tt);
181         return code;
182     }
183     *gnumber = temp;
184     /* end the transaction, automatically releasing locks */
185     code = ubik_EndTrans(tt);
186     return code;
187 }
188
189 int
190 SAMPLE_Trun(struct rx_connection *rxconn)
191 {
192     afs_int32 code;
193     struct ubik_trans *tt;
194     struct timeval tv;
195
196     /* truncation operation requires a write transaction, too */
197     code = ubik_BeginTrans(dbase, UBIK_WRITETRANS, &tt);
198     if (code)
199         return code;
200     printf("about to set lock\n");
201     /* lock the database */
202     code = ubik_SetLock(tt, 1, 1, LOCKWRITE);
203     printf("now have lock\n");
204     if (code) {
205         ubik_AbortTrans(tt);
206         return code;
207     }
208     if (sleepTime) {
209         tv.tv_sec = sleepTime;
210         tv.tv_usec = 0;
211 #ifdef AFS_PTHREAD_ENV
212         select(0, 0, 0, 0, &tv);
213 #else
214         IOMGR_Select(0, 0, 0, 0, &tv);
215 #endif
216     }
217     /* shrink the file */
218     code = ubik_Truncate(tt, 0);
219     if (code) {
220         ubik_AbortTrans(tt);
221         return code;
222     }
223     /* commit */
224     code = ubik_EndTrans(tt);
225     return code;
226 }
227
228 int
229 SAMPLE_Test(struct rx_connection *rxconn)
230 {
231     afs_int32 code, temp;
232     struct ubik_trans *tt;
233     struct timeval tv;
234
235     /* first start a new transaction.  Must be a write transaction since
236      * we're going to change some data (with ubik_Write) */
237     code = ubik_BeginTrans(dbase, UBIK_WRITETRANS, &tt);
238     if (code)
239         return code;
240     printf("about to set lock\n");
241     /* now set database locks.  Must do this or people may read uncommitted
242      * data.  Note that we're just setting a lock at position 1, which is
243      * this program's convention for locking the whole database */
244     code = ubik_SetLock(tt, 1, 1, LOCKWRITE);
245     printf("now have lock\n");
246     if (code) {
247         ubik_AbortTrans(tt);
248         return code;
249     }
250     /* sleep for a little while to make it possible for us to test for some
251      * race conditions */
252     if (sleepTime) {
253         tv.tv_sec = sleepTime;
254         tv.tv_usec = 0;
255 #ifdef AFS_PTHREAD_ENV
256         select(0, 0, 0, 0, &tv);
257 #else
258         IOMGR_Select(0, 0, 0, 0, &tv);
259 #endif
260     }
261     /* read the original value */
262     code = ubik_Read(tt, &temp, sizeof(afs_int32));
263     if (code == UEOF) {
264         printf("short read, using 0\n");
265         temp = 0;
266     } else if (code) {
267         ubik_AbortTrans(tt);
268         return code;
269     }
270     ubik_AbortTrans(tt);        /* surprise! pretend something went wrong */
271     return code;
272 }
273
274
275 #include "AFS_component_version_number.c"
276
277 extern int SAMPLE_ExecuteRequest(struct rx_call *);
278                 
279 int
280 main(int argc, char **argv)
281 {
282     register afs_int32 code, i;
283     afs_int32 serverList[MAXSERVERS];
284     afs_int32 myHost;
285     struct rx_service *tservice;
286     struct rx_securityClass *sc[2];
287     char dbfileName[128];
288
289     if (argc == 1) {
290         printf("usage: userver -servers <serverlist> {-sleep <sleeptime>}\n");
291         exit(0);
292     }
293 #ifdef AFS_NT40_ENV
294     /* initialize winsock */
295     if (afs_winsockInit() < 0)
296         return -1;
297 #endif
298     /* parse our own local arguments */
299     sleepTime = 0;
300     for (i = 1; i < argc; i++) {
301         if (strcmp(argv[i], "-sleep") == 0) {
302             if (i >= argc - 1) {
303                 printf("missing time in -sleep argument\n");
304                 exit(1);
305             }
306             sleepTime = atoi(argv[i + 1]);
307             i++;
308         }
309     }
310     /* call routine to parse command line -servers switch, filling in
311      * myHost and serverList arrays appropriately */
312     code = ubik_ParseServerList(argc, argv, &myHost, serverList);
313     if (code) {
314         printf("could not parse server list, code %d\n", code);
315         exit(1);
316     }
317     /* call ServerInit with the values from ParseServerList.  Also specify the
318      * name to use for the database files (/tmp/testdb), and the port (3000)
319      * for RPC requests.  ServerInit returns a pointer to the database (in
320      * dbase), which is required for creating new transactions */
321
322     sprintf(dbfileName, "%s/testdb", gettmpdir());
323
324     code =
325         ubik_ServerInit(myHost, htons(3000), serverList, dbfileName, &dbase);
326
327     if (code) {
328         printf("ubik init failed with code %d\n", code);
329         exit(1);
330     }
331
332     sc[0] = rxnull_NewServerSecurityObject();
333 #if 0
334     sc[1] = rxvab_NewServerSecurityObject("applexx", 0);
335 #endif
336     tservice = rx_NewService(0, USER_SERVICE_ID, "Sample", sc, 1 /*2 */ ,
337                              SAMPLE_ExecuteRequest);
338     if (tservice == (struct rx_service *)0) {
339         printf("Could not create SAMPLE rx service\n");
340         exit(3);
341     }
342     rx_SetMinProcs(tservice, 2);
343     rx_SetMaxProcs(tservice, 3);
344
345     rx_StartServer(1);          /* Why waste this idle process?? */
346     
347     return 0;
348 }