CMS 3D CMS Logo

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