The Gaudi Framework  master (fcd9f667)
Loading...
Searching...
No Matches
FileSvc.cpp
Go to the documentation of this file.
1/***********************************************************************************\
2* (c) Copyright 2024-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\***********************************************************************************/
15#include <GaudiKernel/Service.h>
17#include <TFile.h>
18#include <boost/algorithm/string.hpp>
19#include <memory>
20#include <optional>
21#include <string>
22#include <unordered_map>
23#include <vector>
24
42class FileSvc : public extends<Service, Gaudi::Interfaces::IFileSvc> {
43public:
44 // Constructor
45 FileSvc( const std::string& name, ISvcLocator* svc );
46
47 StatusCode initialize() override;
48
49 StatusCode finalize() override;
50
57 std::shared_ptr<TFile> getFile( const std::string& identifier ) override;
58
60 bool hasIdentifier( const std::string& identifier ) const override;
61
62public:
63 // See FileSvc documentation for the syntax supported for paths
65 this, "Config", {}, "Map of keywords to file paths for file access" };
66
67private:
76 std::shared_ptr<TFile> openFile( const std::string& filePath, const std::string& option, int compress );
77
83
84private:
85 // Map holding file identifiers to file indices in the m_files vector
86 std::unordered_map<std::string, size_t> m_identifiers;
87
88 // Vector to hold all files unique pointers
89 std::vector<std::shared_ptr<TFile>> m_files;
90};
91
93
94namespace {
101 std::map<std::string, std::string> parseFilePath( const std::string& path ) {
102 std::vector<std::string> parts;
103 boost::split( parts, path, boost::is_any_of( "?" ) );
104 std::map<std::string, std::string> result;
105 if ( parts.size() > 1 ) {
106 std::vector<std::string> params;
107 boost::split( params, parts[1], boost::is_any_of( "&" ) );
108 for ( auto& param : params ) {
109 std::vector<std::string> kv;
110 boost::split( kv, param, boost::is_any_of( "=" ) );
111 if ( kv.size() == 2 ) { result[boost::trim_copy( kv[0] )] = boost::trim_copy( kv[1] ); }
112 }
113 }
114 result["mode"] = ( result.find( "mode" ) == result.end() ) ? "CREATE" : result["mode"];
115 result["path"] = boost::trim_copy( parts[0] );
116 return result;
117 }
118
128 StatusCode checkConfig( const std::map<std::string, std::string>& configMap, const FileSvc& svc ) {
129 std::map<std::string, std::map<std::string, std::string>> fileParams;
130 for ( const auto& [identifier, path] : configMap ) {
131 auto params = parseFilePath( path );
132
133 auto& existingParams = fileParams[params["path"]];
134 if ( !existingParams.empty() ) {
135 if ( existingParams != params ) {
136 svc.error() << "Conflicting configurations for file path: " << params["path"] << endmsg;
137 return StatusCode::FAILURE;
138 }
139 } else {
140 existingParams = std::move( params );
141 }
142 }
143 return StatusCode::SUCCESS;
144 }
145
153 std::optional<size_t> findFileIndex( const std::vector<std::shared_ptr<TFile>>& files, const std::string& filePath ) {
154 auto it = std::find_if( files.begin(), files.end(),
155 [&filePath]( const auto& file ) { return file && file->GetName() == filePath; } );
156 if ( it != files.end() ) { return std::distance( files.begin(), it ); }
157 return std::nullopt;
158 }
159} // namespace
160
161FileSvc::FileSvc( const std::string& name, ISvcLocator* svc ) : base_class( name, svc ) {}
162
164 return Service::initialize().andThen( [this]() {
165 auto incidentSvc = service<IIncidentSvc>( "IncidentSvc", false );
166
167 if ( checkConfig( m_config, *this ).isFailure() ) { return StatusCode::FAILURE; }
168
169 for ( const auto& [identifier, path] : m_config ) {
170 auto params = parseFilePath( path );
171
172 // Check if this file is already opened and mapped
173 if ( auto fileIndex = findFileIndex( m_files, params["path"] ) ) {
174 // File already opened, just map the identifier to the existing index
175 m_identifiers[boost::to_lower_copy( identifier )] = *fileIndex;
176 } else {
177 // File not found, open a new one
178 int compress = ( params.find( "compress" ) != params.end() )
179 ? std::stoi( params["compress"] )
180 : ROOT::RCompressionSetting::EDefaults::kUseCompiledDefault;
181 if ( auto file = openFile( path, params["mode"], compress ) ) {
182 m_files.push_back( std::move( file ) );
183 m_identifiers[boost::to_lower_copy( identifier )] = m_files.size() - 1;
184 auto* outputFile = m_files.back().get();
185 if ( incidentSvc ) {
186 incidentSvc->fireIncident(
187 ContextIncident<TFile*>( outputFile->GetName(), "CONNECTED_OUTPUT", outputFile ) );
188 }
189 } else {
190 error() << "Failed to open file: " << params["path"] << endmsg;
191 return StatusCode::FAILURE;
192 }
193 }
194 }
195
196 return StatusCode::SUCCESS;
197 } );
198}
199
201
202std::shared_ptr<TFile> FileSvc::getFile( const std::string& identifier ) {
203 auto it = m_identifiers.find( boost::to_lower_copy( identifier ) );
204 if ( it != m_identifiers.end() && it->second < m_files.size() ) { return m_files[it->second]; }
205 error() << "No file associated with identifier: " << identifier << endmsg;
206 return nullptr;
207}
208
209bool FileSvc::hasIdentifier( const std::string& identifier ) const {
210 return m_identifiers.find( boost::to_lower_copy( identifier ) ) != m_identifiers.end();
211}
212
213std::shared_ptr<TFile> FileSvc::openFile( const std::string& filePath, const std::string& option, int compress ) {
214 auto file = std::make_shared<TFile>( filePath.c_str(), option.c_str(), "", compress );
215 if ( !file || file->IsZombie() ) { return nullptr; }
216 return file;
217}
218
220 for ( const auto& file : m_files ) {
221 if ( file ) { file->Close(); }
222 }
223 m_files.clear();
224 m_identifiers.clear();
225 return StatusCode::SUCCESS;
226}
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)
Implementation of the IFileSvc interface, allowing algorithms to access ROOT files via a centralized ...
Definition FileSvc.cpp:42
Gaudi::Property< std::map< std::string, std::string > > m_config
Definition FileSvc.cpp:64
StatusCode closeFiles()
Close all files.
Definition FileSvc.cpp:219
std::vector< std::shared_ptr< TFile > > m_files
Definition FileSvc.cpp:89
StatusCode initialize() override
Definition FileSvc.cpp:163
bool hasIdentifier(const std::string &identifier) const override
Check if a given identifier is known to the service.
Definition FileSvc.cpp:209
StatusCode finalize() override
Definition FileSvc.cpp:200
std::unordered_map< std::string, size_t > m_identifiers
Definition FileSvc.cpp:86
FileSvc(const std::string &name, ISvcLocator *svc)
Definition FileSvc.cpp:161
std::shared_ptr< TFile > getFile(const std::string &identifier) override
Get a TFile pointer based on an identifier.
Definition FileSvc.cpp:202
std::shared_ptr< TFile > openFile(const std::string &filePath, const std::string &option, int compress)
Open a file based on a specified path and opening mode.
Definition FileSvc.cpp:213
Implementation of property with value of concrete type.
Definition Property.h:35
The ISvcLocator is the interface implemented by the Service Factory in the Application Manager to loc...
Definition ISvcLocator.h:42
const std::string & name() const override
Retrieve name of the service.
Definition Service.cpp:333
SmartIF< IFace > service(const std::string &name, bool createIf=true) const
Definition Service.h:79
StatusCode initialize() override
Definition Service.cpp:118
This class is used for returning status codes from appropriate routines.
Definition StatusCode.h:64
StatusCode andThen(F &&f, ARGS &&... args) const
Chain code blocks making the execution conditional a success result.
Definition StatusCode.h:151
constexpr static const auto SUCCESS
Definition StatusCode.h:99
constexpr static const auto FAILURE
Definition StatusCode.h:100
Base class used to extend a class implementing other interfaces.
Definition extends.h:19