CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_5/src/IOPool/Output/src/RootOutputFile.cc

Go to the documentation of this file.
00001 
00002 #include "IOPool/Output/src/RootOutputFile.h"
00003 
00004 #include "FWCore/Utilities/interface/GlobalIdentifier.h"
00005 
00006 #include "DataFormats/Provenance/interface/EventAuxiliary.h"
00007 #include "FWCore/Version/interface/GetFileFormatVersion.h"
00008 #include "DataFormats/Provenance/interface/FileFormatVersion.h"
00009 #include "FWCore/Utilities/interface/EDMException.h"
00010 #include "FWCore/Utilities/interface/Algorithms.h"
00011 #include "FWCore/Utilities/interface/Digest.h"
00012 #include "FWCore/Framework/interface/FileBlock.h"
00013 #include "FWCore/Framework/interface/EventPrincipal.h"
00014 #include "FWCore/Framework/interface/LuminosityBlockPrincipal.h"
00015 #include "FWCore/Framework/interface/RunPrincipal.h"
00016 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00017 #include "DataFormats/Common/interface/OutputHandle.h"
00018 #include "DataFormats/Provenance/interface/BranchChildren.h"
00019 #include "DataFormats/Provenance/interface/BranchIDList.h"
00020 #include "DataFormats/Provenance/interface/Parentage.h"
00021 #include "DataFormats/Provenance/interface/ParentageRegistry.h"
00022 #include "DataFormats/Provenance/interface/EventID.h"
00023 #include "DataFormats/Provenance/interface/ParameterSetBlob.h"
00024 #include "DataFormats/Provenance/interface/ParameterSetID.h"
00025 #include "DataFormats/Provenance/interface/ProcessHistoryRegistry.h"
00026 #include "DataFormats/Provenance/interface/ProcessHistoryID.h"
00027 #include "DataFormats/Provenance/interface/ProductRegistry.h"
00028 #include "FWCore/Framework/interface/ConstProductRegistry.h"
00029 #include "FWCore/ParameterSet/interface/ParameterSet.h"
00030 #include "FWCore/ParameterSet/interface/Registry.h"
00031 #include "FWCore/ServiceRegistry/interface/Service.h"
00032 
00033 #include "TROOT.h"
00034 #include "TTree.h"
00035 #include "TFile.h"
00036 #include "TClass.h"
00037 #include "Rtypes.h"
00038 #include "RVersion.h"
00039 
00040 #if ROOT_VERSION_CODE >= ROOT_VERSION(5,30,0)
00041 #include "Compression.h"
00042 #endif
00043 
00044 #include <algorithm>
00045 #include <iomanip>
00046 #include <sstream>
00047 
00048 namespace edm {
00049 
00050   namespace {
00051     bool
00052     sorterForJobReportHash(BranchDescription const* lh, BranchDescription const* rh) {
00053       return
00054         lh->fullClassName() < rh->fullClassName() ? true :
00055         lh->fullClassName() > rh->fullClassName() ? false :
00056         lh->moduleLabel() < rh->moduleLabel() ? true :
00057         lh->moduleLabel() > rh->moduleLabel() ? false :
00058         lh->productInstanceName() < rh->productInstanceName() ? true :
00059         lh->productInstanceName() > rh->productInstanceName() ? false :
00060         lh->processName() < rh->processName() ? true :
00061         false;
00062     }
00063   }
00064 
00065   RootOutputFile::RootOutputFile(PoolOutputModule* om, std::string const& fileName, std::string const& logicalFileName) :
00066       file_(fileName),
00067       logicalFile_(logicalFileName),
00068       reportToken_(0),
00069       om_(om),
00070       whyNotFastClonable_(om_->whyNotFastClonable()),
00071       canFastCloneAux_(false),
00072       filePtr_(TFile::Open(file_.c_str(), "recreate", "", om_->compressionLevel())),
00073       fid_(),
00074       eventEntryNumber_(0LL),
00075       lumiEntryNumber_(0LL),
00076       runEntryNumber_(0LL),
00077       indexIntoFile_(),
00078       metaDataTree_(0),
00079       parameterSetsTree_(0),
00080       parentageTree_(0),
00081       lumiAux_(),
00082       runAux_(),
00083       pEventAux_(0),
00084       pLumiAux_(&lumiAux_),
00085       pRunAux_(&runAux_),
00086       eventEntryInfoVector_(),
00087       pEventEntryInfoVector_(&eventEntryInfoVector_),
00088       pBranchListIndexes_(0),
00089       pEventSelectionIDs_(0),
00090       eventTree_(filePtr_, InEvent, om_->splitLevel(), om_->treeMaxVirtualSize()),
00091       lumiTree_(filePtr_, InLumi, om_->splitLevel(), om_->treeMaxVirtualSize()),
00092       runTree_(filePtr_, InRun, om_->splitLevel(), om_->treeMaxVirtualSize()),
00093       treePointers_(),
00094       dataTypeReported_(false),
00095       parentageIDs_(),
00096       branchesWithStoredHistory_() {
00097 #if ROOT_VERSION_CODE >= ROOT_VERSION(5,30,0)
00098     if (om_->compressionAlgorithm() == std::string("ZLIB")) {
00099       filePtr_->SetCompressionAlgorithm(ROOT::kZLIB);
00100     } else if (om_->compressionAlgorithm() == std::string("LZMA")) {
00101       filePtr_->SetCompressionAlgorithm(ROOT::kLZMA);
00102     } else {
00103       throw Exception(errors::Configuration) << "PoolOutputModule configured with unknown compression algorithm '" << om_->compressionAlgorithm() << "'\n"
00104                                              << "Allowed compression algorithms are ZLIB and LZMA\n";
00105     }
00106 #endif
00107     if (-1 != om->eventAutoFlushSize()) {
00108       eventTree_.setAutoFlush(-1*om->eventAutoFlushSize());
00109     }
00110     eventTree_.addAuxiliary<EventAuxiliary>(BranchTypeToAuxiliaryBranchName(InEvent),
00111                                             pEventAux_, om_->auxItems()[InEvent].basketSize_);
00112     eventTree_.addAuxiliary<StoredProductProvenanceVector>(BranchTypeToProductProvenanceBranchName(InEvent),
00113                                                      pEventEntryInfoVector_, om_->auxItems()[InEvent].basketSize_);
00114     eventTree_.addAuxiliary<EventSelectionIDVector>(poolNames::eventSelectionsBranchName(),
00115                                                     pEventSelectionIDs_, om_->auxItems()[InEvent].basketSize_,false);
00116     eventTree_.addAuxiliary<BranchListIndexes>(poolNames::branchListIndexesBranchName(),
00117                                                pBranchListIndexes_, om_->auxItems()[InEvent].basketSize_);
00118 
00119     lumiTree_.addAuxiliary<LuminosityBlockAuxiliary>(BranchTypeToAuxiliaryBranchName(InLumi),
00120                                                      pLumiAux_, om_->auxItems()[InLumi].basketSize_);
00121 
00122     runTree_.addAuxiliary<RunAuxiliary>(BranchTypeToAuxiliaryBranchName(InRun),
00123                                         pRunAux_, om_->auxItems()[InRun].basketSize_);
00124 
00125     treePointers_[InEvent] = &eventTree_;
00126     treePointers_[InLumi]  = &lumiTree_;
00127     treePointers_[InRun]   = &runTree_;
00128 
00129     for(int i = InEvent; i < NumBranchTypes; ++i) {
00130       BranchType branchType = static_cast<BranchType>(i);
00131       RootOutputTree *theTree = treePointers_[branchType];
00132       for(OutputItemList::const_iterator it = om_->selectedOutputItemList()[branchType].begin(),
00133           itEnd = om_->selectedOutputItemList()[branchType].end();
00134           it != itEnd; ++it) {
00135         it->product_ = 0;
00136         BranchDescription const& desc = *it->branchDescription_;
00137         desc.init();
00138         theTree->addBranch(desc.branchName(),
00139                            desc.wrappedName(),
00140                            desc.getInterface(),
00141                            it->product_,
00142                            it->splitLevel_,
00143                            it->basketSize_,
00144                            it->branchDescription_->produced());
00145         //make sure we always store product registry info for all branches we create
00146         branchesWithStoredHistory_.insert(it->branchID());
00147       }
00148     }
00149     // Don't split metadata tree or event description tree
00150     metaDataTree_         = RootOutputTree::makeTTree(filePtr_.get(), poolNames::metaDataTreeName(), 0);
00151     parentageTree_ = RootOutputTree::makeTTree(filePtr_.get(), poolNames::parentageTreeName(), 0);
00152     parameterSetsTree_    = RootOutputTree::makeTTree(filePtr_.get(), poolNames::parameterSetsTreeName(), 0);
00153 
00154     fid_ = FileID(createGlobalIdentifier());
00155 
00156     // For the Job Report, get a vector of branch names in the "Events" tree.
00157     // Also create a hash of all the branch names in the "Events" tree
00158     // in a deterministic order, except use the full class name instead of the friendly class name.
00159     // To avoid extra string copies, we create a vector of pointers into the product registry,
00160     // and use a custom comparison operator for sorting.
00161     std::vector<std::string> branchNames;
00162     std::vector<BranchDescription const*> branches;
00163     branchNames.reserve(om_->selectedOutputItemList()[InEvent].size());
00164     branches.reserve(om->selectedOutputItemList()[InEvent].size());
00165     for(OutputItemList::const_iterator it = om_->selectedOutputItemList()[InEvent].begin(),
00166           itEnd = om_->selectedOutputItemList()[InEvent].end();
00167           it != itEnd; ++it) {
00168       branchNames.push_back(it->branchDescription_->branchName());
00169       branches.push_back(it->branchDescription_);
00170     }
00171     // Now sort the branches for the hash.
00172     sort_all(branches, sorterForJobReportHash);
00173     // Now, make a concatenated string.
00174     std::ostringstream oss;
00175     char const underscore = '_';
00176     for(std::vector<BranchDescription const*>::const_iterator it = branches.begin(), itEnd = branches.end(); it != itEnd; ++it) {
00177       BranchDescription const& bd = **it;
00178       oss << bd.fullClassName() << underscore
00179           << bd.moduleLabel() << underscore
00180           << bd.productInstanceName() << underscore
00181           << bd.processName() << underscore;
00182     }
00183     std::string stringrep = oss.str();
00184     cms::Digest md5alg(stringrep);
00185 
00186     // Register the output file with the JobReport service
00187     // and get back the token for it.
00188     std::string moduleName = "PoolOutputModule";
00189     Service<JobReport> reportSvc;
00190     reportToken_ = reportSvc->outputFileOpened(
00191                       file_, logicalFile_,  // PFN and LFN
00192                       om_->catalog(),  // catalog
00193                       moduleName,   // module class name
00194                       om_->moduleLabel(),  // module label
00195                       fid_.fid(), // file id (guid)
00196                       std::string(), // data type (not yet known, so string is empty).
00197                       md5alg.digest().toString(), // branch hash
00198                       branchNames); // branch names being written
00199   }
00200 
00201   namespace {
00202     void
00203     maybeIssueWarning(int whyNotFastClonable, std::string const& ifileName, std::string const& ofileName) {
00204 
00205       // No message if fast cloning was deliberately disabled, or if there are no events to copy anyway.
00206       if ((whyNotFastClonable &
00207         (FileBlock::DisabledInConfigFile | FileBlock::NoRootInputSource | FileBlock::NotProcessingEvents | FileBlock::NoEventsInFile)) != 0) {
00208         return;
00209       }
00210 
00211       // There will be a message stating every reason that fast cloning was not possible.
00212       // If at one or more of the reasons was because of something the user explicitly specified (e.g. event selection, skipping events),
00213       // or if the input file was in an old format, the message will be informational.  Otherwise, the message will be a warning.
00214       bool isWarning = true;
00215       std::ostringstream message;
00216       message << "Fast copying of file " << ifileName << " to file " << ofileName << " is disabled because:\n";
00217       if((whyNotFastClonable & FileBlock::HasSecondaryFileSequence) != 0) {
00218         message << "a SecondaryFileSequence was specified.\n";
00219         whyNotFastClonable &= ~(FileBlock::HasSecondaryFileSequence);
00220         isWarning = false;
00221       }
00222       if((whyNotFastClonable & FileBlock::FileTooOld) != 0) {
00223         message << "the input file is in an old format.\n";
00224         whyNotFastClonable &= ~(FileBlock::FileTooOld);
00225         isWarning = false;
00226       }
00227       if((whyNotFastClonable & FileBlock::EventsToBeSorted) != 0) {
00228         message << "events need to be sorted.\n";
00229         whyNotFastClonable &= ~(FileBlock::EventsToBeSorted);
00230       }
00231       if((whyNotFastClonable & FileBlock::RunOrLumiNotContiguous) != 0) {
00232         message << "a run or a lumi is not contiguous in the input file.\n";
00233         whyNotFastClonable &= ~(FileBlock::RunOrLumiNotContiguous);
00234       }
00235       if((whyNotFastClonable & FileBlock::EventsOrLumisSelectedByID) != 0) {
00236         message << "events or lumis were selected or skipped by ID.\n";
00237         whyNotFastClonable &= ~(FileBlock::EventsOrLumisSelectedByID);
00238         isWarning = false;
00239       }
00240       if((whyNotFastClonable & FileBlock::InitialEventsSkipped) != 0) {
00241         message << "initial events, lumis or runs were skipped.\n";
00242         whyNotFastClonable &= ~(FileBlock::InitialEventsSkipped);
00243         isWarning = false;
00244       }
00245       if((whyNotFastClonable & FileBlock::DuplicateEventsRemoved) != 0) {
00246         message << "some events were skipped because of duplicate checking.\n";
00247         whyNotFastClonable &= ~(FileBlock::DuplicateEventsRemoved);
00248       }
00249       if((whyNotFastClonable & FileBlock::MaxEventsTooSmall) != 0) {
00250         message << "some events were not copied because of maxEvents limit.\n";
00251         whyNotFastClonable &= ~(FileBlock::MaxEventsTooSmall);
00252         isWarning = false;
00253       }
00254       if((whyNotFastClonable & FileBlock::MaxLumisTooSmall) != 0) {
00255         message << "some events were not copied because of maxLumis limit.\n";
00256         whyNotFastClonable &= ~(FileBlock::MaxLumisTooSmall);
00257         isWarning = false;
00258       }
00259       if((whyNotFastClonable & FileBlock::ParallelProcesses) != 0) {
00260         message << "parallel processing was specified.\n";
00261         whyNotFastClonable &= ~(FileBlock::ParallelProcesses);
00262         isWarning = false;
00263       }
00264       if((whyNotFastClonable & FileBlock::EventSelectionUsed) != 0) {
00265         message << "an EventSelector was specified.\n";
00266         whyNotFastClonable &= ~(FileBlock::EventSelectionUsed);
00267         isWarning = false;
00268       }
00269       if((whyNotFastClonable & FileBlock::OutputMaxEventsTooSmall) != 0) {
00270         message << "some events were not copied because of maxEvents output limit.\n";
00271         whyNotFastClonable &= ~(FileBlock::OutputMaxEventsTooSmall);
00272         isWarning = false;
00273       }
00274       if((whyNotFastClonable & FileBlock::SplitLevelMismatch) != 0) {
00275         message << "the split level or basket size of a branch or branches was modified.\n";
00276         whyNotFastClonable &= ~(FileBlock::SplitLevelMismatch);
00277       }
00278       if((whyNotFastClonable & FileBlock::BranchMismatch) != 0) {
00279         message << "The format of a data product has changed.\n";
00280         whyNotFastClonable &= ~(FileBlock::BranchMismatch);
00281       }
00282       assert(whyNotFastClonable == FileBlock::CanFastClone);
00283       if (isWarning) {
00284         LogWarning("FastCloningDisabled") << message.str();
00285       } else {
00286         LogInfo("FastCloningDisabled") << message.str();
00287       }
00288     }
00289   }
00290 
00291   void RootOutputFile::beginInputFile(FileBlock const& fb, int remainingEvents) {
00292 
00293     // Reset per input file information
00294     whyNotFastClonable_ = om_->whyNotFastClonable();
00295     canFastCloneAux_ = false;
00296 
00297     if(fb.tree() != 0) {
00298 
00299       whyNotFastClonable_ |= fb.whyNotFastClonable();
00300 
00301       if(remainingEvents >= 0 && remainingEvents < fb.tree()->GetEntries()) {
00302         whyNotFastClonable_ |= FileBlock::OutputMaxEventsTooSmall;
00303       }
00304 
00305       bool match = eventTree_.checkSplitLevelsAndBasketSizes(fb.tree());
00306       if(!match) {
00307         if(om_->overrideInputFileSplitLevels()) {
00308           // We may be fast copying.  We must disable fast copying if the split levels
00309           // or basket sizes do not match.
00310           whyNotFastClonable_ |= FileBlock::SplitLevelMismatch;
00311         } else {
00312           // We are using the input split levels and basket sizes from the first input file
00313           // for copied output branches.  In this case, we throw an exception if any branches
00314           // have different split levels or basket sizes in a subsequent input file.
00315           // If the mismatch is in the first file, there is a bug somewhere, so we assert.
00316           assert(om_->inputFileCount() > 1);
00317           throw Exception(errors::MismatchedInputFiles, "RootOutputFile::beginInputFile()") <<
00318             "Merge failure because input file " << file_ << " has different ROOT split levels or basket sizes\n" <<
00319             "than previous files.  To allow merging in splite of this, use the configuration parameter\n" <<
00320             "overrideInputFileSplitLevels=cms.untracked.bool(True)\n" <<
00321             "in every PoolOutputModule.\n";
00322         }
00323       }
00324 
00325       // Since this check can be time consuming, we do it only if we would otherwise fast clone.
00326       if(whyNotFastClonable_ == FileBlock::CanFastClone) {
00327         if(!eventTree_.checkIfFastClonable(fb.tree())) {
00328           whyNotFastClonable_ |= FileBlock::BranchMismatch;
00329         }
00330       }
00331       // We now check if we can fast copy the auxiliary branches.
00332       // We can do so only if we can otherwise fast copy,
00333       // the input file has the current format (these branches are in the Events Tree),
00334       // there are no newly dropped or produced products,
00335       // no metadata has been dropped,
00336       // ID's have not been modified,
00337       // and the branch list indexes do not need modification.
00338 
00339       // Note: Fast copy of the EventProductProvenance branch is unsafe
00340       // unless we can enforce that the parentage information for a fully copied
00341       // output file will be the same as for the input file, with nothing dropped.
00342       // This has never been enforced, and, withthe EDAlias feature, it may no longer
00343       // work by accident.
00344       // So, for now, we do not enable fast cloning of the non-product branches.
00345 /*
00346       Service<ConstProductRegistry> reg;
00347       canFastCloneAux_ = (whyNotFastClonable_ == FileBlock::CanFastClone) &&
00348                           fb.fileFormatVersion().noMetaDataTrees() &&
00349                           !om_->hasNewlyDroppedBranch()[InEvent] &&
00350                           !fb.hasNewlyDroppedBranch()[InEvent] &&
00351                           om_->dropMetaData() == PoolOutputModule::DropNone &&
00352                           !reg->anyProductProduced() &&
00353                           !fb.modifiedIDs() &&
00354                           fb.branchListIndexesUnchanged();
00355 */
00356 
00357       // Report the fast copying status.
00358       Service<JobReport> reportSvc;
00359       reportSvc->reportFastCopyingStatus(reportToken_, fb.fileName(), whyNotFastClonable_ == FileBlock::CanFastClone);
00360     } else {
00361       whyNotFastClonable_ |= FileBlock::NoRootInputSource;
00362     }
00363 
00364     eventTree_.maybeFastCloneTree(whyNotFastClonable_ == FileBlock::CanFastClone, canFastCloneAux_, fb.tree(), om_->basketOrder());
00365 
00366     // Possibly issue warning or informational message if we haven't fast cloned.
00367     if(fb.tree() != 0 && whyNotFastClonable_ != FileBlock::CanFastClone) {
00368       maybeIssueWarning(whyNotFastClonable_, fb.fileName(), file_);
00369     }
00370   }
00371 
00372   void RootOutputFile::respondToCloseInputFile(FileBlock const&) {
00373     eventTree_.setEntries();
00374     lumiTree_.setEntries();
00375     runTree_.setEntries();
00376   }
00377 
00378   bool RootOutputFile::shouldWeCloseFile() const {
00379     unsigned int const oneK = 1024;
00380     Long64_t size = filePtr_->GetSize()/oneK;
00381     return(size >= om_->maxFileSize());
00382   }
00383 
00384   void RootOutputFile::writeOne(EventPrincipal const& e) {
00385     // Auxiliary branch
00386     pEventAux_ = &e.aux();
00387 
00388     // Because getting the data may cause an exception to be thrown we want to do that
00389     // first before writing anything to the file about this event
00390     // NOTE: pEventAux_, pBranchListIndexes_, pEventSelectionIDs_, and pEventEntryInfoVector_
00391     // must be set before calling fillBranches since they get written out in that routine.
00392     assert(pEventAux_->processHistoryID() == e.processHistoryID());
00393     pBranchListIndexes_ = &e.branchListIndexes();
00394 
00395     // Note: The EventSelectionIDVector should have a one to one correspondence with the processes in the process history.
00396     // Therefore, a new entry should be added if and only if the current process has been added to the process history,
00397     // which is done if and only if there is a produced product.
00398     Service<ConstProductRegistry> reg;
00399     EventSelectionIDVector esids = e.eventSelectionIDs();
00400     if (reg->anyProductProduced() || !om_->wantAllEvents()) {
00401       esids.push_back(om_->selectorConfig());
00402     }
00403     pEventSelectionIDs_ = &esids;
00404     fillBranches(InEvent, e, pEventEntryInfoVector_);
00405 
00406     // Add the dataType to the job report if it hasn't already been done
00407     if(!dataTypeReported_) {
00408       Service<JobReport> reportSvc;
00409       std::string dataType("MC");
00410       if(pEventAux_->isRealData())  dataType = "Data";
00411       reportSvc->reportDataType(reportToken_, dataType);
00412       dataTypeReported_ = true;
00413     }
00414 
00415     // Store the reduced ID in the IndexIntoFile
00416     ProcessHistoryID reducedPHID = ProcessHistoryRegistry::instance()->extra().reduceProcessHistoryID(e.processHistoryID());
00417     // Add event to index
00418     indexIntoFile_.addEntry(reducedPHID, pEventAux_->run(), pEventAux_->luminosityBlock(), pEventAux_->event(), eventEntryNumber_);
00419     ++eventEntryNumber_;
00420 
00421     // Report event written
00422     Service<JobReport> reportSvc;
00423     reportSvc->eventWrittenToFile(reportToken_, e.id().run(), e.id().event());
00424   }
00425 
00426   void RootOutputFile::writeLuminosityBlock(LuminosityBlockPrincipal const& lb) {
00427     // Auxiliary branch
00428     // NOTE: lumiAux_ must be filled before calling fillBranches since it gets written out in that routine.
00429     lumiAux_ = lb.aux();
00430     // Use the updated process historyID
00431     lumiAux_.setProcessHistoryID(lb.processHistoryID());
00432     // Store the reduced ID in the IndexIntoFile
00433     ProcessHistoryID reducedPHID = ProcessHistoryRegistry::instance()->extra().reduceProcessHistoryID(lb.processHistoryID());
00434     // Add lumi to index.
00435     indexIntoFile_.addEntry(reducedPHID, lumiAux_.run(), lumiAux_.luminosityBlock(), 0U, lumiEntryNumber_);
00436     ++lumiEntryNumber_;
00437     fillBranches(InLumi, lb, 0);
00438     lumiTree_.optimizeBaskets(10ULL*1024*1024);
00439   }
00440 
00441   void RootOutputFile::writeRun(RunPrincipal const& r) {
00442     // Auxiliary branch
00443     // NOTE: runAux_ must be filled before calling fillBranches since it gets written out in that routine.
00444     runAux_ = r.aux();
00445     // Use the updated process historyID
00446     runAux_.setProcessHistoryID(r.processHistoryID());
00447     // Store the reduced ID in the IndexIntoFile
00448     ProcessHistoryID reducedPHID = ProcessHistoryRegistry::instance()->extra().reduceProcessHistoryID(r.processHistoryID());
00449     // Add run to index.
00450     indexIntoFile_.addEntry(reducedPHID, runAux_.run(), 0U, 0U, runEntryNumber_);
00451     ++runEntryNumber_;
00452     fillBranches(InRun, r, 0);
00453     runTree_.optimizeBaskets(10ULL*1024*1024);
00454   }
00455 
00456   void RootOutputFile::writeParentageRegistry() {
00457     Parentage const* desc(0);
00458 
00459     if(!parentageTree_->Branch(poolNames::parentageBranchName().c_str(),
00460                                         &desc, om_->basketSize(), 0))
00461       throw Exception(errors::FatalRootError)
00462         << "Failed to create a branch for Parentages in the output file";
00463 
00464     
00465     //NOTE: for some reason the empty Parentage is not added to the registry some of the time
00466     ParentageRegistry& ptReg = *ParentageRegistry::instance();
00467     ptReg.insertMapped(Parentage());
00468     
00469     std::vector<ParentageID> orderedIDs(parentageIDs_.size());
00470     for(std::map<ParentageID,unsigned int>::const_iterator it = parentageIDs_.begin(),
00471         itEnd = parentageIDs_.end();
00472         it != itEnd;
00473         ++it) {
00474       orderedIDs[it->second]=it->first;
00475     }
00476     //now put them into the TTree in the correct order
00477     for(std::vector<ParentageID>::const_iterator it = orderedIDs.begin(),
00478         itEnd = orderedIDs.end();
00479         it != itEnd;
00480         ++it) {
00481       desc = ptReg.getMapped(*it);
00482       //NOTE: some old format files have missing Parentage info
00483       // so a null value of desc can't be fatal.
00484       // Root will default construct an object in that case.
00485       parentageTree_->Fill();
00486     }    
00487   }
00488 
00489   void RootOutputFile::writeFileFormatVersion() {
00490     FileFormatVersion fileFormatVersion(getFileFormatVersion());
00491     FileFormatVersion* pFileFmtVsn = &fileFormatVersion;
00492     TBranch* b = metaDataTree_->Branch(poolNames::fileFormatVersionBranchName().c_str(), &pFileFmtVsn, om_->basketSize(), 0);
00493     assert(b);
00494     b->Fill();
00495   }
00496 
00497   void RootOutputFile::writeFileIdentifier() {
00498     FileID* fidPtr = &fid_;
00499     TBranch* b = metaDataTree_->Branch(poolNames::fileIdentifierBranchName().c_str(), &fidPtr, om_->basketSize(), 0);
00500     assert(b);
00501     b->Fill();
00502   }
00503 
00504   void RootOutputFile::writeIndexIntoFile() {
00505     if (eventTree_.checkEntriesInReadBranches(eventEntryNumber_) == false) {
00506       Exception ex(errors::OtherCMS);
00507       ex << "The number of entries in at least one output TBranch whose entries\n"
00508             "were copied from the input does not match the number of events\n"
00509             "recorded in IndexIntoFile. This might (or might not) indicate a\n"
00510             "problem related to fast copy.";
00511       ex.addContext("Calling RootOutputFile::writeIndexIntoFile");
00512       throw ex;
00513     }
00514     indexIntoFile_.sortVector_Run_Or_Lumi_Entries();
00515     IndexIntoFile* iifPtr = &indexIntoFile_;
00516     TBranch* b = metaDataTree_->Branch(poolNames::indexIntoFileBranchName().c_str(), &iifPtr, om_->basketSize(), 0);
00517     assert(b);
00518     b->Fill();
00519   }
00520 
00521   void RootOutputFile::writeProcessConfigurationRegistry() {
00522     typedef ProcessConfigurationRegistry::collection_type Map;
00523     Map const& procConfigMap = ProcessConfigurationRegistry::instance()->data();
00524     ProcessConfigurationVector procConfigVector;
00525     for(Map::const_iterator i = procConfigMap.begin(), e = procConfigMap.end(); i != e; ++i) {
00526       procConfigVector.push_back(i->second);
00527     }
00528     sort_all(procConfigVector);
00529     ProcessConfigurationVector* p = &procConfigVector;
00530     TBranch* b = metaDataTree_->Branch(poolNames::processConfigurationBranchName().c_str(), &p, om_->basketSize(), 0);
00531     assert(b);
00532     b->Fill();
00533   }
00534 
00535   void RootOutputFile::writeProcessHistoryRegistry() {
00536     typedef ProcessHistoryRegistry::collection_type Map;
00537     Map const& procHistoryMap = ProcessHistoryRegistry::instance()->data();
00538     ProcessHistoryVector procHistoryVector;
00539     for(Map::const_iterator i = procHistoryMap.begin(), e = procHistoryMap.end(); i != e; ++i) {
00540       procHistoryVector.push_back(i->second);
00541     }
00542     ProcessHistoryVector* p = &procHistoryVector;
00543     TBranch* b = metaDataTree_->Branch(poolNames::processHistoryBranchName().c_str(), &p, om_->basketSize(), 0);
00544     assert(b);
00545     b->Fill();
00546   }
00547 
00548   void RootOutputFile::writeBranchIDListRegistry() {
00549     BranchIDLists const* p = om_->branchIDLists();
00550     TBranch* b = metaDataTree_->Branch(poolNames::branchIDListBranchName().c_str(), &p, om_->basketSize(), 0);
00551     assert(b);
00552     b->Fill();
00553   }
00554 
00555   void RootOutputFile::writeParameterSetRegistry() {
00556     std::pair<ParameterSetID, ParameterSetBlob> idToBlob;
00557     std::pair<ParameterSetID, ParameterSetBlob>* pIdToBlob = &idToBlob;
00558     TBranch* b = parameterSetsTree_->Branch(poolNames::idToParameterSetBlobsBranchName().c_str(),&pIdToBlob,om_->basketSize(), 0);
00559 
00560     for(pset::Registry::const_iterator it = pset::Registry::instance()->begin(),
00561         itEnd = pset::Registry::instance()->end();
00562         it != itEnd;
00563         ++it) {
00564       idToBlob.first = it->first;
00565       idToBlob.second.pset() = it->second.toString();
00566 
00567       b->Fill();
00568     }
00569   }
00570 
00571   void RootOutputFile::writeProductDescriptionRegistry() {
00572     // Make a local copy of the ProductRegistry, removing any transient or pruned products.
00573     typedef ProductRegistry::ProductList ProductList;
00574     Service<ConstProductRegistry> reg;
00575     ProductRegistry pReg(reg->productList());
00576     ProductList& pList  = const_cast<ProductList &>(pReg.productList());
00577     for(auto const& prod : pList) {
00578       if(prod.second.branchID() != prod.second.originalBranchID()) {
00579         if(branchesWithStoredHistory_.find(prod.second.branchID()) != branchesWithStoredHistory_.end()) {
00580           branchesWithStoredHistory_.insert(prod.second.originalBranchID());
00581         }
00582       }
00583     }
00584     std::set<BranchID>::iterator end = branchesWithStoredHistory_.end();
00585     for(ProductList::iterator it = pList.begin(); it != pList.end();) {
00586       if(branchesWithStoredHistory_.find(it->second.branchID()) == end) {
00587         // avoid invalidating iterator on deletion
00588         ProductList::iterator itCopy = it;
00589         ++it;
00590         pList.erase(itCopy);
00591 
00592       } else {
00593         ++it;
00594       }
00595     }
00596 
00597     ProductRegistry* ppReg = &pReg;
00598     TBranch* b = metaDataTree_->Branch(poolNames::productDescriptionBranchName().c_str(), &ppReg, om_->basketSize(), 0);
00599     assert(b);
00600     b->Fill();
00601   }
00602   void RootOutputFile::writeProductDependencies() {
00603     BranchChildren& pDeps = const_cast<BranchChildren&>(om_->branchChildren());
00604     BranchChildren* ppDeps = &pDeps;
00605     TBranch* b = metaDataTree_->Branch(poolNames::productDependenciesBranchName().c_str(), &ppDeps, om_->basketSize(), 0);
00606     assert(b);
00607     b->Fill();
00608   }
00609 
00610   void RootOutputFile::finishEndFile() {
00611     metaDataTree_->SetEntries(-1);
00612     RootOutputTree::writeTTree(metaDataTree_);
00613     RootOutputTree::writeTTree(parameterSetsTree_);
00614 
00615     RootOutputTree::writeTTree(parentageTree_);
00616 
00617     // Create branch aliases for all the branches in the
00618     // events/lumis/runs trees. The loop is over all types of data
00619     // products.
00620     for(int i = InEvent; i < NumBranchTypes; ++i) {
00621       BranchType branchType = static_cast<BranchType>(i);
00622       setBranchAliases(treePointers_[branchType]->tree(), om_->keptProducts()[branchType]);
00623       treePointers_[branchType]->writeTree();
00624     }
00625 
00626     // close the file -- mfp
00627     // Just to play it safe, zero all pointers to objects in the TFile to be closed.
00628     metaDataTree_ = parentageTree_ = 0;
00629     for(RootOutputTreePtrArray::iterator it = treePointers_.begin(), itEnd = treePointers_.end(); it != itEnd; ++it) {
00630       (*it)->close();
00631       (*it) = 0;
00632     }
00633     filePtr_->Close();
00634     filePtr_.reset();
00635 
00636     // report that file has been closed
00637     Service<JobReport> reportSvc;
00638     reportSvc->outputFileClosed(reportToken_);
00639 
00640   }
00641 
00642   void
00643   RootOutputFile::setBranchAliases(TTree* tree, Selections const& branches) const {
00644     if(tree && tree->GetNbranches() != 0) {
00645       for(Selections::const_iterator i = branches.begin(), iEnd = branches.end();
00646           i != iEnd; ++i) {
00647         BranchDescription const& pd = **i;
00648         std::string const& full = pd.branchName() + "obj";
00649         if(pd.branchAliases().empty()) {
00650           std::string const& alias =
00651               (pd.productInstanceName().empty() ? pd.moduleLabel() : pd.productInstanceName());
00652           tree->SetAlias(alias.c_str(), full.c_str());
00653         } else {
00654           std::set<std::string>::const_iterator it = pd.branchAliases().begin(), itEnd = pd.branchAliases().end();
00655           for(; it != itEnd; ++it) {
00656             tree->SetAlias((*it).c_str(), full.c_str());
00657           }
00658         }
00659       }
00660     }
00661   }
00662 
00663   void
00664   RootOutputFile::insertAncestors(ProductProvenance const& iGetParents,
00665                                   EventPrincipal const& principal,
00666                                   bool produced,
00667                                   std::set<StoredProductProvenance>& oToFill) {
00668     assert(om_->dropMetaData() != PoolOutputModule::DropAll);
00669     assert(produced || om_->dropMetaData() != PoolOutputModule::DropPrior);
00670     if(om_->dropMetaData() == PoolOutputModule::DropDroppedPrior && !produced) return;
00671     BranchMapper const& iMapper = *principal.branchMapperPtr();
00672     std::vector<BranchID> const& parentIDs = iGetParents.parentage().parents();
00673     for(std::vector<BranchID>::const_iterator it = parentIDs.begin(), itEnd = parentIDs.end();
00674           it != itEnd; ++it) {
00675       branchesWithStoredHistory_.insert(*it);
00676       ProductProvenance const* info = iMapper.branchIDToProvenance(*it);
00677       if(info) {
00678         if(om_->dropMetaData() == PoolOutputModule::DropNone ||
00679                  principal.getProvenance(info->branchID()).product().produced()) {
00680           if(insertProductProvenance(*info,oToFill) ) {
00681             //haven't seen this one yet
00682             insertAncestors(*info, principal, produced, oToFill);
00683           }
00684         }
00685       }
00686     }
00687   }
00688 
00689   void RootOutputFile::fillBranches(
00690                 BranchType const& branchType,
00691                 Principal const& principal,
00692                 StoredProductProvenanceVector* productProvenanceVecPtr) {
00693 
00694     typedef std::vector<std::pair<TClass*, void const*> > Dummies;
00695     Dummies dummies;
00696 
00697     bool const fastCloning = (branchType == InEvent) && (whyNotFastClonable_ == FileBlock::CanFastClone);
00698 
00699     OutputItemList const& items = om_->selectedOutputItemList()[branchType];
00700 
00701     std::set<StoredProductProvenance> provenanceToKeep;
00702 
00703     // Loop over EDProduct branches, fill the provenance, and write the branch.
00704     for(OutputItemList::const_iterator i = items.begin(), iEnd = items.end(); i != iEnd; ++i) {
00705 
00706       BranchID const& id = i->branchDescription_->branchID();
00707       branchesWithStoredHistory_.insert(id);
00708 
00709       bool produced = i->branchDescription_->produced();
00710       bool keepProvenance = productProvenanceVecPtr != 0 &&
00711                             (om_->dropMetaData() == PoolOutputModule::DropNone ||
00712                              om_->dropMetaData() == PoolOutputModule::DropDroppedPrior ||
00713                             (om_->dropMetaData() == PoolOutputModule::DropPrior && produced));
00714       bool getProd = (produced || !fastCloning ||
00715          treePointers_[branchType]->uncloned(i->branchDescription_->branchName()));
00716 
00717       void const* product = 0;
00718       OutputHandle const oh = principal.getForOutput(id, getProd);
00719       if(keepProvenance && oh.productProvenance()) {
00720         insertProductProvenance(*oh.productProvenance(),provenanceToKeep);
00721         //provenanceToKeep.insert(*oh.productProvenance());
00722         EventPrincipal const& eventPrincipal = dynamic_cast<EventPrincipal const&>(principal);
00723         assert(eventPrincipal.branchMapperPtr());
00724         insertAncestors(*oh.productProvenance(), eventPrincipal, produced, provenanceToKeep);
00725       }
00726       product = oh.wrapper();
00727       if(getProd) {
00728         if(product == 0) {
00729           // No product with this ID is in the event.
00730           // Add a null product.
00731           TClass* cp = gROOT->GetClass(i->branchDescription_->wrappedName().c_str());
00732           product = cp->New();
00733           dummies.emplace_back(cp, product);
00734         }
00735         i->product_ = product;
00736       }
00737     }
00738 
00739     if(productProvenanceVecPtr != 0) productProvenanceVecPtr->assign(provenanceToKeep.begin(), provenanceToKeep.end());
00740     treePointers_[branchType]->fillTree();
00741     if(productProvenanceVecPtr != 0) productProvenanceVecPtr->clear();
00742     for(Dummies::iterator it = dummies.begin(), itEnd = dummies.end(); it != itEnd; ++it) {
00743       it->first->Destructor(const_cast<void *>(it->second));
00744     }
00745   }
00746   
00747   bool
00748   RootOutputFile::insertProductProvenance(const edm::ProductProvenance& iProv,
00749                                           std::set<edm::StoredProductProvenance>& oToInsert) {
00750     StoredProductProvenance toStore;
00751     toStore.branchID_ = iProv.branchID().id();
00752     std::set<edm::StoredProductProvenance>::iterator itFound = oToInsert.find(toStore);
00753     if(itFound == oToInsert.end()) {
00754       //get the index to the ParentageID or insert a new value if not already present
00755       std::pair<std::map<edm::ParentageID,unsigned int>::iterator,bool> i = parentageIDs_.insert(std::make_pair(iProv.parentageID(),static_cast<unsigned int>(parentageIDs_.size())));
00756       toStore.parentageIDIndex_ = i.first->second;
00757       if(toStore.parentageIDIndex_ >= parentageIDs_.size()) {
00758         throw edm::Exception(errors::LogicError)
00759           << "RootOutputFile::insertProductProvenance\n"
00760           << "The parentage ID index value " << toStore.parentageIDIndex_ << " is out of bounds.  The maximum value is currently " << parentageIDs_.size()-1 << ".\n"
00761           << "This should never happen.\n"
00762           << "Please report this to the framework hypernews forum 'hn-cms-edmFramework@cern.ch'.\n";
00763       }
00764 
00765       oToInsert.insert(toStore);
00766       return true;
00767     }
00768     return false;
00769   }
00770 }