2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afsconfig.h>
11 #include <afs/param.h>
13 #ifdef IGNORE_SOME_GCC_WARNINGS
14 # pragma GCC diagnostic warning "-Wstrict-prototypes"
18 #include "afsincludes.h"
22 #include <afs/pthread_glock.h>
33 #include <netinet/in.h>
35 #include <afs/rxgen_consts.h>
36 #define UBIK_LEGACY_CALLITER
43 short ubik_initializationState; /*!< initial state is zero */
47 * \brief Parse list for clients.
50 ubik_ParseClientList(int argc, char **argv, afs_int32 * aothers)
54 register struct hostent *th;
55 afs_int32 temp, counter;
58 inServer = 0; /* haven't seen -servers yet */
60 for (i = 1; i < argc; i++) {
61 /* look for -servers argument */
67 /* otherwise this is a new host name */
69 th = gethostbyname(tp);
74 memmove((void *)&temp, (const void *)th->h_addr,
77 if (counter++ >= MAXSERVERS)
81 /* haven't seen a -server yet */
82 if (!strcmp(tp, "-servers")) {
88 /* never saw a -server */
91 if (counter < MAXSERVERS)
92 *aothers++ = 0; /* null terminate if room */
96 #ifdef AFS_PTHREAD_ENV
100 static pthread_once_t random_once = PTHREAD_ONCE_INIT;
101 static int called_afs_random_once;
102 static pthread_key_t random_number_key;
105 afs_random_once(void)
107 assert(pthread_key_create(&random_number_key, NULL) == 0);
108 called_afs_random_once = 1;
113 #if !defined(UKERNEL)
115 * \brief use time and pid to try to get some initial randomness.
117 #define ranstage(x) (x)= (afs_uint32) (3141592621U*((afs_uint32)x)+1)
120 * \brief Random number generator and constants from KnuthV2 2d ed, p170
123 * X = (aX + c) % m \n
124 * m is a power of two \n
126 * a is 0.73m should be 0.01m .. 0.99m \n
127 * c is more or less immaterial. 1 or a is suggested. \n
129 * NB: LOW ORDER BITS are not very random. To get small random numbers,
130 * treat result as <1, with implied binary point, and multiply by
133 * NB: Has to be unsigned, since shifts on signed quantities may preserve
136 * In this case, m == 2^32, the mod operation is implicit. a == pi, which
137 * is used because it has some interesting characteristics (lacks any
138 * interesting bit-patterns).
143 #ifdef AFS_PTHREAD_ENV
146 if (!called_afs_random_once)
147 pthread_once(&random_once, afs_random_once);
149 state = (uintptr_t) pthread_getspecific(random_number_key);
151 static afs_uint32 state = 0;
156 state = time(0) + getpid();
157 for (i = 0; i < 15; i++) {
163 #ifdef AFS_PTHREAD_ENV
164 pthread_setspecific(random_number_key, (const void *)(uintptr_t)state);
171 * \brief Returns int 0..14 using the high bits of a pseudo-random number instead of
172 * the low bits, as the low bits are "less random" than the high ones...
174 * \todo Slight roundoff error exists, an excercise for the reader.
176 * Need to multiply by something with lots of ones in it, so multiply by
177 * 8 or 16 is right out.
180 afs_randomMod15(void)
184 temp = afs_random() >> 4;
185 temp = (temp * 15) >> 28;
189 #endif /* !defined(UKERNEL) */
194 #define abs(a) ((a) < 0 ? -1*(a) : (a))
196 ubik_ClientInit(register struct rx_connection **serverconns,
197 struct ubik_client **aclient)
202 register struct ubik_client *tc;
204 initialize_U_error_table();
206 if (*aclient) { /* the application is doing a re-initialization */
207 LOCK_UBIK_CLIENT((*aclient));
208 /* this is an important defensive check */
209 if (!((*aclient)->initializationState)) {
210 UNLOCK_UBIK_CLIENT((*aclient));
211 return UREINITIALIZE;
214 /* release all existing connections */
215 for (tc = *aclient, i = 0; i < MAXSERVERS; i++) {
216 struct rx_connection *rxConn = ubik_GetRPCConn(tc, i);
219 #ifdef AFS_PTHREAD_ENV
220 rx_ReleaseCachedConnection(rxConn);
222 rx_DestroyConnection(rxConn);
225 UNLOCK_UBIK_CLIENT((*aclient));
226 #ifdef AFS_PTHREAD_ENV
227 if (pthread_mutex_destroy(&((*aclient)->cm)))
228 return UMUTEXDESTROY;
231 tc = (struct ubik_client *)malloc(sizeof(struct ubik_client));
235 memset((void *)tc, 0, sizeof(*tc));
236 #ifdef AFS_PTHREAD_ENV
237 if (pthread_mutex_init(&(tc->cm), (const pthread_mutexattr_t *)0)) {
241 tc->initializationState = ++ubik_initializationState;
243 /* first count the # of server conns so we can randomize properly */
245 for (i = 0; i < MAXSERVERS; i++) {
246 if (serverconns[i] == (struct rx_connection *)0)
251 /* here count is the # of servers we're actually passed in. Compute
252 * offset, a number between 0..count-1, where we'll start copying from the
253 * client-provided array. */
254 for (i = 0; i < count; i++) {
255 offset = afs_randomMod15() % count;
256 for (j = abs(offset); j < 2 * count; j++) {
257 if (!tc->conns[abs(j % count)]) {
258 tc->conns[abs(j % count)] = serverconns[i];
269 * \brief Destroy an ubik connection.
271 * It calls rx to destroy the component rx connections, then frees the ubik
272 * connection structure.
275 ubik_ClientDestroy(struct ubik_client * aclient)
281 LOCK_UBIK_CLIENT(aclient);
282 for (c = 0; c < MAXSERVERS; c++) {
283 struct rx_connection *rxConn = ubik_GetRPCConn(aclient, c);
286 #ifdef AFS_PTHREAD_ENV
287 rx_ReleaseCachedConnection(rxConn);
289 rx_DestroyConnection(rxConn);
292 aclient->initializationState = 0; /* client in not initialized */
293 UNLOCK_UBIK_CLIENT(aclient);
294 #ifdef AFS_PTHREAD_ENV
295 pthread_mutex_destroy(&(aclient->cm)); /* ignore failure */
302 * \brief So that intermittent failures that cause connections to die
303 * don't kill whole ubik connection, refresh them when the connection is in
306 struct rx_connection *
307 ubik_RefreshConn(struct rx_connection *tc)
312 struct rx_securityClass *sc;
314 struct rx_connection *newTc;
316 host = rx_HostOf(rx_PeerOf(tc));
317 port = rx_PortOf(rx_PeerOf(tc));
318 service = rx_ServiceIdOf(tc);
319 sc = rx_SecurityObjectOf(tc);
320 si = rx_SecurityClassOf(tc);
323 * destroy old one after creating new one so that refCount on security
324 * object cannot reach zero.
326 newTc = rx_NewConnection(host, port, service, sc, si);
327 rx_DestroyConnection(tc);
331 #ifdef AFS_PTHREAD_ENV
333 pthread_once_t ubik_client_once = PTHREAD_ONCE_INIT;
334 pthread_mutex_t ubik_client_mutex;
335 #define LOCK_UCLNT_CACHE \
336 assert(pthread_once(&ubik_client_once, ubik_client_init_mutex) == 0 && \
337 pthread_mutex_lock(&ubik_client_mutex)==0)
338 #define UNLOCK_UCLNT_CACHE assert(pthread_mutex_unlock(&ubik_client_mutex)==0)
341 ubik_client_init_mutex(void)
343 assert(pthread_mutex_init(&ubik_client_mutex, NULL) == 0);
348 #define LOCK_UCLNT_CACHE
349 #define UNLOCK_UCLNT_CACHE
354 static int *calls_needsync[SYNCCOUNT]; /* proc calls that need the sync site */
355 static int synccount = 0;
360 * \brief Call this after getting back a #UNOTSYNC.
362 * \note Getting a #UNOTSYNC error code back does \b not guarantee
363 * that there is a sync site yet elected. However, if there is a sync
364 * site out there somewhere, and you're trying an operation that
365 * requires a sync site, ubik will return #UNOTSYNC, indicating the
366 * operation won't work until you find a sync site
369 try_GetSyncSite(register struct ubik_client *aclient, afs_int32 apos)
374 afs_int32 thisHost, newHost;
375 struct rx_connection *tc;
378 origLevel = aclient->initializationState;
381 tc = aclient->conns[apos];
382 if (tc && rx_ConnError(tc)) {
383 aclient->conns[apos] = (tc = ubik_RefreshConn(tc));
389 /* now see if we can find the sync site host */
390 code = VOTE_GetSyncSite(tc, &newHost);
391 if (aclient->initializationState != origLevel) {
392 return -1; /* somebody did a ubik_ClientInit */
395 if (!code && newHost) {
396 newHost = htonl(newHost); /* convert back to network order */
399 * position count at the appropriate slot in the client
400 * structure and retry. If we can't find in slot, we'll just
401 * continue through the whole list
403 for (i = 0; i < MAXSERVERS; i++) {
404 rxp = rx_PeerOf(aclient->conns[i]);
405 thisHost = rx_HostOf(rxp);
408 } else if (thisHost == newHost) {
409 return i; /* we were told to use this one */
420 * \brief Create an internal version of ubik_CallIter that takes an additional
421 * parameter - to indicate whether the ubik client handle has already
425 CallIter(int (*aproc) (), register struct ubik_client *aclient,
426 afs_int32 aflags, int *apos, long p1, long p2, long p3, long p4,
427 long p5, long p6, long p7, long p8, long p9, long p10, long p11,
428 long p12, long p13, long p14, long p15, long p16, int needlock)
430 register afs_int32 code;
431 struct rx_connection *tc;
435 LOCK_UBIK_CLIENT(aclient);
437 origLevel = aclient->initializationState;
441 while (*apos < MAXSERVERS) {
442 /* tc is the next conn to try */
443 tc = aclient->conns[*apos];
446 UNLOCK_UBIK_CLIENT(aclient);
451 if (rx_ConnError(tc)) {
452 tc = ubik_RefreshConn(tc);
453 aclient->conns[*apos] = tc;
456 if ((aflags & UPUBIKONLY) && (aclient->states[*apos] & CFLastFailed)) {
457 (*apos)++; /* try another one if this server is down */
459 break; /* this is the desired path */
462 if (*apos >= MAXSERVERS) {
464 UNLOCK_UBIK_CLIENT(aclient);
470 (*aproc) (tc, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13,
472 if (aclient->initializationState != origLevel) {
474 UNLOCK_UBIK_CLIENT(aclient);
476 return code; /* somebody did a ubik_ClientInit */
479 /* what should I do in case of UNOQUORUM ? */
481 aclient->states[*apos] |= CFLastFailed; /* network errors */
483 /* either misc ubik code, or misc application code or success. */
484 aclient->states[*apos] &= ~CFLastFailed; /* operation worked */
489 UNLOCK_UBIK_CLIENT(aclient);
495 * \brief This is part of an iterator. It doesn't handle finding sync sites.
498 ubik_CallIter(int (*aproc) (), struct ubik_client *aclient,
499 afs_int32 aflags, int *apos, long p1, long p2,
500 long p3, long p4, long p5, long p6, long p7,
501 long p8, long p9, long p10, long p11, long p12,
502 long p13, long p14, long p15, long p16)
504 return CallIter(aproc, aclient, aflags, apos, p1, p2, p3, p4, p5, p6, p7,
505 p8, p9, p10, p11, p12, p13, p14, p15, p16, NEED_LOCK);
509 * \brief Call this instead of stub and we'll guarantee to find a host that's up.
511 * \todo In the future, we should also put in a protocol to find the sync site.
514 ubik_Call_New(int (*aproc) (), register struct ubik_client *aclient,
515 afs_int32 aflags, long p1, long p2, long p3, long p4, long p5,
516 long p6, long p7, long p8, long p9, long p10, long p11,
517 long p12, long p13, long p14, long p15, long p16)
519 afs_int32 code, rcode;
526 LOCK_UBIK_CLIENT(aclient);
529 origLevel = aclient->initializationState;
531 /* Do two passes. First pass only checks servers known running */
532 for (aflags |= UPUBIKONLY, pass = 0; pass < 2;
533 pass++, aflags &= ~UPUBIKONLY) {
538 CallIter(aproc, aclient, aflags, &count, p1, p2, p3, p4, p5,
539 p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16,
541 if (code && (aclient->initializationState != origLevel)) {
544 if (code == UNOSERVERS) {
547 rcode = code; /* remember code from last good call */
549 if (code == UNOTSYNC) { /* means this requires a sync site */
550 if (aclient->conns[3]) { /* don't bother unless 4 or more srv */
551 temp = try_GetSyncSite(aclient, count);
552 if (aclient->initializationState != origLevel) {
553 goto restart; /* somebody did a ubik_ClientInit */
555 if ((temp >= 0) && ((temp > count) || (stepBack++ <= 2))) {
556 count = temp; /* generally try to make progress */
559 } else if ((code >= 0) && (code != UNOQUORUM)) {
560 UNLOCK_UBIK_CLIENT(aclient);
561 return code; /* success or global error condition */
565 UNLOCK_UBIK_CLIENT(aclient);
570 * call this instead of stub and we'll guarantee to find a host that's up.
572 * \todo In the future, we should also put in a protocol to find the sync site.
575 ubik_Call(int (*aproc) (), register struct ubik_client *aclient,
576 afs_int32 aflags, long p1, long p2, long p3, long p4,
577 long p5, long p6, long p7, long p8, long p9, long p10,
578 long p11, long p12, long p13, long p14, long p15, long p16)
580 afs_int32 rcode, code, newHost, thisHost, i, count;
581 int chaseCount, pass, needsync, inlist, j;
582 struct rx_connection *tc;
586 if (aflags & UBIK_CALL_NEW)
587 return ubik_Call_New(aproc, aclient, aflags, p1, p2, p3, p4,
588 p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15,
593 LOCK_UBIK_CLIENT(aclient);
596 origLevel = aclient->initializationState;
598 chaseCount = inlist = needsync = 0;
601 for (j = 0; ((j < SYNCCOUNT) && calls_needsync[j]); j++) {
602 if (calls_needsync[j] == (int *)aproc) {
603 inlist = needsync = 1;
609 * First pass, we try all servers that are up.
610 * Second pass, we try all servers.
612 for (pass = 0; pass < 2; pass++) { /*p */
613 /* For each entry in our servers list */
614 for (count = 0;; count++) { /*s */
617 /* Need a sync site. Lets try to quickly find it */
618 if (aclient->syncSite) {
619 newHost = aclient->syncSite; /* already in network order */
620 aclient->syncSite = 0; /* Will reset if it works */
621 } else if (aclient->conns[3]) {
622 /* If there are fewer than four db servers in a cell,
623 * there's no point in making the GetSyncSite call.
624 * At best, it's a wash. At worst, it results in more
625 * RPCs than you would otherwise make.
627 tc = aclient->conns[count];
628 if (tc && rx_ConnError(tc)) {
629 aclient->conns[count] = tc = ubik_RefreshConn(tc);
633 code = VOTE_GetSyncSite(tc, &newHost);
634 if (aclient->initializationState != origLevel)
635 goto restart; /* somebody did a ubik_ClientInit */
638 newHost = htonl(newHost); /* convert to network order */
643 /* position count at the appropriate slot in the client
644 * structure and retry. If we can't find in slot, we'll
645 * just continue through the whole list
647 for (i = 0; i < MAXSERVERS && aclient->conns[i]; i++) {
648 rxp = rx_PeerOf(aclient->conns[i]);
649 thisHost = rx_HostOf(rxp);
652 if (thisHost == newHost) {
653 if (chaseCount++ > 2)
654 break; /* avoid loop asking */
655 count = i; /* this index is the sync site */
662 tc = aclient->conns[count];
663 if (tc && rx_ConnError(tc)) {
664 aclient->conns[count] = tc = ubik_RefreshConn(tc);
669 if ((pass == 0) && (aclient->states[count] & CFLastFailed)) {
670 continue; /* this guy's down */
674 (*aproc) (tc, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11,
675 p12, p13, p14, p15, p16);
676 if (aclient->initializationState != origLevel) {
677 /* somebody did a ubik_ClientInit */
679 goto restart; /* call failed */
681 goto done; /* call suceeded */
683 if (rcode < 0) { /* network errors */
684 aclient->states[count] |= CFLastFailed; /* Mark serer down */
685 } else if (rcode == UNOTSYNC) {
687 } else if (rcode != UNOQUORUM) {
688 /* either misc ubik code, or misc appl code, or success. */
689 aclient->states[count] &= ~CFLastFailed; /* mark server up */
690 goto done; /* all done */
697 if (!inlist) { /* Remember proc call that needs sync site */
699 calls_needsync[synccount % SYNCCOUNT] = (int *)aproc;
704 if (!rcode) { /* Remember the sync site - cmd successful */
705 rxp = rx_PeerOf(aclient->conns[count]);
706 aclient->syncSite = rx_HostOf(rxp);
709 UNLOCK_UBIK_CLIENT(aclient);