Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
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 "TFileMergeInfo.h"
38#include "TClassRef.h"
39#include "TROOT.h"
40#include "TMemFile.h"
41#include "TVirtualMutex.h"
42
43#ifdef WIN32
44// For _getmaxstdio
45#include <cstdio>
46#else
47// For getrlimit
48#include <sys/time.h>
49#include <sys/resource.h>
50#endif
51
52#include <cstring>
53#include <map>
54
55
58TClassRef R__RNTuple_Class("ROOT::RNTuple");
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
71#else
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
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
125
126////////////////////////////////////////////////////////////////////////////////
127/// Closes output file
128
134
135////////////////////////////////////////////////////////////////////////////////
136/// Add file to file merger.
137
139{
140 if (fPrintLevel > 0) {
141 Printf("%s Source file %d: %s", fMsgPrefix.Data(), fFileList.GetEntries() + fExcessFiles.GetEntries() + 1, url);
142 }
143
144 TFile *newfile = nullptr;
146
147 if (fFileList.GetEntries() >= (fMaxOpenedFiles-1)) {
148
151
152 urlObj = new TObjString(url);
153 urlObj->SetBit(kCpProgress);
155 return kTRUE;
156 }
157
158 // We want gDirectory untouched by anything going on here
160
161 if (fLocal) {
162 TUUID uuid;
163 localcopy.Form("file:%s/ROOTMERGE-%s.root", gSystem->TempDirectory(), uuid.AsString());
165 Error("AddFile", "cannot get a local copy of file %s", url);
166 return kFALSE;
167 }
168 newfile = TFile::Open(localcopy, "READ");
169 } else {
170 newfile = TFile::Open(url, "READ");
171 }
172
173 // Zombie files should also be skipped
174 if (newfile && newfile->IsZombie()) {
175 delete newfile;
176 newfile = nullptr;
177 }
178
179 if (!newfile) {
180 if (fLocal)
181 Error("AddFile", "cannot open local copy %s of URL %s",
182 localcopy.Data(), url);
183 else
184 Error("AddFile", "cannot open file %s", url);
185 return kFALSE;
186 } else {
187 if (fOutputFile && fOutputFile->GetCompressionSettings() != newfile->GetCompressionSettings())
189
190 newfile->SetBit(kCanDelete);
192
195
196 return kTRUE;
197 }
198}
199
200////////////////////////////////////////////////////////////////////////////////
201/// Add the TFile to this file merger and *do not* give ownership of the TFile to this
202/// object.
203///
204/// Return kTRUE if the addition was successful.
205
210
211////////////////////////////////////////////////////////////////////////////////
212/// Add the TFile to this file merger and give ownership of the TFile to this
213/// object (unless kFALSE is returned).
214///
215/// Return kTRUE if the addition was successful.
216
221
222////////////////////////////////////////////////////////////////////////////////
223/// Add the TFile to this file merger and give ownership of the TFile to this
224/// object (unless kFALSE is returned).
225///
226/// Return kTRUE if the addition was successful.
227
229{
230 if (source == 0 || source->IsZombie()) {
231 return kFALSE;
232 }
233
234 if (fPrintLevel > 0) {
235 Printf("%s Source file %d: %s",fMsgPrefix.Data(),fFileList.GetEntries()+1,source->GetName());
236 }
237
238 TFile *newfile = 0;
240
241 // We want gDirectory untouched by anything going on here
243 if (fLocal && !source->InheritsFrom(TMemFile::Class())) {
244 TUUID uuid;
245 localcopy.Form("file:%s/ROOTMERGE-%s.root", gSystem->TempDirectory(), uuid.AsString());
246 if (!source->Cp(localcopy, cpProgress)) {
247 Error("AddFile", "cannot get a local copy of file %s", source->GetName());
248 return kFALSE;
249 }
250 newfile = TFile::Open(localcopy, "READ");
251 // Zombie files should also be skipped
252 if (newfile && newfile->IsZombie()) {
253 delete newfile;
254 newfile = 0;
255 }
256 } else {
257 newfile = source;
258 }
259
260 if (!newfile) {
261 if (fLocal)
262 Error("AddFile", "cannot open local copy %s of URL %s",
263 localcopy.Data(), source->GetName());
264 else
265 Error("AddFile", "cannot open file %s", source->GetName());
266 return kFALSE;
267 } else {
268 if (fOutputFile && fOutputFile->GetCompressionSettings() != newfile->GetCompressionSettings()) fCompressionChange = kTRUE;
269
270 if (own || newfile != source) {
271 newfile->SetBit(kCanDelete);
272 } else {
273 newfile->ResetBit(kCanDelete);
274 }
276
277 TObjString *urlObj = new TObjString(source->GetName());
279
280 if (newfile != source && own) {
281 delete source;
282 }
283 return kTRUE;
284 }
285}
286
287////////////////////////////////////////////////////////////////////////////////
288/// Open merger output file.
289
294
295////////////////////////////////////////////////////////////////////////////////
296/// Open merger output file.
297
299{
300 Bool_t res = OutputFile(outputfile,(force?"RECREATE":"CREATE"),1); // 1 is the same as the default from the TFile constructor.
303 return res;
304}
305
306////////////////////////////////////////////////////////////////////////////////
307/// Open merger output file.
308///
309/// The 'mode' parameter is passed to the TFile constructor as the option, it
310/// should be one of 'NEW','CREATE','RECREATE','UPDATE'
311/// 'UPDATE' is usually used in conjunction with IncrementalMerge.
312
314{
315 // We want gDirectory untouched by anything going on here
318 return OutputFile(std::unique_ptr<TFile>(outputFile));
319
320 Error("OutputFile", "cannot open the MERGER output file %s", fOutputFilename.Data());
321 return kFALSE;
322}
323
324////////////////////////////////////////////////////////////////////////////////
325/// Set an output file opened externally by the users
326
328{
329 if (!outputfile || outputfile->IsZombie()) {
330 Error("OutputFile", "cannot open the MERGER output file %s", (outputfile) ? outputfile->GetName() : "");
331 return kFALSE;
332 }
333
334 if (!outputfile->IsWritable()) {
335 Error("OutputFile", "output file %s is not writable", outputfile->GetName());
336 return kFALSE;
337 }
338
340
342 fOutputFile = 0; // This avoids the complaint from RecursiveRemove about the file being deleted which is here
343 // spurrious. (see RecursiveRemove).
345
346 fOutputFilename = outputfile->GetName();
347 // We want gDirectory untouched by anything going on here
349 fOutputFile = outputfile.release(); // Transfer the ownership of the file.
350
351 return kTRUE;
352}
353
354////////////////////////////////////////////////////////////////////////////////
355/// Open merger output file. 'mode' is passed to the TFile constructor as the option, it should
356/// be one of 'NEW','CREATE','RECREATE','UPDATE'
357/// 'UPDATE' is usually used in conjunction with IncrementalMerge.
358
359Bool_t TFileMerger::OutputFile(const char *outputfile, const char *mode /* = "RECREATE" */)
360{
361 Bool_t res = OutputFile(outputfile,mode,1); // 1 is the same as the default from the TFile constructor.
363 return res;
364}
365
366////////////////////////////////////////////////////////////////////////////////
367/// Print list of files being merged.
368
370{
371 fFileList.Print(options);
372 fExcessFiles.Print(options);
373}
374
375////////////////////////////////////////////////////////////////////////////////
376/// Merge the files.
377///
378/// If no output file was specified it will write into
379/// the file "FileMerger.root" in the working directory. Returns true
380/// on success, false in case of error.
381
386
387namespace {
388
390{
391 return (cl->GetMerge() || cl->InheritsFrom(TDirectory::Class()) ||
392 (cl->IsTObject() && !cl->IsLoaded() &&
393 /* If it has a dictionary and GetMerge() is nullptr then we already know the answer
394 to the next question is 'no, if we were to ask we would useless trigger
395 auto-parsing */
396 (cl->GetMethodWithPrototype("Merge", "TCollection*,TFileMergeInfo*") ||
397 cl->GetMethodWithPrototype("Merge", "TCollection*"))));
398};
399
401{
402 Bool_t status = kTRUE;
403 if (cl->InheritsFrom(TCollection::Class())) {
404 // Don't overwrite, if the object were not merged.
405 if (obj->Write(name, canBeMerged ? TObject::kSingleKey | TObject::kOverwrite : TObject::kSingleKey) <= 0) {
406 status = kFALSE;
407 }
408 ((TCollection *)obj)->SetOwner();
409 if (ownobj)
410 delete obj;
411 } else {
412 // Don't overwrite, if the object were not merged.
413 // NOTE: this is probably wrong for emulated objects.
414 if (cl->IsTObject()) {
415 if (obj->Write(name, canBeMerged ? TObject::kOverwrite : 0) <= 0) {
416 status = kFALSE;
417 }
419 } else {
420 if (target->WriteObjectAny((void *)obj, cl, name, canBeMerged ? "OverWrite" : "") <= 0) {
421 status = kFALSE;
422 }
423 }
424 if (ownobj)
425 cl->Destructor(obj); // just in case the class is not loaded.
426 }
427 return status;
428}
429
431{
432 // Recurse until we find a different name or type appear.
433 TKey *key = (TKey*)peeknextkey();
434 if (!key || name != key->GetName()) {
435 return kTRUE;
436 }
438 if (IsMergeable(cl))
439 return kTRUE;
440 // Now we can advance the real iterator
441 (void)nextkey();
443 TObject *obj = key->ReadObj();
444
445 return WriteOneAndDelete(name, cl, obj, kFALSE, kTRUE, target) && result;
446};
447
448} // anonymous namespace
449
453 TObject *obj, TIter &nextkey)
454{
455 const char *keyname = obj ? obj->GetName() : key->GetName();
456 const char *keyclassname = obj ? obj->IsA()->GetName() : key->GetClassName();
457 const char *keytitle = obj ? obj->GetTitle() : key->GetTitle();
458
459 // Keep only the highest cycle number for each key for mergeable objects. They are stored
460 // in the (hash) list consecutively and in decreasing order of cycles, so we can continue
461 // until the name changes. We flag the case here and we act consequently later.
464
465 // Read in but do not copy directly the processIds.
466 if (strcmp(keyclassname, "TProcessID") == 0 && key) {
467 key->ReadObj();
468 return kTRUE;
469 }
470
471 // If we have already seen this object [name], we already processed
472 // the whole list of files for this objects and we can just skip it
473 // and any related cycles.
474 if (allNames.FindObject(keyname)) {
476 return kTRUE;
477 }
478
480 if (!cl) {
481 Info("MergeRecursive", "cannot indentify object type (%s), name: %s title: %s",
483 return kTRUE;
484 }
485 // For mergeable objects we add the names in a local hashlist handling them
486 // again (see above)
487 if (IsMergeable(cl))
488 allNames.Add(new TObjString(keyname));
489
491 // Skip the TTree objects and any related cycles.
493 return kTRUE;
494 }
495 // Check if only the listed objects are to be merged
496 if (type & kOnlyListed) {
498 oldkeyname += " ";
501 if ((!onlyListed) && (!cl->InheritsFrom(TDirectory::Class()))) return kTRUE;
502 }
503
504 if (!(type&kResetable && type&kNonResetable)) {
505 // If neither or both are requested at the same time, we merger both types.
506 if (!(type&kResetable)) {
507 if (cl->GetResetAfterMerge()) {
508 // Skip the object with a reset after merge routine (TTree and other incrementally mergeable objects)
510 return kTRUE;
511 }
512 }
513 if (!(type&kNonResetable)) {
514 if (!cl->GetResetAfterMerge()) {
515 // Skip the object without a reset after merge routine (Histograms and other non incrementally mergeable objects)
517 return kTRUE;
518 }
519 }
520 }
521 // read object from first source file
522 if (type & kIncremental) {
523 if (!obj)
524 obj = current_sourcedir->GetList()->FindObject(keyname);
525 if (!obj && key) {
526 obj = key->ReadObj();
527 ownobj = kTRUE;
528 } else if (obj && info.fIsFirst && current_sourcedir != target
529 && !cl->InheritsFrom( TDirectory::Class() )) {
530 R__ASSERT(cl->IsTObject());
532 obj = obj->Clone();
533 ownobj = kTRUE;
534 }
535 } else if (key) {
536 obj = key->ReadObj();
537 ownobj = kTRUE;
538 }
539 if (!obj) {
540 Info("MergeRecursive", "could not read object for key {%s, %s}",
542 return kTRUE;
543 }
544 Bool_t canBeFound = (type & kIncremental) && (target->GetList()->FindObject(keyname) != nullptr);
545
546 // if (cl->IsTObject())
547 // obj->ResetBit(kMustCleanup);
548 if (cl->IsTObject() && cl != obj->IsA()) {
549 Error("MergeRecursive", "TKey and object retrieve disagree on type (%s vs %s). Continuing with %s.",
550 keyclassname, obj->IsA()->GetName(), obj->IsA()->GetName());
551 cl = obj->IsA();
552 }
554
555 std::map<std::tuple<std::string, std::string, std::string>, TDirectory*> dirtodelete;
556 auto getDirectory = [&dirtodelete](TDirectory *parent, const char *name, const TString &pathname) {
557 auto mapkey = std::make_tuple(parent->GetName(), name, pathname.Data());
558 auto result = dirtodelete.find(mapkey);
559 if (result != dirtodelete.end()) {
560 return result->second;
561 }
562
563 auto dir = dynamic_cast<TDirectory *>(parent->GetDirectory(pathname));
564 if (dir)
565 dirtodelete[mapkey] = dir;
566
567 return dir;
568 };
569
570 if ( cl->InheritsFrom( TDirectory::Class() ) ) {
571 // it's a subdirectory
572
573 target->cd();
575
576 // For incremental or already seen we may have already a directory created
577 if (type & kIncremental || alreadyseen) {
578 newdir = target->GetDirectory(obj->GetName());
579 if (!newdir) {
580 newdir = target->mkdir( obj->GetName(), obj->GetTitle() );
581 // newdir->ResetBit(kMustCleanup);
582 }
583 } else {
584 newdir = target->mkdir( obj->GetName(), obj->GetTitle() );
585 // newdir->ResetBit(kMustCleanup);
586 }
587
588 // newdir is now the starting point of another round of merging
589 // newdir still knows its depth within the target file via
590 // GetPath(), so we can still figure out where we are in the recursion
591
592 // If this folder is a onlyListed object, merge everything inside.
593 const auto mergeType = onlyListed ? type & ~kOnlyListed : type;
595
596 if ((type & kOnlyListed) && !(type & kIncremental) && !onlyListed && newdir->GetNkeys() == 0) {
597 // None of the children were merged, and the directory is not listed
598 delete newdir;
599 newdir = nullptr;
600 target->rmdir(obj->GetName());
601 }
602 // Delete newdir directory after having written it (merged)
603 if (!(type&kIncremental)) delete newdir;
605 if (!status) return kFALSE;
606 } else if (!cl->IsTObject() && cl->GetMerge()) {
607 // merge objects that don't derive from TObject
609 Warning("MergeRecursive", "Merging RNTuples is experimental");
610
611 // Collect all the data to be passed on to the merger
613 // First entry is the TKey of the ntuple
614 mergeData.Add(key);
615 // Second entry is the output file
616 mergeData.Add(target->GetFile());
617 // Remaining entries are the input files
619 while (const auto &inFile = nextFile()) {
620 mergeData.Add(inFile);
621 }
622 // Get the merge fuction and pass the data
623 ROOT::MergeFunc_t func = cl->GetMerge();
624 Long64_t result = func(obj, &mergeData, &info);
625 mergeData.Clear("nodelete");
626 if (result < 0) {
627 Error("MergeRecursive", "Could NOT merge RNTuples!");
628 return kFALSE;
629 }
630 } else {
632 Error("MergeRecursive", "Merging objects that don't inherit from TObject is unimplemented (key: %s of type %s in file %s)",
633 keyname, keyclassname, nextsource->GetName());
635 }
636 } else if (cl->IsTObject() && cl->GetMerge()) {
637 // Check if already treated
638 if (alreadyseen) return kTRUE;
639
643
644 // Loop over all source files and merge same-name object
646 if (nextsource == 0) {
647 // There is only one file in the list
648 ROOT::MergeFunc_t func = cl->GetMerge();
649 func(obj, &inputs, &info);
650 info.fIsFirst = kFALSE;
651 } else {
652 do {
653 // make sure we are at the correct directory level by cd'ing to path
654 TDirectory *ndir = getDirectory(nextsource, target->GetName(), path);
655 if (ndir) {
656 // For consistency (and persformance), we reset the MustCleanup be also for those
657 // 'key' retrieved indirectly.
658 // ndir->ResetBit(kMustCleanup);
659 ndir->cd();
660 TObject *hobj = ndir->GetList()->FindObject(keyname);
661 if (!hobj) {
662 TKey *key2 = (TKey*)ndir->GetListOfKeys()->FindObject(keyname);
663 if (key2) {
664 hobj = key2->ReadObj();
665 if (!hobj) {
666 switch (fErrBehavior) {
668 Error("MergeRecursive", "could not read object for key {%s, %s}; in file %s", keyname,
669 keytitle, nextsource->GetName());
671 return kFALSE;
673 Warning("MergeRecursive", "could not read object for key {%s, %s}; skipping file %s",
674 keyname, keytitle, nextsource->GetName());
676 return kTRUE;
677 }
678 }
679 todelete.Add(hobj);
680 }
681 }
682 if (hobj) {
683 // Set ownership for collections
684 if (hobj->InheritsFrom(TCollection::Class())) {
685 ((TCollection*)hobj)->SetOwner();
686 }
687 hobj->ResetBit(kMustCleanup);
688 inputs.Add(hobj);
689 if (!oneGo) {
690 ROOT::MergeFunc_t func = cl->GetMerge();
691 Long64_t result = func(obj, &inputs, &info);
692 info.fIsFirst = kFALSE;
693 if (result < 0) {
694 Error("MergeRecursive", "calling Merge() on '%s' with the corresponding object in '%s'",
695 keyname, nextsource->GetName());
696 }
697 inputs.Clear();
698 todelete.Delete();
699 }
700 }
701 }
703 } while (nextsource);
704 // Merge the list, if still to be done
705 if (oneGo || info.fIsFirst) {
706 ROOT::MergeFunc_t func = cl->GetMerge();
707 func(obj, &inputs, &info);
708 info.fIsFirst = kFALSE;
709 inputs.Clear();
710 todelete.Delete();
711 }
712 }
713 } else if (cl->IsTObject()) {
714 // try synthesizing the Merge method call according to the TObject
715 TList listH;
717 if (cl->GetMethodWithPrototype("Merge", "TCollection*,TFileMergeInfo*")) {
718 listHargs.Form("(TCollection*)0x%zx,(TFileMergeInfo*)0x%zx",
719 (size_t)&listH, (size_t)&info);
720 } else if (cl->GetMethodWithPrototype("Merge", "TCollection*")) {
721 listHargs.Form("((TCollection*)0x%zx)", (size_t)&listH);
722 } else {
723 // pass unmergeable objects through to the output file
725 }
726 if (canBeMerged) {
727 if (alreadyseen) {
728 // skip already seen mergeable objects, don't skip unmergeable objects
729 return kTRUE;
730 }
731 // Loop over all source files and merge same-name object
733 if (nextsource == 0) {
734 // There is only one file in the list
735 Int_t error = 0;
736 obj->Execute("Merge", listHargs.Data(), &error);
737 info.fIsFirst = kFALSE;
738 if (error) {
739 Error("MergeRecursive", "calling Merge() on '%s' with the corresponding object in '%s'",
740 obj->GetName(), keyname);
741 }
742 } else {
743 while (nextsource) {
744 // make sure we are at the correct directory level by cd'ing to path
745 TDirectory *ndir = getDirectory(nextsource, target->GetName(), path);
746 if (ndir) {
747 ndir->cd();
748 TKey *key2 = (TKey*)ndir->GetListOfKeys()->FindObject(keyname);
749 if (key2) {
750 TObject *hobj = key2->ReadObj();
751 if (!hobj) {
752 switch (fErrBehavior) {
754 Error("MergeRecursive", "could not read object for key {%s, %s}; in file %s", keyname,
755 keytitle, nextsource->GetName());
757 return kFALSE;
759 Warning("MergeRecursive", "could not read object for key {%s, %s}; skipping file %s",
760 keyname, keytitle, nextsource->GetName());
762 return kTRUE;
763 }
764 }
765 // Set ownership for collections
766 if (hobj->InheritsFrom(TCollection::Class())) {
767 ((TCollection*)hobj)->SetOwner();
768 }
769 hobj->ResetBit(kMustCleanup);
770 listH.Add(hobj);
771 Int_t error = 0;
772 obj->Execute("Merge", listHargs.Data(), &error);
773 info.fIsFirst = kFALSE;
774 if (error) {
775 Error("MergeRecursive", "calling Merge() on '%s' with the corresponding object in '%s'",
776 obj->GetName(), nextsource->GetName());
777 }
778 listH.Delete();
779 }
780 }
782 }
783 // Merge the list, if still to be done
784 if (info.fIsFirst) {
785 Int_t error = 0;
786 obj->Execute("Merge", listHargs.Data(), &error);
787 info.fIsFirst = kFALSE;
788 listH.Delete();
789 }
790 }
791 }
792 } else {
793 // Object is of no type that we can merge
795 }
796
797 // now write the merged histogram (which is "in" obj) to the target file
798 // note that this will just store obj in the current directory level,
799 // which is not persistent until the complete directory itself is stored
800 // by "target->SaveSelf()" below
801 target->cd();
802
804 //!!if the object is a tree, it is stored in globChain...
805 if (cl->InheritsFrom(TDirectory::Class())) {
806 // printf("cas d'une directory\n");
807
808 auto dirobj = dynamic_cast<TDirectory *>(obj);
809 TString dirpath(dirobj->GetPath());
810 // coverity[unchecked_value] 'target' is from a file so GetPath always returns path starting with filename:
811 dirpath.Remove(0, std::strlen(dirobj->GetFile()->GetPath()));
812
813 // Do not delete the directory if it is part of the output
814 // and we are in incremental mode (because it will be reused
815 // and has not been written to disk (for performance reason).
816 // coverity[var_deref_model] the IsA()->InheritsFrom guarantees that the dynamic_cast will succeed.
817 if (ownobj && (!(type & kIncremental) || dirobj->GetFile() != target)) {
818 dirobj->ResetBit(kMustCleanup);
819 delete dirobj;
820 }
821 // Let's also delete the directory from the other source (thanks to the 'allNames'
822 // mechanism above we will not process the directories when tranversing the next
823 // files).
824 for (const auto &[_, ndir] : dirtodelete) {
825 // For consistency (and performance), we reset the MustCleanup be also for those
826 // 'key' retrieved indirectly.
827 ndir->ResetBit(kMustCleanup);
828 delete ndir;
829 }
830 } else if (!canBeFound) { // object (TTree, TH1) is not yet owned by the target, thus write it
831 if (gDebug > 0)
832 Info("MergeOne", "Writing partial result of %s into target", oldkeyname.Data());
833 if (!canBeMerged) {
836 status = WriteOneAndDelete(oldkeyname, cl, obj, kFALSE, ownobj, target) && status;
837 } else {
838 status = WriteOneAndDelete(oldkeyname, cl, obj, kTRUE, ownobj, target) && status;
839 }
840 }
841 info.Reset();
842 return kTRUE;
843}
844
845////////////////////////////////////////////////////////////////////////////////
846/// Merge all objects in a directory
847///
848/// The type is defined by the bit values in TFileMerger::EPartialMergeType.
849
851{
852 Bool_t status = kTRUE;
854 if (fPrintLevel > 0) {
855 Printf("%s Target path: %s",fMsgPrefix.Data(),target->GetPath());
856 }
857
858 // Get the dir name
859 TString path(target->GetPath());
860 // coverity[unchecked_value] 'target' is from a file so GetPath always returns path starting with filename:
861 path.Remove(0, std::strlen(target->GetFile()->GetPath()));
862
863 Int_t nguess = sourcelist->GetSize()+1000;
865 allNames.SetOwner(kTRUE);
866 // If the mode is set to skipping list objects, add names to the allNames list
867 if (type & kSkipListed) {
869 arr->SetOwner(kFALSE);
870 for (Int_t iname=0; iname<arr->GetEntriesFast(); iname++)
871 allNames.Add(arr->At(iname));
872 delete arr;
873 }
874 ((THashList*)target->GetList())->Rehash(nguess);
875 ((THashList*)target->GetListOfKeys())->Rehash(nguess);
876
878 info.fIOFeatures = fIOFeatures;
879 info.fOptions = fMergeOptions;
881 info.fOptions.Append(" fast");
882 }
883
886 if (type & kIncremental) {
887 current_file = 0;
889 } else {
890 current_file = (TFile*)sourcelist->First();
891 current_sourcedir = current_file->GetDirectory(path);
892 }
894 // When current_sourcedir != 0 and current_file == 0 we are going over the target
895 // for an incremental merge.
898
899 // Loop over live objects
900 TIter nextobj( current_sourcedir->GetList() );
901 TObject *obj;
902 while ( (obj = (TKey*)nextobj())) {
904 info, oldkeyname, allNames, status, onlyListed, path,
906 nullptr, obj, nextobj);
907 if (!result)
908 return kFALSE; // Stop completely in case of error.
909 } // while ( (obj = (TKey*)nextobj()))
910
911 // loop over all keys in this directory
912 TIter nextkey( current_sourcedir->GetListOfKeys() );
913 TKey *key;
914
915 while ( (key = (TKey*)nextkey())) {
917 info, oldkeyname, allNames, status, onlyListed, path,
919 key, nullptr, nextkey);
920 if (!result)
921 return kFALSE; // Stop completely in case of error.
922 } // while ( ( TKey *key = (TKey*)nextkey() ) )
923 }
925 if (current_file) {
926 current_sourcedir = current_file->GetDirectory(path);
927 } else {
929 }
930 }
931 // save modifications to the target directory.
932 if (!(type&kIncremental)) {
933 // In case of incremental build, we will call Write on the top directory/file, so we do not need
934 // to call SaveSelf explicilty.
935 target->SaveSelf(kTRUE);
936 }
937
938 return status;
939}
940
941////////////////////////////////////////////////////////////////////////////////
942/// Merge the files. If no output file was specified it will write into
943/// the file "FileMerger.root" in the working directory. Returns true
944/// on success, false in case of error.
945/// The type is defined by the bit values in EPartialMergeType:
946///
947/// kRegular : normal merge, overwriting the output file
948/// kIncremental : merge the input file with the content of the output file (if already exising) (default)
949/// kResetable : merge only the objects with a MergeAfterReset member function.
950/// kNonResetable : merge only the objects without a MergeAfterReset member function.
951/// kDelayWrite : delay the TFile write (to reduce the number of write when reusing the file)
952/// kAll : merge all type of objects (default)
953/// kAllIncremental : merge incrementally all type of objects.
954/// kOnlyListed : merge only the objects specified in fObjectNames list
955/// kSkipListed : skip objects specified in fObjectNames list
956/// kKeepCompression: keep compression level unchanged for each input
957///
958/// If the type is not set to kIncremental, the output file is deleted at the end of this operation.
959
961{
962 if (!fOutputFile) {
964 if (outf.IsNull()) {
965 outf.Form("file:%s/FileMerger.root", gSystem->TempDirectory());
966 Info("PartialMerge", "will merge the results to the file %s\n"
967 "since you didn't specify a merge filename",
968 TUrl(outf).GetFile());
969 }
970 if (!OutputFile(outf.Data())) {
971 return kFALSE;
972 }
973 }
974
975 // Special treatment for the single file case to improve efficiency...
976 if ((fFileList.GetEntries() == 1) && !fExcessFiles.GetEntries() &&
980
981 TFile *file = (TFile *) fFileList.First();
982 if (!file || (file && file->IsZombie())) {
983 Error("PartialMerge", "one-file case: problem attaching to file");
984 return kFALSE;
985 }
987 if (!(result = file->Cp(fOutputFilename))) {
988 Error("PartialMerge", "one-file case: could not copy '%s' to '%s'",
989 file->GetPath(), fOutputFilename.Data());
990 return kFALSE;
991 }
992 if (file->TestBit(kCanDelete)) file->Close();
993
994 // Remove the temporary file
995 if (fLocal && !file->InheritsFrom(TMemFile::Class())) {
996 TUrl u(file->GetPath(), kTRUE);
997 if (gSystem->Unlink(u.GetFile()) != 0)
998 Warning("PartialMerge", "problems removing temporary local file '%s'", u.GetFile());
999 }
1000 fFileList.Clear();
1001 return result;
1002 }
1003
1006
1008
1010 Int_t type = in_type;
1011 while (result && fFileList.GetEntries()>0) {
1013
1014 // Remove local copies if there are any
1015 TIter next(&fFileList);
1016 TFile *file;
1017 while ((file = (TFile*) next())) {
1018 // close the files
1019 if (file->TestBit(kCanDelete)) file->Close();
1020 // remove the temporary files
1021 if(fLocal && !file->InheritsFrom(TMemFile::Class())) {
1022 TString p(file->GetPath());
1023 // coverity[unchecked_value] Index is return a value with range or NPos to select the whole name.
1024 p = p(0, p.Index(':',0));
1025 gSystem->Unlink(p);
1026 }
1027 }
1028 fFileList.Clear();
1029 if (result && fExcessFiles.GetEntries() > 0) {
1030 // We merge the first set of files in the output,
1031 // we now need to open the next set and make
1032 // sure we accumulate into the output, so we
1033 // switch to incremental merging (if not already set)
1036 }
1037 }
1038 if (!result) {
1039 Error("Merge", "error during merge of your ROOT files");
1040 } else {
1041 // Close or write is required so the file is complete.
1042 if (in_type & kIncremental) {
1043 // In the case of 'kDelayWrite' the caller want to avoid having to
1044 // write the output objects once for every input file and instead
1045 // write it only once at the end of the process.
1046 if (!(in_type & kDelayWrite))
1048 } else {
1049 // If in_type is not incremental but type is incremental we are now in
1050 // the case where the user "explicitly" request a non-incremental merge
1051 // but we still have internally an incremental merge. Because the user
1052 // did not request the incremental merge they also probably do not to a
1053 // final Write of the file and thus not doing the write here would lead
1054 // to data loss ...
1055 if (type & kIncremental)
1057 gROOT->GetListOfFiles()->Remove(fOutputFile);
1058 fOutputFile->Close();
1059 }
1060 }
1061
1062 // Cleanup
1063 if (in_type & kIncremental) {
1064 Clear();
1065 } else {
1069 }
1070 return result;
1071}
1072
1073////////////////////////////////////////////////////////////////////////////////
1074/// Open up to (fMaxOpenedFiles-1) of the excess files.
1075
1077{
1078 if (fPrintLevel > 0) {
1079 Printf("%s Opening the next %d files", fMsgPrefix.Data(), std::min(fExcessFiles.GetEntries(), fMaxOpenedFiles - 1));
1080 }
1081 Int_t nfiles = 0;
1082 TIter next(&fExcessFiles);
1083 TObjString *url = 0;
1085 // We want gDirectory untouched by anything going on here
1087 while( nfiles < (fMaxOpenedFiles-1) && ( url = (TObjString*)next() ) ) {
1088 TFile *newfile = 0;
1089 if (fLocal) {
1090 TUUID uuid;
1091 localcopy.Form("file:%s/ROOTMERGE-%s.root", gSystem->TempDirectory(), uuid.AsString());
1092 if (!TFile::Cp(url->GetName(), localcopy, url->TestBit(kCpProgress))) {
1093 Error("OpenExcessFiles", "cannot get a local copy of file %s", url->GetName());
1094 return kFALSE;
1095 }
1096 newfile = TFile::Open(localcopy, "READ");
1097 } else {
1098 newfile = TFile::Open(url->GetName(), "READ");
1099 }
1100
1101 if (!newfile) {
1102 if (fLocal)
1103 Error("OpenExcessFiles", "cannot open local copy %s of URL %s",
1104 localcopy.Data(), url->GetName());
1105 else
1106 Error("OpenExcessFiles", "cannot open file %s", url->GetName());
1107 return kFALSE;
1108 } else {
1109 if (fOutputFile && fOutputFile->GetCompressionLevel() != newfile->GetCompressionLevel()) fCompressionChange = kTRUE;
1110
1111 newfile->SetBit(kCanDelete);
1113 ++nfiles;
1115 }
1116 }
1117 return kTRUE;
1118}
1119
1120////////////////////////////////////////////////////////////////////////////////
1121/// Intercept the case where the output TFile is deleted!
1122
1124{
1126 Fatal("RecursiveRemove","Output file of the TFile Merger (targeting %s) has been deleted (likely due to a TTree larger than 100Gb)", fOutputFilename.Data());
1127 }
1128
1129}
1130
1131////////////////////////////////////////////////////////////////////////////////
1132/// Set a limit to the number of files that TFileMerger will open simultaneously.
1133///
1134/// This number includes both the read input files and the output file.
1135/// \param newmax if higher than the system limit, we reset it to the system limit;
1136/// if less than two, we reset it to 2 (one for the output file and one for the input file).
1137
1139{
1141 if (newmax < sysmax) {
1143 } else {
1145 }
1146 if (fMaxOpenedFiles < 2) {
1147 fMaxOpenedFiles = 2;
1148 }
1149}
1150
1151////////////////////////////////////////////////////////////////////////////////
1152/// Set the prefix to be used when printing informational message.
1153
1154void TFileMerger::SetMsgPrefix(const char *prefix)
1155{
1156 fMsgPrefix = prefix;
1157}
1158
#define SafeDelete(p)
Definition RConfig.hxx:533
bool Bool_t
Boolean (0=false, 1=true) (bool)
Definition RtypesCore.h:77
int Int_t
Signed integer 4 bytes (int)
Definition RtypesCore.h:59
constexpr Bool_t kFALSE
Definition RtypesCore.h:108
constexpr Bool_t kTRUE
Definition RtypesCore.h:107
const char Option_t
Option string (const char)
Definition RtypesCore.h:80
#define BIT(n)
Definition Rtypes.h:91
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:125
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 ...
TClassRef R__RNTuple_Class("ROOT::RNTuple")
TClassRef R__TTree_Class("TTree")
static const Int_t kCpProgress
static const Int_t kCintFileNumber
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t target
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char mode
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
char name[80]
Definition TGX11.cxx:110
@ kMustCleanup
Definition TObject.h:371
Int_t gDebug
Global variable setting the debug level. Set to 0 to disable, increase it in steps of 1 to increase t...
Definition TROOT.cxx:627
R__EXTERN TVirtualMutex * gROOTMutex
Definition TROOT.h:63
#define gROOT
Definition TROOT.h:411
void Printf(const char *fmt,...)
Formats a string in a circular formatting buffer and prints the string.
Definition TString.cxx:2509
R__EXTERN TSystem * gSystem
Definition TSystem.h:572
#define R__LOCKGUARD(mutex)
#define _(A, B)
Definition cfortran.h:108
const_iterator end() const
TClassRef is used to implement a permanent reference to a TClass object.
Definition TClassRef.h:29
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:84
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:4483
void Destructor(void *obj, Bool_t dtorOnly=kFALSE)
Explicitly call destructor for object.
Definition TClass.cxx:5439
ROOT::ResetAfterMergeFunc_t GetResetAfterMerge() const
Return the wrapper around Merge.
Definition TClass.cxx:7544
Bool_t IsLoaded() const
Return true if the shared library of this class is currently in the a process's memory.
Definition TClass.cxx:5954
Bool_t IsTObject() const
Return kTRUE is the class inherits from TObject.
Definition TClass.cxx:5980
Bool_t InheritsFrom(const char *cl) const override
Return kTRUE if this class inherits from a class with name "classname".
Definition TClass.cxx:4901
ROOT::MergeFunc_t GetMerge() const
Return the wrapper around Merge.
Definition TClass.cxx:7536
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:2973
Collection abstract base class.
Definition TCollection.h:65
static TClass * Class()
virtual Int_t GetEntries() const
virtual void SetOwner(Bool_t enable=kTRUE)
Set whether this collection is the owner (enable==true) of its content.
void Print(Option_t *option="") const override
Default print for collections, calls Print(option, 1).
TDirectory::TContext keeps track and restore the current directory.
Definition TDirectory.h:89
Describe directory structure in memory.
Definition TDirectory.h:45
static TClass * Class()
virtual TDirectory * GetDirectory(const char *namecycle, Bool_t printError=false, const char *funcname="GetDirectory")
Find a directory using apath.
virtual const char * GetPath() const
Returns the full path of the directory.
TString fObjectNames
List of object names to be either merged exclusively or skipped.
Definition TFileMerger.h:63
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:64
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:62
virtual Bool_t MergeRecursive(TDirectory *target, TList *sourcelist, Int_t type=kRegular|kAll)
Merge all objects in a directory.
void RecursiveRemove(TObject *obj) override
Intercept the case where the output TFile is deleted!
TList fFileList
A list the file (TFile*) which shall be merged.
Definition TFileMerger.h:47
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:49
TString fMsgPrefix
Prefix to be used when printing informational message (default TFileMerger)
Definition TFileMerger.h:57
TIOFeatures * fIOFeatures
IO features to use in the output file.
Definition TFileMerger.h:56
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:51
bool fOutFileWasExplicitlyClosed
! the user has called CloseOutputFile(), so we shouldn't error out in RecursiveRemove
Definition TFileMerger.h:67
@ kAll
Merge all type of objects (default)
Definition TFileMerger.h:87
@ kIncremental
Merge the input file with the content of the output file (if already existing).
Definition TFileMerger.h:82
@ kKeepCompression
Keep compression level unchanged for each input files.
Definition TFileMerger.h:92
@ kSkipListed
Skip objects specified in fObjectNames list.
Definition TFileMerger.h:91
@ kNonResetable
Only the objects without a MergeAfterReset member function.
Definition TFileMerger.h:84
@ kResetable
Only the objects with a MergeAfterReset member function.
Definition TFileMerger.h:83
@ kOnlyListed
Only the objects specified in fObjectNames list.
Definition TFileMerger.h:90
@ kRegular
Normal merge, overwriting the output file.
Definition TFileMerger.h:81
@ kDelayWrite
Delay the TFile write (to reduce the number of write when reusing the file)
Definition TFileMerger.h:85
Bool_t fExplicitCompLevel
True if the user explicitly requested a compression level change (default kFALSE)
Definition TFileMerger.h:52
Bool_t fCompressionChange
True if the output and input have different compression level (default kFALSE)
Definition TFileMerger.h:53
EErrorBehavior fErrBehavior
What to do in case of errors during merging.
Definition TFileMerger.h:58
Int_t fPrintLevel
How much information to print out at run time.
Definition TFileMerger.h:54
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:55
void CloseOutputFile()
Closes output file.
~TFileMerger() override
Cleanup.
@ kFailOnError
The merging process will stop and yield failure when encountering invalid objects.
@ kSkipOnError
The merging process will skip invalid objects and continue.
Bool_t OpenExcessFiles()
Open up to (fMaxOpenedFiles-1) 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:65
TFile * fOutputFile
The outputfile for merging.
Definition TFileMerger.h:48
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:61
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:60
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:50
A ROOT file is an on-disk file, usually with extension .root, that stores objects in a file-system-li...
Definition TFile.h:131
Int_t GetCompressionSettings() const
Definition TFile.h:480
virtual Bool_t Cp(const char *dst, Bool_t progressbar=kTRUE, UInt_t bufsize=1000000)
Allows to copy this file to the dst URL.
Definition TFile.cxx:4686
Int_t Write(const char *name=nullptr, Int_t opt=0, Int_t bufsize=0) override
Write memory objects to this file.
Definition TFile.cxx:2466
Int_t GetCompressionLevel() const
Definition TFile.h:474
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:3764
void Close(Option_t *option="") override
Close a file.
Definition TFile.cxx:958
@ kCancelTTreeChangeRequest
Definition TFile.h:276
THashList implements a hybrid collection class consisting of a hash table and a list to store TObject...
Definition THashList.h:34
Book space in a file, create I/O buffers, to fill them, (un)compress them.
Definition TKey.h:28
const char * GetTitle() const override
Returns title (title can contain 32x32 xpm thumbnail/icon).
Definition TKey.cxx:1523
virtual const char * GetClassName() const
Definition TKey.h:75
virtual TObject * ReadObj()
To read a TObject* from the file.
Definition TKey.cxx:760
A doubly linked list.
Definition TList.h:38
void Clear(Option_t *option="") override
Remove all objects from the list.
Definition TList.cxx:399
void Add(TObject *obj) override
Definition TList.h:81
TObject * Remove(TObject *obj) override
Remove object from the list.
Definition TList.cxx:819
TObject * First() const override
Return the first object in the list. Returns 0 when list is empty.
Definition TList.cxx:656
static TClass * Class()
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
An array of TObjects.
Definition TObjArray.h:31
Collectable string class.
Definition TObjString.h:28
Mother of all ROOT objects.
Definition TObject.h:41
virtual void Clear(Option_t *="")
Definition TObject.h:125
@ kOverwrite
overwrite existing object with same name
Definition TObject.h:98
@ kSingleKey
write collection with single key
Definition TObject.h:97
virtual const char * GetName() const
Returns name of object.
Definition TObject.cxx:457
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition TObject.h:202
virtual TObject * Clone(const char *newname="") const
Make a clone of an object using the Streamer facility.
Definition TObject.cxx:242
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition TObject.cxx:1057
virtual void Execute(const char *method, const char *params, Int_t *error=nullptr)
Execute method on this object with the given parameter string, e.g.
Definition TObject.cxx:377
R__ALWAYS_INLINE Bool_t IsZombie() const
Definition TObject.h:159
virtual Int_t Write(const char *name=nullptr, Int_t option=0, Int_t bufsize=0)
Write this object to the current directory.
Definition TObject.cxx:964
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition TObject.cxx:864
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition TObject.cxx:543
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1071
virtual void Fatal(const char *method, const char *msgfmt,...) const
Issue fatal error message.
Definition TObject.cxx:1099
virtual const char * GetTitle() const
Returns title of object.
Definition TObject.cxx:501
virtual TClass * IsA() const
Definition TObject.h:246
void ResetBit(UInt_t f)
Definition TObject.h:201
@ kCanDelete
if object in a list can be deleted
Definition TObject.h:68
@ kMustCleanup
if object destructor must call RecursiveRemove()
Definition TObject.h:70
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition TObject.cxx:1045
Basic string class.
Definition TString.h:138
void Clear()
Clear string without changing its capacity.
Definition TString.cxx:1241
const char * Data() const
Definition TString.h:384
TObjArray * Tokenize(const TString &delim) const
This function is used to isolate sequential tokens in a TString.
Definition TString.cxx:2270
TString & Remove(Ssiz_t pos)
Definition TString.h:693
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition TString.h:640
virtual int Unlink(const char *name)
Unlink, i.e.
Definition TSystem.cxx:1392
virtual const char * TempDirectory() const
Return a user configured or systemwide directory to create temporary files in.
Definition TSystem.cxx:1493
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:570
This class represents a WWW compatible URL.
Definition TUrl.h:33
Long64_t(* MergeFunc_t)(void *, TCollection *, TFileMergeInfo *)
Definition Rtypes.h:121