CMS 3D CMS Logo

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