The Gaudi Framework  master (1304469f)
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
23class FileSvc : public extends<Service, Gaudi::Interfaces::IFileSvc> {
24public:
25 // Constructor
26 FileSvc( const std::string& name, ISvcLocator* svc );
27
28 StatusCode initialize() override;
29
30 StatusCode finalize() override;
31
37 std::shared_ptr<TFile> getFile( const std::string& identifier ) override;
38
40 bool hasIdentifier( const std::string& identifier ) const override;
41
42public:
43 // Property to map file identifiers to file paths
45 this, "Config", {}, "Map of keywords to file paths for file access" };
46
47private:
55 std::shared_ptr<TFile> openFile( const std::string& filePath, const std::string& option, int compress );
56
62
63private:
64 // Map holding file identifiers to file indices in the m_files vector
65 std::unordered_map<std::string, size_t> m_identifiers;
66
67 // Vector to hold all files unique pointers
68 std::vector<std::shared_ptr<TFile>> m_files;
69};
70
72
73namespace {
80 std::map<std::string, std::string> parseFilePath( const std::string& path ) {
81 std::vector<std::string> parts;
82 boost::split( parts, path, boost::is_any_of( "?" ) );
83 std::map<std::string, std::string> result;
84 if ( parts.size() > 1 ) {
85 std::vector<std::string> params;
86 boost::split( params, parts[1], boost::is_any_of( "&" ) );
87 for ( auto& param : params ) {
88 std::vector<std::string> kv;
89 boost::split( kv, param, boost::is_any_of( "=" ) );
90 if ( kv.size() == 2 ) { result[boost::trim_copy( kv[0] )] = boost::trim_copy( kv[1] ); }
91 }
92 }
93 result["mode"] = ( result.find( "mode" ) == result.end() ) ? "CREATE" : result["mode"];
94 result["path"] = boost::trim_copy( parts[0] );
95 return result;
96 }
97
107 StatusCode checkConfig( const std::map<std::string, std::string>& configMap, const FileSvc& svc ) {
108 std::map<std::string, std::map<std::string, std::string>> fileParams;
109 for ( const auto& [identifier, path] : configMap ) {
110 auto params = parseFilePath( path );
111
112 auto& existingParams = fileParams[params["path"]];
113 if ( !existingParams.empty() ) {
114 if ( existingParams != params ) {
115 svc.error() << "Conflicting configurations for file path: " << params["path"] << endmsg;
116 return StatusCode::FAILURE;
117 }
118 } else {
119 existingParams = std::move( params );
120 }
121 }
122 return StatusCode::SUCCESS;
123 }
124
132 std::optional<size_t> findFileIndex( const std::vector<std::shared_ptr<TFile>>& files, const std::string& filePath ) {
133 auto it = std::find_if( files.begin(), files.end(),
134 [&filePath]( const auto& file ) { return file && file->GetName() == filePath; } );
135 if ( it != files.end() ) { return std::distance( files.begin(), it ); }
136 return std::nullopt;
137 }
138} // namespace
139
140FileSvc::FileSvc( const std::string& name, ISvcLocator* svc ) : base_class( name, svc ) {}
141
143 return Service::initialize().andThen( [this]() {
144 if ( checkConfig( m_config, *this ).isFailure() ) { return StatusCode::FAILURE; }
145
146 for ( const auto& [identifier, path] : m_config ) {
147 auto params = parseFilePath( path );
148
149 // Check if this file is already opened and mapped
150 if ( auto fileIndex = findFileIndex( m_files, params["path"] ) ) {
151 // File already opened, just map the identifier to the existing index
152 m_identifiers[boost::to_lower_copy( identifier )] = *fileIndex;
153 } else {
154 // File not found, open a new one
155 int compress = ( params.find( "compress" ) != params.end() )
156 ? std::stoi( params["compress"] )
157 : ROOT::RCompressionSetting::EDefaults::kUseCompiledDefault;
158 if ( auto file = openFile( path, params["mode"], compress ) ) {
159 m_files.push_back( std::move( file ) );
160 m_identifiers[boost::to_lower_copy( identifier )] = m_files.size() - 1;
161 } else {
162 error() << "Failed to open file: " << params["path"] << endmsg;
163 return StatusCode::FAILURE;
164 }
165 }
166 }
167
168 return StatusCode::SUCCESS;
169 } );
170}
171
173
174std::shared_ptr<TFile> FileSvc::getFile( const std::string& identifier ) {
175 auto it = m_identifiers.find( boost::to_lower_copy( identifier ) );
176 if ( it != m_identifiers.end() && it->second < m_files.size() ) { return m_files[it->second]; }
177 error() << "No file associated with identifier: " << identifier << endmsg;
178 return nullptr;
179}
180
181bool FileSvc::hasIdentifier( const std::string& identifier ) const {
182 return m_identifiers.find( boost::to_lower_copy( identifier ) ) != m_identifiers.end();
183}
184
185std::shared_ptr<TFile> FileSvc::openFile( const std::string& filePath, const std::string& option, int compress ) {
186 auto file = std::make_shared<TFile>( filePath.c_str(), option.c_str(), "", compress );
187 if ( !file || file->IsZombie() ) { return nullptr; }
188 return file;
189}
190
192 for ( const auto& file : m_files ) {
193 if ( file ) { file->Close(); }
194 }
195 m_files.clear();
196 m_identifiers.clear();
197 return StatusCode::SUCCESS;
198}
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)
Gaudi::Property< std::map< std::string, std::string > > m_config
Definition FileSvc.cpp:44
StatusCode closeFiles()
Close all files.
Definition FileSvc.cpp:191
std::vector< std::shared_ptr< TFile > > m_files
Definition FileSvc.cpp:68
StatusCode initialize() override
Definition FileSvc.cpp:142
bool hasIdentifier(const std::string &identifier) const override
Check if a given identifier is known to the service.
Definition FileSvc.cpp:181
StatusCode finalize() override
Definition FileSvc.cpp:172
std::unordered_map< std::string, size_t > m_identifiers
Definition FileSvc.cpp:65
FileSvc(const std::string &name, ISvcLocator *svc)
Definition FileSvc.cpp:140
std::shared_ptr< TFile > getFile(const std::string &identifier) override
Get a TFile pointer based on an identifier.
Definition FileSvc.cpp:174
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:185
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