Warning, /include/Geant4/tools/wroot/branch is written in an unsupported language. File is not indexed.
0001 // Copyright (C) 2010, Guy Barrand. All rights reserved.
0002 // See the file tools.license for terms.
0003
0004 #ifndef tools_wroot_branch
0005 #define tools_wroot_branch
0006
0007 #include "leaf"
0008 #include "basket"
0009 #include "../forit"
0010
0011 #include "imutex"
0012
0013 namespace tools {
0014 namespace wroot {
0015
0016 class branch : public virtual ibo {
0017 //static uint32 kDoNotProcess() {return (1<<10);} // Active bit for branches
0018 #ifdef TOOLS_MEM
0019 static const std::string& s_class() {
0020 static const std::string s_v("tools::wroot::branch");
0021 return s_v;
0022 }
0023 #endif
0024 public: //ibo
0025 virtual const std::string& store_cls() const {
0026 static const std::string s_v("TBranch");
0027 return s_v;
0028 }
0029 virtual bool stream(buffer& a_buffer) const {
0030 unsigned int c;
0031 if(!a_buffer.write_version(8,c)) return false;
0032 if(!Named_stream(a_buffer,m_name,m_title)) return false;
0033
0034 if(!AttFill_stream(a_buffer)) return false;
0035
0036 int fEntryOffsetLen = 1000;
0037 int fOffset = 0;
0038 int fSplitLevel = 0;
0039
0040 if(!a_buffer.write(fCompress)) return false;
0041 if(!a_buffer.write(m_basket_size)) return false;
0042 if(!a_buffer.write(fEntryOffsetLen)) return false;
0043 if(!a_buffer.write(m_write_basket)) return false;
0044 int fEntryNumber = (int)m_entry_number;
0045 if(!a_buffer.write(fEntryNumber)) return false;
0046 if(!a_buffer.write(fOffset)) return false;
0047 if(!a_buffer.write(m_max_baskets)) return false;
0048 if(!a_buffer.write(fSplitLevel)) return false;
0049 double fEntries = (double)m_entries;
0050 if(!a_buffer.write(fEntries)) return false;
0051 double fTotBytes = (double)m_tot_bytes;
0052 double fZipBytes = (double)m_zip_bytes;
0053 if(!a_buffer.write(fTotBytes)) return false;
0054 if(!a_buffer.write(fZipBytes)) return false;
0055
0056 if(!m_branches.stream(a_buffer)) return false;
0057 if(!m_leaves.stream(a_buffer)) return false;
0058 if(!m_baskets.stream(a_buffer)) return false;
0059
0060 /*
0061 {uint32 remaining_baskets = 0;
0062 for(uint32 i=0;i<m_max_baskets;i++) {
0063 if(m_baskets[i]) {
0064 m_out << "debug : remaining basket : index " << i << ", bytes = " << m_baskets[i]->number_of_bytes()
0065 << std::endl;
0066 remaining_baskets++;
0067 }
0068 }
0069 m_out << "tools::wroot::branch::stream :"
0070 << " write_basket = " << m_write_basket
0071 << ", max_baskets = " << m_max_baskets
0072 << ", remaining_baskets = " << remaining_baskets << "."
0073 << std::endl;}
0074 */
0075
0076 // See TStreamerInfo::ReadBuffer::WriteBasicPointer
0077 if(!a_buffer.write((char)1)) return false;
0078 if(!a_buffer.write_fast_array(fBasketBytes,m_max_baskets)) return false;
0079 if(!a_buffer.write((char)1)) return false;
0080 if(!a_buffer.write_fast_array(fBasketEntry,m_max_baskets)) return false;
0081
0082 char isBigFile = 1;
0083 //GB : begin
0084 //if(fTree.directory().file().end()>RIO_START_BIG_FILE()) isBigFile = 2;
0085 {for(uint32 i=0;i<m_max_baskets;i++) {
0086 if(fBasketSeek[i]>START_BIG_FILE()) {
0087 isBigFile = 2;
0088 break;
0089 }
0090 }}
0091 //GB : end
0092
0093 if(!a_buffer.write(isBigFile)) return false;
0094 if(isBigFile==2) {
0095 if(!a_buffer.write_fast_array(fBasketSeek,m_max_baskets)) return false;
0096 } else {
0097 for(uint32 i=0;i<m_max_baskets;i++) {
0098 if(fBasketSeek[i]>START_BIG_FILE()) { //G.Barrand : add this test.
0099 m_out << "tools::wroot::branch::stream :"
0100 << " attempt to write big Seek "
0101 << fBasketSeek[i] << " on 32 bits."
0102 << std::endl;
0103 return false;
0104 }
0105
0106 if(!a_buffer.write((seek32)fBasketSeek[i])) return false;
0107 }
0108 }
0109
0110 // fFileName
0111 if(!a_buffer.write(std::string(""))) return false;
0112
0113 if(!a_buffer.set_byte_count(c)) return false;
0114 return true;
0115 }
0116
0117 public:
0118 branch(std::ostream& a_out,bool a_byte_swap,uint32 a_compression,
0119 seek a_seek_directory,const std::string& a_name,const std::string& a_title,bool a_verbose)
0120 :m_out(a_out)
0121 ,m_byte_swap(a_byte_swap)
0122 ,m_verbose(a_verbose)
0123 ,m_seek_directory(a_seek_directory)
0124 ,m_name(a_name)
0125 ,m_title(a_title)
0126 ,fAutoDelete(false)
0127
0128 //,m_branches(true)
0129 //,m_leaves(true)
0130 ,fCompress(a_compression)
0131 ,m_basket_size(32000)
0132 ,m_write_basket(0)
0133 ,m_entry_number(0)
0134 ,m_entries(0)
0135 ,m_tot_bytes(0)
0136 ,m_zip_bytes(0)
0137 ,m_max_baskets(10)
0138 ,fBasketBytes(0)
0139 ,fBasketEntry(0)
0140 ,fBasketSeek(0)
0141 {
0142 #ifdef TOOLS_MEM
0143 mem::increment(s_class().c_str());
0144 #endif
0145 m_baskets.resize(m_max_baskets,0);
0146 fBasketBytes = new uint32[m_max_baskets];
0147 fBasketEntry = new uint32[m_max_baskets];
0148 fBasketSeek = new seek[m_max_baskets];
0149 {for(uint32 i=0;i<m_max_baskets;i++) {
0150 m_baskets[i] = 0;
0151 fBasketBytes[i] = 0;
0152 fBasketEntry[i] = 0;
0153 fBasketSeek[i] = 0;
0154 }}
0155 m_baskets[m_write_basket] = new basket(m_out,m_byte_swap,a_seek_directory,m_name,m_title,"TBasket",m_basket_size,m_verbose);
0156 fBasketEntry[m_write_basket] = (uint32)m_entry_number;
0157 }
0158 virtual ~branch(){
0159 // {for(uint32 i=0;i<=m_write_basket;i++) {
0160 // m_out << " " << i << ", " << fBasketEntry[i] << std::endl;
0161 // }}
0162
0163 delete [] fBasketBytes;
0164 delete [] fBasketEntry;
0165 delete [] fBasketSeek;
0166 fBasketBytes = 0;
0167 fBasketEntry = 0;
0168 fBasketSeek = 0;
0169
0170 #ifdef TOOLS_MEM
0171 mem::decrement(s_class().c_str());
0172 #endif
0173 }
0174 protected:
0175 branch(const branch& a_from)
0176 :ibo(a_from)
0177 ,m_out(a_from.m_out)
0178 ,m_seek_directory(a_from.m_seek_directory)
0179 {}
0180 branch& operator=(const branch&){return *this;}
0181 public:
0182 const std::string& name() const {return m_name;}
0183 const std::string& title() const {return m_title;}
0184
0185 uint64 entries() const {return m_entries;}
0186
0187 uint64 tot_bytes() const {return m_tot_bytes;}
0188 void set_tot_bytes(uint64 a_value) {m_tot_bytes = a_value;}
0189
0190 uint64 zip_bytes() const {return m_zip_bytes;}
0191 void set_zip_bytes(uint64 a_value) {m_zip_bytes = a_value;}
0192
0193 void set_basket_size(uint32 a_size) {m_basket_size = a_size;}
0194 uint32 basket_size() const {return m_basket_size;}
0195
0196 ////////////////////////////////////////////////
0197 ////////////////////////////////////////////////
0198 ////////////////////////////////////////////////
0199 template <class T>
0200 leaf_ref<T>* create_leaf_ref(const std::string& a_name,const T& a_ref){
0201 leaf_ref<T>* lf = new leaf_ref<T>(m_out,a_name,a_ref);
0202 m_leaves.push_back(lf);
0203 return lf;
0204 }
0205
0206 leaf_string_ref* create_leaf_string_ref(const std::string& a_name,const std::string& a_ref){
0207 leaf_string_ref* lf = new leaf_string_ref(m_out,a_name,a_ref);
0208 m_leaves.push_back(lf);
0209 return lf;
0210 }
0211 ////////////////////////////////////////////////
0212 ////////////////////////////////////////////////
0213 ////////////////////////////////////////////////
0214
0215 template <class T>
0216 leaf<T>* create_leaf(const std::string& a_name){
0217 leaf<T>* lf = new leaf<T>(m_out,a_name);
0218 m_leaves.push_back(lf);
0219 return lf;
0220 }
0221
0222 leaf_string* create_leaf_string(const std::string& a_name){
0223 leaf_string* lf = new leaf_string(m_out,a_name);
0224 m_leaves.push_back(lf);
0225 return lf;
0226 }
0227
0228 leaf_element* create_leaf_element(const std::string& a_name,int a_id,int a_type){
0229 leaf_element* lf = new leaf_element(m_out,a_name,a_id,a_type);
0230 m_leaves.push_back(lf);
0231 return lf;
0232 }
0233
0234 // for row_wise ntuple :
0235 template <class T>
0236 leaf_std_vector_ref<T>* create_leaf_std_vector_ref(const std::string& a_name,
0237 base_leaf& a_leaf_count,const std::vector<T>& a_ref) {
0238 leaf_std_vector_ref<T>* lf = new leaf_std_vector_ref<T>(m_out,a_name,a_leaf_count,a_ref);
0239 m_leaves.push_back(lf);
0240 return lf;
0241 }
0242
0243 const std::vector<base_leaf*>& leaves() const {return m_leaves;}
0244
0245 void reset() {
0246 m_baskets.clear_objs();
0247 delete [] fBasketBytes;
0248 delete [] fBasketEntry;
0249 delete [] fBasketSeek;
0250 fBasketBytes = 0;
0251 fBasketEntry = 0;
0252 fBasketSeek = 0;
0253
0254 m_max_baskets = 10;
0255
0256 m_write_basket = 0;
0257 m_entry_number = 0;
0258 m_entries = 0;
0259 m_tot_bytes = 0;
0260 m_zip_bytes = 0;
0261
0262 m_baskets.resize(m_max_baskets,0);
0263 fBasketBytes = new uint32[m_max_baskets];
0264 fBasketEntry = new uint32[m_max_baskets];
0265 fBasketSeek = new seek[m_max_baskets];
0266 {for(uint32 i=0;i<m_max_baskets;i++) {
0267 m_baskets[i] = 0;
0268 fBasketBytes[i] = 0;
0269 fBasketEntry[i] = 0;
0270 fBasketSeek[i] = 0;
0271 }}
0272 fBasketEntry[m_write_basket] = (uint32)m_entry_number;
0273 m_baskets[m_write_basket] = new basket(m_out,m_byte_swap,m_seek_directory,m_name,m_title,"TBasket",m_basket_size,m_verbose);
0274
0275 {tools_vforit(branch*,m_branches,it) (*it)->reset();}
0276 }
0277
0278 bool fill(ifile& a_file,uint32& a_nbytes,uint32& a_add_bytes,uint32& a_nout) {
0279 a_nbytes = 0;
0280 a_add_bytes = 0;
0281 a_nout = 0;
0282
0283 if(m_write_basket>=m_max_baskets) {
0284 m_out << "tools::wroot::branch::fill :"
0285 << " potential overflow : m_write_basket (" << m_write_basket << ")"
0286 << " >= m_max_baskets (" << m_max_baskets << ")."
0287 << std::endl;
0288 return false;
0289 }
0290
0291 //FIXME if (TestBit(kDoNotProcess)) return 0;
0292
0293 basket* bk = m_baskets[m_write_basket];
0294 if(!bk) {
0295 m_out << "tools::wroot::branch::fill :"
0296 << " m_baskets[m_write_basket] should not be null."
0297 << std::endl;
0298 return false;
0299 }
0300
0301 buffer& buf = bk->datbuf();
0302
0303 buf.reset_objs_map();
0304
0305 uint32 lold = buf.length();
0306
0307 bk->update(bk->key_length()+lold);
0308 m_entries++;
0309 m_entry_number++;
0310
0311 if(!fill_leaves(buf)) {
0312 m_out << "tools::wroot::branch::fill :"
0313 << " fill_leaves() failed."
0314 << std::endl;
0315 return false;
0316 }
0317
0318 uint32 lnew = buf.length();
0319 uint32 nbytes = lnew - lold;
0320 uint32 nsize = 0;
0321
0322 uint32 add_bytes = 0;
0323 uint32 nout = 0;
0324
0325 // Should we create a new basket?
0326 // Compare expected next size with m_basket_size.
0327 if((lnew+2*nsize+nbytes)>=m_basket_size) {
0328 if(!bk->write_on_file(a_file,m_write_basket,nout)) {//it set bk m_seek_key, set a_file.m_END.
0329 //Does a a_file.set_END().
0330 m_out << "tools::wroot::branch::fill :"
0331 << " basket.write_on_file() failed."
0332 << std::endl;
0333 return false;
0334 }
0335 fBasketBytes[m_write_basket] = bk->number_of_bytes();
0336 //fBasketEntry[m_write_basket] = // not done here since we do not know here the first entry.
0337 fBasketSeek[m_write_basket] = bk->seek_key();
0338
0339 add_bytes = bk->object_size() + bk->key_length();
0340
0341 delete bk;
0342 m_baskets[m_write_basket] = 0;
0343
0344 m_tot_bytes += add_bytes;
0345 m_zip_bytes += nout;
0346
0347 m_write_basket++;
0348 if(!check_alloc_fBasketXxx()) return false;
0349
0350 m_baskets[m_write_basket] = new basket(m_out,m_byte_swap,
0351 m_seek_directory,m_name,m_title,"TBasket",m_basket_size,
0352 m_verbose);
0353 fBasketEntry[m_write_basket] = (uint32)m_entry_number;
0354 }
0355 a_nbytes = nbytes;
0356 a_add_bytes = add_bytes;
0357 a_nout = nout;
0358 return true;
0359 }
0360
0361 ///////////////////////////////////////////////////////////////////////////
0362 /// for parallelization : /////////////////////////////////////////////////
0363 ///////////////////////////////////////////////////////////////////////////
0364 bool add_basket(ifile& a_file,basket& a_basket,uint32& a_add_bytes,uint32& a_nout) {
0365 //done on a (main) ntuple/branch.
0366
0367 if(m_write_basket>=m_max_baskets) {
0368 m_out << "tools::wroot::branch::add_basket :"
0369 << " potential overflow : m_write_basket (" << m_write_basket << ")"
0370 << " >= m_max_baskets (" << m_max_baskets << ")."
0371 << std::endl;
0372 return false;
0373 }
0374
0375 uint32 nout;
0376 if(!a_basket.write_on_file(a_file,m_write_basket,nout)) { //a_file is the main file (a true file).
0377 //the upper set a_basket.m_seek_key, set a_file.m_END. Does a a_file.set_END().
0378 m_out << "tools::wroot::branch::add_basket :"
0379 << " basket.write_on_file() failed."
0380 << std::endl;
0381 return false;
0382 }
0383
0384 fBasketBytes[m_write_basket] = a_basket.number_of_bytes();
0385 fBasketEntry[m_write_basket] = (uint32)m_entry_number;
0386 fBasketSeek[m_write_basket] = a_basket.seek_key();
0387
0388 m_entries += a_basket.nev();
0389 m_entry_number += a_basket.nev();
0390
0391 uint32 add_bytes = a_basket.object_size() + a_basket.key_length();
0392
0393 delete m_baskets[m_write_basket];
0394 m_baskets[m_write_basket] = 0;
0395
0396 m_write_basket++;
0397 if(!check_alloc_fBasketXxx()) return false;
0398
0399 m_baskets[m_write_basket] = new basket(m_out,m_byte_swap,
0400 m_seek_directory,m_name,m_title,"TBasket",m_basket_size,
0401 m_verbose);
0402 fBasketEntry[m_write_basket] = (uint32)m_entry_number;
0403
0404 a_add_bytes = add_bytes;
0405 a_nout = nout;
0406 return true;
0407 }
0408
0409 class iadd_basket {
0410 public:
0411 virtual ~iadd_basket() {}
0412 public:
0413 virtual bool add_basket(basket*) = 0;
0414 };
0415
0416 bool pfill(iadd_basket& a_badd,uint32 a_nev) {
0417 //done on a pntuple/branch.
0418
0419 //a_nbytes = 0;
0420 //a_add_bytes = 0;
0421 //a_nout = 0;
0422
0423 // this method uses always m_baskets[0].
0424
0425 basket* bk = m_baskets[m_write_basket];
0426 if(!bk) {
0427 m_out << "tools::wroot::branch::parallel_fill :"
0428 << " get_basket failed."
0429 << std::endl;
0430 return false;
0431 }
0432
0433 buffer& buf = bk->datbuf();
0434
0435 uint32 lold = buf.length();
0436
0437 bk->update(bk->key_length()+lold);
0438
0439 //m_entries++; //not used by parallel branches.
0440 //m_entry_number++; //idem.
0441
0442 if(!fill_leaves(buf)) {
0443 m_out << "tools::wroot::branch::parallel_fill :"
0444 << " fill_leaves() failed."
0445 << std::endl;
0446 return false;
0447 }
0448
0449 uint32 lnew = buf.length();
0450 uint32 nbytes = lnew - lold;
0451
0452 // Should we create a new basket?
0453 bool store_basket = false;
0454 if(a_nev) {
0455 store_basket = (bk->nev()>=a_nev); // trigger add_basket per number of entries reached.
0456 } else {
0457 store_basket = ((lnew+nbytes)>=m_basket_size); // trigger add_basket when reaching m_basket_size.
0458 }
0459
0460 if(store_basket) {
0461 if(!a_badd.add_basket(bk)) { //we give ownership of bk.
0462 m_out << "tools::wroot::branch::parallel_fill :"
0463 << " main_branch.add_basket() failed."
0464 << std::endl;
0465 return false;
0466 }
0467 //delete bk; //no, it is deleted by the a_badd.add_basket().
0468 bool main_branch_byte_swap = m_byte_swap; //NOTE : it assumes that pntuple/branch and main/branch have same byte_swap.
0469 bool main_branch_verbose = m_verbose;
0470 m_baskets[m_write_basket] = new basket(m_out,main_branch_byte_swap,
0471 m_seek_directory,m_name,m_title,"TBasket",m_basket_size,
0472 main_branch_verbose);
0473 }
0474
0475 return true;
0476 }
0477
0478 bool end_pfill(iadd_basket& a_badd) {
0479 //done on a pntuple/branch.
0480
0481 basket* bk = m_baskets[m_write_basket];
0482 if(!bk) {
0483 m_out << "tools::wroot::branch::end_pfill :"
0484 << " m_baskets[m_write_basket] should not be null."
0485 << std::endl;
0486 return false;
0487 }
0488
0489 buffer& buf = bk->datbuf();
0490 uint32 lold = buf.length();
0491
0492 if(lold) {
0493 if(!a_badd.add_basket(bk)) { //we give ownership of bk.
0494 m_out << "tools::wroot::branch::parallel_fill :"
0495 << " main_branch.add_basket() failed."
0496 << std::endl;
0497 return false;
0498 }
0499 } else {
0500 delete bk;
0501 }
0502
0503 m_baskets[m_write_basket] = 0; // no need to recreate a basket since it is end of fill.
0504
0505 return true;
0506 }
0507
0508 ///////////////////////////////////////////////////////////////////////////
0509 ///////////////////////////////////////////////////////////////////////////
0510 ///////////////////////////////////////////////////////////////////////////
0511 protected:
0512 bool check_alloc_fBasketXxx() {
0513 if(m_write_basket>=m_max_baskets) {
0514 //Increase BasketEntry buffer of a minimum of 10 locations
0515 // and a maximum of 50 per cent of current size
0516 uint32 newsize = mx<uint32>(10,uint32(1.5*m_max_baskets));
0517 if(newsize>=START_BIG_FILE()) {
0518 //we are going to have pb with uint32[] indexing.
0519 m_out << "tools::wroot::branch::add_basket :"
0520 << " new size for fBasket[Bytes,Entry,Seek] arrays"
0521 << " is too close of 32 bits limit."
0522 << std::endl;
0523 m_out << "tools::wroot::branch::add_basket :"
0524 << " you have to work with larger basket size."
0525 << std::endl;
0526 return false;
0527 }
0528
0529 m_baskets.resize(newsize,0);
0530
0531 if(!realloc<uint32>(fBasketBytes,newsize,m_max_baskets,true)) {
0532 m_out << "tools::wroot::branch::add_basket : realloc failed." << std::endl;
0533 return false;
0534 }
0535 if(!realloc<uint32>(fBasketEntry,newsize,m_max_baskets,true)){
0536 m_out << "tools::wroot::branch::add_basket : realloc failed." << std::endl;
0537 return false;
0538 }
0539 if(!realloc<seek>(fBasketSeek,newsize,m_max_baskets,true)){
0540 m_out << "tools::wroot::branch::add_basket : realloc failed." << std::endl;
0541 return false;
0542 }
0543 m_max_baskets = newsize;
0544 }
0545
0546 m_baskets[m_write_basket] = 0;
0547 fBasketBytes[m_write_basket] = 0;
0548 fBasketEntry[m_write_basket] = 0;
0549 fBasketSeek[m_write_basket] = 0;
0550
0551 return true;
0552 }
0553
0554 virtual bool fill_leaves(buffer& a_buffer) { //virtual for branch_element.
0555 tools_vforit(base_leaf*,m_leaves,it) {
0556 if(!(*it)->fill_buffer(a_buffer)) return false;
0557 }
0558 return true;
0559 }
0560 protected:
0561 std::ostream& m_out;
0562 bool m_byte_swap;
0563 bool m_verbose;
0564 seek m_seek_directory;
0565 obj_array<basket> m_baskets;
0566 /// for parallelization :
0567 public:
0568 std::vector<basket*> m_parallel_baskets;
0569 protected:
0570 //Object
0571 //uint32 m_bits;
0572 //Named
0573 std::string m_name;
0574 std::string m_title;
0575
0576 bool fAutoDelete;
0577 private: //be sure that sub branches are not used for the moment.
0578 obj_array<branch> m_branches;
0579 protected:
0580 obj_array<base_leaf> m_leaves;
0581 uint32 fCompress; // Compression level and algorithm
0582 uint32 m_basket_size; // Initial Size of Basket Buffer
0583 uint32 m_write_basket; // Last basket number written
0584 uint64 m_entry_number; // Current entry number (last one filled in this branch)
0585 uint64 m_entries; // Number of entries
0586 uint64 m_tot_bytes;
0587 uint64 m_zip_bytes;
0588 uint32 m_max_baskets;
0589 uint32* fBasketBytes; //[m_max_baskets] Length of baskets on file
0590 uint32* fBasketEntry; //[m_max_baskets] Table of first entry in eack basket
0591 seek* fBasketSeek; //[m_max_baskets] Addresses of baskets on file
0592 };
0593
0594 }}
0595
0596 #endif