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
(1) Event cond_true: |
Condition "name", taking true branch |
(2) Event cond_false: |
Condition "name[0]", taking false branch |
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();
(3) Event if_end: |
End of if statement |
157 }
(5) Event uninit_member: |
Non-static class member "fFileBackUp" is not initialized in this constructor nor in any functions that it calls. |
(7) Event uninit_member: |
Non-static class member "fDirectoryBackUp" is not initialized in this constructor nor in any functions that it calls. |
(9) Event uninit_member: |
Non-static class member "fRunNumber" is not initialized in this constructor nor in any functions that it calls. |
(11) Event uninit_member: |
Non-static class member "fEventNumber" is not initialized in this constructor nor in any functions that it calls. |
(13) Event uninit_member: |
Non-static class member "fCursorPosition" is not initialized in this constructor nor in any functions that it calls. |
(15) Event uninit_member: |
Non-static class member "fOwnTFile" is not initialized in this constructor nor in any functions that it calls. |
Also see events: |
[member_decl][member_decl][member_decl][member_decl][member_decl][member_decl] |
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