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