From d34468d3ece0372f36d9ca05bfca0fcda3b8878b Mon Sep 17 00:00:00 2001
From: Scott Snyder <scott.snyder@cern.ch>
Date: Wed, 22 May 2019 11:11:48 +0000
Subject: [PATCH] CxxUtils: Allow ConcurrentRangeMap::emplace to extend the
 last range.

Add an option to ConcurrentRangeMap::emplace to allow extending the
range of the last entry in the case of a duplicate.  We used to do this
from WriteCondHandle, but that was racy; do it here so we can do both
steps without releasing the lock.
---
 Control/AthenaKernel/AthenaKernel/CondCont.h  | 37 +++++++--
 .../AthenaKernel/AthenaKernel/CondCont.icc    |  7 +-
 Control/AthenaKernel/src/CondCont.cxx         | 41 ++++++++--
 Control/AthenaKernel/test/CondCont_test.cxx   | 30 ++++---
 .../CxxUtils/CxxUtils/ConcurrentRangeMap.h    | 70 ++++++++++++----
 .../CxxUtils/CxxUtils/ConcurrentRangeMap.icc  | 82 ++++++++++++++-----
 .../CxxUtils/test/ConcurrentRangeMap_test.cxx | 46 ++++++++---
 Control/StoreGate/StoreGate/WriteCondHandle.h | 11 ---
 8 files changed, 234 insertions(+), 90 deletions(-)

diff --git a/Control/AthenaKernel/AthenaKernel/CondCont.h b/Control/AthenaKernel/AthenaKernel/CondCont.h
index 06fd5dcb0e3..20fecab6d29 100644
--- a/Control/AthenaKernel/AthenaKernel/CondCont.h
+++ b/Control/AthenaKernel/AthenaKernel/CondCont.h
@@ -101,7 +101,7 @@ namespace Athena {
 
 /**
  * @brief Define extended status codes used by CondCont.
- *        We add DUPLICATE and OVERLAP.
+ *        We add DUPLICATE, OVERLAP, and EXTENDED.
  */
 enum class CondContStatusCode : StatusCode::code_t
 {
@@ -118,7 +118,16 @@ enum class CondContStatusCode : StatusCode::code_t
   // Attempt to insert an item in a CondCont with a range that partially
   // overlaps with an existing one.
   // This is classified as Success.
-  OVERLAP           = 11
+  OVERLAP           = 11,
+
+  // Attempt to insert an item in a CondCont where the new range is an extension
+  // of the last range.  That is, the start time of the new range matches
+  // that of the last range in the container, and the end time of the new range
+  // is larger than that of the last range in the container.  The end time
+  // of the last range has been extended to match the new range.
+  // The payload of the existing range is unchanged, and the new
+  // item has been deleted.
+  EXTENDED          = 12
 };
 STATUSCODE_ENUM_DECL (CondContStatusCode)
 
@@ -131,8 +140,8 @@ class CondContBase
 public:
   /**
    * @brief Status code category for ContCont.
-   *        This adds new codes DUPLICATE and OVERLAP, which are classified
-   *        as success.
+   *        This adds new codes DUPLICATE, OVERLAP, and EXTENDED,
+   *        which are classified as success.
    */
   class Category : public StatusCode::Category
   {
@@ -157,6 +166,11 @@ public:
     static bool isOverlap (code_t code);
     /// Helper to test whether a code is OVERLAP.
     static bool isOverlap (StatusCode code);
+
+    /// Helper to test whether a code is EXTENDED.
+    static bool isExtended (code_t code);
+    /// Helper to test whether a code is EXTENDED.
+    static bool isExtended (StatusCode code);
   };
 
 
@@ -269,6 +283,8 @@ public:
    * The container will take ownership of this object.
    *
    * Returns SUCCESS if the object was successfully inserted;
+   * EXTENDS if the last existing range in the container was extended
+   * to match the new range;
    * OVERLAP if the object was inserted but the range partially overlaps
    * with an existing one;
    * DUPLICATE if the object wasn't inserted because the range
@@ -440,16 +456,17 @@ public:
     // I don't think IOVDbSvc should do _that_, so we check for that here.
     bool overlap (const RangeKey& r1, const RangeKey& r2) const
     { return r1.m_stop > r2.m_stop; }
-    bool extendRange (RangeKey& r, const RangeKey& newRange) const
+    int extendRange (RangeKey& r, const RangeKey& newRange) const
     {
       if (r.m_start != newRange.m_start) {
-        return false;
+        return -1;
       }
       if (newRange.m_stop > r.m_stop) {
         r.m_stop = newRange.m_stop;
         r.m_range = newRange.m_range;
+        return 1;
       }
-      return true;
+      return 0;
     }
   };
 
