13 #include <TFileMergeInfo.h>
15 #include <TDirectory.h>
20 #include <TMethodCall.h>
25 #include <TFunction.h>
26 #include <TTreeCloner.h>
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(),
61 const std::string&
mode ) {
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" );
112 Error(
"addFile",
XAOD_MESSAGE(
"Couldn't open file \"%s\"" ),
114 return StatusCode::FAILURE;
120 Info(
"addFile",
"Opened \"%s\" for reading", localName.c_str() );
126 return StatusCode::SUCCESS;
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;
165 Info(
"addMetaDataTool",
"Added tool of type \"%s\"",
170 return StatusCode::SUCCESS;
186 Error(
"merge",
XAOD_MESSAGE(
"No output file specified" ) );
187 return StatusCode::FAILURE;
192 Warning(
"merge",
"No input files were specified" );
193 return StatusCode::RECOVERABLE;
198 Warning(
"merge",
"Number of entries can't be specified in fast "
219 return StatusCode::SUCCESS;
258 Info(
"closeFiles",
"Closing all open files" );
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 ) {
281 Info(
"closeFiles",
"Closed: %s",
m_input[
i ]->GetName() );
285 p =
p( 0,
p.Index(
':', 0 ) );
286 if( gSystem->Unlink(
p ) ) {
290 return StatusCode::FAILURE;
293 Info(
"closeFiles",
"Deleted: %s",
m_input[
i ]->GetName() );
305 Info(
"closeFiles",
"Closed: %s",
m_output->GetName() );
321 return StatusCode::SUCCESS;
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;
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" ) ) {
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" ) ) {
431 Info(
"mergeDirectory",
"Appears to be a TTree" );
440 Info(
"mergeDirectory",
441 "Skipping it because of m_treesToSkip" );
447 if( processedTrees.find(
key->GetName() ) !=
448 processedTrees.end() ) {
450 Info(
"mergeDirectory",
451 "Skipping it, because it was processed already" );
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() ) {
482 Info(
"mergeDirectory",
"TTree \"%s\" has friends; "
483 "skipping from merge", itree->GetName() );
494 std::unique_ptr< TEvent >&
event =
m_events[
key->GetName() ];
496 event.reset(
new TEvent(
m_mode ) );
506 Info(
"mergeDirectory",
"Copying xAOD tree \"%s\"",
510 Info(
"mergeDirectory",
"Copying non-xAOD tree \"%s\"",
520 std::unique_ptr< TEvent >&
event =
m_events[
key->GetName() ];
521 if( !
event.get() ) {
522 event.reset(
new TEvent() );
524 if( !
event->m_outTree ) {
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() ) );
568 Info(
"mergeDirectory",
569 "Merging the tree into an existing one" );
574 const std::vector< ::TBranch* > missingMerged =
576 const std::vector< ::TBranch* > missingIncoming =
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 ) {
590 Info(
"mergeDirectory",
"Adding auxiliary branch: %s",
599 const std::vector< ::TBranch* > skippedBranches =
601 for( ::TBranch*
br : skippedBranches ) {
602 itree->SetBranchStatus(
br->GetName(), 0 );
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 );
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" );
699 Info(
"mergeDirectory",
"Cloning the tree as is" );
711 const std::vector< ::TBranch* > skippedBranches =
713 for( ::TBranch*
br : skippedBranches ) {
714 itree->SetBranchStatus(
br->GetName(), 0 );
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 );
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;
764 Info(
"mergeDirectory",
"Slow copying xAOD tree \"%s\"",
769 const ::Long64_t
entries =
event->getEntries();
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 ),
791 static_cast< int >(
entries ) :
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" ) ) {
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() ) ) {
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;
862 Info(
"mergeDirectory",
"Simply writing it to the output" );
873 return StatusCode::SUCCESS;
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() ) {
916 Info(
"mergeObject",
"Type doesn't have a Merge function" );
918 return StatusCode::RECOVERABLE;
927 mergeMethod.SetParam( ( Long_t ) &
list );
928 mergeMethod.Execute( &
output );
931 Info(
"mergeObject",
"Merging executed successfully" );
935 return StatusCode::SUCCESS;
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\"",
1006 Info(
"createMetaDataTools",
"Created tool of type \"%s\"",
1012 return StatusCode::SUCCESS;
1023 std::vector< ::TBranch* >
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* >
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() ) ) {
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;