CMS 3D CMS Logo

/data/doxygen/doxygen-1.7.3/gen/CMSSW_4_2_8/src/DataFormats/FWLite/src/DataGetterHelper.cc

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 //
00003 // Package:     DataFormats/FWLite
00004 // Class  :     DataGetterHelper
00005 //
00006 // Implementation:
00007 //     [Notes on implementation]
00008 //
00009 // Original Author: Eric Vaandering
00010 //         Created:  Fri Jan 29 11:58:01 CST 2010
00011 //
00012 
00013 // system include files
00014 #include <iostream>
00015 #include "Reflex/Type.h"
00016 #include "Reflex/Object.h"
00017 
00018 // user include files
00019 #include "DataFormats/FWLite/interface/DataGetterHelper.h"
00020 #include "TFile.h"
00021 #include "TTree.h"
00022 #include "TTreeCache.h"
00023 #include "FWCore/Utilities/interface/Exception.h"
00024 #include "DataFormats/Common/interface/EDProduct.h"
00025 
00026 #include "FWCore/FWLite/interface/setRefStreamer.h"
00027 
00028 #include "FWCore/Utilities/interface/WrappedClassName.h"
00029 
00030 #include "FWCore/Utilities/interface/EDMException.h"
00031 
00032 #define TTCACHE_SIZE 20*1024*1024
00033 
00034 namespace fwlite {
00035     //
00036     // constants, enums and typedefs
00037     //
00038 
00039     //
00040     // DataGetterHelper takes ownership of the TTreeCache, so make use of it by
00041     // the file exception safe
00042     //
00043     class withTCache {
00044     public:
00045         withTCache(TFile* file, TTreeCache* tc) : f_(file) { f_->SetCacheRead(tc); }
00046         ~withTCache() { f_->SetCacheRead(0); }
00047     private:
00048         TFile* f_;
00049     };
00050 
00051     //
00052     // static data member definitions
00053     //
00054     typedef std::map<internal::DataKey, boost::shared_ptr<internal::Data> > DataMap;
00055     // empty object used to signal that the branch requested was not found
00056     static internal::Data branchNotFound;
00057 
00058     //
00059     // constructors and destructor
00060     //
00061     DataGetterHelper::DataGetterHelper(TTree* tree,
00062                                        boost::shared_ptr<HistoryGetterBase> historyGetter,
00063                                        boost::shared_ptr<BranchMapReader> branchMap,
00064                                        boost::shared_ptr<edm::EDProductGetter> getter,
00065                                        bool useCache):
00066         branchMap_(branchMap),
00067         historyGetter_(historyGetter),
00068         getter_(getter),
00069         tcache_(0),
00070         tcTrained_(false)
00071     {
00072         if(0==tree) {
00073             throw cms::Exception("NoTree")<<"The TTree pointer passed to the constructor was null";
00074         }
00075         tree_ = tree;
00076         if (useCache) {
00077             tree_->SetCacheSize(TTCACHE_SIZE);
00078             TFile* iFile(branchMap_->getFile());
00079             tcache_.reset(dynamic_cast<TTreeCache*>(iFile->GetCacheRead()));
00080             iFile->SetCacheRead(0);
00081             //std::cout << "In const " << iFile << " " << tcache_ << " " << iFile->GetCacheRead() << std::endl;
00082         }
00083     }
00084 
00085     // DataGetterHelper::DataGetterHelper(const DataGetterHelper& rhs)
00086     // {
00087     //    // do actual copying here;
00088     // }
00089 
00090     DataGetterHelper::~DataGetterHelper() {    }
00091 
00092     //
00093     // assignment operators
00094     //
00095     // const DataGetterHelper& DataGetterHelper::operator=(const DataGetterHelper& rhs)
00096     // {
00097     //   //An exception safe implementation is
00098     //   DataGetterHelper temp(rhs);
00099     //   swap(rhs);
00100     //
00101     //   return *this;
00102     // }
00103 
00104     //
00105     // member functions
00106     //
00107 
00108 
00109 
00110     //
00111     // const member functions
00112     //
00113 
00114     //
00115     // static member functions
00116     //
00117 
00118 
00119     static
00120     TBranch* findBranch(TTree* iTree, const std::string& iMainLabels, const std::string& iProcess) {
00121         std::string branchName(iMainLabels);
00122         branchName+=iProcess;
00123         //branchName+=".obj";
00124         branchName+=".";
00125         return iTree->GetBranch(branchName.c_str());
00126     }
00127 
00128     void
00129     DataGetterHelper::getBranchData(edm::EDProductGetter* iGetter,
00130                     Long64_t index,
00131                     internal::Data& iData) const
00132     {
00133         GetterOperate op(iGetter);
00134 
00135         //WORK AROUND FOR ROOT!!
00136         //Create a new instance so that we can clear any cache the object uses
00137         //this slows the code down
00138         Reflex::Object obj = iData.obj_;
00139         iData.obj_ = iData.obj_.TypeOf().Construct();
00140         iData.pObj_ = iData.obj_.Address();
00141         iData.branch_->SetAddress(&(iData.pObj_));
00142         //If a REF to this was requested in the past, we might as well do the work now
00143         if(0!=iData.pProd_) {
00144             //The type is the same so the offset will be the same
00145             void* p = iData.pProd_;
00146             iData.pProd_ = reinterpret_cast<edm::EDProduct*>(static_cast<char*>(iData.obj_.Address())+(static_cast<char*>(p)-static_cast<char*>(obj.Address())));
00147         }
00148         obj.Destruct();
00149         //END OF WORK AROUND
00150 
00151         if (0 == tcache_.get()) {
00152             iData.branch_->GetEntry(index);
00153         } else {
00154             if (!tcTrained_) {
00155                 tcache_->SetLearnEntries(100);
00156                 tcache_->SetEntryRange(0, tree_->GetEntries());
00157                 tcTrained_ = true;
00158             }
00159             withTCache tcguard(branchMap_->getFile(), tcache_.get());
00160             tree_->LoadTree(index);
00161             iData.branch_->GetEntry(index);
00162        }
00163        iData.lastProduct_=index;
00164     }
00165 
00166 
00167     internal::Data&
00168     DataGetterHelper::getBranchDataFor(const std::type_info& iInfo,
00169                     const char* iModuleLabel,
00170                     const char* iProductInstanceLabel,
00171                     const char* iProcessLabel) const
00172     {
00173         edm::TypeID type(iInfo);
00174         internal::DataKey key(type, iModuleLabel, iProductInstanceLabel, iProcessLabel);
00175 
00176         boost::shared_ptr<internal::Data> theData;
00177         DataMap::iterator itFind = data_.find(key);
00178         if(itFind == data_.end() ) {
00179             //see if such a branch actually exists
00180             const std::string sep("_");
00181             //CHANGE: If this fails, need to lookup the the friendly name which was used to write the file
00182             std::string name(type.friendlyClassName());
00183             name +=sep+std::string(key.module());
00184             name +=sep+std::string(key.product())+sep;
00185 
00186             //if we have to lookup the process label, remember it and register the product again
00187             std::string foundProcessLabel;
00188             TBranch* branch = 0;
00189 
00190             if (0==iProcessLabel || iProcessLabel==key.kEmpty() ||
00191                 strlen(iProcessLabel)==0) {
00192                 const std::string* lastLabel=0;
00193                 //have to search in reverse order since newest are on the bottom
00194                 const edm::ProcessHistory& h = DataGetterHelper::history();
00195                 for (edm::ProcessHistory::const_reverse_iterator iproc = h.rbegin(), eproc = h.rend();
00196                     iproc != eproc;
00197                     ++iproc) {
00198 
00199                     lastLabel = &(iproc->processName());
00200                     branch=findBranch(tree_,name,iproc->processName());
00201                     if(0!=branch) {
00202                     break;
00203                     }
00204                 }
00205                 if(0==branch) {
00206                     return branchNotFound;
00207                 }
00208                 //do we already have this one?
00209                 if(0!=lastLabel) {
00210                     internal::DataKey fullKey(type,iModuleLabel,iProductInstanceLabel,lastLabel->c_str());
00211                     itFind = data_.find(fullKey);
00212                     if(itFind != data_.end()) {
00213                         //remember the data we've found
00214                         theData = itFind->second;
00215                     } else {
00216                         //only set this if we don't already have it since it this string is not empty we re-register
00217                         foundProcessLabel = *lastLabel;
00218                     }
00219                 }
00220             } else {
00221                 //we have all the pieces
00222                 branch = findBranch(tree_,name,key.process());
00223                 if(0==branch){
00224                     return branchNotFound;
00225                 }
00226             }
00227 
00228             //cache the info
00229             char* newModule = new char[strlen(iModuleLabel)+1];
00230             std::strcpy(newModule,iModuleLabel);
00231             labels_.push_back(newModule);
00232 
00233             char* newProduct = const_cast<char*>(key.product());
00234             if(newProduct[0] != 0) {
00235                 newProduct = new char[strlen(newProduct)+1];
00236                 std::strcpy(newProduct,key.product());
00237                 labels_.push_back(newProduct);
00238             }
00239             char* newProcess = const_cast<char*>(key.process());
00240             if(newProcess[0]!=0) {
00241                 newProcess = new char[strlen(newProcess)+1];
00242                 std::strcpy(newProcess,key.process());
00243                 labels_.push_back(newProcess);
00244             }
00245             internal::DataKey newKey(edm::TypeID(iInfo),newModule,newProduct,newProcess);
00246 
00247             if(0 == theData.get() ) {
00248                 //We do not already have this data as another key
00249 
00250                 //Use Reflex to create an instance of the object to be used as a buffer
00251                 Reflex::Type rType = Reflex::Type::ByTypeInfo(iInfo);
00252                 if(rType == Reflex::Type()) {
00253                     throw cms::Exception("UnknownType")<<"No Reflex dictionary exists for type "<<iInfo.name();
00254                 }
00255                 Reflex::Object obj = rType.Construct();
00256 
00257                 if(obj.Address() == 0) {
00258                     throw cms::Exception("ConstructionFailed")<<"failed to construct an instance of "<<rType.Name();
00259                 }
00260                 boost::shared_ptr<internal::Data> newData(new internal::Data() );
00261                 newData->branch_ = branch;
00262                 newData->obj_ = obj;
00263                 newData->lastProduct_=-1;
00264                 newData->pObj_ = obj.Address();
00265                 newData->pProd_ = 0;
00266                 branch->SetAddress(&(newData->pObj_));
00267                 theData = newData;
00268             }
00269             itFind = data_.insert(std::make_pair(newKey, theData)).first;
00270 
00271             if(foundProcessLabel.size()) {
00272                 //also remember it with the process label
00273                 newProcess = new char[foundProcessLabel.size()+1];
00274                 std::strcpy(newProcess,foundProcessLabel.c_str());
00275                 labels_.push_back(newProcess);
00276                 internal::DataKey newKey(edm::TypeID(iInfo),newModule,newProduct,newProcess);
00277 
00278                 data_.insert(std::make_pair(newKey,theData));
00279             }
00280         }
00281         return *(itFind->second);
00282     }
00283 
00284     const std::string
00285     DataGetterHelper::getBranchNameFor(const std::type_info& iInfo,
00286                     const char* iModuleLabel,
00287                     const char* iProductInstanceLabel,
00288                     const char* iProcessLabel) const
00289     {
00290         internal::Data& theData =
00291             DataGetterHelper::getBranchDataFor(iInfo, iModuleLabel, iProductInstanceLabel, iProcessLabel);
00292 
00293         if (0 != theData.branch_) {
00294             return std::string(theData.branch_->GetName());
00295         }
00296         return std::string("");
00297     }
00298 
00299     bool
00300     DataGetterHelper::getByLabel(const std::type_info& iInfo,
00301                     const char* iModuleLabel,
00302                     const char* iProductInstanceLabel,
00303                     const char* iProcessLabel,
00304                     void* oData, Long_t index) const
00305     {
00306         // Maintain atEnd() check in parent classes
00307         void** pOData = reinterpret_cast<void**>(oData);
00308         *pOData = 0;
00309 
00310         internal::Data& theData =
00311             DataGetterHelper::getBranchDataFor(iInfo, iModuleLabel, iProductInstanceLabel, iProcessLabel);
00312 
00313         if (0 != theData.branch_) {
00314             if(index != theData.lastProduct_) {
00315                 //haven't gotten the data for this event
00316                 getBranchData(getter_.get(), index, theData);
00317             }
00318             *pOData = theData.obj_.Address();
00319         }
00320 
00321         if ( 0 == *pOData ) return false;
00322         else return true;
00323     }
00324 
00325 
00326     edm::EDProduct const*
00327     DataGetterHelper::getByProductID(edm::ProductID const& iID, Long_t index) const
00328     {
00329         std::map<edm::ProductID,boost::shared_ptr<internal::Data> >::const_iterator itFound = idToData_.find(iID);
00330         if(itFound == idToData_.end() ) {
00331             edm::BranchDescription bDesc = branchMap_->productToBranch(iID);
00332 
00333             if (!bDesc.branchID().isValid()) {
00334                 return 0;
00335             }
00336 
00337             //Calculate the key from the branch description
00338             Reflex::Type type( Reflex::Type::ByName(edm::wrappedClassName(bDesc.fullClassName())));
00339             assert( Reflex::Type() != type) ;
00340 
00341             //Only the product instance label may be empty
00342             const char* pIL = bDesc.productInstanceName().c_str();
00343             if(pIL[0] == 0) {
00344                 pIL = 0;
00345             }
00346             internal::DataKey k(edm::TypeID(type.TypeInfo()),
00347                                 bDesc.moduleLabel().c_str(),
00348                                 pIL,
00349                                 bDesc.processName().c_str());
00350 
00351             //has this already been gotten?
00352             KeyToDataMap::iterator itData = data_.find(k);
00353             if(data_.end() == itData) {
00354                 //ask for the data
00355                 void* dummy = 0;
00356                 getByLabel(type.TypeInfo(),
00357                             k.module(),
00358                             k.product(),
00359                             k.process(),
00360                             &dummy, index);
00361                 if (0 == dummy) {
00362                     return 0;
00363                 }
00364                 itData = data_.find(k);
00365                 assert(itData != data_.end());
00366                 //assert(0!=dummy);
00367                 assert(dummy == itData->second->obj_.Address());
00368             }
00369             itFound = idToData_.insert(std::make_pair(iID,itData->second)).first;
00370         }
00371         if(index != itFound->second->lastProduct_) {
00372             //haven't gotten the data for this event
00373             getBranchData(getter_.get(), index, *(itFound->second));
00374         }
00375         if(0==itFound->second->pProd_) {
00376             //need to convert pointer to proper type
00377             static Reflex::Type sEDProd( Reflex::Type::ByTypeInfo(typeid(edm::EDProduct)));
00378             //assert( sEDProd != Reflex::Type() );
00379             Reflex::Object edProdObj = itFound->second->obj_.CastObject( sEDProd );
00380 
00381             itFound->second->pProd_ = reinterpret_cast<edm::EDProduct*>(edProdObj.Address());
00382 
00383             if(0==itFound->second->pProd_) {
00384                 cms::Exception("FailedConversion")
00385                     <<"failed to convert a '"<<itFound->second->obj_.TypeOf().Name()<<"' to a edm::EDProduct";
00386             }
00387         }
00388         return itFound->second->pProd_;
00389     }
00390 
00391 
00392     const edm::ProcessHistory& DataGetterHelper::history() const {
00393         return historyGetter_->history();
00394     }
00395 
00396 
00397     //
00398     // static member functions
00399     //
00400     void
00401     DataGetterHelper::throwProductNotFoundException(const std::type_info& iType, const char* iModule, const char* iProduct, const char* iProcess)
00402     {
00403         edm::TypeID type(iType);
00404         throw edm::Exception(edm::errors::ProductNotFound)<<"A branch was found for \n  type ='"<<type.className()<<"'\n  module='"<<iModule
00405             <<"'\n  productInstance='"<<((0!=iProduct)?iProduct:"")<<"'\n  process='"<<((0!=iProcess)?iProcess:"")<<"'\n"
00406             "but no data is available for this Lumi";
00407     }
00408 
00409 }