diff --git a/Event/ByteStreamCnvSvc/src/ByteStreamEventStorageInputSvc.cxx b/Event/ByteStreamCnvSvc/src/ByteStreamEventStorageInputSvc.cxx
index fa0263f26580dbc532ede3c8ef2d0b13a1b39fb4..869c0a250628a06f3bf8571f9dd6e63661de6662 100644
--- a/Event/ByteStreamCnvSvc/src/ByteStreamEventStorageInputSvc.cxx
+++ b/Event/ByteStreamCnvSvc/src/ByteStreamEventStorageInputSvc.cxx
@@ -40,11 +40,8 @@
 ByteStreamEventStorageInputSvc::ByteStreamEventStorageInputSvc(const std::string& name,
 		ISvcLocator* svcloc) : ByteStreamInputSvc(name, svcloc),
 	//m_totalEventCounter(0),
-	m_re(0),
-        m_eventStatus(0),
 	m_reader(0),
         m_evtInFile(0),
-        m_eventOffset(0),
 	m_sgSvc("StoreGateSvc", name),
 	m_mdSvc("StoreGateSvc/InputMetaDataStore", name),
 	m_incidentSvc("IncidentSvc", name),
@@ -66,8 +63,8 @@ ByteStreamEventStorageInputSvc::ByteStreamEventStorageInputSvc(const std::string
 }
 //------------------------------------------------------------------------------
 ByteStreamEventStorageInputSvc::~ByteStreamEventStorageInputSvc() {
-   delete m_re; m_re = 0;
-   delete m_reader; m_reader = 0;
+  
+  delete m_reader; m_reader = 0;
 }
 //------------------------------------------------------------------------------
 StatusCode ByteStreamEventStorageInputSvc::initialize() {
@@ -126,7 +123,8 @@ StatusCode ByteStreamEventStorageInputSvc::stop() {
 //------------------------------------------------------------------------------
 StatusCode ByteStreamEventStorageInputSvc::finalize() {
    // delete the old event
-   releaseCurrentEvent();
+  //   releaseCurrentEvent(); // destruction of service obj will clear it
+  
    if (!m_sgSvc.release().isSuccess()) {
       ATH_MSG_WARNING("Cannot release StoreGateSvc");
    }
@@ -246,13 +244,17 @@ bool ByteStreamEventStorageInputSvc::loadMetadata()
 }
 
 const RawEvent* ByteStreamEventStorageInputSvc::previousEvent() {
+
+  std::lock_guard<std::mutex> lock( m_readerMutex );
+  const EventContext context{ Gaudi::Hive::currentContext() };
+
   // Load data buffer from file
   char *buf;
   unsigned int eventSize;
   if (readerReady()) {
     //get current event position (cast to long long until native tdaq implementation)
     m_evtInFile--;
-    m_eventOffset = m_evtOffsets.at(m_evtInFile);
+    m_evtFileOffset = m_evtOffsets.at(m_evtInFile);
     DRError ecode = m_reader->getData(eventSize,&buf,m_evtOffsets.at(m_evtInFile -1));
     if (DRWAIT == ecode && m_wait > 0) {
       do {
@@ -263,7 +265,7 @@ const RawEvent* ByteStreamEventStorageInputSvc::previousEvent() {
           ATH_MSG_ERROR("System Error while running sleep");
           return 0;
         }
-      } while(m_reader->getData(eventSize,&buf,m_eventOffset) == DRWAIT);
+      } while(m_reader->getData(eventSize,&buf,m_evtFileOffset) == DRWAIT);
     } else if (DROK != ecode) {
       ATH_MSG_ERROR("Error reading next event");
       throw ByteStreamExceptions::readError();
@@ -275,57 +277,65 @@ const RawEvent* ByteStreamEventStorageInputSvc::previousEvent() {
     return 0;
   }
 
+  EventCache* cache = m_eventsCache.get(context);
   // initialize before building RawEvent
-  releaseCurrentEvent();
+  releaseEvent( cache );
  
   // Use buffer to build FullEventFragment
   try {
-    buildFragment(buf,eventSize,true);
+    buildFragment( cache, buf, eventSize, true);
   }
   catch (...) {
     // rethrow any exceptions
     throw;
   }
 
-  if (m_re==0) {
+  if ( cache->rawEvent == 0 ) {
     ATH_MSG_ERROR("Failure to build fragment");
     return 0;
   }
 
   // Set it for the data provider
-  m_robProvider->setNextEvent(m_re);
-  m_robProvider->setEventStatus(m_eventStatus);
+  m_robProvider->setNextEvent(context, cache->rawEvent);
+  m_robProvider->setEventStatus(context, cache->eventStatus);
 
   // dump
   if (m_dump) {
-    DumpFrags::dump(m_re);
+    DumpFrags::dump( cache->rawEvent );
   }
-  return(m_re);
+  ATH_MSG_DEBUG( "switched to previous event in slot " << context );
+  return( cache->rawEvent );
+  
 }
 //------------------------------------------------------------------------------
 // Read the next event.
 const RawEvent* ByteStreamEventStorageInputSvc::nextEvent() {
 
+  std::lock_guard<std::mutex> lock( m_readerMutex );
+  const EventContext context{ Gaudi::Hive::currentContext() };
+
   // Load data buffer from file
   char *buf;
   unsigned int eventSize;
   if (readerReady()) {
     DRError ecode;
     // Check if have moved back from high water mark
-    m_evtInFile++; // increment iterator
+    m_evtInFile ++; // increment iterator
     if (m_evtInFile+1 > m_evtOffsets.size()) { 
       //get current event position (cast to long long until native tdaq implementation)
       ATH_MSG_DEBUG("nextEvent _above_ high water mark");
-      m_eventOffset = (long long)m_reader->getPosition();
-      m_evtOffsets.push_back(m_eventOffset);
+      m_evtFileOffset = (long long)m_reader->getPosition();
+      m_evtOffsets.push_back(m_evtFileOffset);
       ecode = m_reader->getData(eventSize,&buf);
     }
+
     else {
       // Load from previous offset
       ATH_MSG_DEBUG("nextEvent below high water mark");
-      m_eventOffset = m_evtOffsets.at(m_evtInFile-1);
-      ecode = m_reader->getData(eventSize,&buf,m_eventOffset);
+      m_evtFileOffset = m_evtOffsets.at( m_evtInFile-1 );
+      ecode = m_reader->getData( eventSize, &buf, m_evtFileOffset );
     }
+
     if (DRWAIT == ecode && m_wait > 0) {
       do {
         // wait for n seconds
@@ -335,7 +345,7 @@ const RawEvent* ByteStreamEventStorageInputSvc::nextEvent() {
           ATH_MSG_ERROR("System Error while running sleep");
           return 0;
         }
-      } while(m_reader->getData(eventSize,&buf) == DRWAIT);
+      } while(m_reader->getData( eventSize, &buf ) == DRWAIT);
     } else if (DROK != ecode) {
       ATH_MSG_ERROR("Error reading next event");
       throw ByteStreamExceptions::readError();
@@ -346,58 +356,67 @@ const RawEvent* ByteStreamEventStorageInputSvc::nextEvent() {
     ATH_MSG_ERROR("DataReader not ready. Need to getBlockIterator first");
     return 0;
   }
+  EventCache* cache = m_eventsCache.get(context);
 
   // initialize before building RawEvent
-  releaseCurrentEvent();
+  releaseEvent( cache );
  
   // Use buffer to build FullEventFragment
   try {
-    buildFragment(buf,eventSize,true);
+    buildFragment( cache,  buf, eventSize, true );
   }
   catch (...) {
     // rethrow any exceptions
     throw;
   }
 
-  if (m_re==0) {
+  if ( cache->rawEvent == 0 ) {
     ATH_MSG_ERROR("Failure to build fragment");
     return 0;
   }
 
+  
   // Set it for the data provider
-  m_robProvider->setNextEvent(m_re);
-  m_robProvider->setEventStatus(m_eventStatus);
+  m_robProvider->setNextEvent( context, cache->rawEvent );
+  m_robProvider->setEventStatus( context, cache->eventStatus );
 
   //++m_totalEventCounter;
 
   // dump
   if (m_dump) {
-    DumpFrags::dump(m_re);
+    DumpFrags::dump( cache->rawEvent );
   }
-  return(m_re);
+  ATH_MSG_DEBUG( "switched to next event in slot " << context );
+  return( cache->rawEvent );
+}
+
+void ByteStreamEventStorageInputSvc::validateEvent() {
+  const EventContext context{ Gaudi::Hive::currentContext() };
+  m_eventsCache.get(context)->eventStatus = validateEvent( m_eventsCache.get(context)->rawEvent );
 }
 
-void ByteStreamEventStorageInputSvc::validateEvent()
+unsigned ByteStreamEventStorageInputSvc::validateEvent( const RawEvent* rawEvent ) const
 {
+  unsigned int status = 0;
   if (m_valEvent) {
     // check validity
     std::vector<eformat::FragmentProblem> p;
-    m_re->problems(p);
+    rawEvent->problems(p);
     if (!p.empty()) {
-      m_eventStatus += 0x01000000;
+      status += 0x01000000;
       // bad event
       ATH_MSG_WARNING("Failed to create FullEventFragment");
       for (std::vector<eformat::FragmentProblem>::const_iterator i = p.begin(), iEnd = p.end();
 	        i != iEnd; i++) {
         ATH_MSG_WARNING(eformat::helper::FragmentProblemDictionary.string(*i));
       }
-      releaseCurrentEvent();
+      //      releaseCurrentEvent();
       throw ByteStreamExceptions::badFragmentData();
     }
-    if (!ROBFragmentCheck()) {
-      m_eventStatus += 0x02000000;
+    if ( !ROBFragmentCheck( rawEvent ) ) {
+      status += 0x02000000;
       // bad event
-      releaseCurrentEvent();
+      //      releaseCurrentEvent();
       ATH_MSG_ERROR("Skipping bad event");
       throw ByteStreamExceptions::badFragmentData();
     }
@@ -405,9 +424,10 @@ void ByteStreamEventStorageInputSvc::validateEvent()
   else {
     ATH_MSG_DEBUG("Processing event without validating.");
   }
+  return status;
 }
 
-void ByteStreamEventStorageInputSvc::buildFragment(void* data, uint32_t eventSize, bool validate)
+void ByteStreamEventStorageInputSvc::buildFragment(EventCache* cache, void* data, uint32_t eventSize, bool validate) const
 {
   OFFLINE_FRAGMENTS_NAMESPACE::DataType* fragment = reinterpret_cast<OFFLINE_FRAGMENTS_NAMESPACE::DataType*>(data);
   if (validate) {
@@ -442,7 +462,7 @@ void ByteStreamEventStorageInputSvc::buildFragment(void* data, uint32_t eventSiz
       } catch (eformat::Issue& ex) {
         // bad event
         ATH_MSG_WARNING(ex.what());
-        releaseCurrentEvent();
+	//        releaseCurrentEvent();
         ATH_MSG_ERROR("Skipping bad event");
         throw ByteStreamExceptions::badFragment();
       }
@@ -455,15 +475,15 @@ void ByteStreamEventStorageInputSvc::buildFragment(void* data, uint32_t eventSiz
   } 
   // This is a FullEventFragment
   // make a new FEFrag in memory from it
-  m_eventStatus = 0;
+  cache->eventStatus = 0;
   if (fragment[5] > 0) {
-    m_eventStatus += eformat::helper::Status(fragment[6]).specific();
-    m_eventStatus += (eformat::helper::Status(fragment[6]).generic() & 0x000000ff) << 16;
+    cache->eventStatus += eformat::helper::Status(fragment[6]).specific();
+    cache->eventStatus += (eformat::helper::Status(fragment[6]).generic() & 0x000000ff) << 16;
   }
 
   // This is a FullEventFragment
   // make a new RawEvent in memory from it
-  m_re = new RawEvent(fragment);
+  cache->rawEvent = new RawEvent(fragment);
   ATH_MSG_DEBUG("Made an FullEventFragment from ES " << fragment);
 
 }
@@ -474,14 +494,14 @@ StatusCode ByteStreamEventStorageInputSvc::generateDataHeader()
   // get file GUID
   m_fileGUID = m_reader->GUID();
   // reader returns -1 when end of the file is reached
-  if (m_eventOffset != -1) {
+  if (m_evtFileOffset != -1) {
     ATH_MSG_DEBUG("ByteStream File GUID:" << m_fileGUID);
-    ATH_MSG_DEBUG("ByteStream Event Position in File: " << m_eventOffset);
+    ATH_MSG_DEBUG("ByteStream Event Position in File: " << m_evtFileOffset);
     // Created data header element with BS provenance information
     Token* token = new Token();
     token->setDb(m_fileGUID);
     token->setTechnology(0x00001000);
-    token->setOid(Token::OID_t(0LL, m_eventOffset));
+    token->setOid(Token::OID_t(0LL, m_evtFileOffset));
     DataHeaderElement Dhe(ClassID_traits<DataHeader>::ID(), "StreamRAW", token);
     // Create data header itself
     DataHeader* Dh = new DataHeader();
@@ -533,14 +553,15 @@ StatusCode ByteStreamEventStorageInputSvc::generateDataHeader()
 }
 
 //__________________________________________________________________________
-void ByteStreamEventStorageInputSvc::releaseCurrentEvent()
+void ByteStreamEventStorageInputSvc::releaseEvent( EventCache* cache)
 {
    // cleanup parts of previous event and re-init them
-   if (m_re) {
+   if ( cache->rawEvent ) {
       OFFLINE_FRAGMENTS_NAMESPACE::PointerType fragment = 0;
-      m_re->start(fragment);
+      cache->rawEvent->start(fragment);
       delete [] fragment; fragment = 0;
-      delete m_re; m_re = 0;
+      delete cache->rawEvent; cache->rawEvent = 0;
+      cache->eventStatus = 0;
    }
 }
 
@@ -620,14 +641,14 @@ bool ByteStreamEventStorageInputSvc::readerReady()
    return (!eofFlag)&&moreEvent;
 }
 //__________________________________________________________________________
-bool ByteStreamEventStorageInputSvc::ROBFragmentCheck()
+bool ByteStreamEventStorageInputSvc::ROBFragmentCheck( const RawEvent* re ) const
 {
    bool allOK = true;
-   uint32_t total = m_re->nchildren(), lastId = 0;
+   uint32_t total = re->nchildren(), lastId = 0;
    std::vector<eformat::FragmentProblem> p;
    for (size_t i = 0; i<total; ++i) {
      OFFLINE_FRAGMENTS_NAMESPACE::PointerType fp;
-     m_re->child(fp, i);
+     re->child(fp, i);
      OFFLINE_FRAGMENTS_NAMESPACE::ROBFragment f(fp);
      lastId = f.source_id();
      p.clear();
@@ -643,15 +664,22 @@ bool ByteStreamEventStorageInputSvc::ROBFragmentCheck()
    return allOK;
 }
 //__________________________________________________________________________
-void ByteStreamEventStorageInputSvc::setEvent(void* data, unsigned int eventStatus)
+void ByteStreamEventStorageInputSvc::setEvent(void* data, unsigned int eventStatus) {
+  const EventContext context{ Gaudi::Hive::currentContext() };
+  return setEvent( context, data, eventStatus );
+}
+
+void ByteStreamEventStorageInputSvc::setEvent( const EventContext& context, void* data, unsigned int eventStatus )
 {
-   releaseCurrentEvent();
+  EventCache* cache = m_eventsCache.get( context );
+  releaseEvent( cache );
    OFFLINE_FRAGMENTS_NAMESPACE::DataType* fragment = reinterpret_cast<OFFLINE_FRAGMENTS_NAMESPACE::DataType*>(data);
-   m_re = new RawEvent(fragment);
-   m_eventStatus = eventStatus;
+   cache->rawEvent = new RawEvent(fragment);
+   cache->eventStatus = eventStatus;
    // Set it for the data provider
-   m_robProvider->setNextEvent(m_re);
-   m_robProvider->setEventStatus(m_eventStatus);
+   m_robProvider->setNextEvent(context, cache->rawEvent );
+   m_robProvider->setEventStatus(context, cache->eventStatus );
+
    // Build a DH for use by other components
    StatusCode rec_sg = generateDataHeader();
    if (rec_sg != StatusCode::SUCCESS) {
@@ -660,11 +688,13 @@ void ByteStreamEventStorageInputSvc::setEvent(void* data, unsigned int eventStat
 }
 //__________________________________________________________________________
 const RawEvent* ByteStreamEventStorageInputSvc::currentEvent() const {
-   return(m_re);
+  const EventContext context{ Gaudi::Hive::currentContext() };
+  return m_eventsCache.get(context)->rawEvent;
 }
 //__________________________________________________________________________
 unsigned int ByteStreamEventStorageInputSvc::currentEventStatus() const {
-   return(m_eventStatus);
+  const EventContext context{ Gaudi::Hive::currentContext() };
+  return m_eventsCache.get(context)->eventStatus;
 }
 //________________________________________________________________________________
 StatusCode ByteStreamEventStorageInputSvc::queryInterface(const InterfaceID& riid, void** ppvInterface) {
@@ -677,3 +707,8 @@ StatusCode ByteStreamEventStorageInputSvc::queryInterface(const InterfaceID& rii
    addRef();
    return(StatusCode::SUCCESS);
 }
+
+ByteStreamEventStorageInputSvc::EventCache::~EventCache() {
+  delete rawEvent;
+  rawEvent = 0;
+}
diff --git a/Event/ByteStreamCnvSvc/src/ByteStreamEventStorageInputSvc.h b/Event/ByteStreamCnvSvc/src/ByteStreamEventStorageInputSvc.h
index 13ae68c7100880c16c579ceede0adc352b257e9e..b54252a8cf22d889ac1ca5aab9233281de41fec6 100644
--- a/Event/ByteStreamCnvSvc/src/ByteStreamEventStorageInputSvc.h
+++ b/Event/ByteStreamCnvSvc/src/ByteStreamEventStorageInputSvc.h
@@ -15,7 +15,7 @@
 #include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h"
 #include "ByteStreamCnvSvc/IByteStreamFreeMetadataSvc.h"
 #include "ByteStreamData/RawEvent.h"
-
+#include "AthenaKernel/SlotSpecificObj.h"
 #include "EventStorage/DataReader.h"
 
 // FrameWork includes
@@ -53,7 +53,8 @@ public:
 
    /// Return the current event status
    virtual unsigned int currentEventStatus() const;
-   virtual void validateEvent();
+   virtual void validateEvent(); 
+
 
    virtual long positionInBlock();
    virtual long getBlockIterator(const std::string fileName);
@@ -66,19 +67,28 @@ private: // internal member functions
    bool loadMetadata();
 
 private: // data
+   std::mutex m_readerMutex;
+
+   struct EventCache {
+     ~EventCache();
+     RawEvent*          rawEvent = 0;            //!< current event
+     unsigned int       eventStatus = 0;   //!< check_tree() status of the current event
+     long long int      eventOffset = 0;   //!< event offset within a file, can be -1          
+   };
+
+   SG::SlotSpecificObj<EventCache> m_eventsCache;
+
    //int                m_totalEventCounter; //!< event Counter
-   RawEvent*          m_re;            //!< current event
-   unsigned int       m_eventStatus;   //!< check_tree() status of the current event
    DataReader*        m_reader;        //!< DataReader from EventStorage
 
    mutable std::vector<int>     m_numEvt;    //!< number of events in that file
    mutable std::vector<int>     m_firstEvt;  //!< event number of first event in that file
    mutable std::vector<long long int> m_evtOffsets;  //!< offset for event i in that file
    unsigned int                 m_evtInFile;
-
+   long long int      m_evtFileOffset = 0;   //!< last read in event offset within a file, can be -1     
    // Event back navigation info
    std::string        m_fileGUID;      //!< current file GUID
-   long long int      m_eventOffset;   //!< event offset within a file, can be -1
+
 
    /// Pointer to StoreGate
    ServiceHandle<StoreGateSvc> m_sgSvc; //!< StoreGateSvc
@@ -105,10 +115,15 @@ private: // properties
 
 private: // internal helper functions
 
-   void buildFragment(void* data, uint32_t eventSize, bool validate);
-   void releaseCurrentEvent();
+   void buildFragment( EventCache* cache, void* data, uint32_t eventSize, bool validate ) const;
+   void releaseEvent( EventCache* );
    bool readerReady();
-   bool ROBFragmentCheck();
+   bool ROBFragmentCheck( const RawEvent* ) const;
+   unsigned validateEvent( const RawEvent* rawEvent ) const;
+   void setEvent( const EventContext& context, void* data, unsigned int eventStatus );
+   
+   enum Advance{ PREVIOUS = -1, NEXT = 1 };
+   const RawEvent* getEvent( Advance step );
 };
 
 #endif
diff --git a/Event/ByteStreamCnvSvcBase/ByteStreamCnvSvcBase/IROBDataProviderSvc.h b/Event/ByteStreamCnvSvcBase/ByteStreamCnvSvcBase/IROBDataProviderSvc.h
index a2b935254baaa95619a9cb1caebaaa5a31b43200..a5c5a0d3abff0a32e8240597d56c1acde4eb1f95 100755
--- a/Event/ByteStreamCnvSvcBase/ByteStreamCnvSvcBase/IROBDataProviderSvc.h
+++ b/Event/ByteStreamCnvSvcBase/ByteStreamCnvSvcBase/IROBDataProviderSvc.h
@@ -7,13 +7,15 @@
 
 #include "GaudiKernel/IInterface.h"
 #include "ByteStreamData/RawEvent.h"
+#include "GaudiKernel/EventContext.h"
 
 #include <cstdint>
 #include <vector>
 #include <string>
+#include <stdexcept>
 
 // Declaration of the interface ID ( interface id, major version, minor version)
-static const InterfaceID IID_IROBDataProviderSvc("IROBDataProviderSvc", 1 , 0);
+//static const InterfaceID IID_IROBDataProviderSvc("IROBDataProviderSvc", 1 , 0);
 
 /** @class IROBDataProviderSvc
     @brief Interface class for managing ROB for both online and offline.
@@ -24,7 +26,8 @@ public:
    typedef std::vector<const OFFLINE_FRAGMENTS_NAMESPACE::ROBFragment*> VROBFRAG;
 
    /// Retrieve interface ID
-   static const InterfaceID& interfaceID() { return IID_IROBDataProviderSvc; }
+  //   static const InterfaceID& interfaceID() { return IID_IROBDataProviderSvc; }
+  DeclareInterfaceID(IROBDataProviderSvc, 1, 1);
 
    /// Add ROBFragments to cache for given ROB ids, ROB fragments may be retrieved with DataCollector
    virtual void addROBData(const std::vector<uint32_t>& robIds, const std::string callerName="UNKNOWN") = 0 ;
@@ -32,20 +35,50 @@ public:
    /// Add a given LVL1/LVL2 ROBFragment to cache
    virtual void setNextEvent(const std::vector<OFFLINE_FRAGMENTS_NAMESPACE::ROBFragment>& result) = 0 ;
 
+
    /// Add all ROBFragments of a RawEvent to cache
    virtual void setNextEvent(const RawEvent* re) = 0 ;
 
+
    /// Retrieve ROBFragments for given ROB ids from cache
    virtual void getROBData(const std::vector<uint32_t>& robIds, VROBFRAG& robFragments, const std::string callerName="UNKNOWN") = 0;
 
+
    /// Retrieve the whole event.
    virtual const RawEvent* getEvent() = 0;
 
+
    /// Store the status for the event.
    virtual void setEventStatus(uint32_t status) = 0;
 
+
    /// Retrieve the status for the event.
    virtual uint32_t getEventStatus() = 0;
+
+
+   // variants for MT, it has an implementation for now in order not to require change in all implementations yet, they will all become pure virtual methods
+   virtual void addROBData(const EventContext& /*context*/, const std::vector<uint32_t>& /*robIds*/, const std::string callerName="UNKNOWN") { 
+     throw std::runtime_error( std::string( "Unimplemented ") + __FUNCTION__ + callerName) ; 
+   }
+   virtual void setNextEvent(const EventContext& /*context*/, const std::vector<OFFLINE_FRAGMENTS_NAMESPACE::ROBFragment>& /*result*/) {
+     throw std::runtime_error( std::string("Unimplemented ") + __FUNCTION__ ); 
+   }
+   virtual void setNextEvent( const EventContext& /*context*/, const RawEvent* /*re*/) {
+     throw std::runtime_error(std::string("Unimplemented ") + __FUNCTION__ ); 
+   }
+   virtual void getROBData(const EventContext& /*context*/, const std::vector<uint32_t>& /*robIds*/, VROBFRAG& /*robFragments*/, const std::string callerName="UNKNOWN") { 
+     throw std::runtime_error( std::string( "Unimplemented ") + __FUNCTION__ + callerName) ; 
+   }
+   virtual const RawEvent* getEvent(const EventContext& /*context*/) {
+     throw std::runtime_error(std::string("Unimplemented ") + __FUNCTION__ ); 
+   }
+   virtual void setEventStatus(const EventContext& /*context*/, uint32_t /*status*/) {
+     throw std::runtime_error(std::string("Unimplemented ") + __FUNCTION__ ); 
+   }
+   virtual uint32_t getEventStatus(const EventContext& /*context*/) {
+     throw std::runtime_error(std::string("Unimplemented ") + __FUNCTION__ ); 
+     return 0;
+   }
 };
 
 #endif
diff --git a/Event/ByteStreamCnvSvcBase/ByteStreamCnvSvcBase/ROBDataProviderSvc.h b/Event/ByteStreamCnvSvcBase/ByteStreamCnvSvcBase/ROBDataProviderSvc.h
index 96a2e499178d295849434a6799e9d450257a8bba..d0c003e21c79902e061510bbecc7cdddf0bee3b9 100755
--- a/Event/ByteStreamCnvSvcBase/ByteStreamCnvSvcBase/ROBDataProviderSvc.h
+++ b/Event/ByteStreamCnvSvcBase/ByteStreamCnvSvcBase/ROBDataProviderSvc.h
@@ -29,11 +29,11 @@
 #include "ByteStreamData/RawEvent.h"
 #include "eformat/SourceIdentifier.h"
 #include "AthenaBaseComps/AthService.h"
-
+#include "AthenaKernel/SlotSpecificObj.h"
 #include <vector>
 #include <map>
 
-class ROBDataProviderSvc :  public ::AthService, virtual public IROBDataProviderSvc {
+class ROBDataProviderSvc :  public extends<AthService, IROBDataProviderSvc> {
 
 public:
    /// ROB Fragment class
@@ -48,28 +48,38 @@ public:
    virtual StatusCode initialize();
 
    /// Gaudi queryInterface method.
-   virtual StatusCode queryInterface(const InterfaceID& riid, void** ppvInterface);
+   //   virtual StatusCode queryInterface(const InterfaceID& riid, void** ppvInterface);
 
    /// Add ROBFragments to cache for given ROB ids, ROB fragments may be retrieved with DataCollector
-   virtual void addROBData(const std::vector<uint32_t>& robIds, const std::string callerName="UNKNOWN");
+   virtual void addROBData(const std::vector<uint32_t>& robIds, const std::string callerName="UNKNOWN") override;
 
    /// Add a given LVL1/LVL2 ROBFragment to cache
-   virtual void setNextEvent(const std::vector<ROBF>& result);
+   virtual void setNextEvent(const std::vector<ROBF>& result) override;
 
    /// Add all ROBFragments of a RawEvent to cache
-   virtual void setNextEvent(const RawEvent* re);
+   virtual void setNextEvent(const RawEvent* re) override;
 
    /// Retrieve ROBFragments for given ROB ids from cache
-   virtual void getROBData(const std::vector<uint32_t>& robIds, std::vector<const ROBF*>& robFragments, const std::string callerName="UNKNOWN");
+   virtual void getROBData(const std::vector<uint32_t>& robIds, std::vector<const ROBF*>& robFragments, const std::string callerName="UNKNOWN") override;
 
    /// Retrieve the whole event.
-   virtual const RawEvent* getEvent();
+   virtual const RawEvent* getEvent() override;
 
    /// Store the status for the event.
-   virtual void setEventStatus(uint32_t status);
+   virtual void setEventStatus(uint32_t status) override;
 
    /// Retrieve the status for the event.
-   virtual uint32_t getEventStatus();
+   virtual uint32_t getEventStatus() override;
+
+
+   /// MT variants 
+   virtual void addROBData(const EventContext& context, const std::vector<uint32_t>& robIds, const std::string callerName="UNKNOWN") override;
+   virtual void setNextEvent(const EventContext& context, const std::vector<OFFLINE_FRAGMENTS_NAMESPACE::ROBFragment>& result) override;
+   virtual void setNextEvent(const EventContext& context, const RawEvent* re) override;
+   virtual void getROBData(const EventContext& context, const std::vector<uint32_t>& robIds, VROBFRAG& robFragments, const std::string callerName="UNKNOWN") override;
+   virtual const RawEvent* getEvent(const EventContext& context) override;
+   virtual void setEventStatus(const EventContext& context, uint32_t status) override;
+   virtual uint32_t getEventStatus(const EventContext& context) override;
 
 protected:
    /// vector of ROBFragment class
@@ -77,11 +87,18 @@ protected:
 
    /// map for all the ROB fragments
    typedef std::map<uint32_t, const ROBF*, std::less<uint32_t> > ROBMAP;
-   ROBMAP m_robmap;
-
-   /// lvl1 ID of cached data
-   uint32_t m_currentLvl1ID;
 
+  struct EventCache {
+    ~EventCache();
+    const RawEvent* event = 0;
+    uint32_t eventStatus = 0;    
+    uint32_t currentLvl1ID = 0;    
+    ROBMAP robmap;
+ 
+  };
+  SG::SlotSpecificObj<EventCache> m_eventsCache;
+
+   /// Remaining attributes are for configuration
    /// vector of Source ids and status words to be ignored for the ROB map
    typedef SimpleProperty< std::vector< std::pair<int, int> > > ArrayPairIntProperty;
    ArrayPairIntProperty  m_filterRobWithStatus; // filter with full ROB SourceID
@@ -98,17 +115,14 @@ protected:
 
    /// Filter out empty ROB fragments which are send by the ROS
    BooleanProperty m_filterEmptyROB;
+   bool m_maskL2EFModuleID = false;    
 
-   /// flag which tells if module IDs from the L2 and EF result should be masked off
-   bool m_maskL2EFModuleID;
 
-private: // data
-   const RawEvent* m_event;
 
-   uint32_t m_eventStatus;
+private: // data
 
 private: //
-   void robmapClear();
+  static void robmapClear(ROBMAP& toclear);
 };
 
 #endif
diff --git a/Event/ByteStreamCnvSvcBase/CMakeLists.txt b/Event/ByteStreamCnvSvcBase/CMakeLists.txt
index ff0d9e489600df383c71ec591db902ade9bd8af4..4455602fc12776dd5257238d89e672ec76a6b55c 100644
--- a/Event/ByteStreamCnvSvcBase/CMakeLists.txt
+++ b/Event/ByteStreamCnvSvcBase/CMakeLists.txt
@@ -14,7 +14,8 @@ atlas_depends_on_subdirs( PUBLIC
                           Event/ByteStreamData
                           GaudiKernel
                           PRIVATE
-                          Control/SGTools )
+                          Control/SGTools
+			  AtlasTest/TestTools )
 
 # External dependencies:
 find_package( tdaq-common COMPONENTS eformat eformat_write )
@@ -32,6 +33,12 @@ atlas_add_component( ByteStreamCnvSvcBase
                      INCLUDE_DIRS ${TDAQ-COMMON_INCLUDE_DIRS}
                      LINK_LIBRARIES ${TDAQ-COMMON_LIBRARIES} AthenaBaseComps AthenaKernel StoreGateLib SGtests ByteStreamData ByteStreamData_test GaudiKernel SGTools ByteStreamCnvSvcBaseLib )
 
+# - commented out for the meoment, seem like CI is not adding just compiled packages to the pythonpath
+#atlas_add_test( ROBDataProviderSvcMT		 
+#		SCRIPT test/test_ROBDataProviderSvcMT.sh		
+#		TIMEOUT 1200 )
+#
+
 # Install files from the package:
 atlas_install_joboptions( share/*.py )
 
diff --git a/Event/ByteStreamCnvSvcBase/share/testROBDataProviderSvcMT.py b/Event/ByteStreamCnvSvcBase/share/testROBDataProviderSvcMT.py
new file mode 100644
index 0000000000000000000000000000000000000000..db960851af8b12f166dc96170b6690c5303669d4
--- /dev/null
+++ b/Event/ByteStreamCnvSvcBase/share/testROBDataProviderSvcMT.py
@@ -0,0 +1,41 @@
+#**************************************************************
+#
+# jopOptions file for reading ByteStream 
+#
+#==============================================================
+# Input 
+include( "ByteStreamCnvSvc/BSEventStorageEventSelector_jobOptions.py" )
+svcMgr.ByteStreamInputSvc.FullFileName = [ "/cvmfs/atlas-nightlies.cern.ch/repo/data/data-art/TrigP1Test/data17_13TeV.00327265.physics_EnhancedBias.merge.RAW._lb0100._SFO-1._0001.1" ]
+#svcMgr.ByteStreamInputSvc.FullFileName = [ "/afs/cern.ch/atlas/offline/test/daq.m4_combined.0020720.extract.L1TT-b00000010._0001.data" ]
+#svcMgr.ByteStreamInputSvc.FullFileName += [ "/afs/cern.ch/atlas/offline/test/daq.m4_combined.0020720.extract.L1TT-b00000010._0001.data" ]
+#svcMgr.EventSelector.InputCollections = [ "/afs/cern.ch/atlas/offline/test/daq.m4_combined.0020720.extract.L1TT-b00000010._0001.data" ]
+#svcMgr.ByteStreamInputSvc.MaxBadEvents = 1
+#svcMgr.ByteStreamInputSvc.ValidateEvent = False
+
+#from AthenaCommon.AppMgr import theApp
+theApp.EvtMax = -1
+
+from AthenaCommon.AlgSequence import AthSequencer
+topSequence = AthSequencer("AthAlgSeq")
+#from xAODEventInfoCnv.xAODEventInfoCnvConf import xAODReader__EventInfoReaderAlg
+#alg = xAODReader__EventInfoReaderAlg()
+#alg.SGKey = "ByteStreamxAODEventInfo"
+#alg.OutputLevel = 2
+#topSequence += alg
+
+
+#include("AthenaPoolTools/EventCount_jobOptions.py")
+
+MessageSvc.OutputLevel = INFO
+svcMgr.EventSelector.OutputLevel = DEBUG
+svcMgr.ByteStreamInputSvc.OutputLevel = DEBUG
+svcMgr.ByteStreamCnvSvc.OutputLevel = DEBUG
+svcMgr.ByteStreamAddressProviderSvc.OutputLevel = DEBUG
+
+from ByteStreamCnvSvcBase.ByteStreamCnvSvcBaseConf import ROBDataProviderMTTest
+testAlg = ROBDataProviderMTTest()
+testAlg.OutputLevel = DEBUG
+
+from AthenaCommon.AppMgr import topSequence
+
+topSequence += testAlg
diff --git a/Event/ByteStreamCnvSvcBase/src/ROBDataProviderMTTest.cxx b/Event/ByteStreamCnvSvcBase/src/ROBDataProviderMTTest.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..5797f9b7fb5eafe5737d6e498d3ef31cd9c77419
--- /dev/null
+++ b/Event/ByteStreamCnvSvcBase/src/ROBDataProviderMTTest.cxx
@@ -0,0 +1,67 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+#include <algorithm>
+#include "GaudiKernel/Property.h"
+#include "TestTools/ParallelCallTest.h"
+#include "ROBDataProviderMTTest.h"
+
+
+
+ROBDataProviderMTTest::ROBDataProviderMTTest( const std::string& name, 
+			  ISvcLocator* pSvcLocator ) : 
+  ::AthReentrantAlgorithm( name, pSvcLocator ) {
+}
+
+ROBDataProviderMTTest::~ROBDataProviderMTTest() {}
+
+StatusCode ROBDataProviderMTTest::initialize() {
+  CHECK( m_robDataProvider.retrieve() );
+
+  return StatusCode::SUCCESS;
+}
+
+StatusCode ROBDataProviderMTTest::finalize() {
+  return StatusCode::SUCCESS;
+}
+
+StatusCode ROBDataProviderMTTest::execute_r( const EventContext& context ) const
+{  
+  // will be asking for many ROBs from the list and check if all of them come from the same physical event
+  const RawEvent* ev = m_robDataProvider->getEvent( context );
+  ATH_MSG_DEBUG( "Obtained event, global id: " << ev->global_id() << " lvl1 id: " << ev->lvl1_id() );
+  uint32_t lvl1ID = ev->lvl1_id();
+  std::vector<uint32_t> robIDs;
+  
+  {
+    //    std::vector<ROBFragment> robs
+    std::vector<eformat::read::ROBFragment> robs;
+    ev->robs( robs );
+    for ( auto& rob: robs ) {
+      robIDs.push_back( rob.rob_source_id() );
+    }
+  }
+
+  std::random_shuffle( robIDs.begin(), robIDs.end() );
+
+  // we try now the other method, getROBData, in 8 steps
+  std::vector<std::vector<uint32_t>> requests(8);
+  
+  for ( size_t index = 0; index < robIDs.size(); ++index ) {
+    requests[index % requests.size() ].push_back( robIDs[index] );
+  }
+  for ( auto & reqPart: requests ) {
+    //    ATH_MSG_DEBUG( "Performing getROBData request for this robs: " << reqPart);
+    IROBDataProviderSvc::VROBFRAG robs;
+    m_robDataProvider->getROBData( context, reqPart, robs ); 
+    for ( auto& rob: robs ) {
+      if ( rob->rod_lvl1_id() != lvl1ID ) 
+	ATH_MSG_ERROR( "ROB of ID "<< rob->rob_source_id()  << "  Lvl1 ID missmatch, in ROB " 
+		       <<  rob->rod_lvl1_id() << " in Event header " << lvl1ID );      
+    }
+  }
+  
+  return StatusCode::SUCCESS;
+}
+
+
diff --git a/Event/ByteStreamCnvSvcBase/src/ROBDataProviderMTTest.h b/Event/ByteStreamCnvSvcBase/src/ROBDataProviderMTTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..12468b2d71dd1c04423f6261608c32fb9008d202
--- /dev/null
+++ b/Event/ByteStreamCnvSvcBase/src/ROBDataProviderMTTest.h
@@ -0,0 +1,41 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+#ifndef BYTESTREAMCNVSVCBASE_ROBDATAPROVIDERMTTEST_H
+#define BYTESTREAMCNVSVCBASE_ROBDATAPROVIDERMTTEST_H 1
+
+#include <string>
+
+#include "AthenaBaseComps/AthReentrantAlgorithm.h"
+#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h"
+
+
+/**
+ * @class $(klass)s
+ * @brief 
+ **/
+
+class ROBDataProviderMTTest
+  : public ::AthReentrantAlgorithm
+{ 
+ public: 
+
+  ROBDataProviderMTTest( const std::string& name, ISvcLocator* pSvcLocator );
+
+  virtual ~ROBDataProviderMTTest(); 
+
+
+  //ROBDataProviderMTTest &operator=(const ROBDataProviderMTTest &alg); 
+
+  StatusCode  initialize() override;
+  StatusCode  execute_r(const EventContext& context) const override;
+  StatusCode  finalize() override;
+ 
+ private: 
+  ROBDataProviderMTTest();
+  ServiceHandle<IROBDataProviderSvc> m_robDataProvider{ this, "ROBDataProvider", "ROBDataProviderSvc/ROBDataProviderSvc", ""};
+  
+}; 
+
+
+#endif //> !BYTESTREAMCNVSVCBASE_ROBDATAPROVIDERMTTEST_H
diff --git a/Event/ByteStreamCnvSvcBase/src/ROBDataProviderSvc.cxx b/Event/ByteStreamCnvSvcBase/src/ROBDataProviderSvc.cxx
index 37cbddd63f864030bd14ed5ff90db53b285da0c1..1b2cce4381550b65db9a47ffcaaa31633d940d3c 100755
--- a/Event/ByteStreamCnvSvcBase/src/ROBDataProviderSvc.cxx
+++ b/Event/ByteStreamCnvSvcBase/src/ROBDataProviderSvc.cxx
@@ -4,6 +4,8 @@
 
 //===================================================================
 //  Implementation of ROBDataProviderSvc
+//  Revision: November 2017
+//      MT readiness
 //  Revision:  July 11, 2002
 //      Modified for eformat
 //  Revision:  Aug 18, 2003
@@ -82,16 +84,17 @@
 #include "eformat/Status.h"
 
 // Constructor.
-ROBDataProviderSvc::ROBDataProviderSvc(const std::string& name, ISvcLocator* svcloc) :
-  ::AthService(name,svcloc), m_robmap(), m_currentLvl1ID(0), m_maskL2EFModuleID(false), m_event(0), m_eventStatus(0) {
-   declareProperty("filterRobWithStatus", m_filterRobWithStatus);
-   declareProperty("filterSubDetWithStatus", m_filterSubDetWithStatus);
-   declareProperty("filterEmptyROB", m_filterEmptyROB = false);
+ROBDataProviderSvc::ROBDataProviderSvc(const std::string& name, ISvcLocator* svcloc) 
+  : base_class(name, svcloc) {
+
+  declareProperty("filterRobWithStatus", m_filterRobWithStatus);
+  declareProperty("filterSubDetWithStatus", m_filterSubDetWithStatus);
+  declareProperty("filterEmptyROB", m_filterEmptyROB = false);
 }
 
 // Destructor.
 ROBDataProviderSvc::~ROBDataProviderSvc() {
-   robmapClear();
+  // the eventsCache take care of cleaaning itself
 }
 
 // Initialization
@@ -101,7 +104,8 @@ StatusCode ROBDataProviderSvc::initialize() {
       ATH_MSG_FATAL("Cannot initialize AthService base class.");
       return(StatusCode::FAILURE);
    }
-
+   m_eventsCache = SG::SlotSpecificObj<EventCache>( SG::getNSlots() );
+   
    for (unsigned int i = 0; i < m_filterRobWithStatus.value().size(); i++) {
       eformat::helper::SourceIdentifier tmpsrc(m_filterRobWithStatus.value()[i].first);
       if (tmpsrc.human_detector() != "UNKNOWN") {
@@ -146,23 +150,34 @@ StatusCode ROBDataProviderSvc::initialize() {
    }
    return(StatusCode::SUCCESS);
 }
-/// Query interface
-StatusCode ROBDataProviderSvc::queryInterface(const InterfaceID& riid, void** ppvInterface) {
-   if (IROBDataProviderSvc::interfaceID().versionMatch(riid)) {
-      *ppvInterface = dynamic_cast<IROBDataProviderSvc*>(this);
-   } else {
-      // Interface is not directly available: try out a base class
-      return(::AthService::queryInterface(riid, ppvInterface));
-   }
-   addRef();
-   return(StatusCode::SUCCESS);
-}
+
+// /// Query interface
+// StatusCode ROBDataProviderSvc::queryInterface(const InterfaceID& riid, void** ppvInterface) {
+//    if (IROBDataProviderSvc::interfaceID().versionMatch(riid)) {
+//       *ppvInterface = dynamic_cast<IROBDataProviderSvc*>(this);
+//    } else {
+//       // Interface is not directly available: try out a base class
+//       return(::AthService::queryInterface(riid, ppvInterface));
+//    }
+//    addRef();
+//    return(StatusCode::SUCCESS);
+// }
 
 /**
     - in offline only check that given ROB ids are in the map, issue an
       error if not
 */
+  
+
+
 void ROBDataProviderSvc::addROBData(const std::vector<uint32_t>& robIds, const std::string callerName) {
+  const EventContext context{ Gaudi::Hive::currentContext() };
+  return addROBData( context, robIds, callerName );
+}
+
+void ROBDataProviderSvc::addROBData(const EventContext& context, const std::vector<uint32_t>& robIds, const std::string callerName) {
+    EventCache* cache = m_eventsCache.get( context );
+
    // Copy missing ROB ids to vector with pthread allocator
    ATH_MSG_DEBUG(" ---> Number of ROB Id s requested : " << robIds.size() << ", Caller Name = " << callerName);
    // for offline running all requested ROBs should be found in cache
@@ -173,23 +188,25 @@ void ROBDataProviderSvc::addROBData(const std::vector<uint32_t>& robIds, const s
       if ( (eformat::helper::SourceIdentifier(id).module_id() != 0) &&
 	   (eformat::helper::SourceIdentifier(id).subdetector_id() == eformat::TDAQ_LVL2) ) {
 	 id = eformat::helper::SourceIdentifier(eformat::helper::SourceIdentifier(id).subdetector_id(),0).code();
-	 if (!m_maskL2EFModuleID) {
+	 // TB if it is inconsistent we should not continue like this?
+	 if ( !m_maskL2EFModuleID ) {
 	   ATH_MSG_ERROR("Inconsistent flag for masking L2/EF module IDs");
 	   m_maskL2EFModuleID=true;
 	 }
       } else if ( (eformat::helper::SourceIdentifier(id).module_id() != 0) && 
 		  (eformat::helper::SourceIdentifier(id).subdetector_id() == eformat::TDAQ_EVENT_FILTER) &&
-		  (m_maskL2EFModuleID) ) {
+		  ( m_maskL2EFModuleID ) ) {
 	 id = eformat::helper::SourceIdentifier(eformat::helper::SourceIdentifier(id).subdetector_id(),0).code();
       }
-      ROBMAP::iterator map_it = m_robmap.find(id) ;
-      if (map_it != m_robmap.end()) {
+      ROBMAP& robmap( cache->robmap );
+      ROBMAP::iterator map_it = robmap.find(id) ;
+      if (map_it != robmap.end()) {
          ATH_MSG_DEBUG(" ---> Found   ROB Id : 0x" << MSG::hex << (*map_it).second->source_id()
 	         << MSG::dec << " in cache");
       } else {
          ATH_MSG_DEBUG(" ---> ROB Id : 0x" << MSG::hex << id
 	         << MSG::dec << " not found in cache for running mode OFFLINE (method addROBData),");
-	 ATH_MSG_DEBUG("      Lvl1 id  = " << m_currentLvl1ID);
+	 ATH_MSG_DEBUG("      Lvl1 id  = " << cache->currentLvl1ID);
     }
   }
   return;
@@ -199,8 +216,13 @@ void ROBDataProviderSvc::addROBData(const std::vector<uint32_t>& robIds, const s
     - this version is for offline use only
 */
 void ROBDataProviderSvc::setNextEvent(const std::vector<ROBF>& result) {
-   // clear the old map
-   robmapClear();
+  const EventContext context{ Gaudi::Hive::currentContext() };
+  return setNextEvent( context, result );
+}
+void ROBDataProviderSvc::setNextEvent(const EventContext& /*context*/, const std::vector<ROBF>& result) { 
+  // clear the old map
+  // TB honestly, why do any action if this is FATAL mistake
+  //  robmapClear( m_eventsCache.get(context)->robmap );
 
    // This method should never be used by offline
    ATH_MSG_FATAL(" +-----------------------------------------------------------------+ ");
@@ -212,15 +234,26 @@ void ROBDataProviderSvc::setNextEvent(const std::vector<ROBF>& result) {
    return;
 }
 
+
+
+
 /** - add a new Raw event
     - rebuild the map
 */
 void ROBDataProviderSvc::setNextEvent(const RawEvent* re) {
-   m_event = re;
+  // obtain context and redirect to the real implementation
+  const EventContext context{ Gaudi::Hive::currentContext() };
+  return setNextEvent( context, re );
+}
+
+void ROBDataProviderSvc::setNextEvent( const EventContext& context, const RawEvent* re ) {
+  EventCache* cache = m_eventsCache.get( context );
+  
+   cache->event = re;
    // clear the old map
-   robmapClear();
+   robmapClear( cache->robmap );
    // set the LVL1 id
-   m_currentLvl1ID = re->lvl1_id();
+   cache->currentLvl1ID = re->lvl1_id();
    // set flag for masking L2/EF module ID, this is only necessary for the separate L2 and EF systems from Run 1 
    m_maskL2EFModuleID = (re->nlvl2_trigger_info() != 0);
 
@@ -253,7 +286,7 @@ void ROBDataProviderSvc::setNextEvent(const RawEvent* re) {
       }
       if ((rob->rod_ndata() == 0) && (m_filterEmptyROB)) {
          ATH_MSG_DEBUG( " ---> Empty ROB Id = 0x" << MSG::hex << id << MSG::dec
-	         << " removed for L1 Id = " << m_currentLvl1ID);
+	         << " removed for L1 Id = " << cache->currentLvl1ID);
           delete rob;
       } else if (filterRobWithStatus(rob)) {
          if (rob->nstatus() > 0) {
@@ -263,29 +296,36 @@ void ROBDataProviderSvc::setNextEvent(const RawEvent* re) {
             ATH_MSG_DEBUG(" ---> ROB Id = 0x" << MSG::hex << id << std::setfill('0')
 	            << " with Generic Status Code = 0x" << std::setw(4) << tmpstatus.generic()
 	            << " and Specific Status Code = 0x" << std::setw(4) << tmpstatus.specific() << MSG::dec
-	            << " removed for L1 Id = " << m_currentLvl1ID);
+	            << " removed for L1 Id = " << cache->currentLvl1ID);
          }
          delete rob;
       } else {
-         ROBMAP::const_iterator it = m_robmap.find(id);
-         if (it != m_robmap.end()) {
+         ROBMAP::const_iterator it = cache->robmap.find(id);
+         if (it != cache->robmap.end()) {
             ATH_MSG_WARNING(" ROBDataProviderSvc:: Duplicate ROBID 0x" << MSG::hex << id
 	            << " found. " << MSG::dec << " Overwriting the previous one ");
-            delete m_robmap[id];
-            m_robmap[id] = rob;
+            delete cache->robmap[id];
+            cache->robmap[id] = rob;
          } else {
-            m_robmap[id] = rob;
+            cache->robmap[id] = rob;
          }
       }
    }
-   ATH_MSG_DEBUG(" ---> setNextEvent offline for " << name());
-   ATH_MSG_DEBUG("      current LVL1 id   = " << m_currentLvl1ID);
-   ATH_MSG_DEBUG("      size of ROB cache = " << m_robmap.size());
+   ATH_MSG_DEBUG(" ---> setNextEvent offline for " << name() );
+   ATH_MSG_DEBUG("      current LVL1 id   = " << cache->currentLvl1ID );
+   ATH_MSG_DEBUG("      size of ROB cache = " << cache->robmap.size() );
    return;
 }
 /** return ROBData for ROBID
  */
 void ROBDataProviderSvc::getROBData(const std::vector<uint32_t>& ids, std::vector<const ROBF*>& v, const std::string callerName) {
+  const EventContext context{ Gaudi::Hive::currentContext() };
+  return getROBData( context, ids, v, callerName );
+}
+
+void ROBDataProviderSvc::getROBData(const EventContext& context, const std::vector<uint32_t>& ids, std::vector<const ROBF*>& v, const std::string callerName) {
+  EventCache* cache = m_eventsCache.get( context );
+  
    for (std::vector<uint32_t>::const_iterator it = ids.begin(), it_end = ids.end(); it != it_end; it++) {
       uint32_t id = (*it);
       // mask off the module ID for L2 and EF result for Run 1 data
@@ -301,15 +341,15 @@ void ROBDataProviderSvc::getROBData(const std::vector<uint32_t>& ids, std::vecto
 		  (m_maskL2EFModuleID) ) {
 	 id = eformat::helper::SourceIdentifier(eformat::helper::SourceIdentifier(id).subdetector_id(),0).code();
       }
-      ROBMAP::iterator map_it = m_robmap.find(id);
-      if (map_it != m_robmap.end()) {
+      ROBMAP::iterator map_it = cache->robmap.find(id);
+      if (map_it != cache->robmap.end()) {
          v.push_back((*map_it).second);
       } else {
 	ATH_MSG_DEBUG("Failed to find ROB for id 0x" << MSG::hex << id << MSG::dec << ", Caller Name = " << callerName);
 #ifndef NDEBUG
          int nrob = 0;
-         ATH_MSG_VERBOSE(" --- Dump of ROB cache ids --- total size = " << m_robmap.size());
-         for (ROBMAP::iterator cache_it = m_robmap.begin(), cache_end = m_robmap.end();
+         ATH_MSG_VERBOSE(" --- Dump of ROB cache ids --- total size = " << cache->robmap.size());
+         for (ROBMAP::iterator cache_it = cache->robmap.begin(), cache_end = cache->robmap.end();
 	         cache_it != cache_end; cache_it++) {
 	    ++nrob;
 	    ATH_MSG_VERBOSE(" # = " << nrob << "  id = 0x" << MSG::hex << (*cache_it).second->source_id() << MSG::dec);
@@ -321,23 +361,40 @@ void ROBDataProviderSvc::getROBData(const std::vector<uint32_t>& ids, std::vecto
 }
 /** - clear ROB map
  */
-void ROBDataProviderSvc::robmapClear() {
-  for (ROBMAP::const_iterator it = m_robmap.begin(), itE = m_robmap.end(); it != itE; ++it) {
+void ROBDataProviderSvc::robmapClear( ROBMAP& toclear) {
+  for (ROBMAP::const_iterator it = toclear.begin(), itE = toclear.end(); it != itE; ++it) {
      delete it->second;
   }
-  m_robmap.clear();
+  toclear.clear();
 }
 /// Retrieve the whole event.
 const RawEvent* ROBDataProviderSvc::getEvent() {
-   return(m_event);
+  const EventContext context{ Gaudi::Hive::currentContext() };
+  return getEvent( context );
 }
+const RawEvent* ROBDataProviderSvc::getEvent( const EventContext& context ) {
+  
+  return m_eventsCache.get( context )->event;
+}
+
+
 /// Set the status for the event.
 void ROBDataProviderSvc::setEventStatus(uint32_t status) {
-   m_eventStatus = status;
+  const EventContext context{ Gaudi::Hive::currentContext() };
+  setEventStatus( context, status );
+}
+
+void ROBDataProviderSvc::setEventStatus(const EventContext& context, uint32_t status) {
+  m_eventsCache.get(context)->eventStatus = status;
 }
 /// Retrieve the status for the event.
 uint32_t ROBDataProviderSvc::getEventStatus() {
-   return(m_eventStatus);
+  const EventContext context{ Gaudi::Hive::currentContext() };
+  return getEventStatus( context );
+}
+
+uint32_t ROBDataProviderSvc::getEventStatus( const EventContext& context ) {
+  return m_eventsCache.get( context )->eventStatus;
 }
 /** - filter ROB with Sub Detector Id and Status Code
 */
@@ -379,3 +436,9 @@ bool ROBDataProviderSvc::filterRobWithStatus(const ROBF* rob) {
    }
    return(false);
 }
+
+
+ROBDataProviderSvc::EventCache::~EventCache() {
+  delete event;
+  ROBDataProviderSvc::robmapClear( robmap );
+}
diff --git a/Event/ByteStreamCnvSvcBase/src/components/ByteStreamCnvSvcBase_entries.cxx b/Event/ByteStreamCnvSvcBase/src/components/ByteStreamCnvSvcBase_entries.cxx
index 8b192cf1d8166d23e6a9e5c46f6e42fefa292975..5d0e6d9f0c994445bca57feeb1966b55c802f266 100644
--- a/Event/ByteStreamCnvSvcBase/src/components/ByteStreamCnvSvcBase_entries.cxx
+++ b/Event/ByteStreamCnvSvcBase/src/components/ByteStreamCnvSvcBase_entries.cxx
@@ -1,8 +1,9 @@
 #include "ByteStreamCnvSvcBase/ByteStreamCnvSvcBase.h"
 #include "ByteStreamCnvSvcBase/ByteStreamAddressProviderSvc.h"
 #include "ByteStreamCnvSvcBase/ROBDataProviderSvc.h"
+#include "../ROBDataProviderMTTest.h"
 
 DECLARE_COMPONENT( ByteStreamCnvSvcBase )
 DECLARE_COMPONENT( ByteStreamAddressProviderSvc )
 DECLARE_COMPONENT( ROBDataProviderSvc )
-
+DECLARE_COMPONENT( ROBDataProviderMTTest )
diff --git a/Event/ByteStreamCnvSvcBase/test/test_ROBDataProviderSvcMT.sh b/Event/ByteStreamCnvSvcBase/test/test_ROBDataProviderSvcMT.sh
new file mode 100755
index 0000000000000000000000000000000000000000..b144dd6bce95f4bcc1653f771144d35c4cf1ead6
--- /dev/null
+++ b/Event/ByteStreamCnvSvcBase/test/test_ROBDataProviderSvcMT.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+# art-type: build
+# art-ci: master
+
+athena --threads=4 ByteStreamCnvSvcBase/testROBDataProviderSvcMT.py
+
+
diff --git a/Trigger/TrigDataAccess/TrigDataAccessMonitoring/TrigDataAccessMonitoring/MonROBDataProviderSvc.h b/Trigger/TrigDataAccess/TrigDataAccessMonitoring/TrigDataAccessMonitoring/MonROBDataProviderSvc.h
index 75f67f04bf0c8e85e53f58109eaf683cf66a104d..9fd215209438138e68f02ca6e9130c794db8500f 100644
--- a/Trigger/TrigDataAccess/TrigDataAccessMonitoring/TrigDataAccessMonitoring/MonROBDataProviderSvc.h
+++ b/Trigger/TrigDataAccess/TrigDataAccessMonitoring/TrigDataAccessMonitoring/MonROBDataProviderSvc.h
@@ -55,21 +55,25 @@ public:
     /// --- Implementation of IROBDataProviderSvc interface ---    
 
     /// Add ROBFragments to cache for given ROB ids, ROB fragments may be retrieved with DataCollector 
+    using ROBDataProviderSvc::addROBData;
     virtual void addROBData(const std::vector<uint32_t>& robIds,
 			    const std::string callerName="UNKNOWN");
 
     /// Add a given LVL1/LVL2 ROBFragment to cache 
+    using ROBDataProviderSvc::setNextEvent;
     virtual void setNextEvent(const std::vector<ROBF>& result);
 
     /// Add all ROBFragments of a RawEvent to cache 
-    virtual void setNextEvent(const RawEvent* re);
+    virtual void setNextEvent(const RawEvent* re) override;
 
     /// Retrieve ROBFragments for given ROB ids from cache 
+    using ROBDataProviderSvc::getROBData;
     virtual void getROBData(const std::vector<uint32_t>& robIds, 
 			    std::vector<const ROBF*>& robFragments,
                             const std::string callerName="UNKNOWN");
  
     /// Retrieve the whole event.
+    using ROBDataProviderSvc::getEvent;
     virtual const RawEvent* getEvent() ;
 
     /// --- Implementation of IIncidentListener interface ---
@@ -103,8 +107,11 @@ private:
 
     // monitoring
     std::map<eformat::GenericStatus, std::string> m_map_GenericStatus;
+    const std::string& genericStatusName( eformat::GenericStatus ) const;
+
     std::vector<std::string>                      m_vec_SpecificStatus;
-    std::vector<uint32_t>                         m_robAlreadyAccessed;
+    
+    SG::SlotSpecificObj< std::vector<uint32_t> > m_robAlreadyAccessed;
 
     BooleanProperty m_doMonitoring;
     BooleanProperty m_doDetailedROBMonitoring;
diff --git a/Trigger/TrigDataAccess/TrigDataAccessMonitoring/src/MonROBDataProviderSvc.cxx b/Trigger/TrigDataAccess/TrigDataAccessMonitoring/src/MonROBDataProviderSvc.cxx
index af3a94f1b54f863b06dbd7732df1b8fb85231195..a4edba585d3ad913c3e420566fe77bdb92cc7962 100644
--- a/Trigger/TrigDataAccess/TrigDataAccessMonitoring/src/MonROBDataProviderSvc.cxx
+++ b/Trigger/TrigDataAccess/TrigDataAccessMonitoring/src/MonROBDataProviderSvc.cxx
@@ -50,34 +50,47 @@ MonROBDataProviderSvc::MonROBDataProviderSvc(const std::string& name, ISvcLocato
   declareProperty("HistReceivedROBsPerCall", m_histProp_receivedROBsPerCall,"Number of ROBs received");
   declareProperty("HistTimeROBretrieval", m_histProp_timeROBretrieval,"Timing for ROB retrieval");
   
-  // fill map with generic status codes
-  m_map_GenericStatus[eformat::UNCLASSIFIED]      = "UNCLASSIFIED"; 
-  m_map_GenericStatus[eformat::BCID_CHECK_FAIL]   = "BCID_CHECK_FAIL"; 
-  m_map_GenericStatus[eformat::LVL1ID_CHECK_FAIL] = "LVL1ID_CHECK_FAIL"; 
-  m_map_GenericStatus[eformat::TIMEOUT]           = "TIMEOUT"; 
-  m_map_GenericStatus[eformat::DATA_CORRUPTION]   = "DATA_CORRUPTION"; 
-  m_map_GenericStatus[eformat::INTERNAL_OVERFLOW] = "INTERNAL_OVERFLOW"; 
 
   // fill vector with specific status codes
-  m_vec_SpecificStatus.reserve(16);
-  m_vec_SpecificStatus.push_back("TRIGGER_TYPE_SYNC_ERROR"); 
-  m_vec_SpecificStatus.push_back("FRAGMENT_SIZE_ERROR"); 
-  m_vec_SpecificStatus.push_back("DATABLOCK_ERROR"); 
-  m_vec_SpecificStatus.push_back("CTRL_WORD_ERROR"); 
-  m_vec_SpecificStatus.push_back("MISSING_BOF"); 
-  m_vec_SpecificStatus.push_back("MISSING_EOF"); 
-  m_vec_SpecificStatus.push_back("INVALID_HEADER_MARKER"); 
-  m_vec_SpecificStatus.push_back("FORMAT_ERROR"); 
-  m_vec_SpecificStatus.push_back("DUPLICATE_EVENT"); 
-  m_vec_SpecificStatus.push_back("SEQUENCE_ERROR"); 
-  m_vec_SpecificStatus.push_back("TRANSMISSION_ERROR"); 
-  m_vec_SpecificStatus.push_back("TRUNCATION"); 
-  m_vec_SpecificStatus.push_back("SHORT_FRAGMENT"); 
-  m_vec_SpecificStatus.push_back("FRAGMENT_LOST"); 
-  m_vec_SpecificStatus.push_back("FRAGMENT_PENDING"); 
-  m_vec_SpecificStatus.push_back("ROL_DISABLED"); 
+  m_vec_SpecificStatus = {
+    "TRIGGER_TYPE_SYNC_ERROR", 
+    "FRAGMENT_SIZE_ERROR", 
+    "DATABLOCK_ERROR", 
+    "CTRL_WORD_ERROR", 
+    "MISSING_BOF", 
+    "MISSING_EOF", 
+    "INVALID_HEADER_MARKER", 
+    "FORMAT_ERROR", 
+    "DUPLICATE_EVENT", 
+    "SEQUENCE_ERROR", 
+    "TRANSMISSION_ERROR", 
+    "TRUNCATION", 
+    "SHORT_FRAGMENT", 
+    "FRAGMENT_LOST", 
+    "FRAGMENT_PENDING", 
+    "ROL_DISABLED", 
+  };
+
+  m_map_GenericStatus =  {
+	{eformat::UNCLASSIFIED,       "UNCLASSIFIED"}, 
+	{eformat::BCID_CHECK_FAIL,    "BCID_CHECK_FAIL"}, 
+	{eformat::LVL1ID_CHECK_FAIL,  "LVL1ID_CHECK_FAIL"}, 
+	{eformat::TIMEOUT,            "TIMEOUT"}, 
+	{eformat::DATA_CORRUPTION,    "DATA_CORRUPTION"}, 
+	{eformat::INTERNAL_OVERFLOW,  "INTERNAL_OVERFLOW"}
+  };
+
 } 
 
+const std::string& MonROBDataProviderSvc::genericStatusName( eformat::GenericStatus s ) const {
+  // fill map with generic status codes
+  static std::string unknown = "UNKNOWN";
+  std::map<eformat::GenericStatus, std::string>::const_iterator i = m_map_GenericStatus.find( s );
+  if ( i == m_map_GenericStatus.end() ) 
+    return unknown;
+  return i->second;
+}
+
 // Destructor.
 MonROBDataProviderSvc::~MonROBDataProviderSvc()
 {
@@ -205,7 +218,7 @@ void MonROBDataProviderSvc::addROBData(const std::vector<uint32_t>& robIds, cons
       }
     }
     // initialize new ROBDataMonitorStruct
-    p_robMonStruct = new robmonitor::ROBDataMonitorStruct(m_currentLvl1ID, robIds, caller_name);
+    p_robMonStruct = new robmonitor::ROBDataMonitorStruct(getEvent()->lvl1_id(), robIds, caller_name);
   }
 
   // for offline running the requested ROBs should be found in the cache
@@ -218,6 +231,9 @@ void MonROBDataProviderSvc::addROBData(const std::vector<uint32_t>& robIds, cons
   uint32_t number_ROB_found(0);
   uint32_t number_ROB_not_found(0);
 
+  const EventContext context{ Gaudi::Hive::currentContext() };
+  const ROBMAP& robmap = m_eventsCache.get(context)->robmap;
+
   for(std::vector<uint32_t>::const_iterator it=robIds.begin(); it!=robIds.end(); ++it){
     uint32_t id = (*it);
     // mask off the module ID for L2 and EF result for Run 1 data
@@ -229,9 +245,10 @@ void MonROBDataProviderSvc::addROBData(const std::vector<uint32_t>& robIds, cons
 		(ROBDataProviderSvc::m_maskL2EFModuleID) ) {
       id = eformat::helper::SourceIdentifier(eformat::helper::SourceIdentifier(id).subdetector_id(),0).code();
     }
+
     // check if ROB is already in cache
-    ROBDataProviderSvc::ROBMAP::iterator map_it = m_robmap.find(id) ;
-    if(map_it != m_robmap.end()) { // ROB found in cache
+    ROBDataProviderSvc::ROBMAP::const_iterator map_it = robmap.find(id) ;
+    if(map_it != robmap.end()) { // ROB found in cache
       number_ROB_found++;
 
       if(logLevel() <= MSG::DEBUG)
@@ -250,12 +267,12 @@ void MonROBDataProviderSvc::addROBData(const std::vector<uint32_t>& robIds, cons
 		    (ROBDataProviderSvc::m_maskL2EFModuleID) ) {
 	  accessed_id = eformat::helper::SourceIdentifier(eformat::helper::SourceIdentifier(id).subdetector_id(),0).code();
 	}
-	std::vector<uint32_t>::iterator robAlreadyAccessed_it = find(m_robAlreadyAccessed.begin(), m_robAlreadyAccessed.end(), accessed_id);
-	if (robAlreadyAccessed_it != m_robAlreadyAccessed.end()) {
+	std::vector<uint32_t>::iterator robAlreadyAccessed_it = find(m_robAlreadyAccessed.get(context)->begin(), m_robAlreadyAccessed.get(context)->end(), accessed_id);
+	if (robAlreadyAccessed_it != m_robAlreadyAccessed.get(context)->end()) {
 	  (p_robMonStruct->requested_ROBs)[id].rob_history = robmonitor::CACHED;    // the ROB was already accessed
 	} else {
 	  (p_robMonStruct->requested_ROBs)[id].rob_history = robmonitor::RETRIEVED; // first time the ROB is accessed
-	  m_robAlreadyAccessed.push_back(accessed_id);
+	  m_robAlreadyAccessed.get(context)->push_back(accessed_id);
 	}
 	(p_robMonStruct->requested_ROBs)[id].rob_size = ((*map_it).second)->fragment_size_word();
 	if ( (*map_it).second->nstatus() != 0 ) {
@@ -268,7 +285,7 @@ void MonROBDataProviderSvc::addROBData(const std::vector<uint32_t>& robIds, cons
 	  //* fill monitoring histogram for ROB generic status
 	  if ( m_hist_genericStatusForROB ) {
 	    if ((*it_status) != 0) m_hist_genericStatusForROB->Fill(eformat::helper::SourceIdentifier((*map_it).second->source_id()).human_detector().c_str(),
-								    m_map_GenericStatus[eformat::helper::Status(*it_status).generic()].c_str(),1.);
+								    genericStatusName(eformat::helper::Status(*it_status).generic()).c_str(),1.);
 	  }
 
 	  //* fill monitoring histogram for ROB specific status
@@ -314,7 +331,7 @@ void MonROBDataProviderSvc::addROBData(const std::vector<uint32_t>& robIds, cons
 		<< " ---> Number of ROB Id s requested : " << robIds.size()
 		<< ". Number of ROB Id s found/not found = " << number_ROB_found 
 		<< "/" << number_ROB_not_found
-		<< " for Lvl1 id = "<< m_currentLvl1ID 
+		<< " for Lvl1 id = "<< getEvent()->lvl1_id()
 		<< endmsg;
 
   //* histograms for number of requested/received ROBs
@@ -327,18 +344,20 @@ void MonROBDataProviderSvc::addROBData(const std::vector<uint32_t>& robIds, cons
 }
 
 void MonROBDataProviderSvc::setNextEvent(const std::vector<ROBF>& result) 
-{ 
-  ROBDataProviderSvc::setNextEvent(result);
-  m_robAlreadyAccessed.clear();
-  m_robAlreadyAccessed.resize( m_robmap.size() );
+{   
+  const EventContext context{ Gaudi::Hive::currentContext() };  
+  ROBDataProviderSvc::setNextEvent(context, result);
+  m_robAlreadyAccessed.get(context)->clear();
+  m_robAlreadyAccessed.get(context)->resize( m_eventsCache.get(context)->robmap.size() );
   return; 
 }
 
 void MonROBDataProviderSvc::setNextEvent(const RawEvent* re) 
 { 
-  ROBDataProviderSvc::setNextEvent(re);
-  m_robAlreadyAccessed.clear();
-  m_robAlreadyAccessed.resize( m_robmap.size() );
+  const EventContext context{ Gaudi::Hive::currentContext() };
+  ROBDataProviderSvc::setNextEvent(context, re);
+  m_robAlreadyAccessed.get(context)->clear();
+  m_robAlreadyAccessed.get(context)->resize( m_eventsCache.get(context)->robmap.size() );
   return ;
 }
 
@@ -443,7 +462,7 @@ void MonROBDataProviderSvc::handle(const Incident& incident) {
   m_hist_genericStatusForROB = new TH2F ("GenericStatusForROBsFromSubDetectors",
 					 "GenericStatusForROBsFromSubDetectors;;",
 					 n_bins_partEBSubDet,0.,(float) n_bins_partEBSubDet,
-					 m_map_GenericStatus.size(),0., (float) m_map_GenericStatus.size());
+					 m_map_GenericStatus.size(), 0., (float) m_map_GenericStatus.size());
   if (m_hist_genericStatusForROB) {
     uint32_t n_tmp_bin = 1;
     for (uint16_t i=0; i<256; i++) {
diff --git a/Trigger/TrigDataAccess/TrigROBDataProviderSvc/src/TrigROBDataProviderSvc.cxx b/Trigger/TrigDataAccess/TrigROBDataProviderSvc/src/TrigROBDataProviderSvc.cxx
index a7bf6f874214b925a2e3169ade9dd48d22b7458e..a141ea0baeaf11160bccfdd332ecb07eef5485f6 100755
--- a/Trigger/TrigDataAccess/TrigROBDataProviderSvc/src/TrigROBDataProviderSvc.cxx
+++ b/Trigger/TrigDataAccess/TrigROBDataProviderSvc/src/TrigROBDataProviderSvc.cxx
@@ -505,7 +505,7 @@ void TrigROBDataProviderSvc::addROBData(const std::vector<uint32_t>& robIds, con
     robmonitor::ROBDataMonitorStruct* p_robMonStruct(0);
     if ( p_robMonCollection ) { 
       // initialize new ROBDataMonitorStruct
-      p_robMonStruct = new robmonitor::ROBDataMonitorStruct(m_currentLvl1ID, robIdsUnique, m_callerName);
+      p_robMonStruct = new robmonitor::ROBDataMonitorStruct(lvl1_id(), robIdsUnique, m_callerName);
     }
 
     // for online running the requested ROBs should be not found in cache
@@ -623,7 +623,7 @@ void TrigROBDataProviderSvc::addROBData(const std::vector<uint32_t>& robIds, con
 		    << "      or input ROB Id list was empty, \n" 
 		    << "      or all requested ROBs were not retrieved due to the veto list.\n" 
 		    << "      Number of requested ROB Ids = " << robIdsUnique.size() << "\n"
-		    << "      Lvl1 id                     = " << m_currentLvl1ID 
+		    << "      Lvl1 id                     = " << lvl1_id() 
 		    << endmsg;
       // Set ROB request time also in the case when no DataCollector request is necessary 
       // to allow correlation with RoI request times
@@ -668,7 +668,7 @@ void TrigROBDataProviderSvc::addROBData(const std::vector<uint32_t>& robIds, con
 
 	  logStream() << MSG::DEBUG 
 		      << " ---> addROBData for "<<m_callerName<<": A ROB/ROS mapping is available the following ROB Ids are scheduled for retrieval in getROBData: \n"
-		      << "      Lvl1 id                     = " << m_currentLvl1ID << "\n"
+		      << "      Lvl1 id                     = " << lvl1_id() << "\n"
 		      << ost.str()
 		      << endmsg;
 	}
@@ -682,15 +682,20 @@ void TrigROBDataProviderSvc::addROBData(const std::vector<uint32_t>& robIds, con
   return;
 }
 
+uint32_t TrigROBDataProviderSvc::lvl1_id() {
+  return getEvent()->lvl1_id();
+}
+
 /** - in online add the LVL1/LVL2 result
     - rebuild the map
     - set flag for online running
 */
+
 void TrigROBDataProviderSvc::setNextEvent(const std::vector<ROBF>& result) 
 { 
   // clear the ROB map
   m_online_robmap.clear(); 
-  m_currentLvl1ID = 0;
+  //m_currentLvl1ID = 0;
 
   // clear the maps used for prefetching
   m_Det_Robs_for_retrieval.clear();
@@ -709,27 +714,28 @@ void TrigROBDataProviderSvc::setNextEvent(const std::vector<ROBF>& result)
   }
 
   // set the LVL1 id
-  m_currentLvl1ID = result[0].rod_lvl1_id();
+  uint32_t currentLvl1ID = result[0].rod_lvl1_id();
 
   // add fragments to map
   std::vector<ROBF>::const_iterator it_robf     = result.begin();
   std::vector<ROBF>::const_iterator it_robf_end = result.end();
+
   for(; it_robf!=it_robf_end; ++it_robf) {
     uint32_t id = it_robf->source_id() ;
     // check current L1 ID against CTP fragment when possible
     if ( (eformat::helper::SourceIdentifier(id).subdetector_id() == eformat::TDAQ_CTP) &&
-	 (it_robf->rod_lvl1_id() != m_currentLvl1ID) ) {
+	 ( it_robf->rod_lvl1_id() != currentLvl1ID ) ) {
       logStream() << MSG::ERROR << " ---> Lvl1 ID mismatch for CTP fragment with SourceId = 0x" << MSG::hex << id << MSG::dec
 		  << " and L1 Id = " << it_robf->rod_lvl1_id()  
-		  << " to currently used L1 Id = " << m_currentLvl1ID 
+		  << " to currently used L1 Id = " << currentLvl1ID 
 		  << " -> Use CTP version from now on."<< endmsg;
-      m_currentLvl1ID = it_robf->rod_lvl1_id() ;
+      //      currentLvl1ID = it_robf->rod_lvl1_id(); // TB is this ERROR real or some past history
     }
     // remove empty ROB fragments or ones with bad status, if requested
     if ((it_robf->rod_ndata() == 0) && (m_removeEmptyROB)) { 
       if(logLevel() <= MSG::DEBUG) { 
 	logStream() << MSG::DEBUG << " ---> Empty ROB Id = 0x" << MSG::hex << id << MSG::dec
-		    << " removed for L1 Id = " << m_currentLvl1ID << endmsg;
+		    << " removed for L1 Id = " << currentLvl1ID << endmsg;
       }  
     } else if ( ROBDataProviderSvc::filterRobWithStatus(&*it_robf) ) {
       if ((logLevel() <= MSG::DEBUG) && (it_robf->nstatus() > 0)) {
@@ -741,7 +747,7 @@ void TrigROBDataProviderSvc::setNextEvent(const std::vector<ROBF>& result)
 		    << " with Generic Status Code = 0x" << std::setw(4) << tmpstatus.generic()
 		    << " and Specific Status Code = 0x" << std::setw(4) << tmpstatus.specific()
 		    << MSG::dec
-		    << " removed for L1 Id = " << m_currentLvl1ID << endmsg;
+		    << " removed for L1 Id = " << currentLvl1ID << endmsg;
       }
     } else {
       // mask off the module ID for L2 and EF result for Run 1 data
@@ -789,7 +795,7 @@ void TrigROBDataProviderSvc::setNextEvent(const std::vector<ROBF>& result)
   if(logLevel() <= MSG::DEBUG) {
     logStream()<<MSG::DEBUG<< " ---> setNextEvent online for "<< name()<<endmsg; 
     logStream()<<MSG::DEBUG<< "      online running    = " << m_onlineRunning <<endmsg;
-    logStream()<<MSG::DEBUG<< "      current LVL1 id   = " << m_currentLvl1ID <<endmsg;
+    logStream()<<MSG::DEBUG<< "      current LVL1 id   = " << currentLvl1ID <<endmsg;
     logStream()<<MSG::DEBUG<< "      # LVL1 ROBs       = " << result.size() <<endmsg;
     logStream()<<MSG::DEBUG<< "      size of ROB cache = " << m_online_robmap.size() <<endmsg;
     logStream()<<MSG::DEBUG<< dumpROBcache() <<endmsg; 
@@ -933,7 +939,7 @@ void TrigROBDataProviderSvc::getROBData(const std::vector<uint32_t>& robIds, std
       robmonitor::ROBDataMonitorStruct* p_robMonStruct(0);
       if ( p_robMonCollection ) {
 	// initialize new ROBDataMonitorStruct
-	p_robMonStruct = new robmonitor::ROBDataMonitorStruct(m_currentLvl1ID, robIdsForRetrieval,  m_callerName);
+	p_robMonStruct = new robmonitor::ROBDataMonitorStruct(lvl1_id(), robIdsForRetrieval,  m_callerName);
       }
 
       // update internal ROB cache 
@@ -1093,10 +1099,12 @@ int TrigROBDataProviderSvc::collectCompleteEventData(const std::string callerNam
   struct timeval time_stop;
   if ( m_doMonitoring || m_doDetailedROBMonitoring.value() ) gettimeofday(&time_start, 0);
 
+  const EventContext context{ Gaudi::Hive::currentContext() };
+  const ROBMAP& robmap = m_eventsCache.get(context)->robmap;
 
   // Get ROB Fragments to complete event from offline ROBDataProviderSvc
-  for(ROBDataProviderSvc::ROBMAP::const_iterator offline_rob_map_it=ROBDataProviderSvc::m_robmap.begin();
-      offline_rob_map_it != ROBDataProviderSvc::m_robmap.end(); ++offline_rob_map_it) {
+  for(ROBDataProviderSvc::ROBMAP::const_iterator offline_rob_map_it=robmap.begin();
+      offline_rob_map_it != robmap.end(); ++offline_rob_map_it) {
     uint32_t id = (*offline_rob_map_it).first; 
     ONLINE_ROBMAP::iterator map_it = m_online_robmap.find(id); 
     if (map_it == m_online_robmap.end()) robIdsForRetrieval.push_back(id); 
@@ -1131,7 +1139,7 @@ int TrigROBDataProviderSvc::collectCompleteEventData(const std::string callerNam
   robmonitor::ROBDataMonitorStruct* p_robMonStruct(0);
   if ( p_robMonCollection ) {
     // initialize new ROBDataMonitorStruct
-    p_robMonStruct = new robmonitor::ROBDataMonitorStruct(m_currentLvl1ID, robIdsForRetrieval,  m_callerName);
+    p_robMonStruct = new robmonitor::ROBDataMonitorStruct( lvl1_id(), robIdsForRetrieval,  m_callerName);
   }
 
   if ( m_doMonitoring || p_robMonStruct ) {
@@ -1175,7 +1183,7 @@ int TrigROBDataProviderSvc::collectCompleteEventData(const std::string callerNam
   if (logLevel() <= MSG::DEBUG) {
     logStream() << MSG::DEBUG
         << " ---> collectCompleteEventData: The following ROB Ids were received from DataCollector : \n"
-        << "      Lvl1 id                                             = " << m_currentLvl1ID << "\n"
+		<< "      Lvl1 id                                             = " << lvl1_id() << "\n"
         << "      Number of actually received ROB Ids                 = " << retrievedRobIds.size()
         << endmsg;
   }
@@ -1384,7 +1392,7 @@ void TrigROBDataProviderSvc::addROBDataToCache(std::vector<uint32_t>& robIdsForR
 
   if(logLevel() <= MSG::DEBUG)
     logStream() << MSG::DEBUG << " ---> addROBDataToCache for "<<m_callerName<<": Number of ROB Ids requested for retrieval : " << robIdsForRetrieval.size() 
-		<< ", Lvl1 id = " << m_currentLvl1ID << endmsg;
+		<< ", Lvl1 id = " << lvl1_id() << endmsg;
 
   // return if no ROBs are requested
   if (robIdsForRetrieval.size() == 0) return;
@@ -1464,7 +1472,7 @@ void TrigROBDataProviderSvc::addROBDataToCache(std::vector<uint32_t>& robIdsForR
       ost << "       # = "<< std::setw(5) << rob_counter << " ROB id = 0x" << std::hex << (*rob_it) << std::dec << "\n" ; 
     logStream() << MSG::DEBUG 
 		<< " ---> addROBDataToCache for "<<m_callerName<<": The following ROB Ids were received from DataCollector : \n"
-		<< "      Lvl1 id                                             = " << m_currentLvl1ID << "\n"
+		<< "      Lvl1 id                                             = " << lvl1_id() << "\n"
                 << "      Number of detector ROB Ids requested for retrieval  = " << vRobIds.size() << "\n"
                 << "      Number of MET ROB Ids requested for retrieval       = " << vMETRobIds.size() << "\n"
                 << "      Number of actually received ROB Ids                 = " << retrievedRobIds.size() << "\n"
@@ -1524,7 +1532,7 @@ void TrigROBDataProviderSvc::addROBDataToCache(std::vector<uint32_t>& robIdsForR
     if (((*it_robf)->rod_ndata() == 0) && (m_removeEmptyROB)) { 
       if(logLevel() <= MSG::DEBUG) { 
 	logStream() << MSG::DEBUG << " ---> addROBDataToCache for "<<m_callerName<<": Empty ROB Id = 0x" << MSG::hex << id << MSG::dec
-		    << " removed for L1 Id = " << m_currentLvl1ID << endmsg;
+		    << " removed for L1 Id = " << lvl1_id() << endmsg;
       }
     } else if ( ROBDataProviderSvc::filterRobWithStatus(&*(*it_robf)) ) {
       if ((logLevel() <= MSG::DEBUG) && ((*it_robf)->nstatus() > 0)) {
@@ -1536,7 +1544,7 @@ void TrigROBDataProviderSvc::addROBDataToCache(std::vector<uint32_t>& robIdsForR
 		    << " with Generic Status Code = 0x" << std::setw(4) << tmpstatus.generic()
 		    << " and Specific Status Code = 0x" << std::setw(4) << tmpstatus.specific()
 		    << MSG::dec
-		    << " removed for L1 Id = " << m_currentLvl1ID << endmsg;
+		    << " removed for L1 Id = " <<lvl1_id() << endmsg;
       }
     } else {
       // mask off the module ID for L2 and EF result for Run 1 data
diff --git a/Trigger/TrigDataAccess/TrigROBDataProviderSvc/src/TrigROBDataProviderSvc.h b/Trigger/TrigDataAccess/TrigROBDataProviderSvc/src/TrigROBDataProviderSvc.h
index 40b026a020142831947f27e1fe43a1f46a6e69dd..f61546dd48a479ae3432b7b92b0034c93e234857 100755
--- a/Trigger/TrigDataAccess/TrigROBDataProviderSvc/src/TrigROBDataProviderSvc.h
+++ b/Trigger/TrigDataAccess/TrigROBDataProviderSvc/src/TrigROBDataProviderSvc.h
@@ -75,22 +75,27 @@ public:
     /// --- Implementation of IROBDataProviderSvc interface ---    
 
     /// Add ROBFragments to cache for given ROB ids, ROB fragments may be retrieved with DataCollector 
+    using ROBDataProviderSvc::addROBData;
     virtual void addROBData(const std::vector<uint32_t>& robIds,
-			    const std::string callerName="UNKNOWN");
+			    const std::string callerName="UNKNOWN") override;
 
     /// Add a given LVL1 ROBFragment to cache 
-    virtual void setNextEvent(const std::vector<ROBF>& result);
+    using ROBDataProviderSvc::setNextEvent;
+    virtual void setNextEvent(const std::vector<ROBF>& result) override;
 
-    /// Add all ROBFragments of a RawEvent to cache 
-    virtual void setNextEvent(const RawEvent* re);
+
+    /// Add all ROBFragments of a RawEvent to cache     
+    virtual void setNextEvent(const RawEvent* re) override;
 
     /// Retrieve ROBFragments for given ROB ids from cache 
+    using ROBDataProviderSvc::getROBData;
     virtual void getROBData(const std::vector<uint32_t>& robIds, 
 			    std::vector<const ROBF*>& robFragments,
-			    const std::string callerName="UNKNOWN");
+			    const std::string callerName="UNKNOWN") override;
  
     /// Retrieve the whole event.
-    virtual const RawEvent* getEvent() ;
+    using ROBDataProviderSvc::getEvent;
+    virtual const RawEvent* getEvent() override;
 
     /// --- Implementation of ITrigROBDataProviderSvc interface ---
 
@@ -152,6 +157,8 @@ protected:
     /// vector of Source ids  to be ignored for the ROB map clear
     std::vector<uint32_t>    m_l1_ROB_ids;
 
+    /// lvl1 id of CTP fragment
+    uint32_t lvl1_id(); 
 private:
     typedef ServiceHandle<StoreGateSvc> StoreGateSvc_t;
     /// Reference to StoreGateSvc;
diff --git a/Trigger/TrigDataAccess/TrigROBDataProviderSvc/src/TrigROBDataProviderSvc_RTT.h b/Trigger/TrigDataAccess/TrigROBDataProviderSvc/src/TrigROBDataProviderSvc_RTT.h
index cecfefdcf2d739924db23e9c777ae7d64fab5320..0f0ba0bcc8a0cb21a07fb9347a8f0e67bd7e9e0f 100644
--- a/Trigger/TrigDataAccess/TrigROBDataProviderSvc/src/TrigROBDataProviderSvc_RTT.h
+++ b/Trigger/TrigDataAccess/TrigROBDataProviderSvc/src/TrigROBDataProviderSvc_RTT.h
@@ -67,15 +67,18 @@ class TrigROBDataProviderSvc_RTT : public TrigROBDataProviderSvc,
   void setCallerName(const std::string);
 
   //declare ROBdata // inherited from base class
+  using ROBDataProviderSvc::addROBData;
   void addROBData(const std::vector<uint32_t>& robIds,
 		  const std::string callerName="UNKNOWN");
 
   /// Retrieve ROBFragments for given ROB ids from cache 
+  using ROBDataProviderSvc::getROBData;
   void getROBData(const std::vector<uint32_t>& robIds, 
 		  std::vector<const ROBF*>& robFragments,
 		  const std::string callerName="UNKNOWN");
  
   /// Add a given LVL1 ROBFragment to cache 
+  using ROBDataProviderSvc::setNextEvent;
   void setNextEvent(const std::vector<ROBF>& result);
 
   /// Add all ROBFragments of a RawEvent to cache