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