@@ -496,6 +513,8 @@ protected:
    * @param ctx Event context for the current thread.
    *
    * Returns SUCCESS if the object was successfully inserted;
+   * EXTENDS if the last existing range in the container was extended
+   * to match the new range;
    * OVERLAP if the object was inserted but the range partially overlaps
    * with an existing one;
    * DUPLICATE if the object wasn't inserted because the range
@@ -670,6 +689,8 @@ public:
    * The container will take ownership of this object.
    *
    * Returns SUCCESS if the object was successfully inserted;
+   * EXTENDS if the last existing range in the container was extended
+   * to match the new range;
    * OVERLAP if the object was inserted but the range partially overlaps
    * with an existing one;
    * DUPLICATE if the object wasn't inserted because the range
@@ -873,6 +894,8 @@ public:
    * on the most-derived @c CondCont.
    *
    * Returns SUCCESS if the object was successfully inserted;
+   * EXTENDS if the last existing range in the container was extended
+   * to match the new range;
    * OVERLAP if the object was inserted but the range partially overlaps
    * with an existing one;
    * DUPLICATE if the object wasn't inserted because the range
diff --git a/Control/AthenaKernel/AthenaKernel/CondCont.icc b/Control/AthenaKernel/AthenaKernel/CondCont.icc
index 292038da230..8eaee9ac4d5 100644
--- a/Control/AthenaKernel/AthenaKernel/CondCont.icc
+++ b/Control/AthenaKernel/AthenaKernel/CondCont.icc
@@ -1,9 +1,6 @@
 /*
-  Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
 */
-/*
- */
-// $Id$
 /**
  * @file AthenaKernel/CondCont.icc
  * @author Vakho, Charles, Scott
@@ -234,6 +231,8 @@ CondCont<T>::~CondCont<T>()
  * on the most-derived @c CondCont.
  *
  * Returns SUCCESS if the object was successfully inserted;
+ * EXTENDS if the last existing range in the container was extended
+ * to match the new range;
  * OVERLAP if the object was inserted but the range partially overlaps
  * with an existing one;
  * DUPLICATE if the object wasn't inserted because the range
diff --git a/Control/AthenaKernel/src/CondCont.cxx b/Control/AthenaKernel/src/CondCont.cxx
index 05abcf361ab..a7981792c95 100644
--- a/Control/AthenaKernel/src/CondCont.cxx
+++ b/Control/AthenaKernel/src/CondCont.cxx
@@ -1,7 +1,6 @@
 /*
-  Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
 */
