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_files
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 kClingFileNumber = 100;
62////////////////////////////////////////////////////////////////////////////////
63/// Return the maximum number of allowed opened files minus some wiggle room
64/// for Cling 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 > kClingFileNumber) {
81 // Limit the maximum number of opened files to 128 to mitigate memory
82 // consumption issues that may arise during merges with many files.
83 // For further details see analysis at:
84 // https://github.com/root-project/root/issues/21660
85 return std::min(128, maxfiles - kClingFileNumber);
86 } else if (maxfiles > 5) {
87 return maxfiles - 5;
88 } else {
89 return maxfiles;
90 }
91}
92
93////////////////////////////////////////////////////////////////////////////////
94/// Create file merger object.
95
97 : fMaxOpenedFiles( R__GetSystemMaxOpenedFiles() ),
98 fLocal(isLocal), fHistoOneGo(histoOneGo)
99{
102
104 gROOT->GetListOfCleanups()->Add(this);
105}
106
107////////////////////////////////////////////////////////////////////////////////
108/// Cleanup.
109
111{
112 {
114 gROOT->GetListOfCleanups()->Remove(this);
115 }
117}
118
119////////////////////////////////////////////////////////////////////////////////
120/// Reset merger file list.
121
129
130////////////////////////////////////////////////////////////////////////////////
131/// Closes output file
132
138
139////////////////////////////////////////////////////////////////////////////////
140/// Add file to file merger.
141
142Bool_t TFileMerger::AddFile(const char *url, Bool_t cpProgress)
143{
144 if (fPrintLevel > 0) {
145 Printf("%s Source file %d: %s", fMsgPrefix.Data(), fFileList.GetEntries() + fExcessFiles.GetEntries() + 1, url);
146 }
147
148 TFile *newfile = nullptr;
149 TString localcopy;
150
151 if (fFileList.GetEntries() >= (fMaxOpenedFiles-1)) {
152
153 TObjString *urlObj = new TObjString(url);
154 fMergeList.Add(urlObj);
155
156 urlObj = new TObjString(url);
157 urlObj->SetBit(kCpProgress);
158 fExcessFiles.Add(urlObj);
159 return kTRUE;
160 }
161
162 // We want gDirectory untouched by anything going on here
164
165 if (fLocal) {
166 TUUID uuid;
167 localcopy.Form("file:%s/ROOTMERGE-%s.root", gSystem->TempDirectory(), uuid.AsString());
168 if (!TFile::Cp(url, localcopy, cpProgress)) {
169 Error("AddFile", "cannot get a local copy of file %s", url);
170 return kFALSE;
171 }
172 newfile = TFile::Open(localcopy, "READ");
173 } else {
174 newfile = TFile::Open(url, "READ");
175 }
176
177 // Zombie files should also be skipped
178 if (newfile && newfile->IsZombie()) {
179 delete newfile;
180 newfile = nullptr;
181 }
182
183 if (!newfile) {
184 if (fLocal)
185 Error("AddFile", "cannot open local copy %s of URL %s",
186 localcopy.Data(), url);
187 else
188 Error("AddFile", "cannot open file %s", url);
189 return kFALSE;
190 } else {
193
194 newfile->SetBit(kCanDelete);
195 fFileList.Add(newfile);
196
197 TObjString *urlObj = new TObjString(url);
198 fMergeList.Add(urlObj);
199
200 return kTRUE;
201 }
202}
203
204////////////////////////////////////////////////////////////////////////////////
205/// Add the TFile to this file merger and *do not* give ownership of the TFile to this
206/// object.
207///
208/// Return kTRUE if the addition was successful.
209
211{
212 return AddFile(source,kFALSE,cpProgress);
213}
214
215////////////////////////////////////////////////////////////////////////////////
216/// Add the TFile to this file merger and give ownership of the TFile to this
217/// object (unless kFALSE is returned).
218///
219/// Return kTRUE if the addition was successful.
220
222{
223 return AddFile(source,kTRUE,cpProgress);
224}
225
226////////////////////////////////////////////////////////////////////////////////
227/// Add the TFile to this file merger and give ownership of the TFile to this
228/// object (unless kFALSE is returned).
229///
230/// Return kTRUE if the addition was successful.
231
233{
234 if (source == 0 || source->IsZombie()) {
235 return kFALSE;
236 }
237
238 if (fPrintLevel > 0) {
239 Printf("%s Source file %d: %s",fMsgPrefix.Data(),fFileList.GetEntries()+1,source->GetName());
240 }
241
242 TFile *newfile = 0;
243 TString localcopy;
244
245 // We want gDirectory untouched by anything going on here
247 if (fLocal && !source->InheritsFrom(TMemFile::Class())) {
248 TUUID uuid;
249 localcopy.Form("file:%s/ROOTMERGE-%s.root", gSystem->TempDirectory(), uuid.AsString());
250 if (!source->Cp(localcopy, cpProgress)) {
251 Error("AddFile", "cannot get a local copy of file %s", source->GetName());
252 return kFALSE;
253 }
254 newfile = TFile::Open(localcopy, "READ");
255 // Zombie files should also be skipped
256 if (newfile && newfile->IsZombie()) {
257 delete newfile;
258 newfile = 0;
259 }
260 } else {
261 newfile = source;
262 }
263
264 if (!newfile) {
265 if (fLocal)
266 Error("AddFile", "cannot open local copy %s of URL %s",
267 localcopy.Data(), source->GetName());
268 else
269 Error("AddFile", "cannot open file %s", source->GetName());
270 return kFALSE;
271 } else {
273
274 if (own || newfile != source) {
275 newfile->SetBit(kCanDelete);
276 } else {
277 newfile->ResetBit(kCanDelete);
278 }
279 fFileList.Add(newfile);
280
281 TObjString *urlObj = new TObjString(source->GetName());
282 fMergeList.Add(urlObj);
283
284 if (newfile != source && own) {
285 delete source;
286 }
287 return kTRUE;
288 }
289}
290
291////////////////////////////////////////////////////////////////////////////////
292/// Open merger output file.
293
294Bool_t TFileMerger::OutputFile(const char *outputfile, Bool_t force, Int_t compressionLevel)
295{
296 return OutputFile(outputfile,(force?"RECREATE":"CREATE"),compressionLevel);
297}
298
299////////////////////////////////////////////////////////////////////////////////
300/// Open merger output file.
301
302Bool_t TFileMerger::OutputFile(const char *outputfile, Bool_t force)
303{
304 Bool_t res = OutputFile(outputfile,(force?"RECREATE":"CREATE"),1); // 1 is the same as the default from the TFile constructor.
307 return res;
308}
309
310////////////////////////////////////////////////////////////////////////////////
311/// Open merger output file.
312///
313/// The 'mode' parameter is passed to the TFile constructor as the option, it
314/// should be one of 'NEW','CREATE','RECREATE','UPDATE'
315/// 'UPDATE' is usually used in conjunction with IncrementalMerge.
316
317Bool_t TFileMerger::OutputFile(const char *outputfile, const char *mode, Int_t compressionLevel)
318{
319 // We want gDirectory untouched by anything going on here
321 if (TFile *outputFile = TFile::Open(outputfile, mode, "", compressionLevel))
322 return OutputFile(std::unique_ptr<TFile>(outputFile));
323
324 Error("OutputFile", "cannot open the MERGER output file %s", fOutputFilename.Data());
325 return kFALSE;
326}
327
328////////////////////////////////////////////////////////////////////////////////
329/// Set an output file opened externally by the users
330
331Bool_t TFileMerger::OutputFile(std::unique_ptr<TFile> outputfile)
332{
333 if (!outputfile || outputfile->IsZombie()) {
334 Error("OutputFile", "cannot open the MERGER output file %s", (outputfile) ? outputfile->GetName() : "");
335 return kFALSE;
336 }
337
338 if (!outputfile->IsWritable()) {
339 Error("OutputFile", "output file %s is not writable", outputfile->GetName());
340 return kFALSE;
341 }
342
344
345 TFile *oldfile = fOutputFile;
346 fOutputFile = 0; // This avoids the complaint from RecursiveRemove about the file being deleted which is here
347 // spurrious. (see RecursiveRemove).
348 SafeDelete(oldfile);
349
350 fOutputFilename = outputfile->GetName();
351 // We want gDirectory untouched by anything going on here
353 fOutputFile = outputfile.release(); // Transfer the ownership of the file.
354
355 return kTRUE;
356}
357
358////////////////////////////////////////////////////////////////////////////////
359/// Open merger output file. 'mode' is passed to the TFile constructor as the option, it should
360/// be one of 'NEW','CREATE','RECREATE','UPDATE'
361/// 'UPDATE' is usually used in conjunction with IncrementalMerge.
362
363Bool_t TFileMerger::OutputFile(const char *outputfile, const char *mode /* = "RECREATE" */)
364{
365 Bool_t res = OutputFile(outputfile,mode,1); // 1 is the same as the default from the TFile constructor.
367 return res;
368}
369
370////////////////////////////////////////////////////////////////////////////////
371/// Print list of files being merged.
372
374{
375 fFileList.Print(options);
376 fExcessFiles.Print(options);
377}
378
379////////////////////////////////////////////////////////////////////////////////
380/// Merge the files.
381///
382/// If no output file was specified it will write into
383/// the file "FileMerger.root" in the working directory. Returns true
384/// on success, false in case of error.
385
390
391namespace {
392
393Bool_t IsMergeable(TClass *cl)
394{
395 return (cl->GetMerge() || cl->InheritsFrom(TDirectory::Class()) ||
396 (cl->IsTObject() && !cl->IsLoaded() &&
397 /* If it has a dictionary and GetMerge() is nullptr then we already know the answer
398 to the next question is 'no, if we were to ask we would useless trigger
399 auto-parsing */
400 (cl->GetMethodWithPrototype("Merge", "TCollection*,TFileMergeInfo*") ||
401 cl->GetMethodWithPrototype("Merge", "TCollection*"))));
402};
403
404Bool_t WriteOneAndDelete(const TString &name, TClass *cl, TObject *obj, bool canBeMerged, Bool_t ownobj, TDirectory *target)
405{
406 Bool_t status = kTRUE;
407 if (cl->InheritsFrom(TCollection::Class())) {
408 // Don't overwrite, if the object were not merged.
409 if (obj->Write(name, canBeMerged ? TObject::kSingleKey | TObject::kOverwrite : TObject::kSingleKey) <= 0) {
410 status = kFALSE;
411 }
412 ((TCollection *)obj)->SetOwner();
413 if (ownobj)
414 delete obj;
415 } else {
416 // Don't overwrite, if the object were not merged.
417 // NOTE: this is probably wrong for emulated objects.
418 if (cl->IsTObject()) {
419 if (obj->Write(name, canBeMerged ? TObject::kOverwrite : 0) <= 0) {
420 status = kFALSE;
421 }
423 } else {
424 if (target->WriteObjectAny((void *)obj, cl, name, canBeMerged ? "OverWrite" : "") <= 0) {
425 status = kFALSE;
426 }
427 }
428 if (ownobj)
429 cl->Destructor(obj); // just in case the class is not loaded.
430 }
431 return status;
432}
433
434Bool_t WriteCycleInOrder(const TString &name, TIter &nextkey, TIter &peeknextkey, TDirectory *target)
435{
436 // Recurse until we find a different name or type appear.
437 TKey *key = (TKey*)peeknextkey();
438 if (!key || name != key->GetName()) {
439 return kTRUE;
440 }
442 if (IsMergeable(cl))
443 return kTRUE;
444 // Now we can advance the real iterator
445 (void)nextkey();
446 Bool_t result = WriteCycleInOrder(name, nextkey, peeknextkey, target);
447 TObject *obj = key->ReadObj();
448
449 return WriteOneAndDelete(name, cl, obj, kFALSE, kTRUE, target) && result;
450};
451
452} // anonymous namespace
453
455 TString &oldkeyname, THashList &allNames, Bool_t &status, Bool_t &onlyListed,
456 const TString &path, TDirectory *current_sourcedir, TFile *current_file, TKey *key,
457 TObject *obj, TIter &nextkey)
458{
459 const char *keyname = obj ? obj->GetName() : key->GetName();
460 const char *keyclassname = obj ? obj->IsA()->GetName() : key->GetClassName();
461 const char *keytitle = obj ? obj->GetTitle() : key->GetTitle();
462
463 // Keep only the highest cycle number for each key for mergeable objects. They are stored
464 // in the (hash) list consecutively and in decreasing order of cycles, so we can continue
465 // until the name changes. We flag the case here and we act consequently later.
466 Bool_t alreadyseen = (oldkeyname == keyname) ? kTRUE : kFALSE;
467 Bool_t ownobj = kFALSE;
468
469 // Read in but do not copy directly the processIds.
470 if (strcmp(keyclassname, "TProcessID") == 0 && key) {
471 key->ReadObj();
472 return kTRUE;
473 }
474
475 // If we have already seen this object [name], we already processed
476 // the whole list of files for this objects and we can just skip it
477 // and any related cycles.
478 if (allNames.FindObject(keyname)) {
479 oldkeyname = keyname;
480 return kTRUE;
481 }
482
483 TClass *cl = TClass::GetClass(keyclassname);
484 if (!cl) {
485 Info("MergeRecursive", "cannot indentify object type (%s), name: %s title: %s",
486 keyclassname, keyname, keytitle);
487 return kTRUE;
488 }
489 // For mergeable objects we add the names in a local hashlist handling them
490 // again (see above)
491 if (IsMergeable(cl))
492 allNames.Add(new TObjString(keyname));
493
495 // Skip the TTree objects and any related cycles.
496 oldkeyname = keyname;
497 return kTRUE;
498 }
499 // Check if only the listed objects are to be merged
500 if (type & kOnlyListed) {
501 // Search for " key " in " a b c " to match whole words only.
502 // Without the leading space, a key that is a prefix or suffix of a listed name
503 // would match. AddObjectNames() guarantees a trailing space in fObjectNames.
504 TString searchName = " ";
505 searchName += keyname;
506 searchName += " ";
507 onlyListed = (" " + fObjectNames).Contains(searchName);
508 if ((!onlyListed) && (!cl->InheritsFrom(TDirectory::Class()))) return kTRUE;
509 }
510
511 if (!(type&kResetable && type&kNonResetable)) {
512 // If neither or both are requested at the same time, we merger both types.
513 if (!(type&kResetable)) {
514 if (cl->GetResetAfterMerge()) {
515 // Skip the object with a reset after merge routine (TTree and other incrementally mergeable objects)
516 oldkeyname = keyname;
517 return kTRUE;
518 }
519 }
520 if (!(type&kNonResetable)) {
521 if (!cl->GetResetAfterMerge()) {
522 // Skip the object without a reset after merge routine (Histograms and other non incrementally mergeable objects)
523 oldkeyname = keyname;
524 return kTRUE;
525 }
526 }
527 }
528 // read object from first source file
529 if (type & kIncremental) {
530 if (!obj)
531 obj = current_sourcedir->GetList()->FindObject(keyname);
532 if (!obj && key) {
533 obj = key->ReadObj();
534 ownobj = kTRUE;
535 } else if (obj && info.fIsFirst && current_sourcedir != target
536 && !cl->InheritsFrom( TDirectory::Class() )) {
537 R__ASSERT(cl->IsTObject());
538 TDirectory::TContext ctxt(current_sourcedir);
539 obj = obj->Clone();
540 ownobj = kTRUE;
541 }
542 } else if (key) {
543 obj = key->ReadObj();
544 ownobj = kTRUE;
545 }
546 if (!obj) {
547 Info("MergeRecursive", "could not read object for key {%s, %s}",
548 keyname, keytitle);
549 return kTRUE;
550 }
551 Bool_t canBeFound = (type & kIncremental) && (target->GetList()->FindObject(keyname) != nullptr);
552
553 // if (cl->IsTObject())
554 // obj->ResetBit(kMustCleanup);
555 if (cl->IsTObject() && cl != obj->IsA()) {
556 Error("MergeRecursive", "TKey and object retrieve disagree on type (%s vs %s). Continuing with %s.",
557 keyclassname, obj->IsA()->GetName(), obj->IsA()->GetName());
558 cl = obj->IsA();
559 }
560 Bool_t canBeMerged = kTRUE;
561
562 std::map<std::tuple<std::string, std::string, std::string>, TDirectory*> dirtodelete;
563 auto getDirectory = [&dirtodelete](TDirectory *parent, const char *name, const TString &pathname) {
564 auto mapkey = std::make_tuple(parent->GetName(), name, pathname.Data());
565 auto result = dirtodelete.find(mapkey);
566 if (result != dirtodelete.end()) {
567 return result->second;
568 }
569
570 auto dir = dynamic_cast<TDirectory *>(parent->GetDirectory(pathname));
571 if (dir)
572 dirtodelete[mapkey] = dir;
573
574 return dir;
575 };
576
577 if ( cl->InheritsFrom( TDirectory::Class() ) ) {
578 // it's a subdirectory
579
580 target->cd();
581 TDirectory *newdir;
582
583 // For incremental or already seen we may have already a directory created
584 if (type & kIncremental || alreadyseen) {
585 newdir = target->GetDirectory(obj->GetName());
586 if (!newdir) {
587 newdir = target->mkdir( obj->GetName(), obj->GetTitle() );
588 // newdir->ResetBit(kMustCleanup);
589 }
590 } else {
591 newdir = target->mkdir( obj->GetName(), obj->GetTitle() );
592 // newdir->ResetBit(kMustCleanup);
593 }
594
595 // newdir is now the starting point of another round of merging
596 // newdir still knows its depth within the target file via
597 // GetPath(), so we can still figure out where we are in the recursion
598
599 // If this folder is a onlyListed object, merge everything inside.
600 const auto mergeType = onlyListed ? type & ~kOnlyListed : type;
601 status = MergeRecursive(newdir, sourcelist, mergeType);
602
603 if ((type & kOnlyListed) && !(type & kIncremental) && !onlyListed && newdir->GetNkeys() == 0) {
604 // None of the children were merged, and the directory is not listed
605 delete newdir;
606 newdir = nullptr;
607 target->rmdir(obj->GetName());
608 }
609 // Delete newdir directory after having written it (merged)
610 if (!(type&kIncremental)) delete newdir;
611 if (onlyListed) type |= kOnlyListed;
612 if (!status) return kFALSE;
613 } else if (!cl->IsTObject() && cl->GetMerge()) {
614 // merge objects that don't derive from TObject
616 // Collect all the data to be passed on to the merger
617 TList mergeData;
618 // First entry is the TKey of the ntuple
619 mergeData.Add(key);
620 // Second entry is the output file
621 mergeData.Add(target->GetFile());
622 // Remaining entries are the input files
623 TIter nextFile(sourcelist);
624 while (const auto &inFile = nextFile()) {
625 mergeData.Add(inFile);
626 }
627 // Get the merge fuction and pass the data
628 ROOT::MergeFunc_t func = cl->GetMerge();
629 Long64_t result = func(obj, &mergeData, &info);
630 mergeData.Clear("nodelete");
631 if (result < 0) {
632 Error("MergeRecursive", "Could NOT merge RNTuples!");
633 return kFALSE;
634 }
635 } else {
636 TFile *nextsource = current_file ? (TFile*)sourcelist->After( current_file ) : (TFile*)sourcelist->First();
637 Error("MergeRecursive", "Merging objects that don't inherit from TObject is unimplemented (key: %s of type %s in file %s)",
638 keyname, keyclassname, nextsource->GetName());
639 canBeMerged = kFALSE;
640 }
641 } else if (cl->IsTObject() && cl->GetMerge()) {
642 // Check if already treated
643 if (alreadyseen) return kTRUE;
644
645 TList inputs;
646 TList todelete;
648
649 // Loop over all source files and merge same-name object
650 TFile *nextsource = current_file ? (TFile*)sourcelist->After( current_file ) : (TFile*)sourcelist->First();
651 if (nextsource == 0) {
652 // There is only one file in the list
653 ROOT::MergeFunc_t func = cl->GetMerge();
654 func(obj, &inputs, &info);
655 info.fIsFirst = kFALSE;
656 } else {
657 do {
658 // make sure we are at the correct directory level by cd'ing to path
659 TDirectory *ndir = getDirectory(nextsource, target->GetName(), path);
660 if (ndir) {
661 // For consistency (and persformance), we reset the MustCleanup be also for those
662 // 'key' retrieved indirectly.
663 // ndir->ResetBit(kMustCleanup);
664 ndir->cd();
665 TObject *hobj = ndir->GetList()->FindObject(keyname);
666 if (!hobj) {
667 TKey *key2 = (TKey*)ndir->GetListOfKeys()->FindObject(keyname);
668 if (key2) {
669 if (strcmp(key2->GetClassName(), keyclassname) != 0) {
670 Error("MergeRecursive",
671 "Object type mismatch for key '%s' in file '%s': expected '%s' but found '%s'.", keyname,
672 nextsource->GetName(), keyclassname, key2->GetClassName());
673 nextsource = (TFile *)sourcelist->After(nextsource);
674 return kFALSE;
675 }
676 hobj = key2->ReadObj();
677 if (!hobj) {
678 switch (fErrBehavior) {
680 Error("MergeRecursive", "could not read object for key {%s, %s}; in file %s", keyname,
681 keytitle, nextsource->GetName());
682 nextsource = (TFile *)sourcelist->After(nextsource);
683 return kFALSE;
685 Warning("MergeRecursive", "could not read object for key {%s, %s}; skipping file %s",
686 keyname, keytitle, nextsource->GetName());
687 nextsource = (TFile *)sourcelist->After(nextsource);
688 return kTRUE;
689 }
690 }
691 todelete.Add(hobj);
692 }
693 }
694 if (hobj) {
695 // Set ownership for collections
696 if (hobj->InheritsFrom(TCollection::Class())) {
697 ((TCollection*)hobj)->SetOwner();
698 }
699 hobj->ResetBit(kMustCleanup);
700 inputs.Add(hobj);
701 if (!oneGo) {
702 ROOT::MergeFunc_t func = cl->GetMerge();
703 Long64_t result = func(obj, &inputs, &info);
704 info.fIsFirst = kFALSE;
705 if (result < 0) {
706 Error("MergeRecursive", "calling Merge() on '%s' with the corresponding object in '%s'",
707 keyname, nextsource->GetName());
708 }
709 inputs.Clear();
710 todelete.Delete();
711 }
712 }
713 }
714 nextsource = (TFile*)sourcelist->After( nextsource );
715 } while (nextsource);
716 // Merge the list, if still to be done
717 if (oneGo || info.fIsFirst) {
718 ROOT::MergeFunc_t func = cl->GetMerge();
719 func(obj, &inputs, &info);
720 info.fIsFirst = kFALSE;
721 inputs.Clear();
722 todelete.Delete();
723 }
724 }
725 } else if (cl->IsTObject()) {
726 // try synthesizing the Merge method call according to the TObject
727 TList listH;
728 TString listHargs;
729 if (cl->GetMethodWithPrototype("Merge", "TCollection*,TFileMergeInfo*")) {
730 listHargs.Form("(TCollection*)0x%zx,(TFileMergeInfo*)0x%zx",
731 (size_t)&listH, (size_t)&info);
732 } else if (cl->GetMethodWithPrototype("Merge", "TCollection*")) {
733 listHargs.Form("((TCollection*)0x%zx)", (size_t)&listH);
734 } else {
735 // pass unmergeable objects through to the output file
736 canBeMerged = kFALSE;
737 }
738 if (canBeMerged) {
739 if (alreadyseen) {
740 // skip already seen mergeable objects, don't skip unmergeable objects
741 return kTRUE;
742 }
743 // Loop over all source files and merge same-name object
744 TFile *nextsource = current_file ? (TFile*)sourcelist->After( current_file ) : (TFile*)sourcelist->First();
745 if (nextsource == 0) {
746 // There is only one file in the list
747 Int_t error = 0;
748 obj->Execute("Merge", listHargs.Data(), &error);
749 info.fIsFirst = kFALSE;
750 if (error) {
751 Error("MergeRecursive", "calling Merge() on '%s' with the corresponding object in '%s'",
752 obj->GetName(), keyname);
753 }
754 } else {
755 while (nextsource) {
756 // make sure we are at the correct directory level by cd'ing to path
757 TDirectory *ndir = getDirectory(nextsource, target->GetName(), path);
758 if (ndir) {
759 ndir->cd();
760 TKey *key2 = (TKey*)ndir->GetListOfKeys()->FindObject(keyname);
761 if (key2) {
762 TObject *hobj = key2->ReadObj();
763 if (!hobj) {
764 switch (fErrBehavior) {
766 Error("MergeRecursive", "could not read object for key {%s, %s}; in file %s", keyname,
767 keytitle, nextsource->GetName());
768 nextsource = (TFile *)sourcelist->After(nextsource);
769 return kFALSE;
771 Warning("MergeRecursive", "could not read object for key {%s, %s}; skipping file %s",
772 keyname, keytitle, nextsource->GetName());
773 nextsource = (TFile *)sourcelist->After(nextsource);
774 return kTRUE;
775 }
776 }
777 // Set ownership for collections
778 if (hobj->InheritsFrom(TCollection::Class())) {
779 ((TCollection*)hobj)->SetOwner();
780 }
781 hobj->ResetBit(kMustCleanup);
782 listH.Add(hobj);
783 Int_t error = 0;
784 obj->Execute("Merge", listHargs.Data(), &error);
785 info.fIsFirst = kFALSE;
786 if (error) {
787 Error("MergeRecursive", "calling Merge() on '%s' with the corresponding object in '%s'",
788 obj->GetName(), nextsource->GetName());
789 }
790 listH.Delete();
791 }
792 }
793 nextsource = (TFile*)sourcelist->After( nextsource );
794 }
795 // Merge the list, if still to be done
796 if (info.fIsFirst) {
797 Int_t error = 0;
798 obj->Execute("Merge", listHargs.Data(), &error);
799 info.fIsFirst = kFALSE;
800 listH.Delete();
801 }
802 }
803 }
804 } else {
805 // Object is of no type that we can merge
806 canBeMerged = kFALSE;
807 }
808
809 // now write the merged histogram (which is "in" obj) to the target file
810 // note that this will just store obj in the current directory level,
811 // which is not persistent until the complete directory itself is stored
812 // by "target->SaveSelf()" below
813 target->cd();
814
815 oldkeyname = keyname;
816 // if the object is a tree, it is stored in globChain...
817 if (cl->InheritsFrom(TDirectory::Class())) {
818 // printf("cas d'une directory\n");
819
820 auto dirobj = dynamic_cast<TDirectory *>(obj);
821 TString dirpath(dirobj->GetPath());
822 // coverity[unchecked_value] 'target' is from a file so GetPath always returns path starting with filename:
823 dirpath.Remove(0, std::strlen(dirobj->GetFile()->GetPath()));
824
825 // Do not delete the directory if it is part of the output
826 // and we are in incremental mode (because it will be reused
827 // and has not been written to disk (for performance reason).
828 // coverity[var_deref_model] the IsA()->InheritsFrom guarantees that the dynamic_cast will succeed.
829 if (ownobj && (!(type & kIncremental) || dirobj->GetFile() != target->GetFile())) {
830 dirobj->ResetBit(kMustCleanup);
831 delete dirobj;
832 }
833 // Let's also delete the directory from the other source (thanks to the 'allNames'
834 // mechanism above we will not process the directories when tranversing the next
835 // files).
836 for (const auto &[_, ndir] : dirtodelete) {
837 // For consistency (and performance), we reset the MustCleanup be also for those
838 // 'key' retrieved indirectly.
839 ndir->ResetBit(kMustCleanup);
840 delete ndir;
841 }
842 } else if (!canBeFound) { // object (TTree, TH1) is not yet owned by the target, thus write it
843 if (gDebug > 0)
844 Info("MergeOne", "Writing partial result of %s into target", oldkeyname.Data());
845 if (!canBeMerged) {
846 TIter peeknextkey(nextkey);
847 status = WriteCycleInOrder(oldkeyname, nextkey, peeknextkey, target) && status;
848 status = WriteOneAndDelete(oldkeyname, cl, obj, kFALSE, ownobj, target) && status;
849 } else {
850 status = WriteOneAndDelete(oldkeyname, cl, obj, kTRUE, ownobj, target) && status;
851 }
852 }
853 info.Reset();
854 return kTRUE;
855}
856
857////////////////////////////////////////////////////////////////////////////////
858/// Merge all objects in a directory
859///
860/// The type is defined by the bit values in TFileMerger::EPartialMergeType.
861
862Bool_t TFileMerger::MergeRecursive(TDirectory *target, TList *sourcelist, Int_t type /* = kRegular | kAll */)
863{
864 Bool_t status = kTRUE;
865 Bool_t onlyListed = kFALSE;
866 if (fPrintLevel > 0) {
867 Printf("%s Target path: %s",fMsgPrefix.Data(),target->GetPath());
868 }
869
870 // Get the dir name
871 TString path(target->GetPath());
872 // coverity[unchecked_value] 'target' is from a file so GetPath always returns path starting with filename:
873 path.Remove(0, std::strlen(target->GetFile()->GetPath()));
874
875 Int_t nguess = sourcelist->GetSize()+1000;
876 THashList allNames(nguess);
877 allNames.SetOwner(kTRUE);
878 // If the mode is set to skipping list objects, add names to the allNames list
879 if (type & kSkipListed) {
880 TObjArray *arr = fObjectNames.Tokenize(" ");
881 arr->SetOwner(kFALSE);
882 for (Int_t iname=0; iname<arr->GetEntriesFast(); iname++)
883 allNames.Add(arr->At(iname));
884 delete arr;
885 }
886 ((THashList*)target->GetList())->Rehash(nguess);
887 ((THashList*)target->GetListOfKeys())->Rehash(nguess);
888
891 info.fOptions = fMergeOptions;
893 info.fOptions.Append(" fast");
894 }
895
896 TFile *current_file;
897 TDirectory *current_sourcedir;
898 if (type & kIncremental) {
899 current_file = 0;
900 current_sourcedir = target;
901 } else {
902 current_file = (TFile*)sourcelist->First();
903 current_sourcedir = current_file->GetDirectory(path);
904 }
905 while (current_file || current_sourcedir) {
906 // When current_sourcedir != 0 and current_file == 0 we are going over the target
907 // for an incremental merge.
908 if (current_sourcedir && (current_file == 0 || current_sourcedir != target)) {
909 TString oldkeyname;
910
911 // Loop over live objects
912 TIter nextobj( current_sourcedir->GetList() );
913 TObject *obj;
914 while ( (obj = (TKey*)nextobj())) {
915 auto result = MergeOne(target, sourcelist, type,
916 info, oldkeyname, allNames, status, onlyListed, path,
917 current_sourcedir, current_file,
918 nullptr, obj, nextobj);
919 if (!result)
920 return kFALSE; // Stop completely in case of error.
921 } // while ( (obj = (TKey*)nextobj()))
922
923 // loop over all keys in this directory
924 TIter nextkey( current_sourcedir->GetListOfKeys() );
925 TKey *key;
926
927 while ( (key = (TKey*)nextkey())) {
928 auto result = MergeOne(target, sourcelist, type,
929 info, oldkeyname, allNames, status, onlyListed, path,
930 current_sourcedir, current_file,
931 key, nullptr, nextkey);
932 if (!result)
933 return kFALSE; // Stop completely in case of error.
934 } // while ( ( TKey *key = (TKey*)nextkey() ) )
935 }
936 current_file = current_file ? (TFile*)sourcelist->After(current_file) : (TFile*)sourcelist->First();
937 if (current_file) {
938 current_sourcedir = current_file->GetDirectory(path);
939 } else {
940 current_sourcedir = 0;
941 }
942 }
943 // save modifications to the target directory.
944 if (!(type&kIncremental)) {
945 // In case of incremental build, we will call Write on the top directory/file, so we do not need
946 // to call SaveSelf explicilty.
947 target->SaveSelf(kTRUE);
948 }
949
950 return status;
951}
952
953////////////////////////////////////////////////////////////////////////////////
954/// Merge the files. If no output file was specified it will write into
955/// the file "FileMerger.root" in the working directory. Returns true
956/// on success, false in case of error.
957/// The type is defined by the bit values in EPartialMergeType:
958///
959/// kRegular : normal merge, overwriting the output file
960/// kIncremental : merge the input file with the content of the output file (if already exising) (default)
961/// kResetable : merge only the objects with a MergeAfterReset member function.
962/// kNonResetable : merge only the objects without a MergeAfterReset member function.
963/// kDelayWrite : delay the TFile write (to reduce the number of write when reusing the file)
964/// kAll : merge all type of objects (default)
965/// kAllIncremental : merge incrementally all type of objects.
966/// kOnlyListed : merge only the objects specified in fObjectNames list
967/// kSkipListed : skip objects specified in fObjectNames list
968/// kKeepCompression: keep compression level unchanged for each input
969///
970/// If the type is not set to kIncremental, the output file is deleted at the end of this operation.
971
973{
974 if (!fOutputFile) {
976 if (outf.IsNull()) {
977 outf.Form("file:%s/FileMerger.root", gSystem->TempDirectory());
978 Info("PartialMerge", "will merge the results to the file %s\n"
979 "since you didn't specify a merge filename",
980 TUrl(outf).GetFile());
981 }
982 if (!OutputFile(outf.Data())) {
983 return kFALSE;
984 }
985 }
986
987 // Special treatment for the single file case to improve efficiency...
988 if ((fFileList.GetEntries() == 1) && !fExcessFiles.GetEntries() &&
992
993 TFile *file = (TFile *) fFileList.First();
994 if (!file || (file && file->IsZombie())) {
995 Error("PartialMerge", "one-file case: problem attaching to file");
996 return kFALSE;
997 }
999 if (!(result = file->Cp(fOutputFilename))) {
1000 Error("PartialMerge", "one-file case: could not copy '%s' to '%s'",
1001 file->GetPath(), fOutputFilename.Data());
1002 return kFALSE;
1003 }
1004 if (file->TestBit(kCanDelete)) file->Close();
1005
1006 // Remove the temporary file
1007 if (fLocal && !file->InheritsFrom(TMemFile::Class())) {
1008 TUrl u(file->GetPath(), kTRUE);
1009 if (gSystem->Unlink(u.GetFile()) != 0)
1010 Warning("PartialMerge", "problems removing temporary local file '%s'", u.GetFile());
1011 }
1012 fFileList.Clear();
1013 return result;
1014 }
1015
1018
1020
1022 Int_t type = in_type;
1023 while (result && fFileList.GetEntries()>0) {
1025
1026 // Remove local copies if there are any
1027 TIter next(&fFileList);
1028 TFile *file;
1029 while ((file = (TFile*) next())) {
1030 // close the files
1031 if (file->TestBit(kCanDelete)) file->Close();
1032 // remove the temporary files
1033 if(fLocal && !file->InheritsFrom(TMemFile::Class())) {
1034 TString p(file->GetPath());
1035 // coverity[unchecked_value] Index is return a value with range or NPos to select the whole name.
1036 p = p(0, p.Index(':',0));
1037 gSystem->Unlink(p);
1038 }
1039 }
1040 fFileList.Clear();
1041 if (result && fExcessFiles.GetEntries() > 0) {
1042 // We merge the first set of files in the output,
1043 // we now need to open the next set and make
1044 // sure we accumulate into the output, so we
1045 // switch to incremental merging (if not already set)
1048 }
1049 }
1050 if (!result) {
1051 Error("Merge", "error during merge of your ROOT files");
1052 } else {
1053 // Close or write is required so the file is complete.
1054 if (in_type & kIncremental) {
1055 // In the case of 'kDelayWrite' the caller want to avoid having to
1056 // write the output objects once for every input file and instead
1057 // write it only once at the end of the process.
1058 if (!(in_type & kDelayWrite))
1060 } else {
1061 // If in_type is not incremental but type is incremental we are now in
1062 // the case where the user "explicitly" request a non-incremental merge
1063 // but we still have internally an incremental merge. Because the user
1064 // did not request the incremental merge they also probably do not to a
1065 // final Write of the file and thus not doing the write here would lead
1066 // to data loss ...
1067 if (type & kIncremental)
1069 gROOT->GetListOfFiles()->Remove(fOutputFile);
1070 fOutputFile->Close();
1071 }
1072 }
1073
1074 // Cleanup
1075 if (in_type & kIncremental) {
1076 Clear();
1077 } else {
1081 }
1082 return result;
1083}
1084
1085////////////////////////////////////////////////////////////////////////////////
1086/// Open up to (fMaxOpenedFiles-1) of the excess files.
1087
1089{
1090 if (fPrintLevel > 0) {
1091 Printf("%s Opening the next %d files", fMsgPrefix.Data(), std::min(fExcessFiles.GetEntries(), fMaxOpenedFiles - 1));
1092 }
1093 Int_t nfiles = 0;
1094 TIter next(&fExcessFiles);
1095 TObjString *url = 0;
1096 TString localcopy;
1097 // We want gDirectory untouched by anything going on here
1099 while( nfiles < (fMaxOpenedFiles-1) && ( url = (TObjString*)next() ) ) {
1100 TFile *newfile = 0;
1101 if (fLocal) {
1102 TUUID uuid;
1103 localcopy.Form("file:%s/ROOTMERGE-%s.root", gSystem->TempDirectory(), uuid.AsString());
1104 if (!TFile::Cp(url->GetName(), localcopy, url->TestBit(kCpProgress))) {
1105 Error("OpenExcessFiles", "cannot get a local copy of file %s", url->GetName());
1106 return kFALSE;
1107 }
1108 newfile = TFile::Open(localcopy, "READ");
1109 } else {
1110 newfile = TFile::Open(url->GetName(), "READ");
1111 }
1112
1113 if (!newfile) {
1114 if (fLocal)
1115 Error("OpenExcessFiles", "cannot open local copy %s of URL %s",
1116 localcopy.Data(), url->GetName());
1117 else
1118 Error("OpenExcessFiles", "cannot open file %s", url->GetName());
1119 return kFALSE;
1120 } else {
1122
1123 newfile->SetBit(kCanDelete);
1124 fFileList.Add(newfile);
1125 ++nfiles;
1126 fExcessFiles.Remove(url);
1127 }
1128 }
1129 return kTRUE;
1130}
1131
1132////////////////////////////////////////////////////////////////////////////////
1133/// Intercept the case where the output TFile is deleted!
1134
1136{
1138 Fatal("RecursiveRemove","Output file of the TFile Merger (targeting %s) has been deleted (likely due to a TTree larger than 100Gb)", fOutputFilename.Data());
1139 }
1140
1141}
1142
1143////////////////////////////////////////////////////////////////////////////////
1144/// Set a limit to the number of files that TFileMerger will open simultaneously.
1145///
1146/// This number includes both the read input files and the output file.
1147/// \param newmax if higher than the system limit, we reset it to the system limit;
1148/// if less than two, we reset it to 2 (one for the output file and one for the input file).
1149
1151{
1153 if (newmax < sysmax) {
1154 fMaxOpenedFiles = newmax;
1155 } else {
1156 fMaxOpenedFiles = sysmax;
1157 }
1158 if (fMaxOpenedFiles < 2) {
1159 fMaxOpenedFiles = 2;
1160 }
1161}
1162
1163////////////////////////////////////////////////////////////////////////////////
1164/// Set the prefix to be used when printing informational message.
1165
1166void TFileMerger::SetMsgPrefix(const char *prefix)
1167{
1168 fMsgPrefix = prefix;
1169}
#define SafeDelete(p)
Definition RConfig.hxx:507
bool Bool_t
Boolean (0=false, 1=true) (bool)
Definition RtypesCore.h:78
int Int_t
Signed integer 4 bytes (int)
Definition RtypesCore.h:60
constexpr Bool_t kFALSE
Definition RtypesCore.h:109
long long Long64_t
Portable signed long integer 8 bytes.
Definition RtypesCore.h:84
constexpr Bool_t kTRUE
Definition RtypesCore.h:108
const char Option_t
Option string (const char)
Definition RtypesCore.h:81
#define BIT(n)
Definition Rtypes.h:90
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:139
TClassRef R__TH1_Class("TH1")
static const Int_t kClingFileNumber
static Int_t R__GetSystemMaxOpenedFiles()
Return the maximum number of allowed opened files minus some wiggle room for Cling or at least of the...
TClassRef R__RNTuple_Class("ROOT::RNTuple")
TClassRef R__TTree_Class("TTree")
static const Int_t kCpProgress
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:142
@ kMustCleanup
Definition TObject.h:376
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:792
R__EXTERN TVirtualMutex * gROOTMutex
Definition TROOT.h:63
#define gROOT
Definition TROOT.h:417
void Printf(const char *fmt,...)
Formats a string in a circular formatting buffer and prints the string.
Definition TString.cxx:2585
R__EXTERN TSystem * gSystem
Definition TSystem.h:582
#define R__LOCKGUARD(mutex)
#define _(A, B)
Definition cfortran.h:112
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:4577
void Destructor(void *obj, Bool_t dtorOnly=kFALSE)
Explicitly call destructor for object.
Definition TClass.cxx:5533
ROOT::ResetAfterMergeFunc_t GetResetAfterMerge() const
Return the wrapper around Merge.
Definition TClass.cxx:7667
Bool_t IsLoaded() const
Return true if the shared library of this class is currently in the a process's memory.
Definition TClass.cxx:6080
Bool_t IsTObject() const
Return kTRUE is the class inherits from TObject.
Definition TClass.cxx:6106
Bool_t InheritsFrom(const char *cl) const override
Return kTRUE if this class inherits from a class with name "classname".
Definition TClass.cxx:4995
ROOT::MergeFunc_t GetMerge() const
Return the wrapper around Merge.
Definition TClass.cxx:7659
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:2999
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).
virtual Int_t GetSize() const
Return the capacity of the collection, i.e.
TDirectory * GetDirectory(const char *apath, Bool_t printError=false, const char *funcname="GetDirectory") override
Find a directory named "apath".
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 TList * GetList() const
Definition TDirectory.h:223
virtual TDirectory * GetDirectory(const char *namecycle, Bool_t printError=false, const char *funcname="GetDirectory")
Find a directory using apath.
virtual Int_t GetNkeys() const
Definition TDirectory.h:228
virtual const char * GetPath() const
Returns the full path of the directory.
virtual Bool_t cd()
Change current directory to "this" directory.
virtual TList * GetListOfKeys() const
Definition TDirectory.h:224
A class to pass information from the TFileMerger to the objects being merged.
TIOFeatures * fIOFeatures
Any ROOT IO features that should be explicitly enabled.
Bool_t fIsFirst
True if this is the first call to Merge for this series of object.
TString fOptions
Additional text based option being passed down to customize the merge.
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 file, usually with extension .root, that stores data and code in the form of serialized objects in ...
Definition TFile.h:130
Int_t GetCompressionSettings() const
Definition TFile.h:489
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:4709
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:2503
Int_t GetCompressionLevel() const
Definition TFile.h:483
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:3802
void Close(Option_t *option="") override
Close a file.
Definition TFile.cxx:992
@ kCancelTTreeChangeRequest
Definition TFile.h:275
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 override
Find object using its name.
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:1686
virtual const char * GetClassName() const
Definition TKey.h:77
virtual TObject * ReadObj()
To read a TObject* from the file.
Definition TKey.cxx:812
A doubly linked list.
Definition TList.h:38
TObject * After(const TObject *obj) const override
Returns the object after object obj.
Definition TList.cxx:460
void Clear(Option_t *option="") override
Remove all objects from the list.
Definition TList.cxx:532
TObject * FindObject(const char *name) const override
Find an object in this list using its name.
Definition TList.cxx:708
void Add(TObject *obj) override
Definition TList.h:81
TObject * Remove(TObject *obj) override
Remove object from the list.
Definition TList.cxx:952
TObject * First() const override
Return the first object in the list. Returns 0 when list is empty.
Definition TList.cxx:789
void Delete(Option_t *option="") override
Remove all objects from the list AND delete all heap based objects.
Definition TList.cxx:600
static TClass * Class()
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
An array of TObjects.
Definition TObjArray.h:31
Int_t GetEntriesFast() const
Definition TObjArray.h:58
TObject * At(Int_t idx) const override
Definition TObjArray.h:170
Collectable string class.
Definition TObjString.h:28
const char * GetName() const override
Returns name of object.
Definition TObjString.h:38
Mother of all ROOT objects.
Definition TObject.h:42
virtual void Clear(Option_t *="")
Definition TObject.h:127
virtual const char * GetName() const
Returns name of object.
Definition TObject.cxx:461
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition TObject.h:204
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:1082
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:161
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:987
@ kOverwrite
overwrite existing object with same name
Definition TObject.h:101
@ kSingleKey
write collection with single key
Definition TObject.h:100
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition TObject.cxx:886
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition TObject.cxx:548
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1096
virtual void Fatal(const char *method, const char *msgfmt,...) const
Issue fatal error message.
Definition TObject.cxx:1124
virtual const char * GetTitle() const
Returns title of object.
Definition TObject.cxx:506
virtual TClass * IsA() const
Definition TObject.h:248
void ResetBit(UInt_t f)
Definition TObject.h:203
@ kCanDelete
if object in a list can be deleted
Definition TObject.h:71
@ kMustCleanup
if object destructor must call RecursiveRemove()
Definition TObject.h:73
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition TObject.cxx:1070
Basic string class.
Definition TString.h:137
void Clear()
Clear string without changing its capacity.
Definition TString.cxx:1242
const char * Data() const
Definition TString.h:385
TObjArray * Tokenize(const TString &delim) const
This function is used to isolate sequential tokens in a TString.
Definition TString.cxx:2345
Bool_t IsNull() const
Definition TString.h:423
TString & Remove(Ssiz_t pos)
Definition TString.h:695
TString & Append(const char *cs)
Definition TString.h:582
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition TString.cxx:2438
virtual int Unlink(const char *name)
Unlink, i.e.
Definition TSystem.cxx:1403
virtual const char * TempDirectory() const
Return a user configured or systemwide directory to create temporary files in.
Definition TSystem.cxx:1504
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:602
This class represents a WWW compatible URL.
Definition TUrl.h:33
const char * GetFile() const
Definition TUrl.h:69
Long64_t(* MergeFunc_t)(void *, TCollection *, TFileMergeInfo *)
Definition Rtypes.h:120