Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2025-05-23 23:48:33

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