-// $Id$
 /**
  * @file AthenaKernel/src/CondCont.cpp
  * @author Vakho, Charles, Scott
@@ -42,6 +41,9 @@ std::string CondContBase::Category::message (code_t code) const
   else if (code == static_cast<code_t> (CondContStatusCode::OVERLAP)) {
     return "OVERLAP";
   }
+  else if (code == static_cast<code_t> (CondContStatusCode::EXTENDED)) {
+    return "EXTENDED";
+  }
   return StatusCode::Category::message (code);
 }
 
@@ -53,6 +55,7 @@ bool CondContBase::Category::isSuccess (code_t code) const
 {
   return code == static_cast<code_t>( CondContStatusCode::DUPLICATE ) ||
     code == static_cast<code_t>( CondContStatusCode::OVERLAP ) ||
+    code == static_cast<code_t>( CondContStatusCode::EXTENDED ) ||
     code == static_cast<code_t>( CondContStatusCode::SUCCESS );
 }
 
@@ -85,6 +88,20 @@ bool CondContBase::Category::isOverlap (StatusCode code)
 }
 
 
+/// Helper to test whether a code is EXTENDED.
+bool CondContBase::Category::isExtended (code_t code)
+{
+  return code == static_cast<code_t> (CondContStatusCode::EXTENDED);
+}
+
+
+/// Helper to test whether a code is EXTENDED.
+bool CondContBase::Category::isExtended (StatusCode code)
+{
+  return isExtended (code.getCode());
+}
+
+
 STATUSCODE_ENUM_IMPL (CondContStatusCode, CondContBase::Category)
 
 
@@ -211,6 +228,8 @@ CondContBase::CondContBase (Athena::IRCUSvc& rcusvc,
  * @param ctx Event context for the current thread.
  *
  * Returns SUCCESS if the object was successfully inserted;
+ * EXTENDS if the last existing range in the container was extended
+ * to match the new range;
  * OVERLAP if the object was inserted but the range partially overlaps
  * with an existing one;
  * DUPLICATE if the object wasn't inserted because the range
@@ -285,12 +304,18 @@ CondContBase::insertBase (const EventIDRange& r,
 
   CondContSet::EmplaceResult reslt =
     m_condSet.emplace( RangeKey(r, start_key, stop_key),
-                       std::move(t), ctx );
+                       std::move(t),
+                       m_keyType != KeyType::MIXED,
+                       ctx );
 
   if (reslt == CondContSet::EmplaceResult::DUPLICATE)
   {
     return CondContStatusCode::DUPLICATE;
   }
+  else if (reslt == CondContSet::EmplaceResult::EXTENDED)
+  {
+    return CondContStatusCode::EXTENDED;
+  }
   else if (reslt == CondContSet::EmplaceResult::OVERLAP) {
     return CondContStatusCode::OVERLAP;
   }
@@ -384,7 +409,7 @@ CondContBase::extendLastRangeBase (const EventIDRange& newRange,
     std::abort();
   }
   
-  if (m_condSet.extendLastRange (RangeKey (newRange, start, stop), ctx) != nullptr)
+  if (m_condSet.extendLastRange (RangeKey (newRange, start, stop), ctx) >= 0)
   {
     return StatusCode::SUCCESS;
   }
@@ -544,6 +569,8 @@ CondContSingleBase::ranges() const
  * The container will take ownership of this object.
  *
  * Returns SUCCESS if the object was successfully inserted;
+ * EXTENDS if the last existing range in the container was extended
+ * to match the new range;
  * OVERLAP if the object was inserted but the range partially overlaps
  * with an existing one;
  * DUPLICATE if the object wasn't inserted because the range
@@ -858,12 +885,16 @@ CondContMixedBase::insertMixed (const EventIDRange& r,
 
   CondContSet::EmplaceResult reslt =
     tsmap->emplace ( RangeKey(r, start_key, stop_key),
-                     std::move(t), ctx );
+                     std::move(t), false, ctx );
 
   if (reslt == CondContSet::EmplaceResult::DUPLICATE)
   {
     return CondContStatusCode::DUPLICATE;
   }
+  else if (reslt == CondContSet::EmplaceResult::EXTENDED)
+  {
+    std::abort();  // Shouldn't happen.
+  }
   else if (reslt == CondContSet::EmplaceResult::OVERLAP) {
     return CondContStatusCode::OVERLAP;
   }
diff --git a/Control/AthenaKernel/test/CondCont_test.cxx b/Control/AthenaKernel/test/CondCont_test.cxx
index f024d15b7ab..a8fc93813a5 100644
--- a/Control/AthenaKernel/test/CondCont_test.cxx
+++ b/Control/AthenaKernel/test/CondCont_test.cxx
@@ -284,6 +284,18 @@ void checkit (const CondCont<T>& cc_rl,
 }
 
 
+std::string dump_cc (const CondCont<B>& cc)
+{
+  std::ostringstream ss;
+  for (const EventIDRange& r : cc.ranges()) {
+    const B* p = nullptr;
+    assert (cc.find (r.start(), p));
+    ss << r << " [" << p->m_x << "]\n";
+  }
+  return ss.str();
+}
+
+
 void test1 (TestRCUSvc& rcusvc)
 {
   std::cout << "test1\n";
@@ -361,6 +373,12 @@ void test1 (TestRCUSvc& rcusvc)
   assert (cc_ts.insert (EventIDRange (timestamp (100), timestamp (200)),
                         std::make_unique<B> (50)).isSuccess());
 
+  sc = cc_ts.insert (EventIDRange (timestamp (100), timestamp (300)),
+                     std::make_unique<B> (60));
+  assert (sc.isSuccess());
+  assert (CondContBase::Category::isExtended (sc));
+  assert (dump_cc(cc_ts) == "{[0,0,t:100] - [t:300]} [50]\n");
+
   //*** Test errors from find().
   const B* b = nullptr;
   assert (!cc_rl.find (timestamp (100), b));
@@ -402,18 +420,6 @@ void test2 (TestRCUSvc& rcusvc)
 }
 
 
-std::string dump_cc (const CondCont<B>& cc)
-{
-  std::ostringstream ss;
-  for (const EventIDRange& r : cc.ranges()) {
-    const B* p = nullptr;
-    assert (cc.find (r.start(), p));
-    ss << r << " [" << p->m_x << "]\n";
-  }
-  return ss.str();
-}
-
-
 // Test an extensible container.
 void test3 (TestRCUSvc& rcusvc)
 {
diff --git a/Control/CxxUtils/CxxUtils/ConcurrentRangeMap.h b/Control/CxxUtils/CxxUtils/ConcurrentRangeMap.h
index e71ce573c83..b2abc1076d8 100644
--- a/Control/CxxUtils/CxxUtils/ConcurrentRangeMap.h
+++ b/Control/CxxUtils/CxxUtils/ConcurrentRangeMap.h
@@ -1,6 +1,6 @@
 // This file's extension implies that it's C, but it's really -*- C++ -*-.
 /*
-  Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
 */
 /*
  */
