00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "TFileMerger.h"
00028 #include "TUrl.h"
00029 #include "TFile.h"
00030 #include "TUUID.h"
00031 #include "TSystem.h"
00032 #include "TH1.h"
00033 #include "THStack.h"
00034 #include "TChain.h"
00035 #include "TKey.h"
00036 #include "THashList.h"
00037 #include "TObjString.h"
00038 #include "TClass.h"
00039 #include "TMethodCall.h"
00040 #include "Riostream.h"
00041
00042
00043 ClassImp(TFileMerger)
00044
00045
00046 TFileMerger::TFileMerger(Bool_t isLocal, Bool_t histoOneGo)
00047 : fOutputFile(0), fFastMethod(kTRUE), fNoTrees(kFALSE),
00048 fLocal(isLocal), fHistoOneGo(histoOneGo)
00049 {
00050
00051
00052 fFileList = new TList;
00053 fFileList->SetOwner(kTRUE);
00054
00055 fMergeList = new TList;
00056 fMergeList->SetOwner(kTRUE);
00057 }
00058
00059
00060 TFileMerger::~TFileMerger()
00061 {
00062
00063
00064 SafeDelete(fFileList);
00065 SafeDelete(fMergeList);
00066 SafeDelete(fOutputFile);
00067 }
00068
00069
00070 void TFileMerger::Reset()
00071 {
00072
00073
00074 fFileList->Clear();
00075 fMergeList->Clear();
00076 }
00077
00078
00079 Bool_t TFileMerger::AddFile(const char *url, Bool_t cpProgress)
00080 {
00081
00082
00083 TFile *newfile = 0;
00084 TString localcopy;
00085
00086 if (fLocal) {
00087 TUUID uuid;
00088 localcopy.Form("file:%s/ROOTMERGE-%s.root", gSystem->TempDirectory(), uuid.AsString());
00089 if (!TFile::Cp(url, localcopy, cpProgress)) {
00090 Error("AddFile", "cannot get a local copy of file %s", url);
00091 return kFALSE;
00092 }
00093 newfile = TFile::Open(localcopy, "READ");
00094 } else {
00095 newfile = TFile::Open(url, "READ");
00096 }
00097
00098 if (!newfile) {
00099 if (fLocal)
00100 Error("AddFile", "cannot open local copy %s of URL %s",
00101 localcopy.Data(), url);
00102 else
00103 Error("AddFile", "cannot open file %s", url);
00104 return kFALSE;
00105 } else {
00106 fFileList->Add(newfile);
00107
00108 if (!fMergeList)
00109 fMergeList = new TList;
00110 TObjString *urlObj = new TObjString(url);
00111 fMergeList->Add(urlObj);
00112
00113 return kTRUE;
00114 }
00115 }
00116
00117
00118 Bool_t TFileMerger::OutputFile(const char *outputfile)
00119 {
00120
00121
00122 SafeDelete(fOutputFile);
00123
00124 fOutputFilename = outputfile;
00125
00126 if (!(fOutputFile = TFile::Open(outputfile, "RECREATE"))) {
00127 Error("OutputFile", "cannot open the MERGER output file %s", fOutputFilename.Data());
00128 return kFALSE;
00129 }
00130 return kTRUE;
00131 }
00132
00133
00134 void TFileMerger::PrintFiles(Option_t *options)
00135 {
00136
00137
00138 fFileList->Print(options);
00139 }
00140
00141
00142 Bool_t TFileMerger::Merge(Bool_t)
00143 {
00144
00145
00146
00147
00148 if (!fOutputFile) {
00149 TString outf(fOutputFilename);
00150 if (outf.IsNull()) {
00151 outf.Form("file:%s/FileMerger.root", gSystem->TempDirectory());
00152 Info("Merge", "will merge the results to the file %s\n"
00153 "since you didn't specify a merge filename",
00154 TUrl(outf).GetFile());
00155 }
00156 if (!OutputFile(outf.Data())) {
00157 return kFALSE;
00158 }
00159 }
00160
00161 Bool_t result = MergeRecursive(fOutputFile, fFileList);
00162 if (!result) {
00163 Error("Merge", "error during merge of your ROOT files");
00164 } else {
00165
00166 fOutputFile->Close();
00167 }
00168
00169
00170 SafeDelete(fOutputFile);
00171
00172
00173 TIter next(fFileList);
00174 TFile *file;
00175 while ((file = (TFile*) next())) {
00176
00177 file->Close();
00178
00179 if(fLocal) {
00180 TString p(file->GetPath());
00181 p = p(0, p.Index(':',0));
00182 gSystem->Unlink(p);
00183 }
00184 }
00185 return result;
00186 }
00187
00188
00189 Bool_t TFileMerger::MergeRecursive(TDirectory *target, TList *sourcelist)
00190 {
00191
00192
00193
00194
00195 TString path(target->GetPath());
00196 path.Remove(0, path.Last(':') + 2);
00197
00198
00199 Bool_t addDirStat = TH1::AddDirectoryStatus();
00200 TH1::AddDirectory(kFALSE);
00201
00202 TDirectory *first_source = (TDirectory*)sourcelist->First();
00203
00204 Int_t nguess = sourcelist->GetSize()+1000;
00205 THashList allNames(nguess);
00206 ((THashList*)target->GetList())->Rehash(nguess);
00207 ((THashList*)target->GetListOfKeys())->Rehash(nguess);
00208
00209 while (first_source) {
00210 TDirectory *current_sourcedir = first_source->GetDirectory(path);
00211 if (!current_sourcedir) {
00212 first_source = (TDirectory*)sourcelist->After(first_source);
00213 continue;
00214 }
00215
00216
00217 TChain *globChain = 0;
00218 TIter nextkey( current_sourcedir->GetListOfKeys() );
00219 TKey *key, *oldkey=0;
00220
00221 while ( (key = (TKey*)nextkey())) {
00222 if (current_sourcedir == target) break;
00223
00224 if (oldkey && !strcmp(oldkey->GetName(),key->GetName())) continue;
00225 if (!strcmp(key->GetClassName(),"TProcessID")) {key->ReadObj(); continue;}
00226 if (allNames.FindObject(key->GetName())) continue;
00227 TClass *cl = TClass::GetClass(key->GetClassName());
00228 if (!cl || !cl->InheritsFrom(TObject::Class())) {
00229 Info("MergeRecursive", "cannot merge object type, name: %s title: %s",
00230 key->GetName(), key->GetTitle());
00231 continue;
00232 }
00233 allNames.Add(new TObjString(key->GetName()));
00234
00235
00236 current_sourcedir->cd();
00237 TObject *obj = key->ReadObj();
00238 if (!obj) {
00239 Info("MergeRecursive", "could not read object for key {%s, %s}",
00240 key->GetName(), key->GetTitle());
00241 continue;
00242 }
00243
00244 if (obj->IsA()->InheritsFrom(TH1::Class())) {
00245
00246
00247 TH1 *h1 = (TH1*)obj;
00248 TList listH;
00249
00250
00251
00252 TFile *nextsource = (TFile*)sourcelist->After( first_source );
00253 while ( nextsource ) {
00254
00255 TDirectory *ndir = nextsource->GetDirectory(path);
00256 if (ndir) {
00257 ndir->cd();
00258 TKey *key2 = (TKey*)gDirectory->GetListOfKeys()->FindObject(key->GetName());
00259 if (key2) {
00260 TObject *hobj = key2->ReadObj();
00261 hobj->ResetBit(kMustCleanup);
00262 listH.Add(hobj);
00263
00264 if (!fHistoOneGo) {
00265 h1->Merge(&listH);
00266 listH.Delete();
00267 }
00268 }
00269 }
00270 nextsource = (TFile*)sourcelist->After( nextsource );
00271 }
00272
00273 if (fHistoOneGo) {
00274 h1->Merge(&listH);
00275 listH.Delete();
00276 }
00277 } else if ( obj->IsA()->InheritsFrom( TTree::Class() ) ) {
00278
00279
00280 if (!fNoTrees) {
00281 TString obj_name;
00282 if (path.Length()) {
00283 obj_name = path + "/" + obj->GetName();
00284 } else {
00285 obj_name = obj->GetName();
00286 }
00287 globChain = new TChain(obj_name);
00288 globChain->Add(first_source->GetName());
00289 TFile *nextsource = (TFile*)sourcelist->After( first_source );
00290 while ( nextsource ) {
00291
00292 TFile *curf = TFile::Open(nextsource->GetName());
00293 if (curf) {
00294 Bool_t mustAdd = kFALSE;
00295 if (curf->FindKey(obj_name)) {
00296 mustAdd = kTRUE;
00297 } else {
00298
00299
00300 TObject *aobj = curf->Get(obj_name);
00301 if (aobj) { mustAdd = kTRUE; delete aobj;}
00302 }
00303 if (mustAdd) {
00304 globChain->Add(nextsource->GetName());
00305 }
00306 }
00307 delete curf;
00308 nextsource = (TFile*)sourcelist->After( nextsource );
00309 }
00310 }
00311 } else if ( obj->IsA()->InheritsFrom( TDirectory::Class() ) ) {
00312
00313
00314
00315
00316 target->cd();
00317 TDirectory *newdir = target->mkdir( obj->GetName(), obj->GetTitle() );
00318
00319
00320
00321
00322 MergeRecursive( newdir, sourcelist);
00323
00324 } else if (obj->InheritsFrom(TObject::Class()) &&
00325 obj->IsA()->GetMethodWithPrototype("Merge", "TCollection*") ) {
00326
00327
00328 TList listH;
00329 TString listHargs;
00330 listHargs.Form("((TCollection*)0x%lx)", (ULong_t)&listH);
00331
00332
00333 TFile *nextsource = (TFile*)sourcelist->After( first_source );
00334 while (nextsource) {
00335
00336 TDirectory *ndir = nextsource->GetDirectory(path);
00337 if (ndir) {
00338 ndir->cd();
00339 TKey *key2 = (TKey*)gDirectory->GetListOfKeys()->FindObject(key->GetName());
00340 if (key2) {
00341 TObject *hobj = key2->ReadObj();
00342
00343 if (hobj->InheritsFrom(TCollection::Class())) {
00344 ((TCollection*)hobj)->SetOwner();
00345 }
00346 hobj->ResetBit(kMustCleanup);
00347 listH.Add(hobj);
00348 Int_t error = 0;
00349 obj->Execute("Merge", listHargs.Data(), &error);
00350 if (error) {
00351 Error("MergeRecursive", "calling Merge() on '%s' with the corresponding object in '%s'",
00352 obj->GetName(), nextsource->GetName());
00353 }
00354 listH.Delete();
00355 }
00356 }
00357 nextsource = (TFile*)sourcelist->After( nextsource );
00358 }
00359 } else if ( obj->IsA()->InheritsFrom( THStack::Class() ) ) {
00360 THStack *hstack1 = (THStack*) obj;
00361 TList* l = new TList();
00362
00363
00364
00365 TFile *nextsource = (TFile*)sourcelist->After( first_source );
00366 while ( nextsource ) {
00367
00368 TDirectory *ndir = nextsource->GetDirectory(path);
00369 if (ndir) {
00370 ndir->cd();
00371 TKey *key2 = (TKey*)gDirectory->GetListOfKeys()->FindObject(hstack1->GetName());
00372 if (key2) {
00373 THStack *hstack2 = (THStack*) key2->ReadObj();
00374 l->Add(hstack2->GetHists()->Clone());
00375 delete hstack2;
00376 }
00377 }
00378
00379 nextsource = (TFile*)sourcelist->After( nextsource );
00380 }
00381 hstack1->GetHists()->Merge(l);
00382 l->Delete();
00383 } else {
00384
00385 Warning("MergeRecursive", "cannot merge object type (n:'%s', t:'%s') - "
00386 "Merge(TCollection *) not implemented",
00387 obj->GetName(), obj->GetTitle());
00388
00389
00390 TFile *nextsource = (TFile*)sourcelist->After( first_source );
00391 while (nextsource) {
00392
00393 TDirectory *ndir = nextsource->GetDirectory(path);
00394 if (ndir) {
00395 ndir->cd();
00396 TKey *key2 = (TKey*)gDirectory->GetListOfKeys()->FindObject(key->GetName());
00397 if (key2) {
00398 TObject *nobj = key2->ReadObj();
00399 nobj->ResetBit(kMustCleanup);
00400 if (target->WriteTObject(nobj, key2->GetName(), "SingleKey") <= 0) {
00401 Warning("MergeRecursive", "problems copying object (n:'%s', t:'%s') to output file ",
00402 obj->GetName(), obj->GetTitle());
00403 }
00404 delete nobj;
00405 }
00406 }
00407 nextsource = (TFile*)sourcelist->After( nextsource );
00408 }
00409 }
00410
00411
00412
00413
00414
00415 target->cd();
00416
00417
00418 if(obj->IsA()->InheritsFrom( TDirectory::Class() )) {
00419
00420 } else if(obj->IsA()->InheritsFrom( TTree::Class() )) {
00421 if (!fNoTrees) {
00422 if (globChain) {
00423 globChain->ls();
00424 if (fFastMethod) globChain->Merge(target->GetFile(),0,"keep fast");
00425 else globChain->Merge(target->GetFile(),0,"keep");
00426 delete globChain;
00427 }
00428 }
00429 } else if (obj->IsA()->InheritsFrom( TCollection::Class() )) {
00430 obj->Write( key->GetName(), TObject::kSingleKey );
00431 ((TCollection*)obj)->SetOwner();
00432 } else {
00433 obj->Write( key->GetName() );
00434 }
00435 if (obj->IsA()->InheritsFrom(TCollection::Class())) ((TCollection*)obj)->Delete();
00436 oldkey = key;
00437 delete obj;
00438 }
00439 first_source = (TDirectory*)sourcelist->After(first_source);
00440 }
00441
00442 target->SaveSelf(kTRUE);
00443 TH1::AddDirectory(addDirStat);
00444 return kTRUE;
00445 }