CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
DataGetterHelper.cc
Go to the documentation of this file.
1 // -*- C++ -*-
2 //
3 // Package: DataFormats/FWLite
4 // Class : DataGetterHelper
5 //
6 // Implementation:
7 // [Notes on implementation]
8 //
9 // Original Author: Eric Vaandering
10 // Created: Fri Jan 29 11:58:01 CST 2010
11 //
12 
13 // system include files
14 #include <iostream>
15 #include "Reflex/Type.h"
16 #include "Reflex/Object.h"
17 #include "Reflex/Member.h"
18 
19 // user include files
21 #include "TFile.h"
22 #include "TTree.h"
23 #include "TTreeCache.h"
26 
28 
30 
32 
33 #define TTCACHE_SIZE 20*1024*1024
34 
35 namespace fwlite {
36  //
37  // constants, enums and typedefs
38  //
39 
40  //
41  // DataGetterHelper takes ownership of the TTreeCache, so make use of it by
42  // the file exception safe
43  //
44  class withTCache {
45  public:
46  withTCache(TFile* file, TTreeCache* tc) : f_(file) { f_->SetCacheRead(tc); }
47  ~withTCache() { f_->SetCacheRead(0); }
48  private:
49  TFile* f_;
50  };
51 
52  //
53  // static data member definitions
54  //
55  typedef std::map<internal::DataKey, boost::shared_ptr<internal::Data> > DataMap;
56  // empty object used to signal that the branch requested was not found
58 
59  //
60  // constructors and destructor
61  //
63  boost::shared_ptr<HistoryGetterBase> historyGetter,
64  boost::shared_ptr<BranchMapReader> branchMap,
65  boost::shared_ptr<edm::EDProductGetter> getter,
66  bool useCache):
67  branchMap_(branchMap),
68  historyGetter_(historyGetter),
69  getter_(getter),
70  tcache_(0),
71  tcTrained_(false)
72  {
73  if(0==tree) {
74  throw cms::Exception("NoTree")<<"The TTree pointer passed to the constructor was null";
75  }
76  tree_ = tree;
77  if (useCache) {
78  tree_->SetCacheSize(TTCACHE_SIZE);
79  TFile* iFile(branchMap_->getFile());
80  tcache_.reset(dynamic_cast<TTreeCache*>(iFile->GetCacheRead()));
81  iFile->SetCacheRead(0);
82  //std::cout << "In const " << iFile << " " << tcache_ << " " << iFile->GetCacheRead() << std::endl;
83  }
84  }
85 
86  // DataGetterHelper::DataGetterHelper(const DataGetterHelper& rhs)
87  // {
88  // // do actual copying here;
89  // }
90 
92 
93  //
94  // assignment operators
95  //
96  // const DataGetterHelper& DataGetterHelper::operator=(const DataGetterHelper& rhs)
97  // {
98  // //An exception safe implementation is
99  // DataGetterHelper temp(rhs);
100  // swap(rhs);
101  //
102  // return *this;
103  // }
104 
105  //
106  // member functions
107  //
108 
109 
110 
111  //
112  // const member functions
113  //
114 
115  //
116  // static member functions
117  //
118 
119 
120  static
121  TBranch* findBranch(TTree* iTree, std::string const& iMainLabels, std::string const& iProcess) {
122  std::string branchName(iMainLabels);
123  branchName+=iProcess;
124  //branchName+=".obj";
125  branchName+=".";
126  return iTree->GetBranch(branchName.c_str());
127  }
128 
129  void
131  Long64_t index,
132  internal::Data& iData) const
133  {
134  GetterOperate op(iGetter);
135 
136  //WORK AROUND FOR ROOT!!
137  //Create a new instance so that we can clear any cache the object uses
138  //this slows the code down
139  Reflex::Object obj = iData.obj_;
140  iData.obj_ = iData.obj_.TypeOf().Construct();
141  iData.pObj_ = iData.obj_.Address();
142  iData.branch_->SetAddress(&(iData.pObj_));
143  //If a REF to this was requested in the past, we might as well do the work now
144  if(0!=iData.pProd_) {
145  iData.pProd_ = iData.obj_.Address();
146  }
147  obj.Destruct();
148  //END OF WORK AROUND
149 
150  if (0 == tcache_.get()) {
151  iData.branch_->GetEntry(index);
152  } else {
153  if (!tcTrained_) {
154  tcache_->SetLearnEntries(100);
155  tcache_->SetEntryRange(0, tree_->GetEntries());
156  tcTrained_ = true;
157  }
158  withTCache tcguard(branchMap_->getFile(), tcache_.get());
159  tree_->LoadTree(index);
160  iData.branch_->GetEntry(index);
161  }
162  iData.lastProduct_=index;
163  }
164 
165 
167  DataGetterHelper::getBranchDataFor(std::type_info const& iInfo,
168  char const* iModuleLabel,
169  char const* iProductInstanceLabel,
170  char const* iProcessLabel) const
171  {
172  edm::TypeID type(iInfo);
173  internal::DataKey key(type, iModuleLabel, iProductInstanceLabel, iProcessLabel);
174 
175  boost::shared_ptr<internal::Data> theData;
176  DataMap::iterator itFind = data_.find(key);
177  if(itFind == data_.end()) {
178  //see if such a branch actually exists
179  std::string const sep("_");
180  //CHANGE: If this fails, need to lookup the the friendly name which was used to write the file
181  std::string name(type.friendlyClassName());
182  name +=sep+std::string(key.module());
183  name +=sep+std::string(key.product())+sep;
184 
185  //if we have to lookup the process label, remember it and register the product again
186  std::string foundProcessLabel;
187  TBranch* branch = 0;
188 
189  if (0==iProcessLabel || iProcessLabel==key.kEmpty() ||
190  strlen(iProcessLabel)==0) {
191  std::string const* lastLabel=0;
192  //have to search in reverse order since newest are on the bottom
194  for (edm::ProcessHistory::const_reverse_iterator iproc = h.rbegin(), eproc = h.rend();
195  iproc != eproc;
196  ++iproc) {
197 
198  lastLabel = &(iproc->processName());
199  branch=findBranch(tree_,name,iproc->processName());
200  if(0!=branch) {
201  break;
202  }
203  }
204  if(0==branch) {
205  return branchNotFound;
206  }
207  //do we already have this one?
208  if(0!=lastLabel) {
209  internal::DataKey fullKey(type,iModuleLabel,iProductInstanceLabel,lastLabel->c_str());
210  itFind = data_.find(fullKey);
211  if(itFind != data_.end()) {
212  //remember the data we've found
213  theData = itFind->second;
214  } else {
215  //only set this if we don't already have it since it this string is not empty we re-register
216  foundProcessLabel = *lastLabel;
217  }
218  }
219  } else {
220  //we have all the pieces
221  branch = findBranch(tree_,name,key.process());
222  if(0==branch){
223  return branchNotFound;
224  }
225  }
226 
227  //cache the info
228  size_t moduleLabelLen = strlen(iModuleLabel)+1;
229  char* newModule = new char[moduleLabelLen];
230  std::strncpy(newModule,iModuleLabel,moduleLabelLen);
231  labels_.push_back(newModule);
232 
233  char* newProduct = const_cast<char*>(key.product());
234  if(newProduct[0] != 0) {
235  size_t newProductLen = strlen(newProduct)+1;
236  newProduct = new char[newProductLen];
237  std::strncpy(newProduct,key.product(),newProductLen);
238  labels_.push_back(newProduct);
239  }
240  char* newProcess = const_cast<char*>(key.process());
241  if(newProcess[0]!=0) {
242  size_t newProcessLen = strlen(newProcess)+1;
243  newProcess = new char[newProcessLen];
244  std::strncpy(newProcess,key.process(),newProcessLen);
245  labels_.push_back(newProcess);
246  }
247  internal::DataKey newKey(edm::TypeID(iInfo),newModule,newProduct,newProcess);
248 
249  if(0 == theData.get()) {
250  //We do not already have this data as another key
251 
252  //Use Reflex to create an instance of the object to be used as a buffer
253  Reflex::Type rType = Reflex::Type::ByTypeInfo(iInfo);
254  if(rType == Reflex::Type()) {
255  throw cms::Exception("UnknownType")<<"No Reflex dictionary exists for type "<<iInfo.name();
256  }
257  Reflex::Object obj = rType.Construct();
258 
259  if(obj.Address() == 0) {
260  throw cms::Exception("ConstructionFailed")<<"failed to construct an instance of "<<rType.Name();
261  }
262  boost::shared_ptr<internal::Data> newData(new internal::Data());
263  newData->branch_ = branch;
264  newData->obj_ = obj;
265  newData->lastProduct_=-1;
266  newData->pObj_ = obj.Address();
267  newData->pProd_ = 0;
268  branch->SetAddress(&(newData->pObj_));
269  newData->interface_ = 0;
270  Reflex::Member getTheInterface = rType.FunctionMemberByName(std::string("getInterface"));
271  getTheInterface.Invoke(newData->interface_);
272  theData = newData;
273  }
274  itFind = data_.insert(std::make_pair(newKey, theData)).first;
275 
276  if(foundProcessLabel.size()) {
277  //also remember it with the process label
278  newProcess = new char[foundProcessLabel.size()+1];
279  std::strcpy(newProcess,foundProcessLabel.c_str());
280  labels_.push_back(newProcess);
281  internal::DataKey newKey(edm::TypeID(iInfo),newModule,newProduct,newProcess);
282 
283  data_.insert(std::make_pair(newKey,theData));
284  }
285  }
286  return *(itFind->second);
287  }
288 
289  std::string const
290  DataGetterHelper::getBranchNameFor(std::type_info const& iInfo,
291  char const* iModuleLabel,
292  char const* iProductInstanceLabel,
293  char const* iProcessLabel) const
294  {
295  internal::Data& theData =
296  DataGetterHelper::getBranchDataFor(iInfo, iModuleLabel, iProductInstanceLabel, iProcessLabel);
297 
298  if (0 != theData.branch_) {
299  return std::string(theData.branch_->GetName());
300  }
301  return std::string("");
302  }
303 
304  bool
305  DataGetterHelper::getByLabel(std::type_info const& iInfo,
306  char const* iModuleLabel,
307  char const* iProductInstanceLabel,
308  char const* iProcessLabel,
309  void* oData, Long_t index) const
310  {
311  // Maintain atEnd() check in parent classes
312  void** pOData = reinterpret_cast<void**>(oData);
313  *pOData = 0;
314 
315  internal::Data& theData =
316  DataGetterHelper::getBranchDataFor(iInfo, iModuleLabel, iProductInstanceLabel, iProcessLabel);
317 
318  if (0 != theData.branch_) {
319  if(index != theData.lastProduct_) {
320  //haven't gotten the data for this event
321  getBranchData(getter_.get(), index, theData);
322  }
323  *pOData = theData.obj_.Address();
324  }
325 
326  if (0 == *pOData) return false;
327  else return true;
328  }
329 
330  bool
331  DataGetterHelper::getByLabel(std::type_info const& iInfo,
332  char const* iModuleLabel,
333  char const* iProductInstanceLabel,
334  char const* iProcessLabel,
335  edm::WrapperHolder& holder, Long_t index) const {
336 
337  // Maintain atEnd() check in parent classes
338 
339  internal::Data& theData =
340  DataGetterHelper::getBranchDataFor(iInfo, iModuleLabel, iProductInstanceLabel, iProcessLabel);
341 
342  if(0 != theData.branch_) {
343  if(index != theData.lastProduct_) {
344  //haven't gotten the data for this event
345  getBranchData(getter_.get(), index, theData);
346  }
347  }
348 
349  holder = edm::WrapperHolder(theData.obj_.Address(), theData.interface_);
350  return holder.isValid();
351  }
352 
355  {
356  typedef std::pair<edm::ProductID,edm::BranchListIndexes> IDPair;
357  IDPair theID = std::make_pair(iID, branchMap_->branchListIndexes());
358  std::map<IDPair,boost::shared_ptr<internal::Data> >::const_iterator itFound = idToData_.find(theID);
359  if(itFound == idToData_.end()) {
360  edm::BranchDescription const& bDesc = branchMap_->productToBranch(iID);
361 
362  if (!bDesc.branchID().isValid()) {
363  return edm::WrapperHolder();
364  }
365 
366  //Calculate the key from the branch description
367  Reflex::Type type(Reflex::Type::ByName(edm::wrappedClassName(bDesc.fullClassName())));
368  assert(Reflex::Type() != type) ;
369 
370  //Only the product instance label may be empty
371  char const* pIL = bDesc.productInstanceName().c_str();
372  if(pIL[0] == 0) {
373  pIL = 0;
374  }
375  internal::DataKey k(edm::TypeID(type.TypeInfo()),
376  bDesc.moduleLabel().c_str(),
377  pIL,
378  bDesc.processName().c_str());
379 
380  //has this already been gotten?
381  KeyToDataMap::iterator itData = data_.find(k);
382  if(data_.end() == itData) {
383  //ask for the data
384  edm::WrapperHolder holder;
385  getByLabel(type.TypeInfo(),
386  k.module(),
387  k.product(),
388  k.process(),
389  holder, index);
390  if(!holder.isValid()) {
391  return holder;
392  }
393  itData = data_.find(k);
394  assert(itData != data_.end());
395  assert(holder.wrapper() == itData->second->obj_.Address());
396  }
397  itFound = idToData_.insert(std::make_pair(theID,itData->second)).first;
398  }
399  if(index != itFound->second->lastProduct_) {
400  //haven't gotten the data for this event
401  getBranchData(getter_.get(), index, *(itFound->second));
402  }
403  if(0==itFound->second->pProd_) {
404  itFound->second->pProd_ = itFound->second->obj_.Address();
405 
406  if(0==itFound->second->pProd_) {
407  return edm::WrapperHolder();
408  }
409  }
410  //return itFound->second->pProd_;
411  return edm::WrapperHolder(itFound->second->pProd_, itFound->second->interface_);
412  }
413 
415  return historyGetter_->history();
416  }
417 
418 
419  //
420  // static member functions
421  //
422  void
423  DataGetterHelper::throwProductNotFoundException(std::type_info const& iType, char const* iModule, char const* iProduct, char const* iProcess)
424  {
425  edm::TypeID type(iType);
426  throw edm::Exception(edm::errors::ProductNotFound)<<"A branch was found for \n type ='"<<type.className()<<"'\n module='"<<iModule
427  <<"'\n productInstance='"<<((0!=iProduct)?iProduct:"")<<"'\n process='"<<((0!=iProcess)?iProcess:"")<<"'\n"
428  "but no data is available for this Lumi";
429  }
430 
431 }
const_reverse_iterator rbegin() const
static TBranch * findBranch(TTree *iTree, std::string const &iMainLabels, std::string const &iProcess)
type
Definition: HCALResponse.h:22
std::map< std::pair< edm::ProductID, edm::BranchListIndexes >, boost::shared_ptr< internal::Data > > idToData_
std::vector< char const * > labels_
collection_type::const_reverse_iterator const_reverse_iterator
DataGetterHelper(TTree *tree, boost::shared_ptr< HistoryGetterBase > historyGetter, boost::shared_ptr< BranchMapReader > branchMap=boost::shared_ptr< BranchMapReader >(), boost::shared_ptr< edm::EDProductGetter > getter=boost::shared_ptr< edm::EDProductGetter >(), bool useCache=false)
virtual std::string const getBranchNameFor(std::type_info const &, char const *, char const *, char const *) const
std::string const & processName() const
char const * product() const
bool isValid() const
Definition: BranchID.h:24
char const * kEmpty() const
char const * module() const
const edm::ProcessHistory & history() const
boost::shared_ptr< edm::EDProductGetter > getter_
std::map< internal::DataKey, boost::shared_ptr< internal::Data > > DataMap
const_reverse_iterator rend() const
std::string const & moduleLabel() const
std::string const & productInstanceName() const
static void throwProductNotFoundException(std::type_info const &, char const *, char const *, char const *)
static internal::Data branchNotFound
edm::WrapperInterfaceBase * interface_
#define TTCACHE_SIZE
std::auto_ptr< TTreeCache > tcache_
BranchID const & branchID() const
std::string className() const
Definition: TypeID.cc:51
std::string const & fullClassName() const
int k[5][pyjets_maxn]
The Signals That Services Can Subscribe To This is based on ActivityRegistry h
Helper function to determine trigger accepts.
Definition: Activities.doc:4
std::string wrappedClassName(std::string const &iFullName)
void getBranchData(edm::EDProductGetter *, Long64_t, internal::Data &) const
char const * process() const
internal::Data & getBranchDataFor(std::type_info const &, char const *, char const *, char const *) const
boost::shared_ptr< BranchMapReader > branchMap_
list key
Definition: combine.py:13
virtual bool getByLabel(std::type_info const &, char const *, char const *, char const *, void *, Long_t) const
withTCache(TFile *file, TTreeCache *tc)
bool isValid() const
Definition: WrapperHolder.h:27
void const * wrapper() const
Definition: WrapperHolder.h:76
edm::WrapperHolder getByProductID(edm::ProductID const &, Long_t) const
boost::shared_ptr< fwlite::HistoryGetterBase > historyGetter_
std::string friendlyClassName() const
Definition: TypeID.cc:74