rx: Remove delays in multi_End_Ignore
[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     memset(pbuffer, 0, sizeof(pbuffer));
476
477     opr_threadname_set("recovery");
478
479     /* otherwise, begin interaction */
480     urecovery_state = 0;
481     lastProbeTime = 0;
482     while (1) {
483         /* Run through this loop every 4 seconds */
484         tv.tv_sec = 4;
485         tv.tv_usec = 0;
486 #ifdef AFS_PTHREAD_ENV
487         select(0, 0, 0, 0, &tv);
488 #else
489         IOMGR_Select(0, 0, 0, 0, &tv);
490 #endif
491
492         ViceLog(5, ("recovery running in state %x\n", urecovery_state));
493
494         /* Every 30 seconds, check all the down servers and mark them
495          * as up if they respond. When a server comes up or found to
496          * not be current, then re-find the the best database and
497          * propogate it.
498          */
499         if ((now = FT_ApproxTime()) > 30 + lastProbeTime) {
500
501             for (ts = ubik_servers, doingRPC = 0; ts; ts = ts->next) {
502                 UBIK_BEACON_LOCK;
503                 if (!ts->up) {
504                     UBIK_BEACON_UNLOCK;
505                     doingRPC = 1;
506                     code = DoProbe(ts);
507                     if (code == 0) {
508                         UBIK_BEACON_LOCK;
509                         ts->up = 1;
510                         UBIK_BEACON_UNLOCK;
511                         DBHOLD(ubik_dbase);
512                         urecovery_state &= ~UBIK_RECFOUNDDB;
513                         DBRELE(ubik_dbase);
514                     }
515                 } else {
516                     UBIK_BEACON_UNLOCK;
517                     DBHOLD(ubik_dbase);
518                     if (!ts->currentDB)
519                         urecovery_state &= ~UBIK_RECFOUNDDB;
520                     DBRELE(ubik_dbase);
521                 }
522             }
523
524             if (doingRPC)
525                 now = FT_ApproxTime();
526             lastProbeTime = now;
527         }
528
529         /* Mark whether we are the sync site */
530         DBHOLD(ubik_dbase);
531         if (!ubeacon_AmSyncSite()) {
532             urecovery_state &= ~UBIK_RECSYNCSITE;
533             DBRELE(ubik_dbase);
534             continue;           /* nothing to do */
535         }
536         urecovery_state |= UBIK_RECSYNCSITE;
537
538         /* If a server has just come up or if we have not found the
539          * most current database, then go find the most current db.
540          */
541         if (!(urecovery_state & UBIK_RECFOUNDDB)) {
542             int okcalls = 0;
543             DBRELE(ubik_dbase);
544             bestServer = (struct ubik_server *)0;
545             bestDBVersion.epoch = 0;
546             bestDBVersion.counter = 0;
547             for (ts = ubik_servers; ts; ts = ts->next) {
548                 UBIK_BEACON_LOCK;
549                 if (!ts->up) {
550                     UBIK_BEACON_UNLOCK;
551                     continue;   /* don't bother with these guys */
552                 }
553                 UBIK_BEACON_UNLOCK;
554                 if (ts->isClone)
555                     continue;
556                 UBIK_ADDR_LOCK;
557                 code = DISK_GetVersion(ts->disk_rxcid, &ts->version);
558                 UBIK_ADDR_UNLOCK;
559                 if (code == 0) {
560                     okcalls++;
561                     /* perhaps this is the best version */
562                     if (vcmp(ts->version, bestDBVersion) > 0) {
563                         /* new best version */
564                         bestDBVersion = ts->version;
565                         bestServer = ts;
566                     }
567                 }
568             }
569
570             DBHOLD(ubik_dbase);
571
572             if (okcalls + 1 >= ubik_quorum) {
573                 /* If we've asked a majority of sites about their db version,
574                  * then we can say with confidence that we've found the best db
575                  * version. If we haven't contacted most sites (because
576                  * GetVersion failed or because we already know the server is
577                  * down), then we don't really know if we know about the best
578                  * db version. So we can only proceed in here if 'okcalls'
579                  * indicates we managed to contact a majority of sites. */
580
581                 /* take into consideration our version. Remember if we,
582                  * the sync site, have the best version. Also note that
583                  * we may need to send the best version out.
584                  */
585                 if (vcmp(ubik_dbase->version, bestDBVersion) >= 0) {
586                     bestDBVersion = ubik_dbase->version;
587                     bestServer = (struct ubik_server *)0;
588                     urecovery_state |= UBIK_RECHAVEDB;
589                 } else {
590                     /* Clear the flag only when we know we have to retrieve
591                      * the db. Because urecovery_AllBetter() looks at it.
592                      */
593                     urecovery_state &= ~UBIK_RECHAVEDB;
594                 }
595                 urecovery_state |= UBIK_RECFOUNDDB;
596                 urecovery_state &= ~UBIK_RECSENTDB;
597             }
598         }
599         if (!(urecovery_state & UBIK_RECFOUNDDB)) {
600             DBRELE(ubik_dbase);
601             continue;           /* not ready */
602         }
603
604         /* If we, the sync site, do not have the best db version, then
605          * go and get it from the server that does.
606          */
607         if ((urecovery_state & UBIK_RECHAVEDB) || !bestServer) {
608             urecovery_state |= UBIK_RECHAVEDB;
609         } else {
610             /* we don't have the best version; we should fetch it. */
611             urecovery_AbortAll(ubik_dbase);
612
613             pbuffer[0] = '\0';
614
615             /* Rx code to do the Bulk fetch */
616             file = 0;
617             offset = 0;
618             UBIK_ADDR_LOCK;
619             rxcall = rx_NewCall(bestServer->disk_rxcid);
620
621             ViceLog(0, ("Ubik: Synchronize database: receive (via GetFile) "
622                         "from server %s begin\n",
623                        afs_inet_ntoa_r(bestServer->addr[0], hoststr)));
624             UBIK_ADDR_UNLOCK;
625
626             code = StartDISK_GetFile(rxcall, file);
627             if (code) {
628                 ViceLog(0, ("StartDiskGetFile failed=%d\n", code));
629                 goto FetchEndCall;
630             }
631             nbytes = rx_Read(rxcall, (char *)&length, sizeof(afs_int32));
632             length = ntohl(length);
633             if (nbytes != sizeof(afs_int32)) {
634                 ViceLog(0, ("Rx-read length error=%d\n", BULK_ERROR));
635                 code = EIO;
636                 goto FetchEndCall;
637             }
638
639             /* give invalid label during file transit */
640             UBIK_VERSION_LOCK;
641             tversion.epoch = 0;
642             code = (*ubik_dbase->setlabel) (ubik_dbase, file, &tversion);
643             UBIK_VERSION_UNLOCK;
644             if (code) {
645                 ViceLog(0, ("setlabel io error=%d\n", code));
646                 goto FetchEndCall;
647             }
648             snprintf(pbuffer, sizeof(pbuffer), "%s.DB%s%d.TMP",
649                      ubik_dbase->pathName, (file<0)?"SYS":"",
650                      (file<0)?-file:file);
651             fd = open(pbuffer, O_CREAT | O_RDWR | O_TRUNC, 0600);
652             if (fd < 0) {
653                 code = errno;
654                 goto FetchEndCall;
655             }
656             code = lseek(fd, HDRSIZE, 0);
657             if (code != HDRSIZE) {
658                 close(fd);
659                 goto FetchEndCall;
660             }
661
662             pass = 0;
663             while (length > 0) {
664                 tlen = (length > sizeof(tbuffer) ? sizeof(tbuffer) : length);
665 #ifndef AFS_PTHREAD_ENV
666                 if (pass % 4 == 0)
667                     IOMGR_Poll();
668 #endif
669                 nbytes = rx_Read(rxcall, tbuffer, tlen);
670                 if (nbytes != tlen) {
671                     ViceLog(0, ("Rx-read bulk error=%d\n", BULK_ERROR));
672                     code = EIO;
673                     close(fd);
674                     goto FetchEndCall;
675                 }
676                 nbytes = write(fd, tbuffer, tlen);
677                 pass++;
678                 if (nbytes != tlen) {
679                     code = UIOERROR;
680                     close(fd);
681                     goto FetchEndCall;
682                 }
683                 offset += tlen;
684                 length -= tlen;
685             }
686             code = close(fd);
687             if (code)
688                 goto FetchEndCall;
689             code = EndDISK_GetFile(rxcall, &tversion);
690           FetchEndCall:
691             code = rx_EndCall(rxcall, code);
692             if (!code) {
693                 /* we got a new file, set up its header */
694                 urecovery_state |= UBIK_RECHAVEDB;
695                 UBIK_VERSION_LOCK;
696                 memcpy(&ubik_dbase->version, &tversion,
697                        sizeof(struct ubik_version));
698                 snprintf(tbuffer, sizeof(tbuffer), "%s.DB%s%d",
699                          ubik_dbase->pathName, (file<0)?"SYS":"",
700                          (file<0)?-file:file);
701 #ifdef AFS_NT40_ENV
702                 snprintf(pbuffer, sizeof(pbuffer), "%s.DB%s%d.OLD",
703                          ubik_dbase->pathName, (file<0)?"SYS":"",
704                          (file<0)?-file:file);
705                 code = unlink(pbuffer);
706                 if (!code)
707                     code = rename(tbuffer, pbuffer);
708                 snprintf(pbuffer, sizeof(pbuffer), "%s.DB%s%d.TMP",
709                          ubik_dbase->pathName, (file<0)?"SYS":"",
710                          (file<0)?-file:file);
711 #endif
712                 if (!code)
713                     code = rename(pbuffer, tbuffer);
714                 if (!code) {
715                     (*ubik_dbase->open) (ubik_dbase, file);
716                     /* after data is good, sync disk with correct label */
717                     code =
718                         (*ubik_dbase->setlabel) (ubik_dbase, 0,
719                                                  &ubik_dbase->version);
720                 }
721                 UBIK_VERSION_UNLOCK;
722 #ifdef AFS_NT40_ENV
723                 snprintf(pbuffer, sizeof(pbuffer), "%s.DB%s%d.OLD",
724                          ubik_dbase->pathName, (file<0)?"SYS":"",
725                          (file<0)?-file:file);
726                 unlink(pbuffer);
727 #endif
728             }
729             if (code) {
730                 if (pbuffer[0] != '\0') {
731                     unlink(pbuffer);
732                 }
733                 /*
734                  * We will effectively invalidate the old data forever now.
735                  * Unclear if we *should* but we do.
736                  */
737                 UBIK_VERSION_LOCK;
738                 ubik_dbase->version.epoch = 0;
739                 ubik_dbase->version.counter = 0;
740                 UBIK_VERSION_UNLOCK;
741                 ViceLog(0,
742                     ("Ubik: Synchronize database: receive (via GetFile) "
743                     "from server %s failed (error = %d)\n",
744                     afs_inet_ntoa_r(bestServer->addr[0], hoststr), code));
745             } else {
746                 ViceLog(0,
747                     ("Ubik: Synchronize database: receive (via GetFile) "
748                     "from server %s complete, version: %d.%d\n",
749                     afs_inet_ntoa_r(bestServer->addr[0], hoststr),
750                     ubik_dbase->version.epoch, ubik_dbase->version.counter));
751
752                 urecovery_state |= UBIK_RECHAVEDB;
753             }
754             udisk_Invalidate(ubik_dbase, 0);    /* data has changed */
755         }
756         if (!(urecovery_state & UBIK_RECHAVEDB)) {
757             DBRELE(ubik_dbase);
758             continue;           /* not ready */
759         }
760
761         /* If the database was newly initialized, then when we establish quorum, write
762          * a new label. This allows urecovery_AllBetter() to allow access for reads.
763          * Setting it to 2 also allows another site to come along with a newer
764          * database and overwrite this one.
765          */
766         if (ubik_dbase->version.epoch == 1) {
767             urecovery_AbortAll(ubik_dbase);
768             UBIK_VERSION_LOCK;
769             ubik_dbase->version.epoch = 2;
770             ubik_dbase->version.counter = 1;
771             code =
772                 (*ubik_dbase->setlabel) (ubik_dbase, 0, &ubik_dbase->version);
773             UBIK_VERSION_UNLOCK;
774             udisk_Invalidate(ubik_dbase, 0);    /* data may have changed */
775         }
776
777         /* Check the other sites and send the database to them if they
778          * do not have the current db.
779          */
780         if (!(urecovery_state & UBIK_RECSENTDB)) {
781             /* now propagate out new version to everyone else */
782             dbok = 1;           /* start off assuming they all worked */
783
784             /*
785              * Check if a write transaction is in progress. We can't send the
786              * db when a write is in progress here because the db would be
787              * obsolete as soon as it goes there. Also, ops after the begin
788              * trans would reach the recepient and wouldn't find a transaction
789              * pending there.  Frankly, I don't think it's possible to get past
790              * the write-lock above if there is a write transaction in progress,
791              * but then, it won't hurt to check, will it?
792              */
793             if (ubik_dbase->dbFlags & DBWRITING) {
794                 struct timeval tv;
795                 int safety = 0;
796                 long cur_usec = 50000;
797                 while ((ubik_dbase->dbFlags & DBWRITING) && (safety < 500)) {
798                     DBRELE(ubik_dbase);
799                     /* sleep for a little while */
800                     tv.tv_sec = 0;
801                     tv.tv_usec = cur_usec;
802 #ifdef AFS_PTHREAD_ENV
803                     select(0, 0, 0, 0, &tv);
804 #else
805                     IOMGR_Select(0, 0, 0, 0, &tv);
806 #endif
807                     cur_usec += 10000;
808                     safety++;
809                     DBHOLD(ubik_dbase);
810                 }
811             }
812
813             for (ts = ubik_servers; ts; ts = ts->next) {
814                 UBIK_ADDR_LOCK;
815                 inAddr.s_addr = ts->addr[0];
816                 UBIK_ADDR_UNLOCK;
817                 UBIK_BEACON_LOCK;
818                 if (!ts->up) {
819                     UBIK_BEACON_UNLOCK;
820                     /* It would be nice to have this message at loglevel
821                      * 0 as well, but it will log once every 4s for each
822                      * down server while in this recovery state.  This
823                      * should only be changed to loglevel 0 if it is
824                      * also rate-limited.
825                      */
826                     ViceLog(5, ("recovery cannot send version to %s\n",
827                                 afs_inet_ntoa_r(inAddr.s_addr, hoststr)));
828                     dbok = 0;
829                     continue;
830                 }
831                 UBIK_BEACON_UNLOCK;
832
833                 if (vcmp(ts->version, ubik_dbase->version) != 0) {
834                     ViceLog(0, ("Synchronize database: send (via SendFile) "
835                                 "to server %s begin\n",
836                             afs_inet_ntoa_r(inAddr.s_addr, hoststr)));
837
838                     /* Rx code to do the Bulk Store */
839                     code = (*ubik_dbase->stat) (ubik_dbase, 0, &ubikstat);
840                     if (!code) {
841                         length = ubikstat.size;
842                         file = offset = 0;
843                         UBIK_ADDR_LOCK;
844                         rxcall = rx_NewCall(ts->disk_rxcid);
845                         UBIK_ADDR_UNLOCK;
846                         code =
847                             StartDISK_SendFile(rxcall, file, length,
848                                                &ubik_dbase->version);
849                         if (code) {
850                             ViceLog(0, ("StartDiskSendFile failed=%d\n",
851                                         code));
852                             goto StoreEndCall;
853                         }
854                         while (length > 0) {
855                             tlen =
856                                 (length >
857                                  sizeof(tbuffer) ? sizeof(tbuffer) : length);
858                             nbytes =
859                                 (*ubik_dbase->read) (ubik_dbase, file,
860                                                      tbuffer, offset, tlen);
861                             if (nbytes != tlen) {
862                                 code = UIOERROR;
863                                 ViceLog(0, ("Local disk read error=%d\n", code));
864                                 goto StoreEndCall;
865                             }
866                             nbytes = rx_Write(rxcall, tbuffer, tlen);
867                             if (nbytes != tlen) {
868                                 code = BULK_ERROR;
869                                 ViceLog(0, ("Rx-write bulk error=%d\n", code));
870                                 goto StoreEndCall;
871                             }
872                             offset += tlen;
873                             length -= tlen;
874                         }
875                         code = EndDISK_SendFile(rxcall);
876                       StoreEndCall:
877                         code = rx_EndCall(rxcall, code);
878                     }
879
880                     if (code == 0) {
881                         /* we set a new file, process its header */
882                         ts->version = ubik_dbase->version;
883                         ts->currentDB = 1;
884                         ViceLog(0,
885                             ("Ubik: Synchronize database: send (via SendFile) "
886                             "to server %s complete, version: %d.%d\n",
887                             afs_inet_ntoa_r(inAddr.s_addr, hoststr),
888                             ts->version.epoch, ts->version.counter));
889
890                     } else {
891                         dbok = 0;
892                         ViceLog(0,
893                             ("Ubik: Synchronize database: send (via SendFile) "
894                              "to server %s failed (error = %d)\n",
895                             afs_inet_ntoa_r(inAddr.s_addr, hoststr), code));
896                     }
897                 } else {
898                     /* mark file up to date */
899                     ts->currentDB = 1;
900                 }
901             }
902             if (dbok)
903                 urecovery_state |= UBIK_RECSENTDB;
904         }
905         DBRELE(ubik_dbase);
906     }
907     AFS_UNREACHED(return(NULL));
908 }
909
910 /*!
911  * \brief send a Probe to all the network address of this server
912  *
913  * \return 0 if success, else return 1
914  */
915 int
916 DoProbe(struct ubik_server *server)
917 {
918     struct rx_connection *conns[UBIK_MAX_INTERFACE_ADDR];
919     struct rx_connection *connSuccess = 0;
920     int i, nconns, success_i = -1;
921     afs_uint32 addr;
922     char buffer[32];
923     char hoststr[16];
924
925     UBIK_ADDR_LOCK;
926     for (i = 0; (i < UBIK_MAX_INTERFACE_ADDR) && (addr = server->addr[i]);
927          i++) {
928         conns[i] =
929             rx_NewConnection(addr, ubik_callPortal, DISK_SERVICE_ID,
930                              addr_globals.ubikSecClass, addr_globals.ubikSecIndex);
931
932         /* user requirement to use only the primary interface */
933         if (ubikPrimaryAddrOnly) {
934             i = 1;
935             break;
936         }
937     }
938     UBIK_ADDR_UNLOCK;
939     nconns = i;
940     opr_Assert(nconns);                 /* at least one interface address for this server */
941
942     multi_Rx(conns, nconns) {
943         multi_DISK_Probe();
944         if (!multi_error) {     /* first success */
945             success_i = multi_i;
946
947             multi_Abort;
948         }
949     } multi_End;
950
951     if (success_i >= 0) {
952         UBIK_ADDR_LOCK;
953         addr = server->addr[success_i]; /* successful interface addr */
954
955         if (server->disk_rxcid) /* destroy existing conn */
956             rx_DestroyConnection(server->disk_rxcid);
957         if (server->vote_rxcid)
958             rx_DestroyConnection(server->vote_rxcid);
959
960         /* make new connections */
961         server->disk_rxcid = conns[success_i];
962         server->vote_rxcid = rx_NewConnection(addr, ubik_callPortal,
963                                               VOTE_SERVICE_ID, addr_globals.ubikSecClass,
964                                               addr_globals.ubikSecIndex);
965
966         connSuccess = conns[success_i];
967         strcpy(buffer, afs_inet_ntoa_r(server->addr[0], hoststr));
968
969         ViceLog(0, ("ubik:server %s is back up: will be contacted through %s\n",
970              buffer, afs_inet_ntoa_r(addr, hoststr)));
971         UBIK_ADDR_UNLOCK;
972     }
973
974     /* Destroy all connections except the one on which we succeeded */
975     for (i = 0; i < nconns; i++)
976         if (conns[i] != connSuccess)
977             rx_DestroyConnection(conns[i]);
978
979     if (!connSuccess)
980         ViceLog(5, ("ubik:server %s still down\n",
981                     afs_inet_ntoa_r(server->addr[0], hoststr)));
982
983     if (connSuccess)
984         return 0;               /* success */
985     else
986         return 1;               /* failure */
987 }