@@ -82,7 +82,7 @@ namespace CxxUtils {
  *  // has returned true.
  *  bool overlap (const RANGE& r1, const RANGE& r2) const;
  *  // Required only for extendLastRange --- which see.
- *  bool extendRange (Range& range, const Range& newRange) const;
+ *  int extendRange (Range& range, const Range& newRange) const;
  @endcode
  *
  * In order to implement updating concurrently with reading, we need to
@@ -305,7 +305,11 @@ public:
     OVERLAP,
 
     /// New object duplicates an existing range, and was not added.
-    DUPLICATE
+    DUPLICATE,
+
+    // Existing range was extended to match the new range; new object
+    // was deleted.
+    EXTENDED
   };
 
 
@@ -313,16 +317,27 @@ public:
    * @brief Add a new element to the map.
    * @param range Validity range for this element.
    * @param ptr Payload for this element.
+   * @param tryExtend If true, then allow an existing range to be extended
+   *                  (see below).
    * @param ctx Execution context.
    *
    * Returns SUCCESS if the new element was successfully inserted.
-   * Returns DUPLICATE if the range compared equal to an existing one. In that case,
-   * no new element is inserted (and @c ptr gets deleted).
+   * Returns DUPLICATE if the range compared equal to an existing one.
+   *         In that case, no new element is inserted (and @c ptr gets deleted).
+   * Returns EXTEND if the range of the last element was extended to @c range.
+   *         This happens if @c tryExtend is true, @c range is equal
+   *         to the range of the last element (according to @c m_compare),
+   *         and the range can be extended according to @c extendRange.
+   *         (This will generally mean that the start time of @c range
+   *         matches the last range, and end time of @c range is after
+   *         the end time of the last range.)  In this case, again no
+   *         new element is inserted and @c ptr is deleted.
    * Returns OVERLAP if the range of the new element overlaps
-   * an existing element (the new element is still inserted).
+   *         an existing element (the new element is still inserted).
    */
   EmplaceResult emplace (const RANGE& range,
                          payload_unique_ptr ptr,
+                         bool tryExtend = false,
                          const typename Updater_t::Context_t& ctx =
                            Updater_t::defaultContext());
 
@@ -350,25 +365,26 @@ public:
    * @c extendRange method of the @c COMPARE object:
    *
    *@code
-   *  bool extendRange (Range& range, const Range& newRange) const;
+   *  int extendRange (Range& range, const Range& newRange) const;
    @endif
    *
    * This is called with the existing range and the end range, and returns
-   * a success flag.
+   * a flag.  -1 indicates an error, 0 indicates that no change
+   * was made to the range, and 1 indicates that the range was extended.
    * It should generally be safe to extend a range by making the end later.
    * Suggested semantics are:
-   *  - Return false if the start keys don't match.
+   *  - Return -1 if the start keys don't match.
    *  - If the end value of @c newRange is later then then end value of @c range,
    *    then update the end value of @c range to match @c newRange and
