CMS 3D CMS Logo

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