TRFIOFile.cxx

Go to the documentation of this file.
00001 // @(#)root/rfio:$Id: TRFIOFile.cxx 35358 2010-09-17 09:58:04Z rdm $
00002 // Author: Fons Rademakers 20/01/99 + Giulia Taurelli 29/06/2006 + Andreas Peters 07/12/2007
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2007, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 ///////////////////////////////////////////////////////////////////////////
00013 //                                                                       //
00014 // TRFIOFile                                                             //
00015 //                                                                       //
00016 // A TRFIOFile is like a normal TFile except that it reads and writes    //
00017 // its data via a rfiod server (for more on the rfiod daemon see         //
00018 // http://wwwinfo.cern.ch/pdp/serv/shift.html). TRFIOFile file names     //
00019 // are in standard URL format with protocol "rfio". The following are    //
00020 // valid TRFIOFile URL's:                                                //
00021 //                                                                       //
00022 //    rfio:/afs/cern.ch/user/r/rdm/galice.root                           //
00023 //         where galice.root is a symlink of the type /shift/.../...     //
00024 //    rfio:na49db1:/data1/raw.root                                       //
00025 //    rfio:/castor/cern.ch/user/r/rdm/test.root                          //
00026 //                                                                       //
00027 // If Castor 2.1 is used the file names can be given also in the         //
00028 // following ways:                                                       //
00029 //                                                                       //
00030 //  rfio://host:port/?path=FILEPATH                                      //
00031 //  rfio://host/?path=FILEPATH                                           //
00032 //  rfio:///castor?path=FILEPATH                                         //
00033 //  rfio://stager_host:stager_port/?path=/castor/cern.ch/user/r/         //
00034 //    rdm/bla.root&svcClass=MYSVCLASS&castorVersion=MYCASTORVERSION      //
00035 //  rfio://stager_host/?path=/castor/cern.ch/user/r/                     //
00036 //    rdm/bla.root&svcClass=MYSVCLASS&castorVersion=MYCASTORVERSION      //
00037 //  rfio:///castor?path=/castor/cern.ch/user/r/                          //
00038 //    rdm/bla.root&svcClass=MYSVCLASS&castorVersion=MYCASTORVERSION      //
00039 //                                                                       //
00040 // path is mandatory as parameter but all the other ones are optional.   //
00041 //                                                                       //
00042 // For the ultimate description of supported urls see:                   //
00043 //    https://twiki.cern.ch/twiki/bin/view/FIOgroup/RfioRootTurl         //
00044 //                                                                       //
00045 ///////////////////////////////////////////////////////////////////////////
00046 
00047 #include "TRFIOFile.h"
00048 #include "TROOT.h"
00049 #include "TTimeStamp.h"
00050 #include "TVirtualPerfStats.h"
00051 
00052 #include <sys/stat.h>
00053 #include <sys/types.h>
00054 #include <stdlib.h>
00055 #ifndef R__WIN32
00056 #include <unistd.h>
00057 #if defined(R__SUN) || defined(R__SGI) || defined(R__HPUX) ||         \
00058 defined(R__AIX) || defined(R__LINUX) || defined(R__SOLARIS) ||        \
00059 defined(R__ALPHA) || defined(R__HIUX) || defined(R__FBSD) ||          \
00060 defined(R__MACOSX) || defined(R__HURD) || defined(R__OBSD)
00061 #define HAS_DIRENT
00062 #endif
00063 #endif
00064 
00065 #ifdef HAS_DIRENT
00066 #include <dirent.h>
00067 #endif
00068 
00069 #include <rfio.h>
00070 #include <rfio_api.h>
00071 #include <serrno.h>
00072 
00073 
00074 ClassImp(TRFIOFile)
00075 ClassImp(TRFIOSystem)
00076 
00077 //______________________________________________________________________________
00078 TRFIOFile::TRFIOFile(const char *url, Option_t *option, const char *ftitle,
00079                      Int_t compress)
00080    : TFile(url, "NET", ftitle, compress)
00081 {
00082    // Create a RFIO file object. A RFIO file is the same as a TFile
00083    // except that it is being accessed via a rfiod server. The url
00084    // argument must be of the form: rfio:/path/file.root (where file.root
00085    // is a symlink of type /shift/aaa/bbb/ccc) or rfio:server:/path/file.root.
00086    // If the file specified in the URL does not exist, is not accessable
00087    // or can not be created the kZombie bit will be set in the TRFIOFile
00088    // object. Use IsZombie() to see if the file is accessable.
00089    // For a description of the option and other arguments see the TFile ctor.
00090    // The preferred interface to this constructor is via TFile::Open().
00091 
00092    fOption = option;
00093    fOption.ToUpper();
00094 
00095    Int_t readopt = RFIO_READBUF;
00096    ::rfiosetopt(RFIO_READOPT, &readopt, 4);
00097 
00098    if (fOption == "NEW")
00099       fOption = "CREATE";
00100 
00101    Bool_t create   = (fOption == "CREATE") ? kTRUE : kFALSE;
00102    Bool_t recreate = (fOption == "RECREATE") ? kTRUE : kFALSE;
00103    Bool_t update   = (fOption == "UPDATE") ? kTRUE : kFALSE;
00104    Bool_t read     = (fOption == "READ") ? kTRUE : kFALSE;
00105    if (!create && !recreate && !update && !read) {
00106       read    = kTRUE;
00107       fOption = "READ";
00108    }
00109 
00110    // to be able to use the turl starting with castor:
00111    if (!strcmp(fUrl.GetProtocol(), "castor"))
00112       fUrl.SetProtocol("rfio");
00113 
00114    // old RFIO client does not ignore ?filetpye=raw, remove it
00115    TString opt = fUrl.GetOptions();
00116    if (opt.Contains("&filetype=raw")) {
00117       opt.ReplaceAll("&filetype=raw", "");
00118       fUrl.SetOptions(opt);
00119    } else if (opt.Contains("filetype=raw")) {
00120       opt.ReplaceAll("filetype=raw", "");
00121       fUrl.SetOptions(opt);
00122    }
00123 
00124    // old RFIO client lib does not support :///, need to change to :////
00125    Bool_t addSlash = kFALSE;
00126    if ((strstr(url, ":/")   && !strstr(url, "://")) ||
00127        (strstr(url, ":///") && !strstr(url, ":////")))
00128       addSlash = kTRUE;
00129 
00130    // the complete turl in fname
00131    TString fname;
00132    if (!addSlash)
00133       fname.Form("%s://%s", fUrl.GetProtocol(), fUrl.GetFile());
00134    else
00135       fname.Form("%s:///%s", fUrl.GetProtocol(), fUrl.GetFile());
00136    if (strlen(fUrl.GetOptions()))
00137       fname += Form("?%s", fUrl.GetOptions());
00138 
00139    if (recreate) {
00140       if (::rfio_access((char*)fname.Data(), kFileExists) == 0)
00141          ::rfio_unlink((char*)fname.Data());
00142       recreate = kFALSE;
00143       create   = kTRUE;
00144       fOption  = "CREATE";
00145    }
00146    if (create && ::rfio_access((char*)fname.Data(), kFileExists) == 0) {
00147       Error("TRFIOFile", "file %s already exists", fname.Data());
00148       goto zombie;
00149    }
00150    if (update) {
00151       if (::rfio_access((char*)fname.Data(), kFileExists) != 0) {
00152          update = kFALSE;
00153          create = kTRUE;
00154       }
00155       if (update && ::rfio_access((char*)fname.Data(), kWritePermission) != 0) {
00156          Error("TRFIOFile", "no write permission, could not open file %s", fname.Data());
00157          goto zombie;
00158       }
00159    }
00160 
00161    // Connect to file system stream
00162    fRealName = fname;
00163 
00164    if (create || update) {
00165 #ifndef WIN32
00166       fD = SysOpen(fname.Data(), O_RDWR | O_CREAT, 0644);
00167 #else
00168       fD = SysOpen(fname.Data(), O_RDWR | O_CREAT | O_BINARY, S_IREAD | S_IWRITE);
00169 #endif
00170       if (fD == -1) {
00171          SysError("TRFIOFile", "file %s can not be opened", fname.Data());
00172          goto zombie;
00173       }
00174       fWritable = kTRUE;
00175    } else {
00176 #ifndef WIN32
00177       fD = SysOpen(fname.Data(), O_RDONLY, 0644);
00178 #else
00179       fD = SysOpen(fname.Data(), O_RDONLY | O_BINARY, S_IREAD | S_IWRITE);
00180 #endif
00181       if (fD == -1) {
00182          SysError("TRFIOFile", "file %s can not be opened for reading", fname.Data());
00183          goto zombie;
00184       }
00185       fWritable = kFALSE;
00186    }
00187 
00188    Init(create);
00189 
00190    return;
00191 
00192 zombie:
00193    // error in file opening occured, make this object a zombie
00194    MakeZombie();
00195    gDirectory = gROOT;
00196 }
00197 
00198 //______________________________________________________________________________
00199 TRFIOFile::~TRFIOFile()
00200 {
00201    // RFIO file dtor. Close and flush directory structure.
00202 
00203    Close();
00204 }
00205 
00206 //______________________________________________________________________________
00207 Bool_t TRFIOFile::ReadBuffers(char *buf, Long64_t *pos, Int_t *len, Int_t nbuf)
00208 {
00209    // Read a list of buffers given in pos[] and len[] and return it
00210    // in a single buffer. Returns kTRUE in case of error.
00211 
00212    static struct iovec64 *iov = 0;
00213    static Int_t iovsize = 128;
00214    Int_t n;
00215 
00216    if (IsZombie()) {
00217       Error("ReadBuffers", "cannot read because object is in 'zombie' state");
00218       return kTRUE;
00219    }
00220 
00221    if (!IsOpen()) {
00222       Error("ReadBuffers", "the remote file is not open");
00223       return kTRUE;
00224    }
00225 
00226    Double_t start = 0;
00227    if (gPerfStats) start = TTimeStamp();
00228 
00229    // we maintain a static iove64 buffer to avoid malloc/free with every call
00230    if (!iov) {
00231       if (nbuf > iovsize)
00232          iovsize = nbuf;
00233 
00234       iov = (struct iovec64*)malloc(sizeof(struct iovec64) * iovsize);
00235       if (gDebug > 1)
00236          Info("TRFIOFile", "allocating iovec64 with size %d", iovsize);
00237       if (!iov) {
00238          Error("TRFIOFile", "error allocating preseek vector of size %ld",
00239                (Long_t)sizeof(struct iovec64) * iovsize);
00240          return kTRUE;
00241       }
00242    } else {
00243       if (nbuf > iovsize) {
00244          iovsize = nbuf;
00245          iov = (struct iovec64*) realloc(iov, sizeof(struct iovec64) * iovsize);
00246          if (gDebug > 1)
00247             Info("TRFIOFile", "re-allocating iovec64 with size %d", iovsize);
00248          if (!iov) {
00249             Error("TRFIOFile", "error reallocating preseek vector of size %ld",
00250                   (Long_t)sizeof(struct iovec64) * iovsize);
00251             return kTRUE;
00252          }
00253       }
00254    }
00255 
00256    for (n = 0; n < nbuf; n++) {
00257       if (gDebug>1)
00258          Info("TFIOFile", "adding chunk %d, %lld %d", n, pos[n], len[n]);
00259       iov[n].iov_base = pos[n] + fArchiveOffset;
00260       iov[n].iov_len  = len[n];
00261    }
00262 
00263    // prefetch the stuff
00264    if (rfio_preseek64(fD, iov, nbuf) < 0) {
00265       Error("TRFIOFile", "error doing rfio_preseek");
00266       return kTRUE;
00267    }
00268 
00269    // read the chunks
00270    Int_t k = 0;
00271 
00272    for (n = 0; n < nbuf; n++) {
00273       if (rfio_lseek64(fD, iov[n].iov_base, SEEK_SET) < 0) {
00274          Error("TRFIOFile", "error doing rfio_lseek");
00275          return kTRUE;
00276       }
00277       if (rfio_read(fD, buf+k, iov[n].iov_len) < 0) {
00278          Error("TRFIOFile", "error doing rfio_read");
00279          return kTRUE;
00280       }
00281       k += iov[n].iov_len;
00282    }
00283 
00284    fBytesRead += k;
00285 #ifdef WIN32
00286    SetFileBytesRead(GetFileBytesRead() + k);
00287    SetFileReadCalls(GetFileReadCalls() + 1);
00288 #else
00289    fgBytesRead += k;
00290    fgReadCalls++;
00291 #endif
00292 
00293    if (gPerfStats)
00294       gPerfStats->FileReadEvent(this, k, start);
00295 
00296    return kFALSE;
00297 }
00298 
00299 //______________________________________________________________________________
00300 Int_t TRFIOFile::SysOpen(const char *pathname, Int_t flags, UInt_t mode)
00301 {
00302    // Interface to system open. All arguments like in POSIX open.
00303    Int_t ret = ::rfio_open64((char*)pathname, flags, (Int_t) mode);
00304    if (ret < 0)
00305       gSystem->SetErrorStr(::rfio_serror());
00306    return ret;
00307 }
00308 
00309 //______________________________________________________________________________
00310 Int_t TRFIOFile::SysClose(Int_t fd)
00311 {
00312    // Interface to system close. All arguments like in POSIX close.
00313 
00314    Int_t ret = ::rfio_close(fd);
00315    if (ret < 0)
00316       gSystem->SetErrorStr(::rfio_serror());
00317    return ret;
00318 }
00319 
00320 //______________________________________________________________________________
00321 Int_t TRFIOFile::SysRead(Int_t fd, void *buf, Int_t len)
00322 {
00323    // Interface to system read. All arguments like in POSIX read.
00324 
00325    Int_t ret = ::rfio_read(fd, (char *)buf, len);
00326    if (ret < 0)
00327       gSystem->SetErrorStr(::rfio_serror());
00328    return ret;
00329 }
00330 
00331 //______________________________________________________________________________
00332 Int_t TRFIOFile::SysWrite(Int_t fd, const void *buf, Int_t len)
00333 {
00334    // Interface to system write. All arguments like in POSIX write.
00335 
00336    Int_t ret = ::rfio_write(fd, (char *)buf, len);
00337    if (ret < 0)
00338       gSystem->SetErrorStr(::rfio_serror());
00339    return ret;
00340 }
00341 
00342 //______________________________________________________________________________
00343 Long64_t TRFIOFile::SysSeek(Int_t fd, Long64_t offset, Int_t whence)
00344 {
00345    // Interface to system lseek. All arguments like in POSIX lseek
00346    // except that the offset and return value are Long_t to be able to
00347    // handle 64 bit file systems.
00348 
00349    Long64_t ret = ::rfio_lseek64(fd, offset, whence);
00350 
00351    if (ret < 0)
00352       gSystem->SetErrorStr(::rfio_serror());
00353 
00354    return ret;
00355 }
00356 
00357 //______________________________________________________________________________
00358 Int_t TRFIOFile::SysStat(Int_t fd, Long_t *id, Long64_t *size, Long_t *flags,
00359                          Long_t *modtime)
00360 {
00361    // Interface to TSystem:GetPathInfo(). Generally implemented via
00362    // stat() or fstat().
00363 
00364    struct stat64 statbuf;
00365 
00366    if (::rfio_fstat64(fd, &statbuf) >= 0) {
00367       if (id)
00368          *id = (statbuf.st_dev << 24) + statbuf.st_ino;
00369       if (size)
00370          *size = statbuf.st_size;
00371       if (modtime)
00372          *modtime = statbuf.st_mtime;
00373       if (flags) {
00374          *flags = 0;
00375          if (statbuf.st_mode & ((S_IEXEC)|(S_IEXEC>>3)|(S_IEXEC>>6)))
00376             *flags |= 1;
00377          if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
00378             *flags |= 2;
00379          if ((statbuf.st_mode & S_IFMT) != S_IFREG &&
00380              (statbuf.st_mode & S_IFMT) != S_IFDIR)
00381             *flags |= 4;
00382       }
00383       return 0;
00384    }
00385 
00386    gSystem->SetErrorStr(::rfio_serror());
00387    return 1;
00388 }
00389 
00390 //______________________________________________________________________________
00391 Int_t TRFIOFile::GetErrno() const
00392 {
00393    // Method returning rfio_errno. For RFIO files must use this
00394    // function since we need to check rfio_errno then serrno and finally errno.
00395 
00396    if (rfio_errno)
00397       return rfio_errno;
00398    if (serrno)
00399       return serrno;
00400    return TSystem::GetErrno();
00401 }
00402 
00403 //______________________________________________________________________________
00404 void TRFIOFile::ResetErrno() const
00405 {
00406    // Method resetting the rfio_errno, serrno and errno.
00407 
00408    rfio_errno = 0;
00409    serrno = 0;
00410    TSystem::ResetErrno();
00411 }
00412 
00413 
00414 //______________________________________________________________________________
00415 TRFIOSystem::TRFIOSystem() : TSystem("-rfio", "RFIO Helper System")
00416 {
00417    // Create helper class that allows directory access via rfiod.
00418    // The name must start with '-' to bypass the TSystem singleton check.
00419 
00420    SetName("rfio");
00421 
00422    fDirp = 0;
00423 }
00424 
00425 //______________________________________________________________________________
00426 Int_t TRFIOSystem::MakeDirectory(const char *dir)
00427 {
00428    // Make a directory via rfiod.
00429 
00430    TUrl url(dir);
00431    Int_t ret = ::rfio_mkdir((char*)url.GetFileAndOptions(), 0755);
00432    if (ret < 0)
00433       gSystem->SetErrorStr(::rfio_serror());
00434    return ret;
00435 }
00436 
00437 //______________________________________________________________________________
00438 void *TRFIOSystem::OpenDirectory(const char *dir)
00439 {
00440    // Open a directory via rfiod. Returns an opaque pointer to a dir
00441    // structure. Returns 0 in case of error.
00442 
00443    if (fDirp) {
00444       Error("OpenDirectory", "invalid directory pointer (should never happen)");
00445       fDirp = 0;
00446    }
00447 
00448    TUrl url(dir);
00449 
00450    struct stat finfo;
00451    if (::rfio_stat((char*)url.GetFileAndOptions(), &finfo) < 0)
00452       return 0;
00453 
00454    if ((finfo.st_mode & S_IFMT) != S_IFDIR)
00455       return 0;
00456 
00457    fDirp = (void*) ::rfio_opendir((char*)url.GetFileAndOptions());
00458 
00459    if (!fDirp)
00460       gSystem->SetErrorStr(::rfio_serror());
00461 
00462    return fDirp;
00463 }
00464 
00465 //______________________________________________________________________________
00466 void TRFIOSystem::FreeDirectory(void *dirp)
00467 {
00468    // Free directory via rfiod.
00469 
00470    if (dirp != fDirp) {
00471       Error("FreeDirectory", "invalid directory pointer (should never happen)");
00472       return;
00473    }
00474 
00475    if (dirp)
00476       ::rfio_closedir((DIR*)dirp);
00477 
00478    fDirp = 0;
00479 }
00480 
00481 //______________________________________________________________________________
00482 const char *TRFIOSystem::GetDirEntry(void *dirp)
00483 {
00484    // Get directory entry via rfiod. Returns 0 in case no more entries.
00485 
00486    if (dirp != fDirp) {
00487       Error("GetDirEntry", "invalid directory pointer (should never happen)");
00488       return 0;
00489    }
00490 
00491    struct dirent *dp;
00492 
00493    if (dirp) {
00494       dp = (struct dirent *) ::rfio_readdir((DIR*)dirp);
00495       if (!dp)
00496          return 0;
00497       return dp->d_name;
00498    }
00499    return 0;
00500 }
00501 
00502 //______________________________________________________________________________
00503 Int_t TRFIOSystem::GetPathInfo(const char *path, FileStat_t &buf)
00504 {
00505    // Get info about a file. Info is returned in the form of a FileStat_t
00506    // structure (see TSystem.h).
00507    // The function returns 0 in case of success and 1 if the file could
00508    // not be stat'ed.
00509 
00510    TUrl url(path);
00511 
00512    struct stat64 sbuf;
00513    if (path && ::rfio_stat64((char*)url.GetFileAndOptions(), &sbuf) >= 0) {
00514 
00515       buf.fDev    = sbuf.st_dev;
00516       buf.fIno    = sbuf.st_ino;
00517       buf.fMode   = sbuf.st_mode;
00518       buf.fUid    = sbuf.st_uid;
00519       buf.fGid    = sbuf.st_gid;
00520       buf.fSize   = sbuf.st_size;
00521       buf.fMtime  = sbuf.st_mtime;
00522       buf.fIsLink = kFALSE;
00523 
00524       return 0;
00525    }
00526    return 1;
00527 }
00528 
00529 //______________________________________________________________________________
00530 Bool_t TRFIOSystem::AccessPathName(const char *path, EAccessMode mode)
00531 {
00532    // Returns FALSE if one can access a file using the specified access mode.
00533    // Mode is the same as for the Unix access(2) function.
00534    // Attention, bizarre convention of return value!!
00535 
00536    TUrl url(path);
00537    if (::rfio_access((char*)url.GetFileAndOptions(), mode) == 0)
00538       return kFALSE;
00539    gSystem->SetErrorStr(::rfio_serror());
00540    return kTRUE;
00541 }
00542 
00543 //______________________________________________________________________________
00544 Int_t TRFIOSystem::Unlink(const char *path)
00545 {
00546    // Unlink, i.e. remove, a file or directory. Returns 0 when succesfull,
00547    // -1 in case of failure.
00548 
00549    TUrl url(path);
00550 
00551    struct stat finfo;
00552    if (rfio_stat((char*)url.GetFileAndOptions(), &finfo) < 0)
00553       return -1;
00554 
00555    if (R_ISDIR(finfo.st_mode))
00556       return rfio_rmdir((char*)url.GetFileAndOptions());
00557    else
00558       return rfio_unlink((char*)url.GetFileAndOptions());
00559 }

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