-   *    return true.
-   *  - Otherwise do nothing and return true.
+   *    return 1.
+   *  - Otherwise do nothing and return 0.
    *
-   * If the extendRange call returns true, then this function returns an iterator
-   * pointing at the last element.  Otherwise, it returns nullptr.
+   * Returns -1 if there was an error; 1 if the last range was extended;
+   * and 0 if nothing was changed.
    */
-  const_iterator extendLastRange (const RANGE& newRange,
-                                  const typename Updater_t::Context_t& ctx =
-                                    Updater_t::defaultContext());
+  int extendLastRange (const RANGE& newRange,
+                       const typename Updater_t::Context_t& ctx =
+                         Updater_t::defaultContext());
 
 
   /**
@@ -444,6 +460,11 @@ public:
 
 
 private:
+  /// Type of the mutex for this container.
+  typedef std::mutex mutex_t;
+  typedef std::lock_guard<mutex_t> lock_t;
+
+
   /**
    * @brief Return the begin/last pointers.
    * @param [inout] last Current value of last.
@@ -493,6 +514,21 @@ private:
                     value_type* new_end,
                     const typename Updater_t::Context_t& ctx);
 
+  
+  /**
+   * @brief Extend the range of the last entry of the map.
+   * @param Lock object.
+   * @param newRange New range to use for the last entry.
+   * @param ctx Execution context.
+   *
+   * Implementation of @c extendLastRange; see there for details.
+   * Must be called with the lock held.
+   */
+  int extendImpl (lock_t& lock,
+                  const RANGE& newRange,
+                    const typename Updater_t::Context_t& ctx);
+
+
 
   /// Updater object.  This maintains ownership of the current implementation
   /// class and the older versions.
@@ -526,8 +562,6 @@ private:
   size_t m_maxSize;
 
   /// Mutex protecting the container.
-  typedef std::mutex mutex_t;
-  typedef std::lock_guard<mutex_t> lock_t;
   mutex_t m_mutex;
 };
 
diff --git a/Control/CxxUtils/CxxUtils/ConcurrentRangeMap.icc b/Control/CxxUtils/CxxUtils/ConcurrentRangeMap.icc
index c19d32364e5..b4b1124cf8f 100644
--- a/Control/CxxUtils/CxxUtils/ConcurrentRangeMap.icc
+++ b/Control/CxxUtils/CxxUtils/ConcurrentRangeMap.icc
@@ -1,9 +1,6 @@
 /*
   Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
 */
