inlib
1.2.0
|
00001 // Copyright (C) 2010, Guy Barrand. All rights reserved. 00002 // See the file inlib.license for terms. 00003 00004 #ifndef inlib_wroot_basket 00005 #define inlib_wroot_basket 00006 00007 #include "ibo" 00008 #include "key" 00009 #include "buffer" 00010 00011 namespace inlib { 00012 namespace wroot { 00013 00014 class basket : public virtual ibo, public key { 00015 static uint32 START_BIG_FILE() {return 2000000000;} 00016 public: 00017 static const std::string& s_class() { 00018 static const std::string s_v("inlib::wroot::basket"); 00019 return s_v; 00020 } 00021 public: //ibo 00022 virtual const std::string& store_cls() const { 00023 static const std::string s_v("TBasket"); 00024 return s_v; 00025 } 00026 virtual bool stream(buffer& a_buffer) const { 00027 // in principle we pass here only for the last basket 00028 // of a branch when it is streamed from branch::stream(). 00029 00030 // some consitency checks : 00031 if(!m_data.length()) { 00032 // to be sure to not work on a basket already written 00033 // with write_on_file() 00034 m_file.out() << "inlib::wroot::basket::stream :" 00035 << " m_data.length() is null." 00036 << std::endl; 00037 return false; 00038 } 00039 if(m_seek_key) { 00040 m_file.out() << "inlib::wroot::basket::stream :" 00041 << " m_seek_key is not null." 00042 << std::endl; 00043 return false; 00044 } 00045 if(m_last) { 00046 m_file.out() << "inlib::wroot::basket::stream :" 00047 << " m_last is not null." 00048 << std::endl; 00049 return false; 00050 } 00051 if(!m_entry_offset) { 00052 m_file.out() << "inlib::wroot::basket::stream :" 00053 << " m_entry_offset is null." 00054 << std::endl; 00055 return false; 00056 } 00057 00058 {uint32 last = m_data.length()+m_key_length; 00059 if(last>m_last) { 00060 const_cast<basket&>(*this).m_last = last; 00061 }} 00062 if(m_last>m_buf_size) { 00063 const_cast<basket&>(*this).m_buf_size = m_last; 00064 } 00065 00066 char flag = 11; 00067 if(m_displacement) flag += 40; 00068 if(!_stream_header(a_buffer,flag)) return false; 00069 00070 if(m_entry_offset && m_nev) { 00071 if(!a_buffer.write_array(m_entry_offset,m_nev)) return false; 00072 if(m_displacement) { 00073 if(!a_buffer.write_array(m_displacement,m_nev)) return false; 00074 } 00075 } 00076 00077 if(m_data.to_displace()) { 00078 //NOTE : how / when handle the displacements ? 00079 m_file.out() << "inlib::wroot::basket::stream :" 00080 << " WARNING : m_data buffer has offsets to displace." 00081 << std::endl; 00082 //if(!const_cast<basket&>(*this).m_data.displace_mapped(m_key_length)) 00083 // return false; //??? 00084 } 00085 00086 buffer bref(m_file.out(),m_file.byte_swap(),256); 00087 if(!_stream_header(bref)) return false; //then header stored twice ! 00088 //if(bref.length()!=m_key_length) {} 00089 if(!bref.write_fast_array(m_data.buf(),m_data.length())) return false; 00090 if(!a_buffer.write_fast_array(bref.buf(),bref.length())) return false; 00091 00092 return true; 00093 } 00094 public: 00095 basket(ifile& a_file, 00096 seek a_seek_parent_dir, 00097 const std::string& a_object_name, 00098 const std::string& a_object_title, 00099 const std::string& a_object_class, 00100 uint32 a_basket_size) 00101 :key(a_file,a_seek_parent_dir, 00102 a_object_name,a_object_title,a_object_class,0) 00103 ,m_data(a_file.out(),a_file.byte_swap(),a_basket_size) 00104 ,m_nev_buf_size(1000) 00105 ,m_nev(0) 00106 ,m_last(0) 00107 ,m_entry_offset(0) 00108 ,m_displacement(0) 00109 { 00110 #ifdef INLIB_MEM 00111 mem::increment(s_class().c_str()); 00112 #endif 00113 00114 m_key_length = header_record_size(m_version); 00115 initialize(0); 00116 00117 if(m_nev_buf_size) m_entry_offset = new uint32[m_nev_buf_size]; 00118 } 00119 virtual ~basket(){ 00120 delete [] m_entry_offset; 00121 delete [] m_displacement; 00122 m_entry_offset = 0; 00123 m_displacement = 0; 00124 #ifdef INLIB_MEM 00125 mem::decrement(s_class().c_str()); 00126 #endif 00127 } 00128 protected: 00129 basket(const basket& a_from) 00130 : ibo(a_from) 00131 ,key(a_from) 00132 ,m_data(m_file.out(),m_file.byte_swap(),256) 00133 ,m_nev_buf_size(a_from.m_nev_buf_size) 00134 ,m_nev(a_from.m_nev) 00135 ,m_last(a_from.m_last) 00136 ,m_entry_offset(0) 00137 ,m_displacement(0) 00138 { 00139 #ifdef INLIB_MEM 00140 mem::increment(s_class().c_str()); 00141 #endif 00142 } 00143 basket& operator=(const basket& a_from){ 00144 key::operator=(a_from); 00145 m_nev_buf_size = a_from.m_nev_buf_size; 00146 m_nev = a_from.m_nev; 00147 m_last = a_from.m_last; 00148 return *this; 00149 } 00150 public: 00151 buffer& datbuf() {return m_data;} 00152 00153 bool update(uint32 a_offset) { 00154 if(m_entry_offset) { 00155 if((m_nev+1)>=m_nev_buf_size) { //why +1 ? 00156 uint32 newsize = mx<uint32>(10,2*m_nev_buf_size); 00157 if(!realloc<uint32>(m_entry_offset,newsize,m_nev_buf_size,true)){ 00158 m_file.out() << "inlib::wroot::basket::update : realloc failed." 00159 << std::endl; 00160 return false; 00161 } 00162 if(m_displacement) { 00163 if(!realloc<int>(m_displacement,newsize,m_nev_buf_size,true)){ 00164 m_file.out() << "inlib::wroot::basket::update : realloc failed." 00165 << std::endl; 00166 return false; 00167 } 00168 } 00169 00170 m_nev_buf_size = newsize; 00171 00172 // Update branch only for the first 10 baskets 00173 //if (fBranch.writeBasket() < 10) 00174 // fBranch.setEntryOffsetLength(newsize); 00175 } 00176 m_entry_offset[m_nev] = a_offset; 00177 00178 //if (skipped!=offset && !m_displacement){ 00179 // m_displacement = new int[m_nevSize]; 00180 // for(int i=0;i<m_nev_buf_size;i++) 00181 // m_displacement[i] = m_entry_offset[i]; 00182 //} 00183 //if (m_displacement) { 00184 // m_displacement[m_nev] = skipped; 00185 // fBufferRef->setDisplacement(skipped); 00186 //} 00187 00188 } 00189 m_nev++; 00190 return true; 00191 } 00192 00193 bool write_on_file(uint16 a_cycle,uint32& a_nbytes) { 00194 // write m_data buffer into file. 00195 //NOTE : m_data does not contain the key at its head. 00196 // At this point m_seek_key should be 0. 00197 00198 a_nbytes = 0; 00199 00200 if(m_seek_key) { 00201 m_file.out() << "inlib::wroot::basket::write_on_file :" 00202 << " m_seek_key should be 0." 00203 << std::endl; 00204 return false; 00205 } 00206 00207 if(m_version>1000) { 00208 } else { 00209 if(m_file.END()>START_BIG_FILE()) { 00210 //GB : enforce m_version>1000 if m_version is still 2 but 00211 // seek_key>START_BIG_FILE. If not doing that we shall 00212 // write a big m_seek_key on a seek32 and then have 00213 // a problem when reading. 00214 00215 //m_file.out() << "inlib::wroot::basket::write_on_file : " 00216 // << " WARNING : pos>START_BIG_FILE." 00217 // << std::endl; 00218 00219 m_version += 1000; 00220 m_key_length += 8; 00221 00222 if(m_entry_offset) { 00223 for(uint32 i=0;i<m_nev;i++) m_entry_offset[i] += 8; 00224 if(m_displacement) { 00225 //??? Do we have to shift them ? 00226 m_file.out() << "inlib::wroot::basket::write_on_file : " 00227 << " displace logic : m_displacement not null." 00228 << std::endl; 00229 } 00230 } 00231 00232 } 00233 } 00234 00235 // Transfer m_entry_offset table at the end of fBuffer. Offsets to fBuffer 00236 // are transformed in entry length to optimize compression algorithm. 00237 m_last = m_key_length+m_data.length(); 00238 if(m_entry_offset) { 00239 if(!m_data.write_array<uint32>(m_entry_offset,m_nev+1)) { //GB : why +1 ? 00240 delete [] m_entry_offset; 00241 m_entry_offset = 0; 00242 return false; 00243 } 00244 delete [] m_entry_offset; 00245 m_entry_offset = 0; 00246 if(m_displacement) { 00247 if(!m_data.write_array<int>(m_displacement,m_nev+1)) { 00248 delete [] m_displacement; 00249 m_displacement = 0; 00250 return false; 00251 } 00252 delete [] m_displacement; 00253 m_displacement = 0; 00254 } 00255 } 00256 00257 m_object_size = m_data.length(); //uncompressed size. 00258 00259 m_cycle = a_cycle; 00260 00261 if(!m_data.displace_mapped(m_key_length)) return false; 00262 00263 char* kbuf = 0; 00264 uint32 klen = 0; 00265 bool kdelete = false; 00266 m_file.compress_buffer(m_data,kbuf,klen,kdelete); 00267 00268 if(klen>m_object_size) { 00269 m_file.out() << "inlib::wroot::basket::write_on_file :" 00270 << " compression anomaly " 00271 << " m_object_size " << m_object_size 00272 << " klen " << klen 00273 << std::endl; 00274 if(kdelete) delete [] kbuf; 00275 return false; 00276 } 00277 00278 if(!initialize(klen)) { //it will do a file.set_END() 00279 m_file.out() << "inlib::wroot::basket::write_on_file :" 00280 << " initialize() failed." 00281 << std::endl; 00282 if(kdelete) delete [] kbuf; 00283 return false; 00284 } 00285 00286 //write header of the key : 00287 {buffer bref(m_file.out(),m_file.byte_swap(),256); 00288 if(!_stream_header(bref)) return false; 00289 if(bref.length()!=m_key_length) { 00290 m_file.out() << "inlib::wroot::basket::write_on_file :" 00291 << " key len anomaly " << bref.length() 00292 << " m_key_length " << m_key_length 00293 << std::endl; 00294 if(kdelete) delete [] kbuf; 00295 return false; 00296 } 00297 ::memcpy(m_buffer,bref.buf(),m_key_length);} 00298 00299 ::memcpy(m_buffer+m_key_length,kbuf,klen); 00300 if(kdelete) delete [] kbuf; 00301 00302 uint32 nbytes; 00303 if(!key::write_file(nbytes)) return false; 00304 00305 m_data.pos() = m_data.buf(); //empty m_data. 00306 00307 a_nbytes = m_key_length + klen; 00308 return true; 00309 } 00310 protected: 00311 uint32 header_record_size(uint32 a_version) const { 00312 // header only. 00313 uint32 nbytes = key::record_size(a_version); 00314 00315 nbytes += sizeof(short); //version 00316 nbytes += sizeof(uint32); //m_buf_size 00317 nbytes += sizeof(uint32); //m_nev_buf_size 00318 nbytes += sizeof(uint32); //m_nev 00319 nbytes += sizeof(uint32); //m_last 00320 nbytes += sizeof(char); //flag 00321 00322 return nbytes; 00323 } 00324 bool _stream_header(buffer& a_buffer,char a_flag = 0) const { 00325 {uint32 l = key::record_size(m_version); 00326 if((a_buffer.length()+l)>a_buffer.size()) { 00327 if(!a_buffer.expand(a_buffer.size()+l)) return false; 00328 } 00329 wbuf wb(m_file.out(),m_file.byte_swap(),a_buffer.max_pos(),a_buffer.pos()); 00330 if(!key::to_buffer(wb)) return false;} 00331 00332 if(!a_buffer.write_version(2)) return false; 00333 if(!a_buffer.write(m_buf_size)) return false; 00334 if(!a_buffer.write(m_nev_buf_size)) return false; 00335 if(!a_buffer.write(m_nev)) return false; 00336 if(!a_buffer.write(m_last)) return false; 00337 if(!a_buffer.write(a_flag)) return false; 00338 return true; 00339 } 00340 protected: 00341 buffer m_data; 00342 protected: 00343 uint32 m_nev_buf_size; //Length in Int_t of m_entry_offset 00344 uint32 m_nev; //Number of entries in basket 00345 uint32 m_last; //Pointer to last used byte in basket 00346 uint32* m_entry_offset; //[m_nev] Offset of entries in fBuffer(TKey) 00347 int* m_displacement; 00348 }; 00349 00350 }} 00351 00352 #endif