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