-/*
- */
-// $Id$
 /**
  * @file CxxUtils/ConcurrentRangeMap.icc
  * @author scott snyder <snyder@bnl.gov>
@@ -165,18 +162,29 @@ CONCURRENTRANGEMAP::find (const key_query_type& key) const
  * @brief Add a new element to the map.
  * @param range Validity range for this element.
  * @param ptr Payload for this element.
+ * @param tryExtend If true, then allow an existing range to be extended
+ *                  (see below).
  * @param ctx Execution context.
  *
  * Returns SUCCESS if the new element was successfully inserted.
- * Returns DUPLICATE if the range compared equal to an existing one. In that case,
- * no new element is inserted (and @c ptr gets deleted).
+ * Returns DUPLICATE if the range compared equal to an existing one.
+ *         In that case, no new element is inserted (and @c ptr gets deleted).
+ * Returns EXTEND if the range of the last element was extended to @c range.
+ *         This happens if @c tryExtend is true, @c range is equal
+ *         to the range of the last element (according to @c m_compare),
+ *         and the range can be extended according to @c extendRange.
+ *         (This will generally mean that the start time of @c range
+ *         matches the last range, and end time of @c range is after
+ *         the end time of the last range.)  In this case, again no
+ *         new element is inserted and @c ptr is deleted.
  * Returns OVERLAP if the range of the new element overlaps
- * an existing element (the new element is still inserted).
+ *         an existing element (the new element is still inserted).
  */
 T_CONCURRENTRANGEMAP
 typename CONCURRENTRANGEMAP::EmplaceResult
 CONCURRENTRANGEMAP::emplace (const RANGE& range,
                              payload_unique_ptr ptr,
+                             bool tryExtend /*= false*/,
                              const typename Updater_t::Context_t& ctx
                                /*= Updater_t::defaultContext()*/)
 {
@@ -191,6 +199,11 @@ CONCURRENTRANGEMAP::emplace (const RANGE& range,
   // Make sure the new element is not a duplicate of the last.  Fail if so.
   if (last && !pastEnd && !m_compare (range, last->first)) {
     // Duplicate of the last entry.
+    if (tryExtend) {
+      if (extendImpl (lock, range, ctx) > 0) {
+        return EmplaceResult::EXTENDED;
+      }
+    }
     return EmplaceResult::DUPLICATE;
   }
 
@@ -361,33 +374,65 @@ CONCURRENTRANGEMAP::erase (const key_query_type& key,
  * @c extendRange method of the @c COMPARE object:
  *
  *@code
- *  bool extendRange (Range& range, const Range& newRange) const;
+ *  int extendRange (Range& range, const Range& newRange) const;
  @endif
  *
  * This is called with the existing range and the end range, and returns
- * a success flag.
+ * a flag.  -1 indicates an error, 0 indicates that no change
+ * was made to the range, and 1 indicates that the range was extended.
  * It should generally be safe to extend a range by making the end later.
  * Suggested semantics are:
- *  - Return false if the start keys don't match.
+ *  - Return -1 if the start keys don't match.
  *  - If the end value of @c newRange is later then then end value of @c range,
  *    then update the end value of @c range to match @c newRange and
- *    return true.
- *  - Otherwise do nothing and return true.
+ *    return 1.
+ *  - Otherwise do nothing and return 0.
  *
- * If the extendRange call returns true, then this function returns an iterator
- * pointing at the last element.  Otherwise, it returns nullptr.
+ * Returns -1 if there was an error; 1 if the last range was extended;
+ * and 0 if nothing was changed.
  */
 T_CONCURRENTRANGEMAP
-typename CONCURRENTRANGEMAP::const_iterator
+int
 CONCURRENTRANGEMAP::extendLastRange (const RANGE& newRange,
                                      const typename Updater_t::Context_t& ctx
                                      /*= Updater_t::defaultContext()*/)
 {
   lock_t lock (m_mutex);
+  return extendImpl (lock, newRange, ctx);
+}
+
 
+/**
+ * @brief Extend the range of the last entry of the map.
+ * @param Lock object.
+ * @param newRange New range to use for the last entry.
+ * @param ctx Execution context.
+ *
+ * Implementation of @c extendLastRange; see there for details.
+ * Must be called with the lock held.
+ */
+T_CONCURRENTRANGEMAP
+int
+CONCURRENTRANGEMAP::extendImpl (lock_t& /*lock*/,
+                                const RANGE& newRange,
+                                const typename Updater_t::Context_t& ctx)
+{
   // Return if the container's empty.
   value_type* last = m_last;
-  if (last == nullptr) return nullptr;
+  if (last == nullptr) return -1;
+
+  // Test the range.
+  RANGE extendedRange = last->first;
+  int flag = m_compare.extendRange (extendedRange, newRange);
+
+  if (flag < 0) {
+    // Error.
+    return -1;
+  }
+  else if (flag == 0) {
+    // No-op.
+    return 0;
+  }
 
   // Make a new implementation object and copy data.
   size_t capacity = m_impl->capacity();
@@ -399,15 +444,12 @@ CONCURRENTRANGEMAP::extendLastRange (const RANGE& newRange,
   new_end = std::copy (begin, end, new_end);
 
   // Update the range of the last entry.
-  bool ret = m_compare.extendRange ((new_end-1)->first, newRange);
+  (new_end-1)->first = extendedRange;
 
   // Install the new implementation.
   installImpl (std::move (new_impl), new_begin, new_end, ctx);
 
-  if (ret) {
-    return new_end-1;
-  }
-  return nullptr;
+  return 1;
 }
 
                            
diff --git a/Control/CxxUtils/test/ConcurrentRangeMap_test.cxx b/Control/CxxUtils/test/ConcurrentRangeMap_test.cxx
index bd780dfc7b9..f951ad653e7 100644
--- a/Control/CxxUtils/test/ConcurrentRangeMap_test.cxx
+++ b/Control/CxxUtils/test/ConcurrentRangeMap_test.cxx
@@ -54,13 +54,16 @@ struct RangeCompare
   bool overlap (const Range& r1, const Range& r2) const
   { return r1.m_end > r2.m_begin; }
 
-  bool extendRange (Range& r, const Range& newRange) const
+  int extendRange (Range& r, const Range& newRange) const
   {
     if (r.m_begin != newRange.m_begin) {
-      return false;
+      return -1;
     }
-    r.m_end = std::max (r.m_end, newRange.m_end);
-    return true;
+    if (newRange.m_end <= r.m_end) {
+      return 0;
+    }
+    r.m_end = newRange.m_end;
+    return 1;
   }
 };
 
@@ -501,17 +504,13 @@ void test1a()
 
     //======
 
-    TestMap::const_iterator it;
-
-    it = map.extendLastRange (Range (97, 110));
-    assert (it != nullptr);
+    assert (map.extendLastRange (Range (97, 110)) == 1);
     
     // 93..96->650 97..110->660 - - - - - -
     assert (map.capacity() == 8);
     assert (map.size() == 2);
     r = map.range();
     assert (r.size() == 2);
-    assert (it == r.end()-1);
     assert (r.begin()->second->m_x == 650);
     assert ((r.begin()+1)->second->m_x == 660);
     assert ((r.begin()+1)->first.m_begin == 97);
@@ -527,15 +526,13 @@ void test1a()
 
     //======
 
-    it = map.extendLastRange (Range (97, 105));
-    assert (it != nullptr);
+    assert (map.extendLastRange (Range (97, 105)) == 0);
     
     // 93..96->650 97..110->660 - - - - - -
     assert (map.capacity() == 8);
     assert (map.size() == 2);
     r = map.range();
     assert (r.size() == 2);
-    assert (it == r.end()-1);
     assert (r.begin()->second->m_x == 650);
     assert ((r.begin()+1)->second->m_x == 660);
     assert ((r.begin()+1)->first.m_begin == 97);
@@ -551,7 +548,7 @@ void test1a()
 
     //======
 
-    assert ( ! map.extendLastRange (Range (98, 120)));
+    assert ( map.extendLastRange (Range (98, 120)) < 0 );
     // 93..96->650 97..110->660 - - - - - -
     assert (map.capacity() == 8);
     assert (map.size() == 2);
@@ -569,6 +566,29 @@ void test1a()
 
     assert (map.nInserts() == 12);
     assert (map.maxSize()  == 6);
+
+    //======
+
+    assert (map.emplace (Range (97, 150),
+                         std::make_unique<Payload> (670, &phist), true) ==
+            TestMap::EmplaceResult::EXTENDED);
+    // 93..96->650 97..150->660 - - - - - -
+    assert (map.capacity() == 8);
+    assert (map.size() == 2);
+    r = map.range();
+    assert (r.size() == 2);
+    assert (r.begin()->second->m_x == 650);
+    assert ((r.begin()+1)->second->m_x == 660);
+    assert ((r.begin()+1)->first.m_begin == 97);
+    assert ((r.begin()+1)->first.m_end == 150);
+    assert (map.find (92) == nullptr);
+    assert (map.find (94)->second->m_x == 650);
+    assert (map.find (105)->second->m_x == 660);
+
+    assert (!phist.empty());
+
+    assert (map.nInserts() == 12);
+    assert (map.maxSize()  == 6);
   }
 
   assert (phist.empty());
diff --git a/Control/StoreGate/StoreGate/WriteCondHandle.h b/Control/StoreGate/StoreGate/WriteCondHandle.h
index 530d1aace92..45bdd8d92fd 100644
--- a/Control/StoreGate/StoreGate/WriteCondHandle.h
+++ b/Control/StoreGate/StoreGate/WriteCondHandle.h
@@ -135,17 +135,6 @@ namespace SG {
 #endif
       sc = StatusCode::SUCCESS;
     }
-    // If the object exists already, try to extend it
-    else if (CondContBase::Category::isDuplicate (sc) &&
-             m_cc->keyType() != CondContBase::KeyType::MIXED) {
-      sc = this->extendLastRange(r, m_ctx);
-      if (sc.isFailure()) {
-        msg << MSG::ERROR
-            << "WriteCondHandle::record() : cannot extend duplicate range"
-            << endmsg;
-        return StatusCode::FAILURE;
-      }
-    }
  
     return sc;
   }
-- 
GitLab