Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2025-01-31 02:19:24

0001 /**----------------------------------------------------------------------
0002   ----------------------------------------------------------------------*/
0003 #ifdef __clang__
0004 #pragma GCC diagnostic ignored "-Wc++20-extensions"
0005 #endif
0006 
0007 #include "FWCore/Framework/interface/Principal.h"
0008 
0009 #include "DataFormats/Provenance/interface/ProcessConfiguration.h"
0010 #include "DataFormats/Provenance/interface/ProductResolverIndexHelper.h"
0011 #include "DataFormats/Provenance/interface/ProductRegistry.h"
0012 #include "DataFormats/Common/interface/FunctorHandleExceptionFactory.h"
0013 #include "FWCore/Framework/interface/DelayedReader.h"
0014 #include "FWCore/Framework/interface/HistoryAppender.h"
0015 #include "FWCore/Framework/src/ProductDeletedException.h"
0016 #include "FWCore/Framework/interface/ProductPutterBase.h"
0017 #include "FWCore/Framework/interface/EDConsumerBase.h"
0018 #include "DroppedDataProductResolver.h"
0019 #include "FWCore/Utilities/interface/EDMException.h"
0020 #include "FWCore/Utilities/interface/ProductResolverIndex.h"
0021 #include "FWCore/Utilities/interface/TypeID.h"
0022 #include "FWCore/Utilities/interface/WrappedClassName.h"
0023 #include "FWCore/Utilities/interface/Likely.h"
0024 
0025 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0026 
0027 #include <algorithm>
0028 #include <cstring>
0029 #include <limits>
0030 #include <sstream>
0031 #include <stdexcept>
0032 #include <typeinfo>
0033 #include <atomic>
0034 
0035 namespace edm {
0036 
0037   static ProcessHistory const s_emptyProcessHistory;
0038 
0039   static std::string appendCurrentProcessIfAlias(std::string const& processFromInputTag,
0040                                                  std::string const& currentProcess) {
0041     if (processFromInputTag == InputTag::kCurrentProcess) {
0042       std::string returnValue = processFromInputTag;
0043       returnValue += " (";
0044       returnValue += currentProcess;
0045       returnValue += ")";
0046       return returnValue;
0047     }
0048     return processFromInputTag;
0049   }
0050 
0051   static void throwProductNotFoundException(char const* where, errors::ErrorCodes error, BranchID const& bid) {
0052     throw Exception(error, "InvalidID") << "Principal::" << where << ": no product with given branch id: " << bid
0053                                         << "\n";
0054   }
0055 
0056   static std::shared_ptr<cms::Exception> makeNotFoundException(char const* where,
0057                                                                KindOfType kindOfType,
0058                                                                TypeID const& productType,
0059                                                                std::string const& label,
0060                                                                std::string const& instance,
0061                                                                std::string const& process) {
0062     std::shared_ptr<cms::Exception> exception = std::make_shared<Exception>(errors::ProductNotFound);
0063     if (kindOfType == PRODUCT_TYPE) {
0064       *exception << "Principal::" << where
0065                  << ": Found zero products matching all criteria\nLooking for type: " << productType << "\n"
0066                  << "Looking for module label: " << label << "\n"
0067                  << "Looking for productInstanceName: " << instance << "\n"
0068                  << (process.empty() ? "" : "Looking for process: ") << process << "\n";
0069     } else {
0070       *exception << "Principal::" << where
0071                  << ": Found zero products matching all criteria\nLooking for a container with elements of type: "
0072                  << productType << "\n"
0073                  << "Looking for module label: " << label << "\n"
0074                  << "Looking for productInstanceName: " << instance << "\n"
0075                  << (process.empty() ? "" : "Looking for process: ") << process << "\n";
0076     }
0077     return exception;
0078   }
0079 
0080   static void throwAmbiguousException(const char* where,
0081                                       TypeID const& productType,
0082                                       std::string const& label,
0083                                       std::string const& instance,
0084                                       std::string const& process) {
0085     cms::Exception exception("AmbiguousProduct");
0086     exception << "Principal::" << where
0087               << ": More than 1 product matches all criteria\nLooking for type: " << productType << "\n"
0088               << "Looking for module label: " << label << "\n"
0089               << "Looking for productInstanceName: " << instance << "\n"
0090               << (process.empty() ? "" : "Looking for process: ") << process << "\n"
0091               << "This can only occur with get function calls using a Handle<View> argument.\n"
0092               << "Try a get not using a View or change the instance name of one of the products";
0093     throw exception;
0094   }
0095 
0096   namespace {
0097     void failedToRegisterConsumes(KindOfType kindOfType,
0098                                   TypeID const& productType,
0099                                   std::string const& moduleLabel,
0100                                   std::string const& productInstanceName,
0101                                   std::string const& processName) {
0102       cms::Exception exception("GetByLabelWithoutRegistration");
0103       exception << "::getByLabel without corresponding call to consumes or mayConsumes for this module.\n"
0104                 << (kindOfType == PRODUCT_TYPE ? "  type: " : " type: edm::View<") << productType
0105                 << (kindOfType == PRODUCT_TYPE ? "\n  module label: " : ">\n  module label: ") << moduleLabel
0106                 << "\n  product instance name: '" << productInstanceName << "'\n  process name: '" << processName
0107                 << "'\n";
0108       throw exception;
0109     }
0110   }  // namespace
0111 
0112   //0 means unset
0113   static std::atomic<Principal::CacheIdentifier_t> s_nextIdentifier{1};
0114   static inline Principal::CacheIdentifier_t nextIdentifier() {
0115     return s_nextIdentifier.fetch_add(1, std::memory_order_acq_rel);
0116   }
0117 
0118   Principal::Principal(std::shared_ptr<ProductRegistry const> reg,
0119                        std::vector<std::shared_ptr<ProductResolverBase>>&& resolvers,
0120                        ProcessConfiguration const& pc,
0121                        BranchType bt,
0122                        HistoryAppender* historyAppender)
0123       : EDProductGetter(),
0124         processHistoryPtr_(),
0125         processHistoryID_(),
0126         processHistoryIDBeforeConfig_(),
0127         processConfiguration_(&pc),
0128         productResolvers_(resolvers.begin(), resolvers.end()),
0129         preg_(reg),
0130         productLookup_(reg->productLookup(bt)),
0131         lookupProcessOrder_(productLookup_->lookupProcessNames().size(), 0),
0132         reader_(),
0133         branchType_(bt),
0134         historyAppender_(historyAppender),
0135         cacheIdentifier_(nextIdentifier()) {}
0136   Principal::~Principal() {}
0137 
0138   // Number of products in the Principal.
0139   // For products in an input file and not yet read in due to delayed read,
0140   // this routine assumes a real product is there.
0141   size_t Principal::size() const {
0142     size_t size = 0U;
0143     for (auto const& prod : *this) {
0144       if (prod->singleProduct() &&  // Not a NoProcessProductResolver
0145           !prod->productUnavailable() && !prod->unscheduledWasNotRun() && !prod->productDescription().dropped()) {
0146         ++size;
0147       }
0148     }
0149     return size;
0150   }
0151 
0152   // adjust provenance for input products after new input file has been merged
0153   bool Principal::adjustToNewProductRegistry(ProductRegistry const& reg) {
0154     ProductRegistry::ProductList const& prodsList = reg.productList();
0155     for (auto const& prod : prodsList) {
0156       ProductDescription const& bd = prod.second;
0157       if (!bd.produced() && (bd.branchType() == branchType_)) {
0158         auto cbd = std::make_shared<ProductDescription const>(bd);
0159         auto phb = getExistingProduct(cbd->branchID());
0160         if (phb == nullptr || phb->productDescription().branchName() != cbd->branchName()) {
0161           return false;
0162         }
0163         phb->resetProductDescription(cbd);
0164       }
0165     }
0166     return true;
0167   }
0168 
0169   void Principal::addDroppedProduct(ProductDescription const& bd) {
0170     addProductOrThrow(std::make_unique<DroppedDataProductResolver>(std::make_shared<ProductDescription const>(bd)));
0171   }
0172 
0173   // "Zero" the principal so it can be reused for another Event.
0174   void Principal::clearPrincipal() {
0175     //We do not clear the product history information
0176     // because it rarely changes and recalculating takes
0177     // time.
0178     reader_ = nullptr;
0179     for (auto& prod : *this) {
0180       prod->resetProductData();
0181     }
0182   }
0183 
0184   void Principal::deleteProduct(BranchID const& id) const {
0185     auto phb = getExistingProduct(id);
0186     assert(nullptr != phb);
0187     phb->unsafe_deleteProduct();
0188   }
0189 
0190   void Principal::setupUnscheduled(UnscheduledConfigurator const& iConfigure) {
0191     applyToResolvers([&iConfigure](ProductResolverBase* iResolver) { iResolver->setupUnscheduled(iConfigure); });
0192   }
0193 
0194   void Principal::fillPrincipal(DelayedReader* reader) {
0195     //increment identifier here since clearPrincipal isn't called for Run/Lumi
0196     cacheIdentifier_ = nextIdentifier();
0197     if (reader) {
0198       reader_ = reader;
0199     }
0200   }
0201 
0202   // Set the principal for the Event, Lumi, or Run.
0203   void Principal::fillPrincipal(ProcessHistoryID const& hist,
0204                                 ProcessHistory const* processHistory,
0205                                 DelayedReader* reader) {
0206     fillPrincipal(reader);
0207 
0208     if (historyAppender_ && productRegistry().anyProductProduced()) {
0209       if ((not processHistoryPtr_) || (processHistoryIDBeforeConfig_ != hist)) {
0210         processHistoryPtr_ = historyAppender_->appendToProcessHistory(hist, processHistory, *processConfiguration_);
0211         processHistoryID_ = processHistoryPtr_->id();
0212         processHistoryIDBeforeConfig_ = hist;
0213       }
0214     } else {
0215       std::shared_ptr<ProcessHistory const> inputProcessHistory;
0216       if ((not processHistoryPtr_) || (processHistoryIDBeforeConfig_ != hist)) {
0217         if (hist.isValid()) {
0218           //does not own the pointer
0219           auto noDel = [](void const*) {};
0220           inputProcessHistory = std::shared_ptr<ProcessHistory const>(processHistory, noDel);
0221           if (inputProcessHistory.get() == nullptr) {
0222             throw Exception(errors::LogicError) << "Principal::fillPrincipal\n"
0223                                                 << "Input ProcessHistory not found in registry\n"
0224                                                 << "Contact a Framework developer\n";
0225           }
0226         } else {
0227           //Since this is static we don't want it deleted
0228           inputProcessHistory = std::shared_ptr<ProcessHistory const>(&s_emptyProcessHistory, [](void const*) {});
0229           //no need to do any ordering since it is empty
0230           orderProcessHistoryID_ = hist;
0231         }
0232         processHistoryID_ = hist;
0233         processHistoryPtr_ = inputProcessHistory;
0234         processHistoryIDBeforeConfig_ = hist;
0235       }
0236     }
0237 
0238     if (orderProcessHistoryID_ != processHistoryID_) {
0239       std::vector<std::string> const& lookupProcessNames = productLookup_->lookupProcessNames();
0240       lookupProcessOrder_.assign(lookupProcessNames.size(), 0);
0241       unsigned int k = 0;
0242 
0243       // We loop over processes in reverse order of the ProcessHistory.
0244       // If any entries in the product lookup tables are associated with
0245       // the process we add it to the vector of processes in the order
0246       // the lookup should be performed. There is one exception though,
0247       // We start with the current process even if it is not in the ProcessHistory.
0248       // The current process might be needed but not be in the process
0249       // history if all the products produced in the current process are
0250       // transient.
0251       {
0252         auto nameIterCurrentProcess =
0253             std::find(lookupProcessNames.begin(), lookupProcessNames.end(), processConfiguration_->processName());
0254         if (nameIterCurrentProcess != lookupProcessNames.end()) {
0255           lookupProcessOrder_.at(k) = nameIterCurrentProcess - lookupProcessNames.begin();
0256           ++k;
0257         }
0258       }
0259 
0260       // We just looked for the current process so skip it if
0261       // it is in the ProcessHistory.
0262       auto iter = processHistoryPtr_->rbegin();
0263       if (iter->processName() == processConfiguration_->processName()) {
0264         ++iter;
0265       }
0266 
0267       for (auto iEnd = processHistoryPtr_->rend(); iter != iEnd; ++iter) {
0268         auto nameIter = std::find(lookupProcessNames.begin(), lookupProcessNames.end(), iter->processName());
0269         if (nameIter == lookupProcessNames.end()) {
0270           continue;
0271         }
0272         lookupProcessOrder_.at(k) = nameIter - lookupProcessNames.begin();
0273         ++k;
0274       }
0275       orderProcessHistoryID_ = processHistoryID_;
0276     }
0277   }
0278 
0279   // Set the principal for the ProcessBlock
0280   void Principal::fillPrincipal(std::string const& processNameOfBlock, DelayedReader* reader) {
0281     fillPrincipal(reader);
0282 
0283     std::vector<std::string> const& lookupProcessNames = productLookup_->lookupProcessNames();
0284     lookupProcessOrder_.assign(lookupProcessNames.size(), 0);
0285     if (!lookupProcessOrder_.empty()) {
0286       auto iter = std::find(lookupProcessNames.begin(), lookupProcessNames.end(), processNameOfBlock);
0287       if (iter != lookupProcessNames.end()) {
0288         lookupProcessOrder_[0] = iter - lookupProcessNames.begin();
0289       }
0290     }
0291   }
0292 
0293   ProductResolverBase* Principal::getExistingProduct(BranchID const& branchID) {
0294     return const_cast<ProductResolverBase*>(const_cast<const Principal*>(this)->getExistingProduct(branchID));
0295   }
0296 
0297   ProductResolverBase const* Principal::getExistingProduct(BranchID const& branchID) const {
0298     ProductResolverIndex index = preg_->indexFrom(branchID);
0299     assert(index != ProductResolverIndexInvalid);
0300     return productResolvers_.at(index).get();
0301   }
0302 
0303   ProductResolverBase const* Principal::getExistingProduct(ProductResolverBase const& productResolver) const {
0304     auto phb = getExistingProduct(productResolver.productDescription().branchID());
0305     if (nullptr != phb && BranchKey(productResolver.productDescription()) != BranchKey(phb->productDescription())) {
0306       ProductDescription const& newProduct = phb->productDescription();
0307       ProductDescription const& existing = productResolver.productDescription();
0308       if (newProduct.branchName() != existing.branchName() && newProduct.branchID() == existing.branchID()) {
0309         throw cms::Exception("HashCollision")
0310             << "Principal::getExistingProduct\n"
0311             << " Branch " << newProduct.branchName() << " has same branch ID as branch " << existing.branchName()
0312             << "\n"
0313             << "Workaround: change process name or product instance name of " << newProduct.branchName() << "\n";
0314       } else {
0315         assert(nullptr == phb ||
0316                BranchKey(productResolver.productDescription()) == BranchKey(phb->productDescription()));
0317       }
0318     }
0319     return phb;
0320   }
0321 
0322   std::vector<ProductDescription const*> Principal::productDescriptions() const {
0323     std::vector<ProductDescription const*> retValue;
0324     for (auto const& p : productRegistry().productList()) {
0325       if (p.second.branchType() == branchType()) {
0326         retValue.push_back(&p.second);
0327       }
0328     }
0329     return retValue;
0330   }
0331 
0332   void Principal::addProduct_(std::unique_ptr<ProductResolverBase> productResolver) {
0333     ProductDescription const& bd = productResolver->productDescription();
0334     assert(!bd.className().empty());
0335     assert(!bd.friendlyClassName().empty());
0336     assert(!bd.moduleLabel().empty());
0337     assert(!bd.processName().empty());
0338     SharedProductPtr phb(productResolver.release());
0339 
0340     ProductResolverIndex index = preg_->indexFrom(bd.branchID());
0341     assert(index != ProductResolverIndexInvalid);
0342     productResolvers_[index] = phb;
0343   }
0344 
0345   void Principal::addProductOrThrow(std::unique_ptr<ProductResolverBase> productResolver) {
0346     ProductResolverBase const* phb = getExistingProduct(*productResolver);
0347     if (phb != nullptr) {
0348       ProductDescription const& bd = productResolver->productDescription();
0349       throw Exception(errors::InsertFailure, "AlreadyPresent")
0350           << "addProductOrThrow: Problem found while adding product, "
0351           << "product already exists for (" << bd.friendlyClassName() << "," << bd.moduleLabel() << ","
0352           << bd.productInstanceName() << "," << bd.processName() << ")\n";
0353     }
0354     addProduct_(std::move(productResolver));
0355   }
0356 
0357   Principal::ConstProductResolverPtr Principal::getProductResolver(BranchID const& bid) const {
0358     ProductResolverIndex index = preg_->indexFrom(bid);
0359     if (index == ProductResolverIndexInvalid) {
0360       return ConstProductResolverPtr();
0361     }
0362     return getProductResolverByIndex(index);
0363   }
0364 
0365   Principal::ConstProductResolverPtr Principal::getProductResolverByIndex(
0366       ProductResolverIndex const& index) const noexcept {
0367     assert(index < productResolvers_.size());
0368     ConstProductResolverPtr const phb = productResolvers_[index].get();
0369     return phb;
0370   }
0371 
0372   unsigned int Principal::processBlockIndex(std::string const&) const {
0373     throw Exception(errors::LogicError) << "Principal::processBlockIndex not implemented for this type of Principal";
0374   }
0375 
0376   BasicHandle Principal::getByLabel(KindOfType kindOfType,
0377                                     TypeID const& typeID,
0378                                     InputTag const& inputTag,
0379                                     EDConsumerBase const* consumer,
0380                                     SharedResourcesAcquirer* sra,
0381                                     ModuleCallingContext const* mcc) const {
0382     // Not implemented for ProcessBlocks, it might work though, not tested
0383     // The other getByLabel function is used for ProcessBlocks by TestProcessor
0384     assert(branchType_ != InProcess);
0385 
0386     ProductData const* result = findProductByLabel(kindOfType, typeID, inputTag, consumer, sra, mcc);
0387     if (result == nullptr) {
0388       return BasicHandle(makeHandleExceptionFactory([=, this]() -> std::shared_ptr<cms::Exception> {
0389         return makeNotFoundException(
0390             "getByLabel",
0391             kindOfType,
0392             typeID,
0393             inputTag.label(),
0394             inputTag.instance(),
0395             appendCurrentProcessIfAlias(inputTag.process(), processConfiguration_->processName()));
0396       }));
0397     }
0398     return BasicHandle(result->wrapper(), &(result->provenance()));
0399   }
0400 
0401   BasicHandle Principal::getByLabel(KindOfType kindOfType,
0402                                     TypeID const& typeID,
0403                                     std::string const& label,
0404                                     std::string const& instance,
0405                                     std::string const& process,
0406                                     EDConsumerBase const* consumer,
0407                                     SharedResourcesAcquirer* sra,
0408                                     ModuleCallingContext const* mcc) const {
0409     ProductData const* result = findProductByLabel(kindOfType, typeID, label, instance, process, consumer, sra, mcc);
0410     if (result == nullptr) {
0411       return BasicHandle(makeHandleExceptionFactory([=]() -> std::shared_ptr<cms::Exception> {
0412         return makeNotFoundException("getByLabel", kindOfType, typeID, label, instance, process);
0413       }));
0414     }
0415     return BasicHandle(result->wrapper(), &(result->provenance()));
0416   }
0417 
0418   BasicHandle Principal::getByToken(KindOfType,
0419                                     TypeID const&,
0420                                     ProductResolverIndex index,
0421                                     bool skipCurrentProcess,
0422                                     bool& ambiguous,
0423                                     SharedResourcesAcquirer* sra,
0424                                     ModuleCallingContext const* mcc) const {
0425     assert(index != ProductResolverIndexInvalid);
0426     auto& productResolver = productResolvers_[index];
0427     assert(nullptr != productResolver.get());
0428     auto resolution = productResolver->resolveProduct(*this, skipCurrentProcess, sra, mcc);
0429     if (resolution.isAmbiguous()) {
0430       ambiguous = true;
0431       //The caller is looking explicitly for this case
0432       // and uses the extra data at the caller to setup the exception
0433       return BasicHandle::makeInvalid();
0434     }
0435     auto productData = resolution.data();
0436     if (productData == nullptr) {
0437       //The caller is looking explicitly for this case
0438       // and uses the extra data at the caller to setup the exception
0439       return BasicHandle::makeInvalid();
0440     }
0441     return BasicHandle(productData->wrapper(), &(productData->provenance()));
0442   }
0443 
0444   void Principal::prefetchAsync(WaitingTaskHolder task,
0445                                 ProductResolverIndex index,
0446                                 bool skipCurrentProcess,
0447                                 ServiceToken const& token,
0448                                 ModuleCallingContext const* mcc) const {
0449     auto const& productResolver = productResolvers_.at(index);
0450     assert(nullptr != productResolver.get());
0451     productResolver->prefetchAsync(task, *this, skipCurrentProcess, token, nullptr, mcc);
0452   }
0453 
0454   ProductData const* Principal::findProductByLabel(KindOfType kindOfType,
0455                                                    TypeID const& typeID,
0456                                                    InputTag const& inputTag,
0457                                                    EDConsumerBase const* consumer,
0458                                                    SharedResourcesAcquirer* sra,
0459                                                    ModuleCallingContext const* mcc) const {
0460     bool skipCurrentProcess = inputTag.willSkipCurrentProcess();
0461 
0462     ProductResolverIndex index = inputTag.indexFor(typeID, branchType(), &productRegistry());
0463 
0464     if (index == ProductResolverIndexInvalid) {
0465       char const* processName = inputTag.process().c_str();
0466       if (skipCurrentProcess) {
0467         processName = "\0";
0468       } else if (inputTag.process() == InputTag::kCurrentProcess) {
0469         processName = processConfiguration_->processName().c_str();
0470       }
0471 
0472       index =
0473           productLookup().index(kindOfType, typeID, inputTag.label().c_str(), inputTag.instance().c_str(), processName);
0474 
0475       if (index == ProductResolverIndexAmbiguous) {
0476         throwAmbiguousException("findProductByLabel",
0477                                 typeID,
0478                                 inputTag.label(),
0479                                 inputTag.instance(),
0480                                 appendCurrentProcessIfAlias(inputTag.process(), processConfiguration_->processName()));
0481       } else if (index == ProductResolverIndexInvalid) {
0482         // can occur because of missing consumes if nothing else in the process consumes the product
0483         for (auto const& item : preg_->productList()) {
0484           auto const& bd = item.second;
0485           if (bd.present() and bd.unwrappedTypeID() == typeID and bd.moduleLabel() == inputTag.label() and
0486               bd.productInstanceName() == inputTag.instance()) {
0487             bool const inCurrentProcess = bd.processName() == processConfiguration_->processName();
0488             if (inputTag.process().empty() or bd.processName() == inputTag.process() or
0489                 (skipCurrentProcess and not inCurrentProcess) or
0490                 (inputTag.process() == InputTag::kCurrentProcess and inCurrentProcess)) {
0491               failedToRegisterConsumes(
0492                   kindOfType,
0493                   typeID,
0494                   inputTag.label(),
0495                   inputTag.instance(),
0496                   appendCurrentProcessIfAlias(inputTag.process(), processConfiguration_->processName()));
0497             }
0498           }
0499         }
0500         return nullptr;
0501       }
0502       inputTag.tryToCacheIndex(index, typeID, branchType(), &productRegistry());
0503     }
0504     if (UNLIKELY(consumer and (not consumer->registeredToConsume(index, skipCurrentProcess, branchType())))) {
0505       failedToRegisterConsumes(kindOfType,
0506                                typeID,
0507                                inputTag.label(),
0508                                inputTag.instance(),
0509                                appendCurrentProcessIfAlias(inputTag.process(), processConfiguration_->processName()));
0510     }
0511 
0512     auto const& productResolver = productResolvers_[index];
0513 
0514     auto resolution = productResolver->resolveProduct(*this, skipCurrentProcess, sra, mcc);
0515     if (resolution.isAmbiguous()) {
0516       throwAmbiguousException("findProductByLabel",
0517                               typeID,
0518                               inputTag.label(),
0519                               inputTag.instance(),
0520                               appendCurrentProcessIfAlias(inputTag.process(), processConfiguration_->processName()));
0521     }
0522     return resolution.data();
0523   }
0524 
0525   ProductData const* Principal::findProductByLabel(KindOfType kindOfType,
0526                                                    TypeID const& typeID,
0527                                                    std::string const& label,
0528                                                    std::string const& instance,
0529                                                    std::string const& process,
0530                                                    EDConsumerBase const* consumer,
0531                                                    SharedResourcesAcquirer* sra,
0532                                                    ModuleCallingContext const* mcc) const {
0533     ProductResolverIndex index =
0534         productLookup().index(kindOfType, typeID, label.c_str(), instance.c_str(), process.c_str());
0535 
0536     if (index == ProductResolverIndexAmbiguous) {
0537       throwAmbiguousException("findProductByLabel", typeID, label, instance, process);
0538     } else if (index == ProductResolverIndexInvalid) {
0539       // can occur because of missing consumes if nothing else in the process consumes the product
0540       for (auto const& item : preg_->productList()) {
0541         auto const& bd = item.second;
0542         if (bd.present() and bd.unwrappedTypeID() == typeID and bd.moduleLabel() == label and
0543             bd.productInstanceName() == instance) {
0544           if (process.empty() or bd.processName() == process) {
0545             failedToRegisterConsumes(kindOfType, typeID, label, instance, process);
0546           }
0547         }
0548       }
0549       return nullptr;
0550     }
0551 
0552     if (UNLIKELY(consumer and (not consumer->registeredToConsume(index, false, branchType())))) {
0553       failedToRegisterConsumes(kindOfType, typeID, label, instance, process);
0554     }
0555 
0556     auto const& productResolver = productResolvers_[index];
0557 
0558     auto resolution = productResolver->resolveProduct(*this, false, sra, mcc);
0559     if (resolution.isAmbiguous()) {
0560       throwAmbiguousException("findProductByLabel", typeID, label, instance, process);
0561     }
0562     return resolution.data();
0563   }
0564 
0565   ProductData const* Principal::findProductByTag(TypeID const& typeID,
0566                                                  InputTag const& tag,
0567                                                  ModuleCallingContext const* mcc) const {
0568     // Not implemented for ProcessBlocks
0569     assert(branchType_ != InProcess);
0570 
0571     ProductData const* productData = findProductByLabel(PRODUCT_TYPE, typeID, tag, nullptr, nullptr, mcc);
0572     return productData;
0573   }
0574 
0575   Provenance const& Principal::getProvenance(BranchID const& bid) const {
0576     ConstProductResolverPtr const phb = getProductResolver(bid);
0577     if (phb == nullptr) {
0578       throwProductNotFoundException("getProvenance", errors::ProductNotFound, bid);
0579     }
0580 
0581     if (phb->unscheduledWasNotRun()) {
0582       throw edm::Exception(errors::UnimplementedFeature)
0583           << "Requesting provenance from unrun EDProducer. The requested branch ID was: " << bid;
0584     }
0585     return *phb->provenance();
0586   }
0587 
0588   StableProvenance const& Principal::getStableProvenance(BranchID const& bid) const {
0589     ConstProductResolverPtr const phb = getProductResolver(bid);
0590     if (phb == nullptr) {
0591       throwProductNotFoundException("getStableProvenance", errors::ProductNotFound, bid);
0592     }
0593     //NOTE: in all implementations, this never returns a nullptr
0594     return *phb->stableProvenance();
0595   }
0596 
0597   // This one is mostly for test printout purposes
0598   // No attempt to trigger on demand execution
0599   // Skips provenance when the EDProduct is not there
0600   void Principal::getAllProvenance(std::vector<Provenance const*>& provenances) const {
0601     provenances.clear();
0602     for (auto const& productResolver : *this) {
0603       if (productResolver->singleProduct() && productResolver->provenanceAvailable() &&
0604           !productResolver->productDescription().isAnyAlias()) {
0605         // We do not attempt to get the event/lumi/run status from the provenance,
0606         // because the per event provenance may have been dropped.
0607         if (productResolver->provenance()->productDescription().present()) {
0608           provenances.push_back(productResolver->provenance());
0609         }
0610       }
0611     }
0612   }
0613 
0614   // This one is also mostly for test printout purposes
0615   // No attempt to trigger on demand execution
0616   // Skips provenance for dropped branches.
0617   void Principal::getAllStableProvenance(std::vector<StableProvenance const*>& provenances) const {
0618     provenances.clear();
0619     for (auto const& productResolver : *this) {
0620       if (productResolver->singleProduct() && !productResolver->productDescription().isAnyAlias()) {
0621         if (productResolver->stableProvenance()->productDescription().present()) {
0622           provenances.push_back(productResolver->stableProvenance());
0623         }
0624       }
0625     }
0626   }
0627 
0628   void Principal::recombine(Principal& other, std::vector<BranchID> const& bids) {
0629     for (auto& prod : bids) {
0630       ProductResolverIndex index = preg_->indexFrom(prod);
0631       assert(index != ProductResolverIndexInvalid);
0632       ProductResolverIndex indexO = other.preg_->indexFrom(prod);
0633       assert(indexO != ProductResolverIndexInvalid);
0634       get_underlying_safe(productResolvers_[index]).swap(get_underlying_safe(other.productResolvers_[indexO]));
0635     }
0636     reader_->mergeReaders(other.reader());
0637   }
0638 
0639   WrapperBase const* Principal::getIt(ProductID const&) const {
0640     assert(false);
0641     return nullptr;
0642   }
0643 
0644   std::optional<std::tuple<WrapperBase const*, unsigned int>> Principal::getThinnedProduct(ProductID const&,
0645                                                                                            unsigned int) const {
0646     assert(false);
0647     return std::nullopt;
0648   }
0649 
0650   void Principal::getThinnedProducts(ProductID const&,
0651                                      std::vector<WrapperBase const*>&,
0652                                      std::vector<unsigned int>&) const {
0653     assert(false);
0654   }
0655 
0656   OptionalThinnedKey Principal::getThinnedKeyFrom(ProductID const&, unsigned int, ProductID const&) const {
0657     assert(false);
0658     return std::monostate{};
0659   }
0660 
0661   void Principal::put_(std::unique_ptr<WrapperBase> prod, ProductResolverBase const* phb) const {
0662     dynamic_cast<ProductPutterBase const*>(phb)->putProduct(std::move(prod));
0663   }
0664 
0665   void Principal::put_(ProductDescription const& bd, std::unique_ptr<WrapperBase> edp) const {
0666     if (edp.get() == nullptr) {
0667       throw edm::Exception(edm::errors::InsertFailure, "Null Pointer")
0668           << "put: Cannot put because unique_ptr to product is null."
0669           << "\n";
0670     }
0671     auto phb = getExistingProduct(bd.branchID());
0672     assert(phb);
0673     // ProductResolver assumes ownership
0674     put_(std::move(edp), phb);
0675   }
0676 
0677   void Principal::adjustIndexesAfterProductRegistryAddition() {
0678     if (preg_->getNextIndexValue(branchType_) != productResolvers_.size()) {
0679       bool changed = false;
0680       productResolvers_.resize(preg_->getNextIndexValue(branchType_));
0681       for (auto const& prod : preg_->productList()) {
0682         ProductDescription const& bd = prod.second;
0683         if (bd.branchType() == branchType_) {
0684           ProductResolverIndex index = preg_->indexFrom(bd.branchID());
0685           assert(index != ProductResolverIndexInvalid);
0686           if (!productResolvers_[index]) {
0687             // no product holder.  Must add one. The new entry must be an input product holder.
0688             assert(!bd.produced());
0689             assert(bd.dropped());
0690             //adding the resolver allows access to the provenance for the data product
0691             addDroppedProduct(bd);
0692             changed = true;
0693           }
0694         }
0695       }
0696       if (changed) {
0697         changedIndexes_();
0698       }
0699     }
0700     assert(preg_->getNextIndexValue(branchType_) == productResolvers_.size());
0701   }
0702 
0703   void Principal::readAllFromSourceAndMergeImmediately(MergeableRunProductMetadata const* mergeableRunProductMetadata) {
0704     if (not reader()) {
0705       return;
0706     }
0707 
0708     for (auto& prod : *this) {
0709       prod->retrieveAndMerge(*this, mergeableRunProductMetadata);
0710     }
0711   }
0712 }  // namespace edm