From 3e5115e9e31bd18f2d8f336075def4d8290a4f7f Mon Sep 17 00:00:00 2001
From: Adam Edward Barton <adam.edward.barton@cern.ch>
Date: Mon, 25 May 2020 10:51:54 +0000
Subject: [PATCH] Virtualize the internal code of the IdentifiableContainer and
 use standard vector iteration for faster access

---
 .../T_AthenaPoolCreateFuncs.h                 |   6 +-
 Database/TPTools/TPTools/TPConverter.icc      |   9 +-
 Event/EventContainers/CMakeLists.txt          |   5 +
 .../EventContainers/IDC_WriteHandleBase.h     |   6 -
 .../EventContainers/IIdentifiableCont.h       |   2 +-
 .../EventContainers/I_InternalIDC.h           |  50 +++++
 .../EventContainers/IdentifiableCache.h       |   4 +-
 .../EventContainers/IdentifiableCacheBase.h   |  55 +----
 .../IdentifiableContainerBase.h               |  45 ++--
 .../EventContainers/IdentifiableContainerMT.h | 194 +++++-------------
 .../EventContainers/InternalOffline.h         |  45 ++++
 .../EventContainers/InternalOnline.h          |  57 +++++
 .../EventContainers/SelectAllObjectMT.h       |  35 ++--
 .../EventContainers/EventContainers/deleter.h |  37 ++++
 Event/EventContainers/share/IDBenchTest.ref   |   1 +
 Event/EventContainers/share/IDStressTest.ref  |  10 +-
 .../src/IDC_WriteHandleBase.cxx               |   1 -
 .../src/IdentifiableCacheBase.cxx             |  58 ++----
 .../src/IdentifiableContainerBase.cxx         | 106 ++--------
 Event/EventContainers/src/InternalOffline.cxx | 110 ++++++++++
 Event/EventContainers/src/InternalOnline.cxx  | 154 ++++++++++++++
 Event/EventContainers/test/IDC_Benchmark.cxx  |  71 +++++++
 .../test/IDC_Realistic_Test.cxx               |  44 +++-
 .../test/IDMT_ContainerTest.cxx               |  47 ++++-
 24 files changed, 761 insertions(+), 391 deletions(-)
 create mode 100644 Event/EventContainers/EventContainers/I_InternalIDC.h
 create mode 100644 Event/EventContainers/EventContainers/InternalOffline.h
 create mode 100644 Event/EventContainers/EventContainers/InternalOnline.h
 create mode 100644 Event/EventContainers/EventContainers/deleter.h
 create mode 100644 Event/EventContainers/share/IDBenchTest.ref
 create mode 100644 Event/EventContainers/src/InternalOffline.cxx
 create mode 100644 Event/EventContainers/src/InternalOnline.cxx
 create mode 100644 Event/EventContainers/test/IDC_Benchmark.cxx

diff --git a/Database/AthenaPOOL/AthenaPoolCnvSvc/AthenaPoolCnvSvc/T_AthenaPoolCreateFuncs.h b/Database/AthenaPOOL/AthenaPoolCnvSvc/AthenaPoolCnvSvc/T_AthenaPoolCreateFuncs.h
index f9d4e0aaafd..72a905ee01a 100644
--- a/Database/AthenaPOOL/AthenaPoolCnvSvc/AthenaPoolCnvSvc/T_AthenaPoolCreateFuncs.h
+++ b/Database/AthenaPOOL/AthenaPoolCnvSvc/AthenaPoolCnvSvc/T_AthenaPoolCreateFuncs.h
@@ -29,8 +29,10 @@
 #include "GaudiKernel/MsgStream.h"
 #include <memory>
 #include <type_traits>
-class IdentifiableContainerBase;
 
