414d1ad3357afe8b41668207a22d235fae8a0e44
[openafs.git] / src / ubik / recovery.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 #include <roken.h>
14
15 #include <afs/opr.h>
16
17 #ifdef AFS_PTHREAD_ENV
18 # include <opr/lock.h>
19 #else
20 # include <opr/lockstub.h>
21 #endif
22
23 #include <rx/rx.h>
24 #include <afs/afsutil.h>
25 #include <afs/cellconfig.h>
26
27
28 #define UBIK_INTERNALS
29 #include "ubik.h"
30 #include "ubik_int.h"
31
32 /*! \file
33  * This module is responsible for determining when the system has
34  * recovered to the point that it can handle new transactions.  It
35  * replays logs, polls to determine the current dbase after a crash,
36  * and distributes the new database to the others.
37  *
38  * The sync site associates a version number with each database.  It
39  * broadcasts the version associated with its current dbase in every
40  * one of its beacon messages.  When the sync site send a dbase to a
41  * server, it also sends the db's version.  A non-sync site server can
42  * tell if it has the right dbase version by simply comparing the
43  * version from the beacon message \p uvote_dbVersion with the version
44  * associated with the database \p ubik_dbase->version.  The sync site
45  * itself simply has one counter to keep track of all of this (again
46  * \p ubik_dbase->version).
47  *
48  * sync site: routine called when the sync site loses its quorum; this
49  * procedure is called "up" from the beacon package.  It resyncs the
50  * dbase and nudges the recovery daemon to try to propagate out the
51  * changes.  It also resets the recovery daemon's state, since
52  * recovery must potentially find a new dbase to propagate out.  This
53  * routine should not do anything with variables used by non-sync site
54  * servers.
55  */
56
57 /*!
58  * if this flag is set, then ubik will use only the primary address
59  * (the address specified in the CellServDB) to contact other
60  * ubik servers. Ubik recovery will not try opening connections
61  * to the alternate interface addresses.
62  */
63 int ubikPrimaryAddrOnly;
64
65 int
66 urecovery_ResetState(void)
67 {
68     urecovery_state = 0;
69     return 0;
70 }
71
72 /*!
73  * \brief sync site
74  *
75  * routine called when a non-sync site server goes down; restarts recovery
76  * process to send missing server the new db when it comes back up for
77  * non-sync site servers.
78  *
79  * \note This routine should not do anything with variables used by non-sync site servers.
80  */
81 int
82 urecovery_LostServer(struct ubik_server *ts)
83 {
84     ubeacon_ReinitServer(ts);
85     return 0;
86 }
87
88 /*!
89  * return true iff we have a current database (called by both sync
90  * sites and non-sync sites) How do we determine this?  If we're the
91  * sync site, we wait until recovery has finished fetching and
92  * re-labelling its dbase (it may still be trying to propagate it out
93  * to everyone else; that's THEIR problem).  If we're not the sync
94  * site, then we must have a dbase labelled with the right version,
95  * and we must have a currently-good sync site.
96  */
97 int
98 urecovery_AllBetter(struct ubik_dbase *adbase, int areadAny)
99 {
100     afs_int32 rcode;
101
102     ViceLog(25, ("allbetter checking\n"));
103     rcode = 0;
104
105
106     if (areadAny) {
107         if (ubik_dbase->version.epoch > 1)
108             rcode = 1;          /* Happy with any good version of database */
109     }
110
111     /* Check if we're sync site and we've got the right data */
112     else if (ubeacon_AmSyncSite() && (urecovery_state & UBIK_RECHAVEDB)) {
113         rcode = 1;
114     }
115
116     /* next, check if we're aux site, and we've ever been sent the
117      * right data (note that if a dbase update fails, we won't think
118      * that the sync site is still the sync site, 'cause it won't talk
119      * to us until a timeout period has gone by.  When we recover, we
120      * leave this clear until we get a new dbase */
121     else if (uvote_HaveSyncAndVersion(ubik_dbase->version)) {
122         rcode = 1;
123     }
124
125     ViceLog(25, ("allbetter: returning %d\n", rcode));
126     return rcode;
127 }
128
129 /*!
130  * \brief abort all transactions on this database
131  */
132 int
133 urecovery_AbortAll(struct ubik_dbase *adbase)
134 {
135     struct ubik_trans *tt;
136     int reads = 0, writes = 0;
137
138     for (tt = adbase->activeTrans; tt; tt = tt->next) {
139         if (tt->type == UBIK_WRITETRANS)
140             writes++;
141         else
142             reads++;
143         udisk_abort(tt);
144     }
145     ViceLog(0, ("urecovery_AbortAll: just aborted %d read and %d write transactions\n",
146                     reads, writes));
147     return 0;
148 }
149
150 /*!
151  * \brief this routine aborts the current remote transaction, if any, if the tid is wrong
152  */
153 int
154 urecovery_CheckTid(struct ubik_tid *atid, int abortalways)
155 {
156     if (ubik_currentTrans) {
157         /* there is remote write trans, see if we match, see if this
158          * is a new transaction */
159         if (atid->epoch != ubik_currentTrans->tid.epoch
160             || atid->counter > ubik_currentTrans->tid.counter || abortalways) {
161             /* don't match, abort it */
162             int endit = 0;
163             /* If the thread is not waiting for lock - ok to end it */
164             if (ubik_currentTrans->locktype != LOCKWAIT) {
165                 endit = 1;
166             }
167
168             ViceLog(0, ("urecovery_CheckTid: Aborting/ending bad remote "
169                         "transaction. (tx %d.%d, atid %d.%d, abortalways %d, "
170                         "endit %d)\n",
171                         ubik_currentTrans->tid.epoch,
172                         ubik_currentTrans->tid.counter,
173                         atid->epoch, atid->counter,
174                         abortalways, endit));
175             if (endit) {
176                 udisk_end(ubik_currentTrans);
177             }
178             ubik_currentTrans = (struct ubik_trans *)0;
179         }
180     }
181     return 0;
182 }
183
184 /*!
185  * \brief replay logs
186  *
187  * log format is defined here, and implicitly in disk.c
188  *
189  * 4 byte opcode, followed by parameters, each 4 bytes long.  All integers
190  * are in logged in network standard byte order, in case we want to move logs
191  * from machine-to-machine someday.
192  *
193  * Begin transaction: opcode \n
194  * Commit transaction: opcode, version (8 bytes) \n
195  * Truncate file: opcode, file number, length \n
196  * Abort transaction: opcode \n
197  * Write data: opcode, file, position, length, <length> data bytes \n
198  *
199  * A very simple routine, it just replays the log.  Note that this is a new-value only log, which
200  * implies that no uncommitted data is written to the dbase: one writes data to the log, including
201  * the commit record, then we allow data to be written through to the dbase.  In our particular
202  * implementation, once a transaction is done, we write out the pages to the database, so that
203  * our buffer package doesn't have to know about stable and uncommitted data in the memory buffers:
204  * any changed data while there is an uncommitted write transaction can be zapped during an
205  * abort and the remaining dbase on the disk is exactly the right dbase, without having to read
206  * the log.
207  */
208 static int
209 ReplayLog(struct ubik_dbase *adbase)
210 {
211     afs_int32 opcode;
212     afs_int32 code, tpos;
213     int logIsGood;
214     afs_int32 len, thisSize, tfile, filePos;
215     afs_int32 buffer[4];
216     afs_int32 syncFile = -1;
217     afs_int32 data[1024];
218
219     /* read the lock twice, once to see whether we have a transaction to deal
220      * with that committed, (theoretically, we should support more than one
221      * trans in the log at once, but not yet), and once replaying the
222      * transactions.  */
223     tpos = 0;
224     logIsGood = 0;
225     /* for now, assume that all ops in log pertain to one transaction; see if there's a commit */
226     while (1) {
227         code =
228             (*adbase->read) (adbase, LOGFILE, (char *)&opcode, tpos,
229                              sizeof(afs_int32));
230         if (code != sizeof(afs_int32))
231             break;
232         opcode = ntohl(opcode);
233         if (opcode == LOGNEW) {
234             /* handle begin trans */
235             tpos += sizeof(afs_int32);
236         } else if (opcode == LOGABORT)
237             break;
238         else if (opcode == LOGEND) {
239             logIsGood = 1;
240             break;
241         } else if (opcode == LOGTRUNCATE) {
242             tpos += 4;
243             code =
244                 (*adbase->read) (adbase, LOGFILE, (char *)buffer, tpos,
245                                  2 * sizeof(afs_int32));
246             if (code != 2 * sizeof(afs_int32))
247                 break;          /* premature eof or io error */
248             tpos += 2 * sizeof(afs_int32);
249         } else if (opcode == LOGDATA) {
250             tpos += 4;
251             code =
252                 (*adbase->read) (adbase, LOGFILE, (char *)buffer, tpos,
253                                  3 * sizeof(afs_int32));
254             if (code != 3 * sizeof(afs_int32))
255                 break;
256             /* otherwise, skip over the data bytes, too */
257             tpos += ntohl(buffer[2]) + 3 * sizeof(afs_int32);
258         } else {
259             ViceLog(0, ("corrupt log opcode (%d) at position %d\n", opcode,
260                        tpos));
261             break;              /* corrupt log! */
262         }
263     }
264     if (logIsGood) {
265         /* actually do the replay; log should go all the way through the commit record, since
266          * we just read it above. */
267         tpos = 0;
268         logIsGood = 0;
269         syncFile = -1;
270         while (1) {
271             code =
272                 (*adbase->read) (adbase, LOGFILE, (char *)&opcode, tpos,
273                                  sizeof(afs_int32));
274             if (code != sizeof(afs_int32))
275                 break;
276             opcode = ntohl(opcode);
277             if (opcode == LOGNEW) {
278                 /* handle begin trans */
279                 tpos += sizeof(afs_int32);
280             } else if (opcode == LOGABORT)
281                 panic("log abort\n");
282             else if (opcode == LOGEND) {
283                 struct ubik_version version;
284                 tpos += 4;
285                 code =
286                     (*adbase->read) (adbase, LOGFILE, (char *)buffer, tpos,
287                                      2 * sizeof(afs_int32));
288                 if (code != 2 * sizeof(afs_int32))
289                     return UBADLOG;
290                 version.epoch = ntohl(buffer[0]);
291                 version.counter = ntohl(buffer[1]);
292                 code = (*adbase->setlabel) (adbase, 0, &version);
293                 if (code)
294                     return code;
295                 ViceLog(0, ("Successfully replayed log for interrupted "
296                            "transaction; db version is now %ld.%ld\n",
297                            (long) version.epoch, (long) version.counter));
298                 logIsGood = 1;
299                 break;          /* all done now */
300             } else if (opcode == LOGTRUNCATE) {
301                 tpos += 4;
302                 code =
303                     (*adbase->read) (adbase, LOGFILE, (char *)buffer, tpos,
304                                      2 * sizeof(afs_int32));
305                 if (code != 2 * sizeof(afs_int32))
306                     break;      /* premature eof or io error */
307                 tpos += 2 * sizeof(afs_int32);
308                 code =
309                     (*adbase->truncate) (adbase, ntohl(buffer[0]),
310                                          ntohl(buffer[1]));
311                 if (code)
312                     return code;
313             } else if (opcode == LOGDATA) {
314                 tpos += 4;
315                 code =
316                     (*adbase->read) (adbase, LOGFILE, (char *)buffer, tpos,
317                                      3 * sizeof(afs_int32));
318                 if (code != 3 * sizeof(afs_int32))
319                     break;
320                 tpos += 3 * sizeof(afs_int32);
321                 /* otherwise, skip over the data bytes, too */
322                 len = ntohl(buffer[2]); /* total number of bytes to copy */
323                 filePos = ntohl(buffer[1]);
324                 tfile = ntohl(buffer[0]);
325                 /* try to minimize file syncs */
326                 if (syncFile != tfile) {
327                     if (syncFile >= 0)
328                         code = (*adbase->sync) (adbase, syncFile);
329                     else
330                         code = 0;
331                     syncFile = tfile;
332                     if (code)
333                         return code;
334                 }
335                 while (len > 0) {
336                     thisSize = (len > sizeof(data) ? sizeof(data) : len);
337                     /* copy sizeof(data) buffer bytes at a time */
338                     code =
339                         (*adbase->read) (adbase, LOGFILE, (char *)data, tpos,
340                                          thisSize);
341                     if (code != thisSize)
342                         return UBADLOG;
343                     code =
344                         (*adbase->write) (adbase, tfile, (char *)data, filePos,
345                                           thisSize);
346                     if (code != thisSize)
347                         return UBADLOG;
348                     filePos += thisSize;
349                     tpos += thisSize;
350                     len -= thisSize;
351                 }
352             } else {
353                 ViceLog(0, ("corrupt log opcode (%d) at position %d\n",
354                            opcode, tpos));
355                 break;          /* corrupt log! */
356             }
357         }
358         if (logIsGood) {
359             if (syncFile >= 0)
360                 code = (*adbase->sync) (adbase, syncFile);
361             if (code)
362                 return code;
363         } else {
364             ViceLog(0, ("Log read error on pass 2\n"));
365             return UBADLOG;
366         }
367     }
368
369     /* now truncate the log, we're done with it */
370     code = (*adbase->truncate) (adbase, LOGFILE, 0);
371     return code;
372 }
373
374 /*! \brief
375  * Called at initialization to figure out version of the dbase we really have.
376  *
377  * This routine is called after replaying the log; it reads the restored labels.
378  */
379 static int
380 InitializeDB(struct ubik_dbase *adbase)
381 {
382     afs_int32 code;
383
384     code = (*adbase->getlabel) (adbase, 0, &adbase->version);
385     if (code) {
386         /* try setting the label to a new value */
387         UBIK_VERSION_LOCK;
388         adbase->version.epoch = 1;      /* value for newly-initialized db */
389         adbase->version.counter = 1;
390         code = (*adbase->setlabel) (adbase, 0, &adbase->version);
391         if (code) {
392             /* failed, try to set it back */
393             adbase->version.epoch = 0;
394             adbase->version.counter = 0;
395             (*adbase->setlabel) (adbase, 0, &adbase->version);
396         }
397         UBIK_VERSION_UNLOCK;
398     }
399     return 0;
400 }
401
402 /*!
403  * \brief initialize the local ubik_dbase
404  *
405  * We replay the logs and then read the resulting file to figure out what version we've really got.
406  */
407 int
408 urecovery_Initialize(struct ubik_dbase *adbase)
409 {
410     afs_int32 code;
411
412     DBHOLD(adbase);
413     code = ReplayLog(adbase);
414     if (code)
415         goto done;
416     code = InitializeDB(adbase);
417 done:
418     DBRELE(adbase);
419     return code;
420 }
421
422 /*!
423  * \brief Main interaction loop for the recovery manager
424  *
425  * The recovery light-weight process only runs when you're the
426  * synchronization site.  It performs the following tasks, if and only
427  * if the prerequisite tasks have been performed successfully (it
428  * keeps track of which ones have been performed in its bit map,
429  * \p urecovery_state).
430  *
431  * First, it is responsible for probing that all servers are up.  This
432  * is the only operation that must be performed even if this is not
433  * yet the sync site, since otherwise this site may not notice that
434  * enough other machines are running to even elect this guy to be the
435  * sync site.
436  *
437  * After that, the recovery process does nothing until the beacon and
438  * voting modules manage to get this site elected sync site.
439  *
440  * After becoming sync site, recovery first attempts to find the best
441  * database available in the network (it must do this in order to
442  * ensure finding the latest committed data).  After finding the right
443  * database, it must fetch this dbase to the sync site.
444  *
445  * After fetching the dbase, it relabels it with a new version number,
446  * to ensure that everyone recognizes this dbase as the most recent
447  * dbase.
448  *
449  * One the dbase has been relabelled, this machine can start handling
450  * requests.  However, the recovery module still has one more task:
451  * propagating the dbase out to everyone who is up in the network.
452  */
453 void *
454 urecovery_Interact(void *dummy)
455 {
456     afs_int32 code;
457     struct ubik_server *bestServer = NULL;
458     struct ubik_server *ts;
459     int dbok, doingRPC, now;
460     afs_int32 lastProbeTime;
461     /* if we're the sync site, the best db version we've found yet */
462     static struct ubik_version bestDBVersion;
463     struct ubik_version tversion;
464     struct timeval tv;
465     int length, tlen, offset, file, nbytes;
466     struct rx_call *rxcall;
467     char tbuffer[1024];
468     struct ubik_stat ubikstat;
469     struct in_addr inAddr;
470     char hoststr[16];
471     char pbuffer[1028];
472     int fd = -1;
473     afs_int32 pass;
474
475     opr_threadname_set("recovery");
476
477     /* otherwise, begin interaction */
478     urecovery_state = 0;
479     lastProbeTime = 0;
480     while (1) {
481         /* Run through this loop every 4 seconds */
482         tv.tv_sec = 4;
483         tv.tv_usec = 0;
484 #ifdef AFS_PTHREAD_ENV
485         select(0, 0, 0, 0, &tv);
486 #else
487         IOMGR_Select(0, 0, 0, 0, &tv);
488 #endif
489
490         ViceLog(5, ("recovery running in state %x\n", urecovery_state));
491
492         /* Every 30 seconds, check all the down servers and mark them
493          * as up if they respond. When a server comes up or found to
494          * not be current, then re-find the the best database and
495          * propogate it.
496          */
497         if ((now = FT_ApproxTime()) > 30 + lastProbeTime) {
498
499             for (ts = ubik_servers, doingRPC = 0; ts; ts = ts->next) {
500                 UBIK_BEACON_LOCK;
501                 if (!ts->up) {
502                     UBIK_BEACON_UNLOCK;
503                     doingRPC = 1;
504                     code = DoProbe(ts);
505                     if (code == 0) {
506                         UBIK_BEACON_LOCK;
507                         ts->up = 1;
508                         UBIK_BEACON_UNLOCK;
509                         DBHOLD(ubik_dbase);
510                         urecovery_state &= ~UBIK_RECFOUNDDB;
511                         DBRELE(ubik_dbase);
512                     }
513                 } else {
514                     UBIK_BEACON_UNLOCK;
515                     DBHOLD(ubik_dbase);
516                     if (!ts->currentDB)
517                         urecovery_state &= ~UBIK_RECFOUNDDB;
518                     DBRELE(ubik_dbase);
519                 }
520             }
521
522             if (doingRPC)
523                 now = FT_ApproxTime();
524             lastProbeTime = now;
525         }
526
527         /* Mark whether we are the sync site */
528         DBHOLD(ubik_dbase);
529         if (!ubeacon_AmSyncSite()) {
530             urecovery_state &= ~UBIK_RECSYNCSITE;
531             DBRELE(ubik_dbase);
532             continue;           /* nothing to do */
533         }
534         urecovery_state |= UBIK_RECSYNCSITE;
535
536         /* If a server has just come up or if we have not found the
537          * most current database, then go find the most current db.
538          */
539         if (!(urecovery_state & UBIK_RECFOUNDDB)) {
540             int okcalls = 0;
541             DBRELE(ubik_dbase);
542             bestServer = (struct ubik_server *)0;
543             bestDBVersion.epoch = 0;
544             bestDBVersion.counter = 0;
545             for (ts = ubik_servers; ts; ts = ts->next) {
546                 UBIK_BEACON_LOCK;
547                 if (!ts->up) {
548                     UBIK_BEACON_UNLOCK;
549                     continue;   /* don't bother with these guys */
550                 }
551                 UBIK_BEACON_UNLOCK;
552                 if (ts->isClone)
553                     continue;
554                 UBIK_ADDR_LOCK;
555                 code = DISK_GetVersion(ts->disk_rxcid, &ts->version);
556                 UBIK_ADDR_UNLOCK;
557                 if (code == 0) {
558                     okcalls++;
559                     /* perhaps this is the best version */
560                     if (vcmp(ts->version, bestDBVersion) > 0) {
561                         /* new best version */
562                         bestDBVersion = ts->version;
563                         bestServer = ts;
564                     }
565                 }
566             }
567
568             DBHOLD(ubik_dbase);
569
570             if (okcalls + 1 >= ubik_quorum) {
571                 /* If we've asked a majority of sites about their db version,
572                  * then we can say with confidence that we've found the best db
573                  * version. If we haven't contacted most sites (because
574                  * GetVersion failed or because we already know the server is
575                  * down), then we don't really know if we know about the best
576                  * db version. So we can only proceed in here if 'okcalls'
577                  * indicates we managed to contact a majority of sites. */
578
579                 /* take into consideration our version. Remember if we,
580                  * the sync site, have the best version. Also note that
581                  * we may need to send the best version out.
582                  */
583                 if (vcmp(ubik_dbase->version, bestDBVersion) >= 0) {
584                     bestDBVersion = ubik_dbase->version;
585                     bestServer = (struct ubik_server *)0;
586                     urecovery_state |= UBIK_RECHAVEDB;
587                 } else {
588                     /* Clear the flag only when we know we have to retrieve
589                      * the db. Because urecovery_AllBetter() looks at it.
590                      */
591                     urecovery_state &= ~UBIK_RECHAVEDB;
592                 }
593                 urecovery_state |= UBIK_RECFOUNDDB;
594                 urecovery_state &= ~UBIK_RECSENTDB;
595             }
596         }
597         if (!(urecovery_state & UBIK_RECFOUNDDB)) {
598             DBRELE(ubik_dbase);
599             continue;           /* not ready */
600         }
601
602         /* If we, the sync site, do not have the best db version, then
603          * go and get it from the server that does.
604          */
605         if ((urecovery_state & UBIK_RECHAVEDB) || !bestServer) {
606             urecovery_state |= UBIK_RECHAVEDB;
607         } else {
608             /* we don't have the best version; we should fetch it. */
609             urecovery_AbortAll(ubik_dbase);
610
611             /* Rx code to do the Bulk fetch */
612             file = 0;
613             offset = 0;
614             UBIK_ADDR_LOCK;
615             rxcall = rx_NewCall(bestServer->disk_rxcid);
616
617             ViceLog(0, ("Ubik: Synchronize database: receive (via GetFile) "
618                         "from server %s begin\n",
619                        afs_inet_ntoa_r(bestServer->addr[0], hoststr)));
620             UBIK_ADDR_UNLOCK;
621
622             code = StartDISK_GetFile(rxcall, file);
623             if (code) {
624                 ViceLog(0, ("StartDiskGetFile failed=%d\n", code));
625                 goto FetchEndCall;
626             }
627             nbytes = rx_Read(rxcall, (char *)&length, sizeof(afs_int32));
628             length = ntohl(length);
629             if (nbytes != sizeof(afs_int32)) {
630                 ViceLog(0, ("Rx-read length error=%d\n", BULK_ERROR));
631                 code = EIO;
632                 goto FetchEndCall;
633             }
634
635             /* give invalid label during file transit */
636             UBIK_VERSION_LOCK;
637             tversion.epoch = 0;
638             code = (*ubik_dbase->setlabel) (ubik_dbase, file, &tversion);
639             UBIK_VERSION_UNLOCK;
640             if (code) {
641                 ViceLog(0, ("setlabel io error=%d\n", code));
642                 goto FetchEndCall;
643             }
644             snprintf(pbuffer, sizeof(pbuffer), "%s.DB%s%d.TMP",
645                      ubik_dbase->pathName, (file<0)?"SYS":"",
646                      (file<0)?-file:file);
647             fd = open(pbuffer, O_CREAT | O_RDWR | O_TRUNC, 0600);
648             if (fd < 0) {
649                 code = errno;
650                 goto FetchEndCall;
651             }
652             code = lseek(fd, HDRSIZE, 0);
653             if (code != HDRSIZE) {
654                 close(fd);
655                 goto FetchEndCall;
656             }
657
658             pass = 0;
659             while (length > 0) {
660                 tlen = (length > sizeof(tbuffer) ? sizeof(tbuffer) : length);
661 #ifndef AFS_PTHREAD_ENV
662                 if (pass % 4 == 0)
663                     IOMGR_Poll();
664 #endif
665                 nbytes = rx_Read(rxcall, tbuffer, tlen);
666                 if (nbytes != tlen) {
667                     ViceLog(0, ("Rx-read bulk error=%d\n", BULK_ERROR));
668                     code = EIO;
669                     close(fd);
670                     goto FetchEndCall;
671                 }
672                 nbytes = write(fd, tbuffer, tlen);
673                 pass++;
674                 if (nbytes != tlen) {
675                     code = UIOERROR;
676                     close(fd);
677                     goto FetchEndCall;
678                 }
679                 offset += tlen;
680                 length -= tlen;
681             }
682             code = close(fd);
683             if (code)
684                 goto FetchEndCall;
685             code = EndDISK_GetFile(rxcall, &tversion);
686           FetchEndCall:
687             code = rx_EndCall(rxcall, code);
688             if (!code) {
689                 /* we got a new file, set up its header */
690                 urecovery_state |= UBIK_RECHAVEDB;
691                 UBIK_VERSION_LOCK;
692                 memcpy(&ubik_dbase->version, &tversion,
693                        sizeof(struct ubik_version));
694                 snprintf(tbuffer, sizeof(tbuffer), "%s.DB%s%d",
695                          ubik_dbase->pathName, (file<0)?"SYS":"",
696                          (file<0)?-file:file);
697 #ifdef AFS_NT40_ENV
698                 snprintf(pbuffer, sizeof(pbuffer), "%s.DB%s%d.OLD",
699                          ubik_dbase->pathName, (file<0)?"SYS":"",
700                          (file<0)?-file:file);
701                 code = unlink(pbuffer);
702                 if (!code)
703                     code = rename(tbuffer, pbuffer);
704                 snprintf(pbuffer, sizeof(pbuffer), "%s.DB%s%d.TMP",
705                          ubik_dbase->pathName, (file<0)?"SYS":"",
706                          (file<0)?-file:file);
707 #endif
708                 if (!code)
709                     code = rename(pbuffer, tbuffer);
710                 if (!code) {
711                     (*ubik_dbase->open) (ubik_dbase, file);
712                     /* after data is good, sync disk with correct label */
713                     code =
714                         (*ubik_dbase->setlabel) (ubik_dbase, 0,
715                                                  &ubik_dbase->version);
716                 }
717                 UBIK_VERSION_UNLOCK;
718 #ifdef AFS_NT40_ENV
719                 snprintf(pbuffer, sizeof(pbuffer), "%s.DB%s%d.OLD",
720                          ubik_dbase->pathName, (file<0)?"SYS":"",
721                          (file<0)?-file:file);
722                 unlink(pbuffer);
723 #endif
724             }
725             if (code) {
726                 unlink(pbuffer);
727                 /*
728                  * We will effectively invalidate the old data forever now.
729                  * Unclear if we *should* but we do.
730                  */
731                 UBIK_VERSION_LOCK;
732                 ubik_dbase->version.epoch = 0;
733                 ubik_dbase->version.counter = 0;
734                 UBIK_VERSION_UNLOCK;
735                 ViceLog(0,
736                     ("Ubik: Synchronize database: receive (via GetFile) "
737                     "from server %s failed (error = %d)\n",
738                     afs_inet_ntoa_r(bestServer->addr[0], hoststr), code));
739             } else {
740                 ViceLog(0,
741                     ("Ubik: Synchronize database: receive (via GetFile) "
742                     "from server %s complete, version: %d.%d\n",
743                     afs_inet_ntoa_r(bestServer->addr[0], hoststr),
744                     ubik_dbase->version.epoch, ubik_dbase->version.counter));
745
746                 urecovery_state |= UBIK_RECHAVEDB;
747             }
748             udisk_Invalidate(ubik_dbase, 0);    /* data has changed */
749         }
750         if (!(urecovery_state & UBIK_RECHAVEDB)) {
751             DBRELE(ubik_dbase);
752             continue;           /* not ready */
753         }
754
755         /* If the database was newly initialized, then when we establish quorum, write
756          * a new label. This allows urecovery_AllBetter() to allow access for reads.
757          * Setting it to 2 also allows another site to come along with a newer
758          * database and overwrite this one.
759          */
760         if (ubik_dbase->version.epoch == 1) {
761             urecovery_AbortAll(ubik_dbase);
762             UBIK_VERSION_LOCK;
763             ubik_dbase->version.epoch = 2;
764             ubik_dbase->version.counter = 1;
765             code =
766                 (*ubik_dbase->setlabel) (ubik_dbase, 0, &ubik_dbase->version);
767             UBIK_VERSION_UNLOCK;
768             udisk_Invalidate(ubik_dbase, 0);    /* data may have changed */
769         }
770
771         /* Check the other sites and send the database to them if they
772          * do not have the current db.
773          */
774         if (!(urecovery_state & UBIK_RECSENTDB)) {
775             /* now propagate out new version to everyone else */
776             dbok = 1;           /* start off assuming they all worked */
777
778             /*
779              * Check if a write transaction is in progress. We can't send the
780              * db when a write is in progress here because the db would be
781              * obsolete as soon as it goes there. Also, ops after the begin
782              * trans would reach the recepient and wouldn't find a transaction
783              * pending there.  Frankly, I don't think it's possible to get past
784              * the write-lock above if there is a write transaction in progress,
785              * but then, it won't hurt to check, will it?
786              */
787             if (ubik_dbase->dbFlags & DBWRITING) {
788                 struct timeval tv;
789                 int safety = 0;
790                 long cur_usec = 50000;
791                 while ((ubik_dbase->dbFlags & DBWRITING) && (safety < 500)) {
792                     DBRELE(ubik_dbase);
793                     /* sleep for a little while */
794                     tv.tv_sec = 0;
795                     tv.tv_usec = cur_usec;
796 #ifdef AFS_PTHREAD_ENV
797                     select(0, 0, 0, 0, &tv);
798 #else
799                     IOMGR_Select(0, 0, 0, 0, &tv);
800 #endif
801                     cur_usec += 10000;
802                     safety++;
803                     DBHOLD(ubik_dbase);
804                 }
805             }
806
807             for (ts = ubik_servers; ts; ts = ts->next) {
808                 UBIK_ADDR_LOCK;
809                 inAddr.s_addr = ts->addr[0];
810                 UBIK_ADDR_UNLOCK;
811                 UBIK_BEACON_LOCK;
812                 if (!ts->up) {
813                     UBIK_BEACON_UNLOCK;
814                     /* It would be nice to have this message at loglevel
815                      * 0 as well, but it will log once every 4s for each
816                      * down server while in this recovery state.  This
817                      * should only be changed to loglevel 0 if it is
818                      * also rate-limited.
819                      */
820                     ViceLog(5, ("recovery cannot send version to %s\n",
821                                 afs_inet_ntoa_r(inAddr.s_addr, hoststr)));
822                     dbok = 0;
823                     continue;
824                 }
825                 UBIK_BEACON_UNLOCK;
826
827                 if (vcmp(ts->version, ubik_dbase->version) != 0) {
828                     ViceLog(0, ("Synchronize database: send (via SendFile) "
829                                 "to server %s begin\n",
830                             afs_inet_ntoa_r(inAddr.s_addr, hoststr)));
831
832                     /* Rx code to do the Bulk Store */
833                     code = (*ubik_dbase->stat) (ubik_dbase, 0, &ubikstat);
834                     if (!code) {
835                         length = ubikstat.size;
836                         file = offset = 0;
837                         UBIK_ADDR_LOCK;
838                         rxcall = rx_NewCall(ts->disk_rxcid);
839                         UBIK_ADDR_UNLOCK;
840                         code =
841                             StartDISK_SendFile(rxcall, file, length,
842                                                &ubik_dbase->version);
843                         if (code) {
844                             ViceLog(0, ("StartDiskSendFile failed=%d\n",
845                                         code));
846                             goto StoreEndCall;
847                         }
848                         while (length > 0) {
849                             tlen =
850                                 (length >
851                                  sizeof(tbuffer) ? sizeof(tbuffer) : length);
852                             nbytes =
853                                 (*ubik_dbase->read) (ubik_dbase, file,
854                                                      tbuffer, offset, tlen);
855                             if (nbytes != tlen) {
856                                 code = UIOERROR;
857                                 ViceLog(0, ("Local disk read error=%d\n", code));
858                                 goto StoreEndCall;
859                             }
860                             nbytes = rx_Write(rxcall, tbuffer, tlen);
861                             if (nbytes != tlen) {
862                                 code = BULK_ERROR;
863                                 ViceLog(0, ("Rx-write bulk error=%d\n", code));
864                                 goto StoreEndCall;
865                             }
866                             offset += tlen;
867                             length -= tlen;
868                         }
869                         code = EndDISK_SendFile(rxcall);
870                       StoreEndCall:
871                         code = rx_EndCall(rxcall, code);
872                     }
873
874                     if (code == 0) {
875                         /* we set a new file, process its header */
876                         ts->version = ubik_dbase->version;
877                         ts->currentDB = 1;
878                         ViceLog(0,
879                             ("Ubik: Synchronize database: send (via SendFile) "
880                             "to server %s complete, version: %d.%d\n",
881                             afs_inet_ntoa_r(inAddr.s_addr, hoststr),
882                             ts->version.epoch, ts->version.counter));
883
884                     } else {
885                         dbok = 0;
886                         ViceLog(0,
887                             ("Ubik: Synchronize database: send (via SendFile) "
888                              "to server %s failed (error = %d)\n",
889                             afs_inet_ntoa_r(inAddr.s_addr, hoststr), code));
890                     }
891                 } else {
892                     /* mark file up to date */
893                     ts->currentDB = 1;
894                 }
895             }
896             if (dbok)
897                 urecovery_state |= UBIK_RECSENTDB;
898         }
899         DBRELE(ubik_dbase);
900     }
901     AFS_UNREACHED(return(NULL));
902 }
903
904 /*!
905  * \brief send a Probe to all the network address of this server
906  *
907  * \return 0 if success, else return 1
908  */
909 int
910 DoProbe(struct ubik_server *server)
911 {
912     struct rx_connection *conns[UBIK_MAX_INTERFACE_ADDR];
913     struct rx_connection *connSuccess = 0;
914     int i, nconns, success_i = -1;
915     afs_uint32 addr;
916     char buffer[32];
917     char hoststr[16];
918
919     UBIK_ADDR_LOCK;
920     for (i = 0; (i < UBIK_MAX_INTERFACE_ADDR) && (addr = server->addr[i]);
921          i++) {
922         conns[i] =
923             rx_NewConnection(addr, ubik_callPortal, DISK_SERVICE_ID,
924                              addr_globals.ubikSecClass, addr_globals.ubikSecIndex);
925
926         /* user requirement to use only the primary interface */
927         if (ubikPrimaryAddrOnly) {
928             i = 1;
929             break;
930         }
931     }
932     UBIK_ADDR_UNLOCK;
933     nconns = i;
934     opr_Assert(nconns);                 /* at least one interface address for this server */
935
936     multi_Rx(conns, nconns) {
937         multi_DISK_Probe();
938         if (!multi_error) {     /* first success */
939             success_i = multi_i;
940
941             multi_Abort;
942         }
943     } multi_End_Ignore;
944
945     if (success_i >= 0) {
946         UBIK_ADDR_LOCK;
947         addr = server->addr[success_i]; /* successful interface addr */
948
949         if (server->disk_rxcid) /* destroy existing conn */
950             rx_DestroyConnection(server->disk_rxcid);
951         if (server->vote_rxcid)
952             rx_DestroyConnection(server->vote_rxcid);
953
954         /* make new connections */
955         server->disk_rxcid = conns[success_i];
956         server->vote_rxcid = rx_NewConnection(addr, ubik_callPortal,
957                                               VOTE_SERVICE_ID, addr_globals.ubikSecClass,
958                                               addr_globals.ubikSecIndex);
959
960         connSuccess = conns[success_i];
961         strcpy(buffer, afs_inet_ntoa_r(server->addr[0], hoststr));
962
963         ViceLog(0, ("ubik:server %s is back up: will be contacted through %s\n",
964              buffer, afs_inet_ntoa_r(addr, hoststr)));
965         UBIK_ADDR_UNLOCK;
966     }
967
968     /* Destroy all connections except the one on which we succeeded */
969     for (i = 0; i < nconns; i++)
970         if (conns[i] != connSuccess)
971             rx_DestroyConnection(conns[i]);
972
973     if (!connSuccess)
974         ViceLog(5, ("ubik:server %s still down\n",
975                     afs_inet_ntoa_r(server->addr[0], hoststr)));
976
977     if (connSuccess)
978         return 0;               /* success */
979     else
980         return 1;               /* failure */
981 }