XrdOssSpace.cc

Go to the documentation of this file.
00001 /******************************************************************************/
00002 /*                                                                            */
00003 /*                        X r d O s s S p a c e . c c                         */
00004 /*                                                                            */
00005 /* (c) 2008 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: XrdOssSpace.cc 35287 2010-09-14 21:19:35Z ganis $
00012  
00013 const char *XrdOssSpaceCVSID = "$Id: XrdOssSpace.cc 35287 2010-09-14 21:19:35Z ganis $";
00014 
00015 #include <sys/types.h>
00016 #include <sys/stat.h>
00017 #include <fcntl.h>
00018 #include <errno.h>
00019 #include <stddef.h>
00020 #include <stdio.h>
00021 
00022 #include "XrdOss/XrdOssCache.hh"
00023 #include "XrdOss/XrdOssSpace.hh"
00024 #include "XrdOuc/XrdOuca2x.hh"
00025 #include "XrdOuc/XrdOucEnv.hh"
00026 #include "XrdOuc/XrdOucStream.hh"
00027 #include "XrdOuc/XrdOucUtils.hh"
00028 #include "XrdSys/XrdSysError.hh"
00029 #include "XrdSys/XrdSysPlatform.hh"
00030 
00031 /******************************************************************************/
00032 /*                   G l o b a l s   a n d   S t a t i c s                    */
00033 /******************************************************************************/
00034 
00035 extern XrdSysError OssEroute;
00036 
00037        const char       *XrdOssSpace::qFname                     = 0;
00038        const char       *XrdOssSpace::uFname                     = 0;
00039        XrdOssSpace::uEnt XrdOssSpace::uData[XrdOssSpace::maxEnt] = {{{0}}};
00040        short             XrdOssSpace::uDvec[XrdOssSpace::maxEnt] = {0};
00041        int               XrdOssSpace::fencEnt                    = 0;
00042        int               XrdOssSpace::freeEnt                    =-1;
00043        int               XrdOssSpace::aFD                        =-1;
00044        int               XrdOssSpace::Solitary                   = 0;
00045        time_t            XrdOssSpace::lastMtime                  = 0;
00046 
00047 /******************************************************************************/
00048 /*                                A d j u s t                                 */
00049 /******************************************************************************/
00050   
00051 void XrdOssSpace::Adjust(int Gent, off_t Space, sType stNum)
00052 {
00053    int offset, unlk = 0;
00054    int uOff = offsetof(uEnt,Bytes[0]) + (sizeof(long long)*stNum);
00055 
00056 // Verify the entry number
00057 //
00058    if (Gent < 0 || Gent >= fencEnt) return;
00059    offset = sizeof(uEnt)*Gent + uOff;
00060 
00061 // For stand-alone processes, we need to convert server adjustments to make
00062 // the update inter-process safe.
00063 //
00064    if (Solitary && stNum == Serv) stNum = (Space > 0 ? Pstg : Purg);
00065 
00066 // Check if we need a lock and a refresh. For admin stats we need to make the
00067 // result idempotent w.r.t. updates by convoluting pstg/purg space numbers.
00068 //
00069    if (stNum != Serv)
00070       {if (!UsageLock()) return;
00071        if (pread(aFD, &uData[Gent], sizeof(uEnt), offset-uOff) < 0)
00072           {OssEroute.Emsg("Adjust", errno, "read usage file", uFname);
00073            UsageLock(0); return;
00074           }
00075        if (stNum == Admin)
00076           {uData[Gent].Bytes[Admin] = 0;
00077            Space = Space - uData[Gent].Bytes[Pstg] + uData[Gent].Bytes[Purg];
00078           }
00079        unlk = 1;
00080       }
00081 
00082 // Update the space statistic (protected by caller's mutex)
00083 //
00084    if ((uData[Gent].Bytes[stNum] += Space) < 0 && stNum != Admin)
00085       uData[Gent].Bytes[stNum] = 0;
00086 
00087 // Write out the the changed field. For servers, we can do this without a lock
00088 // because we are the only ones allowed to write this field.
00089 //
00090    if (pwrite(aFD, &uData[Gent].Bytes[stNum], ULen, offset) < 0)
00091       OssEroute.Emsg("Adjust", errno, "update usage file", uFname);
00092 
00093 // Unlock the file if we locked it
00094 //
00095    if (unlk) UsageLock(0);
00096 }
00097 
00098 /******************************************************************************/
00099   
00100 void XrdOssSpace::Adjust(const char *GName, off_t Space, sType stNum)
00101 {
00102    int i;
00103 
00104 // Try to find the current entry in the file
00105 //
00106    if ((i = findEnt(GName)) >= 0) Adjust(i, Space, stNum);
00107 }
00108 
00109 /******************************************************************************/
00110 /*                                A s s i g n                                 */
00111 /******************************************************************************/
00112   
00113 int XrdOssSpace::Assign(const char *GName, long long &Usage)
00114 {
00115    off_t offset;
00116    int i;
00117 
00118 // Try to find the current entry in the file
00119 //
00120    if ((i = findEnt(GName)) >= 0)
00121       {Usage = uData[i].Bytes[Serv];
00122        return i;
00123       }
00124 
00125 // See if we can create a new entry
00126 //
00127    Usage = 0;
00128    if (freeEnt >= maxEnt || freeEnt < 0)
00129       {OssEroute.Emsg("Assign", uFname, "overflowed for", GName);
00130        return -1;
00131       }
00132 
00133 // Create the entry
00134 //
00135    if (!UsageLock()) return -1;
00136    memset(&uData[freeEnt], 0, sizeof(uEnt));
00137    strcpy(uData[freeEnt].gName, GName);
00138    uData[freeEnt].Bytes[addT] = static_cast<long long>(time(0));
00139    offset = sizeof(uEnt) * freeEnt;
00140    if (pwrite(aFD, &uData[freeEnt], sizeof(uEnt), offset) < 0)
00141       {OssEroute.Emsg("Adjust", errno, "update usage file", uFname);
00142        UsageLock(0); return -1;
00143       }
00144    UsageLock(0);
00145 
00146 // Add this to the vector table
00147 //
00148    uDvec[fencEnt++] = i = freeEnt;
00149 
00150 // Find next free entry
00151 //
00152    for (freeEnt = freeEnt+1; freeEnt < maxEnt; freeEnt++)
00153        if (*uData[freeEnt].gName == '\0') break;
00154 
00155 // All done here
00156 //
00157    return i;
00158 }
00159 
00160 /******************************************************************************/
00161 /*                               f i n d E n t                                */
00162 /******************************************************************************/
00163   
00164 int XrdOssSpace::findEnt(const char *GName)
00165 {
00166    int i;
00167 
00168 // Try to find the current entry in the file
00169 //
00170    for (i = 0; i < fencEnt; i++)
00171        if (!strcmp(uData[uDvec[i]].gName, GName)) return i;
00172    return -1;
00173 }
00174 
00175 /******************************************************************************/
00176 /*                                  I n i t                                   */
00177 /******************************************************************************/
00178   
00179 int XrdOssSpace::Init() {return (uFname ? haveUsage:0) | (qFname ? haveQuota:0);}
00180 
00181 /******************************************************************************/
00182   
00183 int XrdOssSpace::Init(const char *aPath, const char *qPath, int isSOL)
00184 {
00185    static const mode_t theMode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
00186    struct stat buf;
00187    const char *iP;
00188    char *aP, buff[1048];
00189    int i, opts, updt = 0;
00190 
00191 // Indicate whether we are solitary or not
00192 //
00193    Solitary = isSOL;
00194 
00195 // Handle quota file first
00196 //
00197    if (qPath)
00198       {qFname = strdup(qPath);
00199        if (!Quotas()) return 0;
00200        XrdOucEnv::Export("XRDOSSQUOTAFILE", qFname);
00201       }
00202 
00203 // Construct the file path for the usage file
00204 //
00205    if (!aPath) return 1;
00206    strcpy(buff, aPath);
00207    aP = buff + strlen(aPath);
00208    if (*(aP-1) != '/') *aP++ = '/';
00209    if ((iP = XrdOucUtils::InstName(-1)))
00210       {strcpy(aP, iP); aP += strlen(iP); *aP++ = '/'; *aP = '\0';
00211        mkdir(buff, S_IRWXU | S_IRWXG);
00212       }
00213    strcpy(aP, ".Usage");
00214    uFname = strdup(buff);
00215    XrdOucEnv::Export("XRDOSSUSAGEFILE", uFname);
00216 
00217 // First check if the file really exists, if not, create it
00218 //
00219    if (stat(uFname, &buf))
00220       if (errno != ENOENT)
00221          {OssEroute.Emsg("Init", errno, "open", uFname);
00222           return 0;
00223          } else opts = O_CREAT|O_TRUNC;
00224       else if ( buf.st_size != DataSz && buf.st_size)
00225               {OssEroute.Emsg("Init", uFname, "has invalid size."); return 0;}
00226               else opts = 0;
00227 
00228 // Open the target file
00229 //
00230    if ((aFD = open(uFname, opts|O_RDWR|O_SYNC, theMode)) < 0)
00231       {OssEroute.Emsg("Init", errno, "open", uFname);
00232        return 0;
00233       }
00234 
00235 // Lock the file
00236 //
00237    UsageLock();
00238 
00239 // Either read the contents or initialize the contents
00240 //
00241    if (opts & O_CREAT || buf.st_size == 0)
00242       {memset(uData, 0, sizeof(uData));
00243        if (!write(aFD, uData, sizeof(uData)))
00244           {OssEroute.Emsg("Init", errno, "create", uFname);
00245            UsageLock(0); return 0;
00246           }
00247        fencEnt = 0; freeEnt = 0;
00248      } else {
00249       if (!read(aFD, uData, sizeof(uData)))
00250          {OssEroute.Emsg("Init", errno, "read", uFname);
00251           UsageLock(0); return 0;
00252          }
00253       for (i = 0; i < maxEnt; i++)
00254           {if (*uData[i].gName != '\0')
00255               {uDvec[fencEnt++] = i; updt = Readjust(i);}
00256               else if (freeEnt < 0) freeEnt = i;
00257           }
00258       if (freeEnt < 0) OssEroute.Emsg("Init", uFname, "is full.");
00259      }
00260 
00261 // If we need to rewrite the data, do so
00262 //
00263    if (updt && pwrite(aFD, uData, sizeof(uData), 0) < 0)
00264       OssEroute.Emsg("Init", errno, "rewrite", uFname);
00265 
00266 // All done
00267 //
00268    UsageLock(0); 
00269    sprintf(buff, "%d usage log entries in use; %d available.", 
00270                  fencEnt, maxEnt-fencEnt);
00271    OssEroute.Emsg("Init", buff);
00272    return 1;
00273 }
00274 
00275 /******************************************************************************/
00276 /*                                Q u o t a s                                 */
00277 /******************************************************************************/
00278   
00279 int XrdOssSpace::Quotas()
00280 {
00281   XrdOucStream Config(&OssEroute);
00282   XrdOssCache_Group *fsg;
00283   struct stat buf;
00284   long long qval;
00285   char cgroup[minSNbsz], *val;
00286   int qFD, NoGo = 0;
00287 
00288 // See if the file has changed (note the firs time through it will have)
00289 //
00290    if (stat(qFname,&buf))
00291       {OssEroute.Emsg("Quotas", errno, "process quota file", qFname);
00292        return 0;
00293       }
00294    if (buf.st_mtime == lastMtime) return 0;
00295    lastMtime = buf.st_mtime;
00296 
00297 // Try to open the quota file.
00298 //
00299    if ( (qFD = open(qFname, O_RDONLY, 0)) < 0)
00300       {OssEroute.Emsg("Quotas", errno, "open quota file", qFname);
00301        return 0;
00302       }
00303 
00304 // Attach the file to a stream and tell people what we are doing
00305 //
00306    OssEroute.Emsg("Quotas", "Processing quota file", qFname);
00307    Config.Attach(qFD);
00308 
00309 // Now start reading records until eof.
00310 //
00311    while((val = Config.GetMyFirstWord()))
00312         {if (strlen(val) >= sizeof(cgroup))
00313             {OssEroute.Emsg("Quotas", "invalid quota group =", val);
00314              NoGo = 1; continue;
00315             }
00316          strcpy(cgroup, val);
00317 
00318          if (!(val = Config.GetWord()))
00319             {OssEroute.Emsg("Quotas", "quota value not specified for", cgroup);
00320              NoGo = 1; continue;
00321             }
00322          if (XrdOuca2x::a2sz(OssEroute, "quota", val, &qval))
00323             {NoGo = 1; continue;
00324             }
00325          fsg = XrdOssCache_Group::fsgroups;
00326          while(fsg && strcmp(cgroup, fsg->group)) fsg = fsg->next;
00327          if (fsg) fsg->Quota = qval;
00328          if (!strcmp("public", cgroup)) XrdOssCache_Group::PubQuota = qval;
00329             else if (!fsg) OssEroute.Emsg("Quotas", cgroup, 
00330                                      "cache group not found; quota ignored");
00331         }
00332     close(qFD);
00333     return (NoGo ? 0 : 1);
00334 }
00335 
00336 /******************************************************************************/
00337 /*                              R e a d j u s t                               */
00338 /******************************************************************************/
00339   
00340 int XrdOssSpace::Readjust()
00341 {
00342    static time_t lastUtime = 0;
00343    struct stat buf;
00344    int k, rwsz, updt = 0;
00345 
00346 // No readjustment needed if we are not a server or we have nothing
00347 //
00348    if (fencEnt <= 0) return 0;
00349    if (!fstat(aFD, &buf))
00350       {if (buf.st_mtime == lastUtime) return 0;
00351        lastUtime = buf.st_mtime;
00352       }
00353    rwsz = sizeof(uEnt)*(uDvec[fencEnt-1] + 1);
00354 
00355 // Lock the file
00356 //
00357    UsageLock();
00358 
00359 // Read the file again
00360 //
00361    if (!pread(aFD, uData, rwsz, 0))
00362       {OssEroute.Emsg("Readjust", errno, "read", uFname);
00363        UsageLock(0); return 0;
00364       }
00365 
00366 // Perform necessary readjustments but only for things we know about
00367 //
00368    for (k = 0; k < fencEnt; k++) updt |= Readjust(uDvec[k]);
00369 
00370 // If we need to rewrite the data, do so
00371 //
00372    if (updt && pwrite(aFD, uData, rwsz, 0) < 0)
00373       OssEroute.Emsg("Readjust", errno, "rewrite", uFname);
00374 
00375 // All done
00376 //
00377    UsageLock(0);
00378    return updt;
00379 }
00380 
00381 /******************************************************************************/
00382   
00383 int XrdOssSpace::Readjust(int i)
00384 {
00385 
00386 // Check if any readjustment is needed
00387 //
00388    if (uData[i].Bytes[Pstg] || uData[i].Bytes[Purg] || uData[i].Bytes[Admin])
00389       {uData[i].Bytes[Serv] = uData[i].Bytes[Serv] + uData[i].Bytes[Pstg]
00390                             - uData[i].Bytes[Purg] + uData[i].Bytes[Admin];
00391        uData[i].Bytes[Pstg] = uData[i].Bytes[Purg] = uData[i].Bytes[Admin] = 0;
00392        return 1;
00393       }
00394    return 0;
00395 }
00396 
00397 /******************************************************************************/
00398 /*                              U n a s s i g n                               */
00399 /******************************************************************************/
00400   
00401 int XrdOssSpace::Unassign(const char *GName)
00402 {
00403    off_t offset;
00404    int k, i;
00405 
00406 // Try to find the current entry in the file
00407 //
00408    for (k = 0; k < fencEnt; k++)
00409        if (!strcmp(uData[uDvec[k]].gName, GName)) break;
00410    if (k >= fencEnt) return -1;
00411    i = uDvec[k];
00412 
00413 // Create the entry
00414 //
00415    if (!UsageLock()) return -1;
00416    memset(&uData[i], 0, sizeof(uEnt));
00417    offset = sizeof(uEnt) * i;
00418    if (pwrite(aFD, &uData[freeEnt], sizeof(uEnt), offset) < 0)
00419       {OssEroute.Emsg("Unassign", errno, "update usage file", uFname);
00420        UsageLock(0); return -1;
00421       }
00422    UsageLock(0);
00423 
00424 // Squish out the uDvec
00425 //
00426    if (i < freeEnt) freeEnt = i;
00427    for (i = k+1; i < fencEnt; i++) uDvec[k++] = uDvec[i];
00428    fencEnt--;
00429    return 0;
00430 }
00431   
00432 /******************************************************************************/
00433 /*                                 U s a g e                                  */
00434 /******************************************************************************/
00435   
00436 long long XrdOssSpace::Usage(const char *GName, struct uEnt &uVal, int rrd)
00437 {
00438    int i, rwsz;
00439 
00440 // If we need to re-read the file, do so
00441 //
00442    if (rrd)
00443       {if (fencEnt <= 0) return -1;
00444        UsageLock();
00445        rwsz = sizeof(uEnt)*(uDvec[fencEnt-1] + 1);
00446        if (!pread(aFD, uData, rwsz, 0))
00447           {OssEroute.Emsg("Readjust", errno, "read", uFname);
00448            UsageLock(0); return -1;
00449           }
00450        UsageLock(0);
00451       }
00452 
00453 // Try to find the current entry in the file
00454 //
00455    if ((i = findEnt(GName)) >= 0)
00456       {uVal = uData[i];
00457        return uData[i].Bytes[Serv];
00458       }
00459 
00460 // Not found
00461 //
00462    memset(&uVal, 0, sizeof(uEnt));
00463    return -1;
00464 }
00465 
00466 /******************************************************************************/
00467 /* private:                    U s a g e L o c k                              */
00468 /******************************************************************************/
00469   
00470 int XrdOssSpace::UsageLock(int Dolock)
00471 {
00472    FLOCK_t lock_args;
00473    const char *What;
00474    int rc;
00475 
00476 // Establish locking options
00477 //
00478    bzero(&lock_args, sizeof(lock_args));
00479    if (Dolock) {lock_args.l_type = F_WRLCK; What =   "lock";}
00480       else     {lock_args.l_type = F_UNLCK; What = "unlock";}
00481 
00482 // Perform action.
00483 //
00484    do {rc = fcntl(aFD,F_SETLKW,&lock_args);} while(rc < 0 && errno == EINTR);
00485    if (rc < 0) {OssEroute.Emsg("UpdateLock", errno, What, uFname); return 0;}
00486 
00487 // All done
00488 //
00489    return 1;
00490 }

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