3838#include < boost/filesystem.hpp>
3939#include < boost/algorithm/string.hpp>
4040#include < iostream>
41+ #include < mutex>
4142
4243namespace o2
4344{
@@ -46,6 +47,8 @@ namespace ccdb
4647
4748using namespace std ;
4849
50+ std::mutex gIOMutex ; // to protect TMemFile IO operations
51+
4952CcdbApi::~CcdbApi ()
5053{
5154 curl_global_cleanup ();
@@ -97,6 +100,7 @@ std::unique_ptr<std::vector<char>> CcdbApi::createObjectImage(const void* obj, s
97100{
98101 // Create a binary image of the object, if CcdbObjectInfo pointer is provided, register there
99102 // the assigned object class name and the filename
103+ std::lock_guard<std::mutex> guard (gIOMutex );
100104 std::string className = o2::utils::MemFileHelper::getClassName (tinfo);
101105 std::string tmpFileName = generateFileName (className);
102106 if (info) {
@@ -116,6 +120,7 @@ std::unique_ptr<std::vector<char>> CcdbApi::createObjectImage(const TObject* roo
116120 info->setFileName (tmpFileName);
117121 info->setObjectType (" TObject" ); // why TObject and not the actual name?
118122 }
123+ std::lock_guard<std::mutex> guard (gIOMutex );
119124 return o2::utils::MemFileHelper::createFileImage (*rootObject, tmpFileName, CCDBOBJECT_ENTRY);
120125}
121126
@@ -358,6 +363,7 @@ TObject* CcdbApi::retrieve(std::string const& path, std::map<std::string, std::s
358363 long response_code;
359364 res = curl_easy_getinfo (curl_handle, CURLINFO_RESPONSE_CODE, &response_code);
360365 if ((res == CURLE_OK) && (response_code != 404 )) {
366+ std::lock_guard<std::mutex> guard (gIOMutex );
361367 TMessage mess (kMESS_OBJECT );
362368 mess.SetBuffer (chunk.memory , chunk.size , kFALSE );
363369 mess.SetReadMode ();
@@ -484,6 +490,7 @@ TObject* CcdbApi::retrieveFromTFile(std::string const& path, std::map<std::strin
484490 if ((res == CURLE_OK) && (response_code != 404 )) {
485491 Int_t previousErrorLevel = gErrorIgnoreLevel ;
486492 gErrorIgnoreLevel = kFatal ;
493+ std::lock_guard<std::mutex> guard (gIOMutex );
487494 TMemFile memFile (" name" , chunk.memory , chunk.size , " READ" );
488495 gErrorIgnoreLevel = previousErrorLevel;
489496 if (!memFile.IsZombie ()) {
@@ -584,14 +591,13 @@ void CcdbApi::retrieveBlob(std::string const& path, std::string const& targetdir
584591 if (success) {
585592 // trying to append metadata to the file so that it can be inspected WHERE/HOW/WHAT IT corresponds to
586593 // Just a demonstrator for the moment
587- TFile snapshotfile (targetpath.c_str (), " UPDATE" );
588594 CCDBQuery querysummary (path, metadata, timestamp);
589- snapshotfile.WriteObjectAny (&querysummary, TClass::GetClass (typeid (querysummary)), CCDBQUERY_ENTRY);
590-
591595 // retrieveHeaders
592596 auto headers = retrieveHeaders (path, metadata, timestamp);
597+ std::lock_guard<std::mutex> guard (gIOMutex );
598+ TFile snapshotfile (targetpath.c_str (), " UPDATE" );
599+ snapshotfile.WriteObjectAny (&querysummary, TClass::GetClass (typeid (querysummary)), CCDBQUERY_ENTRY);
593600 snapshotfile.WriteObjectAny (&headers, TClass::GetClass (typeid (metadata)), CCDBMETA_ENTRY);
594-
595601 snapshotfile.Close ();
596602 }
597603}
@@ -641,12 +647,14 @@ void* CcdbApi::extractFromTFile(TFile& file, TClass const* cl)
641647 return result;
642648}
643649
644- void * CcdbApi::extractFromLocalFile (std::string const & filename, TClass const * tcl ) const
650+ void * CcdbApi::extractFromLocalFile (std::string const & filename, std::type_info const & tinfo ) const
645651{
646652 if (!boost::filesystem::exists (filename)) {
647653 LOG (INFO) << " Local snapshot " << filename << " not found \n " ;
648654 return nullptr ;
649655 }
656+ std::lock_guard<std::mutex> guard (gIOMutex );
657+ auto tcl = tinfo2TClass (tinfo);
650658 TFile f (filename.c_str (), " READ" );
651659 return extractFromTFile (f, tcl);
652660}
@@ -673,28 +681,32 @@ bool CcdbApi::initTGrid() const
673681 return mAlienInstance != nullptr ;
674682}
675683
676- void * CcdbApi::downloadAlienContent (std::string const & url, TClass* cl ) const
684+ void * CcdbApi::downloadAlienContent (std::string const & url, std::type_info const & tinfo ) const
677685{
678686 if (!initTGrid ()) {
679687 return nullptr ;
680688 }
689+ std::lock_guard<std::mutex> guard (gIOMutex );
681690 auto memfile = TMemFile::Open (url.c_str (), " OPEN" );
682691 if (memfile) {
692+ auto cl = tinfo2TClass (tinfo);
683693 auto content = extractFromTFile (*memfile, cl);
684694 delete memfile;
685695 return content;
686696 }
687697 return nullptr ;
688698}
689699
690- void * CcdbApi::interpretAsTMemFileAndExtract (char * contentptr, size_t contentsize, TClass* tcl ) const
700+ void * CcdbApi::interpretAsTMemFileAndExtract (char * contentptr, size_t contentsize, std::type_info const & tinfo ) const
691701{
692702 void * result = nullptr ;
693703 Int_t previousErrorLevel = gErrorIgnoreLevel ;
694704 gErrorIgnoreLevel = kFatal ;
705+ std::lock_guard<std::mutex> guard (gIOMutex );
695706 TMemFile memFile (" name" , contentptr, contentsize, " READ" );
696707 gErrorIgnoreLevel = previousErrorLevel;
697708 if (!memFile.IsZombie ()) {
709+ auto tcl = tinfo2TClass (tinfo);
698710 result = extractFromTFile (memFile, tcl);
699711 if (!result) {
700712 LOG (ERROR) << o2::utils::concat_string (" Couldn't retrieve object corresponding to " , tcl->GetName (), " from TFile" );
@@ -705,7 +717,7 @@ void* CcdbApi::interpretAsTMemFileAndExtract(char* contentptr, size_t contentsiz
705717}
706718
707719// navigate sequence of URLs until TFile content is found; object is extracted and returned
708- void * CcdbApi::navigateURLsAndRetrieveContent (CURL* curl_handle, std::string const & url, TClass* cl , std::map<string, string>* headers) const
720+ void * CcdbApi::navigateURLsAndRetrieveContent (CURL* curl_handle, std::string const & url, std::type_info const & tinfo , std::map<string, string>* headers) const
709721{
710722 // a global internal data structure that can be filled with HTTP header information
711723 // static --> to avoid frequent alloc/dealloc as optimization
@@ -714,7 +726,7 @@ void* CcdbApi::navigateURLsAndRetrieveContent(CURL* curl_handle, std::string con
714726
715727 // let's see first of all if the url is something specific that curl cannot handle
716728 if (url.find (" alien:/" , 0 ) != std::string::npos) {
717- return downloadAlienContent (url, cl );
729+ return downloadAlienContent (url, tinfo );
718730 }
719731 // add other final cases here
720732 // example root://
@@ -750,7 +762,7 @@ void* CcdbApi::navigateURLsAndRetrieveContent(CURL* curl_handle, std::string con
750762 }
751763 if (200 <= response_code && response_code < 300 ) {
752764 // good response and the content is directly provided and should have been dumped into "chunk"
753- content = interpretAsTMemFileAndExtract (chunk.memory , chunk.size , cl );
765+ content = interpretAsTMemFileAndExtract (chunk.memory , chunk.size , tinfo );
754766 } else if (response_code == 304 ) {
755767 // this means the object exist but I am not serving
756768 // it since it's already in your possession
@@ -791,7 +803,7 @@ void* CcdbApi::navigateURLsAndRetrieveContent(CURL* curl_handle, std::string con
791803 for (auto & l : locs) {
792804 if (l.size () > 0 ) {
793805 LOG (DEBUG) << " Trying content location " << l;
794- content = navigateURLsAndRetrieveContent (curl_handle, l, cl , nullptr );
806+ content = navigateURLsAndRetrieveContent (curl_handle, l, tinfo , nullptr );
795807 if (content /* or other success marker in future */ ) {
796808 break ;
797809 }
@@ -824,17 +836,12 @@ void* CcdbApi::retrieveFromTFile(std::type_info const& tinfo, std::string const&
824836 const std::string& createdNotAfter, const std::string& createdNotBefore) const
825837{
826838 // We need the TClass for this type; will verify if dictionary exists
827- auto tcl = TClass::GetClass (tinfo);
828- if (!tcl) {
829- std::cerr << " Could not retrieve ROOT dictionary for type " << tinfo.name () << " aborting to read from CCDB\n " ;
830- return nullptr ;
831- }
832839
833840 CURL* curl_handle = curl_easy_init ();
834841 string fullUrl = getFullUrlForRetrieval (curl_handle, path, metadata, timestamp);
835842 // if we are in snapshot mode we can simply open the file; extract the object and return
836843 if (mInSnapshotMode ) {
837- return extractFromLocalFile (fullUrl, tcl );
844+ return extractFromLocalFile (fullUrl, tinfo );
838845 }
839846
840847 // add some global options to the curl query
@@ -853,7 +860,7 @@ void* CcdbApi::retrieveFromTFile(std::type_info const& tinfo, std::string const&
853860 }
854861 curl_easy_setopt (curl_handle, CURLOPT_HTTPHEADER, list);
855862
856- auto content = navigateURLsAndRetrieveContent (curl_handle, fullUrl, tcl , headers);
863+ auto content = navigateURLsAndRetrieveContent (curl_handle, fullUrl, tinfo , headers);
857864 curl_easy_cleanup (curl_handle);
858865 return content;
859866}
@@ -1142,5 +1149,15 @@ std::vector<std::string> CcdbApi::getAllFolders(std::string const& top) const
11421149 return folders;
11431150}
11441151
1152+ TClass* CcdbApi::tinfo2TClass (std::type_info const & tinfo)
1153+ {
1154+ TClass* cl = TClass::GetClass (tinfo);
1155+ if (!cl) {
1156+ throw std::runtime_error (fmt::format (" Could not retrieve ROOT dictionary for type {}, aborting" , tinfo.name ()));
1157+ return nullptr ;
1158+ }
1159+ return cl;
1160+ }
1161+
11451162} // namespace ccdb
11461163} // namespace o2
0 commit comments