Fairport  v1.0.38
fairport/ndb/database.h
Go to the documentation of this file.
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