From 048c41ca36062704fed93bb02c5f755bb23d5d27 Mon Sep 17 00:00:00 2001 From: Rafal Bielski <rafal.bielski@cern.ch> Date: Mon, 28 May 2018 15:59:39 +0200 Subject: [PATCH] align cxx code with recent athena/master updates updated the HLT code to be in line with commit 2ac03440 includes all changes in master up to 28/05/2018 noon --- HLT/Trigger/TrigControl/TrigPSC/TrigPSC/Psc.h | 17 +- .../TrigPSC/share/TrigPSCPythonSetup.py | 2 +- HLT/Trigger/TrigControl/TrigPSC/src/Psc.cxx | 7 +- .../TrigServices/HltROBDataProviderSvc.h | 28 +- .../TrigServices/src/HltEventLoopMgr.cxx | 34 +- .../src/HltROBDataProviderSvc.cxx | 2 +- .../TrigServices/src/THistSvcHLT.cxx | 2008 +++++++++++++++-- .../TrigServices/src/THistSvcHLT.h | 332 ++- .../TrigServices/src/THistSvcHLT.icc | 330 ++- .../TrigServices/src/TrigMonTHistSvc.cxx | 43 +- .../TrigServices/src/TrigMonTHistSvc.h | 6 +- .../src/TrigSORFromPtreeHelper.cxx | 21 +- 12 files changed, 2546 insertions(+), 284 deletions(-) diff --git a/HLT/Trigger/TrigControl/TrigPSC/TrigPSC/Psc.h b/HLT/Trigger/TrigControl/TrigPSC/TrigPSC/Psc.h index 181314ff80d..4cfc8e5e3d7 100644 --- a/HLT/Trigger/TrigControl/TrigPSC/TrigPSC/Psc.h +++ b/HLT/Trigger/TrigControl/TrigPSC/TrigPSC/Psc.h @@ -17,7 +17,7 @@ #include "hltinterface/HLTInterface.h" #include "hltinterface/EventId.h" -// to be removed +// to be removed together with the Psc::process method #include "hltinterface/HLTResult.h" // Gaudi Includes @@ -39,13 +39,13 @@ namespace psc { // Fwd decl class Config; - + /** * Common base class for HLT Pesa Steering Controller. */ class Psc: public hltinterface::HLTInterface { - public: + public: /** * C'tor. (Nothing happens here...) */ @@ -103,9 +103,7 @@ namespace psc { virtual bool hltUserCommand (const boost::property_tree::ptree& args); /** - * Start the event loop - * - * The HLT will start requesting events only after this has been called. + * Starts the HLT event loop. The HLT framework will start requesting and processing events. */ virtual void doEventLoop (); @@ -144,11 +142,11 @@ namespace psc { IAppMgrUI* m_pesaAppMgr; ///< Application Manager std::string m_nameEventLoopMgr; ///< name of the event loop manager bool m_interactive; ///< Running in interactive mode (athenaMT/PT) - + // User command handling bool m_failNextUsrCmd; unsigned int m_sleepNextUsrCmd; - psc::Config * m_config; + psc::Config * m_config; // =========================== DEPRECATED METHODS ============================== @@ -167,8 +165,7 @@ namespace psc { hltinterface::HLTResult& hltr, const hltinterface::EventId& evId); - }; } - + #endif /* TRIGPSC_PSC_H */ diff --git a/HLT/Trigger/TrigControl/TrigPSC/share/TrigPSCPythonSetup.py b/HLT/Trigger/TrigControl/TrigPSC/share/TrigPSCPythonSetup.py index f80bbd9a1ae..0d584140216 100755 --- a/HLT/Trigger/TrigControl/TrigPSC/share/TrigPSCPythonSetup.py +++ b/HLT/Trigger/TrigControl/TrigPSC/share/TrigPSCPythonSetup.py @@ -42,7 +42,7 @@ if len(logLevel)==1: logLevel.append("ERROR") ### FOR DEVELOPMENT: force verbose log level -logLevel=["VERBOSE","INFO","ERROR"] +logLevel=["VERBOSE","DEBUG","INFO","ERROR"] ## test and set log level try: diff --git a/HLT/Trigger/TrigControl/TrigPSC/src/Psc.cxx b/HLT/Trigger/TrigControl/TrigPSC/src/Psc.cxx index bf89755586f..6865902ccbe 100644 --- a/HLT/Trigger/TrigControl/TrigPSC/src/Psc.cxx +++ b/HLT/Trigger/TrigControl/TrigPSC/src/Psc.cxx @@ -132,11 +132,11 @@ bool psc::Psc::configure(const ptree& config) */ void* libHandle = 0; auto retval = System::loadDynamicLib(dllname, &libHandle); - if (retval == 0) { + if (retval == 1) { ERS_DEBUG(1,"Successfully pre-loaded " << dllname << "library"); } else { - ERS_DEBUG(1,"Failed pre-loading " << dllname << "library with error code " << retval); + ERS_DEBUG(1,"Failed pre-loading " << dllname << "library, returned code " << retval); } } @@ -532,7 +532,6 @@ bool psc::Psc::prepareForRun (const ptree& args) return false; } - /* commenting out as shutdown() is private in master branch // Cleanup of dangling database connections from RDBAccessSvc ServiceHandle<IRDBAccessSvc> p_rdbAccessSvc("RDBAccessSvc","psc::Psc"); if(p_rdbAccessSvc->shutdown("*Everything*")) { @@ -542,7 +541,6 @@ bool psc::Psc::prepareForRun (const ptree& args) p_rdbAccessSvc->release(); return false; } - */ // sleep some time to allow the closing of DB connections; // actual timeout depends on connection parameters, we seem to have 5 seconds @@ -997,6 +995,7 @@ template <typename T> StatusCode psc::Psc::callOnEventLoopMgr(std::function<StatusCode (T*)> func, const std::string& name) const { + // FIXME static variables are dangerous when forking static T* processingMgr = 0; StatusCode sc; if(!processingMgr) // if we already got it, no need to find it again diff --git a/HLT/Trigger/TrigControl/TrigServices/TrigServices/HltROBDataProviderSvc.h b/HLT/Trigger/TrigControl/TrigServices/TrigServices/HltROBDataProviderSvc.h index 33878d27f3f..a9e37fbdcfb 100644 --- a/HLT/Trigger/TrigControl/TrigServices/TrigServices/HltROBDataProviderSvc.h +++ b/HLT/Trigger/TrigControl/TrigServices/TrigServices/HltROBDataProviderSvc.h @@ -81,22 +81,42 @@ public: /// --- Implementation of IROBDataProviderSvc interface --- /// Add ROBFragments to cache for given ROB ids, ROB fragments may be retrieved with DataCollector + virtual void addROBData(const EventContext& /*ctx*/, + const std::vector<uint32_t>& robIds, + const std::string callerName="UNKNOWN") + { + addROBData(robIds, callerName); + } virtual void addROBData(const std::vector<uint32_t>& robIds, const std::string callerName="UNKNOWN"); /// Add a given LVL1/HLT ROBFragment to cache + virtual void setNextEvent(const EventContext& /*ctx*/, + const std::vector<ROBF>& result) + { setNextEvent (result); } virtual void setNextEvent(const std::vector<ROBF>& result); /// Add all ROBFragments of a RawEvent to cache + virtual void setNextEvent(const EventContext& /*ctx*/, const RawEvent* re) + { setNextEvent(re); } virtual void setNextEvent(const RawEvent* re); /// Retrieve ROBFragments for given ROB ids from cache + virtual void getROBData(const EventContext& /*ctx*/, + const std::vector<uint32_t>& robIds, + std::vector<const ROBF*>& robFragments, + const std::string callerName="UNKNOWN") + { + getROBData (robIds, robFragments, callerName); + } virtual void getROBData(const std::vector<uint32_t>& robIds, std::vector<const ROBF*>& robFragments, const std::string callerName="UNKNOWN"); /// Retrieve the whole event. - virtual const RawEvent* getEvent() ; + virtual const RawEvent* getEvent(const EventContext& /*ctx*/) + { return getEvent(); } + virtual const RawEvent* getEvent(); /// --- Implementation of ITrigROBDataProviderSvc interface --- @@ -114,11 +134,17 @@ public: virtual std::map<uint32_t, ROBF>::iterator endROBCache() { return m_online_robmap.end(); } /// Flag to check if complete event data are already in cache + virtual bool isEventComplete(const EventContext& /*ctx*/) const { return m_isEventComplete; } virtual bool isEventComplete() { return m_isEventComplete; } /// Collect all data for an event from the ROS and put them into the cache /// Return value: number of ROBs which were retrieved to complete the event /// Optinonally the name of the caller of this method can be specified for cost monitoring + virtual int collectCompleteEventData(const EventContext& /*ctx*/, + const std::string callerName="UNKNOWN") + { + return collectCompleteEventData(callerName); + } virtual int collectCompleteEventData(const std::string callerName="UNKNOWN"); /// set the name of the program which uses the ROBDataProviderSvc diff --git a/HLT/Trigger/TrigControl/TrigServices/src/HltEventLoopMgr.cxx b/HLT/Trigger/TrigControl/TrigServices/src/HltEventLoopMgr.cxx index a234048618b..f432e02b11c 100644 --- a/HLT/Trigger/TrigControl/TrigServices/src/HltEventLoopMgr.cxx +++ b/HLT/Trigger/TrigControl/TrigServices/src/HltEventLoopMgr.cxx @@ -28,7 +28,6 @@ #include "TrigServices/HltEventLoopMgr.h" #include "TrigSORFromPtreeHelper.h" #include "TrigCOOLUpdateHelper.h" -#include "TrigPreFlightCheck.h" // TDAQ includes #include "hltinterface/DataCollector.h" @@ -275,28 +274,6 @@ StatusCode HltEventLoopMgr::initialize() m_threadPoolSize = m_threadPoolSvc->poolSize(); debug() << "ThreadPoolSvc available with pool size " << m_threadPoolSize << endmsg; } - - //---------------------------------------------------------------------------- - // Pre-flight check - //---------------------------------------------------------------------------- - ToolHandle<TrigPreFlightCheck> preFlightCheck("TrigPreFlightCheck"); - if (preFlightCheck.retrieve().isFailure()) { - fatal() << "Error retrieving TrigPreFlightCheck " + preFlightCheck << endmsg; - return StatusCode::FAILURE; - } - - // A failed pre-flight check is fatal in a partition - if (validPartition()) { - if (preFlightCheck->check(MSG::ERROR).isFailure()) { - fatal() << "Pre-flight check for HLT failed." << endmsg; - return StatusCode::FAILURE; - } - } - else { - if (preFlightCheck->check(MSG::WARNING).isFailure()) - warning() << "Pre-flight check for HLT failed." << endmsg; - } - preFlightCheck->release(); //---------------------------------------------------------------------------- // Setup the HLT Histogram Service when configured @@ -670,11 +647,16 @@ const SOR* HltEventLoopMgr::processRunParams(const ptree & pt) // update the run number m_currentRun = pt.get<uint32_t>("RunParams.run_number"); + // need to provide an event context extended with a run number, down the line passed to IOVDBSvc::signalBeginRun + EventContext runStartEventContext = {}; // with invalid evt number and slot number + runStartEventContext.setExtension(Atlas::ExtendedEventContext(m_evtStore->hiveProxyDict(), m_currentRun)); + // Fill SOR parameters from the ptree TrigSORFromPtreeHelper sorhelp{msgStream()}; - const SOR* sor = sorhelp.fillSOR(pt.get_child("RunParams")); - if(!sor) - error() << ST_WHERE << "setup of SOR from ptree failed" << endmsg; + const SOR* sor = sorhelp.fillSOR(pt.get_child("RunParams"),runStartEventContext); + if(!sor) { + error() << ST_WHERE << "setup of SOR from ptree failed" << endmsg; + } verbose() << "end of " << __FUNCTION__ << endmsg; return sor; diff --git a/HLT/Trigger/TrigControl/TrigServices/src/HltROBDataProviderSvc.cxx b/HLT/Trigger/TrigControl/TrigServices/src/HltROBDataProviderSvc.cxx index d063fafc783..d68ed1b6385 100644 --- a/HLT/Trigger/TrigControl/TrigServices/src/HltROBDataProviderSvc.cxx +++ b/HLT/Trigger/TrigControl/TrigServices/src/HltROBDataProviderSvc.cxx @@ -935,7 +935,7 @@ void HltROBDataProviderSvc::handle(const Incident& incident) { } // *-- booking path - std::string path = std::string("/EXPERT/"); + std::string path = std::string("/EXPERT/") + name() + "/"; // *-- number of bins for sub detector plots (55 SubDet max.) uint32_t n_bins_partEBSubDet = eformat::helper::SubDetectorDictionary.size(); diff --git a/HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.cxx b/HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.cxx index 2b5a0e823d1..12da877f9d1 100644 --- a/HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.cxx +++ b/HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.cxx @@ -1,289 +1,2023 @@ /* - Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration -*/ + * This is a copy of GaudiSvc/src/THistSvc with THistSvc renamed to THistSvcHLT + * to allow inheritance of this class by TrigMonTHistSvc. + */ +// system headers +#include <cstdio> +#include <sstream> +#include <streambuf> +// boost headers +#include "boost/algorithm/string/case_conv.hpp" + +// ROOT headers +#include "TDirectory.h" +#include "TError.h" +#include "TFile.h" +#include "TGraph.h" +#include "TKey.h" +#include "TROOT.h" + +// Gaudi headers +#include "GaudiKernel/AttribStringParser.h" +#include "GaudiKernel/FileIncident.h" +#include "GaudiKernel/GaudiException.h" +#include "GaudiKernel/IEventProcessor.h" +#include "GaudiKernel/IFileMgr.h" +#include "GaudiKernel/IIncidentSvc.h" +#include "GaudiKernel/IIoComponentMgr.h" +#include "GaudiKernel/IJobOptionsSvc.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/Property.h" + +// local headers #include "THistSvcHLT.h" -DECLARE_COMPONENT(THistSvcHLT) +DECLARE_COMPONENT( THistSvcHLT ) -THistSvcHLT::THistSvcHLT(const std::string& name, ISvcLocator* svcLoc) -: base_class(name, svcLoc) +namespace { - verbose() << "start of " << __FUNCTION__ << endmsg; - declareProperty("AutoSave", m_autoSave=0); - declareProperty("AutoFlush", m_autoFlush=0); - declareProperty("PrintAll", m_print=false); - declareProperty("MaxFileSize", m_maxFileSize=10240, - "maximum file size in MB. if exceeded, will cause an abort. -1 to never check."); - declareProperty("CompressionLevel", m_compressionLevel=1); - /*->declareUpdateHandler(&THistSvcHLT::setupCompressionLevel, this);*/ - declareProperty("Output", m_outputfile); - /*->declareUpdateHandler(&THistSvcHLT::setupOutputFile, this);*/ - declareProperty("Input", m_inputfile); - /*->declareUpdateHandler(&THistSvcHLT::setupInputFile, this);*/ - verbose() << "end of " << __FUNCTION__ << endmsg; + template <typename InputIterator, typename OutputIterator, typename UnaryOperation, typename UnaryPredicate> + OutputIterator transform_if( InputIterator first, InputIterator last, OutputIterator result, UnaryOperation op, + UnaryPredicate pred ) + { + while ( first != last ) { + if ( pred( *first ) ) *result++ = op( *first ); + ++first; + } + return result; + } + + constexpr struct select1st_t { + template <typename T, typename S> + const T& operator()( const std::pair<T, S>& p ) const + { + return p.first; + } + } select1st{}; +} + +//*************************************************************************// + +THistSvcHLT::THistSvcHLT( const std::string& name, ISvcLocator* svc ) : base_class( name, svc ) +{ + m_compressionLevel.declareUpdateHandler( &THistSvcHLT::setupCompressionLevel, this ); + m_outputfile.declareUpdateHandler( &THistSvcHLT::setupOutputFile, this ); + m_inputfile.declareUpdateHandler( &THistSvcHLT::setupInputFile, this ); } StatusCode THistSvcHLT::initialize() { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; - return StatusCode::SUCCESS; + GlobalDirectoryRestore restore( m_svcMut ); + + StatusCode status = Service::initialize(); + + if ( status.isFailure() ) { + error() << "initializing service" << endmsg; + return status; + } + + StatusCode st( StatusCode::SUCCESS ); + + try { + setupOutputFile( m_outputfile ); + } catch ( GaudiException& err ) { + error() << "Caught: " << err << endmsg; + st = StatusCode::FAILURE; + } + + try { + setupInputFile( m_inputfile ); + } catch ( GaudiException& err ) { + error() << "Caught: " << err << endmsg; + st = StatusCode::FAILURE; + } + + // Protect against multiple instances of TROOT + if ( !gROOT ) { + static TROOT root( "root", "ROOT I/O" ); + // gDebug = 99; + } else { + if ( msgLevel( MSG::VERBOSE ) ) { + verbose() << "ROOT already initialized, debug = " << gDebug << endmsg; + } + } + + if ( service( "IncidentSvc", p_incSvc, true ).isFailure() ) { + error() << "unable to get the IncidentSvc" << endmsg; + st = StatusCode::FAILURE; + } else { + p_incSvc->addListener( this, "EndEvent", 100, true ); + } + + if ( service( "FileMgr", p_fileMgr, true ).isFailure() ) { + error() << "unable to get the FileMgr" << endmsg; + st = StatusCode::FAILURE; + } else { + debug() << "got the FileMgr" << endmsg; + } + + // Register open/close callback actions + using namespace std::placeholders; + auto boa = [this]( const Io::FileAttr* fa, const std::string& caller ) { return this->rootOpenAction( fa, caller ); }; + if ( p_fileMgr->regAction( boa, Io::OPEN, Io::ROOT ).isFailure() ) { + error() << "unable to register ROOT file open action with FileMgr" << endmsg; + } + auto bea = [this]( const Io::FileAttr* fa, const std::string& caller ) { + return this->rootOpenErrAction( fa, caller ); + }; + if ( p_fileMgr->regAction( bea, Io::OPEN_ERR, Io::ROOT ).isFailure() ) { + error() << "unable to register ROOT file open Error action with FileMgr" << endmsg; + } + + m_okToConnect = true; + if ( m_delayConnect ) { + if ( !m_inputfile.value().empty() ) { + setupInputFile( m_inputfile ); + } + if ( !m_outputfile.value().empty() ) { + setupOutputFile( m_outputfile ); + } + + m_delayConnect = false; + } + m_alreadyConnectedOutFiles.clear(); + m_alreadyConnectedInFiles.clear(); + + IIoComponentMgr* iomgr = nullptr; + if ( service( "IoComponentMgr", iomgr, true ).isFailure() ) { + error() << "unable to get the IoComponentMgr" << endmsg; + st = StatusCode::FAILURE; + } else { + if ( !iomgr->io_register( this ).isSuccess() ) { + error() << "could not register with the I/O component manager !" << endmsg; + st = StatusCode::FAILURE; + } else { + bool all_good = true; + // register input/output files... + for ( const auto& reg : m_files ) { + const std::string& fname = reg.second.first->GetName(); + const IIoComponentMgr::IoMode::Type iomode = + ( reg.second.second == THistSvcHLT::READ ? IIoComponentMgr::IoMode::READ : IIoComponentMgr::IoMode::WRITE ); + if ( !iomgr->io_register( this, iomode, fname ).isSuccess() ) { + warning() << "could not register file [" << fname << "] with the I/O component manager..." << endmsg; + all_good = false; + } else { + info() << "registered file [" << fname << "]... [ok]" << endmsg; + } + } + if ( !all_good ) { + error() << "problem while registering input/output files with " + << "the I/O component manager !" << endmsg; + st = StatusCode::FAILURE; + } + } + } + + if ( st.isFailure() ) { + fatal() << "Unable to initialize THistSvcHLT" << endmsg; + } + + return st; } StatusCode THistSvcHLT::reinitialize() { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; + GlobalDirectoryRestore restore( m_svcMut ); + warning() << "reinitialize not implemented" << endmsg; return StatusCode::SUCCESS; } StatusCode THistSvcHLT::finalize() { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; - return StatusCode::SUCCESS; -} + GlobalDirectoryRestore restore( m_svcMut ); -StatusCode THistSvcHLT::regHist(const std::string& name) -{ - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; - return StatusCode::SUCCESS; + if ( msgLevel( MSG::DEBUG ) ) { + dump(); + debug() << "THistSvcHLT::finalize" << endmsg; + } + +#ifndef NDEBUG + if ( msgLevel( MSG::DEBUG ) ) { + for ( const auto& itr : m_uids ) { + THistID& thid = itr.second->at( 0 ); + TObject* tobj = thid.obj; + + std::string dirname( "none" ); + if ( tobj && tobj->IsA()->InheritsFrom( "TTree" ) ) { + TTree* tree = dynamic_cast<TTree*>( tobj ); + if ( tree->GetDirectory() != 0 ) { + dirname = tree->GetDirectory()->GetPath(); + } + } else if ( tobj && tobj->IsA()->InheritsFrom( "TGraph" ) ) { + if ( !thid.temp ) { + dirname = thid.file->GetPath(); + std::string id2( thid.id ); + id2.erase( 0, id2.find( "/", 1 ) ); + id2.erase( id2.rfind( "/" ), id2.length() ); + if ( id2.find( "/" ) == 0 ) { + id2.erase( 0, 1 ); + } + dirname += id2; + } else { + dirname = "/tmp"; + } + } else if ( tobj && tobj->IsA()->InheritsFrom( "TH1" ) ) { + TH1* th = dynamic_cast<TH1*>( tobj ); + if ( th == nullptr ) { + error() << "Couldn't dcast: " << itr.first << endmsg; + } else { + if ( th->GetDirectory() != 0 ) { + dirname = th->GetDirectory()->GetPath(); + } + } + } else if ( !tobj ) { + warning() << itr.first << " has NULL TObject ptr" << endmsg; + } + debug() << "finalize: " << thid << endmsg; + } + } +#endif + + if ( writeObjectsToFile().isFailure() ) { + error() << "problems writing histograms" << endmsg; + } + + if ( m_print ) { + info() << "Listing contents of ROOT files: " << endmsg; + } + std::vector<TFile*> deleted_files; + for ( auto& itr : m_files ) { + if ( std::find( deleted_files.begin(), deleted_files.end(), itr.second.first ) == deleted_files.end() ) { + deleted_files.push_back( itr.second.first ); + +#ifndef NDEBUG + if ( msgLevel( MSG::DEBUG ) ) { + debug() << "finalizing stream/file " << itr.first << ":" << itr.second.first->GetName() << endmsg; + } +#endif + } else { +#ifndef NDEBUG + if ( msgLevel( MSG::DEBUG ) ) { + debug() << "already finalized stream " << itr.first << endmsg; + } +#endif + continue; + } + + if ( m_print && msgLevel( MSG::INFO ) ) { + info() << "==> File: " << itr.second.first->GetName() << " stream: " << itr.first << endmsg; + + itr.second.first->Print( "base" ); + } + + std::string tmpfn = itr.second.first->GetName(); + + p_fileMgr->close( itr.second.first, name() ); + + IIncidentSvc* pIncidentSvc = nullptr; + if ( service( "IncidentSvc", pIncidentSvc ).isFailure() ) { + error() << "Unable to get the IncidentSvc" << endmsg; + return StatusCode::FAILURE; + } + + if ( itr.second.second == SHARE ) { + // Merge File + void* vfile = nullptr; + int returncode = + p_fileMgr->open( Io::ROOT, name(), m_sharedFiles[itr.first], Io::WRITE | Io::APPEND, vfile, "HIST" ); + + if ( returncode ) { + error() << "unable to open Final Output File: \"" << m_sharedFiles[itr.first] << "\" for merging" << endmsg; + return StatusCode::FAILURE; + } + + TFile* outputfile = (TFile*)vfile; + pIncidentSvc->fireIncident( FileIncident( name(), IncidentType::WroteToOutputFile, m_sharedFiles[itr.first] ) ); + + if ( msgLevel( MSG::DEBUG ) ) { + debug() << "THistSvcHLT::writeObjectsToFile()::Merging Rootfile " << endmsg; + } + + vfile = nullptr; + returncode = p_fileMgr->open( Io::ROOT, name(), tmpfn, Io::READ, vfile, "HIST" ); + + if ( returncode ) { + error() << "unable to open temporary file: \"" << tmpfn << endmsg; + return StatusCode::FAILURE; + } + + TFile* inputfile = (TFile*)vfile; + + outputfile->SetCompressionLevel( inputfile->GetCompressionLevel() ); + + MergeRootFile( outputfile, inputfile ); + + outputfile->Write(); + p_fileMgr->close( outputfile, name() ); + p_fileMgr->close( inputfile, name() ); + + if ( msgLevel( MSG::DEBUG ) ) { + debug() << "Trying to remove temporary file \"" << tmpfn << "\"" << endmsg; + } + + std::remove( tmpfn.c_str() ); + } + delete itr.second.first; + } + + m_files.clear(); + m_sharedFiles.clear(); + m_fileStreams.clear(); + m_hlist.clear(); // vhid* is deleted in m_tobjs + m_uids.clear(); // vhid* is deleted in m_tobjs + m_ids.clear(); // vhid* is deleted in m_tobjs + + for ( auto& obj : m_tobjs ) { + // TObject*'s are already dealt with through root file i/o + delete obj.second.first; // delete vhid* + } + m_tobjs.clear(); + + return Service::finalize(); } -StatusCode THistSvcHLT::regHist(const std::string& name, std::unique_ptr<TH1> hist) +//*************************************************************************// + +StatusCode THistSvcHLT::regHist( const std::string& id ) { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; - return StatusCode::SUCCESS; + std::unique_ptr<TH1> hist = nullptr; + return regHist_i( std::move( hist ), id, false ); } -StatusCode THistSvcHLT::regHist(const std::string& name, std::unique_ptr<TH1> hist, TH1* hist_ptr) +StatusCode THistSvcHLT::regHist( const std::string& id, std::unique_ptr<TH1> hist ) { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; - return StatusCode::SUCCESS; + return regHist_i( std::move( hist ), id, false ); } -StatusCode THistSvcHLT::regHist(const std::string& name, TH1*) +StatusCode THistSvcHLT::regHist( const std::string& id, std::unique_ptr<TH1> hist, TH1* hist_ptr ) { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; - return StatusCode::SUCCESS; + // This is only to support a common use case where the histogram is used after its registration + if ( hist_ptr != nullptr ) { + hist_ptr = hist.get(); + } + return regHist_i( std::move( hist ), id, false ); } -StatusCode THistSvcHLT::getHist(const std::string& name, TH1*&, size_t index) const +StatusCode THistSvcHLT::regHist( const std::string& id, TH1* hist_ptr ) { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; - return StatusCode::SUCCESS; + std::unique_ptr<TH1> hist( hist_ptr ); + return regHist_i( std::move( hist ), id, false ); } -StatusCode THistSvcHLT::getHist(const std::string& name, TH2*&, size_t index) const +StatusCode THistSvcHLT::getHist( const std::string& id, TH1*& hist, size_t ind ) const { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; - return StatusCode::SUCCESS; + hist = getHist_i<TH1>( id, ind ); + if ( hist != nullptr ) { + return StatusCode::SUCCESS; + } else { + return StatusCode::FAILURE; + } } -StatusCode THistSvcHLT::getHist(const std::string& name, TH3*&, size_t index) const +StatusCode THistSvcHLT::getHist( const std::string& id, TH2*& hist, size_t ind ) const { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; - return StatusCode::SUCCESS; + hist = getHist_i<TH2>( id, ind ); + if ( hist != nullptr ) { + return StatusCode::SUCCESS; + } else { + return StatusCode::FAILURE; + } } -StatusCode THistSvcHLT::regTree(const std::string& name) +StatusCode THistSvcHLT::getHist( const std::string& id, TH3*& hist, size_t ind ) const { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; - return StatusCode::SUCCESS; + hist = getHist_i<TH3>( id, ind ); + if ( hist != nullptr ) { + return StatusCode::SUCCESS; + } else { + return StatusCode::FAILURE; + } } -StatusCode THistSvcHLT::regTree(const std::string& name, TTree* tree) +StatusCode THistSvcHLT::regTree( const std::string& id ) { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; - return StatusCode::SUCCESS; + std::unique_ptr<TTree> tree = nullptr; + return regHist_i( std::move( tree ), id, false ); } -StatusCode THistSvcHLT::regTree(const std::string& name, std::unique_ptr<TTree> tree) +StatusCode THistSvcHLT::regTree( const std::string& id, std::unique_ptr<TTree> tree ) { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; - return StatusCode::SUCCESS; + StatusCode sc = regHist_i( std::move( tree ), id, false ); + TTree* tr = nullptr; + if ( getTree( id, tr ).isSuccess() && sc.isSuccess() ) { + if ( m_autoSave != 0 ) { + tr->SetAutoSave( m_autoSave ); + } + tr->SetAutoFlush( m_autoFlush ); + } + return sc; } -StatusCode THistSvcHLT::getTree( const std::string& name, TTree*& tree) const +StatusCode THistSvcHLT::regTree( const std::string& id, TTree* tree_ptr ) { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; - return StatusCode::SUCCESS; + std::unique_ptr<TTree> tree( tree_ptr ); + StatusCode sc = regHist_i( std::move( tree ), id, false ); + TTree* tr = nullptr; + if ( getTree( id, tr ).isSuccess() && sc.isSuccess() ) { + if ( m_autoSave != 0 ) { + tr->SetAutoSave( m_autoSave ); + } + tr->SetAutoFlush( m_autoFlush ); + } + return sc; } -StatusCode THistSvcHLT::regGraph(const std::string& name) +StatusCode THistSvcHLT::getTree( const std::string& id, TTree*& tree ) const { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; - return StatusCode::SUCCESS; + tree = getHist_i<TTree>( id ); + if ( tree != nullptr ) { + return StatusCode::SUCCESS; + } else { + return StatusCode::FAILURE; + } } -StatusCode THistSvcHLT::regGraph(const std::string& name, std::unique_ptr<TGraph> graph) +StatusCode THistSvcHLT::regGraph( const std::string& id ) { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; - return StatusCode::SUCCESS; + std::unique_ptr<TGraph> graph = std::make_unique<TGraph>(); + return regHist_i( std::move( graph ), id, false ); } -StatusCode THistSvcHLT::regGraph(const std::string& name, TGraph* graph) +StatusCode THistSvcHLT::regGraph( const std::string& id, std::unique_ptr<TGraph> graph ) { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; - return StatusCode::SUCCESS; + if ( strcmp( graph->GetName(), "Graph" ) == 0 ) { + std::string id2( id ); + std::string::size_type i = id2.rfind( "/" ); + if ( i != std::string::npos ) { + id2.erase( 0, i + 1 ); + } + + info() << "setting name of TGraph id: \"" << id << "\" to \"" << id2 << "\" since it is unset" << endmsg; + graph->SetName( id2.c_str() ); + } + + return regHist_i( std::move( graph ), id, false ); } -StatusCode THistSvcHLT::getGraph(const std::string& name, TGraph*& graph) const +StatusCode THistSvcHLT::regGraph( const std::string& id, TGraph* graph_ptr ) { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; - return StatusCode::SUCCESS; + std::unique_ptr<TGraph> graph( graph_ptr ); + if ( strcmp( graph->GetName(), "Graph" ) == 0 ) { + std::string id2( id ); + std::string::size_type i = id2.rfind( "/" ); + if ( i != std::string::npos ) { + id2.erase( 0, i + 1 ); + } + + info() << "setting name of TGraph id: \"" << id << "\" to \"" << id2 << "\" since it is unset" << endmsg; + graph->SetName( id2.c_str() ); + } + + return regHist_i( std::move( graph ), id, false ); } -StatusCode THistSvcHLT::regShared(const std::string& name, std::unique_ptr<TH1> hist, LockedHandle<TH1>& lh) +StatusCode THistSvcHLT::getGraph( const std::string& id, TGraph*& graph ) const { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; - return StatusCode::SUCCESS; + graph = getHist_i<TGraph>( id ); + if ( graph != nullptr ) { + return StatusCode::SUCCESS; + } else { + return StatusCode::FAILURE; + } } -StatusCode THistSvcHLT::regShared(const std::string& name, std::unique_ptr<TH2> hist, LockedHandle<TH2>& lh) +StatusCode THistSvcHLT::regShared( const std::string& id, std::unique_ptr<TH1> hist, LockedHandle<TH1>& lh ) { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; - return StatusCode::SUCCESS; + lh = regShared_i<TH1>( id, std::move( hist ) ); + if ( lh ) { + return StatusCode::SUCCESS; + } else { + return StatusCode::FAILURE; + } } -StatusCode THistSvcHLT::regShared(const std::string& name, std::unique_ptr<TH3> hist, LockedHandle<TH3>& lh) +StatusCode THistSvcHLT::regShared( const std::string& id, std::unique_ptr<TH2> hist, LockedHandle<TH2>& lh ) { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; - return StatusCode::SUCCESS; + lh = regShared_i<TH2>( id, std::move( hist ) ); + if ( lh ) { + return StatusCode::SUCCESS; + } else { + return StatusCode::FAILURE; + } } -StatusCode THistSvcHLT::regShared(const std::string& name, std::unique_ptr<TGraph> graph, LockedHandle<TGraph>& lh) +StatusCode THistSvcHLT::regShared( const std::string& id, std::unique_ptr<TH3> hist, LockedHandle<TH3>& lh ) { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; - return StatusCode::SUCCESS; + lh = regShared_i<TH3>( id, std::move( hist ) ); + if ( lh ) { + return StatusCode::SUCCESS; + } else { + return StatusCode::FAILURE; + } } -StatusCode THistSvcHLT::getShared(const std::string& name, LockedHandle<TH1>& lh) const +StatusCode THistSvcHLT::regShared( const std::string& id, std::unique_ptr<TGraph> graph, LockedHandle<TGraph>& lh ) { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; - return StatusCode::SUCCESS; + lh = regShared_i<TGraph>( id, std::move( graph ) ); + if ( lh ) { + return StatusCode::SUCCESS; + } else { + return StatusCode::FAILURE; + } } -StatusCode THistSvcHLT::getShared(const std::string& name, LockedHandle<TH2>& lh) const +StatusCode THistSvcHLT::getShared( const std::string& name, LockedHandle<TH1>& lh ) const { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; - return StatusCode::SUCCESS; + lh = getShared_i<TH1>( name ); + if ( lh ) { + return StatusCode::SUCCESS; + } else { + return StatusCode::FAILURE; + } } -StatusCode THistSvcHLT::getShared(const std::string& name, LockedHandle<TH3>& lh) const +StatusCode THistSvcHLT::getShared( const std::string& name, LockedHandle<TH2>& lh ) const { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; - return StatusCode::SUCCESS; + lh = getShared_i<TH2>( name ); + if ( lh ) { + return StatusCode::SUCCESS; + } else { + return StatusCode::FAILURE; + } } -StatusCode THistSvcHLT::getShared(const std::string& name, LockedHandle<TGraph>& lh) const +StatusCode THistSvcHLT::getShared( const std::string& name, LockedHandle<TH3>& lh ) const { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; - return StatusCode::SUCCESS; + lh = getShared_i<TH3>( name ); + if ( lh ) { + return StatusCode::SUCCESS; + } else { + return StatusCode::FAILURE; + } } -StatusCode THistSvcHLT::deReg(const std::string& name) +StatusCode THistSvcHLT::getShared( const std::string& name, LockedHandle<TGraph>& lh ) const { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; - return StatusCode::SUCCESS; + lh = getShared_i<TGraph>( name ); + if ( lh ) { + return StatusCode::SUCCESS; + } else { + return StatusCode::FAILURE; + } } -StatusCode THistSvcHLT::deReg(TObject* obj) +StatusCode THistSvcHLT::deReg( const std::string& id ) { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; - return StatusCode::SUCCESS; + auto itr = m_uids.find( id ); + if ( itr == m_uids.end() ) { + error() << "Problem deregistering id \"" << id << "\": not found in registry" << endmsg; + return StatusCode::FAILURE; + } + + vhid_t* vh = itr->second; + debug() << "will deregister " << vh->size() << " elements of id \"" << id << "\"" << endmsg; + StatusCode sc( StatusCode::SUCCESS ); + while ( vh->size() > 0 ) { + if ( deReg( vh->back().obj ).isFailure() ) { + sc = StatusCode::FAILURE; + error() << "Problems deRegistering " << vh->size() << " element of id \"" << id << "\"" << endmsg; + break; + } + } + + return sc; } -StatusCode THistSvcHLT::merge(const std::string& id) +StatusCode THistSvcHLT::deReg( TObject* obj ) { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; - return StatusCode::SUCCESS; + objMap_t::iterator obj_itr = m_tobjs.find( obj ); + if ( obj_itr != m_tobjs.end() ) { + vhid_t* vhid = obj_itr->second.first; + THistID hid = obj_itr->second.first->at( obj_itr->second.second ); + + auto uid_itr = m_uids.find( hid.id ); + if ( uid_itr == m_uids.end() ) { + error() << "Problems deregistering TObject \"" << obj->GetName() << "\" with id \"" << hid.id + << "\": not in uidMap" << endmsg; + return StatusCode::FAILURE; + } + + if ( vhid->size() == 1 ) { + // We are the last object, so we have to delete vhid properly + debug() << "vhid for " << hid.id << " is empty. deleting" << endmsg; + + std::string root, rem; + parseString( hid.id, root, rem ); + + auto mitr = m_ids.equal_range( rem ); + auto id_itr = std::find_if( mitr.first, mitr.second, + [&]( idMap_t::const_reference i ) { return i.second->at( 0 ).obj == obj; } ); + if ( id_itr == mitr.second ) { + error() << "Problems deregistering TObject \"" << obj->GetName() << "\" with id \"" << hid.id + << "\": not in idMap" << endmsg; + return StatusCode::FAILURE; + } + + auto hlist_itr = std::find( m_hlist.begin(), m_hlist.end(), vhid ); + if ( hlist_itr == m_hlist.end() ) { + error() << "Problems deregistering TObject \"" << obj->GetName() << "\" with id \"" << hid.id + << "\": not in hlist" << endmsg; + return StatusCode::FAILURE; + } + + m_tobjs.erase( obj_itr ); + vhid->erase( vhid->begin() + obj_itr->second.second ); + + m_uids.erase( uid_itr ); + m_ids.erase( id_itr ); + m_hlist.erase( hlist_itr ); + + delete vhid; + + } else if ( vhid->size() > 1 ) { + m_tobjs.erase( obj_itr ); + vhid->erase( vhid->begin() + obj_itr->second.second ); + + // vector of THistID is still not empty (i.e. other instances with same name registered) + } else { + error() << "Deregistration failed unexpectedly. (bug in THistSvcHLT?)" << endmsg; + } + return StatusCode::SUCCESS; + } else { + error() << "Cannot unregister TObject \"" << obj->GetName() << "\": not known to THistSvcHLT" << endmsg; + return StatusCode::FAILURE; + } } -StatusCode THistSvcHLT::merge(TObject* obj) +StatusCode THistSvcHLT::merge( const std::string& name ) { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; - return StatusCode::SUCCESS; + uidMap_t::iterator itr = m_uids.find( name ); + if ( itr == m_uids.end() ) { + error() << "merge: id \"" << name << "\" not found" << endmsg; + return StatusCode::FAILURE; + } + + return merge( itr->second ); } -bool THistSvcHLT::exists( const std::string& name ) const +StatusCode THistSvcHLT::merge( TObject* obj ) { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; - return false; + objMap_t::iterator itr = m_tobjs.find( obj ); + if ( itr != m_tobjs.end() ) { + return merge( itr->second.first ); + } else { + error() << "merge: unknown object " << obj << endmsg; + return StatusCode::FAILURE; + } } +bool THistSvcHLT::exists( const std::string& name ) const { return ( getHist_i<TH1>( name, 0, true ) != nullptr ); } + std::vector<std::string> THistSvcHLT::getHists() const { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; - return {}; + std::vector<std::string> names; + names.reserve( m_uids.size() ); + transform_if( std::begin( m_uids ), std::end( m_uids ), std::back_inserter( names ), select1st, + []( uidMap_t::const_reference i ) { return i.second->at( 0 ).obj->IsA()->InheritsFrom( "TH1" ); } ); + return names; } std::vector<std::string> THistSvcHLT::getTrees() const { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; - return {}; + std::vector<std::string> names; + names.reserve( m_uids.size() ); + transform_if( std::begin( m_uids ), std::end( m_uids ), std::back_inserter( names ), select1st, + []( uidMap_t::const_reference i ) { return i.second->at( 0 ).obj->IsA()->InheritsFrom( "TTree" ); } ); + return names; } std::vector<std::string> THistSvcHLT::getGraphs() const { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; - return {}; + std::vector<std::string> names; + names.reserve( m_uids.size() ); + transform_if( std::begin( m_uids ), std::end( m_uids ), std::back_inserter( names ), select1st, + []( uidMap_t::const_reference i ) { return i.second->at( 0 ).obj->IsA()->InheritsFrom( "TGraph" ); } ); + return names; } -StatusCode THistSvcHLT::getTHists(TDirectory* td, TList&, bool recurse) const +StatusCode THistSvcHLT::getTHists( TDirectory* td, TList& tl, bool rcs ) const { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; + GlobalDirectoryRestore restore( m_svcMut ); + + gErrorIgnoreLevel = kBreak; + + if ( !td->cd() ) { + error() << "getTHists: No such TDirectory \"" << td->GetPath() << "\"" << endmsg; + return StatusCode::FAILURE; + } + + if ( msgLevel( MSG::DEBUG ) ) { + debug() << "getTHists: \"" << td->GetPath() << "\": found " << td->GetListOfKeys()->GetSize() << " keys" << endmsg; + } + + TIter nextkey( td->GetListOfKeys() ); + while ( TKey* key = (TKey*)nextkey() ) { + auto& log = debug(); + if ( msgLevel( MSG::DEBUG ) ) log << " key: " << key->GetName(); + TObject* obj = key->ReadObj(); + if ( obj != 0 && obj->IsA()->InheritsFrom( "TDirectory" ) ) { + if ( msgLevel( MSG::DEBUG ) ) log << " (" << obj->IsA()->GetName() << ")"; + } else if ( obj != 0 && obj->IsA()->InheritsFrom( "TH1" ) ) { + if ( msgLevel( MSG::DEBUG ) ) log << " (" << obj->IsA()->GetName() << ")"; + tl.Add( obj ); + } else if ( obj != 0 ) { + if ( msgLevel( MSG::DEBUG ) ) log << " [" << obj->IsA()->GetName() << "]"; + } + if ( msgLevel( MSG::DEBUG ) ) log << endmsg; + } + + // operate recursively + if ( rcs ) { + nextkey = td->GetListOfKeys(); + while ( TKey* key = (TKey*)nextkey() ) { + TObject* obj = key->ReadObj(); + if ( obj && obj->IsA()->InheritsFrom( "TDirectory" ) ) { + TDirectory* tt = dynamic_cast<TDirectory*>( obj ); + getTHists( tt, tl, rcs ); + } + } + } + return StatusCode::SUCCESS; } -StatusCode THistSvcHLT::getTHists(const std::string& name, TList&, bool recurse) const +StatusCode THistSvcHLT::getTHists( const std::string& dir, TList& tl, bool rcs ) const { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; - return StatusCode::SUCCESS; + + GlobalDirectoryRestore restore( m_svcMut ); + + gErrorIgnoreLevel = kBreak; + + StatusCode sc; + + std::string stream, rem, r2; + parseString( dir, stream, rem ); + + auto itr = m_files.find( stream ); + if ( itr != m_files.end() ) { + r2 = itr->second.first->GetName(); + r2 += ":/"; + r2 += rem; + + if ( msgLevel( MSG::DEBUG ) ) { + debug() << "getTHists: \"" << dir << "\" looks like a stream name." + << " associated TFile: \"" << itr->second.first->GetName() << "\"" << endmsg; + } + + if ( gDirectory->cd( r2.c_str() ) ) { + m_curstream = stream; + sc = getTHists( gDirectory, tl, rcs ); + m_curstream = ""; + return sc; + } else { + if ( msgLevel( MSG::DEBUG ) ) { + debug() << "getTHists: no such TDirectory \"" << r2 << "\"" << endmsg; + } + } + + } else { + if ( msgLevel( MSG::DEBUG ) ) { + debug() << "getTHists: stream \"" << stream << "\" not found" << endmsg; + } + } + + if ( !gDirectory->cd( dir.c_str() ) ) { + error() << "getTHists: No such TDirectory/stream \"" << dir << "\"" << endmsg; + sc = StatusCode::FAILURE; + } else { + sc = getTHists( gDirectory, tl, rcs ); + } + + return sc; } -StatusCode THistSvcHLT::getTHists(TDirectory* td, TList& tl, bool recurse, bool reg) +StatusCode THistSvcHLT::getTHists( TDirectory* td, TList& tl, bool rcs, bool reg ) { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; + GlobalDirectoryRestore restore( m_svcMut ); + + gErrorIgnoreLevel = kBreak; + + if ( !td->cd() ) { + error() << "getTHists: No such TDirectory \"" << td->GetPath() << "\"" << endmsg; + return StatusCode::FAILURE; + } + + if ( msgLevel( MSG::DEBUG ) ) { + debug() << "getTHists: \"" << td->GetPath() << "\": found " << td->GetListOfKeys()->GetSize() << " keys" << endmsg; + } + + TIter nextkey( td->GetListOfKeys() ); + while ( TKey* key = (TKey*)nextkey() ) { + auto& log = debug(); + if ( msgLevel( MSG::DEBUG ) ) log << " key: " << key->GetName(); + TObject* obj = key->ReadObj(); + if ( obj && obj->IsA()->InheritsFrom( "TDirectory" ) ) { + if ( msgLevel( MSG::DEBUG ) ) log << " (" << obj->IsA()->GetName() << ")"; + } else if ( obj && obj->IsA()->InheritsFrom( "TH1" ) ) { + if ( msgLevel( MSG::DEBUG ) ) log << " (" << obj->IsA()->GetName() << ")"; + tl.Add( obj ); + if ( reg && m_curstream != "" ) { + std::string dir = td->GetPath(); + std::string fil = td->GetFile()->GetName(); + dir.erase( 0, fil.length() + 1 ); + std::string id = "/" + m_curstream; + if ( dir == "/" ) { + id = id + "/" + key->GetName(); + } else { + id = id + dir + "/" + key->GetName(); + } + if ( !exists( id ) ) { + if ( msgLevel( MSG::DEBUG ) ) log << " reg as \"" << id << "\""; + regHist( id ).ignore(); + } else { + if ( msgLevel( MSG::DEBUG ) ) log << " already registered"; + } + } + } else if ( obj ) { + if ( msgLevel( MSG::DEBUG ) ) log << " [" << obj->IsA()->GetName() << "]"; + } + if ( msgLevel( MSG::DEBUG ) ) log << endmsg; + } + + // operate recursively + if ( rcs ) { + nextkey = td->GetListOfKeys(); + while ( TKey* key = (TKey*)nextkey() ) { + TObject* obj = key->ReadObj(); + if ( obj && obj->IsA()->InheritsFrom( "TDirectory" ) ) { + TDirectory* tt = dynamic_cast<TDirectory*>( obj ); + getTHists( tt, tl, rcs, reg ); + } + } + } + return StatusCode::SUCCESS; } -StatusCode THistSvcHLT::getTHists(const std::string& name, TList& tl, bool recurse, bool reg) +StatusCode THistSvcHLT::getTHists( const std::string& dir, TList& tl, bool rcs, bool reg ) { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; - return StatusCode::SUCCESS; + GlobalDirectoryRestore restore( m_svcMut ); + + gErrorIgnoreLevel = kBreak; + + StatusCode sc; + + std::string stream, rem, r2; + parseString( dir, stream, rem ); + + auto itr = m_files.find( stream ); + if ( itr != m_files.end() ) { + r2 = itr->second.first->GetName(); + r2 += ":/"; + r2 += rem; + + if ( msgLevel( MSG::DEBUG ) ) { + debug() << "getTHists: \"" << dir << "\" looks like a stream name." + << " associated TFile: \"" << itr->second.first->GetName() << "\"" << endmsg; + } + + if ( gDirectory->cd( r2.c_str() ) ) { + m_curstream = stream; + sc = getTHists( gDirectory, tl, rcs, reg ); + m_curstream.clear(); + return sc; + } + if ( msgLevel( MSG::DEBUG ) ) { + debug() << "getTHists: no such TDirectory \"" << r2 << "\"" << endmsg; + } + } else { + if ( msgLevel( MSG::DEBUG ) ) { + debug() << "getTHists: stream \"" << stream << "\" not found" << endmsg; + } + } + + if ( !gDirectory->cd( dir.c_str() ) ) { + error() << "getTHists: No such TDirectory/stream \"" << dir << "\"" << endmsg; + sc = StatusCode::FAILURE; + } else { + if ( reg ) { + warning() << "Unable to register histograms automatically " + << "without a valid stream name" << endmsg; + reg = false; + } + sc = getTHists( gDirectory, tl, rcs, reg ); + } + + return sc; } -StatusCode THistSvcHLT::getTTrees(TDirectory* td, TList&, bool recurse) const +StatusCode THistSvcHLT::getTTrees( TDirectory* td, TList& tl, bool rcs ) const { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; + GlobalDirectoryRestore restore( m_svcMut ); + + gErrorIgnoreLevel = kBreak; + + if ( !td->cd() ) { + error() << "getTTrees: No such TDirectory \"" << td->GetPath() << "\"" << endmsg; + return StatusCode::FAILURE; + } + + if ( msgLevel( MSG::DEBUG ) ) { + debug() << "getTHists: \"" << td->GetPath() << "\": found " << td->GetListOfKeys()->GetSize() << " keys" << endmsg; + } + + TIter nextkey( td->GetListOfKeys() ); + while ( TKey* key = (TKey*)nextkey() ) { + auto& log = debug(); + if ( msgLevel( MSG::DEBUG ) ) log << " key: " << key->GetName(); + TObject* obj = key->ReadObj(); + if ( obj != 0 && obj->IsA()->InheritsFrom( "TDirectory" ) ) { + if ( msgLevel( MSG::DEBUG ) ) log << " (" << obj->IsA()->GetName() << ")"; + } else if ( obj != 0 && obj->IsA()->InheritsFrom( "TTree" ) ) { + if ( msgLevel( MSG::DEBUG ) ) log << " (" << obj->IsA()->GetName() << ")"; + tl.Add( obj ); + } else if ( obj != 0 ) { + if ( msgLevel( MSG::DEBUG ) ) log << " [" << obj->IsA()->GetName() << "]"; + } + log << endmsg; + } + + // operate recursively + if ( rcs ) { + nextkey = td->GetListOfKeys(); + while ( TKey* key = (TKey*)nextkey() ) { + TObject* obj = key->ReadObj(); + if ( obj && obj->IsA()->InheritsFrom( "TDirectory" ) ) { + TDirectory* tt = dynamic_cast<TDirectory*>( obj ); + getTTrees( tt, tl, rcs ); + } + } + } + return StatusCode::SUCCESS; } -StatusCode THistSvcHLT::getTTrees(const std::string& name, TList&, bool recurse) const +StatusCode THistSvcHLT::getTTrees( const std::string& dir, TList& tl, bool rcs ) const +{ + GlobalDirectoryRestore restore( m_svcMut ); + + gErrorIgnoreLevel = kBreak; + + StatusCode sc; + + std::string stream, rem, r2; + parseString( dir, stream, rem ); + + auto itr = m_files.find( stream ); + if ( itr != m_files.end() ) { + r2 = itr->second.first->GetName(); + r2 += ":/"; + r2 += rem; + + if ( msgLevel( MSG::DEBUG ) ) { + debug() << "getTTrees: \"" << dir << "\" looks like a stream name." + << " associated TFile: \"" << itr->second.first->GetName() << "\"" << endmsg; + } + + if ( gDirectory->cd( r2.c_str() ) ) { + return getTTrees( gDirectory, tl, rcs ); + } + if ( msgLevel( MSG::DEBUG ) ) { + debug() << "getTTrees: no such TDirectory \"" << r2 << "\"" << endmsg; + } + } else { + if ( msgLevel( MSG::DEBUG ) ) { + debug() << "getTTrees: stream \"" << stream << "\" not found" << endmsg; + } + } + + if ( !gDirectory->cd( dir.c_str() ) ) { + error() << "getTTrees: No such TDirectory/stream \"" << dir << "\"" << endmsg; + sc = StatusCode::FAILURE; + } else { + sc = getTTrees( gDirectory, tl, rcs ); + } + return sc; +} + +StatusCode THistSvcHLT::getTTrees( TDirectory* td, TList& tl, bool rcs, bool reg ) { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; + GlobalDirectoryRestore restore( m_svcMut ); + + gErrorIgnoreLevel = kBreak; + + if ( !td->cd() ) { + error() << "getTTrees: No such TDirectory \"" << td->GetPath() << "\"" << endmsg; + return StatusCode::FAILURE; + } + + if ( msgLevel( MSG::DEBUG ) ) { + debug() << "getTHists: \"" << td->GetPath() << "\": found " << td->GetListOfKeys()->GetSize() << " keys" << endmsg; + } + + TIter nextkey( td->GetListOfKeys() ); + while ( TKey* key = (TKey*)nextkey() ) { + auto& log = debug(); + if ( msgLevel( MSG::DEBUG ) ) log << " key: " << key->GetName(); + TObject* obj = key->ReadObj(); + if ( obj && obj->IsA()->InheritsFrom( "TDirectory" ) ) { + if ( msgLevel( MSG::DEBUG ) ) log << " (" << obj->IsA()->GetName() << ")"; + } else if ( obj && obj->IsA()->InheritsFrom( "TTree" ) ) { + if ( msgLevel( MSG::DEBUG ) ) log << " (" << obj->IsA()->GetName() << ")"; + tl.Add( obj ); + if ( reg && m_curstream != "" ) { + std::string dir = td->GetPath(); + std::string fil = td->GetFile()->GetName(); + dir.erase( 0, fil.length() + 1 ); + std::string id = "/" + m_curstream; + if ( dir == "/" ) { + id = id + "/" + key->GetName(); + } else { + id = id + dir + "/" + key->GetName(); + } + if ( !exists( id ) ) { + if ( msgLevel( MSG::DEBUG ) ) log << " reg as \"" << id << "\""; + regHist( id ).ignore(); + } else { + if ( msgLevel( MSG::DEBUG ) ) log << " already registered"; + } + } + } else if ( obj != 0 ) { + if ( msgLevel( MSG::DEBUG ) ) log << " [" << obj->IsA()->GetName() << "]"; + } + if ( msgLevel( MSG::DEBUG ) ) log << endmsg; + } + + // operate recursively + if ( rcs ) { + nextkey = td->GetListOfKeys(); + while ( TKey* key = (TKey*)nextkey() ) { + TObject* obj = key->ReadObj(); + if ( obj && obj->IsA()->InheritsFrom( "TDirectory" ) ) { + TDirectory* tt = dynamic_cast<TDirectory*>( obj ); + getTTrees( tt, tl, rcs, reg ); + } + } + } + return StatusCode::SUCCESS; } -StatusCode THistSvcHLT::getTTrees(TDirectory* td, TList& tl, bool recurse, bool reg) +StatusCode THistSvcHLT::getTTrees( const std::string& dir, TList& tl, bool rcs, bool reg ) +{ + GlobalDirectoryRestore restore( m_svcMut ); + + gErrorIgnoreLevel = kBreak; + + StatusCode sc; + + std::string stream, rem, r2; + parseString( dir, stream, rem ); + + auto itr = m_files.find( stream ); + if ( itr != m_files.end() ) { + r2 = itr->second.first->GetName(); + r2 += ":/"; + r2 += rem; + + if ( msgLevel( MSG::DEBUG ) ) { + debug() << "getTTrees: \"" << dir << "\" looks like a stream name." + << " associated TFile: \"" << itr->second.first->GetName() << "\"" << endmsg; + } + + if ( gDirectory->cd( r2.c_str() ) ) { + return getTTrees( gDirectory, tl, rcs, reg ); + } else { + if ( msgLevel( MSG::DEBUG ) ) { + debug() << "getTTrees: no such TDirectory \"" << r2 << "\"" << endmsg; + } + } + } else { + if ( msgLevel( MSG::DEBUG ) ) { + debug() << "getTTrees: stream \"" << stream << "\" not found" << endmsg; + } + } + + if ( !gDirectory->cd( dir.c_str() ) ) { + error() << "getTTrees: No such TDirectory/stream \"" << dir << "\"" << endmsg; + return StatusCode::FAILURE; + } + + return getTTrees( gDirectory, tl, rcs, reg ); +} + +//*************************************************************************// + +void THistSvcHLT::handle( const Incident& /* inc */ ) +{ + if ( m_signaledStop ) return; + + if ( m_maxFileSize.value() == -1 ) return; + + // convert to bytes. + Long64_t mfs = (Long64_t)m_maxFileSize.value() * (Long64_t)1048576; + Long64_t mfs_warn = mfs * 95 / 100; + + updateFiles(); + + std::map<std::string, std::pair<TFile*, Mode>>::const_iterator itr; + for ( const auto& f : m_files ) { + TFile* tf = f.second.first; + +#ifndef NDEBUG + if ( msgLevel( MSG::DEBUG ) ) { + debug() << "stream: " << f.first << " name: " << tf->GetName() << " size: " << tf->GetSize() << endmsg; + } +#endif + + // Signal job to terminate if output file is too large + if ( tf->GetSize() > mfs ) { + + m_signaledStop = true; + + fatal() << "file \"" << tf->GetName() << "\" associated with stream \"" << f.first + << "\" has exceeded the max file size of " << m_maxFileSize.value() << "MB. Terminating Job." << endmsg; + + IEventProcessor* evt = nullptr; + if ( service( "ApplicationMgr", evt, true ).isSuccess() ) { + evt->stopRun(); + evt->release(); + } else { + abort(); + } + } else if ( tf->GetSize() > mfs_warn ) { + warning() << "file \"" << tf->GetName() << "\" associated with stream \"" << f.first + << "\" is at 95% of its maximum allowable file size of " << m_maxFileSize.value() << "MB" << endmsg; + } + } +} + +/** @brief callback method to reinitialize the internal state of + * the component for I/O purposes (e.g. upon @c fork(2)) + */ +StatusCode THistSvcHLT::io_reinit() +{ + bool all_good = true; + if ( msgLevel( MSG::DEBUG ) ) { + debug() << "reinitializing I/O..." << endmsg; + } + + // retrieve the I/O component manager... + + IIoComponentMgr* iomgr = nullptr; + + if ( service( "IoComponentMgr", iomgr, true ).isFailure() ) { + error() << "could not retrieve I/O component manager !" << endmsg; + return StatusCode::FAILURE; + } + + GlobalDirectoryRestore restore( m_svcMut ); + // to hide the expected errors upon closing the files whose + // file descriptors have been swept under the rug... + gErrorIgnoreLevel = kFatal; + + for ( auto& ifile : m_files ) { + TFile* f = ifile.second.first; + std::string fname = f->GetName(); + if ( msgLevel( MSG::DEBUG ) ) { + debug() << "file [" << fname << "] mode: [" << f->GetOption() << "] r:" << f->GetFileBytesRead() + << " w:" << f->GetFileBytesWritten() << " cnt:" << f->GetFileCounter() << endmsg; + } + + if ( ifile.second.second == READ ) { + if ( msgLevel( MSG::DEBUG ) ) { + debug() << " TFile opened in READ mode: not reassigning names" << endmsg; + } + continue; + } + + if ( !iomgr->io_retrieve( this, fname ).isSuccess() ) { + error() << "could not retrieve new name for [" << fname << "] !!" << endmsg; + all_good = false; + continue; + } else { + if ( msgLevel( MSG::DEBUG ) ) { + debug() << "got a new name [" << fname << "]..." << endmsg; + } + } + + void* vf = nullptr; + Option_t* opts = f->GetOption(); + int r = p_fileMgr->open( Io::ROOT, name(), fname, Io::WRITE, vf, "HIST" ); + if ( r != 0 ) { + error() << "unable to open file \"" << fname << "\" for writing" << endmsg; + return StatusCode::FAILURE; + } + TFile* newfile = (TFile*)vf; + newfile->SetOption( opts ); + + if ( ifile.second.second != THistSvcHLT::READ ) { + copyFileLayout( newfile, f ); + ifile.second.first = newfile; + } + + // loop over all uids and migrate them to the new file + for ( auto& uid : m_uids ) { + for ( auto& hid : *uid.second ) { + if ( hid.file != f ) continue; + TDirectory* olddir = this->changeDir( hid ); + hid.file = newfile; + // side-effect: create needed directories... + TDirectory* newdir = this->changeDir( hid ); + TClass* cl = hid.obj->IsA(); + + // migrate the objects to the new file. + // thanks to the object model of ROOT, it is super easy. + if ( cl->InheritsFrom( "TTree" ) ) { + dynamic_cast<TTree*>( hid.obj )->SetDirectory( newdir ); + dynamic_cast<TTree*>( hid.obj )->Reset(); + } else if ( cl->InheritsFrom( "TH1" ) ) { + dynamic_cast<TH1*>( hid.obj )->SetDirectory( newdir ); + dynamic_cast<TH1*>( hid.obj )->Reset(); + } else if ( cl->InheritsFrom( "TGraph" ) ) { + olddir->Remove( hid.obj ); + newdir->Append( hid.obj ); + } else { + error() << "id: \"" << hid.id << "\" is not a inheriting from a class " + << "we know how to handle (received [" << cl->GetName() << "], " + << "expected [TTree, TH1 or TGraph]) !" << endmsg << "attaching to current dir [" << newdir->GetPath() + << "] " + << "nonetheless..." << endmsg; + olddir->Remove( hid.obj ); + newdir->Append( hid.obj ); + } + } + } + f->ReOpen( "READ" ); + p_fileMgr->close( f, name() ); + f = newfile; + } + + return all_good ? StatusCode::SUCCESS : StatusCode::FAILURE; +} + +//*************************************************************************// + +THistSvcHLT::GlobalDirectoryRestore::GlobalDirectoryRestore( THistSvcMutex_t& mut ) : m_lock( mut ) { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; + m_gDirectory = gDirectory; + m_gFile = gFile; + m_gErrorIgnoreLevel = gErrorIgnoreLevel; +} + +THistSvcHLT::GlobalDirectoryRestore::~GlobalDirectoryRestore() +{ + gDirectory = m_gDirectory; + gFile = m_gFile; + gErrorIgnoreLevel = m_gErrorIgnoreLevel; +} + +//*************************************************************************// + +template <typename T> +T* THistSvcHLT::readHist( const std::string& id ) const +{ + return dynamic_cast<T*>( readHist_i<T>( id ) ); +} + +TTree* THistSvcHLT::readTree( const std::string& id ) const { return dynamic_cast<TTree*>( readHist_i<TTree>( id ) ); } + +void THistSvcHLT::updateFiles() +{ + // If TTrees grow beyond TTree::fgMaxTreeSize, a new file is + // automatically created by root, and the old one closed. We + // need to migrate all the UIDs over to show the correct file + // pointer. This is ugly. + + if ( msgLevel( MSG::DEBUG ) ) debug() << "updateFiles()" << endmsg; + + for ( auto uitr = m_uids.begin(); uitr != m_uids.end(); ++uitr ) { + for ( auto& hid : *( uitr->second ) ) { +#ifndef NDEBUG + if ( msgLevel( MSG::VERBOSE ) ) + verbose() << " update: " << uitr->first << " " << hid.id << " " << hid.mode << endmsg; +#endif + TObject* to = hid.obj; + TFile* oldFile = hid.file; + if ( !to ) { + warning() << uitr->first << ": TObject == 0" << endmsg; + } else if ( hid.temp || hid.mode == READ ) { +// do nothing - no need to check how big the file is since we +// are just reading it. +#ifndef NDEBUG + if ( msgLevel( MSG::VERBOSE ) ) verbose() << " skipping" << endmsg; +#endif + } else if ( to->IsA()->InheritsFrom( "TTree" ) ) { + TTree* tr = dynamic_cast<TTree*>( to ); + TFile* newFile = tr->GetCurrentFile(); + + if ( oldFile != newFile ) { + std::string newFileName = newFile->GetName(); + std::string oldFileName, streamName, rem; + TFile* dummy = nullptr; + findStream( hid.id, streamName, rem, dummy ); + + for ( auto& itr : m_files ) { + if ( itr.second.first == oldFile ) { + itr.second.first = newFile; + } + } + + for ( auto uitr2 = uitr; uitr2 != m_uids.end(); ++uitr2 ) { + for ( auto& hid2 : *( uitr2->second ) ) { + if ( hid2.file == oldFile ) { + hid2.file = newFile; + } + } + } + + auto sitr = std::find_if( std::begin( m_fileStreams ), std::end( m_fileStreams ), + [&]( streamMap::const_reference s ) { return s.second == streamName; } ); + if ( sitr != std::end( m_fileStreams ) ) oldFileName = sitr->first; + +#ifndef NDEBUG + if ( msgLevel( MSG::DEBUG ) ) { + debug() << "migrating uid: " << hid.id << " stream: " << streamName << " oldFile: " << oldFileName + << " newFile: " << newFileName << endmsg; + } +#endif + + if ( !oldFileName.empty() ) { + auto i = m_fileStreams.lower_bound( oldFileName ); + while ( i != std::end( m_fileStreams ) && i->first == oldFileName ) { +#ifndef NDEBUG + if ( msgLevel( MSG::DEBUG ) ) { + debug() << "changing filename \"" << i->first << "\" to \"" << newFileName << "\" for stream \"" + << i->second << "\"" << endmsg; + } +#endif + std::string nm = std::move( i->second ); + i = m_fileStreams.erase( i ); + m_fileStreams.emplace( newFileName, std::move( nm ) ); + } + } else { + error() << "Problems updating fileStreams with new file name" << endmsg; + } + } + } + } + } +} + +StatusCode THistSvcHLT::writeObjectsToFile() +{ + updateFiles(); + + std::for_each( m_files.begin(), m_files.end(), []( std::pair<const std::string, std::pair<TFile*, Mode>>& i ) { + auto mode = i.second.second; + auto file = i.second.first; + if ( mode == WRITE || mode == UPDATE || mode == SHARE ) { + file->Write( "", TObject::kOverwrite ); + } else if ( mode == APPEND ) { + file->Write( "" ); + } + } ); + + if ( msgLevel( MSG::DEBUG ) ) { + debug() << "THistSvcHLT::writeObjectsToFile()::List of Files connected in ROOT " << endmsg; + TSeqCollection* filelist = gROOT->GetListOfFiles(); + for ( int ii = 0; ii < filelist->GetEntries(); ii++ ) { + debug() << "THistSvcHLT::writeObjectsToFile()::List of Files connected in ROOT: \"" << filelist->At( ii )->GetName() + << "\"" << endmsg; + } + } + return StatusCode::SUCCESS; } -StatusCode THistSvcHLT::getTTrees(const std::string& name, TList& tl, bool recurse, bool reg) +StatusCode THistSvcHLT::connect( const std::string& ident ) { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; + auto loc = ident.find( " " ); + std::string stream = ident.substr( 0, loc ); + char typ( 0 ); + typedef std::pair<std::string, std::string> Prop; + std::vector<Prop> props; + std::string filename, db_typ( "ROOT" ); + int cl( 1 ); + + if ( loc != std::string::npos ) { + using Parser = Gaudi::Utils::AttribStringParser; + for ( auto attrib : Parser( ident.substr( loc + 1 ) ) ) { + auto TAG = boost::algorithm::to_upper_copy( attrib.tag ); + auto VAL = boost::algorithm::to_upper_copy( attrib.value ); + + if ( TAG == "FILE" || TAG == "DATAFILE" ) { + filename = attrib.value; + removeDoubleSlash( filename ); + } else if ( TAG == "OPT" ) { + if ( VAL == "APPEND" || VAL == "UPDATE" ) { + typ = 'A'; + } else if ( VAL == "CREATE" || VAL == "NEW" || VAL == "WRITE" ) { + typ = 'N'; + } else if ( VAL == "RECREATE" ) { + typ = 'R'; + } else if ( VAL == "SHARE" ) { + typ = 'S'; + } else if ( VAL == "OLD" || VAL == "READ" ) { + typ = 'O'; + } else { + error() << "Unknown OPT: \"" << attrib.value << "\"" << endmsg; + typ = 0; + } + } else if ( TAG == "TYP" ) { + db_typ = std::move( attrib.value ); + } else if ( TAG == "CL" ) { + cl = std::stoi( attrib.value ); + } else { + props.emplace_back( attrib.tag, attrib.value ); + } + } + } + + if ( stream == "temp" ) { + error() << "in JobOption \"" << ident << "\": stream name \"temp\" reserved." << endmsg; + return StatusCode::FAILURE; + } + + if ( db_typ != "ROOT" ) { + error() << "in JobOption \"" << ident << "\": technology type \"" << db_typ << "\" not supported." << endmsg; + return StatusCode::FAILURE; + } + + if ( m_files.find( stream ) != m_files.end() ) { + error() << "in JobOption \"" << ident << "\":\n stream \"" << stream << "\" already connected to file: \"" + << m_files[stream].first->GetName() << "\"" << endmsg; + return StatusCode::FAILURE; + } + + Mode newMode; + if ( typ == 'O' ) { + newMode = THistSvcHLT::READ; + } else if ( typ == 'N' ) { + newMode = THistSvcHLT::WRITE; + } else if ( typ == 'A' ) { + newMode = THistSvcHLT::APPEND; + } else if ( typ == 'R' ) { + newMode = THistSvcHLT::UPDATE; + } else if ( typ == 'S' ) { + newMode = THistSvcHLT::SHARE; + } else { + // something else? + error() << "No OPT= specified or unknown access mode in: " << ident << endmsg; + return StatusCode::FAILURE; + } + + // Is this file already connected to another stream? + if ( m_fileStreams.find( filename ) != m_fileStreams.end() ) { + auto fitr = m_fileStreams.equal_range( filename ); + + const std::string& oldstream = fitr.first->second; + + const auto& f_info = m_files[oldstream]; + + if ( newMode != f_info.second ) { + error() << "in JobOption \"" << ident << "\":\n file \"" << filename << "\" already opened by stream: \"" + << oldstream << "\" with different access mode." << endmsg; + return StatusCode::FAILURE; + } else { + TFile* f2 = f_info.first; + m_files[stream] = std::make_pair( f2, newMode ); + if ( msgLevel( MSG::DEBUG ) ) + debug() << "Connecting stream: \"" << stream << "\" to previously opened TFile: \"" << filename << "\"" + << endmsg; + return StatusCode::SUCCESS; + } + } + + IIncidentSvc* pi = nullptr; + if ( service( "IncidentSvc", pi ).isFailure() ) { + error() << "Unable to get the IncidentSvc" << endmsg; + return StatusCode::FAILURE; + } + + void* vf = nullptr; + TFile* f = nullptr; + + if ( newMode == THistSvcHLT::READ ) { + // old file + int r = p_fileMgr->open( Io::ROOT, name(), filename, Io::READ, vf, "HIST" ); + + if ( r != 0 ) { + error() << "Unable to open ROOT file " << filename << " for reading" << endmsg; + return StatusCode::FAILURE; + } + + f = (TFile*)vf; + + // FIX ME! + pi->fireIncident( FileIncident( name(), "BeginHistFile", filename ) ); + + } else if ( newMode == THistSvcHLT::WRITE ) { + // new file. error if file exists + int r = p_fileMgr->open( Io::ROOT, name(), filename, ( Io::WRITE | Io::CREATE | Io::EXCL ), vf, "HIST" ); + + if ( r != 0 ) { + error() << "Unable to open ROOT file " << filename << " for writing" << endmsg; + return StatusCode::FAILURE; + } + + f = (TFile*)vf; + + } else if ( newMode == THistSvcHLT::APPEND ) { + // update file + int r = p_fileMgr->open( Io::ROOT, name(), filename, ( Io::WRITE | Io::APPEND ), vf, "HIST" ); + if ( r != 0 ) { + error() << "unable to open file \"" << filename << "\" for appending" << endmsg; + return StatusCode::FAILURE; + } + + f = (TFile*)vf; + + } else if ( newMode == THistSvcHLT::SHARE ) { + // SHARE file type + // For SHARE files, all data will be stored in a temp file and will be + // merged into the target file in writeObjectsToFile() when finalize(), + // this help to solve some confliction. e.g. with storegate + static int ishared = 0; + std::string realfilename = filename; + filename = "tmp_THistSvcHLT_" + std::to_string( ishared++ ) + ".root"; + + if ( msgLevel( MSG::DEBUG ) ) { + debug() << "Creating temp file \"" << filename << "\" and realfilename=" << realfilename << endmsg; + } + m_sharedFiles[stream] = realfilename; + + int r = p_fileMgr->open( Io::ROOT, name(), filename, ( Io::WRITE | Io::CREATE | Io::EXCL ), vf, "HIST" ); + + if ( r != 0 ) { + error() << "Unable to open ROOT file " << filename << " for writing" << endmsg; + return StatusCode::FAILURE; + } + + f = (TFile*)vf; + + } else if ( newMode == THistSvcHLT::UPDATE ) { + // update file + int r = p_fileMgr->open( Io::ROOT, name(), filename, ( Io::WRITE | Io::CREATE ), vf, "HIST" ); + + if ( r != 0 ) { + error() << "Unable to open ROOT file " << filename << " for appending" << endmsg; + return StatusCode::FAILURE; + } + + f = (TFile*)vf; + } + + m_files[stream] = std::make_pair( f, newMode ); + m_fileStreams.insert( std::make_pair( filename, stream ) ); + + if ( msgLevel( MSG::DEBUG ) ) { + debug() << "Opening TFile \"" << filename << "\" stream: \"" << stream << "\" mode: \"" << typ << "\"" + << " comp level: " << cl << endmsg; + } + return StatusCode::SUCCESS; } -void THistSvcHLT::handle( const Incident& ) +TDirectory* THistSvcHLT::changeDir( const THistSvcHLT::THistID& hid ) const { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; + std::string uid = hid.id; + TFile* file = hid.file; + std::string stream, fdir, bdir, dir, id; + + if ( file ) { + file->cd( "/" ); + } else { + gROOT->cd(); + } + + fdir = uid; + bdir = stripDirectoryName( fdir ); + + while ( ( dir = stripDirectoryName( fdir ) ) != "" ) { + if ( !gDirectory->GetKey( dir.c_str() ) ) { + gDirectory->mkdir( dir.c_str() ); + } + gDirectory->cd( dir.c_str() ); + } + + return gDirectory; } -StatusCode THistSvcHLT::io_reinit() +std::string THistSvcHLT::stripDirectoryName( std::string& dir ) const +{ + std::string::size_type i = dir.find( "/" ); + + if ( i == std::string::npos ) return {}; + + if ( i == 0 ) { + dir.erase( 0, 1 ); + return stripDirectoryName( dir ); + } + + std::string root = dir.substr( 0, i ); + dir.erase( 0, i ); + + return root; +} + +void THistSvcHLT::removeDoubleSlash( std::string& id ) const +{ + while ( id.find( "//" ) != std::string::npos ) { + id.replace( id.find( "//" ), 2, "/" ); + } +} + +void THistSvcHLT::MergeRootFile( TDirectory* target, TDirectory* source ) +{ + if ( msgLevel( MSG::DEBUG ) ) { + debug() << "Target path: " << target->GetPath() << endmsg; + } + TString path( (char*)strstr( target->GetPath(), ":" ) ); + path.Remove( 0, 2 ); + + source->cd( path ); + TDirectory* current_sourcedir = gDirectory; + + // loop over all keys in this directory + TList* lkeys = current_sourcedir->GetListOfKeys(); + int nkeys = lkeys->GetEntries(); + TKey* key = nullptr; + for ( int jj = 0; jj < nkeys; jj++ ) { + key = (TKey*)lkeys->At( jj ); + std::string pathnameinsource = current_sourcedir->GetPath() + std::string( "/" ) + key->GetName(); + if ( msgLevel( MSG::DEBUG ) ) { + debug() << "Reading Key:" << pathnameinsource << endmsg; + } + TObject* obj = source->Get( pathnameinsource.c_str() ); + + if ( obj ) { + if ( obj->IsA()->InheritsFrom( "TDirectory" ) ) { + // it's a subdirectory + if ( msgLevel( MSG::DEBUG ) ) { + debug() << "Found subdirectory " << obj->GetName() << endmsg; + } + + // create a new subdir of same name and title in the target file + target->cd(); + TDirectory* newtargetdir = target->mkdir( obj->GetName(), obj->GetTitle() ); + + MergeRootFile( newtargetdir, source ); + + } else if ( obj->IsA()->InheritsFrom( "TTree" ) ) { + if ( msgLevel( MSG::DEBUG ) ) { + debug() << "Found TTree " << obj->GetName() << endmsg; + } + TTree* mytree = dynamic_cast<TTree*>( obj ); + int nentries = (int)mytree->GetEntries(); + mytree->SetBranchStatus( "*", 1 ); + + if ( msgLevel( MSG::DEBUG ) ) { + debug() << "Dumping TTree " << nentries << " entries" << endmsg; + } + target->cd(); + mytree->CloneTree(); + + } else { + target->cd(); + obj->Write( key->GetName() ); + } + } + } +} + +bool THistSvcHLT::findStream( const std::string& id, std::string& stream, std::string& rem, TFile*& file ) const +{ + auto pos = id.find( "/" ); + + if ( pos == std::string::npos ) { + // no "/" in id + stream = "temp"; + rem = id; + } else if ( pos != 0 ) { + // id does not start with "/" + stream = "temp"; + rem = id; + } else { + // id starts with "/" + + auto pos2 = id.find( "/", pos + 1 ); + + if ( pos2 == std::string::npos ) { + // need at least 2 "/" in format "/STREAM/name" or "/STREAM/dir/name" + error() << "badly formed Hist/Tree id: \"" << id << "\"" << endmsg; + return false; + } + parseString( id, stream, rem ); + } + + if ( stream == "temp" ) { + file = nullptr; + return true; + } + + auto itr = m_files.find( stream ); + file = ( itr != m_files.end() ? itr->second.first : nullptr ); + if ( !file ) { + warning() << "no stream \"" << stream << "\" associated with id: \"" << id << "\"" << endmsg; + } + + return true; +} + +void THistSvcHLT::parseString( const std::string& id, std::string& root, std::string& rem ) const +{ + auto pos = id.find( "/" ); + + if ( pos == std::string::npos ) { + root.clear(); + rem = id; + } else if ( pos == 0 ) { + parseString( id.substr( 1 ), root, rem ); + } else { + root = id.substr( 0, pos ); + rem = id.substr( pos + 1 ); + } +} + +void THistSvcHLT::setupInputFile( Gaudi::Details::PropertyBase& + /*m_inputfile*/ ) +{ + if ( FSMState() < Gaudi::StateMachine::CONFIGURED || !m_okToConnect ) { + debug() << "Delaying connection of Input Files until Initialize" + << ". now in " << FSMState() << endmsg; + + m_delayConnect = true; + } else { + debug() << "Now connecting of Input Files" << endmsg; + + StatusCode sc = StatusCode::SUCCESS; + + for ( const auto& itr : m_inputfile.value() ) { + if ( m_alreadyConnectedInFiles.end() != m_alreadyConnectedInFiles.find( itr ) ) { + continue; + } + if ( connect( itr ).isFailure() ) { + sc = StatusCode::FAILURE; + } else { + m_alreadyConnectedInFiles.insert( itr ); + } + } + + if ( !sc.isSuccess() ) { + throw GaudiException( "Problem connecting inputfile !!", name(), StatusCode::FAILURE ); + } + } +} + +void THistSvcHLT::setupOutputFile( Gaudi::Details::PropertyBase& + /*m_outputfile*/ ) +{ + if ( FSMState() < Gaudi::StateMachine::CONFIGURED || !m_okToConnect ) { + debug() << "Delaying connection of Input Files until Initialize" + << ". now in " << FSMState() << endmsg; + m_delayConnect = true; + } else { + StatusCode sc = StatusCode::SUCCESS; + for ( const auto& itr : m_outputfile.value() ) { + if ( m_alreadyConnectedOutFiles.end() != m_alreadyConnectedOutFiles.find( itr ) ) { + continue; + } + if ( connect( itr ).isFailure() ) { + sc = StatusCode::FAILURE; + } else { + m_alreadyConnectedOutFiles.insert( itr ); + } + } + + if ( !sc.isSuccess() ) { + throw GaudiException( "Problem connecting outputfile !!", name(), StatusCode::FAILURE ); + } + } +} + +void THistSvcHLT::setupCompressionLevel( Gaudi::Details::PropertyBase& + /* cl */ ) +{ + warning() << "\"CompressionLevel\" Property has been deprecated. " + << "Set it via the \"CL=\" parameter in the \"Output\" Property" << endmsg; +} + +void THistSvcHLT::copyFileLayout( TDirectory* destination, TDirectory* source ) +{ + if ( msgLevel( MSG::DEBUG ) ) { + debug() << "copyFileLayout() to destination path: " << destination->GetPath() << endmsg; + } + + // strip out URLs + TString path( (char*)strstr( destination->GetPath(), ":" ) ); + path.Remove( 0, 2 ); + + source->cd( path ); + TDirectory* current_source_dir = gDirectory; + + // loop over all keys in this directory + TList* key_list = current_source_dir->GetListOfKeys(); + int n = key_list->GetEntries(); + for ( int j = 0; j < n; ++j ) { + TKey* k = (TKey*)key_list->At( j ); + const std::string source_pathname = current_source_dir->GetPath() + std::string( "/" ) + k->GetName(); + TObject* o = source->Get( source_pathname.c_str() ); + + if ( o && o->IsA()->InheritsFrom( "TDirectory" ) ) { + if ( msgLevel( MSG::VERBOSE ) ) { + verbose() << " subdir [" << o->GetName() << "]..." << endmsg; + } + destination->cd(); + TDirectory* destination_dir = destination->mkdir( o->GetName(), o->GetTitle() ); + copyFileLayout( destination_dir, source ); + } + } // loop over keys + return; +} + +size_t THistSvcHLT::findHistID( const std::string& id, const THistID*& hid, const size_t& index ) const +{ + GlobalDirectoryRestore restore( m_svcMut ); + + std::string idr( id ); + removeDoubleSlash( idr ); + + hid = 0; + + if ( idr.find( "/" ) == 0 ) { + // fully specified name, starts with "/" + auto itr = m_uids.find( idr ); + if ( itr == m_uids.end() ) { + // no matches found + return 0; + } else { + // one or more matches found (clones). + if ( index >= itr->second->size() ) { + error() << "no index " << index << " found for Hist " << idr << endmsg; + return 0; + } + hid = &( itr->second->at( index ) ); + return 1; + } + } else { + // name not fully specified. + auto mitr = m_ids.equal_range( idr ); + if ( mitr.first == mitr.second ) { + // not found + return 0; + } else if ( distance( mitr.first, mitr.second ) == 1 ) { + // one found + if ( index >= mitr.first->second->size() ) { + error() << "no index " << index << " found for Hist " << idr << endmsg; + return 0; + } + hid = &( mitr.first->second->at( 0 ) ); + return 1; + } else { + // multiple matches + hid = &( mitr.first->second->at( 0 ) ); + return distance( mitr.first, mitr.second ); + } + } +} + +void THistSvcHLT::dump() const { - verbose() << "dummy implementation of " << __FUNCTION__ << endmsg; + std::ostringstream ost; + + // list< vector<THistID> > + ost << "m_hlist: size: " << m_hlist.size() << "\n"; + for ( auto& vh : m_hlist ) { + ost << " - " << vh->at( 0 ) << " :: [" << vh << "] " << vh->size() << " {"; + for ( auto& e : *vh ) { + TObject* o = e.obj; + ost << "[" << o << "]"; + } + ost << "}\n"; + } + + // map uid -> vector<THistID>* + ost << "\n" + << "m_uids: " << m_uids.size() << "\n"; + for ( auto& e : m_uids ) { + ost << " - " << e.first << " [" << e.second << "]" << std::endl; + } + + // multimap id -> vector<THistID>* + ost << "\n" + << "m_ids: " << m_ids.size() << "\n"; + for ( auto& e : m_ids ) { + ost << " - " << e.first << " [" << e.second << "]" << std::endl; + } + + // map TObject* -> THistID* + ost << "\n" + << "m_tobjs: " << m_tobjs.size() << "\n"; + for ( auto& e : m_tobjs ) { + TObject* o = e.first; + THistID& i = e.second.first->at( e.second.second ); + ost << " - " << o << " -> " << i << std::endl; + } + + debug() << "dumping THistSvcHLT contents\n" << ost.str() << endmsg; +} + +StatusCode THistSvcHLT::merge( const THistID& hid ) { return merge( hid.id ); } + +StatusCode THistSvcHLT::merge( vhid_t* vh ) +{ + const std::string& name = vh->at( 0 ).id; + if ( vh->size() == 1 ) { + debug() << "merge: id: \"" << name << "\" is size 1. nothing to do" << endmsg; + return StatusCode::SUCCESS; + } + + if ( !vh->at( 0 ).obj->IsA()->InheritsFrom( "TH1" ) ) { + error() << "merge: id \"" << name << "\" is not a THn. Cannot merge" << endmsg; + return StatusCode::FAILURE; + } + + TList* l = new TList(); + for ( size_t i = 1; i < vh->size(); ++i ) { + debug() << "merge: id: \"" << name << "\" (" << vh->at( i ).obj << ") adding index " << i << endmsg; + l->Add( vh->at( i ).obj ); + } + + TH1* t0 = dynamic_cast<TH1*>( vh->at( 0 ).obj ); + if ( t0 == 0 ) { + error() << "merge: could not dcast " << name << "(" << t0 << ") index " << 0 << " to TH1" << endmsg; + return StatusCode::FAILURE; + } + + Long64_t n = t0->Merge( l ); + + debug() << "merge: id: \"" << name << "\" merged " << n << " entries" << endmsg; + + for ( size_t i = 1; i < vh->size(); ++i ) { + TH1* th = dynamic_cast<TH1*>( vh->at( i ).obj ); + if ( th != 0 ) { + debug() << "clearing index " << i << "(" << th << ")" << endmsg; + th->SetDirectory( nullptr ); + th->Reset(); + } else { + error() << "merge: could not dcast " << name << " index " << i << " to TH1" << endmsg; + return StatusCode::FAILURE; + } + } return StatusCode::SUCCESS; } +StatusCode THistSvcHLT::rootOpenAction( const Io::FileAttr* fa, const std::string& caller ) +{ + if ( fa->tech() != Io::ROOT ) { + // This should never happen + return StatusCode::SUCCESS; + } + + if ( fa->desc() != "HIST" ) { + return StatusCode::SUCCESS; + } + + p_incSvc->fireIncident( FileIncident( caller, "OpenHistFile", fa->name() ) ); + + if ( fa->flags().isRead() ) { + p_incSvc->fireIncident( FileIncident( caller, "BeginHistFile", fa->name() ) ); + } else if ( fa->flags().isWrite() ) { + p_incSvc->fireIncident( FileIncident( caller, IncidentType::BeginOutputFile, fa->name() ) ); + } else { + // for Io::RW + p_incSvc->fireIncident( FileIncident( caller, IncidentType::BeginOutputFile, fa->name() ) ); + } + + return StatusCode::SUCCESS; +} + +StatusCode THistSvcHLT::rootOpenErrAction( const Io::FileAttr* fa, const std::string& caller ) +{ + if ( fa->tech() != Io::ROOT ) { + // This should never happen + return StatusCode::SUCCESS; + } + + if ( fa->desc() != "HIST" ) { + return StatusCode::SUCCESS; + } + + if ( fa->flags().isRead() ) { + p_incSvc->fireIncident( FileIncident( caller, IncidentType::FailInputFile, fa->name() ) ); + } else if ( fa->flags().isWrite() ) { + p_incSvc->fireIncident( FileIncident( caller, IncidentType::FailOutputFile, fa->name() ) ); + } else { + // for Io::RW + p_incSvc->fireIncident( FileIncident( caller, "FailRWFile", fa->name() ) ); + } + + return StatusCode::SUCCESS; +} diff --git a/HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.h b/HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.h index 1f72e52d7bc..9ff4a578f27 100644 --- a/HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.h +++ b/HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.h @@ -28,90 +28,133 @@ #include "TObject.h" #include "TTree.h" -#include "AthenaBaseComps/AthService.h" - class IIncidentSvc; -class THistSvcHLT: public extends3<Service, ITHistSvc, IIncidentListener, IIoComponent> { -class THistSvcHLT : public extends<AthService, ITHistSvc, IIncidentListener, IIoComponent> +class THistSvcHLT : public extends<Service, ITHistSvc, IIncidentListener, IIoComponent> { public: - - THistSvcHLT(const std::string& name, ISvcLocator* svcLoc); + THistSvcHLT( const std::string& name, ISvcLocator* svc ); + StatusCode initialize() override; StatusCode reinitialize() override; StatusCode finalize() override; - + +public: // Methods from ITHistSvc /// @name Functions to manage ROOT histograms of any kind /// @{ - StatusCode regHist(const std::string& name) override; - StatusCode regHist(const std::string& name, std::unique_ptr<TH1> hist) override; - StatusCode regHist(const std::string& name, std::unique_ptr<TH1> hist, TH1* hist_ptr) override; - StatusCode regHist(const std::string& name, TH1*) override; - - StatusCode getHist(const std::string& name, TH1*&, size_t index = 0) const override; - StatusCode getHist(const std::string& name, TH2*&, size_t index = 0) const override; - StatusCode getHist(const std::string& name, TH3*&, size_t index = 0) const override; + + /// Register a new ROOT histogram TH*X with a name + StatusCode regHist( const std::string& name ) override; + /// Register an existing ROOT histogram TH*X with name and moved unique_ptr + /// @param [in] name defines the histogram id/name under which it is recorded + /// @param [in] hist transfers ownership of the histogram to the THistSvc + StatusCode regHist( const std::string& name, std::unique_ptr<TH1> hist ) override; + /// Register an existing ROOT histogram TH*X with name and moved unique_ptr + /// @param [in] name defines the histogram id/name under which it is recorded + /// @param [in] hist transfers ownership of the histogram to the THistSvc + /// @param [out] hist_ptr for compatibility: return raw pointer to managed object to support common usage in Athena + StatusCode regHist( const std::string& name, std::unique_ptr<TH1> hist, TH1* hist_ptr ) override; + /// @deprecated {Just for compatibility purposes. Ownership should be clearly managed.} + /// Register an existing ROOT histogram TH*X with name and pointer + StatusCode regHist( const std::string& name, TH1* ) override; + + /// Return histogram with given name as TH1*, THistSvcMT still owns object. + StatusCode getHist( const std::string& name, TH1*&, size_t index = 0 ) const override; + /// Return histogram with given name as TH2*, THistSvcMT still owns object. + StatusCode getHist( const std::string& name, TH2*&, size_t index = 0 ) const override; + /// Return histogram with given name as TH3*, THistSvcMT still owns object. + StatusCode getHist( const std::string& name, TH3*&, size_t index = 0 ) const override; + /// @} /// @name Functions to manage TTrees /// @{ - StatusCode regTree(const std::string& name) override; - StatusCode regTree(const std::string& name, TTree* tree) override; - StatusCode regTree(const std::string& name, std::unique_ptr<TTree> tree) override; - - StatusCode getTree( const std::string& name, TTree*& tree) const override; + + /// Register a new TTree with a given name + StatusCode regTree( const std::string& name ) override; + /// Register an existing TTree with a given name and moved unique_ptr + StatusCode regTree( const std::string& name, std::unique_ptr<TTree> ) override; + /// @deprecated {Just kept for compatibiltiy to current ATLAS code. Pleas use std::unique_ptrs instead!} + /// Register a new TTree with a given name and a raw pointer + StatusCode regTree( const std::string& name, TTree* ) override; + /// Return TTree with given name + StatusCode getTree( const std::string& name, TTree*& ) const override; + /// @} /// @name Functions to manage TGraphs /// @{ - StatusCode regGraph(const std::string& name) override; - StatusCode regGraph(const std::string& name, std::unique_ptr<TGraph> graph) override; - StatusCode regGraph(const std::string& name, TGraph* graph) override; - - StatusCode getGraph(const std::string& name, TGraph*& graph) const override; + + /// Register a new TGraph with a given name + StatusCode regGraph( const std::string& name ) override; + /// Register an existing TGraph with a given name and moved unique_ptr + StatusCode regGraph( const std::string& name, std::unique_ptr<TGraph> ) override; + /// @deprecated {Just kept for compatibiltiy to current ATLAS code. Pleas use std::unique_ptrs instead!} + /// Register a new TGraph with a given name and a raw pointer + virtual StatusCode regGraph( const std::string& name, TGraph* ) override; + /// Return TGraph with given name + StatusCode getGraph( const std::string& name, TGraph*& ) const override; + /// @} - /// @name Functions to manage shared objects + /// @name Functions managing shared objects /// @{ - StatusCode regShared(const std::string& name, std::unique_ptr<TH1> hist, LockedHandle<TH1>& lh) override; - StatusCode regShared(const std::string& name, std::unique_ptr<TH2> hist, LockedHandle<TH2>& lh) override; - StatusCode regShared(const std::string& name, std::unique_ptr<TH3> hist, LockedHandle<TH3>& lh) override; - StatusCode regShared(const std::string& name, std::unique_ptr<TGraph> graph, LockedHandle<TGraph>& lh) override; - - StatusCode getShared(const std::string& name, LockedHandle<TH1>& lh) const override; - StatusCode getShared(const std::string& name, LockedHandle<TH2>& lh) const override; - StatusCode getShared(const std::string& name, LockedHandle<TH3>& lh) const override; - StatusCode getShared(const std::string& name, LockedHandle<TGraph>& lh) const override; + + /// Register shared object of type TH1 and return LockedHandle for that object + StatusCode regShared( const std::string& name, std::unique_ptr<TH1>, LockedHandle<TH1>& ) override; + /// Register shared object of type TH2 and return LockedHandle for that object + StatusCode regShared( const std::string& name, std::unique_ptr<TH2>, LockedHandle<TH2>& ) override; + /// Register shared object of type TH3 and return LockedHandle for that object + StatusCode regShared( const std::string& name, std::unique_ptr<TH3>, LockedHandle<TH3>& ) override; + /// Register shared object of type TGraph and return LockedHandle for that object + StatusCode regShared( const std::string& name, std::unique_ptr<TGraph>, LockedHandle<TGraph>& ) override; + /// Retrieve shared object with given name as TH1 through LockedHandle + StatusCode getShared( const std::string& name, LockedHandle<TH1>& ) const override; + /// Retrieve shared object with given name as TH2 through LockedHandle + StatusCode getShared( const std::string& name, LockedHandle<TH2>& ) const override; + /// Retrieve shared object with given name as TH3 through LockedHandle + StatusCode getShared( const std::string& name, LockedHandle<TH3>& ) const override; + /// Retrieve shared object with given name as TGraph through LockedHandle + StatusCode getShared( const std::string& name, LockedHandle<TGraph>& ) const override; + /// @} - + /// @name Functions that work on any TObject in the THistSvcMT /// @{ - StatusCode deReg(const std::string& name) override; - StatusCode deReg(TObject* obj) override; - StatusCode merge(const std::string& id) override; - StatusCode merge(TObject* obj) override; + /// Deregister object with given name and give up ownership (without deletion!) + StatusCode deReg( const std::string& name ) override; + /// Deregister obejct identified by TObject* and give up ownership (without deletion!) + StatusCode deReg( TObject* obj ) override; + + /// Merge all clones for object with a given id + StatusCode merge( const std::string& id ) override; + /// Merge all clones for given TObject* + StatusCode merge( TObject* ) override; + /// Check if object with given name is managed by THistSvcMT bool exists( const std::string& name ) const override; + /// @} /// @name Functions returning lists of all histograms, trees and graphs /// @{ + std::vector<std::string> getHists() const override; std::vector<std::string> getTrees() const override; std::vector<std::string> getGraphs() const override; - StatusCode getTHists(TDirectory* td, TList&, bool recurse = false) const override; - StatusCode getTHists(const std::string& name, TList&, bool recurse = false) const override; - StatusCode getTHists(TDirectory* td, TList& tl, bool recurse = false, bool reg = false) override; - StatusCode getTHists(const std::string& name, TList& tl, bool recurse = false, bool reg = false) override; + StatusCode getTHists( TDirectory* td, TList&, bool recurse = false ) const override; + StatusCode getTHists( const std::string& name, TList&, bool recurse = false ) const override; + StatusCode getTHists( TDirectory* td, TList& tl, bool recurse = false, bool reg = false ) override; + StatusCode getTHists( const std::string& name, TList& tl, bool recurse = false, bool reg = false ) override; + + StatusCode getTTrees( TDirectory* td, TList&, bool recurse = false ) const override; + StatusCode getTTrees( const std::string& name, TList&, bool recurse = false ) const override; + StatusCode getTTrees( TDirectory* td, TList& tl, bool recurse = false, bool reg = false ) override; + StatusCode getTTrees( const std::string& name, TList& tl, bool recurse = false, bool reg = false ) override; - StatusCode getTTrees(TDirectory* td, TList&, bool recurse = false) const override; - StatusCode getTTrees(const std::string& name, TList&, bool recurse = false) const override; - StatusCode getTTrees(TDirectory* td, TList& tl, bool recurse = false, bool reg = false) override; - StatusCode getTTrees(const std::string& name, TList& tl, bool recurse = false, bool reg = false) override; /// @} public: @@ -122,15 +165,194 @@ public: // From IIoComponent StatusCode io_reinit() override; -protected: - ~THistSvcHLT() override = default; - private: - // Properties - IntegerProperty m_autoSave, m_autoFlush, m_compressionLevel, m_maxFileSize; - BooleanProperty m_print; - StringArrayProperty m_inputfile, m_outputfile; + typedef std::recursive_mutex THistSvcMutex_t; + typedef std::mutex histMut_t; + + /// Helper class that manages ROOts global directory and file + class GlobalDirectoryRestore + { + public: + GlobalDirectoryRestore( THistSvcMutex_t& mut ); + ~GlobalDirectoryRestore(); + + private: + TDirectory* m_gDirectory; + TFile* m_gFile; + int m_gErrorIgnoreLevel; + std::lock_guard<THistSvcMutex_t> m_lock; + }; + + /// Enumerating all possible file access modes + enum Mode { READ, WRITE, UPDATE, APPEND, SHARE, INVALID }; + + /// Helper struct that bundles the histogram ID with a mutex, TFile and TObject* + struct THistID { + std::string id{""}; + bool temp{true}; + TObject* obj{nullptr}; + TFile* file{nullptr}; + Mode mode{INVALID}; + histMut_t* mutex{nullptr}; + bool shared{false}; + + THistID() = default; + THistID( const THistID& rhs ) = default; + THistID( std::string& i, bool& t, TObject* o, TFile* f ) : id( i ), temp( t ), obj( o ), file( f ) {} + THistID( std::string& i, bool& t, TObject* o, TFile* f, Mode m ) + : id( i ), temp( t ), obj( o ), file( f ), mode( m ) + { + } + + void reset() + { + id = ""; + temp = true; + obj = nullptr; + file = nullptr; + mode = INVALID; + mutex = nullptr; + shared = false; + } + + bool operator<( THistID const& rhs ) const { return ( obj < rhs.obj ); } + + friend std::ostream& operator<<( std::ostream& ost, const THistID& hid ) + { + ost << "id: " << hid.id << " t: " << hid.temp << " s: " << hid.shared << " M: " << hid.mode << " m: " << hid.mutex + << " o: " << hid.obj << " " << hid.obj->IsA()->GetName(); + return ost; + } + }; + + /// @name Container definitions + /// @{ + + std::vector<std::string> m_Rstream, m_Wstream; + + /// list of already connected files. This is to keep track of files + /// registered by the setupInputFile callback method + std::set<std::string> m_alreadyConnectedInFiles; + + /// list of already connected files. This is to keep track of files + /// registered by the setupOutputFile callback method + std::set<std::string> m_alreadyConnectedOutFiles; + + // containers for fast lookups + // same uid for all elements in vec + typedef std::vector<THistID> vhid_t; + // all THistIDs + typedef std::list<vhid_t*> hlist_t; + // uid: /stream/name -> vhid + typedef std::unordered_map<std::string, vhid_t*> uidMap_t; + // name -> vhid + typedef std::unordered_multimap<std::string, vhid_t*> idMap_t; + typedef std::unordered_map<TObject*, std::pair<vhid_t*, size_t>> objMap_t; + + hlist_t m_hlist; + uidMap_t m_uids; + idMap_t m_ids; + + // Container holding all TObjects and vhid*s + objMap_t m_tobjs; + + std::map<std::string, std::pair<TFile*, Mode>> m_files; // stream->file + typedef std::multimap<std::string, std::string> streamMap; + streamMap m_fileStreams; // fileName->streams + + // stream->filename of shared files + std::map<std::string, std::string> m_sharedFiles; + + /// @} + + /// @name Templated helper functions to register and retrieve Histograms and TObjects + /// @{ + + template <typename T> + StatusCode regHist_i( std::unique_ptr<T> hist, const std::string& name, bool shared ); + template <typename T> + StatusCode regHist_i( std::unique_ptr<T> hist, const std::string& name, bool shared, THistID*& hid ); + template <typename T> + T* getHist_i( const std::string& name, const size_t& ind = 0, bool quiet = false ) const; + template <typename T> + T* readHist_i( const std::string& name ) const; + + template <typename T> + LockedHandle<T> regShared_i( const std::string& id, std::unique_ptr<T> hist ); + template <typename T> + LockedHandle<T> getShared_i( const std::string& name ) const; + + /// @} + + /// @name Collection of private helper methods + /// @{ + + template <typename T> + T* readHist( const std::string& name ) const; + TTree* readTree( const std::string& name ) const; + + /// Handle case where TTree grows beyond TTree::fgMaxTreeSize + void updateFiles(); + StatusCode writeObjectsToFile(); + StatusCode connect( const std::string& ); + TDirectory* changeDir( const THistSvcHLT::THistID& hid ) const; + std::string stripDirectoryName( std::string& dir ) const; + void removeDoubleSlash( std::string& ) const; + + void MergeRootFile( TDirectory*, TDirectory* ); + + bool findStream( const std::string& name, std::string& root, std::string& rem, TFile*& file ) const; + void parseString( const std::string& id, std::string& root, std::string& rem ) const; + + /// call-back method to handle input stream property + void setupInputFile( Gaudi::Details::PropertyBase& inputfile ); + + /// call-back method to handle output stream property + void setupOutputFile( Gaudi::Details::PropertyBase& outputfile ); + + void setupCompressionLevel( Gaudi::Details::PropertyBase& cmp ); + + /// helper function to recursively copy the layout of a TFile into a new TFile + void copyFileLayout( TDirectory*, TDirectory* ); + + size_t findHistID( const std::string& id, const THistID*& hid, const size_t& index = 0 ) const; + + void dump() const; + + /// Helper method to merge THistID objects + StatusCode merge( const THistID& ); + /// Helper method to merge vectors of THistID + StatusCode merge( vhid_t* ); + + StatusCode rootOpenAction( FILEMGR_CALLBACK_ARGS ); + StatusCode rootOpenErrAction( FILEMGR_CALLBACK_ARGS ); + + /// @} + + /// @name Gaudi properties + /// @{ + + Gaudi::Property<int> m_autoSave{this, "AutoSave", 0}; + Gaudi::Property<int> m_autoFlush{this, "AutoFlush", 0}; + Gaudi::Property<bool> m_print{this, "PrintAll", false}; + Gaudi::Property<int> m_maxFileSize{this, "MaxFileSize", 10240, "maximum file size in MB. if exceeded," + " will cause an abort. -1 to never check."}; + Gaudi::Property<int> m_compressionLevel{this, "CompressionLevel", 1}; + Gaudi::Property<std::vector<std::string>> m_outputfile{this, "Output", {}}; + Gaudi::Property<std::vector<std::string>> m_inputfile{this, "Input", {}}; + + /// @} + + IIncidentSvc* p_incSvc = nullptr; + IFileMgr* p_fileMgr = nullptr; + + bool m_signaledStop = false; + bool m_delayConnect = false; + bool m_okToConnect = false; + + mutable std::string m_curstream; + mutable THistSvcMutex_t m_svcMut; }; // Include template implementation diff --git a/HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.icc b/HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.icc index ae4adb5d4e5..9595c3a580e 100644 --- a/HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.icc +++ b/HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.icc @@ -5,6 +5,334 @@ #ifndef THISTSVCHLT_ICC #define THISTSVCHLT_ICC -// inline methods temporarily deleted +#include <map> +#include <string> + +#include "TFile.h" +#include "TObject.h" + +#ifndef GAUDIKERNEL_MSGSTREAM_H +#include "GaudiKernel/MsgStream.h" +#endif + +#include "GaudiKernel/System.h" + +template <typename T> +StatusCode THistSvcHLT::regHist_i( std::unique_ptr<T> hist, const std::string& id, bool shared ) +{ + THistID* hid = nullptr ; + return regHist_i( std::move(hist), id, shared, hid ); +} + +template <typename T> +StatusCode THistSvcHLT::regHist_i( std::unique_ptr<T> hist_unique, const std::string& id, bool shared, THistID*& phid ) +{ + GlobalDirectoryRestore restore( m_svcMut ); + phid = nullptr; + + // It is sad that we lose propper memory management here + T* hist = nullptr; + if( hist_unique.get() != nullptr ) { + hist = hist_unique.release(); + } + debug() << "regHist_i obj: " << hist << " id: " << id << " s: " << shared << endmsg; + + std::string idr( id ); + removeDoubleSlash( idr ); + + if ( idr.find( "/" ) == idr.length() ) { + error() << "Badly formed identifier \"" << idr << "\": " + << "Must not end with a /" << endmsg; + delete hist; + return StatusCode::FAILURE; + } + + TFile* f = nullptr; + std::string stream, name; + if ( !findStream( idr, stream, name, f ) ) { + error() << "Could not register id: \"" << idr << "\"" << endmsg; + delete hist; + return StatusCode::FAILURE; + } + + std::string uid = "/" + stream + "/" + name; + + uidMap_t::iterator uitr = m_uids.find( uid ); + bool exists( false ); + if ( uitr != m_uids.end() ) { + exists = true; + TObject* t1 = uitr->second->at( 0 ).obj; + if ( hist->Compare( t1 ) != 0 ) { + error() << "previously registered object with identifier \"" << uid << "\" does not compare to this one" + << endmsg; + delete hist; + return StatusCode::FAILURE; + } else { + debug() << "previously registered id \"" << uid << "\": num " << uitr->second->size() << endmsg; + } + } + + bool temp = false; + if ( !f ) { + temp = true; + if ( msgLevel( MSG::DEBUG ) ) { + debug() << "Historgram with id \"" << idr << "\" is temporary" << endmsg; + } + } + + TObject* to = nullptr; + THistID hid; + // check to see if this hist is to be read in; + if ( !temp && m_files.find( stream )->second.second == READ ) { + if ( hist != 0 ) { + warning() << "Registering id: \"" << idr << "\" with non zero pointer!" << endmsg; + } + + hist = readHist_i<T>( idr ); + if ( hist == nullptr ) { + error() << "Unable to read in hist" << endmsg; + delete hist; + return StatusCode::FAILURE; + } + to = dynamic_cast<TObject*>( hist ); + hid = THistID( uid, temp, to, f, m_files.find( stream )->second.second ); + } else if ( !hist ) { + error() << "Unable to read in hist with id: \"" << idr << "\"" << endmsg; + delete hist; + return StatusCode::FAILURE; + } else { + to = dynamic_cast<TObject*>( hist ); + if ( to == nullptr ) { + error() << "Could not dcast to TObject. id: \"" << idr << "\"" << endmsg; + delete hist; + return StatusCode::FAILURE; + } + + auto oitr = m_tobjs.find( to ); + if ( oitr != m_tobjs.end() ) { + error() << "already registered id: \"" << idr << "\" with identifier \"" + << oitr->second.first->at( oitr->second.second ).id << "\"" << endmsg; + delete hist; + return StatusCode::FAILURE; + } + + hid = THistID( uid, temp, to, f, m_files.find( stream )->second.second ); + hid.shared = shared; + TDirectory* dir = changeDir( hid ); + + if ( dynamic_cast<TTree*>( hist ) ) { + dynamic_cast<TTree*>( hist )->SetDirectory( dir ); + } else if ( dynamic_cast<TH1*>( hist) ) { + dynamic_cast<TH1*>( hist )->SetDirectory( dir ); + } else if ( dynamic_cast<TGraph*>( hist ) ) { + dir->Append( hist ); + } else { + error() << "id: \"" << idr << "\" is not a TH, TTree, or TGraph. Attaching it to current dir." << endmsg; + dir->Append( hist ); + } + } + + std::string fname; + if ( !f ) { + fname = "none"; + } else { + fname = f->GetName(); + } + + debug() << "Registering" << ( shared ? " shared " : " " ) << System::typeinfoName( typeid( *hist ) ) << " title: \"" + << hist->GetTitle() << "\" id: \"" << uid + << "\" dir: " + // << hist->GetDirectory()->GetPath() << " " + << changeDir( hid )->GetPath() << " file: " << fname << endmsg; + + // create a mutex for all shared histograms + if ( shared ) { + hid.mutex = new histMut_t; + } + + if ( exists ) { + vhid_t* vi = uitr->second; + vi->push_back( hid ); + phid = &( vi->back() ); + + m_tobjs.emplace( to, std::pair<vhid_t*, size_t>( vi, vi->size() - 1 ) ); + } else { + vhid_t* vi = new vhid_t{hid}; + m_hlist.emplace( m_hlist.end(), vi ); + + phid = &( vi->back() ); + m_uids.emplace( uid, vi ); + m_ids.emplace( name, vi ); + + m_tobjs.emplace( to, std::pair<vhid_t*, size_t>( vi, 0 ) ); + } + + debug() << "regHist_i THistID: " << hid << endmsg; + + return StatusCode::SUCCESS; +} + +template <typename T> +T* THistSvcHLT::getHist_i( const std::string& id, const size_t& ind, bool quiet ) const +{ + // id starts with "/": unique + + GlobalDirectoryRestore restore( m_svcMut ); + + T* hist = nullptr; + const THistID* hid = nullptr; + size_t num = findHistID( id, hid, ind ); + if ( num == 0 ) { + // no matches found + if ( !quiet ) { + error() << "could not locate Hist with id \"" << id << "\"" << endmsg; + } + return nullptr; + } else if ( num > 1 ) { + if ( !quiet ) { + // return failure if trying to GET a single hist + error() << "Multiple matches with id \"" << id << "\"." + << " Further specifications required." << endmsg; + return nullptr; + } else { + info() << "Found multiple matches with id \"" << id << "\"" << endmsg; + // return first match if just INQUIRING (i.e. != nullptr) + hist = dynamic_cast<T*>( hid->obj ); + if ( hist == nullptr ) { + error() << "dcast failed, Hist id: \"" << id << "\"" << endmsg; + return nullptr; + } + } + } else { + hist = dynamic_cast<T*>( hid->obj ); + if ( hist == nullptr ) { + error() << "dcast failed, Hist id: \"" << id << "\"" << endmsg; + return nullptr; + } + verbose() << "found unique Hist title: \"" << hist->GetTitle() << "\" id: \"" << id << "\"" << endmsg; + } + + return hist; +} + +template <typename T> +T* THistSvcHLT::readHist_i( const std::string& id ) const +{ + GlobalDirectoryRestore restore( m_svcMut ); + + std::string idr( id ); + removeDoubleSlash( idr ); + + std::string stream, rem, dir, fdir, bdir, fdir2; + TFile* file = nullptr; + + if ( !findStream( idr, stream, rem, file ) ) { + return nullptr; + } + + if ( !file ) { + error() << "no associated file found" << endmsg; + return nullptr; + } + + file->cd( "/" ); + + fdir = idr; + bdir = stripDirectoryName( fdir ); + fdir2 = fdir; + while ( ( dir = stripDirectoryName( fdir ) ) != "" ) { + if ( !gDirectory->GetKey( dir.c_str() ) ) { + error() << "Directory \"" << fdir2 << "\" doesnt exist in " << file->GetName() << endmsg; + return nullptr; + } + gDirectory->cd( dir.c_str() ); + } + + TObject* to = nullptr; + gDirectory->GetObject( fdir.c_str(), to ); + + if ( !to ) { + error() << "Could not get obj \"" << fdir << "\" in " << gDirectory->GetPath() << endmsg; + return nullptr; + } + + T* hist = dynamic_cast<T*>( to ); + if ( hist == nullptr ) { + error() << "Could not convert \"" << idr << "\" to a " << System::typeinfoName( typeid( *hist ) ) << " as is a " + << to->IsA()->GetName() << endmsg; + return nullptr; + } + + if ( msgLevel( MSG::DEBUG ) ) { + debug() << "Read in " << hist->IsA()->GetName() << " \"" << hist->GetName() << "\" from file " << file->GetName() + << endmsg; + hist->Print(); + } + + return hist; +} + +template <typename T> +LockedHandle<T> THistSvcHLT::regShared_i( const std::string& id, std::unique_ptr<T> hist ) +{ + LockedHandle<T> lh( nullptr, nullptr ); + const THistID* hid = nullptr; + if ( findHistID( id, hid ) == 0 ) { + T* phist = hist.get(); + THistID* phid = nullptr; + if ( regHist_i( std::move(hist), id, true, phid ).isSuccess() ) { + lh.set( phist, phid->mutex ); + + } else { + error() << "regSharedHist: unable to register shared hist with id \"" << id << "\"" << endmsg; + } + } else { + if ( !hid->shared ) { + error() << "regSharedHist: previously register Hist with id \"" << id << "\" was not marked shared" << endmsg; + } + + if ( hist->Compare( hid->obj ) != 0 ) { + error() << "regSharedHist: Histogram " << id << " does not compare with " << hid << endmsg; + } else { + T* phist = dynamic_cast<T*>( hid->obj ); + if ( phist == 0 ) { + error() << "regSharedHist: unable to dcast retrieved shared hist \"" << id << "\" of type " + << hid->obj->IsA()->GetName() << " to requested type " << System::typeinfoName( typeid( T ) ) << endmsg; + } else { + lh.set( phist, hid->mutex ); + delete hist.release(); + } + } + } + return lh; +} + +template <typename T> +LockedHandle<T> THistSvcHLT::getShared_i( const std::string& name ) const +{ + GlobalDirectoryRestore restore( m_svcMut ); + + const THistID* hid = nullptr; + size_t i = findHistID( name, hid ); + + LockedHandle<T> hist( nullptr, nullptr ); + + if ( i == 1 ) { + if ( !hid->shared ) { + error() << "getSharedHist: found Hist with id \"" << name << "\", but it's not marked as shared" << endmsg; + return hist; + } + T* h1 = dynamic_cast<T*>( hid->obj ); + hist = LockedHandle<T>( h1, hid->mutex ); + + debug() << "getSharedHist: found THistID: " << *hid << endmsg; + } else if ( i == 0 ) { + error() << "no histograms matching id \"" << name << "\" found" << endmsg; + } else { + info() << "multiple matches for id \"" << name << "\" found [" << i << "], probably from different streams" + << endmsg; + } + return hist; +} #endif // GAUDISVC_THISTSVC_ICC diff --git a/HLT/Trigger/TrigControl/TrigServices/src/TrigMonTHistSvc.cxx b/HLT/Trigger/TrigControl/TrigServices/src/TrigMonTHistSvc.cxx index aa5993009f4..5569c1725e4 100644 --- a/HLT/Trigger/TrigControl/TrigServices/src/TrigMonTHistSvc.cxx +++ b/HLT/Trigger/TrigControl/TrigServices/src/TrigMonTHistSvc.cxx @@ -29,6 +29,7 @@ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * TrigMonTHistSvc::TrigMonTHistSvc( const std::string& name, ISvcLocator* svc ) : THistSvcHLT(name, svc), + AthMessaging(msgSvc(), name), m_excludeType("()"), m_includeType(".+"), m_excludeName(".*\\..*"), @@ -59,8 +60,6 @@ StatusCode TrigMonTHistSvc::initialize() { msg().setLevel(outputLevel()); // fix summing up flag if not running in separate threads - //~ if ( ! isGaudiThreaded(name()) ) - m_add = true; // Protect against multiple instances of TROOT if ( 0 == gROOT ) { @@ -134,6 +133,8 @@ StatusCode TrigMonTHistSvc::regHist(const std::string& id, TH1* hist_ptr) { + + StatusCode TrigMonTHistSvc::regTree(const std::string& id) { return THistSvcHLT::regTree(id); } @@ -188,34 +189,16 @@ template <typename T> StatusCode TrigMonTHistSvc::regHist_i(std::unique_ptr<T> h std::string regid; if ( isObjectAllowed(id, hist).isFailure() ) { return StatusCode::FAILURE; - } - // prepend by service name if the histograms are not going to be added - // this way they are registered under different unique names - // from each service - //~ if ( m_add ) - regid = id; -/* - else { - std::string n = getGaudiThreadIDfromName(name()); - - // strip blanks at the end of service name - std::string::size_type pos; - while ( (pos = n.find('\0', 0)) != std::string::npos) - n.erase(pos,1); - // build the name used for registration - regid = id+n; - } -*/ - - if (hist->Class()->InheritsFrom(TH1::Class())) { - hltinterface::IInfoRegister::instance()->registerTObject(name(), regid, hist); - ATH_MSG_DEBUG("Histogram " << hist->GetName() - << " registered under " << regid << " " << m_add << " " << name()); - } else { - ATH_MSG_ERROR("Trying to register " << hist->ClassName() - << " but this does not inherit from TH1 histogram"); - return StatusCode::SUCCESS; - } + } + regid = id; + + if (hist->Class()->InheritsFrom(TH1::Class())) { + hltinterface::IInfoRegister::instance()->registerTObject(name(), regid, hist); + ATH_MSG_DEBUG("Histogram " << hist->GetName() + << " registered under " << regid << " " << name()); + } else { + ATH_MSG_ERROR("Trying to register " << hist->ClassName() + << " but this does not inherit from TH1 histogram"); return StatusCode::SUCCESS; } return StatusCode::SUCCESS; diff --git a/HLT/Trigger/TrigControl/TrigServices/src/TrigMonTHistSvc.h b/HLT/Trigger/TrigControl/TrigServices/src/TrigMonTHistSvc.h index c5c52d19f5d..099f338b980 100644 --- a/HLT/Trigger/TrigControl/TrigServices/src/TrigMonTHistSvc.h +++ b/HLT/Trigger/TrigControl/TrigServices/src/TrigMonTHistSvc.h @@ -33,13 +33,17 @@ class TTree; #include <boost/regex.hpp> -class TrigMonTHistSvc: public THistSvcHLT +class TrigMonTHistSvc: virtual public THistSvcHLT, + public AthMessaging { public: TrigMonTHistSvc(const std::string& name, ISvcLocator *svc ); virtual ~TrigMonTHistSvc(); + TrigMonTHistSvc(const std::string& name, ISvcLocator *svc ); + virtual ~TrigMonTHistSvc(); + virtual StatusCode queryInterface( const InterfaceID& riid, void** ppvInterface ); diff --git a/HLT/Trigger/TrigControl/TrigServices/src/TrigSORFromPtreeHelper.cxx b/HLT/Trigger/TrigControl/TrigServices/src/TrigSORFromPtreeHelper.cxx index 46c7272eab8..35ca19e6cde 100644 --- a/HLT/Trigger/TrigControl/TrigServices/src/TrigSORFromPtreeHelper.cxx +++ b/HLT/Trigger/TrigControl/TrigServices/src/TrigSORFromPtreeHelper.cxx @@ -12,8 +12,6 @@ */ #include "TrigSORFromPtreeHelper.h" -#include "GaudiKernel/EventContext.h" -#include "AthenaKernel/ExtendedEventContext.h" #include "AthenaKernel/IIOVDbSvc.h" #include "AthenaKernel/IAddressProvider.h" #include "owl/time.h" @@ -65,24 +63,12 @@ const SORHelper::SOR * SORHelper::fillSOR(const ptree & rparams, const EventCont m_log << MSG::ERROR << ST_WHERE << "could not find IOVDbSvc. Time dependent conditions data may be not properly handled." << endmsg; } else { - m_log << MSG::VERBOSE << ST_WHERE - << "Retrieved IOVDbSvc" << endmsg; IOVTime currentIOVTime(rparams.get<unsigned int>("run_number"), IOVTime::MINEVENT, OWLTime{(rparams.get_child("timeSOR").data()).c_str()}.total_mksec_utc() * 1000); - - m_log << MSG::VERBOSE << ST_WHERE - << "Created currentIOVTime object" << endmsg; - - // need to provide an event context extended with a run number to IOVDBSvc::signalBeginRun - EventContext dummyEventContext(0, 0); - dummyEventContext.setExtension(Atlas::ExtendedEventContext(dstore.get(), rparams.get<unsigned int>("run_number"))); - - m_log << MSG::VERBOSE << ST_WHERE - << "Created dummyEventContext" << endmsg; - + // Signal BeginRun directly to IOVDbSvc to set complete IOV start time - if (StatusCode::SUCCESS != iovdbsvc->signalBeginRun(currentIOVTime,dummyEventContext)) { + if (StatusCode::SUCCESS != iovdbsvc->signalBeginRun(currentIOVTime, ctx)) { m_log << MSG::ERROR << ST_WHERE << "Unable to signal begin run IOVTime to IOVDbSvc. IOVTime = " << currentIOVTime << endmsg; } else { @@ -235,7 +221,8 @@ SORHelper::updateProxy(const SG & dstore, SOR * sor) const return StatusCode::FAILURE; } - // check if the proxy has an IAddressProvider, if not set IOVDbSvc as provider + // check if the transient address has an IAddressProvider, if not set + //IOVDbSvc as provider if (!proxy->provider()) { // get handle to the IOVDbSvc ServiceHandle<IIOVDbSvc> iovdbsvc("IOVDbSvc", CLNAME); -- GitLab