9#include <framework/database/TestingPayloadStorage.h> 
   10#include <framework/dataobjects/EventMetaData.h> 
   11#include <framework/logging/Logger.h> 
   12#include <framework/utilities/FileSystem.h> 
   13#include <framework/utilities/ScopeGuard.h> 
   15#include <TDirectory.h> 
   21#include <boost/algorithm/string.hpp> 
   23namespace fs = std::filesystem;
 
   25namespace Belle2::Conditions {
 
   41    for (
const auto& [revision, iov] : it->second) {
 
   42      if (iov.contains(event)) {
 
   50          B2FATAL(
"Could not find payload file specified in testing payload storage" << 
LogVar(
"storage filen", 
m_filename)
 
   51                  << 
LogVar(
"name", info.name) << 
LogVar(
"local revision", info.revision)
 
   52                  << 
LogVar(
"payload filename", info.filename));
 
   60      B2WARNING(
"Conditions: Temporary testing payload used for processing" << 
LogVar(
"storage file", 
m_filename)
 
   61                << 
LogVar(
"name", info.name) << 
LogVar(
"revision", info.revision) << 
LogVar(
"iov", info.iov));
 
 
   71      B2WARNING(
"Given testing payload storage file doesn't exist or is not a regular file" << 
LogVar(
"storage file", 
m_filename));
 
   76    if (!file.is_open()) {
 
   77      B2FATAL(
"Opening of testing payload storage file failed" << 
LogVar(
"storage file", 
m_filename) << 
LogVar(
"error", strerror(errno)));
 
   84        std::getline(file, line);
 
   87        size_t commentChar = line.find(
'#');
 
   88        if (commentChar != std::string::npos) {
 
   89          line = line.substr(0, commentChar);
 
   92        boost::algorithm::trim(line);
 
   94        if (line.empty()) 
continue;
 
  100          std::stringstream(line) >> name >> revision >> iov;
 
  101        } 
catch (std::runtime_error& e) {
 
  102          throw std::runtime_error(
"line must be of the form 'dbstore/<payloadname> <revision> <firstExp>,<firstRun>,<finalExp>,<finalRun>'");
 
  105        size_t pos = name.find(
'/');
 
  106        if (pos == std::string::npos) {
 
  107          throw std::runtime_error(
"payload name must be of the form dbstore/<payloadname>");
 
  109        std::string module = name.substr(pos + 1, name.length());
 
  112                << 
LogVar(
"revision/md5", revision) << 
LogVar(
"iov", iov));
 
  113        m_payloads[module].emplace_back(revision, iov);
 
  115    } 
catch (std::exception& e) {
 
  116      B2FATAL(
"Problem reading testing payloads storage" << 
LogVar(
"storage file", 
m_filename)
 
  117              << 
LogVar(
"line", lineno) << 
LogVar(
"error", e.what()));
 
  121      std::reverse(payload.second.begin(), payload.second.end());
 
 
  126                                                     const std::string& revision)
 
  128    std::stringstream result;
 
  129    if (!path.empty()) result << path << 
'/';
 
  130    result << 
"dbstore_" << name << 
"_rev_" << revision << 
".root";
 
 
  136    return store(name, iov, 
"", [
this, &
object, &name](
const std::string & filename) {
 
 
  144    fs::path resolved = fs::canonical(fileName);
 
  145    if (not fs::is_regular_file(resolved)) {
 
  146      B2ERROR(
"Problem creating testing payload: Given payload storage file doesn't exist" << 
LogVar(
"storage file", fileName));
 
  149    return store(name, iov, resolved.string(), [&resolved](
const std::string & destination) {
 
  151      fs::copy_file(resolved, destination, fs::copy_options::overwrite_existing);
 
 
  157                                    const std::string& source, 
const std::function<
bool(
const std::string&)>& writer)
 
  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" 
  172    fs::path sourcefile{source};
 
  174    char* temporaryFileName = 
new char[length + 16];
 
  176    std::strcpy(temporaryFileName + length, 
"/payload_XXXXXX");
 
  177    if (source.empty()) {
 
  179        int fileDescriptor = mkstemp(temporaryFileName);
 
  180        if ((fileDescriptor == -1) && (errno != EINTR)) {
 
  181          B2ERROR(
"Cannot create payload file:" << strerror(errno));
 
  182          delete[] temporaryFileName;
 
  185        if (fileDescriptor > 0) {
 
  186          sourcefile = temporaryFileName;
 
  187          close(fileDescriptor);
 
  190        B2DEBUG(35, 
"first try to create tempfile failed, trying again");
 
  192      if (!writer(sourcefile.string())) 
return false;
 
  194    delete[] temporaryFileName;
 
  199    ScopeGuard delete_srcfile([&sourcefile] {fs::remove(sourcefile);});
 
  200    if (!source.empty()) delete_srcfile.
release();
 
  208      B2ERROR(
"Locking of testing payload storage file failed, cannot create payload" 
  213    if (!file.is_open()) {
 
  214      B2ERROR(
"Could not open testing payload storage file for writing" << 
LogVar(
"storage file", 
m_filename));
 
  219    std::string revision;
 
  221    for (
int i = 6; i <= 32; ++i) {
 
  222      revision = md5.substr(0, i);
 
  227        if (source.empty()) {
 
  228          fs::rename(sourcefile, filename);
 
  229          delete_srcfile.release();
 
  231          fs::copy_file(source, filename, fs::copy_options::overwrite_existing);
 
  238      B2ERROR(
"Cannot create payload file: checksum mismatch for existing files");
 
  242    file << 
"dbstore/" << name << 
" " << revision << 
" " << iov << std::endl;
 
  244            << 
LogVar(
"local revision", revision) << 
LogVar(
"iov", iov));
 
 
  253    TDirectory::TContext saveDir;
 
  255    std::unique_ptr<TFile> file{TFile::Open((fileName + 
"?reproducible=PayloadFile").c_str(), 
"RECREATE")};
 
  256    if (!file || !file->IsOpen()) {
 
  257      B2ERROR(
"Could not open payload file for writing." << 
LogVar(
"filename", 
m_filename));
 
  261    object->Write(name.c_str(), TObject::kSingleKey);
 
 
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.
bool m_initialized
Remember whether we read the file already.
std::string m_payloadDir
Directory containing the storage file as absolute file name.
bool writePayload(const std::string &fileName, const std::string &name, const TObject *object)
Write a payload file from the given object and 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::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.
void read()
Read the given storage file, done lazily on first access to get() after construction or call to reset...
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.
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.
bool get(const EventMetaData &event, PayloadMetadata &info)
Try to fill the PayloadMetaData for the given EventMetaData, return true on success,...
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 ...
TestingPayloadStorage(const std::string &filename)
Create a new instance to work on a given filename.
Helper class for locking a file.
bool lock(int timeout=300, bool ignoreErrors=false)
Try to lock the file.
static std::string calculateMD5(const std::string &filename)
Calculate the MD5 checksum of a given file.
static bool fileExists(const std::string &filename)
Check if the file with given filename exists.
A class that describes the interval of experiments/runs for which an object in the database is valid.
Simple ScopeGuard to execute a function at the end of the object lifetime.
void release()
Release the guard without calling the cleanup function.
Class to store variables with their name which were sent to the logging service.