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