Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

PerFile.cxx

Go to the documentation of this file.
00001 
00002 //
00003 // PerFile
00004 //
00005 // Package: Per (Persistency).
00006 //
00007 // S. Kasahara 11/00
00008 //
00009 // Purpose: This class opens, maintains (e.g. keeps track of number of 
00010 //          clients), and closes a single ROOT file.  It is a helper class 
00011 //          for the PerFileManager class.  The user does not open/close files 
00012 //          directly with the PerFile class, but instead should open 
00013 //          and close files through the singleton PerFileManager class.
00014 //
00016 
00017 #include <errno.h>
00018 #include "TNetFile.h"
00019 #include "TSystem.h"
00020 #ifdef HAVE_NO_NETERRORS_HEADER
00021 // pre-2003-08-29 (3.10/00) header
00022   #include "rootd.h"
00023 #else
00024   #include "NetErrors.h"
00025 #endif
00026 #include "Persistency/PerFile.h"
00027 #include "MessageService/MsgService.h"
00028 
00029 std::ostream& operator<<(std::ostream& ms, const PerFile& fm) {
00030   return fm.Print(ms);
00031 }
00032 
00033 ClassImp(PerFile)
00034 
00035 //   Definition of static data members
00036 //   *********************************
00037 
00038 CVSID("$Id: PerFile.cxx,v 1.17 2005/09/25 19:25:52 schubert Exp $");
00039 
00040 
00041 // Definition of methods (alphabetical order)
00042 // ***************************************************
00043 
00044 bool PerFile::AddNewClient(Per::EAccessMode accessmode) {
00045   //
00046   //  Purpose:  Add new client to the previously opened file if new requested 
00047   //            accessmode is compatible with the accessmode in which the file
00048   //            was originally opened. If successful fNumClient is incremented.
00049   //
00050   //  Arguments: 
00051   //    accessmode: enumerated file access mode of type EAccessMode (defined
00052   //                in Per.h).
00053   //
00054   //  Return:    true means client was successfully added to file.
00055   //             false means new accessmode was incompatible with original
00056   //             accessmode.
00057   //
00058   //  Contact:   S. Kasahara
00059   // 
00060   //  Notes: access modes kNew & kRecreate are considered compatible, 
00061   //         all other mode combinations are considered incompatible.
00062 
00063   bool accessok = false;
00064 
00065   if(fAccessMode == accessmode) {
00066     accessok = true;
00067   }
00068   else {
00069     if((fAccessMode == Per::kNew || fAccessMode == Per::kRecreate) &&
00070        (accessmode == Per::kNew || accessmode == Per::kRecreate)) {
00071         accessok = true;
00072     }
00073   }
00074 
00075   if(accessok) fNumClient++;
00076   return accessok;  
00077 }
00078 
00079 UInt_t PerFile::Close(bool kForce) {
00080   //
00081   //  Purpose:  Decrement the number of clients to open file, and close
00082   //            file if number of clients reaches zero.  Argument kForce set
00083   //            true forces closure of file regardless of number of clients
00084   //            (default is kForce==false).
00085   //
00086   //  Arguments: 
00087   //    kForce:  bool to force file closure regardless of number of clients.
00088   //             (by default kForce is set false).
00089   //
00090   //  Return:  number of clients of file remaining after method completes.
00091   //
00092   //  Contact:   S. Kasahara
00093   // 
00094 
00095   if (!kForce) {
00096     if(fNumClient > 0) fNumClient--; // decrement number of clients by one
00097   }
00098   else {
00099     fNumClient=0; // user requested forced file closure.
00100   }
00101 
00102   if( !fNumClient ) {
00103     // No clients left, close file
00104     if (IsOpen()) {
00105       if (fTFile -> IsWritable()) {
00106         // Write out Key with name "FileEnd" as final object to file.  
00107         // This marker is used by a reader of an open file to determine 
00108         // when a file has actually been closed by the writer.
00109         TDirectory *savedir = gDirectory;
00110         fTFile -> cd();  // change to file directory
00111         TNamed *isend = new TNamed("FileEnd","PerFile End Key");
00112         isend -> Write(NULL,TObject::kOverwrite);
00113         delete isend;
00114         savedir -> cd(); // change back to users directory
00115       }
00116       fTFile -> Close();
00117       delete fTFile;
00118       fTFile = 0;
00119     }
00120   }
00121 
00122   return fNumClient;
00123 }
00124 
00125 bool PerFile::HasFileEndKey() const {
00126   //
00127   //  Purpose:  Determine if file has been closed by the writer.  This
00128   //            is determined by the presence or absence of a "FileEnd"
00129   //            Key.
00130   //
00131   //  Arguments: none.
00132   //
00133   //  Return:  true if "FileEnd" Key is present, else false.
00134   //
00135   //  Contact:   S. Kasahara
00136   // 
00137   //  Notes:  This method is used by a reader of an open file to determine 
00138   //          when that file has actually been closed by the writer.  
00139   //
00140 
00141   if ( IsOpen() && (fTFile -> Get("FileEnd")) )
00142     return true;
00143   else 
00144     return false;
00145 
00146 }
00147 
00148 PerFile::PerFile(string fullfilepathname, Per::EAccessMode accessmode):
00149   fFullFilePathName(fullfilepathname),fAccessMode(accessmode),fTFile(0),
00150   fNumClient(0),fRemote(false),fErrorCode(Per::kErrSuccess) {
00151   //
00152   //  Purpose:  PerFile constructor.  Opens ROOT TFile with requested 
00153   //            filename and accessmode.  Uses the static TFile::Open
00154   //            method to open both local and remote files transparently.
00155   //            User should use PerFile::IsOpen() to check to see if
00156   //            file was opened successfully.
00157   //
00158   //  Arguments: 
00159   //    fullfilepathname:  full file path name to be opened.  If file is
00160   //                       remote, must follow protocol as defined in
00161   //                       the TFile::Open method.  Specifically for remote
00162   //                       files served by the rootd server daemon, the
00163   //                       file name is prefaced by "root:" or "roots:" 
00164   //                       and the node name as in:
00165   //                       "root://urheim.hep.umn.edu/~minos/filename.dat"
00166   //                       See the TNetFile class description or  
00167   //                       http://root.cern.ch/root/NetFile.html for more 
00168   //                       information on the remote file name format.
00169   //    accessmode: enumerated access mode of type EAccessMode (defined in
00170   //                Per.h) in which file is to be opened:  
00171   //                kRead = open file in read only mode.
00172   //                kNew = open new file in read/write. If file exists 
00173   //                       previously, do not overwrite.
00174   //                kRecreate = same as kNew, but if file exists previously
00175   //                            overwrite.
00176   //                kUpdate = open existing file in read/write mode.
00177   //
00178   //  Return: n/a.
00179   //
00180   //  Notes: Authorization for remote access follows the protocol
00181   //         discussed in http://root.cern.ch/root/NetFile.html with
00182   //         useage dependent on how the rootd server was configured on
00183   //         the remote site.  
00184   //         One approach, when not using secure authentication, is
00185   //         to store the username&password required for remote access in
00186   //         a .netrc file located in the user's home directory.  The format 
00187   //         for a line in the .netrc file is:
00188   //         machine <machine name> login <username> password <password>
00189   //         e.g.
00190   //         machine urheim.hep.umn.edu login myusername password mypassword
00191   //                     
00192   //         If the constructor fails to open the file successfully, 
00193   //         PerFile::GetErrorCode can be used to determine the reason
00194   //         for the failure.
00195   // 
00196   //  Contact:   S. Kasahara
00197   // 
00198 
00199   gSystem -> ResetErrno();
00200   
00201   // Open File assuming default compression mode.  May want to specify
00202   // eventually both the compression mode and a job related title.
00203   // Determine if file is remote
00204   if ( fullfilepathname.find("root:") == 0 
00205     || fullfilepathname.find("roots:") == 0 ) {
00206     fRemote = true;
00207     // Assumes that user has correctly set up authorization according to
00208     // instructions in http://root.cern.ch/root/NetFile.html
00209     // Use of TNetFile is enforced instead of relying on TFile::Open, because
00210     // TFile::Open defaults to TFile even if the user has specified "root:"
00211     // if it determines that access is local and parses the file string to
00212     // determine the local file path.  This does not result in 
00213     // a correct file path if rootd has been set up for anonymous useage.
00214     // Update: 9/25/2005, SK/GMI  The TEnv configuration variable
00215     // "TFile.ForceRemote" is now set true in the PerFileManager, so
00216     // that TFile::Open can be used in all cases. The old line:
00217     // fTFile =new TNetFile(fullfilepathname.c_str(),Per::AsString(accessmode),
00218     //                      "Persistency file");
00219     // has been replaced by:
00220     fTFile = TFile::Open(fullfilepathname.c_str(),Per::AsString(accessmode),
00221                          "Persistency file");
00222   }
00223   else {
00224     fTFile = TFile::Open(fullfilepathname.c_str(),Per::AsString(accessmode),
00225                          "Persistency file");
00226   }
00227 
00228 
00229   if (fTFile == (TFile*)0 || fTFile -> IsZombie() || !fTFile ->IsOpen()) {
00230     // File did not open successfully
00231     MSG("Per", Msg::kInfo) << "Unable to open " << fullfilepathname 
00232         << " with accessmode " << Per::AsString(accessmode) << endl;
00233     fErrorCode = Per::kErrFileError;
00234     if ( fTFile && fRemote ) {
00235       TNetFile* netfile = dynamic_cast<TNetFile*>(fTFile);
00236       if (netfile) {
00237         switch ( netfile -> GetErrorCode() ) {
00238         case kErrFileExists:
00239           fErrorCode = Per::kErrFileExists; break;
00240         case kErrNoFile:
00241           fErrorCode = Per::kErrFileNotFound; break;
00242         case kErrNoSpace:
00243           fErrorCode = Per::kErrFileNoSpace; break;
00244         default:
00245           break;
00246         }
00247       }
00248     }
00249     else if (fTFile) {
00250       // Local file, determine why file failed to open through system calls
00251       if (accessmode == Per::kNew &&
00252           !(gSystem -> AccessPathName(fullfilepathname.c_str(),kFileExists))) {
00253         // New file failed to open due to existing file of same name
00254         fErrorCode = Per::kErrFileExists;
00255       }
00256       else if (accessmode == Per::kRead &&
00257          (gSystem -> AccessPathName(fullfilepathname.c_str(),kFileExists))) {
00258         // File failed to open because it does not exist
00259         fErrorCode = Per::kErrFileNotFound;
00260       }
00261       else {
00262         switch (fTFile -> GetErrno()) {
00263           // TFile::TFile runs its own error checking so all file open errors 
00264           // won't appear in errno
00265         case ENOSPC:
00266           fErrorCode = Per::kErrFileNoSpace; break;
00267         default:
00268           break;
00269         }
00270       }
00271     }
00272     if(fTFile) delete fTFile; fTFile = 0;
00273   }
00274   else {
00275     fNumClient++;
00276     // fRemote is used to describe rootd served files only
00277     // rootd files that are not closed will not UseCache because
00278     // of dispatcher service concerns
00279     if ( !fRemote || HasFileEndKey() ) fTFile->UseCache();
00280   }
00281   
00282 }
00283 
00284 PerFile::~PerFile() {
00285   //
00286   //  Purpose:  PerFile destructor.  Closes ROOT TFile and retrieves
00287   //            allocated memory.
00288   //
00289   //  Contact:   S. Kasahara
00290   // 
00291 
00292   if (IsOpen()) {
00293     fTFile -> Close();
00294     delete fTFile; fTFile = 0;
00295   }
00296   fNumClient = 0;
00297 
00298 }
00299 
00300 std::ostream& PerFile::Print(std::ostream& ms) const {
00301   //
00302   //  Purpose:  Print status of file on ostream.
00303   //
00304   //  Arguments: ms ostream to display on.
00305   //
00306   //  Return:  ostream reference.
00307   //
00308   //  Contact:   S. Kasahara
00309   // 
00310 
00311 
00312   ms << (IsRemote() ? "Remote" : "Local") << " File " << fFullFilePathName;
00313  
00314   if (IsOpen()) {
00315     ms << " is open with accessmode " << Per::AsString(fAccessMode) 
00316        << " and " << fNumClient << " client(s)."<< endl;
00317   }
00318   else {
00319     ms << " was not opened successfully with accessmode " 
00320        << Per::AsString(fAccessMode) << "."<<endl;
00321   }
00322 
00323   return ms;
00324 
00325 }
00326 
00327 
00328 
00329 
00330 

Generated on Mon Feb 15 11:07:18 2010 for loon by  doxygen 1.3.9.1