+namespace EventContainers{
+  class IdentifiableContainerBase;
+}
 
 namespace AthenaPoolCnvSvc {
 
@@ -124,7 +126,7 @@ createTransient (TPCNV& cnv,
                  MsgStream& log)
 {
   typedef typename TPCNV::Trans_t Trans_t;
-  if constexpr(std::is_base_of< IdentifiableContainerBase, Trans_t>::value &&
+  if constexpr(std::is_base_of< EventContainers::IdentifiableContainerBase, Trans_t>::value &&
                !std::is_default_constructible<Trans_t>::value)
   {
     log << "IdentifiableContainerBase is not compatible with createTransient" << endmsg;
diff --git a/Database/TPTools/TPTools/TPConverter.icc b/Database/TPTools/TPTools/TPConverter.icc
index 0a2b2209aa1..90ce12ed48f 100644
--- a/Database/TPTools/TPTools/TPConverter.icc
+++ b/Database/TPTools/TPTools/TPConverter.icc
@@ -70,14 +70,15 @@ toPersistentWithKey_impl( const TRANS *trans,
    }
    return TPObjRef( this->m_pStorageTID, size );
 }
-
+namespace EventContainers{
 class IdentifiableContainerBase;
+}
 class IdentifiableValueContainerBase;
 template< class TRANS_BASE, class TRANS, class PERS >
 TRANS* TPPolyCnvBase<TRANS_BASE, TRANS, PERS>::
 createTransient ([[maybe_unused]] const PERS* persObj, MsgStream &log)
 {
-    if constexpr(std::is_base_of< IdentifiableContainerBase, TRANS>::value && !std::is_default_constructible<TRANS>::value) {
+    if constexpr(std::is_base_of< EventContainers::IdentifiableContainerBase, TRANS>::value && !std::is_default_constructible<TRANS>::value) {
       log << "IdentifiableContainerBase is not compatable with createTransient" << std::endl;
       return nullptr;
     }else if constexpr(std::is_base_of< IdentifiableValueContainerBase, TRANS>::value && !std::is_default_constructible<TRANS>::value){
@@ -99,7 +100,7 @@ createTransientWithKey ([[maybe_unused]] const PERS* persObj,
                         const std::string& key,
                         MsgStream& log)
 {
-    if constexpr(std::is_base_of< IdentifiableContainerBase, TRANS>::value && !std::is_default_constructible<TRANS>::value) {
+    if constexpr(std::is_base_of< EventContainers::IdentifiableContainerBase, TRANS>::value && !std::is_default_constructible<TRANS>::value) {
       log << "IdentifiableContainerBase is not compatable with createTransient" << std::endl;
       return nullptr;
     }else if constexpr(std::is_base_of< IdentifiableValueContainerBase, TRANS>::value && !std::is_default_constructible<TRANS>::value){
@@ -120,7 +121,7 @@ template< class TRANS, class PERS >
 TRANS* TPConverterConstBase<TRANS, PERS>::createTransientConst
   (const PERS* persObj, MsgStream& log) const
 {
-  if constexpr(std::is_base_of< IdentifiableContainerBase, TRANS>::value && !std::is_default_constructible<TRANS>::value) {
+  if constexpr(std::is_base_of< EventContainers::IdentifiableContainerBase, TRANS>::value && !std::is_default_constructible<TRANS>::value) {
       log << "IdentifiableContainerBase is not compatable with createTransient" << std::endl;
       return nullptr;
    }else if constexpr(std::is_base_of< IdentifiableValueContainerBase, TRANS>::value && !std::is_default_constructible<TRANS>::value){
diff --git a/Event/EventContainers/CMakeLists.txt b/Event/EventContainers/CMakeLists.txt
index 3b2187e6cac..6a78b1d010c 100644
--- a/Event/EventContainers/CMakeLists.txt
+++ b/Event/EventContainers/CMakeLists.txt
@@ -38,3 +38,8 @@ atlas_add_test( IDCValueTest SOURCES test/IDCValueTest.cxx
                 INCLUDE_DIRS src test EventContainers
                 LINK_LIBRARIES Identifier AthenaKernel GaudiKernel EventContainers
               )
+atlas_add_test( IDBenchTest SOURCES test/IDC_Benchmark.cxx
+                INCLUDE_DIRS src test EventContainers
+                LINK_LIBRARIES Identifier AthenaKernel GaudiKernel EventContainers
+                LOG_IGNORE_PATTERN "time"
+              )
\ No newline at end of file
diff --git a/Event/EventContainers/EventContainers/IDC_WriteHandleBase.h b/Event/EventContainers/EventContainers/IDC_WriteHandleBase.h
index 719404a7c1d..1e25cf03262 100644
--- a/Event/EventContainers/EventContainers/IDC_WriteHandleBase.h
+++ b/Event/EventContainers/EventContainers/IDC_WriteHandleBase.h
@@ -14,13 +14,7 @@ namespace EventContainers {
 struct mutexPair{
    std::condition_variable condition;
    std::mutex mutex;
-#ifndef NDEBUG
-   std::atomic<int> counter;
-#endif
    mutexPair() : condition(), mutex() {
-#ifndef NDEBUG
-      counter.store(0);
-#endif
    }
 };
 
diff --git a/Event/EventContainers/EventContainers/IIdentifiableCont.h b/Event/EventContainers/EventContainers/IIdentifiableCont.h
index 1d9e18de2fd..1d644f5e094 100644
--- a/Event/EventContainers/EventContainers/IIdentifiableCont.h
+++ b/Event/EventContainers/EventContainers/IIdentifiableCont.h
@@ -5,7 +5,7 @@
 
 #ifndef EVENTCONTAINERS_IIDENTIFIABLECONT_H
 #define EVENTCONTAINERS_IIDENTIFIABLECONT_H
-#include "Identifier/Identifier.h"
+#include "Identifier/IdentifierHash.h"
 #include <memory>
 
 namespace EventContainers {
diff --git a/Event/EventContainers/EventContainers/I_InternalIDC.h b/Event/EventContainers/EventContainers/I_InternalIDC.h
new file mode 100644
index 00000000000..2300f952670
--- /dev/null
+++ b/Event/EventContainers/EventContainers/I_InternalIDC.h
@@ -0,0 +1,50 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef EVENTCONTAINERS_I_INTERNALIDC_H
+#define EVENTCONTAINERS_I_INTERNALIDC_H
+
+#include "Identifier/IdentifierHash.h"
+#include "GaudiKernel/StatusCode.h"
+#include <vector>
+#include <utility>
+
+namespace EventContainers{
+class IDC_WriteHandleBase;
+/*
+The intention of the IdentifiableContainer is to provide a key-value map
+for collection pointers. To increase memory and cpu efficiency the online trigger 
+system different “views” can share collection that are created concurrently.
+To efficiently support these different uses while not imposing overhead on the
+offline case and to maintain a consistent interface the internals of the class are
+virtualised.
+
+A standard iterator is provided for fast iteration in a sequential order.
+*/
+class I_InternalIDC{
+public:
+    typedef std::pair < IdentifierHash::value_type, const void* > hashPair;
+    typedef std::vector < hashPair >::const_iterator InternalConstItr;
+    #include "EventContainers/deleter.h"
+    virtual InternalConstItr cbegin() const=0;
+    virtual InternalConstItr cend() const=0;
+    virtual InternalConstItr indexFind( IdentifierHash hashId ) const =0;
+    virtual ~I_InternalIDC() = default;
+    virtual void Wait() const = 0;
+    virtual bool tryAddFromCache(IdentifierHash hashId, EventContainers::IDC_WriteHandleBase &lock) = 0;
+    virtual bool tryAddFromCache(IdentifierHash hashId) = 0;
+    virtual std::vector<IdentifierHash> GetAllCurrentHashes() const =0;
+    virtual const std::vector < hashPair >& GetAllHashPtrPair() const = 0;
+    virtual size_t numberOfCollections() const = 0;
+    virtual size_t fullSize() const noexcept =0;
+    virtual StatusCode fetchOrCreate(IdentifierHash hashId) =0;
+    virtual StatusCode fetchOrCreate(const std::vector<IdentifierHash> &hashIds) =0;
+    virtual bool insert(IdentifierHash hashId, const void* ptr) =0;
+    virtual const void* FindIndexPtr(IdentifierHash hashId) const noexcept = 0;
+    virtual StatusCode addLock(IdentifierHash hashId, const void* ptr) = 0;
+    virtual void* removeCollection( IdentifierHash hashId ) =0;
+};
+
+}
+#endif
\ No newline at end of file
diff --git a/Event/EventContainers/EventContainers/IdentifiableCache.h b/Event/EventContainers/EventContainers/IdentifiableCache.h
index 0c0d3aa7d22..e95325dfeda 100644
--- a/Event/EventContainers/EventContainers/IdentifiableCache.h
+++ b/Event/EventContainers/EventContainers/IdentifiableCache.h
@@ -71,12 +71,12 @@ public:
     return reinterpret_cast<const T*> (IdentifiableCacheBase::get (hash));
   }
 
-  bool add (IdentifierHash hash, const T* p)
+  std::pair<bool, const void*> add (IdentifierHash hash, const T* p)
   {
     return IdentifiableCacheBase::add (hash, p);
   }
 
-  bool add (IdentifierHash hash, std::unique_ptr<T> p)
+  std::pair<bool, const void*> add (IdentifierHash hash, std::unique_ptr<T> p)
   {
     return IdentifiableCacheBase::add (hash, void_unique_ptr(std::move(p)));
   }
diff --git a/Event/EventContainers/EventContainers/IdentifiableCacheBase.h b/Event/EventContainers/EventContainers/IdentifiableCacheBase.h
index 92a12a85b8f..be173fe0913 100644
--- a/Event/EventContainers/EventContainers/IdentifiableCacheBase.h
+++ b/Event/EventContainers/EventContainers/IdentifiableCacheBase.h
@@ -5,12 +5,7 @@
 */
 
 // $Id: IdentifiableCacheBase.h 791541 2017-01-09 10:43:53Z smh $
-/**
- * @file IdentifiableCacheBase.h
- * @author scott snyder <snyder@bnl.gov>
- * @date Mar, 2016
- * @brief 
- */
+
 
 
 #ifndef EVENTCONTAINERS_IDENTIFIABLECACHEBASE_H
@@ -37,43 +32,13 @@ public:
 //here for access from other classes
 static constexpr uintptr_t INVALIDflag = UINTPTR_MAX;
 static constexpr uintptr_t ABORTEDflag = UINTPTR_MAX-1;
-static constexpr size_t s_defaultBucketSize =6;
+static constexpr size_t s_defaultBucketSize =2;
 
 typedef std::true_type thread_safe;
 typedef std::set<IdentifierHash> idset_t;
 
-#if 0
-  struct deleter
-  {
-    void operator() (const void* p);
-  };
-#endif
-
-  typedef void deleter_f (const void* p);
+#include "EventContainers/deleter.h"
 
-  class void_unique_ptr
-    : public std::unique_ptr<const void, deleter_f*>
-  {
-  public:
-    using std::unique_ptr<const void, deleter_f*>::unique_ptr;
-
-    template <class T>
-    struct Deleter
-    {
-      static void deleter (const void* p)
-      {
-        delete reinterpret_cast<const T*>(p);
-      }
-    };
-
-    template <class T>
-    void_unique_ptr(std::unique_ptr<T> p)
-      : std::unique_ptr<const void, deleter_f*> (p.release(),
-                                                 Deleter<T>::deleter)
-    {
-    }
-  };
-  
   struct IMaker
   {
     bool m_IsReEntrant = false;
@@ -92,13 +57,13 @@ typedef std::set<IdentifierHash> idset_t;
   ///In a threaded situation this collection will be valid but will not container hashes later added
   std::vector<IdentifierHash> ids();
   
-  bool add (IdentifierHash hash, const void* p) noexcept;
+  std::pair<bool, const void*> add (IdentifierHash hash, const void* p) noexcept;
 
   // addLock is same as method above except we check for invalid state first,
   // more optimal for calling using writehandle lock method
-  bool addLock (IdentifierHash hash, const void* p) noexcept;
-  bool addLock (IdentifierHash hash, void_unique_ptr p) noexcept;
-  bool add (IdentifierHash hash, void_unique_ptr p) noexcept;
+  std::pair<bool, const void*> addLock (IdentifierHash hash, const void* p) noexcept;
+  std::pair<bool, const void*> addLock (IdentifierHash hash, void_unique_ptr p) noexcept;
+  std::pair<bool, const void*> add (IdentifierHash hash, void_unique_ptr p) noexcept;
 
   bool IMakerPresent() const { return m_maker!=nullptr; }
 
@@ -128,9 +93,7 @@ typedef std::set<IdentifierHash> idset_t;
   size_t fullSize() const { return m_vec.size(); }
   ///In a concurrent situation this number isn't necessarily perfectly synchronised with ids().size()
   size_t numberOfHashes();
-#ifndef NDEBUG
-  void cancelWait(IdentifierHash hash);
-#endif
+
 protected:
   IdentifiableCacheBase (IdentifierHash maxHash, const IMaker* maker, size_t lockBucketSize);
   IdentifiableCacheBase (IdentifierHash maxHash, const IMaker* maker);
@@ -140,7 +103,7 @@ protected:
   void notifyHash(IdentifierHash hash);
 private:
   std::vector<std::atomic<const void*> > m_vec;
-  
+  friend class InternalOnline;
   const IMaker* m_maker;
 
   typedef std::mutex mutex_t;
diff --git a/Event/EventContainers/EventContainers/IdentifiableContainerBase.h b/Event/EventContainers/EventContainers/IdentifiableContainerBase.h
index 86d697f8226..3e6d14b424f 100644
--- a/Event/EventContainers/EventContainers/IdentifiableContainerBase.h
+++ b/Event/EventContainers/EventContainers/IdentifiableContainerBase.h
@@ -1,39 +1,42 @@
 /*
-  Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
 */
 
 
 #ifndef EVENTCONTAINERS_IDENTIFIABLECONTAINERBASE_H
 #define EVENTCONTAINERS_IDENTIFIABLECONTAINERBASE_H
-
-#include "EventContainers/IdentifiableCacheBase.h"
+#include "EventContainers/I_InternalIDC.h"
 #include "CxxUtils/checker_macros.h"
 
-class IdentifiableContainerBase{
 
+namespace EventContainers{ class IdentifiableCacheBase; 
+
+class IdentifiableContainerBase{
 public:
+#include "EventContainers/deleter.h"
     typedef std::vector<IdentifierHash> Hash_Container;
-    IdentifiableContainerBase(EventContainers::IdentifiableCacheBase *cache, bool online);
-    static Hash_Container::const_iterator findHash(Hash_Container*, IdentifierHash);
-    ~IdentifiableContainerBase();
+    IdentifiableContainerBase(EventContainers::IdentifiableCacheBase *cache);
+    IdentifiableContainerBase(size_t maxsize);
+    ~IdentifiableContainerBase() = default;
 protected:
-    EventContainers::IdentifiableCacheBase *m_cacheLink;
     bool m_OnlineMode;
-    mutable std::atomic<bool> m_waitNeeded ATLAS_THREAD_SAFE; //These mutables are carefully thought out, do not change
     typedef EventContainers::IdentifiableCacheBase IdentifiableCacheBase;
-    mutable std::vector< IdentifierHash > m_waitlist ATLAS_THREAD_SAFE;
-    mutable std::mutex m_waitMutex ATLAS_THREAD_SAFE;
-    mutable std::vector<bool> m_mask ATLAS_THREAD_SAFE;
-    std::vector<IdentifierHash> GetAllCurrentHashes() const;
-
-    void Wait() const;
-    bool tryAddFromCache(IdentifierHash hashId, EventContainers::IDC_WriteHandleBase &lock);
-    bool tryAddFromCache(IdentifierHash hashId);
-    void cleanup();
-    size_t numberOfCollections() const;
+    std::unique_ptr<I_InternalIDC> m_link;
+    std::vector<IdentifierHash> GetAllCurrentHashes() const { return m_link->GetAllCurrentHashes(); }
+    bool insert(IdentifierHash hashId, const void* ptr) { return m_link->insert(hashId, ptr); }
+    void Wait() const { m_link->Wait(); }
+    bool tryAddFromCache(IdentifierHash hashId, EventContainers::IDC_WriteHandleBase &lock) { 
+        return m_link->tryAddFromCache(hashId, lock); }
+    bool tryAddFromCache(IdentifierHash hashId){ return m_link->tryAddFromCache(hashId); }
+    void cleanup(deleter_f* deleter);
+    size_t numberOfCollections() const { return m_link->numberOfCollections(); }
     void ResetMask();
-    StatusCode fetchOrCreate(IdentifierHash hashId);
-    StatusCode fetchOrCreate(const std::vector<IdentifierHash> &hashIds);
+    StatusCode fetchOrCreate(IdentifierHash hashId){ return m_link->fetchOrCreate(hashId); }
+    StatusCode fetchOrCreate(const std::vector<IdentifierHash> &hashIds) { return m_link->fetchOrCreate(hashIds); }
+    const void* indexFindPtr( IdentifierHash hashId ) const { return m_link->FindIndexPtr(hashId); }
 };
 
+}
+
+
 #endif
diff --git a/Event/EventContainers/EventContainers/IdentifiableContainerMT.h b/Event/EventContainers/EventContainers/IdentifiableContainerMT.h
index cb1e7bb2fb3..054d29a9360 100644
--- a/Event/EventContainers/EventContainers/IdentifiableContainerMT.h
+++ b/Event/EventContainers/EventContainers/IdentifiableContainerMT.h
@@ -16,48 +16,34 @@
  */
 
 #include "Identifier/Identifier.h"
-#include "EventContainers/IdentifiableCache.h"
 #include "EventContainers/IIdentifiableCont.h"
 #include <memory>
 #include "GaudiKernel/DataObject.h"
 #include "EventContainers/IdentifiableContainerBase.h"
 #include "EventContainers/IDC_WriteHandleBase.h"
 #include "CxxUtils/AthUnlikelyMacros.h"
-//const_iterator and indexFind are provided for backwards compatability. they are not optimal
-/*
-IT is faster to iterate over the container with this method:
-    auto hashes= m_container->GetAllCurrentHashes();
-    for (auto hash : hashes) {
-        T* coll = m_container->indexFindPtr(hash); 
-        //Use coll here
-    }
-*/
+#include "EventContainers/IdentifiableCache.h"
+#include "EventContainers/InternalOffline.h"
 
 template < class T>
-class IdentifiableContainerMT : public DataObject, public IdentifiableContainerBase, public EventContainers::IIdentifiableCont<T>
+class IdentifiableContainerMT : public DataObject, public EventContainers::IdentifiableContainerBase, public EventContainers::IIdentifiableCont<T>
 {
 
-
 public:
 
     class IDC_WriteHandle : EventContainers::IDC_WriteHandleBase {
         friend class IdentifiableContainerMT<T>;
         IdentifiableContainerMT<T> *m_IDC_ptr;
         IdentifierHash m_hashId;
-        bool m_alreadyPresent;
         public:
-        IDC_WriteHandle() : IDC_WriteHandleBase(), m_IDC_ptr(0), m_hashId(0), m_alreadyPresent(false) { }
+        IDC_WriteHandle() : IDC_WriteHandleBase(), m_IDC_ptr(0), m_hashId(0) { }
         IDC_WriteHandle& operator=(const IDC_WriteHandle& other) = delete;
         IDC_WriteHandle(const IDC_WriteHandle& other) = delete;
-        IDC_WriteHandle& operator=(IDC_WriteHandle&& other) noexcept{
-           Swap(*this, other);
-           return *this;
-        }
-        void Swap(IDC_WriteHandle& a, IDC_WriteHandle& b) noexcept {
+        IDC_WriteHandle& operator=(IDC_WriteHandle&& other) noexcept = delete;
+        static void Swap(IDC_WriteHandle& a, IDC_WriteHandle& b) noexcept {
            if(&a == &b) return;
            std::swap(a.m_IDC_ptr, b.m_IDC_ptr);
            std::swap(a.m_hashId, b.m_hashId);
-           std::swap(a.m_alreadyPresent, b.m_alreadyPresent);
            std::swap(a.m_atomic, b.m_atomic);
            std::swap(a.m_mut, b.m_mut);
         }
@@ -69,10 +55,11 @@ public:
            if(ATH_UNLIKELY(m_IDC_ptr==nullptr)) return StatusCode::FAILURE;
            StatusCode sc = m_IDC_ptr->addLock(std::move(ptr), m_hashId);
            IDC_WriteHandleBase::ReleaseLock();
-           m_alreadyPresent = true;
            return sc;
         }
-        bool alreadyPresent() const { return m_alreadyPresent; }
+        bool alreadyPresent() { return m_IDC_ptr->m_link->tryAddFromCache(m_hashId, *this); }
+        ///This method is to avoid calling an expensive operation in the offline case
+        bool OnlineAndPresentInAnotherView() { return m_IDC_ptr->m_OnlineMode && m_IDC_ptr->m_link->tryAddFromCache(m_hashId, *this); }
     };
 
 
@@ -89,16 +76,13 @@ public:
     typedef T          base_value_type;
 
 
-    ICACHE* castCache() { return static_cast<ICACHE*>(m_cacheLink); }
-    ICACHE* castCache() const { return static_cast<ICACHE*>(m_cacheLink); }
-
     class const_iterator
     {
 
     public:
 
         /// iterator constructor
-        const_iterator() : m_sptr(), m_current(nullptr), m_hash(0), m_idContainer(nullptr), m_end(false) { }
+        const_iterator() : m_itr() {}
         const_iterator(const_iterator&&) = default;
         const_iterator(const const_iterator&) = default;
         const_iterator& operator = ( const const_iterator & ) = default; //move operators may be useful for shared_ptr
@@ -108,41 +92,8 @@ public:
 
         /// increment operator
         const_iterator& operator ++ () {
-            if(m_end) return *this;
-            //If called on iterator created by "fast" iterator method const_iterator( const MyType* idC, IdentifierHash hash  )
-            if(!m_sptr) { 
-                auto ids = m_idContainer->GetAllCurrentHashes();
-                m_sptr    = std::shared_ptr<Hash_Container> (new Hash_Container());
-                m_sptr->swap(ids);
-                m_hashItr = IdentifiableContainerBase::findHash(m_sptr.get(), m_hash);
-                if(m_hashItr==m_sptr->end()) {
-                    m_end = true;
-                    m_sptr.reset();
-                    return *this;
-                }
-            }
-            
-#ifdef IdentifiableCacheBaseRemove            
-            do {
-                ++m_hashItr;
-                if(m_hashItr==m_sptr->end()) {
-                    m_end = true;
-                    m_sptr.reset();
-                    return *this;
-                }
-                m_current = m_idContainer->indexFindPtr(*m_hashItr);
-            } while(m_current==nullptr); //If we implement remove, this can happen
-            
-#else
-             ++m_hashItr;
-             if(m_hashItr==m_sptr->end()) {
-                 m_end = true;
-                 m_sptr.reset();
-                 return *this;
-             }
-             m_current = m_idContainer->indexFindPtr(*m_hashItr);
-#endif       
-             return *this;
+            ++m_itr;
+            return *this;
         }
 
         /// increment operator
@@ -153,74 +104,41 @@ public:
         }
 
         const T* cptr () const {
-            return m_current;
+            return reinterpret_cast<const T*>( m_itr->second );
         }
 
         const T* operator * () const {
-            return m_current;
+            return reinterpret_cast<const T*>( m_itr->second );
         }
 
         const T* operator ->() const { return (operator*()); }
 
         /// comparison operator
         bool operator != ( const const_iterator &it ) const {
-            if(m_end || it.m_end) return m_end!= it.m_end;
-            return m_current!= it.m_current;
+            return m_itr!= it.m_itr;
         }
 
         /// comparison operator
         bool operator == ( const const_iterator &it ) const {
-            if(m_end || it.m_end) return m_end == it.m_end;
-            return m_current == it.m_current;
+            return m_itr == it.m_itr;
         }
 
         /// hashId of the pointed-to element
         //Calling this on an end iterator is undefined behaviour
         IdentifierHash hashId() const {
-            return !m_sptr ? m_hash : *m_hashItr;
+            return m_itr->first;
         }
 
     protected:
         friend class IdentifiableContainerMT<T>;
 
-        const_iterator(const MyType* idC, bool end) : m_sptr(), m_current(nullptr), m_hash(0), 
-         m_idContainer(idC), m_end(end)
-        {
-            if(!m_end) {
-                auto ids = m_idContainer->GetAllCurrentHashes();
-                if(ids.empty()) {//For empty containers
-                    m_end = true;
-                } else {
-                    m_sptr   = std::shared_ptr<Hash_Container> (new Hash_Container());
-                    m_sptr->swap(ids);
-                    m_hashItr = m_sptr->begin();            
-                    m_current = m_idContainer->indexFindPtr(*m_hashItr);
-#ifdef IdentifiableCacheBaseRemove  
-                    if(m_current==nullptr){  ++(*this); } //If we implement remove, this can happen
-#endif
-                }
-            }
-        }
-
+        const_iterator(EventContainers::I_InternalIDC::InternalConstItr itr) : m_itr(std::move(itr)) {}
 
-        //Alot of existing code creates a lot of iterators but doesn't interator over it
-        //This constructor delays creation of hash vector until ++ is called
-        const_iterator( const MyType* idC, IdentifierHash hash  ) :m_sptr(),
-            m_hash(hash), m_idContainer(idC) {
 
-            m_current = m_idContainer->indexFindPtr(hash);
-            m_end = m_current==nullptr;
-        }
-
-        Hash_Container::const_iterator m_hashItr;
-        std::shared_ptr<Hash_Container> m_sptr;
-        const T* m_current;
-        IdentifierHash m_hash;
-        const MyType *m_idContainer;
-        bool m_end;
+        EventContainers::I_InternalIDC::InternalConstItr m_itr;
     };
 
-
+    friend class IDC_WriteHandle;
 
     /// constructor initializes the collection the hashmax, OFFLINE usages pattern
     IdentifiableContainerMT(IdentifierHash hashMax);
@@ -228,7 +146,7 @@ public:
     /// constructor initializes with a link to a cache, ONLINE usage pattern
     IdentifiableContainerMT(ICACHE *cache);
 
-    ~IdentifiableContainerMT() { if(!m_OnlineMode) delete castCache(); }
+    ~IdentifiableContainerMT() { if(!m_OnlineMode) static_cast<EventContainers::InternalOffline*>(m_link.get())->cleanUp(void_unique_ptr::Deleter<T>::deleter); }
 
     virtual bool hasExternalCache() const override final { return m_OnlineMode; }
 
@@ -239,8 +157,7 @@ public:
     virtual const T* indexFindPtr( IdentifierHash hashId ) const override final;
 
     const_iterator indexFind( IdentifierHash hashId ) const {
-        const_iterator it(this, hashId);
-        return it;
+        return m_link->indexFind(hashId);
     }
 
     /// insert collection into container with id hash
@@ -282,12 +199,12 @@ public:
 
     /// return full size of container
     virtual size_t fullSize() const  override final {
-        return m_mask.size();
+        return m_link->fullSize();
     }
 
     ///Duplicate of fullSize for backwards compatability
     size_t size() const {
-        return m_mask.size();
+        return m_link->fullSize();
     }    
 
     /// return number of collections
@@ -295,6 +212,11 @@ public:
         return IdentifiableContainerBase::numberOfCollections();
     }
 
+    const std::vector < std::pair<IdentifierHash::value_type, const T*> >& GetAllHashPtrPair() const{
+        static_assert(sizeof(const T*) == sizeof(const void*) && std::is_pointer<const T*>::value);
+        return reinterpret_cast<const std::vector < std::pair<IdentifierHash::value_type, const T*> >&>
+                (m_link->GetAllHashPtrPair());
+    }
     
     ///Returns a collection of all hashes availiable in this IDC.
     ///If this is an "offline" mode IDC then this is identical to the cache
@@ -306,14 +228,13 @@ public:
 
     /// return const_iterator for first entry
     const_iterator begin() const {
-        const_iterator it(this, false);
-        return it;
+        return const_iterator(m_link->cbegin());
     }
 
 
     /// return const_iterator for end of container
     const_iterator end() const {
-        return const_iterator(nullptr, true);
+        return const_iterator(m_link->cend());
     }
 
     [[nodiscard]] IDC_WriteHandle getWriteHandle(IdentifierHash hash)
@@ -321,7 +242,6 @@ public:
        IDC_WriteHandle lock;
        lock.m_hashId = hash;
        lock.m_IDC_ptr = this;
-       lock.m_alreadyPresent = IdentifiableContainerBase::tryAddFromCache(hash, lock);
        return lock;
     }
 };
@@ -331,11 +251,7 @@ template < class T>
 T*  //Please don't do this we want to get rid of this
 IdentifiableContainerMT<T>::removeCollection( IdentifierHash hashId )
 {
-    using namespace EventContainers;
-    const T* ptr = reinterpret_cast<const T*> (castCache()->find (hashId));
-    castCache()->remove(hashId);
-    m_mask[hashId] = false;
-    return const_cast<T*>(ptr);
+    return reinterpret_cast<T*>(m_link->removeCollection(hashId));
 }
 #endif
 
@@ -343,13 +259,13 @@ IdentifiableContainerMT<T>::removeCollection( IdentifierHash hashId )
 
 // Constructor for OFFLINE style IDC
 template < class T>
-IdentifiableContainerMT<T>::IdentifiableContainerMT(IdentifierHash maxHash) :  IdentifiableContainerBase(new ICACHE(maxHash, nullptr), false)
+IdentifiableContainerMT<T>::IdentifiableContainerMT(IdentifierHash maxHash) :  IdentifiableContainerBase(maxHash)
 {
 }
 
 // Constructor for ONLINE style IDC
 template < class T>
-IdentifiableContainerMT<T>::IdentifiableContainerMT(ICACHE *cache) : IdentifiableContainerBase(cache, true)
+IdentifiableContainerMT<T>::IdentifiableContainerMT(ICACHE *cache) : IdentifiableContainerBase(cache)
 {
 }
 
@@ -360,8 +276,7 @@ template < class T>
 const T*
 IdentifiableContainerMT<T>::indexFindPtr( IdentifierHash hashId ) const
 {
-    if((hashId < m_mask.size()) and m_mask[hashId])  return castCache()->findWait(hashId);
-    else return nullptr;
+    return reinterpret_cast<const T* > (IdentifiableContainerBase::indexFindPtr(hashId));
 }
 
 // insert collection into container with id hash
@@ -370,8 +285,7 @@ StatusCode
 IdentifiableContainerMT<T>::addCollection(const T* coll, IdentifierHash hashId)
 {
     // update m_hashids
-    if (ATH_UNLIKELY(! castCache()->add(hashId, coll))) return StatusCode::FAILURE;
-    m_mask[hashId] = true;
+    if (ATH_UNLIKELY(! IdentifiableContainerBase::insert(hashId, coll))) return StatusCode::FAILURE;
     return StatusCode::SUCCESS;
 
 }
@@ -382,8 +296,7 @@ template < class T>
 void
 IdentifiableContainerMT<T>::cleanup()
 {
-    if(m_OnlineMode) { IdentifiableContainerBase::ResetMask();  }
-    else { castCache()->clearCache(); }
+    IdentifiableContainerBase::cleanup(void_unique_ptr::Deleter<T>::deleter);
 }
 
 template < class T>
@@ -414,18 +327,20 @@ IdentifiableContainerMT<T>::naughtyRetrieve(IdentifierHash hashId, T* &collToRet
 {
    if(ATH_UNLIKELY(m_OnlineMode)) return StatusCode::FAILURE;//NEVER ALLOW FOR EXTERNAL CACHE
    else {
-      collToRetrieve = const_cast< T* > (castCache()->find(hashId));//collToRetrieve can be null on success
+      auto p = reinterpret_cast<const T* > (static_cast<EventContainers::InternalOffline*>(m_link.get())->FindIndexPtr(hashId));//collToRetrieve can be null on success
+      collToRetrieve = const_cast<T*>(p);
       return StatusCode::SUCCESS;
    }
 }
 
 template < class T>
 StatusCode
-IdentifiableContainerMT<T>::addOrDelete(std::unique_ptr<T> ptr, IdentifierHash hashId)
+IdentifiableContainerMT<T>::addOrDelete(std::unique_ptr<T> uptr, IdentifierHash hashId)
 {
-    if(ATH_UNLIKELY(hashId >= m_mask.size())) return StatusCode::FAILURE;
-    castCache()->add(hashId, std::move(ptr));
-    m_mask[hashId] = true; //it wasn't added it is already present therefore mask could be true
+    if(ATH_UNLIKELY(hashId >= m_link->fullSize())) return StatusCode::FAILURE;
+    auto ptr = uptr.release();
+    bool b = IdentifiableContainerBase::insert(hashId, ptr);
+    if(!b) delete ptr;
     return StatusCode::SUCCESS;
 }
 
@@ -433,25 +348,18 @@ template < class T>
 StatusCode
 IdentifiableContainerMT<T>::addLock(std::unique_ptr<T> ptr, IdentifierHash hashId)
 {
-    if(ATH_UNLIKELY(hashId >= m_mask.size())) return StatusCode::FAILURE;
-    [[maybe_unused]] bool deleted = !castCache()->addLock(hashId, std::move(ptr));
-#ifndef NDEBUG
-    if(deleted){
-      std::cout << "IDC WARNING Deletion shouldn't occur in addLock paradigm" << std::endl;
-    }
-#endif
-    m_mask[hashId] = true; //it wasn't added it is already present therefore mask could be true
-    return StatusCode::SUCCESS;
+    return m_link->addLock(hashId, ptr.release());
 }
 
 template < class T>
 StatusCode
-IdentifiableContainerMT<T>::addOrDelete(std::unique_ptr<T> ptr, IdentifierHash hashId, bool &deleted)
+IdentifiableContainerMT<T>::addOrDelete(std::unique_ptr<T> uptr, IdentifierHash hashId, bool &deleted)
 {
-    if(ATH_UNLIKELY(hashId >= m_mask.size())) return StatusCode::FAILURE;
-    bool added = castCache()->add(hashId, std::move(ptr));
-    m_mask[hashId] = true;
-    deleted = !added;
+    if(ATH_UNLIKELY(hashId >= m_link->fullSize())) return StatusCode::FAILURE;
+    auto ptr = uptr.release();
+    bool b = IdentifiableContainerBase::insert(hashId, ptr);
+    if(!b) delete ptr;
+    deleted = !b;
     return StatusCode::SUCCESS;
 }
 
diff --git a/Event/EventContainers/EventContainers/InternalOffline.h b/Event/EventContainers/EventContainers/InternalOffline.h
new file mode 100644
index 00000000000..1bb03226ce2
--- /dev/null
+++ b/Event/EventContainers/EventContainers/InternalOffline.h
@@ -0,0 +1,45 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef EVENTCONTAINERS_INTERNALOFFLINE_H
+#define EVENTCONTAINERS_INTERNALOFFLINE_H
+#include "EventContainers/I_InternalIDC.h"
+
+namespace EventContainers{
+/*
+This class implements the IdentifiableContainer code for the offline case.
+To avoid excess memory usage just the key-value pair is stored and can be directly
+iterated upon.
+
+Faster consecutive iteration, slower random access.
+Prefer iteration over FindIndexPtr and indexFind
+*/
+class InternalOffline final : public I_InternalIDC {
+public:
+    InternalOffline(size_t max);
+    virtual ~InternalOffline()=default;
+    virtual InternalConstItr cbegin() const override;
+    virtual InternalConstItr cend() const override;
+    virtual InternalConstItr indexFind( IdentifierHash hashId ) const override;
+    virtual const std::vector < hashPair >& GetAllHashPtrPair() const override;
+    std::vector<std::pair<IdentifierHash::value_type, const void*>> m_map;
+    size_t m_maximumSize;
+    virtual bool tryAddFromCache(IdentifierHash hashId, EventContainers::IDC_WriteHandleBase &lock) override;
+    virtual bool tryAddFromCache(IdentifierHash hashId) override;
+    virtual void Wait() const override;
+    virtual std::vector<IdentifierHash> GetAllCurrentHashes() const override;
+    virtual size_t numberOfCollections() const override;
+    void cleanUp(deleter_f* deleter) noexcept;
+    virtual size_t fullSize() const noexcept override {return m_maximumSize;}
+    virtual StatusCode fetchOrCreate(IdentifierHash hashId) override;
+    virtual StatusCode fetchOrCreate(const std::vector<IdentifierHash> &hashIds) override;
+    virtual bool insert(IdentifierHash hashId, const void* ptr) override;
+    virtual const void* FindIndexPtr(IdentifierHash hashId) const noexcept override;
+    virtual StatusCode addLock(IdentifierHash hashId, const void* ptr) override;
+    virtual void* removeCollection( IdentifierHash hashId ) override;
+
+};
+
+}
+#endif
diff --git a/Event/EventContainers/EventContainers/InternalOnline.h b/Event/EventContainers/EventContainers/InternalOnline.h
new file mode 100644
index 00000000000..eb78185ff9c
--- /dev/null
+++ b/Event/EventContainers/EventContainers/InternalOnline.h
@@ -0,0 +1,57 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef EVENTCONTAINERS_INTERNALONLINE_H
+#define EVENTCONTAINERS_INTERNALONLINE_H
+
+#include "EventContainers/I_InternalIDC.h"
+#include "CxxUtils/checker_macros.h"
+#include <atomic>
+#include <mutex>
+
+namespace EventContainers{
+class IdentifiableCacheBase;
+/*
+The online implementation keeps a pointer to an external cache which owns the collections
+and can be filled concurrently. The container itself maintains a bit mask to identify which
+collections can be accessed from this container. It also maintains a wait list which records
+uncompleted objects that were added to the container. When a complete collection is
+requested the wait-list is processed, locking the thread until all elements are completed.
+The intention of this is to delay thread locking until the last possible moment and thus
+hopefully avoid it altogether.
+Random access is fast since it takes a direct index to the external cache element.
+Ordered iteration is also fast after the lazily initialised collection is constructed.
+*/
+class InternalOnline final : public I_InternalIDC {
+public:
+    InternalOnline(EventContainers::IdentifiableCacheBase *cache);
+    virtual InternalConstItr cbegin() const override;
+    virtual InternalConstItr cend() const override;
+    virtual InternalConstItr indexFind( IdentifierHash hashId ) const override;
+    virtual const std::vector < hashPair >& GetAllHashPtrPair() const override;
+    virtual ~InternalOnline()=default;
+    virtual void Wait() const override;
+    virtual bool tryAddFromCache(IdentifierHash hashId, EventContainers::IDC_WriteHandleBase &lock) override;
+    virtual bool tryAddFromCache(IdentifierHash hashId) override;
+    virtual std::vector<IdentifierHash> GetAllCurrentHashes() const override;
+    virtual size_t numberOfCollections() const override;
+    void ResetMask();
+    virtual size_t fullSize() const noexcept override { return m_mask.size(); }
+    virtual StatusCode fetchOrCreate(IdentifierHash hashId) override;
+    virtual StatusCode fetchOrCreate(const std::vector<IdentifierHash> &hashIds) override;
+    virtual bool insert(IdentifierHash hashId, const void* ptr) override;
+    virtual const void* FindIndexPtr(IdentifierHash hashId) const noexcept override;
+    virtual StatusCode addLock(IdentifierHash hashId, const void* ptr) override;
+    virtual void* removeCollection( IdentifierHash hashId ) override;
+private:
+    EventContainers::IdentifiableCacheBase *m_cacheLink;
+    mutable std::vector< IdentifierHash > m_waitlist ATLAS_THREAD_SAFE;
+    mutable std::vector<std::pair<IdentifierHash::value_type, const void*>> m_map ATLAS_THREAD_SAFE;
+    mutable std::mutex m_waitMutex ATLAS_THREAD_SAFE;
+    mutable std::vector<bool> m_mask ATLAS_THREAD_SAFE;
+    mutable std::atomic<bool> m_waitNeeded ATLAS_THREAD_SAFE; //These mutables are carefully thought out, do not change
+};
+
+}
+#endif
diff --git a/Event/EventContainers/EventContainers/SelectAllObjectMT.h b/Event/EventContainers/EventContainers/SelectAllObjectMT.h
index 42a25c0f7c5..3adb448a5c1 100644
--- a/Event/EventContainers/EventContainers/SelectAllObjectMT.h
+++ b/Event/EventContainers/EventContainers/SelectAllObjectMT.h
@@ -15,11 +15,12 @@ public:
 //	typedef OBJECT OBJECT;
     typedef SelectAllObjectMT<DCC,OBJECT>  MyType;
     typedef typename DC::const_iterator Object_const_iterator;
-    typedef typename DCC::Hash_Container::const_iterator Hash_iterator;
+    typedef typename DCC::const_iterator Cont_iterator;
+//    typedef typename DCC::Hash_Container::const_iterator Hash_iterator;
 
     class const_iterator
     {
-        Hash_iterator m_hash_itr;
+        Cont_iterator m_cont_itr;
         const SelectAllObjectMT<DCC,OBJECT>* m_Parent;
         Object_const_iterator m_digit_it;
         const DC* m_dc;  // cache DC
@@ -29,12 +30,9 @@ public:
 
 SKIPNEXT:
 
-            ++m_hash_itr;
-            if(m_hash_itr != m_Parent->m_hashes.cend()) {
-                m_dc = m_Parent->m_dcc->indexFindPtr(*m_hash_itr);
-#ifdef IdentifiableCacheBaseRemove
-                if(m_dc == nullptr) goto SKIPNEXT;//In case we implement remove
-#endif
+            ++m_cont_itr;
+            if(m_cont_itr != m_Parent->m_dcc->end()) {
+                m_dc = *m_cont_itr;
                 m_digit_it = m_dc->begin();
                 if(m_digit_it == m_dc->end()) goto SKIPNEXT;
             } else {
@@ -47,16 +45,16 @@ SKIPNEXT:
 
         const_iterator()
             :
-            m_hash_itr(),
+            m_cont_itr(),
             m_Parent(nullptr),
             m_digit_it(),
             m_dc(nullptr)
         {}
 
-        const_iterator(const Hash_iterator &itr, const SelectAllObjectMT<DCC,OBJECT>* parent,
+        const_iterator(const Cont_iterator &itr, const SelectAllObjectMT<DCC,OBJECT>* parent,
                        Object_const_iterator digitit, const DC* dc )
             :
-            m_hash_itr(itr),
+            m_cont_itr(itr),
             m_Parent(parent),
             m_digit_it(digitit),
             m_dc(dc)
@@ -94,7 +92,7 @@ SKIPNEXT:
 
         bool operator != ( const const_iterator it ) const
         {
-            if( it.m_hash_itr != m_hash_itr || it.m_digit_it != m_digit_it )
+            if( it.m_cont_itr != m_cont_itr || it.m_digit_it != m_digit_it )
                 return true;
 
             return false;
@@ -102,25 +100,25 @@ SKIPNEXT:
 
         bool operator == ( const const_iterator it ) const
         {
-            return( it.m_hash_itr == m_hash_itr && it.m_digit_it == m_digit_it );
+            return( it.m_cont_itr == m_cont_itr && it.m_digit_it == m_digit_it );
         }
 
 
 
     };
 
-    SelectAllObjectMT(const DCC* dcc) : m_dcc(dcc), m_hashes(dcc->GetAllCurrentHashes())
+    SelectAllObjectMT(const DCC* dcc) : m_dcc(dcc)
     { }
 
     SelectAllObjectMT( ) = delete;
 
     const_iterator begin() {
-        Hash_iterator b = m_hashes.cbegin();
+        auto b = m_dcc->begin();
 NEXT:
         const DC* dc = nullptr;
         Object_const_iterator digit_it;
-        if(b!= m_hashes.cend()) {
-            dc = m_dcc->indexFindPtr(*b);
+        if(b!= m_dcc->end()) {
+            dc = *b;
             digit_it = dc->begin();
             if(digit_it == dc->end()){ 
                ++b;
@@ -131,7 +129,7 @@ NEXT:
     }
 
     const_iterator end() {
-        Hash_iterator b = m_hashes.cend();
+        auto b = m_dcc->end();
         const DC* dc = nullptr;
         Object_const_iterator digit_it;
         return const_iterator(b, this, digit_it, dc);
@@ -149,7 +147,6 @@ NEXT:
 private:
     // pointer to the container it is processing.
     const DCC* m_dcc;
-    const typename DCC::Hash_Container m_hashes;
 };
 
 
diff --git a/Event/EventContainers/EventContainers/deleter.h b/Event/EventContainers/EventContainers/deleter.h
new file mode 100644
index 00000000000..6d43c66ed56
--- /dev/null
+++ b/Event/EventContainers/EventContainers/deleter.h
@@ -0,0 +1,37 @@
+#ifndef EVENTCONTAINERS_DELETER_H
+//#define EVENTCONTAINERS_DELETER_H
+
+#if 0
+  struct deleter
+  {
+    void operator() (const void* p);
+  };
+#endif
+
+
+  typedef void deleter_f (const void* p);
+
+  class void_unique_ptr
+    : public std::unique_ptr<const void, deleter_f*>
+  {
+  public:
+    using std::unique_ptr<const void, deleter_f*>::unique_ptr;
+
+    template <class T>
+    struct Deleter
+    {
+      static void deleter (const void* p)
+      {
+        delete reinterpret_cast<const T*>(p);
+      }
+    };
+
+    template <class T>
+    void_unique_ptr(std::unique_ptr<T> p)
+      : std::unique_ptr<const void, deleter_f*> (p.release(),
+                                                 Deleter<T>::deleter)
+    {
+    }
+  };
+  
+#endif
diff --git a/Event/EventContainers/share/IDBenchTest.ref b/Event/EventContainers/share/IDBenchTest.ref
new file mode 100644
index 00000000000..bc19b99b74c
--- /dev/null
+++ b/Event/EventContainers/share/IDBenchTest.ref
@@ -0,0 +1 @@
+Test Successful
diff --git a/Event/EventContainers/share/IDStressTest.ref b/Event/EventContainers/share/IDStressTest.ref
index ddc13f633d9..252a5f9afba 100644
--- a/Event/EventContainers/share/IDStressTest.ref
+++ b/Event/EventContainers/share/IDStressTest.ref
@@ -14,10 +14,11 @@ range 450 to 1450
 30/50
 40/50
 NoLock
-deleted 163825
-countHit 256975
+deleted 144501
+countHit 276299
 fills 500000
 reads 492300
+itreads 492300
 aborted 7700
 0/50
 10/50
@@ -29,8 +30,9 @@ deleted 0
 countHit 427500
 fills 500000
 reads 492300
+itreads 492300
 aborted 7700
 Total elements 500000
 MyDigits left undeleted 0
-no lock time 2.60611
-lock time 1.12183
+no lock time 3.7096
+lock time 0.983746
diff --git a/Event/EventContainers/src/IDC_WriteHandleBase.cxx b/Event/EventContainers/src/IDC_WriteHandleBase.cxx
index f555cbc4669..83710778c12 100644
--- a/Event/EventContainers/src/IDC_WriteHandleBase.cxx
+++ b/Event/EventContainers/src/IDC_WriteHandleBase.cxx
@@ -23,7 +23,6 @@ void IDC_WriteHandleBase::ReleaseLock(){
 
 //Running code
    assert(m_atomic->load() != ABORTstate);
-   assert(m_mut->counter >= 0);
    lockguard lk(m_mut->mutex);
    m_atomic->compare_exchange_strong(waitstate, ABORTstate);
    m_mut->condition.notify_all();
diff --git a/Event/EventContainers/src/IdentifiableCacheBase.cxx b/Event/EventContainers/src/IdentifiableCacheBase.cxx
index 3298c38115f..9d1f1130dac 100644
--- a/Event/EventContainers/src/IdentifiableCacheBase.cxx
+++ b/Event/EventContainers/src/IdentifiableCacheBase.cxx
@@ -58,10 +58,6 @@ int IdentifiableCacheBase::tryLock(IdentifierHash hash, IDC_WriteHandleBase &loc
 
    if(ptr1 == INVALID){
       //Second call while not finished
-#ifndef NDEBUG
-      size_t slot = hash % m_NMutexes;
-      m_HoldingMutexes[slot].counter++;
-#endif
       wait.emplace_back(hash);
       return 1;
    }
@@ -84,12 +80,6 @@ void IdentifiableCacheBase::clear (deleter_f* deleter)
   }else{
     for (size_t i=0; i<s ;i++) m_vec[i].store(nullptr, std::memory_order_relaxed);//Need to clear incase of aborts
   }
-#ifndef NDEBUG
-  for(size_t i =0; i<m_NMutexes; i++){
-     if(m_HoldingMutexes[i].counter!=0) std::cout << " counter is " << m_HoldingMutexes[i].counter << std::endl;
-     assert(m_HoldingMutexes[i].counter==0);
-  }
-#endif
 }
 
 
@@ -103,12 +93,6 @@ void IdentifiableCacheBase::cleanUp (deleter_f* deleter)
       if(p && p < ABORTED) deleter (p);
     }
   }
-#ifndef NDEBUG
-  for(size_t i =0; i<m_NMutexes; i++){
-     if(m_HoldingMutexes[i].counter!=0) std::cout << "IdentifiableCacheBase counter is " << m_HoldingMutexes[i].counter << std::endl;
-     assert(m_HoldingMutexes[i].counter==0);
-  }
-#endif
 }
 
 int IdentifiableCacheBase::itemAborted (IdentifierHash hash){
@@ -146,13 +130,7 @@ const void* IdentifiableCacheBase::waitFor(IdentifierHash hash)
    }
    return item;
 }
-#ifndef NDEBUG
-void IdentifiableCacheBase::cancelWait(IdentifierHash hash){
-   assert(m_NMutexes > 0);
-   size_t slot = hash % m_NMutexes;
-   m_HoldingMutexes[slot].counter--;
-}
-#endif
+
 const void* IdentifiableCacheBase::findWait (IdentifierHash hash)
 {
   if (ATH_UNLIKELY(hash >= m_vec.size())) return nullptr;
@@ -248,56 +226,56 @@ std::vector<IdentifierHash> IdentifiableCacheBase::ids()
 }
 
 
-bool IdentifiableCacheBase::add (IdentifierHash hash, const void* p) noexcept
+std::pair<bool, const void*> IdentifiableCacheBase::add (IdentifierHash hash, const void* p) noexcept
 {
-  if (ATH_UNLIKELY(hash >= m_vec.size())) return false;
-  if(p==nullptr) return false;
+  if (ATH_UNLIKELY(hash >= m_vec.size())) return std::make_pair(false, nullptr);
+  if(p==nullptr) return std::make_pair(false, nullptr);
   const void* nul=nullptr;
   if(m_vec[hash].compare_exchange_strong(nul, p)){
      m_currentHashes++;
-     return true;
+     return std::make_pair(true, p);
   }
   const void* invalid = INVALID;
   if(m_vec[hash].compare_exchange_strong(invalid, p)){
      m_currentHashes++;
-     return true;
+     return std::make_pair(true, p);
   }
-  return false;
+  return std::make_pair(false, invalid);
 }
 
 
-bool IdentifiableCacheBase::addLock (IdentifierHash hash, const void* p) noexcept
+std::pair<bool, const void*> IdentifiableCacheBase::addLock (IdentifierHash hash, const void* p) noexcept
 { //Same as method above except we check for invalid state first,
   // more optimal for calling using writehandle lock method
   assert(hash < m_vec.size());
-  if(p==nullptr) return false;
+  if(p==nullptr) return std::make_pair(false, nullptr);
   const void* invalid = INVALID;
   if(m_vec[hash].compare_exchange_strong(invalid, p)){
      m_currentHashes++;
-     return true;
+     return std::make_pair(true, p);
   }
   const void* nul=nullptr;
   if(m_vec[hash].compare_exchange_strong(nul, p)){
      m_currentHashes++;
-     return true;
+     return std::make_pair(true, p);
   }
-  return false;
+  return std::make_pair(false, nul);
 }
 
-bool IdentifiableCacheBase::addLock (IdentifierHash hash,
+std::pair<bool, const void*> IdentifiableCacheBase::addLock (IdentifierHash hash,
                                  void_unique_ptr p) noexcept
 {
-  bool b = addLock(hash, p.get());
-  if(b) p.release();
+  std::pair<bool, const void*> b = addLock(hash, p.get());
+  if(b.first) p.release();
   return b;
 }
 
 
-bool IdentifiableCacheBase::add (IdentifierHash hash,
+std::pair<bool, const void*> IdentifiableCacheBase::add (IdentifierHash hash,
                                  void_unique_ptr p) noexcept
 {
-  bool b = add(hash, p.get());
-  if(b) p.release();
+  std::pair<bool, const void*> b = add(hash, p.get());
+  if(b.first) p.release();
   return b;
 }
 
diff --git a/Event/EventContainers/src/IdentifiableContainerBase.cxx b/Event/EventContainers/src/IdentifiableContainerBase.cxx
index da1eb7af930..b01279096f3 100644
--- a/Event/EventContainers/src/IdentifiableContainerBase.cxx
+++ b/Event/EventContainers/src/IdentifiableContainerBase.cxx
@@ -5,106 +5,24 @@
 #include <algorithm>
 #include "EventContainers/IDC_WriteHandleBase.h"
 #include "CxxUtils/AthUnlikelyMacros.h"
+#include "EventContainers/InternalOnline.h"
+#include "EventContainers/InternalOffline.h"
 
-  IdentifiableContainerBase::IdentifiableContainerBase(EventContainers::IdentifiableCacheBase *cache, bool online)
-  {
-    m_cacheLink = cache;
-    m_OnlineMode = online;
-    m_mask.assign(cache->fullSize(), !online);
-    m_waitNeeded.store(false, std::memory_order_relaxed);
-  }
-
-  IdentifiableContainerBase::Hash_Container::const_iterator IdentifiableContainerBase::findHash(IdentifiableContainerBase::Hash_Container* container, IdentifierHash hash){
-    return std::find(container->begin(), container->end(), hash);
-  }
-
-  IdentifiableContainerBase::~IdentifiableContainerBase(){
-#ifndef NDEBUG
-    //Deregister unused interest
-    while(!m_waitlist.empty()){
-       IdentifierHash hash = m_waitlist.back();
-       m_cacheLink->cancelWait(hash);
-       m_waitlist.pop_back();
-    }
-#endif
-  }
-
-  void IdentifiableContainerBase::Wait() const{
-    //lockguard to protect m_waitlist from multiple wait calls
-    typedef std::lock_guard<decltype(m_waitMutex)> lockguard;
-    lockguard lock(m_waitMutex);
 
-    const void* ABORTstate = reinterpret_cast<const void*>(IdentifiableCacheBase::ABORTEDflag);
-    while(!m_waitlist.empty()){
-       IdentifierHash hash = m_waitlist.back();
-       const void* ptr = m_cacheLink->waitFor(hash);
-#ifndef NDEBUG
-       m_cacheLink->cancelWait(hash);
-#endif
-       if(ptr == ABORTstate) m_mask[hash] = false;//reset flag
-       m_waitlist.pop_back();
-       
-    }
-    m_waitNeeded.store(false);
-  }
+using namespace EventContainers;
 
-  bool IdentifiableContainerBase::tryAddFromCache(IdentifierHash hashId, EventContainers::IDC_WriteHandleBase &lock)
+  IdentifiableContainerBase::IdentifiableContainerBase(EventContainers::IdentifiableCacheBase *cache)
   {
-    if(!m_OnlineMode){
-       return tryAddFromCache(hashId);//No point calling expensive lock method
-    }
-    int flag = m_cacheLink->tryLock(hashId, lock, m_waitlist);
-    //Relaxed since this should not be running in threaded situation.
-    if(!m_waitlist.empty()) m_waitNeeded.store(true, std::memory_order_relaxed);
-    if(flag > 0) {
-      m_mask[hashId] = flag!=3;
-      return true;
-    }
-    return false;
+  	m_link = std::make_unique<EventContainers::InternalOnline>(cache);
+    m_OnlineMode = true;
   }
 
-  bool IdentifiableContainerBase::tryAddFromCache(IdentifierHash hashId)
-  {
-    auto ptr = m_cacheLink->find(hashId);
-    if(ptr==nullptr){
-        return false; 
-    }
-    m_mask[hashId] = true;
-    return true; 
+  IdentifiableContainerBase::IdentifiableContainerBase(size_t max){
+    m_OnlineMode = false;
+    m_link = std::make_unique<EventContainers::InternalOffline>(max);
   }
 
-  std::vector<IdentifierHash> IdentifiableContainerBase::GetAllCurrentHashes() const {
-     if(not m_OnlineMode) return m_cacheLink->ids();
-     else{
-         if(m_waitNeeded) Wait();
-         std::vector<IdentifierHash> ids;
-         for(size_t i =0 ; i < m_mask.size(); ++i) if(m_mask[i]) ids.emplace_back(i);
-         return ids;
-     }
+  void  IdentifiableContainerBase::cleanup(deleter_f* deleter){
+    if(m_OnlineMode) throw std::runtime_error("Not implemented in online mode");
+    static_cast<EventContainers::InternalOffline*>(m_link.get())->cleanUp(deleter);
   }
-
-  size_t IdentifiableContainerBase::numberOfCollections() const{
-     if(!m_OnlineMode) return m_cacheLink->numberOfHashes();
-     if(m_waitNeeded) Wait(); 
-     size_t count =std::accumulate(m_mask.begin(), m_mask.end(), 0);
-     return count;
-  }
-
-
-  void IdentifiableContainerBase::ResetMask(){
-     m_mask.assign(m_cacheLink->fullSize(), false);
-  }
-
-  StatusCode IdentifiableContainerBase::fetchOrCreate(IdentifierHash hashId){
-    if(ATH_UNLIKELY(!m_cacheLink->IMakerPresent())) return StatusCode::FAILURE;
-    auto ptr = m_cacheLink->get(hashId);
-    m_mask[hashId] = ptr !=nullptr;
-    return StatusCode::SUCCESS;
-  }
-
-  StatusCode IdentifiableContainerBase::fetchOrCreate(const std::vector<IdentifierHash> &hashIds){
-    if(ATH_UNLIKELY(!m_cacheLink->IMakerPresent())) return StatusCode::FAILURE;
-    m_cacheLink->createSet(hashIds, m_mask);
-    return StatusCode::SUCCESS;
-  }
-
diff --git a/Event/EventContainers/src/InternalOffline.cxx b/Event/EventContainers/src/InternalOffline.cxx
new file mode 100644
index 00000000000..2eb5bb12e35
--- /dev/null
+++ b/Event/EventContainers/src/InternalOffline.cxx
@@ -0,0 +1,110 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "EventContainers/InternalOffline.h"
+#include <algorithm>
+#include "EventContainers/IDC_WriteHandleBase.h"
+
+using namespace EventContainers;
+typedef I_InternalIDC::InternalConstItr InternalConstItr;
+InternalOffline::InternalOffline(size_t max) : m_maximumSize(max) {}
+
+
+bool InternalOffline::tryAddFromCache(IdentifierHash hash, EventContainers::IDC_WriteHandleBase&) {
+    return indexFind(hash) != m_map.cend();//No Cache in offline mode
+}
+
+bool InternalOffline::tryAddFromCache(IdentifierHash hash)
+{
+    return indexFind(hash) != m_map.cend();//No Cache in offline mode
+}
+
+void InternalOffline::Wait() const {
+    //No need to wait in offline, deliberately empty method
+}
+
+std::vector<IdentifierHash> InternalOffline::GetAllCurrentHashes() const {
+    std::vector<IdentifierHash> ids;
+    ids.reserve(m_map.size());
+    for(auto &x : m_map) {
+        ids.emplace_back(x.first);
+    }
+    return ids;
+}
+
+InternalConstItr
+ InternalOffline::cend() const {
+    return m_map.cend();
+}
+
+const std::vector < I_InternalIDC::hashPair >& InternalOffline::GetAllHashPtrPair() const{ return m_map; }
+
+InternalConstItr
+ InternalOffline::cbegin() const {
+    return m_map.cbegin();
+}
+
+InternalConstItr InternalOffline::indexFind( IdentifierHash hashId ) const{
+   auto itr = std::lower_bound( m_map.cbegin(), m_map.cend(), hashId.value(), [](const hashPair &lhs,  IdentifierHash::value_type rhs) -> bool { return lhs.first < rhs; } );
+   if(itr!= m_map.cend() && itr->first==hashId) return itr;
+   return m_map.cend();
+//  return std::find_if(m_map.begin(), m_map.end(), [hashId](const hashPair &lhs) -> bool { return lhs.first == hashId; });
+}
+
+size_t InternalOffline::numberOfCollections() const {
+    return m_map.size();
+}
+
+void InternalOffline::cleanUp(deleter_f* deleter) noexcept {
+    for(const auto& x : m_map)  deleter(x.second);
+    m_map.clear();
+}
+
+bool InternalOffline::insert(IdentifierHash hashId, const void* ptr) {
+    if(m_map.empty() || m_map.back().first < hashId){
+        m_map.emplace_back(hashId, ptr);
+        return true;
+    }
+    auto itr = std::lower_bound( m_map.begin(), m_map.end(), hashId.value(), [](const hashPair &lhs,  IdentifierHash::value_type rhs) -> bool { return lhs.first < rhs; } );
+    if(itr == std::end(m_map) || itr->first != hashId)
+    {
+        m_map.emplace(itr, hashId, ptr);
+        return true;
+    }
+    return false;
+}
+
+const void* InternalOffline::FindIndexPtr(IdentifierHash hashId) const noexcept{
+    auto itr = indexFind(hashId);
+    if(itr != m_map.end()) return itr->second;
+    return nullptr;
+}
+
+StatusCode InternalOffline::addLock(IdentifierHash hashId, const void* ptr) {
+    bool added = insert(hashId, ptr);
+    if(!added) {
+#ifndef NDEBUG
+        std::cout << "IDC WARNING Deletion shouldn't occur in addLock paradigm" << std::endl;
+#endif
+        return StatusCode::FAILURE;
+    }
+    return StatusCode::SUCCESS;
+}
+
+void* InternalOffline::removeCollection( IdentifierHash hashId ) {
+   auto itr = std::lower_bound( m_map.begin(), m_map.end(), hashId.value(), [](hashPair &lhs,  IdentifierHash::value_type rhs) -> bool { return lhs.first < rhs; } );
+   if(itr== m_map.end() || itr->first!=hashId) return nullptr;
+   void* ptr = const_cast< void* > (itr->second);
+   m_map.erase(itr);
+   return ptr;
+}
+
+StatusCode InternalOffline::fetchOrCreate(IdentifierHash) {
+    throw std::runtime_error("Not implemented in offline mode");
+}
+StatusCode InternalOffline::fetchOrCreate(const std::vector<IdentifierHash>&)
+{
+    throw std::runtime_error("Not implemented in offline mode");
+}
+
diff --git a/Event/EventContainers/src/InternalOnline.cxx b/Event/EventContainers/src/InternalOnline.cxx
new file mode 100644
index 00000000000..7c721d1f003
--- /dev/null
+++ b/Event/EventContainers/src/InternalOnline.cxx
@@ -0,0 +1,154 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "EventContainers/InternalOnline.h"
+#include <algorithm>
+#include "EventContainers/IDC_WriteHandleBase.h"
+#include "CxxUtils/AthUnlikelyMacros.h"
+#include "EventContainers/IdentifiableCacheBase.h"
+
+
+using namespace EventContainers;
+typedef I_InternalIDC::InternalConstItr InternalConstItr;
+
+
+InternalOnline::InternalOnline(EventContainers::IdentifiableCacheBase *cache) : m_cacheLink(cache),
+    m_mask(cache->fullSize(), false), m_waitNeeded(false) {}
+
+const std::vector < I_InternalIDC::hashPair >& InternalOnline::GetAllHashPtrPair() const{
+  if(m_waitNeeded) Wait();
+  return m_map; 
+}
+
+
+InternalConstItr
+ InternalOnline::cend() const {
+    if(m_waitNeeded) Wait();
+    return m_map.cend();
+}
+
+InternalConstItr
+ InternalOnline::cbegin() const {
+    if(m_waitNeeded) Wait();
+    return m_map.cbegin();
+}
+
+InternalConstItr InternalOnline::indexFind( IdentifierHash hashId ) const{
+  if(m_waitNeeded) Wait();
+   auto itr = std::lower_bound( m_map.begin(), m_map.end(), hashId.value(), [](hashPair &lhs,  IdentifierHash::value_type rhs) -> bool { return lhs.first < rhs; } );
+   if(itr!= m_map.end() && itr->first==hashId) return itr;
+   return m_map.end();
+}
+
+void InternalOnline::Wait() const {
+    //lockguard to protect m_waitlist from multiple wait calls
+    std::lock_guard lock (m_waitMutex);
+    if(m_waitNeeded == false) return;
+    using namespace EventContainers;
+    const void* ABORTstate = reinterpret_cast<const void*>(IdentifiableCacheBase::ABORTEDflag);
+    while(!m_waitlist.empty()) {
+        IdentifierHash hash = m_waitlist.back();
+        const void* ptr = m_cacheLink->waitFor(hash);
+        if(ptr == ABORTstate) {
+          m_mask[hash] = false;
+        }
+        m_waitlist.pop_back();
+    }
+    m_map.clear();
+    for(size_t i =0;i<m_mask.size();i++){
+        if(m_mask[i]) m_map.emplace_back(i, m_cacheLink->m_vec[i].load());
+    }
+    m_waitNeeded.store(false);
+}
+
+bool InternalOnline::tryAddFromCache(IdentifierHash hashId, EventContainers::IDC_WriteHandleBase &lock) {
+    int flag = m_cacheLink->tryLock(hashId, lock, m_waitlist);
+    //Relaxed since this should not be running in threaded situation.
+    if(!m_waitlist.empty()) m_waitNeeded.store(true, std::memory_order_relaxed);
+    if(flag > 0) {
+        if(flag!=3){
+           m_mask[hashId] = true;
+           m_waitNeeded.store(true, std::memory_order_relaxed);
+        }
+        return true;
+    }
+    return false;
+}
+
+bool InternalOnline::tryAddFromCache(IdentifierHash hashId)
+{
+    auto ptr = m_cacheLink->find(hashId);
+    if(ptr==nullptr) {
+        return false;
+    }
+    m_mask[hashId] = true;
+    m_waitNeeded.store(true, std::memory_order_relaxed);
+    return true;
+}
+
+std::vector<IdentifierHash> InternalOnline::GetAllCurrentHashes() const {
+    if(m_waitNeeded) Wait();
+    std::vector<IdentifierHash> ids;
+    ids.reserve(m_map.size());
+    for(auto &x : m_map) {
+        ids.emplace_back(x.first);
+    }
+    return ids;
+}
+
+size_t InternalOnline::numberOfCollections() const {
+    if(m_waitNeeded) Wait();
+    return m_map.size();
+}
+
+void InternalOnline::ResetMask() {
+    if(m_waitNeeded) Wait();
+    m_mask.assign(m_cacheLink->fullSize(), false);
+    m_map.clear();
+    m_waitNeeded.store(true, std::memory_order_relaxed);
+}
+
+StatusCode InternalOnline::fetchOrCreate(IdentifierHash hashId) {
+    if(ATH_UNLIKELY(!m_cacheLink->IMakerPresent())) return StatusCode::FAILURE;
+    auto ptr = m_cacheLink->get(hashId);
+    if(ptr) { m_mask[hashId] =true; m_waitNeeded.store(true, std::memory_order_relaxed); }
+    return StatusCode::SUCCESS;
+}
+
+StatusCode InternalOnline::fetchOrCreate(const std::vector<IdentifierHash> &/*hashIds*/) {
+    throw std::runtime_error("Not implemented");
+//    if(ATH_UNLIKELY(!m_cacheLink->IMakerPresent())) return StatusCode::FAILURE;
+//    m_cacheLink->createSet(hashIds, m_mask);
+//    return StatusCode::SUCCESS;
+}
+
+
+bool InternalOnline::insert(IdentifierHash hashId, const void* ptr) {
+    std::pair<bool, const void*> cacheinserted = m_cacheLink->add(hashId, ptr);
+    m_mask[hashId] = true; //it wasn't added it is already present therefore mask could be true
+    m_waitNeeded.store(true, std::memory_order_relaxed);
+    return ptr == cacheinserted.second;
+}
+
+const void* InternalOnline::FindIndexPtr(IdentifierHash hashId) const noexcept {
+    if(hashId < m_mask.size() and m_mask[hashId]) return m_cacheLink->findWait(hashId);
+    return nullptr;
+}
+
+StatusCode InternalOnline::addLock(IdentifierHash hashId, const void* ptr) {
+    if(ATH_UNLIKELY(hashId >= m_mask.size())) return StatusCode::FAILURE;
+    [[maybe_unused]] std::pair<bool, const void*> added = m_cacheLink->addLock(hashId, ptr);
+#ifndef NDEBUG
+    if(!added.first) {
+        std::cout << "IDC WARNING Deletion shouldn't occur in addLock paradigm" << std::endl;
+    }
+#endif
+    m_mask[hashId] = true; //it wasn't added it is already present therefore mask could be true
+    m_waitNeeded.store(true, std::memory_order_relaxed);
+    return StatusCode::SUCCESS;
+}
+
+void* InternalOnline::removeCollection( IdentifierHash  ) {
+    throw std::runtime_error("Do not remove things from an online IDC");
+}
diff --git a/Event/EventContainers/test/IDC_Benchmark.cxx b/Event/EventContainers/test/IDC_Benchmark.cxx
new file mode 100644
index 00000000000..5c577317ff2
--- /dev/null
+++ b/Event/EventContainers/test/IDC_Benchmark.cxx
@@ -0,0 +1,71 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+#include "EventContainers/IdentifiableContainerMT.h"
+#include "EventContainers/IdentifiableCache.h"
+#include <chrono>
+
+using namespace EventContainers;
+
+
+template<typename T>
+void timedelete(std::string name, T* ptr){
+   auto start1 = std::chrono::steady_clock::now();
+   delete ptr;
+   auto end1 = std::chrono::steady_clock::now();
+   std::chrono::duration<double> time = end1-start1;
+   std::cout << name  << " delete time " << time.count() << std::endl;
+}
+
+void accessTime(std::string name, IdentifiableContainerMT<long unsigned int>& container){
+
+   auto start3 = std::chrono::steady_clock::now();
+   auto offlinecnt = container.GetAllCurrentHashes();
+   for(auto hash : offlinecnt) if(hash !=  *container.indexFindPtr(hash) ) std::abort();
+   auto end3 = std::chrono::steady_clock::now();
+   std::chrono::duration<double> offlinerandom = end3-start3;
+   std::cout << name << " random time " << offlinerandom.count() << std::endl;
+
+   auto start4 = std::chrono::steady_clock::now();
+   size_t i=0;
+   for(auto hash : container) {if(*hash != offlinecnt[i].value() ) std::abort(); i++; }
+   auto end4 = std::chrono::steady_clock::now();
+   std::chrono::duration<double> offlineit = end4-start4;
+   std::cout << name << " iteration time " << offlineit.count() << std::endl;
+
+   auto start5 = std::chrono::steady_clock::now();
+   const auto& directaccess = container.GetAllHashPtrPair();
+   for(const auto &[hashId, ptr] : directaccess) {if(hashId != *ptr ) std::abort(); i++; }
+   auto end5 = std::chrono::steady_clock::now();
+   std::chrono::duration<double> offlinedir = end5-start5;
+   std::cout << name << " direct time " << offlinedir.count() << std::endl;
+}
+
+int main(){
+   
+   auto start1 = std::chrono::steady_clock::now();
+   auto offline = new IdentifiableContainerMT<long unsigned int>(50000);
+   for(size_t i =3;i<50000;i+=3){
+      offline->addCollection(new long unsigned int(i) ,i).ignore();
+   }
+   auto end1 = std::chrono::steady_clock::now();
+   std::chrono::duration<double> offlinefill = end1-start1;
+   std::cout << "offline fill time " << offlinefill.count() << std::endl;
+   auto start2 = std::chrono::steady_clock::now();
+   auto cache  = new IdentifiableCache<long unsigned int>(50000, nullptr);
+   auto online = new IdentifiableContainerMT<long unsigned int>(cache);
+
+   for(size_t i =3;i<50000;i+=3){
+      online->addCollection(new long unsigned int(i) , i).ignore();
+   }
+   auto end2 = std::chrono::steady_clock::now();
+   std::chrono::duration<double> onlinefill = end2-start2;
+   std::cout << "online fill time " << onlinefill.count() << std::endl;
+   accessTime("online ", *online);
+   accessTime("offline ", *offline);
+   timedelete("onlineCont ", online);
+   timedelete("onlineCache ", cache);
+   timedelete("offline ", offline);
+   std::cout << "Test Successful" << std::endl;
+   return 0;
+}
diff --git a/Event/EventContainers/test/IDC_Realistic_Test.cxx b/Event/EventContainers/test/IDC_Realistic_Test.cxx
index f84599a82e8..37497319ac0 100644
--- a/Event/EventContainers/test/IDC_Realistic_Test.cxx
+++ b/Event/EventContainers/test/IDC_Realistic_Test.cxx
@@ -134,12 +134,14 @@ struct counters {
     int cachehit=0;
     int fills =0;
     int reads =0;
+    int itreads =0;
     int aborted =0;
     void Add(const counters &rh) {
         deletedcount+= rh.deletedcount;
         cachehit+= rh.cachehit;
         fills+= rh.fills;
         reads+= rh.reads;
+        itreads+= rh.itreads;
         aborted += rh.aborted;
     }
     void Print() const {
@@ -147,6 +149,7 @@ struct counters {
         std::cout << "countHit " << cachehit << '\n';
         std::cout << "fills " << fills << '\n';
         std::cout << "reads " << reads << '\n';
+        std::cout << "itreads " << itreads << '\n';
         std::cout << "aborted " << aborted << '\n';
     }
     counters() {
@@ -154,6 +157,7 @@ struct counters {
         cachehit=0;
         fills =0;
         reads =0;
+        itreads=0;
         aborted=0;
     }
 };
@@ -176,10 +180,16 @@ public:
 
         int wrong = 0;
         auto hashes = container.GetAllCurrentHashes();
+        auto countall = container.numberOfCollections();
+        if(hashes.size() != countall){
+            std::cout << "Counts don't match" << std::endl;
+            std::abort();
+        }
         if(hashes.size()!=(size_t) 1000-c.aborted) {
             std::cout << "Error container is " << hashes.size() << " not " << 1000-c.aborted << std::endl;
             std::abort();
         }
+        //Check random access method
         for(const auto x : hashes) {
             auto p = container.indexFindPtr(x);
             int j =0;
@@ -192,6 +202,36 @@ public:
             }
             c.reads++;
         }
+        //check iterator method
+        int orig=0;
+        for(auto p : container){
+            int j =0;
+            for(auto q : *p) {
+                if(q->val() != (initialdata[hashes[orig]]->at(j++))->val()) wrong++;
+            }
+            if(j!=ndigits) {
+                std::cout << "n digits wrong"<<std::endl;
+                std::abort();
+            }
+            c.itreads++;
+            orig++;
+        }
+        int orig2=0;
+        const auto& directaccess = container.GetAllHashPtrPair();
+        for(const auto &[hashId, ptr] : directaccess){
+            int j =0;
+            if(hashes[orig2] != hashId){
+                std::cout << "directaccess broke " << std::endl;
+                std::abort();
+            }
+            for(auto q : *ptr) {
+                if(q->val() != (initialdata[hashes[orig2]]->at(j++))->val()) {
+                    std::cout << "directaccess broke " << std::endl;
+                    std::abort();
+                }
+            }
+            orig2++;
+        }
         if(wrong > 0) {
             std::cout << "Thread " << threads << " found wrong data " << wrong << std::endl;
             std::abort();
@@ -361,7 +401,7 @@ int main() {
         }
         std::cout << "NoLock\n";
         c.Print();
-        if(c.fills!=c.reads+c.aborted) {
+        if(c.fills!=c.reads+c.aborted || c.fills!=c.itreads+c.aborted ) {
             std::cout << "Fills do not equal reads " << std::endl;
             std::abort();
         }
@@ -378,7 +418,7 @@ int main() {
         }
         std::cout << "Lock\n";
         c.Print();
-        if(c.fills!=c.reads+c.aborted) {
+        if(c.fills!=c.reads+c.aborted || c.fills!=c.itreads+c.aborted ) {
             std::cout << "Fills do not equal reads " << std::endl;
             std::abort();
         }
diff --git a/Event/EventContainers/test/IDMT_ContainerTest.cxx b/Event/EventContainers/test/IDMT_ContainerTest.cxx
index df8ec1d3517..17207fdb4df 100644
--- a/Event/EventContainers/test/IDMT_ContainerTest.cxx
+++ b/Event/EventContainers/test/IDMT_ContainerTest.cxx
@@ -5,7 +5,7 @@
 // This is a test cxx file for IdentifiableContainerMT. 
 //  
 #include "EventContainers/IdentifiableContainerMT.h" 
-#include "EventContainers/SelectAllObjectMT.h"
+#include "EventContainers/SelectAllObject.h"
 #include "EventContainers/IdentifiableContTemp.h"
 #include "ID_ContainerTest.h" 
 #include "GaudiKernel/System.h" 
@@ -154,7 +154,7 @@ return 0;}
 
 int ID_ContainerTest::execute(){
 
-    typedef SelectAllObjectMT<MyCollectionContainer,MyDigit> SELECTOR ;
+    typedef SelectAllObject<MyCollectionContainer,MyDigit> SELECTOR ;
     typedef SELECTOR::const_iterator digit_const_iterator; 
 //    typedef MyCollectionContainer::const_iterator collection_iterator;
     
@@ -604,14 +604,49 @@ int ID_ContainerTest::execute(){
     }
     {
     MyCollectionContainer::IDC_WriteHandle lock;
-    lock = containerOnline->getWriteHandle(IdentifierHash(50));
-    lock = containerOnline->getWriteHandle(IdentifierHash(50));//Try to break the locks
-    lock = containerOnline->getWriteHandle(IdentifierHash(60));
-    lock = containerOnline->getWriteHandle(IdentifierHash(70));
+    MyCollectionContainer::IDC_WriteHandle lock2 = containerOnline->getWriteHandle(IdentifierHash(50));
+    MyCollectionContainer::IDC_WriteHandle::Swap(lock, lock2);
+    //lock = containerOnline->getWriteHandle(IdentifierHash(50));//Try to break the locks
+    //lock = containerOnline->getWriteHandle(IdentifierHash(60));
+    //lock = containerOnline->getWriteHandle(IdentifierHash(70));
     }
 
     delete containerOnline;
     delete cache;
+
+
+    auto containerordertest = new MyCollectionContainer(500);
+    containerordertest->addCollection(nullptr, 4).ignore();
+    containerordertest->addCollection(nullptr, 3).ignore();
+    containerordertest->addCollection(nullptr, 2).ignore();
+    containerordertest->addCollection(nullptr, 1).ignore();
+    containerordertest->addCollection(nullptr, 5).ignore();
+    containerordertest->addCollection(nullptr, 4).ignore(); //Deliberate duplicate
+    containerordertest->addCollection(nullptr, 7).ignore();
+
+    auto hashes  = containerordertest->GetAllCurrentHashes();
+    size_t last =0;
+    for(auto i : hashes){
+        if(last >= i) {
+            std::cout << "Ordering error" <<std::endl;
+            std::abort();
+        }
+        last =i;
+    }
+    last =0;
+    for(auto [hash,ptr] : containerordertest->GetAllHashPtrPair() ){
+        if(last >= hash) {
+            std::cout << "Ordering error" <<std::endl;
+            std::abort();
+        }
+        last =hash;
+    }
+    if(containerordertest->numberOfCollections() != 6){
+        std::cout << "Duplicate got added " << std::endl;
+        std::abort();
+    }
+
+    delete containerordertest;
     std::cout << "MyDigits left undeleted " << MyDigit::s_total << std::endl;    
 }
     return 0;
-- 
GitLab