From 247bd6eaac8c475e3690ff1e639748d350d4d99c Mon Sep 17 00:00:00 2001
From: Peter Van Gemmeren <peter.van.gemmeren@cern.ch>
Date: Wed, 13 Aug 2014 22:04:47 +0200
Subject: [PATCH] Avoid leaking DataHeaderForm object when reading next object
 (PersistentDataModelAthenaPool-00-01-02)

---
 .../cmt/requirements                          |  14 ++
 .../doc/MainPage.h                            |  42 ++++
 .../src/DataHeaderCnv.cxx                     | 196 ++++++++++++++++++
 .../src/DataHeaderCnv.h                       |  44 ++++
 4 files changed, 296 insertions(+)
 create mode 100755 Database/PersistentDataModelAthenaPool/cmt/requirements
 create mode 100755 Database/PersistentDataModelAthenaPool/doc/MainPage.h
 create mode 100755 Database/PersistentDataModelAthenaPool/src/DataHeaderCnv.cxx
 create mode 100755 Database/PersistentDataModelAthenaPool/src/DataHeaderCnv.h

diff --git a/Database/PersistentDataModelAthenaPool/cmt/requirements b/Database/PersistentDataModelAthenaPool/cmt/requirements
new file mode 100755
index 00000000000..6207d482d66
--- /dev/null
+++ b/Database/PersistentDataModelAthenaPool/cmt/requirements
@@ -0,0 +1,14 @@
+package PersistentDataModelAthenaPool
+
+author Peter Van Gemmeren <gemmeren@anl.gov>
+
+use AtlasPolicy           AtlasPolicy-*
+
+private
+use AtlasCORAL                  AtlasCORAL-*                  External
+use PersistentDataModel         PersistentDataModel-*         Database
+use PersistentDataModelTPCnv    PersistentDataModelTPCnv-*    Database
+use AthenaPoolCnvSvc            AthenaPoolCnvSvc-*            Database/AthenaPOOL
+use AthenaPoolUtilities         AthenaPoolUtilities-*         Database/AthenaPOOL
+
+apply_pattern poolcnv files="-s=${PersistentDataModel_root}/PersistentDataModel DataHeader.h"
diff --git a/Database/PersistentDataModelAthenaPool/doc/MainPage.h b/Database/PersistentDataModelAthenaPool/doc/MainPage.h
new file mode 100755
index 00000000000..dda041dca7b
--- /dev/null
+++ b/Database/PersistentDataModelAthenaPool/doc/MainPage.h
@@ -0,0 +1,42 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/**
+
+@mainpage
+
+The PersistentDataModelAthenaPool package contains the converter for the persistent Data Model classes in
+PersistentDataModel.
+
+
+@section Properties Settable PersistentDataModelAthenaPool Properties (Job Options)
+
+This package has no properties and no jobOptions.
+
+
+@section Documentation Additional Documentation 
+
+See the ATLAS User/Developer HowTo document for additional information.
+
+The code can be browsed using LXR 
+(http://alxr.usatlas.bnl.gov/lxr/source/atlas/Database/PersistentDataModelAthenaPool/)
+   
+
+@section Examples Examples
+The package Database/AthenaPOOL/AthenaPoolExample contains running examples of algorithms writing and
+reading Data Objects using AthenaPool. 
+
+
+@section Requirements Requirements 
+
+@include requirements 
+
+
+@section PackagesUsed Packages Used 
+
+@htmlinclude used_packages.html
+
+
+@author Peter van Gemmeren <gemmeren@anl.gov>
+*/
diff --git a/Database/PersistentDataModelAthenaPool/src/DataHeaderCnv.cxx b/Database/PersistentDataModelAthenaPool/src/DataHeaderCnv.cxx
new file mode 100755
index 00000000000..658cffd41aa
--- /dev/null
+++ b/Database/PersistentDataModelAthenaPool/src/DataHeaderCnv.cxx
@@ -0,0 +1,196 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/** @file DataHeaderCnv.cxx
+ *  @brief This file contains the implementation for the DataHeaderCnv class.
+ *  @author Peter van Gemmeren <gemmeren@anl.gov>
+ *  $Id: DataHeaderCnv.cxx,v 1.15 2009-04-21 22:04:51 gemmeren Exp $
+ **/
+
+#include "DataHeaderCnv.h"
+
+#include "PersistentDataModel/Token.h"
+#include "PersistentDataModelTPCnv/DataHeaderCnv_p3.h"
+#include "PersistentDataModelTPCnv/DataHeaderCnv_p4.h"
+
+#include "CoralBase/AttributeList.h"
+#include "CoralBase/Attribute.h"
+
+#include <memory>
+#include <stdexcept>
+
+DataHeaderCnv::DataHeaderCnv(ISvcLocator* svcloc) :
+	T_AthenaPoolCustomCnv<DataHeader, DataHeader_p5>::T_AthenaPoolCustomCnv(svcloc),
+	m_TPconverter(),
+	m_dhFormMdx(),
+	m_dhForm(0) {
+}
+DataHeaderCnv::~DataHeaderCnv() {
+   delete m_dhForm ; m_dhForm = 0;
+}
+
+//______________________________________________________________________________
+StatusCode DataHeaderCnv::DataObjectToPool(DataObject* pObj, const std::string& tname) {
+   const std::string className = "DataHeader_p5";
+   const std::string classMapName = "DataHeaderForm_p5";
+   if (!m_dictionaryOkWrite) {
+      if (!m_athenaPoolCnvSvc->testDictionary(className)) {
+         MsgStream log(messageService(), "DataHeaderCnv");
+         log << MSG::ERROR << "There is no correct dictionary for class \"" << className << "\"" << endreq;
+         return(StatusCode::FAILURE);
+      }
+      if (!m_athenaPoolCnvSvc->testDictionary(classMapName)) {
+         MsgStream log(messageService(), "DataHeaderCnv");
+         log << MSG::ERROR << "There is no correct dictionary for class \"" << classMapName << "\"" << endreq;
+         return(StatusCode::FAILURE);
+      }
+      m_dictionaryOkWrite = true;
+   }
+   if (!m_classDesc) {
+      MsgStream log(messageService(), "DataHeaderCnv");
+      log << MSG::DEBUG << "Retrieve class description for class \"" << className << "\"" << endreq;
+      m_classDesc = RootType(className);
+   }
+   if (!m_mapClassDesc) {
+      MsgStream log(messageService(), "DataHeaderCnv");
+      log << MSG::DEBUG << "Retrieve class description for map class \"" << classMapName << "\"" << endreq;
+      m_mapClassDesc = RootType(classMapName);
+   }
+   DataHeader* obj = 0;
+   bool success = SG::fromStorable(pObj, obj);
+   if (!success || obj == 0) {
+      MsgStream log(messageService(), "DataHeaderCnv");
+      log << MSG::ERROR << "Failed to cast DataHeader to transient type" << endreq;
+      return(StatusCode::FAILURE);
+   }
+   DataHeader_p5* persObj = 0;
+   try {
+      persObj = createPersistent(obj);
+   } catch (std::exception &e) {
+      MsgStream log(messageService(), "DataHeaderCnv");
+      log << MSG::FATAL << "Failed to convert DataHeader to persistent type: " << e.what() << endreq;
+      return(StatusCode::FAILURE);
+   }
+   m_persObjList.push_back(persObj);
+   this->setPlacementWithType("DataHeaderForm", tname);
+   const Token* token = m_athenaPoolCnvSvc->registerForWrite(m_placement, &persObj->dhForm(), m_mapClassDesc);
+   if (token == 0) {
+      MsgStream log(messageService(), "DataHeaderCnv");
+      log << MSG::FATAL << "Failed to write DataHeaderForm" << endreq;
+      return(StatusCode::FAILURE);
+   }
+   this->setPlacementWithType("DataHeader", tname);
+   this->m_poolToken = m_athenaPoolCnvSvc->registerForWrite(m_placement, persObj, m_classDesc);
+   if (this->m_poolToken == 0) {
+      delete token; token = 0;
+      MsgStream log(messageService(), "DataHeaderCnv");
+      log << MSG::FATAL << "Failed to write DataHeader" << endreq;
+      return(StatusCode::FAILURE);
+   }
+   m_TPconverter.insertDHRef(persObj, obj->getProcessTag(), this->m_poolToken->toString());
+   persObj->setDhFormToken(token->toString());
+   delete token; token = 0;
+   const coral::AttributeList* list = obj->getAttributeList();
+   if (list != 0) {
+      obj->setEvtRefTokenStr(this->m_poolToken->toString());
+      this->setPlacementWithType("AttributeList", "Token");
+      token = m_athenaPoolCnvSvc->registerForWrite(m_placement, obj->getEvtRefTokenStr().c_str(), RootType("Token"));
+      delete token; token = 0;
+      for (coral::AttributeList::const_iterator iter = list->begin(), last = list->end(); iter != last; ++iter) {
+         this->setPlacementWithType("AttributeList", (*iter).specification().name());
+         token = m_athenaPoolCnvSvc->registerForWrite(m_placement,
+	         (*iter).addressOfData(),
+                 RootType((*iter).specification().type()) );
+         delete token; token = 0;
+      }
+   }
+   return(StatusCode::SUCCESS);
+}
+//______________________________________________________________________________
+DataHeader_p5* DataHeaderCnv::poolReadObject_p5() {
+   DataHeader_p5* pObj = 0;
+   const std::string className = "DataHeader_p5";
+   const Token* token = this->m_poolToken;
+   if (token == 0) {
+      throw std::runtime_error("There is no valid token for class " + className);
+   }
+   if (!m_dictionaryOkRead) {
+      m_dictionaryOkRead = m_athenaPoolCnvSvc->testDictionary(className);
+      if (!m_dictionaryOkRead) {
+         throw std::runtime_error("There is no correct dictionary for class " + className);
+      }
+   }
+   void* voidPtr = 0;
+   try {
+      m_athenaPoolCnvSvc->setObjPtr(voidPtr, token);
+   } catch (std::exception &e) {
+      std::string error = e.what();
+      throw std::runtime_error(error);
+   }
+   if (voidPtr == 0) {
+      throw std::runtime_error("Could not get object for token = " + token->toString());
+   }
+   pObj = reinterpret_cast<DataHeader_p5*>(voidPtr);
+   if (pObj == 0) {
+      throw std::runtime_error("Failed to cast object for token = " + token->toString());
+   }
+   Token mapToken;
+   mapToken.fromString(pObj->dhFormToken());
+   if (mapToken.classID() != Guid::null()) {
+      if (pObj->dhFormMdx() != m_dhFormMdx) {
+         try {
+            m_athenaPoolCnvSvc->setObjPtr(voidPtr, &mapToken);
+         } catch (std::exception &e) {
+            std::string error = e.what();
+            throw std::runtime_error(error);
+         }
+         if (voidPtr == 0) {
+            throw std::runtime_error("Could not get object for token = " + mapToken.toString());
+         }
+         delete m_dhForm ; m_dhForm = reinterpret_cast<DataHeaderForm_p5*>(voidPtr);
+         m_dhFormMdx = pObj->dhFormMdx();
+         if (m_dhForm == 0) {
+            throw std::runtime_error("Failed to cast object for token = " + mapToken.toString());
+         }
+      }
+      pObj->setDhForm(*m_dhForm);
+   }
+   return(pObj);
+}
+//______________________________________________________________________________
+DataHeader_p5* DataHeaderCnv::createPersistent(DataHeader* transObj) {
+   DataHeader_p5* persObj = m_TPconverter.createPersistent(transObj);
+   return(persObj);
+}
+//______________________________________________________________________________
+DataHeader* DataHeaderCnv::createTransient() {
+   if (this->m_poolToken == 0) {
+      return(0);
+   }
+   if (this->m_poolToken->technology() == 0x00001000) { // Artificial ByteStream DataHeader Token
+      DataHeader* dh = new DataHeader();
+      std::string bestPfn, fileType;
+      m_athenaPoolCnvSvc->getPoolSvc()->lookupBestPfn(this->m_poolToken->dbID().toString(), bestPfn, fileType);
+      const Token* copy = new Token(this->m_poolToken);
+      DataHeaderElement dhe(ClassID_traits<DataHeader>::ID(), bestPfn, copy);
+      dh->insert(dhe);
+      return(dh);
+   }
+   static const pool::Guid p5_guid("D82968A1-CF91-4320-B2DD-E0F739CBC7E6");
+   static const pool::Guid p4_guid("9630EB7B-CCD7-47D9-A39B-CBBF4133CDF2");
+   static const pool::Guid p3_guid("EC1318F0-8E28-45F8-9A2D-2597C1CC87A6");
+   if (this->compareClassGuid(p5_guid)) {
+      std::auto_ptr<DataHeader_p5> obj_p5(this->poolReadObject_p5());
+      return(m_TPconverter.createTransient(obj_p5.get()));
+   } else if (this->compareClassGuid(p4_guid)) {
+      std::auto_ptr<DataHeader_p4> obj_p4(this->poolReadObject<DataHeader_p4>());
+      DataHeaderCnv_p4 tPconverter_p4;
+      return(tPconverter_p4.createTransient(obj_p4.get()));
+   } else if (this->compareClassGuid(p3_guid)) {
+      std::auto_ptr<DataHeader_p3> obj_p3(this->poolReadObject<DataHeader_p3>());
+      DataHeaderCnv_p3 tPconverter_p3;
+      return(tPconverter_p3.createTransient(obj_p3.get()));
+   }
+   return(0);
+}
diff --git a/Database/PersistentDataModelAthenaPool/src/DataHeaderCnv.h b/Database/PersistentDataModelAthenaPool/src/DataHeaderCnv.h
new file mode 100755
index 00000000000..2706c2d805c
--- /dev/null
+++ b/Database/PersistentDataModelAthenaPool/src/DataHeaderCnv.h
@@ -0,0 +1,44 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef DATAHEADERCNV_H
+#define DATAHEADERCNV_H
+
+/**
+ *  @file DataHeaderCnv.h
+ *  @brief This file contains the class definition for the DataHeaderCnv class.
+ *  @author Peter van Gemmeren <gemmeren@anl.gov>
+ *  $Id: DataHeaderCnv.h,v 1.9 2009-04-21 22:04:51 gemmeren Exp $
+ **/
+
+#include "AthenaPoolCnvSvc/T_AthenaPoolCustomCnv.h"
+#include "PersistentDataModel/DataHeader.h"
+#include "PersistentDataModelTPCnv/DataHeader_p5.h"
+#include "PersistentDataModelTPCnv/DataHeaderCnv_p5.h"
+
+/** @class DataHeaderCnv
+ *  @brief This class provides the converter to customize the saving of DataHeader.
+ **/
+class DataHeaderCnv : public T_AthenaPoolCustomCnv<DataHeader, DataHeader_p5> {
+   friend class CnvFactory<DataHeaderCnv>;
+public:
+   DataHeaderCnv(ISvcLocator* svcloc);
+   ~DataHeaderCnv();
+
+   /// Extend base-class conversion methods
+   virtual StatusCode DataObjectToPool(DataObject* pObj, const std::string& tname);
+
+   virtual DataHeader_p5* poolReadObject_p5();
+
+   virtual DataHeader_p5* createPersistent(DataHeader* transObj);
+   virtual DataHeader* createTransient();
+
+private:
+   DataHeaderCnv_p5 m_TPconverter;
+   RootType m_mapClassDesc;
+   mutable std::string m_dhFormMdx;
+   mutable DataHeaderForm_p5* m_dhForm;
+};
+
+#endif
-- 
GitLab