Fairport  v1.0.38
fairport/ltp/table.h
Go to the documentation of this file.
00001 
00002 
00003 
00004 
00005 
00006 #ifndef FAIRPORT_LTP_TABLE_H
00007 #define FAIRPORT_LTP_TABLE_H
00008 
00009 #include <vector>
00010 #if __GNUC__
00011 # include <tr1/unordered_map>
00012 #else
00013 # include <unordered_map>
00014 #endif
00015 #include <boost/iterator/iterator_facade.hpp>
00016 
00017 #include "fairport/util/primitives.h"
00018 
00019 #include "fairport/ndb/node.h"
00020 
00021 #include "fairport/ltp/object.h"
00022 #include "fairport/ltp/heap.h"
00023 
00024 namespace fairport
00025 {
00026 
00027 class table_impl;
00029 
00030 typedef std::tr1::shared_ptr<table_impl> table_ptr;
00031 typedef std::tr1::shared_ptr<const table_impl> const_table_ptr;
00033 
00037 table_ptr open_table(const node& n);
00038 
00049 class const_table_row : public const_property_object
00050 {
00051 public:
00054     const_table_row(const const_table_row& other)
00055         : m_position(other.m_position), m_table(other.m_table) { }
00059     const_table_row(ulong position, const const_table_ptr& table)
00060         : m_position(position), m_table(table) { }
00061 
00064     row_id get_row_id() const;
00065 
00066     // const_property_object
00067     std::vector<prop_id> get_prop_list() const;
00068     prop_type get_prop_type(prop_id id) const;
00069     bool prop_exists(prop_id id) const;
00070     size_t size(prop_id id) const;
00071     hnid_stream_device open_prop_stream(prop_id id);
00072 
00073 private:
00074     // const_property_object
00075     byte get_value_1(prop_id id) const;
00076     ushort get_value_2(prop_id id) const;
00077     ulong get_value_4(prop_id id) const;
00078     ulonglong get_value_8(prop_id id) const;
00079     std::vector<byte> get_value_variable(prop_id id) const;
00080 
00081     ulong m_position;           
00082     const_table_ptr m_table;    
00083 };
00084 
00092 class const_table_row_iter : public boost::iterator_facade<const_table_row_iter, const_table_row, boost::random_access_traversal_tag, const_table_row>
00093 {
00094 public:
00096     const_table_row_iter()
00097         : m_position(0) { }
00098 
00102     const_table_row_iter(ulong pos, const const_table_ptr& table) 
00103         : m_position(pos), m_table(table)  { }
00104 
00105 private:
00106     friend class boost::iterator_core_access;
00107 
00108     void increment() { ++m_position; }
00109     bool equal(const const_table_row_iter& other) const
00110         { return ((m_position == other.m_position) && (m_table == other.m_table)); }
00111     const_table_row dereference() const
00112         { return const_table_row(m_position, m_table); }
00113     void decrement() { --m_position; }
00114     void advance(int off) { m_position += off; }
00115     size_t distance_to(const const_table_row_iter& other) const
00116         { return (other.m_position - m_position); }
00117 
00118     ulong m_position;
00119     const_table_ptr m_table;
00120 };
00121 
00136 class table_impl : public std::tr1::enable_shared_from_this<table_impl>
00137 {
00138 public:
00139     virtual ~table_impl() { }
00144     virtual ulong lookup_row(row_id id) const = 0;
00145 
00149     const_table_row operator[](ulong row) const
00150         { return const_table_row(row, shared_from_this()); }
00153     const_table_row_iter begin() const
00154         { return const_table_row_iter(0, shared_from_this()); }
00157     const_table_row_iter end() const
00158         { return const_table_row_iter(size(), shared_from_this()); }
00159     
00162     virtual node& get_node() = 0;
00165     virtual const node& get_node() const = 0;
00172     virtual ulonglong get_cell_value(ulong row, prop_id id) const = 0;
00179     virtual std::vector<byte> read_cell(ulong row, prop_id id) const = 0;
00187     virtual hnid_stream_device open_cell_stream(ulong row, prop_id id) = 0;
00194     virtual std::vector<prop_id> get_prop_list() const = 0;
00197     virtual prop_type get_prop_type(prop_id id) const = 0;
00203     virtual row_id get_row_id(ulong row) const = 0;
00206     virtual size_t size() const = 0;
00211     virtual bool prop_exists(ulong row, prop_id id) const = 0;
00217     virtual size_t row_prop_size(ulong row, prop_id id) const = 0;
00218 };
00219 
00233 class empty_table : public table_impl
00234 {
00235 public:
00236     node& get_node() 
00237         { throw key_not_found<node_id>(0); }
00238     const node& get_node() const
00239         { throw key_not_found<node_id>(0); }
00240     ulong lookup_row(row_id id) const
00241         { throw key_not_found<row_id>(id); }
00242     ulonglong get_cell_value(ulong row, prop_id) const
00243         { throw key_not_found<ulong>(row); }
00244     std::vector<byte> read_cell(ulong row, prop_id) const
00245         { throw key_not_found<ulong>(row); }
00246     hnid_stream_device open_cell_stream(ulong row, prop_id)
00247         { throw key_not_found<ulong>(row); }
00248     std::vector<prop_id> get_prop_list() const
00249         { return std::vector<prop_id>(); }
00250     prop_type get_prop_type(prop_id id) const
00251         { throw key_not_found<prop_id>(id); }
00252     row_id get_row_id(ulong row) const
00253         { throw key_not_found<ulong>(row); }
00254     size_t size() const
00255         { return 0; }
00256     bool prop_exists(ulong row, prop_id) const
00257         { throw key_not_found<ulong>(row); }
00258     size_t row_prop_size(ulong row, prop_id) const
00259         { throw key_not_found<ulong>(row); }
00260 };
00261 
00276 template<typename T>
00277 class basic_table : public table_impl
00278 {
00279 public:
00280     node& get_node() 
00281         { return m_prows->get_node(); }
00282     const node& get_node() const
00283         { return m_prows->get_node(); }
00284     ulong lookup_row(row_id id) const;
00285     ulonglong get_cell_value(ulong row, prop_id id) const;
00286     std::vector<byte> read_cell(ulong row, prop_id id) const;
00287     hnid_stream_device open_cell_stream(ulong row, prop_id id);
00288     std::vector<prop_id> get_prop_list() const;
00289     prop_type get_prop_type(prop_id id) const;
00290     row_id get_row_id(ulong row) const;
00291     size_t size() const;
00292     bool prop_exists(ulong row, prop_id id) const;
00293     size_t row_prop_size(ulong row, prop_id id) const;
00294 
00295 private:
00296     friend table_ptr open_table(const node& n);
00297     basic_table(const node& n);
00298 
00299     std::tr1::shared_ptr<bth_node<row_id, T> > m_prows;
00300 
00301     // only one of the following two items is valid
00302     std::vector<byte> m_vec_rowarray;
00303     std::tr1::shared_ptr<node> m_pnode_rowarray;
00304 
00305     std::tr1::unordered_map<prop_id, disk::column_description> m_columns; 
00306     typedef std::tr1::unordered_map<prop_id, disk::column_description>::iterator column_iter;
00307     typedef std::tr1::unordered_map<prop_id, disk::column_description>::const_iterator const_column_iter;
00308 
00309     ushort m_offsets[disk::tc_offsets_max];
00310 
00311     // helper functions
00314     ulong cb_per_row() const { return m_offsets[disk::tc_offsets_bitmap]; }
00317     ulong exists_bitmap_start() const { return m_offsets[disk::tc_offsets_one]; }
00320     ulong rows_per_page() const { return (m_pnode_rowarray ? m_pnode_rowarray->get_page_size(0) / cb_per_row() : m_vec_rowarray.size() / cb_per_row()); }
00325     template<typename Val> Val read_raw_row(ulong row, ushort offset) const;
00328     std::vector<byte> read_exists_bitmap(ulong row) const;
00329 };
00330 
00331 typedef basic_table<ushort> small_table;
00332 typedef basic_table<ulong> large_table;
00333 
00346 class table
00347 {
00348 public:
00349 
00351     table()
00352         : m_ptable(new empty_table()) { }
00353 
00356     explicit table(const node& n);
00359     table(const table& other)
00360         : m_ptable(other.m_ptable) { }
00361 
00363     const_table_row operator[](ulong row) const
00364         { return (*m_ptable)[row]; }
00366     const_table_row_iter begin() const
00367         { return m_ptable->begin(); }
00369     const_table_row_iter end() const
00370         { return m_ptable->end(); }
00371 
00373     node& get_node() 
00374         { return m_ptable->get_node(); }
00376     const node& get_node() const
00377         { return m_ptable->get_node(); }
00379     ulonglong get_cell_value(ulong row, prop_id id) const
00380         { return m_ptable->get_cell_value(row, id); }
00382     std::vector<byte> read_cell(ulong row, prop_id id) const
00383         { return m_ptable->read_cell(row, id); }
00385     hnid_stream_device open_cell_stream(ulong row, prop_id id)
00386         { return m_ptable->open_cell_stream(row, id); }
00388     std::vector<prop_id> get_prop_list() const
00389         { return m_ptable->get_prop_list(); }
00391     prop_type get_prop_type(prop_id id) const
00392         { return m_ptable->get_prop_type(id); }
00394     row_id get_row_id(ulong row) const
00395         { return m_ptable->get_row_id(row); }
00397     ulong lookup_row(row_id id) const
00398         { return m_ptable->lookup_row(id); }
00400     size_t size() const
00401         { return m_ptable->size(); }
00402 
00403 private:
00404     table_ptr m_ptable;
00405 };
00406 
00407 } // end fairport namespace
00408 
00409 inline fairport::table_ptr fairport::open_table(const node& n)
00410 {
00411     if(n.get_id() == nid_all_message_search_contents)
00412     {
00413         throw not_implemented("gust table");
00414     }
00415 
00416     heap h(n);
00417     std::vector<byte> table_info = h.read(h.get_root_id());
00418     disk::tc_header* pheader = (disk::tc_header*)&table_info[0];
00419 
00420     std::vector<byte> bth_info = h.read(pheader->row_btree_id);
00421     disk::bth_header* pbthheader = (disk::bth_header*)&bth_info[0];
00422 
00423     if(pbthheader->entry_size == 4)
00424        return table_ptr(new large_table(n));
00425     else
00426        return table_ptr(new small_table(n));
00427 }
00428 
00429 inline std::vector<fairport::prop_id> fairport::const_table_row::get_prop_list() const
00430 {
00431     std::vector<prop_id> columns = m_table->get_prop_list();
00432     std::vector<prop_id> props;
00433 
00434     for(size_t i = 0; i < columns.size(); ++i)
00435     {
00436         if(prop_exists(columns[i]))
00437             props.push_back(columns[i]);
00438     }
00439 
00440     return props;
00441 }
00442 
00443 inline size_t fairport::const_table_row::size(prop_id id) const
00444 {
00445     return m_table->row_prop_size(m_position, id);
00446 }
00447 
00448 inline fairport::prop_type fairport::const_table_row::get_prop_type(prop_id id) const
00449 {
00450     return m_table->get_prop_type(id);
00451 }
00452 
00453 inline bool fairport::const_table_row::prop_exists(prop_id id) const
00454 {
00455     return m_table->prop_exists(m_position, id);
00456 }
00457 
00458 inline fairport::row_id fairport::const_table_row::get_row_id() const
00459 {
00460     return m_table->get_row_id(m_position);
00461 }
00462 
00463 inline fairport::byte fairport::const_table_row::get_value_1(prop_id id) const
00464 {
00465     return (byte)m_table->get_cell_value(m_position, id); 
00466 }
00467 
00468 inline fairport::ushort fairport::const_table_row::get_value_2(prop_id id) const
00469 {
00470     return (ushort)m_table->get_cell_value(m_position, id); 
00471 }
00472 
00473 inline fairport::ulong fairport::const_table_row::get_value_4(prop_id id) const
00474 {
00475     return (ulong)m_table->get_cell_value(m_position, id); 
00476 }
00477 
00478 inline fairport::ulonglong fairport::const_table_row::get_value_8(prop_id id) const
00479 {
00480     return m_table->get_cell_value(m_position, id); 
00481 }
00482 
00483 inline std::vector<fairport::byte> fairport::const_table_row::get_value_variable(prop_id id) const
00484 { 
00485     return m_table->read_cell(m_position, id); 
00486 }
00487 
00488 inline fairport::hnid_stream_device fairport::const_table_row::open_prop_stream(prop_id id)
00489 {
00490     return (std::tr1::const_pointer_cast<table_impl>(m_table))->open_cell_stream(m_position, id);
00491 }
00492 
00493 template<typename T>
00494 inline fairport::basic_table<T>::basic_table(const node& n)
00495 {
00496     heap h(n, disk::heap_sig_tc);
00497 
00498     std::vector<byte> table_info = h.read(h.get_root_id());
00499     disk::tc_header* pheader = (disk::tc_header*)&table_info[0];
00500 
00501 #ifdef FAIRPORT_VALIDATION_LEVEL_WEAK
00502     if(pheader->signature != disk::heap_sig_tc)
00503         throw sig_mismatch("heap_sig_tc expected", 0, n.get_id(), pheader->signature, disk::heap_sig_tc);
00504 #endif
00505 
00506     m_prows = h.open_bth<row_id, T>(pheader->row_btree_id);
00507 
00508     for(int i = 0; i < pheader->num_columns; ++i)
00509         m_columns[pheader->columns[i].id] = pheader->columns[i];
00510 
00511     for(int i = 0; i < disk::tc_offsets_max; ++i)
00512         m_offsets[i] = pheader->size_offsets[i];
00513 
00514     if(is_subnode_id(pheader->row_matrix_id))
00515     {
00516         m_pnode_rowarray.reset(new node(n.lookup(pheader->row_matrix_id)));
00517     }
00518     else if(pheader->row_matrix_id)
00519     {
00520         m_vec_rowarray = h.read(pheader->row_matrix_id);
00521     }
00522 }
00523 
00524 template<typename T>
00525 inline size_t fairport::basic_table<T>::size() const
00526 {
00527     if(m_pnode_rowarray)
00528     {
00529         return (m_pnode_rowarray->get_page_count()-1) * rows_per_page() + m_pnode_rowarray->get_page_size(m_pnode_rowarray->get_page_count()-1) / cb_per_row();
00530     }
00531     else 
00532     {
00533         return m_vec_rowarray.size() / cb_per_row();
00534     }
00535 }
00536 
00537 template<typename T>
00538 inline std::vector<fairport::prop_id> fairport::basic_table<T>::get_prop_list() const
00539 {
00540     std::vector<prop_id> props;
00541 
00542     for(const_column_iter i = m_columns.begin(); i != m_columns.end(); ++i)
00543         props.push_back(i->first);
00544 
00545     return props;
00546 }
00547 
00548 template<typename T>
00549 inline fairport::ulong fairport::basic_table<T>::lookup_row(row_id id) const
00550 { 
00551     try 
00552     { 
00553         return (ulong)m_prows->lookup(id); 
00554     } 
00555     catch(key_not_found<T>& e) 
00556     { 
00557         throw key_not_found<row_id>(e.which()); 
00558     } 
00559 }
00560 
00561 template<typename T>
00562 inline fairport::ulonglong fairport::basic_table<T>::get_cell_value(ulong row, prop_id id) const
00563 {
00564     if(!prop_exists(row, id))
00565         throw key_not_found<prop_id>(id);
00566 
00567     const_column_iter column = m_columns.find(id);
00568     ulonglong value;
00569 
00570     switch(column->second.size)
00571     {
00572         case 8:
00573             value = read_raw_row<ulonglong>(row, column->second.offset);
00574             break;
00575         case 4:
00576             value = read_raw_row<ulong>(row, column->second.offset);
00577             break;
00578         case 2:
00579             value = read_raw_row<ushort>(row, column->second.offset);
00580             break;
00581         case 1:
00582             value = read_raw_row<byte>(row, column->second.offset);
00583             break;
00584         default:
00585             throw database_corrupt("get_cell_value: invalid cell size");
00586     }
00587 
00588     return value;
00589 }
00590 
00591 template<typename T>
00592 inline size_t fairport::basic_table<T>::row_prop_size(ulong row, prop_id id) const
00593 {
00594     heapnode_id hid = static_cast<heapnode_id>(get_cell_value(row, id));
00595 
00596     if(is_subnode_id(hid))
00597         return get_node().lookup(hid).size();
00598     else
00599         return m_prows->get_heap_ptr()->size(hid);
00600 }
00601 
00602 template<typename T>
00603 inline std::vector<fairport::byte> fairport::basic_table<T>::read_cell(ulong row, prop_id id) const
00604 {
00605     heapnode_id hid = static_cast<heapnode_id>(get_cell_value(row, id));
00606     std::vector<byte> buffer;
00607 
00608     if(is_subnode_id(hid))
00609     {
00610         node sub(get_node().lookup(hid));
00611         buffer.resize(sub.size());
00612         sub.read(buffer, 0);
00613     }
00614     else
00615     {
00616         buffer = m_prows->get_heap_ptr()->read(hid);
00617     }
00618     return buffer;
00619 }
00620 
00621 template<typename T>
00622 inline fairport::hnid_stream_device fairport::basic_table<T>::open_cell_stream(ulong row, prop_id id)
00623 {
00624     heapnode_id hid = static_cast<heapnode_id>(get_cell_value(row, id));
00625 
00626     if(is_subnode_id(hid))
00627         return get_node().lookup(hid).open_as_stream();
00628     else
00629         return m_prows->get_heap_ptr()->open_stream(hid);
00630 }
00631 
00632 template<typename T>
00633 inline fairport::prop_type fairport::basic_table<T>::get_prop_type(prop_id id) const
00634 {
00635     const_column_iter iter = m_columns.find(id);
00636 
00637     if(iter == m_columns.end())
00638         throw key_not_found<prop_id>(id);
00639 
00640     return (prop_type)iter->second.type;
00641 }
00642 
00643 template<typename T>
00644 inline fairport::row_id fairport::basic_table<T>::get_row_id(ulong row) const
00645 {
00646     return read_raw_row<row_id>(row, 0);
00647 }
00648 
00649 template<typename T>
00650 template<typename Val>
00651 inline Val fairport::basic_table<T>::read_raw_row(ulong row, ushort offset) const
00652 {
00653     if(row >= size())
00654         throw std::out_of_range("row >= size()");
00655 
00656     if(m_pnode_rowarray)
00657     {
00658         ulong page_num = row / rows_per_page();
00659         ulong page_offset = (row % rows_per_page()) * cb_per_row();
00660 
00661         return m_pnode_rowarray->read<Val>(page_num, page_offset+offset);
00662     }
00663     else
00664     {
00665         Val val;
00666         memcpy(&val, &m_vec_rowarray[ row * cb_per_row() + offset ], sizeof(Val));
00667         return val;
00668     }
00669 }
00670 
00671 template<typename T>
00672 inline std::vector<fairport::byte> fairport::basic_table<T>::read_exists_bitmap(ulong row) const
00673 {
00674     std::vector<byte> exists_bitmap(cb_per_row() - exists_bitmap_start());
00675 
00676     if(row >= size())
00677         throw std::out_of_range("row >= size()");
00678 
00679     if(m_pnode_rowarray)
00680     {
00681         ulong page_num = row / rows_per_page();
00682         ulong page_offset = (row % rows_per_page()) * cb_per_row();
00683 
00684         m_pnode_rowarray->read(exists_bitmap, page_num, page_offset + exists_bitmap_start());
00685     }
00686     else
00687     {
00688         memcpy(&exists_bitmap[0], &m_vec_rowarray[ row * cb_per_row() + exists_bitmap_start() ], exists_bitmap.size());
00689     }    
00690 
00691     return exists_bitmap;
00692 }
00693 
00694 template<typename T>
00695 inline bool fairport::basic_table<T>::prop_exists(ulong row, prop_id id) const
00696 {
00697     const_column_iter column = m_columns.find(id);
00698 
00699     if(column == m_columns.end())
00700         return false;
00701 
00702     std::vector<byte> exists_map = read_exists_bitmap(row);
00703 
00704     return test_bit(&exists_map[0], column->second.bit_offset);
00705 }
00706 
00707 inline fairport::table::table(const node& n)
00708 {
00709     m_ptable = open_table(n);
00710 }
00711 #endif