CMS 3D CMS Logo

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