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

SourceOrDerived.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 // SourceOrDerived.C
00021 // Last modified on Mon Jan  9 22:35:39 EST 2006 by ken@xorian.net   
00022 //      modified on Thu Jul 20 14:28:02 PDT 2000 by mann   
00023 //      modified on Tue May  4 10:51:02 PDT 1999 by heydon 
00024 //
00025 // Library code to implement SourceOrDerived.H
00026 // 
00027 
00028 #include <Basics.H>
00029 #include "SourceOrDerived.H"
00030 #include "ShortIdBlock.H"
00031 #include <VestaConfig.H>
00032 #include <Thread.H>
00033 #include <pthread.h>
00034 #include <assert.h>
00035 #include <iomanip>
00036 #include <errno.h>
00037 #if defined(__unix) || defined(__linux__)
00038 #include <unistd.h>
00039 #endif
00040 #include <stdio.h>
00041 #if defined(__digital__)
00042 #include <sys/mode.h>
00043 #endif
00044 #if defined (__linux__)
00045 #include <signal.h>
00046 #endif
00047 #include <sys/stat.h>
00048 #include <fcntl.h>
00049 
00050 #include <FS.H>
00051 
00052 using std::cerr;
00053 using std::endl;
00054 using std::hex;
00055 using std::fstream;
00056 using std::ios;
00057 
00058 // Directory modes for SID files hardwired here
00059 const int SID_DIR_MODE = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
00060 
00061 const int LeaseSafetyMargin = 60; // sec
00062 
00063 //
00064 // We keep a stockpile of each kind of short id.
00065 //
00066 
00067 class ShortIdStock {
00068     bool leafflag;
00069     ShortIdBlock *block[2];   // one block in use, one in reserve
00070     int usng;                 // block number we are allocating from, 0 or 1
00071     Basics::mutex mu;
00072     Basics::cond need;        // broadcast whenever a block is used up
00073     Basics::cond have;        // broadcast when no blocks were available,
00074                               //  and one is acquired
00075     Basics::thread stockboy_; // gets more blocks
00076     static void *stockboy(void *arg);
00077   public:
00078     ShortIdStock(bool leafflag);
00079     ShortId newShortId();
00080 };
00081 
00082 typedef ShortIdStock *ShortIdStockP;
00083 
00084 static ShortIdStockP stock[2];
00085 static pthread_once_t stockOnce = PTHREAD_ONCE_INIT;
00086 static pthread_once_t mrlnOnce = PTHREAD_ONCE_INIT;
00087 static Basics::mutex mu;
00088 static char* metadataRootLocalName = NULL;
00089 
00090 extern "C"
00091 {
00092   static void 
00093   SourceOrDerived_initStock()
00094   {
00095     stock[0] = NEW_CONSTR(ShortIdStock, (false));
00096     stock[1] = NEW_CONSTR(ShortIdStock, (true));
00097   }
00098 
00099   void
00100   SourceOrDerived_initMRLN()
00101   {
00102     try {
00103         Text mrtext;
00104         mrtext = VestaConfig::get_Text("Repository", "metadata_root");
00105         metadataRootLocalName = strdup(mrtext.cchars());
00106     } catch (VestaConfig::failure f) {
00107         cerr << "SourceOrDerived_initMRLN: " << f.msg << endl;
00108         throw; // meant to be uncaught and fatal
00109     }
00110   }
00111 }
00112 
00113 void
00114 SourceOrDerived::setMetadataRootLocalName(char* pathname) throw ()
00115 {
00116     int err = pthread_once(&mrlnOnce, SourceOrDerived_initMRLN);
00117     assert(err == 0);
00118     mu.lock();
00119     free(metadataRootLocalName);
00120     metadataRootLocalName = strdup(pathname);
00121     mu.unlock();
00122 }
00123 
00124 char*
00125 SourceOrDerived::getMetadataRootLocalName() throw ()
00126 {
00127     int err = pthread_once(&mrlnOnce, SourceOrDerived_initMRLN);
00128     assert(err == 0);
00129     mu.lock();
00130     char* ret = strdup(metadataRootLocalName);
00131     mu.unlock();
00132     return ret;
00133 }
00134 
00135 // 
00136 // Constructor for a ShortIdStock
00137 //
00138 ShortIdStock::ShortIdStock(bool leafflag)
00139 {
00140     ShortIdStock::leafflag = leafflag;
00141     block[0] = block[1] = NULL;
00142     usng = 0;
00143 
00144     Basics::thread_attr stockboy_attr;
00145 #if defined (_POSIX_THREAD_PRIORITY_SCHEDULING) && !defined(__linux__)
00146     // Linux only allows the superuser to use SCHED_RR
00147     stockboy_attr.set_schedpolicy(SCHED_RR);
00148     stockboy_attr.set_inheritsched(PTHREAD_EXPLICIT_SCHED);
00149     stockboy_attr.set_sched_priority(sched_get_priority_min(SCHED_RR));
00150 #endif
00151   
00152     stockboy_.fork(stockboy, (void *) this, stockboy_attr);
00153 }
00154 
00155 //
00156 // Stockboy thread.  Gets more ShortId blocks to keep some in stock.
00157 //
00158 void *
00159 ShortIdStock::stockboy(void *arg)
00160 {
00161     ShortIdStock *mystock = (ShortIdStock *) arg;
00162     ShortIdBlock *newblock;
00163     
00164     signal(SIGPIPE, SIG_IGN);
00165     signal(SIGQUIT, SIG_DFL);
00166     //signal(SIGSEGV, SIG_DFL); // oops, process may be using incremental GC
00167     signal(SIGABRT, SIG_DFL);
00168     signal(SIGILL, SIG_DFL);
00169     signal(SIGBUS, SIG_DFL);
00170 
00171     mystock->mu.lock();
00172     for (;;) {
00173       outer_continue:
00174         struct timespec wakeup;
00175         wakeup.tv_sec = 0x7fffffff;
00176         wakeup.tv_nsec = 0;
00177         bool need_wakeup = false;
00178         try {
00179             int which;
00180             for (which = 0; which <= 1; which++) {
00181                 if (mystock->block[which] != NULL &&
00182                     time(0) > mystock->block[which]->leaseExpires) {
00183                     // Lease already expired.  Should not happen.
00184                     cerr << "ShortIdStock::stockboy: "
00185                       << "internal error - expired lease on block 0x" << hex
00186                       << mystock->block[which]->start << endl;
00187                     delete mystock->block[which];
00188                     mystock->block[which] = NULL;
00189                 }
00190                 if (mystock->block[which] == NULL) {
00191                     mystock->mu.unlock();
00192                     newblock = ShortIdBlock::acquire(mystock->leafflag);
00193                     mystock->mu.lock();
00194                     assert(mystock->block[which] == NULL);
00195                     mystock->block[which] = newblock;
00196                     if (mystock->block[mystock->usng] == NULL) {
00197                         mystock->usng = which;
00198                     }
00199                     mystock->have.broadcast();
00200                     goto outer_continue;
00201                 }
00202                 if (time(0) >= (mystock->block[which]->leaseExpires -
00203                                 2*LeaseSafetyMargin)) {
00204                     mystock->mu.unlock();
00205                     bool leaseValid =
00206                       ShortIdBlock::renew(mystock->block[which]);
00207                     assert(leaseValid);
00208                     mystock->mu.lock();
00209                     goto outer_continue;
00210                 }
00211                 if ((mystock->block[which]->leaseExpires !=
00212                      ShortIdBlock::leaseNonexpiring) &&
00213                     (wakeup.tv_sec >
00214                      mystock->block[which]->leaseExpires - LeaseSafetyMargin)){
00215                     wakeup.tv_sec =
00216                       mystock->block[which]->leaseExpires - LeaseSafetyMargin;
00217                     need_wakeup = true;
00218                 }           
00219             }
00220         } catch (SRPC::failure f) {
00221             cerr << "ShortIdStock::stockboy: "
00222               << f.msg << " (" << f.r << ")"
00223               << " on SRPC to repository" << endl;
00224             throw;  // !!crash with uncaught exception
00225         }
00226         if (need_wakeup) {
00227             mystock->need.timedwait(mystock->mu, &wakeup);
00228         } else {
00229             mystock->need.wait(mystock->mu);
00230         }
00231     }
00232     //return (void *)NULL;    // Not reached
00233 }    
00234 
00235 void
00236 SourceOrDerived::releaseResources() throw ()
00237 {
00239     return;
00240 }
00241 
00242 ShortId
00243 ShortIdStock::newShortId()
00244 {
00245     ShortId sid;
00246     
00247     mu.lock();
00248     do {
00249         while (block[usng] == NULL) {
00250             have.wait(mu);
00251         }
00252         sid = block[usng]->assignNextAvail();
00253         if (sid == 0) {
00254             delete block[usng];
00255             block[usng] = NULL;
00256             usng = 1 - usng;
00257             need.broadcast();
00258         }
00259     } while (sid == 0);
00260     mu.unlock();
00261     return sid;
00262 }
00263 
00264 char*
00265 SourceOrDerived::shortIdToName(ShortId sid, bool tailOnly) throw ()
00266 {
00267     int err = pthread_once(&mrlnOnce, SourceOrDerived_initMRLN);
00268     assert(err == 0);
00269     mu.lock();
00270     char *ret =
00271       ShortIdBlock::shortIdToName(sid, tailOnly ? "" : metadataRootLocalName);
00272     mu.unlock();
00273     return ret;
00274 }
00275 
00276 
00277 static int
00278 MakeDirs(char* name)
00279 {
00280     char *q, *r;
00281     q = name;
00282     if (*q == PathnameSep) q++;
00283     for (;;) {
00284         r = strchr(q, PathnameSep);
00285         if (r == NULL) {
00286             break;
00287         } else {
00288             *r = '\0';
00289             int ret = mkdir(name, SID_DIR_MODE);
00290             *r = PathnameSep;
00291             if (ret < 0 && errno != EEXIST) return ret;
00292             q = r + 1;
00293         }
00294     }
00295     return 0;
00296 }
00297 
00298 static Text parentDir(Text path)
00299 {
00300   int slashPos = path.FindCharR(PathnameSep);
00301   assert(slashPos != -1);
00302   return path.Sub(0, slashPos);
00303 }
00304 
00305 ShortId
00306 SourceOrDerived::create(bool leafflag, ios::openmode mode, mode_t prot)
00307   throw(SRPC::failure, SourceOrDerived::Fatal)
00308 {
00309     int err = pthread_once(&stockOnce, SourceOrDerived_initStock);
00310     assert(err == 0);
00311     ShortId sid = stock[leafflag?1:0]->newShortId();
00312     char *name = SourceOrDerived::shortIdToName(sid, false);
00313 
00314     // Make sure that the directory containing this shortid exists.
00315     if(!FS::IsDirectory(parentDir(name)))
00316       {
00317         int ret = MakeDirs(name);
00318         if (ret < 0) {
00319             if (errno == EACCES) {
00320                 throw Fatal("no permission to create shortid file");
00321             }
00322             clear(ios::badbit); // sets badbit
00323             delete [] name;
00324             return NullShortId;
00325         }
00326       }
00327 
00328     // Shortid file shouldn't exist yet.  If it does, it's an error.
00329     if(FS::Exists(name))
00330       {
00331         clear(ios::badbit);     // sets badbit
00332         delete [] name;
00333         return NullShortId;
00334       }
00335 
00336     // Create the file with the correct mode.
00337     try
00338       {
00339         FS::Touch(name, prot, false);
00340       }
00341     // Should never happen, since we already covered this case above,
00342     // but there is a race.
00343     catch(FS::AlreadyExists)
00344       {
00345         clear(ios::badbit);     // sets badbit
00346         delete [] name;
00347         return NullShortId;
00348       }
00349     catch(FS::Failure &err)
00350       {
00351         clear(ios::badbit);     // sets badbit
00352         delete [] name;
00353         if (err.get_errno() == EACCES) {
00354             throw Fatal("no permission to create shortid file");
00355         }
00356         return NullShortId;
00357       }
00358     
00359     // Open the file.
00360     fstream::open(name, mode);
00361     delete [] name;
00362     if (fail()) {
00363         if (errno == EACCES) {
00364             throw Fatal("no permission to open shortid file after creating it");
00365         }
00366         return NullShortId;
00367     }
00368 
00369     return sid;
00370 }
00371 
00372 void
00373 SourceOrDerived::open(ShortId sid, ios::openmode mode) throw ()
00374 {
00375     char *name = SourceOrDerived::shortIdToName(sid, false);
00376     if(FS::Exists(name))
00377       {
00378         fstream::open(name, mode);
00379       }
00380     else
00381       {
00382         clear(ios::badbit);     // sets badbit
00383       }
00384     delete [] name;
00385 }
00386 
00387 int
00388 SourceOrDerived::fdcreate(ShortId& sid, bool leafflag, mode_t prot)
00389   throw(SRPC::failure, SourceOrDerived::Fatal)
00390 {
00391     int err = pthread_once(&stockOnce, SourceOrDerived_initStock);
00392     assert(err == 0);
00393     sid = stock[leafflag?1:0]->newShortId();
00394     char *name = SourceOrDerived::shortIdToName(sid, false);
00395     int fd;
00396     
00397     // First, optimistically assume the directories are all there
00398     fd = ::open(name, O_RDWR | O_CREAT | O_EXCL, prot);
00399     if (fd < 0 && errno == ENOENT) {
00400         // Oops, a directory on the path is missing.
00401         // Make them all.
00402         int ret = MakeDirs(name);
00403         if (ret < 0) {
00404             fd = -1; 
00405         } else {
00406             fd = ::open(name, O_RDWR | O_CREAT | O_EXCL, prot);
00407         }
00408     }
00409     if (fd < 0) {
00410         if (errno == EACCES) {
00411             throw Fatal("no permission to create shortid file");
00412         }
00413         sid = NullShortId;
00414     }
00415     delete [] name;
00416     return fd;
00417 }
00418 
00419 int
00420 SourceOrDerived::fdopen(ShortId sid, int oflag, mode_t prot) throw ()
00421 {
00422     char *name = SourceOrDerived::shortIdToName(sid, false);
00423     oflag &= ~(O_CREAT);
00424     int ret = ::open(name, oflag, prot);
00425     delete [] name;
00426     return ret;
00427 }
00428 
00429 bool
00430 SourceOrDerived::touch(ShortId sid) throw ()
00431 {
00432     char *name = SourceOrDerived::shortIdToName(sid, false);
00433     struct timeval times[2];
00434     gettimeofday(&times[0], NULL);
00435     times[1] = times[0];
00436     int ok = utimes(name, times);
00437     delete [] name;
00438     return (ok == 0);
00439 }
00440 
00441 int
00442 SourceOrDerived::keepDerived(ShortIdsFile ds, time_t dt, bool force)
00443   throw(SRPC::failure)
00444 {
00445     return ShortIdBlock::keepDerived(ds, dt, force);
00446 }
00447 
00448 void
00449 SourceOrDerived::checkpoint() throw(SRPC::failure)
00450 {
00451     ShortIdBlock::checkpoint();
00452 }
00453 
00454 void
00455 SourceOrDerived::getWeedingState(ShortIdsFile& ds, time_t& dt,
00456                                  ShortIdsFile& ss, time_t& st,
00457                                  bool& sourceWeedInProgress,
00458                                  bool& deletionsInProgress,
00459                                  bool& deletionsDone,
00460                                  bool& checkpointInProgress)
00461   throw(SRPC::failure)
00462 {
00463     ShortIdBlock::getWeedingState(ds, dt, ss, st, sourceWeedInProgress,
00464                                   deletionsInProgress, deletionsDone,
00465                                   checkpointInProgress);
00466 }
00467 
00468 

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