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