Belle II Software  release-08-01-10
FileCatalog.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 
9 #include <framework/core/FileCatalog.h>
10 #include <framework/dataobjects/FileMetaData.h>
11 #include <framework/logging/Logger.h>
12 #include <framework/utilities/FileSystem.h>
13 #include <framework/utilities/EnvironmentVariables.h>
14 
15 #include <fstream>
16 #include <filesystem>
17 
18 using namespace Belle2;
19 namespace fs = std::filesystem;
20 
21 
22 
24 {
25  static FileCatalog instance;
26  return instance;
27 }
28 
29 
30 FileCatalog::FileCatalog() : m_fileName("")
31 {
32  // check for BELLE2_FILECATALOG environment variable
33  std::string fileCatalog = EnvironmentVariables::get("BELLE2_FILECATALOG", "");
34  if (fileCatalog == "NONE") return;
35 
36  // check for file catalog in home directory
37  if (fileCatalog.empty()) {
38  const std::string path{"~/Belle2FileCatalog.xml"};
39  if (fs::exists(path)) {
40  fileCatalog = path;
41  }
42  }
43 
44  // use file catalog in current directory if nothing else found
45  if (fileCatalog.empty()) {
46  fileCatalog = "Belle2FileCatalog.xml";
47  }
48 
49  // get absolute path name
50  m_fileName = fs::absolute(fileCatalog).c_str();
51 }
52 
53 
55 {
56  fileMap.clear();
57 
58  std::ifstream file(m_fileName.c_str());
59  if (!file.is_open()) return false;
60 
61  try {
62  while (!file.eof()) {
63  FileMetaData entry;
64  std::string physicalFileName;
65  if (entry.read(file, physicalFileName)) fileMap[entry.getLfn()] = std::make_pair(physicalFileName, entry);
66  }
67  } catch (std::exception& e) {
68  B2ERROR("Errors occured while reading " << m_fileName <<
69  ", maybe it is corrupted? Note that your .root files should be unaffected. (Error details: " << e.what() << ")");
70  return false;
71  }
72 
73  return true;
74 }
75 
76 
78 {
79  std::ofstream file(m_fileName.c_str());
80  if (!file.is_open()) return false;
81 
82  file << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
83  file << "<FileCatalog>\n";
84  for (const auto& entry : fileMap) entry.second.second.write(file, entry.second.first);
85  file << "</FileCatalog>\n";
86 
87  return true;
88 }
89 
90 bool FileCatalog::registerFile(const std::string& fileName, FileMetaData& metaData, const std::string& oldLFN)
91 {
92  if (m_fileName.empty()) return false;
93 
94  // make sure we have an LFN
95  if (metaData.getLfn().empty()) {
96  B2ERROR("Cannot register a file without a valid LFN");
97  return false;
98  }
99 
100  // get lock for write access to file catalog
102  if (!lock.lock()) {
103  B2ERROR("Locking of file catalog " << m_fileName << " failed.");
104  return false;
105  }
106 
107  // read the file catalog
108  FileMap fileMap;
109  if (!readCatalog(fileMap)) {
110  B2ERROR("Failed to read file catalog " << m_fileName);
111  return false;
112  }
113 
114  // check whether a file with this name is already registered and remove if so
115  for (auto it = fileMap.begin(); it != fileMap.end(); ++it) {
116  auto&& lfn = (*it).first;
117  if (!oldLFN.empty() and oldLFN == lfn) {
118  // old LFN exists and we requested an update so no warning, just remove
119  fileMap.erase(it);
120  break;
121  }
122  if (metaData.getLfn() == lfn) {
123  B2WARNING("A file with the same LFN is already registered and will be overwritten in the catalog."
124  << LogVar("LFN", lfn) << LogVar("old PFN", (*it).second.first) << LogVar("new PFN", fileName));
125  fileMap.erase(it);
126  break;
127  }
128  }
129 
130  // add the new entry and write the file catalog
131  fileMap[metaData.getLfn()] = std::make_pair(fileName, metaData);
132 
133  if (!writeCatalog(fileMap)) {
134  B2ERROR("Failed to write file catalog " << m_fileName);
135  return false;
136  }
137 
138  return true;
139 }
140 
141 
142 bool FileCatalog::getMetaData(std::string& fileName, FileMetaData& metaData)
143 {
144  metaData = FileMetaData();
145  if (m_fileName.empty()) return false;
146  if (!fs::exists(m_fileName)) return false;
147 
148  // get lock for read access to file catalog
149  FileSystem::Lock lock(m_fileName, true);
150  if (!lock.lock()) {
151  B2ERROR("Locking of file catalog " << m_fileName << " failed.");
152  return false;
153  }
154 
155  // read the file catalog
156  FileMap fileMap;
157  if (!readCatalog(fileMap)) {
158  B2ERROR("Failed to read file catalog " << m_fileName);
159  return false;
160  }
161 
162  // find the entry with given LFN
163  auto iEntry = fileMap.find(fileName);
164  if (iEntry != fileMap.end()) {
165  metaData = iEntry->second.second;
166  if (!iEntry->second.first.empty()) fileName = iEntry->second.first;
167  return true;
168  }
169  for (const auto& entry : fileMap) {
170  if (fileName.compare(entry.second.first) == 0) {
171  metaData = entry.second.second;
172  return true;
173  }
174  }
175 
176  return false;
177 }
178 
179 
180 std::string FileCatalog::getPhysicalFileName(const std::string& lfn)
181 {
182  std::string fileName = lfn;
183  FileMetaData metaData;
184  if (!getMetaData(fileName, metaData)) {
185  B2DEBUG(100, "No LFN " << lfn << " found in the file catalog.");
186  }
187  return fileName;
188 }
This class provides an interface to the file (metadata) catalog.
Definition: FileCatalog.h:24
static FileCatalog & Instance()
Static method to get a reference to the FileCatalog instance.
Definition: FileCatalog.cc:23
virtual bool registerFile(const std::string &fileName, FileMetaData &metaData, const std::string &oldLFN="")
Register a file in the (local) file catalog.
Definition: FileCatalog.cc:90
std::map< std::string, std::pair< std::string, FileMetaData > > FileMap
Map with file catalog content.
Definition: FileCatalog.h:71
virtual bool getMetaData(std::string &fileName, FileMetaData &metaData)
Get the metadata of a file with given (logical) file name.
Definition: FileCatalog.cc:142
virtual std::string getPhysicalFileName(const std::string &lfn)
Get the physical file name for the LFN.
Definition: FileCatalog.cc:180
std::string m_fileName
Name of the file catalog file.
Definition: FileCatalog.h:89
bool writeCatalog(const FileMap &fileMap)
Write the file catalog to the local file.
Definition: FileCatalog.cc:77
FileCatalog()
Constructor: locate local database file.
Definition: FileCatalog.cc:30
bool readCatalog(FileMap &fileMap)
Read the file catalog from the local file.
Definition: FileCatalog.cc:54
Metadata information about a file.
Definition: FileMetaData.h:29
const std::string & getLfn() const
Logical file name getter.
Definition: FileMetaData.h:37
bool read(std::istream &input, std::string &physicalFileName)
Read file meta data in xml format from the input stream.
Helper class for locking a file.
Definition: FileSystem.h:97
bool lock(int timeout=300, bool ignoreErrors=false)
Try to lock the file.
Definition: FileSystem.cc:186
Class to store variables with their name which were sent to the logging service.
static std::string get(const std::string &name, const std::string &fallback="")
Get the value of an environment variable or the given fallback value if the variable is not set.
Abstract base class for different kinds of events.