Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2025-03-13 02:31:52

0001 #include "DataFormats/Provenance/interface/ProductDescription.h"
0002 #include "DataFormats/Provenance/interface/BranchKey.h"
0003 #include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
0004 #include "FWCore/Utilities/interface/EDMException.h"
0005 #include "FWCore/Framework/interface/SignallingProductRegistryFiller.h"
0006 
0007 #include "processEDAliases.h"
0008 
0009 #include <map>
0010 
0011 namespace edm {
0012   namespace {
0013     void checkAndInsertAlias(std::string const& friendlyClassName,
0014                              std::string const& moduleLabel,
0015                              std::string const& productInstanceName,
0016                              std::string const& processName,
0017                              std::string const& alias,
0018                              std::string const& instanceAlias,
0019                              ProductRegistry const& preg,
0020                              std::multimap<BranchKey, BranchKey>& aliasMap,
0021                              std::map<BranchKey, BranchKey>& aliasKeys) {
0022       std::string const star("*");
0023 
0024       BranchKey key(friendlyClassName, moduleLabel, productInstanceName, processName);
0025       if (preg.productList().find(key) == preg.productList().end()) {
0026         // No product was found matching the alias.
0027         // We throw an exception only if a module with the specified module label was created in this process.
0028         for (auto const& product : preg.productList()) {
0029           if (moduleLabel == product.first.moduleLabel() && processName == product.first.processName()) {
0030             throw Exception(errors::Configuration, "EDAlias does not match data\n")
0031                 << "There are no products of type '" << friendlyClassName << "'\n"
0032                 << "with module label '" << moduleLabel << "' and instance name '" << productInstanceName << "'.\n";
0033           }
0034         }
0035       }
0036 
0037       if (auto iter = aliasMap.find(key); iter != aliasMap.end()) {
0038         // If the same EDAlias defines multiple products pointing to the same product, throw
0039         if (iter->second.moduleLabel() == alias) {
0040           throw Exception(errors::Configuration, "EDAlias conflict\n")
0041               << "The module label alias '" << alias << "' is used for multiple products of type '" << friendlyClassName
0042               << "' with module label '" << moduleLabel << "' and instance name '" << productInstanceName
0043               << "'. One alias has the instance name '" << iter->first.productInstanceName()
0044               << "' and the other has the instance name '" << instanceAlias << "'.";
0045         }
0046       }
0047 
0048       std::string const& theInstanceAlias(instanceAlias == star ? productInstanceName : instanceAlias);
0049       BranchKey aliasKey(friendlyClassName, alias, theInstanceAlias, processName);
0050       if (auto it = preg.productList().find(aliasKey); it != preg.productList().end()) {
0051         // We might have already inserted an alias that was a chosen case of a SwitchProducer
0052         if (not it->second.isAlias()) {
0053           throw Exception(errors::Configuration, "EDAlias conflicts with data\n")
0054               << "A product of type '" << friendlyClassName << "'\n"
0055               << "with module label '" << alias << "' and instance name '" << theInstanceAlias << "'\n"
0056               << "already exists.\n";
0057         }
0058         return;
0059       }
0060       auto iter = aliasKeys.find(aliasKey);
0061       if (iter != aliasKeys.end()) {
0062         // The alias matches a previous one.  If the same alias is used for different product, throw.
0063         if (iter->second != key) {
0064           throw Exception(errors::Configuration, "EDAlias conflict\n")
0065               << "The module label alias '" << alias << "' and product instance alias '" << theInstanceAlias << "'\n"
0066               << "are used for multiple products of type '" << friendlyClassName << "'\n"
0067               << "One has module label '" << moduleLabel << "' and product instance name '" << productInstanceName
0068               << "',\n"
0069               << "the other has module label '" << iter->second.moduleLabel() << "' and product instance name '"
0070               << iter->second.productInstanceName() << "'.\n";
0071         }
0072       } else {
0073         auto prodIter = preg.productList().find(key);
0074         if (prodIter != preg.productList().end()) {
0075           if (!prodIter->second.produced()) {
0076             throw Exception(errors::Configuration, "EDAlias\n")
0077                 << "The module label alias '" << alias << "' and product instance alias '" << theInstanceAlias << "'\n"
0078                 << "are used for a product of type '" << friendlyClassName << "'\n"
0079                 << "with module label '" << moduleLabel << "' and product instance name '" << productInstanceName
0080                 << "',\n"
0081                 << "An EDAlias can only be used for products produced in the current process. This one is not.\n";
0082           }
0083           aliasMap.insert(std::make_pair(key, aliasKey));
0084           aliasKeys.insert(std::make_pair(aliasKey, key));
0085         }
0086       }
0087     }
0088   }  // namespace
0089 
0090   namespace detail {
0091     void processEDAliases(std::vector<std::string> const& aliasNamesToProcess,
0092                           std::unordered_set<std::string> const& aliasModulesToProcess,
0093                           ParameterSet const& proc_pset,
0094                           std::string const& processName,
0095                           SignallingProductRegistryFiller& preg) {
0096       if (aliasNamesToProcess.empty()) {
0097         return;
0098       }
0099       std::string const star("*");
0100       std::string const empty("");
0101       ParameterSetDescription desc;
0102       desc.add<std::string>("type");
0103       desc.add<std::string>("fromProductInstance", star);
0104       desc.add<std::string>("toProductInstance", star);
0105 
0106       std::multimap<BranchKey, BranchKey> aliasMap;
0107 
0108       std::map<BranchKey, BranchKey> aliasKeys;  // Used to search for duplicates or clashes.
0109 
0110       // Auxiliary search structure to support wildcard for friendlyClassName
0111       std::multimap<std::string, BranchKey> moduleLabelToBranches;
0112       for (auto const& prod : preg.registry().productList()) {
0113         if (processName == prod.second.processName()) {
0114           moduleLabelToBranches.emplace(prod.first.moduleLabel(), prod.first);
0115         }
0116       }
0117 
0118       // Now, loop over the alias information and store it in aliasMap.
0119       for (std::string const& alias : aliasNamesToProcess) {
0120         ParameterSet const& aliasPSet = proc_pset.getParameterSet(alias);
0121         std::vector<std::string> vPSetNames = aliasPSet.getParameterNamesForType<VParameterSet>();
0122         for (std::string const& moduleLabel : vPSetNames) {
0123           if (not aliasModulesToProcess.empty() and
0124               aliasModulesToProcess.find(moduleLabel) == aliasModulesToProcess.end()) {
0125             continue;
0126           }
0127 
0128           VParameterSet vPSet = aliasPSet.getParameter<VParameterSet>(moduleLabel);
0129           for (ParameterSet& pset : vPSet) {
0130             desc.validate(pset);
0131             std::string friendlyClassName = pset.getParameter<std::string>("type");
0132             std::string productInstanceName = pset.getParameter<std::string>("fromProductInstance");
0133             std::string instanceAlias = pset.getParameter<std::string>("toProductInstance");
0134 
0135             if (friendlyClassName == star) {
0136               bool processHasLabel = false;
0137               bool match = false;
0138               for (auto it = moduleLabelToBranches.lower_bound(moduleLabel);
0139                    it != moduleLabelToBranches.end() && it->first == moduleLabel;
0140                    ++it) {
0141                 processHasLabel = true;
0142                 if (productInstanceName != star and productInstanceName != it->second.productInstanceName()) {
0143                   continue;
0144                 }
0145                 match = true;
0146 
0147                 checkAndInsertAlias(it->second.friendlyClassName(),
0148                                     moduleLabel,
0149                                     it->second.productInstanceName(),
0150                                     processName,
0151                                     alias,
0152                                     instanceAlias,
0153                                     preg.registry(),
0154                                     aliasMap,
0155                                     aliasKeys);
0156               }
0157               if (not match and processHasLabel) {
0158                 // No product was found matching the alias.
0159                 // We throw an exception only if a module with the specified module label was created in this process.
0160                 // Note that if that condition is ever relatex, it  might be best to throw an exception with different
0161                 // message (omitting productInstanceName) in case 'productInstanceName == start'
0162                 throw Exception(errors::Configuration, "EDAlias parameter set mismatch\n")
0163                     << "There are no products with module label '" << moduleLabel << "' and product instance name '"
0164                     << productInstanceName << "'.\n";
0165               }
0166             } else if (productInstanceName == star) {
0167               bool match = false;
0168               BranchKey lowerBound(friendlyClassName, moduleLabel, empty, empty);
0169               for (ProductRegistry::ProductList::const_iterator it =
0170                        preg.registry().productList().lower_bound(lowerBound);
0171                    it != preg.registry().productList().end() && it->first.friendlyClassName() == friendlyClassName &&
0172                    it->first.moduleLabel() == moduleLabel;
0173                    ++it) {
0174                 if (it->first.processName() != processName) {
0175                   continue;
0176                 }
0177                 match = true;
0178 
0179                 checkAndInsertAlias(friendlyClassName,
0180                                     moduleLabel,
0181                                     it->first.productInstanceName(),
0182                                     processName,
0183                                     alias,
0184                                     instanceAlias,
0185                                     preg.registry(),
0186                                     aliasMap,
0187                                     aliasKeys);
0188               }
0189               if (!match) {
0190                 // No product was found matching the alias.
0191                 // We throw an exception only if a module with the specified module label was created in this process.
0192                 for (auto const& product : preg.registry().productList()) {
0193                   if (moduleLabel == product.first.moduleLabel() && processName == product.first.processName()) {
0194                     throw Exception(errors::Configuration, "EDAlias parameter set mismatch\n")
0195                         << "There are no products of type '" << friendlyClassName << "'\n"
0196                         << "with module label '" << moduleLabel << "'.\n";
0197                   }
0198                 }
0199               }
0200             } else {
0201               checkAndInsertAlias(friendlyClassName,
0202                                   moduleLabel,
0203                                   productInstanceName,
0204                                   processName,
0205                                   alias,
0206                                   instanceAlias,
0207                                   preg.registry(),
0208                                   aliasMap,
0209                                   aliasKeys);
0210             }
0211           }
0212         }
0213       }
0214 
0215       // Now add the new alias entries to the product registry.
0216       for (auto const& aliasEntry : aliasMap) {
0217         // Then check that the alias-for product exists
0218         ProductRegistry::ProductList::const_iterator it = preg.registry().productList().find(aliasEntry.first);
0219         assert(it != preg.registry().productList().end());
0220         preg.addLabelAlias(it->second, aliasEntry.second.moduleLabel(), aliasEntry.second.productInstanceName());
0221       }
0222     }
0223   }  // namespace detail
0224 }  // namespace edm