Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:13:03

0001 // -*- C++ -*-
0002 //
0003 // Package:     ServiceRegistry
0004 // Class  :     ServicesManager
0005 //
0006 // Implementation:
0007 //     <Notes on implementation>
0008 //
0009 // Original Author:  Chris Jones
0010 //         Created:  Mon Sep  5 13:33:19 EDT 2005
0011 //
0012 
0013 // user include files
0014 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0015 
0016 #include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
0017 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0018 #include "FWCore/ParameterSet/interface/ParameterSetDescriptionFillerBase.h"
0019 #include "FWCore/ParameterSet/interface/ParameterSetDescriptionFillerPluginFactory.h"
0020 
0021 #include "FWCore/ServiceRegistry/interface/ServicePluginFactory.h"
0022 #include "FWCore/ServiceRegistry/interface/ServiceRegistry.h"
0023 #include "FWCore/ServiceRegistry/interface/ServiceToken.h"
0024 #include "FWCore/ServiceRegistry/interface/ServicesManager.h"
0025 
0026 #include "FWCore/Utilities/interface/ConvertException.h"
0027 #include "FWCore/Utilities/interface/Exception.h"
0028 #include "FWCore/Utilities/interface/TypeDemangler.h"
0029 
0030 // system include files
0031 #include <set>
0032 #include <string>
0033 #include <exception>
0034 #include <sstream>
0035 
0036 //
0037 // constants, enums and typedefs
0038 //
0039 
0040 namespace edm {
0041   namespace serviceregistry {
0042 
0043     ServicesManager::MakerHolder::MakerHolder(std::shared_ptr<ServiceMakerBase> iMaker,
0044                                               ParameterSet& iPSet,
0045                                               ActivityRegistry& iRegistry)
0046         : maker_(iMaker), pset_(&iPSet), registry_(&iRegistry), wasAdded_(false) {}
0047 
0048     bool ServicesManager::MakerHolder::add(ServicesManager& oManager) const {
0049       if (!wasAdded_) {
0050         wasAdded_ = maker_->make(*pset_, *registry_, oManager);
0051         if (wasAdded_ && maker_->saveConfiguration()) {
0052           pset_->addUntrackedParameter("@save_config", true);
0053         }
0054       }
0055       return wasAdded_;
0056     }
0057 
0058     //
0059     // static data member definitions
0060     //
0061 
0062     //
0063     // constructors and destructor
0064     //
0065     ServicesManager::ServicesManager(std::vector<ParameterSet>& iConfiguration) : type2Maker_(new Type2Maker) {
0066       //First create the list of makers
0067       fillListOfMakers(iConfiguration);
0068 
0069       createServices();
0070     }
0071 
0072     ServicesManager::ServicesManager(ServiceToken iToken,
0073                                      ServiceLegacy iLegacy,
0074                                      std::vector<ParameterSet>& iConfiguration,
0075                                      bool associate)
0076         : associatedManager_(associate ? iToken.manager_ : std::shared_ptr<ServicesManager>()),
0077           type2Maker_(new Type2Maker) {
0078       fillListOfMakers(iConfiguration);
0079 
0080       //find overlaps between services in iToken and iConfiguration
0081       typedef std::set<TypeIDBase> TypeSet;
0082       TypeSet configTypes;
0083       for (Type2Maker::iterator itType = type2Maker_->begin(), itTypeEnd = type2Maker_->end(); itType != itTypeEnd;
0084            ++itType) {
0085         configTypes.insert(itType->first);
0086       }
0087 
0088       TypeSet tokenTypes;
0089       if (nullptr != iToken.manager_.get()) {
0090         for (Type2Service::iterator itType = iToken.manager_->type2Service_.begin(),
0091                                     itTypeEnd = iToken.manager_->type2Service_.end();
0092              itType != itTypeEnd;
0093              ++itType) {
0094           tokenTypes.insert(itType->first);
0095         }
0096 
0097         typedef std::set<TypeIDBase> IntersectionType;
0098         IntersectionType intersection;
0099         std::set_intersection(configTypes.begin(),
0100                               configTypes.end(),
0101                               tokenTypes.begin(),
0102                               tokenTypes.end(),
0103                               inserter(intersection, intersection.end()));
0104 
0105         switch (iLegacy) {
0106           case kOverlapIsError:
0107             if (!intersection.empty()) {
0108               throw Exception(errors::Configuration, "Service")
0109                   << "the Service "
0110                   << (*type2Maker_)
0111                          .find(*(intersection.begin()))
0112                          ->second.pset_->getParameter<std::string>("@service_type")
0113                   << " already has an instance of that type of Service";
0114             } else {
0115               //get all the services from Token
0116               type2Service_ = iToken.manager_->type2Service_;
0117             }
0118             break;
0119           case kTokenOverrides:
0120             //get all the services from Token
0121             type2Service_ = iToken.manager_->type2Service_;
0122 
0123             //remove from type2Maker the overlapping services so we never try to make them
0124             for (IntersectionType::iterator itType = intersection.begin(), itTypeEnd = intersection.end();
0125                  itType != itTypeEnd;
0126                  ++itType) {
0127               Type2Maker::iterator itFound = type2Maker_->find(*itType);
0128               //HLT needs it such that even if a service isn't created we store its PSet if needed
0129               if (itFound->second.maker_->saveConfiguration()) {
0130                 itFound->second.pset_->addUntrackedParameter("@save_config", true);
0131               }
0132               type2Maker_->erase(itFound);
0133             }
0134             break;
0135           case kConfigurationOverrides:
0136             //get all the services from the Configuration, except process wide services
0137             type2Service_ = iToken.manager_->type2Service_;
0138 
0139             //now remove the ones we do not want
0140             for (IntersectionType::iterator itType = intersection.begin(), itTypeEnd = intersection.end();
0141                  itType != itTypeEnd;
0142                  ++itType) {
0143               Type2Maker::iterator itFound = type2Maker_->find(*itType);
0144               if (itFound->second.maker_->processWideService()) {
0145                 // This is a process wide service, so the token overrides the configuration.
0146                 //HLT needs it such that even if a service isn't created we store its PSet if needed
0147                 if (itFound->second.maker_->saveConfiguration()) {
0148                   itFound->second.pset_->addUntrackedParameter("@save_config", true);
0149                 }
0150                 std::string type(typeDemangle(itType->name()));
0151                 LogInfo("Configuration") << "Warning: You have reconfigured service\n"
0152                                          << "'" << type << "' in a subprocess.\n"
0153                                          << "This service has already been configured.\n"
0154                                          << "This particular service may not be reconfigured in a subprocess.\n"
0155                                          << "The reconfiguration will be ignored.\n";
0156                 type2Maker_->erase(itFound);
0157               } else {
0158                 // This is not a process wide service, so the configuration overrides the token.
0159                 type2Service_.erase(type2Service_.find(*itType));
0160               }
0161             }
0162             break;
0163         }
0164         //make sure our signals are propagated to our 'inherited' Services
0165         if (associate)
0166           registry_.copySlotsFrom(associatedManager_->registry_);
0167       }
0168       createServices();
0169     }
0170 
0171     // ServicesManager::ServicesManager(ServicesManager const& rhs) {
0172     //    // do actual copying here;
0173     // }
0174 
0175     ServicesManager::~ServicesManager() {
0176       // Force the Service destructors to execute in the reverse order of construction.
0177       // Note that services passed in by a token are not included in this loop and
0178       // do not get destroyed until the ServicesManager object that created them is destroyed
0179       // which occurs after the body of this destructor is executed (the correct order).
0180       // Services directly passed in by a put and not created in the constructor
0181       // may or not be detroyed in the desired order because this class does not control
0182       // their creation (as I'm writing this comment everything in a standard cmsRun
0183       // executable is destroyed in the desired order).
0184       for (std::vector<TypeIDBase>::const_reverse_iterator idIter = actualCreationOrder_.rbegin(),
0185                                                            idEnd = actualCreationOrder_.rend();
0186            idIter != idEnd;
0187            ++idIter) {
0188         Type2Service::iterator itService = type2Service_.find(*idIter);
0189 
0190         if (itService != type2Service_.end()) {
0191           // This will cause the Service's destruction if
0192           // there are no other shared pointers around
0193           itService->second.reset();
0194         }
0195       }
0196     }
0197 
0198     //
0199     // assignment operators
0200     //
0201     // ServicesManager const& ServicesManager::operator=(ServicesManager const& rhs) {
0202     //   //An exception safe implementation is
0203     //   ServicesManager temp(rhs);
0204     //   swap(rhs);
0205     //
0206     //   return *this;
0207     // }
0208 
0209     //
0210     // member functions
0211     //
0212     void ServicesManager::connect(ActivityRegistry& iOther) { registry_.connect(iOther); }
0213 
0214     void ServicesManager::connectTo(ActivityRegistry& iOther) { iOther.connect(registry_); }
0215 
0216     void ServicesManager::copySlotsFrom(ActivityRegistry& iOther) { registry_.copySlotsFrom(iOther); }
0217 
0218     void ServicesManager::copySlotsTo(ActivityRegistry& iOther) { iOther.copySlotsFrom(registry_); }
0219 
0220     void ServicesManager::fillListOfMakers(std::vector<ParameterSet>& iConfiguration) {
0221       for (std::vector<ParameterSet>::iterator itParam = iConfiguration.begin(), itParamEnd = iConfiguration.end();
0222            itParam != itParamEnd;
0223            ++itParam) {
0224         std::shared_ptr<ServiceMakerBase> base(
0225             ServicePluginFactory::get()->create(itParam->getParameter<std::string>("@service_type")));
0226 
0227         if (nullptr == base.get()) {
0228           throw Exception(errors::Configuration, "Service")
0229               << "could not find a service named " << itParam->getParameter<std::string>("@service_type")
0230               << ". Please check spelling.";
0231         }
0232         Type2Maker::iterator itFound = type2Maker_->find(TypeIDBase(base->serviceType()));
0233         if (itFound != type2Maker_->end()) {
0234           throw Exception(errors::Configuration, "Service")
0235               << " the service " << itParam->getParameter<std::string>("@service_type")
0236               << " provides the same service as " << itFound->second.pset_->getParameter<std::string>("@service_type")
0237               << "\n Please reconfigure job to only use one of these services.";
0238         }
0239         type2Maker_->insert(
0240             Type2Maker::value_type(TypeIDBase(base->serviceType()), MakerHolder(base, *itParam, registry_)));
0241         requestedCreationOrder_.push_back(TypeIDBase(base->serviceType()));
0242       }
0243     }
0244 
0245     namespace {
0246       struct NoOp {
0247         void operator()(ServicesManager*) {}
0248       };
0249     }  // namespace
0250 
0251     void ServicesManager::createServiceFor(MakerHolder const& iMaker) {
0252       std::string serviceType = iMaker.pset_->getParameter<std::string>("@service_type");
0253       std::unique_ptr<ParameterSetDescriptionFillerBase> filler(
0254           ParameterSetDescriptionFillerPluginFactory::get()->create(serviceType));
0255       ConfigurationDescriptions descriptions(filler->baseType(), serviceType);
0256       filler->fill(descriptions);
0257 
0258       try {
0259         convertException::wrap([&]() { descriptions.validate(*(iMaker.pset_), serviceType); });
0260       } catch (cms::Exception& iException) {
0261         std::ostringstream ost;
0262         ost << "Validating configuration of service of type " << serviceType;
0263         iException.addContext(ost.str());
0264         throw;
0265       }
0266       try {
0267         convertException::wrap([&]() {
0268           // This creates the service
0269           iMaker.add(*this);
0270         });
0271       } catch (cms::Exception& iException) {
0272         std::ostringstream ost;
0273         ost << "Constructing service of type " << serviceType;
0274         iException.addContext(ost.str());
0275         throw;
0276       }
0277     }
0278 
0279     void ServicesManager::createServices() {
0280       //create a shared_ptr of 'this' that will not delete us
0281       std::shared_ptr<ServicesManager> shareThis(this, NoOp());
0282 
0283       ServiceToken token(shareThis);
0284 
0285       //Now make our services to ones obtained via ServiceRegistry
0286       // when this goes out of scope, it will revert back to the previous Service set
0287       ServiceRegistry::Operate operate(token);
0288 
0289       //Now, make each Service.  If a service depends on a service that has yet to be
0290       // created, that other service will automatically be made
0291 
0292       for (std::vector<TypeIDBase>::const_iterator idIter = requestedCreationOrder_.begin(),
0293                                                    idEnd = requestedCreationOrder_.end();
0294            idIter != idEnd;
0295            ++idIter) {
0296         Type2Maker::iterator itMaker = type2Maker_->find(*idIter);
0297 
0298         // Check to make sure this maker is still there.  They are deleted
0299         // sometimes and that is OK.
0300         if (itMaker != type2Maker_->end()) {
0301           createServiceFor(itMaker->second);
0302         }
0303       }
0304       //No longer need the makers
0305       type2Maker_ = nullptr;  // propagate_const<T> has no reset() function
0306     }
0307     //
0308     // const member functions
0309     //
0310 
0311     //
0312     // static member functions
0313     //
0314   }  // namespace serviceregistry
0315 }  // namespace edm