49#include <sys/resource.h>
70 maxfiles = _getmaxstdio();
73 if (getrlimit(RLIMIT_NOFILE,&filelimit)==0) {
74 maxfiles = filelimit.rlim_cur;
86 }
else if (maxfiles > 5) {
104 gROOT->GetListOfCleanups()->Add(
this);
114 gROOT->GetListOfCleanups()->Remove(
this);
148 TFile *newfile =
nullptr;
168 if (!
TFile::Cp(url, localcopy, cpProgress)) {
169 Error(
"AddFile",
"cannot get a local copy of file %s", url);
178 if (newfile && newfile->
IsZombie()) {
185 Error(
"AddFile",
"cannot open local copy %s of URL %s",
186 localcopy.
Data(), url);
188 Error(
"AddFile",
"cannot open file %s", url);
234 if (source == 0 || source->
IsZombie()) {
250 if (!source->
Cp(localcopy, cpProgress)) {
251 Error(
"AddFile",
"cannot get a local copy of file %s", source->
GetName());
256 if (newfile && newfile->
IsZombie()) {
266 Error(
"AddFile",
"cannot open local copy %s of URL %s",
269 Error(
"AddFile",
"cannot open file %s", source->
GetName());
274 if (own || newfile != source) {
284 if (newfile != source && own) {
296 return OutputFile(outputfile,(force?
"RECREATE":
"CREATE"),compressionLevel);
321 if (
TFile *outputFile =
TFile::Open(outputfile, mode,
"", compressionLevel))
322 return OutputFile(std::unique_ptr<TFile>(outputFile));
333 if (!outputfile || outputfile->IsZombie()) {
334 Error(
"OutputFile",
"cannot open the MERGER output file %s", (outputfile) ? outputfile->GetName() :
"");
338 if (!outputfile->IsWritable()) {
339 Error(
"OutputFile",
"output file %s is not writable", outputfile->GetName());
424 if (target->
WriteObjectAny((
void *)obj, cl,
name, canBeMerged ?
"OverWrite" :
"") <= 0) {
446 Bool_t result = WriteCycleInOrder(
name, nextkey, peeknextkey, target);
449 return WriteOneAndDelete(
name, cl, obj,
kFALSE,
kTRUE, target) && result;
470 if (strcmp(keyclassname,
"TProcessID") == 0 && key) {
479 oldkeyname = keyname;
485 Info(
"MergeRecursive",
"cannot indentify object type (%s), name: %s title: %s",
486 keyclassname, keyname, keytitle);
496 oldkeyname = keyname;
501 oldkeyname = keyname;
504 oldkeyname = keyname;
513 oldkeyname = keyname;
520 oldkeyname = keyname;
532 }
else if (obj && info.
fIsFirst && current_sourcedir != target
544 Info(
"MergeRecursive",
"could not read object for key {%s, %s}",
553 Error(
"MergeRecursive",
"TKey and object retrieve disagree on type (%s vs %s). Continuing with %s.",
559 std::map<std::tuple<std::string, std::string, std::string>,
TDirectory*> dirtodelete;
561 auto mapkey = std::make_tuple(parent->
GetName(),
name, pathname.Data());
562 auto result = dirtodelete.find(mapkey);
563 if (result != dirtodelete.end()) {
564 return result->second;
569 dirtodelete[mapkey] = dir;
597 const auto mergeType = onlyListed ? type &
~kOnlyListed : type;
609 if (!status)
return kFALSE;
613 Warning(
"MergeRecursive",
"Merging RNTuples is experimental");
622 TIter nextFile(sourcelist);
623 while (
const auto &inFile = nextFile()) {
624 mergeData.
Add(inFile);
628 Long64_t result = func(obj, &mergeData, &info);
629 mergeData.
Clear(
"nodelete");
631 Error(
"MergeRecursive",
"Could NOT merge RNTuples!");
636 Error(
"MergeRecursive",
"Merging objects that don't inherit from TObject is unimplemented (key: %s of type %s in file %s)",
637 keyname, keyclassname, nextsource->
GetName());
642 if (alreadyseen)
return kTRUE;
650 if (nextsource == 0) {
653 func(obj, &inputs, &info);
669 Error(
"MergeRecursive",
670 "Object type mismatch for key '%s' in file '%s': expected '%s' but found '%s'.", keyname,
672 nextsource = (
TFile *)sourcelist->
After(nextsource);
679 Error(
"MergeRecursive",
"could not read object for key {%s, %s}; in file %s", keyname,
680 keytitle, nextsource->
GetName());
681 nextsource = (
TFile *)sourcelist->
After(nextsource);
684 Warning(
"MergeRecursive",
"could not read object for key {%s, %s}; skipping file %s",
685 keyname, keytitle, nextsource->
GetName());
686 nextsource = (
TFile *)sourcelist->
After(nextsource);
702 Long64_t result = func(obj, &inputs, &info);
705 Error(
"MergeRecursive",
"calling Merge() on '%s' with the corresponding object in '%s'",
706 keyname, nextsource->
GetName());
713 nextsource = (
TFile*)sourcelist->
After( nextsource );
714 }
while (nextsource);
718 func(obj, &inputs, &info);
729 listHargs.
Form(
"(TCollection*)0x%zx,(TFileMergeInfo*)0x%zx",
730 (
size_t)&listH, (
size_t)&info);
732 listHargs.
Form(
"((TCollection*)0x%zx)", (
size_t)&listH);
744 if (nextsource == 0) {
750 Error(
"MergeRecursive",
"calling Merge() on '%s' with the corresponding object in '%s'",
765 Error(
"MergeRecursive",
"could not read object for key {%s, %s}; in file %s", keyname,
766 keytitle, nextsource->
GetName());
767 nextsource = (
TFile *)sourcelist->
After(nextsource);
770 Warning(
"MergeRecursive",
"could not read object for key {%s, %s}; skipping file %s",
771 keyname, keytitle, nextsource->
GetName());
772 nextsource = (
TFile *)sourcelist->
After(nextsource);
786 Error(
"MergeRecursive",
"calling Merge() on '%s' with the corresponding object in '%s'",
792 nextsource = (
TFile*)sourcelist->
After( nextsource );
814 oldkeyname = keyname;
819 auto dirobj =
dynamic_cast<TDirectory *
>(obj);
820 TString dirpath(dirobj->GetPath());
822 dirpath.
Remove(0, std::strlen(dirobj->GetFile()->GetPath()));
828 if (ownobj && (!(type &
kIncremental) || dirobj->GetFile() != target)) {
835 for (
const auto &[
_, ndir] : dirtodelete) {
841 }
else if (!canBeFound) {
843 Info(
"MergeOne",
"Writing partial result of %s into target", oldkeyname.
Data());
845 TIter peeknextkey(nextkey);
846 status = WriteCycleInOrder(oldkeyname, nextkey, peeknextkey, target) && status;
847 status = WriteOneAndDelete(oldkeyname, cl, obj,
kFALSE, ownobj, target) && status;
849 status = WriteOneAndDelete(oldkeyname, cl, obj,
kTRUE, ownobj, target) && status;
882 allNames.
Add(arr->
At(iname));
899 current_sourcedir = target;
904 while (current_file || current_sourcedir) {
907 if (current_sourcedir && (current_file == 0 || current_sourcedir != target)) {
913 while ( (obj = (
TKey*)nextobj())) {
914 auto result =
MergeOne(target, sourcelist, type,
915 info, oldkeyname, allNames, status, onlyListed, path,
916 current_sourcedir, current_file,
917 nullptr, obj, nextobj);
926 while ( (key = (
TKey*)nextkey())) {
927 auto result =
MergeOne(target, sourcelist, type,
928 info, oldkeyname, allNames, status, onlyListed, path,
929 current_sourcedir, current_file,
930 key,
nullptr, nextkey);
935 current_file = current_file ? (
TFile*)sourcelist->
After(current_file) : (
TFile*)sourcelist->
First();
939 current_sourcedir = 0;
976 outf.
Form(
"file:%s/FileMerger.root",
gSystem->TempDirectory());
977 Info(
"PartialMerge",
"will merge the results to the file %s\n"
978 "since you didn't specify a merge filename",
979 TUrl(outf).GetFile());
993 if (!file || (file && file->
IsZombie())) {
994 Error(
"PartialMerge",
"one-file case: problem attaching to file");
999 Error(
"PartialMerge",
"one-file case: could not copy '%s' to '%s'",
1009 Warning(
"PartialMerge",
"problems removing temporary local file '%s'", u.
GetFile());
1021 Int_t type = in_type;
1022 while (result &&
fFileList.GetEntries()>0) {
1028 while ((file = (
TFile*) next())) {
1035 p = p(0, p.
Index(
':',0));
1050 Error(
"Merge",
"error during merge of your ROOT files");
1104 Error(
"OpenExcessFiles",
"cannot get a local copy of file %s", url->
GetName());
1114 Error(
"OpenExcessFiles",
"cannot open local copy %s of URL %s",
1117 Error(
"OpenExcessFiles",
"cannot open file %s", url->
GetName());
1137 Fatal(
"RecursiveRemove",
"Output file of the TFile Merger (targeting %s) has been deleted (likely due to a TTree larger than 100Gb)",
fOutputFilename.Data());
1152 if (newmax < sysmax) {
int Int_t
Signed integer 4 bytes (int).
bool Bool_t
Boolean (0=false, 1=true) (bool).
long long Long64_t
Portable signed long integer 8 bytes.
const char Option_t
Option string (const char).
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
TClassRef R__TH1_Class("TH1")
static const Int_t kClingFileNumber
static Int_t R__GetSystemMaxOpenedFiles()
Return the maximum number of allowed opened files minus some wiggle room for Cling or at least of the...
TClassRef R__RNTuple_Class("ROOT::RNTuple")
TClassRef R__TTree_Class("TTree")
static const Int_t kCpProgress
externTVirtualMutex * gROOTMutex
void Printf(const char *fmt,...)
Formats a string in a circular formatting buffer and prints the string.
#define R__LOCKGUARD(mutex)
TClassRef is used to implement a permanent reference to a TClass object.
TClass instances represent classes, structs and namespaces in the ROOT type system.
TMethod * GetMethodWithPrototype(const char *method, const char *proto, Bool_t objectIsConst=kFALSE, ROOT::EFunctionMatchMode mode=ROOT::kConversionMatch)
Find the method with a given prototype.
void Destructor(void *obj, Bool_t dtorOnly=kFALSE)
Explicitly call destructor for object.
ROOT::ResetAfterMergeFunc_t GetResetAfterMerge() const
Return the wrapper around Merge.
Bool_t IsLoaded() const
Return true if the shared library of this class is currently in the a process's memory.
Bool_t IsTObject() const
Return kTRUE is the class inherits from TObject.
Bool_t InheritsFrom(const char *cl) const override
Return kTRUE if this class inherits from a class with name "classname".
ROOT::MergeFunc_t GetMerge() const
Return the wrapper around Merge.
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.
Collection abstract base class.
virtual void SetOwner(Bool_t enable=kTRUE)
Set whether this collection is the owner (enable==true) of its content.
virtual Int_t GetSize() const
Return the capacity of the collection, i.e.
TDirectory * GetDirectory(const char *apath, Bool_t printError=false, const char *funcname="GetDirectory") override
Find a directory using apath.
TDirectory::TContext keeps track and restore the current directory.
Describe directory structure in memory.
virtual TList * GetList() const
virtual TDirectory * GetDirectory(const char *namecycle, Bool_t printError=false, const char *funcname="GetDirectory")
Find a directory using apath.
virtual Int_t GetNkeys() const
virtual const char * GetPath() const
Returns the full path of the directory.
virtual void rmdir(const char *name)
Removes subdirectory from the directory When directory is deleted, all keys in all subdirectories wil...
virtual Int_t WriteObjectAny(const void *, const char *, const char *, Option_t *="", Int_t=0)
virtual TFile * GetFile() const
virtual Bool_t cd()
Change current directory to "this" directory.
virtual void SaveSelf(Bool_t=kFALSE)
virtual TDirectory * mkdir(const char *name, const char *title="", Bool_t returnExistingDirectory=kFALSE)
Create a sub-directory "a" or a hierarchy of sub-directories "a/b/c/...".
virtual TList * GetListOfKeys() const
A class to pass information from the TFileMerger to the objects being merged.
TIOFeatures * fIOFeatures
Any ROOT IO features that should be explicitly enabled.
Bool_t fIsFirst
True if this is the first call to Merge for this series of object.
TString fOptions
Additional text based option being passed down to customize the merge.
TString fObjectNames
List of object names to be either merged exclusively or skipped.
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
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).
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.
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.
TString fMsgPrefix
Prefix to be used when printing informational message (default TFileMerger).
TIOFeatures * fIOFeatures
IO features to use in the output file.
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).
bool fOutFileWasExplicitlyClosed
! the user has called CloseOutputFile(), so we shouldn't error out in RecursiveRemove
@ kAll
Merge all type of objects (default).
@ kIncremental
Merge the input file with the content of the output file (if already existing).
@ kKeepCompression
Keep compression level unchanged for each input files.
@ kSkipListed
Skip objects specified in fObjectNames list.
@ kNonResetable
Only the objects without a MergeAfterReset member function.
@ kResetable
Only the objects with a MergeAfterReset member function.
@ kOnlyListed
Only the objects specified in fObjectNames list.
@ kRegular
Normal merge, overwriting the output file.
@ kDelayWrite
Delay the TFile write (to reduce the number of write when reusing the file).
Bool_t fExplicitCompLevel
True if the user explicitly requested a compression level change (default kFALSE).
Bool_t fCompressionChange
True if the output and input have different compression level (default kFALSE).
EErrorBehavior fErrBehavior
What to do in case of errors during merging.
Int_t fPrintLevel
How much information to print out at run time.
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.
void CloseOutputFile()
Closes output file.
~TFileMerger() override
Cleanup.
@ kFailOnError
The merging process will stop and yield failure when encountering invalid objects.
@ kSkipOnError
The merging process will skip invalid objects and continue.
Bool_t OpenExcessFiles()
Open up to (fMaxOpenedFiles-1) of the excess files.
TList fExcessFiles
! List of TObjString containing the name of the files not yet added to fFileList due to user or syste...
TFile * fOutputFile
The outputfile for merging.
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).
virtual void Reset()
Reset merger file list.
Int_t fMaxOpenedFiles
Maximum number of files opened at the same time by the TFileMerger.
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).
A file, usually with extension .root, that stores data and code in the form of serialized objects in ...
Int_t GetCompressionSettings() const
virtual Bool_t Cp(const char *dst, Bool_t progressbar=kTRUE, UInt_t bufsize=1000000)
Allows to copy this file to the dst URL.
Int_t GetCompressionLevel() const
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.
void Close(Option_t *option="") override
Close a file.
@ kCancelTTreeChangeRequest
THashList implements a hybrid collection class consisting of a hash table and a list to store TObject...
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.
const char * GetTitle() const override
Returns title (title can contain 32x32 xpm thumbnail/icon).
virtual const char * GetClassName() const
virtual TObject * ReadObj()
To read a TObject* from the file.
TObject * After(const TObject *obj) const override
Returns the object after object obj.
void Clear(Option_t *option="") override
Remove all objects from the list.
TObject * FindObject(const char *name) const override
Find an object in this list using its name.
void Add(TObject *obj) override
TObject * First() const override
Return the first object in the list. Returns 0 when list is empty.
void Delete(Option_t *option="") override
Remove all objects from the list AND delete all heap based objects.
const char * GetName() const override
Returns name of object.
Int_t GetEntriesFast() const
TObject * At(Int_t idx) const override
Collectable string class.
const char * GetName() const override
Returns name of object.
Mother of all ROOT objects.
virtual void Clear(Option_t *="")
Bool_t TestBit(UInt_t f) const
virtual const char * GetName() const
Returns name of object.
virtual TObject * Clone(const char *newname="") const
Make a clone of an object using the Streamer facility.
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
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.
virtual Int_t Write(const char *name=nullptr, Int_t option=0, Int_t bufsize=0)
Write this object to the current directory.
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
virtual void Fatal(const char *method, const char *msgfmt,...) const
Issue fatal error message.
virtual const char * GetTitle() const
Returns title of object.
virtual TClass * IsA() const
@ kOverwrite
overwrite existing object with same name
@ kSingleKey
write collection with single key
TObject()
TObject constructor.
@ kCanDelete
if object in a list can be deleted
@ kMustCleanup
if object destructor must call RecursiveRemove()
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
const char * Data() const
TString & Remove(Ssiz_t pos)
TString & Append(const char *cs)
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
This class defines a UUID (Universally Unique IDentifier), also known as GUIDs (Globally Unique IDent...
const char * AsString() const
Return UUID as string. Copy string immediately since it will be reused.
This class represents a WWW compatible URL.
const char * GetFile() const
Long64_t(* MergeFunc_t)(void *, TCollection *, TFileMergeInfo *)