Fairport
v1.0.38
|
00001 00002 00003 00004 00005 00006 00007 00008 #ifndef FAIRPORT_NDB_DATABASE_H 00009 #define FAIRPORT_NDB_DATABASE_H 00010 00011 #include <fstream> 00012 #include <memory> 00013 00014 #include "fairport/util/btree.h" 00015 #include "fairport/util/errors.h" 00016 #include "fairport/util/primitives.h" 00017 #include "fairport/util/util.h" 00018 00019 #include "fairport/disk/disk.h" 00020 00021 #include "fairport/ndb/node.h" 00022 #include "fairport/ndb/page.h" 00023 #include "fairport/ndb/database_iface.h" 00024 00025 namespace fairport 00026 { 00027 00028 class node; 00029 00030 template<typename T> 00031 class database_impl; 00032 typedef database_impl<ulonglong> large_pst; 00033 typedef database_impl<ulong> small_pst; 00034 00042 shared_db_ptr open_database(const std::wstring& filename); 00050 std::tr1::shared_ptr<small_pst> open_small_pst(const std::wstring& filename); 00058 std::tr1::shared_ptr<large_pst> open_large_pst(const std::wstring& filename); 00059 00071 template<typename T> 00072 class database_impl : public db_context 00073 { 00074 public: 00075 00076 bool is_pst() const 00077 { return m_header.wVerClient == disk::database_pst; } 00078 00080 00081 node lookup_node(node_id nid) 00082 { return node(this->shared_from_this(), lookup_node_info(nid)); } 00083 node_info lookup_node_info(node_id nid); 00084 block_info lookup_block_info(block_id bid); 00086 00088 00089 std::tr1::shared_ptr<bbt_page> read_bbt_root(); 00090 std::tr1::shared_ptr<nbt_page> read_nbt_root(); 00091 std::tr1::shared_ptr<bbt_page> read_bbt_page(const page_info& pi); 00092 std::tr1::shared_ptr<nbt_page> read_nbt_page(const page_info& pi); 00093 std::tr1::shared_ptr<nbt_leaf_page> read_nbt_leaf_page(const page_info& pi); 00094 std::tr1::shared_ptr<bbt_leaf_page> read_bbt_leaf_page(const page_info& pi); 00095 std::tr1::shared_ptr<nbt_nonleaf_page> read_nbt_nonleaf_page(const page_info& pi); 00096 std::tr1::shared_ptr<bbt_nonleaf_page> read_bbt_nonleaf_page(const page_info& pi); 00098 00100 00101 std::tr1::shared_ptr<block> read_block(const shared_db_ptr& parent, block_id bid) 00102 { return read_block(parent, lookup_block_info(bid)); } 00103 std::tr1::shared_ptr<data_block> read_data_block(const shared_db_ptr& parent, block_id bid) 00104 { return read_data_block(parent, lookup_block_info(bid)); } 00105 std::tr1::shared_ptr<extended_block> read_extended_block(const shared_db_ptr& parent, block_id bid) 00106 { return read_extended_block(parent, lookup_block_info(bid)); } 00107 std::tr1::shared_ptr<external_block> read_external_block(const shared_db_ptr& parent, block_id bid) 00108 { return read_external_block(parent, lookup_block_info(bid)); } 00109 std::tr1::shared_ptr<subnode_block> read_subnode_block(const shared_db_ptr& parent, block_id bid) 00110 { return read_subnode_block(parent, lookup_block_info(bid)); } 00111 std::tr1::shared_ptr<subnode_leaf_block> read_subnode_leaf_block(const shared_db_ptr& parent, block_id bid) 00112 { return read_subnode_leaf_block(parent, lookup_block_info(bid)); } 00113 std::tr1::shared_ptr<subnode_nonleaf_block> read_subnode_nonleaf_block(const shared_db_ptr& parent, block_id bid) 00114 { return read_subnode_nonleaf_block(parent, lookup_block_info(bid)); } 00115 00116 std::tr1::shared_ptr<block> read_block(const shared_db_ptr& parent, const block_info& bi); 00117 std::tr1::shared_ptr<data_block> read_data_block(const shared_db_ptr& parent, const block_info& bi); 00118 std::tr1::shared_ptr<extended_block> read_extended_block(const shared_db_ptr& parent, const block_info& bi); 00119 std::tr1::shared_ptr<external_block> read_external_block(const shared_db_ptr& parent, const block_info& bi); 00120 std::tr1::shared_ptr<subnode_block> read_subnode_block(const shared_db_ptr& parent, const block_info& bi); 00121 std::tr1::shared_ptr<subnode_leaf_block> read_subnode_leaf_block(const shared_db_ptr& parent, const block_info& bi); 00122 std::tr1::shared_ptr<subnode_nonleaf_block> read_subnode_nonleaf_block(const shared_db_ptr& parent, const block_info& bi); 00124 00125 protected: 00126 database_impl(); // = delete 00131 database_impl(const std::wstring& filename); 00135 void validate_header(); 00136 00143 std::vector<byte> read_block_data(const block_info& bi); 00151 std::vector<byte> read_page_data(const page_info& pi); 00152 00153 std::tr1::shared_ptr<nbt_leaf_page> read_nbt_leaf_page(const page_info& pi, disk::nbt_leaf_page<T>& the_page); 00154 std::tr1::shared_ptr<bbt_leaf_page> read_bbt_leaf_page(const page_info& pi, disk::bbt_leaf_page<T>& the_page); 00155 00156 template<typename K, typename V> 00157 std::tr1::shared_ptr<bt_nonleaf_page<K,V> > read_bt_nonleaf_page(const page_info& pi, disk::bt_page<T, disk::bt_entry<T> >& the_page); 00158 00159 std::tr1::shared_ptr<subnode_leaf_block> read_subnode_leaf_block(const shared_db_ptr& parent, const block_info& bi, disk::sub_leaf_block<T>& sub_block); 00160 std::tr1::shared_ptr<subnode_nonleaf_block> read_subnode_nonleaf_block(const shared_db_ptr& parent, const block_info& bi, disk::sub_nonleaf_block<T>& sub_block); 00161 00162 friend shared_db_ptr open_database(const std::wstring& filename); 00163 friend std::tr1::shared_ptr<small_pst> open_small_pst(const std::wstring& filename); 00164 friend std::tr1::shared_ptr<large_pst> open_large_pst(const std::wstring& filename); 00165 00166 file m_file; 00167 disk::header<T> m_header; 00168 std::tr1::shared_ptr<bbt_page> m_bbt_root; 00169 std::tr1::shared_ptr<nbt_page> m_nbt_root; 00170 }; 00171 00173 template<> 00174 inline void database_impl<ulong>::validate_header() 00175 { 00176 // the behavior of open_database depends on this throw; this can not go under FAIRPORT_VALIDATION_WEAK 00177 if(m_header.wVer >= disk::database_format_unicode_min) 00178 throw invalid_format(); 00179 00180 #ifdef FAIRPORT_VALIDATION_LEVEL_WEAK 00181 ulong crc = disk::compute_crc(((byte*)&m_header) + disk::header_crc_locations<ulong>::start, disk::header_crc_locations<ulong>::length); 00182 00183 if(crc != m_header.dwCRCPartial) 00184 throw crc_fail("header dwCRCPartial failure", 0, 0, crc, m_header.dwCRCPartial); 00185 #endif 00186 } 00187 00188 template<> 00189 inline void database_impl<ulonglong>::validate_header() 00190 { 00191 // the behavior of open_database depends on this throw; this can not go under FAIRPORT_VALIDATION_WEAK 00192 if(m_header.wVer < disk::database_format_unicode_min) 00193 throw invalid_format(); 00194 00195 #ifdef FAIRPORT_VALIDATION_LEVEL_WEAK 00196 ulong crc_partial = disk::compute_crc(((byte*)&m_header) + disk::header_crc_locations<ulonglong>::partial_start, disk::header_crc_locations<ulonglong>::partial_length); 00197 ulong crc_full = disk::compute_crc(((byte*)&m_header) + disk::header_crc_locations<ulonglong>::full_start, disk::header_crc_locations<ulonglong>::full_length); 00198 00199 if(crc_partial != m_header.dwCRCPartial) 00200 throw crc_fail("header dwCRCPartial failure", 0, 0, crc_partial, m_header.dwCRCPartial); 00201 00202 if(crc_full != m_header.dwCRCFull) 00203 throw crc_fail("header dwCRCFull failure", 0, 0, crc_full, m_header.dwCRCFull); 00204 #endif 00205 } 00207 } // end namespace 00208 00209 inline fairport::shared_db_ptr fairport::open_database(const std::wstring& filename) 00210 { 00211 try 00212 { 00213 shared_db_ptr db = open_small_pst(filename); 00214 return db; 00215 } 00216 catch(invalid_format&) 00217 { 00218 // well, that didn't work 00219 } 00220 00221 shared_db_ptr db = open_large_pst(filename); 00222 return db; 00223 } 00224 00225 inline std::tr1::shared_ptr<fairport::small_pst> fairport::open_small_pst(const std::wstring& filename) 00226 { 00227 std::tr1::shared_ptr<small_pst> db(new small_pst(filename)); 00228 return db; 00229 } 00230 00231 inline std::tr1::shared_ptr<fairport::large_pst> fairport::open_large_pst(const std::wstring& filename) 00232 { 00233 std::tr1::shared_ptr<large_pst> db(new large_pst(filename)); 00234 return db; 00235 } 00236 00237 template<typename T> 00238 inline std::vector<fairport::byte> fairport::database_impl<T>::read_block_data(const block_info& bi) 00239 { 00240 size_t aligned_size = disk::align_disk<T>(bi.size); 00241 00242 #ifdef FAIRPORT_VALIDATION_LEVEL_WEAK 00243 if(aligned_size > disk::max_block_disk_size) 00244 throw unexpected_block("nonsensical block size"); 00245 00246 if(bi.address + aligned_size > m_header.root_info.ibFileEof) 00247 throw unexpected_block("nonsensical block location; past eof"); 00248 #endif 00249 00250 std::vector<byte> buffer(aligned_size); 00251 disk::block_trailer<T>* bt = (disk::block_trailer<T>*)(&buffer[0] + aligned_size - sizeof(disk::block_trailer<T>)); 00252 00253 m_file.read(buffer, bi.address); 00254 00255 #ifdef FAIRPORT_VALIDATION_LEVEL_WEAK 00256 if(bt->bid != bi.id) 00257 throw unexpected_block("wrong block id"); 00258 00259 if(bt->cb != bi.size) 00260 throw unexpected_block("wrong block size"); 00261 00262 if(bt->signature != disk::compute_signature(bi.id, bi.address)) 00263 throw sig_mismatch("block sig mismatch", bi.address, bi.id, disk::compute_signature(bi.id, bi.address), bt->signature); 00264 #endif 00265 00266 #ifdef FAIRPORT_VALIDATION_LEVEL_FULL 00267 ulong crc = disk::compute_crc(&buffer[0], bi.size); 00268 if(crc != bt->crc) 00269 throw crc_fail("block crc failure", bi.address, bi.id, crc, bt->crc); 00270 #endif 00271 00272 return buffer; 00273 } 00274 00275 template<typename T> 00276 std::vector<fairport::byte> fairport::database_impl<T>::read_page_data(const page_info& pi) 00277 { 00278 #ifdef FAIRPORT_VALIDATION_LEVEL_WEAK 00279 if(pi.address + disk::page_size > m_header.root_info.ibFileEof) 00280 throw unexpected_page("nonsensical page location; past eof"); 00281 00282 if(((pi.address - disk::first_amap_page_location) % disk::page_size) != 0) 00283 throw unexpected_page("nonsensical page location; not sector aligned"); 00284 #endif 00285 00286 std::vector<byte> buffer(disk::page_size); 00287 disk::page<T>* ppage = (disk::page<T>*)&buffer[0]; 00288 00289 m_file.read(buffer, pi.address); 00290 00291 #ifdef FAIRPORT_VALIDATION_LEVEL_FULL 00292 ulong crc = disk::compute_crc(&buffer[0], disk::page<T>::page_data_size); 00293 if(crc != ppage->trailer.crc) 00294 throw crc_fail("page crc failure", pi.address, pi.id, crc, ppage->trailer.crc); 00295 #endif 00296 00297 #ifdef FAIRPORT_VALIDATION_LEVEL_WEAK 00298 if(ppage->trailer.bid != pi.id) 00299 throw unexpected_page("wrong page id"); 00300 00301 if(ppage->trailer.page_type != ppage->trailer.page_type_repeat) 00302 throw database_corrupt("ptype != ptype repeat?"); 00303 00304 if(ppage->trailer.signature != disk::compute_signature(pi.id, pi.address)) 00305 throw sig_mismatch("page sig mismatch", pi.address, pi.id, disk::compute_signature(pi.id, pi.address), ppage->trailer.signature); 00306 #endif 00307 00308 return buffer; 00309 } 00310 00311 00312 template<typename T> 00313 inline std::tr1::shared_ptr<fairport::bbt_page> fairport::database_impl<T>::read_bbt_root() 00314 { 00315 if(!m_bbt_root) 00316 { 00317 page_info pi = { m_header.root_info.brefBBT.bid, m_header.root_info.brefBBT.ib }; 00318 m_bbt_root = read_bbt_page(pi); 00319 } 00320 00321 return m_bbt_root; 00322 } 00323 00324 template<typename T> 00325 inline std::tr1::shared_ptr<fairport::nbt_page> fairport::database_impl<T>::read_nbt_root() 00326 { 00327 if(!m_nbt_root) 00328 { 00329 page_info pi = { m_header.root_info.brefNBT.bid, m_header.root_info.brefNBT.ib }; 00330 m_nbt_root = read_nbt_page(pi); 00331 } 00332 00333 return m_nbt_root; 00334 } 00335 00336 template<typename T> 00337 inline fairport::database_impl<T>::database_impl(const std::wstring& filename) 00338 : m_file(filename) 00339 { 00340 std::vector<byte> buffer(sizeof(m_header)); 00341 m_file.read(buffer, 0); 00342 memcpy(&m_header, &buffer[0], sizeof(m_header)); 00343 00344 validate_header(); 00345 } 00346 00347 template<typename T> 00348 inline std::tr1::shared_ptr<fairport::nbt_leaf_page> fairport::database_impl<T>::read_nbt_leaf_page(const page_info& pi) 00349 { 00350 std::vector<byte> buffer = read_page_data(pi); 00351 disk::page<T>* ppage = (disk::page<T>*)&buffer[0]; 00352 00353 if(ppage->trailer.page_type == disk::page_type_nbt) 00354 { 00355 disk::nbt_leaf_page<T>* leaf_page = (disk::nbt_leaf_page<T>*)ppage; 00356 00357 if(leaf_page->level == 0) 00358 return read_nbt_leaf_page(pi, *leaf_page); 00359 } 00360 00361 throw unexpected_page("page_type != page_type_nbt"); 00362 } 00363 00364 template<typename T> 00365 inline std::tr1::shared_ptr<fairport::nbt_leaf_page> fairport::database_impl<T>::read_nbt_leaf_page(const page_info& pi, disk::nbt_leaf_page<T>& the_page) 00366 { 00367 node_info ni; 00368 std::vector<std::pair<node_id, node_info> > nodes; 00369 00370 for(int i = 0; i < the_page.num_entries; ++i) 00371 { 00372 ni.id = static_cast<node_id>(the_page.entries[i].nid); 00373 ni.data_bid = the_page.entries[i].data; 00374 ni.sub_bid = the_page.entries[i].sub; 00375 ni.parent_id = the_page.entries[i].parent_nid; 00376 00377 nodes.push_back(std::make_pair(ni.id, ni)); 00378 } 00379 00380 #ifndef BOOST_NO_RVALUE_REFERENCES 00381 return std::tr1::shared_ptr<nbt_leaf_page>(new nbt_leaf_page(shared_from_this(), pi, std::move(nodes))); 00382 #else 00383 return std::tr1::shared_ptr<nbt_leaf_page>(new nbt_leaf_page(shared_from_this(), pi, nodes)); 00384 #endif 00385 } 00386 00387 template<typename T> 00388 inline std::tr1::shared_ptr<fairport::bbt_leaf_page> fairport::database_impl<T>::read_bbt_leaf_page(const page_info& pi) 00389 { 00390 std::vector<byte> buffer = read_page_data(pi); 00391 disk::page<T>* ppage = (disk::page<T>*)&buffer[0]; 00392 00393 if(ppage->trailer.page_type == disk::page_type_bbt) 00394 { 00395 disk::bbt_leaf_page<T>* leaf_page = (disk::bbt_leaf_page<T>*)ppage; 00396 00397 if(leaf_page->level == 0) 00398 return read_bbt_leaf_page(pi, *leaf_page); 00399 } 00400 00401 throw unexpected_page("page_type != page_type_bbt"); 00402 } 00403 00404 template<typename T> 00405 inline std::tr1::shared_ptr<fairport::bbt_leaf_page> fairport::database_impl<T>::read_bbt_leaf_page(const page_info& pi, disk::bbt_leaf_page<T>& the_page) 00406 { 00407 block_info bi; 00408 std::vector<std::pair<block_id, block_info> > blocks; 00409 00410 for(int i = 0; i < the_page.num_entries; ++i) 00411 { 00412 bi.id = the_page.entries[i].ref.bid; 00413 bi.address = the_page.entries[i].ref.ib; 00414 bi.size = the_page.entries[i].size; 00415 bi.ref_count = the_page.entries[i].ref_count; 00416 00417 blocks.push_back(std::make_pair(bi.id, bi)); 00418 } 00419 00420 #ifndef BOOST_NO_RVALUE_REFERENCES 00421 return std::tr1::shared_ptr<bbt_leaf_page>(new bbt_leaf_page(shared_from_this(), pi, std::move(blocks))); 00422 #else 00423 return std::tr1::shared_ptr<bbt_leaf_page>(new bbt_leaf_page(shared_from_this(), pi, blocks)); 00424 #endif 00425 } 00426 00427 template<typename T> 00428 inline std::tr1::shared_ptr<fairport::nbt_nonleaf_page> fairport::database_impl<T>::read_nbt_nonleaf_page(const page_info& pi) 00429 { 00430 std::vector<byte> buffer = read_page_data(pi); 00431 disk::page<T>* ppage = (disk::page<T>*)&buffer[0]; 00432 00433 if(ppage->trailer.page_type == disk::page_type_nbt) 00434 { 00435 disk::nbt_nonleaf_page<T>* nonleaf_page = (disk::nbt_nonleaf_page<T>*)ppage; 00436 00437 if(nonleaf_page->level > 0) 00438 return read_bt_nonleaf_page<node_id, node_info>(pi, *nonleaf_page); 00439 } 00440 00441 throw unexpected_page("page_type != page_type_nbt"); 00442 } 00443 00444 template<typename T> 00445 template<typename K, typename V> 00446 inline std::tr1::shared_ptr<fairport::bt_nonleaf_page<K,V> > fairport::database_impl<T>::read_bt_nonleaf_page(const page_info& pi, fairport::disk::bt_page<T, disk::bt_entry<T> >& the_page) 00447 { 00448 std::vector<std::pair<K, page_info> > nodes; 00449 00450 for(int i = 0; i < the_page.num_entries; ++i) 00451 { 00452 page_info subpi = { the_page.entries[i].ref.bid, the_page.entries[i].ref.ib }; 00453 nodes.push_back(std::make_pair(static_cast<K>(the_page.entries[i].key), subpi)); 00454 } 00455 00456 #ifndef BOOST_NO_RVALUE_REFERENCES 00457 return std::tr1::shared_ptr<bt_nonleaf_page<K,V> >(new bt_nonleaf_page<K,V>(shared_from_this(), pi, the_page.level, std::move(nodes))); 00458 #else 00459 return std::tr1::shared_ptr<bt_nonleaf_page<K,V> >(new bt_nonleaf_page<K,V>(shared_from_this(), pi, the_page.level, nodes)); 00460 #endif 00461 } 00462 00463 template<typename T> 00464 inline std::tr1::shared_ptr<fairport::bbt_nonleaf_page> fairport::database_impl<T>::read_bbt_nonleaf_page(const page_info& pi) 00465 { 00466 std::vector<byte> buffer = read_page_data(pi); 00467 disk::page<T>* ppage = (disk::page<T>*)&buffer[0]; 00468 00469 if(ppage->trailer.page_type == disk::page_type_bbt) 00470 { 00471 disk::bbt_nonleaf_page<T>* nonleaf_page = (disk::bbt_nonleaf_page<T>*)ppage; 00472 00473 if(nonleaf_page->level > 0) 00474 return read_bt_nonleaf_page<block_id, block_info>(pi, *nonleaf_page); 00475 } 00476 00477 throw unexpected_page("page_type != page_type_bbt"); 00478 } 00479 00480 template<typename T> 00481 inline std::tr1::shared_ptr<fairport::bbt_page> fairport::database_impl<T>::read_bbt_page(const page_info& pi) 00482 { 00483 std::vector<byte> buffer = read_page_data(pi); 00484 disk::page<T>* ppage = (disk::page<T>*)&buffer[0]; 00485 00486 if(ppage->trailer.page_type == disk::page_type_bbt) 00487 { 00488 disk::bbt_leaf_page<T>* leaf = (disk::bbt_leaf_page<T>*)ppage; 00489 if(leaf->level == 0) 00490 { 00491 // it really is a leaf! 00492 return read_bbt_leaf_page(pi, *leaf); 00493 } 00494 else 00495 { 00496 disk::bbt_nonleaf_page<T>* nonleaf = (disk::bbt_nonleaf_page<T>*)ppage; 00497 return read_bt_nonleaf_page<block_id, block_info>(pi, *nonleaf); 00498 } 00499 } 00500 else 00501 { 00502 throw unexpected_page("page_type != page_type_bbt"); 00503 } 00504 } 00505 00506 template<typename T> 00507 inline std::tr1::shared_ptr<fairport::nbt_page> fairport::database_impl<T>::read_nbt_page(const page_info& pi) 00508 { 00509 std::vector<byte> buffer = read_page_data(pi); 00510 disk::page<T>* ppage = (disk::page<T>*)&buffer[0]; 00511 00512 if(ppage->trailer.page_type == disk::page_type_nbt) 00513 { 00514 disk::nbt_leaf_page<T>* leaf = (disk::nbt_leaf_page<T>*)ppage; 00515 if(leaf->level == 0) 00516 { 00517 // it really is a leaf! 00518 return read_nbt_leaf_page(pi, *leaf); 00519 } 00520 else 00521 { 00522 disk::nbt_nonleaf_page<T>* nonleaf = (disk::nbt_nonleaf_page<T>*)ppage; 00523 return read_bt_nonleaf_page<node_id, node_info>(pi, *nonleaf); 00524 } 00525 } 00526 else 00527 { 00528 throw unexpected_page("page_type != page_type_nbt"); 00529 } 00530 } 00531 00532 template<typename T> 00533 inline fairport::node_info fairport::database_impl<T>::lookup_node_info(node_id nid) 00534 { 00535 return read_nbt_root()->lookup(nid); 00536 } 00537 00538 template<typename T> 00539 inline fairport::block_info fairport::database_impl<T>::lookup_block_info(block_id bid) 00540 { 00541 if(bid == 0) 00542 { 00543 block_info bi; 00544 bi.id = bi.address = bi.size = bi.ref_count = 0; 00545 return bi; 00546 } 00547 else 00548 { 00549 return read_bbt_root()->lookup(bid & (~(block_id(disk::block_id_attached_bit)))); 00550 } 00551 } 00552 00553 template<typename T> 00554 inline std::tr1::shared_ptr<fairport::block> fairport::database_impl<T>::read_block(const shared_db_ptr& parent, const block_info& bi) 00555 { 00556 std::tr1::shared_ptr<block> pblock; 00557 00558 try 00559 { 00560 pblock = read_data_block(parent, bi); 00561 } 00562 catch(unexpected_block&) 00563 { 00564 pblock = read_subnode_block(parent, bi); 00565 } 00566 00567 return pblock; 00568 } 00569 00570 template<typename T> 00571 inline std::tr1::shared_ptr<fairport::data_block> fairport::database_impl<T>::read_data_block(const shared_db_ptr& parent, const block_info& bi) 00572 { 00573 if(disk::bid_is_external(bi.id)) 00574 return read_external_block(parent, bi); 00575 00576 std::vector<byte> buffer(sizeof(disk::extended_block<T>)); 00577 disk::extended_block<T>* peblock = (disk::extended_block<T>*)&buffer[0]; 00578 m_file.read(buffer, bi.address); 00579 00580 // the behavior of read_block depends on this throw; this can not go under FAIRPORT_VALIDATION_WEAK 00581 if(peblock->block_type != disk::block_type_extended) 00582 throw unexpected_block("extended block expected"); 00583 00584 return read_extended_block(parent, bi); 00585 } 00586 00587 template<typename T> 00588 inline std::tr1::shared_ptr<fairport::extended_block> fairport::database_impl<T>::read_extended_block(const shared_db_ptr& parent, const block_info& bi) 00589 { 00590 if(!disk::bid_is_internal(bi.id)) 00591 throw unexpected_block("internal bid expected"); 00592 00593 std::vector<byte> buffer = read_block_data(bi); 00594 disk::extended_block<T>* peblock = (disk::extended_block<T>*)&buffer[0]; 00595 std::vector<block_id> child_blocks; 00596 00597 for(int i = 0; i < peblock->count; ++i) 00598 child_blocks.push_back(peblock->bid[i]); 00599 00600 #ifdef __GNUC__ 00601 // GCC gave link errors on extended_block<T> and external_block<T> max_size 00602 // with the below alernative 00603 uint sub_size = 0; 00604 if(peblock->level == 1) 00605 sub_size = disk::external_block<T>::max_size; 00606 else 00607 sub_size = disk::extended_block<T>::max_size; 00608 #else 00609 uint sub_size = (peblock->level == 1 ? disk::external_block<T>::max_size : disk::extended_block<T>::max_size); 00610 #endif 00611 uint sub_page_count = peblock->level == 1 ? 1 : disk::extended_block<T>::max_count; 00612 00613 #ifndef BOOST_NO_RVALUE_REFERENCES 00614 return std::tr1::shared_ptr<extended_block>(new extended_block(parent, bi, peblock->level, peblock->total_size, sub_size, disk::extended_block<T>::max_count, sub_page_count, std::move(child_blocks))); 00615 #else 00616 return std::tr1::shared_ptr<extended_block>(new extended_block(parent, bi, peblock->level, peblock->total_size, sub_size, disk::extended_block<T>::max_count, sub_page_count, child_blocks)); 00617 #endif 00618 } 00619 00620 template<typename T> 00621 inline std::tr1::shared_ptr<fairport::external_block> fairport::database_impl<T>::read_external_block(const shared_db_ptr& parent, const block_info& bi) 00622 { 00623 if(bi.id == 0) 00624 { 00625 return std::tr1::shared_ptr<external_block>(new external_block(parent, bi, disk::external_block<T>::max_size, std::vector<byte>())); 00626 } 00627 00628 if(!disk::bid_is_external(bi.id)) 00629 throw unexpected_block("External BID expected"); 00630 00631 std::vector<byte> buffer = read_block_data(bi); 00632 00633 if(m_header.bCryptMethod == disk::crypt_method_permute) 00634 { 00635 disk::permute(&buffer[0], bi.size, false); 00636 } 00637 else if(m_header.bCryptMethod == disk::crypt_method_cyclic) 00638 { 00639 disk::cyclic(&buffer[0], bi.size, (ulong)bi.id); 00640 } 00641 00642 #ifndef BOOST_NO_RVALUE_REFERENCES 00643 return std::tr1::shared_ptr<external_block>(new external_block(parent, bi, disk::external_block<T>::max_size, std::move(buffer))); 00644 #else 00645 return std::tr1::shared_ptr<external_block>(new external_block(parent, bi, disk::external_block<T>::max_size, buffer)); 00646 #endif 00647 } 00648 00649 template<typename T> 00650 inline std::tr1::shared_ptr<fairport::subnode_block> fairport::database_impl<T>::read_subnode_block(const shared_db_ptr& parent, const block_info& bi) 00651 { 00652 if(bi.id == 0) 00653 { 00654 return std::tr1::shared_ptr<subnode_block>(new subnode_leaf_block(parent, bi, std::vector<std::pair<node_id, subnode_info> >())); 00655 } 00656 00657 std::vector<byte> buffer = read_block_data(bi); 00658 disk::sub_leaf_block<T>* psub = (disk::sub_leaf_block<T>*)&buffer[0]; 00659 std::tr1::shared_ptr<subnode_block> sub_block; 00660 00661 if(psub->level == 0) 00662 { 00663 sub_block = read_subnode_leaf_block(parent, bi, *psub); 00664 } 00665 else 00666 { 00667 sub_block = read_subnode_nonleaf_block(parent, bi, *(disk::sub_nonleaf_block<T>*)&buffer[0]); 00668 } 00669 00670 return sub_block; 00671 } 00672 00673 template<typename T> 00674 inline std::tr1::shared_ptr<fairport::subnode_leaf_block> fairport::database_impl<T>::read_subnode_leaf_block(const shared_db_ptr& parent, const block_info& bi) 00675 { 00676 std::vector<byte> buffer = read_block_data(bi); 00677 disk::sub_leaf_block<T>* psub = (disk::sub_leaf_block<T>*)&buffer[0]; 00678 std::tr1::shared_ptr<subnode_leaf_block> sub_block; 00679 00680 if(psub->level == 0) 00681 { 00682 sub_block = read_subnode_leaf_block(parent, bi, *psub); 00683 } 00684 else 00685 { 00686 throw unexpected_block("psub->level != 0"); 00687 } 00688 00689 return sub_block; 00690 } 00691 00692 template<typename T> 00693 inline std::tr1::shared_ptr<fairport::subnode_nonleaf_block> fairport::database_impl<T>::read_subnode_nonleaf_block(const shared_db_ptr& parent, const block_info& bi) 00694 { 00695 std::vector<byte> buffer = read_block_data(bi); 00696 disk::sub_nonleaf_block<T>* psub = (disk::sub_nonleaf_block<T>*)&buffer[0]; 00697 std::tr1::shared_ptr<subnode_nonleaf_block> sub_block; 00698 00699 if(psub->level != 0) 00700 { 00701 sub_block = read_subnode_nonleaf_block(parent, bi, *psub); 00702 } 00703 else 00704 { 00705 throw unexpected_block("psub->level == 1"); 00706 } 00707 00708 return sub_block; 00709 } 00710 00711 template<typename T> 00712 inline std::tr1::shared_ptr<fairport::subnode_leaf_block> fairport::database_impl<T>::read_subnode_leaf_block(const shared_db_ptr& parent, const block_info& bi, disk::sub_leaf_block<T>& sub_block) 00713 { 00714 subnode_info ni; 00715 std::vector<std::pair<node_id, subnode_info> > subnodes; 00716 00717 for(int i = 0; i < sub_block.count; ++i) 00718 { 00719 #ifdef _MSC_VER 00720 #pragma warning(push) 00721 #pragma warning(disable:6385) 00722 #endif 00723 ni.id = sub_block.entry[i].nid; 00724 ni.data_bid = sub_block.entry[i].data; 00725 ni.sub_bid = sub_block.entry[i].sub; 00726 #ifdef _MSC_VER 00727 #pragma warning(pop) 00728 #endif 00729 00730 subnodes.push_back(std::make_pair(sub_block.entry[i].nid, ni)); 00731 } 00732 00733 #ifndef BOOST_NO_RVALUE_REFERENCES 00734 return std::tr1::shared_ptr<subnode_leaf_block>(new subnode_leaf_block(parent, bi, std::move(subnodes))); 00735 #else 00736 return std::tr1::shared_ptr<subnode_leaf_block>(new subnode_leaf_block(parent, bi, subnodes)); 00737 #endif 00738 } 00739 00740 template<typename T> 00741 inline std::tr1::shared_ptr<fairport::subnode_nonleaf_block> fairport::database_impl<T>::read_subnode_nonleaf_block(const shared_db_ptr& parent, const block_info& bi, disk::sub_nonleaf_block<T>& sub_block) 00742 { 00743 std::vector<std::pair<node_id, block_id> > subnodes; 00744 00745 for(int i = 0; i < sub_block.count; ++i) 00746 { 00747 #ifdef _MSC_VER 00748 #pragma warning(suppress:6385) 00749 #endif 00750 subnodes.push_back(std::make_pair(sub_block.entry[i].nid_key, sub_block.entry[i].sub_block_bid)); 00751 } 00752 00753 #ifndef BOOST_NO_RVALUE_REFERENCES 00754 return std::tr1::shared_ptr<subnode_nonleaf_block>(new subnode_nonleaf_block(parent, bi, std::move(subnodes))); 00755 #else 00756 return std::tr1::shared_ptr<subnode_nonleaf_block>(new subnode_nonleaf_block(parent, bi, subnodes)); 00757 #endif 00758 } 00759 00760 #endif