File indexing completed on 2023-05-31 00:37:54
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_rfioType("castor"),
0082 m_connected(false),
0083 m_cacheTempDir(),
0084 m_cacheTempDirPtr(nullptr),
0085 m_cacheMinFree(),
0086 m_cacheMinFreePtr(nullptr),
0087 m_cacheHint(),
0088 m_cacheHintPtr(nullptr),
0089 m_cloneCacheHint(),
0090 m_cloneCacheHintPtr(nullptr),
0091 m_readHint(),
0092 m_readHintPtr(nullptr),
0093 m_ttreeCacheSize(0U),
0094 m_ttreeCacheSizePtr(nullptr),
0095 m_timeout(0U),
0096 m_timeoutPtr(nullptr),
0097 m_debugLevel(0U),
0098 m_enablePrefetching(false),
0099 m_enablePrefetchingPtr(nullptr),
0100 m_nativeProtocols(),
0101 m_nativeProtocolsPtr(nullptr),
0102 m_statisticsDestination(),
0103 m_statisticsAddrInfo(nullptr),
0104 m_statisticsInfoAvail(false),
0105 m_siteName(),
0106 m_subSiteName() {
0107 this->parse(m_url);
0108
0109
0110 overrideFromPSet("overrideSourceCacheTempDir", pset, m_cacheTempDir, m_cacheTempDirPtr);
0111 overrideFromPSet("overrideSourceCacheMinFree", pset, m_cacheMinFree, m_cacheMinFreePtr);
0112 overrideFromPSet("overrideSourceCacheHintDir", pset, m_cacheHint, m_cacheHintPtr);
0113 overrideFromPSet("overrideSourceCloneCacheHintDir", pset, m_cloneCacheHint, m_cloneCacheHintPtr);
0114 overrideFromPSet("overrideSourceReadHint", pset, m_readHint, m_readHintPtr);
0115 overrideFromPSet("overrideSourceNativeProtocols", pset, m_nativeProtocols, m_nativeProtocolsPtr);
0116 overrideFromPSet("overrideSourceTTreeCacheSize", pset, m_ttreeCacheSize, m_ttreeCacheSizePtr);
0117 overrideFromPSet("overrideSourceTimeout", pset, m_timeout, m_timeoutPtr);
0118 overrideFromPSet("overridePrefetching", pset, m_enablePrefetching, m_enablePrefetchingPtr);
0119 const std::string *tmpStringPtr = nullptr;
0120 overrideFromPSet("overrideStatisticsDestination", pset, m_statisticsDestination, tmpStringPtr);
0121 this->computeStatisticsDestination();
0122 std::vector<std::string> tmpStatisticsInfo;
0123 std::vector<std::string> const *tmpStatisticsInfoPtr = nullptr;
0124 overrideFromPSet("overrideStatisticsInfo", pset, tmpStatisticsInfo, tmpStatisticsInfoPtr);
0125 if (tmpStatisticsInfoPtr) {
0126 m_statisticsInfoAvail = true;
0127 m_statisticsInfo.clear();
0128 for (auto &entry : tmpStatisticsInfo) {
0129 m_statisticsInfo.insert(std::move(entry));
0130 }
0131 }
0132
0133 if (pset.exists("debugLevel")) {
0134 m_debugLevel = pset.getUntrackedParameter<unsigned int>("debugLevel");
0135 }
0136 if (pset.exists("overrideUseLocalConnectString")) {
0137 m_useLocalConnectString = pset.getUntrackedParameter<bool>("overrideUseLocalConnectString");
0138 }
0139 if (pset.exists("overrideLocalConnectPrefix")) {
0140 m_localConnectPrefix = pset.getUntrackedParameter<std::string>("overrideLocalConnectPrefix");
0141 }
0142 if (pset.exists("overrideLocalConnectSuffix")) {
0143 m_localConnectSuffix = pset.getUntrackedParameter<std::string>("overrideLocalConnectSuffix");
0144 }
0145 }
0146
0147 SiteLocalConfigService::~SiteLocalConfigService() {
0148 if (m_statisticsAddrInfo) {
0149 freeaddrinfo(m_statisticsAddrInfo);
0150 m_statisticsAddrInfo = nullptr;
0151 }
0152 }
0153
0154 std::vector<std::string> const &SiteLocalConfigService::trivialDataCatalogs() const {
0155 if (!m_connected) {
0156 static std::vector<std::string> const tmp{"file:PoolFileCatalog.xml"};
0157 return tmp;
0158 }
0159
0160 if (m_trivialDataCatalogs.empty()) {
0161 cms::Exception ex("SiteLocalConfigService");
0162 ex << "Did not find catalogs in event-data section in " << m_url;
0163 ex.addContext("edm::SiteLocalConfigService::trivialDataCatalogs()");
0164 throw ex;
0165 }
0166
0167 return m_trivialDataCatalogs;
0168 }
0169
0170 std::vector<edm::CatalogAttributes> const &SiteLocalConfigService::dataCatalogs() const {
0171 if (!m_connected) {
0172 cms::Exception ex("SiteLocalConfigService");
0173 ex << "Incomplete configuration. Valid site-local-config not found at " << m_url;
0174 ex.addContext("edm::SiteLocalConfigService::dataCatalogs()");
0175 throw ex;
0176 }
0177 if (m_dataCatalogs.empty()) {
0178 cms::Exception ex("SiteLocalConfigService");
0179 ex << "Did not find catalogs in data-access section in " << m_url;
0180 ex.addContext("edm::SiteLocalConfigService::dataCatalogs()");
0181 throw ex;
0182 }
0183 return m_dataCatalogs;
0184 }
0185
0186 std::filesystem::path const SiteLocalConfigService::storageDescriptionPath(
0187 edm::CatalogAttributes const &aDataCatalog) const {
0188 std::string siteconfig_path = std::string(std::getenv("SITECONFIG_PATH"));
0189 std::filesystem::path filename_storage;
0190
0191 if (aDataCatalog.site == aDataCatalog.storageSite) {
0192
0193 if (aDataCatalog.subSite.empty())
0194 filename_storage = siteconfig_path;
0195
0196 else
0197 filename_storage = siteconfig_path + "/..";
0198 } else {
0199
0200 if (aDataCatalog.subSite.empty())
0201 filename_storage = siteconfig_path + "/../" + aDataCatalog.storageSite;
0202
0203 else
0204 filename_storage = siteconfig_path + "/../../" + aDataCatalog.storageSite;
0205 }
0206 filename_storage /= "storage.json";
0207 try {
0208 filename_storage = std::filesystem::canonical(filename_storage);
0209 } catch (std::exception &e) {
0210 cms::Exception ex("SiteLocalConfigService");
0211 ex << "Fail to convert path to the storage description, " << filename_storage.string()
0212 << ", to the canonical absolute path"
0213 << ". Path exists?";
0214 ex.addContext("edm::SiteLocalConfigService::storageDescriptionPath()");
0215 throw ex;
0216 }
0217 return filename_storage;
0218 }
0219
0220 std::string const SiteLocalConfigService::frontierConnect(std::string const &servlet) const {
0221 if (!m_connected) {
0222 throw cms::Exception("Incomplete configuration") << "Valid site-local-config not found at " << m_url;
0223 }
0224
0225 if (m_frontierConnect.empty()) {
0226 throw cms::Exception("Incomplete configuration")
0227 << "Did not find frontier-connect in calib-data section in " << m_url;
0228 }
0229
0230 if (servlet.empty()) {
0231 return m_frontierConnect;
0232 }
0233
0234
0235
0236 std::string::size_type nextparen = 0;
0237 std::string::size_type serverurl, lastslash;
0238 std::string complexstr = "";
0239 while ((serverurl = m_frontierConnect.find("(serverurl=", nextparen)) != std::string::npos) {
0240 complexstr.append(m_frontierConnect, nextparen, serverurl - nextparen);
0241 nextparen = m_frontierConnect.find(')', serverurl);
0242 lastslash = m_frontierConnect.rfind('/', nextparen);
0243 complexstr.append(m_frontierConnect, serverurl, lastslash - serverurl + 1);
0244 complexstr.append(servlet);
0245 }
0246 complexstr.append(m_frontierConnect, nextparen, m_frontierConnect.length() - nextparen);
0247
0248 return complexstr;
0249 }
0250
0251 std::string const SiteLocalConfigService::lookupCalibConnect(std::string const &input) const {
0252 static std::string const proto = "frontier://";
0253
0254 if (input.substr(0, proto.length()) == proto) {
0255
0256
0257
0258
0259
0260
0261
0262
0263
0264
0265
0266
0267
0268
0269 std::string::size_type startservlet = proto.length();
0270
0271 std::string::size_type endservlet = input.find('(', startservlet);
0272 if (endservlet == std::string::npos) {
0273 endservlet = input.rfind('/', input.length());
0274 }
0275 std::string servlet = input.substr(startservlet, endservlet - startservlet);
0276 if ((!servlet.empty()) && (servlet.find_first_of(":/)[]") == std::string::npos)) {
0277 if (servlet == "cms_conditions_data") {
0278
0279 servlet = "";
0280 }
0281 return proto + frontierConnect(servlet) + input.substr(endservlet);
0282 }
0283 }
0284 return input;
0285 }
0286
0287 std::string const SiteLocalConfigService::rfioType(void) const { return m_rfioType; }
0288
0289 std::string const *SiteLocalConfigService::sourceCacheTempDir() const { return m_cacheTempDirPtr; }
0290
0291 double const *SiteLocalConfigService::sourceCacheMinFree() const { return m_cacheMinFreePtr; }
0292
0293 std::string const *SiteLocalConfigService::sourceCacheHint() const { return m_cacheHintPtr; }
0294
0295 std::string const *SiteLocalConfigService::sourceCloneCacheHint() const { return m_cloneCacheHintPtr; }
0296
0297 std::string const *SiteLocalConfigService::sourceReadHint() const { return m_readHintPtr; }
0298
0299 unsigned int const *SiteLocalConfigService::sourceTTreeCacheSize() const { return m_ttreeCacheSizePtr; }
0300
0301 unsigned int const *SiteLocalConfigService::sourceTimeout() const { return m_timeoutPtr; }
0302
0303 bool SiteLocalConfigService::enablePrefetching() const {
0304 return m_enablePrefetchingPtr ? *m_enablePrefetchingPtr : false;
0305 }
0306
0307 unsigned int SiteLocalConfigService::debugLevel() const { return m_debugLevel; }
0308
0309 std::vector<std::string> const *SiteLocalConfigService::sourceNativeProtocols() const {
0310 return m_nativeProtocolsPtr;
0311 }
0312
0313 struct addrinfo const *SiteLocalConfigService::statisticsDestination() const { return m_statisticsAddrInfo; }
0314
0315 std::set<std::string> const *SiteLocalConfigService::statisticsInfo() const {
0316 return m_statisticsInfoAvail ? &m_statisticsInfo : nullptr;
0317 }
0318
0319 std::string const &SiteLocalConfigService::siteName() const { return m_siteName; }
0320 std::string const &SiteLocalConfigService::subSiteName() const { return m_subSiteName; }
0321 bool SiteLocalConfigService::useLocalConnectString() const { return m_useLocalConnectString; }
0322 std::string const &SiteLocalConfigService::localConnectPrefix() const { return m_localConnectPrefix; }
0323 std::string const &SiteLocalConfigService::localConnectSuffix() const { return m_localConnectSuffix; }
0324
0325 void SiteLocalConfigService::getCatalog(tinyxml2::XMLElement const &cat, std::string site, std::string subSite) {
0326 edm::CatalogAttributes aCatalog;
0327 aCatalog.site = site;
0328 aCatalog.subSite = subSite;
0329 auto tmp_site = std::string(safe(cat.Attribute("site")));
0330
0331 if (tmp_site.empty())
0332 aCatalog.storageSite = site;
0333
0334 else
0335 aCatalog.storageSite = tmp_site;
0336 aCatalog.volume = std::string(safe(cat.Attribute("volume")));
0337 aCatalog.protocol = std::string(safe(cat.Attribute("protocol")));
0338 m_dataCatalogs.push_back(aCatalog);
0339 }
0340
0341 void SiteLocalConfigService::parse(std::string const &url) {
0342 tinyxml2::XMLDocument doc;
0343 auto loadErr = doc.LoadFile(url.c_str());
0344 if (loadErr != tinyxml2::XML_SUCCESS) {
0345 return;
0346 }
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 auto rfiotype = eventData->FirstChildElement("rfiotype");
0412 if (rfiotype) {
0413 m_rfioType = safe(rfiotype->Attribute("value"));
0414 }
0415 }
0416
0417
0418
0419
0420
0421
0422
0423
0424
0425
0426 auto dataAccess = site->FirstChildElement("data-access");
0427 if (dataAccess) {
0428
0429 auto catalog = dataAccess->FirstChildElement("catalog");
0430 if (catalog) {
0431
0432 getCatalog(*catalog, m_siteName, m_subSiteName);
0433
0434 catalog = catalog->NextSiblingElement("catalog");
0435 while (catalog) {
0436
0437 getCatalog(*catalog, m_siteName, m_subSiteName);
0438
0439 catalog = catalog->NextSiblingElement("catalog");
0440 }
0441 }
0442 }
0443
0444
0445 auto calibData = site->FirstChildElement("calib-data");
0446
0447 if (calibData) {
0448 auto frontierConnect = calibData->FirstChildElement("frontier-connect");
0449
0450 if (frontierConnect) {
0451 m_frontierConnect = _toParenString(*frontierConnect);
0452 }
0453 auto localConnect = calibData->FirstChildElement("local-connect");
0454 if (localConnect) {
0455 if (frontierConnect) {
0456 throw cms::Exception("Illegal site local configuration")
0457 << "It is illegal to include both frontier-connect and local-connect in the same XML file";
0458 }
0459 m_useLocalConnectString = true;
0460 auto connectString = localConnect->FirstChildElement("connectString");
0461 if (connectString) {
0462 m_localConnectPrefix = safe(connectString->Attribute("prefix"));
0463 m_localConnectSuffix = safe(connectString->Attribute("suffix"));
0464 }
0465 }
0466 }
0467
0468
0469 auto sourceConfig = site->FirstChildElement("source-config");
0470
0471 if (sourceConfig) {
0472 auto cacheTempDir = sourceConfig->FirstChildElement("cache-temp-dir");
0473
0474 if (cacheTempDir) {
0475 m_cacheTempDir = safe(cacheTempDir->Attribute("name"));
0476 m_cacheTempDirPtr = &m_cacheTempDir;
0477 }
0478
0479 auto cacheMinFree = sourceConfig->FirstChildElement("cache-min-free");
0480
0481 if (cacheMinFree) {
0482
0483 m_cacheMinFree = cacheMinFree->DoubleAttribute("value");
0484 m_cacheMinFreePtr = &m_cacheMinFree;
0485 }
0486
0487 auto cacheHint = sourceConfig->FirstChildElement("cache-hint");
0488
0489 if (cacheHint) {
0490 m_cacheHint = safe(cacheHint->Attribute("value"));
0491 m_cacheHintPtr = &m_cacheHint;
0492 }
0493
0494 auto cloneCacheHint = sourceConfig->FirstChildElement("clone-cache-hint");
0495
0496 if (cloneCacheHint) {
0497 m_cloneCacheHint = safe(cloneCacheHint->Attribute("value"));
0498 m_cloneCacheHintPtr = &m_cloneCacheHint;
0499 }
0500
0501 auto readHint = sourceConfig->FirstChildElement("read-hint");
0502
0503 if (readHint) {
0504 m_readHint = safe(readHint->Attribute("value"));
0505 m_readHintPtr = &m_readHint;
0506 }
0507
0508 auto ttreeCacheSize = sourceConfig->FirstChildElement("ttree-cache-size");
0509
0510 if (ttreeCacheSize) {
0511 m_ttreeCacheSize = ttreeCacheSize->UnsignedAttribute("value");
0512 m_ttreeCacheSizePtr = &m_ttreeCacheSize;
0513 }
0514
0515 auto timeout = sourceConfig->FirstChildElement("timeout-in-seconds");
0516
0517 if (timeout) {
0518 m_timeout = timeout->UnsignedAttribute("value");
0519 m_timeoutPtr = &m_timeout;
0520 }
0521
0522 auto statsDest = sourceConfig->FirstChildElement("statistics-destination");
0523
0524 if (statsDest) {
0525 m_statisticsDestination = safe(statsDest->Attribute("endpoint"));
0526 if (m_statisticsDestination.empty()) {
0527 m_statisticsDestination = safe(statsDest->Attribute("name"));
0528 }
0529 std::string tmpStatisticsInfo = safe(statsDest->Attribute("info"));
0530 boost::split(m_statisticsInfo, tmpStatisticsInfo, boost::is_any_of("\t ,"));
0531 m_statisticsInfoAvail = !tmpStatisticsInfo.empty();
0532 }
0533
0534 auto prefetching = sourceConfig->FirstChildElement("prefetching");
0535
0536 if (prefetching) {
0537 m_enablePrefetching = prefetching->BoolAttribute("value");
0538 m_enablePrefetchingPtr = &m_enablePrefetching;
0539 }
0540
0541 auto nativeProtocol = sourceConfig->FirstChildElement("native-protocols");
0542
0543 if (nativeProtocol) {
0544 for (auto child = nativeProtocol->FirstChildElement(); child != nullptr;
0545 child = child->NextSiblingElement()) {
0546 m_nativeProtocols.push_back(safe(child->Attribute("prefix")));
0547 }
0548 m_nativeProtocolsPtr = &m_nativeProtocols;
0549 }
0550 }
0551 }
0552 m_connected = true;
0553 }
0554
0555 void SiteLocalConfigService::computeStatisticsDestination() {
0556 std::vector<std::string> inputStrings;
0557 boost::split(inputStrings, m_statisticsDestination, boost::is_any_of(":"));
0558 const std::string &host = inputStrings[0];
0559 const std::string &port = (inputStrings.size() > 1) ? inputStrings[1] : m_statisticsDefaultPort;
0560 struct addrinfo *res;
0561 struct addrinfo hints;
0562 memset(&hints, '\0', sizeof(hints));
0563 hints.ai_socktype = SOCK_DGRAM;
0564 hints.ai_flags = AI_ADDRCONFIG;
0565 hints.ai_family = AF_UNSPEC;
0566 int e = getaddrinfo(host.c_str(), port.c_str(), &hints, &res);
0567 if (e != 0) {
0568
0569 return;
0570 }
0571 m_statisticsAddrInfo = res;
0572 }
0573
0574 void SiteLocalConfigService::fillDescriptions(ConfigurationDescriptions &descriptions) {
0575 ParameterSetDescription desc;
0576 desc.setComment("Service to translate logical file names to physical file names.");
0577
0578 desc.addOptionalUntracked<std::string>("siteLocalConfigFileUrl", std::string())
0579 ->setComment(
0580 "Specify the file containing the site local config. Empty string will load from default directory.");
0581 desc.addOptionalUntracked<std::string>("overrideSourceCacheTempDir");
0582 desc.addOptionalUntracked<double>("overrideSourceCacheMinFree");
0583 desc.addOptionalUntracked<std::string>("overrideSourceCacheHintDir");
0584 desc.addOptionalUntracked<std::string>("overrideSourceCloneCacheHintDir")
0585 ->setComment("Provide an alternate cache hint for fast cloning.");
0586 desc.addOptionalUntracked<std::string>("overrideSourceReadHint");
0587 desc.addOptionalUntracked<std::vector<std::string> >("overrideSourceNativeProtocols");
0588 desc.addOptionalUntracked<unsigned int>("overrideSourceTTreeCacheSize");
0589 desc.addOptionalUntracked<unsigned int>("overrideSourceTimeout");
0590 desc.addOptionalUntracked<unsigned int>("debugLevel");
0591 desc.addOptionalUntracked<bool>("overridePrefetching")
0592 ->setComment("Request ROOT to asynchronously prefetch I/O during computation.");
0593 desc.addOptionalUntracked<std::string>("overrideStatisticsDestination")
0594 ->setComment(
0595 "Provide an alternate network destination for I/O statistics (must be in the form of host:port).");
0596 desc.addOptionalUntracked<std::vector<std::string> >("overrideStatisticsInfo")
0597 ->setComment(
0598 "Provide an alternate listing of statistics to send (comma separated list; current options are 'dn' or "
0599 "'nodn'). If left blank, all information is snet (including DNs).");
0600 desc.addOptionalUntracked<bool>("overrideUseLocalConnectString");
0601 desc.addOptionalUntracked<std::string>("overrideLocalConnectPrefix");
0602 desc.addOptionalUntracked<std::string>("overrideLocalConnectSuffix");
0603 descriptions.add("SiteLocalConfigService", desc);
0604 }
0605 }
0606 }