From 9858d0efedccfc7f3f4427206e4b62d68d0a0e05 Mon Sep 17 00:00:00 2001
From: scott snyder <sss@karma>
Date: Wed, 7 Oct 2020 13:16:10 -0400
Subject: [PATCH] CollectionBase: Enable thread-safety checking.

Enable thread-safety checking.
Fix resulting warnings.
CollectionFactory / CollectionService marked as not thread-safe
due to const-correctness violations.
---
 Database/APR/CollectionBase/CMakeLists.txt    |  2 +-
 .../CollectionBase/ATLAS_CHECK_THREAD_SAFETY  |  1 +
 .../CollectionBase/CollectionDescription.h    | 13 ++--
 .../CollectionBase/CollectionFactory.h        |  6 +-
 .../CollectionBase/CollectionService.h        |  5 +-
 .../CollectionBase/ICollectionMetadata.h      | 25 ++------
 .../CollectionBase/ICollectionService.h       |  5 +-
 .../src/CollectionDescription.cpp             | 60 +++++++++++++++++--
 .../CollectionBase/src/CollectionFactory.cpp  |  4 +-
 Database/APR/CollectionBase/src/TokenList.cpp | 21 ++++++-
 .../APR/CollectionBase/test/Factory_test.cxx  |  6 +-
 11 files changed, 106 insertions(+), 42 deletions(-)
 create mode 100644 Database/APR/CollectionBase/CollectionBase/ATLAS_CHECK_THREAD_SAFETY

