diff --git a/io/io/inc/LinkDef.h b/io/io/inc/LinkDef.h index 6aed5e56af922057d07ed486c9bd3a4e4f237091..121994e34c18d52ac7d5b0b8265a4de871c0d8f3 100644 --- a/io/io/inc/LinkDef.h +++ b/io/io/inc/LinkDef.h @@ -21,6 +21,7 @@ #pragma link C++ class TFile-; #pragma link C++ class TFileCacheRead+; #pragma link C++ class TFileCacheWrite+; +#pragma link C++ class TFileMerger+; #pragma link C++ class TFree; #pragma link C++ class TKey-; #pragma link C++ class TKeyMapFile; diff --git a/proof/proofplayer/inc/TFileMerger.h b/io/io/inc/TFileMerger.h similarity index 100% rename from proof/proofplayer/inc/TFileMerger.h rename to io/io/inc/TFileMerger.h diff --git a/proof/proofplayer/src/TFileMerger.cxx b/io/io/src/TFileMerger.cxx similarity index 98% rename from proof/proofplayer/src/TFileMerger.cxx rename to io/io/src/TFileMerger.cxx index f16b1b7118c90f3c5dc6a5483c12419569ed1f16..99329514084f8151283a74eb3de28b90d1223b27 100644 --- a/proof/proofplayer/src/TFileMerger.cxx +++ b/io/io/src/TFileMerger.cxx @@ -222,9 +222,12 @@ Bool_t TFileMerger::MergeRecursive(TDirectory *target, TList *sourcelist) path.Remove(0, path.Last(':') + 2); // Gain time, do not add the objects in the list in memory. - Bool_t addDirStat = gROOT->ProcessLineFast("TH1::AddDirectoryStatus()"); - gROOT->ProcessLine("TH1::AddDirectory(kFALSE);"); - + Bool_t addDirStat = kTRUE; + if (R__TH1_Class) { + gROOT->ProcessLineFast("TH1::AddDirectoryStatus()"); + gROOT->ProcessLine("TH1::AddDirectory(kFALSE);"); + } + TDirectory *first_source = (TDirectory*)sourcelist->First(); Int_t nguess = sourcelist->GetSize()+1000; @@ -485,6 +488,8 @@ Bool_t TFileMerger::MergeRecursive(TDirectory *target, TList *sourcelist) } // save modifications to target file target->SaveSelf(kTRUE); - gROOT->ProcessLine(TString::Format("TH1::AddDirectory(%d);",addDirStat)); + if (R__TH1_Class) { + gROOT->ProcessLine(TString::Format("TH1::AddDirectory(%d);",addDirStat)); + } return status; } diff --git a/main/src/hadd.cxx b/main/src/hadd.cxx index 4a36fcc818056f72b0100fb4ff0a012d6de5769e..93e39f02537bcc0c1ab4e568ed33c203bf6bac15 100644 --- a/main/src/hadd.cxx +++ b/main/src/hadd.cxx @@ -61,11 +61,8 @@ #include "RConfig.h" #include <string> -#include "TChain.h" #include "TFile.h" #include "THashList.h" -#include "TH1.h" -#include "THStack.h" #include "TKey.h" #include "TObjString.h" #include "Riostream.h" @@ -73,6 +70,8 @@ #include "TSystem.h" #include <stdlib.h> +#include "TFileMerger.h" + TList *FileList; TFile *Target, *Source; Bool_t noTrees; @@ -143,23 +142,30 @@ int main( int argc, char **argv ) cout << "Target file: " << argv[ffirst-1] << endl; - Target = TFile::Open( argv[ffirst-1], (force?"RECREATE":"CREATE") ); - if (!Target || Target->IsZombie()) { + TFileMerger merger(kFALSE,kFALSE); + merger.SetPrintLevel(99); + if (!merger.OutputFile(argv[ffirst-1],force,newcomp) ) { cerr << "Error opening target file (does " << argv[ffirst-1] << " exist?)." << endl; cerr << "Pass \"-f\" argument to force re-creation of output file." << endl; exit(1); } - Target->SetCompressionLevel(newcomp); - - // by default hadd can merge Trees in a file that can go up to 100 Gbytes - // No need to set this, as 100Gb is now the TTree default - // Long64_t maxsize = 100000000; //100GB - // maxsize *= 1000; //to bypass some compiler limitations with big constants - // TTree::SetMaxTreeSize(maxsize); fastMethod = kTRUE; for ( int i = ffirst; i < argc; i++ ) { - if( AddFile(FileList, argv[i], newcomp) !=0 ) { + if (argv[i] && argv[i][0]=='@') { + std::ifstream indirect_file(argv[i]+1); + if( ! indirect_file.is_open() ) { + std::cerr<< "Could not open indirect file " << (argv[i]+1) << std::endl; + return 1; + } + while( indirect_file ){ + std::string line; + std::getline(indirect_file, line); + if( !merger.AddFile(line.c_str()) ) { + return 1; + } + } + } else if( ! merger.AddFile(argv[i]) ) { if ( skip_errors ) { cerr << "Skipping file with error: " << argv[i] << endl; } else { @@ -168,257 +174,20 @@ int main( int argc, char **argv ) } } } - if (!fastMethod && !reoptimize) { + if (merger.HasCompressionChange() && !reoptimize) { // Don't warn if the user any request re-optimization. cout <<"Sources and Target have different compression levels"<<endl; cout <<"Merging will be slower"<<endl; } - int status = MergeRootfile( Target, FileList); + Bool_t status = merger.Merge(); //must delete Target to avoid a problem with dictionaries in~ TROOT delete Target; - return status; -} - -//___________________________________________________________________________ -int AddFile(TList* sourcelist, std::string entry, int newcomp) -{ - // add a new file to the list of files - static int count(0); - if( entry.empty() ) return 0; - size_t j =entry.find_first_not_of(' '); - if( j==std::string::npos ) return 0; - entry = entry.substr(j); - if( entry.substr(0,1)=="@"){ - std::ifstream indirect_file(entry.substr(1).c_str() ); - if( ! indirect_file.is_open() ) { - std::cerr<< "Could not open indirect file " << entry.substr(1) << std::endl; - return 1; - } - while( indirect_file ){ - std::string line; - std::getline(indirect_file, line); - if( AddFile(sourcelist, line, newcomp)!=0 )return 1;; - } + if (status) { return 0; - } - cout << "Source file " << (++count) << ": " << entry << endl; - - TFile* source = TFile::Open( entry.c_str()); - if( source==0 ){ - cerr << "Could not open file " << entry << endl; - return 1; - } else if ( source->IsZombie() ) { - cerr << "Could not properly read file " << entry << endl; + } else { return 1; } - sourcelist->Add(source); - if (newcomp != source->GetCompressionLevel()) fastMethod = kFALSE; - return 0; -} - - -//___________________________________________________________________________ -int MergeRootfile( TDirectory *target, TList *sourcelist) -{ - // Merge all objects in a directory - int status = 0; - cout << "Target path: " << target->GetPath() << endl; - TString path( (char*)strstr( target->GetPath(), ":" ) ); - path.Remove( 0, 2 ); - - TDirectory *first_source = (TDirectory*)sourcelist->First(); - Int_t nguess = sourcelist->GetSize()+1000; - THashList allNames(nguess); - ((THashList*)target->GetList())->Rehash(nguess); - ((THashList*)target->GetListOfKeys())->Rehash(nguess); - TList listH; - TString listHargs; - listHargs.Form("((TCollection*)0x%lx)", (ULong_t)&listH); - while(first_source) { - TDirectory *current_sourcedir = first_source->GetDirectory(path); - if (!current_sourcedir) { - first_source = (TDirectory*)sourcelist->After(first_source); - continue; - } - - // loop over all keys in this directory - TChain *globChain = 0; - TIter nextkey( current_sourcedir->GetListOfKeys() ); - TKey *key, *oldkey=0; - //gain time, do not add the objects in the list in memory - TH1::AddDirectory(kFALSE); - - while ( (key = (TKey*)nextkey())) { - if (current_sourcedir == target) break; - //keep only the highest cycle number for each key - if (oldkey && !strcmp(oldkey->GetName(),key->GetName())) continue; - if (!strcmp(key->GetClassName(),"TProcessID")) {key->ReadObj(); continue;} - if (allNames.FindObject(key->GetName())) continue; - TClass *cl = TClass::GetClass(key->GetClassName()); - if (!cl || !cl->InheritsFrom(TObject::Class())) { - cout << "Cannot merge object type, name: " - << key->GetName() << " title: " << key->GetTitle() << endl; - continue; - } - allNames.Add(new TObjString(key->GetName())); - // read object from first source file - //current_sourcedir->cd(); - TObject *obj = key->ReadObj(); - //printf("keyname=%s, obj=%x\n",key->GetName(),obj); - - if ( obj->IsA()->InheritsFrom( TTree::Class() ) ) { - - // loop over all source files create a chain of Trees "globChain" - if (!noTrees) { - TString obj_name; - if (path.Length()) { - obj_name = path + "/" + obj->GetName(); - } else { - obj_name = obj->GetName(); - } - globChain = new TChain(obj_name); - globChain->Add(first_source->GetName()); - TFile *nextsource = (TFile*)sourcelist->After( first_source ); - while ( nextsource ) { - //do not add to the list a file that does not contain this Tree - TFile *curf = TFile::Open(nextsource->GetName()); - if (curf) { - Bool_t mustAdd = kFALSE; - if (curf->FindKey(obj_name)) { - mustAdd = kTRUE; - } else { - //we could be more clever here. No need to import the object - //we are missing a function in TDirectory - TObject *aobj = curf->Get(obj_name); - if (aobj) { mustAdd = kTRUE; delete aobj;} - } - if (mustAdd) { - globChain->Add(nextsource->GetName()); - } - } - delete curf; - nextsource = (TFile*)sourcelist->After( nextsource ); - } - } - } else if ( obj->IsA()->InheritsFrom( TDirectory::Class() ) ) { - // it's a subdirectory - - cout << "Found subdirectory " << obj->GetName() << endl; - // create a new subdir of same name and title in the target file - target->cd(); - TDirectory *newdir = target->mkdir( obj->GetName(), obj->GetTitle() ); - - // newdir is now the starting point of another round of merging - // newdir still knows its depth within the target file via - // GetPath(), so we can still figure out where we are in the recursion - status = MergeRootfile( newdir, sourcelist); - if (status) return status; - - } else if ( obj->InheritsFrom(TObject::Class()) - && obj->IsA()->GetMethodWithPrototype("Merge", "TCollection*") ) { - // object implements Merge(TCollection*) - - // loop over all source files and merge same-name object - TFile *nextsource = (TFile*)sourcelist->After( first_source ); - while ( nextsource ) { - // make sure we are at the correct directory level by cd'ing to path - TDirectory *ndir = nextsource->GetDirectory(path); - if (ndir) { - ndir->cd(); - TKey *key2 = (TKey*)gDirectory->GetListOfKeys()->FindObject(key->GetName()); - if (key2) { - TObject *hobj = key2->ReadObj(); - hobj->ResetBit(kMustCleanup); - listH.Add(hobj); - Int_t error = 0; - obj->Execute("Merge", listHargs.Data(), &error); - if (error) { - cerr << "Error calling Merge() on " << obj->GetName() - << " with the corresponding object in " << nextsource->GetName() << endl; - } - listH.Delete(); - } - } - nextsource = (TFile*)sourcelist->After( nextsource ); - } - } else if ( obj->IsA()->InheritsFrom( THStack::Class() ) ) { - THStack *hstack1 = (THStack*) obj; - TList* l = new TList(); - - // loop over all source files and merge the histos of the - // corresponding THStacks with the one pointed to by "hstack1" - TFile *nextsource = (TFile*)sourcelist->After( first_source ); - while ( nextsource ) { - // make sure we are at the correct directory level by cd'ing to path - TDirectory *ndir = nextsource->GetDirectory(path); - if (ndir) { - ndir->cd(); - TKey *key2 = (TKey*)gDirectory->GetListOfKeys()->FindObject(hstack1->GetName()); - if (key2) { - THStack *hstack2 = (THStack*) key2->ReadObj(); - l->Add(hstack2->GetHists()->Clone()); - delete hstack2; - } - } - - nextsource = (TFile*)sourcelist->After( nextsource ); - } - hstack1->GetHists()->Merge(l); - l->Delete(); - } else { - // object is of no type that we can merge - cout << "Cannot merge object type, name: " - << obj->GetName() << " title: " << obj->GetTitle() << endl; - - // loop over all source files and write similar objects directly to the output file - TFile *nextsource = (TFile*)sourcelist->After( first_source ); - while ( nextsource ) { - // make sure we are at the correct directory level by cd'ing to path - TDirectory *ndir = nextsource->GetDirectory(path); - if (ndir) { - ndir->cd(); - TKey *key2 = (TKey*)gDirectory->GetListOfKeys()->FindObject(key->GetName()); - if (key2) { - TObject *nobj = key2->ReadObj(); - nobj->ResetBit(kMustCleanup); - int nbytes1 = target->WriteTObject(nobj, key2->GetName(), "SingleKey" ); - if (nbytes1 <= 0) status = -1; - delete nobj; - } - } - nextsource = (TFile*)sourcelist->After( nextsource ); - } - } - - // now write the merged histogram (which is "in" obj) to the target file - // note that this will just store obj in the current directory level, - // which is not persistent until the complete directory itself is stored - // by "target->Write()" below - target->cd(); - - //!!if the object is a tree, it is stored in globChain... - if(obj->IsA()->InheritsFrom( TDirectory::Class() )) { - //printf("cas d'une directory\n"); - } else if(obj->IsA()->InheritsFrom( TTree::Class() )) { - if (!noTrees) { - globChain->ls("noaddr"); - if (fastMethod && !reoptimize) globChain->Merge(target->GetFile(),0,"keep fast"); - else globChain->Merge(target->GetFile(),0,"keep"); - delete globChain; - } - } else { - int nbytes2 = obj->Write( key->GetName(), TObject::kSingleKey ); - if (nbytes2 <= 0) status = -1; - } - oldkey = key; - delete obj; - } // while ( ( TKey *key = (TKey*)nextkey() ) ) - first_source = (TDirectory*)sourcelist->After(first_source); - } - // save modifications to target file - target->SaveSelf(kTRUE); - return status; } diff --git a/proof/proofplayer/inc/LinkDef.h b/proof/proofplayer/inc/LinkDef.h index 369e5f9d7d1d8328acaf3f68d9d6d812e023bb5b..03fae20f07f72a30f144a665d939b581ca7541c2 100644 --- a/proof/proofplayer/inc/LinkDef.h +++ b/proof/proofplayer/inc/LinkDef.h @@ -42,7 +42,6 @@ #pragma link C++ class TProofLimitsFinder; #pragma link C++ class TDrawFeedback+; #pragma link C++ class TStatus+; -#pragma link C++ class TFileMerger+; #pragma link C++ class TProofOutputFile+; #pragma link C++ class TOutputListSelectorDataMap+;