Logo ROOT  
Reference Guide
TFileMerger.cxx
Go to the documentation of this file.
1// @(#)root/io:$Id$
2// Author: Andreas Peters + Fons Rademakers + Rene Brun 26/5/2005
3
4/*************************************************************************
5 * Copyright (C) 1995-2005, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12/**
13\class TFileMerger TFileMerger.cxx
14\ingroup IO
15
16This class provides file copy and merging services.
17
18It can be used to copy files (not only ROOT files), using TFile or
19any of its remote file access plugins. It is therefore useful in
20a Grid environment where the files might be accessible only remotely.
21The merging interface allows files containing histograms and trees
22to be merged, like the standalone hadd program.
23*/
24
25#include "TFileMerger.h"
26#include "TDirectory.h"
27#include "TError.h"
28#include "TUrl.h"
29#include "TFile.h"
30#include "TUUID.h"
31#include "TSystem.h"
32#include "TKey.h"
33#include "THashList.h"
34#include "TObjString.h"
35#include "TObjArray.h"
36#include "TClass.h"
37#include "Riostream.h"
38#include "TFileMergeInfo.h"
39#include "TClassRef.h"
40#include "TROOT.h"
41#include "TMemFile.h"
42#include "TVirtualMutex.h"
43
44#ifdef WIN32
45// For _getmaxstdio
46#include <stdio.h>
47#else
48// For getrlimit
49#include <sys/time.h>
50#include <sys/resource.h>
51#endif
52
53#include <cstring>
54
56
59
60static const Int_t kCpProgress = BIT(14);
61static const Int_t kCintFileNumber = 100;
62////////////////////////////////////////////////////////////////////////////////
63/// Return the maximum number of allowed opened files minus some wiggle room
64/// for CINT or at least of the standard library (stdio).
65
67{
68 int maxfiles;
69#ifdef WIN32
70 maxfiles = _getmaxstdio();
71#else
72 rlimit filelimit;
73 if (getrlimit(RLIMIT_NOFILE,&filelimit)==0) {
74 maxfiles = filelimit.rlim_cur;
75 } else {
76 // We could not get the value from getrlimit, let's return a reasonable default.
77 maxfiles = 512;
78 }
79#endif
80 if (maxfiles > kCintFileNumber) {
81 return maxfiles - kCintFileNumber;
82 } else if (maxfiles > 5) {
83 return maxfiles - 5;
84 } else {
85 return maxfiles;
86 }
87}
88
89////////////////////////////////////////////////////////////////////////////////
90/// Create file merger object.
91
93 : fMaxOpenedFiles( R__GetSystemMaxOpenedFiles() ),
94 fLocal(isLocal), fHistoOneGo(histoOneGo)
95{
98
100 gROOT->GetListOfCleanups()->Add(this);
101}
102
103////////////////////////////////////////////////////////////////////////////////
104/// Cleanup.
105
107{
108 {
110 gROOT->GetListOfCleanups()->Remove(this);
111 }
113}
114
115////////////////////////////////////////////////////////////////////////////////
116/// Reset merger file list.
117
119{
124}
125
126////////////////////////////////////////////////////////////////////////////////
127/// Add file to file merger.
128
129Bool_t TFileMerger::AddFile(const char *url, Bool_t cpProgress)
130{
131 if (fPrintLevel > 0) {
132 Printf("%s Source file %d: %s", fMsgPrefix.Data(), fFileList.GetEntries() + fExcessFiles.GetEntries() + 1, url);
133 }
134
135 TFile *newfile = 0;
136 TString localcopy;
137
138 if (fFileList.GetEntries() >= (fMaxOpenedFiles-1)) {
139
140 TObjString *urlObj = new TObjString(url);
141 fMergeList.Add(urlObj);
142
143 urlObj = new TObjString(url);
144 urlObj->SetBit(kCpProgress);
145 fExcessFiles.Add(urlObj);
146 return kTRUE;
147 }
148
149 // We want gDirectory untouched by anything going on here
151
152 if (fLocal) {
153 TUUID uuid;
154 localcopy.Form("file:%s/ROOTMERGE-%s.root", gSystem->TempDirectory(), uuid.AsString());
155 if (!TFile::Cp(url, localcopy, cpProgress)) {
156 Error("AddFile", "cannot get a local copy of file %s", url);
157 return kFALSE;
158 }
159 newfile = TFile::Open(localcopy, "READ");
160 } else {
161 newfile = TFile::Open(url, "READ");
162 }
163
164 // Zombie files should also be skipped
165 if (newfile && newfile->IsZombie()) {
166 delete newfile;
167 newfile = 0;
168 }
169
170 if (!newfile) {
171 if (fLocal)
172 Error("AddFile", "cannot open local copy %s of URL %s",
173 localcopy.Data(), url);
174 else
175 Error("AddFile", "cannot open file %s", url);
176 return kFALSE;
177 } else {
179
180 newfile->SetBit(kCanDelete);
181 fFileList.Add(newfile);
182
183 TObjString *urlObj = new TObjString(url);
184 fMergeList.Add(urlObj);
185
186 return kTRUE;
187 }
188}
189
190////////////////////////////////////////////////////////////////////////////////
191/// Add the TFile to this file merger and *do not* give ownership of the TFile to this
192/// object.
193///
194/// Return kTRUE if the addition was successful.
195
197{
198 return AddFile(source,kFALSE,cpProgress);
199}
200
201////////////////////////////////////////////////////////////////////////////////
202/// Add the TFile to this file merger and give ownership of the TFile to this
203/// object (unless kFALSE is returned).
204///
205/// Return kTRUE if the addition was successful.
206
208{
209 return AddFile(source,kTRUE,cpProgress);
210}
211
212////////////////////////////////////////////////////////////////////////////////
213/// Add the TFile to this file merger and give ownership of the TFile to this
214/// object (unless kFALSE is returned).
215///
216/// Return kTRUE if the addition was successful.
217
219{
220 if (source == 0 || source->IsZombie()) {
221 return kFALSE;
222 }
223
224 if (fPrintLevel > 0) {
225 Printf("%s Source file %d: %s",fMsgPrefix.Data(),fFileList.GetEntries()+1,source->GetName());
226 }
227
228 TFile *newfile = 0;
229 TString localcopy;
230
231 // We want gDirectory untouched by anything going on here
233 if (fLocal && !source->InheritsFrom(TMemFile::Class())) {
234 TUUID uuid;
235 localcopy.Form("file:%s/ROOTMERGE-%s.root", gSystem->TempDirectory(), uuid.AsString());
236 if (!source->Cp(localcopy, cpProgress)) {
237 Error("AddFile", "cannot get a local copy of file %s", source->GetName());
238 return kFALSE;
239 }
240 newfile = TFile::Open(localcopy, "READ");
241 // Zombie files should also be skipped
242 if (newfile && newfile->IsZombie()) {
243 delete newfile;
244 newfile = 0;
245 }
246 } else {
247 newfile = source;
248 }
249
250 if (!newfile) {
251 if (fLocal)
252 Error("AddFile", "cannot open local copy %s of URL %s",
253 localcopy.Data(), source->GetName());
254 else
255 Error("AddFile", "cannot open file %s", source->GetName());
256 return kFALSE;
257 } else {
259
260 if (own || newfile != source) {
261 newfile->SetBit(kCanDelete);
262 } else {
263 newfile->ResetBit(kCanDelete);
264 }
265 fFileList.Add(newfile);
266
267 TObjString *urlObj = new TObjString(source->GetName());
268 fMergeList.Add(urlObj);
269
270 if (newfile != source && own) {
271 delete source;
272 }
273 return kTRUE;
274 }
275}
276
277////////////////////////////////////////////////////////////////////////////////
278/// Open merger output file.
279
280Bool_t TFileMerger::OutputFile(const char *outputfile, Bool_t force, Int_t compressionLevel)
281{
282 return OutputFile(outputfile,(force?"RECREATE":"CREATE"),compressionLevel);
283}
284
285////////////////////////////////////////////////////////////////////////////////
286/// Open merger output file.
287
288Bool_t TFileMerger::OutputFile(const char *outputfile, Bool_t force)
289{
290 Bool_t res = OutputFile(outputfile,(force?"RECREATE":"CREATE"),1); // 1 is the same as the default from the TFile constructor.
292 return res;
293}
294
295////////////////////////////////////////////////////////////////////////////////
296/// Open merger output file.
297///
298/// The 'mode' parameter is passed to the TFile constructor as the option, it
299/// should be one of 'NEW','CREATE','RECREATE','UPDATE'
300/// 'UPDATE' is usually used in conjunction with IncrementalMerge.
301
302Bool_t TFileMerger::OutputFile(const char *outputfile, const char *mode, Int_t compressionLevel)
303{
304 // We want gDirectory untouched by anything going on here
306 if (TFile *outputFile = TFile::Open(outputfile, mode, "", compressionLevel))
307 return OutputFile(std::unique_ptr<TFile>(outputFile));
308
309 Error("OutputFile", "cannot open the MERGER output file %s", fOutputFilename.Data());
310 return kFALSE;
311}
312
313////////////////////////////////////////////////////////////////////////////////
314/// Set an output file opened externally by the users
315
316Bool_t TFileMerger::OutputFile(std::unique_ptr<TFile> outputfile)
317{
318 if (!outputfile || outputfile->IsZombie()) {
319 Error("OutputFile", "cannot open the MERGER output file %s", (outputfile) ? outputfile->GetName() : "");
320 return kFALSE;
321 }
322
323 if (!outputfile->IsWritable()) {
324 Error("OutputFile", "output file %s is not writable", outputfile->GetName());
325 return kFALSE;
326 }
327
329
330 TFile *oldfile = fOutputFile;
331 fOutputFile = 0; // This avoids the complaint from RecursiveRemove about the file being deleted which is here
332 // spurrious. (see RecursiveRemove).
333 SafeDelete(oldfile);
334
335 fOutputFilename = outputfile->GetName();
336 // We want gDirectory untouched by anything going on here
338 fOutputFile = outputfile.release(); // Transfer the ownership of the file.
339
340 return kTRUE;
341}
342
343////////////////////////////////////////////////////////////////////////////////
344/// Open merger output file. 'mode' is passed to the TFile constructor as the option, it should
345/// be one of 'NEW','CREATE','RECREATE','UPDATE'
346/// 'UPDATE' is usually used in conjunction with IncrementalMerge.
347
348Bool_t TFileMerger::OutputFile(const char *outputfile, const char *mode /* = "RECREATE" */)
349{
350 Bool_t res = OutputFile(outputfile,mode,1); // 1 is the same as the default from the TFile constructor.
352 return res;
353}
354
355////////////////////////////////////////////////////////////////////////////////
356/// Print list of files being merged.
357
359{
360 fFileList.Print(options);
361 fExcessFiles.Print(options);
362}
363
364////////////////////////////////////////////////////////////////////////////////
365/// Merge the files.
366///
367/// If no output file was specified it will write into
368/// the file "FileMerger.root" in the working directory. Returns true
369/// on success, false in case of error.
370
372{
373 return PartialMerge(kAll | kRegular);
374}
375
376namespace {
377
378Bool_t IsMergeable(TClass *cl)
379{
380 return (cl->GetMerge() || cl->InheritsFrom(TDirectory::Class()) ||
381 (cl->IsTObject() && !cl->IsLoaded() &&
382 /* If it has a dictionary and GetMerge() is nullptr then we already know the answer
383 to the next question is 'no, if we were to ask we would useless trigger
384 auto-parsing */
385 (cl->GetMethodWithPrototype("Merge", "TCollection*,TFileMergeInfo*") ||
386 cl->GetMethodWithPrototype("Merge", "TCollection*"))));
387};
388
389Bool_t WriteOneAndDelete(const TString &name, TClass *cl, TObject *obj, bool canBeMerged, Bool_t ownobj, TDirectory *target)
390{
391 Bool_t status = kTRUE;
392 if (cl->InheritsFrom(TCollection::Class())) {
393 // Don't overwrite, if the object were not merged.
394 if (obj->Write(name, canBeMerged ? TObject::kSingleKey | TObject::kOverwrite : TObject::kSingleKey) <= 0) {
395 status = kFALSE;
396 }
397 ((TCollection *)obj)->SetOwner();
398 if (ownobj)
399 delete obj;
400 } else {
401 // Don't overwrite, if the object were not merged.
402 // NOTE: this is probably wrong for emulated objects.
403 if (cl->IsTObject()) {
404 if (obj->Write(name, canBeMerged ? TObject::kOverwrite : 0) <= 0) {
405 status = kFALSE;
406 }
408 } else {
409 if (target->WriteObjectAny((void *)obj, cl, name, canBeMerged ? "OverWrite" : "") <= 0) {
410 status = kFALSE;
411 }
412 }
413 if (ownobj)
414 cl->Destructor(obj); // just in case the class is not loaded.
415 }
416 return status;
417}
418
419Bool_t WriteCycleInOrder(const TString &name, TIter &nextkey, TIter &peeknextkey, TDirectory *target)
420{
421 // Recurse until we find a different name or type appear.
422 TKey *key = (TKey*)peeknextkey();
423 if (!key || name != key->GetName()) {
424 return kTRUE;
425 }
427 if (IsMergeable(cl))
428 return kTRUE;
429 // Now we can advance the real iterator
430 (void)nextkey();
431 Bool_t result = WriteCycleInOrder(name, nextkey, peeknextkey, target);
432 TObject *obj = key->ReadObj();
433
434 return WriteOneAndDelete(name, cl, obj, kFALSE, kTRUE, target) && result;
435};
436
437} // anonymous namespace
438
440 TString &oldkeyname, THashList &allNames, Bool_t &status, Bool_t &onlyListed,
441 const TString &path, TDirectory *current_sourcedir, TFile *current_file, TKey *key,
442 TObject *obj, TIter &nextkey)
443{
444 const char *keyname = obj ? obj->GetName() : key->GetName();
445 const char *keyclassname = obj ? obj->IsA()->GetName() : key->GetClassName();
446 const char *keytitle = obj ? obj->GetTitle() : key->GetTitle();
447
448 // Keep only the highest cycle number for each key for mergeable objects. They are stored
449 // in the (hash) list consecutively and in decreasing order of cycles, so we can continue
450 // until the name changes. We flag the case here and we act consequently later.
451 Bool_t alreadyseen = (oldkeyname == keyname) ? kTRUE : kFALSE;
452 Bool_t ownobj = kFALSE;
453
454 // Read in but do not copy directly the processIds.
455 if (strcmp(keyclassname, "TProcessID") == 0 && key) {
456 key->ReadObj();
457 return kTRUE;
458 }
459
460 // If we have already seen this object [name], we already processed
461 // the whole list of files for this objects and we can just skip it
462 // and any related cycles.
463 if (allNames.FindObject(keyname)) {
464 oldkeyname = keyname;
465 return kTRUE;
466 }
467
468 TClass *cl = TClass::GetClass(keyclassname);
469 if (!cl) {
470 Info("MergeRecursive", "cannot indentify object type (%s), name: %s title: %s",
471 keyclassname, keyname, keytitle);
472 return kTRUE;
473 }
474 // For mergeable objects we add the names in a local hashlist handling them
475 // again (see above)
476 if (IsMergeable(cl))
477 allNames.Add(new TObjString(keyname));
478
480 // Skip the TTree objects and any related cycles.
481 oldkeyname = keyname;
482 return kTRUE;
483 }
484 // Check if only the listed objects are to be merged
485 if (type & kOnlyListed) {
486 onlyListed = kFALSE;
487 oldkeyname = keyname;
488 oldkeyname += " ";
489 onlyListed = fObjectNames.Contains(oldkeyname);
490 oldkeyname = keyname;
491 if ((!onlyListed) && (!cl->InheritsFrom(TDirectory::Class()))) return kTRUE;
492 }
493
494 if (!(type&kResetable && type&kNonResetable)) {
495 // If neither or both are requested at the same time, we merger both types.
496 if (!(type&kResetable)) {
497 if (cl->GetResetAfterMerge()) {
498 // Skip the object with a reset after merge routine (TTree and other incrementally mergeable objects)
499 oldkeyname = keyname;
500 return kTRUE;
501 }
502 }
503 if (!(type&kNonResetable)) {
504 if (!cl->GetResetAfterMerge()) {
505 // Skip the object without a reset after merge routine (Histograms and other non incrementally mergeable objects)
506 oldkeyname = keyname;
507 return kTRUE;
508 }
509 }
510 }
511 // read object from first source file
512 if (type & kIncremental) {
513 if (!obj)
514 obj = current_sourcedir->GetList()->FindObject(keyname);
515 if (!obj && key) {
516 obj = key->ReadObj();
517 ownobj = kTRUE;
518 } else if (obj && info.fIsFirst && current_sourcedir != target
519 && !cl->InheritsFrom( TDirectory::Class() )) {
520 R__ASSERT(cl->IsTObject());
521 TDirectory::TContext ctxt(current_sourcedir);
522 obj = obj->Clone();
523 ownobj = kTRUE;
524 }
525 } else if (key) {
526 obj = key->ReadObj();
527 ownobj = kTRUE;
528 }
529 if (!obj) {
530 Info("MergeRecursive", "could not read object for key {%s, %s}",
531 keyname, keytitle);
532 return kTRUE;
533 }
534 Bool_t canBeFound = (type & kIncremental) && (current_sourcedir->GetList()->FindObject(keyname) != nullptr);
535
536 // if (cl->IsTObject())
537 // obj->ResetBit(kMustCleanup);
538 if (cl->IsTObject() && cl != obj->IsA()) {
539 Error("MergeRecursive", "TKey and object retrieve disagree on type (%s vs %s). Continuing with %s.",
540 keyclassname, obj->IsA()->GetName(), obj->IsA()->GetName());
541 cl = obj->IsA();
542 }
543 Bool_t canBeMerged = kTRUE;
544
545 TList dirtodelete;
546 auto getDirectory = [&dirtodelete](TDirectory *parent, const char *name, const TString &pathname)
547 {
548 TDirectory *result = dynamic_cast<TDirectory*>(parent->GetList()->FindObject(name));
549 if (!result) {
550 result = parent->GetDirectory(pathname);
551 if (result && result != parent)
552 dirtodelete.Add(result);
553 }
554
555 return result;
556 };
557
558 if ( cl->InheritsFrom( TDirectory::Class() ) ) {
559 // it's a subdirectory
560
561 target->cd();
562 TDirectory *newdir;
563
564 // For incremental or already seen we may have already a directory created
565 if (type & kIncremental || alreadyseen) {
566 newdir = target->GetDirectory(obj->GetName());
567 if (!newdir) {
568 newdir = target->mkdir( obj->GetName(), obj->GetTitle() );
569 // newdir->ResetBit(kMustCleanup);
570 }
571 } else {
572 newdir = target->mkdir( obj->GetName(), obj->GetTitle() );
573 // newdir->ResetBit(kMustCleanup);
574 }
575
576 // newdir is now the starting point of another round of merging
577 // newdir still knows its depth within the target file via
578 // GetPath(), so we can still figure out where we are in the recursion
579
580 // If this folder is a onlyListed object, merge everything inside.
581 if (onlyListed) type &= ~kOnlyListed;
582 status = MergeRecursive(newdir, sourcelist, type);
583 if (onlyListed) type |= kOnlyListed;
584 if (!status) return kFALSE;
585 } else if (!cl->IsTObject() && cl->GetMerge()) {
586 // merge objects that don't derive from TObject
587 TFile *nextsource = current_file ? (TFile*)sourcelist->After( current_file ) : (TFile*)sourcelist->First();
588 Error("MergeRecursive", "Merging objects that don't inherit from TObject is unimplemented (key: %s of type %s in file %s)",
589 keyname, keyclassname, nextsource->GetName());
590 canBeMerged = kFALSE;
591 } else if (cl->IsTObject() && cl->GetMerge()) {
592 // Check if already treated
593 if (alreadyseen) return kTRUE;
594
595 TList inputs;
596 TList todelete;
598
599 // Loop over all source files and merge same-name object
600 TFile *nextsource = current_file ? (TFile*)sourcelist->After( current_file ) : (TFile*)sourcelist->First();
601 if (nextsource == 0) {
602 // There is only one file in the list
603 ROOT::MergeFunc_t func = cl->GetMerge();
604 func(obj, &inputs, &info);
605 info.fIsFirst = kFALSE;
606 } else {
607 do {
608 // make sure we are at the correct directory level by cd'ing to path
609 TDirectory *ndir = getDirectory(nextsource, target->GetName(), path);
610 if (ndir) {
611 // For consistency (and persformance), we reset the MustCleanup be also for those
612 // 'key' retrieved indirectly.
613 // ndir->ResetBit(kMustCleanup);
614 ndir->cd();
615 TObject *hobj = ndir->GetList()->FindObject(keyname);
616 if (!hobj) {
617 TKey *key2 = (TKey*)ndir->GetListOfKeys()->FindObject(keyname);
618 if (key2) {
619 hobj = key2->ReadObj();
620 if (!hobj) {
621 Info("MergeRecursive", "could not read object for key {%s, %s}; skipping file %s",
622 keyname, keytitle, nextsource->GetName());
623 nextsource = (TFile*)sourcelist->After(nextsource);
624 return kTRUE;
625 }
626 todelete.Add(hobj);
627 }
628 }
629 if (hobj) {
630 // Set ownership for collections
631 if (hobj->InheritsFrom(TCollection::Class())) {
632 ((TCollection*)hobj)->SetOwner();
633 }
634 hobj->ResetBit(kMustCleanup);
635 inputs.Add(hobj);
636 if (!oneGo) {
637 ROOT::MergeFunc_t func = cl->GetMerge();
638 Long64_t result = func(obj, &inputs, &info);
639 info.fIsFirst = kFALSE;
640 if (result < 0) {
641 Error("MergeRecursive", "calling Merge() on '%s' with the corresponding object in '%s'",
642 keyname, nextsource->GetName());
643 }
644 inputs.Clear();
645 todelete.Delete();
646 }
647 }
648 }
649 nextsource = (TFile*)sourcelist->After( nextsource );
650 } while (nextsource);
651 // Merge the list, if still to be done
652 if (oneGo || info.fIsFirst) {
653 ROOT::MergeFunc_t func = cl->GetMerge();
654 func(obj, &inputs, &info);
655 info.fIsFirst = kFALSE;
656 inputs.Clear();
657 todelete.Delete();
658 }
659 }
660 } else if (cl->IsTObject()) {
661 // try synthesizing the Merge method call according to the TObject
662 TList listH;
663 TString listHargs;
664 if (cl->GetMethodWithPrototype("Merge", "TCollection*,TFileMergeInfo*")) {
665 listHargs.Form("(TCollection*)0x%lx,(TFileMergeInfo*)0x%lx",
666 (ULong_t)&listH, (ULong_t)&info);
667 } else if (cl->GetMethodWithPrototype("Merge", "TCollection*")) {
668 listHargs.Form("((TCollection*)0x%lx)", (ULong_t)&listH);
669 } else {
670 // pass unmergeable objects through to the output file
671 canBeMerged = kFALSE;
672 }
673 if (canBeMerged) {
674 if (alreadyseen) {
675 // skip already seen mergeable objects, don't skip unmergeable objects
676 return kTRUE;
677 }
678 // Loop over all source files and merge same-name object
679 TFile *nextsource = current_file ? (TFile*)sourcelist->After( current_file ) : (TFile*)sourcelist->First();
680 if (nextsource == 0) {
681 // There is only one file in the list
682 Int_t error = 0;
683 obj->Execute("Merge", listHargs.Data(), &error);
684 info.fIsFirst = kFALSE;
685 if (error) {
686 Error("MergeRecursive", "calling Merge() on '%s' with the corresponding object in '%s'",
687 obj->GetName(), keyname);
688 }
689 } else {
690 while (nextsource) {
691 // make sure we are at the correct directory level by cd'ing to path
692 TDirectory *ndir = getDirectory(nextsource, target->GetName(), path);
693 if (ndir) {
694 ndir->cd();
695 TKey *key2 = (TKey*)ndir->GetListOfKeys()->FindObject(keyname);
696 if (key2) {
697 TObject *hobj = key2->ReadObj();
698 if (!hobj) {
699 Info("MergeRecursive", "could not read object for key {%s, %s}; skipping file %s",
700 keyname, keytitle, nextsource->GetName());
701 nextsource = (TFile*)sourcelist->After(nextsource);
702 return kTRUE;
703 }
704 // Set ownership for collections
705 if (hobj->InheritsFrom(TCollection::Class())) {
706 ((TCollection*)hobj)->SetOwner();
707 }
708 hobj->ResetBit(kMustCleanup);
709 listH.Add(hobj);
710 Int_t error = 0;
711 obj->Execute("Merge", listHargs.Data(), &error);
712 info.fIsFirst = kFALSE;
713 if (error) {
714 Error("MergeRecursive", "calling Merge() on '%s' with the corresponding object in '%s'",
715 obj->GetName(), nextsource->GetName());
716 }
717 listH.Delete();
718 }
719 }
720 nextsource = (TFile*)sourcelist->After( nextsource );
721 }
722 // Merge the list, if still to be done
723 if (info.fIsFirst) {
724 Int_t error = 0;
725 obj->Execute("Merge", listHargs.Data(), &error);
726 info.fIsFirst = kFALSE;
727 listH.Delete();
728 }
729 }
730 }
731 } else {
732 // Object is of no type that we can merge
733 canBeMerged = kFALSE;
734 }
735
736 // now write the merged histogram (which is "in" obj) to the target file
737 // note that this will just store obj in the current directory level,
738 // which is not persistent until the complete directory itself is stored
739 // by "target->SaveSelf()" below
740 target->cd();
741
742 oldkeyname = keyname;
743 //!!if the object is a tree, it is stored in globChain...
744 if (cl->InheritsFrom(TDirectory::Class())) {
745 // printf("cas d'une directory\n");
746
747 auto dirobj = dynamic_cast<TDirectory *>(obj);
748 TString dirpath(dirobj->GetPath());
749 // coverity[unchecked_value] 'target' is from a file so GetPath always returns path starting with filename:
750 dirpath.Remove(0, std::strlen(dirobj->GetFile()->GetPath()));
751
752 // Do not delete the directory if it is part of the output
753 // and we are in incremental mode (because it will be reused
754 // and has not been written to disk (for performance reason).
755 // coverity[var_deref_model] the IsA()->InheritsFrom guarantees that the dynamic_cast will succeed.
756 if (ownobj && (!(type & kIncremental) || dirobj->GetFile() != target)) {
757 dirobj->ResetBit(kMustCleanup);
758 delete dirobj;
759 }
760 // Let's also delete the directory from the other source (thanks to the 'allNames'
761 // mechanism above we will not process the directories when tranversing the next
762 // files).
763 TIter deliter(&dirtodelete);
764 while(TObject *ndir = deliter()) {
765 // For consistency (and performance), we reset the MustCleanup be also for those
766 // 'key' retrieved indirectly.
767 ndir->ResetBit(kMustCleanup);
768 delete ndir;
769 }
770 } else if (!canBeFound) { // Don't write the partial result for TTree and TH1
771
772 if (!canBeMerged) {
773 TIter peeknextkey(nextkey);
774 status = WriteCycleInOrder(oldkeyname, nextkey, peeknextkey, target) && status;
775 status = WriteOneAndDelete(oldkeyname, cl, obj, kFALSE, ownobj, target) && status;
776 } else {
777 status = WriteOneAndDelete(oldkeyname, cl, obj, kTRUE, ownobj, target) && status;
778 }
779 }
780 info.Reset();
781 dirtodelete.Clear("nodelete"); // If needed the delete is done explicitly above.
782 return kTRUE;
783}
784
785////////////////////////////////////////////////////////////////////////////////
786/// Merge all objects in a directory
787///
788/// The type is defined by the bit values in TFileMerger::EPartialMergeType.
789
790Bool_t TFileMerger::MergeRecursive(TDirectory *target, TList *sourcelist, Int_t type /* = kRegular | kAll */)
791{
792 Bool_t status = kTRUE;
793 Bool_t onlyListed = kFALSE;
794 if (fPrintLevel > 0) {
795 Printf("%s Target path: %s",fMsgPrefix.Data(),target->GetPath());
796 }
797
798 // Get the dir name
799 TString path(target->GetPath());
800 // coverity[unchecked_value] 'target' is from a file so GetPath always returns path starting with filename:
801 path.Remove(0, std::strlen(target->GetFile()->GetPath()));
802
803 Int_t nguess = sourcelist->GetSize()+1000;
804 THashList allNames(nguess);
805 allNames.SetOwner(kTRUE);
806 // If the mode is set to skipping list objects, add names to the allNames list
807 if (type & kSkipListed) {
808 TObjArray *arr = fObjectNames.Tokenize(" ");
809 arr->SetOwner(kFALSE);
810 for (Int_t iname=0; iname<arr->GetEntriesFast(); iname++)
811 allNames.Add(arr->At(iname));
812 delete arr;
813 }
814 ((THashList*)target->GetList())->Rehash(nguess);
815 ((THashList*)target->GetListOfKeys())->Rehash(nguess);
816
817 TFileMergeInfo info(target);
819 info.fOptions = fMergeOptions;
821 info.fOptions.Append(" fast");
822 }
823
824 TFile *current_file;
825 TDirectory *current_sourcedir;
826 if (type & kIncremental) {
827 current_file = 0;
828 current_sourcedir = target;
829 } else {
830 current_file = (TFile*)sourcelist->First();
831 current_sourcedir = current_file->GetDirectory(path);
832 }
833 while (current_file || current_sourcedir) {
834 // When current_sourcedir != 0 and current_file == 0 we are going over the target
835 // for an incremental merge.
836 if (current_sourcedir && (current_file == 0 || current_sourcedir != target)) {
837 TString oldkeyname;
838
839 // Loop over live objects
840 TIter nextobj( current_sourcedir->GetList() );
841 TObject *obj;
842 while ( (obj = (TKey*)nextobj())) {
843 auto result = MergeOne(target, sourcelist, type,
844 info, oldkeyname, allNames, status, onlyListed, path,
845 current_sourcedir, current_file,
846 nullptr, obj, nextobj);
847 if (!result)
848 return kFALSE; // Stop completely in case of error.
849 } // while ( (obj = (TKey*)nextobj()))
850
851 // loop over all keys in this directory
852 TIter nextkey( current_sourcedir->GetListOfKeys() );
853 TKey *key;
854
855 while ( (key = (TKey*)nextkey())) {
856 auto result = MergeOne(target, sourcelist, type,
857 info, oldkeyname, allNames, status, onlyListed, path,
858 current_sourcedir, current_file,
859 key, nullptr, nextkey);
860 if (!result)
861 return kFALSE; // Stop completely in case of error.
862 } // while ( ( TKey *key = (TKey*)nextkey() ) )
863 }
864 current_file = current_file ? (TFile*)sourcelist->After(current_file) : (TFile*)sourcelist->First();
865 if (current_file) {
866 current_sourcedir = current_file->GetDirectory(path);
867 } else {
868 current_sourcedir = 0;
869 }
870 }
871 // save modifications to the target directory.
872 if (!(type&kIncremental)) {
873 // In case of incremental build, we will call Write on the top directory/file, so we do not need
874 // to call SaveSelf explicilty.
875 target->SaveSelf(kTRUE);
876 }
877
878 return status;
879}
880
881////////////////////////////////////////////////////////////////////////////////
882/// Merge the files. If no output file was specified it will write into
883/// the file "FileMerger.root" in the working directory. Returns true
884/// on success, false in case of error.
885/// The type is defined by the bit values in EPartialMergeType:
886/// kRegular : normal merge, overwritting the output file
887/// kIncremental : merge the input file with the content of the output file (if already exising) (default)
888/// kAll : merge all type of objects (default)
889/// kResetable : merge only the objects with a MergeAfterReset member function.
890/// kNonResetable : merge only the objects without a MergeAfterReset member function.
891///
892/// If the type is set to kIncremental the output file is done deleted at the end of
893/// this operation. If the type is not set to kIncremental, the output file is closed.
894
896{
897 if (!fOutputFile) {
899 if (outf.IsNull()) {
900 outf.Form("file:%s/FileMerger.root", gSystem->TempDirectory());
901 Info("PartialMerge", "will merge the results to the file %s\n"
902 "since you didn't specify a merge filename",
903 TUrl(outf).GetFile());
904 }
905 if (!OutputFile(outf.Data())) {
906 return kFALSE;
907 }
908 }
909
910 // Special treament for the single file case ...
911 if ((fFileList.GetEntries() == 1) && !fExcessFiles.GetEntries() &&
915
916 TFile *file = (TFile *) fFileList.First();
917 if (!file || (file && file->IsZombie())) {
918 Error("PartialMerge", "one-file case: problem attaching to file");
919 return kFALSE;
920 }
921 Bool_t result = kTRUE;
922 if (!(result = file->Cp(fOutputFilename))) {
923 Error("PartialMerge", "one-file case: could not copy '%s' to '%s'",
924 file->GetPath(), fOutputFilename.Data());
925 return kFALSE;
926 }
927 if (file->TestBit(kCanDelete)) file->Close();
928
929 // Remove the temporary file
930 if (fLocal && !file->InheritsFrom(TMemFile::Class())) {
931 TUrl u(file->GetPath(), kTRUE);
932 if (gSystem->Unlink(u.GetFile()) != 0)
933 Warning("PartialMerge", "problems removing temporary local file '%s'", u.GetFile());
934 }
936 return result;
937 }
938
940
942
943 Bool_t result = kTRUE;
944 Int_t type = in_type;
945 while (result && fFileList.GetEntries()>0) {
947
948 // Remove local copies if there are any
949 TIter next(&fFileList);
950 TFile *file;
951 while ((file = (TFile*) next())) {
952 // close the files
953 if (file->TestBit(kCanDelete)) file->Close();
954 // remove the temporary files
955 if(fLocal && !file->InheritsFrom(TMemFile::Class())) {
956 TString p(file->GetPath());
957 // coverity[unchecked_value] Index is return a value with range or NPos to select the whole name.
958 p = p(0, p.Index(':',0));
959 gSystem->Unlink(p);
960 }
961 }
963 if (result && fExcessFiles.GetEntries() > 0) {
964 // We merge the first set of files in the output,
965 // we now need to open the next set and make
966 // sure we accumulate into the output, so we
967 // switch to incremental merging (if not already set)
969 result = OpenExcessFiles();
970 }
971 }
972 if (!result) {
973 Error("Merge", "error during merge of your ROOT files");
974 } else {
975 // Close or write is required so the file is complete.
976 if (in_type & kIncremental) {
977 // In the case of 'kDelayWrite' the caller want to avoid having to
978 // write the output objects once for every input file and instead
979 // write it only once at the end of the process.
980 if (!(in_type & kDelayWrite))
982 } else {
983 // If in_type is not incremental but type is incremental we are now in
984 // the case where the user "explicitly" request a non-incremental merge
985 // but we still have internally an incremental merge. Because the user
986 // did not request the incremental merge they also probably do not to a
987 // final Write of the file and thus not doing the write here would lead
988 // to data loss ...
989 if (type & kIncremental)
991 gROOT->GetListOfFiles()->Remove(fOutputFile);
993 }
994 }
995
996 // Cleanup
997 if (in_type & kIncremental) {
998 Clear();
999 } else {
1002 }
1003 return result;
1004}
1005
1006////////////////////////////////////////////////////////////////////////////////
1007/// Open up to fMaxOpenedFiles of the excess files.
1008
1010{
1011 if (fPrintLevel > 0) {
1012 Printf("%s Opening the next %d files", fMsgPrefix.Data(), TMath::Min(fExcessFiles.GetEntries(), fMaxOpenedFiles - 1));
1013 }
1014 Int_t nfiles = 0;
1015 TIter next(&fExcessFiles);
1016 TObjString *url = 0;
1017 TString localcopy;
1018 // We want gDirectory untouched by anything going on here
1020 while( nfiles < (fMaxOpenedFiles-1) && ( url = (TObjString*)next() ) ) {
1021 TFile *newfile = 0;
1022 if (fLocal) {
1023 TUUID uuid;
1024 localcopy.Form("file:%s/ROOTMERGE-%s.root", gSystem->TempDirectory(), uuid.AsString());
1025 if (!TFile::Cp(url->GetName(), localcopy, url->TestBit(kCpProgress))) {
1026 Error("OpenExcessFiles", "cannot get a local copy of file %s", url->GetName());
1027 return kFALSE;
1028 }
1029 newfile = TFile::Open(localcopy, "READ");
1030 } else {
1031 newfile = TFile::Open(url->GetName(), "READ");
1032 }
1033
1034 if (!newfile) {
1035 if (fLocal)
1036 Error("OpenExcessFiles", "cannot open local copy %s of URL %s",
1037 localcopy.Data(), url->GetName());
1038 else
1039 Error("OpenExcessFiles", "cannot open file %s", url->GetName());
1040 return kFALSE;
1041 } else {
1043
1044 newfile->SetBit(kCanDelete);
1045 fFileList.Add(newfile);
1046 ++nfiles;
1047 fExcessFiles.Remove(url);
1048 }
1049 }
1050 return kTRUE;
1051}
1052
1053////////////////////////////////////////////////////////////////////////////////
1054/// Intercept the case where the output TFile is deleted!
1055
1057{
1058 if (obj == fOutputFile) {
1059 Fatal("RecursiveRemove","Output file of the TFile Merger (targeting %s) has been deleted (likely due to a TTree larger than 100Gb)", fOutputFilename.Data());
1060 }
1061
1062}
1063
1064////////////////////////////////////////////////////////////////////////////////
1065/// Set a limit to the number of files that TFileMerger will open simultaneously.
1066///
1067/// If the request is higher than the system limit, we reset it to the system limit.
1068/// If the request is less than two, we reset it to 2 (one for the output file and one for the input file).
1069
1071{
1073 if (newmax < sysmax) {
1074 fMaxOpenedFiles = newmax;
1075 } else {
1076 fMaxOpenedFiles = sysmax;
1077 }
1078 if (fMaxOpenedFiles < 2) {
1079 fMaxOpenedFiles = 2;
1080 }
1081}
1082
1083////////////////////////////////////////////////////////////////////////////////
1084/// Set the prefix to be used when printing informational message.
1085
1086void TFileMerger::SetMsgPrefix(const char *prefix)
1087{
1088 fMsgPrefix = prefix;
1089}
1090
void Class()
Definition: Class.C:29
#define SafeDelete(p)
Definition: RConfig.hxx:543
int Int_t
Definition: RtypesCore.h:43
const Bool_t kFALSE
Definition: RtypesCore.h:90
unsigned long ULong_t
Definition: RtypesCore.h:53
bool Bool_t
Definition: RtypesCore.h:61
long long Long64_t
Definition: RtypesCore.h:71
const Bool_t kTRUE
Definition: RtypesCore.h:89
const char Option_t
Definition: RtypesCore.h:64
#define BIT(n)
Definition: Rtypes.h:83
#define ClassImp(name)
Definition: Rtypes.h:361
#define R__ASSERT(e)
Definition: TError.h:96
TClassRef R__TH1_Class("TH1")
static Int_t R__GetSystemMaxOpenedFiles()
Return the maximum number of allowed opened files minus some wiggle room for CINT or at least of the ...
Definition: TFileMerger.cxx:66
TClassRef R__TTree_Class("TTree")
static const Int_t kCpProgress
Definition: TFileMerger.cxx:60
static const Int_t kCintFileNumber
Definition: TFileMerger.cxx:61
char name[80]
Definition: TGX11.cxx:109
int type
Definition: TGX11.cxx:120
@ kMustCleanup
Definition: TObject.h:355
R__EXTERN TVirtualMutex * gROOTMutex
Definition: TROOT.h:59
#define gROOT
Definition: TROOT.h:406
void Printf(const char *fmt,...)
typedef void((*Func_t)())
R__EXTERN TSystem * gSystem
Definition: TSystem.h:556
#define R__LOCKGUARD(mutex)
TClassRef is used to implement a permanent reference to a TClass object.
Definition: TClassRef.h:28
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition: TClass.h:80
TMethod * GetMethodWithPrototype(const char *method, const char *proto, Bool_t objectIsConst=kFALSE, ROOT::EFunctionMatchMode mode=ROOT::kConversionMatch)
Find the method with a given prototype.
Definition: TClass.cxx:4419
void Destructor(void *obj, Bool_t dtorOnly=kFALSE)
Explicitly call destructor for object.
Definition: TClass.cxx:5363
ROOT::ResetAfterMergeFunc_t GetResetAfterMerge() const
Bool_t IsLoaded() const
Return true if the shared library of this class is currently in the a process's memory.
Definition: TClass.cxx:5875
Bool_t IsTObject() const
Return kTRUE is the class inherits from TObject.
Definition: TClass.cxx:5901
ROOT::MergeFunc_t GetMerge() const
Bool_t InheritsFrom(const char *cl) const
Return kTRUE if this class inherits from a class with name "classname".
Definition: TClass.cxx:4837
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition: TClass.cxx:2948
Collection abstract base class.
Definition: TCollection.h:63
virtual void Print(Option_t *option="") const
Default print for collections, calls Print(option, 1).
virtual Int_t GetEntries() const
Definition: TCollection.h:177
virtual void SetOwner(Bool_t enable=kTRUE)
Set whether this collection is the owner (enable==true) of its content.
virtual Int_t GetSize() const
Return the capacity of the collection, i.e.
Definition: TCollection.h:182
TDirectory * GetDirectory(const char *apath, Bool_t printError=false, const char *funcname="GetDirectory") override
Find a directory named "apath".
Small helper to keep current directory context.
Definition: TDirectory.h:47
Describe directory structure in memory.
Definition: TDirectory.h:40
virtual TList * GetList() const
Definition: TDirectory.h:165
virtual TDirectory * GetDirectory(const char *namecycle, Bool_t printError=false, const char *funcname="GetDirectory")
Find a directory using apath.
Definition: TDirectory.cxx:401
virtual const char * GetPath() const
Returns the full path of the directory.
Definition: TDirectory.cxx:988
virtual Int_t WriteObjectAny(const void *, const char *, const char *, Option_t *="", Int_t=0)
Definition: TDirectory.h:216
virtual TFile * GetFile() const
Definition: TDirectory.h:163
virtual void SaveSelf(Bool_t=kFALSE)
Definition: TDirectory.h:197
virtual TDirectory * mkdir(const char *name, const char *title="", Bool_t returnExistingDirectory=kFALSE)
Create a sub-directory "a" or a hierarchy of sub-directories "a/b/c/...".
virtual TList * GetListOfKeys() const
Definition: TDirectory.h:166
virtual Bool_t cd(const char *path=nullptr)
Change current directory to "this" directory.
Definition: TDirectory.cxx:498
TIOFeatures * fIOFeatures
This class provides file copy and merging services.
Definition: TFileMerger.h:32
TString fObjectNames
List of object names to be either merged exclusively or skipped.
Definition: TFileMerger.h:56
virtual Bool_t OutputFile(const char *url, Bool_t force)
Open merger output file.
TList fMergeList
list of TObjString containing the name of the files need to be merged
Definition: TFileMerger.h:57
virtual Bool_t AddFile(TFile *source, Bool_t own, Bool_t cpProgress)
Add the TFile to this file merger and give ownership of the TFile to this object (unless kFALSE is re...
virtual void PrintFiles(Option_t *options)
Print list of files being merged.
Bool_t fHistoOneGo
Merger histos in one go (default is kTRUE)
Definition: TFileMerger.h:55
virtual Bool_t MergeRecursive(TDirectory *target, TList *sourcelist, Int_t type=kRegular|kAll)
Merge all objects in a directory.
TList fFileList
A list the file (TFile*) which shall be merged.
Definition: TFileMerger.h:41
virtual Bool_t Merge(Bool_t=kTRUE)
Merge the files.
virtual Bool_t MergeOne(TDirectory *target, TList *sourcelist, Int_t type, TFileMergeInfo &info, TString &oldkeyname, THashList &allNames, Bool_t &status, Bool_t &onlyListed, const TString &path, TDirectory *current_sourcedir, TFile *current_file, TKey *key, TObject *obj, TIter &nextkey)
TString fOutputFilename
The name of the outputfile for merging.
Definition: TFileMerger.h:43
virtual void RecursiveRemove(TObject *obj)
Intercept the case where the output TFile is deleted!
TString fMsgPrefix
Prefix to be used when printing informational message (default TFileMerger)
Definition: TFileMerger.h:51
TIOFeatures * fIOFeatures
IO features to use in the output file.
Definition: TFileMerger.h:50
TFileMerger(const TFileMerger &)=delete
void SetMsgPrefix(const char *prefix)
Set the prefix to be used when printing informational message.
Bool_t fNoTrees
True if Trees should not be merged (default is kFALSE)
Definition: TFileMerger.h:45
@ kAll
Merge all type of objects (default)
Definition: TFileMerger.h:78
@ kIncremental
Merge the input file with the content of the output file (if already exising).
Definition: TFileMerger.h:73
@ kKeepCompression
Keep compression level unchanged for each input files.
Definition: TFileMerger.h:83
@ kSkipListed
Skip objects specified in fObjectNames list.
Definition: TFileMerger.h:82
@ kNonResetable
Only the objects without a MergeAfterReset member function.
Definition: TFileMerger.h:75
@ kResetable
Only the objects with a MergeAfterReset member function.
Definition: TFileMerger.h:74
@ kOnlyListed
Only the objects specified in fObjectNames list.
Definition: TFileMerger.h:81
@ kRegular
Normal merge, overwritting the output file.
Definition: TFileMerger.h:72
@ kDelayWrite
Delay the TFile write (to reduce the number of write when reusing the file)
Definition: TFileMerger.h:76
Bool_t fExplicitCompLevel
True if the user explicitly requested a compressio level change (default kFALSE)
Definition: TFileMerger.h:46
Bool_t fCompressionChange
True if the output and input have different compression level (default kFALSE)
Definition: TFileMerger.h:47
virtual ~TFileMerger()
Cleanup.
Int_t fPrintLevel
How much information to print out at run time.
Definition: TFileMerger.h:48
void SetMaxOpenedFiles(Int_t newmax)
Set a limit to the number of files that TFileMerger will open simultaneously.
TString fMergeOptions
Options (in string format) to be passed down to the Merge functions.
Definition: TFileMerger.h:49
Bool_t OpenExcessFiles()
Open up to fMaxOpenedFiles of the excess files.
TList fExcessFiles
! List of TObjString containing the name of the files not yet added to fFileList due to user or syste...
Definition: TFileMerger.h:58
TFile * fOutputFile
The outputfile for merging.
Definition: TFileMerger.h:42
virtual Bool_t PartialMerge(Int_t type=kAll|kIncremental)
Merge the files.
Bool_t fLocal
Makes local copies of merging files if True (default is kTRUE)
Definition: TFileMerger.h:54
virtual void Reset()
Reset merger file list.
Int_t fMaxOpenedFiles
Maximum number of files opened at the same time by the TFileMerger.
Definition: TFileMerger.h:53
virtual Bool_t AddAdoptFile(TFile *source, Bool_t cpProgress=kTRUE)
Add the TFile to this file merger and give ownership of the TFile to this object (unless kFALSE is re...
Bool_t fFastMethod
True if using Fast merging algorithm (default)
Definition: TFileMerger.h:44
A ROOT file is a suite of consecutive data records (TKey instances) with a well defined format.
Definition: TFile.h:53
Int_t GetCompressionSettings() const
Definition: TFile.h:398
Int_t GetCompressionLevel() const
Definition: TFile.h:392
virtual Bool_t Cp(const char *dst, Bool_t progressbar=kTRUE, UInt_t buffersize=1000000)
Allows to copy this file to the dst URL.
Definition: TFile.cxx:4839
static TFile * Open(const char *name, Option_t *option="", const char *ftitle="", Int_t compress=ROOT::RCompressionSetting::EDefaults::kUseCompiledDefault, Int_t netopt=0)
Create / open a file.
Definition: TFile.cxx:3942
Int_t Write(const char *name=nullptr, Int_t opt=0, Int_t bufsiz=0) override
Write memory objects to this file.
Definition: TFile.cxx:2297
void Close(Option_t *option="") override
Close a file.
Definition: TFile.cxx:873
THashList implements a hybrid collection class consisting of a hash table and a list to store TObject...
Definition: THashList.h:34
TObject * FindObject(const char *name) const
Find object using its name.
Definition: THashList.cxx:262
Book space in a file, create I/O buffers, to fill them, (un)compress them.
Definition: TKey.h:28
virtual const char * GetClassName() const
Definition: TKey.h:76
virtual const char * GetTitle() const
Returns title (title can contain 32x32 xpm thumbnail/icon).
Definition: TKey.cxx:1520
virtual TObject * ReadObj()
To read a TObject* from the file.
Definition: TKey.cxx:738
A doubly linked list.
Definition: TList.h:44
virtual void Add(TObject *obj)
Definition: TList.h:87
virtual TObject * After(const TObject *obj) const
Returns the object after object obj.
Definition: TList.cxx:329
virtual TObject * Remove(TObject *obj)
Remove object from the list.
Definition: TList.cxx:821
virtual TObject * FindObject(const char *name) const
Find an object in this list using its name.
Definition: TList.cxx:577
virtual void Delete(Option_t *option="")
Remove all objects from the list AND delete all heap based objects.
Definition: TList.cxx:469
virtual TObject * First() const
Return the first object in the list. Returns 0 when list is empty.
Definition: TList.cxx:658
virtual void Clear(Option_t *option="")
Remove all objects from the list.
Definition: TList.cxx:401
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
An array of TObjects.
Definition: TObjArray.h:37
Int_t GetEntriesFast() const
Definition: TObjArray.h:64
TObject * At(Int_t idx) const
Definition: TObjArray.h:166
Collectable string class.
Definition: TObjString.h:28
const char * GetName() const
Returns name of object.
Definition: TObjString.h:38
Mother of all ROOT objects.
Definition: TObject.h:37
virtual void Clear(Option_t *="")
Definition: TObject.h:115
virtual Int_t Write(const char *name=0, Int_t option=0, Int_t bufsize=0)
Write this object to the current directory.
Definition: TObject.cxx:796
@ kOverwrite
overwrite existing object with same name
Definition: TObject.h:88
@ kSingleKey
write collection with single key
Definition: TObject.h:87
virtual const char * GetName() const
Returns name of object.
Definition: TObject.cxx:357
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition: TObject.h:187
virtual TObject * Clone(const char *newname="") const
Make a clone of an object using the Streamer facility.
Definition: TObject.cxx:144
virtual void Execute(const char *method, const char *params, Int_t *error=0)
Execute method on this object with the given parameter string, e.g.
Definition: TObject.cxx:277
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition: TObject.cxx:877
R__ALWAYS_INLINE Bool_t IsZombie() const
Definition: TObject.h:149
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition: TObject.cxx:694
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition: TObject.cxx:443
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:891
virtual void Fatal(const char *method, const char *msgfmt,...) const
Issue fatal error message.
Definition: TObject.cxx:919
virtual const char * GetTitle() const
Returns title of object.
Definition: TObject.cxx:401
void ResetBit(UInt_t f)
Definition: TObject.h:186
@ kCanDelete
if object in a list can be deleted
Definition: TObject.h:58
@ kMustCleanup
if object destructor must call RecursiveRemove()
Definition: TObject.h:60
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition: TObject.cxx:865
Basic string class.
Definition: TString.h:131
void Clear()
Clear string without changing its capacity.
Definition: TString.cxx:1176
const char * Data() const
Definition: TString.h:364
TObjArray * Tokenize(const TString &delim) const
This function is used to isolate sequential tokens in a TString.
Definition: TString.cxx:2197
Bool_t IsNull() const
Definition: TString.h:402
TString & Remove(Ssiz_t pos)
Definition: TString.h:668
TString & Append(const char *cs)
Definition: TString.h:559
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition: TString.cxx:2289
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition: TString.h:619
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition: TString.h:634
virtual int Unlink(const char *name)
Unlink, i.e.
Definition: TSystem.cxx:1376
virtual const char * TempDirectory() const
Return a user configured or systemwide directory to create temporary files in.
Definition: TSystem.cxx:1477
This class defines a UUID (Universally Unique IDentifier), also known as GUIDs (Globally Unique IDent...
Definition: TUUID.h:42
const char * AsString() const
Return UUID as string. Copy string immediately since it will be reused.
Definition: TUUID.cxx:562
This class represents a WWW compatible URL.
Definition: TUrl.h:35
const char * GetFile() const
Definition: TUrl.h:71
Long64_t(* MergeFunc_t)(void *, TCollection *, TFileMergeInfo *)
Definition: Rtypes.h:112
Short_t Min(Short_t a, Short_t b)
Definition: TMathBase.h:180
Definition: file.py:1