CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_5_3_1/src/FWCore/Framework/src/Principal.cc

Go to the documentation of this file.
00001 
00004 #include "FWCore/Framework/interface/Principal.h"
00005 
00006 #include "DataFormats/Provenance/interface/ProcessHistoryRegistry.h"
00007 #include "DataFormats/Provenance/interface/ProductRegistry.h"
00008 #include "FWCore/Framework/interface/DelayedReader.h"
00009 #include "FWCore/Framework/interface/HistoryAppender.h"
00010 #include "FWCore/Framework/interface/Selector.h"
00011 #include "FWCore/Framework/interface/ProductDeletedException.h"
00012 #include "FWCore/Utilities/interface/Algorithms.h"
00013 #include "FWCore/Utilities/interface/EDMException.h"
00014 #include "FWCore/Utilities/interface/ReflexTools.h"
00015 #include "FWCore/Utilities/interface/WrappedClassName.h"
00016 
00017 #include <algorithm>
00018 #include <cstring>
00019 #include <limits>
00020 #include <sstream>
00021 #include <stdexcept>
00022 
00023 //using boost::lambda::_1;
00024 
00025 namespace edm {
00026 
00027   ProcessHistory Principal::emptyProcessHistory_;
00028 
00029   static
00030   void
00031   maybeThrowMissingDictionaryException(TypeID const& productType, bool isElement, std::vector<std::string> const& missingDictionaries) {
00032     if(binary_search_all(missingDictionaries, productType.className())) {
00033       checkDictionaries(isElement ? productType.className() : wrappedClassName(productType.className()), false);
00034       throwMissingDictionariesException();
00035     }
00036   }
00037 
00038   static
00039   void
00040   throwMultiFoundException(char const* where, int nFound, TypeID const& productType) {
00041     throw Exception(errors::ProductNotFound)
00042       << "Principal::" << where << ": Found " << nFound << " products rather than one which match all criteria\n"
00043       << "Looking for type: " << productType << "\n";
00044   }
00045 
00046   static
00047   void
00048   throwGroupNotFoundException(char const* where, errors::ErrorCodes error, BranchID const& bid) {
00049     throw Exception(error, "InvalidID")
00050       << "Principal::" << where << ": no product with given branch id: "<< bid << "\n";
00051   }
00052 
00053   static
00054   void
00055   throwCorruptionException(char const* where, std::string const& branchName) {
00056     throw Exception(errors::EventCorruption)
00057        << "Principal::" << where <<": Product on branch " << branchName << " occurs twice in the same event.\n";
00058   }
00059 
00060   static
00061   boost::shared_ptr<cms::Exception>
00062   makeNotFoundException(char const* where, TypeID const& productType) {
00063     boost::shared_ptr<cms::Exception> exception(new Exception(errors::ProductNotFound));
00064     *exception << "Principal::" << where << ": Found zero products matching all criteria\nLooking for type: " << productType << "\n";
00065     return exception;
00066   }
00067 
00068   static
00069   boost::shared_ptr<cms::Exception>
00070   makeNotFoundException(char const* where, TypeID const& productType, std::string const& label, std::string const& instance, std::string const& process) {
00071     boost::shared_ptr<cms::Exception> exception(new Exception(errors::ProductNotFound));
00072     *exception << "Principal::" << where << ": Found zero products matching all criteria\nLooking for type: " << productType << "\n"
00073                << "Looking for module label: " << label << "\n" << "Looking for productInstanceName: " << instance << "\n"
00074                << (process.empty() ? "" : "Looking for process: ") << process << "\n";
00075     return exception;
00076   }
00077 
00078   static
00079   void
00080   throwProductDeletedException(const char* where, TypeID const& productType,std::string const& label, std::string const& instance, std::string const& process) {
00081     boost::shared_ptr<cms::Exception> exception(new ProductDeletedException());
00082     *exception << "Principal::" << where << ": The product matching all criteria\nLooking for type: " << productType << "\n"
00083     << "Looking for module label: " << label << "\n" << "Looking for productInstanceName: " << instance << "\n"
00084     << (process.empty() ? "" : "Looking for process: ") << process << "\n"
00085     << "Was already deleted. This means there is a configuration error.\nThe module which is asking for this data must be configured to state that it will read this data.";
00086     throw exception;
00087     
00088   }
00089 
00090   
00091   static
00092   void
00093   throwNotFoundException(char const* where, TypeID const& productType, InputTag const& tag) {
00094     boost::shared_ptr<cms::Exception> exception = makeNotFoundException(where, productType, tag.label(), tag.instance(), tag.process());
00095     throw *exception;
00096   }
00097   
00098 
00099   Principal::Principal(boost::shared_ptr<ProductRegistry const> reg,
00100                        ProcessConfiguration const& pc,
00101                        BranchType bt,
00102                        HistoryAppender* historyAppender) :
00103     EDProductGetter(),
00104     processHistoryPtr_(0),
00105     processHistoryID_(),
00106     processConfiguration_(&pc),
00107     groups_(reg->constProductList().size(), SharedGroupPtr()),
00108     preg_(reg),
00109     reader_(),
00110     productPtrs_(),
00111     branchType_(bt),
00112     historyAppender_(historyAppender) {
00113 
00114     //Now that these have been set, we can create the list of Branches we need.
00115     std::string const source("source");
00116     ProductRegistry::ProductList const& prodsList = reg->productList();
00117     for(ProductRegistry::ProductList::const_iterator itProdInfo = prodsList.begin(),
00118           itProdInfoEnd = prodsList.end();
00119         itProdInfo != itProdInfoEnd;
00120         ++itProdInfo) {
00121       if(itProdInfo->second.branchType() == branchType_) {
00122         boost::shared_ptr<ConstBranchDescription> bd(new ConstBranchDescription(itProdInfo->second));
00123         if(bd->produced()) {
00124           if(bd->moduleLabel() == source) {
00125             addGroupSource(bd);
00126           } else if(bd->onDemand()) {
00127             assert(bt == InEvent);
00128             addOnDemandGroup(bd);
00129           } else {
00130             addGroupScheduled(bd);
00131           }
00132         } else {
00133           addGroupInput(bd);
00134         }
00135       }
00136     }
00137   }
00138 
00139   Principal::~Principal() {
00140   }
00141 
00142   // Number of products in the Principal.
00143   // For products in an input file and not yet read in due to delayed read,
00144   // this routine assumes a real product is there.
00145   size_t
00146   Principal::size() const {
00147     size_t size = 0U;
00148     for(const_iterator it = this->begin(), itEnd = this->end(); it != itEnd; ++it) {
00149       Group const& g = **it;
00150       if(!g.productUnavailable() && !g.onDemand() && !g.branchDescription().dropped()) {
00151         ++size;
00152       }
00153     }
00154     return size;
00155   }
00156 
00157   //adjust provenance for input groups after new input file has been merged
00158   bool
00159   Principal::adjustToNewProductRegistry(ProductRegistry const& reg) {
00160     if(reg.constProductList().size() > groups_.size()) {
00161       return false;
00162     }
00163     ProductRegistry::ProductList const& prodsList = reg.productList();
00164     for(ProductRegistry::ProductList::const_iterator itProdInfo = prodsList.begin(),
00165           itProdInfoEnd = prodsList.end();
00166         itProdInfo != itProdInfoEnd;
00167         ++itProdInfo) {
00168     if(!itProdInfo->second.produced() && (itProdInfo->second.branchType() == branchType_)) {
00169         boost::shared_ptr<ConstBranchDescription> bd(new ConstBranchDescription(itProdInfo->second));
00170         Group *g = getExistingGroup(itProdInfo->second.branchID());
00171         if(g == 0 || g->branchDescription().branchName() != bd->branchName()) {
00172             return false;
00173         }
00174         g->resetBranchDescription(bd);
00175       }
00176     }
00177     return true;
00178   }
00179 
00180   void
00181   Principal::addGroupScheduled(boost::shared_ptr<ConstBranchDescription> bd) {
00182     std::auto_ptr<Group> g(new ScheduledGroup(bd));
00183     addGroupOrThrow(g);
00184   }
00185 
00186   void
00187   Principal::addGroupSource(boost::shared_ptr<ConstBranchDescription> bd) {
00188     std::auto_ptr<Group> g(new SourceGroup(bd));
00189     addGroupOrThrow(g);
00190   }
00191 
00192   void
00193   Principal::addGroupInput(boost::shared_ptr<ConstBranchDescription> bd) {
00194     std::auto_ptr<Group> g(new InputGroup(bd));
00195     addGroupOrThrow(g);
00196   }
00197 
00198   void
00199   Principal::addOnDemandGroup(boost::shared_ptr<ConstBranchDescription> bd) {
00200     std::auto_ptr<Group> g(new UnscheduledGroup(bd));
00201     addGroupOrThrow(g);
00202   }
00203 
00204   // "Zero" the principal so it can be reused for another Event.
00205   void
00206   Principal::clearPrincipal() {
00207     processHistoryPtr_ = 0;
00208     processHistoryID_ = ProcessHistoryID();
00209     reader_ = 0;
00210     for (Principal::const_iterator i = begin(), iEnd = end(); i != iEnd; ++i) {
00211       (*i)->resetProductData();
00212     }
00213     productPtrs_.clear();
00214   }
00215 
00216   void
00217   Principal::deleteProduct(BranchID const& id) {
00218     Group* g = getExistingGroup(id);
00219     assert(0!=g);
00220     auto itFound = productPtrs_.find(g->product().get());
00221     if(itFound != productPtrs_.end()) {
00222       productPtrs_.erase(itFound);
00223     } 
00224     g->deleteProduct();
00225   }
00226   
00227   // Set the principal for the Event, Lumi, or Run.
00228   void
00229   Principal::fillPrincipal(ProcessHistoryID const& hist, DelayedReader* reader) {
00230     if(reader) {
00231       reader_ = reader;
00232     }
00233 
00234     ProcessHistory const* inputProcessHistory = 0;
00235     if (historyAppender_ && productRegistry().anyProductProduced()) {
00236       CachedHistory const& cachedHistory = 
00237         historyAppender_->appendToProcessHistory(hist,
00238                                                 *processConfiguration_);
00239       processHistoryPtr_ = cachedHistory.processHistory();
00240       processHistoryID_ = cachedHistory.processHistoryID();
00241       inputProcessHistory = cachedHistory.inputProcessHistory();
00242     }
00243     else {
00244       if (hist.isValid()) {
00245         ProcessHistoryRegistry* registry = ProcessHistoryRegistry::instance();
00246         inputProcessHistory = registry->getMapped(hist);
00247         if (inputProcessHistory == 0) {
00248           throw Exception(errors::LogicError)
00249             << "Principal::fillPrincipal\n"
00250             << "Input ProcessHistory not found in registry\n"
00251             << "Contact a Framework developer\n";
00252         }
00253       } else {
00254         inputProcessHistory = &emptyProcessHistory_;
00255       }
00256       processHistoryID_ = hist;
00257       processHistoryPtr_ = inputProcessHistory;        
00258     }
00259 
00260     preg_->productLookup().reorderIfNecessary(branchType_, *inputProcessHistory,
00261                                          processConfiguration_->processName());
00262     preg_->elementLookup().reorderIfNecessary(branchType_, *inputProcessHistory,
00263                                          processConfiguration_->processName());
00264   }
00265 
00266   Group*
00267   Principal::getExistingGroup(BranchID const& branchID) {
00268     ProductTransientIndex index = preg_->indexFrom(branchID);
00269     assert(index != ProductRegistry::kInvalidIndex);
00270     SharedGroupPtr ptr = groups_.at(index);
00271     return ptr.get();
00272   }
00273 
00274   Group*
00275   Principal::getExistingGroup(Group const& group) {
00276     Group* g = getExistingGroup(group.branchDescription().branchID());
00277     assert(0 == g || BranchKey(group.branchDescription()) == BranchKey(g->branchDescription()));
00278     return g;
00279   }
00280 
00281   void
00282   Principal::addGroup_(std::auto_ptr<Group> group) {
00283     ConstBranchDescription const& bd = group->branchDescription();
00284     assert (!bd.className().empty());
00285     assert (!bd.friendlyClassName().empty());
00286     assert (!bd.moduleLabel().empty());
00287     assert (!bd.processName().empty());
00288     SharedGroupPtr g(group);
00289 
00290     ProductTransientIndex index = preg_->indexFrom(bd.branchID());
00291     assert(index != ProductRegistry::kInvalidIndex);
00292     groups_[index] = g;
00293   }
00294 
00295   void
00296   Principal::addGroupOrThrow(std::auto_ptr<Group> group) {
00297     Group const* g = getExistingGroup(*group);
00298     if(g != 0) {
00299       ConstBranchDescription const& bd = group->branchDescription();
00300       throw Exception(errors::InsertFailure, "AlreadyPresent")
00301           << "addGroupOrThrow: Problem found while adding product, "
00302           << "product already exists for ("
00303           << bd.friendlyClassName() << ","
00304           << bd.moduleLabel() << ","
00305           << bd.productInstanceName() << ","
00306           << bd.processName()
00307           << ")\n";
00308     }
00309     addGroup_(group);
00310   }
00311 
00312   Principal::ConstGroupPtr
00313   Principal::getGroup(BranchID const& bid, bool resolveProd, bool fillOnDemand) const {
00314     ProductTransientIndex index = preg_->indexFrom(bid);
00315     if(index == ProductRegistry::kInvalidIndex){
00316        return ConstGroupPtr();
00317     }
00318     return getGroupByIndex(index, resolveProd, fillOnDemand);
00319   }
00320 
00321   Principal::ConstGroupPtr
00322   Principal::getGroupByIndex(ProductTransientIndex const& index, bool resolveProd, bool fillOnDemand) const {
00323 
00324     ConstGroupPtr const g = groups_[index].get();
00325     if(0 == g) {
00326       return g;
00327     }
00328     if(resolveProd && !g->productUnavailable()) {
00329       this->resolveProduct(*g, fillOnDemand);
00330     }
00331     return g;
00332   }
00333 
00334   BasicHandle
00335   Principal::getBySelector(TypeID const& productType,
00336                            SelectorBase const& sel) const {
00337     BasicHandle result;
00338 
00339     int nFound = findGroup(productType,
00340                            preg_->productLookup(),
00341                            sel,
00342                            result);
00343 
00344     if(nFound == 0) {
00345       boost::shared_ptr<cms::Exception> whyFailed = makeNotFoundException("getBySelector", productType);
00346       return BasicHandle(whyFailed);
00347     }
00348     if(nFound > 1) {
00349       throwMultiFoundException("getBySelector", nFound, productType);
00350     }
00351     return result;
00352   }
00353 
00354   BasicHandle
00355   Principal::getByLabel(TypeID const& productType,
00356                         std::string const& label,
00357                         std::string const& productInstanceName,
00358                         std::string const& processName,
00359                         size_t& cachedOffset,
00360                         int& fillCount) const {
00361 
00362     ProductData const* result = findGroupByLabel(productType,
00363                                                  preg_->productLookup(),
00364                                                  label,
00365                                                  productInstanceName,
00366                                                  processName,
00367                                                  cachedOffset,
00368                                                  fillCount);
00369 
00370     if(result == 0) {
00371       boost::shared_ptr<cms::Exception> whyFailed = makeNotFoundException("getByLabel", productType, label, productInstanceName, processName);
00372       return BasicHandle(whyFailed);
00373     }
00374     return BasicHandle(*result);
00375   }
00376 
00377 
00378   void
00379   Principal::getMany(TypeID const& productType,
00380                      SelectorBase const& sel,
00381                      BasicHandleVec& results) const {
00382 
00383     findGroups(productType,
00384                preg_->productLookup(),
00385                sel,
00386                results);
00387 
00388     return;
00389   }
00390 
00391   BasicHandle
00392   Principal::getByType(TypeID const& productType) const {
00393 
00394     BasicHandle result;
00395     MatchAllSelector sel;
00396 
00397     int nFound = findGroup(productType,
00398                            preg_->productLookup(),
00399                            sel,
00400                            result);
00401 
00402     if(nFound == 0) {
00403       boost::shared_ptr<cms::Exception> whyFailed = makeNotFoundException("getByType", productType);
00404       return BasicHandle(whyFailed);
00405     }
00406 
00407     if(nFound > 1) {
00408       throwMultiFoundException("getByType", nFound, productType);
00409     }
00410     return result;
00411   }
00412 
00413   void
00414   Principal::getManyByType(TypeID const& productType,
00415                            BasicHandleVec& results) const {
00416 
00417     MatchAllSelector sel;
00418 
00419     findGroups(productType,
00420                preg_->productLookup(),
00421                sel,
00422                results);
00423     return;
00424   }
00425 
00426   size_t
00427   Principal::getMatchingSequence(TypeID const& typeID,
00428                                  SelectorBase const& selector,
00429                                  BasicHandle& result) const {
00430 
00431     // One new argument is the element lookup container
00432     // Otherwise this just passes through the arguments to findGroup
00433     return findGroup(typeID,
00434                      preg_->elementLookup(),
00435                      selector,
00436                      result);
00437   }
00438 
00439   size_t
00440   Principal::findGroups(TypeID const& typeID,
00441                         TransientProductLookupMap const& typeLookup,
00442                         SelectorBase const& selector,
00443                         BasicHandleVec& results) const {
00444     assert(results.empty());
00445 
00446     typedef TransientProductLookupMap TypeLookup;
00447     // A class without a dictionary cannot be in an Event/Lumi/Run.
00448     // First, we check if the class has a dictionary.  If it does not, we throw an exception.
00449     // The missing dictionary might be for the class itself, the wrapped class, or a component of the class.
00450     std::pair<TypeLookup::const_iterator, TypeLookup::const_iterator> const range = typeLookup.equal_range(TypeInBranchType(typeID, branchType_));
00451     if(range.first == range.second) {
00452       maybeThrowMissingDictionaryException(typeID, &typeLookup == &preg_->elementLookup(), preg_->missingDictionaries());
00453     }
00454 
00455     results.reserve(range.second - range.first);
00456 
00457     for(TypeLookup::const_iterator it = range.first; it != range.second; ++it) {
00458 
00459       if(selector.match(*(it->branchDescription()))) {
00460 
00461         //now see if the data is actually available
00462         ConstGroupPtr const& group = getGroupByIndex(it->index(), false, false);
00463         //NOTE sometimes 'group->productUnavailable()' is true if was already deleted
00464         if(group && group->productWasDeleted()) {
00465           throwProductDeletedException("findGroups",
00466                                        typeID,
00467                                        it->branchDescription()->moduleLabel(),
00468                                        it->branchDescription()->productInstanceName(),
00469                                        it->branchDescription()->processName());
00470         }
00471 
00472         // Skip product if not available.
00473         if(group && !group->productUnavailable()) {
00474 
00475           this->resolveProduct(*group, true);
00476           // If the product is a dummy filler, group will now be marked unavailable.
00477           // Unscheduled execution can fail to produce the EDProduct so check
00478           if(group->product() && !group->productUnavailable() && !group->onDemand()) {
00479             // Found a good match, save it
00480             BasicHandle bh(group->productData());
00481             results.push_back(bh);
00482           }
00483         }
00484       }
00485     }
00486     return results.size();
00487   }
00488 
00489   size_t
00490   Principal::findGroup(TypeID const& typeID,
00491                        TransientProductLookupMap const& typeLookup,
00492                        SelectorBase const& selector,
00493                        BasicHandle& result) const {
00494     assert(!result.isValid());
00495 
00496     size_t count = 0U;
00497 
00498     typedef TransientProductLookupMap TypeLookup;
00499     // A class without a dictionary cannot be in an Event/Lumi/Run.
00500     // First, we check if the class has a dictionary.  If it does not, we throw an exception.
00501     // The missing dictionary might be for the class itself, the wrapped class, or a component of the class.
00502     std::pair<TypeLookup::const_iterator, TypeLookup::const_iterator> const range = typeLookup.equal_range(TypeInBranchType(typeID, branchType_));
00503     if(range.first == range.second) {
00504       maybeThrowMissingDictionaryException(typeID, &typeLookup == &preg_->elementLookup(), preg_->missingDictionaries());
00505     }
00506 
00507     unsigned int processLevelFound = std::numeric_limits<unsigned int>::max();
00508     for(TypeLookup::const_iterator it = range.first; it != range.second; ++it) {
00509       if(it->processIndex() > processLevelFound) {
00510         //this is for a less recent process and we've already found a match for a more recent process
00511         continue;
00512       }
00513 
00514       if(selector.match(*(it->branchDescription()))) {
00515 
00516         //now see if the data is actually available
00517         ConstGroupPtr const& group = getGroupByIndex(it->index(), false, false);
00518         if(group && group->productWasDeleted()) {
00519           throwProductDeletedException("findGroup",
00520                                        typeID,
00521                                        it->branchDescription()->moduleLabel(),
00522                                        it->branchDescription()->productInstanceName(),
00523                                        it->branchDescription()->processName());
00524         }
00525 
00526         // Skip product if not available.
00527         if(group && !group->productUnavailable()) {
00528 
00529           this->resolveProduct(*group, true);
00530           // If the product is a dummy filler, group will now be marked unavailable.
00531           // Unscheduled execution can fail to produce the EDProduct so check
00532           if(group->product() && !group->productUnavailable() && !group->onDemand()) {
00533             if(it->processIndex() < processLevelFound) {
00534               processLevelFound = it->processIndex();
00535               count = 0U;
00536             }
00537             if(count == 0U) {
00538               // Found a unique (so far) match, save it
00539               result = BasicHandle(group->productData());
00540             }
00541             ++count;
00542           }
00543         }
00544       }
00545     }
00546     if(count != 1) result = BasicHandle();
00547     return count;
00548   }
00549 
00550   ProductData const*
00551   Principal::findGroupByLabel(TypeID const& typeID,
00552                               TransientProductLookupMap const& typeLookup,
00553                               std::string const& moduleLabel,
00554                               std::string const& productInstanceName,
00555                               std::string const& processName,
00556                               size_t& cachedOffset,
00557                               int& fillCount) const {
00558 
00559     typedef TransientProductLookupMap TypeLookup;
00560     bool isCached = (fillCount > 0 && fillCount == typeLookup.fillCount());
00561     bool toBeCached = (fillCount >= 0 && !isCached);
00562 
00563     std::pair<TypeLookup::const_iterator, TypeLookup::const_iterator> range =
00564         (isCached ? std::make_pair(typeLookup.begin() + cachedOffset, typeLookup.end()) : typeLookup.equal_range(TypeInBranchType(typeID, branchType_), moduleLabel, productInstanceName));
00565 
00566     if(toBeCached) {
00567       cachedOffset = range.first - typeLookup.begin();
00568       fillCount = typeLookup.fillCount();
00569     }
00570 
00571     if(range.first == range.second) {
00572       if(toBeCached) {
00573         cachedOffset = typeLookup.end() - typeLookup.begin();
00574       }
00575       // We check for a missing dictionary.  We do this only in this error leg.
00576       // A class without a dictionary cannot be in an Event/Lumi/Run.
00577       // We check if the class has a dictionary.  If it does not, we throw an exception.
00578       // The missing dictionary might be for the class itself, the wrapped class, or a component of the class.
00579       std::pair<TypeLookup::const_iterator, TypeLookup::const_iterator> const typeRange = typeLookup.equal_range(TypeInBranchType(typeID, branchType_));
00580       if(typeRange.first == typeRange.second) {
00581         maybeThrowMissingDictionaryException(typeID, &typeLookup == &preg_->elementLookup(), preg_->missingDictionaries());
00582       }
00583       return 0;
00584     }
00585 
00586     if(!processName.empty()) {
00587       if(isCached) {
00588         assert(processName == range.first->branchDescription()->processName());
00589         range.second = range.first + 1;
00590       } else if(toBeCached) {
00591         bool processFound = false;
00592         for(TypeLookup::const_iterator it = range.first; it != range.second; ++it) {
00593           if(it->isFirst() && it != range.first) {
00594             break;
00595           }
00596           if(processName == it->branchDescription()->processName()) {
00597             processFound = true;
00598             range.first = it;
00599             cachedOffset = range.first - typeLookup.begin();
00600             range.second = range.first + 1;
00601             break;
00602           }
00603         }
00604         if(!processFound) {
00605           cachedOffset = typeLookup.end() - typeLookup.begin();
00606           return 0;
00607         }
00608       } // end if(toBeCached)
00609     }
00610 
00611     for(TypeLookup::const_iterator it = range.first; it != range.second; ++it) {
00612       if(it->isFirst() && it != range.first) {
00613         return 0;
00614       }
00615       if(!processName.empty() && processName != it->branchDescription()->processName()) {
00616         continue;
00617       }
00618       //now see if the data is actually available
00619       ConstGroupPtr const& group = getGroupByIndex(it->index(), false, false);
00620       if(group && group->productWasDeleted()) {
00621         throwProductDeletedException("findGroupByLabel",
00622                                      typeID,
00623                                      moduleLabel,
00624                                      productInstanceName,
00625                                      processName);
00626       }
00627 
00628       // Skip product if not available.
00629       if(group && !group->productUnavailable()) {
00630         this->resolveProduct(*group, true);
00631         // If the product is a dummy filler, group will now be marked unavailable.
00632         // Unscheduled execution can fail to produce the EDProduct so check
00633         if(group->product() && !group->productUnavailable() && !group->onDemand()) {
00634           // Found the match
00635           return &group->productData();
00636         }
00637       }
00638     }
00639     return 0;
00640   }
00641 
00642   ProductData const*
00643   Principal::findGroupByTag(TypeID const& typeID, InputTag const& tag) const {
00644     ProductData const* productData =
00645         findGroupByLabel(typeID,
00646                          preg_->productLookup(),
00647                          tag.label(),
00648                          tag.instance(),
00649                          tag.process(),
00650                          tag.cachedOffset(),
00651                          tag.fillCount());
00652     if(productData == 0) {
00653       throwNotFoundException("findProductByTag", typeID, tag);
00654     }
00655     return productData;
00656   }
00657 
00658   OutputHandle
00659   Principal::getForOutput(BranchID const& bid, bool getProd) const {
00660     ConstGroupPtr const g = getGroup(bid, getProd, false);
00661     if(g == 0) {
00662       throwGroupNotFoundException("getForOutput", errors::LogicError, bid);
00663     }
00664     if (g->productWasDeleted()) {
00665       throwProductDeletedException("getForOutput",g->productType(),
00666                                    g->moduleLabel(),
00667                                    g->productInstanceName(),
00668                                    g->processName());
00669     }
00670     if(!g->provenance() || (!g->product() && !g->productProvenancePtr())) {
00671       return OutputHandle();
00672     }
00673     return OutputHandle(WrapperHolder(g->product().get(), g->productData().getInterface()), &g->branchDescription(), g->productProvenancePtr());
00674   }
00675 
00676   Provenance
00677   Principal::getProvenance(BranchID const& bid) const {
00678     ConstGroupPtr const g = getGroup(bid, false, true);
00679     if(g == 0) {
00680       throwGroupNotFoundException("getProvenance", errors::ProductNotFound, bid);
00681     }
00682 
00683     if(g->onDemand()) {
00684       unscheduledFill(g->branchDescription().moduleLabel());
00685     }
00686     // We already tried to produce the unscheduled products above
00687     // If they still are not there, then throw
00688     if(g->onDemand()) {
00689       throwGroupNotFoundException("getProvenance(onDemand)", errors::ProductNotFound, bid);
00690     }
00691 
00692     return *g->provenance();
00693   }
00694 
00695   // This one is mostly for test printout purposes
00696   // No attempt to trigger on demand execution
00697   // Skips provenance when the EDProduct is not there
00698   void
00699   Principal::getAllProvenance(std::vector<Provenance const*>& provenances) const {
00700     provenances.clear();
00701     for (const_iterator i = begin(), iEnd = end(); i != iEnd; ++i) {
00702       if((*i)->provenanceAvailable()) {
00703         // We do not attempt to get the event/lumi/run status from the provenance,
00704         // because the per event provenance may have been dropped.
00705         if((*i)->provenance()->product().present()) {
00706            provenances.push_back((*i)->provenance());
00707         }
00708       }
00709     }
00710   }
00711 
00712   void
00713   Principal::recombine(Principal& other, std::vector<BranchID> const& bids) {
00714     for (std::vector<BranchID>::const_iterator it = bids.begin(), itEnd = bids.end(); it != itEnd; ++it) {
00715       ProductTransientIndex index= preg_->indexFrom(*it);
00716       assert(index!=ProductRegistry::kInvalidIndex);
00717       ProductTransientIndex indexO = other.preg_->indexFrom(*it);
00718       assert(indexO!=ProductRegistry::kInvalidIndex);
00719       groups_[index].swap(other.groups_[indexO]);
00720     }
00721     reader_->mergeReaders(other.reader());
00722   }
00723 
00724   WrapperHolder
00725   Principal::getIt(ProductID const&) const {
00726     assert(0);
00727     return WrapperHolder();
00728   }
00729 
00730   void
00731   Principal::maybeFlushCache(TypeID const& tid, InputTag const& tag) const {
00732     if(tag.typeID() != tid ||
00733         tag.branchType() != branchType() ||
00734         tag.productRegistry() != &productRegistry()) {
00735       tag.fillCount() = 0;
00736       tag.cachedOffset() = 0U;
00737       tag.typeID() = tid;
00738       tag.branchType() = branchType();
00739       tag.productRegistry() = &productRegistry();
00740     }
00741   }
00742 
00743   void
00744   Principal::checkUniquenessAndType(WrapperOwningHolder const& prod, Group const* g) const {
00745     if(!prod.isValid()) return;
00746     // These are defensive checks against things that should never happen, but have.
00747     // Checks that the same physical product has not already been put into the event.
00748     bool alreadyPresent = !productPtrs_.insert(prod.wrapper()).second;
00749     if(alreadyPresent) {
00750       g->checkType(prod);
00751       const_cast<WrapperOwningHolder&>(prod).reset();
00752       throwCorruptionException("checkUniquenessAndType", g->branchDescription().branchName());
00753     }
00754     // Checks that the real type of the product matches the branch.
00755     g->checkType(prod);
00756   }
00757 
00758   void
00759   Principal::putOrMerge(WrapperOwningHolder const& prod, Group const* g) const {
00760     bool willBePut = g->putOrMergeProduct();
00761     if(willBePut) {
00762       checkUniquenessAndType(prod, g);
00763       g->putProduct(prod);
00764     } else {
00765       g->checkType(prod);
00766       g->mergeProduct(prod);
00767     }
00768   }
00769 
00770   void
00771   Principal::putOrMerge(WrapperOwningHolder const& prod, ProductProvenance& prov, Group* g) {
00772     bool willBePut = g->putOrMergeProduct();
00773     if(willBePut) {
00774       checkUniquenessAndType(prod, g);
00775       g->putProduct(prod, prov);
00776     } else {
00777       g->checkType(prod);
00778       g->mergeProduct(prod, prov);
00779     }
00780   }
00781 
00782   void
00783   Principal::adjustIndexesAfterProductRegistryAddition() {
00784     if(preg_->constProductList().size() > groups_.size()) {
00785       GroupCollection newGroups(preg_->constProductList().size(), SharedGroupPtr());
00786       for (Principal::const_iterator i = begin(), iEnd = end(); i != iEnd; ++i) {
00787         ProductTransientIndex index = preg_->indexFrom((*i)->branchDescription().branchID());
00788         assert(index != ProductRegistry::kInvalidIndex);
00789         newGroups[index] = *i;
00790       }
00791       groups_.swap(newGroups);
00792       // Now we must add new groups for any new product registry entries.
00793       ProductRegistry::ProductList const& prodsList = preg_->productList();
00794       for(ProductRegistry::ProductList::const_iterator itProdInfo = prodsList.begin(),
00795           itProdInfoEnd = prodsList.end();
00796           itProdInfo != itProdInfoEnd;
00797           ++itProdInfo) {
00798         if(itProdInfo->second.branchType() == branchType_) {
00799           ProductTransientIndex index = preg_->indexFrom(itProdInfo->second.branchID());
00800           assert(index != ProductRegistry::kInvalidIndex);
00801           if(!groups_[index]) {
00802             // no group.  Must add one. The new entry must be an input group.
00803             assert(!itProdInfo->second.produced());
00804             boost::shared_ptr<ConstBranchDescription> bd(new ConstBranchDescription(itProdInfo->second));
00805             addGroupInput(bd);
00806           }
00807         }
00808       }
00809     }
00810   }
00811 }