The Gaudi Framework  v30r2 (9eca68f7)
THistSvc.cpp
Go to the documentation of this file.
1 // system headers
2 #include <cstdio>
3 #include <sstream>
4 #include <streambuf>
5 
6 // boost headers
7 #include "boost/algorithm/string/case_conv.hpp"
8 
9 // ROOT headers
10 #include "TDirectory.h"
11 #include "TError.h"
12 #include "TFile.h"
13 #include "TGraph.h"
14 #include "TKey.h"
15 #include "TROOT.h"
16 
17 // Gaudi headers
22 #include "GaudiKernel/IFileMgr.h"
27 #include "GaudiKernel/Property.h"
28 
29 // local headers
30 #include "THistSvc.h"
31 
33 
34 namespace
35 {
36  template <typename InputIterator, typename OutputIterator, typename UnaryOperation, typename UnaryPredicate>
37  OutputIterator transform_if( InputIterator first, InputIterator last, OutputIterator result, UnaryOperation op,
38  UnaryPredicate pred )
39  {
40  while ( first != last ) {
41  if ( pred( *first ) ) *result++ = op( *first );
42  ++first;
43  }
44  return result;
45  }
46 
47  constexpr struct select1st_t {
48  template <typename T, typename S>
49  const T& operator()( const std::pair<T, S>& p ) const
50  {
51  return p.first;
52  }
53  } select1st{};
54 }
55 
56 //*************************************************************************//
57 
59 {
60  m_compressionLevel.declareUpdateHandler( &THistSvc::setupCompressionLevel, this );
61  m_outputfile.declareUpdateHandler( &THistSvc::setupOutputFile, this );
62  m_inputfile.declareUpdateHandler( &THistSvc::setupInputFile, this );
63 }
64 
66 {
68 
70 
71  if ( status.isFailure() ) {
72  error() << "initializing service" << endmsg;
73  return status;
74  }
75 
77 
78  try {
80  } catch ( GaudiException& err ) {
81  error() << "Caught: " << err << endmsg;
83  }
84 
85  try {
87  } catch ( GaudiException& err ) {
88  error() << "Caught: " << err << endmsg;
90  }
91 
92  // Protect against multiple instances of TROOT
93  if ( !gROOT ) {
94  static TROOT root( "root", "ROOT I/O" );
95  // gDebug = 99;
96  } else {
97  if ( msgLevel( MSG::VERBOSE ) ) {
98  verbose() << "ROOT already initialized, debug = " << gDebug << endmsg;
99  }
100  }
101 
102  if ( service( "IncidentSvc", p_incSvc, true ).isFailure() ) {
103  error() << "unable to get the IncidentSvc" << endmsg;
104  st = StatusCode::FAILURE;
105  } else {
106  p_incSvc->addListener( this, "EndEvent", 100, true );
107  }
108 
109  if ( service( "FileMgr", p_fileMgr, true ).isFailure() ) {
110  error() << "unable to get the FileMgr" << endmsg;
111  st = StatusCode::FAILURE;
112  } else {
113  debug() << "got the FileMgr" << endmsg;
114  }
115 
116  // Register open/close callback actions
117  using namespace std::placeholders;
118  auto boa = [this]( const Io::FileAttr* fa, const std::string& caller ) { return this->rootOpenAction( fa, caller ); };
119  if ( p_fileMgr->regAction( boa, Io::OPEN, Io::ROOT ).isFailure() ) {
120  error() << "unable to register ROOT file open action with FileMgr" << endmsg;
121  }
122  auto bea = [this]( const Io::FileAttr* fa, const std::string& caller ) {
123  return this->rootOpenErrAction( fa, caller );
124  };
125  if ( p_fileMgr->regAction( bea, Io::OPEN_ERR, Io::ROOT ).isFailure() ) {
126  error() << "unable to register ROOT file open Error action with FileMgr" << endmsg;
127  }
128 
129  m_okToConnect = true;
130  if ( m_delayConnect ) {
131  if ( !m_inputfile.value().empty() ) {
133  }
134  if ( !m_outputfile.value().empty() ) {
136  }
137 
138  m_delayConnect = false;
139  }
142 
143  IIoComponentMgr* iomgr = nullptr;
144  if ( service( "IoComponentMgr", iomgr, true ).isFailure() ) {
145  error() << "unable to get the IoComponentMgr" << endmsg;
146  st = StatusCode::FAILURE;
147  } else {
148  if ( !iomgr->io_register( this ).isSuccess() ) {
149  error() << "could not register with the I/O component manager !" << endmsg;
150  st = StatusCode::FAILURE;
151  } else {
152  bool all_good = true;
153  // register input/output files...
154  for ( const auto& reg : m_files ) {
155  const std::string& fname = reg.second.first->GetName();
156  const IIoComponentMgr::IoMode::Type iomode =
158  if ( !iomgr->io_register( this, iomode, fname ).isSuccess() ) {
159  warning() << "could not register file [" << fname << "] with the I/O component manager..." << endmsg;
160  all_good = false;
161  } else {
162  info() << "registered file [" << fname << "]... [ok]" << endmsg;
163  }
164  }
165  if ( !all_good ) {
166  error() << "problem while registering input/output files with "
167  << "the I/O component manager !" << endmsg;
168  st = StatusCode::FAILURE;
169  }
170  }
171  }
172 
173  if ( st.isFailure() ) {
174  fatal() << "Unable to initialize THistSvc" << endmsg;
175  }
176 
177  return st;
178 }
179 
181 {
182  GlobalDirectoryRestore restore( m_svcMut );
183  warning() << "reinitialize not implemented" << endmsg;
184  return StatusCode::SUCCESS;
185 }
186 
188 {
189  GlobalDirectoryRestore restore( m_svcMut );
190 
191  if ( msgLevel( MSG::DEBUG ) ) {
192  dump();
193  debug() << "THistSvc::finalize" << endmsg;
194  }
195 
196 #ifndef NDEBUG
197  if ( msgLevel( MSG::DEBUG ) ) {
198  for ( const auto& itr : m_uids ) {
199  THistID& thid = itr.second->at( 0 );
200  TObject* tobj = thid.obj;
201 
202  std::string dirname( "none" );
203  if ( tobj && tobj->IsA()->InheritsFrom( "TTree" ) ) {
204  TTree* tree = dynamic_cast<TTree*>( tobj );
205  if ( tree->GetDirectory() != 0 ) {
206  dirname = tree->GetDirectory()->GetPath();
207  }
208  } else if ( tobj && tobj->IsA()->InheritsFrom( "TGraph" ) ) {
209  if ( !thid.temp ) {
210  dirname = thid.file->GetPath();
211  std::string id2( thid.id );
212  id2.erase( 0, id2.find( "/", 1 ) );
213  id2.erase( id2.rfind( "/" ), id2.length() );
214  if ( id2.find( "/" ) == 0 ) {
215  id2.erase( 0, 1 );
216  }
217  dirname += id2;
218  } else {
219  dirname = "/tmp";
220  }
221  } else if ( tobj && tobj->IsA()->InheritsFrom( "TH1" ) ) {
222  TH1* th = dynamic_cast<TH1*>( tobj );
223  if ( th == nullptr ) {
224  error() << "Couldn't dcast: " << itr.first << endmsg;
225  } else {
226  if ( th->GetDirectory() != 0 ) {
227  dirname = th->GetDirectory()->GetPath();
228  }
229  }
230  } else if ( !tobj ) {
231  warning() << itr.first << " has NULL TObject ptr" << endmsg;
232  }
233  debug() << "finalize: " << thid << endmsg;
234  }
235  }
236 #endif
237 
238  if ( writeObjectsToFile().isFailure() ) {
239  error() << "problems writing histograms" << endmsg;
240  }
241 
242  if ( m_print ) {
243  info() << "Listing contents of ROOT files: " << endmsg;
244  }
245  std::vector<TFile*> deleted_files;
246  for ( auto& itr : m_files ) {
247  if ( std::find( deleted_files.begin(), deleted_files.end(), itr.second.first ) == deleted_files.end() ) {
248  deleted_files.push_back( itr.second.first );
249 
250 #ifndef NDEBUG
251  if ( msgLevel( MSG::DEBUG ) ) {
252  debug() << "finalizing stream/file " << itr.first << ":" << itr.second.first->GetName() << endmsg;
253  }
254 #endif
255  } else {
256 #ifndef NDEBUG
257  if ( msgLevel( MSG::DEBUG ) ) {
258  debug() << "already finalized stream " << itr.first << endmsg;
259  }
260 #endif
261  continue;
262  }
263 
264  if ( m_print && msgLevel( MSG::INFO ) ) {
265  info() << "==> File: " << itr.second.first->GetName() << " stream: " << itr.first << endmsg;
266 
267  itr.second.first->Print( "base" );
268  }
269 
270  std::string tmpfn = itr.second.first->GetName();
271 
272  p_fileMgr->close( itr.second.first, name() );
273 
274  IIncidentSvc* pIncidentSvc = nullptr;
275  if ( service( "IncidentSvc", pIncidentSvc ).isFailure() ) {
276  error() << "Unable to get the IncidentSvc" << endmsg;
277  return StatusCode::FAILURE;
278  }
279 
280  if ( itr.second.second == SHARE ) {
281  // Merge File
282  void* vfile = nullptr;
283  int returncode =
284  p_fileMgr->open( Io::ROOT, name(), m_sharedFiles[itr.first], Io::WRITE | Io::APPEND, vfile, "HIST" );
285 
286  if ( returncode ) {
287  error() << "unable to open Final Output File: \"" << m_sharedFiles[itr.first] << "\" for merging" << endmsg;
288  return StatusCode::FAILURE;
289  }
290 
291  TFile* outputfile = (TFile*)vfile;
292  pIncidentSvc->fireIncident( FileIncident( name(), IncidentType::WroteToOutputFile, m_sharedFiles[itr.first] ) );
293 
294  if ( msgLevel( MSG::DEBUG ) ) {
295  debug() << "THistSvc::writeObjectsToFile()::Merging Rootfile " << endmsg;
296  }
297 
298  vfile = nullptr;
299  returncode = p_fileMgr->open( Io::ROOT, name(), tmpfn, Io::READ, vfile, "HIST" );
300 
301  if ( returncode ) {
302  error() << "unable to open temporary file: \"" << tmpfn << endmsg;
303  return StatusCode::FAILURE;
304  }
305 
306  TFile* inputfile = (TFile*)vfile;
307 
308  outputfile->SetCompressionLevel( inputfile->GetCompressionLevel() );
309 
310  MergeRootFile( outputfile, inputfile );
311 
312  outputfile->Write();
313  p_fileMgr->close( outputfile, name() );
314  p_fileMgr->close( inputfile, name() );
315 
316  if ( msgLevel( MSG::DEBUG ) ) {
317  debug() << "Trying to remove temporary file \"" << tmpfn << "\"" << endmsg;
318  }
319 
320  std::remove( tmpfn.c_str() );
321  }
322  delete itr.second.first;
323  }
324 
325  m_files.clear();
328  m_hlist.clear(); // vhid* is deleted in m_tobjs
329  m_uids.clear(); // vhid* is deleted in m_tobjs
330  m_ids.clear(); // vhid* is deleted in m_tobjs
331 
332  for ( auto& obj : m_tobjs ) {
333  // TObject*'s are already dealt with through root file i/o
334  delete obj.second.first; // delete vhid*
335  }
336  m_tobjs.clear();
337 
338  return Service::finalize();
339 }
340 
341 //*************************************************************************//
342 
344 {
345  std::unique_ptr<TH1> hist = nullptr;
346  return regHist_i( std::move( hist ), id, false );
347 }
348 
350 {
351  return regHist_i( std::move( hist ), id, false );
352 }
353 
355 {
356  // This is only to support a common use case where the histogram is used after its registration
357  if ( hist_ptr != nullptr ) {
358  hist_ptr = hist.get();
359  }
360  return regHist_i( std::move( hist ), id, false );
361 }
362 
363 StatusCode THistSvc::regHist( const std::string& id, TH1* hist_ptr )
364 {
365  std::unique_ptr<TH1> hist( hist_ptr );
366  return regHist_i( std::move( hist ), id, false );
367 }
368 
369 StatusCode THistSvc::getHist( const std::string& id, TH1*& hist, size_t ind ) const
370 {
371  hist = getHist_i<TH1>( id, ind );
372  if ( hist != nullptr ) {
373  return StatusCode::SUCCESS;
374  } else {
375  return StatusCode::FAILURE;
376  }
377 }
378 
379 StatusCode THistSvc::getHist( const std::string& id, TH2*& hist, size_t ind ) const
380 {
381  hist = getHist_i<TH2>( id, ind );
382  if ( hist != nullptr ) {
383  return StatusCode::SUCCESS;
384  } else {
385  return StatusCode::FAILURE;
386  }
387 }
388 
389 StatusCode THistSvc::getHist( const std::string& id, TH3*& hist, size_t ind ) const
390 {
391  hist = getHist_i<TH3>( id, ind );
392  if ( hist != nullptr ) {
393  return StatusCode::SUCCESS;
394  } else {
395  return StatusCode::FAILURE;
396  }
397 }
398 
400 {
401  std::unique_ptr<TTree> tree = nullptr;
402  return regHist_i( std::move( tree ), id, false );
403 }
404 
406 {
407  StatusCode sc = regHist_i( std::move( tree ), id, false );
408  TTree* tr = nullptr;
409  if ( getTree( id, tr ).isSuccess() && sc.isSuccess() ) {
410  if ( m_autoSave != 0 ) {
411  tr->SetAutoSave( m_autoSave );
412  }
413  tr->SetAutoFlush( m_autoFlush );
414  }
415  return sc;
416 }
417 
418 StatusCode THistSvc::regTree( const std::string& id, TTree* tree_ptr )
419 {
420  std::unique_ptr<TTree> tree( tree_ptr );
421  StatusCode sc = regHist_i( std::move( tree ), id, false );
422  TTree* tr = nullptr;
423  if ( getTree( id, tr ).isSuccess() && sc.isSuccess() ) {
424  if ( m_autoSave != 0 ) {
425  tr->SetAutoSave( m_autoSave );
426  }
427  tr->SetAutoFlush( m_autoFlush );
428  }
429  return sc;
430 }
431 
432 StatusCode THistSvc::getTree( const std::string& id, TTree*& tree ) const
433 {
434  tree = getHist_i<TTree>( id );
435  if ( tree != nullptr ) {
436  return StatusCode::SUCCESS;
437  } else {
438  return StatusCode::FAILURE;
439  }
440 }
441 
443 {
444  std::unique_ptr<TGraph> graph = std::make_unique<TGraph>();
445  return regHist_i( std::move( graph ), id, false );
446 }
447 
449 {
450  if ( strcmp( graph->GetName(), "Graph" ) == 0 ) {
451  std::string id2( id );
452  std::string::size_type i = id2.rfind( "/" );
453  if ( i != std::string::npos ) {
454  id2.erase( 0, i + 1 );
455  }
456 
457  info() << "setting name of TGraph id: \"" << id << "\" to \"" << id2 << "\" since it is unset" << endmsg;
458  graph->SetName( id2.c_str() );
459  }
460 
461  return regHist_i( std::move( graph ), id, false );
462 }
463 
464 StatusCode THistSvc::regGraph( const std::string& id, TGraph* graph_ptr )
465 {
466  std::unique_ptr<TGraph> graph( graph_ptr );
467  if ( strcmp( graph->GetName(), "Graph" ) == 0 ) {
468  std::string id2( id );
469  std::string::size_type i = id2.rfind( "/" );
470  if ( i != std::string::npos ) {
471  id2.erase( 0, i + 1 );
472  }
473 
474  info() << "setting name of TGraph id: \"" << id << "\" to \"" << id2 << "\" since it is unset" << endmsg;
475  graph->SetName( id2.c_str() );
476  }
477 
478  return regHist_i( std::move( graph ), id, false );
479 }
480 
481 StatusCode THistSvc::getGraph( const std::string& id, TGraph*& graph ) const
482 {
483  graph = getHist_i<TGraph>( id );
484  if ( graph != nullptr ) {
485  return StatusCode::SUCCESS;
486  } else {
487  return StatusCode::FAILURE;
488  }
489 }
490 
492 {
493  lh = regShared_i<TH1>( id, std::move( hist ) );
494  if ( lh ) {
495  return StatusCode::SUCCESS;
496  } else {
497  return StatusCode::FAILURE;
498  }
499 }
500 
502 {
503  lh = regShared_i<TH2>( id, std::move( hist ) );
504  if ( lh ) {
505  return StatusCode::SUCCESS;
506  } else {
507  return StatusCode::FAILURE;
508  }
509 }
510 
512 {
513  lh = regShared_i<TH3>( id, std::move( hist ) );
514  if ( lh ) {
515  return StatusCode::SUCCESS;
516  } else {
517  return StatusCode::FAILURE;
518  }
519 }
520 
522 {
523  lh = regShared_i<TGraph>( id, std::move( graph ) );
524  if ( lh ) {
525  return StatusCode::SUCCESS;
526  } else {
527  return StatusCode::FAILURE;
528  }
529 }
530 
532 {
533  lh = getShared_i<TH1>( name );
534  if ( lh ) {
535  return StatusCode::SUCCESS;
536  } else {
537  return StatusCode::FAILURE;
538  }
539 }
540 
542 {
543  lh = getShared_i<TH2>( name );
544  if ( lh ) {
545  return StatusCode::SUCCESS;
546  } else {
547  return StatusCode::FAILURE;
548  }
549 }
550 
552 {
553  lh = getShared_i<TH3>( name );
554  if ( lh ) {
555  return StatusCode::SUCCESS;
556  } else {
557  return StatusCode::FAILURE;
558  }
559 }
560 
562 {
563  lh = getShared_i<TGraph>( name );
564  if ( lh ) {
565  return StatusCode::SUCCESS;
566  } else {
567  return StatusCode::FAILURE;
568  }
569 }
570 
572 {
573  auto itr = m_uids.find( id );
574  if ( itr == m_uids.end() ) {
575  error() << "Problem deregistering id \"" << id << "\": not found in registry" << endmsg;
576  return StatusCode::FAILURE;
577  }
578 
579  vhid_t* vh = itr->second;
580  debug() << "will deregister " << vh->size() << " elements of id \"" << id << "\"" << endmsg;
582  while ( vh->size() > 0 ) {
583  if ( deReg( vh->back().obj ).isFailure() ) {
584  sc = StatusCode::FAILURE;
585  error() << "Problems deRegistering " << vh->size() << " element of id \"" << id << "\"" << endmsg;
586  break;
587  }
588  }
589 
590  return sc;
591 }
592 
594 {
595  objMap_t::iterator obj_itr = m_tobjs.find( obj );
596  if ( obj_itr != m_tobjs.end() ) {
597  vhid_t* vhid = obj_itr->second.first;
598  THistID hid = obj_itr->second.first->at( obj_itr->second.second );
599 
600  auto uid_itr = m_uids.find( hid.id );
601  if ( uid_itr == m_uids.end() ) {
602  error() << "Problems deregistering TObject \"" << obj->GetName() << "\" with id \"" << hid.id
603  << "\": not in uidMap" << endmsg;
604  return StatusCode::FAILURE;
605  }
606 
607  if ( vhid->size() == 1 ) {
608  // We are the last object, so we have to delete vhid properly
609  debug() << "vhid for " << hid.id << " is empty. deleting" << endmsg;
610 
611  std::string root, rem;
612  parseString( hid.id, root, rem );
613 
614  auto mitr = m_ids.equal_range( rem );
615  auto id_itr = std::find_if( mitr.first, mitr.second,
616  [&]( idMap_t::const_reference i ) { return i.second->at( 0 ).obj == obj; } );
617  if ( id_itr == mitr.second ) {
618  error() << "Problems deregistering TObject \"" << obj->GetName() << "\" with id \"" << hid.id
619  << "\": not in idMap" << endmsg;
620  return StatusCode::FAILURE;
621  }
622 
623  auto hlist_itr = std::find( m_hlist.begin(), m_hlist.end(), vhid );
624  if ( hlist_itr == m_hlist.end() ) {
625  error() << "Problems deregistering TObject \"" << obj->GetName() << "\" with id \"" << hid.id
626  << "\": not in hlist" << endmsg;
627  return StatusCode::FAILURE;
628  }
629 
630  m_tobjs.erase( obj_itr );
631  vhid->erase( vhid->begin() + obj_itr->second.second );
632 
633  m_uids.erase( uid_itr );
634  m_ids.erase( id_itr );
635  m_hlist.erase( hlist_itr );
636 
637  delete vhid;
638 
639  } else if ( vhid->size() > 1 ) {
640  m_tobjs.erase( obj_itr );
641  vhid->erase( vhid->begin() + obj_itr->second.second );
642 
643  // vector of THistID is still not empty (i.e. other instances with same name registered)
644  } else {
645  error() << "Deregistration failed unexpectedly. (bug in THistSvc?)" << endmsg;
646  }
647  return StatusCode::SUCCESS;
648  } else {
649  error() << "Cannot unregister TObject \"" << obj->GetName() << "\": not known to THistSvc" << endmsg;
650  return StatusCode::FAILURE;
651  }
652 }
653 
655 {
656  uidMap_t::iterator itr = m_uids.find( name );
657  if ( itr == m_uids.end() ) {
658  error() << "merge: id \"" << name << "\" not found" << endmsg;
659  return StatusCode::FAILURE;
660  }
661 
662  return merge( itr->second );
663 }
664 
666 {
667  objMap_t::iterator itr = m_tobjs.find( obj );
668  if ( itr != m_tobjs.end() ) {
669  return merge( itr->second.first );
670  } else {
671  error() << "merge: unknown object " << obj << endmsg;
672  return StatusCode::FAILURE;
673  }
674 }
675 
676 bool THistSvc::exists( const std::string& name ) const { return ( getHist_i<TH1>( name, 0, true ) != nullptr ); }
677 
679 {
681  names.reserve( m_uids.size() );
682  transform_if( std::begin( m_uids ), std::end( m_uids ), std::back_inserter( names ), select1st,
683  []( uidMap_t::const_reference i ) { return i.second->at( 0 ).obj->IsA()->InheritsFrom( "TH1" ); } );
684  return names;
685 }
686 
688 {
690  names.reserve( m_uids.size() );
691  transform_if( std::begin( m_uids ), std::end( m_uids ), std::back_inserter( names ), select1st,
692  []( uidMap_t::const_reference i ) { return i.second->at( 0 ).obj->IsA()->InheritsFrom( "TTree" ); } );
693  return names;
694 }
695 
697 {
699  names.reserve( m_uids.size() );
700  transform_if( std::begin( m_uids ), std::end( m_uids ), std::back_inserter( names ), select1st,
701  []( uidMap_t::const_reference i ) { return i.second->at( 0 ).obj->IsA()->InheritsFrom( "TGraph" ); } );
702  return names;
703 }
704 
705 StatusCode THistSvc::getTHists( TDirectory* td, TList& tl, bool rcs ) const
706 {
707  GlobalDirectoryRestore restore( m_svcMut );
708 
709  gErrorIgnoreLevel = kBreak;
710 
711  if ( !td->cd() ) {
712  error() << "getTHists: No such TDirectory \"" << td->GetPath() << "\"" << endmsg;
713  return StatusCode::FAILURE;
714  }
715 
716  if ( msgLevel( MSG::DEBUG ) ) {
717  debug() << "getTHists: \"" << td->GetPath() << "\": found " << td->GetListOfKeys()->GetSize() << " keys" << endmsg;
718  }
719 
720  TIter nextkey( td->GetListOfKeys() );
721  while ( TKey* key = (TKey*)nextkey() ) {
722  auto& log = debug();
723  if ( msgLevel( MSG::DEBUG ) ) log << " key: " << key->GetName();
724  TObject* obj = key->ReadObj();
725  if ( obj != 0 && obj->IsA()->InheritsFrom( "TDirectory" ) ) {
726  if ( msgLevel( MSG::DEBUG ) ) log << " (" << obj->IsA()->GetName() << ")";
727  } else if ( obj != 0 && obj->IsA()->InheritsFrom( "TH1" ) ) {
728  if ( msgLevel( MSG::DEBUG ) ) log << " (" << obj->IsA()->GetName() << ")";
729  tl.Add( obj );
730  } else if ( obj != 0 ) {
731  if ( msgLevel( MSG::DEBUG ) ) log << " [" << obj->IsA()->GetName() << "]";
732  }
733  if ( msgLevel( MSG::DEBUG ) ) log << endmsg;
734  }
735 
736  // operate recursively
737  if ( rcs ) {
738  nextkey = td->GetListOfKeys();
739  while ( TKey* key = (TKey*)nextkey() ) {
740  TObject* obj = key->ReadObj();
741  if ( obj && obj->IsA()->InheritsFrom( "TDirectory" ) ) {
742  TDirectory* tt = dynamic_cast<TDirectory*>( obj );
743  getTHists( tt, tl, rcs );
744  }
745  }
746  }
747 
748  return StatusCode::SUCCESS;
749 }
750 
751 StatusCode THistSvc::getTHists( const std::string& dir, TList& tl, bool rcs ) const
752 {
753 
754  GlobalDirectoryRestore restore( m_svcMut );
755 
756  gErrorIgnoreLevel = kBreak;
757 
758  StatusCode sc;
759 
760  std::string stream, rem, r2;
761  parseString( dir, stream, rem );
762 
763  auto itr = m_files.find( stream );
764  if ( itr != m_files.end() ) {
765  r2 = itr->second.first->GetName();
766  r2 += ":/";
767  r2 += rem;
768 
769  if ( msgLevel( MSG::DEBUG ) ) {
770  debug() << "getTHists: \"" << dir << "\" looks like a stream name."
771  << " associated TFile: \"" << itr->second.first->GetName() << "\"" << endmsg;
772  }
773 
774  if ( gDirectory->cd( r2.c_str() ) ) {
775  m_curstream = stream;
776  sc = getTHists( gDirectory, tl, rcs );
777  m_curstream = "";
778  return sc;
779  } else {
780  if ( msgLevel( MSG::DEBUG ) ) {
781  debug() << "getTHists: no such TDirectory \"" << r2 << "\"" << endmsg;
782  }
783  }
784 
785  } else {
786  if ( msgLevel( MSG::DEBUG ) ) {
787  debug() << "getTHists: stream \"" << stream << "\" not found" << endmsg;
788  }
789  }
790 
791  if ( !gDirectory->cd( dir.c_str() ) ) {
792  error() << "getTHists: No such TDirectory/stream \"" << dir << "\"" << endmsg;
793  sc = StatusCode::FAILURE;
794  } else {
795  sc = getTHists( gDirectory, tl, rcs );
796  }
797 
798  return sc;
799 }
800 
801 StatusCode THistSvc::getTHists( TDirectory* td, TList& tl, bool rcs, bool reg )
802 {
803  GlobalDirectoryRestore restore( m_svcMut );
804 
805  gErrorIgnoreLevel = kBreak;
806 
807  if ( !td->cd() ) {
808  error() << "getTHists: No such TDirectory \"" << td->GetPath() << "\"" << endmsg;
809  return StatusCode::FAILURE;
810  }
811 
812  if ( msgLevel( MSG::DEBUG ) ) {
813  debug() << "getTHists: \"" << td->GetPath() << "\": found " << td->GetListOfKeys()->GetSize() << " keys" << endmsg;
814  }
815 
816  TIter nextkey( td->GetListOfKeys() );
817  while ( TKey* key = (TKey*)nextkey() ) {
818  auto& log = debug();
819  if ( msgLevel( MSG::DEBUG ) ) log << " key: " << key->GetName();
820  TObject* obj = key->ReadObj();
821  if ( obj && obj->IsA()->InheritsFrom( "TDirectory" ) ) {
822  if ( msgLevel( MSG::DEBUG ) ) log << " (" << obj->IsA()->GetName() << ")";
823  } else if ( obj && obj->IsA()->InheritsFrom( "TH1" ) ) {
824  if ( msgLevel( MSG::DEBUG ) ) log << " (" << obj->IsA()->GetName() << ")";
825  tl.Add( obj );
826  if ( reg && m_curstream != "" ) {
827  std::string dir = td->GetPath();
828  std::string fil = td->GetFile()->GetName();
829  dir.erase( 0, fil.length() + 1 );
830  std::string id = "/" + m_curstream;
831  if ( dir == "/" ) {
832  id = id + "/" + key->GetName();
833  } else {
834  id = id + dir + "/" + key->GetName();
835  }
836  if ( !exists( id ) ) {
837  if ( msgLevel( MSG::DEBUG ) ) log << " reg as \"" << id << "\"";
838  regHist( id ).ignore();
839  } else {
840  if ( msgLevel( MSG::DEBUG ) ) log << " already registered";
841  }
842  }
843  } else if ( obj ) {
844  if ( msgLevel( MSG::DEBUG ) ) log << " [" << obj->IsA()->GetName() << "]";
845  }
846  if ( msgLevel( MSG::DEBUG ) ) log << endmsg;
847  }
848 
849  // operate recursively
850  if ( rcs ) {
851  nextkey = td->GetListOfKeys();
852  while ( TKey* key = (TKey*)nextkey() ) {
853  TObject* obj = key->ReadObj();
854  if ( obj && obj->IsA()->InheritsFrom( "TDirectory" ) ) {
855  TDirectory* tt = dynamic_cast<TDirectory*>( obj );
856  getTHists( tt, tl, rcs, reg );
857  }
858  }
859  }
860 
861  return StatusCode::SUCCESS;
862 }
863 
864 StatusCode THistSvc::getTHists( const std::string& dir, TList& tl, bool rcs, bool reg )
865 {
866  GlobalDirectoryRestore restore( m_svcMut );
867 
868  gErrorIgnoreLevel = kBreak;
869 
870  StatusCode sc;
871 
872  std::string stream, rem, r2;
873  parseString( dir, stream, rem );
874 
875  auto itr = m_files.find( stream );
876  if ( itr != m_files.end() ) {
877  r2 = itr->second.first->GetName();
878  r2 += ":/";
879  r2 += rem;
880 
881  if ( msgLevel( MSG::DEBUG ) ) {
882  debug() << "getTHists: \"" << dir << "\" looks like a stream name."
883  << " associated TFile: \"" << itr->second.first->GetName() << "\"" << endmsg;
884  }
885 
886  if ( gDirectory->cd( r2.c_str() ) ) {
887  m_curstream = stream;
888  sc = getTHists( gDirectory, tl, rcs, reg );
889  m_curstream.clear();
890  return sc;
891  }
892  if ( msgLevel( MSG::DEBUG ) ) {
893  debug() << "getTHists: no such TDirectory \"" << r2 << "\"" << endmsg;
894  }
895  } else {
896  if ( msgLevel( MSG::DEBUG ) ) {
897  debug() << "getTHists: stream \"" << stream << "\" not found" << endmsg;
898  }
899  }
900 
901  if ( !gDirectory->cd( dir.c_str() ) ) {
902  error() << "getTHists: No such TDirectory/stream \"" << dir << "\"" << endmsg;
903  sc = StatusCode::FAILURE;
904  } else {
905  if ( reg ) {
906  warning() << "Unable to register histograms automatically "
907  << "without a valid stream name" << endmsg;
908  reg = false;
909  }
910  sc = getTHists( gDirectory, tl, rcs, reg );
911  }
912 
913  return sc;
914 }
915 
916 StatusCode THistSvc::getTTrees( TDirectory* td, TList& tl, bool rcs ) const
917 {
918  GlobalDirectoryRestore restore( m_svcMut );
919 
920  gErrorIgnoreLevel = kBreak;
921 
922  if ( !td->cd() ) {
923  error() << "getTTrees: No such TDirectory \"" << td->GetPath() << "\"" << endmsg;
924  return StatusCode::FAILURE;
925  }
926 
927  if ( msgLevel( MSG::DEBUG ) ) {
928  debug() << "getTHists: \"" << td->GetPath() << "\": found " << td->GetListOfKeys()->GetSize() << " keys" << endmsg;
929  }
930 
931  TIter nextkey( td->GetListOfKeys() );
932  while ( TKey* key = (TKey*)nextkey() ) {
933  auto& log = debug();
934  if ( msgLevel( MSG::DEBUG ) ) log << " key: " << key->GetName();
935  TObject* obj = key->ReadObj();
936  if ( obj != 0 && obj->IsA()->InheritsFrom( "TDirectory" ) ) {
937  if ( msgLevel( MSG::DEBUG ) ) log << " (" << obj->IsA()->GetName() << ")";
938  } else if ( obj != 0 && obj->IsA()->InheritsFrom( "TTree" ) ) {
939  if ( msgLevel( MSG::DEBUG ) ) log << " (" << obj->IsA()->GetName() << ")";
940  tl.Add( obj );
941  } else if ( obj != 0 ) {
942  if ( msgLevel( MSG::DEBUG ) ) log << " [" << obj->IsA()->GetName() << "]";
943  }
944  log << endmsg;
945  }
946 
947  // operate recursively
948  if ( rcs ) {
949  nextkey = td->GetListOfKeys();
950  while ( TKey* key = (TKey*)nextkey() ) {
951  TObject* obj = key->ReadObj();
952  if ( obj && obj->IsA()->InheritsFrom( "TDirectory" ) ) {
953  TDirectory* tt = dynamic_cast<TDirectory*>( obj );
954  getTTrees( tt, tl, rcs );
955  }
956  }
957  }
958 
959  return StatusCode::SUCCESS;
960 }
961 
962 StatusCode THistSvc::getTTrees( const std::string& dir, TList& tl, bool rcs ) const
963 {
964  GlobalDirectoryRestore restore( m_svcMut );
965 
966  gErrorIgnoreLevel = kBreak;
967 
968  StatusCode sc;
969 
970  std::string stream, rem, r2;
971  parseString( dir, stream, rem );
972 
973  auto itr = m_files.find( stream );
974  if ( itr != m_files.end() ) {
975  r2 = itr->second.first->GetName();
976  r2 += ":/";
977  r2 += rem;
978 
979  if ( msgLevel( MSG::DEBUG ) ) {
980  debug() << "getTTrees: \"" << dir << "\" looks like a stream name."
981  << " associated TFile: \"" << itr->second.first->GetName() << "\"" << endmsg;
982  }
983 
984  if ( gDirectory->cd( r2.c_str() ) ) {
985  return getTTrees( gDirectory, tl, rcs );
986  }
987  if ( msgLevel( MSG::DEBUG ) ) {
988  debug() << "getTTrees: no such TDirectory \"" << r2 << "\"" << endmsg;
989  }
990  } else {
991  if ( msgLevel( MSG::DEBUG ) ) {
992  debug() << "getTTrees: stream \"" << stream << "\" not found" << endmsg;
993  }
994  }
995 
996  if ( !gDirectory->cd( dir.c_str() ) ) {
997  error() << "getTTrees: No such TDirectory/stream \"" << dir << "\"" << endmsg;
998  sc = StatusCode::FAILURE;
999  } else {
1000  sc = getTTrees( gDirectory, tl, rcs );
1001  }
1002  return sc;
1003 }
1004 
1005 StatusCode THistSvc::getTTrees( TDirectory* td, TList& tl, bool rcs, bool reg )
1006 {
1007  GlobalDirectoryRestore restore( m_svcMut );
1008 
1009  gErrorIgnoreLevel = kBreak;
1010 
1011  if ( !td->cd() ) {
1012  error() << "getTTrees: No such TDirectory \"" << td->GetPath() << "\"" << endmsg;
1013  return StatusCode::FAILURE;
1014  }
1015 
1016  if ( msgLevel( MSG::DEBUG ) ) {
1017  debug() << "getTHists: \"" << td->GetPath() << "\": found " << td->GetListOfKeys()->GetSize() << " keys" << endmsg;
1018  }
1019 
1020  TIter nextkey( td->GetListOfKeys() );
1021  while ( TKey* key = (TKey*)nextkey() ) {
1022  auto& log = debug();
1023  if ( msgLevel( MSG::DEBUG ) ) log << " key: " << key->GetName();
1024  TObject* obj = key->ReadObj();
1025  if ( obj && obj->IsA()->InheritsFrom( "TDirectory" ) ) {
1026  if ( msgLevel( MSG::DEBUG ) ) log << " (" << obj->IsA()->GetName() << ")";
1027  } else if ( obj && obj->IsA()->InheritsFrom( "TTree" ) ) {
1028  if ( msgLevel( MSG::DEBUG ) ) log << " (" << obj->IsA()->GetName() << ")";
1029  tl.Add( obj );
1030  if ( reg && m_curstream != "" ) {
1031  std::string dir = td->GetPath();
1032  std::string fil = td->GetFile()->GetName();
1033  dir.erase( 0, fil.length() + 1 );
1034  std::string id = "/" + m_curstream;
1035  if ( dir == "/" ) {
1036  id = id + "/" + key->GetName();
1037  } else {
1038  id = id + dir + "/" + key->GetName();
1039  }
1040  if ( !exists( id ) ) {
1041  if ( msgLevel( MSG::DEBUG ) ) log << " reg as \"" << id << "\"";
1042  regHist( id ).ignore();
1043  } else {
1044  if ( msgLevel( MSG::DEBUG ) ) log << " already registered";
1045  }
1046  }
1047  } else if ( obj != 0 ) {
1048  if ( msgLevel( MSG::DEBUG ) ) log << " [" << obj->IsA()->GetName() << "]";
1049  }
1050  if ( msgLevel( MSG::DEBUG ) ) log << endmsg;
1051  }
1052 
1053  // operate recursively
1054  if ( rcs ) {
1055  nextkey = td->GetListOfKeys();
1056  while ( TKey* key = (TKey*)nextkey() ) {
1057  TObject* obj = key->ReadObj();
1058  if ( obj && obj->IsA()->InheritsFrom( "TDirectory" ) ) {
1059  TDirectory* tt = dynamic_cast<TDirectory*>( obj );
1060  getTTrees( tt, tl, rcs, reg );
1061  }
1062  }
1063  }
1064 
1065  return StatusCode::SUCCESS;
1066 }
1067 
1068 StatusCode THistSvc::getTTrees( const std::string& dir, TList& tl, bool rcs, bool reg )
1069 {
1070  GlobalDirectoryRestore restore( m_svcMut );
1071 
1072  gErrorIgnoreLevel = kBreak;
1073 
1074  StatusCode sc;
1075 
1076  std::string stream, rem, r2;
1077  parseString( dir, stream, rem );
1078 
1079  auto itr = m_files.find( stream );
1080  if ( itr != m_files.end() ) {
1081  r2 = itr->second.first->GetName();
1082  r2 += ":/";
1083  r2 += rem;
1084 
1085  if ( msgLevel( MSG::DEBUG ) ) {
1086  debug() << "getTTrees: \"" << dir << "\" looks like a stream name."
1087  << " associated TFile: \"" << itr->second.first->GetName() << "\"" << endmsg;
1088  }
1089 
1090  if ( gDirectory->cd( r2.c_str() ) ) {
1091  return getTTrees( gDirectory, tl, rcs, reg );
1092  } else {
1093  if ( msgLevel( MSG::DEBUG ) ) {
1094  debug() << "getTTrees: no such TDirectory \"" << r2 << "\"" << endmsg;
1095  }
1096  }
1097  } else {
1098  if ( msgLevel( MSG::DEBUG ) ) {
1099  debug() << "getTTrees: stream \"" << stream << "\" not found" << endmsg;
1100  }
1101  }
1102 
1103  if ( !gDirectory->cd( dir.c_str() ) ) {
1104  error() << "getTTrees: No such TDirectory/stream \"" << dir << "\"" << endmsg;
1105  return StatusCode::FAILURE;
1106  }
1107 
1108  return getTTrees( gDirectory, tl, rcs, reg );
1109 }
1110 
1111 //*************************************************************************//
1112 
1113 void THistSvc::handle( const Incident& /* inc */ )
1114 {
1115  if ( m_signaledStop ) return;
1116 
1117  if ( m_maxFileSize.value() == -1 ) return;
1118 
1119  // convert to bytes.
1120  Long64_t mfs = (Long64_t)m_maxFileSize.value() * (Long64_t)1048576;
1121  Long64_t mfs_warn = mfs * 95 / 100;
1122 
1123  updateFiles();
1124 
1125  std::map<std::string, std::pair<TFile*, Mode>>::const_iterator itr;
1126  for ( const auto& f : m_files ) {
1127  TFile* tf = f.second.first;
1128 
1129 #ifndef NDEBUG
1130  if ( msgLevel( MSG::DEBUG ) ) {
1131  debug() << "stream: " << f.first << " name: " << tf->GetName() << " size: " << tf->GetSize() << endmsg;
1132  }
1133 #endif
1134 
1135  // Signal job to terminate if output file is too large
1136  if ( tf->GetSize() > mfs ) {
1137 
1138  m_signaledStop = true;
1139 
1140  fatal() << "file \"" << tf->GetName() << "\" associated with stream \"" << f.first
1141  << "\" has exceeded the max file size of " << m_maxFileSize.value() << "MB. Terminating Job." << endmsg;
1142 
1143  IEventProcessor* evt = nullptr;
1144  if ( service( "ApplicationMgr", evt, true ).isSuccess() ) {
1145  evt->stopRun();
1146  evt->release();
1147  } else {
1148  abort();
1149  }
1150  } else if ( tf->GetSize() > mfs_warn ) {
1151  warning() << "file \"" << tf->GetName() << "\" associated with stream \"" << f.first
1152  << "\" is at 95% of its maximum allowable file size of " << m_maxFileSize.value() << "MB" << endmsg;
1153  }
1154  }
1155 }
1156 
1161 {
1162  bool all_good = true;
1163  if ( msgLevel( MSG::DEBUG ) ) {
1164  debug() << "reinitializing I/O..." << endmsg;
1165  }
1166 
1167  // retrieve the I/O component manager...
1168 
1169  IIoComponentMgr* iomgr = nullptr;
1170 
1171  if ( service( "IoComponentMgr", iomgr, true ).isFailure() ) {
1172  error() << "could not retrieve I/O component manager !" << endmsg;
1173  return StatusCode::FAILURE;
1174  }
1175 
1176  GlobalDirectoryRestore restore( m_svcMut );
1177  // to hide the expected errors upon closing the files whose
1178  // file descriptors have been swept under the rug...
1179  gErrorIgnoreLevel = kFatal;
1180 
1181  for ( auto& ifile : m_files ) {
1182  TFile* f = ifile.second.first;
1183  std::string fname = f->GetName();
1184  if ( msgLevel( MSG::DEBUG ) ) {
1185  debug() << "file [" << fname << "] mode: [" << f->GetOption() << "] r:" << f->GetFileBytesRead()
1186  << " w:" << f->GetFileBytesWritten() << " cnt:" << f->GetFileCounter() << endmsg;
1187  }
1188 
1189  if ( ifile.second.second == READ ) {
1190  if ( msgLevel( MSG::DEBUG ) ) {
1191  debug() << " TFile opened in READ mode: not reassigning names" << endmsg;
1192  }
1193  continue;
1194  }
1195 
1196  if ( !iomgr->io_retrieve( this, fname ).isSuccess() ) {
1197  error() << "could not retrieve new name for [" << fname << "] !!" << endmsg;
1198  all_good = false;
1199  continue;
1200  } else {
1201  if ( msgLevel( MSG::DEBUG ) ) {
1202  debug() << "got a new name [" << fname << "]..." << endmsg;
1203  }
1204  }
1205 
1206  void* vf = nullptr;
1207  Option_t* opts = f->GetOption();
1208  int r = p_fileMgr->open( Io::ROOT, name(), fname, Io::WRITE, vf, "HIST" );
1209  if ( r != 0 ) {
1210  error() << "unable to open file \"" << fname << "\" for writing" << endmsg;
1211  return StatusCode::FAILURE;
1212  }
1213  TFile* newfile = (TFile*)vf;
1214  newfile->SetOption( opts );
1215 
1216  if ( ifile.second.second != THistSvc::READ ) {
1217  copyFileLayout( newfile, f );
1218  ifile.second.first = newfile;
1219  }
1220 
1221  // loop over all uids and migrate them to the new file
1222  // XXX FIXME: this double loop sucks...
1223  for ( auto& uid : m_uidsX ) {
1224  THistID& hid = uid.second;
1225  if ( hid.file != f ) continue;
1226  TDirectory* olddir = this->changeDir( hid );
1227  hid.file = newfile;
1228  // side-effect: create needed directories...
1229  TDirectory* newdir = this->changeDir( hid );
1230  TClass* cl = hid.obj->IsA();
1231 
1232  // migrate the objects to the new file.
1233  // thanks to the object model of ROOT, it is super easy.
1234  if ( cl->InheritsFrom( "TTree" ) ) {
1235  dynamic_cast<TTree*>( hid.obj )->SetDirectory( newdir );
1236  dynamic_cast<TTree*>( hid.obj )->Reset();
1237  } else if ( cl->InheritsFrom( "TH1" ) ) {
1238  dynamic_cast<TH1*>( hid.obj )->SetDirectory( newdir );
1239  dynamic_cast<TH1*>( hid.obj )->Reset();
1240  } else if ( cl->InheritsFrom( "TGraph" ) ) {
1241  olddir->Remove( hid.obj );
1242  newdir->Append( hid.obj );
1243  } else {
1244  error() << "id: \"" << hid.id << "\" is not a inheriting from a class "
1245  << "we know how to handle (received [" << cl->GetName() << "], "
1246  << "expected [TTree, TH1 or TGraph]) !" << endmsg << "attaching to current dir [" << newdir->GetPath()
1247  << "] "
1248  << "nonetheless..." << endmsg;
1249  olddir->Remove( hid.obj );
1250  newdir->Append( hid.obj );
1251  }
1252  }
1253  f->ReOpen( "READ" );
1254  p_fileMgr->close( f, name() );
1255  f = newfile;
1256  }
1257 
1258  return all_good ? StatusCode::SUCCESS : StatusCode::FAILURE;
1259 }
1260 
1261 //*************************************************************************//
1262 
1264 {
1265  m_gDirectory = gDirectory;
1266  m_gFile = gFile;
1267  m_gErrorIgnoreLevel = gErrorIgnoreLevel;
1268 }
1269 
1271 {
1272  gDirectory = m_gDirectory;
1273  gFile = m_gFile;
1274  gErrorIgnoreLevel = m_gErrorIgnoreLevel;
1275 }
1276 
1277 //*************************************************************************//
1278 
1279 template <typename T>
1280 T* THistSvc::readHist( const std::string& id ) const
1281 {
1282  return dynamic_cast<T*>( readHist_i<T>( id ) );
1283 }
1284 
1285 TTree* THistSvc::readTree( const std::string& id ) const { return dynamic_cast<TTree*>( readHist_i<TTree>( id ) ); }
1286 
1288 {
1289  // If TTrees grow beyond TTree::fgMaxTreeSize, a new file is
1290  // automatically created by root, and the old one closed. We
1291  // need to migrate all the UIDs over to show the correct file
1292  // pointer. This is ugly.
1293 
1294  if ( msgLevel( MSG::DEBUG ) ) debug() << "updateFiles()" << endmsg;
1295 
1296  for ( auto uitr = m_uidsX.begin(); uitr != m_uidsX.end(); ++uitr ) {
1297 #ifndef NDEBUG
1298  if ( msgLevel( MSG::VERBOSE ) )
1299  verbose() << " update: " << uitr->first << " " << uitr->second.id << " " << uitr->second.mode << endmsg;
1300 #endif
1301  TObject* to = uitr->second.obj;
1302  TFile* oldFile = uitr->second.file;
1303  if ( !to ) {
1304  warning() << uitr->first << ": TObject == 0" << endmsg;
1305  } else if ( uitr->second.temp || uitr->second.mode == READ ) {
1306 // do nothing - no need to check how big the file is since we
1307 // are just reading it.
1308 #ifndef NDEBUG
1309  if ( msgLevel( MSG::VERBOSE ) ) verbose() << " skipping" << endmsg;
1310 #endif
1311  } else if ( to->IsA()->InheritsFrom( "TTree" ) ) {
1312  TTree* tr = dynamic_cast<TTree*>( to );
1313  TFile* newFile = tr->GetCurrentFile();
1314 
1315  if ( oldFile != newFile ) {
1316  std::string newFileName = newFile->GetName();
1317  std::string oldFileName, streamName, rem;
1318  TFile* dummy = nullptr;
1319  findStream( uitr->second.id, streamName, rem, dummy );
1320 
1321  for ( auto& itr : m_files ) {
1322  if ( itr.second.first == oldFile ) {
1323  itr.second.first = newFile;
1324  }
1325  }
1326 
1327  for ( auto uitr2 = uitr; uitr2 != m_uidsX.end(); ++uitr2 ) {
1328  if ( uitr2->second.file == oldFile ) {
1329  uitr2->second.file = newFile;
1330  }
1331  }
1332 
1334  [&]( streamMap::const_reference s ) { return s.second == streamName; } );
1335  if ( sitr != std::end( m_fileStreams ) ) oldFileName = sitr->first;
1336 
1337 #ifndef NDEBUG
1338  if ( msgLevel( MSG::DEBUG ) ) {
1339  debug() << "migrating uid: " << uitr->second.id << " stream: " << streamName
1340  << " oldFile: " << oldFileName << " newFile: " << newFileName << endmsg;
1341  }
1342 #endif
1343 
1344  if ( !oldFileName.empty() ) {
1345  auto i = m_fileStreams.lower_bound( oldFileName );
1346  while ( i != std::end( m_fileStreams ) && i->first == oldFileName ) {
1347 #ifndef NDEBUG
1348  if ( msgLevel( MSG::DEBUG ) ) {
1349  debug() << "changing filename \"" << i->first << "\" to \"" << newFileName << "\" for stream \""
1350  << i->second << "\"" << endmsg;
1351  }
1352 #endif
1353  std::string nm = std::move( i->second );
1354  i = m_fileStreams.erase( i );
1355  m_fileStreams.emplace( newFileName, std::move( nm ) );
1356  }
1357  } else {
1358  error() << "Problems updating fileStreams with new file name" << endmsg;
1359  }
1360  }
1361  }
1362  }
1363 }
1364 
1366 {
1367  updateFiles();
1368 
1370  auto mode = i.second.second;
1371  auto file = i.second.first;
1372  if ( mode == WRITE || mode == UPDATE || mode == SHARE ) {
1373  file->Write( "", TObject::kOverwrite );
1374  } else if ( mode == APPEND ) {
1375  file->Write( "" );
1376  }
1377  } );
1378 
1379  if ( msgLevel( MSG::DEBUG ) ) {
1380  debug() << "THistSvc::writeObjectsToFile()::List of Files connected in ROOT " << endmsg;
1381  TSeqCollection* filelist = gROOT->GetListOfFiles();
1382  for ( int ii = 0; ii < filelist->GetEntries(); ii++ ) {
1383  debug() << "THistSvc::writeObjectsToFile()::List of Files connected in ROOT: \"" << filelist->At( ii )->GetName()
1384  << "\"" << endmsg;
1385  }
1386  }
1387 
1388  return StatusCode::SUCCESS;
1389 }
1390 
1392 {
1393  auto loc = ident.find( " " );
1394  std::string stream = ident.substr( 0, loc );
1395  char typ( 0 );
1397  std::vector<Prop> props;
1398  std::string filename, db_typ( "ROOT" );
1399  int cl( 1 );
1400 
1401  if ( loc != std::string::npos ) {
1402  using Parser = Gaudi::Utils::AttribStringParser;
1403  for ( auto attrib : Parser( ident.substr( loc + 1 ) ) ) {
1404  auto TAG = boost::algorithm::to_upper_copy( attrib.tag );
1405  auto VAL = boost::algorithm::to_upper_copy( attrib.value );
1406 
1407  if ( TAG == "FILE" || TAG == "DATAFILE" ) {
1408  filename = attrib.value;
1409  removeDoubleSlash( filename );
1410  } else if ( TAG == "OPT" ) {
1411  if ( VAL == "APPEND" || VAL == "UPDATE" ) {
1412  typ = 'A';
1413  } else if ( VAL == "CREATE" || VAL == "NEW" || VAL == "WRITE" ) {
1414  typ = 'N';
1415  } else if ( VAL == "RECREATE" ) {
1416  typ = 'R';
1417  } else if ( VAL == "SHARE" ) {
1418  typ = 'S';
1419  } else if ( VAL == "OLD" || VAL == "READ" ) {
1420  typ = 'O';
1421  } else {
1422  error() << "Unknown OPT: \"" << attrib.value << "\"" << endmsg;
1423  typ = 0;
1424  }
1425  } else if ( TAG == "TYP" ) {
1426  db_typ = std::move( attrib.value );
1427  } else if ( TAG == "CL" ) {
1428  cl = std::stoi( attrib.value );
1429  } else {
1430  props.emplace_back( attrib.tag, attrib.value );
1431  }
1432  }
1433  }
1434 
1435  if ( stream == "temp" ) {
1436  error() << "in JobOption \"" << ident << "\": stream name \"temp\" reserved." << endmsg;
1437  return StatusCode::FAILURE;
1438  }
1439 
1440  if ( db_typ != "ROOT" ) {
1441  error() << "in JobOption \"" << ident << "\": technology type \"" << db_typ << "\" not supported." << endmsg;
1442  return StatusCode::FAILURE;
1443  }
1444 
1445  if ( m_files.find( stream ) != m_files.end() ) {
1446  error() << "in JobOption \"" << ident << "\":\n stream \"" << stream << "\" already connected to file: \""
1447  << m_files[stream].first->GetName() << "\"" << endmsg;
1448  return StatusCode::FAILURE;
1449  }
1450 
1451  Mode newMode;
1452  if ( typ == 'O' ) {
1453  newMode = THistSvc::READ;
1454  } else if ( typ == 'N' ) {
1455  newMode = THistSvc::WRITE;
1456  } else if ( typ == 'A' ) {
1457  newMode = THistSvc::APPEND;
1458  } else if ( typ == 'R' ) {
1459  newMode = THistSvc::UPDATE;
1460  } else if ( typ == 'S' ) {
1461  newMode = THistSvc::SHARE;
1462  } else {
1463  // something else?
1464  error() << "No OPT= specified or unknown access mode in: " << ident << endmsg;
1465  return StatusCode::FAILURE;
1466  }
1467 
1468  // Is this file already connected to another stream?
1469  if ( m_fileStreams.find( filename ) != m_fileStreams.end() ) {
1470  auto fitr = m_fileStreams.equal_range( filename );
1471 
1472  const std::string& oldstream = fitr.first->second;
1473 
1474  const auto& f_info = m_files[oldstream];
1475 
1476  if ( newMode != f_info.second ) {
1477  error() << "in JobOption \"" << ident << "\":\n file \"" << filename << "\" already opened by stream: \""
1478  << oldstream << "\" with different access mode." << endmsg;
1479  return StatusCode::FAILURE;
1480  } else {
1481  TFile* f2 = f_info.first;
1482  m_files[stream] = std::make_pair( f2, newMode );
1483  if ( msgLevel( MSG::DEBUG ) )
1484  debug() << "Connecting stream: \"" << stream << "\" to previously opened TFile: \"" << filename << "\""
1485  << endmsg;
1486  return StatusCode::SUCCESS;
1487  }
1488  }
1489 
1490  IIncidentSvc* pi = nullptr;
1491  if ( service( "IncidentSvc", pi ).isFailure() ) {
1492  error() << "Unable to get the IncidentSvc" << endmsg;
1493  return StatusCode::FAILURE;
1494  }
1495 
1496  void* vf = nullptr;
1497  TFile* f = nullptr;
1498 
1499  if ( newMode == THistSvc::READ ) {
1500  // old file
1501  int r = p_fileMgr->open( Io::ROOT, name(), filename, Io::READ, vf, "HIST" );
1502 
1503  if ( r != 0 ) {
1504  error() << "Unable to open ROOT file " << filename << " for reading" << endmsg;
1505  return StatusCode::FAILURE;
1506  }
1507 
1508  f = (TFile*)vf;
1509 
1510  // FIX ME!
1511  pi->fireIncident( FileIncident( name(), "BeginHistFile", filename ) );
1512 
1513  } else if ( newMode == THistSvc::WRITE ) {
1514  // new file. error if file exists
1515  int r = p_fileMgr->open( Io::ROOT, name(), filename, ( Io::WRITE | Io::CREATE | Io::EXCL ), vf, "HIST" );
1516 
1517  if ( r != 0 ) {
1518  error() << "Unable to open ROOT file " << filename << " for writing" << endmsg;
1519  return StatusCode::FAILURE;
1520  }
1521 
1522  f = (TFile*)vf;
1523 
1524  } else if ( newMode == THistSvc::APPEND ) {
1525  // update file
1526  int r = p_fileMgr->open( Io::ROOT, name(), filename, ( Io::WRITE | Io::APPEND ), vf, "HIST" );
1527  if ( r != 0 ) {
1528  error() << "unable to open file \"" << filename << "\" for appending" << endmsg;
1529  return StatusCode::FAILURE;
1530  }
1531 
1532  f = (TFile*)vf;
1533 
1534  } else if ( newMode == THistSvc::SHARE ) {
1535  // SHARE file type
1536  // For SHARE files, all data will be stored in a temp file and will be
1537  // merged into the target file in writeObjectsToFile() when finalize(),
1538  // this help to solve some confliction. e.g. with storegate
1539  static int ishared = 0;
1540  std::string realfilename = filename;
1541  filename = "tmp_THistSvc_" + std::to_string( ishared++ ) + ".root";
1542 
1543  if ( msgLevel( MSG::DEBUG ) ) {
1544  debug() << "Creating temp file \"" << filename << "\" and realfilename=" << realfilename << endmsg;
1545  }
1546  m_sharedFiles[stream] = realfilename;
1547 
1548  int r = p_fileMgr->open( Io::ROOT, name(), filename, ( Io::WRITE | Io::CREATE | Io::EXCL ), vf, "HIST" );
1549 
1550  if ( r != 0 ) {
1551  error() << "Unable to open ROOT file " << filename << " for writing" << endmsg;
1552  return StatusCode::FAILURE;
1553  }
1554 
1555  f = (TFile*)vf;
1556 
1557  } else if ( newMode == THistSvc::UPDATE ) {
1558  // update file
1559  int r = p_fileMgr->open( Io::ROOT, name(), filename, ( Io::WRITE | Io::CREATE ), vf, "HIST" );
1560 
1561  if ( r != 0 ) {
1562  error() << "Unable to open ROOT file " << filename << " for appending" << endmsg;
1563  return StatusCode::FAILURE;
1564  }
1565 
1566  f = (TFile*)vf;
1567  }
1568 
1569  m_files[stream] = std::make_pair( f, newMode );
1570  m_fileStreams.insert( std::make_pair( filename, stream ) );
1571 
1572  if ( msgLevel( MSG::DEBUG ) ) {
1573  debug() << "Opening TFile \"" << filename << "\" stream: \"" << stream << "\" mode: \"" << typ << "\""
1574  << " comp level: " << cl << endmsg;
1575  }
1576 
1577  return StatusCode::SUCCESS;
1578 }
1579 
1580 TDirectory* THistSvc::changeDir( const THistSvc::THistID& hid ) const
1581 {
1582  std::string uid = hid.id;
1583  TFile* file = hid.file;
1584  std::string stream, fdir, bdir, dir, id;
1585 
1586  if ( file ) {
1587  file->cd( "/" );
1588  } else {
1589  gROOT->cd();
1590  }
1591 
1592  fdir = uid;
1593  bdir = stripDirectoryName( fdir );
1594 
1595  while ( ( dir = stripDirectoryName( fdir ) ) != "" ) {
1596  if ( !gDirectory->GetKey( dir.c_str() ) ) {
1597  gDirectory->mkdir( dir.c_str() );
1598  }
1599  gDirectory->cd( dir.c_str() );
1600  }
1601 
1602  return gDirectory;
1603 }
1604 
1606 {
1607  std::string::size_type i = dir.find( "/" );
1608 
1609  if ( i == std::string::npos ) return {};
1610 
1611  if ( i == 0 ) {
1612  dir.erase( 0, 1 );
1613  return stripDirectoryName( dir );
1614  }
1615 
1616  std::string root = dir.substr( 0, i );
1617  dir.erase( 0, i );
1618 
1619  return root;
1620 }
1621 
1623 {
1624  while ( id.find( "//" ) != std::string::npos ) {
1625  id.replace( id.find( "//" ), 2, "/" );
1626  }
1627 }
1628 
1629 void THistSvc::MergeRootFile( TDirectory* target, TDirectory* source )
1630 {
1631  if ( msgLevel( MSG::DEBUG ) ) {
1632  debug() << "Target path: " << target->GetPath() << endmsg;
1633  }
1634  TString path( (char*)strstr( target->GetPath(), ":" ) );
1635  path.Remove( 0, 2 );
1636 
1637  source->cd( path );
1638  TDirectory* current_sourcedir = gDirectory;
1639 
1640  // loop over all keys in this directory
1641  TList* lkeys = current_sourcedir->GetListOfKeys();
1642  int nkeys = lkeys->GetEntries();
1643  TKey* key = nullptr;
1644  for ( int jj = 0; jj < nkeys; jj++ ) {
1645  key = (TKey*)lkeys->At( jj );
1646  std::string pathnameinsource = current_sourcedir->GetPath() + std::string( "/" ) + key->GetName();
1647  if ( msgLevel( MSG::DEBUG ) ) {
1648  debug() << "Reading Key:" << pathnameinsource << endmsg;
1649  }
1650  TObject* obj = source->Get( pathnameinsource.c_str() );
1651 
1652  if ( obj ) {
1653  if ( obj->IsA()->InheritsFrom( "TDirectory" ) ) {
1654  // it's a subdirectory
1655  if ( msgLevel( MSG::DEBUG ) ) {
1656  debug() << "Found subdirectory " << obj->GetName() << endmsg;
1657  }
1658 
1659  // create a new subdir of same name and title in the target file
1660  target->cd();
1661  TDirectory* newtargetdir = target->mkdir( obj->GetName(), obj->GetTitle() );
1662 
1663  MergeRootFile( newtargetdir, source );
1664 
1665  } else if ( obj->IsA()->InheritsFrom( "TTree" ) ) {
1666  if ( msgLevel( MSG::DEBUG ) ) {
1667  debug() << "Found TTree " << obj->GetName() << endmsg;
1668  }
1669  TTree* mytree = dynamic_cast<TTree*>( obj );
1670  int nentries = (int)mytree->GetEntries();
1671  mytree->SetBranchStatus( "*", 1 );
1672 
1673  if ( msgLevel( MSG::DEBUG ) ) {
1674  debug() << "Dumping TTree " << nentries << " entries" << endmsg;
1675  }
1676  target->cd();
1677  mytree->CloneTree();
1678 
1679  } else {
1680  target->cd();
1681  obj->Write( key->GetName() );
1682  }
1683  }
1684  }
1685 }
1686 
1687 bool THistSvc::findStream( const std::string& id, std::string& stream, std::string& rem, TFile*& file ) const
1688 {
1689  auto pos = id.find( "/" );
1690 
1691  if ( pos == std::string::npos ) {
1692  // no "/" in id
1693  stream = "temp";
1694  rem = id;
1695  } else if ( pos != 0 ) {
1696  // id does not start with "/"
1697  stream = "temp";
1698  rem = id;
1699  } else {
1700  // id starts with "/"
1701 
1702  auto pos2 = id.find( "/", pos + 1 );
1703 
1704  if ( pos2 == std::string::npos ) {
1705  // need at least 2 "/" in format "/STREAM/name" or "/STREAM/dir/name"
1706  error() << "badly formed Hist/Tree id: \"" << id << "\"" << endmsg;
1707  return false;
1708  }
1709  parseString( id, stream, rem );
1710  }
1711 
1712  if ( stream == "temp" ) {
1713  file = nullptr;
1714  return true;
1715  }
1716 
1717  auto itr = m_files.find( stream );
1718  file = ( itr != m_files.end() ? itr->second.first : nullptr );
1719  if ( !file ) {
1720  warning() << "no stream \"" << stream << "\" associated with id: \"" << id << "\"" << endmsg;
1721  }
1722 
1723  return true;
1724 }
1725 
1727 {
1728  auto pos = id.find( "/" );
1729 
1730  if ( pos == std::string::npos ) {
1731  root.clear();
1732  rem = id;
1733  } else if ( pos == 0 ) {
1734  parseString( id.substr( 1 ), root, rem );
1735  } else {
1736  root = id.substr( 0, pos );
1737  rem = id.substr( pos + 1 );
1738  }
1739 }
1740 
1742  /*m_inputfile*/ )
1743 {
1745  debug() << "Delaying connection of Input Files until Initialize"
1746  << ". now in " << FSMState() << endmsg;
1747 
1748  m_delayConnect = true;
1749  } else {
1750  debug() << "Now connecting of Input Files" << endmsg;
1751 
1753 
1754  for ( const auto& itr : m_inputfile.value() ) {
1756  continue;
1757  }
1758  if ( connect( itr ).isFailure() ) {
1759  sc = StatusCode::FAILURE;
1760  } else {
1762  }
1763  }
1764 
1765  if ( !sc.isSuccess() ) {
1766  throw GaudiException( "Problem connecting inputfile !!", name(), StatusCode::FAILURE );
1767  }
1768  }
1769 }
1770 
1772  /*m_outputfile*/ )
1773 {
1775  debug() << "Delaying connection of Input Files until Initialize"
1776  << ". now in " << FSMState() << endmsg;
1777  m_delayConnect = true;
1778  } else {
1780  for ( const auto& itr : m_outputfile.value() ) {
1782  continue;
1783  }
1784  if ( connect( itr ).isFailure() ) {
1785  sc = StatusCode::FAILURE;
1786  } else {
1788  }
1789  }
1790 
1791  if ( !sc.isSuccess() ) {
1792  throw GaudiException( "Problem connecting outputfile !!", name(), StatusCode::FAILURE );
1793  }
1794  }
1795 }
1796 
1798  /* cl */ )
1799 {
1800  warning() << "\"CompressionLevel\" Property has been deprecated. "
1801  << "Set it via the \"CL=\" parameter in the \"Output\" Property" << endmsg;
1802 }
1803 
1804 void THistSvc::copyFileLayout( TDirectory* destination, TDirectory* source )
1805 {
1806  if ( msgLevel( MSG::DEBUG ) ) {
1807  debug() << "copyFileLayout() to destination path: " << destination->GetPath() << endmsg;
1808  }
1809 
1810  // strip out URLs
1811  TString path( (char*)strstr( destination->GetPath(), ":" ) );
1812  path.Remove( 0, 2 );
1813 
1814  source->cd( path );
1815  TDirectory* current_source_dir = gDirectory;
1816 
1817  // loop over all keys in this directory
1818  TList* key_list = current_source_dir->GetListOfKeys();
1819  int n = key_list->GetEntries();
1820  for ( int j = 0; j < n; ++j ) {
1821  TKey* k = (TKey*)key_list->At( j );
1822  const std::string source_pathname = current_source_dir->GetPath() + std::string( "/" ) + k->GetName();
1823  TObject* o = source->Get( source_pathname.c_str() );
1824 
1825  if ( o && o->IsA()->InheritsFrom( "TDirectory" ) ) {
1826  if ( msgLevel( MSG::VERBOSE ) ) {
1827  verbose() << " subdir [" << o->GetName() << "]..." << endmsg;
1828  }
1829  destination->cd();
1830  TDirectory* destination_dir = destination->mkdir( o->GetName(), o->GetTitle() );
1831  copyFileLayout( destination_dir, source );
1832  }
1833  } // loop over keys
1834  return;
1835 }
1836 
1837 size_t THistSvc::findHistID( const std::string& id, const THistID*& hid, const size_t& index ) const
1838 {
1839  GlobalDirectoryRestore restore( m_svcMut );
1840 
1841  std::string idr( id );
1842  removeDoubleSlash( idr );
1843 
1844  hid = 0;
1845 
1846  if ( idr.find( "/" ) == 0 ) {
1847  // fully specified name, starts with "/"
1848  auto itr = m_uids.find( idr );
1849  if ( itr == m_uids.end() ) {
1850  // no matches found
1851  return 0;
1852  } else {
1853  // one or more matches found (clones).
1854  if ( index >= itr->second->size() ) {
1855  error() << "no index " << index << " found for Hist " << idr << endmsg;
1856  return 0;
1857  }
1858  hid = &( itr->second->at( index ) );
1859  return 1;
1860  }
1861  } else {
1862  // name not fully specified.
1863  auto mitr = m_ids.equal_range( idr );
1864  if ( mitr.first == mitr.second ) {
1865  // not found
1866  return 0;
1867  } else if ( distance( mitr.first, mitr.second ) == 1 ) {
1868  // one found
1869  if ( index >= mitr.first->second->size() ) {
1870  error() << "no index " << index << " found for Hist " << idr << endmsg;
1871  return 0;
1872  }
1873  hid = &( mitr.first->second->at( 0 ) );
1874  return 1;
1875  } else {
1876  // multiple matches
1877  hid = &( mitr.first->second->at( 0 ) );
1878  return distance( mitr.first, mitr.second );
1879  }
1880  }
1881 }
1882 
1883 void THistSvc::dump() const
1884 {
1885  std::ostringstream ost;
1886 
1887  // list< vector<THistID> >
1888  ost << "m_hlist: size: " << m_hlist.size() << "\n";
1889  for ( auto& vh : m_hlist ) {
1890  ost << " - " << vh->at( 0 ) << " :: [" << vh << "] " << vh->size() << " {";
1891  for ( auto& e : *vh ) {
1892  TObject* o = e.obj;
1893  ost << "[" << o << "]";
1894  }
1895  ost << "}\n";
1896  }
1897 
1898  // map uid -> vector<THistID>*
1899  ost << "\n"
1900  << "m_uids: " << m_uids.size() << "\n";
1901  for ( auto& e : m_uids ) {
1902  ost << " - " << e.first << " [" << e.second << "]" << std::endl;
1903  }
1904 
1905  // multimap id -> vector<THistID>*
1906  ost << "\n"
1907  << "m_ids: " << m_ids.size() << "\n";
1908  for ( auto& e : m_ids ) {
1909  ost << " - " << e.first << " [" << e.second << "]" << std::endl;
1910  }
1911 
1912  // map TObject* -> THistID*
1913  ost << "\n"
1914  << "m_tobjs: " << m_tobjs.size() << "\n";
1915  for ( auto& e : m_tobjs ) {
1916  TObject* o = e.first;
1917  THistID& i = e.second.first->at( e.second.second );
1918  ost << " - " << o << " -> " << i << std::endl;
1919  }
1920 
1921  debug() << "dumping THistSvc contents\n" << ost.str() << endmsg;
1922 }
1923 
1924 StatusCode THistSvc::merge( const THistID& hid ) { return merge( hid.id ); }
1925 
1927 {
1928  const std::string& name = vh->at( 0 ).id;
1929  if ( vh->size() == 1 ) {
1930  debug() << "merge: id: \"" << name << "\" is size 1. nothing to do" << endmsg;
1931  return StatusCode::SUCCESS;
1932  }
1933 
1934  if ( !vh->at( 0 ).obj->IsA()->InheritsFrom( "TH1" ) ) {
1935  error() << "merge: id \"" << name << "\" is not a THn. Cannot merge" << endmsg;
1936  return StatusCode::FAILURE;
1937  }
1938 
1939  TList* l = new TList();
1940  for ( size_t i = 1; i < vh->size(); ++i ) {
1941  debug() << "merge: id: \"" << name << "\" (" << vh->at( i ).obj << ") adding index " << i << endmsg;
1942  l->Add( vh->at( i ).obj );
1943  }
1944 
1945  TH1* t0 = dynamic_cast<TH1*>( vh->at( 0 ).obj );
1946  if ( t0 == 0 ) {
1947  error() << "merge: could not dcast " << name << "(" << t0 << ") index " << 0 << " to TH1" << endmsg;
1948  return StatusCode::FAILURE;
1949  }
1950 
1951  Long64_t n = t0->Merge( l );
1952 
1953  debug() << "merge: id: \"" << name << "\" merged " << n << " entries" << endmsg;
1954 
1955  for ( size_t i = 1; i < vh->size(); ++i ) {
1956  TH1* th = dynamic_cast<TH1*>( vh->at( i ).obj );
1957  if ( th != 0 ) {
1958  debug() << "clearing index " << i << "(" << th << ")" << endmsg;
1959  th->SetDirectory( nullptr );
1960  th->Reset();
1961  } else {
1962  error() << "merge: could not dcast " << name << " index " << i << " to TH1" << endmsg;
1963  return StatusCode::FAILURE;
1964  }
1965  }
1966  return StatusCode::SUCCESS;
1967 }
1968 
1970 {
1971  if ( fa->tech() != Io::ROOT ) {
1972  // This should never happen
1973  return StatusCode::SUCCESS;
1974  }
1975 
1976  if ( fa->desc() != "HIST" ) {
1977  return StatusCode::SUCCESS;
1978  }
1979 
1980  p_incSvc->fireIncident( FileIncident( caller, "OpenHistFile", fa->name() ) );
1981 
1982  if ( fa->flags().isRead() ) {
1983  p_incSvc->fireIncident( FileIncident( caller, "BeginHistFile", fa->name() ) );
1984  } else if ( fa->flags().isWrite() ) {
1985  p_incSvc->fireIncident( FileIncident( caller, IncidentType::BeginOutputFile, fa->name() ) );
1986  } else {
1987  // for Io::RW
1988  p_incSvc->fireIncident( FileIncident( caller, IncidentType::BeginOutputFile, fa->name() ) );
1989  }
1990 
1991  return StatusCode::SUCCESS;
1992 }
1993 
1995 {
1996  if ( fa->tech() != Io::ROOT ) {
1997  // This should never happen
1998  return StatusCode::SUCCESS;
1999  }
2000 
2001  if ( fa->desc() != "HIST" ) {
2002  return StatusCode::SUCCESS;
2003  }
2004 
2005  if ( fa->flags().isRead() ) {
2006  p_incSvc->fireIncident( FileIncident( caller, IncidentType::FailInputFile, fa->name() ) );
2007  } else if ( fa->flags().isWrite() ) {
2008  p_incSvc->fireIncident( FileIncident( caller, IncidentType::FailOutputFile, fa->name() ) );
2009  } else {
2010  // for Io::RW
2011  p_incSvc->fireIncident( FileIncident( caller, "FailRWFile", fa->name() ) );
2012  }
2013 
2014  return StatusCode::SUCCESS;
2015 }
Parse attribute strings allowing iteration over the various attributes.
virtual StatusCode io_retrieve(IIoComponent *iocomponent, std::string &fname)=0
: retrieve the new filename for a given IIoComponent and
GlobalDirectoryRestore(THistSvcMutex_t &mut)
Definition: THistSvc.cpp:1263
Helper struct that bundles the histogram ID with a mutex, TFile and TObject*.
Definition: THistSvc.h:186
bool m_delayConnect
Definition: THistSvc.h:352
constexpr static const auto FAILURE
Definition: StatusCode.h:88
StatusCode initialize() override
Definition: Service.cpp:63
void MergeRootFile(TDirectory *, TDirectory *)
Definition: THistSvc.cpp:1629
virtual StatusCode stopRun()=0
Schedule a stop of the current event processing.
StatusCode getGraph(const std::string &name, TGraph *&) const override
Return TGraph with given name.
Definition: THistSvc.cpp:481
This class is the FileIncident.
Definition: FileIncident.h:17
T empty(T...args)
StatusCode initialize() override
Definition: THistSvc.cpp:65
StatusCode deReg(const std::string &name) override
Deregister object with given name and give up ownership (without deletion!)
Definition: THistSvc.cpp:571
Define general base for Gaudi exception.
virtual Io::open_t open(const Io::IoTech &, const std::string &caller, const std::string &fname, const Io::IoFlags &, Io::Fd &, void *&, const std::string &desc, const bool shared=false)=0
The ISvcLocator is the interface implemented by the Service Factory in the Application Manager to loc...
Definition: ISvcLocator.h:25
const std::string & name() const override
Retrieve name of the service.
Definition: Service.cpp:288
TTree * readTree(const std::string &name) const
Definition: THistSvc.cpp:1285
std::string m_curstream
Definition: THistSvc.h:355
StatusCode finalize() override
Definition: Service.cpp:173
MsgStream & info() const
shortcut for the method msgStream(MSG::INFO)
bool m_signaledStop
Definition: THistSvc.h:351
StatusCode regShared(const std::string &name, std::unique_ptr< TH1 >, LockedHandle< TH1 > &) override
Register shared object of type TH1 and return LockedHandle for that object.
Definition: THistSvc.cpp:491
std::vector< std::string > getGraphs() const override
Definition: THistSvc.cpp:696
uidXMap m_uidsX
Definition: THistSvc.h:241
This file contains the class definition for the FileIncident class.
bool exists(const std::string &name) const override
Check if object with given name is managed by THistSvcMT.
Definition: THistSvc.cpp:676
IIncidentSvc * p_incSvc
Definition: THistSvc.h:348
bool isSuccess() const
Definition: StatusCode.h:287
bool findStream(const std::string &name, std::string &root, std::string &rem, TFile *&file) const
Definition: THistSvc.cpp:1687
StatusCode getTHists(TDirectory *td, TList &, bool recurse=false) const override
Definition: THistSvc.cpp:705
T rfind(T...args)
T to_string(T...args)
MsgStream & verbose() const
shortcut for the method msgStream(MSG::VERBOSE)
T endl(T...args)
StatusCode writeObjectsToFile()
Definition: THistSvc.cpp:1365
StatusCode merge(const std::string &id) override
Merge all clones for object with a given id.
Definition: THistSvc.cpp:654
T end(T...args)
StatusCode rootOpenAction(FILEMGR_CALLBACK_ARGS)
Definition: THistSvc.cpp:1969
void copyFileLayout(TDirectory *, TDirectory *)
helper function to recursively copy the layout of a TFile into a new TFile
Definition: THistSvc.cpp:1804
TDirectory * changeDir(const THistSvc::THistID &hid) const
Definition: THistSvc.cpp:1580
T lower_bound(T...args)
T remove(T...args)
StatusCode getHist(const std::string &name, TH1 *&, size_t index=0) const override
Return histogram with given name as TH1*, THistSvcMT still owns object.
Definition: THistSvc.cpp:369
void setupCompressionLevel(Gaudi::Details::PropertyBase &cmp)
Definition: THistSvc.cpp:1797
STL class.
bool isFailure() const
Definition: StatusCode.h:139
Gaudi::Property< std::vector< std::string > > m_outputfile
Definition: THistSvc.h:343
objMap_t m_tobjs
Definition: THistSvc.h:260
MsgStream & err() const
shortcut for the method msgStream(MSG::ERROR)
std::vector< std::string > getHists() const override
Definition: THistSvc.cpp:678
#define DECLARE_COMPONENT(type)
Definition: PluginService.h:33
STL class.
virtual StatusCode regAction(Io::bfcn_action_t, const Io::Action &, const std::string &d="")=0
T at(T...args)
const std::string & name() const
Definition: IFileMgr.h:189
hlist_t m_hlist
Definition: THistSvc.h:255
idMap_t m_ids
Definition: THistSvc.h:257
Gaudi::Property< int > m_autoSave
Definition: THistSvc.h:337
T push_back(T...args)
MsgStream & error() const
shortcut for the method msgStream(MSG::ERROR)
std::string id
Definition: THistSvc.h:187
virtual void fireIncident(const Incident &incident)=0
Fire an Incident.
std::string stripDirectoryName(std::string &dir) const
Definition: THistSvc.cpp:1605
MsgStream & warning() const
shortcut for the method msgStream(MSG::WARNING)
const std::string & desc() const
Definition: IFileMgr.h:190
Gaudi::Property< std::vector< std::string > > m_inputfile
Definition: THistSvc.h:344
This class is used for returning status codes from appropriate routines.
Definition: StatusCode.h:51
bool m_okToConnect
Definition: THistSvc.h:353
Provides automatic lock/unlock access to a class upon deref of ptr.
Definition: LockedHandle.h:28
Gaudi::Property< bool > m_print
Definition: THistSvc.h:339
bool isWrite() const
Definition: IFileMgr.h:57
void handle(const Incident &) override
Definition: THistSvc.cpp:1113
Gaudi::Property< int > m_maxFileSize
Definition: THistSvc.h:340
T erase(T...args)
void dump() const
Definition: THistSvc.cpp:1883
StatusCode getTree(const std::string &name, TTree *&) const override
Return TTree with given name.
Definition: THistSvc.cpp:432
T make_pair(T...args)
StatusCode rootOpenErrAction(FILEMGR_CALLBACK_ARGS)
Definition: THistSvc.cpp:1994
PropertyBase base class allowing PropertyBase* collections to be "homogeneous".
Definition: Property.h:32
Gaudi::Property< int > m_compressionLevel
Definition: THistSvc.h:342
void parseString(const std::string &id, std::string &root, std::string &rem) const
Definition: THistSvc.cpp:1726
T clear(T...args)
StatusCode finalize() override
Definition: THistSvc.cpp:187
T move(T...args)
StatusCode regHist_i(std::unique_ptr< T > hist, const std::string &name, bool shared)
Definition: THistSvc.icc:17
constexpr static const auto SUCCESS
Definition: StatusCode.h:87
StatusCode regHist(const std::string &name) override
Register a new ROOT histogram TH*X with a name.
Definition: THistSvc.cpp:343
Mode
Enumerating all possible file access modes.
Definition: THistSvc.h:183
dictionary l
Definition: gaudirun.py:440
T get(T...args)
constexpr double nm
Definition: SystemOfUnits.h:83
T insert(T...args)
StatusCode getTTrees(TDirectory *td, TList &, bool recurse=false) const override
Definition: THistSvc.cpp:916
T find(T...args)
T length(T...args)
TObject * obj
Definition: THistSvc.h:189
STL class.
virtual unsigned long release()=0
Release Interface instance.
STL class.
StatusCode reinitialize() override
Definition: THistSvc.cpp:180
virtual Out operator()(const vector_of_const_< In > &inputs) const =0
MsgStream & debug() const
shortcut for the method msgStream(MSG::DEBUG)
IoTech tech() const
Definition: IFileMgr.h:191
T begin(T...args)
T back_inserter(T...args)
const StatusCode & ignore() const
Ignore/check StatusCode.
Definition: StatusCode.h:165
T c_str(T...args)
Base class for all Incidents (computing events).
Definition: Incident.h:17
virtual void addListener(IIncidentListener *lis, const std::string &type="", long priority=0, bool rethrow=false, bool singleShot=false)=0
Add listener.
uidMap_t m_uids
Definition: THistSvc.h:256
std::map< std::string, std::pair< TFile *, Mode > > m_files
Definition: THistSvc.h:262
T emplace(T...args)
T back(T...args)
string s
Definition: gaudirun.py:253
Gaudi::StateMachine::State FSMState() const override
Definition: Service.h:54
StatusCode connect(const std::string &)
Definition: THistSvc.cpp:1391
The IEventProcessor is the interface to process events.
virtual StatusCode io_register(IIoComponent *iocomponent)=0
: allow a IIoComponent to register itself with this manager so appropriate actions can be taken when ...
IFileMgr * p_fileMgr
Definition: THistSvc.h:349
bool isRead() const
Definition: IFileMgr.h:56
std::set< std::string > m_alreadyConnectedOutFiles
list of already connected files.
Definition: THistSvc.h:235
T substr(T...args)
StatusCode regTree(const std::string &name) override
Register a new TTree with a given name.
Definition: THistSvc.cpp:399
std::map< std::string, std::string > m_sharedFiles
Definition: THistSvc.h:266
size_t findHistID(const std::string &id, const THistID *&hid, const size_t &index=0) const
Definition: THistSvc.cpp:1837
StatusCode service(const std::string &name, const T *&psvc, bool createIf=true) const
Access a service by name, creating it if it doesn&#39;t already exist.
Definition: Service.h:85
std::vector< std::string > getTrees() const override
Definition: THistSvc.cpp:687
StatusCode getShared(const std::string &name, LockedHandle< TH1 > &) const override
Retrieve shared object with given name as TH1 through LockedHandle.
Definition: THistSvc.cpp:531
MsgStream & fatal() const
shortcut for the method msgStream(MSG::FATAL)
std::set< std::string > m_alreadyConnectedInFiles
list of already connected files.
Definition: THistSvc.h:231
void setupInputFile(Gaudi::Details::PropertyBase &inputfile)
call-back method to handle input stream property
Definition: THistSvc.cpp:1741
void setupOutputFile(Gaudi::Details::PropertyBase &outputfile)
call-back method to handle output stream property
Definition: THistSvc.cpp:1771
T for_each(T...args)
StatusCode regGraph(const std::string &name) override
Register a new TGraph with a given name.
Definition: THistSvc.cpp:442
Gaudi::Property< int > m_autoFlush
Definition: THistSvc.h:338
THistSvc(const std::string &name, ISvcLocator *svc)
Definition: THistSvc.cpp:58
IoFlags flags() const
Definition: IFileMgr.h:192
T stoi(T...args)
StatusCode io_reinit() override
callback method to reinitialize the internal state of the component for I/O purposes (e...
Definition: THistSvc.cpp:1160
THistSvcMutex_t m_svcMut
Definition: THistSvc.h:357
Helper class that manages ROOts global directory and file.
Definition: THistSvc.h:169
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition: MsgStream.h:209
constexpr double pi
The interface implemented by the IncidentSvc service.
Definition: IIncidentSvc.h:23
streamMap m_fileStreams
Definition: THistSvc.h:263
T * readHist(const std::string &name) const
Definition: THistSvc.cpp:1280
evt
Definition: IOTest.py:96
void removeDoubleSlash(std::string &) const
Definition: THistSvc.cpp:1622
T reserve(T...args)
void updateFiles()
Handle case where TTree grows beyond TTree::fgMaxTreeSize.
Definition: THistSvc.cpp:1287
MSG::Level msgLevel() const
get the cached level (originally extracted from the embedded MsgStream)
T emplace_back(T...args)
virtual Io::close_t close(const Io::Fd, const std::string &caller)=0