more-prototyping-20030513
[openafs.git] / src / ubik / vote.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 RCSID("$Header$");
14
15 #include <sys/types.h>
16 #ifdef AFS_NT40_ENV
17 #include <winsock2.h>
18 #else
19 #include <sys/file.h>
20 #include <netinet/in.h>
21 #endif
22 #include <afs/afsutil.h>
23 #include <lock.h>
24 #ifdef HAVE_STRING_H
25 #include <string.h>
26 #else
27 #ifdef HAVE_STRINGS_H
28 #include <strings.h>
29 #endif
30 #endif
31 #include <rx/xdr.h>
32 #include <rx/rx.h>
33 #include <afs/afsutil.h>
34 #include <time.h>
35
36 #define UBIK_INTERNALS
37 #include "ubik.h"
38 #include "ubik_int.h"
39
40 /*
41     General Ubik Goal:
42     The goal is to provide reliable operation among N servers, such that any
43     server can crash with the remaining servers continuing operation within a
44     short period of time.  While a *short* outage is acceptable, this time
45     should be order of 3 minutes or less.
46     
47     Theory of operation:
48     
49     Note: SMALLTIME and BIGTIME are essentially the same time value, separated
50     only by the clock skew, MAXSKEW.  In general, if you are making guarantees
51     for someone else, promise them no more than SMALLTIME seconds of whatever
52     invariant you provide.  If you are waiting to be sure some invariant is now
53     *false*, wait at least BIGTIME seconds to be sure that SMALLTIME seconds
54     has passed at the other site.
55
56     Now, back to the design:
57     One site in the collection is a special site, designated the *sync* site.
58     The sync site sends periodic messages, which can be thought of as
59     keep-alive messages.  When a non-sync site hears from the sync site, it
60     knows that it is getting updates for the next SMALLTIME seconds from that
61     sync site.
62     
63     If a server does not hear from the sync site in SMALLTIME seconds, it
64     determines that it no longer is getting updates, and thus refuses to give
65     out potentially out-of-date data.  If a sync site can not muster a majority
66     of servers to agree that it is the sync site, then there is a possibility
67     that a network partition has occurred, allowing another server to claim to
68     be the sync site.  Thus, any time that the sync site has not heard from a
69     majority of the servers in the last SMALLTIME seconds, it voluntarily
70     relinquishes its role as sync site.
71     
72     While attempting to nominate a new sync site, certain rules apply.  First,
73     a server can not reply "ok" (return 1 from ServBeacon) to two different
74     hosts in less than BIGTIME seconds; this allows a server that has heard
75     affirmative replies from a majority of the servers to know that no other
76     server in the network has heard enough affirmative replies in the last
77     BIGTIME seconds to become sync site, too.  The variables ubik_lastYesTime
78     and lastYesHost are used by all servers to keep track of which host they
79     have last replied affirmatively to, when queried by a potential new sync
80     site.
81     
82     Once a sync site has become a sync site, it periodically sends beacon
83     messages with a parameter of 1, indicating that it already has determined
84     it is supposed to be the sync site.  The servers treat such a message as a
85     guarantee that no other site will become sync site for the next SMALLTIME
86     seconds.  In the interim, these servers can answer a query concerning which
87     site is the sync site without any communication with any server.  The
88     variables lastBeaconArrival and lastBeaconHost are used by all servers to
89     keep track of which sync site has last contacted them.
90     
91     One complication occurs while nominating a new sync site: each site may be
92     trying to nominate a different site (based on the value of lastYesHost),
93     yet we must nominate the smallest host (under some order), to prevent this
94     process from looping.  The process could loop by having each server give
95     one vote to another server, but with no server getting a majority of the
96     votes.  To avoid this, we try to withhold our votes for the server with the
97     lowest internet address (an easy-to-generate order).  To this effect, we
98     keep track (in lowestTime and lowestHost) of the lowest server trying to
99     become a sync site.  We wait for this server unless there is already a sync
100     site (indicated by ServBeacon's parameter being 1).
101 */
102
103 afs_int32 ubik_debugFlag        = 0;            /* print out debugging messages? */
104
105 /* these statics are used by all sites in nominating new sync sites */
106 afs_int32 ubik_lastYesTime = 0; /* time we sent the last *yes* vote */
107 static afs_uint32 lastYesHost = 0xffffffff; /* host to which we sent *yes* vote */
108 /* Next is time sync site began this vote: guarantees sync site until this + SMALLTIME */
109 static afs_int32 lastYesClaim = 0;
110 static int lastYesState = 0;    /* did last site we voted for claim to be sync site? */
111
112 /* used to guarantee that nomination process doesn't loop */
113 static afs_int32 lowestTime = 0;
114 static afs_uint32 lowestHost = 0xffffffff;
115 static afs_int32 syncTime = 0;
116 static afs_int32 syncHost = 0;
117
118 /* used to remember which dbase version is the one at the sync site (for non-sync sites */
119 struct ubik_version ubik_dbVersion;     /* sync site's dbase version */
120 struct ubik_tid ubik_dbTid;             /* sync site's tid, or 0 if none */
121
122 /* decide if we should try to become sync site.  The basic rule is that we
123  * don't run if there is a valid sync site and it ain't us (we have to run if
124  * it is us, in order to keep our votes).  If there is no sync site, then we
125  * want to run if we're the lowest numbered host running, otherwise we defer to
126  * the lowest host.  However, if the lowest host hasn't been heard from for a
127  * while, then we start running again, in case he crashed.
128  *
129  * This function returns true if we should run, and false otherwise.
130  */
131 int uvote_ShouldIRun(void)
132 {
133     register afs_int32 now;
134     
135     now = FT_ApproxTime();
136     if (BIGTIME + ubik_lastYesTime < now) return 1;    /* no valid guy even trying */
137     if (lastYesState && lastYesHost != ubik_host[0]) return 0; /* other guy is sync site, leave him alone */
138     if (ntohl((afs_uint32) lastYesHost) < ntohl((afs_uint32) ubik_host[0]))
139         return 0;    /* if someone is valid and better than us, don't run */
140     /* otherwise we should run */
141     return 1;
142 }
143
144 /* Return the current synchronization site, if any.  Simple approach: if the
145  * last guy we voted yes for claims to be the sync site, then we we're happy to
146  * use that guy for a sync site until the time his mandate expires.  If the guy
147  * does not claim to be sync site, then, of course, there's none.
148  *
149  * In addition, if we lost the sync, we set urecovery_syncSite to an invalid
150  * value, indicating that we no longer know which version of the dbase is the
151  * one we should have.  We'll get a new one when we next hear from the sync
152  * site.
153  *
154  * This function returns 0 or currently valid sync site.  It can return our own
155  * address, if we're the sync site.
156  */
157 afs_int32 uvote_GetSyncSite(void)
158 {
159     register afs_int32 now;
160     register afs_int32 code;
161
162     if (!lastYesState) code = 0;
163     else {
164         now = FT_ApproxTime();
165         if (SMALLTIME + lastYesClaim < now) code = 0;    /* last guy timed out */
166         else code = lastYesHost;
167     }
168     return code;
169 }
170
171 /* called by the sync site to handle vote beacons; if aconn is null, this is a
172  * local call; returns 0 or time whe the vote was sent.  It returns 0 if we are
173  * not voting for this sync site, or the time we actually voted yes, if
174  * non-zero.
175  */
176 afs_int32 SVOTE_Beacon(register struct rx_call *rxcall, afs_int32 astate, 
177         afs_int32 astart, struct ubik_version *avers, struct ubik_tid *atid)
178 {
179     register afs_int32 otherHost;
180     register afs_int32 now;
181     afs_int32 vote;
182     struct rx_connection *aconn;
183     struct rx_peer *rxp;
184     struct ubik_server *ts;
185     int isClone = 0;
186
187     now = FT_ApproxTime();                      /* close to current time */
188     if (rxcall) {                               /* caller's host */
189         aconn = rx_ConnectionOf(rxcall);
190         rxp = rx_PeerOf(aconn);
191         otherHost = rx_HostOf(rxp);
192
193                 /* get the primary interface address for this host.  */
194                 /* This is the identifier that ubik uses. */
195         otherHost = ubikGetPrimaryInterfaceAddr(otherHost);
196         if ( !otherHost )
197         {
198                 ubik_dprint("Received beacon from unknown host %s\n",
199                                         afs_inet_ntoa(rx_HostOf(rxp)));
200                 return 0; /* I don't know about you: vote no */
201         }
202         for (ts = ubik_servers; ts; ts = ts->next) {
203             if (ts->addr[0] == otherHost) break;
204         }
205         if (!ts) ubik_dprint("Unknown host %x has sent a beacon\n", otherHost);
206         if (ts && ts->isClone) isClone = 1;
207     } else {
208         otherHost = ubik_host[0];                       /* this host */
209         isClone = amIClone;
210     }
211
212     ubik_dprint("Received beacon type %d from host %s\n", astate, 
213                                 afs_inet_ntoa(otherHost));
214
215     /* compute the lowest server we've heard from.  We'll try to only vote for
216        this dude if we don't already have a synchronization site.  Also, don't
217        let a very old lowestHost confusing things forever.  We pick a new
218        lowestHost after BIGTIME seconds to limit the damage if this host
219        actually crashes.  Finally, we also count in this computation: don't
220        pick someone else if we're even better!
221
222        Note that the test below must be <=, not <, so that we keep refreshing
223        lowestTime.  Otherwise it will look like we haven't heard from
224        lowestHost in a while and another host could slip in.  */
225
226
227     /* First compute the lowest host we've heard from, whether we want them
228        for a sync site or not.  If we haven't heard from a site in BIGTIME
229        seconds, we ignore its presence in lowestHost: it may have crashed.
230        Note that we don't ever let anyone appear in our lowestHost if we're
231        lower than them, 'cause we know we're up. */
232     /* But do not consider clones for lowesHost since they never may become
233        sync site */
234     if (!isClone &&
235         (ntohl((afs_uint32) otherHost) <= ntohl((afs_uint32) lowestHost)
236         || lowestTime + BIGTIME < now)) {
237         lowestTime = now;
238         lowestHost = otherHost;
239     }
240     /* why do we need this next check?  Consider the case where each of two
241        servers decides the other is lowestHost.  Each stops sending beacons
242        'cause the other is there.  Not obvious that this process terminates:
243        i.e. each guy could restart procedure and again think other side is
244        lowest.  Need to prove: if one guy in the system is lowest and knows
245        he's lowest, these loops don't occur.  because if someone knows he's
246        lowest, he will send out beacons telling others to vote for him. */
247     if (!amIClone &&
248         (ntohl((afs_uint32) ubik_host[0]) <= ntohl((afs_uint32) lowestHost)
249         || lowestTime + BIGTIME < now)) {
250         lowestTime = now;
251         lowestHost = ubik_host[0];
252     }
253     
254     /* tell if we've heard from a sync site recently (even if we're not voting
255        for this dude yet).  After a while, time the guy out. */
256     if (astate) {   /* this guy is a sync site */
257         syncHost = otherHost;
258         syncTime = now;
259     }
260     else if (syncTime + BIGTIME < now) {
261        if (syncHost) {
262           ubik_dprint("Ubik: Lost contact with sync-site %d.%d.%d.%d (NOT in quorum)\n",
263                       ((syncHost>>24)&0xff), ((syncHost>>16)&0xff),
264                       ((syncHost>> 8)&0xff), (syncHost      &0xff));
265        }
266        syncHost = 0;
267     }
268
269     /* decide how to vote */
270     vote = 0;               /* start off voting no */
271
272     /* if we this guy isn't a sync site, we don't really have to vote for him.
273        We get to apply some heuristics to try to avoid weird oscillation sates
274        in the voting procedure. */
275     if (astate == 0) {
276         /* in here only if this guy doesn't claim to be a sync site */
277
278         /* lowestHost is also trying for our votes, then just say no. */
279         if (ntohl(lowestHost) != ntohl(otherHost)) {
280             return 0;
281         }
282
283         /* someone else *is* a sync site, just say no */
284         if (syncHost && syncHost != otherHost)
285             return 0;
286     } else  /* fast startup if this is the only non-clone */
287     if (lastYesHost == 0xffffffff && otherHost == ubik_host[0]) {
288         int i = 0;
289         for (ts = ubik_servers; ts; ts = ts->next) {
290             if (ts->addr[0] == otherHost) continue;
291             if (!ts->isClone) i++;
292         }
293         if (!i) lastYesHost = otherHost;
294     }
295         
296
297     if (isClone) return 0; /* clone never can become sync site */
298
299     /* Don't promise sync site support to more than one host every BIGTIME
300        seconds.  This is the heart of our invariants in this system. */
301     if (ubik_lastYesTime + BIGTIME < now || otherHost == lastYesHost) {
302         if ((ubik_lastYesTime+BIGTIME < now) || 
303             (otherHost != lastYesHost) ||
304             (lastYesState != astate)) {
305            /* A new vote or a change in the vote or changed quorum */
306            ubik_dprint("Ubik: vote 'yes' for %s %s\n",
307                                 afs_inet_ntoa(otherHost),
308                        (astate?"(in quorum)":"(NOT in quorum)"));
309         }
310
311         vote = now;                 /* vote yes */
312         ubik_lastYesTime = now;     /* remember when we voted yes */
313         lastYesClaim = astart;      /* remember for computing when sync site expires */
314         lastYesHost = otherHost;    /* and who for */
315         lastYesState = astate;      /* remember if site is a sync site */
316         ubik_dbVersion = *avers;    /* resync value */
317         ubik_dbTid = *atid;         /* transaction id, if any, of active trans */
318         urecovery_CheckTid(atid);   /* check if current write trans needs aborted */
319     }
320     return vote;
321 }
322
323 /* handle per-server debug command, where 0 is the first server.  Basic network
324    debugging hooks. */
325 afs_int32 SVOTE_SDebug(struct rx_call *rxcall, afs_int32 awhich,
326         register struct ubik_sdebug *aparm)
327 {
328     afs_int32 code, isClone;
329     code = SVOTE_XSDebug(rxcall, awhich, aparm, &isClone);
330     return code;
331 }
332
333 afs_int32 SVOTE_XSDebug(struct rx_call *rxcall, afs_int32 awhich, 
334         register struct ubik_sdebug *aparm, afs_int32 *isclone)
335 {
336     register struct ubik_server *ts;
337     register int i;
338     for(ts=ubik_servers; ts; ts=ts->next) {
339         if (awhich-- == 0) {
340             /* we're done */
341             aparm->addr = ntohl(ts->addr[0]); /* primary interface */
342             for ( i=0; i < UBIK_MAX_INTERFACE_ADDR-1; i++)
343                 aparm->altAddr[i] = ntohl(ts->addr[i+1]);
344             aparm->lastVoteTime = ts->lastVoteTime;
345             aparm->lastBeaconSent = ts->lastBeaconSent;
346             memcpy(&aparm->remoteVersion, &ts->version, sizeof(struct ubik_version));
347             aparm->lastVote = ts->lastVote;
348             aparm->up = ts->up;
349             aparm->beaconSinceDown = ts->beaconSinceDown;
350             aparm->currentDB = ts->currentDB;
351             *isclone = ts->isClone;
352             return 0;
353         }
354     }
355     return 2;
356 }
357
358 afs_int32 SVOTE_XDebug(struct rx_call *rxcall, register struct ubik_debug *aparm, 
359         afs_int32 *isclone)
360 {
361     afs_int32 code;
362
363     code = SVOTE_Debug(rxcall, aparm);
364     *isclone = amIClone;
365     return code;
366 }
367
368 /* handle basic network debug command.  This is the global state dumper */
369 afs_int32 SVOTE_Debug(struct rx_call *rxcall, register struct ubik_debug *aparm)
370 {
371     int  i;
372     /* fill in the basic debug structure.  Note the the RPC protocol transfers,
373      * integers in host order. */
374     
375     aparm->now = FT_ApproxTime();
376     aparm->lastYesTime = ubik_lastYesTime;
377     aparm->lastYesHost = ntohl(lastYesHost);
378     aparm->lastYesState = lastYesState;
379     aparm->lastYesClaim = lastYesClaim;
380     aparm->lowestHost = ntohl(lowestHost);
381     aparm->lowestTime = lowestTime;
382     aparm->syncHost = ntohl(syncHost);
383     aparm->syncTime = syncTime;
384
385     /* fill in all interface addresses of myself in hostbyte order */
386     for ( i=0; i < UBIK_MAX_INTERFACE_ADDR; i++)
387         aparm->interfaceAddr[i] = ntohl(ubik_host[i]);   
388
389     aparm->amSyncSite = ubik_amSyncSite;
390     ubeacon_Debug(aparm);
391     
392     udisk_Debug(aparm);
393     
394     ulock_Debug(aparm);
395
396     /* Get the recovery state. The label of the database may not have 
397      * been written yet but set the flag so udebug behavior remains.
398      * Defect 9477.
399      */
400     aparm->recoveryState = urecovery_state;
401     if ((urecovery_state & UBIK_RECSYNCSITE) && 
402         (urecovery_state & UBIK_RECFOUNDDB ) &&
403         (urecovery_state & UBIK_RECHAVEDB  ) ) {
404        aparm->recoveryState |= UBIK_RECLABELDB;
405     }
406     memcpy(&aparm->syncVersion, &ubik_dbVersion, sizeof(struct ubik_version));
407     memcpy(&aparm->syncTid, &ubik_dbTid, sizeof(struct ubik_tid));
408     aparm->activeWrite = (ubik_dbase->flags & DBWRITING);
409     aparm->tidCounter = ubik_dbase->tidCounter;
410     
411     if (ubik_currentTrans) {
412         aparm->currentTrans = 1;
413         if (ubik_currentTrans->type == UBIK_WRITETRANS) aparm->writeTrans = 1;
414         else aparm->writeTrans = 0;
415     }
416     else {
417         aparm->currentTrans = 0;
418     }
419
420     aparm->epochTime = ubik_epochTime;
421
422     return 0;
423 }
424
425 afs_int32 SVOTE_SDebugOld(struct rx_call *rxcall, afs_int32 awhich, register struct ubik_sdebug_old *aparm)
426 {
427     register struct ubik_server *ts;
428
429     for(ts=ubik_servers; ts; ts=ts->next) {
430         if (awhich-- == 0) {
431             /* we're done */
432             aparm->addr = ntohl(ts->addr[0]); /* primary interface */
433             aparm->lastVoteTime = ts->lastVoteTime;
434             aparm->lastBeaconSent = ts->lastBeaconSent;
435             memcpy(&aparm->remoteVersion, &ts->version, sizeof(struct ubik_version));
436             aparm->lastVote = ts->lastVote;
437             aparm->up = ts->up;
438             aparm->beaconSinceDown = ts->beaconSinceDown;
439             aparm->currentDB = ts->currentDB;
440             return 0;
441         }
442     }
443     return 2;
444 }
445
446
447 /* handle basic network debug command.  This is the global state dumper */
448 afs_int32 SVOTE_DebugOld(struct rx_call *rxcall, register struct ubik_debug_old *aparm)
449 {
450
451     /* fill in the basic debug structure.  Note the the RPC protocol transfers,
452      * integers in host order. */
453     
454     aparm->now = FT_ApproxTime();
455     aparm->lastYesTime = ubik_lastYesTime;
456     aparm->lastYesHost = ntohl(lastYesHost);
457     aparm->lastYesState = lastYesState;
458     aparm->lastYesClaim = lastYesClaim;
459     aparm->lowestHost = ntohl(lowestHost);
460     aparm->lowestTime = lowestTime;
461     aparm->syncHost = ntohl(syncHost);
462     aparm->syncTime = syncTime;
463
464     aparm->amSyncSite = ubik_amSyncSite;
465     ubeacon_Debug(aparm);
466     
467     udisk_Debug(aparm);
468     
469     ulock_Debug(aparm);
470
471     /* Get the recovery state. The label of the database may not have 
472      * been written yet but set the flag so udebug behavior remains.
473      * Defect 9477.
474      */
475     aparm->recoveryState = urecovery_state;
476     if ((urecovery_state & UBIK_RECSYNCSITE) && 
477         (urecovery_state & UBIK_RECFOUNDDB ) &&
478         (urecovery_state & UBIK_RECHAVEDB  ) ) {
479        aparm->recoveryState |= UBIK_RECLABELDB;
480     }
481     memcpy(&aparm->syncVersion, &ubik_dbVersion, sizeof(struct ubik_version));
482     memcpy(&aparm->syncTid, &ubik_dbTid, sizeof(struct ubik_tid));
483     aparm->activeWrite = (ubik_dbase->flags & DBWRITING);
484     aparm->tidCounter = ubik_dbase->tidCounter;
485     
486     if (ubik_currentTrans) {
487         aparm->currentTrans = 1;
488         if (ubik_currentTrans->type == UBIK_WRITETRANS) aparm->writeTrans = 1;
489         else aparm->writeTrans = 0;
490     }
491     else {
492         aparm->currentTrans = 0;
493     }
494
495     aparm->epochTime = ubik_epochTime;
496
497     return 0;
498 }
499
500
501 /* get the sync site; called by remote servers to find where they should go */
502 afs_int32 SVOTE_GetSyncSite(register struct rx_call *rxcall, register afs_int32 *ahost)
503 {
504     register afs_int32 temp;
505
506     temp = uvote_GetSyncSite();
507     *ahost = ntohl(temp);
508     return 0;
509 }
510
511 int ubik_dprint(char *a, char *b, char *c, char *d, char *e, char *f, char *g, char *h)
512 {
513     ViceLog(5, (a,b,c,d,e,f,g,h));
514 }
515
516 int ubik_print(char *a, char *b, char *c, char *d, char *e, char *f, char *g, char *h)
517 {
518   ViceLog(0, (a,b,c,d,e,f,g,h));
519 }
520
521 /* called once/run to init the vote module */
522 int uvote_Init(void)
523 {
524     /* pretend we just voted for someone else, since we just restarted */
525     ubik_lastYesTime = FT_ApproxTime();
526     return 0;
527 }