The Gaudi Framework  master (2df85225)
Loading...
Searching...
No Matches
FileSvc.cpp
Go to the documentation of this file.
1/***********************************************************************************\
2* (c) Copyright 2024-2025 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\***********************************************************************************/
13#include <GaudiKernel/Service.h>
15#include <TFile.h>
16#include <boost/algorithm/string.hpp>
17#include <memory>
18#include <optional>
19#include <string>
20#include <unordered_map>
21#include <vector>
22
39class FileSvc : public extends<Service, Gaudi::Interfaces::IFileSvc> {
40public:
41 // Constructor
42 FileSvc( const std::string& name, ISvcLocator* svc );
43
44 StatusCode initialize() override;
45
46 StatusCode finalize() override;
47
54 std::shared_ptr<TFile> getFile( const std::string& identifier ) override;
55
57 bool hasIdentifier( const std::string& identifier ) const override;
58
59public:
60 // See FileSvc documentation for the syntax supported for paths
62 this, "Config", {}, "Map of keywords to file paths for file access" };
63
64private:
73 std::shared_ptr<TFile> openFile( const std::string& filePath, const std::string& option, int compress );
74
80
81private:
82 // Map holding file identifiers to file indices in the m_files vector
83 std::unordered_map<std::string, size_t> m_identifiers;
84
85 // Vector to hold all files unique pointers
86 std::vector<std::shared_ptr<TFile>> m_files;
87};
88
90
91namespace {
98 std::map<std::string, std::string> parseFilePath( const std::string& path ) {
99 std::vector<std::string> parts;
100 boost::split( parts, path, boost::is_any_of( "?" ) );
101 std::map<std::string, std::string> result;
102 if ( parts.size() > 1 ) {
103 std::vector<std::string> params;
104 boost::split( params, parts[1], boost::is_any_of( "&" ) );
105 for ( auto& param : params ) {
106 std::vector<std::string> kv;
107 boost::split( kv, param, boost::is_any_of( "=" ) );
108 if ( kv.size() == 2 ) { result[boost::trim_copy( kv[0] )] = boost::trim_copy( kv[1] ); }
109 }
110 }
111 result["mode"] = ( result.find( "mode" ) == result.end() ) ? "CREATE" : result["mode"];
112 result["path"] = boost::trim_copy( parts[0] );
113 return result;
114 }
115
125 StatusCode checkConfig( const std::map<std::string, std::string>& configMap, const FileSvc& svc ) {
126 std::map<std::string, std::map<std::string, std::string>> fileParams;
127 for ( const auto& [identifier, path] : configMap ) {
128 auto params = parseFilePath( path );
129
130 auto& existingParams = fileParams[params["path"]];
131 if ( !existingParams.empty() ) {
132 if ( existingParams != params ) {
133 svc.error() << "Conflicting configurations for file path: " << params["path"] << endmsg;
134 return StatusCode::FAILURE;
135 }
136 } else {
137 existingParams = std::move( params );
138 }
139 }
140 return StatusCode::SUCCESS;
141 }
142
150 std::optional<size_t> findFileIndex( const std::vector<std::shared_ptr<TFile>>& files, const std::string& filePath ) {
151 auto it = std::find_if( files.begin(), files.end(),
152 [&filePath]( const auto& file ) { return file && file->GetName() == filePath; } );
153 if ( it != files.end() ) { return std::distance( files.begin(), it ); }
154 return std::nullopt;
155 }
156} // namespace
157
158FileSvc::FileSvc( const std::string& name, ISvcLocator* svc ) : base_class( name, svc ) {}
159
161 return Service::initialize().andThen( [this]() {
162 if ( checkConfig( m_config, *this ).isFailure() ) { return StatusCode::FAILURE; }
163
164 for ( const auto& [identifier, path] : m_config ) {
165 auto params = parseFilePath( path );
166
167 // Check if this file is already opened and mapped
168 if ( auto fileIndex = findFileIndex( m_files, params["path"] ) ) {
169 // File already opened, just map the identifier to the existing index
170 m_identifiers[boost::to_lower_copy( identifier )] = *fileIndex;
171 } else {
172 // File not found, open a new one
173 int compress = ( params.find( "compress" ) != params.end() )
174 ? std::stoi( params["compress"] )
175 : ROOT::RCompressionSetting::EDefaults::kUseCompiledDefault;
176 if ( auto file = openFile( path, params["mode"], compress ) ) {
177 m_files.push_back( std::move( file ) );
178 m_identifiers[boost::to_lower_copy( identifier )] = m_files.size() - 1;
179 } else {
180 error() << "Failed to open file: " << params["path"] << endmsg;
181 return StatusCode::FAILURE;
182 }
183 }
184 }
185
186 return StatusCode::SUCCESS;
187 } );
188}
189
191
192std::shared_ptr<TFile> FileSvc::getFile( const std::string& identifier ) {
193 auto it = m_identifiers.find( boost::to_lower_copy( identifier ) );
194 if ( it != m_identifiers.end() && it->second < m_files.size() ) { return m_files[it->second]; }
195 error() << "No file associated with identifier: " << identifier << endmsg;
196 return nullptr;
197}
198
199bool FileSvc::hasIdentifier( const std::string& identifier ) const {
200 return m_identifiers.find( boost::to_lower_copy( identifier ) ) != m_identifiers.end();
201}
202
203std::shared_ptr<TFile> FileSvc::openFile( const std::string& filePath, const std::string& option, int compress ) {
204 auto file = std::make_shared<TFile>( filePath.c_str(), option.c_str(), "", compress );
205 if ( !file || file->IsZombie() ) { return nullptr; }
206 return file;
207}
208
210 for ( const auto& file : m_files ) {
211 if ( file ) { file->Close(); }
212 }
213 m_files.clear();
214 m_identifiers.clear();
215 return StatusCode::SUCCESS;
216}
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:39
Gaudi::Property< std::map< std::string, std::string > > m_config
Definition FileSvc.cpp:61
StatusCode closeFiles()
Close all files.
Definition FileSvc.cpp:209
std::vector< std::shared_ptr< TFile > > m_files
Definition FileSvc.cpp:86
StatusCode initialize() override
Definition FileSvc.cpp:160
bool hasIdentifier(const std::string &identifier) const override
Check if a given identifier is known to the service.
Definition FileSvc.cpp:199
StatusCode finalize() override
Definition FileSvc.cpp:190
std::unordered_map< std::string, size_t > m_identifiers
Definition FileSvc.cpp:83
FileSvc(const std::string &name, ISvcLocator *svc)
Definition FileSvc.cpp:158
std::shared_ptr< TFile > getFile(const std::string &identifier) override
Get a TFile pointer based on an identifier.
Definition FileSvc.cpp:192
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:203
Implementation of property with value of concrete type.
Definition PropertyFwd.h:27
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
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:163
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