XrdCnsLogClient.cc

Go to the documentation of this file.
00001 /******************************************************************************/
00002 /*                                                                            */
00003 /*                    X r d C n s L o g C l i e n t . 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: XrdCnsLogClient.cc 32231 2010-02-05 18:24:46Z ganis $
00012 
00013 const char *XrdCnsLogClientCVSID = "$Id: XrdCnsLogClient.cc 32231 2010-02-05 18:24:46Z ganis $";
00014   
00015 #include <errno.h>
00016 #include <unistd.h>
00017 #include <fcntl.h>
00018 #include <string.h>
00019 #include <stdio.h>
00020 #include <sys/types.h>
00021 #include <sys/stat.h>
00022 #include <sys/uio.h>
00023 
00024 #include "Xrd/XrdTrace.hh"
00025 
00026 #include "XrdClient/XrdClient.hh"
00027 #include "XrdClient/XrdClientAdmin.hh"
00028 
00029 #include "XrdCns/XrdCnsConfig.hh"
00030 #include "XrdCns/XrdCnsInventory.hh"
00031 #include "XrdCns/XrdCnsLog.hh"
00032 #include "XrdCns/XrdCnsLogClient.hh"
00033 #include "XrdCns/XrdCnsLogFile.hh"
00034 #include "XrdCns/XrdCnsLogRec.hh"
00035 #include "XrdCns/XrdCnsXref.hh"
00036 
00037 #include "XrdNet/XrdNetDNS.hh"
00038 #include "XrdOuc/XrdOucNSWalk.hh"
00039 #include "XrdOuc/XrdOucTList.hh"
00040 #include "XrdOuc/XrdOucUtils.hh"
00041 #include "XrdSys/XrdSysError.hh"
00042 #include "XrdSys/XrdSysTimer.hh"
00043 
00044 /******************************************************************************/
00045 /*                        G l o b a l   O b j e c t s                         */
00046 /******************************************************************************/
00047   
00048 namespace XrdCns
00049 {
00050 extern XrdCnsConfig Config;
00051 
00052 extern XrdSysError  MLog;
00053 
00054 extern XrdOucTrace  XrdTrace;
00055 }
00056 
00057 using namespace XrdCns;
00058 
00059 /******************************************************************************/
00060 /*                           C o n s t r u c t o r                            */
00061 /******************************************************************************/
00062   
00063 XrdCnsLogClient::XrdCnsLogClient(XrdOucTList     *rP,
00064                                  XrdCnsLogClient *pClient) : lfSem(0)
00065 {
00066    static int cNum = 0;
00067    static int bSfx = static_cast<int>(time(0)) - 1248126834;
00068    static char *myName = XrdNetDNS::getHostName();
00069    char destBuff[512];
00070 
00071 // Save our index into the commit array
00072 //
00073    pfxNF    = cNum++;
00074    Next     = pClient;
00075    sfxFN    = bSfx;
00076    logFirst = 0;
00077    logLast  = 0;
00078    urlHost  = strdup(rP->text);
00079 
00080 // Construct our logfile path (gauranteed to end with a slash)
00081 //
00082    strcpy(logDir, Config.ePath);
00083    logFN = logDir + strlen(Config.ePath);
00084    strcpy(logFN, rP->text);
00085    logFN = logFN + strlen(rP->text);
00086    *logFN++ = '/';
00087 
00088 // Estabish the file creation url
00089 //
00090    crtFN = crtURL + sprintf(crtURL, "root://%s/", urlHost);
00091 
00092 // Estalish the admin URL
00093 //
00094    sprintf(destBuff, "root://%s//tmp", urlHost);
00095    admURL = strdup(destBuff);
00096    Admin = 0;
00097 
00098 // Establish the backup operation processing
00099 //
00100    arkOnly = Config.Opts & XrdCnsConfig::optNoCns;
00101    if (rP->val >= 0) {*arkURL = '\0'; arkFN = 0;}
00102       else {strcpy(arkURL, crtURL); arkPath = arkURL + strlen(crtURL);
00103             strcpy(arkPath,Config.bPath); strcat(arkPath, myName);
00104             arkFN  = arkPath + strlen(arkPath); *arkFN++ = '/';
00105             if (!arkOnly) arkOnly= (rP == Config.bDest);
00106             MLog.Emsg("LogClient", "Server inventory at", arkURL);
00107            }
00108 }
00109 
00110 /******************************************************************************/
00111 /*                              A c t i v a t e                               */
00112 /******************************************************************************/
00113   
00114 int XrdCnsLogClient::Activate(XrdCnsLogFile *basefile)
00115 {
00116    XrdCnsLogFile *lfP;
00117 
00118 // Construct the our name for the file
00119 //
00120    sfxFN++;
00121    sprintf(logFN,"cns.log.%d.%010d", pfxNF, sfxFN);
00122 
00123 // Create new log file and subscribe it to the base file
00124 //
00125    if ((lfP = basefile->Subscribe(logDir, pfxNF)))
00126       {lfMutex.Lock();
00127        if (logLast) logLast->Next = lfP;
00128           else logFirst = lfP;
00129        logLast = lfP; lfSem.Post();
00130        lfMutex.UnLock();
00131       }
00132 
00133 // All done
00134 //
00135    if (Next) return Next->Activate(basefile);
00136    return 1;
00137 }
00138 
00139 /******************************************************************************/
00140 /*                                  I n i t                                   */
00141 /******************************************************************************/
00142   
00143 int XrdCnsLogClient::Init()
00144 {
00145    static const int Mode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH;
00146    XrdOucNSWalk::NSEnt *nInv = 0, *nFirst, *nsP;
00147    XrdCnsLogFile *fP;
00148    long long totsz = 0;
00149    int rc;
00150 
00151 // Delete any partial inventory log file
00152 //
00153    strcpy(logFN, XrdCnsLog::invFNa);
00154    unlink(logDir);
00155 
00156 // Create a path if it does not exist
00157 //
00158    if ((rc = XrdOucUtils::makePath(logDir, Mode)))
00159       {MLog.Emsg("Init", rc, "create log path", logDir); return 0;}
00160 
00161 // Now get all of the log files in the directory
00162 //
00163    *logFN = '\0';
00164    nFirst = XrdCnsLog::List(logDir, &nInv);
00165 
00166 // If this is a recreate then only one log file will be processed
00167 //
00168    if (Config.Opts & XrdCnsConfig::optRecr)
00169       while((nsP = nFirst))
00170            {nFirst = nFirst->Next; delete nsP;}
00171 
00172 // If there is an inventory log, make sure it's first in the process list
00173 //
00174    if (nInv) {nInv->Next = nFirst; nFirst = nInv;
00175               nInv->Stat.st_nlink = 0;
00176              }
00177 
00178 // Document what we have while we create a log file list
00179 //
00180    while((nsP = nFirst))
00181         {nFirst = nFirst->Next;
00182          MLog.Emsg("Init", "Recovered log file", nsP->Path);
00183          fP = new XrdCnsLogFile(nsP->Path, nsP->Stat.st_nlink, 0);
00184          if (logLast) logLast->Next = fP;
00185             else      logFirst      = fP;
00186          totsz += nsP->Stat.st_size;
00187          logLast = fP;
00188          delete nsP;
00189         }
00190 
00191 // Now indicate if something is amiss
00192 //
00193    if (totsz > 10*1024*1024)
00194       MLog.Emsg("Init", "Warning! More than 10MB of logs queued for", urlHost);
00195 
00196 // If this is a create, then run the log file, otherwise return for a start
00197 //
00198    if (!(Config.Opts & XrdCnsConfig::optRecr)) return 1;
00199    if (!(rc = Run(0)))
00200       MLog.Emsg("LogClient", urlHost, "namespace recreation failed!");
00201    return rc;
00202 }
00203   
00204 /******************************************************************************/
00205 /*                                   R u n                                    */
00206 /******************************************************************************/
00207 
00208 int XrdCnsLogClient::Run(int Always)
00209 {
00210    const char *TraceID = "ClientRun";
00211    XrdCnsLogFile *lfP = 0;
00212    XrdCnsLogRec  *lrP;
00213    char invDir[MAXPATHLEN+1], *invFN = invDir;
00214    time_t mCheck = time(0) - 10;
00215    int n, Ok = 0;
00216 
00217 // This may be a one time excution to recreate the name space (with out
00218 // without an inventory). Check if this is the case.
00219 //
00220    if (!Always && !arkFN && !Manifest()) return 0;
00221 
00222 // Process requests as they come in. We are always assured that we have at
00223 // least one log file in the chain of log files. Note that log records
00224 // returned by CnsLogFile are *not* recycleable!
00225 //
00226    Admin = admConnect(Admin);
00227 
00228 do{if (arkFN && time(0) >= mCheck)
00229       {if (!Manifest())
00230           {if (!Always) return 0;
00231            MLog.Emsg("LogClient","Unable to create inventory at",arkURL);
00232           }
00233        mCheck = time(0) + Config.mInt;
00234       }
00235 
00236    do {lfMutex.Lock();
00237        if ((lfP = logFirst))
00238           {if (!(logFirst = lfP->Next)) logLast = 0; lfMutex.UnLock();}
00239           else {lfMutex.UnLock(); lfSem.Wait();}
00240       } while(!lfP);
00241 
00242    if (lfP->Open())
00243       {while((lrP = lfP->getRec()))
00244             {if (arkOnly) continue;
00245              TRACE(DEBUG, urlHost <<" log data: '" <<lrP->Data() <<"'");
00246              switch (lrP->Type())
00247                     {case XrdCnsLogRec::lrClosew: Ok = do_Trunc (lrP); break;
00248                      case XrdCnsLogRec::lrCreate: Ok = do_Create(lrP); break;
00249                      case XrdCnsLogRec::lrInvD:   strcpy(invDir, lrP->Lfn1(n));
00250                                                   invFN = invDir+n; Ok = 0;
00251                                                   *invFN++ = '/';
00252                                                   break;
00253                      case XrdCnsLogRec::lrInvF:   strcpy(invFN, lrP->Lfn1());
00254                                         if ((Ok = do_Create(lrP, invDir)))
00255                                              Ok = do_Trunc( lrP, invDir);
00256                                                   break;
00257                      case XrdCnsLogRec::lrMkdir:  Ok = do_Mkdir (lrP); break;
00258                      case XrdCnsLogRec::lrMv:     Ok = do_Mv    (lrP); break;
00259                      case XrdCnsLogRec::lrRm:     Ok = do_Rm    (lrP); break;
00260                      case XrdCnsLogRec::lrRmdir:  Ok = do_Rmdir (lrP); break;
00261                      case XrdCnsLogRec::lrMount:
00262                      case XrdCnsLogRec::lrSpace:
00263                           if (Config.Space)
00264                              Config.Space->Add(lrP->Lfn1(),lrP->Space());
00265                                                                        break;
00266                      case XrdCnsLogRec::lrTOD:                         break;
00267                      default: MLog.Emsg("Run","Invalid logrec for",lrP->Lfn1());
00268                               Ok = 0;
00269                     }
00270              if (Ok) lfP->Commit();
00271             }
00272        if (!arkFN || Archive(lfP)) lfP->Unlink();
00273        delete lfP;
00274       }
00275   } while(Always);
00276 
00277 // We get here only for 1-time command processing (unthreaded)
00278 //
00279    return 1;
00280 }
00281   
00282 /******************************************************************************/
00283 /*                                 S t a r t                                  */
00284 /******************************************************************************/
00285   
00286 namespace XrdCns
00287 {
00288 void *StartLogClient(void *parg)
00289 {
00290    XrdCnsLogClient *lcP = static_cast<XrdCnsLogClient *>(parg);
00291    lcP->Run();
00292    return (void *)0;
00293 }
00294 }
00295 
00296 int XrdCnsLogClient::Start()
00297 {
00298    pthread_t tid;
00299    int rc;
00300 
00301 // Start the log client
00302 //
00303    if ((rc = XrdSysThread::Run(&tid, StartLogClient, (void *)this,
00304                                  XRDSYSTHREAD_BIND, "Log client")))
00305       {MLog.Emsg("Start", rc, "create log client thread");
00306        if (Next) Next->Start();
00307        return 0;
00308       }
00309 
00310 // All done
00311 //
00312    if (Next) return Next->Start();
00313    return 1;
00314 }
00315 
00316 /******************************************************************************/
00317 /*                       P r i v a t e   M e t h o d s                        */
00318 /******************************************************************************/
00319 /******************************************************************************/
00320 /*                            a d m C o n n e c t                             */
00321 /******************************************************************************/
00322 
00323 XrdClientAdmin *XrdCnsLogClient::admConnect(XrdClientAdmin *adminP)
00324 {
00325    const char *TraceID = "admConnect";
00326    static XrdSysMutex xcMutex;
00327 
00328 // If we have a previous instance of the admin, delete it
00329 //
00330    if (adminP) delete adminP;
00331 
00332 // Get a new admin
00333 //
00334    xcMutex.Lock();
00335    adminP = new XrdClientAdmin(admURL);
00336    xcMutex.UnLock();
00337 
00338 // Loop until connected
00339 //
00340    do {TRACE(DEBUG, "Connecting to " <<urlHost);
00341        if (adminP->Connect()) break;
00342        xrdEmsg("connect", admURL, adminP);
00343        XrdSysTimer::Snooze(20);
00344       } while (1);
00345 
00346 // All done
00347 //
00348    return adminP;
00349 }
00350 
00351 /******************************************************************************/
00352 /*                               A r c h i v e                                */
00353 /******************************************************************************/
00354   
00355 int XrdCnsLogClient::Archive(XrdCnsLogFile *lfP)
00356 {
00357    static const int OMode = kXR_open_updt | kXR_delete | kXR_mkpath;
00358    static const int AMode = kXR_ur | kXR_uw | kXR_gr | kXR_gw | kXR_or;
00359    XrdClient *fP;
00360    int   Blen, rc = 1;
00361    const char *lFN;
00362    char *oP, oldName[2048], *Buff = lfP->getLog(Blen);
00363 
00364 // See if there is anything to archive
00365 //
00366    if (!arkFN || !Blen) return 1;
00367 
00368 // Get the log file name (we can't use our object's one)
00369 //
00370    if (!(lFN = rindex(lfP->FName(), '/')))
00371       {MLog.Emsg("LogClient", "Unable to determine archive log file name.");
00372        return 0;
00373       } else lFN++;
00374 
00375 // Get a client instance
00376 //
00377    strcpy(arkFN, lFN);
00378    MLog.Emsg("Archive", "Creating backup", arkURL);
00379    *arkFN = '.';
00380    fP = new XrdClient(arkURL);
00381 
00382 // Open the target file and write out the log and close the file
00383 //
00384    if (!fP->Open(AMode, OMode, 0) || (fP->LastServerResp()->status) != kXR_ok)
00385       xrdEmsg("archive", lfP->FName(), fP);
00386       else if (Buff && Blen && !fP->Write(Buff, 0, Blen))
00387               xrdEmsg("write", lfP->FName(), fP);
00388               else rc = 0;
00389 
00390 // Rename the file to what it really should be
00391 //
00392    delete fP;
00393    strcpy(oldName, arkURL); *arkFN = (*lFN == 'i' ? 'I' : *lFN);
00394    oP = oldName + (arkPath - arkURL);
00395    if (!Admin->Mv(oP, arkPath))
00396       {xrdEmsg("rename", oldName, Admin); Admin->Rm(oP);  rc = 1;}
00397    
00398    return rc == 0;
00399 }
00400   
00401 /******************************************************************************/
00402 /*                             d o _ C r e a t e                              */
00403 /******************************************************************************/
00404   
00405 int XrdCnsLogClient::do_Create(XrdCnsLogRec *lrP, const char *lfn)
00406 {
00407    static const int OMode = kXR_open_updt | kXR_delete | kXR_mkpath;
00408    XrdClient *fP;
00409    int AMode = kXR_ur | kXR_uw;
00410    int CMode, Ok = 1;
00411 
00412 // Construct the Mode
00413 //
00414    CMode = lrP->Mode();
00415    if (CMode & S_IRGRP) AMode |= kXR_gr;
00416    if (CMode & S_IWGRP) AMode |= kXR_gw;
00417    if (CMode & S_IROTH) AMode |= kXR_or;
00418 
00419 // Get a client instance
00420 //
00421    if (!lfn) strcpy(crtFN, lrP->Lfn1());
00422       else {strcpy(crtFN, lfn);
00423             if (Config.Space)
00424                {char *spName = Config.Space->Key(lrP->Space());
00425                 if (spName && strcmp(spName, "public"))
00426                    {strcat(crtFN, "?oss.cgroup="); strcat(crtFN, spName);}
00427                }
00428            }
00429    fP = new XrdClient(crtURL);
00430 
00431 // Open the target file and write out the log
00432 //
00433    if (!fP->Open(AMode, OMode, 0) || (fP->LastServerResp()->status) != kXR_ok)
00434       Ok = xrdEmsg("create", lrP->Lfn1(), fP);
00435 
00436 // Finish up
00437 //
00438    delete fP;
00439    return Ok;
00440 }
00441   
00442 /******************************************************************************/
00443 /*                              d o _ M k d i r                               */
00444 /******************************************************************************/
00445   
00446 int XrdCnsLogClient::do_Mkdir(XrdCnsLogRec *lrP)
00447 {
00448    if (!Admin->Mkdir(lrP->Lfn1(), 7, 7, 5))
00449       return xrdEmsg("mkdir", lrP->Lfn1());
00450    return 1;
00451 }
00452 
00453 /******************************************************************************/
00454 /*                                 d o _ M v                                  */
00455 /******************************************************************************/
00456   
00457 int XrdCnsLogClient::do_Mv(XrdCnsLogRec *lrP)
00458 {
00459    if (!Admin->Mv(lrP->Lfn1(), lrP->Lfn2()))
00460       return xrdEmsg("mv", lrP->Lfn1());
00461    return 1;
00462 }
00463 
00464 /******************************************************************************/
00465 /*                                 d o _ R m                                  */
00466 /******************************************************************************/
00467   
00468 int XrdCnsLogClient::do_Rm(XrdCnsLogRec *lrP)
00469 {
00470    if (!Admin->Rm(lrP->Lfn1())) return xrdEmsg("rm", lrP->Lfn1());
00471    return 1;
00472 }
00473 
00474 /******************************************************************************/
00475 /*                              d o _ R m d i r                               */
00476 /******************************************************************************/
00477   
00478 int XrdCnsLogClient::do_Rmdir(XrdCnsLogRec *lrP)
00479 {
00480    if (!Admin->Rmdir(lrP->Lfn1())) return xrdEmsg("rmdir", lrP->Lfn1());
00481    return 1;
00482 }
00483 
00484 /******************************************************************************/
00485 /*                              d o _ T r u n c                               */
00486 /******************************************************************************/
00487   
00488 int XrdCnsLogClient::do_Trunc(XrdCnsLogRec *lrP, const char *lfn)
00489 {
00490    if (!Admin->Truncate((lfn ? lfn : lrP->Lfn1()), lrP->Size()))
00491       return xrdEmsg("trunc", (lfn ? lfn : lrP->Lfn1()));
00492    return 1;
00493 }
00494 
00495 /******************************************************************************/
00496 /*                              M a n i f e s t                               */
00497 /******************************************************************************/
00498 
00499 int XrdCnsLogClient::Manifest()
00500 {
00501    const char *TraceID = "Manifest";
00502    XrdCnsInventory Inventory;
00503    
00504    XrdCnsLogFile *lfP;
00505    XrdOucTList *xP;
00506    long long vSize;
00507    long V1, V2, V3;
00508    char oldName[MAXPATHLEN+1];
00509 
00510 // Check if we will be processing an inventory log file
00511 //
00512    lfMutex.Lock();
00513    if (logFirst)
00514       {const char *fN = rindex(logFirst->FName(), '/');
00515        if (fN && !strcmp(XrdCnsLog::invFNz, fN+1))
00516           {lfMutex.UnLock(); return 1;}
00517       }
00518    lfMutex.UnLock();
00519 
00520 // Check if we have an inventory file at the destination
00521 //
00522    if (arkFN)
00523       {strcpy(arkFN, XrdCnsLog::invFNz);
00524        if (Admin->Stat(arkPath, V1, vSize, V2, V3)) return 1;
00525        if (Admin->LastServerError()->errnum != kXR_NotFound)
00526           {xrdEmsg("find inventory", arkPath, Admin); return 0;}
00527        TRACE(DEBUG, "Creating inventory...");
00528       }
00529 
00530 // Create a log file for the inventory
00531 //
00532    strcpy(logFN, XrdCnsLog::invFNa);
00533    lfP = new XrdCnsLogFile(logDir, 0, 0);
00534    if (!(lfP->Open(0))) {delete lfP; return 0;}
00535 
00536 // Initialize inventory processing
00537 //
00538    Inventory.Init(lfP);
00539 
00540 // Now inventory all the exported paths
00541 //
00542    xP = Config.Exports;
00543    while(xP && Inventory.Conduct(xP->text)) xP = xP->next;
00544    lfP->Eol(); delete lfP;
00545 
00546 // Check if all went well
00547 //
00548    if (xP) {unlink(logDir); return 0;}
00549 
00550 // Rename the file to what we really want it to be
00551 //
00552    strcpy(oldName, logDir); strcpy(logFN, XrdCnsLog::invFNt);
00553    if (rename(oldName, logDir))
00554       {MLog.Emsg("Manifest", errno, "rename", oldName);
00555        unlink(logDir); return 0;
00556       }
00557 
00558 // Create a new log file object to handle this log file and chain it in
00559 //
00560    lfP = new XrdCnsLogFile(logDir, 0, 0);
00561    lfMutex.Lock();
00562    lfP->Next = logFirst; logFirst = lfP;
00563    if (!logLast) logLast = lfP;
00564    lfMutex.UnLock();
00565 
00566 // All done
00567 //
00568    return 1;
00569 }
00570  
00571 /******************************************************************************/
00572 /*                              m a p E r r o r                               */
00573 /******************************************************************************/
00574   
00575 int XrdCnsLogClient::mapError(int rc)
00576 {
00577     switch(rc)
00578        {case kXR_NotFound:      return ENOENT;
00579         case kXR_NotAuthorized: return EACCES;
00580         case kXR_IOError:       return EIO;
00581         case kXR_NoMemory:      return ENOMEM;
00582         case kXR_NoSpace:       return ENOSPC;
00583         case kXR_ArgTooLong:    return ENAMETOOLONG;
00584         case kXR_noserver:      return EHOSTUNREACH;
00585         case kXR_NotFile:       return ENOTBLK;
00586         case kXR_isDirectory:   return EISDIR;
00587         case kXR_FSError:       return ENOSYS;
00588         default:                return ECANCELED;
00589        }
00590 }
00591   
00592 /******************************************************************************/
00593 /*                               x r d E m s g                                */
00594 /******************************************************************************/
00595 
00596 int XrdCnsLogClient::xrdEmsg(const char *Opname, const char *theFN,
00597                              XrdClientAdmin *aP)
00598 {
00599    char *etext  =  aP->LastServerError()->errmsg;
00600    int rc=mapError(aP->LastServerError()->errnum);
00601 
00602    if (rc == ECANCELED && etext && *etext) MLog.Emsg("LogClient", etext);
00603       else MLog.Emsg("LogClient", rc, Opname, theFN);
00604    return 0;
00605 }
00606 
00607 /******************************************************************************/
00608 
00609 int XrdCnsLogClient::xrdEmsg(const char *Opname, const char *theFN)
00610 {
00611    return xrdEmsg(Opname, theFN, Admin);
00612 }
00613 
00614 /******************************************************************************/
00615 
00616 int XrdCnsLogClient::xrdEmsg(const char *Opn, const char *Fn, XrdClient *fP)
00617 {
00618    char *etext  =  fP->LastServerError()->errmsg;
00619    int rc=mapError(fP->LastServerError()->errnum);
00620 
00621    if (rc == ECANCELED && etext && *etext) MLog.Emsg("LogClient", etext);
00622       else MLog.Emsg("LogClient", rc, Opn, Fn);
00623    return 0;
00624 }

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