1 // @(#)root/table:$Name: $:$Id: StFileIter.cxx,v 1.6 2009/03/27 17:40:16 fine Exp $ 2 // Author: Valery Fine(fine@bnl.gov) 01/03/2001 3 4 /************************************************************************* 5 * Copyright (C) 1995-2004, Rene Brun and Fons Rademakers. * 6 * Copyright (C) 2001 [BNL] Brookhaven National Laboratory. * 7 * All rights reserved. * 8 * * 9 * For the licensing terms see $ROOTSYS/LICENSE. * 10 * For the list of contributors see $ROOTSYS/README/CREDITS. * 11 *************************************************************************/ 12 13 /////////////////////////////////////////////////////////////////////////// 14 // // 15 // Class to iterate (read / write ) the events written to TFile. // 16 // The event is supposed to assign an unique ID in form of // 17 // // 18 // TKey <event Id> ::= eventName "." run_number "." event_number // 19 // // 20 // and stored as the TKey name of the object written // 21 // // 22 // /////// ////////// //////// /////// ////// 23 // 24 // void TesStFileIter(){ 25 // // This macros tests the various methods of StFileIter class. 26 // gSystem->Load("libTable"); 27 // 28 // //First create simple ROOT file 29 // TDataSet *ds = new TDataSet("event"); 30 // TObject *nextObject = 0; 31 // TRandom run; 32 // TRandom event; 33 // { 34 // StFileIter outSet("test.root","RECREATE"); 35 // UInt_t totalEvent = 10; 36 // UInt_t runNumber = 20010301; 37 // Int_t i=0; 38 // Int_t j=0; 39 // for (;j < 10;j++) { 40 // for (i = 1;i<totalEvent;i++) { 41 // outSet.NextEventPut(ds,UInt_t(i),UInt_t(runNumber+j+10*run.Rndm()-5)); 42 // } 43 // } 44 // } 45 // printf(" ----------------------> TFile has been created <--------------------\n"); 46 // TFile *f = new TFile("test.root"); 47 // StFileIter readObj(f); 48 // // the number of the object available directly from "MyDataSet.root" 49 // Int_t size = readObj.TotalKeys(); 50 // printf(" The total number of the objects: %d\n",size); 51 // 52 // //----------------------------------------------------------------------- 53 // // Loop over all objects, read them in to memory one by one 54 // 55 // printf(" -- > Loop over all objects, read them in to memory one by one < -- \n"); 56 // for( readObj = 0; int(readObj) < size; ++readObj){ 57 // nextObject = *readObj; 58 // printf(" %d bytes of the object \"%s\" of class \"%s\" written with TKey \"%s\" has been read from file\n" 59 // ,readObj.GetObjlen() 60 // ,nextObject->GetName() 61 // ,nextObject->IsA()->GetName() 62 // ,(const char *)readObj 63 // ); 64 // delete nextObject; 65 // } 66 // //----------------------------------------------------------------------- 67 // // Now loop over all objects in inverse order 68 // printf(" -- > Now loop over all objects in inverse order < -- \n"); 69 // for( readObj = size-1; (int)readObj >= 0; --readObj) 70 // { 71 // nextObject = *readObj; 72 // if (nextObject) { 73 // printf(" Object \"%s\" of class \"%s\" written with TKey \"%s\" has been read from file\n" 74 // ,nextObject->GetName() 75 // , nextObject->IsA()->GetName() 76 // ,(const char *)readObj 77 // ); 78 // delete nextObject; 79 // } else { 80 // printf("Error reading file by index\n"); 81 // } 82 // } 83 // //----------------------------------------------------------------------- 84 // // Loop over the objects starting from the object with the key name "event.02.01" 85 // printf(" -- > Loop over the objects starting from the object with the key name \"event.02.01\" < -- \n"); 86 // for( readObj = "event.02.01"; (const char *)readObj != 0; ++readObj){ 87 // nextObject = *readObj; 88 // printf(" Object \"%s\" of class \"%s\" written with Tkey \"%s\" has been read from file\n" 89 // , nextObject->GetName() 90 // , nextObject->IsA()->GetName() 91 // , (const char *)readObj 92 // ); 93 // delete nextObject; 94 // } 95 // 96 // printf(" -- > Loop over the objects starting from the 86-th object" < -- \n"); 97 // for( readObj = (const char *)(readObj = 86); (const char *)readObj != 0; ++readObj){ 98 // nextObject = *readObj; 99 // printf(" Object \"%s\" of class \"%s\" written with Tkey \"%s\" has been read from file\n" 100 // , nextObject->GetName() 101 // , nextObject->IsA()->GetName() 102 // , (const char *)readObj 103 // ); 104 // delete nextObject; 105 // } 106 // 107 // } 108 //----------------------------------------------------------------------- 109 /////////////////////////////////////////////////////////////////////////// 110 111 112 #include <assert.h> 113 114 #include "TEnv.h" 115 #include "TSystem.h" 116 #include "TFile.h" 117 #include "TKey.h" 118 119 #include "StFileIter.h" 120 #include "TDsKey.h" 121 122 ClassImp(StFileIter) 123 124 //__________________________________________________________________________ 125 StFileIter::StFileIter(TFile *file) : fFileBackUp(0),fDirectoryBackUp(0), fNestedIterator(0) 126 , fRootFile(file) 127 , fEventName("event"), fRunNumber(UInt_t(-1)),fEventNumber(UInt_t(-1)) 128 , fCursorPosition(-1), fOwnTFile(kFALSE) 129 { 130 // Create iterator over all objects from the TFile provided 131 Initialize(); 132 } 133 134 //__________________________________________________________________________ 135 StFileIter::StFileIter(TDirectory *directory) : fFileBackUp(0),fDirectoryBackUp(0), fNestedIterator(0) 136 , fRootFile(directory) 137 , fEventName("event"), fRunNumber(UInt_t(-1)),fEventNumber(UInt_t(-1)) 138 , fCursorPosition(-1), fOwnTFile(kFALSE) 139 { 140 // Create iterator over all objects from the TDirectory provided 141 Initialize(); 142 } 143 //__________________________________________________________________________ 144 StFileIter::StFileIter(const char *name, Option_t *option, const char *ftitle 145 , Int_t compress, Int_t /*netopt*/) :fNestedIterator(0),fRootFile (0) 146 { 147 // Open ROOT TFile by the name provided; 148 // This TFile is to be deleted by the StFileIter alone 149 if (name && name[0]) { 150 fOwnTFile = kTRUE; 151 // Map a special file system to rfio 152 // /hpss/in2p3.fr/group/atlas/cppm/data/genz 153 // #setenv HPSSIN bnlhpss:/home/atlasgen/evgen 154 // #example for castor: /castor/cern.ch/user/p/paniccia/evgen 155 fRootFile = TFile::Open(MapName(name),option,ftitle,compress); 156 Initialize(); 157 } 158 } 159 160 //__________________________________________________________________________ 161 StFileIter::StFileIter(const StFileIter &dst) : TListIter() 162 ,fFileBackUp(0), fDirectoryBackUp(0), fNestedIterator(0) 163 ,fRootFile(dst.fRootFile),fEventName(dst.fEventName), fRunNumber(dst.fRunNumber) 164 ,fEventNumber(dst.fRunNumber), 165 fCursorPosition(-1), fOwnTFile(dst.fOwnTFile) 166 { 167 // Copy ctor can be used with the "read only" files only. 168 assert(!fRootFile->IsWritable()); 169 if (fRootFile && fOwnTFile && !fRootFile->IsWritable()) { 170 // Reopen the file 171 if (fRootFile->InheritsFrom(TFile::Class())) 172 { 173 TFile *thisFile = (TFile *)fRootFile; 174 fRootFile = TFile::Open(MapName(fRootFile->GetName()) 175 ,fRootFile->GetOption() 176 ,fRootFile->GetTitle() 177 ,thisFile->GetCompressionLevel()); 178 } 179 } 180 181 Initialize(); 182 // Adjust this iterator position 183 SkipObjects(dst.fCursorPosition); 184 } 185 //__________________________________________________________________________ 186 StFileIter::~StFileIter() 187 { 188 // StFileIter dtor 189 StFileIter *deleteit = fNestedIterator; fNestedIterator = 0; 190 delete deleteit; 191 if (fRootFile && fOwnTFile ) { // delete own TFile if any 192 if (fRootFile->IsWritable()) fRootFile->Write(); 193 fRootFile->Close(); 194 delete fRootFile; 195 fRootFile = 0; 196 } 197 } 198 199 //__________________________________________________________________________ 200 void StFileIter::Initialize() 201 { 202 //to be documented 203 if (fRootFile) { 204 fDirection = kIterForward; 205 if (IsOpen()) Reset(); 206 else { 207 if (fRootFile && fOwnTFile ) delete fRootFile; 208 fRootFile = 0; 209 } 210 } 211 } 212 //__________________________________________________________________________ 213 Bool_t StFileIter::IsOpen() const 214 { 215 Bool_t iOpen = kFALSE; 216 if (fRootFile && !fRootFile->IsZombie() ) { 217 iOpen = kTRUE; 218 if (fRootFile->InheritsFrom(TFile::Class()) && !((TFile*)fRootFile)->IsOpen()) 219 iOpen = kFALSE; 220 } 221 return iOpen; 222 } 223 224 //__________________________________________________________________________ 225 TKey *StFileIter::GetCurrentKey() const 226 { 227 // return the pointer to the current TKey 228 229 return ((StFileIter*)this)->SkipObjects(0); 230 } 231 //__________________________________________________________________________ 232 Int_t StFileIter::GetDepth() const 233 { 234 // return the current number of the nested subdirectroies; 235 // = 0 - means there is no subdirectories 236 return fNestedIterator ? fNestedIterator->GetDepth()+1 : 0; 237 } 238 239 //__________________________________________________________________________ 240 const char *StFileIter::GetKeyName() const 241 { 242 // return the name of the current TKey 243 const char *name = 0; 244 TKey *key = GetCurrentKey(); 245 if (key) name = key->GetName(); 246 return name; 247 } 248 //__________________________________________________________________________ 249 TObject *StFileIter::GetObject() const 250 { 251 // read the object from TFile defined by the current TKey 252 // 253 // ATTENTION: memory leak danger !!! 254 // --------- 255 // This method does create a new object and it is the end-user 256 // code responsibility to take care about this object 257 // to avoid memory leak. 258 // 259 return ReadObj(GetCurrentKey()); 260 } 261 //__________________________________________________________________________ 262 Int_t StFileIter::GetObjlen() const 263 { 264 // Returns the uncompressed length of the current object 265 Int_t lenObj = 0; 266 TKey *key = GetCurrentKey(); 267 if (key) lenObj = ((TKey *)key)->GetObjlen(); 268 return lenObj; 269 } 270 //__________________________________________________________________________ 271 Int_t StFileIter::TotalKeys() const 272 { 273 // The total number of the TKey keys in the current TDirectory only 274 // Usually this means the total number of different objects 275 // those can be read one by one. 276 // It does NOT count the nested sub-TDirectory. 277 // It is too costly and it can be abused. 278 279 Int_t size = 0; 280 if(fList) size += fList->GetSize(); 281 return size; 282 } 283 //__________________________________________________________________________ 284 TObject *StFileIter::Next(Int_t nSkip) 285 { 286 // return the pointer to the object defined by next TKey 287 // This method is not recommended. It was done for the sake 288 // of the compatibility with TListIter 289 290 SkipObjects(nSkip); 291 return GetObject(); 292 } 293 294 //__________________________________________________________________________ 295 void StFileIter::PurgeKeys(TList *listOfKeys) { 296 assert(listOfKeys); 297 // Remove the TKey duplication, 298 // leave the keys with highest cycle number only 299 // Sort if first 300 listOfKeys->Sort(); 301 TObjLink *lnk = listOfKeys->FirstLink(); 302 while(lnk) { 303 TKey *key = (TKey *)lnk->GetObject(); 304 Short_t cycle = key->GetCycle(); 305 const char *keyName = key->GetName(); 306 // Check next object 307 lnk = lnk->Next(); 308 if (lnk) { 309 TKey *nextkey = 0; 310 TObjLink *lnkThis = lnk; 311 while ( lnk 312 && (nextkey = (TKey *)lnk->GetObject()) 313 && !strcmp(nextkey->GetName(), keyName) 314 ) { 315 // compare the cycles 316 Short_t nextCycle = nextkey->GetCycle() ; 317 //printf(" StFileIter::PurgeKeys found new cycle %s :%d : %d\n", 318 // keyName,cycle ,nextCycle); 319 assert(cycle != nextCycle); 320 TObjLink *lnkNext = lnk->Next(); 321 if (cycle > nextCycle ) { 322 delete listOfKeys->Remove(lnk); 323 } else { 324 delete listOfKeys->Remove(lnkThis); 325 cycle = nextCycle; 326 lnkThis = lnk; 327 } 328 lnk = lnkNext; 329 } 330 } 331 } 332 } 333 334 //__________________________________________________________________________ 335 void StFileIter::Reset() 336 { 337 // Reset the status of the iterator 338 if (fNestedIterator) { 339 StFileIter *it = fNestedIterator; 340 fNestedIterator=0; 341 delete it; 342 } 343 TListIter::Reset(); 344 if (!fRootFile->IsWritable()) { 345 TList *listOfKeys = fRootFile->GetListOfKeys(); 346 if (listOfKeys) { 347 if (!listOfKeys->IsSorted()) PurgeKeys(listOfKeys); 348 fList = listOfKeys; 349 if (fDirection == kIterForward) { 350 fCursorPosition = 0; 351 fCurCursor = fList->FirstLink(); 352 if (fCurCursor) fCursor = fCurCursor->Next(); 353 } else { 354 fCursorPosition = fList->GetSize()-1; 355 fCurCursor = fList->LastLink(); 356 if (fCurCursor) fCursor = fCurCursor->Prev(); 357 } 358 } 359 } 360 } 361 //__________________________________________________________________________ 362 void StFileIter::SetCursorPosition(const char *keyNameToFind) 363 { 364 // Find the key by the name provided 365 Reset(); 366 while( (*this != keyNameToFind) && SkipObjects() ); 367 } 368 //__________________________________________________________________________ 369 TKey *StFileIter::SkipObjects(Int_t nSkip) 370 { 371 // 372 // Returns the TKey pointer to the nSkip TKey object from the current one 373 // nSkip = 0; the state of the iterator is not changed 374 // 375 // nSkip > 0; iterator skips nSkip objects in the container. 376 // the direction of the iteration is 377 // sign(nSkip)*kIterForward 378 // 379 // Returns: TKey that can be used to fetch the object from the TDirectory 380 // 381 TKey *nextObject = fNestedIterator ? fNestedIterator->SkipObjects(nSkip): 0; 382 if (!nextObject) { 383 if (fNestedIterator) { 384 StFileIter *it = fNestedIterator; 385 fNestedIterator = 0; 386 delete it; 387 } 388 Int_t collectionSize = 0; 389 if (fList && (collectionSize = fList->GetSize()) ) { 390 if (fDirection !=kIterForward) nSkip = -nSkip; 391 Int_t newPos = fCursorPosition + nSkip; 392 if (0 <= newPos && newPos < collectionSize) { 393 do { 394 if (fCursorPosition < newPos) { 395 fCursorPosition++; 396 fCurCursor = fCursor; 397 fCursor = fCursor->Next(); 398 } else if (fCursorPosition > newPos) { 399 fCursorPosition--; 400 fCurCursor = fCursor; 401 fCursor = fCursor->Prev(); 402 } 403 } while (fCursorPosition != newPos); 404 if (fCurCursor) nextObject = dynamic_cast<TKey *>(fCurCursor->GetObject()); 405 } else { 406 fCurCursor = fCursor = 0; 407 if (newPos < 0) { 408 fCursorPosition = -1; 409 if (fList) fCursor = fList->FirstLink(); 410 } else { 411 fCursorPosition = collectionSize; 412 if (fList) fCursor = fList->LastLink(); 413 } 414 } 415 } 416 } 417 return nextObject; 418 } 419 //__________________________________________________________________________ 420 TKey *StFileIter::NextEventKey(UInt_t eventNumber, UInt_t runNumber, const char *name) 421 { 422 423 // Return the key that name matches the "event" . "run number" . "event number" schema 424 // Attention: Side effect: Been called from the end-user code this method causes 425 // ========= the StFileIter::NextObjectGet() to get the "next" object, 426 // defined by "next" key. 427 428 Bool_t reset = kFALSE; 429 if (name && name[0] && name[0] != '*') { if (fEventName > name) reset = kTRUE; fEventName = name; } 430 if (runNumber !=UInt_t(-1) ) { if (fRunNumber > runNumber) reset = kTRUE; fRunNumber = runNumber;} 431 if (eventNumber !=UInt_t(-1) ) { if (fEventNumber > eventNumber) reset = kTRUE; fEventNumber = eventNumber;} 432 433 if (reset) Reset(); 434 // TIter &nextKey = *fKeysIterator; 435 TKey *key = 0; 436 TDsKey thisKey; 437 while ( (key = SkipObjects()) ) { 438 if (fDirection==kIterForward) fCursorPosition++; 439 else fCursorPosition--; 440 if ( strcmp(name,"*") ) { 441 thisKey.SetKey(key->GetName()); 442 if (thisKey.GetName() < name) continue; 443 if (thisKey.GetName() > name) { key = 0; break; } 444 } 445 // Check "run number" 446 if (runNumber != UInt_t(-1)) { 447 UInt_t thisRunNumber = thisKey.RunNumber(); 448 if (thisRunNumber < runNumber) continue; 449 if (thisRunNumber < runNumber) { key = 0; break; } 450 } 451 // Check "event number" 452 if (eventNumber != UInt_t(-1)) { 453 UInt_t thisEventNumber = thisKey.EventNumber(); 454 if (thisEventNumber < eventNumber) continue; 455 if (thisEventNumber > eventNumber) {key = 0; break; } 456 } 457 break; 458 } 459 return key; 460 } 461 //__________________________________________________________________________ 462 TObject *StFileIter::NextEventGet(UInt_t eventNumber, UInt_t runNumber, const char *name) 463 { 464 // reads, creates and returns the object by TKey name that matches 465 // the "name" ."runNumber" ." eventNumber" schema 466 // Attention: This method does create a new TObject and it is the user 467 // code responsibility to take care (delete) this object to avoid 468 // memory leak. 469 470 return ReadObj(NextEventKey(eventNumber,runNumber,name)); 471 } 472 473 //__________________________________________________________________________ 474 TObject *StFileIter::ReadObj(const TKey *key) const 475 { 476 //Read the next TObject from for the TDirectory by TKey provided 477 TObject *obj = 0; 478 if (fNestedIterator) obj = fNestedIterator->ReadObj(key); 479 else if (key) { 480 obj = ((TKey *)key)->ReadObj(); 481 if (obj && obj->InheritsFrom(TDirectory::Class()) ) 482 { 483 // create the next iteration level. 484 assert(!fNestedIterator); 485 ((StFileIter*)this)->fNestedIterator = new StFileIter((TDirectory *)obj); 486 // FIXME: needs to set fDirection if needed 02/11/2007 vf 487 } 488 } 489 return obj; 490 } 491 492 //__________________________________________________________________________ 493 Int_t StFileIter::NextEventPut(TObject *obj, UInt_t eventNum, UInt_t runNumber 494 , const char *name) 495 { 496 // Create a special TKey name with obj provided and write it out. 497 498 Int_t wBytes = 0; 499 if (obj && IsOpen() && fRootFile->IsWritable()) { 500 TDsKey thisKey(runNumber,eventNum); 501 if (name && name[0]) 502 thisKey.SetName(name); 503 else 504 thisKey.SetName(obj->GetName()); 505 506 if (fRootFile != gDirectory) { 507 SaveFileScope(); 508 fRootFile->cd(); 509 } 510 wBytes = obj->Write(thisKey.GetKey()); 511 if (fRootFile->InheritsFrom(TFile::Class())) ((TFile*)fRootFile)->Flush(); 512 if (fRootFile != gDirectory) RestoreFileScope(); 513 } 514 return wBytes; 515 } 516 //__________________________________________________________________________ 517 TString StFileIter::MapName(const char *name, const char *localSystemKey,const char *mountedFileSystemKey) 518 { 519 // -------------------------------------------------------------------------------------- 520 // MapName(const char *name, const char *localSystemKey,const char *mountedFileSystemKey) 521 // -------------------------------------------------------------------------------------- 522 // Substitute the logical name with the real one if any 523 // 1. add a line into system.rootrc or ~/.rootrc or ./.rootrc 524 // 525 // StFileIter.ForeignFileMap mapFile // the name of the file 526 // to map the local name 527 // to the global file service 528 // 529 // If this line is omitted then StFileIter class seeks for 530 // the default mapping file in the current directory "io.config" 531 532 // 2. If the "io.config" file found then it defines the mapping as follows: 533 // 534 // StFileIter.LocalFileSystem /castor 535 // StFileIter.MountedFileSystem rfio:/castor 536 537 // If "io.config" doesn't exist then no mapping is to be performed 538 // and all file names are treated "as is" 539 540 if ( !localSystemKey) localSystemKey = GetLocalFileNameKey(); 541 if ( !mountedFileSystemKey) mountedFileSystemKey = GetForeignFileSystemKey(); 542 TString newName = name; 543 TString fileMap = gEnv->GetValue(GetResourceName(),GetDefaultMapFileName()); 544 const char *localName = 0; 545 const char *foreignName = 0; 546 if ( gSystem->AccessPathName(fileMap) == 0 ){ 547 TEnv myMapResource(fileMap); 548 localName = myMapResource.Defined(localSystemKey) ? 549 myMapResource.GetValue(localSystemKey,"") : 0; 550 foreignName = myMapResource.Defined(mountedFileSystemKey) ? 551 myMapResource.GetValue(mountedFileSystemKey,""):0; 552 } else { 553 localName = "/castor"; // This is the default CERN name 554 foreignName = "rfio:/castor"; // and it needs "RFIO" 555 } 556 if (localName && localName[0] 557 && foreignName 558 && foreignName[0] 559 && newName.BeginsWith(localName) ) 560 newName.Replace(0,strlen(localName),foreignName); 561 return newName; 562 } 563