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