XrdFrmPurge.cc

Go to the documentation of this file.
00001 /******************************************************************************/
00002 /*                                                                            */
00003 /*                        X r d F r m P u r g e . c c                         */
00004 /*                                                                            */
00005 /* (c) 2009 by the Board of Trustees of the Leland Stanford, Jr., University  */
00006 /*                            All Rights Reserved                             */
00007 /*   Produced by Andrew Hanushevsky for Stanford University under contract    */
00008 /*              DE-AC02-76-SFO0515 with the Department of Energy              */
00009 /******************************************************************************/
00010   
00011 //         $Id: XrdFrmPurge.cc 35287 2010-09-14 21:19:35Z ganis $
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 /*                         L o c a l   C l a s s e s                          */
00040 /******************************************************************************/
00041 /******************************************************************************/
00042 /*                  C l a s s   X r d F r m P u r g e D i r                   */
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 /*                               i s E m p t y                                */
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 // Check if this directory is still considered active
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 // We can expire the directory. However, we need to get the parent mtime
00087 // because removing this directory should not change the parent's mtime.
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 // Delete the directory
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, &times);
00104               }
00105 
00106 // Report if successful
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 /*                     C l a s s   X r d F r m P u r g e                      */
00124 /******************************************************************************/
00125 /******************************************************************************/
00126 /*                        S t a t i c   M e m b e r s                         */
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 /*                           C o n s t r u c t o r                            */
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 /* Private:                          A d d                                    */
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 // First, get the space name associated with the base file
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 // Ignore the file is the space is not enabled for purging
00185 //
00186    if (!(psP->Enabled)) {delete sP; return;}
00187    psP->numFiles++;
00188 
00189 // Check to see if the file is really eligible for purging
00190 //
00191    if ((Why = psP->Eligible(sP, xTime)))
00192       {DEBUG(sP->basePath() <<"cannot be purged; " <<Why);
00193        delete sP;
00194        return;
00195       }
00196 
00197 // Add the file to the purge table or the defer queue based on access time
00198 //
00199    if (xTime >= psP->Hold) psP->FSTab.Add(sP);
00200       else psP->Defer(sP, xTime);
00201 }
00202   
00203 /******************************************************************************/
00204 /* Private:                      A d v a n c e                                */
00205 /******************************************************************************/
00206 
00207 XrdFrmFileset *XrdFrmPurge::Advance()
00208 {
00209    XrdFrmFileset *fP, *xP;
00210    int n;
00211 
00212 // Find a defer queue entry that meets the hold threshold
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 // Try to re-add everything in this queue
00220 //
00221    while((xP = fP))
00222         {fP = fP->Next;
00223          if (xP->Refresh(0,0)) Add(xP);
00224             else delete xP;
00225         }
00226 
00227 // Return based on whether something now exists in the purge table
00228 //
00229    return FSTab.Oldest();
00230 }
00231   
00232 /******************************************************************************/
00233 /* Private:                        C l e a r                                  */
00234 /******************************************************************************/
00235   
00236 void XrdFrmPurge::Clear()
00237 {
00238    XrdFrmFileset *fP;
00239    int n;
00240 
00241 // Zero out the defer queue
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 // Purge the eligible file table
00248 //
00249    FSTab.Purge();
00250 
00251 // Clear counters
00252 //
00253    numFiles = 0; prgFiles = 0; purgBytes = 0;
00254 }
00255   
00256 /******************************************************************************/
00257 /* Private:                        D e f e r                                  */
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 // Slot the entry into the defer queue vector
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 /*                               D i s p l a y                                */
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 // Type header
00286 //
00287    Say.Say("=====> ", "Purge configuration:");
00288 
00289 // Display what we will scan
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 // Display directory hold value
00299 //
00300    if (Config.dirHold < 0) strcpy(buff, "forever");
00301       else sprintf(buff, "%d", Config.dirHold);
00302    Say.Say("=====> ", "Directory hold: ", buff);
00303 
00304 // Run through all of the policies, displaying each one
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 /* Private:                     E l i g i b l e                               */
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 // Get the acess time and modification time
00334 //
00335    aTime = baseFile->Stat.st_atime;
00336    mTime = baseFile->Stat.st_mtime;
00337 
00338 // File is not eligible if it's been accessed too recently
00339 //
00340    xTime = static_cast<int>(nowTime - aTime);
00341    if (hTime && xTime <= hTime) return "is in hold";
00342 
00343 // File is ineligible if it has a fail file
00344 //
00345    if (sP->failFile()) return "has fail file";
00346 
00347 // If there is a lock file and the file has not migrated, then ineligible
00348 // Note that entries were pre-screened for lock file requirements.
00349 //
00350    if (lockFile && lockFile->Stat.st_mtime < mTime) return "not migrated";
00351 
00352 // If there is no pin file, then it is eligible subject to external policy
00353 //
00354    if (!(pinFile = sP->pinFile())) return 0;
00355 
00356 // If the pin file sticky bit is on then the pin is permanent (ineligible)
00357 //
00358    if (pinFile->Stat.st_mode & S_ISUID) return "is perm pinned";
00359 
00360 // If the mtime of the pin file is in the future this is when it gets unpinned
00361 //
00362    if (pinFile->Stat.st_mtime > nowTime) return "is time pinned";
00363 
00364 // Check if there are more conditions
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 // The contents of the file indicate how long the inactive period is, get it
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 // Get the inactivity period
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 /* Private:                         F i n d                                   */
00391 /******************************************************************************/
00392 
00393 XrdFrmPurge *XrdFrmPurge::Find(const char *snp)
00394 {
00395    XrdFrmPurge *spP = First;
00396   
00397 // See if we already have this space defined
00398 //
00399    while(spP && strcmp(snp, spP->SName)) spP = spP->Next;
00400    return spP;
00401 }
00402 
00403 /******************************************************************************/
00404 /*                                  I n i t                                   */
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 // The first step is to remove any defined policies for which there is no space
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 // For each space enable it and optionally over-ride policy
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 // Go through each space policy getting the actual space and calculating
00456 // the targets based on the policy (we need to do this only once)
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 // Make sure "public" still exists. While this should not happen, we check for
00483 // this possibility anyway.
00484 //
00485    if (!(Default = Find("public")))
00486       {Say.Emsg("Init", "Unable to start purge; no public policy found.");
00487        return 0;
00488       }
00489 
00490 // If a policy program is present, then we need to verify it
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 // All went well
00503 //
00504    return 1;
00505 }
00506   
00507 /******************************************************************************/
00508 /* Private:                   L o w O n S p a c e                             */
00509 /******************************************************************************/
00510 
00511 // This method *must* be called prior to Purge() and returns:
00512 // =0 -> Purge not needed.
00513 //!>0 -> Purge is  needed.
00514   
00515 int XrdFrmPurge::LowOnSpace()
00516 {
00517    XrdOssVSInfo VSInfo;
00518    XrdFrmPurge *psP = First;
00519    time_t eNow;
00520 
00521 // Recalculate free space and set initial status
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 // If enough space then indicate no purge is needed
00538 //
00539    if (!Left2Do) return 0;
00540 
00541 // Reset all policies to prepare for purging
00542 //
00543    psP = First;
00544    while(psP)
00545         {psP->Clear();
00546          psP = psP->Next;
00547         }
00548 
00549 // We must check whether or not a full name space scan is required. This is
00550 // based on the last time we did one and whether or not a space needs one now.
00551 //
00552    eNow = time(0);
00553    if (eNow >= nextReset) {lastReset = eNow; nextReset = 0; Scan();}
00554    return 1;
00555 }
00556 
00557 /******************************************************************************/
00558 /*                                P o l i c y                                 */
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 // Find or create a new policy
00567 //
00568    if (!(psP = Find(sname))) First = psP = new XrdFrmPurge(sname, First);
00569 
00570 // Fill out the policy
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 /*                                 P u r g e                                  */
00582 /******************************************************************************/
00583   
00584 void XrdFrmPurge::Purge()
00585 {
00586    XrdFrmPurge *psP = First;
00587 
00588 // Check if are low on space, if not, ignore the call
00589 //
00590    if (!LowOnSpace())
00591       {Say.Emsg("Purge", "Purge cycle skipped; all policies met.");
00592        return;
00593       }
00594 
00595 // Report data at the start of the purge cycle
00596 //
00597    Say.Emsg("Purge", "Purge cycle started.");
00598    Stats(0);
00599 
00600 // Cycle through each space until we no longer can cycle
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 // Report data at the end of the purge cycle
00610 //
00611    Stats(1);
00612    Say.Emsg("Purge", "Purge cycle ended.");
00613 }
00614 
00615 /******************************************************************************/
00616 /* Private:                    P u r g e F i l e                              */
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 // If we have don't have a file, see if we can grab some from the defer queue
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 // All done, indicate whether we should stop now
00652 //
00653    return freeSpace >= maxFSpace || Stop;
00654 }
00655 
00656 /******************************************************************************/
00657 /* Private:                       R e m f i x                                 */
00658 /******************************************************************************/
00659 
00660 void XrdFrmPurge::Remfix(const char *Ftype, const char *Fname)
00661 {
00662 // Remove the offending file
00663 //
00664    if (!Config.ossFS->Unlink(Fname,XRDOSS_isPFN))
00665       Say.Emsg("Remfix", Ftype, "file orphan fixed; removed", Fname);
00666 }
00667   
00668 /******************************************************************************/
00669 /* Private:                         S c a n                                   */
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 // Purge that bad file table evey 24 hours to keep complaints down
00689 //
00690    if (nowT - lastHP >= 86400) {BadFiles.Purge(); lastHP = nowT;}
00691 
00692 // Determine if we need to do an empty directory trim
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 // Indicate scan started
00702 //
00703    VMSG("Scan", "Name space", Extra, "scan started. . .");
00704 
00705 // Process each directory
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 // If we did a directory purge, schedule the next one and say what we did
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 // Indicate scan ended
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 // Issue warning if we encountered errors
00736 //
00737    if (Bad) Say.Emsg("Scan", "Errors encountered while scanning for "
00738                              "purgeable files.");
00739 }
00740 
00741 /******************************************************************************/
00742 /* Private:                       S c r e e n                                 */
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 // Verify that we have all the relevant files
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 // Issue message if we haven't issued one before
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 /* Private:                        S t a t s                                  */
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 // Report data for each enabled space
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 /* Private:                        T r a c k                                  */
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 // Format the size
00835 //
00836    XrdOucUtils::fmtBytes(static_cast<long long>(fP->Stat.st_size),
00837                          fszbf, sizeof(fszbf));
00838 
00839 // Format the information and display it
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 /* Private:                       X P o l O K                                 */
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 // Construct the data to be sent (not mt here)
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 // Now finish up the vector
00917 //
00918    Data[k-1] = (char *)"\n"; Data[k] = 0; Dlen[k] = 0;
00919 
00920 // Feed the program this information get the response
00921 //
00922    if (PolProg->Feed((const char **)Data, Dlen) || !(Resp=PolStream->GetLine()))
00923       {Stop = 1; return "external policy failed";}
00924 
00925 // Decode the response (single line with a charcater y|n|a)
00926 //
00927    if (*Resp == 'y') return 0;
00928    if (*Resp == 'n') return "external policy reject";
00929    Stop = 1;
00930    return "external policy stop";
00931 }

Generated on Tue Jul 5 14:46:36 2011 for ROOT_528-00b_version by  doxygen 1.5.1