00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
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
00059 const int SID_DIR_MODE = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
00060
00061 const int LeaseSafetyMargin = 60;
00062
00063
00064
00065
00066
00067 class ShortIdStock {
00068 bool leafflag;
00069 ShortIdBlock *block[2];
00070 int usng;
00071 Basics::mutex mu;
00072 Basics::cond need;
00073 Basics::cond have;
00074
00075 Basics::thread stockboy_;
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;
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
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
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
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
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
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;
00225 }
00226 if (need_wakeup) {
00227 mystock->need.timedwait(mystock->mu, &wakeup);
00228 } else {
00229 mystock->need.wait(mystock->mu);
00230 }
00231 }
00232
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
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);
00323 delete [] name;
00324 return NullShortId;
00325 }
00326 }
00327
00328
00329 if(FS::Exists(name))
00330 {
00331 clear(ios::badbit);
00332 delete [] name;
00333 return NullShortId;
00334 }
00335
00336
00337 try
00338 {
00339 FS::Touch(name, prot, false);
00340 }
00341
00342
00343 catch(FS::AlreadyExists)
00344 {
00345 clear(ios::badbit);
00346 delete [] name;
00347 return NullShortId;
00348 }
00349 catch(FS::Failure &err)
00350 {
00351 clear(ios::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
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);
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
00398 fd = ::open(name, O_RDWR | O_CREAT | O_EXCL, prot);
00399 if (fd < 0 && errno == ENOENT) {
00400
00401
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(×[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