The Gaudi Framework  master (d98a2936)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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 \***********************************************************************************/
12 #include <Gaudi/Parsers/Factory.h>
13 #include <GaudiKernel/Service.h>
14 #include <GaudiKernel/StatusCode.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 
23 class FileSvc : public extends<Service, Gaudi::Interfaces::IFileSvc> {
24 public:
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 
42 public:
43  // Property to map file identifiers to file paths
45  this, "Config", {}, "Map of keywords to file paths for file access" };
46 
47 private:
55  std::shared_ptr<TFile> openFile( const std::string& filePath, const std::string& option, int compress );
56 
62 
63 private:
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 
73 namespace {
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 
140 FileSvc::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 
174 std::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 
181 bool FileSvc::hasIdentifier( const std::string& identifier ) const {
182  return m_identifiers.find( boost::to_lower_copy( identifier ) ) != m_identifiers.end();
183 }
184 
185 std::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 }
FileSvc::FileSvc
FileSvc(const std::string &name, ISvcLocator *svc)
Definition: FileSvc.cpp:140
FileSvc
Definition: FileSvc.cpp:23
Service::initialize
StatusCode initialize() override
Definition: Service.cpp:118
FileSvc::finalize
StatusCode finalize() override
Definition: FileSvc.cpp:172
StatusCode::andThen
StatusCode andThen(F &&f, ARGS &&... args) const
Chain code blocks making the execution conditional a success result.
Definition: StatusCode.h:163
FileSvc::getFile
std::shared_ptr< TFile > getFile(const std::string &identifier) override
Get a TFile pointer based on an identifier.
Definition: FileSvc.cpp:174
AtlasMCRecoFullPrecedenceDump.path
path
Definition: AtlasMCRecoFullPrecedenceDump.py:49
FileSvc::closeFiles
StatusCode closeFiles()
Close all files.
Definition: FileSvc.cpp:191
ISvcLocator
Definition: ISvcLocator.h:42
FileSvc::initialize
StatusCode initialize() override
Definition: FileSvc.cpp:142
StatusCode.h
Service::name
const std::string & name() const override
Retrieve name of the service
Definition: Service.cpp:333
StatusCode
Definition: StatusCode.h:64
CommonMessaging
Definition: CommonMessaging.h:65
IFileSvc.h
FileSvc::m_config
Gaudi::Property< std::map< std::string, std::string > > m_config
Definition: FileSvc.cpp:44
endmsg
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition: MsgStream.h:198
extends
Base class used to extend a class implementing other interfaces.
Definition: extends.h:19
Service.h
Factory.h
Containers::vector
struct GAUDI_API vector
Parametrisation class for vector-like implementation.
Definition: KeyedObjectManager.h:31
FileSvc::openFile
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
ConditionsStallTest.name
name
Definition: ConditionsStallTest.py:77
StatusCode::SUCCESS
constexpr static const auto SUCCESS
Definition: StatusCode.h:99
DECLARE_COMPONENT
#define DECLARE_COMPONENT(type)
Definition: PluginServiceV1.h:45
FileSvc::hasIdentifier
bool hasIdentifier(const std::string &identifier) const override
Check if a given identifier is known to the service.
Definition: FileSvc.cpp:181
StatusCode::FAILURE
constexpr static const auto FAILURE
Definition: StatusCode.h:100
FileSvc::m_identifiers
std::unordered_map< std::string, size_t > m_identifiers
Definition: FileSvc.cpp:65
Gaudi::Property
Implementation of property with value of concrete type.
Definition: Property.h:35
FileSvc::m_files
std::vector< std::shared_ptr< TFile > > m_files
Definition: FileSvc.cpp:68