ATLAS Offline Software
Loading...
Searching...
No Matches
RDBAccessSvc.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
4
13
14#include "RDBAccessSvc.h"
15#include "RDBRecordset.h"
16#include "RDBVersionAccessor.h"
17#include "RDBQuery.h"
18
19#include "RelationalAccess/ISessionProxy.h"
20#include "RelationalAccess/ITransaction.h"
21#include "RelationalAccess/SchemaException.h"
22#include "RelationalAccess/ConnectionService.h"
23#include "RelationalAccess/ICursor.h"
24#include "RelationalAccess/ITable.h"
25#include "RelationalAccess/ISchema.h"
26#include "RelationalAccess/IQuery.h"
27
28#include "DBLock/DBLock.h"
29
31
32#include "CoralBase/Exception.h"
33
34#include <thread>
35
36RDBAccessSvc::RDBAccessSvc(const std::string& name, ISvcLocator* svc)
37 : base_class(name,svc)
38{
39}
40
41bool RDBAccessSvc::connect(const std::string& connName)
42{
43 std::scoped_lock<std::mutex> guard(m_sessionMutex);
44 // Check if it is the first attempt to open a connection connName
45 if(m_sessions.find(connName)==m_sessions.end()) {
46 ATH_MSG_DEBUG(" Trying to open the connection " << connName << " for the first time");
47 // Add initial entries for this connection to three maps
48 // 1. Sessions
49 // 2. open connections
50 // 3. Recordset by connection
51 m_sessions[connName] = nullptr;
52 m_openConnections[connName] = 0;
53 m_recordsetptrs.emplace(connName,RecordsetPtrMap());
54 }
55
56 // Use existing Connection Proxy if available
57 if(m_openConnections[connName]++) {
58 ATH_MSG_DEBUG(" Connection " << connName << " already open, sessions = " << m_openConnections[connName]);
59 return true;
60 }
61
62 // Request new connection proxy from the Connection Service
63 coral::ConnectionService conSvcH;
64 coral::ISessionProxy *proxy = nullptr;
65 try {
66 proxy = conSvcH.connect(connName,coral::ReadOnly);
67 proxy->transaction().start(true);
68 ATH_MSG_DEBUG("Proxy for connection " << connName << " obtained");
69 }
70 catch(std::exception& e) {
71 ATH_MSG_ERROR("Exception caught: " << e.what());
72 m_openConnections[connName]--;
73 return false;
74 }
75
76 m_sessions[connName] = proxy;
77
78 return true;
79}
80
81bool RDBAccessSvc::disconnect(const std::string& connName)
82{
83 auto connection = m_openConnections.find(connName);
84 if(connection==m_openConnections.end()) {
85 ATH_MSG_ERROR("Wrong name for the connection: " << connName);
86 return false;
87 }
88
89 std::scoped_lock<std::mutex> guard(m_sessionMutex);
90 if(connection->second>0) {
91 connection->second--;
92
93 ATH_MSG_DEBUG("Connection " << connName << " Sessions = " << connection->second);
94
95 if(connection->second==0) {
96 auto session = m_sessions.find(connName);
97 if(session!=m_sessions.end()) {
98 session->second->transaction().commit();
99 delete session->second;
100 session->second = nullptr;
101 }
102
103 ATH_MSG_DEBUG(connName << " Disconnected!");
104 }
105 }
106 return true;
107}
108
109bool RDBAccessSvc::shutdown(const std::string& connName)
110{
111 if(connName=="*Everything*") {
112 for(const auto& ii : m_openConnections) {
113 if(ii.second != 0) {
114 ATH_MSG_INFO("Close everything: Connection: " << ii.first << " with reference count = " << ii.second << " will be closed.");
115 if(!shutdown_connection(ii.first)) {
116 return false;
117 }
118 }
119 }
120 return true;
121 }
122
123 return shutdown_connection(connName);
124}
125
126bool RDBAccessSvc::shutdown_connection(const std::string& connName)
127{
128 auto connection = m_openConnections.find(connName);
129 if(connection==m_openConnections.end()) {
130 ATH_MSG_ERROR("Wrong name for the connection: " << connName);
131 return false;
132 }
133 std::scoped_lock<std::mutex> guard(m_sessionMutex);
134 connection->second = 0;
135
136 auto session = m_sessions.find(connName);
137 if(session!=m_sessions.end()
138 && session->second) {
139 session->second->transaction().commit();
140 delete session->second;
141 session->second = nullptr;
142 }
143
144 ATH_MSG_DEBUG(connName << " Disconnected!");
145
146 return true;
147}
148
150 , const std::string& tag
151 , const std::string& tag2node
152 , const std::string& connName)
153{
154 std::string key = node + "::" + tag;
155 if(tag2node!="")
156 key += ("::" + tag2node);
157
158 ATH_MSG_DEBUG("Getting RecordsetPtr with key " << key);
159
160 Athena::DBLock dblock;
161 std::scoped_lock<std::mutex> guard(m_recordsetMutex);
162
163 RecordsetPtrMap& recordsets = m_recordsetptrs[connName];
164 RecordsetPtrMap::const_iterator it = recordsets.find(key);
165 if(it != recordsets.end()) {
166 ATH_MSG_DEBUG("Reusing existing recordset");
167 return it->second;
168 }
169
170 if(!connect(connName)) {
171 ATH_MSG_ERROR("Unable to open connection " << connName << ". Returning empty recordset");
172 return IRDBRecordset_ptr(new RDBRecordset(this));
173 }
174
175 RDBRecordset* recConcrete = new RDBRecordset(this);
176 IRDBRecordset_ptr rec(recConcrete);
177 coral::ISessionProxy* session = m_sessions[connName];
178
179 try {
180 // Check lookup table first
181 std::string lookupMapKey = tag + "::" + connName;
182 GlobalTagLookupMap::const_iterator lookupmap = m_globalTagLookup.find(lookupMapKey);
183 if(lookupmap!=m_globalTagLookup.end()) {
184 TagNameIdByNode::const_iterator childtagdet = lookupmap->second->find(node);
185 if(childtagdet!=lookupmap->second->end()) {
186 recConcrete->getData(session,node,childtagdet->second.first,childtagdet->second.second);
187 }
188 else {
189 recConcrete->setNodeName(node);
190 ATH_MSG_DEBUG("Unable to find tag for the node " << node << " in the cache of global tag " << tag << ". Returning empty recordset");
191 }
192 }
193 else {
194 RDBVersionAccessor versionAccessor(node,(tag2node.empty()?node:tag2node),tag,session,msg());
195 versionAccessor.getChildTagData();
196 recConcrete->getData(session,versionAccessor.getNodeName(),versionAccessor.getTagName(),versionAccessor.getTagID());
197 }
198 }
199 catch(coral::SchemaException& se) {
200 ATH_MSG_ERROR("Schema Exception : " << se.what());
201 }
202 catch(std::exception& e) {
203 ATH_MSG_ERROR(e.what());
204 }
205 catch(...) {
206 ATH_MSG_ERROR("Exception caught(...)");
207 }
208
209 recordsets.emplace(key,rec);
210 disconnect(connName);
211 return rec;
212}
213
214std::unique_ptr<IRDBQuery> RDBAccessSvc::getQuery(const std::string& node
215 , const std::string& tag
216 , const std::string& tag2node
217 , const std::string& connName)
218{
219 ATH_MSG_DEBUG("getQuery (" << node << "," << tag << "," << tag2node << "," << connName << ")");
220 Athena::DBLock dblock;
221 std::scoped_lock<std::mutex> guard(m_recordsetMutex);
222
223 std::unique_ptr<IRDBQuery> query;
224
225 if(!connect(connName)) {
226 ATH_MSG_ERROR("Unable to open connection " << connName << ". Returning nullptr to IRDBQuery");
227 return query;
228 }
229
230 coral::ISessionProxy* session = m_sessions[connName];
231
232 try {
233 // Check lookup table first
234 std::string childTagId("");
235 std::string lookupMapKey = tag + "::" + connName;
236 GlobalTagLookupMap::const_iterator lookupmap = m_globalTagLookup.find(lookupMapKey);
237 if(lookupmap!=m_globalTagLookup.end()) {
238 TagNameIdByNode::const_iterator childtagdet = lookupmap->second->find(node);
239 if(childtagdet!=lookupmap->second->end()) {
240 childTagId = childtagdet->second.second;
241 }
242 }
243 else {
244 RDBVersionAccessor versionAccessor{node,(tag2node.empty()?node:tag2node),tag,session,msg()};
245 versionAccessor.getChildTagData();
246 childTagId = versionAccessor.getTagID();
247 }
248
249 if(childTagId.empty()) {
250 ATH_MSG_WARNING("Could not get the tag for " << node << " node. Returning 0 pointer to IRDBQuery");
251 }
252 else {
253 query = std::unique_ptr<IRDBQuery>(new RDBQuery(dblock,this,node,childTagId,connName));
254 }
255 }
256 catch(coral::SchemaException& se) {
257 ATH_MSG_ERROR("Schema Exception : " << se.what());
258 }
259 catch(std::exception& e) {
260 ATH_MSG_ERROR(e.what());
261 }
262 catch(...) {
263 ATH_MSG_ERROR("Exception caught(...)");
264 }
265
266 disconnect(connName);
267 return query;
268}
269
270std::string RDBAccessSvc::getChildTag(const std::string& childNode
271 , const std::string& parentTag
272 , const std::string& parentNode
273 , const std::string& connName)
274{
275 return getChildTag(childNode
276 , parentTag
277 , parentNode
278 , connName
279 , false);
280}
281
282std::string RDBAccessSvc::getChildTag(const std::string& childNode
283 , const std::string& parentTag
284 , const std::string& parentNode
285 , const std::string& connName
286 , bool force)
287{
288 ATH_MSG_DEBUG("getChildTag for " << childNode << " " << parentTag << " " << parentNode);
289 Athena::DBLock dblock;
290 std::scoped_lock<std::mutex> guard(m_recordsetMutex);
291
292 // Check lookup table first
293 std::string lookupMapKey = parentTag + "::" + connName;
294 GlobalTagLookupMap::const_iterator lookupmap = m_globalTagLookup.find(lookupMapKey);
295 if(lookupmap!=m_globalTagLookup.end()) {
296 TagNameIdByNode::const_iterator childtagdet = lookupmap->second->find(childNode);
297 if(childtagdet!=lookupmap->second->end()) {
298 return childtagdet->second.first;
299 }
300 else {
301 if(!force) {
302 return std::string("");
303 }
304 }
305 }
306
307 if(!connect(connName)) {
308 ATH_MSG_ERROR("Unable to open connection " << connName << ". Returning empty string");
309 return std::string("");
310 }
311
312 std::string childTag("");
313 try {
314 // We don't have lookup table for given parent tag. Go into slow mode through Version Accessor
315 coral::ISessionProxy* session = m_sessions[connName];
316 RDBVersionAccessor versionAccessor(childNode,parentNode,parentTag,session,msg());
317 versionAccessor.getChildTagData();
318
319 childTag = versionAccessor.getTagName();
320 }
321 catch(coral::SchemaException& se) {
322 ATH_MSG_ERROR("Schema Exception : " << se.what());
323 }
324 catch(std::exception& e) {
325 ATH_MSG_ERROR(e.what());
326 }
327 catch(...) {
328 ATH_MSG_ERROR("Exception caught(...)");
329 }
330
331 disconnect(connName);
332
333 return childTag;
334}
335
337 , const std::string& tag
338 , const std::string& connName)
339{
340 ATH_MSG_DEBUG("getTagDetails for tag: " << tag);
341 Athena::DBLock dblock;
342 std::scoped_lock<std::mutex> guard(m_recordsetMutex);
343
344 if(!connect(connName)) {
345 ATH_MSG_ERROR("Failed to open connection " << connName);
346 }
347
348 coral::ISessionProxy* session = m_sessions[connName];
349 try {
350 coral::ITable& tableTag2Node = session->nominalSchema().tableHandle("HVS_TAG2NODE");
351 coral::IQuery *queryTag2Node = tableTag2Node.newQuery();
352 queryTag2Node->addToOutputList("LOCKED");
353 queryTag2Node->addToOutputList("SUPPORTED");
354 queryTag2Node->setMemoryCacheSize(1);
355 coral::AttributeList bindsTag2Node ATLAS_THREAD_SAFE;
356 bindsTag2Node.extend<std::string>("tagN");
357 queryTag2Node->setCondition("TAG_NAME=:tagN", bindsTag2Node);
358 bindsTag2Node[0].data<std::string>() = tag;
359
360 coral::ICursor& cursorTag2Node = queryTag2Node->execute();
361 if(cursorTag2Node.next()) {
362 tagDetails = cursorTag2Node.currentRow();
363 }
364
365 delete queryTag2Node;
366
367 // Build lookup table for the given global tag if has not been built yet
368 std::string lookupMapKey = tag + "::" + connName;
369 if(m_globalTagLookup.find(lookupMapKey)==m_globalTagLookup.end()) {
370 // Get tag contents from the database
371 TagNameIdByNode* lookup = new TagNameIdByNode();
372
373 coral::ITable& tableRootTag2Child = session->nominalSchema().tableHandle("HVS_TAGCACHE");
374 coral::IQuery* queryRootTag2Child = tableRootTag2Child.newQuery();
375 queryRootTag2Child->addToOutputList("CHILDNODE");
376 queryRootTag2Child->addToOutputList("CHILDTAG");
377 queryRootTag2Child->addToOutputList("CHILDTAGID");
378 queryRootTag2Child->setMemoryCacheSize(1);
379 coral::AttributeList bindsRootTag2Child ATLAS_THREAD_SAFE;
380 bindsRootTag2Child.extend<std::string>("tagN");
381 queryRootTag2Child->setCondition("ROOTTAG=:tagN", bindsRootTag2Child);
382 bindsRootTag2Child[0].data<std::string>() = tag;
383 queryRootTag2Child->addToOrderList("CHILDNODE");
384
385 coral::ICursor& cursorRootTag2Child = queryRootTag2Child->execute();
386 while(cursorRootTag2Child.next()) {
387 const coral::AttributeList& row = cursorRootTag2Child.currentRow();
388 (*lookup)[row["CHILDNODE"].data<std::string>()]=std::make_pair(row["CHILDTAG"].data<std::string>(),std::to_string(row["CHILDTAGID"].data<long long>()));
389 }
390
391 delete queryRootTag2Child;
392
393 if(lookup->size()>0) {
394 m_globalTagLookup[lookupMapKey]=lookup;
395 }
396 else {
397 delete lookup;
398 }
399 }
400 }
401 catch(coral::SchemaException& se) {
402 ATH_MSG_INFO("Schema Exception : " << se.what());
403 }
404 catch(std::exception& e) {
405 ATH_MSG_ERROR(e.what());
406 }
407 catch(...) {
408 ATH_MSG_ERROR("Exception caught(...)");
409 }
410
411 disconnect(connName);
412}
413
414void RDBAccessSvc::getAllLeafNodes(std::vector<std::string>& list
415 , const std::string& connName)
416{
417 list.clear();
418 if(!connect(connName)) {
419 ATH_MSG_ERROR("Failed to open Connection " << connName);
420 return;
421 }
422
423 coral::ISessionProxy* session = m_sessions[connName];
424 try {
425 coral::ITable& tableNode = session->nominalSchema().tableHandle("HVS_NODE");
426 coral::IQuery *queryNode = tableNode.newQuery();
427 queryNode->addToOutputList("NODE_NAME");
428 queryNode->setMemoryCacheSize(1);
429 coral::AttributeList empty ATLAS_THREAD_SAFE;
430 queryNode->setCondition("BRANCH_FLAG=0", empty);
431 queryNode->addToOrderList("NODE_NAME");
432
433 coral::ICursor& cursorNode = queryNode->execute();
434 while(cursorNode.next()) {
435 list.push_back(cursorNode.currentRow()["NODE_NAME"].data<std::string>());
436 }
437
438 delete queryNode;
439 }
440 catch(coral::SchemaException& se) {
441 ATH_MSG_INFO("Schema Exception : " << se.what());
442 }
443 catch(std::exception& e) {
444 ATH_MSG_ERROR(e.what());
445 }
446 catch(...) {
447 ATH_MSG_ERROR("Exception caught(...)");
448 }
449
450 disconnect(connName);
451}
452
453std::vector<std::string> RDBAccessSvc::getLockedSupportedTags(const std::string& supportedFlag
454 , const std::string& connName)
455{
456 std::vector<std::string> taglist;
457 if(!connect(connName)) {
458 ATH_MSG_ERROR("Failed to open connection " << connName);
459 }
460 else {
461 try{
462 coral::ISessionProxy* session = m_sessions[connName];
463
464 coral::ITable& tableTag2Node = session->nominalSchema().tableHandle("HVS_TAG2NODE");
465 coral::IQuery* queryTag2Node = tableTag2Node.newQuery();
466 queryTag2Node->addToOutputList("TAG_NAME");
467 queryTag2Node->setMemoryCacheSize(1);
468 coral::AttributeList empty ATLAS_THREAD_SAFE;
469 std::string condString = std::string("NODE_ID=0 AND LOCKED=1 AND SUPPORTED>=")+supportedFlag;
470 queryTag2Node->setCondition(condString,empty);
471 queryTag2Node->addToOrderList("TAG_NAME");
472
473 coral::ICursor& cursorTagName = queryTag2Node->execute();
474 while(cursorTagName.next()) {
475 const coral::AttributeList& row = cursorTagName.currentRow();
476 taglist.push_back(row["TAG_NAME"].data<std::string>());
477 }
478 delete queryTag2Node;
479
480 }
481 catch(coral::SchemaException& se) {
482 ATH_MSG_ERROR("Schema Exception : " << se.what());
483 }
484 catch(std::exception& e) {
485 ATH_MSG_ERROR(e.what());
486 }
487 catch(...) {
488 ATH_MSG_ERROR("Exception caught(...)");
489 }
490 }
491 disconnect(connName);
492 return taglist;
493}
494
495coral::ISessionProxy* RDBAccessSvc::getSession(const std::string& connName)
496{
497 auto sessionIt = m_sessions.find(connName);
498 return sessionIt == m_sessions.end() ? nullptr : sessionIt->second;
499}
500
502{
503 return StatusCode::SUCCESS;
504}
505
507{
508 m_recordsetptrs.clear();
509
510 // Clear global tag lookup table
511 for(auto& [lookupName,lookup] : m_globalTagLookup) {
512 delete lookup;
513 }
514 m_globalTagLookup.clear();
515
516 // Shut down all connections
517 for(auto& [sessionName,session] : m_sessions) {
518 shutdown(sessionName);
519 }
520
521 return StatusCode::SUCCESS;
522}
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
Common database lock.
char data[hepevt_bytes_allocation_ATLAS]
Definition HepEvt.cxx:11
coral::AttributeList RDBTagDetails
std::shared_ptr< IRDBRecordset > IRDBRecordset_ptr
Definition of RDBAccessSvc class.
std::map< std::string, TagNameId > TagNameIdByNode
std::map< std::string, IRDBRecordset_ptr > RecordsetPtrMap
Definition of RDBRecordset class.
Definition of RDBVersionAccessor class.
static const Attributes_t empty
Define macros for attributes used to control the static checker.
#define ATLAS_THREAD_SAFE
Common database lock.
Definition DBLock.h:46
std::vector< std::string > getLockedSupportedTags(const std::string &supportedFlag, const std::string &connName="ATLASDD")
bool connect(const std::string &connName) override
Connect to the relational DB.
bool shutdown(const std::string &connName) override
Closes the connection regardless of the counter value.
bool disconnect(const std::string &connName) override
If the counnection counter==1 closes the connection.
std::mutex m_sessionMutex
SessionMap m_sessions
IRDBRecordset_ptr getRecordsetPtr(const std::string &node, const std::string &tag, const std::string &tag2node="", const std::string &connName="ATLASDD") override
Provides access to the Recordset object containing HVS-tagged data.
bool shutdown_connection(const std::string &connName)
StatusCode finalize() override
RecordsetPtrsByConn m_recordsetptrs
GlobalTagLookupMap m_globalTagLookup
RDBAccessSvc(const std::string &name, ISvcLocator *svc)
Standard Service Constructor.
void getAllLeafNodes(std::vector< std::string > &list, const std::string &connName="ATLASDD")
void getTagDetails(RDBTagDetails &tagDetails, const std::string &tag, const std::string &connName="ATLASDD") override
std::mutex m_recordsetMutex
std::map< std::string, unsigned int > m_openConnections
StatusCode initialize() override
std::string getChildTag(const std::string &childNode, const std::string &parentTag, const std::string &parentNode, const std::string &connName) override
Gets the tag name for the node by giving its parent node tag.
std::unique_ptr< IRDBQuery > getQuery(const std::string &node, const std::string &tag, const std::string &tag2node, const std::string &connName) override
coral::ISessionProxy * getSession(const std::string &connName="ATLASDD")
RDBQuery is an implementation of IRDBQuery interface.
Definition RDBQuery.h:30
RDBRecordset is an implementation of IRDBRecordset interface.
void setNodeName(const std::string &nodeName)
void getData(coral::ISessionProxy *session, const std::string &nodeName, const std::string &tagName, const std::string &tagId)
Constructs SQL query and retrieves the data from DB.
RDBVersionAccessor is a helper class navigating HVS tree and getting child node tag by the tag of one...
const std::string & getTagID() const
void getChildTagData()
Constructs SQL query and retrieves child tag ID and Name from DB.
const std::string & getTagName() const
const std::string & getNodeName() const
Definition node.h:24
Definition query.py:1
MsgStream & msg
Definition testRead.cxx:32