Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2021-02-14 13:29:13

0001 ///////////////////////////////////////
0002 //
0003 // data catalogs are filled in "parse"
0004 //
0005 ///////////////////////////////////////
0006 
0007 //<<<<<< INCLUDES                                                       >>>>>>
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 //<<<<<< PRIVATE DEFINES                                                >>>>>>
0020 //<<<<<< PRIVATE CONSTANTS                                              >>>>>>
0021 //<<<<<< PRIVATE TYPES                                                  >>>>>>
0022 //<<<<<< PRIVATE VARIABLE DEFINITIONS                                   >>>>>>
0023 //<<<<<< PUBLIC VARIABLE DEFINITIONS                                    >>>>>>
0024 //<<<<<< CLASS STRUCTURE INITIALIZATION                                 >>>>>>
0025 //<<<<<< PRIVATE FUNCTION DEFINITIONS                                   >>>>>>
0026 //<<<<<< PUBLIC FUNCTION DEFINITIONS                                    >>>>>>
0027 //<<<<<< MEMBER FUNCTION DEFINITIONS                                    >>>>>>
0028 
0029 namespace {
0030 
0031   // concatenate all the XML node attribute/value pairs into a
0032   // paren-separated string (for use by CORAL and frontier_client)
0033   inline std::string _toParenString(tinyxml2::XMLElement const &nodeToConvert) {
0034     std::ostringstream oss;
0035 
0036     for (auto child = nodeToConvert.FirstChildElement(); child != nullptr; child = child->NextSiblingElement()) {
0037       for (auto attribute = child->FirstAttribute(); attribute != nullptr; attribute = attribute->Next()) {
0038         oss << "(" << child->Name() << attribute->Name() << "=" << attribute->Value() << ")";
0039       }
0040     }
0041     return oss.str();
0042   }
0043 
0044   template <typename T>
0045   static void overrideFromPSet(char const *iName, edm::ParameterSet const &iPSet, T &iHolder, T const *&iPointer) {
0046     if (iPSet.exists(iName)) {
0047       iHolder = iPSet.getUntrackedParameter<T>(iName);
0048       iPointer = &iHolder;
0049     }
0050   }
0051 
0052   constexpr char const *const kEmptyString = "";
0053   const char *safe(const char *iCheck) {
0054     if (iCheck == nullptr) {
0055       return kEmptyString;
0056     }
0057     return iCheck;
0058   }
0059 
0060   std::string defaultURL() {
0061     std::string returnValue;
0062     const char *tmp = std::getenv("CMS_PATH");
0063     if (tmp) {
0064       returnValue = tmp;
0065     }
0066     returnValue += "/SITECONF/local/JobConfig/site-local-config.xml";
0067     return returnValue;
0068   }
0069 
0070 }  // namespace
0071 
0072 namespace edm {
0073   namespace service {
0074 
0075     const std::string SiteLocalConfigService::m_statisticsDefaultPort = "3334";
0076 
0077     SiteLocalConfigService::SiteLocalConfigService(ParameterSet const &pset)
0078         : m_url(pset.getUntrackedParameter<std::string>("siteLocalConfigFileUrl", defaultURL())),
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       this->parse(m_url);
0107 
0108       //apply overrides
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::dataCatalogs(void) const {
0154       if (!m_connected) {
0155         //throw cms::Exception("Incomplete configuration")
0156         //    << "Valid site-local-config not found at " << m_url;
0157         // Return PoolFileCatalog.xml for now
0158         static std::vector<std::string> const tmp{"file:PoolFileCatalog.xml"};
0159         return tmp;
0160       }
0161 
0162       if (m_dataCatalogs.empty()) {
0163         throw cms::Exception("Incomplete configuration") << "Did not find catalogs in event-data section in " << m_url;
0164       }
0165 
0166       return m_dataCatalogs;
0167     }
0168 
0169     std::string const SiteLocalConfigService::frontierConnect(std::string const &servlet) const {
0170       if (!m_connected) {
0171         throw cms::Exception("Incomplete configuration") << "Valid site-local-config not found at " << m_url;
0172       }
0173 
0174       if (m_frontierConnect.empty()) {
0175         throw cms::Exception("Incomplete configuration")
0176             << "Did not find frontier-connect in calib-data section in " << m_url;
0177       }
0178 
0179       if (servlet.empty()) {
0180         return m_frontierConnect;
0181       }
0182 
0183       // Replace the last component of every "serverurl=" piece (up to the
0184       //   next close-paren) with the servlet
0185       std::string::size_type nextparen = 0;
0186       std::string::size_type serverurl, lastslash;
0187       std::string complexstr = "";
0188       while ((serverurl = m_frontierConnect.find("(serverurl=", nextparen)) != std::string::npos) {
0189         complexstr.append(m_frontierConnect, nextparen, serverurl - nextparen);
0190         nextparen = m_frontierConnect.find(')', serverurl);
0191         lastslash = m_frontierConnect.rfind('/', nextparen);
0192         complexstr.append(m_frontierConnect, serverurl, lastslash - serverurl + 1);
0193         complexstr.append(servlet);
0194       }
0195       complexstr.append(m_frontierConnect, nextparen, m_frontierConnect.length() - nextparen);
0196 
0197       return complexstr;
0198     }
0199 
0200     std::string const SiteLocalConfigService::lookupCalibConnect(std::string const &input) const {
0201       static std::string const proto = "frontier://";
0202 
0203       if (input.substr(0, proto.length()) == proto) {
0204         // Replace the part after the frontier:// and before either an open-
0205         //  parentheses (which indicates user-supplied options) or the last
0206         //  slash (which indicates start of the schema) with the complex
0207         //  parenthesized string returned from frontierConnect() (which
0208         //  contains all the information needed to connect to frontier),
0209         //  if that part is a simple servlet name (non-empty and not
0210         //  containing special characters)
0211         // Example connect strings where servlet is replaced:
0212         //  frontier://cms_conditions_data/CMS_COND_ECAL
0213         //  frontier://FrontierInt/CMS_COND_ECAL
0214         //  frontier://FrontierInt(retrieve-ziplevel=0)/CMS_COND_ECAL
0215         // Example connect strings left untouched:
0216         //  frontier://cmsfrontier.cern.ch:8000/FrontierInt/CMS_COND_ECAL
0217         //  frontier://(serverurl=cmsfrontier.cern.ch:8000/FrontierInt)/CMS_COND_ECAL
0218         std::string::size_type startservlet = proto.length();
0219         // if user supplied extra parenthesized options, stop servlet there
0220         std::string::size_type endservlet = input.find('(', startservlet);
0221         if (endservlet == std::string::npos) {
0222           endservlet = input.rfind('/', input.length());
0223         }
0224         std::string servlet = input.substr(startservlet, endservlet - startservlet);
0225         if ((!servlet.empty()) && (servlet.find_first_of(":/)[]") == std::string::npos)) {
0226           if (servlet == "cms_conditions_data") {
0227             // use the default servlet from site-local-config.xml
0228             servlet = "";
0229           }
0230           return proto + frontierConnect(servlet) + input.substr(endservlet);
0231         }
0232       }
0233       return input;
0234     }
0235 
0236     std::string const SiteLocalConfigService::rfioType(void) const { return m_rfioType; }
0237 
0238     std::string const *SiteLocalConfigService::sourceCacheTempDir() const { return m_cacheTempDirPtr; }
0239 
0240     double const *SiteLocalConfigService::sourceCacheMinFree() const { return m_cacheMinFreePtr; }
0241 
0242     std::string const *SiteLocalConfigService::sourceCacheHint() const { return m_cacheHintPtr; }
0243 
0244     std::string const *SiteLocalConfigService::sourceCloneCacheHint() const { return m_cloneCacheHintPtr; }
0245 
0246     std::string const *SiteLocalConfigService::sourceReadHint() const { return m_readHintPtr; }
0247 
0248     unsigned int const *SiteLocalConfigService::sourceTTreeCacheSize() const { return m_ttreeCacheSizePtr; }
0249 
0250     unsigned int const *SiteLocalConfigService::sourceTimeout() const { return m_timeoutPtr; }
0251 
0252     bool SiteLocalConfigService::enablePrefetching() const {
0253       return m_enablePrefetchingPtr ? *m_enablePrefetchingPtr : false;
0254     }
0255 
0256     unsigned int SiteLocalConfigService::debugLevel() const { return m_debugLevel; }
0257 
0258     std::vector<std::string> const *SiteLocalConfigService::sourceNativeProtocols() const {
0259       return m_nativeProtocolsPtr;
0260     }
0261 
0262     struct addrinfo const *SiteLocalConfigService::statisticsDestination() const {
0263       return m_statisticsAddrInfo;
0264     }
0265 
0266     std::set<std::string> const *SiteLocalConfigService::statisticsInfo() const {
0267       return m_statisticsInfoAvail ? &m_statisticsInfo : nullptr;
0268     }
0269 
0270     std::string const &SiteLocalConfigService::siteName() const { return m_siteName; }
0271     bool SiteLocalConfigService::useLocalConnectString() const { return m_useLocalConnectString; }
0272     std::string const &SiteLocalConfigService::localConnectPrefix() const { return m_localConnectPrefix; }
0273     std::string const &SiteLocalConfigService::localConnectSuffix() const { return m_localConnectSuffix; }
0274 
0275     void SiteLocalConfigService::parse(std::string const &url) {
0276       tinyxml2::XMLDocument doc;
0277       auto loadErr = doc.LoadFile(url.c_str());
0278       if (loadErr != tinyxml2::XML_SUCCESS) {
0279         return;
0280       }
0281 
0282       // The Site Config has the following format
0283       // <site-local-config>
0284       // <site name="FNAL">
0285       //   <event-data>
0286       //     <catalog url="trivialcatalog_file:/x/y/z.xml"/>
0287       //     <rfiotype value="castor"/>
0288       //   </event-data>
0289       //   <calib-data>
0290       //     <catalog url="trivialcatalog_file:/x/y/z.xml"/>
0291       //     <frontier-connect>
0292       //       ... frontier-interpreted server/proxy xml ...
0293       //     </frontier-connect>
0294       //     <local-connect>
0295       //       <connectString prefix="anything1" suffix="anything2"/>
0296       //     </local-connect>
0297       //   </calib-data>
0298       //   <source-config>
0299       //     <cache-temp-dir name="/a/b/c"/>
0300       //     <cache-hint value="..."/>
0301       //     <read-hint value="..."/>
0302       //     <ttree-cache-size value="0"/>
0303       //     <native-protocols>
0304       //        <protocol  prefix="dcache"/>
0305       //        <protocol prefix="file"/>
0306       //     </native-protocols>
0307       //   </source-config>
0308       // </site>
0309       // </site-local-config>
0310       auto rootElement = doc.RootElement();
0311 
0312       for (auto site = rootElement->FirstChildElement("site"); site != nullptr;
0313            site = site->NextSiblingElement("site")) {
0314         // Parse the site name
0315         m_siteName = safe(site->Attribute("name"));
0316 
0317         // Parsing of the event data section
0318         {
0319           auto eventData = site->FirstChildElement("event-data");
0320           if (eventData) {
0321             auto catalog = eventData->FirstChildElement("catalog");
0322             if (catalog) {
0323               m_dataCatalogs.push_back(safe(catalog->Attribute("url")));
0324               catalog = catalog->NextSiblingElement("catalog");
0325               while (catalog) {
0326                 m_dataCatalogs.push_back(safe(catalog->Attribute("url")));
0327                 catalog = catalog->NextSiblingElement("catalog");
0328               }
0329             }
0330             auto rfiotype = eventData->FirstChildElement("rfiotype");
0331             if (rfiotype) {
0332               m_rfioType = safe(rfiotype->Attribute("value"));
0333             }
0334           }
0335         }
0336 
0337         // Parsing of the calib-data section
0338         {
0339           auto calibData = site->FirstChildElement("calib-data");
0340 
0341           if (calibData) {
0342             auto frontierConnect = calibData->FirstChildElement("frontier-connect");
0343 
0344             if (frontierConnect) {
0345               m_frontierConnect = _toParenString(*frontierConnect);
0346             }
0347             auto localConnect = calibData->FirstChildElement("local-connect");
0348             if (localConnect) {
0349               if (frontierConnect) {
0350                 throw cms::Exception("Illegal site local configuration")
0351                     << "It is illegal to include both frontier-connect and local-connect in the same XML file";
0352               }
0353               m_useLocalConnectString = true;
0354               auto connectString = localConnect->FirstChildElement("connectString");
0355               if (connectString) {
0356                 m_localConnectPrefix = safe(connectString->Attribute("prefix"));
0357                 m_localConnectSuffix = safe(connectString->Attribute("suffix"));
0358               }
0359             }
0360           }
0361         }
0362 
0363         // Parsing of the source config section
0364         {
0365           auto sourceConfig = site->FirstChildElement("source-config");
0366 
0367           if (sourceConfig) {
0368             auto cacheTempDir = sourceConfig->FirstChildElement("cache-temp-dir");
0369 
0370             if (cacheTempDir) {
0371               m_cacheTempDir = safe(cacheTempDir->Attribute("name"));
0372               m_cacheTempDirPtr = &m_cacheTempDir;
0373             }
0374 
0375             auto cacheMinFree = sourceConfig->FirstChildElement("cache-min-free");
0376 
0377             if (cacheMinFree) {
0378               //TODO what did xerces do if it couldn't convert?
0379               m_cacheMinFree = cacheMinFree->DoubleAttribute("value");
0380               m_cacheMinFreePtr = &m_cacheMinFree;
0381             }
0382 
0383             auto cacheHint = sourceConfig->FirstChildElement("cache-hint");
0384 
0385             if (cacheHint) {
0386               m_cacheHint = safe(cacheHint->Attribute("value"));
0387               m_cacheHintPtr = &m_cacheHint;
0388             }
0389 
0390             auto cloneCacheHint = sourceConfig->FirstChildElement("clone-cache-hint");
0391 
0392             if (cloneCacheHint) {
0393               m_cloneCacheHint = safe(cloneCacheHint->Attribute("value"));
0394               m_cloneCacheHintPtr = &m_cloneCacheHint;
0395             }
0396 
0397             auto readHint = sourceConfig->FirstChildElement("read-hint");
0398 
0399             if (readHint) {
0400               m_readHint = safe(readHint->Attribute("value"));
0401               m_readHintPtr = &m_readHint;
0402             }
0403 
0404             auto ttreeCacheSize = sourceConfig->FirstChildElement("ttree-cache-size");
0405 
0406             if (ttreeCacheSize) {
0407               m_ttreeCacheSize = ttreeCacheSize->UnsignedAttribute("value");
0408               m_ttreeCacheSizePtr = &m_ttreeCacheSize;
0409             }
0410 
0411             auto timeout = sourceConfig->FirstChildElement("timeout-in-seconds");
0412 
0413             if (timeout) {
0414               m_timeout = timeout->UnsignedAttribute("value");
0415               m_timeoutPtr = &m_timeout;
0416             }
0417 
0418             auto statsDest = sourceConfig->FirstChildElement("statistics-destination");
0419 
0420             if (statsDest) {
0421               m_statisticsDestination = safe(statsDest->Attribute("endpoint"));
0422               if (m_statisticsDestination.empty()) {
0423                 m_statisticsDestination = safe(statsDest->Attribute("name"));
0424               }
0425               std::string tmpStatisticsInfo = safe(statsDest->Attribute("info"));
0426               boost::split(m_statisticsInfo, tmpStatisticsInfo, boost::is_any_of("\t ,"));
0427               m_statisticsInfoAvail = !tmpStatisticsInfo.empty();
0428             }
0429 
0430             auto prefetching = sourceConfig->FirstChildElement("prefetching");
0431 
0432             if (prefetching) {
0433               m_enablePrefetching = prefetching->BoolAttribute("value");
0434               m_enablePrefetchingPtr = &m_enablePrefetching;
0435             }
0436 
0437             auto nativeProtocol = sourceConfig->FirstChildElement("native-protocols");
0438 
0439             if (nativeProtocol) {
0440               for (auto child = nativeProtocol->FirstChildElement(); child != nullptr;
0441                    child = child->NextSiblingElement()) {
0442                 m_nativeProtocols.push_back(safe(child->Attribute("prefix")));
0443               }
0444               m_nativeProtocolsPtr = &m_nativeProtocols;
0445             }
0446           }
0447         }
0448       }
0449       m_connected = true;
0450     }
0451 
0452     void SiteLocalConfigService::computeStatisticsDestination() {
0453       std::vector<std::string> inputStrings;
0454       boost::split(inputStrings, m_statisticsDestination, boost::is_any_of(":"));
0455       const std::string &host = inputStrings[0];
0456       const std::string &port = (inputStrings.size() > 1) ? inputStrings[1] : m_statisticsDefaultPort;
0457       struct addrinfo *res;
0458       struct addrinfo hints;
0459       memset(&hints, '\0', sizeof(hints));
0460       hints.ai_socktype = SOCK_DGRAM;
0461       hints.ai_flags = AI_ADDRCONFIG;
0462       hints.ai_family = AF_UNSPEC;
0463       int e = getaddrinfo(host.c_str(), port.c_str(), &hints, &res);
0464       if (e != 0) {
0465         // Silent failure - there's no way to report non-fatal failures from here.
0466         return;
0467       }
0468       m_statisticsAddrInfo = res;
0469     }
0470 
0471     void SiteLocalConfigService::fillDescriptions(ConfigurationDescriptions &descriptions) {
0472       ParameterSetDescription desc;
0473       desc.setComment("Service to translate logical file names to physical file names.");
0474 
0475       desc.addOptionalUntracked<std::string>("siteLocalConfigFileUrl", std::string())
0476           ->setComment(
0477               "Specify the file containing the site local config. Empty string will load from default directory.");
0478       desc.addOptionalUntracked<std::string>("overrideSourceCacheTempDir");
0479       desc.addOptionalUntracked<double>("overrideSourceCacheMinFree");
0480       desc.addOptionalUntracked<std::string>("overrideSourceCacheHintDir");
0481       desc.addOptionalUntracked<std::string>("overrideSourceCloneCacheHintDir")
0482           ->setComment("Provide an alternate cache hint for fast cloning.");
0483       desc.addOptionalUntracked<std::string>("overrideSourceReadHint");
0484       desc.addOptionalUntracked<std::vector<std::string> >("overrideSourceNativeProtocols");
0485       desc.addOptionalUntracked<unsigned int>("overrideSourceTTreeCacheSize");
0486       desc.addOptionalUntracked<unsigned int>("overrideSourceTimeout");
0487       desc.addOptionalUntracked<unsigned int>("debugLevel");
0488       desc.addOptionalUntracked<bool>("overridePrefetching")
0489           ->setComment("Request ROOT to asynchronously prefetch I/O during computation.");
0490       desc.addOptionalUntracked<std::string>("overrideStatisticsDestination")
0491           ->setComment(
0492               "Provide an alternate network destination for I/O statistics (must be in the form of host:port).");
0493       desc.addOptionalUntracked<std::vector<std::string> >("overrideStatisticsInfo")
0494           ->setComment(
0495               "Provide an alternate listing of statistics to send (comma separated list; current options are 'dn' or "
0496               "'nodn').  If left blank, all information is snet (including DNs).");
0497       desc.addOptionalUntracked<bool>("overrideUseLocalConnectString");
0498       desc.addOptionalUntracked<std::string>("overrideLocalConnectPrefix");
0499       desc.addOptionalUntracked<std::string>("overrideLocalConnectSuffix");
0500       descriptions.add("SiteLocalConfigService", desc);
0501     }
0502   }  // namespace service
0503 }  // namespace edm