Belle II Software  release-08-01-10
TestingPayloadStorage Class Reference

Class to store and retrieve temporary payloads. More...

#include <TestingPayloadStorage.h>

Collaboration diagram for TestingPayloadStorage:

Public Member Functions

 TestingPayloadStorage (const std::string &filename)
 Create a new instance to work on a given filename.
 
bool get (const EventMetaData &event, PayloadMetadata &info)
 Try to fill the PayloadMetaData for the given EventMetaData, return true on success, false if no machting payload could be found.
 
bool storeData (const std::string &name, TObject *object, const IntervalOfValidity &iov)
 Store a TObject instance as a payload with given name and interval of validity. More...
 
bool storePayload (const std::string &name, const std::string &fileName, const IntervalOfValidity &iov)
 Store an existing file as payload with given name and interval of validity. More...
 
void reset ()
 Reset the list of known payloads. More...
 

Private Member Functions

void read ()
 Read the given storage file, done lazily on first access to get() after construction or call to reset()
 
bool writePayload (const std::string &fileName, const std::string &name, const TObject *object)
 Write a payload file from the given object and name. More...
 
bool store (const std::string &name, const IntervalOfValidity &iov, const std::string &source, const std::function< bool(const std::string &)> &writer)
 Try to store a new payload with the given name and interval of validity. More...
 

Static Private Member Functions

static std::string payloadFilename (const std::string &path, const std::string &name, const std::string &revision)
 Build the filename for a new payload with a given name and revision in a directory.
 

Private Attributes

std::unordered_map< std::string, std::vector< std::tuple< std::string, IntervalOfValidity > > > m_payloads
 Map of known payloads to a list of known revisions and their interval of validity.
 
std::string m_filename
 Storage file where to look for payloads. More...
 
std::string m_absoluteFilename
 Storage file where to look for payloads converted to an absolute path to be robust against directory changes.
 
std::string m_payloadDir
 Directory containing the storage file as absolute file name. More...
 
bool m_initialized {false}
 Remember whether we read the file already.
 

Detailed Description

Class to store and retrieve temporary payloads.

Temporary payloads are stored in a directory where we create a root files and a plain text file with name, revision and iov for each of these files. This is not very safe but ideal for testing and manual adjustments before final validation and upload to the cental server.

The interface is very basic: We create an instance with a filename and then we either get() payload information for a given event and payload metadata struct or we store a given payload either from an object (storeData()) or from an existing file (storePayload()).

Both call the underlying store() which tries to be robust against multiple processes trying to create payloads at the same time.

Definition at line 39 of file TestingPayloadStorage.h.

Member Function Documentation

◆ reset()

void reset ( void  )
inline

Reset the list of known payloads.

Will trigger re-reading the file on next access to get()

Definition at line 55 of file TestingPayloadStorage.h.

55 { m_initialized = false; }
bool m_initialized
Remember whether we read the file already.

◆ store()

bool store ( const std::string &  name,
const IntervalOfValidity iov,
const std::string &  source,
const std::function< bool(const std::string &)> &  writer 
)
private

Try to store a new payload with the given name and interval of validity.

This function first tries to find the next free revision and then call the writer function to write the payload to the given filename. If the writer function returns success the payload is added to the storage file

Parameters
namepayload name
ioviov for the payload
sourcesource filename to use. If this is empty there is no file yet and it has to be created first
writercallback function to create a file. Will be called with a destination filename if the source parameter was emty

Definition at line 156 of file TestingPayloadStorage.cc.

