| The Gaudi Framework v32r1 (f65d50dc)

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