Implement the auto-generated functions of the class.
In order to merge various kinds of metadata from the input files correctly into the output file, it is possible to specify the type names of dual-use metadata handling tools. The object then creates an instance of the specified tool, which should take care of merging its metadata type in the background.
This function does most of the heavy-lifting in the code. It recursively merges all the objects from an input directory into the output file's corresponding directory.
This function finds branches that appear in the first tree, but don't appear in the second one.
This function is used during fast merging to create branches that have been encountered first in file N (N >= 2).
39 TFileMerger::TFileMerger()
40 : TObject(), m_input(), m_copiedInput(), m_output( 0 ),
41 m_treesToSkip( {
"##Shapes",
"##Links",
"##Params",
43 "CollectionTreeInDet::Track_tlp2",
44 "POOLContainerForm",
"POOLContainer",
45 "POOLCollectionTree",
"MetaData",
46 "MetaDataHdrForm",
"MetaDataHdr" } ),
47 m_events(), m_helperFiles(),
48 m_metaDataToolNames(), m_metaDataTools(),
49 m_mode( TEvent::kClassAccess ), m_entriesToMerge( kBigNumber ),
54 TFileMerger::~TFileMerger() {
57 closeFiles().ignore();
60 StatusCode TFileMerger::setOutputFileName(
const std::string&
name,
61 const std::string&
mode ) {
64 m_output = ::TFile::Open(
name.c_str(),
mode.c_str() );
66 Error(
"setOutputFileName",
67 XAOD_MESSAGE(
"Couldn't open output file \"%s\" in mode "
70 return StatusCode::FAILURE;
74 Info(
"setOutputFileName",
"Opened \"%s\" for writing",
81 return StatusCode::SUCCESS;
89 std::string localName =
name;
96 gSystem->TempDirectory(), uuid.AsString() ).Data();
98 if( ! TFile::Cp(
name.c_str(), localName.c_str(), kTRUE ) ) {
100 XAOD_MESSAGE(
"Couldn't create local copy of \"%s\" under "
102 name.c_str(), localName.c_str() );
103 return StatusCode::FAILURE;
106 Info(
"addFile",
"Made a local copy of: %s",
name.c_str() );
110 ::TFile*
ifile = ::TFile::Open( localName.c_str(),
"READ" );
114 return StatusCode::FAILURE;
118 m_input.push_back(
ifile );
119 m_copiedInput.push_back( copyLocally );
120 Info(
"addFile",
"Opened \"%s\" for reading", localName.c_str() );
126 return StatusCode::SUCCESS;
144 if( m_metaDataToolNames.find(
typeName ) != m_metaDataToolNames.end() ) {
145 Warning(
"addMetaDataTool",
146 "Tool of type \"%s\" is already specified",
148 return StatusCode::RECOVERABLE;
152 ::TClass*
cl = ::TClass::GetClass(
typeName.c_str() );
154 Error(
"addMetaDataTool",
157 return StatusCode::FAILURE;
161 m_metaDataToolNames.insert(
typeName );
164 if( m_verbosity > 1 ) {
165 Info(
"addMetaDataTool",
"Added tool of type \"%s\"",
170 return StatusCode::SUCCESS;
187 return StatusCode::FAILURE;
191 if( ! m_input.size() ) {
192 Warning(
"merge",
"No input files were specified" );
193 return StatusCode::RECOVERABLE;
197 if( (
mode == kFastMerge ) && (
entries != kBigNumber ) ) {
198 Warning(
"merge",
"Number of entries can't be specified in fast "
200 m_entriesToMerge = kBigNumber;
207 for( ::TFile*
file : m_input ) {
209 mergeDirectory( *
file, *m_output,
mode,
true ) );
213 m_output->SaveSelf();
216 RETURN_CHECK(
"xAOD::TFileMerger::merge", closeFiles() );
219 return StatusCode::SUCCESS;
227 void TFileMerger::setAccessMode( TEvent::EAuxMode
mode ) {
238 void TFileMerger::setVerbosity(
int value ) {
244 const std::set< std::string >& TFileMerger::treesSkipped()
const {
246 return m_treesToSkip;
249 void TFileMerger::addTreeToSkip(
const std::string&
name ) {
251 m_treesToSkip.insert(
name );
257 if( m_verbosity >= 1 ) {
258 Info(
"closeFiles",
"Closing all open files" );
262 if( m_input.size() != m_copiedInput.size() ) {
268 auto ev_itr = m_events.begin();
269 auto ev_end = m_events.end();
270 for( ; ev_itr != ev_end; ++ev_itr ) {
271 if( ev_itr->second->m_outTree && m_output ) {
273 ev_itr->second->finishWritingTo( m_output ) );
278 for(
size_t i = 0;
i < m_input.size(); ++
i ) {
279 m_input[
i ]->Close();
280 if( m_verbosity >= 2 ) {
281 Info(
"closeFiles",
"Closed: %s", m_input[
i ]->GetName() );
283 if( m_copiedInput[
i ] ) {
284 TString
p( m_input[
i ]->GetPath() );
285 p =
p( 0,
p.Index(
':', 0 ) );
286 if( gSystem->Unlink(
p ) ) {
290 return StatusCode::FAILURE;
292 if( m_verbosity >= 2 ) {
293 Info(
"closeFiles",
"Deleted: %s", m_input[
i ]->GetName() );
299 m_copiedInput.clear();
304 if( m_verbosity >= 2 ) {
305 Info(
"closeFiles",
"Closed: %s", m_output->GetName() );
315 for( ::TFile*
file : m_helperFiles ) {
318 m_helperFiles.clear();
321 return StatusCode::SUCCESS;
340 if( m_verbosity >= 1 ) {
341 Info(
"mergeDirectory",
"Merging directories:" );
342 Info(
"mergeDirectory",
" input : %s",
input.GetName() );
343 Info(
"mergeDirectory",
" output: %s",
output.GetName() );
347 TList* keyList =
input.GetListOfKeys();
349 Error(
"mergeDirectory",
350 XAOD_MESSAGE(
"Couldn't get list of keys from input directory "
351 "\"%s\"" ),
input.GetName() );
352 return StatusCode::FAILURE;
361 std::set< std::string > processedTrees;
362 for( Int_t
i = 0;
i < keyList->GetSize(); ++
i ) {
365 TKey*
key =
dynamic_cast< TKey*
>( keyList->At(
i ) );
367 Error(
"mergeDirectory",
370 return StatusCode::FAILURE;
372 if( m_verbosity >= 3 ) {
373 Info(
"mergeDirectory",
"Evaluating key \"%s;%hi\" with type "
375 key->GetName(),
key->GetCycle(),
key->GetClassName() );
382 Error(
"mergeDirectory",
385 key->GetName(),
key->GetCycle() );
386 return StatusCode::FAILURE;
392 if(
obj->IsA()->InheritsFrom(
"TDirectory" ) ) {
394 if( m_verbosity >= 3 ) {
395 Info(
"mergeDirectory",
"Appears to be a TDirectory" );
399 TDirectory*
indir =
dynamic_cast< TDirectory*
>(
obj );
401 Error(
"mergeDirectory",
402 XAOD_MESSAGE(
"Couldn't cast to object to TDirectory" ) );
403 return StatusCode::FAILURE;
408 dynamic_cast< TDirectory*
>(
output.Get(
key->GetName() ) );
412 "dummy title" ) ) ) {
413 Error(
"mergeDirectory",
417 return StatusCode::FAILURE;
428 }
else if(
obj->IsA()->InheritsFrom(
"TTree" ) ) {
430 if( m_verbosity >= 3 ) {
431 Info(
"mergeDirectory",
"Appears to be a TTree" );
437 if( m_treesToSkip.find(
key->GetName() ) !=
438 m_treesToSkip.end() ) {
439 if( m_verbosity >= 4 ) {
440 Info(
"mergeDirectory",
441 "Skipping it because of m_treesToSkip" );
447 if( processedTrees.find(
key->GetName() ) !=
448 processedTrees.end() ) {
449 if( m_verbosity >= 4 ) {
450 Info(
"mergeDirectory",
451 "Skipping it, because it was processed already" );
456 if( m_verbosity >= 3 ) {
457 Info(
"mergeDirectory",
458 "Tree not processed yet. Doing so now." );
462 ::TObject* treeObj =
input.Get(
key->GetName() );
464 Fatal(
"mergeDirectory",
466 return StatusCode::FAILURE;
468 ::TTree* itree =
dynamic_cast< TTree*
>( treeObj );
470 Error(
"mergeDirectory",
473 treeObj->GetName() );
474 return StatusCode::FAILURE;
479 if( itree->GetListOfFriends() &&
480 itree->GetListOfFriends()->GetSize() ) {
481 if( m_verbosity >= 2 ) {
482 Info(
"mergeDirectory",
"TTree \"%s\" has friends; "
483 "skipping from merge", itree->GetName() );
494 std::unique_ptr< TEvent >&
event = m_events[
key->GetName() ];
495 if( ( !
event.get() ) || (
event->auxMode() != m_mode ) ) {
496 event.reset(
new TEvent( m_mode ) );
501 createMetaDataTools() );
506 Info(
"mergeDirectory",
"Copying xAOD tree \"%s\"",
510 Info(
"mergeDirectory",
"Copying non-xAOD tree \"%s\"",
515 if(
mode == kFastMerge ) {
520 std::unique_ptr< TEvent >&
event = m_events[
key->GetName() ];
521 if( !
event.get() ) {
522 event.reset(
new TEvent() );
524 if( !
event->m_outTree ) {
533 m_helperFiles.push_back(
ofile );
540 const EventFormat* ief =
event->inputEventFormat();
542 if( ( ! ief ) || ( ! oef ) ) {
543 Error(
"mergeDirectory",
545 Error(
"mergeDirectory",
547 static_cast< const void*
>( ief ),
548 static_cast< void*
>( oef ) );
549 return StatusCode::FAILURE;
551 auto itr = ief->begin();
552 auto end = ief->end();
553 for( ; itr !=
end; ++itr ) {
554 if( ! oef->exists( itr->first ) ) {
555 oef->add( itr->second );
564 dynamic_cast< ::TTree*
>(
output.Get(
key->GetName() ) );
567 if( m_verbosity >= 3 ) {
568 Info(
"mergeDirectory",
569 "Merging the tree into an existing one" );
574 const std::vector< ::TBranch* > missingMerged =
575 getMissingBranches( otree, itree );
576 const std::vector< ::TBranch* > missingIncoming =
577 getMissingBranches( itree, otree );
578 if( m_verbosity >= 4 ) {
579 Info(
"mergeDirectory",
"missingMerged.size() = %i",
580 static_cast< int >( missingMerged.size() ) );
581 Info(
"mergeDirectory",
"missingIncoming.size() = %i",
582 static_cast< int >( missingIncoming.size() ) );
588 for( ::TBranch*
br : missingIncoming ) {
589 if( m_verbosity >= 4 ) {
590 Info(
"mergeDirectory",
"Adding auxiliary branch: %s",
594 addAuxBranch( otree,
br ) );
599 const std::vector< ::TBranch* > skippedBranches =
600 getSkippedBranches( itree );
601 for( ::TBranch*
br : skippedBranches ) {
602 itree->SetBranchStatus(
br->GetName(), 0 );
603 if( m_verbosity >= 4 ) {
604 Info(
"mergeDirectory",
605 "Deactivated branch \"%s\" from merging",
612 TObjArray* obranches = otree->GetListOfBranches();
613 std::map< ::Int_t, ::TBranch* > auxIndices;
614 for( ::TBranch*
br : missingMerged ) {
615 const Int_t
index = obranches->IndexOf(
br );
617 Error(
"mergeDirectory",
620 return StatusCode::FAILURE;
623 obranches->RemoveAt(
index );
624 if( m_verbosity >= 4 ) {
625 Info(
"mergeDirectory",
"Removed branch \"%s\" from "
626 "fast merge list",
br->GetName() );
629 if( auxIndices.size() ) {
630 obranches->Compress();
636 cloner( itree, otree,
"fast SortBasketsByBranch",
637 ( ::TTreeCloner::kNoWarnings |
638 ::TTreeCloner::kIgnoreMissingTopLevel ) );
640 if( ! cloner.IsValid()) {
642 static const char*
const okerror =
"One of the export branch";
643 if( ::strncmp( cloner.GetWarning(), okerror,
644 ::strlen( okerror ) ) == 0 ) {
647 Error(
"mergeDirectory",
649 cloner.GetWarning() );
650 return StatusCode::FAILURE;
655 otree->SetEntries( otree->GetEntries() +
656 itree->GetEntries() );
657 if( ! cloner.Exec() ) {
658 Error(
"mergeDirectory",
660 return StatusCode::FAILURE;
665 for(
auto it : auxIndices ) {
666 const Int_t last = obranches->GetLast();
668 obranches->AddAtAndExpand( obranches->At( last ),
670 for( Int_t
ind = last - 1;
ind >=
it.first; --
ind ) {
671 obranches->AddAt( obranches->At(
ind ),
ind + 1 );
673 obranches->AddAt(
it.second,
it.first );
675 obranches->Add(
it.second );
679 const ::Long64_t ientries = itree->GetEntries();
680 for( ::TBranch*
br : missingMerged ) {
682 for( ::Long64_t
i = 0;
i < ientries; ++
i ) {
683 if(
br->Fill() < 0 ) {
684 Error(
"mergeDirectory",
686 "with default content" ),
688 return StatusCode::FAILURE;
694 otree->AutoSave(
"FlushBaskets" );
698 if( m_verbosity >= 3 ) {
699 Info(
"mergeDirectory",
"Cloning the tree as is" );
711 const std::vector< ::TBranch* > skippedBranches =
712 getSkippedBranches( itree );
713 for( ::TBranch*
br : skippedBranches ) {
714 itree->SetBranchStatus(
br->GetName(), 0 );
715 if( m_verbosity >= 4 ) {
716 Info(
"mergeDirectory",
717 "Deactivated branch \"%s\" from cloning",
725 itree->CloneTree( -1,
726 "fast SortBasketsByBranch" ) ) ) {
727 Error(
"mergeDirectory",
731 return StatusCode::FAILURE;
733 otree->SetDirectory( &
output );
739 }
else if(
mode == kSlowMerge ) {
744 std::unique_ptr< TEvent >&
event = m_events[
key->GetName() ];
745 if( !
event.get() ) {
746 event.reset(
new TEvent() );
750 if( !
event->m_outTree ) {
752 ::TFile*
ofile =
dynamic_cast< ::TFile*
>( &
output );
754 Error(
"mergeDirectory",
756 return StatusCode::FAILURE;
763 if( m_verbosity >= 3 ) {
764 Info(
"mergeDirectory",
"Slow copying xAOD tree \"%s\"",
769 const ::Long64_t
entries =
event->getEntries();
773 if(
event->m_outTree->GetEntries() >= m_entriesToMerge ) {
779 Error(
"mergeDirectory",
782 static_cast< int >(
entry ),
key->GetName() );
783 return StatusCode::FAILURE;
787 if( ! (
entry % 500 ) ) {
788 Info(
"mergeDirectory",
"Copied %i / %i entries",
789 static_cast< int >(
entry ),
790 ( m_entriesToMerge == kBigNumber ?
791 static_cast< int >(
entries ) :
792 static_cast< int >( m_entriesToMerge ) ) );
800 const ::Int_t bytes =
event->fill();
802 Error(
"mergeDirectory",
805 static_cast< int >(
entry ),
key->GetName() );
806 return StatusCode::FAILURE;
807 }
else if( bytes == 0 ) {
808 Warning(
"mergeDirectory",
809 "No payload was written for entry %i",
810 static_cast< int >(
entry ) );
815 Fatal(
"mergeDirectory",
817 static_cast< int >(
mode ) );
821 processedTrees.insert(
key->GetName() );
823 }
else if(
obj->IsA()->InheritsFrom(
"TObject" ) ) {
825 if( m_verbosity >= 3 ) {
826 Info(
"mergeDirectory",
"Appears to be a TObject of type %s",
827 obj->IsA()->GetName() );
831 ::TClass*
cl = ::TClass::GetClass(
key->GetClassName() );
832 if( ( !
cl ) || ( !
cl->IsLoaded() ) ) {
836 if( m_verbosity >= 3 ) {
837 Info(
"mergeDirectory",
"We seem to have a dictionary for it" );
841 TObject* oobj =
output.Get(
key->GetName() );
847 if( ret.isSuccess() ) {
850 oobj->Write( 0, TObject::kOverwrite );
852 }
else if( ret.isFailure() ) {
854 Error(
"mergeDirectory",
856 "\"%s\"" ),
obj->GetName() );
857 return StatusCode::FAILURE;
861 if( m_verbosity >= 3 ) {
862 Info(
"mergeDirectory",
"Simply writing it to the output" );
873 return StatusCode::SUCCESS;
894 if( m_verbosity >= 3 ) {
895 Info(
"mergeObject",
"Called mergeObject( %s, %s )",
900 if( strcmp(
input.IsA()->GetName(),
output.IsA()->GetName() ) ) {
901 Error(
"mergeObject",
902 XAOD_MESSAGE(
"Received objects of different types" ) );
903 Error(
"mergeObject",
905 Error(
"mergeObject",
907 return StatusCode::FAILURE;
911 ::TMethodCall mergeMethod;
912 mergeMethod.InitWithPrototype(
output.IsA(),
"Merge",
"TCollection*" );
913 if( ! mergeMethod.IsValid() ) {
915 if( m_verbosity >= 3 ) {
916 Info(
"mergeObject",
"Type doesn't have a Merge function" );
918 return StatusCode::RECOVERABLE;
927 mergeMethod.SetParam( ( Long_t ) &
list );
928 mergeMethod.Execute( &
output );
930 if( m_verbosity >= 3 ) {
931 Info(
"mergeObject",
"Merging executed successfully" );
935 return StatusCode::SUCCESS;
938 StatusCode TFileMerger::createMetaDataTools() {
941 for(
const std::string&
typeName : m_metaDataToolNames ) {
944 if( m_metaDataTools.find(
typeName ) != m_metaDataTools.end() ) {
949 ::TClass*
cl = ::TClass::GetClass(
typeName.c_str() );
951 Error(
"createMetaDataTools",
954 return StatusCode::FAILURE;
956 void*
ptr =
cl->New();
958 Error(
"createMetaDataTools",
961 return StatusCode::FAILURE;
965 ::TMethodCall initMethod;
966 initMethod.InitWithPrototype(
cl,
"initialize",
"" );
967 if( initMethod.IsValid() ) {
970 const std::string returnTypeName =
971 initMethod.GetMethod()->GetReturnTypeNormalizedName();
972 ::TClass* returnCl = ::TClass::GetClass( returnTypeName.c_str(),
975 returnCl->GetListOfMethods()->FindObject(
"ignore" ) ) {
979 Warning(
"createMetaDataTools",
"No StatusCode was returned" );
981 ::TMethodCall ignoreMethod;
982 ignoreMethod.InitWithPrototype( returnCl,
"ignore",
"" );
984 ignoreMethod.Execute(
static_cast< void*
>(
statusCode ) );
986 Error(
"createMetaDataTools",
988 "of the initialize() function's return "
995 initMethod.Execute(
ptr );
998 Warning(
"createMetaDataTools",
999 "No initialize() function found for tool \"%s\"",
1005 if( m_verbosity > 0 ) {
1006 Info(
"createMetaDataTools",
"Created tool of type \"%s\"",
1012 return StatusCode::SUCCESS;
1023 std::vector< ::TBranch* >
1024 TFileMerger::getMissingBranches( ::TTree*
first,
1025 ::TTree*
second )
const {
1028 std::vector< ::TBranch* >
result;
1031 ::TObjArray* brFirst =
first->GetListOfBranches();
1032 ::TObjArray* brSecond =
second->GetListOfBranches();
1035 for( ::Int_t
i = 0;
i < brFirst->GetEntries(); ++
i ) {
1037 if( brSecond->FindObject( brFirst->At(
i )->GetName() ) ) {
1041 ::TBranch*
br =
dynamic_cast< ::TBranch*
>( brFirst->At(
i ) );
1043 Fatal(
"getMissingBranches",
1044 XAOD_MESSAGE(
"Couldn't cast branch to TBranch?!?" ) );
1049 ::EDataType
dt = kOther_t;
1050 if(
br->GetExpectedType(
cl,
dt ) ) {
1051 Error(
"getMissingBranches",
1052 XAOD_MESSAGE(
"Type could not be extracted for branch "
1053 "\"%s\"" ),
br->GetName() );
1056 if(
cl && ( !
cl->IsLoaded() ) ) {
1068 std::vector< ::TBranch* >
1069 TFileMerger::getSkippedBranches( ::TTree*
tree )
const {
1072 std::vector< ::TBranch* >
result;
1079 for( ::Int_t
i = 0;
i <
branches->GetEntries(); ++
i ) {
1081 ::TBranch*
br =
dynamic_cast< ::TBranch*
>(
branches->At(
i ) );
1083 Fatal(
"getSkippedBranches",
1084 XAOD_MESSAGE(
"Couldn't cast branch to TBranch?!?" ) );
1089 ::EDataType
dt = kOther_t;
1090 if(
br->GetExpectedType(
cl,
dt ) ) {
1091 Error(
"getSkippedBranches",
1092 XAOD_MESSAGE(
"Type could not be extracted for branch "
1093 "\"%s\"" ),
br->GetName() );
1098 if(
cl && ( !
cl->IsLoaded() ) ) {
1113 StatusCode TFileMerger::addAuxBranch( ::TTree* otree,
1114 ::TBranch* ibranch )
const {
1118 ::EDataType
dt = kOther_t;
1119 if( ibranch->GetExpectedType(
cl,
dt ) ) {
1120 Error(
"addAuxBranch",
1121 XAOD_MESSAGE(
"Type could not be extracted for branch \"%s\"" ),
1122 ibranch->GetName() );
1123 return StatusCode::FAILURE;
1127 ::TBranch* obranch = 0;
1133 obranch = otree->Branch( ibranch->GetName(),
cl->GetName(),
1134 &
ptr, ibranch->GetBasketSize(),
1135 ibranch->GetSplitLevel() );
1137 Error(
"addAuxBranch",
1138 XAOD_MESSAGE(
"Couldn't create auxiliary branch \"%s\" with "
1140 ibranch->GetName(),
cl->GetName() );
1141 return StatusCode::FAILURE;
1143 }
else if(
dt != kOther_t ) {
1148 Error(
"addAuxBranch",
1149 XAOD_MESSAGE(
"Type can't be extracted for EDataType = %i"),
1150 static_cast< int >(
dt ) );
1151 return StatusCode::FAILURE;
1153 std::ostringstream leaflist;
1154 leaflist << ibranch->GetName() <<
"/" <<
rootType;
1156 obranch = otree->Branch( ibranch->GetName(),
ptr,
1157 leaflist.str().c_str(),
1158 ibranch->GetBasketSize() );
1160 Error(
"addAuxBranch",
1161 XAOD_MESSAGE(
"Couldn't create auxiliary branch \"%s\" with "
1163 ibranch->GetName(),
static_cast< int >(
dt ) );
1164 return StatusCode::FAILURE;
1167 Error(
"addAuxBranch",
1168 XAOD_MESSAGE(
"Couldn't figure out the type of branch \"%s\"" ),
1169 ibranch->GetName() );
1170 return StatusCode::FAILURE;
1174 obranch->SetAddress( 0 );
1175 for( ::Long64_t
i = 0;
i < otree->GetEntries(); ++
i ) {
1176 if( obranch->Fill() < 0 ) {
1177 Error(
"addAuxBranch",
1178 XAOD_MESSAGE(
"Failed to fill branch \"%s\" with dummy "
1179 "data" ), obranch->GetName() );
1180 return StatusCode::FAILURE;
1185 return StatusCode::SUCCESS;