CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_6_1_1/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     std::set<BranchID>::iterator end = branchesWithStoredHistory_.end();
00578     for(ProductList::iterator it = pList.begin(); it != pList.end();) {
00579       if(branchesWithStoredHistory_.find(it->second.branchID()) == end) {
00580         // avoid invalidating iterator on deletion
00581         ProductList::iterator itCopy = it;
00582         ++it;
00583         pList.erase(itCopy);
00584 
00585       } else {
00586         ++it;
00587       }
00588     }
00589 
00590     ProductRegistry* ppReg = &pReg;
00591     TBranch* b = metaDataTree_->Branch(poolNames::productDescriptionBranchName().c_str(), &ppReg, om_->basketSize(), 0);
00592     assert(b);
00593     b->Fill();
00594   }
00595   void RootOutputFile::writeProductDependencies() {
00596     BranchChildren& pDeps = const_cast<BranchChildren&>(om_->branchChildren());
00597     BranchChildren* ppDeps = &pDeps;
00598     TBranch* b = metaDataTree_->Branch(poolNames::productDependenciesBranchName().c_str(), &ppDeps, om_->basketSize(), 0);
00599     assert(b);
00600     b->Fill();
00601   }
00602 
00603   void RootOutputFile::finishEndFile() {
00604     metaDataTree_->SetEntries(-1);
00605     RootOutputTree::writeTTree(metaDataTree_);
00606     RootOutputTree::writeTTree(parameterSetsTree_);
00607 
00608     RootOutputTree::writeTTree(parentageTree_);
00609 
00610     // Create branch aliases for all the branches in the
00611     // events/lumis/runs trees. The loop is over all types of data
00612     // products.
00613     for(int i = InEvent; i < NumBranchTypes; ++i) {
00614       BranchType branchType = static_cast<BranchType>(i);
00615       setBranchAliases(treePointers_[branchType]->tree(), om_->keptProducts()[branchType]);
00616       treePointers_[branchType]->writeTree();
00617     }
00618 
00619     // close the file -- mfp
00620     // Just to play it safe, zero all pointers to objects in the TFile to be closed.
00621     metaDataTree_ = parentageTree_ = 0;
00622     for(RootOutputTreePtrArray::iterator it = treePointers_.begin(), itEnd = treePointers_.end(); it != itEnd; ++it) {
00623       (*it)->close();
00624       (*it) = 0;
00625     }
00626     filePtr_->Close();
00627     filePtr_.reset();
00628 
00629     // report that file has been closed
00630     Service<JobReport> reportSvc;
00631     reportSvc->outputFileClosed(reportToken_);
00632 
00633   }
00634 
00635   void
00636   RootOutputFile::setBranchAliases(TTree* tree, Selections const& branches) const {
00637     if(tree && tree->GetNbranches() != 0) {
00638       for(Selections::const_iterator i = branches.begin(), iEnd = branches.end();
00639           i != iEnd; ++i) {
00640         BranchDescription const& pd = **i;
00641         std::string const& full = pd.branchName() + "obj";
00642         if(pd.branchAliases().empty()) {
00643           std::string const& alias =
00644               (pd.productInstanceName().empty() ? pd.moduleLabel() : pd.productInstanceName());
00645           tree->SetAlias(alias.c_str(), full.c_str());
00646         } else {
00647           std::set<std::string>::const_iterator it = pd.branchAliases().begin(), itEnd = pd.branchAliases().end();
00648           for(; it != itEnd; ++it) {
00649             tree->SetAlias((*it).c_str(), full.c_str());
00650           }
00651         }
00652       }
00653     }
00654   }
00655 
00656   void
00657   RootOutputFile::insertAncestors(ProductProvenance const& iGetParents,
00658                                   EventPrincipal const& principal,
00659                                   bool produced,
00660                                   std::set<StoredProductProvenance>& oToFill) {
00661     assert(om_->dropMetaData() != PoolOutputModule::DropAll);
00662     assert(produced || om_->dropMetaData() != PoolOutputModule::DropPrior);
00663     if(om_->dropMetaData() == PoolOutputModule::DropDroppedPrior && !produced) return;
00664     BranchMapper const& iMapper = *principal.branchMapperPtr();
00665     std::vector<BranchID> const& parentIDs = iGetParents.parentage().parents();
00666     for(std::vector<BranchID>::const_iterator it = parentIDs.begin(), itEnd = parentIDs.end();
00667           it != itEnd; ++it) {
00668       branchesWithStoredHistory_.insert(*it);
00669       ProductProvenance const* info = iMapper.branchIDToProvenance(*it);
00670       if(info) {
00671         if(om_->dropMetaData() == PoolOutputModule::DropNone ||
00672                  principal.getProvenance(info->branchID()).product().produced()) {
00673           if(insertProductProvenance(*info,oToFill) ) {
00674             //haven't seen this one yet
00675             insertAncestors(*info, principal, produced, oToFill);
00676           }
00677         }
00678       }
00679     }
00680   }
00681 
00682   void RootOutputFile::fillBranches(
00683                 BranchType const& branchType,
00684                 Principal const& principal,
00685                 StoredProductProvenanceVector* productProvenanceVecPtr) {
00686 
00687     typedef std::vector<std::pair<TClass*, void const*> > Dummies;
00688     Dummies dummies;
00689 
00690     bool const fastCloning = (branchType == InEvent) && (whyNotFastClonable_ == FileBlock::CanFastClone);
00691 
00692     OutputItemList const& items = om_->selectedOutputItemList()[branchType];
00693 
00694     std::set<StoredProductProvenance> provenanceToKeep;
00695 
00696     // Loop over EDProduct branches, fill the provenance, and write the branch.
00697     for(OutputItemList::const_iterator i = items.begin(), iEnd = items.end(); i != iEnd; ++i) {
00698 
00699       BranchID const& id = i->branchDescription_->branchID();
00700       branchesWithStoredHistory_.insert(id);
00701       if(i->branchDescription_->isAlias()) {
00702         // We're keeping an EDAlias. Keep the registry entry for the original branch.
00703         branchesWithStoredHistory_.insert(i->branchDescription_->originalBranchID());
00704       }
00705 
00706       bool produced = i->branchDescription_->produced();
00707       bool keepProvenance = productProvenanceVecPtr != 0 &&
00708                             (om_->dropMetaData() == PoolOutputModule::DropNone ||
00709                              om_->dropMetaData() == PoolOutputModule::DropDroppedPrior ||
00710                             (om_->dropMetaData() == PoolOutputModule::DropPrior && produced));
00711       bool getProd = (produced || !fastCloning ||
00712          treePointers_[branchType]->uncloned(i->branchDescription_->branchName()));
00713 
00714       void const* product = 0;
00715       OutputHandle const oh = principal.getForOutput(id, getProd);
00716       if(keepProvenance && oh.productProvenance()) {
00717         insertProductProvenance(*oh.productProvenance(),provenanceToKeep);
00718         //provenanceToKeep.insert(*oh.productProvenance());
00719         EventPrincipal const& eventPrincipal = dynamic_cast<EventPrincipal const&>(principal);
00720         assert(eventPrincipal.branchMapperPtr());
00721         insertAncestors(*oh.productProvenance(), eventPrincipal, produced, provenanceToKeep);
00722       }
00723       product = oh.wrapper();
00724       if(getProd) {
00725         if(product == 0) {
00726           // No product with this ID is in the event.
00727           // Add a null product.
00728           TClass* cp = gROOT->GetClass(i->branchDescription_->wrappedName().c_str());
00729           product = cp->New();
00730           dummies.emplace_back(cp, product);
00731         }
00732         i->product_ = product;
00733       }
00734     }
00735 
00736     if(productProvenanceVecPtr != 0) productProvenanceVecPtr->assign(provenanceToKeep.begin(), provenanceToKeep.end());
00737     treePointers_[branchType]->fillTree();
00738     if(productProvenanceVecPtr != 0) productProvenanceVecPtr->clear();
00739     for(Dummies::iterator it = dummies.begin(), itEnd = dummies.end(); it != itEnd; ++it) {
00740       it->first->Destructor(const_cast<void *>(it->second));
00741     }
00742   }
00743   
00744   bool
00745   RootOutputFile::insertProductProvenance(const edm::ProductProvenance& iProv,
00746                                           std::set<edm::StoredProductProvenance>& oToInsert) {
00747     StoredProductProvenance toStore;
00748     toStore.branchID_ = iProv.branchID().id();
00749     std::set<edm::StoredProductProvenance>::iterator itFound = oToInsert.find(toStore);
00750     if(itFound == oToInsert.end()) {
00751       //get the index to the ParentageID or insert a new value if not already present
00752       std::pair<std::map<edm::ParentageID,unsigned int>::iterator,bool> i = parentageIDs_.insert(std::make_pair(iProv.parentageID(),static_cast<unsigned int>(parentageIDs_.size())));
00753       toStore.parentageIDIndex_ = i.first->second;
00754       if(toStore.parentageIDIndex_ >= parentageIDs_.size()) {
00755         throw edm::Exception(errors::LogicError)
00756           << "RootOutputFile::insertProductProvenance\n"
00757           << "The parentage ID index value " << toStore.parentageIDIndex_ << " is out of bounds.  The maximum value is currently " << parentageIDs_.size()-1 << ".\n"
00758           << "This should never happen.\n"
00759           << "Please report this to the framework hypernews forum 'hn-cms-edmFramework@cern.ch'.\n";
00760       }
00761 
00762       oToInsert.insert(toStore);
00763       return true;
00764     }
00765     return false;
00766   }
00767 }