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