File indexing completed on 2025-04-24 01:28:01
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "FWCore/Services/src/SiteLocalConfigService.h"
0010 #include "FWCore/Utilities/interface/Exception.h"
0011 #include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
0012 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0013 #include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
0014 #include "tinyxml2.h"
0015 #include <sstream>
0016 #include <memory>
0017 #include <boost/algorithm/string.hpp>
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028 namespace {
0029
0030
0031
0032 inline std::string _toParenString(tinyxml2::XMLElement const &nodeToConvert) {
0033 std::ostringstream oss;
0034
0035 for (auto child = nodeToConvert.FirstChildElement(); child != nullptr; child = child->NextSiblingElement()) {
0036 for (auto attribute = child->FirstAttribute(); attribute != nullptr; attribute = attribute->Next()) {
0037 oss << "(" << child->Name() << attribute->Name() << "=" << attribute->Value() << ")";
0038 }
0039 }
0040 return oss.str();
0041 }
0042
0043 template <typename T>
0044 static void overrideFromPSet(char const *iName, edm::ParameterSet const &iPSet, T &iHolder, T const *&iPointer) {
0045 if (iPSet.exists(iName)) {
0046 iHolder = iPSet.getUntrackedParameter<T>(iName);
0047 iPointer = &iHolder;
0048 }
0049 }
0050
0051 constexpr char const *const kEmptyString = "";
0052 const char *safe(const char *iCheck) {
0053 if (iCheck == nullptr) {
0054 return kEmptyString;
0055 }
0056 return iCheck;
0057 }
0058
0059 std::string defaultURL() {
0060 std::string returnValue;
0061 const char *tmp = std::getenv("SITECONFIG_PATH");
0062 if (tmp) {
0063 returnValue = tmp;
0064 }
0065 returnValue += "/JobConfig/site-local-config.xml";
0066 return returnValue;
0067 }
0068
0069 }
0070
0071 namespace edm {
0072 namespace service {
0073
0074 const std::string SiteLocalConfigService::m_statisticsDefaultPort = "3334";
0075
0076 SiteLocalConfigService::SiteLocalConfigService(ParameterSet const &pset)
0077 : m_url(pset.getUntrackedParameter<std::string>("siteLocalConfigFileUrl", defaultURL())),
0078 m_trivialDataCatalogs(),
0079 m_dataCatalogs(),
0080 m_frontierConnect(),
0081 m_connected(false),
0082 m_cacheTempDir(),
0083 m_cacheTempDirPtr(nullptr),
0084 m_cacheMinFree(),
0085 m_cacheMinFreePtr(nullptr),
0086 m_cacheHint(),
0087 m_cacheHintPtr(nullptr),
0088 m_cloneCacheHint(),
0089 m_cloneCacheHintPtr(nullptr),
0090 m_readHint(),
0091 m_readHintPtr(nullptr),
0092 m_ttreeCacheSize(0U),
0093 m_ttreeCacheSizePtr(nullptr),
0094 m_timeout(0U),
0095 m_timeoutPtr(nullptr),
0096 m_debugLevel(0U),
0097 m_enablePrefetching(false),
0098 m_enablePrefetchingPtr(nullptr),
0099 m_nativeProtocols(),
0100 m_nativeProtocolsPtr(nullptr),
0101 m_statisticsDestination(),
0102 m_statisticsAddrInfo(nullptr),
0103 m_statisticsInfoAvail(false),
0104 m_siteName(),
0105 m_subSiteName() {
0106 this->parse(m_url);
0107
0108
0109 overrideFromPSet("overrideSourceCacheTempDir", pset, m_cacheTempDir, m_cacheTempDirPtr);
0110 overrideFromPSet("overrideSourceCacheMinFree", pset, m_cacheMinFree, m_cacheMinFreePtr);
0111 overrideFromPSet("overrideSourceCacheHintDir", pset, m_cacheHint, m_cacheHintPtr);
0112 overrideFromPSet("overrideSourceCloneCacheHintDir", pset, m_cloneCacheHint, m_cloneCacheHintPtr);
0113 overrideFromPSet("overrideSourceReadHint", pset, m_readHint, m_readHintPtr);
0114 overrideFromPSet("overrideSourceNativeProtocols", pset, m_nativeProtocols, m_nativeProtocolsPtr);
0115 overrideFromPSet("overrideSourceTTreeCacheSize", pset, m_ttreeCacheSize, m_ttreeCacheSizePtr);
0116 overrideFromPSet("overrideSourceTimeout", pset, m_timeout, m_timeoutPtr);
0117 overrideFromPSet("overridePrefetching", pset, m_enablePrefetching, m_enablePrefetchingPtr);
0118 const std::string *tmpStringPtr = nullptr;
0119 overrideFromPSet("overrideStatisticsDestination", pset, m_statisticsDestination, tmpStringPtr);
0120 this->computeStatisticsDestination();
0121 std::vector<std::string> tmpStatisticsInfo;
0122 std::vector<std::string> const *tmpStatisticsInfoPtr = nullptr;
0123 overrideFromPSet("overrideStatisticsInfo", pset, tmpStatisticsInfo, tmpStatisticsInfoPtr);
0124 if (tmpStatisticsInfoPtr) {
0125 m_statisticsInfoAvail = true;
0126 m_statisticsInfo.clear();
0127 for (auto &entry : tmpStatisticsInfo) {
0128 m_statisticsInfo.insert(std::move(entry));
0129 }
0130 }
0131
0132 if (pset.exists("debugLevel")) {
0133 m_debugLevel = pset.getUntrackedParameter<unsigned int>("debugLevel");
0134 }
0135 if (pset.exists("overrideUseLocalConnectString")) {
0136 m_useLocalConnectString = pset.getUntrackedParameter<bool>("overrideUseLocalConnectString");
0137 }
0138 if (pset.exists("overrideLocalConnectPrefix")) {
0139 m_localConnectPrefix = pset.getUntrackedParameter<std::string>("overrideLocalConnectPrefix");
0140 }
0141 if (pset.exists("overrideLocalConnectSuffix")) {
0142 m_localConnectSuffix = pset.getUntrackedParameter<std::string>("overrideLocalConnectSuffix");
0143 }
0144 }
0145
0146 SiteLocalConfigService::~SiteLocalConfigService() {
0147 if (m_statisticsAddrInfo) {
0148 freeaddrinfo(m_statisticsAddrInfo);
0149 m_statisticsAddrInfo = nullptr;
0150 }
0151 }
0152
0153 std::vector<std::string> const &SiteLocalConfigService::trivialDataCatalogs() const {
0154 if (!m_connected) {
0155 static std::vector<std::string> const tmp{"file:PoolFileCatalog.xml"};
0156 return tmp;
0157 }
0158
0159 if (m_trivialDataCatalogs.empty()) {
0160 cms::Exception ex("SiteLocalConfigService");
0161 ex << "Did not find catalogs in event-data section in " << m_url;
0162 ex.addContext("edm::SiteLocalConfigService::trivialDataCatalogs()");
0163 throw ex;
0164 }
0165
0166 return m_trivialDataCatalogs;
0167 }
0168
0169 std::vector<edm::CatalogAttributes> const &SiteLocalConfigService::dataCatalogs() const {
0170 if (!m_connected) {
0171 cms::Exception ex("SiteLocalConfigService");
0172 ex << "Incomplete configuration. Valid site-local-config not found at " << m_url;
0173 ex.addContext("edm::SiteLocalConfigService::dataCatalogs()");
0174 throw ex;
0175 }
0176 if (m_dataCatalogs.empty()) {
0177 cms::Exception ex("SiteLocalConfigService");
0178 ex << "Did not find catalogs in data-access section in " << m_url;
0179 ex.addContext("edm::SiteLocalConfigService::dataCatalogs()");
0180 throw ex;
0181 }
0182 return m_dataCatalogs;
0183 }
0184
0185 std::filesystem::path const SiteLocalConfigService::storageDescriptionPath(
0186 edm::CatalogAttributes const &aDataCatalog) const {
0187 char *tmp = std::getenv("SITECONFIG_PATH");
0188 if (tmp == nullptr) {
0189 throw cms::Exception("SiteLocalConfigService") << "SITECONFIG_PATH is not set!";
0190 }
0191 std::string siteconfig_path = std::string(tmp);
0192 std::filesystem::path filename_storage;
0193
0194 if (aDataCatalog.site == aDataCatalog.storageSite) {
0195
0196 if (aDataCatalog.subSite.empty())
0197 filename_storage = siteconfig_path;
0198
0199 else
0200 filename_storage = siteconfig_path + "/..";
0201 } else {
0202
0203 if (aDataCatalog.subSite.empty())
0204 filename_storage = siteconfig_path + "/../" + aDataCatalog.storageSite;
0205
0206 else
0207 filename_storage = siteconfig_path + "/../../" + aDataCatalog.storageSite;
0208 }
0209 filename_storage /= "storage.json";
0210 try {
0211 filename_storage = std::filesystem::canonical(filename_storage);
0212 } catch (std::exception &e) {
0213 cms::Exception ex("SiteLocalConfigService");
0214 ex << "Fail to convert path to the storage description, " << filename_storage.string()
0215 << ", to the canonical absolute path"
0216 << ". Path exists?";
0217 ex.addContext("edm::SiteLocalConfigService::storageDescriptionPath()");
0218 throw ex;
0219 }
0220 return filename_storage;
0221 }
0222
0223 std::string const SiteLocalConfigService::frontierConnect(std::string const &servlet) const {
0224 if (!m_connected) {
0225 throw cms::Exception("Incomplete configuration") << "Valid site-local-config not found at " << m_url;
0226 }
0227
0228 if (m_frontierConnect.empty()) {
0229 throw cms::Exception("Incomplete configuration")
0230 << "Did not find frontier-connect in calib-data section in " << m_url;
0231 }
0232
0233 if (servlet.empty()) {
0234 return m_frontierConnect;
0235 }
0236
0237
0238
0239 std::string::size_type nextparen = 0;
0240 std::string::size_type serverurl, lastslash;
0241 std::string complexstr = "";
0242 while ((serverurl = m_frontierConnect.find("(serverurl=", nextparen)) != std::string::npos) {
0243 complexstr.append(m_frontierConnect, nextparen, serverurl - nextparen);
0244 nextparen = m_frontierConnect.find(')', serverurl);
0245 lastslash = m_frontierConnect.rfind('/', nextparen);
0246 complexstr.append(m_frontierConnect, serverurl, lastslash - serverurl + 1);
0247 complexstr.append(servlet);
0248 }
0249 complexstr.append(m_frontierConnect, nextparen, m_frontierConnect.length() - nextparen);
0250
0251 return complexstr;
0252 }
0253
0254 std::string const SiteLocalConfigService::lookupCalibConnect(std::string const &input) const {
0255 static std::string const proto = "frontier://";
0256
0257 if (input.substr(0, proto.length()) == proto) {
0258
0259
0260
0261
0262
0263
0264
0265
0266
0267
0268
0269
0270
0271
0272 std::string::size_type startservlet = proto.length();
0273
0274 std::string::size_type endservlet = input.find('(', startservlet);
0275 if (endservlet == std::string::npos) {
0276 endservlet = input.rfind('/', input.length());
0277 }
0278 std::string servlet = input.substr(startservlet, endservlet - startservlet);
0279 if ((!servlet.empty()) && (servlet.find_first_of(":/)[]") == std::string::npos)) {
0280 if (servlet == "cms_conditions_data") {
0281
0282 servlet = "";
0283 }
0284 return proto + frontierConnect(servlet) + input.substr(endservlet);
0285 }
0286 }
0287 return input;
0288 }
0289
0290 std::string const *SiteLocalConfigService::sourceCacheTempDir() const { return m_cacheTempDirPtr; }
0291
0292 double const *SiteLocalConfigService::sourceCacheMinFree() const { return m_cacheMinFreePtr; }
0293
0294 std::string const *SiteLocalConfigService::sourceCacheHint() const { return m_cacheHintPtr; }
0295
0296 std::string const *SiteLocalConfigService::sourceCloneCacheHint() const { return m_cloneCacheHintPtr; }
0297
0298 std::string const *SiteLocalConfigService::sourceReadHint() const { return m_readHintPtr; }
0299
0300 unsigned int const *SiteLocalConfigService::sourceTTreeCacheSize() const { return m_ttreeCacheSizePtr; }
0301
0302 unsigned int const *SiteLocalConfigService::sourceTimeout() const { return m_timeoutPtr; }
0303
0304 bool SiteLocalConfigService::enablePrefetching() const {
0305 return m_enablePrefetchingPtr ? *m_enablePrefetchingPtr : false;
0306 }
0307
0308 unsigned int SiteLocalConfigService::debugLevel() const { return m_debugLevel; }
0309
0310 std::vector<std::string> const *SiteLocalConfigService::sourceNativeProtocols() const {
0311 return m_nativeProtocolsPtr;
0312 }
0313
0314 struct addrinfo const *SiteLocalConfigService::statisticsDestination() const { return m_statisticsAddrInfo; }
0315
0316 std::set<std::string> const *SiteLocalConfigService::statisticsInfo() const {
0317 return m_statisticsInfoAvail ? &m_statisticsInfo : nullptr;
0318 }
0319
0320 std::string const &SiteLocalConfigService::siteName() const { return m_siteName; }
0321 std::string const &SiteLocalConfigService::subSiteName() const { return m_subSiteName; }
0322 bool SiteLocalConfigService::useLocalConnectString() const { return m_useLocalConnectString; }
0323 std::string const &SiteLocalConfigService::localConnectPrefix() const { return m_localConnectPrefix; }
0324 std::string const &SiteLocalConfigService::localConnectSuffix() const { return m_localConnectSuffix; }
0325
0326 void SiteLocalConfigService::getCatalog(tinyxml2::XMLElement const &cat, std::string site, std::string subSite) {
0327 edm::CatalogAttributes aCatalog;
0328 aCatalog.site = site;
0329 aCatalog.subSite = subSite;
0330 auto tmp_site = std::string(safe(cat.Attribute("site")));
0331
0332 if (tmp_site.empty())
0333 aCatalog.storageSite = site;
0334
0335 else
0336 aCatalog.storageSite = tmp_site;
0337 aCatalog.volume = std::string(safe(cat.Attribute("volume")));
0338 aCatalog.protocol = std::string(safe(cat.Attribute("protocol")));
0339 m_dataCatalogs.push_back(aCatalog);
0340 }
0341
0342 void SiteLocalConfigService::parse(std::string const &url) {
0343 tinyxml2::XMLDocument doc;
0344 auto loadErr = doc.LoadFile(url.c_str());
0345 if (loadErr != tinyxml2::XML_SUCCESS) {
0346 return;
0347 }
0348
0349
0350
0351
0352
0353
0354
0355
0356
0357
0358
0359
0360
0361
0362
0363
0364
0365
0366
0367
0368
0369
0370
0371
0372
0373
0374
0375
0376
0377
0378 auto rootElement = doc.RootElement();
0379
0380 for (auto site = rootElement->FirstChildElement("site"); site != nullptr;
0381 site = site->NextSiblingElement("site")) {
0382 auto subSite = site->FirstChildElement("subsite");
0383
0384
0385 m_siteName = safe(site->Attribute("name"));
0386 m_subSiteName = std::string();
0387 if (subSite) {
0388
0389 auto subSite_first_child = subSite->FirstChild();
0390 if (subSite_first_child) {
0391 cms::Exception ex("SiteLocalConfigService");
0392 ex << "Invalid site-local-config.xml. Subsite node has children!";
0393 ex.addContext("edm::SiteLocalConfigService::parse()");
0394 throw ex;
0395 }
0396 m_subSiteName = safe(subSite->Attribute("name"));
0397 }
0398
0399
0400 auto eventData = site->FirstChildElement("event-data");
0401 if (eventData) {
0402 auto catalog = eventData->FirstChildElement("catalog");
0403 if (catalog) {
0404 m_trivialDataCatalogs.push_back(safe(catalog->Attribute("url")));
0405 catalog = catalog->NextSiblingElement("catalog");
0406 while (catalog) {
0407 m_trivialDataCatalogs.push_back(safe(catalog->Attribute("url")));
0408 catalog = catalog->NextSiblingElement("catalog");
0409 }
0410 }
0411 }
0412
0413
0414
0415
0416
0417
0418
0419
0420
0421
0422 auto dataAccess = site->FirstChildElement("data-access");
0423 if (dataAccess) {
0424
0425 auto catalog = dataAccess->FirstChildElement("catalog");
0426 if (catalog) {
0427
0428 getCatalog(*catalog, m_siteName, m_subSiteName);
0429
0430 catalog = catalog->NextSiblingElement("catalog");
0431 while (catalog) {
0432
0433 getCatalog(*catalog, m_siteName, m_subSiteName);
0434
0435 catalog = catalog->NextSiblingElement("catalog");
0436 }
0437 }
0438 }
0439
0440
0441 auto calibData = site->FirstChildElement("calib-data");
0442
0443 if (calibData) {
0444 auto frontierConnect = calibData->FirstChildElement("frontier-connect");
0445
0446 if (frontierConnect) {
0447 m_frontierConnect = _toParenString(*frontierConnect);
0448 }
0449 auto localConnect = calibData->FirstChildElement("local-connect");
0450 if (localConnect) {
0451 if (frontierConnect) {
0452 throw cms::Exception("Illegal site local configuration")
0453 << "It is illegal to include both frontier-connect and local-connect in the same XML file";
0454 }
0455 m_useLocalConnectString = true;
0456 auto connectString = localConnect->FirstChildElement("connectString");
0457 if (connectString) {
0458 m_localConnectPrefix = safe(connectString->Attribute("prefix"));
0459 m_localConnectSuffix = safe(connectString->Attribute("suffix"));
0460 }
0461 }
0462 }
0463
0464
0465 auto sourceConfig = site->FirstChildElement("source-config");
0466
0467 if (sourceConfig) {
0468 auto cacheTempDir = sourceConfig->FirstChildElement("cache-temp-dir");
0469
0470 if (cacheTempDir) {
0471 m_cacheTempDir = safe(cacheTempDir->Attribute("name"));
0472 m_cacheTempDirPtr = &m_cacheTempDir;
0473 }
0474
0475 auto cacheMinFree = sourceConfig->FirstChildElement("cache-min-free");
0476
0477 if (cacheMinFree) {
0478
0479 m_cacheMinFree = cacheMinFree->DoubleAttribute("value");
0480 m_cacheMinFreePtr = &m_cacheMinFree;
0481 }
0482
0483 auto cacheHint = sourceConfig->FirstChildElement("cache-hint");
0484
0485 if (cacheHint) {
0486 m_cacheHint = safe(cacheHint->Attribute("value"));
0487 m_cacheHintPtr = &m_cacheHint;
0488 }
0489
0490 auto cloneCacheHint = sourceConfig->FirstChildElement("clone-cache-hint");
0491
0492 if (cloneCacheHint) {
0493 m_cloneCacheHint = safe(cloneCacheHint->Attribute("value"));
0494 m_cloneCacheHintPtr = &m_cloneCacheHint;
0495 }
0496
0497 auto readHint = sourceConfig->FirstChildElement("read-hint");
0498
0499 if (readHint) {
0500 m_readHint = safe(readHint->Attribute("value"));
0501 m_readHintPtr = &m_readHint;
0502 }
0503
0504 auto ttreeCacheSize = sourceConfig->FirstChildElement("ttree-cache-size");
0505
0506 if (ttreeCacheSize) {
0507 m_ttreeCacheSize = ttreeCacheSize->UnsignedAttribute("value");
0508 m_ttreeCacheSizePtr = &m_ttreeCacheSize;
0509 }
0510
0511 auto timeout = sourceConfig->FirstChildElement("timeout-in-seconds");
0512
0513 if (timeout) {
0514 m_timeout = timeout->UnsignedAttribute("value");
0515 m_timeoutPtr = &m_timeout;
0516 }
0517
0518 auto statsDest = sourceConfig->FirstChildElement("statistics-destination");
0519
0520 if (statsDest) {
0521 m_statisticsDestination = safe(statsDest->Attribute("endpoint"));
0522 if (m_statisticsDestination.empty()) {
0523 m_statisticsDestination = safe(statsDest->Attribute("name"));
0524 }
0525 std::string tmpStatisticsInfo = safe(statsDest->Attribute("info"));
0526 boost::split(m_statisticsInfo, tmpStatisticsInfo, boost::is_any_of("\t ,"));
0527 m_statisticsInfoAvail = !tmpStatisticsInfo.empty();
0528 }
0529
0530 auto prefetching = sourceConfig->FirstChildElement("prefetching");
0531
0532 if (prefetching) {
0533 m_enablePrefetching = prefetching->BoolAttribute("value");
0534 m_enablePrefetchingPtr = &m_enablePrefetching;
0535 }
0536
0537 auto nativeProtocol = sourceConfig->FirstChildElement("native-protocols");
0538
0539 if (nativeProtocol) {
0540 for (auto child = nativeProtocol->FirstChildElement(); child != nullptr;
0541 child = child->NextSiblingElement()) {
0542 m_nativeProtocols.push_back(safe(child->Attribute("prefix")));
0543 }
0544 m_nativeProtocolsPtr = &m_nativeProtocols;
0545 }
0546 }
0547 }
0548 m_connected = true;
0549 }
0550
0551 void SiteLocalConfigService::computeStatisticsDestination() {
0552 std::vector<std::string> inputStrings;
0553 boost::split(inputStrings, m_statisticsDestination, boost::is_any_of(":"));
0554 const std::string &host = inputStrings[0];
0555 const std::string &port = (inputStrings.size() > 1) ? inputStrings[1] : m_statisticsDefaultPort;
0556 struct addrinfo *res;
0557 struct addrinfo hints;
0558 memset(&hints, '\0', sizeof(hints));
0559 hints.ai_socktype = SOCK_DGRAM;
0560 hints.ai_flags = AI_ADDRCONFIG;
0561 hints.ai_family = AF_UNSPEC;
0562 int e = getaddrinfo(host.c_str(), port.c_str(), &hints, &res);
0563 if (e != 0) {
0564
0565 return;
0566 }
0567 m_statisticsAddrInfo = res;
0568 }
0569
0570 void SiteLocalConfigService::fillDescriptions(ConfigurationDescriptions &descriptions) {
0571 ParameterSetDescription desc;
0572 desc.setComment("Service to translate logical file names to physical file names.");
0573
0574 desc.addOptionalUntracked<std::string>("siteLocalConfigFileUrl", std::string())
0575 ->setComment(
0576 "Specify the file containing the site local config. Empty string will load from default directory.");
0577 desc.addOptionalUntracked<std::string>("overrideSourceCacheTempDir");
0578 desc.addOptionalUntracked<double>("overrideSourceCacheMinFree");
0579 desc.addOptionalUntracked<std::string>("overrideSourceCacheHintDir");
0580 desc.addOptionalUntracked<std::string>("overrideSourceCloneCacheHintDir")
0581 ->setComment("Provide an alternate cache hint for fast cloning.");
0582 desc.addOptionalUntracked<std::string>("overrideSourceReadHint");
0583 desc.addOptionalUntracked<std::vector<std::string> >("overrideSourceNativeProtocols");
0584 desc.addOptionalUntracked<unsigned int>("overrideSourceTTreeCacheSize");
0585 desc.addOptionalUntracked<unsigned int>("overrideSourceTimeout");
0586 desc.addOptionalUntracked<unsigned int>("debugLevel");
0587 desc.addOptionalUntracked<bool>("overridePrefetching")
0588 ->setComment("Request ROOT to asynchronously prefetch I/O during computation.");
0589 desc.addOptionalUntracked<std::string>("overrideStatisticsDestination")
0590 ->setComment(
0591 "Provide an alternate network destination for I/O statistics (must be in the form of host:port).");
0592 desc.addOptionalUntracked<std::vector<std::string> >("overrideStatisticsInfo")
0593 ->setComment(
0594 "Provide an alternate listing of statistics to send (comma separated list; current options are 'dn' or "
0595 "'nodn'). If left blank, all information is snet (including DNs).");
0596 desc.addOptionalUntracked<bool>("overrideUseLocalConnectString");
0597 desc.addOptionalUntracked<std::string>("overrideLocalConnectPrefix");
0598 desc.addOptionalUntracked<std::string>("overrideLocalConnectSuffix");
0599 descriptions.add("SiteLocalConfigService", desc);
0600 }
0601 }
0602 }