158  {
159  if (iov.empty()) {
160  B2ERROR("IoV is empty, refusing to store object in testing payload storage"
161  "Please provide a valid experiment/run range for the data, for example "
162  "using IntervalOfValidity::always() to store data which is always valid"
163  << LogVar("name", name));
164  return false;
165  }
166 
167  if (!fs::exists(m_payloadDir)) {
168  fs::create_directories(m_payloadDir);
169  }
170 
171  // create a temporary file if we don't have a source file yet
172  fs::path sourcefile{source};
173  int length = m_payloadDir.length();
174  char* temporaryFileName = new char[length + 16];
175  std::strcpy(temporaryFileName, m_payloadDir.c_str());
176  std::strcpy(temporaryFileName + length, "/payload_XXXXXX");
177  if (source.empty()) {
178  while (true) {
179  int fileDescriptor = mkstemp(temporaryFileName);
180  if ((fileDescriptor == -1) && (errno != EINTR)) {
181  B2ERROR("Cannot create payload file:" << strerror(errno));
182  delete[] temporaryFileName;
183  return false;
184  }
185  if (fileDescriptor > 0) {
186  sourcefile = temporaryFileName;
187  close(fileDescriptor);
188  break;
189  }
190  B2DEBUG(35, "first try to create tempfile failed, trying again");
191  }
192  if (!writer(sourcefile.string())) return false;
193  }
194  delete[] temporaryFileName;
195  // If we created a temporary file we want to delete it again so we'd like to
196  // use a scope guard to do so. However we need it in this scope so we need
197  // to create one in any case and release it if we didn't create a temporary
198  // file
199  ScopeGuard delete_srcfile([&sourcefile] {fs::remove(sourcefile);});
200  if (!source.empty()) delete_srcfile.release();
201 
202  std::string md5 = FileSystem::calculateMD5(sourcefile.string());
203 
204  // Ok, now we have the file and it's md5 sum so let's get a write lock to the database file
205  // to avoid race conditions when creating files and writing the info in the text file.
206  FileSystem::Lock lock(m_absoluteFilename);
207  if (!lock.lock()) {
208  B2ERROR("Locking of testing payload storage file failed, cannot create payload"
209  << LogVar("storage file", m_filename));
210  return false;
211  }
212  std::ofstream file(m_absoluteFilename.c_str(), std::ios::app);
213  if (!file.is_open()) {
214  B2ERROR("Could not open testing payload storage file for writing" << LogVar("storage file", m_filename));
215  }
216 
217  // So let's try renaming our temporary payload file to final destination
218  // We start with a 5 digit hash and expand if there's a collision
219  std::string revision;
220  bool found = false;
221  for (int i = 6; i <= 32; ++i) {
222  revision = md5.substr(0, i);
223  auto filename = payloadFilename(m_payloadDir, name, revision);
224  if (FileSystem::fileExists(filename)) {
225  if (md5 != FileSystem::calculateMD5(filename)) continue;
226  } else {
227  if (source.empty()) {
228  fs::rename(sourcefile, filename);
229  delete_srcfile.release();
230  } else {
231  fs::copy_file(source, filename, fs::copy_options::overwrite_existing);
232  }
233  }
234  found = true;
235  break;
236  }
237  if (!found) {
238  B2ERROR("Cannot create payload file: checksum mismatch for existing files");
239  return false;
240  }
241  // Ok, add to the text file
242  file << "dbstore/" << name << " " << revision << " " << iov << std::endl;
243  B2DEBUG(32, "Storing testing payload" << LogVar("storage file", m_filename) << LogVar("name", name)
244  << LogVar("local revision", revision) << LogVar("iov", iov));
245  // And make sure we reread the file on next request to payloads
246  m_initialized = false;
247  return true;
248  }
std::string m_payloadDir
Directory containing the storage file as absolute file name.
static std::string payloadFilename(const std::string &path, const std::string &name, const std::string &revision)
Build the filename for a new payload with a given name and revision in a directory.
std::string m_filename
Storage file where to look for payloads.
std::string m_absoluteFilename
Storage file where to look for payloads converted to an absolute path to be robust against directory ...
static std::string calculateMD5(const std::string &filename)
Calculate the MD5 checksum of a given file.
Definition: FileSystem.cc:78
static bool fileExists(const std::string &filename)
Check if the file with given filename exists.
Definition: FileSystem.cc:32
Class to store variables with their name which were sent to the logging service.

◆ storeData()

bool storeData ( const std::string &  name,
TObject *  object,
const IntervalOfValidity iov 
)

Store a TObject instance as a payload with given name and interval of validity.

This will create a new ROOT file containing the object in the directory of the storage file

Definition at line 134 of file TestingPayloadStorage.cc.

◆ storePayload()

bool storePayload ( const std::string &  name,
const std::string &  fileName,
const IntervalOfValidity iov 
)

Store an existing file as payload with given name and interval of validity.

This will create a copy of the file with a different name in the directory of the storage file

Definition at line 141 of file TestingPayloadStorage.cc.

◆ writePayload()

bool writePayload ( const std::string &  fileName,
const std::string &  name,
const TObject *  object 
)
private

Write a payload file from the given object and name.

Will create new root file containing object under the Key name with the name fileName

Definition at line 250 of file TestingPayloadStorage.cc.

Member Data Documentation

◆ m_filename

std::string m_filename
private

Storage file where to look for payloads.

This is the logical file name as given by the user

Definition at line 62 of file TestingPayloadStorage.h.

◆ m_payloadDir

std::string m_payloadDir
private

Directory containing the storage file as absolute file name.

Will try to create it if it doesn't exist and storeData() or storePayload() is called

Definition at line 68 of file TestingPayloadStorage.h.


The documentation for this class was generated from the following files: