Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2021-08-18 22:30:21

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