diff --git a/Database/APR/CollectionBase/CMakeLists.txt b/Database/APR/CollectionBase/CMakeLists.txt
index fc861d1f9f4..346d4cd3e1a 100644
--- a/Database/APR/CollectionBase/CMakeLists.txt
+++ b/Database/APR/CollectionBase/CMakeLists.txt
@@ -12,7 +12,7 @@ atlas_add_library( CollectionBase
                    src/*.cpp
                    PUBLIC_HEADERS CollectionBase
                    INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${CORAL_INCLUDE_DIRS}
-                   LINK_LIBRARIES ${Boost_LIBRARIES} ${CORAL_LIBRARIES} FileCatalog
+                   LINK_LIBRARIES ${Boost_LIBRARIES} ${CORAL_LIBRARIES} FileCatalog CxxUtils
                    PRIVATE_LINK_LIBRARIES POOLCore PersistentDataModel )
 
 atlas_add_dictionary( CollectionDict
diff --git a/Database/APR/CollectionBase/CollectionBase/ATLAS_CHECK_THREAD_SAFETY b/Database/APR/CollectionBase/CollectionBase/ATLAS_CHECK_THREAD_SAFETY
new file mode 100644
index 00000000000..51c5d7f4f8a
--- /dev/null
+++ b/Database/APR/CollectionBase/CollectionBase/ATLAS_CHECK_THREAD_SAFETY
@@ -0,0 +1 @@
+Database/APR/CollectionBase
diff --git a/Database/APR/CollectionBase/CollectionBase/CollectionDescription.h b/Database/APR/CollectionBase/CollectionBase/CollectionDescription.h
index 6ea5ed57953..47ad8118aa8 100755
--- a/Database/APR/CollectionBase/CollectionBase/CollectionDescription.h
+++ b/Database/APR/CollectionBase/CollectionBase/CollectionDescription.h
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
 */
 
 #ifndef COLLECTIONBASE_COLLECTIONDESCRIPTION_H
@@ -573,13 +573,16 @@ namespace pool {
     // check if the column contains tokens
     virtual bool 	isTokenColumn( const std::string& columnName, const std::string& method ) const;
 
-    // this version includes the 'mothod name' in the error message
-    virtual pool::CollectionColumn* column( const std::string& columnName, const std::string& methodName ) const;
+    // this version includes the 'method name' in the error message
+    virtual pool::CollectionColumn* column( const std::string& columnName, const std::string& methodName );
+    virtual const pool::CollectionColumn* column( const std::string& columnName, const std::string& methodName ) const;
 
     // returns non-const fragment pointer
-    virtual pool::CollectionFragment* collectionFragment( int fragmentId, const std::string& method  ) const;
+    virtual pool::CollectionFragment* collectionFragment( int fragmentId, const std::string& method  );
+    virtual const pool::CollectionFragment* collectionFragment( int fragmentId, const std::string& method  ) const;
     // returns non-const fragment pointer
-    virtual pool::CollectionFragment* collectionFragment( const std::string& fragmentName, const std::string& method ) const;
+    virtual pool::CollectionFragment* collectionFragment( const std::string& fragmentName, const std::string& method );
+    virtual const pool::CollectionFragment* collectionFragment( const std::string& fragmentName, const std::string& method ) const;
 
  public:
     /// print out the description (debugging)
diff --git a/Database/APR/CollectionBase/CollectionBase/CollectionFactory.h b/Database/APR/CollectionBase/CollectionBase/CollectionFactory.h
index 3c77051ffeb..3adbcc2f53d 100755
--- a/Database/APR/CollectionBase/CollectionBase/CollectionFactory.h
+++ b/Database/APR/CollectionBase/CollectionBase/CollectionFactory.h
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
 */
 
 #ifndef COLLECTIONBASE_COLLECTIONFACTORY_H
@@ -8,6 +8,7 @@
 #include "CollectionBase/ICollection.h"
 #include "CollectionBase/CollectionDescription.h"
 #include "FileCatalog/IFileCatalog.h"
+#include "CxxUtils/checker_macros.h"
 
 #include <string>
 #include <vector>
@@ -27,7 +28,8 @@ namespace pool {
    * collection fragments, the latter of which contain a subset of the metadata of a 
    * full collection.
    */
-  class CollectionFactory
+  class ATLAS_NOT_THREAD_SAFE CollectionFactory
+  // not thread-safe due to constness violations wrt the catalog.
   {
   public:
     /// Retrieves the collection factory singleton.
diff --git a/Database/APR/CollectionBase/CollectionBase/CollectionService.h b/Database/APR/CollectionBase/CollectionBase/CollectionService.h
index bee57353970..4800f1a4d1e 100755
--- a/Database/APR/CollectionBase/CollectionBase/CollectionService.h
+++ b/Database/APR/CollectionBase/CollectionBase/CollectionService.h
@@ -1,11 +1,12 @@
 /*
-  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
 */
 
 #ifndef COLLECTIONBASE_COLLECTIONSERVICE_H
 #define COLLECTIONBASE_COLLECTIONSERVICE_H
 
 #include "CollectionBase/ICollectionService.h"
+#include "CxxUtils/checker_macros.h"
 
 
 namespace pool {
@@ -21,7 +22,7 @@ namespace pool {
    * of the metadata of an existing collection. Note that a class that inherits from this 
    * interface must also inherit from the SEAL Service base class. 
    */
-   class CollectionService : virtual public ICollectionService
+   class ATLAS_NOT_THREAD_SAFE CollectionService : virtual public ICollectionService
   {
     // DECLARE_SEAL_COMPONENT;
  
diff --git a/Database/APR/CollectionBase/CollectionBase/ICollectionMetadata.h b/Database/APR/CollectionBase/CollectionBase/ICollectionMetadata.h
index d7825418781..7f5b8667cdb 100644
--- a/Database/APR/CollectionBase/CollectionBase/ICollectionMetadata.h
+++ b/Database/APR/CollectionBase/CollectionBase/ICollectionMetadata.h
@@ -1,11 +1,12 @@
 /*
-  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
 */
 
 #ifndef ICollectionMetadata_h
 #define ICollectionMetadata_h
 
 #include <string>
+#include <memory>
 
 namespace pool {
 
@@ -35,25 +36,11 @@ namespace pool {
        const std::string&	key() const { return m_iterator->key(); }
        const char *		value() const { return m_iterator->value(); }
        
-       ~const_iterator() { delete m_iterator; }
-
-       const_iterator( ICollectionMetadataIterator* iter )
-	     : m_iterator( iter ) {}
-       
-       const_iterator& operator=( const const_iterator& rhs ) { 
-	  m_iterator = rhs.releaseIter();
-	  return *this; 
-       }
-
-    protected:
-       ICollectionMetadataIterator* releaseIter() const {
-	  ICollectionMetadataIterator *iter = m_iterator;
-	  m_iterator = 0;
-	  return iter;
-       }
-       
+       const_iterator( std::unique_ptr<ICollectionMetadataIterator> iter )
+         : m_iterator( std::move(iter) ) {}
        
-       mutable ICollectionMetadataIterator*	m_iterator;      
+     private:
+       std::unique_ptr<ICollectionMetadataIterator> m_iterator;      
      };
 
 
diff --git a/Database/APR/CollectionBase/CollectionBase/ICollectionService.h b/Database/APR/CollectionBase/CollectionBase/ICollectionService.h
index 4d542886c35..025742afce3 100755
--- a/Database/APR/CollectionBase/CollectionBase/ICollectionService.h
+++ b/Database/APR/CollectionBase/CollectionBase/ICollectionService.h
@@ -1,11 +1,12 @@
 /*
-  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
 */
 
 #ifndef COLLECTIONBASE_ICOLLECTIONSERVICE_H
 #define COLLECTIONBASE_ICOLLECTIONSERVICE_H
 
 #include "CollectionBase/ICollection.h"
+#include "CxxUtils/checker_macros.h"
 
 #include <string>
 #include <vector>
@@ -29,7 +30,7 @@ namespace pool {
    * Note that a class that inherits from this interface must also inherit from the SEAL 
    * Service base class. 
    */
-  class ICollectionService
+  class ATLAS_NOT_THREAD_SAFE ICollectionService
   {
   public:
     /**
diff --git a/Database/APR/CollectionBase/src/CollectionDescription.cpp b/Database/APR/CollectionBase/src/CollectionDescription.cpp
index fa90e718772..b9e9902a8cf 100755
--- a/Database/APR/CollectionBase/src/CollectionDescription.cpp
+++ b/Database/APR/CollectionBase/src/CollectionDescription.cpp
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
 */
 
 #include "CollectionBase/CollectionDescription.h"
@@ -1450,7 +1450,7 @@ pool::CollectionDescription::numberOfColumns( std::string fragmentName ) const
    if( !fragmentName.size() )  {
       return  m_attributeColumnForColumnName.size() + m_tokenColumnForColumnName.size();
    }
-   CollectionFragment* fragment = collectionFragment( fragmentName, "numberOfColumns" );
+   const CollectionFragment* fragment = collectionFragment( fragmentName, "numberOfColumns" );
    return fragment->attributeColumns().size() + fragment->tokenColumns().size();
 }
 
@@ -1481,7 +1481,7 @@ pool::CollectionDescription::columnPtr( const std::string& name ) const
 
 // internal use protected method (when non-const column is needed). throws exceptions
 pool::CollectionColumn *
-pool::CollectionDescription::column( const std::string& name, const std::string& method ) const
+pool::CollectionDescription::column( const std::string& name, const std::string& method )
 {
    std::map< std::string, pool::CollectionColumn* >::const_iterator iColumn;
    iColumn = m_attributeColumnForColumnName.find( name );
@@ -1497,6 +1497,22 @@ pool::CollectionDescription::column( const std::string& name, const std::string&
    
 
 
+const pool::CollectionColumn *
+pool::CollectionDescription::column( const std::string& name, const std::string& method ) const
+{
+   std::map< std::string, pool::CollectionColumn* >::const_iterator iColumn;
+   iColumn = m_attributeColumnForColumnName.find( name );
+   if( iColumn == m_attributeColumnForColumnName.end() ) {
+      iColumn = m_tokenColumnForColumnName.find( name );
+      if( iColumn == m_tokenColumnForColumnName.end() )  {
+         std::string errorMsg = "Column with name `" + name + "' does NOT exist.";
+         throw pool::Exception(errorMsg, "CollectionDescription::" + method, "CollectionBase");
+      }
+   }
+   return iColumn->second;
+}
+   
+
 int 
 pool::CollectionDescription::numberOfTokenColumns( std::string fragmentName ) const
 {
@@ -1609,7 +1625,7 @@ pool::CollectionDescription::attributeColumn( const std::string& columnName ) co
 const pool::ICollectionColumn&
 pool::CollectionDescription::attributeColumn( int columnId, int fragmentId ) const
 {
-   CollectionFragment* fragment = collectionFragment( fragmentId, "attributeColumn" );
+   const CollectionFragment* fragment = collectionFragment( fragmentId, "attributeColumn" );
    std::vector< pool::CollectionColumn* > columns = fragment->attributeColumns();
 
    if( columnId >= 0 && columnId < (int) columns.size() )  {
@@ -1630,7 +1646,7 @@ pool::CollectionDescription::attributeColumn( int columnId, int fragmentId ) con
 const pool::ICollectionColumn&
 pool::CollectionDescription::attributeColumn( int columnId, const std::string& fragmentName ) const
 {
-   CollectionFragment* fragment = collectionFragment( fragmentName, "attributeColumn" );
+   const CollectionFragment* fragment = collectionFragment( fragmentName, "attributeColumn" );
    std::vector< pool::CollectionColumn* > columns = fragment->attributeColumns();
    if( columnId >= 0 && columnId < (int)columns.size() )    {
       return *( columns[ columnId ] );
@@ -1777,6 +1793,22 @@ pool::CollectionDescription::collectionFragment( const std::string& fragmentName
    
 
 pool::CollectionFragment *
+pool::CollectionDescription::collectionFragment( const std::string& fragmentName, const std::string& method )
+{
+   std::map< std::string, pool::CollectionFragment* >::const_iterator iFragment = 
+      m_fragmentForFragmentName.find( fragmentName );
+
+   if( iFragment == m_fragmentForFragmentName.end() )  {
+      std::string errorMsg = "Collection fragment `" + fragmentName + "' NOT found.";
+      throw pool::Exception( errorMsg,
+			     "CollectionDescription::" + method,
+			     "CollectionBase" );
+   } 
+   return iFragment->second;
+}
+
+
+const pool::CollectionFragment *
 pool::CollectionDescription::collectionFragment( const std::string& fragmentName, const std::string& method ) const
 {
    std::map< std::string, pool::CollectionFragment* >::const_iterator iFragment = 
@@ -1800,6 +1832,24 @@ pool::CollectionDescription::collectionFragment( int fragmentId ) const
 
 
 pool::CollectionFragment *
+pool::CollectionDescription::collectionFragment( int fragmentId, const std::string& method  )
+{
+  std::map< int, pool::CollectionFragment* >::const_iterator iFragment = m_fragmentForFragmentId.find( fragmentId );
+
+  if ( iFragment == m_fragmentForFragmentId.end() )
+  {
+    std::string errorMsg = "Not using a collection fragment with ID " + std::to_string(fragmentId);
+    throw pool::Exception( errorMsg,
+                           "CollectionDescription::" + method,
+                           "CollectionBase" );
+  }
+ 
+  return iFragment->second;
+}
+
+
+
+const pool::CollectionFragment *
 pool::CollectionDescription::collectionFragment( int fragmentId, const std::string& method  ) const
 {
   std::map< int, pool::CollectionFragment* >::const_iterator iFragment = m_fragmentForFragmentId.find( fragmentId );
diff --git a/Database/APR/CollectionBase/src/CollectionFactory.cpp b/Database/APR/CollectionBase/src/CollectionFactory.cpp
index 803958d8dea..29de465160d 100755
--- a/Database/APR/CollectionBase/src/CollectionFactory.cpp
+++ b/Database/APR/CollectionBase/src/CollectionFactory.cpp
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
 */
 
 #include "CollectionBase/CollectionFactory.h"
@@ -24,7 +24,7 @@ using namespace std;
 using namespace pool;
 
 pool::CollectionFactory pool::CollectionFactory::s_instance;
-static string	thisModule( "POOLCollFactory" );
+static const string	thisModule( "POOLCollFactory" );
 
 const std::string pool::CollectionFactory::c_fileType = "PoolCollection";
 
diff --git a/Database/APR/CollectionBase/src/TokenList.cpp b/Database/APR/CollectionBase/src/TokenList.cpp
index 09385868212..17b8cf9a472 100755
--- a/Database/APR/CollectionBase/src/TokenList.cpp
+++ b/Database/APR/CollectionBase/src/TokenList.cpp
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
 */
 
 #include "CollectionBase/TokenList.h"
@@ -99,14 +99,29 @@ pool::TokenList::extend( const std::string& name )
 Token&
 pool::TokenList::operator[]( const std::string& name )
 {
-   return const_cast<Token&>( ((const TokenList&)*this)[name] );
+   std::map< std::string, Token* >::iterator iData = m_tokenMap.find( name );
+
+   if( iData == m_tokenMap.end() )   {
+      std::string errorMsg = "Cannot find Token with name `" + name + "' in Token list.";
+      throw pool::Exception( errorMsg,
+			     "TokenList::operator[](name)",
+			     "CollectionBase" );
+   }
+   return *( iData->second );
 }
 
 
 Token&
 pool::TokenList::operator[]( unsigned int index )
 {
-   return const_cast<Token&>( ((const TokenList&)*this)[index] );
+   if( index >= m_tokenVector.size() ) {
+      std::ostringstream errorMsg;
+      errorMsg << "Cannot find Token with index `" << index << "' in Token list.";
+      throw pool::Exception( errorMsg.str(),
+			     "TokenList::operator[](index)",
+			     "CollectionBase" );
+   }
+   return *m_tokenVector[index];
 }
 
 
diff --git a/Database/APR/CollectionBase/test/Factory_test.cxx b/Database/APR/CollectionBase/test/Factory_test.cxx
index 6d389082da3..8bdaa1bbd61 100644
--- a/Database/APR/CollectionBase/test/Factory_test.cxx
+++ b/Database/APR/CollectionBase/test/Factory_test.cxx
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
 */
 
 #include <cstdio> // For sprintf on gcc45
@@ -15,6 +15,10 @@
 #include "CollectionBase/ICollection.h"
 #include "CollectionBase/CollectionDescription.h"
 #include "CollectionBase/CollectionFactory.h"
+#include "CxxUtils/checker_macros.h"
+
+
+ATLAS_NO_CHECK_FILE_THREAD_SAFETY;
 
 
 using namespace std;
-- 
GitLab