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
1.3.9.1