00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 const char *XrdFrmPurgeCVSID = "$Id: XrdFrmPurge.cc 35287 2010-09-14 21:19:35Z ganis $";
00014
00015 #include <stdio.h>
00016 #include <string.h>
00017 #include <strings.h>
00018 #include <utime.h>
00019 #include <sys/param.h>
00020 #include <sys/types.h>
00021
00022 #include "XrdNet/XrdNetCmsNotify.hh"
00023 #include "XrdOss/XrdOss.hh"
00024 #include "XrdOss/XrdOssPath.hh"
00025 #include "XrdOuc/XrdOucNSWalk.hh"
00026 #include "XrdOuc/XrdOucTList.hh"
00027 #include "XrdOuc/XrdOucProg.hh"
00028 #include "XrdOuc/XrdOucStream.hh"
00029 #include "XrdOuc/XrdOucUtils.hh"
00030 #include "XrdFrm/XrdFrmFiles.hh"
00031 #include "XrdFrm/XrdFrmConfig.hh"
00032 #include "XrdFrm/XrdFrmPurge.hh"
00033 #include "XrdFrm/XrdFrmTrace.hh"
00034 #include "XrdSys/XrdSysPlatform.hh"
00035
00036 using namespace XrdFrm;
00037
00038
00039
00040
00041
00042
00043
00044
00045 class XrdFrmPurgeDir : XrdOucNSWalk::CallBack
00046 {
00047 public:
00048
00049 void isEmpty(struct stat *dStat, const char *dPath, const char *lkFN);
00050
00051 void Reset(time_t dExp)
00052 {expDirTime = dExp; lowDirTime = 0; numRMD = numEMD = 0;}
00053
00054 time_t expDirTime;
00055 time_t lowDirTime;
00056 int numRMD;
00057 int numEMD;
00058
00059 XrdFrmPurgeDir() {}
00060 ~XrdFrmPurgeDir() {}
00061 };
00062
00063
00064
00065
00066
00067 void XrdFrmPurgeDir::isEmpty(struct stat *dStat, const char *dPath,
00068 const char *lkFN)
00069 {
00070 static const int ossOpts = XRDOSS_isPFN | XRDOSS_resonly;
00071 static const char *What = (Config.Test ? "Zorch " : "Purged ");
00072 struct stat pStat;
00073 struct utimbuf times;
00074 char Parent[MAXPATHLEN+1], *Slash;
00075 int n, rc;
00076
00077
00078
00079 numEMD++;
00080 if (dStat->st_mtime > expDirTime)
00081 {if (!lowDirTime || lowDirTime > dStat->st_mtime)
00082 lowDirTime = dStat->st_mtime;
00083 return;
00084 }
00085
00086
00087
00088
00089 strcpy(Parent, dPath);
00090 n = strlen(Parent);
00091 if (Parent[n-1] == '/') Parent[--n] = '\0';
00092 if ((Slash = rindex(Parent, '/')))
00093 {*Slash = '\0';
00094 if (stat(Parent, &pStat)) Slash = 0;
00095 }
00096
00097
00098
00099 if (Config.Test) rc = 0;
00100 else if (!(rc = Config.ossFS->Remdir(dPath, ossOpts)) && Slash)
00101 {times.actime = pStat.st_atime;
00102 times.modtime = pStat.st_mtime;
00103 utime(Parent, ×);
00104 }
00105
00106
00107
00108 if (!rc)
00109 {numRMD++;
00110 if (Config.Verbose)
00111 {char sbuff[32];
00112 struct tm tNow;
00113 localtime_r(&(dStat->st_mtime), &tNow);
00114 sprintf(sbuff, "%02d%02d%02d %02d:%02d:%02d ",
00115 tNow.tm_year-100, tNow.tm_mon+1, tNow.tm_mday,
00116 tNow.tm_hour, tNow.tm_min, tNow.tm_sec);
00117 Say.Say(What, "empty dir ", sbuff, dPath);
00118 }
00119 }
00120 }
00121
00122
00123
00124
00125
00126
00127
00128
00129 XrdFrmPurge *XrdFrmPurge::First = 0;
00130 XrdFrmPurge *XrdFrmPurge::Default = 0;
00131
00132 XrdOucProg *XrdFrmPurge::PolProg = 0;
00133 XrdOucStream *XrdFrmPurge::PolStream = 0;
00134
00135 int XrdFrmPurge::Left2Do = 0;
00136
00137 time_t XrdFrmPurge::lastReset = 0;
00138 time_t XrdFrmPurge::nextReset = 0;
00139
00140 XrdOucHash<char> XrdFrmPurge::BadFiles;
00141
00142
00143
00144
00145
00146 XrdFrmPurge::XrdFrmPurge(const char *snp, XrdFrmPurge *spp) : FSTab(1)
00147 {
00148 strncpy(SName, snp, sizeof(SName)-1); SName[sizeof(SName)-1] = '\0';
00149 Next = spp;
00150 freeSpace = 0;
00151 usedSpace =-1;
00152 pmaxSpace = 0;
00153 totlSpace = 0;
00154 contSpace = 0;
00155 minFSpace = 0;
00156 maxFSpace = 0;
00157 Enabled = 0;
00158 Stop = 0;
00159 SNlen = strlen(SName);
00160 memset(DeferQ, 0, sizeof(DeferQ));
00161 Clear();
00162 }
00163
00164
00165
00166
00167
00168 void XrdFrmPurge::Add(XrdFrmFileset *sP)
00169 {
00170 EPNAME("Add");
00171 XrdOucNSWalk::NSEnt *baseFile = sP->baseFile();
00172 XrdFrmPurge *psP = Default;
00173 const char *Why;
00174 time_t xTime;
00175
00176
00177
00178 if ((baseFile->Link))
00179 {char snBuff[XrdOssSpace::minSNbsz];
00180 XrdOssPath::getCname(0, snBuff, baseFile->Link, baseFile->Lksz);
00181 if (!(psP = Find(snBuff))) psP = Default;
00182 }
00183
00184
00185
00186 if (!(psP->Enabled)) {delete sP; return;}
00187 psP->numFiles++;
00188
00189
00190
00191 if ((Why = psP->Eligible(sP, xTime)))
00192 {DEBUG(sP->basePath() <<"cannot be purged; " <<Why);
00193 delete sP;
00194 return;
00195 }
00196
00197
00198
00199 if (xTime >= psP->Hold) psP->FSTab.Add(sP);
00200 else psP->Defer(sP, xTime);
00201 }
00202
00203
00204
00205
00206
00207 XrdFrmFileset *XrdFrmPurge::Advance()
00208 {
00209 XrdFrmFileset *fP, *xP;
00210 int n;
00211
00212
00213
00214 for (n = DeferQsz-1; n >= 0 && !DeferQ[n]; n--) {}
00215 if (n < 0) return 0;
00216 if (time(0) - DeferT[n] > Hold) return 0;
00217 fP = DeferQ[n]; DeferQ[n] = 0; DeferT[n] = 0;
00218
00219
00220
00221 while((xP = fP))
00222 {fP = fP->Next;
00223 if (xP->Refresh(0,0)) Add(xP);
00224 else delete xP;
00225 }
00226
00227
00228
00229 return FSTab.Oldest();
00230 }
00231
00232
00233
00234
00235
00236 void XrdFrmPurge::Clear()
00237 {
00238 XrdFrmFileset *fP;
00239 int n;
00240
00241
00242
00243 for (n = 0; n < DeferQsz; n++)
00244 while ((fP = DeferQ[n])) {DeferQ[n] = fP->Next; delete fP;}
00245 memset(DeferT, 0, sizeof(DeferT));
00246
00247
00248
00249 FSTab.Purge();
00250
00251
00252
00253 numFiles = 0; prgFiles = 0; purgBytes = 0;
00254 }
00255
00256
00257
00258
00259
00260 void XrdFrmPurge::Defer(XrdFrmFileset *sP, time_t xTime)
00261 {
00262 time_t aTime = sP->baseFile()->Stat.st_atime;
00263 int n = xTime/DeferQsz;
00264
00265
00266
00267 if (n >= DeferQsz) n = DeferQsz-1;
00268 if (!DeferQ[n] || aTime < DeferT[n]) DeferT[n] = aTime;
00269 sP->Next = DeferQ[n];
00270 DeferQ[n] = sP;
00271 }
00272
00273
00274
00275
00276
00277 void XrdFrmPurge::Display()
00278 {
00279 XrdFrmConfig::VPInfo *vP = Config.pathList;
00280 XrdFrmPurge *spP = First;
00281 XrdOucTList *tP;
00282 const char *isExt;
00283 char buff[1024], minfsp[32], maxfsp[32];
00284
00285
00286
00287 Say.Say("=====> ", "Purge configuration:");
00288
00289
00290
00291 while(vP)
00292 {Say.Say("=====> ", "Scanning ", (vP->Val?"r/w: ":"r/o: "), vP->Name);
00293 tP = vP->Dir;
00294 while(tP) {Say.Say("=====> ", "Excluded ", tP->text); tP = tP->next;}
00295 vP = vP->Next;
00296 }
00297
00298
00299
00300 if (Config.dirHold < 0) strcpy(buff, "forever");
00301 else sprintf(buff, "%d", Config.dirHold);
00302 Say.Say("=====> ", "Directory hold: ", buff);
00303
00304
00305
00306 spP = First;
00307 while(spP)
00308 {if (spP->Enabled)
00309 {XrdOucUtils::fmtBytes(spP->minFSpace, minfsp, sizeof(minfsp));
00310 XrdOucUtils::fmtBytes(spP->maxFSpace, maxfsp, sizeof(maxfsp));
00311 isExt = spP->Ext ? " polprog" : "";
00312 sprintf(buff, "policy %s min %s max %s free; hold: %d%s",
00313 spP->SName, minfsp, maxfsp, spP->Hold, isExt);
00314 } else sprintf(buff, "policy %s nopurge", spP->SName);
00315 Say.Say("=====> ", buff);
00316 spP = spP->Next;
00317 }
00318 }
00319
00320
00321
00322
00323
00324 const char *XrdFrmPurge::Eligible(XrdFrmFileset *sP, time_t &xTime, int hTime)
00325 {
00326 XrdOucNSWalk::NSEnt *baseFile = sP->baseFile();
00327 XrdOucNSWalk::NSEnt *lockFile = sP->lockFile();
00328 XrdOucNSWalk::NSEnt * pinFile;
00329 time_t aTime, mTime, nowTime = time(0);
00330 char pBuff[256];
00331 int pFD, rLen, idleMin;
00332
00333
00334
00335 aTime = baseFile->Stat.st_atime;
00336 mTime = baseFile->Stat.st_mtime;
00337
00338
00339
00340 xTime = static_cast<int>(nowTime - aTime);
00341 if (hTime && xTime <= hTime) return "is in hold";
00342
00343
00344
00345 if (sP->failFile()) return "has fail file";
00346
00347
00348
00349
00350 if (lockFile && lockFile->Stat.st_mtime < mTime) return "not migrated";
00351
00352
00353
00354 if (!(pinFile = sP->pinFile())) return 0;
00355
00356
00357
00358 if (pinFile->Stat.st_mode & S_ISUID) return "is perm pinned";
00359
00360
00361
00362 if (pinFile->Stat.st_mtime > nowTime) return "is time pinned";
00363
00364
00365
00366 if (!(pinFile->Stat.st_size)) return 0;
00367 if ( pinFile->Stat.st_size >= static_cast<off_t>(sizeof(pBuff)))
00368 return "is pinned incorrectly";
00369
00370
00371
00372 if ((pFD = open(pinFile->Path, O_RDONLY)) < 0
00373 || (rLen = read(pFD, pBuff, sizeof(pBuff)-1)) < 0)
00374 {const char *Why = "open";
00375 if (pFD >= 0) {close(pFD); Why = "read";}
00376 Say.Emsg("Eligible", errno, Why, pinFile->Path);
00377 return "is pinned";
00378 }
00379
00380
00381
00382 close(pFD);
00383 pBuff[rLen] = '\0';
00384 if (sscanf(pBuff,"&inact_time=%d",&idleMin) != 1) return "pinfile error";
00385 if (idleMin > xTime) return "is pin defered";
00386 return 0;
00387 }
00388
00389
00390
00391
00392
00393 XrdFrmPurge *XrdFrmPurge::Find(const char *snp)
00394 {
00395 XrdFrmPurge *spP = First;
00396
00397
00398
00399 while(spP && strcmp(snp, spP->SName)) spP = spP->Next;
00400 return spP;
00401 }
00402
00403
00404
00405
00406
00407 int XrdFrmPurge::Init(XrdOucTList *sP, long long minV, int hVal)
00408 {
00409 static char pVec[] = {char(XrdFrmConfig::PP_sname),
00410 char(XrdFrmConfig::PP_pfn),
00411 char(XrdFrmConfig::PP_fsize),
00412 char(XrdFrmConfig::PP_atime),
00413 char(XrdFrmConfig::PP_mtime)
00414 };
00415
00416 XrdFrmConfig::VPInfo *vP;
00417 XrdOssVSInfo vsInfo;
00418 XrdFrmPurge *xP, *ppP = 0, *spP = First;
00419 XrdOucTList *tP;
00420 char xBuff[32];
00421 int setIt, rc, haveExt = 0;
00422
00423
00424
00425 while(spP)
00426 {vP = Config.VPList;
00427 while(vP && strcmp(spP->SName, vP->Name)) vP = vP->Next;
00428 if (!vP && strcmp("public", spP->SName))
00429 {Say.Emsg("Init", "Purge policy", spP->SName,
00430 "deleted; space not defined.");
00431 if (ppP) ppP->Next = spP->Next;
00432 else First = spP->Next;
00433 xP = spP; spP = spP->Next; delete xP;
00434 } else {ppP = spP; spP = spP->Next;}
00435 }
00436
00437
00438
00439 spP = First;
00440 while(spP)
00441 {setIt = 1;
00442 if ((tP = sP))
00443 {while(tP && strcmp(tP->text, spP->SName)) tP = tP->next;
00444 if (!tP) setIt = 0;
00445 }
00446 if (setIt)
00447 {if (minV) spP->minFSpace = spP->maxFSpace = minV;
00448 if (hVal >= 0) {spP->Hold = hVal; spP->Hold2x = hVal*2;}
00449 if (spP->minFSpace && spP->Hold >= 0)
00450 {spP->Enabled = 1; haveExt |= spP->Ext;}
00451 }
00452 spP = spP->Next;
00453 }
00454
00455
00456
00457
00458 spP = First; ppP = 0;
00459 while(spP)
00460 {if ((rc = Config.ossFS->StatVS(&vsInfo, spP->SName, 1)))
00461 {Say.Emsg("Init", rc, "calculate space for", spP->SName);
00462 if (ppP) ppP->Next = spP->Next;
00463 else First = spP->Next;
00464 xP = spP; spP = spP->Next; delete xP; continue;
00465 }
00466 spP->totlSpace = vsInfo.Total;
00467 spP->spaceTLen = sprintf(xBuff, "%lld", vsInfo.Total);
00468 spP->spaceTotl = strdup(xBuff);
00469 spP->pmaxSpace = vsInfo.Large;
00470 spP->spaceTLep = sprintf(xBuff, "%lld", vsInfo.Large);
00471 spP->spaceTotP = strdup(xBuff);
00472 if (spP->minFSpace < 0)
00473 {spP->minFSpace = vsInfo.Total * XRDABS(spP->minFSpace) / 100LL;
00474 spP->maxFSpace = vsInfo.Total * XRDABS(spP->maxFSpace) / 100LL;
00475 } else if (vsInfo.Total < spP->minFSpace
00476 || vsInfo.Total < spP->maxFSpace)
00477 Say.Emsg("Init", "Warning: ", spP->SName, " min/max free "
00478 "space policy exceeds total available!");
00479 ppP = spP; spP = spP->Next;
00480 }
00481
00482
00483
00484
00485 if (!(Default = Find("public")))
00486 {Say.Emsg("Init", "Unable to start purge; no public policy found.");
00487 return 0;
00488 }
00489
00490
00491
00492 if (Config.pProg && haveExt)
00493 {PolProg = new XrdOucProg(&Say);
00494 if (PolProg->Setup(Config.pProg) || PolProg->Start()) return 0;
00495 PolStream = PolProg->getStream();
00496 if (!Config.pVecNum)
00497 {memcpy(Config.pVec, pVec, sizeof(pVec));
00498 Config.pVecNum = sizeof(pVec);
00499 }
00500 }
00501
00502
00503
00504 return 1;
00505 }
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515 int XrdFrmPurge::LowOnSpace()
00516 {
00517 XrdOssVSInfo VSInfo;
00518 XrdFrmPurge *psP = First;
00519 time_t eNow;
00520
00521
00522
00523 Left2Do = 0;
00524 while(psP)
00525 {if (psP->Enabled)
00526 {if (Config.ossFS->StatVS(&VSInfo, psP->SName, 1)) psP->Stop = 1;
00527 else {psP->freeSpace = VSInfo.Free;
00528 psP->contSpace = VSInfo.LFree;
00529 psP->usedSpace = VSInfo.Usage;
00530 if (psP->freeSpace >= psP->minFSpace) psP->Stop = 1;
00531 else {Left2Do++; psP->Stop = 0;}
00532 }
00533 } else psP->Stop = 1;
00534 psP = psP->Next;
00535 }
00536
00537
00538
00539 if (!Left2Do) return 0;
00540
00541
00542
00543 psP = First;
00544 while(psP)
00545 {psP->Clear();
00546 psP = psP->Next;
00547 }
00548
00549
00550
00551
00552 eNow = time(0);
00553 if (eNow >= nextReset) {lastReset = eNow; nextReset = 0; Scan();}
00554 return 1;
00555 }
00556
00557
00558
00559
00560
00561 XrdFrmPurge *XrdFrmPurge::Policy(const char *sname, long long minV,
00562 long long maxV, int hVal, int xVal)
00563 {
00564 XrdFrmPurge *psP;
00565
00566
00567
00568 if (!(psP = Find(sname))) First = psP = new XrdFrmPurge(sname, First);
00569
00570
00571
00572 psP->minFSpace = minV;
00573 psP->maxFSpace = maxV;
00574 psP->Hold = hVal;
00575 psP->Hold2x = hVal*2;
00576 psP->Ext = xVal;
00577 return psP;
00578 }
00579
00580
00581
00582
00583
00584 void XrdFrmPurge::Purge()
00585 {
00586 XrdFrmPurge *psP = First;
00587
00588
00589
00590 if (!LowOnSpace())
00591 {Say.Emsg("Purge", "Purge cycle skipped; all policies met.");
00592 return;
00593 }
00594
00595
00596
00597 Say.Emsg("Purge", "Purge cycle started.");
00598 Stats(0);
00599
00600
00601
00602 do{psP = First;
00603 while(psP && Left2Do)
00604 {if (!(psP->Stop) && (psP->Stop = psP->PurgeFile())) Left2Do--;
00605 psP = psP->Next;
00606 }
00607 } while(Left2Do);
00608
00609
00610
00611 Stats(1);
00612 Say.Emsg("Purge", "Purge cycle ended.");
00613 }
00614
00615
00616
00617
00618
00619 int XrdFrmPurge::PurgeFile()
00620 {
00621 EPNAME("PurgeFile");
00622 static const int unOpts = XRDOSS_isPFN|XRDOSS_isMIG;
00623 XrdFrmFileset *fP;
00624 const char *fn, *Why;
00625 time_t xTime;
00626 int rc, FilePurged = 0;
00627
00628
00629
00630 do{if (!(fP = FSTab.Oldest()) && !(fP = Advance()))
00631 {time_t nextScan = time(0)+Hold;
00632 if (!nextReset || nextScan < nextReset) nextReset = nextScan;
00633 return 1;
00634 }
00635 Why = "file in use";
00636 if (fP->Refresh() && !(Why = Eligible(fP, xTime, Hold))
00637 && (!Ext || !(Why = XPolOK(fP))))
00638 {fn = fP->basePath();
00639 if (Config.Test) rc = 0;
00640 else if (!(rc = Config.ossFS->Unlink(fn, unOpts))
00641 && Config.cmsPath) Config.cmsPath->Gone(fn);
00642 if (!rc) {prgFiles++; FilePurged = 1;
00643 freeSpace += fP->baseFile()->Stat.st_size;
00644 purgBytes += fP->baseFile()->Stat.st_size;
00645 if (Config.Verbose) Track(fP);
00646 }
00647 } else {DEBUG("Purge " <<SName <<": keeping " <<fP->basePath() <<"; " <<Why);}
00648 delete fP;
00649 } while(!FilePurged && !Stop);
00650
00651
00652
00653 return freeSpace >= maxFSpace || Stop;
00654 }
00655
00656
00657
00658
00659
00660 void XrdFrmPurge::Remfix(const char *Ftype, const char *Fname)
00661 {
00662
00663
00664 if (!Config.ossFS->Unlink(Fname,XRDOSS_isPFN))
00665 Say.Emsg("Remfix", Ftype, "file orphan fixed; removed", Fname);
00666 }
00667
00668
00669
00670
00671
00672
00673 void XrdFrmPurge::Scan()
00674 {
00675 static const int Opts = XrdFrmFiles::Recursive | XrdFrmFiles::CompressD
00676 | XrdFrmFiles::NoAutoDel;
00677 static time_t lastHP = time(0), nextDP = 0, nowT = time(0);
00678 static XrdFrmPurgeDir purgeDir;
00679 static XrdOucNSWalk::CallBack *cbP;
00680
00681 XrdFrmConfig::VPInfo *vP = Config.pathList;
00682 XrdFrmFileset *sP;
00683 XrdFrmFiles *fP;
00684 const char *Extra;
00685 char buff[128];
00686 int needLF, ec = 0, Bad = 0, aFiles = 0, bFiles = 0;
00687
00688
00689
00690 if (nowT - lastHP >= 86400) {BadFiles.Purge(); lastHP = nowT;}
00691
00692
00693
00694 if (Config.dirHold < 0 || nowT < nextDP) {cbP = 0; Extra = 0;}
00695 else {nextDP = nowT + Config.dirHold;
00696 purgeDir.Reset(nowT - Config.dirHold);
00697 cbP = (XrdOucNSWalk::CallBack *)&purgeDir;
00698 Extra = "and empty directory";
00699 }
00700
00701
00702
00703 VMSG("Scan", "Name space", Extra, "scan started. . .");
00704
00705
00706
00707 do {fP = new XrdFrmFiles(vP->Name, Opts, vP->Dir, cbP);
00708 needLF = vP->Val;
00709 while((sP = fP->Get(ec,1)))
00710 {aFiles++;
00711 if (Screen(sP, needLF)) Add(sP);
00712 else {delete sP; bFiles++;}
00713 }
00714 if (ec) Bad = 1;
00715 delete fP;
00716 } while((vP = vP->Next));
00717
00718
00719
00720 if (cbP)
00721 {if ((purgeDir.numEMD - purgeDir.numRMD) > 0
00722 && purgeDir.lowDirTime + Config.dirHold < nextDP)
00723 nextDP = purgeDir.lowDirTime + Config.dirHold;
00724 sprintf(buff, "%d of %d empty dir%s removed", purgeDir.numRMD,
00725 purgeDir.numEMD, (purgeDir.numEMD != 1 ? "s":""));
00726 VMSG("Scan", "Empty directory space scan ended;", buff);
00727 }
00728
00729
00730
00731 sprintf(buff, "%d file%s with %d error%s", aFiles, (aFiles != 1 ? "s":""),
00732 bFiles, (bFiles != 1 ? "s":""));
00733 VMSG("Scan", "Name space scan ended;", buff);
00734
00735
00736
00737 if (Bad) Say.Emsg("Scan", "Errors encountered while scanning for "
00738 "purgeable files.");
00739 }
00740
00741
00742
00743
00744
00745 int XrdFrmPurge::Screen(XrdFrmFileset *sP, int needLF)
00746 {
00747 const char *What = 0, *badFN = 0;
00748 char dPath[MAXPATHLEN+1];
00749
00750
00751
00752 if (!(sP->baseFile()))
00753 {if (Config.Fix)
00754 {if (sP->lockFile()) Remfix("Lock", sP->lockPath());
00755 if (sP-> pinFile()) Remfix("Pin", sP-> pinPath());
00756 if (sP->failFile()) Remfix("Fail", sP->failPath());
00757 return 0;
00758 }
00759 What = "No base file for";
00760 if (sP->lockFile()) badFN = sP->lockPath();
00761 else if (sP-> pinFile()) badFN = sP-> pinPath();
00762 else if (sP->failFile()) badFN = sP->failPath();
00763 else {What = "Orhpaned files in"; badFN = dPath;
00764 sP->dirPath(dPath, sizeof(dPath));
00765 }
00766 } else if (needLF && !(sP->lockFile()))
00767 {What = "No lock file for"; badFN = sP->basePath();}
00768 else return 1;
00769
00770
00771
00772 if (!BadFiles.Add(badFN, 0, 0, Hash_data_is_key))
00773 Say.Emsg("Screen", What, badFN);
00774 return 0;
00775 }
00776
00777
00778
00779
00780
00781 void XrdFrmPurge::Stats(int Final)
00782 {
00783 XrdFrmPurge *xsP, *psP = First;
00784 long long pVal, xBytes, zBytes;
00785 const char *xWhat, *nWhat, *zWhat;
00786 char fBuff[64], uBuff[80], sBuff[512], xBuff[64], zBuff[64];
00787 int nFiles;
00788
00789
00790
00791 while((xsP = psP))
00792 {psP = psP->Next;
00793 if (!(xsP->Enabled)) continue;
00794 if (xsP->usedSpace >= 0)
00795 {if (Final) xsP->usedSpace -= xsP->purgBytes;
00796 XrdOucUtils::fmtBytes(xsP->usedSpace, fBuff, sizeof(fBuff));
00797 pVal = xsP->usedSpace*100/xsP->totlSpace;
00798 sprintf(uBuff, "used %s (%lld%%) ", fBuff, pVal);
00799 } else *uBuff = '\0';
00800 XrdOucUtils::fmtBytes(xsP->freeSpace, fBuff, sizeof(fBuff));
00801 pVal = xsP->freeSpace*100/xsP->totlSpace;
00802 if (Final)
00803 {xBytes = xsP->purgBytes; xWhat = "freed";
00804 if ((zBytes = xsP->maxFSpace - xsP->freeSpace) > 0)
00805 {XrdOucUtils::fmtBytes(zBytes, zBuff, sizeof(zBuff));
00806 zWhat = " deficit";
00807 } else {*zBuff = '\0'; zWhat = "need met";}
00808 nFiles = xsP->prgFiles; nWhat = "prgd";
00809 } else {
00810 xBytes = (xsP->freeSpace < xsP->minFSpace
00811 ? xsP->maxFSpace - xsP->freeSpace : 0);
00812 nFiles = xsP->FSTab.Count();
00813 xWhat = "needed"; nWhat = "idle"; *zBuff = '\0'; zWhat = "";
00814 }
00815 XrdOucUtils::fmtBytes(xBytes, xBuff, sizeof(xBuff));
00816 sprintf(sBuff, " %sfree %s (%lld%%) %d files %d %s; %s %s %s%s",
00817 uBuff,fBuff,pVal,xsP->numFiles,nFiles,nWhat,
00818 xBuff,xWhat,zBuff,zWhat);
00819 Say.Say("++++++ ", xsP->SName, sBuff);
00820 }
00821 }
00822
00823
00824
00825
00826
00827 void XrdFrmPurge::Track(XrdFrmFileset *sP)
00828 {
00829 XrdOucNSWalk::NSEnt *fP = sP->baseFile();
00830 const char *What = (Config.Test ? "Zorch " : "Purged ");
00831 char sbuff[128], fszbf[16];
00832 struct tm tNow;
00833
00834
00835
00836 XrdOucUtils::fmtBytes(static_cast<long long>(fP->Stat.st_size),
00837 fszbf, sizeof(fszbf));
00838
00839
00840
00841 localtime_r(&(fP->Stat.st_atime), &tNow);
00842 sprintf(sbuff, " %8s %02d%02d%02d %02d:%02d:%02d ", fszbf,
00843 tNow.tm_year-100, tNow.tm_mon+1, tNow.tm_mday,
00844 tNow.tm_hour, tNow.tm_min, tNow.tm_sec);
00845
00846 Say.Say(What, SName, sbuff, sP->basePath());
00847 }
00848
00849
00850
00851
00852
00853 const char *XrdFrmPurge::XPolOK(XrdFrmFileset *fsP)
00854 {
00855 static char neg1[] = {'-','1','\0'};
00856 XrdOucNSWalk::NSEnt *fP = fsP->baseFile();
00857 char *Data[sizeof(Config.pVec)*2+2];
00858 int Dlen[sizeof(Config.pVec)*2+2];
00859 char atBuff[32], ctBuff[32], mtBuff[32], fsBuff[32], spBuff[32], usBuff[32];
00860 char *Resp;
00861 int i, k = 0;
00862
00863
00864
00865 for (i = 0; i < Config.pVecNum; i++)
00866 {switch(Config.pVec[i])
00867 {case XrdFrmConfig::PP_atime:
00868 Data[k] = atBuff;
00869 Dlen[k] = sprintf(atBuff, "%lld",
00870 static_cast<long long>(fP->Stat.st_atime));
00871 break;
00872 case XrdFrmConfig::PP_ctime:
00873 Data[k] = ctBuff;
00874 Dlen[k] = sprintf(ctBuff, "%lld",
00875 static_cast<long long>(fP->Stat.st_ctime));
00876 break;
00877 case XrdFrmConfig::PP_fname:
00878 Data[k] = fP->File; Dlen[k] = strlen(fP->File);
00879 break;
00880 case XrdFrmConfig::PP_fsize:
00881 Data[k] = fsBuff;
00882 Dlen[k] = sprintf(fsBuff, "%lld",
00883 static_cast<long long>(fP->Stat.st_size));
00884 break;
00885 case XrdFrmConfig::PP_fspace:
00886 Data[k] = spBuff;
00887 Dlen[k] = sprintf(spBuff, "%lld", freeSpace);
00888 break;
00889 case XrdFrmConfig::PP_mtime:
00890 Data[k] = mtBuff;
00891 Dlen[k] = sprintf(mtBuff, "%lld",
00892 static_cast<long long>(fP->Stat.st_mtime));
00893 break;
00894 case XrdFrmConfig::PP_pfn:
00895 Data[k] = (char *)fsP->basePath();
00896 Dlen[k] = strlen(Data[k]);
00897 break;
00898 case XrdFrmConfig::PP_sname:
00899 Data[k] = SName; Dlen[k] = SNlen;
00900 break;
00901 case XrdFrmConfig::PP_tspace:
00902 Data[k] = spaceTotl; Dlen[k] = spaceTLen;
00903 break;
00904 case XrdFrmConfig::PP_usage:
00905 if (usedSpace < 0) {Data[k] = neg1; Dlen[k]=2;}
00906 else {Dlen[k] = sprintf(usBuff, "%lld",
00907 usedSpace - purgBytes);
00908 Data[k] = usBuff;
00909 }
00910 break;
00911 default: break;
00912 }
00913 Data[++k] = (char *)" "; Dlen[k] = 1; k++;
00914 }
00915
00916
00917
00918 Data[k-1] = (char *)"\n"; Data[k] = 0; Dlen[k] = 0;
00919
00920
00921
00922 if (PolProg->Feed((const char **)Data, Dlen) || !(Resp=PolStream->GetLine()))
00923 {Stop = 1; return "external policy failed";}
00924
00925
00926
00927 if (*Resp == 'y') return 0;
00928 if (*Resp == 'n') return "external policy reject";
00929 Stop = 1;
00930 return "external policy stop";
00931 }