Belle II Software  release-08-01-10
MetadataProvider.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/database/MetadataProvider.h>
10 #include <framework/logging/Logger.h>
11 
12 #include <boost/algorithm/string.hpp>
13 
14 namespace Belle2::Conditions {
15  bool MetadataProvider::setTags(const std::vector<std::string>& tags)
16  {
17  m_tags = tags;
18  const size_t validTags = std::count_if(m_tags.begin(), m_tags.end(), [this](const auto & name) {
19  // dispatch obtaining the state to the implementation
20  auto status = getGlobaltagStatus(name);
21  // empty status: Unspecified error already dealt with
22  if (status.empty()) return false;
23  // otherwise check for valid states
24  if (m_usableTagStates.count(status) == 0) {
25  B2ERROR("The globaltag has a status which is not permitted for use. This is for your own protection"
26  << LogVar("globaltag", name)
27  << LogVar("status", status)
28  << LogVar("allowed states", boost::algorithm::join(m_usableTagStates, ", ")));
29  return false;
30  }
31  return true;
32  });
33  return validTags == tags.size();
34  }
35 
36  bool MetadataProvider::getPayloads(int exp, int run, std::vector<PayloadMetadata>& info)
37  {
38  if (info.empty()) return true;
39  for (const auto& tag : m_tags) {
40  // Check whether we already know the payloads for this exp,run ...
41  bool present{false};
42  std::tie(present, m_payloads) = m_cache[tag].get(exp, run);
43  // Apparently not, try to get them
44  if (!present && !updatePayloads(tag, exp, run)) {
45  // Error obtaining payloads means something is wrong (server/network/file problem).
46  // In this case we want to fall back to next metadata provider ...
47  throw std::runtime_error("Problem updating metadata");
48  }
49  // And once we got them let's update the info for all requested payloads
50  const auto& existing = *m_payloads;
51  // and check if we found all payloads we're looking for.
52  // Warning: **DO NOT** use `std::all_of` here which looks better but stops
53  // iteration on the first missing payload instead of going through all the
54  // remaining as well.
55  const size_t found = std::count_if(info.begin(), info.end(), [&existing](auto & payload) {
56  // already filled by previous gt or has a filename from testing payloads ... so don't do anything
57  if (payload.revision > 0 or !payload.filename.empty()) return true;
58  // otherwise look for the payload in the list of existing payloads for this run
59  if (auto&& it = existing.find(payload.name); it != existing.end()) {
60  payload.update(it->second);
61  B2DEBUG(35, "Found requested payload metadata"
62  << LogVar("globaltag", payload.globaltag)
63  << LogVar("name", payload.name)
64  << LogVar("revision", payload.revision)
65  << LogVar("checksum", payload.checksum));
66  return true;
67  }
68  // Not found, fine, not a big problem yet, there can be multiple global tags
69  return false;
70  });
71  // If we found all we don't need to check the next global tag at all ...
72  if (found == info.size()) break;
73  }
74  // Check that all payloads could be found (unless they're optional)
75  // Again, we don't use std::all_of here because then it stops early and we
76  // don't get errors for all missing payloads. But at least it would still be correct.
77  const int missing = std::count_if(info.begin(), info.end(), [this, exp, run](const auto & p) {
78  if (p.revision == 0 and p.filename.empty() and p.required) {
79  B2ERROR("Cannot find payload in any of the configured global tags"
80  << LogVar("name", p.name)
81  << LogVar("globaltags", boost::algorithm::join(m_tags, ", "))
82  << LogVar("experiment", exp) << LogVar("run", run));
83  return true;
84  }
85  return false;
86  });
87  // Only happy without missing payloads
88  return missing == 0;
89  }
90 
91  void MetadataProvider::addPayload(PayloadMetadata&& payload, const std::string& messagePrefix)
92  {
93  const auto [it, inserted] = m_payloads->emplace(payload.name, payload);
94  if (!inserted) {
95  auto& existing = it->second;
96  if (existing.revision < payload.revision) {
97  std::swap(existing, payload);
98  }
99  B2DEBUG(36, messagePrefix << (messagePrefix.empty() ? "" : ": ") << "Found duplicate payload. Discarding one of them"
100  << LogVar("globaltag", existing.globaltag)
101  << LogVar("name", existing.name)
102  << LogVar("revision", existing.revision)
103  << LogVar("checksum", existing.checksum)
104  << LogVar("discarded revision", payload.revision));
105  } else {
106  B2DEBUG(37, messagePrefix << (messagePrefix.empty() ? "" : ": ") << "Found payload"
107  << LogVar("globaltag", payload.globaltag)
108  << LogVar("name", payload.name)
109  << LogVar("revision", payload.revision)
110  << LogVar("checksum", payload.checksum));
111  }
112  }
113 
114  void MetadataProvider::printInfoMessage(const std::string& provider = "")
115  {
116  B2INFO("Conditions Database: found working metadata provider"
117  << LogVar("provider", provider));
118  }
119 
120  std::string NullMetadataProvider::getGlobaltagStatus([[maybe_unused]] const std::string& name)
121  {
122  if (!m_errorShown) B2ERROR("No Metadata provider configured, globaltags cannot be used");
123  m_errorShown = true;
124  return "";
125  }
126 } // Belle2::Conditions namespace
bool setTags(const std::vector< std::string > &tags)
Set the list of globaltag names to be considered for payloads.
std::vector< std::string > m_tags
List of globaltags to consider.
Class to store variables with their name which were sent to the logging service.
Simple struct to group all information necessary for a single payload.