18#include "GaudiKernel/ISvcLocator.h"
19#include "GaudiKernel/IIncidentSvc.h"
20#include "GaudiKernel/Incident.h"
21#include "GaudiKernel/IAlgTool.h"
22#include "GaudiKernel/IToolSvc.h"
23#include "GaudiKernel/IClassIDSvc.h"
24#include "GaudiKernel/Guards.h"
25#include "GaudiKernel/ConcurrencyFlags.h"
50 const char *cstr =
str.c_str();
52 for (
unsigned int i=0; i <
str.length(); ++i) {
53 str2 += toupper(*(cstr+i));
60 std::atomic<bool> s_firstRun(
true);
75 if (
x->clID() ==
y->clID() ) {
76 return (
x->name() <
y->name() );
78 return (
x->clID() <
y->clID() );
90 if (
a->name()!=b->name())
return a->name()<b->name();
91 if (
a->clID()!=b->clID())
return a->clID()<b->clID();
104 const IInterface* parent):
105 base_class(
type, name, parent ),
122 std::map<const DataProxy*, IOVEntry*>::iterator itr;
128 ObjMap::iterator oitr;
130 delete ( oitr->second );
133 for (std::map<CallBackID, BFCN*>::iterator i =
m_cbidMap.begin();
140 std::set< const TransientAddress*, SortTADptr >::const_iterator titr;
155 SmartIF<IProperty> iovSvcProp{service(
"IOVSvc")};
174 p_incSvc->addListener(
this,
"BeginRun", pri,
true);
176 msg().setColor(MSG::GREEN);
177 msg() <<
"IOVRanges will be checked only ";
178 msg().setColor(MSG::CYAN);
180 msg().setColor(MSG::GREEN);
181 msg() <<
" at the start of the job" <<
endmsg;
182 }
else if (updi ==
"RUN") {
184 p_incSvc->addListener(
this,
"BeginRun", pri,
true);
186 msg().setColor(MSG::GREEN);
187 msg() <<
"IOVRanges will be checked at every ";
188 msg().setColor(MSG::CYAN);
190 }
else if (updi ==
"EVENT") {
192 p_incSvc->addListener(
this,
"BeginEvent", pri,
true);
193 p_incSvc->addListener(
this,
"BeginRun", pri,
true);
195 msg().setColor(MSG::GREEN);
196 msg() <<
"IOVRanges will be checked at every ";
197 msg().setColor(MSG::CYAN);
201 <<
"\"event\" \"run\" or \"job\"");
202 return StatusCode::FAILURE;
207 msg().setColor(MSG::GREEN);
208 msg() <<
"IOV Data will be preloaded at the same interval" <<
endmsg;
213 return StatusCode::SUCCESS;
230 else if (!initial_first) {
231 if ( inc.type() !=
m_checkTrigger && inc.type() != IncidentType::BeginRun ) {
236 std::lock_guard<std::recursive_mutex> lock(m_handleMutex);
243 if ( inc.type() !=
m_checkTrigger && inc.type() != IncidentType::BeginRun ) {
252 if (proxy ==
nullptr) {
266 const bool first = initial_first;
269 if(Gaudi::Concurrency::ConcurrencyFlags::numProcs()==0) {
270 if (inc.type() == IncidentType::BeginRun) {
282 set< DataProxy*, SortDPptr > proxiesToReset;
283 if ( inc.type() ==
m_checkTrigger || inc.type() == IncidentType::BeginRun ) {
285 const EventContext& context = inc.context();
289 const EventIDBase& eventID = context.eventID();
290 uint32_t
event = eventID.lumi_block();
291 uint32_t
run = eventID.run_number();
297 curTime.
setTimestamp(1000000000L*(uint64_t)eventID.time_stamp() + eventID.time_stamp_ns_offset());
299 if (msgLvl(MSG::DEBUG)) {
300 msg().setColor(MSG::YELLOW,MSG::RED);
301 msg() << inc.type() <<
": [R/LB] = " << curTime <<
endmsg;
304 if (inc.type() == IncidentType::BeginRun) {
306 SmartIF<IIOVDbSvc> iovDB{service(
"IOVDbSvc",
false)};
311 if (StatusCode::SUCCESS != iovDB->signalBeginRun(curTime,
324 std::set< const TransientAddress*, SortTADptr >::const_iterator titr;
328 if (StatusCode::SUCCESS !=
sc) {
335 if (msgLvl(MSG::VERBOSE)) {
340 if (msgLvl(MSG::DEBUG)) {
348 throw( std::runtime_error(
"IOVSvcTool::preLoadProxies") );
352 SmartIF<IIOVDbSvc> iovDB{service(
"IOVDbSvc",
false)};
354 iovDB->signalEndProxyPreload();
355 ATH_MSG_DEBUG(
"Signaled end proxy preload to IOVDbSvc " << curTime);
367 if (msgLvl(MSG::DEBUG)) {
373 std::map<BFCN*, std::list<std::string> > resetKeys;
380 if (inc.type() == IncidentType::BeginRun &&
m_forceReset && !s_firstRun) {
382 ATH_MSG_DEBUG(
"Resetting all proxies on BeginRun incident for store \""
385 if (msgLvl(MSG::VERBOSE)) {
386 std::set< const SG::DataProxy* >::const_iterator pit;
403 auto itr = proxiesToReset.find(p);
404 if (itr != proxiesToReset.end()) {
405 proxiesToReset.erase( itr );
410 if (!first && proxiesToReset.size() > 0 &&
411 ( (Gaudi::Concurrency::ConcurrencyFlags::numThreads() +
412 Gaudi::Concurrency::ConcurrencyFlags::numConcurrentEvents()) > 0 ) ) {
413 ATH_MSG_FATAL(
"Cannot update Conditions via callback functions in MT after the first event");
414 for (
const auto* prox : proxiesToReset) {
415 ATH_MSG_FATAL(
"CLID=" << prox->clID() <<
", name=" << prox->name());
417 throw GaudiException(
"Cannot update Conditions via callback functions in MT after the first event",name(),StatusCode::FAILURE);
441 Gaudi::Guards::AuditorGuard auditor(
m_names.at(prx), auditorSvc(),
"preLoadProxy");
442 if (prx->accessData() ==
nullptr) {
447 std::list<std::string> keys;
448 pair<pmITR,pmITR> fitr =
m_proxyMap.equal_range( prx );
449 for (
pmITR p=fitr.first; p!=fitr.second; ++p) {
451 std::string key = prx->name();
452 resetKeys[f].emplace_back(prx->name());
464 for (
int i=2; i<=
m_trigTree->maxLevel(); ++i) {
465 CBTree::nodeSet::const_iterator itt, itt_s, itt_e;
467 for (itt = itt_s; itt != itt_e; ++itt) {
470 if (
node->trigger()) {
472 auditorSvc()->before(
"Callback",
m_fcnMap.at(ff).name(),inc.context());
473 if ((*ff)(i,resetKeys[ff]).isFailure()) {
474 auditorSvc()->after(
"Callback",
m_fcnMap.at(ff).name(),inc.context());
476 << std::endl <<
"Skipping all subsequent callbacks.");
481 auditorSvc()->after(
"Callback",
m_fcnMap.at(ff).name(),inc.context());
484 if (perr !=
nullptr)
break;
499 if (perr !=
nullptr)
throw (*perr);
505 std::map<const DataProxy*, IOVEntry*>::iterator pitr;
508 if ( pitr !=
m_entries.end() && pitr->second->range()->isInRange(curTime) ) {
512 if (!prx->updateAddress()) {
514 if (perr !=
nullptr)
throw (*perr);
519 if (msgLvl(MSG::VERBOSE)) {
520 IOpaqueAddress *ioa = prx->address();
524 if (iova !=
nullptr) {
531 if (perr !=
nullptr)
throw (*perr);
535 if ( inc.type() == IncidentType::BeginRun) {
550 if (proxy ==
nullptr) {
552 return StatusCode::FAILURE;
559 <<
" already registered: " << proxy->name());
560 return StatusCode::SUCCESS;
563 std::string tname, fullname;
566 fullname = tname +
"[" + key +
"]";
573 return StatusCode::SUCCESS;
587 if (proxy ==
nullptr) {
589 return StatusCode::FAILURE;
594 std::set<SG::DataProxy*, SortDPptr>::iterator itr =
m_proxies.find(proxy);
597 <<
" not registered: " << proxy->name());
598 return StatusCode::SUCCESS;
605 return StatusCode::SUCCESS;
616 typename SET::iterator it = set.lower_bound(ent);
617 while (it != set.end() && !set.key_comp()(*it, ent) && !set.key_comp()(ent,*it)) {
636 std::lock_guard<std::recursive_mutex> lock(m_handleMutex);
637 assert(
nullptr != pOld);
638 assert(
nullptr != pNew);
648 return StatusCode::SUCCESS;
659 std::map< const SG::DataProxy*, IOVEntry*>::iterator ent =
673 return (
m_trigTree->replaceProxy(pOld, pNew) ?
674 StatusCode::SUCCESS :
675 StatusCode::FAILURE );
688 if (proxy ==
nullptr) {
691 return StatusCode::FAILURE;
708 if (proxy ==
nullptr) {
711 return StatusCode::FAILURE;
729 << tad_in->
clID() <<
"/" << tad_in->
name()
730 <<
") alread in preLoad set. Not inserting");
731 return StatusCode::SUCCESS;
737 << tad_in->
clID() <<
"/" << tad_in->
name()
738 <<
") alread in partPreLoad set. Not inserting");
739 return StatusCode::SUCCESS;
745 return StatusCode::SUCCESS;
759 <<
" alread in preLoad set. Not inserting");
760 return StatusCode::SUCCESS;
766 <<
" alread in partPreLoad set. Not inserting");
767 return StatusCode::SUCCESS;
774 return StatusCode::SUCCESS;
835 ATH_MSG_DEBUG(
"setRange() for clid: " << clid <<
" key: " << key
836 <<
" in IOVrange:" << iovr);
839 ATH_MSG_ERROR(
"IOVRange " << iovr <<
"is not valid. Start OK: "
841 <<
" run/evt/time min/max "
845 return StatusCode::FAILURE;
850 if (proxy ==
nullptr) {
852 return StatusCode::FAILURE;
855 std::lock_guard<std::recursive_mutex> lock(m_handleMutex);
857 return StatusCode::SUCCESS;
867 std::lock_guard<std::recursive_mutex> lock(m_handleMutex);
868 std::map<const DataProxy*,IOVEntry*>::const_iterator itr(
m_entries.find(dp));
870 return StatusCode::FAILURE;
873 iov = *(itr->second->range());
875 return StatusCode::SUCCESS;
884 std::unique_ptr<IOpaqueAddress>& ioa,
885 const IOVTime& curTime)
const {
891 return StatusCode::FAILURE;
902 std::unique_ptr<IOpaqueAddress>& ioa)
const {
903 StatusCode
sc(StatusCode::FAILURE);
907 dynamic_cast<IIOVDbSvc*
>(dp->provider());
908 if (idb !=
nullptr) {
909 sc = idb->getRange(clid, key, time, range, tag, ioa);
914 ATH_MSG_ERROR(
"No proxy found for clid " << clid <<
" key " << key);
923 const IOVRange& range,
const std::string &tag) {
926 if (!range.start().isValid() || !range.stop().isValid()) {
928 return StatusCode::FAILURE;
935 return StatusCode::FAILURE;
938 std::lock_guard<std::recursive_mutex> lock(m_handleMutex);
939 std::map<const DataProxy*,IOVEntry*>::const_iterator itr(
m_entries.find(dp));
947 if (idb !=
nullptr) {
948 return idb->setRange(clid, key, range, tag);
951 return StatusCode::FAILURE;
963 StatusCode scr(StatusCode::SUCCESS);
965 SmartIF<IIOVDbSvc> iovDB{service(
"IOVDbSvc",
false)};
967 std::map<BFCN*, std::list<std::string> > resetKeys;
969 Gaudi::Guards::AuditorGuard auditor(
m_names[dp], auditorSvc(),
"preLoadProxy");
971 if (msgLvl(MSG::VERBOSE)) {
972 msg().setColor(MSG::CYAN);
973 msg() <<
"loading proxy for CLID: " << dp->clID()
977 if (dp->provider() ==
nullptr) {
978 msg() << MSG::FATAL <<
"No provider found for proxy " <<
m_names[dp]
979 <<
". It is probably not a conditions object" << endl;
980 msg() <<
"Proxy Map: ";
983 scr = StatusCode::FAILURE;
994 if (!dp->updateAddress())
995 sc = StatusCode::FAILURE;
1004 iovDB->getKeyInfo(dp->name(), kinfo) && kinfo.
extensible ) {
1005 ATH_MSG_VERBOSE(
"not preloading data for extensible folder " << dp->name());
1009 << dp->clID() <<
"/"
1010 << dp->name() <<
")");
1011 if( dp->accessData() !=
nullptr ) {
1012 sc = StatusCode::SUCCESS;
1014 sc = StatusCode::FAILURE;
1015 ATH_MSG_ERROR(
"preLoading proxies: accessData() failed for " <<
1016 dp->clID() <<
"/" << dp->name() <<
")");
1021 if (
sc.isFailure()) scr=
sc;
1026 for (pitr=
pi.first; pitr!=
pi.second; ++pitr) {
1027 BFCN *f = pitr->second;
1028 resetKeys[f].emplace_back(dp->name());
1032 if (cn !=
nullptr) {
1038 if (scr.isFailure()) {
1039 ATH_MSG_ERROR(
"Problems preLoading proxies. No callbacks triggered.");
1044 for (
int i=2; i<=
m_trigTree->maxLevel(); ++i) {
1045 CBTree::nodeSet::const_iterator itt, itt_s, itt_e;
1047 for (itt = itt_s; itt != itt_e; ++itt) {
1050 if (
node->trigger()) {
1053 auditorSvc()->before(
"Callback",
m_fcnMap[ff].name(),ctx);
1054 if ((*ff)(i,resetKeys[ff]).isFailure()) {
1055 auditorSvc()->after(
"Callback",
m_fcnMap[ff].name(),ctx);
1057 return StatusCode::FAILURE;
1059 auditorSvc()->after(
"Callback",
m_fcnMap[ff].name(),ctx);
1078 std::list<std::string> klist;
1079 klist.push_back(key);
1080 if ( (*fcn)(
I,klist).isFailure() ) {
1082 return StatusCode::FAILURE;
1085 return StatusCode::SUCCESS;
1092 const std::string& key ) {
1096 std::map<const SG::DataProxy*, BFCN*>::const_iterator pitr =
1100 return StatusCode::FAILURE;
1103 BFCN* fcn = pitr->second;
1114 std::string objname;
1117 msg() << endl <<
"ClockTime start set: " << endl;
1119 objname =
m_names.at( (*start_itr)->proxy() );
1120 msg() <<
" " << objname <<
" (" << (*start_itr)->proxy() <<
") "
1121 << (*start_itr)->range()->start() << endl;
1127 msg() <<
"Run/Event start set: " << endl;
1129 objname =
m_names.at( (*start_itr)->proxy() );
1130 msg() <<
" " << objname <<
" (" << (*start_itr)->proxy() <<
") "
1131 << (*start_itr)->range()->start() << endl;
1142 std::string objname;
1145 msg() << endl <<
"ClockTime stop set: " << endl;
1147 objname =
m_names.at((*stop_itr)->proxy());
1148 msg() <<
" " << objname <<
" (" << (*stop_itr)->proxy() <<
") "
1149 << (*stop_itr)->range()->stop() << endl;
1155 msg() <<
"Run/Event stop set: " << endl;
1157 objname =
m_names.at((*stop_itr)->proxy());
1158 msg() <<
" " << objname <<
" (" << (*stop_itr)->proxy() <<
") "
1159 << (*stop_itr)->range()->stop() << endl;
1169 msg() <<
"------------------------------ IOVSvc Proxy Map "
1170 <<
"------------------------------" << endl;
1175 msg() <<
"----------------------------------------------------------"
1176 <<
"---------------------" << endl;
1185 msg() <<
" " << dp <<
" " << dp->clID() <<
" "
1186 << (it ==
m_names.end() ?
"???" : it->second) << endl;
1188 if (
pi.first ==
pi.second) {
1189 msg() <<
" -> no callback associated" << endl;
1191 for (
auto pitr=
pi.first; pitr!=
pi.second; ++pitr) {
1192 BFCN* fcn = pitr->second;
1196 msg() <<
" -> " << fcn <<
" " << cbid.
name() << endl;
1211 std::string tname,fullname;
1212 StatusCode
sc =
p_CLIDSvc->getTypeNameOfID( dp->clID(), tname );
1213 if (
sc.isFailure()) {
1215 return StatusCode::FAILURE;
1217 fullname = tname +
"[" + dp->name() +
"]";
1222 <<
" with DataHandle " << fullname
1223 <<
" -> Need to bind DataHandle first");
1224 return StatusCode::FAILURE;
1231 std::pair<pmITR,pmITR> fitr =
m_proxyMap.equal_range( dp );
1232 for (
pmITR p=fitr.first; p!=fitr.second; ++p) {
1235 <<
" already registered against " << fullname);
1236 return StatusCode::FAILURE;
1245 obs =
new BFCN(fcn);
1252 m_proxyMap.insert(std::pair<const SG::DataProxy*,BFCN* >(dp,obs));
1253 m_bfcnMap.insert(std::pair<BFCN*, const SG::DataProxy*> (obs,dp));
1256 ObjMap::const_iterator oitr =
m_objMap.find(c.ptr());
1258 oitr->second->insert(c);
1260 std::set<CallBackID> *cbs =
new std::set<CallBackID>;
1267 if ( cn ==
nullptr) {
1274 ATH_MSG_ERROR(
"Cannot find callback node for parent DataProxy "
1278 ATH_MSG_DEBUG(
"register by " << c.name() <<
" bound to " << fullname);
1282 ATH_MSG_INFO(
"Still in initialize phase, not tiggering callback for "
1283 << c.name() <<
" bound to " << fullname);
1289 return StatusCode::SUCCESS;
1302 std::set<const SG::DataProxy*> proxyset;
1306 std::pair<fnITR,fnITR> fi1 =
m_bfcnMap.equal_range( obs1 );
1307 for (
fnITR fitr1= fi1.first; fitr1!=fi1.second; ++fitr1) {
1310 std::pair<fnITR,fnITR> fi2 =
m_bfcnMap.equal_range( obs2 );
1311 for (
fnITR fitr2=fi2.first; fitr2!=fi2.second; ++fitr2) {
1316 <<
" cannot be registered since it has already been registered "
1317 <<
"against " <<
m_names[prx1]);
1319 proxyset.insert(prx1);
1324 obs2 =
new BFCN( fcn2 );
1329 std::pair<fnITR,fnITR> fi1 =
m_bfcnMap.equal_range( obs1 );
1330 for(
fnITR fitr1=fi1.first; fitr1!=fi1.second; ++fitr1) {
1332 proxyset.insert(prx1);
1336 if (proxyset.size() == 0) {
1338 <<
" cannot be registered, since it has already been registered"
1339 <<
" against everything it can be.");
1340 return StatusCode::SUCCESS;
1344 ObjMap::const_iterator oitr =
m_objMap.find(c2.ptr());
1346 oitr->second->insert(c2);
1348 std::set<CallBackID> *cbs =
new std::set<CallBackID>;
1354 std::set<const SG::DataProxy*>::iterator pitr;
1355 std::list<std::string> klist;
1356 for (pitr=proxyset.begin(); pitr!=proxyset.end(); ++pitr) {
1358 m_proxyMap.insert(std::pair<const SG::DataProxy*,BFCN* >(prx,obs2));
1359 m_bfcnMap.insert(std::pair<BFCN*,const SG::DataProxy*>(obs2,prx));
1362 klist.push_back( prx->
name() );
1369 if ( cn ==
nullptr) {
1373 if (cp ==
nullptr) {
1375 <<
". This should never happen");
1376 return StatusCode::FAILURE;
1384 ATH_MSG_INFO(
"Still in initialize phase, not tiggering callback for "
1385 << c2.name() <<
" bound to " << *klist.begin());
1391 return StatusCode::SUCCESS;
1402 ObjMap::const_iterator oitr =
m_objMap.find( ia );
1406 ATH_MSG_ERROR(
"No callback registered with AlgTool " << ia->name());
1407 return StatusCode::FAILURE;
1410 std::set<CallBackID> *
sc = oitr->second;
1412 if (
sc->size() == 1) {
1416 return regFcn(cb, c2, fcn2, trigger);
1420 ATH_MSG_ERROR(
"More than one callback registered to AlgTool "
1421 << ia->name() <<
". Found : " <<
sc->size());
1422 return StatusCode::FAILURE;
1432 std::set<std::string>&
tools) {
1436 if (key == pitr->first->name()) {
1442 return ( (
match) ? StatusCode::SUCCESS : StatusCode::FAILURE );
1452 return (StatusCode::SUCCESS);
1459 std::set<SG::DataProxy*, SortDPptr> &proxiesToReset,
1460 const IOVTime& curTime)
const {
1462 if (pSet.begin()==pSet.end())
return;
1464 if (msgLvl(MSG::DEBUG)) {
1465 msg() << MSG::DEBUG <<
"--> scan for resets: start set: " <<
type << endl;
1468 startITR start_itr( pSet.begin() );
1469 while ( start_itr != pSet.end() ) {
1472 if (msgLvl(MSG::DEBUG)) {
1473 msg() <<
"\t" <<
m_names.at((*start_itr)->proxy()) <<
": "
1474 << (*start_itr)->range()->start()<<
" <- removed"<<endl;
1476 proxiesToReset.insert( (*start_itr)->proxy() );
1478 (*start_itr)->setRemovedStart(
true );
1479 pSet.erase(start_itr++);
1486 if (msgLvl(MSG::DEBUG)) {
1496 std::set<SG::DataProxy*, SortDPptr> &proxiesToReset,
1497 const IOVTime& curTime)
const {
1499 if (pSet.begin()==pSet.end())
return;
1500 if (msgLvl(MSG::DEBUG)) {
1501 msg() << MSG::DEBUG <<
"--> scan for resets: stop set: " <<
type << endl;
1504 stopITR stop_itr(pSet.begin());
1505 while ( stop_itr != pSet.end() ) {
1508 if (msgLvl(MSG::DEBUG)) {
1509 msg() <<
" " <<
m_names.at((*stop_itr)->proxy()) <<
": "
1510 << (*stop_itr)->range()->stop()<<
" -> removed"<<endl;
1512 proxiesToReset.insert( (*stop_itr)->proxy() );
1514 (*stop_itr)->setRemovedStop(
true );
1515 pSet.erase(stop_itr++);
1521 if (msgLvl(MSG::DEBUG)) {
1543 if (proxy ==
nullptr) {
1567 ObjMap::const_iterator oitr =
m_objMap.find( ia );
1610 std::string fullname, tname;
1611 if (
p_CLIDSvc->getTypeNameOfID( clid, tname ).isFailure()) {
1613 fullname += std::to_string(clid);
1621 fullname += std::to_string(clid);
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
uint32_t CLID
The Class ID type.
Abstract interface to IOVDbSvc to access IOVRange and tag information.
boost::function< StatusCode(IOVSVC_CALLBACK_ARGS) > IOVSvcCallBackFcn
the type of an IOVSvc call back: it wraps both the method and the object the method is called on
void setProperty(columnar::PythonToolHandle &self, const std::string &key, nb::object value)
const std::string & name() const
const std::string & name() const
interface for IOA providers
Abstract interface to IOVDbSvc to access IOVRange and tag information.
virtual IOVRange range() const
Retrieve IOVRange.
void setStartITR(startITR itr)
void setStopITR(stopITR itr)
const IOVRange * range() const
startITR getStartITR() const
bool removedStart() const
stopITR getStopITR() const
const IOVTime & stop() const
const IOVTime & start() const
Basic time unit for IOVSvc.
static constexpr uint64_t MAXTIMESTAMP
static constexpr uint32_t MAXRUN
void setRunEvent(uint32_t run, uint32_t event) noexcept
bool isValid() const noexcept
static constexpr uint32_t MINEVENT
static constexpr uint64_t MINTIMESTAMP
void setTimestamp(uint64_t timestamp) noexcept
static constexpr uint32_t MAXEVENT
static constexpr uint32_t MINRUN
bool isTimestamp() const noexcept
CLID clID() const
Retrieve clid.
virtual const name_type & name() const override final
Retrieve data object key == string.
CLID clID() const
Retrieve string key:
const std::string & name() const
Get the primary (hashed) SG key.
bool operator()(const SG::DataProxy *, const SG::DataProxy *) const
bool operator()(const SG::TransientAddress *, const SG::TransientAddress *) const
bool match(std::string s1, std::string s2)
match the individual directories of two strings
Filled by IIOVDbSvc::getKeyInfo.