Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2023-03-17 11:02:18

0001 /**----------------------------------------------------------------------
0002   ----------------------------------------------------------------------*/
0003 
0004 #include "FWCore/Framework/interface/Principal.h"
0005 
0006 #include "DataFormats/Provenance/interface/ProcessConfiguration.h"
0007 #include "DataFormats/Provenance/interface/ProductResolverIndexHelper.h"
0008 #include "DataFormats/Provenance/interface/ProductRegistry.h"
0009 #include "DataFormats/Common/interface/FunctorHandleExceptionFactory.h"
0010 #include "FWCore/Framework/interface/DelayedReader.h"
0011 #include "FWCore/Framework/interface/HistoryAppender.h"
0012 #include "FWCore/Framework/src/ProductDeletedException.h"
0013 #include "FWCore/Framework/interface/ProductPutterBase.h"
0014 #include "FWCore/Framework/interface/EDConsumerBase.h"
0015 #include "ProductResolvers.h"
0016 #include "FWCore/Utilities/interface/EDMException.h"
0017 #include "FWCore/Utilities/interface/ProductResolverIndex.h"
0018 #include "FWCore/Utilities/interface/TypeID.h"
0019 #include "FWCore/Utilities/interface/WrappedClassName.h"
0020 #include "FWCore/Utilities/interface/Likely.h"
0021 
0022 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0023 
0024 #include <algorithm>
0025 #include <cstring>
0026 #include <limits>
0027 #include <sstream>
0028 #include <stdexcept>
0029 #include <typeinfo>
0030 #include <atomic>
0031 
0032 namespace edm {
0033 
0034   static ProcessHistory const s_emptyProcessHistory;
0035 
0036   static std::string appendCurrentProcessIfAlias(std::string const& processFromInputTag,
0037                                                  std::string const& currentProcess) {
0038     if (processFromInputTag == InputTag::kCurrentProcess) {
0039       std::string returnValue = processFromInputTag;
0040       returnValue += " (";
0041       returnValue += currentProcess;
0042       returnValue += ")";
0043       return returnValue;
0044     }
0045     return processFromInputTag;
0046   }
0047 
0048   static void throwProductNotFoundException(char const* where, errors::ErrorCodes error, BranchID const& bid) {
0049     throw Exception(error, "InvalidID") << "Principal::" << where << ": no product with given branch id: " << bid
0050                                         << "\n";
0051   }
0052 
0053   static std::shared_ptr<cms::Exception> makeNotFoundException(char const* where,
0054                                                                KindOfType kindOfType,
0055                                                                TypeID const& productType,
0056                                                                std::string const& label,
0057                                                                std::string const& instance,
0058                                                                std::string const& process) {
0059     std::shared_ptr<cms::Exception> exception = std::make_shared<Exception>(errors::ProductNotFound);
0060     if (kindOfType == PRODUCT_TYPE) {
0061       *exception << "Principal::" << where
0062                  << ": Found zero products matching all criteria\nLooking for type: " << productType << "\n"
0063                  << "Looking for module label: " << label << "\n"
0064                  << "Looking for productInstanceName: " << instance << "\n"
0065                  << (process.empty() ? "" : "Looking for process: ") << process << "\n";
0066     } else {
0067       *exception << "Principal::" << where
0068                  << ": Found zero products matching all criteria\nLooking for a container with elements of type: "
0069                  << productType << "\n"
0070                  << "Looking for module label: " << label << "\n"
0071                  << "Looking for productInstanceName: " << instance << "\n"
0072                  << (process.empty() ? "" : "Looking for process: ") << process << "\n";
0073     }
0074     return exception;
0075   }
0076 
0077   static void throwAmbiguousException(const char* where,
0078                                       TypeID const& productType,
0079                                       std::string const& label,
0080                                       std::string const& instance,
0081                                       std::string const& process) {
0082     cms::Exception exception("AmbiguousProduct");
0083     exception << "Principal::" << where
0084               << ": More than 1 product matches all criteria\nLooking for type: " << productType << "\n"
0085               << "Looking for module label: " << label << "\n"
0086               << "Looking for productInstanceName: " << instance << "\n"
0087               << (process.empty() ? "" : "Looking for process: ") << process << "\n"
0088               << "This can only occur with get function calls using a Handle<View> argument.\n"
0089               << "Try a get not using a View or change the instance name of one of the products";
0090     throw exception;
0091   }
0092 
0093   namespace {
0094     void failedToRegisterConsumesMany(edm::TypeID const& iType) {
0095       cms::Exception exception("GetManyWithoutRegistration");
0096       exception << "::getManyByType called for " << iType
0097                 << " without a corresponding consumesMany being called for this module. \n";
0098       throw exception;
0099     }
0100 
0101     void failedToRegisterConsumes(KindOfType kindOfType,
0102                                   TypeID const& productType,
0103                                   std::string const& moduleLabel,
0104                                   std::string const& productInstanceName,
0105                                   std::string const& processName) {
0106       cms::Exception exception("GetByLabelWithoutRegistration");
0107       exception << "::getByLabel without corresponding call to consumes or mayConsumes for this module.\n"
0108                 << (kindOfType == PRODUCT_TYPE ? "  type: " : " type: edm::View<") << productType
0109                 << (kindOfType == PRODUCT_TYPE ? "\n  module label: " : ">\n  module label: ") << moduleLabel
0110                 << "\n  product instance name: '" << productInstanceName << "'\n  process name: '" << processName
0111                 << "'\n";
0112       throw exception;
0113     }
0114   }  // namespace
0115 
0116   //0 means unset
0117   static std::atomic<Principal::CacheIdentifier_t> s_nextIdentifier{1};
0118   static inline Principal::CacheIdentifier_t nextIdentifier() {
0119     return s_nextIdentifier.fetch_add(1, std::memory_order_acq_rel);
0120   }
0121 
0122   Principal::Principal(std::shared_ptr<ProductRegistry const> reg,
0123                        std::shared_ptr<ProductResolverIndexHelper const> productLookup,
0124                        ProcessConfiguration const& pc,
0125                        BranchType bt,
0126                        HistoryAppender* historyAppender,
0127                        bool isForPrimaryProcess)
0128       : EDProductGetter(),
0129         processHistoryPtr_(),
0130         processHistoryID_(),
0131         processHistoryIDBeforeConfig_(),
0132         processConfiguration_(&pc),
0133         productResolvers_(),
0134         preg_(reg),
0135         productLookup_(productLookup),
0136         lookupProcessOrder_(productLookup->lookupProcessNames().size(), 0),
0137         reader_(),
0138         branchType_(bt),
0139         historyAppender_(historyAppender),
0140         cacheIdentifier_(nextIdentifier()) {
0141     productResolvers_.resize(reg->getNextIndexValue(bt));
0142     //Now that these have been set, we can create the list of Branches we need.
0143     std::string const source("source");
0144     ProductRegistry::ProductList const& prodsList = reg->productList();
0145     // The constructor of an alias product holder takes as an argument the product holder for which it is an alias.
0146     // So, the non-alias product holders must be created first.
0147     // Therefore, on this first pass, skip current EDAliases.
0148     bool hasAliases = false;
0149     bool hasSwitchAliases = false;
0150     for (auto const& prod : prodsList) {
0151       BranchDescription const& bd = prod.second;
0152       if (bd.branchType() == branchType_) {
0153         if (isForPrimaryProcess or bd.processName() == pc.processName()) {
0154           if (bd.isAlias()) {
0155             hasAliases = true;
0156           } else if (bd.isSwitchAlias()) {
0157             hasSwitchAliases = true;
0158           } else {
0159             auto cbd = std::make_shared<BranchDescription const>(bd);
0160             if (bd.produced()) {
0161               if (bd.moduleLabel() == source) {
0162                 addSourceProduct(cbd);
0163               } else if (bd.onDemand()) {
0164                 assert(branchType_ == InEvent);
0165                 if (bd.isTransform()) {
0166                   addTransformProduct(cbd);
0167                 } else {
0168                   addUnscheduledProduct(cbd);
0169                 }
0170               } else {
0171                 addScheduledProduct(cbd);
0172               }
0173             } else {
0174               if (bd.onDemand()) {
0175                 addDelayedReaderInputProduct(cbd);
0176               } else {
0177                 addPutOnReadInputProduct(cbd);
0178               }
0179             }
0180           }
0181         } else {
0182           //We are in a SubProcess and this branch is from the parent
0183           auto cbd = std::make_shared<BranchDescription const>(bd);
0184           addParentProcessProduct(cbd);
0185         }
0186       }
0187     }
0188     // Now process any EDAliases
0189     if (hasAliases) {
0190       for (auto const& prod : prodsList) {
0191         BranchDescription const& bd = prod.second;
0192         if (bd.isAlias() && bd.branchType() == branchType_) {
0193           addAliasedProduct(std::make_shared<BranchDescription const>(bd));
0194         }
0195       }
0196     }
0197     // Finally process any SwitchProducer aliases
0198     if (hasSwitchAliases) {
0199       for (auto const& prod : prodsList) {
0200         BranchDescription const& bd = prod.second;
0201         if (bd.isSwitchAlias() && bd.branchType() == branchType_) {
0202           assert(branchType_ == InEvent);
0203           auto cbd = std::make_shared<BranchDescription const>(bd);
0204           // Need different implementation for SwitchProducers not
0205           // in any Path (onDemand) and for those in a Path in order
0206           // to prevent the switch-aliased-for EDProducers from
0207           // being run when the SwitchProducer is in a Path after a
0208           // failing EDFilter.
0209           if (bd.onDemand()) {
0210             addSwitchAliasProduct(cbd);
0211           } else {
0212             addSwitchProducerProduct(cbd);
0213           }
0214         }
0215       }
0216     }
0217 
0218     // Now create the ProductResolvers that search in reverse process
0219     // order and are used for queries where the process name is the
0220     // empty string
0221     std::vector<std::string> const& lookupProcessNames = productLookup_->lookupProcessNames();
0222     std::vector<ProductResolverIndex> matchingHolders(lookupProcessNames.size(), ProductResolverIndexInvalid);
0223     std::vector<bool> ambiguous(lookupProcessNames.size(), false);
0224     unsigned int beginElements = productLookup_->beginElements();
0225     std::vector<TypeID> const& sortedTypeIDs = productLookup_->sortedTypeIDs();
0226     std::vector<ProductResolverIndexHelper::Range> const& ranges = productLookup_->ranges();
0227     std::vector<ProductResolverIndexHelper::IndexAndNames> const& indexAndNames = productLookup_->indexAndNames();
0228     std::vector<char> const& processNamesCharArray = productLookup_->processNames();
0229 
0230     unsigned int numberOfMatches = 0;
0231     ProductResolverIndex lastMatchIndex = ProductResolverIndexInvalid;
0232     if (!sortedTypeIDs.empty()) {
0233       ProductResolverIndex productResolverIndex = ProductResolverIndexInvalid;
0234       for (unsigned int k = 0, kEnd = sortedTypeIDs.size(); k < kEnd; ++k) {
0235         ProductResolverIndexHelper::Range const& range = ranges.at(k);
0236         for (unsigned int i = range.begin(); i < range.end(); ++i) {
0237           ProductResolverIndexHelper::IndexAndNames const& product = indexAndNames.at(i);
0238           if (product.startInProcessNames() == 0) {
0239             if (productResolverIndex != ProductResolverIndexInvalid) {
0240               if ((numberOfMatches == 1) and (lastMatchIndex != ProductResolverIndexAmbiguous)) {
0241                 //only one choice so use a special resolver
0242                 productResolvers_.at(productResolverIndex) =
0243                     std::make_shared<SingleChoiceNoProcessProductResolver>(lastMatchIndex);
0244               } else {
0245                 bool productMadeAtEnd = false;
0246                 //Need to know if the product from this processes is added at end of transition
0247                 for (unsigned int j = 0; j < matchingHolders.size(); ++j) {
0248                   if ((not ambiguous[j]) and ProductResolverIndexInvalid != matchingHolders[j] and
0249                       productResolvers_[matchingHolders[j]]->branchDescription().availableOnlyAtEndTransition()) {
0250                     productMadeAtEnd = true;
0251                     break;
0252                   }
0253                 }
0254                 std::shared_ptr<ProductResolverBase> newHolder =
0255                     std::make_shared<NoProcessProductResolver>(matchingHolders, ambiguous, productMadeAtEnd);
0256                 productResolvers_.at(productResolverIndex) = newHolder;
0257               }
0258               matchingHolders.assign(lookupProcessNames.size(), ProductResolverIndexInvalid);
0259               ambiguous.assign(lookupProcessNames.size(), false);
0260               numberOfMatches = 0;
0261               lastMatchIndex = ProductResolverIndexInvalid;
0262             }
0263             productResolverIndex = product.index();
0264           } else {
0265             std::string process(&processNamesCharArray.at(product.startInProcessNames()));
0266             auto iter = std::find(lookupProcessNames.begin(), lookupProcessNames.end(), process);
0267             assert(iter != lookupProcessNames.end());
0268             ProductResolverIndex iMatchingIndex = product.index();
0269             lastMatchIndex = iMatchingIndex;
0270             assert(iMatchingIndex != ProductResolverIndexInvalid);
0271             ++numberOfMatches;
0272             if (iMatchingIndex == ProductResolverIndexAmbiguous) {
0273               assert(k >= beginElements);
0274               ambiguous.at(iter - lookupProcessNames.begin()) = true;
0275             } else {
0276               matchingHolders.at(iter - lookupProcessNames.begin()) = iMatchingIndex;
0277             }
0278           }
0279         }
0280       }
0281       //Need to know if the product from this processes is added at end of transition
0282       if ((numberOfMatches == 1) and (lastMatchIndex != ProductResolverIndexAmbiguous)) {
0283         //only one choice so use a special resolver
0284         productResolvers_.at(productResolverIndex) =
0285             std::make_shared<SingleChoiceNoProcessProductResolver>(lastMatchIndex);
0286       } else {
0287         bool productMadeAtEnd = false;
0288         for (unsigned int i = 0; i < matchingHolders.size(); ++i) {
0289           if ((not ambiguous[i]) and ProductResolverIndexInvalid != matchingHolders[i] and
0290               productResolvers_[matchingHolders[i]]->branchDescription().availableOnlyAtEndTransition()) {
0291             productMadeAtEnd = true;
0292             break;
0293           }
0294         }
0295         std::shared_ptr<ProductResolverBase> newHolder =
0296             std::make_shared<NoProcessProductResolver>(matchingHolders, ambiguous, productMadeAtEnd);
0297         productResolvers_.at(productResolverIndex) = newHolder;
0298       }
0299     }
0300   }
0301 
0302   Principal::~Principal() {}
0303 
0304   // Number of products in the Principal.
0305   // For products in an input file and not yet read in due to delayed read,
0306   // this routine assumes a real product is there.
0307   size_t Principal::size() const {
0308     size_t size = 0U;
0309     for (auto const& prod : *this) {
0310       if (prod->singleProduct() &&  // Not a NoProcessProductResolver
0311           !prod->productUnavailable() && !prod->unscheduledWasNotRun() && !prod->branchDescription().dropped()) {
0312         ++size;
0313       }
0314     }
0315     return size;
0316   }
0317 
0318   // adjust provenance for input products after new input file has been merged
0319   bool Principal::adjustToNewProductRegistry(ProductRegistry const& reg) {
0320     ProductRegistry::ProductList const& prodsList = reg.productList();
0321     for (auto const& prod : prodsList) {
0322       BranchDescription const& bd = prod.second;
0323       if (!bd.produced() && (bd.branchType() == branchType_)) {
0324         auto cbd = std::make_shared<BranchDescription const>(bd);
0325         auto phb = getExistingProduct(cbd->branchID());
0326         if (phb == nullptr || phb->branchDescription().branchName() != cbd->branchName()) {
0327           return false;
0328         }
0329         phb->resetBranchDescription(cbd);
0330       }
0331     }
0332     return true;
0333   }
0334 
0335   void Principal::addScheduledProduct(std::shared_ptr<BranchDescription const> bd) {
0336     auto phb = std::make_unique<PuttableProductResolver>(std::move(bd));
0337     addProductOrThrow(std::move(phb));
0338   }
0339 
0340   void Principal::addSourceProduct(std::shared_ptr<BranchDescription const> bd) {
0341     auto phb = std::make_unique<PuttableProductResolver>(std::move(bd));
0342     addProductOrThrow(std::move(phb));
0343   }
0344 
0345   void Principal::addDelayedReaderInputProduct(std::shared_ptr<BranchDescription const> bd) {
0346     addProductOrThrow(std::make_unique<DelayedReaderInputProductResolver>(std::move(bd)));
0347   }
0348 
0349   void Principal::addPutOnReadInputProduct(std::shared_ptr<BranchDescription const> bd) {
0350     addProductOrThrow(std::make_unique<PutOnReadInputProductResolver>(std::move(bd)));
0351   }
0352 
0353   void Principal::addUnscheduledProduct(std::shared_ptr<BranchDescription const> bd) {
0354     addProductOrThrow(std::make_unique<UnscheduledProductResolver>(std::move(bd)));
0355   }
0356 
0357   void Principal::addTransformProduct(std::shared_ptr<BranchDescription const> bd) {
0358     addProductOrThrow(std::make_unique<TransformingProductResolver>(std::move(bd)));
0359   }
0360 
0361   void Principal::addAliasedProduct(std::shared_ptr<BranchDescription const> bd) {
0362     ProductResolverIndex index = preg_->indexFrom(bd->originalBranchID());
0363     assert(index != ProductResolverIndexInvalid);
0364 
0365     addProductOrThrow(std::make_unique<AliasProductResolver>(
0366         std::move(bd), dynamic_cast<DataManagingOrAliasProductResolver&>(*productResolvers_[index])));
0367   }
0368 
0369   void Principal::addSwitchProducerProduct(std::shared_ptr<BranchDescription const> bd) {
0370     ProductResolverIndex index = preg_->indexFrom(bd->switchAliasForBranchID());
0371     assert(index != ProductResolverIndexInvalid);
0372 
0373     addProductOrThrow(std::make_unique<SwitchProducerProductResolver>(
0374         std::move(bd), dynamic_cast<DataManagingOrAliasProductResolver&>(*productResolvers_[index])));
0375   }
0376 
0377   void Principal::addSwitchAliasProduct(std::shared_ptr<BranchDescription const> bd) {
0378     ProductResolverIndex index = preg_->indexFrom(bd->switchAliasForBranchID());
0379     assert(index != ProductResolverIndexInvalid);
0380 
0381     addProductOrThrow(std::make_unique<SwitchAliasProductResolver>(
0382         std::move(bd), dynamic_cast<DataManagingOrAliasProductResolver&>(*productResolvers_[index])));
0383   }
0384 
0385   void Principal::addParentProcessProduct(std::shared_ptr<BranchDescription const> bd) {
0386     addProductOrThrow(std::make_unique<ParentProcessProductResolver>(std::move(bd)));
0387   }
0388 
0389   // "Zero" the principal so it can be reused for another Event.
0390   void Principal::clearPrincipal() {
0391     //We do not clear the product history information
0392     // because it rarely changes and recalculating takes
0393     // time.
0394     reader_ = nullptr;
0395     for (auto& prod : *this) {
0396       prod->resetProductData();
0397     }
0398   }
0399 
0400   void Principal::deleteProduct(BranchID const& id) const {
0401     auto phb = getExistingProduct(id);
0402     assert(nullptr != phb);
0403     phb->unsafe_deleteProduct();
0404   }
0405 
0406   void Principal::setupUnscheduled(UnscheduledConfigurator const& iConfigure) {
0407     applyToResolvers([&iConfigure](ProductResolverBase* iResolver) { iResolver->setupUnscheduled(iConfigure); });
0408   }
0409 
0410   void Principal::fillPrincipal(DelayedReader* reader) {
0411     //increment identifier here since clearPrincipal isn't called for Run/Lumi
0412     cacheIdentifier_ = nextIdentifier();
0413     if (reader) {
0414       reader_ = reader;
0415     }
0416   }
0417 
0418   // Set the principal for the Event, Lumi, or Run.
0419   void Principal::fillPrincipal(ProcessHistoryID const& hist,
0420                                 ProcessHistory const* processHistory,
0421                                 DelayedReader* reader) {
0422     fillPrincipal(reader);
0423 
0424     if (historyAppender_ && productRegistry().anyProductProduced()) {
0425       if ((not processHistoryPtr_) || (processHistoryIDBeforeConfig_ != hist)) {
0426         processHistoryPtr_ = historyAppender_->appendToProcessHistory(hist, processHistory, *processConfiguration_);
0427         processHistoryID_ = processHistoryPtr_->id();
0428         processHistoryIDBeforeConfig_ = hist;
0429       }
0430     } else {
0431       std::shared_ptr<ProcessHistory const> inputProcessHistory;
0432       if ((not processHistoryPtr_) || (processHistoryIDBeforeConfig_ != hist)) {
0433         if (hist.isValid()) {
0434           //does not own the pointer
0435           auto noDel = [](void const*) {};
0436           inputProcessHistory = std::shared_ptr<ProcessHistory const>(processHistory, noDel);
0437           if (inputProcessHistory.get() == nullptr) {
0438             throw Exception(errors::LogicError) << "Principal::fillPrincipal\n"
0439                                                 << "Input ProcessHistory not found in registry\n"
0440                                                 << "Contact a Framework developer\n";
0441           }
0442         } else {
0443           //Since this is static we don't want it deleted
0444           inputProcessHistory = std::shared_ptr<ProcessHistory const>(&s_emptyProcessHistory, [](void const*) {});
0445           //no need to do any ordering since it is empty
0446           orderProcessHistoryID_ = hist;
0447         }
0448         processHistoryID_ = hist;
0449         processHistoryPtr_ = inputProcessHistory;
0450         processHistoryIDBeforeConfig_ = hist;
0451       }
0452     }
0453 
0454     if (orderProcessHistoryID_ != processHistoryID_) {
0455       std::vector<std::string> const& lookupProcessNames = productLookup_->lookupProcessNames();
0456       lookupProcessOrder_.assign(lookupProcessNames.size(), 0);
0457       unsigned int k = 0;
0458 
0459       // We loop over processes in reverse order of the ProcessHistory.
0460       // If any entries in the product lookup tables are associated with
0461       // the process we add it to the vector of processes in the order
0462       // the lookup should be performed. There is one exception though,
0463       // We start with the current process even if it is not in the ProcessHistory.
0464       // The current process might be needed but not be in the process
0465       // history if all the products produced in the current process are
0466       // transient.
0467       {
0468         auto nameIterCurrentProcess =
0469             std::find(lookupProcessNames.begin(), lookupProcessNames.end(), processConfiguration_->processName());
0470         if (nameIterCurrentProcess != lookupProcessNames.end()) {
0471           lookupProcessOrder_.at(k) = nameIterCurrentProcess - lookupProcessNames.begin();
0472           ++k;
0473         }
0474       }
0475 
0476       // We just looked for the current process so skip it if
0477       // it is in the ProcessHistory.
0478       auto iter = processHistoryPtr_->rbegin();
0479       if (iter->processName() == processConfiguration_->processName()) {
0480         ++iter;
0481       }
0482 
0483       for (auto iEnd = processHistoryPtr_->rend(); iter != iEnd; ++iter) {
0484         auto nameIter = std::find(lookupProcessNames.begin(), lookupProcessNames.end(), iter->processName());
0485         if (nameIter == lookupProcessNames.end()) {
0486           continue;
0487         }
0488         lookupProcessOrder_.at(k) = nameIter - lookupProcessNames.begin();
0489         ++k;
0490       }
0491       orderProcessHistoryID_ = processHistoryID_;
0492     }
0493   }
0494 
0495   // Set the principal for the ProcessBlock
0496   void Principal::fillPrincipal(std::string const& processNameOfBlock, DelayedReader* reader) {
0497     fillPrincipal(reader);
0498 
0499     std::vector<std::string> const& lookupProcessNames = productLookup_->lookupProcessNames();
0500     lookupProcessOrder_.assign(lookupProcessNames.size(), 0);
0501     if (!lookupProcessOrder_.empty()) {
0502       auto iter = std::find(lookupProcessNames.begin(), lookupProcessNames.end(), processNameOfBlock);
0503       if (iter != lookupProcessNames.end()) {
0504         lookupProcessOrder_[0] = iter - lookupProcessNames.begin();
0505       }
0506     }
0507   }
0508 
0509   ProductResolverBase* Principal::getExistingProduct(BranchID const& branchID) {
0510     return const_cast<ProductResolverBase*>(const_cast<const Principal*>(this)->getExistingProduct(branchID));
0511   }
0512 
0513   ProductResolverBase const* Principal::getExistingProduct(BranchID const& branchID) const {
0514     ProductResolverIndex index = preg_->indexFrom(branchID);
0515     assert(index != ProductResolverIndexInvalid);
0516     return productResolvers_.at(index).get();
0517   }
0518 
0519   ProductResolverBase const* Principal::getExistingProduct(ProductResolverBase const& productResolver) const {
0520     auto phb = getExistingProduct(productResolver.branchDescription().branchID());
0521     if (nullptr != phb && BranchKey(productResolver.branchDescription()) != BranchKey(phb->branchDescription())) {
0522       BranchDescription const& newProduct = phb->branchDescription();
0523       BranchDescription const& existing = productResolver.branchDescription();
0524       if (newProduct.branchName() != existing.branchName() && newProduct.branchID() == existing.branchID()) {
0525         throw cms::Exception("HashCollision")
0526             << "Principal::getExistingProduct\n"
0527             << " Branch " << newProduct.branchName() << " has same branch ID as branch " << existing.branchName()
0528             << "\n"
0529             << "Workaround: change process name or product instance name of " << newProduct.branchName() << "\n";
0530       } else {
0531         assert(nullptr == phb || BranchKey(productResolver.branchDescription()) == BranchKey(phb->branchDescription()));
0532       }
0533     }
0534     return phb;
0535   }
0536 
0537   void Principal::addProduct_(std::unique_ptr<ProductResolverBase> productResolver) {
0538     BranchDescription const& bd = productResolver->branchDescription();
0539     assert(!bd.className().empty());
0540     assert(!bd.friendlyClassName().empty());
0541     assert(!bd.moduleLabel().empty());
0542     assert(!bd.processName().empty());
0543     SharedProductPtr phb(productResolver.release());
0544 
0545     ProductResolverIndex index = preg_->indexFrom(bd.branchID());
0546     assert(index != ProductResolverIndexInvalid);
0547     productResolvers_[index] = phb;
0548   }
0549 
0550   void Principal::addProductOrThrow(std::unique_ptr<ProductResolverBase> productResolver) {
0551     ProductResolverBase const* phb = getExistingProduct(*productResolver);
0552     if (phb != nullptr) {
0553       BranchDescription const& bd = productResolver->branchDescription();
0554       throw Exception(errors::InsertFailure, "AlreadyPresent")
0555           << "addProductOrThrow: Problem found while adding product, "
0556           << "product already exists for (" << bd.friendlyClassName() << "," << bd.moduleLabel() << ","
0557           << bd.productInstanceName() << "," << bd.processName() << ")\n";
0558     }
0559     addProduct_(std::move(productResolver));
0560   }
0561 
0562   Principal::ConstProductResolverPtr Principal::getProductResolver(BranchID const& bid) const {
0563     ProductResolverIndex index = preg_->indexFrom(bid);
0564     if (index == ProductResolverIndexInvalid) {
0565       return ConstProductResolverPtr();
0566     }
0567     return getProductResolverByIndex(index);
0568   }
0569 
0570   Principal::ConstProductResolverPtr Principal::getProductResolverByIndex(ProductResolverIndex const& index) const {
0571     ConstProductResolverPtr const phb = productResolvers_[index].get();
0572     return phb;
0573   }
0574 
0575   unsigned int Principal::processBlockIndex(std::string const&) const {
0576     throw Exception(errors::LogicError) << "Principal::processBlockIndex not implemented for this type of Principal";
0577   }
0578 
0579   BasicHandle Principal::getByLabel(KindOfType kindOfType,
0580                                     TypeID const& typeID,
0581                                     InputTag const& inputTag,
0582                                     EDConsumerBase const* consumer,
0583                                     SharedResourcesAcquirer* sra,
0584                                     ModuleCallingContext const* mcc) const {
0585     // Not implemented for ProcessBlocks, it might work though, not tested
0586     // The other getByLabel function is used for ProcessBlocks by TestProcessor
0587     assert(branchType_ != InProcess);
0588 
0589     ProductData const* result = findProductByLabel(kindOfType, typeID, inputTag, consumer, sra, mcc);
0590     if (result == nullptr) {
0591       return BasicHandle(makeHandleExceptionFactory([=]() -> std::shared_ptr<cms::Exception> {
0592         return makeNotFoundException(
0593             "getByLabel",
0594             kindOfType,
0595             typeID,
0596             inputTag.label(),
0597             inputTag.instance(),
0598             appendCurrentProcessIfAlias(inputTag.process(), processConfiguration_->processName()));
0599       }));
0600     }
0601     return BasicHandle(result->wrapper(), &(result->provenance()));
0602   }
0603 
0604   BasicHandle Principal::getByLabel(KindOfType kindOfType,
0605                                     TypeID const& typeID,
0606                                     std::string const& label,
0607                                     std::string const& instance,
0608                                     std::string const& process,
0609                                     EDConsumerBase const* consumer,
0610                                     SharedResourcesAcquirer* sra,
0611                                     ModuleCallingContext const* mcc) const {
0612     ProductData const* result = findProductByLabel(kindOfType, typeID, label, instance, process, consumer, sra, mcc);
0613     if (result == nullptr) {
0614       return BasicHandle(makeHandleExceptionFactory([=]() -> std::shared_ptr<cms::Exception> {
0615         return makeNotFoundException("getByLabel", kindOfType, typeID, label, instance, process);
0616       }));
0617     }
0618     return BasicHandle(result->wrapper(), &(result->provenance()));
0619   }
0620 
0621   BasicHandle Principal::getByToken(KindOfType,
0622                                     TypeID const&,
0623                                     ProductResolverIndex index,
0624                                     bool skipCurrentProcess,
0625                                     bool& ambiguous,
0626                                     SharedResourcesAcquirer* sra,
0627                                     ModuleCallingContext const* mcc) const {
0628     assert(index != ProductResolverIndexInvalid);
0629     auto& productResolver = productResolvers_[index];
0630     assert(nullptr != productResolver.get());
0631     auto resolution = productResolver->resolveProduct(*this, skipCurrentProcess, sra, mcc);
0632     if (resolution.isAmbiguous()) {
0633       ambiguous = true;
0634       //The caller is looking explicitly for this case
0635       // and uses the extra data at the caller to setup the exception
0636       return BasicHandle::makeInvalid();
0637     }
0638     auto productData = resolution.data();
0639     if (productData == nullptr) {
0640       //The caller is looking explicitly for this case
0641       // and uses the extra data at the caller to setup the exception
0642       return BasicHandle::makeInvalid();
0643     }
0644     return BasicHandle(productData->wrapper(), &(productData->provenance()));
0645   }
0646 
0647   void Principal::prefetchAsync(WaitingTaskHolder task,
0648                                 ProductResolverIndex index,
0649                                 bool skipCurrentProcess,
0650                                 ServiceToken const& token,
0651                                 ModuleCallingContext const* mcc) const {
0652     auto const& productResolver = productResolvers_.at(index);
0653     assert(nullptr != productResolver.get());
0654     productResolver->prefetchAsync(task, *this, skipCurrentProcess, token, nullptr, mcc);
0655   }
0656 
0657   void Principal::getManyByType(TypeID const& typeID,
0658                                 BasicHandleVec& results,
0659                                 EDConsumerBase const* consumer,
0660                                 SharedResourcesAcquirer* sra,
0661                                 ModuleCallingContext const* mcc) const {
0662     // Not implemented for ProcessBlocks
0663     assert(branchType_ != InProcess);
0664 
0665     assert(results.empty());
0666 
0667     if (UNLIKELY(consumer and (not consumer->registeredToConsumeMany(typeID, branchType())))) {
0668       failedToRegisterConsumesMany(typeID);
0669     }
0670 
0671     // This finds the indexes to all the ProductResolver's matching the type
0672     ProductResolverIndexHelper::Matches matches = productLookup().relatedIndexes(PRODUCT_TYPE, typeID);
0673 
0674     if (matches.numberOfMatches() == 0) {
0675       return;
0676     }
0677 
0678     results.reserve(matches.numberOfMatches());
0679 
0680     // Loop over the ProductResolvers. Add the products that are actually
0681     // present into the results. This will also trigger delayed reading,
0682     // on demand production, and check for deleted products as appropriate.
0683 
0684     // Over the years the code that uses getManyByType has grown to depend
0685     // on the ordering of the results. The order originally was just an
0686     // accident of how previous versions of the code were written, but
0687     // here we have to go through some extra effort to preserve that ordering.
0688 
0689     // We build a list of holders that match a particular label and instance.
0690     // When that list is complete we call findProducts, which loops over
0691     // that list in reverse order of the ProcessHistory (starts with the
0692     // most recent).  Then we clear the list and repeat this until all the
0693     // matching label and instance subsets have been dealt with.
0694 
0695     // Note that the function isFullyResolved returns true for the ProductResolvers
0696     // that are associated with an empty process name. Those are the ones that
0697     // know how to search for the most recent process name matching
0698     // a label and instance. We do not need these for getManyByType and
0699     // skip them. In addition to skipping them, we make use of the fact
0700     // that they mark the beginning of each subset of holders with the same
0701     // label and instance. They tell us when to call findProducts.
0702 
0703     std::vector<ProductResolverBase const*> holders;
0704 
0705     for (unsigned int i = 0; i < matches.numberOfMatches(); ++i) {
0706       ProductResolverIndex index = matches.index(i);
0707 
0708       if (!matches.isFullyResolved(i)) {
0709         if (!holders.empty()) {
0710           // Process the ones with a particular module label and instance
0711           findProducts(holders, typeID, results, sra, mcc);
0712           holders.clear();
0713         }
0714       } else {
0715         ProductResolverBase const* productResolver = productResolvers_.at(index).get();
0716         assert(productResolver);
0717         holders.push_back(productResolver);
0718       }
0719     }
0720     // Do not miss the last subset of products
0721     if (!holders.empty()) {
0722       findProducts(holders, typeID, results, sra, mcc);
0723     }
0724     return;
0725   }
0726 
0727   void Principal::findProducts(std::vector<ProductResolverBase const*> const& holders,
0728                                TypeID const&,
0729                                BasicHandleVec& results,
0730                                SharedResourcesAcquirer* sra,
0731                                ModuleCallingContext const* mcc) const {
0732     for (auto iter = processHistoryPtr_->rbegin(), iEnd = processHistoryPtr_->rend(); iter != iEnd; ++iter) {
0733       std::string const& process = iter->processName();
0734       for (auto productResolver : holders) {
0735         BranchDescription const& bd = productResolver->branchDescription();
0736         if (process == bd.processName()) {
0737           // Ignore aliases to avoid matching the same product multiple times.
0738           if (bd.isAnyAlias()) {
0739             continue;
0740           }
0741 
0742           ProductData const* productData = productResolver->resolveProduct(*this, false, sra, mcc).data();
0743           if (productData) {
0744             // Skip product if not available.
0745             results.emplace_back(productData->wrapper(), &(productData->provenance()));
0746           }
0747         }
0748       }
0749     }
0750   }
0751 
0752   ProductData const* Principal::findProductByLabel(KindOfType kindOfType,
0753                                                    TypeID const& typeID,
0754                                                    InputTag const& inputTag,
0755                                                    EDConsumerBase const* consumer,
0756                                                    SharedResourcesAcquirer* sra,
0757                                                    ModuleCallingContext const* mcc) const {
0758     bool skipCurrentProcess = inputTag.willSkipCurrentProcess();
0759 
0760     ProductResolverIndex index = inputTag.indexFor(typeID, branchType(), &productRegistry());
0761 
0762     if (index == ProductResolverIndexInvalid) {
0763       char const* processName = inputTag.process().c_str();
0764       if (skipCurrentProcess) {
0765         processName = "\0";
0766       } else if (inputTag.process() == InputTag::kCurrentProcess) {
0767         processName = processConfiguration_->processName().c_str();
0768       }
0769 
0770       index =
0771           productLookup().index(kindOfType, typeID, inputTag.label().c_str(), inputTag.instance().c_str(), processName);
0772 
0773       if (index == ProductResolverIndexAmbiguous) {
0774         throwAmbiguousException("findProductByLabel",
0775                                 typeID,
0776                                 inputTag.label(),
0777                                 inputTag.instance(),
0778                                 appendCurrentProcessIfAlias(inputTag.process(), processConfiguration_->processName()));
0779       } else if (index == ProductResolverIndexInvalid) {
0780         // can occur because of missing consumes if nothing else in the process consumes the product
0781         for (auto const& item : preg_->productList()) {
0782           auto const& bd = item.second;
0783           if (bd.present() and bd.unwrappedTypeID() == typeID and bd.moduleLabel() == inputTag.label() and
0784               bd.productInstanceName() == inputTag.instance()) {
0785             bool const inCurrentProcess = bd.processName() == processConfiguration_->processName();
0786             if (inputTag.process().empty() or bd.processName() == inputTag.process() or
0787                 (skipCurrentProcess and not inCurrentProcess) or
0788                 (inputTag.process() == InputTag::kCurrentProcess and inCurrentProcess)) {
0789               failedToRegisterConsumes(
0790                   kindOfType,
0791                   typeID,
0792                   inputTag.label(),
0793                   inputTag.instance(),
0794                   appendCurrentProcessIfAlias(inputTag.process(), processConfiguration_->processName()));
0795             }
0796           }
0797         }
0798         return nullptr;
0799       }
0800       inputTag.tryToCacheIndex(index, typeID, branchType(), &productRegistry());
0801     }
0802     if (UNLIKELY(consumer and (not consumer->registeredToConsume(index, skipCurrentProcess, branchType())))) {
0803       failedToRegisterConsumes(kindOfType,
0804                                typeID,
0805                                inputTag.label(),
0806                                inputTag.instance(),
0807                                appendCurrentProcessIfAlias(inputTag.process(), processConfiguration_->processName()));
0808     }
0809 
0810     auto const& productResolver = productResolvers_[index];
0811 
0812     auto resolution = productResolver->resolveProduct(*this, skipCurrentProcess, sra, mcc);
0813     if (resolution.isAmbiguous()) {
0814       throwAmbiguousException("findProductByLabel",
0815                               typeID,
0816                               inputTag.label(),
0817                               inputTag.instance(),
0818                               appendCurrentProcessIfAlias(inputTag.process(), processConfiguration_->processName()));
0819     }
0820     return resolution.data();
0821   }
0822 
0823   ProductData const* Principal::findProductByLabel(KindOfType kindOfType,
0824                                                    TypeID const& typeID,
0825                                                    std::string const& label,
0826                                                    std::string const& instance,
0827                                                    std::string const& process,
0828                                                    EDConsumerBase const* consumer,
0829                                                    SharedResourcesAcquirer* sra,
0830                                                    ModuleCallingContext const* mcc) const {
0831     ProductResolverIndex index =
0832         productLookup().index(kindOfType, typeID, label.c_str(), instance.c_str(), process.c_str());
0833 
0834     if (index == ProductResolverIndexAmbiguous) {
0835       throwAmbiguousException("findProductByLabel", typeID, label, instance, process);
0836     } else if (index == ProductResolverIndexInvalid) {
0837       // can occur because of missing consumes if nothing else in the process consumes the product
0838       for (auto const& item : preg_->productList()) {
0839         auto const& bd = item.second;
0840         if (bd.present() and bd.unwrappedTypeID() == typeID and bd.moduleLabel() == label and
0841             bd.productInstanceName() == instance) {
0842           if (process.empty() or bd.processName() == process) {
0843             failedToRegisterConsumes(kindOfType, typeID, label, instance, process);
0844           }
0845         }
0846       }
0847       return nullptr;
0848     }
0849 
0850     if (UNLIKELY(consumer and (not consumer->registeredToConsume(index, false, branchType())))) {
0851       failedToRegisterConsumes(kindOfType, typeID, label, instance, process);
0852     }
0853 
0854     auto const& productResolver = productResolvers_[index];
0855 
0856     auto resolution = productResolver->resolveProduct(*this, false, sra, mcc);
0857     if (resolution.isAmbiguous()) {
0858       throwAmbiguousException("findProductByLabel", typeID, label, instance, process);
0859     }
0860     return resolution.data();
0861   }
0862 
0863   ProductData const* Principal::findProductByTag(TypeID const& typeID,
0864                                                  InputTag const& tag,
0865                                                  ModuleCallingContext const* mcc) const {
0866     // Not implemented for ProcessBlocks
0867     assert(branchType_ != InProcess);
0868 
0869     ProductData const* productData = findProductByLabel(PRODUCT_TYPE, typeID, tag, nullptr, nullptr, mcc);
0870     return productData;
0871   }
0872 
0873   Provenance const& Principal::getProvenance(BranchID const& bid) const {
0874     ConstProductResolverPtr const phb = getProductResolver(bid);
0875     if (phb == nullptr) {
0876       throwProductNotFoundException("getProvenance", errors::ProductNotFound, bid);
0877     }
0878 
0879     if (phb->unscheduledWasNotRun()) {
0880       throw edm::Exception(errors::UnimplementedFeature)
0881           << "Requesting provenance from unrun EDProducer. The requested branch ID was: " << bid;
0882     }
0883     return *phb->provenance();
0884   }
0885 
0886   StableProvenance const& Principal::getStableProvenance(BranchID const& bid) const {
0887     ConstProductResolverPtr const phb = getProductResolver(bid);
0888     if (phb == nullptr) {
0889       throwProductNotFoundException("getStableProvenance", errors::ProductNotFound, bid);
0890     }
0891     //NOTE: in all implementations, this never returns a nullptr
0892     return *phb->stableProvenance();
0893   }
0894 
0895   // This one is mostly for test printout purposes
0896   // No attempt to trigger on demand execution
0897   // Skips provenance when the EDProduct is not there
0898   void Principal::getAllProvenance(std::vector<Provenance const*>& provenances) const {
0899     provenances.clear();
0900     for (auto const& productResolver : *this) {
0901       if (productResolver->singleProduct() && productResolver->provenanceAvailable() &&
0902           !productResolver->branchDescription().isAnyAlias()) {
0903         // We do not attempt to get the event/lumi/run status from the provenance,
0904         // because the per event provenance may have been dropped.
0905         if (productResolver->provenance()->branchDescription().present()) {
0906           provenances.push_back(productResolver->provenance());
0907         }
0908       }
0909     }
0910   }
0911 
0912   // This one is also mostly for test printout purposes
0913   // No attempt to trigger on demand execution
0914   // Skips provenance for dropped branches.
0915   void Principal::getAllStableProvenance(std::vector<StableProvenance const*>& provenances) const {
0916     provenances.clear();
0917     for (auto const& productResolver : *this) {
0918       if (productResolver->singleProduct() && !productResolver->branchDescription().isAnyAlias()) {
0919         if (productResolver->stableProvenance()->branchDescription().present()) {
0920           provenances.push_back(productResolver->stableProvenance());
0921         }
0922       }
0923     }
0924   }
0925 
0926   void Principal::recombine(Principal& other, std::vector<BranchID> const& bids) {
0927     for (auto& prod : bids) {
0928       ProductResolverIndex index = preg_->indexFrom(prod);
0929       assert(index != ProductResolverIndexInvalid);
0930       ProductResolverIndex indexO = other.preg_->indexFrom(prod);
0931       assert(indexO != ProductResolverIndexInvalid);
0932       get_underlying_safe(productResolvers_[index]).swap(get_underlying_safe(other.productResolvers_[indexO]));
0933     }
0934     reader_->mergeReaders(other.reader());
0935   }
0936 
0937   WrapperBase const* Principal::getIt(ProductID const&) const {
0938     assert(false);
0939     return nullptr;
0940   }
0941 
0942   std::optional<std::tuple<WrapperBase const*, unsigned int>> Principal::getThinnedProduct(ProductID const&,
0943                                                                                            unsigned int) const {
0944     assert(false);
0945     return std::nullopt;
0946   }
0947 
0948   void Principal::getThinnedProducts(ProductID const&,
0949                                      std::vector<WrapperBase const*>&,
0950                                      std::vector<unsigned int>&) const {
0951     assert(false);
0952   }
0953 
0954   OptionalThinnedKey Principal::getThinnedKeyFrom(ProductID const&, unsigned int, ProductID const&) const {
0955     assert(false);
0956     return std::monostate{};
0957   }
0958 
0959   void Principal::put_(std::unique_ptr<WrapperBase> prod, ProductResolverBase const* phb) const {
0960     dynamic_cast<ProductPutterBase const*>(phb)->putProduct(std::move(prod));
0961   }
0962 
0963   void Principal::put_(BranchDescription const& bd, std::unique_ptr<WrapperBase> edp) const {
0964     if (edp.get() == nullptr) {
0965       throw edm::Exception(edm::errors::InsertFailure, "Null Pointer")
0966           << "put: Cannot put because unique_ptr to product is null."
0967           << "\n";
0968     }
0969     auto phb = getExistingProduct(bd.branchID());
0970     assert(phb);
0971     // ProductResolver assumes ownership
0972     put_(std::move(edp), phb);
0973   }
0974 
0975   void Principal::adjustIndexesAfterProductRegistryAddition() {
0976     if (preg_->getNextIndexValue(branchType_) != productResolvers_.size()) {
0977       bool changed = false;
0978       productResolvers_.resize(preg_->getNextIndexValue(branchType_));
0979       for (auto const& prod : preg_->productList()) {
0980         BranchDescription const& bd = prod.second;
0981         if (bd.branchType() == branchType_) {
0982           ProductResolverIndex index = preg_->indexFrom(bd.branchID());
0983           assert(index != ProductResolverIndexInvalid);
0984           if (!productResolvers_[index]) {
0985             // no product holder.  Must add one. The new entry must be an input product holder.
0986             assert(!bd.produced());
0987             auto cbd = std::make_shared<BranchDescription const>(bd);
0988             if (bd.onDemand()) {
0989               addDelayedReaderInputProduct(cbd);
0990             } else {
0991               addPutOnReadInputProduct(cbd);
0992             }
0993             changed = true;
0994           }
0995         }
0996       }
0997       if (changed) {
0998         changedIndexes_();
0999       }
1000     }
1001     assert(preg_->getNextIndexValue(branchType_) == productResolvers_.size());
1002   }
1003 
1004   void Principal::readAllFromSourceAndMergeImmediately(MergeableRunProductMetadata const* mergeableRunProductMetadata) {
1005     if (not reader()) {
1006       return;
1007     }
1008 
1009     for (auto& prod : *this) {
1010       prod->retrieveAndMerge(*this, mergeableRunProductMetadata);
1011     }
1012   }
1013 }  // namespace edm