The Gaudi Framework  master (9f3f8895)
Loading...
Searching...
No Matches
IODataManager.cpp
Go to the documentation of this file.
1/***********************************************************************************\
2* (c) Copyright 1998-2026 CERN for the benefit of the LHCb and ATLAS collaborations *
3* *
4* This software is distributed under the terms of the Apache version 2 licence, *
5* copied verbatim in the file "LICENSE". *
6* *
7* In applying this licence, CERN does not waive the privileges and immunities *
8* granted to it by virtue of its status as an Intergovernmental Organization *
9* or submit itself to any jurisdiction. *
10\***********************************************************************************/
11// Framework include files
12#include "IODataManager.h"
17#include <GaudiKernel/SmartIF.h>
19
20#include <set>
21#include <strings.h>
22
23namespace {
24
25 template <typename InputIterator, typename OutputIterator, typename UnaryOperation, typename UnaryPredicate>
26 OutputIterator transform_copy_if( InputIterator first, InputIterator last, OutputIterator result, UnaryOperation op,
27 UnaryPredicate pred ) {
28 while ( first != last ) {
29 auto val = op( *first );
30 if ( pred( val ) ) *result++ = std::move( val );
31 ++first;
32 }
33 return result;
34 }
35} // namespace
36
37using namespace Gaudi;
38
40
41static std::set<std::string> s_badFiles;
42
45 // Initialize base class
47 MsgStream log( msgSvc(), name() );
48 if ( !status.isSuccess() ) {
49 log << MSG::ERROR << "Error initializing base class Service!" << endmsg;
50 return status;
51 }
52 // Retrieve conversion service handling event iteration
54 if ( !m_catalog ) {
55 log << MSG::ERROR << "Unable to localize interface IFileCatalog from service:" << m_catalogSvcName << endmsg;
57 }
58 m_incSvc = serviceLocator()->service( "IncidentSvc" );
59 if ( !m_incSvc ) {
60 log << MSG::ERROR << "Error initializing IncidentSvc Service!" << endmsg;
61 return status;
62 }
63 return status;
64}
65
68 m_catalog = nullptr; // release
69 return Service::finalize();
70}
71
74 MsgStream log( msgSvc(), name() );
75 log << MSG::ERROR << "Error: " << msg << endmsg;
77}
78
80IODataManager::Connections IODataManager::connections( const IInterface* owner ) const {
81 Connections conns;
82 transform_copy_if(
83 std::begin( m_connectionMap ), std::end( m_connectionMap ), std::back_inserter( conns ),
84 []( ConnectionMap::const_reference i ) { return i.second->connection; },
85 [&]( const IDataConnection* c ) { return !owner || c->owner() == owner; } );
86 return conns;
87}
88
90StatusCode IODataManager::connectRead( bool keep_open, Connection* con ) {
91 if ( !establishConnection( con ) ) {
92 return connectDataIO( UNKNOWN, Connection::READ, con->name(), "UNKNOWN", keep_open, con );
93 }
94 std::string dsn = con ? con->name() : std::string( "Unknown" );
95 return error( "Failed to connect to data:" + dsn );
96}
97
99StatusCode IODataManager::connectWrite( Connection* con, IoType mode, CSTR doctype ) {
100 if ( !establishConnection( con ) ) { return connectDataIO( UNKNOWN, mode, con->name(), doctype, true, con ); }
101 std::string dsn = con ? con->name() : std::string( "Unknown" );
102 return error( "Failed to connect to data:" + dsn );
103}
104
106StatusCode IODataManager::read( Connection* con, void* const data, size_t len ) {
107 return establishConnection( con ).isSuccess() ? con->read( data, len ) : StatusCode::FAILURE;
108}
109
111StatusCode IODataManager::write( Connection* con, const void* data, int len ) {
112 return establishConnection( con ).isSuccess() ? con->write( data, len ) : StatusCode::FAILURE;
113}
114
116long long int IODataManager::seek( Connection* con, long long int where, int origin ) {
117 return establishConnection( con ).isSuccess() ? con->seek( where, origin ) : -1;
118}
119
121 if ( con ) {
122 std::string dataset = con->name();
123 std::string dsn = dataset;
124 StatusCode sc = con->disconnect();
125 if ( ::strncasecmp( dsn.c_str(), "FID:", 4 ) == 0 )
126 dsn = dataset.substr( 4 );
127 else if ( ::strncasecmp( dsn.c_str(), "LFN:", 4 ) == 0 )
128 dsn = dataset.substr( 4 );
129 else if ( ::strncasecmp( dsn.c_str(), "PFN:", 4 ) == 0 )
130 dsn = dataset.substr( 4 );
131
132 auto j = m_fidMap.find( dataset );
133 if ( j != m_fidMap.end() ) {
134 std::string fid = j->second;
135 std::string gfal_name = "gfal:guid:" + fid;
136 auto i = m_connectionMap.find( fid );
137 m_fidMap.erase( j );
138 if ( ( j = m_fidMap.find( fid ) ) != m_fidMap.end() ) m_fidMap.erase( j );
139 if ( ( j = m_fidMap.find( gfal_name ) ) != m_fidMap.end() ) m_fidMap.erase( j );
140 if ( i != m_connectionMap.end() && i->second ) {
141 IDataConnection* c = i->second->connection;
142 if ( ( j = m_fidMap.find( c->pfn() ) ) != m_fidMap.end() ) m_fidMap.erase( j );
143 if ( c->isConnected() ) {
144 MsgStream log( msgSvc(), name() );
145 c->disconnect().ignore( /* AUTOMATICALLY ADDED FOR gaudi/Gaudi!763 */ );
146 log << MSG::INFO << "Disconnect from dataset " << dsn << " [" << fid << "]" << endmsg;
147 }
148 m_connectionMap.erase( i );
149 }
150 }
151 return sc;
152 }
153 return StatusCode::FAILURE;
154}
155
158 if ( e && e->connection ) {
159 switch ( e->ioType ) {
160 case Connection::READ:
161 sc = e->connection->connectRead();
162 break;
163 case Connection::UPDATE:
164 case Connection::CREATE:
165 case Connection::RECREATE:
166 sc = e->connection->connectWrite( e->ioType );
167 break;
168 default:
169 return StatusCode::FAILURE;
170 }
171 if ( sc.isSuccess() && e->ioType == Connection::READ ) {
172 std::vector<Entry*> to_retire;
173 e->connection->resetAge();
174 transform_copy_if(
175 std::begin( m_connectionMap ), std::end( m_connectionMap ), std::back_inserter( to_retire ),
176 []( ConnectionMap::const_reference i ) { return i.second.get(); },
177 [&]( Entry* i ) {
178 IDataConnection* c = i->connection;
179 return e->connection != c && c->isConnected() && !i->keepOpen && c->ageFile() > m_ageLimit;
180 } );
181 if ( !to_retire.empty() ) {
182 MsgStream log( msgSvc(), name() );
183 std::for_each( std::begin( to_retire ), std::end( to_retire ), [&]( Entry* j ) {
185 c->disconnect().ignore( /* AUTOMATICALLY ADDED FOR gaudi/Gaudi!763 */ );
186 log << MSG::INFO << "Disconnect from dataset " << c->pfn() << " [" << c->fid() << "]" << endmsg;
187 } );
188 }
189 }
190 }
191 return sc;
192}
193
196 auto j = m_fidMap.find( dataset );
197 if ( j == m_fidMap.end() ) return nullptr;
198 auto i = m_connectionMap.find( j->second );
199 return ( i != m_connectionMap.end() ) ? i->second->connection : nullptr;
200}
201
203 if ( !con ) return error( "Severe logic bug: No connection object avalible." );
204
205 if ( con->isConnected() ) {
206 con->resetAge();
207 return StatusCode::SUCCESS;
208 }
209 auto i = m_connectionMap.find( con->name() );
210 if ( i != m_connectionMap.end() ) {
211 Connection* c = i->second->connection;
212 if ( c != con ) {
213 m_incSvc->fireIncident( Incident( con->name(), IncidentType::FailInputFile ) );
214 return error( "Severe logic bug: Twice identical connection object for DSN:" + con->name() );
215 }
216 if ( reconnect( i->second.get() ).isSuccess() ) return StatusCode::SUCCESS;
217 }
218 return StatusCode::FAILURE;
219}
220
221StatusCode IODataManager::connectDataIO( int typ, IoType rw, CSTR dataset, CSTR technology, bool keep_open,
222 Connection* connection ) {
223 MsgStream log( msgSvc(), name() );
224 std::string dsn = dataset;
225 try {
227 if ( ::strncasecmp( dsn.c_str(), "FID:", 4 ) == 0 )
228 dsn = dataset.substr( 4 ), typ = FID;
229 else if ( ::strncasecmp( dsn.c_str(), "LFN:", 4 ) == 0 )
230 dsn = dataset.substr( 4 ), typ = LFN;
231 else if ( ::strncasecmp( dsn.c_str(), "PFN:", 4 ) == 0 )
232 dsn = dataset.substr( 4 ), typ = PFN;
233 else if ( typ == UNKNOWN )
234 return connectDataIO( PFN, rw, dsn, technology, keep_open, connection );
235
236 if ( std::find( s_badFiles.begin(), s_badFiles.end(), dsn ) != s_badFiles.end() ) {
237 m_incSvc->fireIncident( Incident( dsn, IncidentType::FailInputFile ) );
239 }
240 if ( typ == FID ) {
241 auto fi = m_connectionMap.find( dsn );
242 if ( fi == m_connectionMap.end() ) {
244 m_catalog->getPFN( dsn, files );
245 if ( files.empty() ) {
246 if ( !m_useGFAL ) {
247 if ( m_quarantine ) s_badFiles.insert( dsn );
248 m_incSvc->fireIncident( Incident( dsn, IncidentType::FailInputFile ) );
249 error( "connectDataIO> failed to resolve FID:" + dsn ).ignore();
251 } else if ( dsn.length() == 36 && dsn[8] == '-' && dsn[13] == '-' ) {
252 std::string gfal_name = "gfal:guid:" + dsn;
253 m_fidMap[dsn] = m_fidMap[dataset] = m_fidMap[gfal_name] = dsn;
254 sc = connectDataIO( PFN, rw, gfal_name, technology, keep_open, connection );
255 if ( sc.isSuccess() ) return sc;
256 if ( m_quarantine ) s_badFiles.insert( dsn );
257 }
258 if ( m_quarantine ) s_badFiles.insert( dsn );
259 m_incSvc->fireIncident( Incident( dsn, IncidentType::FailInputFile ) );
260 error( "connectDataIO> Failed to resolve FID:" + dsn ).ignore();
262 }
263 // keep track of the current return code before we start iterating over
264 // replicas
265 auto appmgr = serviceLocator()->as<IProperty>();
266 int origReturnCode = Gaudi::getAppReturnCode( appmgr );
267 for ( auto i = files.cbegin(); i != files.cend(); ++i ) {
268 std::string pfn = i->first;
269 if ( i != files.cbegin() ) {
270 log << MSG::WARNING << "Attempt to connect dsn:" << dsn << " with next entry in data federation:" << pfn
271 << "." << endmsg;
272 }
273 sc = connectDataIO( PFN, rw, pfn, technology, keep_open, connection );
274 if ( !sc.isSuccess() ) {
275 if ( m_quarantine ) s_badFiles.insert( pfn );
276 m_incSvc->fireIncident( Incident( pfn, IncidentType::FailInputFile ) );
277 } else {
278 m_fidMap[dsn] = m_fidMap[dataset] = m_fidMap[pfn] = dsn;
279 // we found a working replica, let's reset the return code to the old value
280 Gaudi::setAppReturnCode( appmgr, origReturnCode, true ).ignore();
281 return sc;
282 }
283 }
284 log << MSG::ERROR << "Failed to open dsn:" << dsn << " Federated file could not be resolved from "
285 << files.size() << " entries." << endmsg;
287 }
288 return StatusCode::FAILURE;
289 }
290 std::string fid;
291 auto j = m_fidMap.find( dsn );
292 if ( j == m_fidMap.end() ) {
294 switch ( typ ) {
295 case LFN:
296 fid = m_catalog->lookupLFN( dsn );
297 if ( fid.empty() ) {
298 m_incSvc->fireIncident( Incident( dsn, IncidentType::FailInputFile ) );
299 log << MSG::ERROR << "Failed to resolve LFN:" << dsn << " Cannot access this dataset." << endmsg;
301 }
302 break;
303 case PFN:
304 fid = m_catalog->lookupPFN( dsn );
305 if ( !fid.empty() ) m_catalog->getPFN( fid, files );
306 if ( files.empty() ) {
307 if ( rw == Connection::CREATE || rw == Connection::RECREATE ) {
308 if ( fid.empty() ) fid = m_catalog->createFID();
309 m_catalog->registerPFN( fid, dsn, technology );
310 log << MSG::INFO << "Referring to dataset " << dsn << " by its file ID:" << fid << endmsg;
311 } else {
312 fid = dsn;
313 }
314 }
315 break;
316 }
317 } else {
318 fid = j->second;
319 }
320 if ( typ == PFN ) {
321 // Open PFN
322 auto fi = m_connectionMap.find( fid );
323 if ( fi == m_connectionMap.end() ) {
324 connection->setFID( fid );
325 connection->setPFN( dsn );
326 auto e = std::make_unique<Entry>( technology, keep_open, rw, connection );
327 // Here we open the file!
328 if ( !reconnect( e.get() ).isSuccess() ) {
329 if ( m_quarantine ) s_badFiles.insert( dsn );
330 m_incSvc->fireIncident( Incident( dsn, IncidentType::FailInputFile ) );
331 error( "connectDataIO> Cannot connect to database: PFN=" + dsn + " FID=" + fid ).ignore();
333 }
334 fid = connection->fid();
335 if ( m_connectionMap.contains( fid ) ) {
336 // The FID is the one stored in the file itself, so a copy or replica of a file that is
337 // already connected through another PFN reports the same FID. Track this connection by
338 // its PFN: keying it by the FID would drop its entry and alias its dataset name to the
339 // other connection, which a later disconnect() of this dataset would then tear down.
340 log << MSG::DEBUG << "Dataset " << dsn << " has the same FID " << fid
341 << " as an already connected dataset, tracking it by its PFN" << endmsg;
342 fid = dsn;
343 }
344 m_fidMap[dataset] = m_fidMap[dsn] = m_fidMap[fid] = fid;
345 if ( !( rw == Connection::CREATE || rw == Connection::RECREATE ) ) {
346 if ( !m_disablePFNWarning && strcasecmp( dsn.c_str(), connection->fid().c_str() ) == 0 ) {
347 log << MSG::ERROR << "Referring to existing dataset " << dsn << " by its physical name." << endmsg;
348 log << "You may not be able to navigate back to the input file"
349 << " -- processing continues" << endmsg;
350 }
351 }
352 m_connectionMap.emplace( fid, std::move( e ) );
353 return StatusCode::SUCCESS;
354 }
355 // Here we open the file!
356 if ( !reconnect( fi->second.get() ).isSuccess() ) {
357 if ( m_quarantine ) s_badFiles.insert( dsn );
358 m_incSvc->fireIncident( Incident( dsn, IncidentType::FailInputFile ) );
359 error( "connectDataIO> Cannot connect to database: PFN=" + dsn + " FID=" + fid ).ignore();
361 }
362 return StatusCode::SUCCESS;
363 }
364 sc = connectDataIO( FID, rw, fid, technology, keep_open, connection );
365 if ( !sc.isSuccess() && m_quarantine ) {
366 s_badFiles.insert( fid );
367 } else if ( typ == LFN ) {
368 m_fidMap[dataset] = fid;
369 }
370 return sc;
371 } catch ( std::exception& e ) {
372 error( std::string( "connectDataIO> Caught exception:" ) + e.what() ).ignore();
373 } catch ( ... ) { error( std::string( "connectDataIO> Caught unknown exception" ) ).ignore(); }
374 m_incSvc->fireIncident( Incident( dsn, IncidentType::FailInputFile ) );
375 error( "connectDataIO> The dataset " + dsn + " cannot be opened." ).ignore();
376 s_badFiles.insert( dsn );
378}
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition MsgStream.h:198
#define DECLARE_COMPONENT(type)
MsgStream & error() const
shortcut for the method msgStream(MSG::ERROR)
const SmartIF< IMessageSvc > & msgSvc() const
The standard message service.
MsgStream & msg() const
shortcut for the method msgStream(MSG::INFO)
ABC describing basic data connection.
void resetAge()
Reset age.
virtual StatusCode connectRead()=0
Open data stream in read mode.
virtual StatusCode connectWrite(IoType type)=0
Open data stream in write mode.
std::vector< NamedItem > Files
IDataConnection Connection
Connection type definition.
ConnectionMap m_connectionMap
Map with I/O descriptors.
StatusCode connectRead(bool keep_open, Connection *ioDesc) override
Open data stream in read mode.
FidMap m_fidMap
Map of FID to PFN.
const std::string & CSTR
Gaudi::Property< bool > m_quarantine
StatusCode write(Connection *con, const void *data, int len) override
Write raw byte buffer to output stream.
long long int seek(Connection *ioDesc, long long int where, int origin) override
Seek on the file described by ioDesc. Arguments as in seek().
StatusCode finalize() override
IService implementation: finalize the service.
StatusCode read(Connection *ioDesc, void *const data, size_t len) override
Read raw byte buffer from input stream.
SmartIF< IFileCatalog > m_catalog
Reference to file catalog.
StatusCode disconnect(Connection *ioDesc) override
Release data stream.
Gaudi::Property< std::string > m_catalogSvcName
StatusCode establishConnection(Connection *con)
StatusCode connectWrite(Connection *con, IoType mode=Connection::CREATE, CSTR doctype="UNKNOWN") override
Open data stream in write mode.
Gaudi::Property< bool > m_useGFAL
Connection * connection(const std::string &dsn) const override
Retrieve known connection.
StatusCode reconnect(Entry *e)
Gaudi::Property< bool > m_disablePFNWarning
Gaudi::Property< int > m_ageLimit
StatusCode initialize() override
IService implementation: initialize the service.
Connections connections(const IInterface *owner) const override
Get connection by owner instance (0=ALL).
SmartIF< IIncidentSvc > m_incSvc
StatusCode connectDataIO(int typ, IoType rw, CSTR fn, CSTR technology, bool keep, Connection *con)
Definition of the basic interface.
Definition IInterface.h:225
The IProperty is the basic interface for all components which have properties that can be set or get.
Definition IProperty.h:32
virtual SmartIF< IService > & service(const Gaudi::Utils::TypeNameString &typeName, const bool createIf=true)=0
Returns a smart pointer to a service.
SmartIF< IFace > as()
Definition ISvcLocator.h:64
Base class for all Incidents (computing events).
Definition Incident.h:24
Definition of the MsgStream class used to transmit messages.
Definition MsgStream.h:29
SmartIF< ISvcLocator > & serviceLocator() const override
Retrieve pointer to service locator.
Definition Service.cpp:336
StatusCode finalize() override
Definition Service.cpp:223
const std::string & name() const override
Retrieve name of the service.
Definition Service.cpp:333
StatusCode initialize() override
Definition Service.cpp:118
This class is used for returning status codes from appropriate routines.
Definition StatusCode.h:64
void ignore() const
Allow discarding a StatusCode without warning.
Definition StatusCode.h:128
bool isSuccess() const
Definition StatusCode.h:302
constexpr static const auto SUCCESS
Definition StatusCode.h:99
constexpr static const auto FAILURE
Definition StatusCode.h:100
This file provides a Grammar for the type Gaudi::Accumulators::Axis It allows to use that type from p...
Definition __init__.py:1
int getAppReturnCode(const SmartIF< IProperty > &appmgr)
Get the application (current) return code.
StatusCode setAppReturnCode(SmartIF< IProperty > &appmgr, int value, bool force=false)
Set the application return code.
@ WARNING
Definition IMessageSvc.h:22
@ DEBUG
Definition IMessageSvc.h:22
@ ERROR
Definition IMessageSvc.h:22
@ INFO
Definition IMessageSvc.h:22
IoType ioType
IDataConnection * connection