Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

RepositoryMain.C

Go to the documentation of this file.
00001 // Copyright (C) 2001, Compaq Computer Corporation
00002 // 
00003 // This file is part of Vesta.
00004 // 
00005 // Vesta is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU Lesser General Public
00007 // License as published by the Free Software Foundation; either
00008 // version 2.1 of the License, or (at your option) any later version.
00009 // 
00010 // Vesta is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 // Lesser General Public License for more details.
00014 // 
00015 // You should have received a copy of the GNU Lesser General Public
00016 // License along with Vesta; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 
00019 //
00020 // RepositoryMain.C
00021 //
00022 // Main program for repository server
00023 //
00024 
00025 #include "VestaLog.H"
00026 #include "Recovery.H"
00027 #include "VestaSource.H"
00028 #include "ShortIdImpl.H"
00029 #include "ReadersWritersLock.H"
00030 #include "VRConcurrency.H"
00031 #include "VestaConfig.H"
00032 #include "VestaSourceServer.H"
00033 #include "VMemPool.H"
00034 #include "VRWeed.H"
00035 #include "DirShortId.H"
00036 #include "FPShortId.H"
00037 #include "Mastership.H"
00038 #include "Replication.H"
00039 #include "nfsd.H"
00040 #include "logging.H"
00041 #include "getopt.h"
00042 #include <stdlib.h>
00043 #include <pthread.h>
00044 #include <errno.h>
00045 #include <iomanip>
00046 #include <stdio.h>
00047 #include <signal.h>
00048 #include <sys/resource.h>
00049 #ifdef __osf__
00050 #include <sys/sysinfo.h>
00051 #include <machine/hal_sysinfo.h>
00052 #endif
00053 
00054 #include "MutableSidref.H"
00055 
00056 #include "timing.H"
00057 #include "lock_timing.H"
00058 
00059 using std::fstream;
00060 using std::endl;
00061 using std::cerr;
00062 using std::cout;
00063 
00064 #define progress(letter)
00065 //#define progress(letter) putc(letter, stderr)
00066 
00067 // Exported globals
00068 char *program_name;
00069 int nfs_bufreqs;  // # of NFS requests that should fit in socket buffer
00070 int nfs_threads;  // # of NFS server threads (0=use main thread)
00071 
00072 // Imported globals
00073 extern int nfs_port;
00074 extern void GlueInit();
00075 
00076 #define DEFAULT_UMASK 022
00077 
00078 static void usage(FILE *fp, int n)
00079 {
00080   cerr << "Usage: " << program_name
00081        << " [-h] [-d level] [-f first-ckp]" << endl;
00082   exit(n);
00083 }
00084 
00085 // Main driver for recovery.
00086 // Read first.ckp (if any), and first.log through the last log present.
00087 // If first == -1, read most recent ckp (if any) and log.
00088 void
00089 Recover(Text log_dir, int first, Text log_dir2, bool bakckp)
00090 {
00091     VRLog.open(log_dir.chars(), first, false, true,
00092                log_dir2.Empty() ? NULL : log_dir2.chars(), bakckp);
00093 
00094     fstream* ckpt = VRLog.openCheckpoint();
00095     if (ckpt != NULL) {
00096         VMemPool::readCheckpoint(*ckpt, false);
00097         RecoveryReader crr(ckpt);
00098         RecoverFrom(&crr);
00099         ckpt->close();
00100         delete ckpt;
00101     }
00102     if(MutableSidrefRecoveryCheck())
00103       {
00104         MutableSidrefInit();
00105       }
00106     // Recover log records following checkpoint
00107     do {
00108         RecoveryReader lrr(&VRLog);
00109         RecoverFrom(&lrr);
00110         if(MutableSidrefRecoveryCheck())
00111           {
00112             MutableSidrefCheck(0, LongId::noLock);
00113           }
00114     } while (VRLog.nextLog());
00115 }
00116 
00117 // Exit cleanly on SIGINT or SIGTERM
00118 #if defined(__linux__)
00119 // On Linux, we need to remember which is the main thread.
00120 static pthread_t g_main_thread = pthread_self();
00121 #endif
00122 extern "C" void
00123 SigHandler(int sig)
00124 {
00125 #if defined(__linux__)
00126   // The Linux pthreads implementation uses one process per thread.
00127   // The main thread will receive the signal from a ^C and then
00128   // proceed to call exit below.  This will in turn kill off the other
00129   // threads, delivering each of them a signal which will in turn call
00130   // this handler again.  If any of those threads then call exit, the
00131   // pthreads library seems to become confused and crashes.  For that
00132   // reason, we don't call exit unless we're the main thread.
00133   if(pthread_self() != g_main_thread)
00134     {
00135       return;
00136     }
00137 #endif
00138   char* msg;
00139   if (sig == SIGINT) {
00140     msg = "repository: Got SIGINT (^C interrupt signal); exiting.\n";
00141   } else if (sig == SIGTERM) {
00142     msg = "repository: Got SIGTERM (kill signal); exiting.\n";
00143   } else {
00144     assert(false);
00145   }
00146   write(2, msg, strlen(msg));
00147   exit(3);
00148 }
00149 
00150 // This is just a hook to hang breakpoints, etc. on.
00151 void
00152 Siguser1Inner(int sig)
00153 {
00154   return;
00155 }
00156 
00157 extern "C" void
00158 Sigusr1Handler(int sig)
00159 {
00160     Siguser1Inner(sig);
00161 }
00162 
00163 void
00164 Siguser2Inner(int sig)
00165 {
00166   return;
00167 }
00168 
00169 extern "C" void
00170 Sigusr2Handler(int sig)
00171 {
00172     Siguser2Inner(sig);
00173 }
00174 
00175 #ifdef __osf__
00176 extern int __first_fit;
00177 #endif
00178 
00179 // Server version.  This is defined in a file written in progs.ves.
00180 extern const char *Version;
00181 
00182 // Server start time, set in main.
00183 time_t serverStartTime;
00184 
00185 int
00186 main(int argc, char *argv[])
00187 {
00188     int c;
00189     sigset_t set;
00190 
00191     signal(SIGINT, SigHandler);
00192     signal(SIGTERM, SigHandler);
00193     signal(SIGPIPE, SIG_IGN);
00194     signal(SIGQUIT, SIG_DFL);
00195     signal(SIGSEGV, SIG_DFL);
00196     signal(SIGABRT, SIG_DFL);
00197     signal(SIGILL, SIG_DFL);
00198     signal(SIGBUS, SIG_DFL);
00199     signal(SIGUSR1, Sigusr1Handler);
00200     signal(SIGUSR2, Sigusr2Handler);
00201 
00202     // Set blocking on USR1 and USR2 signals for inheritance by child threads.
00203     sigemptyset(&set);
00204     sigaddset(&set, SIGUSR1);
00205     sigaddset(&set, SIGUSR2);
00206     sigprocmask(SIG_BLOCK, &set, NULL);
00207 
00208 #ifdef __osf__
00209     // Reduce lock contention during malloc/free
00210     __first_fit = 2;
00211 #endif
00212 
00213     // Read config file
00214     bool ok, bakckp = 0;
00215     Text metadata_root, log_dir, log_dir2, scratch;
00216     try {
00217         Text t;
00218         metadata_root = VestaConfig::get_Text("Repository", "metadata_root");
00219         chdir(metadata_root.cchars());
00220         SourceOrDerived::setMetadataRootLocalName("");
00221         nfs_port = VestaConfig::get_int("Repository", "NFS_port");
00222         log_dir = VestaConfig::get_Text("Repository", "log_dir");
00223         if (!VestaConfig::get("Repository", "log_dir2", log_dir2)) {
00224             log_dir2 = "";
00225         }
00226         if (VestaConfig::get("Repository", "backup_ckp", t)) {
00227             bakckp = strtol(t.cchars(), NULL, 0) != 0;
00228         }
00229         nfs_bufreqs = VestaConfig::get_int("Repository", "bufreqs");
00230         nfs_threads = VestaConfig::get_int("Repository", "threads");
00231         if (VestaConfig::get("Repository", "debug_level", t)) {
00232             Repos::setDebugLevel(strtol(t.cchars(), NULL, 0));
00233         }
00234         if (VestaConfig::get("Repository", "umask", t)) {
00235             umask(strtol(t.cchars(), NULL, 0));
00236         } else {
00237             umask(DEFAULT_UMASK);
00238         }
00239         // Optional setting of file descriptor limit.
00240         if(VestaConfig::get("Repository", "descriptor_limit", t))
00241           {
00242             int new_limit = strtol(t.cchars(), NULL, 0);
00243             if(errno == ERANGE)
00244               {
00245                 cerr << "[Repository]descriptor_limit: " << strerror(ERANGE)
00246                      << endl;
00247                 exit(2);
00248               }
00249 
00250 #ifdef __osf__
00251             // If needed, enable support for more than 4k file
00252             // descriptors.
00253             if(new_limit > 4096)
00254               {
00255                 int err = setsysinfo(SSI_FD_NEWMAX, NULL, 0, NULL, 1);
00256                 if(err != 0)
00257                   {
00258                     int l_errno = errno;
00259                     cerr << "Enabling more than 4096 descriptors: "
00260                          << strerror(l_errno) << endl;
00261                   }
00262               }
00263 #endif
00264             // Set the soft and hard file descriptor limit to the
00265             // requested value.
00266             struct rlimit new_rlimit;
00267             new_rlimit.rlim_cur = new_limit;
00268             new_rlimit.rlim_max = new_limit;
00269             int err = setrlimit(RLIMIT_NOFILE, &new_rlimit);
00270             if(err != 0)
00271               {
00272                 int l_errno = errno;
00273                 cerr << "setrlimit(RLIMIT_NOFILE, {"
00274                      << new_limit << ", " << new_limit << "}): "
00275                      << strerror(l_errno) << endl;
00276               }
00277           }
00278     } catch (VestaConfig::failure f) {
00279         cerr << f.msg << endl;
00280         exit(2);
00281     }
00282 
00283     /* Parse the command line options and arguments. */
00284     program_name = argv[0];
00285     int first = -1;
00286     opterr = 0;
00287     while ((c = getopt(argc, argv, "hd:f:")) != EOF)
00288       switch (c) {
00289         case 'h':
00290           usage(stdout, 0);
00291           break;
00292         case 'd':
00293           Repos::setDebugLevel(strtol(optarg, NULL, 0));
00294           break;
00295         case 'f':
00296           first = strtol(optarg, NULL, 0);
00297           break;
00298         case 0:
00299           break;
00300         case '?':
00301         default:
00302           usage(stderr, 1);
00303       }
00304 
00305     /* No more arguments allowed. */
00306     if (optind != argc)
00307       usage(stderr, 1);
00308 
00309     // Save previous core file if any
00310     if (Repos::isDebugLevel(DBG_SAVECORE)) {
00311         system("if [ -e core ] ; then mv core core.`date +%m-%d-%y.%T` ; fi");
00312     }
00313 
00314 #ifdef __osf__
00315     // If we think it'll work, set our thread scheduling policy to
00316     // round-robin rather than the default.
00317     Basics::thread::self().set_sched_param(SCHED_RR,
00318                                            sched_get_priority_min(SCHED_RR));
00319 #endif
00320 
00321     // Initialize server
00322     try {
00323         progress('a');
00324         ShortIdServerInit();
00325         progress('b');
00326         AccessControl::serverInit();
00327         progress('c');
00328         VestaSource::init();
00329         progress('d');
00330         InitDirShortId();
00331         progress('e');
00332         InitFPShortId();
00333         progress('f');
00334         MastershipInit1();
00335         progress('g');
00336         Recover(log_dir, first, log_dir2, bakckp);
00337         progress('h');
00338         VRLog.loggingBegin();
00339         progress('i');
00340         if (!Repos::isDebugLevel(DBG_NOWEEDREC)) {
00341             int err = SourceWeed();
00342             if (err) {
00343                 Repos::dprintf(DBG_ALWAYS,
00344                                "source weed failed during recovery, errno = %d\n", err);
00345                 abort();
00346             }
00347             err = DoDeletions();
00348             if (err) {
00349                 Repos::dprintf(DBG_ALWAYS,
00350                                "deletions failed during recovery, errno = %d\n", err);
00351                 abort();
00352             }
00353         }
00354         progress('j');
00355         ShortIdServerInit2();
00356         progress('k');
00357         ShortIdServerExport(NULL);
00358         progress('l');
00359         VestaSource::recoveryDone(); // turns on logging
00360         progress('m');
00361         MastershipInit2();
00362         progress('n');
00363         ReplicationCleanup();
00364         progress('o');
00365         // Record the start time before we start accepting SRPC calls
00366         serverStartTime = time((time_t *) 0);
00367         VestaSourceServerExport();
00368         progress('p');
00369         GlueInit();
00370         progress('q');
00371         nfsd_init(nfs_threads);
00372         progress('r');
00373         Repos::dprintf(DBG_ALWAYS, "Repository server started.  Version %s\n",
00374                        Version);
00375 
00376         // Use main thread for checkpointing (which needs deep recursion)
00377         // and to handle SIGUSR1 and SIGUSR2 (which need deep recursion if
00378         // tied to Third Degree leak checking).
00379         sigemptyset(&set);
00380         sigaddset(&set, SIGUSR1);
00381         sigaddset(&set, SIGUSR2);
00382         sigprocmask(SIG_UNBLOCK, &set, NULL);
00383         progress('s');
00384         CheckpointServer(); // does not return
00385 
00386     } catch (SRPC::failure f) {
00387         cerr << program_name << ": SRPC::failure in initialization: "
00388           << f.msg << " (" << f.r << ")" << endl;
00389         abort();
00390     } catch (VestaLog::Error e) {
00391         cerr << program_name << ": VestaLog::Error in initialization: "
00392           << e.msg << " (" << e.r << ")" << endl;
00393         if (e.msg == "VestaLog::open got \"Permission denied\" locking lock") {
00394             cerr << "Check if there is already a repository running."<< endl;
00395             exit(1);
00396         } else if (e.msg ==
00397                    "VestaLog::open got \"Permission denied\" opening lock") {
00398             cerr << "Check that you have the right user id." << endl;
00399             exit(1);
00400         }
00401         abort();
00402     } catch (VestaConfig::failure f) {
00403         cerr << f.msg << endl;
00404         exit(2);
00405     }
00406 
00407     // Not reached
00408     assert(false);
00409     return 0;
00410 }
00411 

Generated on Mon May 8 00:48:46 2006 for Vesta by  doxygen 1.4.2