ATLAS Offline Software
Loading...
Searching...
No Matches
DBReplicaSvc.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
5// DBReplicaSvc.cxx - service implementing CORAL IReplicaSortingAlgorithm
6// Richard Hawkings, started 24/4/07
7
8#include "DBReplicaSvc.h"
9
11
12#include <fstream>
13#include <cstring>
14
15#include "RelationalAccess/ConnectionService.h"
16#include "RelationalAccess/IConnectionServiceConfiguration.h"
17#include "RelationalAccess/IWebCacheControl.h"
18#include "RelationalAccess/IDatabaseServiceSet.h"
19#include "RelationalAccess/IDatabaseServiceDescription.h"
20
22
23 // determine the hostname (or override if from joboption)
25 // if nothing set on job-options, try environment variable ATLAS_CONDDB
26 if (m_hostname.empty()) {
27 const char* chost=getenv("ATLAS_CONDDB");
28 if (chost) m_hostname=chost;
29 }
30 // if ATLAS_CONDDB not set, try environment variable HOSTNAME
31 if (m_hostname.empty()) {
32 const char* chost=getenv("HOSTNAME");
33 if (chost) m_hostname=chost;
34 // check if the returned host has a .
35 if (m_hostname.find('.')==std::string::npos) {
36 ATH_MSG_DEBUG("HOSTNAME " << m_hostname
37 << " has no domain - try hostname --fqdn");
38 m_hostname="unknown";
39#ifndef __APPLE__
40 system("hostname --fqdn > hostnamelookup.tmp");
41#else
42 // Unfortunately Leopard doesn't understand the -f option to hostname, only Snow Leopard does
43 system("hostname > hostnamelookup.tmp");
44#endif
45 std::ifstream infile;
46 infile.open("hostnamelookup.tmp");
47 if (infile) {
48 infile >> m_hostname;
49 ATH_MSG_DEBUG ("HOSTNAME from fqdn: " << m_hostname);
50 } else {
51 m_hostname="unknown";
52 }
53 }
54 }
55 // check if FRONTIER_SERVER is set, if so, allow generic replicas
56 const char* cfrontier=getenv("FRONTIER_SERVER");
57 if (m_usecoolfrontier && cfrontier && strcmp(cfrontier,"")!=0) {
58 ATH_MSG_INFO ("Frontier server at " << cfrontier
59 << " will be considered for COOL data");
60 m_frontiergen=true;
61 }
62 StatusCode sc=readConfig();
63 if (!m_usecoolsqlite) {
64 ATH_MSG_INFO ("COOL SQLite replicas will be excluded");
65 } else if (m_coolsqlitepattern!="") {
66 ATH_MSG_INFO ("COOL SQLite replicas will be excluded if matching pattern "
68 }
70 ATH_MSG_INFO ("COOL Frontier replicas will be excluded");
71 if (!m_usegeomsqlite)
72 ATH_MSG_INFO ("Geometry SQLite replicas will be excluded");
73 if (m_nofailover)
74 ATH_MSG_INFO ("Failover to secondary replicas disabled");
75 //Other coral configuration settting:
76
77 m_context = &coral::Context::instance();
78 if (m_context == nullptr) {
79 ATH_MSG_FATAL("Failed to access CORAL Context");
80 return (StatusCode::FAILURE);
81 }
82
83 coral::ConnectionService conSvcH;
84 coral::IConnectionServiceConfiguration& csConfig = conSvcH.configuration();
85 csConfig.setReplicaSortingAlgorithm(*this);
86 ATH_MSG_DEBUG("Successfully setup replica sorting algorithm");
87
88 csConfig.setConnectionRetrialPeriod(m_retrialPeriod);
89 csConfig.setConnectionRetrialTimeOut(m_retrialTimeOut);
90 if (m_connClean) {
91 csConfig.enablePoolAutomaticCleanUp();
92 csConfig.setConnectionTimeOut(m_timeOut);
93 } else {
94 csConfig.disablePoolAutomaticCleanUp();
95 csConfig.setConnectionTimeOut(0);
96 }
97 ATH_MSG_INFO("Set connectionsvc retry/timeout/IDLE timeout to " << m_retrialPeriod << "/" << m_retrialTimeOut << "/" << m_timeOut
98 << " seconds with connection cleanup "
99 << (csConfig.isPoolAutomaticCleanUpEnabled() ? "enabled" : "disabled"));
100 // set Frontier web cache compression level
101 coral::IWebCacheControl& webCache = conSvcH.webCacheControl();
102 webCache.setCompressionLevel(m_frontierComp);
103 ATH_MSG_INFO("Frontier compression level set to " << webCache.compressionLevel());
104
105 return sc;
106}
107
109
110 // try to locate the file using pathresolver
111 std::string file=PathResolver::find_file(m_configfile,"DATAPATH");
112 if (file.empty()) {
113 ATH_MSG_ERROR ("Cannot locate configuration file " << m_configfile);
114 return StatusCode::FAILURE;
115 }
116 // open and read the file
117 ATH_MSG_INFO ("Read replica configuration from " << file);
118 FILE* p_inp=fopen(file.c_str(),"r");
119 if (p_inp==nullptr) {
120 ATH_MSG_ERROR ("Cannot open configuration file");
121 return StatusCode::FAILURE;
122 }
123 // buffer for reading line
124 const unsigned int bufsize=999;
125 char p_buf[bufsize];
126 while (!feof(p_inp)) {
127 char* p_line=fgets(p_buf,bufsize,p_inp);
128 if (p_line!=NULL && p_line[0]!='#') {
129 std::string buf=std::string(p_line);
130 std::string::size_type iofs1=0;
131 // analyse based on spaces as separator
132 bool sequal=false;
133 std::vector<std::string> domains;
134 std::vector<std::string> servers;
135 while (iofs1<buf.size()) {
136 std::string::size_type iofs2=buf.find(' ',iofs1);
137 // allow for trailing linefeed
138 if (iofs2==std::string::npos) iofs2=buf.size()-1;
139 std::string token=buf.substr(iofs1,iofs2-iofs1);
140 // skip empty or space tokens
141 if (token!="" && token!=" ") {
142 if (token=="=") {
143 sequal=true;
144 } else if (!sequal) {
145 // token is a domain name
146 domains.push_back(std::move(token));
147 } else {
148 // token is a server name
149 if (!m_nofailover || servers.size()==0 || token=="atlas_dd")
150 servers.push_back(std::move(token));
151 }
152 }
153 iofs1=iofs2+1;
154 }
155 // check the list of domains against the hostname to see if this
156 // set of servers is appropriate
157 bool useit=false;
158 unsigned int bestlen=0;
159 for (const std::string& d : domains) {
160 std::string::size_type len=d.size();
161 std::string::size_type hlen=m_hostname.size();
162 if (hlen>=len && d==m_hostname.substr(hlen-len,len)) {
163 if (len>bestlen) {
164 useit=true;
165 bestlen=len;
166 }
167 }
168 // for 'default' domain name, add the servers as a last resort
169 // if nothing has been found so far
170 if ("default"==d && m_servermap.empty()) {
171 ATH_MSG_INFO ("No specific match for domain found - use default fallback");
172 useit=true;
173 bestlen=0;
174 }
175 }
176 if (useit) {
177 // assign these servers, priority based on position in list
178 // and length of match of domain name
179 for (unsigned int i=0;i<servers.size();++i) {
180 int priority=i*5-100*bestlen;
181 // only add ATLF Frontier generic servers if allowed
182 if (servers[i]!="ATLF" || m_frontiergen) {
183 // give generic Frontier server higher (more negative) priority
184 // so it will be preferred over DBRelaese SQLite file
185 if (servers[i]=="ATLF") priority-=2000;
186 m_servermap.push_back(ServerPair(servers[i],priority));
187 ATH_MSG_DEBUG ("Candidate server " << servers[i] <<
188 " (priority " << priority << ")");
189 }
190 }
191 }
192 }
193 }
194 fclose(p_inp);
195 msg() << MSG::INFO << "Total of " << m_servermap.size() <<
196 " servers found for host " << m_hostname << " [";
197 for (const auto& [name, pri] : m_servermap) {
198 msg() << name << " ";
199 }
200 msg() << "]" << endmsg;
201 return StatusCode::SUCCESS;
202}
203
204void DBReplicaSvc::sort(std::vector<const coral::IDatabaseServiceDescription*>& replicaSet) {
205 // if only one replica offered, return immediately
206 // this helps for online, where explicit configuration file is given
207 // that does not match any of the standard dbreplica.config entries
208 if (replicaSet.size()<=1) return;
209
210 // loop through all the offered replicas
211 std::map<int,const coral::IDatabaseServiceDescription*> primap;
212 for (const coral::IDatabaseServiceDescription* dbdescr : replicaSet) {
213
214 const std::string conn=dbdescr->connectionString();
215 ATH_MSG_DEBUG ("Replica connection string: " << conn);
216 if (conn.find("sqlite_file")!=std::string::npos) {
217 // include SQLite files unless they are vetoed
218 // COOL SQLIte files recognised by ALLP in connection string
219 // vetoed if use-SQlite flag not set, or pattern is found in
220 // SQLite filename
221 // Geometry SQLite files recognised by geomDB in connection string
222 if (!( ((m_usecoolsqlite==false ||
223 (m_coolsqlitepattern!="" &&
224 conn.find(m_coolsqlitepattern)!=std::string::npos))
225 && conn.find("ALLP")!=std::string::npos)
226 || ((m_usegeomsqlite==false ||
227 (m_coolsqlitepattern!="" &&
228 conn.find(m_coolsqlitepattern)!=std::string::npos))
229 && conn.find("geomDB")!=std::string::npos))) {
230 // local sqlite files get -9999, DB release ones
231 // (identified with path starting / or containing DBRelease)
232 // get -999, so local one will be tried first if present
233 if (conn.find("sqlite_file:/")!=std::string::npos ||
234 conn.find("DBRelease")!=std::string::npos) {
235 primap[-999]=dbdescr;
236 } else {
237 primap[-9999]=dbdescr;
238 }
239 }
240 } else {
241 // define priority for technologies with this server (lower = better)
242 bool veto=false;
243 int spri=5; // default for Oracle
244 if (conn.find("frontier:")!=std::string::npos) {
245 spri=3; // use frontier before oracle
246 // dont use frontier servers if disabled, or generic Frontier server
247 // is specified (via '()' in server definition) and FRONTIER_SERVER
248 // env variable is not set
249 if (!m_usecoolfrontier ||
250 (conn.find("()")!=std::string::npos && m_frontiergen==false))
251 veto=true;
252 }
253 // extract the server name (assuming URLs "techno://server/schema")
254 std::string::size_type ipos1=conn.find("://");
255 std::string::size_type ipos2=conn.find('/',ipos1+3);
256 // for Frontier, have to remove the (..) part after the server name
257 // e.g. frontier://ATLAS_COOLPROD/(serverurl=http://xyzfrontier.cern.ch:8000/atlr)/schema
258 std::string::size_type ipos3=conn.find('(',ipos1+3);
259 if (ipos3!=std::string::npos && ipos3<ipos2) ipos2=ipos3;
260 if (ipos1!=std::string::npos && ipos2!=std::string::npos && !veto) {
261 const std::string server=conn.substr(ipos1+3,ipos2-ipos1-3);
262 // check if this server is on list of replicas to use for domain
263 // if so, add it with its associated priority
264 for (const auto& [name, pri] : m_servermap) {
265 if (name==server) {
266 primap[pri+spri]=dbdescr;
267 }
268 }
269 }
270 }
271 }
272 // now create sorted list
273 replicaSet.clear();
274 for (const auto& [pri, db] : primap) {
275 replicaSet.push_back(db);
276 ATH_MSG_DEBUG ("Allowed replica to try (priority " << pri << ") : " << db->connectionString());
277 }
278 if (replicaSet.empty()) {
279 ATH_MSG_ERROR ("No matching replicas found");
280 }
281 ATH_MSG_DEBUG ("Retained total of " << replicaSet.size() << " replicas");
282}
#define endmsg
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_DEBUG(x)
static Double_t sc
Gaudi::Property< int > m_retrialTimeOut
ConnectionRetrialTimeOut, the retrial time out for CORAL Connection Service: default = 300 seconds.
std::string m_hostname
Gaudi::Property< bool > m_connClean
ConnectionCleanUp - whether to use CORAL connection management thread: default = false.
virtual StatusCode initialize() override
Gaudi::Property< std::string > m_testhost
Gaudi::Property< bool > m_usegeomsqlite
coral::Context * m_context
void sort(std::vector< const coral::IDatabaseServiceDescription * > &replicaSet) override
Gaudi::Property< int > m_timeOut
ConnectionTimeOut, the time out for CORAL Connection Service: default = 5 seconds.
std::pair< std::string, int > ServerPair
Gaudi::Property< int > m_frontierComp
Frontier proprties, compression level and list of schemas to be refreshed: default = 5.
Gaudi::Property< int > m_retrialPeriod
ConnectionRetrialPeriod, retry period for CORAL Connection Service: default = 30 seconds.
Gaudi::Property< bool > m_usecoolsqlite
Gaudi::Property< bool > m_nofailover
Gaudi::Property< std::string > m_coolsqlitepattern
std::vector< ServerPair > m_servermap
Gaudi::Property< std::string > m_configfile
StatusCode readConfig()
Gaudi::Property< bool > m_usecoolfrontier
static std::string find_file(const std::string &logical_file_name, const std::string &search_path)
std::vector< std::string > veto
these patterns are anded
Definition listroot.cxx:191
MsgStream & msg
Definition testRead.cxx:32
TFile * file