ATLAS Offline Software
Loading...
Searching...
No Matches
TrigDBLoader.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7#include "./TrigDBHelper.h"
8
9#include "CoralBase/Exception.h"
10#include "CoralBase/Blob.h"
11
12#include "RelationalAccess/ConnectionService.h"
13#include "RelationalAccess/IConnectionServiceConfiguration.h"
14#include "RelationalAccess/ISessionProxy.h"
15#include "RelationalAccess/ISchema.h"
16
17#include "CrestApi/CrestApiBase.h"
18#include "CrestApi/CrestRequest.h"
19
20#include "boost/property_tree/ptree.hpp"
21#include <fstream>
22#include <format>
23
24using ptree = boost::property_tree::ptree;
25
26TrigConf::TrigDBLoader::TrigDBLoader(const std::string & loaderName, const std::string & connection) :
27 TrigConfMessaging(loaderName),
28 m_connection(connection)
29{
30
31
32}
33
34// Destructor defined here because QueryDefinition is an incomplete type in the header
36
37size_t
38TrigConf::TrigDBLoader::schemaVersion(coral::ISessionProxy* session) const {
39
40 static const std::string versionTagPrefix("Trigger-Run3-Schema-v");
41
42 // if database has no schema version, then we return 0
43 if(! session->nominalSchema().existsTable("TRIGGER_SCHEMA") ) {
44 throw std::runtime_error( "Trigger schema has no schema version table" );
45 }
46
48 // tables
49 qdef.addToTableList ( "TRIGGER_SCHEMA" );
50 // attributes
51 qdef.extendOutput<std::string>( "TS_TAG" );
52
53 auto query = qdef.createQuery( session );
54 auto & cursor = query->execute();
55 if ( ! cursor.next() ) {
56 throw std::runtime_error( "Trigger schema has schema version table but it is empty" );
57 }
58
59 const coral::AttributeList& row = cursor.currentRow();
60 std::string versionTag = row["TS_TAG"].data<std::string>();
61 if( ! versionTag.starts_with(versionTagPrefix)) {
62 throw std::runtime_error(std::format("Tag format error: Trigger schema version tag {} does not start with {}", versionTag, versionTagPrefix));
63 }
64
65 std::string vstr = versionTag.substr(versionTagPrefix.size()); // the part of the string containing the version
66 size_t schemaVersion{0};
67 try {
68 schemaVersion = std::stoi(vstr);
69 }
70 catch (const std::invalid_argument& ia) {
71 TRG_MSG_ERROR("Invalid argument when interpreting the version part " << vstr << " of schema tag " << versionTag << ". " << ia.what());
72 throw;
73 }
74
75 TRG_MSG_INFO("TriggerDB schema version: " << schemaVersion);
76 return schemaVersion;
77}
78
79void
80TrigConf::TrigDBLoader::setCrestConnection(const std::string & server, const std::string & version) {
81 // server
82 m_crestServer = server;
83 if(m_crestServer.ends_with('/')) { // remove trailing '/'
84 m_crestServer.pop_back();
85 }
86
87 // use crest flag
88 m_useCrest = ! m_crestServer.empty();
89
90 // version
91 if(version.empty()) {
92 m_crestVersion = DEFAULT_CREST_API_VERSION; // defined in CrestApi/CrestApiBase.h
93 } else {
94 m_crestVersion = version;
95 }
96 if(!m_crestVersion.starts_with('/')) { // prepend '/' if not existent
98 }
99}
100
101void
102TrigConf::TrigDBLoader::setCrestTrigDB(const std::string & crestTrigDB) {
103 m_crestTrigDb = crestTrigDB;
104}
105
106std::unique_ptr<coral::ISessionProxy>
108
109 coral::ConnectionService connSvc;
110 coral::IConnectionServiceConfiguration& csc = connSvc.configuration();
111 csc.setConnectionRetrialPeriod( m_retrialPeriod );
112 csc.setConnectionRetrialTimeOut( m_retrialTimeout );
113 csc.setConnectionTimeOut( m_connectionTimeout );
114
115 /* TODO
116 if(csc.replicaSortingAlgorithm() == nullptr) { // likely to be standalone, create our own
117 TRG_MSG_INFO("Create own ReplicaSortingAlgorithm");
118 m_replicaSorter = new TrigConf::ReplicaSorter();
119 csc.setReplicaSortingAlgorithm(*m_replicaSorter);
120 }
121 */
122
123 TRG_MSG_INFO("Connecting to " << m_connection);
124
125 auto proxy = std::unique_ptr<coral::ISessionProxy>( connSvc.connect(m_connection, coral::AccessMode::ReadOnly) );
126
127 TRG_MSG_INFO("Opened session " << m_connection << " with retrialPeriod/retrialTimeout/connectionTimeout: "
129
130 return proxy;
131}
132
133std::string
134TrigConf::TrigDBLoader::getTrigDataCrest(const std::string & type, int key) const {
135 /*
136 To get the trigger data from the TriggerDB using CrestApi, it has been agreed to
137 use the API's payload query with a special specifier
138
139 triggerdb://<TrigDBSpec>/<TypeSpec>/<DBKey>
140
141 Possible TrigDBSpec: CONF_DATA_RUN3, CONF_MC_RUN3, CONF_REPR_RUN3
142 Possible TypeSpec: L1PS, HLTM, L1M, HLTPS, BGS, MGS, JO
143 */
144
145 std::string url = m_crestServer + m_crestVersion;
146 std::string query = std::format("triggerdb://{}/{}/{}", m_crestTrigDb, type, key);
147
148#if 0
149 /*
150 the final implementation should be the code below
151 however, in the version used by 24.0 the function CrestApi.getPayload(hash) does not work
152 for the trigger: it includes a hash validation that is not applicable for the trigger
153 but only for conditions payload queries by hash
154 */
155 Crest::CrestApi capi = Crest::CrestApi(url);
156 std::string payload = capi.getPayload(query);
157#else
158 /*
159 so for release 24.0 and until the access to the trigger payload is implemented in CrestApi
160 the CrestRequest is build manually. Luckily all needed functionality is accessible
161 (this code is a copy of CrestApi::getPayload() without the checkHash())
162 */
163 Crest::CrestRequest request = Crest::CrestRequest();
164 request.setUrl(url);
165 std::string current_path = "payloads/data?format=BLOB&hash=" + query;
166 nlohmann::json js = nullptr;
167 std::string payload = request.performRequest(current_path, Crest::Action::GET, js, "TrigDbLoader");
168#endif
169
170 return payload;
171}
172
175 const std::map<size_t, TrigConf::QueryDefinition> & queries) const
176{
177 // find the largest version key in the map of defined queries that is <= the schemaVersion
178 size_t maxDefVersion = 0;
179 for(auto & entry : queries) {
180 size_t vkey = entry.first;
181 if(vkey>maxDefVersion and vkey<=schemaVersion) {
182 maxDefVersion = vkey;
183 }
184 }
185 // if nothing found, throw an error
186 if( maxDefVersion==0 ) {
187 TRG_MSG_ERROR("No query for schema version " << schemaVersion << " defined" );
188 throw TrigConf::NoQueryException(std::format("No query available for schema version {}", schemaVersion));
189 }
190 return queries.at(maxDefVersion);
191}
192
193void
194TrigConf::TrigDBLoader::loadFromCrest(unsigned int key, boost::property_tree::ptree & pt,
195 const std::string & outFileName, const std::string & description,
196 const std::string & query_type) const
197{
198 std::string payload;
199 try {
200 payload = getTrigDataCrest(query_type, key);
201 }
202 catch(Crest::CrestException & ex) {
203 TRG_MSG_ERROR("When reading " << description << " for key " << key << " from crest a CrestException was caught ( " << ex.what() <<" )" );
204 throw TrigConf::CrestLoadingException(std::format("{}: {}", getName(), ex.what()));
205 }
206 if(!outFileName.empty()) {
207 writeRawFile(payload, outFileName);
208 TRG_MSG_INFO("Wrote file " << outFileName);
209 }
210 try {
211 stringToPtree(payload, pt);
212 }
213 catch(boost::property_tree::json_parser_error & ex) {
214 TRG_MSG_ERROR("When reading " << description << " for key " << key << " from crest a ptree json parser error was caught ( " << ex.what() <<" )" );
215 throw TrigConf::JsonParsingException(std::format("{}: {}", getName(), ex.what()));
216 }
217}
218
219void
220TrigConf::TrigDBLoader:: loadFromOracle(unsigned int key, boost::property_tree::ptree & pt,
221 const std::string & outFileName, const std::string & description,
222 const std::map<size_t, QueryDefinition> & queries) const
223{
224 auto session = createDBSession();
225 session->transaction().start( /*bool readonly=*/ true);
226 const size_t sv = schemaVersion(session.get());
227 QueryDefinition qdef = getQueryDefinition(sv, queries);
228 try {
229 qdef.setBoundValue<int>("key", key);
230 auto q = qdef.createQuery( session.get() );
231 auto & cursor = q->execute();
232 if ( ! cursor.next() ) {
233 TRG_MSG_ERROR("Tried reading " << description << ", but key " << key << " is not available" );
234 throw TrigConf::NoKeyException(std::format("{}: key {} not available", getName(), key));
235 }
236 const coral::AttributeList& row = cursor.currentRow();
237 const coral::Blob& dataBlob = row[qdef.dataName()].data<coral::Blob>();
238
239 if(!outFileName.empty()) {
240 writeRawFile( dataBlob, outFileName );
241 TRG_MSG_INFO("Wrote file " << outFileName);
242 }
243 blobToPtree( dataBlob, pt );
244 }
245 catch(coral::QueryException & ex) {
246 TRG_MSG_ERROR("When reading " << description << " for key " << key << " a coral::QueryException was caught ( " << ex.what() <<" )" );
247 throw TrigConf::QueryException(std::format("{}: {}", getName(), ex.what()));
248 }
249 catch(boost::property_tree::json_parser_error & ex) {
250 TRG_MSG_ERROR("When reading " << description << " for key " << key << " a ptree json parser error was caught ( " << ex.what() <<" )" );
251 throw TrigConf::JsonParsingException(std::format("{}: {}", getName(), ex.what()));
252 }
253}
boost::property_tree::ptree ptree
Loader class for Trigger configuration from the Trigger DB.
std::unique_ptr< coral::IQuery > createQuery(coral::ISessionProxy *session)
const std::string & dataName()
void setBoundValue(const std::string &fieldName, const T &value)
void extendOutput(const std::string &fieldName)
void addToTableList(const std::string &table, const std::string &table_short="")
const std::string & getName() const
name accessor
TrigConfMessaging(const std::string &name)
Constructor with parameters.
std::unique_ptr< coral::ISessionProxy > createDBSession() const
create (if needed) DB session and return the session proxy
QueryDefinition getQueryDefinition(size_t schemaVersion, const std::map< size_t, QueryDefinition > &queries) const
return query for given schemaVersion from possible queries
std::string getTrigDataCrest(const std::string &type, int key) const
Get trigger configuration from the TriggerDB through Crest.
TrigDBLoader(const std::string &loaderName, const std::string &connection)
Constructor.
void setCrestTrigDB(const std::string &crestTrigDB)
set trigger db for the crest connection
virtual ~TrigDBLoader()
Destructor - cannot be defined here because QueryDefinition is an incomplete type.
void loadFromOracle(unsigned int key, boost::property_tree::ptree &pt, const std::string &outFileName, const std::string &description, const std::map< size_t, QueryDefinition > &queries) const
size_t schemaVersion(coral::ISessionProxy *session) const
access to TriggerDB schema version
void setCrestConnection(const std::string &server, const std::string &version="")
declare CREST as the source of the configuration An empty crest server makes it use Oracle
void loadFromCrest(unsigned int key, boost::property_tree::ptree &pt, const std::string &outFileName, const std::string &description, const std::string &query_type) const
std::string description
glabal timer - how long have I taken so far?
Definition hcg.cxx:91
void stringToPtree(const std::string &json_string, boost::property_tree::ptree &pt)
void writeRawFile(const coral::Blob &data, const std::string &outFileName)
write coral data blob to file
void blobToPtree(const coral::Blob &blob, boost::property_tree::ptree &pt)
Definition query.py:1