Belle II Software development
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
14namespace 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.