1 #ifndef GAUDIROOTCNV_ROOTDATABASEMERGER_H 2 # define GAUDIROOTCNV_ROOTDATABASEMERGER_H 43 unsigned char buf[16];
83 #endif // GAUDIROOTCNV_ROOTDATABASEMERGER_H 85 #ifndef GAUDIROOTCNV_ROOTDATABASEMERGER_H 86 # include "RootDatabaseMerger.h" 87 #endif // GAUDIROOTCNV_ROOTDATABASEMERGER_H 90 #include "TInterpreter.h" 96 #include "TTreeCloner.h" 103 using namespace Gaudi;
107 static bool s_dbg =
true;
118 Bool_t result = gSystem->AccessPathName( fid.
c_str(), kFileExists );
120 return result == kFALSE;
125 const char* fid = file_id.
c_str();
127 ::printf(
"+++ Another output file %s is already open. Request denied.\n", m_output->GetName() );
129 }
else if ( !exists( file_id ) ) {
130 ::printf(
"+++ Cannot attach output file %s --- file does not exist.\n", fid );
133 m_output.reset( TFile::Open( fid,
"UPDATE" ) );
134 if ( m_output && !m_output->IsZombie() ) {
139 ::printf(
"+++ Failed to open new output file %s.\n", fid );
146 ::printf(
"+++ Another output file %s is already open. Request denied.\n", m_output->GetName() );
148 }
else if ( exists( fid ) ) {
149 ::printf(
"+++ Cannot create output file %s --- file already exists.\n", fid.
c_str() );
152 m_output.reset( TFile::Open( fid.
c_str(),
"RECREATE" ) );
153 if ( m_output && !m_output->IsZombie() ) {
154 TTree* t1 =
new TTree(
"Sections",
"Root Section data" );
155 TTree* t2 =
new TTree(
"Refs",
"Root Section data" );
157 t1->Branch(
"Sections", 0,
"Sections/C" );
158 t2->Branch(
"Links", 0,
"Links/C" );
159 t2->Branch(
"Params", 0,
"Params/C" );
160 t2->Branch(
"Databases", 0,
"Databases/C" );
161 t2->Branch(
"Containers", 0,
"Containers/C" );
162 if ( s_dbg ) ::printf(
"+++ Opened new output file %s.\n", fid.
c_str() );
166 ::printf(
"+++ Failed to open new output file %s.\n", fid.
c_str() );
172 static const char* fmt =
"FID=%08lX-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX";
174 TTree* t = (TTree*)m_output->Get(
"Refs" );
179 TBranch* b = t->GetBranch(
"Params" );
181 uuid.GetUUID( d.
buf );
182 sprintf( text, fmt, d.
ibuf[0], d.
sbuf[2], d.
sbuf[3], d.
buf[8], d.
buf[9], d.
buf[10], d.
buf[11], d.
buf[12],
184 b->SetAddress( text );
187 if ( s_dbg ) ::printf(
"+++ Added new GUID %s to merge file.\n", text );
192 ::printf(
"+++ Failed to add new GUID to merge file.\n" );
200 if ( s_dbg ) ::printf(
"+++ Closing merge file.\n" );
203 if ( s_dbg ) m_output->ls();
213 int nb, total = 0, nbytes = 0;
215 TTree* t = (TTree*)m_output->Get(
"Sections" );
217 TBranch* b = t->GetBranch(
"Sections" );
219 b->SetAddress( text );
220 for (
const auto& i : m_sections ) {
221 string cont = i.first;
222 for (
const auto& j : i.second ) {
223 ::sprintf( text,
"[CNT=%s][START=%d][LEN=%d]", cont.
c_str(), j.start, j.length );
229 ::printf(
"+++ Failed to update Sections tree with new entries. [WRITE_ERROR]\n" );
232 ::sprintf( text,
"[END-OF-SECTION]" );
238 ::printf(
"+++ Failed to update Sections branch with new entries. [WRITE_ERROR]\n" );
240 if ( s_dbg ) ::printf(
"+++ Added %d Sections entries with %d bytes in total.\n", total, nbytes );
243 ::printf(
"+++ Failed to update Sections tree with new entries. [NO_OUTPUT_BRANCH]\n" );
246 ::printf(
"+++ Failed to update Sections tree with new entries. [NO_OUTPUT_TREE]\n" );
249 ::printf(
"+++ Failed to update Sections tree with new entries. [NO_OUTPUT_FILE]\n" );
255 for (
const auto& i : m_sections ) {
258 for (
const auto& j : i.second ) {
260 ::sprintf( text,
"['%s'][%d]",
prefix.
c_str(), cnt++ );
262 ::printf(
"+++ section %-55s Start:%8d ... %8d [%d entries]\n", text, j.start, j.start + j.length, j.length );
272 if ( source && !source->IsZombie() ) {
273 size_t idx = fid.
rfind(
'/' );
274 ::printf(
"+++ Start merging input file:%s\n",
275 idx != string::npos ? fid.
substr( idx + 1 ).c_str() : fid.
c_str() );
283 ::printf(
"+++ Cannot open input file:%s\n", source->GetName() );
287 ::printf(
"+++ No valid output file present. Merge request refused for fid:%s.\n", fid.
c_str() );
293 if ( m_treeSections ) {
295 s.start = (int)( out ? out->GetEntries() : 0 );
296 s.
length = (int)in->GetEntries();
297 m_sections[in->GetName()].push_back(
s );
301 TObjArray* a_in = in->GetListOfBranches();
302 for (
int i = 0,
n = a_in->GetLast(); i <
n; ++i ) {
303 TBranch* b_in = (TBranch*)a_in->At( i );
304 TBranch* b_out = out ? out->GetBranch( b_in->GetName() ) : 0;
305 if ( !out || b_out ) {
307 s.start = (int)( b_out ? b_out->GetEntries() : 0 );
308 s.
length = (int)b_in->GetEntries();
309 m_sections[b_in->GetName()].push_back(
s );
312 ::printf(
"+++ Cannot merge incompatible branches:%s.\n", b_in->GetName() );
321 TBranch*
s = src_tree->GetBranch(
name.c_str() );
322 TBranch* o = out_tree->GetBranch(
name.c_str() );
324 s->SetAddress( text );
325 o->SetAddress( text );
326 for ( Long64_t i = 0,
n =
s->GetEntries(); i <
n; ++i ) {
337 TIter nextkey( source->GetListOfKeys() );
339 for ( TKey* key = (TKey*)nextkey(); key; key = (TKey*)nextkey() ) {
340 const char* classname = key->GetClassName();
341 TClass* cl = gROOT->GetClass( classname );
343 if ( cl->InheritsFrom(
"TTree" ) ) {
344 string name = key->GetName();
345 if (
name ==
"Refs" )
continue;
346 m_treeSections = 0 == ::strncmp( key->GetName(),
"<local>_", 7 );
347 printf(
"+++ Copy Tree:%s %d\n",
name.c_str(), int( m_treeSections ) );
349 m_treeSections =
false;
354 m_treeSections =
false;
360 TTree* src_tree = (TTree*)source->Get(
name.c_str() );
362 Long64_t src_entries = src_tree->GetEntries();
363 TTree* out_tree = (TTree*)m_output->Get(
name.c_str() );
365 if ( 0 == src_tree->GetEntries() ) { src_tree->SetEntries( 1 ); }
366 addSections( src_tree, out_tree );
368 out_tree = src_tree->CloneTree( -1,
"fast" );
369 if ( s_dbg ) ::printf(
"+++ Created new Tree %s.\n", out_tree->GetName() );
374 m_output->GetObject(
name.c_str(), out_tree );
375 TTreeCloner cloner( src_tree, out_tree,
"fast" );
376 if ( cloner.IsValid() ) {
377 Long64_t out_entries = out_tree->GetEntries();
378 out_tree->SetEntries( out_entries + src_entries );
379 Bool_t res = cloner.Exec();
380 if ( s_dbg ) ::printf(
"+++ Merged tree: %s res=%d\n", out_tree->GetName(), res );
387 ::printf(
"+++ Got a tree where fast cloning is not possible -- operation failed.\n" );
391 Long64_t nb = out_tree->CopyEntries(src_tree,-1,
"fast");
392 Long64_t out_entries = out_tree->GetEntries();
393 out_tree->SetEntries(out_entries+src_entries);
395 if ( s_dbg ) ::printf(
"+++ Merged tree: %s res=%lld\n",out_tree->GetName(),nb);
404 TTree* src_tree = (TTree*)source->Get(
name.c_str() );
406 TTree* out_tree = (TTree*)m_output->Get(
name.c_str() );
408 addSections( src_tree, out_tree );
409 copyBranch( src_tree, out_tree,
"Links" );
410 copyBranch( src_tree, out_tree,
"Params" );
411 copyBranch( src_tree, out_tree,
"Containers" );
412 copyBranch( src_tree, out_tree,
"Databases" );
420 int merge(
const char* target,
const char* source,
bool fixup =
false,
bool dbg =
true ) {
424 static bool first =
true;
427 gSystem->Load(
"libCintex");
428 gInterpreter->ProcessLine(
"Cintex::Enable()");
436 MergeStatus ret =
m.exists( target ) ?
m.attach( target ) :
m.create( target );
438 ret =
m.merge( source );
441 if ( fixup )
m.createFID();
446 ::printf(
"+++ Cannot open output file:%s\n", target );
RootDatabaseMerger()
Standard constructor.
MergeStatus copyAllTrees(TFile *source)
Copy all data trees from the input file to the output file.
MergeStatus addSections(TTree *in, TTree *out)
Add section information for the next merge step.
MergeStatus create(const std::string &fid)
Create new output file.
MergeStatus saveSections()
Save new sections to the output file.
int merge(const char *target, const char *source, bool fixup=false, bool dbg=true)
bool exists(const std::string &fid) const
Check if a database exists.
std::unique_ptr< TFile > m_output
MergeStatus copyTree(TFile *source, const std::string &name)
Copy one single tree from the input file to the output file.
MergeStatus merge(const std::string &fid)
Merge new input to existing output.
MergeStatus createFID()
Create and add new FID to the newly merged file.
virtual ~RootDatabaseMerger()
Default destructor.
MergeStatus close()
Close output file.
void dumpSections()
Dump collected database sections.
std::map< std::string, ContainerSections > DatabaseSections
std::vector< ContainerSection > ContainerSections
MergeStatus attach(const std::string &fid)
Attach to existing output file for further merging.
MergeStatus copyBranch(TTree *src_tree, TTree *out_tree, const std::string &name)
Copy single reference branch.
MergeStatus copyRefs(TFile *source, const std::string &name)
Copy one single tree from the input file to the output file.
DatabaseSections m_sections
Header file for std:chrono::duration-based Counters.