00001
00004 #include <algorithm>
00005 #include <sstream>
00006 #include <stdexcept>
00007 #include <limits>
00008 #include <cstring>
00009
00010 #include "FWCore/Framework/interface/Principal.h"
00011 #include "DataFormats/Provenance/interface/ProcessHistoryRegistry.h"
00012 #include "DataFormats/Provenance/interface/ProductRegistry.h"
00013 #include "FWCore/Utilities/interface/EDMException.h"
00014 #include "FWCore/Framework/interface/DelayedReader.h"
00015 #include "FWCore/Framework/interface/Selector.h"
00016
00017
00018 namespace edm {
00019
00020 Principal::Principal(boost::shared_ptr<ProductRegistry const> reg,
00021 ProcessConfiguration const& pc,
00022 BranchType bt) :
00023 EDProductGetter(),
00024 processHistoryPtr_(boost::shared_ptr<ProcessHistory>(new ProcessHistory)),
00025 processHistoryID_(processHistoryPtr_->id()),
00026 processConfiguration_(&pc),
00027 groups_(reg->constProductList().size(), SharedGroupPtr()),
00028 preg_(reg),
00029 branchMapperPtr_(),
00030 store_(),
00031 productPtrs_(),
00032 branchType_(bt) {
00033
00034 std::string const source("source");
00035 ProductRegistry::ProductList const& prodsList = reg->productList();
00036 for(ProductRegistry::ProductList::const_iterator itProdInfo = prodsList.begin(),
00037 itProdInfoEnd = prodsList.end();
00038 itProdInfo != itProdInfoEnd;
00039 ++itProdInfo) {
00040 if (itProdInfo->second.branchType() == branchType_) {
00041 boost::shared_ptr<ConstBranchDescription> bd(new ConstBranchDescription(itProdInfo->second));
00042 if (bd->produced()) {
00043 if (bd->moduleLabel() == source) {
00044 addGroupSource(bd);
00045 } else if(bd->onDemand()) {
00046 assert(bt == InEvent);
00047 addOnDemandGroup(bd);
00048 } else {
00049 addGroupScheduled(bd);
00050 }
00051 } else {
00052 addGroupInput(bd);
00053 }
00054 }
00055 }
00056 }
00057
00058 Principal::~Principal() {
00059 }
00060
00061
00062
00063
00064 size_t
00065 Principal::size() const {
00066 size_t size = 0U;
00067 for(const_iterator it = this->begin(), itEnd = this->end(); it != itEnd; ++it) {
00068 Group const& g = **it;
00069 if (!g.productUnavailable() && !g.onDemand() && !g.branchDescription().dropped()) {
00070 ++size;
00071 }
00072 }
00073 return size;
00074 }
00075
00076
00077 bool
00078 Principal::adjustToNewProductRegistry(ProductRegistry const& reg) {
00079 if(reg.constProductList().size() > groups_.size()) {
00080 return false;
00081 }
00082 ProductRegistry::ProductList const& prodsList = reg.productList();
00083 for(ProductRegistry::ProductList::const_iterator itProdInfo = prodsList.begin(),
00084 itProdInfoEnd = prodsList.end();
00085 itProdInfo != itProdInfoEnd;
00086 ++itProdInfo) {
00087 if (!itProdInfo->second.produced() && (itProdInfo->second.branchType() == branchType_)) {
00088 boost::shared_ptr<ConstBranchDescription> bd(new ConstBranchDescription(itProdInfo->second));
00089 Group *g = getExistingGroup(itProdInfo->second.branchID());
00090 if (g == 0 || g->branchDescription().branchName() != bd->branchName()) {
00091 return false;
00092 }
00093 g->resetBranchDescription(bd);
00094 }
00095 }
00096 return true;
00097 }
00098
00099 void
00100 Principal::addGroupScheduled(boost::shared_ptr<ConstBranchDescription> bd) {
00101 std::auto_ptr<Group> g(new ScheduledGroup(bd));
00102 addGroupOrThrow(g);
00103 }
00104
00105 void
00106 Principal::addGroupSource(boost::shared_ptr<ConstBranchDescription> bd) {
00107 std::auto_ptr<Group> g(new SourceGroup(bd));
00108 addGroupOrThrow(g);
00109 }
00110
00111 void
00112 Principal::addGroupInput(boost::shared_ptr<ConstBranchDescription> bd) {
00113 std::auto_ptr<Group> g(new InputGroup(bd));
00114 addGroupOrThrow(g);
00115 }
00116
00117 void
00118 Principal::addOnDemandGroup(boost::shared_ptr<ConstBranchDescription> bd) {
00119 std::auto_ptr<Group> g(new UnscheduledGroup(bd));
00120 addGroupOrThrow(g);
00121 }
00122
00123
00124 void
00125 Principal::clearPrincipal() {
00126 processHistoryPtr_.reset(new ProcessHistory);
00127 processHistoryID_ = processHistoryPtr_->id();
00128 branchMapperPtr_.reset();
00129 store_.reset();
00130 for (Principal::const_iterator i = begin(), iEnd = end(); i != iEnd; ++i) {
00131 (*i)->resetGroupData();
00132 }
00133 productPtrs_.clear();
00134 }
00135
00136
00137 void
00138 Principal::fillPrincipal(ProcessHistoryID const& hist, boost::shared_ptr<BranchMapper> mapper, boost::shared_ptr<DelayedReader> rtrv) {
00139 branchMapperPtr_ = mapper;
00140 store_ = rtrv;
00141 if (hist.isValid()) {
00142 ProcessHistoryRegistry& history(*ProcessHistoryRegistry::instance());
00143 assert(history.notEmpty());
00144 bool found = history.getMapped(hist, *processHistoryPtr_);
00145 assert(found);
00146 processHistoryID_ = processHistoryPtr_->id();
00147 }
00148 preg_->productLookup().reorderIfNecessary(branchType_, *processHistoryPtr_,
00149 processConfiguration_->processName());
00150 preg_->elementLookup().reorderIfNecessary(branchType_, *processHistoryPtr_,
00151 processConfiguration_->processName());
00152 }
00153
00154 Group*
00155 Principal::getExistingGroup(BranchID const& branchID) {
00156 ProductTransientIndex index = preg_->indexFrom(branchID);
00157 assert(index != ProductRegistry::kInvalidIndex);
00158 SharedGroupPtr ptr = groups_.at(index);
00159 return ptr.get();
00160 }
00161
00162 Group*
00163 Principal::getExistingGroup(Group const& group) {
00164 Group* g = getExistingGroup(group.branchDescription().branchID());
00165 assert(0 == g || BranchKey(group.branchDescription()) == BranchKey(g->branchDescription()));
00166 return g;
00167 }
00168
00169 void
00170 Principal::addGroup_(std::auto_ptr<Group> group) {
00171 ConstBranchDescription const& bd = group->branchDescription();
00172 assert (!bd.className().empty());
00173 assert (!bd.friendlyClassName().empty());
00174 assert (!bd.moduleLabel().empty());
00175 assert (!bd.processName().empty());
00176 SharedGroupPtr g(group);
00177
00178 ProductTransientIndex index = preg_->indexFrom(bd.branchID());
00179 assert(index != ProductRegistry::kInvalidIndex);
00180 groups_[index] = g;
00181 }
00182
00183 void
00184 Principal::addGroupOrThrow(std::auto_ptr<Group> group) {
00185 Group const* g = getExistingGroup(*group);
00186 if (g != 0) {
00187 ConstBranchDescription const& bd = group->branchDescription();
00188 throw edm::Exception(edm::errors::InsertFailure,"AlreadyPresent")
00189 << "addGroupOrThrow: Problem found while adding product, "
00190 << "product already exists for ("
00191 << bd.friendlyClassName() << ","
00192 << bd.moduleLabel() << ","
00193 << bd.productInstanceName() << ","
00194 << bd.processName()
00195 << ")\n";
00196 }
00197 addGroup_(group);
00198 }
00199
00200 void
00201 Principal::setProcessHistory(Principal const& principal) {
00202 *processHistoryPtr_ = *principal.processHistoryPtr_;
00203 processHistoryID_ = processHistoryPtr_->id();
00204 }
00205
00206 Principal::SharedConstGroupPtr const
00207 Principal::getGroup(BranchID const& bid, bool resolveProd, bool fillOnDemand) const {
00208 ProductTransientIndex index = preg_->indexFrom(bid);
00209 if(index == ProductRegistry::kInvalidIndex){
00210 return SharedConstGroupPtr();
00211 }
00212 return getGroupByIndex(index, resolveProd, fillOnDemand);
00213 }
00214
00215 Principal::SharedConstGroupPtr const
00216 Principal::getGroupByIndex(ProductTransientIndex const& index, bool resolveProd, bool fillOnDemand) const {
00217
00218 SharedConstGroupPtr const& g = groups_[index];
00219 if (0 == g.get()) {
00220 return g;
00221 }
00222 if (resolveProd && !g->productUnavailable()) {
00223 this->resolveProduct(*g, fillOnDemand);
00224 }
00225 return g;
00226 }
00227
00228 BasicHandle
00229 Principal::getBySelector(TypeID const& productType,
00230 SelectorBase const& sel) const {
00231 BasicHandle result;
00232
00233 int nFound = findGroup(productType,
00234 preg_->productLookup(),
00235 sel,
00236 result);
00237
00238 if (nFound == 0) {
00239 boost::shared_ptr<cms::Exception> whyFailed(new edm::Exception(edm::errors::ProductNotFound));
00240 *whyFailed
00241 << "getBySelector: Found zero products matching all criteria\n"
00242 << "Looking for type: " << productType << "\n";
00243 return BasicHandle(whyFailed);
00244 }
00245 if (nFound > 1) {
00246 throw edm::Exception(edm::errors::ProductNotFound)
00247 << "getBySelector: Found " << nFound << " products rather than one which match all criteria\n"
00248 << "Looking for type: " << productType << "\n";
00249 }
00250 return result;
00251 }
00252
00253 BasicHandle
00254 Principal::getByLabel(TypeID const& productType,
00255 std::string const& label,
00256 std::string const& productInstanceName,
00257 std::string const& processName,
00258 size_t& cachedOffset,
00259 int& fillCount) const {
00260
00261 BasicHandle result;
00262
00263 bool found = findGroupByLabel(productType,
00264 preg_->productLookup(),
00265 label,
00266 productInstanceName,
00267 processName,
00268 cachedOffset,
00269 fillCount,
00270 result);
00271
00272 if (!found) {
00273 boost::shared_ptr<cms::Exception> whyFailed(new edm::Exception(edm::errors::ProductNotFound));
00274 *whyFailed
00275 << "getByLabel: Found zero products matching all criteria\n"
00276 << "Looking for type: " << productType << "\n"
00277 << "Looking for module label: " << label << "\n"
00278 << "Looking for productInstanceName: " << productInstanceName << "\n"
00279 << (processName.empty() ? "" : "Looking for process: ") << processName << "\n";
00280 return BasicHandle(whyFailed);
00281 }
00282 return result;
00283 }
00284
00285
00286 void
00287 Principal::getMany(TypeID const& productType,
00288 SelectorBase const& sel,
00289 BasicHandleVec& results) const {
00290
00291 findGroups(productType,
00292 preg_->productLookup(),
00293 sel,
00294 results);
00295
00296 return;
00297 }
00298
00299 BasicHandle
00300 Principal::getByType(TypeID const& productType) const {
00301
00302 BasicHandle result;
00303 MatchAllSelector sel;
00304
00305 int nFound = findGroup(productType,
00306 preg_->productLookup(),
00307 sel,
00308 result);
00309
00310 if (nFound == 0) {
00311 boost::shared_ptr<cms::Exception> whyFailed(new edm::Exception(edm::errors::ProductNotFound));
00312 *whyFailed
00313 << "getByType: Found zero products matching all criteria\n"
00314 << "Looking for type: " << productType << "\n";
00315 return BasicHandle(whyFailed);
00316 }
00317 if (nFound > 1) {
00318 throw edm::Exception(edm::errors::ProductNotFound)
00319 << "getByType: Found " << nFound << " products rather than one which match all criteria\n"
00320 << "Looking for type: " << productType << "\n";
00321 }
00322 return result;
00323 }
00324
00325 void
00326 Principal::getManyByType(TypeID const& productType,
00327 BasicHandleVec& results) const {
00328
00329 MatchAllSelector sel;
00330
00331 findGroups(productType,
00332 preg_->productLookup(),
00333 sel,
00334 results);
00335 return;
00336 }
00337
00338 size_t
00339 Principal::getMatchingSequence(TypeID const& typeID,
00340 SelectorBase const& selector,
00341 BasicHandle& result) const {
00342
00343
00344
00345 return findGroup(typeID,
00346 preg_->elementLookup(),
00347 selector,
00348 result);
00349 }
00350
00351 size_t
00352 Principal::findGroups(TypeID const& typeID,
00353 TransientProductLookupMap const& typeLookup,
00354 SelectorBase const& selector,
00355 BasicHandleVec& results) const {
00356 assert(results.empty());
00357
00358 typedef TransientProductLookupMap TypeLookup;
00359
00360
00361
00362 std::pair<TypeLookup::const_iterator, TypeLookup::const_iterator> const range = typeLookup.equal_range(TypeInBranchType(typeID,branchType_));
00363 if(range.first == range.second) {
00364 return 0;
00365 }
00366
00367 results.reserve(range.second - range.first);
00368
00369 for(TypeLookup::const_iterator it = range.first; it != range.second; ++it) {
00370
00371 if(selector.match(*(it->branchDescription()))) {
00372
00373
00374 SharedConstGroupPtr const& group = getGroupByIndex(it->index(), false, false);
00375
00376 if (group && !group->productUnavailable()) {
00377 this->resolveProduct(*group, true);
00378
00379
00380 if (!group->productUnavailable() && !group->onDemand()) {
00381
00382 BasicHandle bh(group->product(), group->provenance());
00383 results.push_back(bh);
00384 }
00385 }
00386 }
00387 }
00388 return results.size();
00389 }
00390
00391 size_t
00392 Principal::findGroup(TypeID const& typeID,
00393 TransientProductLookupMap const& typeLookup,
00394 SelectorBase const& selector,
00395 BasicHandle& result) const {
00396 assert(!result.isValid());
00397
00398 size_t count = 0U;
00399
00400 typedef TransientProductLookupMap TypeLookup;
00401
00402
00403
00404 std::pair<TypeLookup::const_iterator, TypeLookup::const_iterator> const range = typeLookup.equal_range(TypeInBranchType(typeID,branchType_));
00405 if(range.first == range.second) {
00406 return 0;
00407 }
00408
00409 unsigned int processLevelFound = std::numeric_limits<unsigned int>::max();
00410 for(TypeLookup::const_iterator it = range.first; it != range.second; ++it) {
00411 if(it->processIndex() > processLevelFound) {
00412
00413 continue;
00414 }
00415
00416 if(selector.match(*(it->branchDescription()))) {
00417
00418
00419 SharedConstGroupPtr const& group = getGroupByIndex(it->index(), false, false);
00420
00421 if (group && !group->productUnavailable()) {
00422 this->resolveProduct(*group, true);
00423
00424
00425 if (!group->productUnavailable() && !group->onDemand()) {
00426 if(it->processIndex() < processLevelFound) {
00427 processLevelFound = it->processIndex();
00428 count = 0U;
00429 }
00430 if (count == 0U) {
00431
00432 result = BasicHandle(group->product(), group->provenance());
00433 }
00434 ++count;
00435 }
00436 }
00437 }
00438 }
00439 if (count != 1) result = BasicHandle();
00440 return count;
00441 }
00442
00443 bool
00444 Principal::findGroupByLabel(TypeID const& typeID,
00445 TransientProductLookupMap const& typeLookup,
00446 std::string const& moduleLabel,
00447 std::string const& productInstanceName,
00448 std::string const& processName,
00449 size_t& cachedOffset,
00450 int& fillCount,
00451 BasicHandle& result) const {
00452 assert(!result.isValid());
00453
00454 typedef TransientProductLookupMap TypeLookup;
00455 bool isCached = (fillCount > 0 && fillCount == typeLookup.fillCount());
00456 bool toBeCached = (fillCount >= 0 && !isCached);
00457
00458 std::pair<TypeLookup::const_iterator, TypeLookup::const_iterator> range =
00459 (isCached ? std::make_pair(typeLookup.begin() + cachedOffset, typeLookup.end()) : typeLookup.equal_range(TypeInBranchType(typeID,branchType_), moduleLabel, productInstanceName));
00460
00461 if (toBeCached) {
00462 cachedOffset = range.first - typeLookup.begin();
00463 fillCount = typeLookup.fillCount();
00464 }
00465
00466 if(range.first == range.second) {
00467 if (toBeCached) {
00468 cachedOffset = typeLookup.end() - typeLookup.begin();
00469 }
00470 return false;
00471 }
00472
00473 if (!processName.empty()) {
00474 if (isCached) {
00475 assert(processName == range.first->branchDescription()->processName());
00476 range.second = range.first + 1;
00477 } else if (toBeCached) {
00478 bool processFound = false;
00479 for(TypeLookup::const_iterator it = range.first; it != range.second; ++it) {
00480 if (it->isFirst() && it != range.first) {
00481 break;
00482 }
00483 if (processName == it->branchDescription()->processName()) {
00484 processFound = true;
00485 range.first = it;
00486 cachedOffset = range.first - typeLookup.begin();
00487 range.second = range.first + 1;
00488 break;
00489 }
00490 }
00491 if (!processFound) {
00492 cachedOffset = typeLookup.end() - typeLookup.begin();
00493 return false;
00494 }
00495 }
00496 }
00497
00498 for(TypeLookup::const_iterator it = range.first; it != range.second; ++it) {
00499 if (it->isFirst() && it != range.first) {
00500 return false;
00501 }
00502 if (!processName.empty() && processName != it->branchDescription()->processName()) {
00503 continue;
00504 }
00505
00506 SharedConstGroupPtr const& group = getGroupByIndex(it->index(), false, false);
00507
00508 if (group && !group->productUnavailable()) {
00509 this->resolveProduct(*group, true);
00510
00511
00512 if (!group->productUnavailable() && !group->onDemand()) {
00513
00514 result = BasicHandle(group->product(), group->provenance());
00515 return true;
00516 }
00517 }
00518 }
00519 return false;
00520 }
00521
00522 OutputHandle
00523 Principal::getForOutput(BranchID const& bid, bool getProd) const {
00524 SharedConstGroupPtr const& g = getGroup(bid, getProd, false);
00525 if (g.get() == 0) {
00526 throw edm::Exception(edm::errors::LogicError, "Principal::getForOutput\n")
00527 << "No entry is present for this branch.\n"
00528 << "The branch id is " << bid << "\n"
00529 << "Contact a framework developer.\n";
00530 }
00531 if (!g->provenance() || (!g->product() && !g->productProvenancePtr())) {
00532 return OutputHandle();
00533 }
00534 return OutputHandle(g->product().get(), &g->branchDescription(), g->productProvenancePtr());
00535 }
00536
00537 Provenance
00538 Principal::getProvenance(BranchID const& bid) const {
00539 SharedConstGroupPtr const& g = getGroup(bid, false, true);
00540 if (g.get() == 0) {
00541 throw edm::Exception(edm::errors::ProductNotFound,"InvalidID")
00542 << "getProvenance: no product with given branch id: "<< bid << "\n";
00543 }
00544
00545 if (g->onDemand()) {
00546 unscheduledFill(g->branchDescription().moduleLabel());
00547 }
00548
00549
00550 if (g->onDemand()) {
00551 throw edm::Exception(edm::errors::ProductNotFound)
00552 << "getProvenance: no product with given BranchID: "<< bid <<"\n";
00553 }
00554
00555 return *g->provenance();
00556 }
00557
00558
00559
00560
00561 void
00562 Principal::getAllProvenance(std::vector<Provenance const*>& provenances) const {
00563 provenances.clear();
00564 for (const_iterator i = begin(), iEnd = end(); i != iEnd; ++i) {
00565 if ((*i)->provenanceAvailable()) {
00566
00567
00568 if ((*i)->provenance()->product().present()) {
00569 provenances.push_back((*i)->provenance());
00570 }
00571 }
00572 }
00573 }
00574
00575 void
00576 Principal::recombine(Principal& other, std::vector<BranchID> const& bids) {
00577 for (std::vector<BranchID>::const_iterator it = bids.begin(), itEnd = bids.end(); it != itEnd; ++it) {
00578 ProductTransientIndex index= preg_->indexFrom(*it);
00579 assert(index!=ProductRegistry::kInvalidIndex);
00580 ProductTransientIndex indexO = other.preg_->indexFrom(*it);
00581 assert(indexO!=ProductRegistry::kInvalidIndex);
00582 groups_[index].swap(other.groups_[indexO]);
00583 }
00584 store_->mergeReaders(other.store());
00585 branchMapperPtr_->mergeMappers(other.branchMapperPtr());
00586 }
00587
00588 EDProduct const*
00589 Principal::getIt(ProductID const& pid) const {
00590 assert(0);
00591 return 0;
00592 }
00593
00594 void
00595 Principal::maybeFlushCache(TypeID const& tid, InputTag const& tag) const {
00596 if (tag.typeID() != tid ||
00597 tag.branchType() != branchType() ||
00598 tag.productRegistry() != &productRegistry()) {
00599 tag.fillCount() = 0;
00600 tag.cachedOffset() = 0U;
00601 tag.typeID() = tid;
00602 tag.branchType() = branchType();
00603 tag.productRegistry() = &productRegistry();
00604 }
00605 }
00606
00607 void
00608 Principal::checkUniquenessAndType(std::auto_ptr<EDProduct>& prod, Group const* g) const {
00609 if (prod.get() == 0) return;
00610
00611
00612 bool alreadyPresent = !productPtrs_.insert(prod.get()).second;
00613 if (alreadyPresent) {
00614 g->checkType(*prod.release());
00615 throw edm::Exception(errors::EventCorruption)
00616 << "Product on branch " << g->branchDescription().branchName() << " occurs twice in the same event.\n";
00617 }
00618
00619 g->checkType(*prod);
00620 }
00621
00622 void
00623 Principal::putOrMerge(std::auto_ptr<EDProduct> prod, Group const* g) const {
00624 bool willBePut = g->putOrMergeProduct();
00625 if (willBePut) {
00626 checkUniquenessAndType(prod, g);
00627 g->putProduct(prod);
00628 } else {
00629 g->checkType(*prod);
00630 g->mergeProduct(prod);
00631 }
00632 }
00633
00634 void
00635 Principal::putOrMerge(std::auto_ptr<EDProduct> prod, std::auto_ptr<ProductProvenance> prov, Group* g) {
00636 bool willBePut = g->putOrMergeProduct();
00637 if (willBePut) {
00638 checkUniquenessAndType(prod, g);
00639 g->putProduct(prod, prov);
00640 } else {
00641 g->checkType(*prod);
00642 g->mergeProduct(prod, prov);
00643 }
00644 }
00645
00646 void
00647 Principal::swapBase(Principal& iOther) {
00648 std::swap(processHistoryPtr_, iOther.processHistoryPtr_);
00649 std::swap(processHistoryID_, iOther.processHistoryID_);
00650 std::swap(processConfiguration_,iOther.processConfiguration_);
00651 std::swap(groups_,iOther.groups_);
00652 std::swap(preg_, iOther.preg_);
00653 std::swap(branchMapperPtr_,iOther.branchMapperPtr_);
00654 std::swap(store_,iOther.store_);
00655 }
00656
00657 void
00658 Principal::adjustIndexesAfterProductRegistryAddition() {
00659 if (preg_->constProductList().size() > groups_.size()) {
00660 GroupCollection newGroups(preg_->constProductList().size(), SharedGroupPtr());
00661 for (Principal::const_iterator i = begin(), iEnd = end(); i != iEnd; ++i) {
00662 ProductTransientIndex index = preg_->indexFrom((*i)->branchDescription().branchID());
00663 assert(index != ProductRegistry::kInvalidIndex);
00664 newGroups[index] = *i;
00665 }
00666 groups_.swap(newGroups);
00667
00668 ProductRegistry::ProductList const& prodsList = preg_->productList();
00669 for(ProductRegistry::ProductList::const_iterator itProdInfo = prodsList.begin(),
00670 itProdInfoEnd = prodsList.end();
00671 itProdInfo != itProdInfoEnd;
00672 ++itProdInfo) {
00673 if (itProdInfo->second.branchType() == branchType_) {
00674 ProductTransientIndex index = preg_->indexFrom(itProdInfo->second.branchID());
00675 assert(index != ProductRegistry::kInvalidIndex);
00676 if (!groups_[index]) {
00677
00678 assert(!itProdInfo->second.produced());
00679 boost::shared_ptr<ConstBranchDescription> bd(new ConstBranchDescription(itProdInfo->second));
00680 addGroupInput(bd);
00681 }
00682 }
00683 }
00684 }
00685 }
00686 }