ATLAS Offline Software
Loading...
Searching...
No Matches
IOVDbSvcConfig.py
Go to the documentation of this file.
1# Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
2
3from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator, ConfigurationError
4import os
5from AthenaConfiguration.ComponentFactory import CompFactory
6from AthenaConfiguration.AccumulatorCache import AccumulatorCache
7from AthenaCommon.Logging import logging
8from functools import cache
9
10msg = logging.getLogger('IOVDbSvcCfg')
11
12def CondInputLoaderCfg(flags, **kwargs):
13 result = ComponentAccumulator()
14 result.addCondAlgo(CompFactory.CondInputLoader(**kwargs))
15 return result
16
17
18def DBReplicaSvcCfg(flags, vetoDBRelease=False, **kwargs):
19 if vetoDBRelease:
20 kwargs.setdefault('COOLSQLiteVetoPattern', '/DBRelease/')
21
22 result = ComponentAccumulator()
23 result.addService(CompFactory.DBReplicaSvc(**kwargs),create=True)
24 return result
25
26
27@AccumulatorCache
28def IOVDbSvcCfg(flags, **kwargs):
29 # Add the conditions loader, must be the first in the sequence
30 result = CondInputLoaderCfg(flags)
31
32 kwargs.setdefault('OnlineMode', flags.Common.isOnline)
33 kwargs.setdefault('dbConnection', flags.IOVDb.DBConnection)
34 # setup knowledge of dbinstance in IOVDbSvc, for global tag x-check
35 kwargs.setdefault('DBInstance', flags.IOVDb.DatabaseInstance)
36
37 if 'FRONTIER_SERVER' in os.environ.keys() and os.environ['FRONTIER_SERVER'] != '':
38 kwargs.setdefault('CacheAlign', 3)
39
40 # Very important cache settings for use of CoralProxy at P1 (ATR-4646)
41 if flags.Common.isOnline and flags.Trigger.Online.isPartition:
42 kwargs['CacheAlign'] = 0
43 kwargs['CacheRun'] = 0
44 kwargs['CacheTime'] = 0
45
46 kwargs.setdefault('GlobalTag', flags.IOVDb.GlobalTag)
47 if 'Folders' in kwargs:
48 kwargs['Folders'] = ['/TagInfo<metaOnly/>'] + kwargs['Folders']
49 else:
50 kwargs.setdefault('Folders', ['/TagInfo<metaOnly/>'])
51
52 # Select CREST backend if needed
53 if flags.IOVDb.UseCREST:
54 kwargs.setdefault('Source', 'CREST')
55 checkGlobalTag(flags.IOVDb.DBConnection,flags.IOVDb.GlobalTag)
56
57 result.addService(CompFactory.IOVDbSvc(**kwargs), primary=True)
58
59 # Set up POOLSvc with appropriate catalogs
60 from AthenaPoolCnvSvc.PoolCommonConfig import PoolSvcCfg
61 result.merge(PoolSvcCfg(flags, withCatalogs=True))
62 if flags.MP.UseSharedReader or flags.MP.UseSharedWriter:
63 from AthenaPoolCnvSvc.PoolCommonConfig import AthenaPoolSharedIOCnvSvcCfg
64 result.merge(AthenaPoolSharedIOCnvSvcCfg(flags))
65 else:
66 from AthenaPoolCnvSvc.PoolCommonConfig import AthenaPoolCnvSvcCfg
67 result.merge(AthenaPoolCnvSvcCfg(flags))
68 result.addService(CompFactory.CondSvc())
69 result.addService(CompFactory.ProxyProviderSvc(ProviderNames=['IOVDbSvc']))
70
71 if not flags.IOVDb.UseCREST:
72 result.merge(DBReplicaSvcCfg(flags, vetoDBRelease=not flags.Input.isMC))
73
74 # Get TagInfoMgr
75 from EventInfoMgt.TagInfoMgrConfig import TagInfoMgrCfg
76 result.merge(TagInfoMgrCfg(flags))
77
78 # Set up MetaDataSvc
79 from AthenaServices.MetaDataSvcConfig import MetaDataSvcCfg
80 result.merge(MetaDataSvcCfg(flags, ['IOVDbMetaDataTool']))
81
82 return result
83
84
85# Convenience method to add folders:
86def addFolders(flags, folderStrings, detDb=None, className=None, extensible=False, tag=None, db=None, modifiers=''):
87 tagString = ''
88 if tag is not None:
89 if flags.IOVDb.UseCREST:
90 tagString = '<ctag>%s</ctag>' % tag
91 else: #COOL variant
92 tagString = '<tag>%s</tag>' % tag
93
94 # Convenience hack: Allow a single string as parameter:
95 if isinstance(folderStrings, str):
96 return addFolderList(flags, ((folderStrings + tagString, detDb, className),), extensible, db, modifiers)
97
98 else: # Got a list of folders
99 folderDefinitions = []
100
101 for folderString in folderStrings:
102 folderDefinitions.append((folderString + tagString, detDb, className))
103
104 return addFolderList(flags, folderDefinitions, extensible, db, modifiers)
105
106
107def addFolderList(flags, listOfFolderInfoTuple, extensible=False, db=None, modifiers=''):
108 """Add access to the given set of folders, in the identified subdetector schema.
109 FolerInfoTuple consists of (foldername,detDB,classname)
110
111 If EXTENSIBLE is set, then if we access an open-ended IOV at the end of the list,
112 the end time for this range will be set to just past the current event.
113 Subsequent accesses will update this end time for subsequent events.
114 This allows the possibility of later adding a new IOV using IOVSvc::setRange."""
115 loadFolders = set()
116 folders = []
117 sqliteFolders = dict()
118
119 if flags.IOVDb.SqliteInput:
120 if flags.IOVDb.UseCREST:
121 sqliteFolders = getCrestDirContent(flags)
122 else:
123 sqliteFolders = getSqliteContent(flags.IOVDb.SqliteInput,
124 flags.IOVDb.SqliteFolders,
125 flags.IOVDb.DatabaseInstance)
126
127 for (fs, detDb, className) in listOfFolderInfoTuple:
128 fse= _extractFolder(fs)
129 # Add class-name to CondInputLoader (if reqired)
130 if className is not None:
131 loadFolders.add((className, fse))
132
133 if fse in sqliteFolders:
134 msg.warning(f'Reading folder {fs} from local storage, bypassing production database')
135 fs += sqliteFolders[fse]
136 elif detDb is not None and fs.find('<db>') == -1:
137
138 if db: # override database name if provided
139 dbName=db
140 else:
141 dbName = flags.IOVDb.DatabaseInstance
142 if detDb in _dblist.keys():
143 fs = f'<db>{_dblist[detDb]}/{dbName}</db> {fs}'
144 elif os.access(detDb, os.R_OK):
145 # Assume slqite file
146 fs = f'<db>sqlite://;schema={detDb};dbname={dbName}</db> {fs}'
147 elif detDb.startswith("crest_fs:"):
148 fs = f'<db>{detDb}</db> {fs}'
149 else:
150 raise ConfigurationError(f'Error, db shorthand {detDb} not known, nor found as sqlite file')
151 # Append database string to folder-name
152
153 if extensible:
154 fs = fs + '<extensible/>'
155
156 # Add explicitly given xml-modifiers (like channel-selection)
157 fs += modifiers
158
159 # Append (modified) folder-name string to IOVDbSvc Folders property
160 folders.append(fs)
161
162
163 result = IOVDbSvcCfg(flags)
164 result.getPrimary().Folders+=folders
165 if loadFolders:
166 result.getCondAlgo('CondInputLoader').Load |= loadFolders
167
168 if flags.IOVDb.CleanerRingSize > 0:
169 #HLT-jobs set IOVDb.CleanerRingSize to 0 to run without the cleaning-service,
170 cleanerSvc = CompFactory.Athena.DelayedConditionsCleanerSvc(RingSize=flags.IOVDb.CleanerRingSize)
171 result.addService(cleanerSvc)
172 result.addService(CompFactory.Athena.ConditionsCleanerSvc(CleanerSvc=cleanerSvc))
173
174
175 return result
176
177
178def addFoldersSplitOnline(flags, detDb, onlineFolders, offlineFolders, className=None, extensible=False, addMCString='_OFL', splitMC=False, tag=None, forceDb=None, modifiers=''):
179 """Add access to given folder, using either online_folder or offline_folder. For MC, add addMCString as a postfix (default is _OFL)"""
180
181 if flags.Common.isOnline and not flags.Input.isMC:
182 folders = onlineFolders
183 elif splitMC and not flags.Input.isMC:
184 folders = onlineFolders
185 else:
186 # MC, so add addMCString
187 detDb = detDb + addMCString
188 folders = offlineFolders
189
190 return addFolders(flags, folders, detDb, className, extensible, tag=tag, db=forceDb, modifiers=modifiers)
191
192
193_dblist = {
194 'INDET':'COOLONL_INDET',
195 'INDET_ONL':'COOLONL_INDET',
196 'PIXEL':'COOLONL_PIXEL',
197 'PIXEL_ONL':'COOLONL_PIXEL',
198 'SCT':'COOLONL_SCT',
199 'SCT_ONL':'COOLONL_SCT',
200 'TRT':'COOLONL_TRT',
201 'TRT_ONL':'COOLONL_TRT',
202 'LAR':'COOLONL_LAR',
203 'LAR_ONL':'COOLONL_LAR',
204 'TILE':'COOLONL_TILE',
205 'TILE_ONL':'COOLONL_TILE',
206 'MUON':'COOLONL_MUON',
207 'MUON_ONL':'COOLONL_MUON',
208 'MUONALIGN':'COOLONL_MUONALIGN',
209 'MUONALIGN_ONL':'COOLONL_MUONALIGN',
210 'MDT':'COOLONL_MDT',
211 'MDT_ONL':'COOLONL_MDT',
212 'RPC':'COOLONL_RPC',
213 'RPC_ONL':'COOLONL_RPC',
214 'TGC':'COOLONL_TGC',
215 'TGC_ONL':'COOLONL_TGC',
216 'CSC':'COOLONL_CSC',
217 'CSC_ONL':'COOLONL_CSC',
218 'TDAQ':'COOLONL_TDAQ',
219 'TDAQ_ONL':'COOLONL_TDAQ',
220 'GLOBAL':'COOLONL_GLOBAL',
221 'GLOBAL_ONL':'COOLONL_GLOBAL',
222 'TRIGGER':'COOLONL_TRIGGER',
223 'TRIGGER_ONL':'COOLONL_TRIGGER',
224 'CALO':'COOLONL_CALO',
225 'CALO_ONL':'COOLONL_CALO',
226 'FWD':'COOLONL_FWD',
227 'FWD_ONL':'COOLONL_FWD',
228 'INDET_OFL':'COOLOFL_INDET',
229 'PIXEL_OFL':'COOLOFL_PIXEL',
230 'SCT_OFL':'COOLOFL_SCT',
231 'TRT_OFL':'COOLOFL_TRT',
232 'LAR_OFL':'COOLOFL_LAR',
233 'TILE_OFL':'COOLOFL_TILE',
234 'MUON_OFL':'COOLOFL_MUON',
235 'MUONALIGN_OFL':'COOLOFL_MUONALIGN',
236 'MDT_OFL':'COOLOFL_MDT',
237 'RPC_OFL':'COOLOFL_RPC',
238 'TGC_OFL':'COOLOFL_TGC',
239 'CSC_OFL':'COOLOFL_CSC',
240 'TDAQ_OFL':'COOLOFL_TDAQ',
241 'DCS_OFL':'COOLOFL_DCS',
242 'GLOBAL_OFL':'COOLOFL_GLOBAL',
243 'TRIGGER_OFL':'COOLOFL_TRIGGER',
244 'CALO_OFL':'COOLOFL_CALO',
245 'FWD_OFL':'COOLOFL_FWD'
246}
247
248
249def addOverride(flags, folder, tag, tagType="tag", db=None):
250 """Add xml override for the specified folder (folder-level tag, forceRunNumber, ...)"""
251 suffix = ''
252 if db:
253 suffix = f' <db>{db}</db>'
254 return IOVDbSvcCfg(flags, overrideTags=(f'<prefix>{folder}</prefix> <{tagType}>{tag}</{tagType}>{suffix}',))
255
256
257def _extractFolder(folderString):
258 """Extract the folder name (non-XML text) from a IOVDbSvc.Folders entry"""
259 folderName = ''
260 xmlTag = ''
261 ix = 0
262 while ix < len(folderString):
263 if (folderString[ix] == '<' and xmlTag == ''):
264 ix2 = folderString.find('>', ix)
265 if ix2 != -1:
266 xmlTag = folderString[ix + 1 : ix2].strip()
267 ix = ix2 + 1
268 elif folderString[ix:ix+2] == '</' and xmlTag != '':
269 ix2 = folderString.find('>', ix)
270 if ix2 != -1:
271 xmlTag = ''
272 ix = ix2 + 1
273 else:
274 ix2 = folderString.find('<', ix)
275 if ix2 == -1:
276 ix2 = len(folderString)
277 if xmlTag == '':
278 folderName = folderName + folderString[ix : ix2]
279 ix = ix2
280 return folderName.strip()
281
282
283@cache #Fill only once
284def getSqliteContent(sqliteInput,takeFolders,databaseInstance):
285 if sqliteInput == "": return dict()
286 sqliteFolders=dict()
287 if isinstance(takeFolders, str):
288 takeFolders=[takeFolders,]
289 dbStr="sqlite://;schema="+ sqliteInput+";dbname="+databaseInstance
290 from PyCool import cool
291 dbSvc = cool.DatabaseSvcFactory.databaseService()
292 db = dbSvc.openDatabase(dbStr)
293 nodelist=db.listAllNodes()
294 for node in nodelist:
295 if db.existsFolder(node):
296 if (len(takeFolders)>0 and str(node) not in takeFolders): continue
297 connStr="<db>"+dbStr+"</db>"
298 f=db.getFolder(node)
299 if f.versioningMode is not cool.FolderVersioning.SINGLE_VERSION:
300 tags=f.listTags()
301 if len(tags)==1:
302 connStr+="<tag>"+tags[0]+"</tag>"
303 sqliteFolders[str(node)]=connStr
304 db.closeDatabase()
305
306 if len(takeFolders)>0:
307 missedFolders=set(takeFolders)-set(sqliteFolders.keys())
308 if len(missedFolders):
309 msg.error("The following folders were requested via the flag IOVSvc.sqliteFolder but not found in the sqlite file %s",(sqliteInput))
310 for f in missedFolders:
311 msg.error(f)
312
313 msg.info("The following folders/tags are read from sqlite:")
314 for v in sqliteFolders.items():
315 msg.info("\t"+str(v))
316 return sqliteFolders
317
318
319
320@AccumulatorCache #Fill only once
322 """The CREST version of getSqliteContent.
323 Signficantly more complicated because CREST has no folder (only tags)
324 If there is a global tag table defined in the local crest directly,
325 we'll try to use it.
326 Otherwise, open the production DB and guess the tag based on the first part of
327 the folder name. Works only if the tag-naming convention is respected:
328 Folder /LAR/ElecCalib/Ramps becomes LARElecCalibRamps-suffix
329 """
330
331 crestDir=flags.IOVDb.SqliteInput
332 if crestDir == "": return dict()
333 requestedTags=flags.IOVDb.SqliteFolders
334 localCrestFolders=dict()
335
336 if len(crestDir.split(":"))==1:
337 crestDir="crest_fs:"+crestDir
338
339 missedTags=set(requestedTags) #copy of the tags
340
341 try:
342 import chai
343 except ImportError as e:
344 msg.error("Cannot import chai, can not inspect local crest directory %s",crestDir)
345 raise e
346
347 try:
348 localdb = chai.Database(crestDir)
349 except Exception as e:
350 msg.error("Failed to connect to crest directoy %s",crestDir)
351 raise e
352
353 #see if there is a global-tag defined in the local CREST dir:
354 localGTs=[]
355 localGT=None
356 try:
357 localGTs=localdb.find_global_tags()
358 except RuntimeError:
359 pass
360
361 if len(localGTs)==1:
362 localGT=localGTs[0]
363 msg.info("Found exactly one global tag in local crest directory: [%s] Try to use it.",localGT)
364 elif len(localGTs)>1:
365 if flags.IOVDb.GlobalTag in localGTs:
366 localGT=flags.IOVDb.GlobalTag
367 msg.info("Global tag %s also defined in local crest directory. Try to use it.",flags.IOVDb.GlobalTag)
368 else:
369 msg.warning("More than one global tag found in crest directory [%s], none matches the global conditions tag %s",
370 crestDir,flags.IOVDb.GlobalTag)
371 if localGT:
372 gt=localdb.get_global_tag(localGT)
373 resolvedTags= gt.resolve_all_tags()
374 for gt2ft in resolvedTags.items():
375 f=gt2ft[0][0]
376 lt=gt2ft[1]
377 if len(requestedTags)>0 and lt not in requestedTags: continue
378 localCrestFolders[f]="<db>"+crestDir+"</db><ctag>"+lt+"</ctag>"
379 missedTags.discard(lt)
380 else:
381 #No local tag hierachy defined. Try to make guesses based on tag hierary in the production db:
382 msg.warning("No (usable) global tag found in local crest directory %s. Open production db, try to guess folder-tag relation")
383 localtags=set(localdb.find_tags())
384
385 try:
386 proddb=chai.Database("crest:"+flags.IOVDb.DBConnection)
387 except Exception as e:
388 msg.error("Failed to connect to crest server %s",flags.IOVDb.CrestServer)
389 raise e
390
391 gt=proddb.get_global_tag(flags.IOVDb.GlobalTag)
392
393 resolvedTags=gt.resolve_all_tags()
394 folderstubToFolderMap={}
395 tbl=str.maketrans(".","-")
396 for gt2ft in resolvedTags.items():
397 f=gt2ft[0][0]
398 ft=gt2ft[1]
399 if ft.startswith("UPGRADE_"): ft=ft[8:] #No idea why we prepend this string ...
400 folderstub="".join(f.split("/")).lower()
401 tagstub=ft.translate(tbl).split("-")[0].lower()
402 if (tagstub != folderstub):
403 msg.warning("Folder-tag %s of folder %s in the production DB does not follow tag naming convention",ft, f)
404
405 folderstubToFolderMap[folderstub]=f
406
407 for lt in localtags:
408 if len(requestedTags)>0 and lt not in requestedTags: continue
409 tagstub=lt.translate(tbl).split("-")[0].lower()
410 if tagstub in folderstubToFolderMap:
411 f=folderstubToFolderMap[tagstub]
412 localCrestFolders[f]="<db>"+crestDir+"</db><ctag>"+lt+"</ctag>"
413 missedTags.discard(lt)
414 else:
415 msg.warning("Cannot guess the folder of the tag %s in the local CREST directory %s",lt,crestDir)
416 msg.warning("Ignoring this tag")
417
418
419 msg.info("The following folders/tags are read from local crest directory:")
420 for v in localCrestFolders.items():
421 msg.info("\t"+str(v))
422 if len(missedTags):
423 msg.error("The following local Crest tags have been explicitly requested via the flag IOVSvc.sqliteFolder but not found in the local crest directory %s",(crestDir))
424 for mt in missedTags:
425 msg.error("\t%s",mt)
426
427 return localCrestFolders
428
429
430
431
432
433
434
435#post-exec-style helper method to remove a folder from IOVDbSvc.Folders and CondInputLoader.Load
436#To be used in calibration-processing jobs that read the condions from anohter source or produce it in the same job
437def blockFolder(ca,folder):
438 "Block use of specified conditions DB folder so data can be read from elsewhere"
439 msg.info("Trying to remove folder [%s] from IOVDbSvc.Folders",folder)
440 iovdbsvc=ca.getService("IOVDbSvc")
441 oldLen=len(iovdbsvc.Folders)
442 iovdbsvc.Folders=[x for x in iovdbsvc.Folders if x.find(folder)==-1]
443 newLen=len(iovdbsvc.Folders)
444 if (oldLen==newLen):
445 msg.warning("Folder [%s] not found in IOVDbSvc.Folder",folder)
446 return
447 elif (oldLen-newLen>1):
448 msg.warning("Folder string [%s] matched more than one folder, removed %i folders",folder,oldLen-newLen)
449
450
451 condInputLoader=ca.getCondAlgo("CondInputLoader")
452 condInputLoader.Load=set([x for x in condInputLoader.Load if x[1].find(folder)==-1])
453 return
454
455
456@cache
457def checkGlobalTag(connStr,currGlobalTag):
458 try:
459 import chai
460 except ImportError:
461 msg.warning("Cannot import chai, cannot check global tag validity. ")
462 return None
463
464 fail=False
465 if connStr.startswith("http"):
466 connStr1="crest:"+connStr
467 else: #Assume local file
468 connStr1="crest_fs:"+connStr
469
470 try:
471 db=chai.Database(connStr1)
472 allGlobalTags=set(db.find_global_tags())
473 except chai._chai.NotFoundError as e:
474 msg.error(str(e))
475 msg.error(f"Could not load data from crest URL {connStr}")
476 fail=True
477 except chai._chai.BackendError as e:
478 msg.error(str(e))
479 msg.error(f"Could not load data from crest URL {connStr}")
480 fail=True
481
482 if fail: raise ConfigurationError()
483
484 if currGlobalTag not in allGlobalTags:
485 from difflib import get_close_matches
486 m1=get_close_matches(currGlobalTag,allGlobalTags,1)
487 msg.error(f"Global tag {currGlobalTag} does not exist"+(f". Did you mean '{m1[0]}'?" if m1 else ""))
488 raise ConfigurationError()
489 del db
490 return None
491
492
493
494
495if __name__ == '__main__':
496 from AthenaConfiguration.AllConfigFlags import initConfigFlags
497 from AthenaConfiguration.TestDefaults import defaultTestFiles
498 flags = initConfigFlags()
499 flags.Input.Files = defaultTestFiles.RAW_RUN2
500 flags.lock()
501
502 acc = IOVDbSvcCfg(flags)
503
504 with open('test.pkl','wb') as f:
505 acc.store(f)
STL class.
std::string find(const std::string &s)
return a remapped string
Definition hcg.cxx:140
std::vector< std::string > split(const std::string &s, const std::string &t=":")
Definition hcg.cxx:179
addOverride(flags, folder, tag, tagType="tag", db=None)
addFolderList(flags, listOfFolderInfoTuple, extensible=False, db=None, modifiers='')
addFolders(flags, folderStrings, detDb=None, className=None, extensible=False, tag=None, db=None, modifiers='')
checkGlobalTag(connStr, currGlobalTag)
CondInputLoaderCfg(flags, **kwargs)
addFoldersSplitOnline(flags, detDb, onlineFolders, offlineFolders, className=None, extensible=False, addMCString='_OFL', splitMC=False, tag=None, forceDb=None, modifiers='')
_extractFolder(folderString)
IOVDbSvcCfg(flags, **kwargs)
DBReplicaSvcCfg(flags, vetoDBRelease=False, **kwargs)
getSqliteContent(sqliteInput, takeFolders, databaseInstance)