From a062735d60aa3a1f865dd58d2774afd2d539f656 Mon Sep 17 00:00:00 2001 From: Antony T Curtis Date: Wed, 13 Apr 2011 19:06:43 -0700 Subject: [PATCH] Cleanup, simplify and optimize. Change makefile a little so that we have debug symbols for the graph core. --- storage/oqgraph/Makefile.am | 29 +- storage/oqgraph/graphcore-graph.h | 91 +- storage/oqgraph/graphcore.cc | 11 +- storage/oqgraph/ha_oqgraph.cc | 30 +- storage/oqgraph/ha_oqgraph.h | 6 +- storage/oqgraph/oqgraph_judy.cc | 13 + storage/oqgraph/oqgraph_judy.h | 20 +- storage/oqgraph/oqgraph_shim.cc | 48 + storage/oqgraph/oqgraph_shim.h | 604 ++++--------- storage/oqgraph/oqgraph_thunk.cc | 1403 ++++++++++------------------- storage/oqgraph/oqgraph_thunk.h | 398 ++------ 11 files changed, 861 insertions(+), 1792 deletions(-) diff --git a/storage/oqgraph/Makefile.am b/storage/oqgraph/Makefile.am index 95884623732..8e096a524d3 100644 --- a/storage/oqgraph/Makefile.am +++ b/storage/oqgraph/Makefile.am @@ -59,9 +59,9 @@ noinst_HEADERS = ha_oqgraph.h \ graphcore-graph.h graphcore-types.h graphcore.h # oqgraph_probes.h -noinst_LTLIBRARIES = libgraphcore.la -libgraphcore_la_SOURCES = graphcore.cc graphcore-graph.cc oqgraph_shim.cc oqgraph_thunk.cc -libgraphcore_la_CXXFLAGS = $(ORIG_CXXFLAGS) $(BOOST_CXXFLAGS) +#noinst_LTLIBRARIES = libgraphcore.la +#libgraphcore_la_SOURCES = graphcore.cc graphcore-graph.cc oqgraph_shim.cc oqgraph_thunk.cc +#libgraphcore_la_CXXFLAGS = $(ORIG_CXXFLAGS) $(BOOST_CXXFLAGS) if BUILD_OQGRAPH_FOR_MYSQL @@ -73,8 +73,27 @@ endif !BUILD_OQGRAPH_STANDALONE EXTRA_LTLIBRARIES = ha_oqgraph.la mysqlplugin_LTLIBRARIES = @plugin_oqgraph_shared_target@ -ha_oqgraph_la_SOURCES = ha_oqgraph.cc oqgraph_judy.cc -ha_oqgraph_la_LIBADD = libgraphcore.la +ha_oqgraph_la_SOURCES = ha_oqgraph.cc oqgraph_judy.cc \ + graphcore.cc graphcore-graph.cc \ + oqgraph_thunk.cc oqgraph_shim.cc + +#ha_oqgraph_la_LIBADD = libgraphcore.la + +ha_oqgraph_la-graphcore.lo: graphcore.cc + $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ORIG_CXXFLAGS) $(BOOST_CXXFLAGS) $(CXXFLAGS) -MT ha_oqgraph_la-graphcore.lo -MD -MP -MF $(DEPDIR)/ha_oqgraph_la-graphcore.Tpo -c -o ha_oqgraph_la-graphcore.lo `test -f 'graphcore.cc' || echo '$(srcdir)/'`graphcore.cc + mv -f $(DEPDIR)/ha_oqgraph_la-graphcore.Tpo $(DEPDIR)/ha_oqgraph_la-graphcore.Plo + +ha_oqgraph_la-graphcore-graph.lo: graphcore-graph.cc + $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ORIG_CXXFLAGS) $(BOOST_CXXFLAGS) $(CXXFLAGS) -MT ha_oqgraph_la-graphcore-graph.lo -MD -MP -MF $(DEPDIR)/ha_oqgraph_la-graphcore-graph.Tpo -c -o ha_oqgraph_la-graphcore-graph.lo `test -f 'graphcore.cc' || echo '$(srcdir)/'`graphcore-graph.cc + mv -f $(DEPDIR)/ha_oqgraph_la-graphcore-graph.Tpo $(DEPDIR)/ha_oqgraph_la-graphcore-graph.Plo + +ha_oqgraph_la-oqgraph_shim.lo: oqgraph_shim.cc + $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ORIG_CXXFLAGS) $(BOOST_CXXFLAGS) $(CXXFLAGS) -MT ha_oqgraph_la-oqgraph_shim.lo -MD -MP -MF $(DEPDIR)/ha_oqgraph_la-oqgraph_shim.Tpo -c -o ha_oqgraph_la-oqgraph_shim.lo `test -f 'oqgraph_shim.cc' || echo '$(srcdir)/'`oqgraph_shim.cc + mv -f $(DEPDIR)/ha_oqgraph_la-oqgraph_shim.Tpo $(DEPDIR)/ha_oqgraph_la-oqgraph_shim.Plo + +ha_oqgraph_la-oqgraph_thunk.lo: oqgraph_thunk.cc + $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ORIG_CXXFLAGS) $(BOOST_CXXFLAGS) $(CXXFLAGS) -MT ha_oqgraph_la-oqgraph_thunk.lo -MD -MP -MF $(DEPDIR)/ha_oqgraph_la-oqgraph_thunk.Tpo -c -o ha_oqgraph_la-oqgraph_thunk.lo `test -f 'oqgraph_thunk.cc' || echo '$(srcdir)/'`oqgraph_thunk.cc + mv -f $(DEPDIR)/ha_oqgraph_la-oqgraph_thunk.Tpo $(DEPDIR)/ha_oqgraph_la-oqgraph_thunk.Plo # if HAVE_DTRACE # ha_oqgraph_la_LIBADD += oqgraph_probes.o diff --git a/storage/oqgraph/graphcore-graph.h b/storage/oqgraph/graphcore-graph.h index fb3b4b987e0..9131028b3bd 100644 --- a/storage/oqgraph/graphcore-graph.h +++ b/storage/oqgraph/graphcore-graph.h @@ -35,18 +35,6 @@ namespace boost { typedef oqgraph3::graph Graph; - template <> - struct hash::vertex_descriptor> - : public std::unary_function< - graph_traits::vertex_descriptor, std::size_t> - { - std::size_t operator()( - const graph_traits::vertex_descriptor& v) const - { - return boost::hash_value(v->id); - } - }; - template struct two_bit_judy_map { @@ -54,15 +42,15 @@ namespace boost typedef two_bit_color_type value_type; typedef void reference; typedef read_write_property_map_tag category; - + open_query::judy_bitset msb; open_query::judy_bitset lsb; IndexMap index; - + two_bit_judy_map(const IndexMap& i) : index(i) { } - + friend two_bit_color_type get( const two_bit_judy_map& pm, typename property_traits::key_type key) @@ -70,7 +58,7 @@ namespace boost typename property_traits::value_type i = get(pm.index, key); return two_bit_color_type((2*int(pm.msb.test(i))) | int(pm.lsb.test(i))); } - + friend void put( two_bit_judy_map& pm, typename property_traits::key_type key, @@ -81,7 +69,7 @@ namespace boost pm.lsb.set(i, value & 1); } }; - + template inline two_bit_judy_map make_two_bit_judy_map(const IndexMap& index) @@ -89,7 +77,7 @@ namespace boost return two_bit_judy_map(index); } - + template struct default_lazy_initializer { @@ -119,11 +107,11 @@ namespace boost const Type& operator()(const Key&) const { return _; } const Type _; }; - + template value_initializer make_value_initializer(const Type& value) { return value_initializer(value); } - + template struct identity_initializer @@ -139,12 +127,12 @@ namespace boost typedef typename Container::value_type::second_type value_type; typedef value_type& reference; typedef lvalue_property_map_tag category; - + lazy_property_map(Container& m, Generator g= Generator()) : _m(m) , _g(g) { } - + reference operator[](const key_type& k) const { typename Container::iterator found= _m.find(k); @@ -154,7 +142,7 @@ namespace boost } return found->second; } - + void set(const key_type& k, const value_type& v) { _m[k] = v; } @@ -162,7 +150,7 @@ namespace boost { return s[k]; } - + friend void put(self& s, const key_type& k, const value_type& v) { s.set(k, v); } @@ -175,61 +163,6 @@ namespace boost make_lazy_property_map(Container& c, Generator g) { return lazy_property_map(c, g); } -#if 0 - - struct map_wra - - - struct property_traits< unordered_map_wrapper - struct property_traits< unordered_map > { - typedef T value_type; - typedef K key_type; - typedef T& reference; - struct category - : public read_write_property_map_tag - , public lvalue_property_map_tag - { }; - - friend reference get( - unordered_map& m, - const key_type& k) - { - return m[k]; - } - - friend void put( - unordered_map& m, - const key_type& k, - const value_type& v) - { - m[k]= v; - } - }; - - //template - //property_traits< unordered_map >::reference - //get(unordered_map& m, - // const property_traits< unordered_map >::key_type& k) - //{ return m[ k ]; } - - //template - //void put( - // unordered_map& m, - // const property_traits< unordered_map >::key_type& k, - // const property_traits< unordered_map >::value_type& v) - //{ m[ k ] = v; } - - //template - //property_traits< unordered_map::reference - //get(unordered_map& m, - // const graph_traits::vertex_descriptor& v) - //{ return m[ v->id ]; } -#endif - } #endif diff --git a/storage/oqgraph/graphcore.cc b/storage/oqgraph/graphcore.cc index f57f7507e82..11a278f62ed 100644 --- a/storage/oqgraph/graphcore.cc +++ b/storage/oqgraph/graphcore.cc @@ -345,7 +345,7 @@ namespace open_query { oqgraph_visit_dist make_oqgraph_visit_dist(const P& p, const D& d, stack_cursor *cursor) { return oqgraph_visit_dist(p, d, cursor); } - + template struct GRAPHCORE_INTERNAL oqgraph_goal @@ -402,7 +402,7 @@ namespace open_query { stack_cursor &m_cursor; P m_p; }; - + template oqgraph_goal make_oqgraph_goal(const Vertex& goal, const P& p, stack_cursor *cursor) @@ -820,7 +820,7 @@ namespace open_query ) ), make_two_bit_judy_map(get(vertex_index, share->g))); - break; + break; case BREADTH_FIRST: breadth_first_visit(share->g, *orig, Q, make_bfs_visitor( @@ -1060,9 +1060,8 @@ int edges_cursor::fetch_row(const row &row_info, row &result) { edge_iterator it, end; reference ref; - size_t count= position; - for (tie(it, end)= edges(share->g); count && it != end; ++it, --count) - ; + tie(it, end)= edges(share->g); + it+= position; if (it != end) ref= reference(position+1, *it); if (int res= fetch_row(row_info, result, ref)) diff --git a/storage/oqgraph/ha_oqgraph.cc b/storage/oqgraph/ha_oqgraph.cc index 06cdad13ccf..5e0936cf81d 100644 --- a/storage/oqgraph/ha_oqgraph.cc +++ b/storage/oqgraph/ha_oqgraph.cc @@ -274,13 +274,13 @@ int ha_oqgraph::open(const char *name, int mode, uint test_if_locked) reinterpret_cast(table->s->option_struct); error_message.length(0); - + const char* p= strend(name)-1; while (p > name && *p != '\\' && *p != '/') --p; init_tmp_table_share( - thd, share, table->s->db.str, table->s->db.length, + thd, share, table->s->db.str, table->s->db.length, options->table_name, ""); size_t tlen= strlen(options->table_name); @@ -303,7 +303,7 @@ int ha_oqgraph::open(const char *name, int mode, uint test_if_locked) free_table_share(share); return thd->main_da.sql_errno(); } - + if (ha_create_table_from_engine(thd, table->s->db.str, options->table_name)) { free_table_share(share); @@ -313,7 +313,7 @@ int ha_oqgraph::open(const char *name, int mode, uint test_if_locked) thd->clear_error(); continue; } - + if (int err= share->error) { open_table_error(share, share->error, share->open_errno, share->errarg); @@ -341,7 +341,7 @@ int ha_oqgraph::open(const char *name, int mode, uint test_if_locked) } edges->reginfo.lock_type= TL_READ; - + edges->tablenr= thd->current_tablenr++; edges->status= STATUS_NO_RECORD; edges->file->ha_start_of_new_statement(); @@ -349,18 +349,18 @@ int ha_oqgraph::open(const char *name, int mode, uint test_if_locked) edges->pos_in_table_list= 0; edges->clear_column_bitmaps(); bfill(table->record[0], table->s->null_bytes, 255); - bfill(table->record[1], table->s->null_bytes, 255); - + bfill(table->record[1], table->s->null_bytes, 255); + // We expect fields origid, destid and optionally weight origid= destid= weight= 0; - + if (!edges->file) { print_error("Some error occurred opening table '%s'", options->table_name); free_table_share(share); return -1; } - + for (Field **field= edges->field; *field; ++field) { if (strcmp(options->origid, (*field)->field_name)) @@ -377,7 +377,7 @@ int ha_oqgraph::open(const char *name, int mode, uint test_if_locked) origid = *field; break; } - + for (Field **field= edges->field; *field; ++field) { if (strcmp(options->destid, (*field)->field_name)) @@ -394,7 +394,7 @@ int ha_oqgraph::open(const char *name, int mode, uint test_if_locked) destid = *field; break; } - + for (Field **field= edges->field; options->weight && *field; ++field) { if (strcmp(options->weight, (*field)->field_name)) @@ -411,7 +411,7 @@ int ha_oqgraph::open(const char *name, int mode, uint test_if_locked) weight = *field; break; } - + if (!origid || !destid || (!weight && options->weight)) { print_error("Data columns missing on table '%s'", options->table_name); @@ -419,7 +419,7 @@ int ha_oqgraph::open(const char *name, int mode, uint test_if_locked) free_table_share(share); return -1; } - + if (!(graph_share = oqgraph::create(edges, origid, destid, weight))) { print_error("Unable to create graph instance."); @@ -428,9 +428,9 @@ int ha_oqgraph::open(const char *name, int mode, uint test_if_locked) return -1; } ref_length= oqgraph::sizeof_ref; - + graph = oqgraph::create(graph_share); - + return 0; } diff --git a/storage/oqgraph/ha_oqgraph.h b/storage/oqgraph/ha_oqgraph.h index 4c606dcc7e4..654635d6ffd 100644 --- a/storage/oqgraph/ha_oqgraph.h +++ b/storage/oqgraph/ha_oqgraph.h @@ -111,11 +111,11 @@ public: THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, enum thr_lock_type lock_type); int cmp_ref(const byte *ref1, const byte *ref2); - + bool get_error_message(int error, String* buf); - + void print_error(const char* fmt, ...); - + private: void update_key_stats(); String error_message; diff --git a/storage/oqgraph/oqgraph_judy.cc b/storage/oqgraph/oqgraph_judy.cc index bf6b8e879c4..5a5d5760718 100644 --- a/storage/oqgraph/oqgraph_judy.cc +++ b/storage/oqgraph/oqgraph_judy.cc @@ -90,6 +90,19 @@ open_query::judy_bitset::size_type open_query::judy_bitset::count() const return rc; } +open_query::judy_bitset& open_query::judy_bitset::set(const judy_bitset& src) +{ + if (!src.empty()) + { + for (size_type pos= src.find_first(); pos != npos; pos= src.find_next(pos)) + { + set(pos); + } + } + return *this; +} + + open_query::judy_bitset::size_type open_query::judy_bitset::find_first() const { int rc; diff --git a/storage/oqgraph/oqgraph_judy.h b/storage/oqgraph/oqgraph_judy.h index 965883c0864..62c772f031b 100644 --- a/storage/oqgraph/oqgraph_judy.h +++ b/storage/oqgraph/oqgraph_judy.h @@ -41,9 +41,21 @@ namespace open_query : array(0) { } + judy_bitset(const judy_bitset& src) + : array(0) + { + set(src); + } + ~judy_bitset() { clear(); } + judy_bitset& operator=(const judy_bitset& src) + { + clear(); + return set(src); + } + void clear(); bool empty() const { return !array; } bool none() const { return npos == find_first(); } @@ -56,6 +68,8 @@ namespace open_query return setbit(n); } + judy_bitset& set(const judy_bitset& src); + judy_bitset& reset(size_type n); judy_bitset& flip(size_type n); bool test(size_type) const; @@ -85,7 +99,7 @@ namespace open_query { if (value) j.flip(n); return *this; } reference& operator-=(bool value) { if (value) j.reset(n); return *this; } - + bool operator~() const { return !j.test(n); } operator bool() const { return j.test(n); } reference& flip() { j.flip(n); return *this; } @@ -94,10 +108,10 @@ namespace open_query judy_bitset& j; size_type n; }; - + reference operator[](size_type n) { return reference(*this, n); } bool operator[](size_type n) const { return test(n); } - + size_type find_first() const; size_type find_next(size_type n) const; private: diff --git a/storage/oqgraph/oqgraph_shim.cc b/storage/oqgraph/oqgraph_shim.cc index 57ffe660532..cef2c4f3a57 100644 --- a/storage/oqgraph/oqgraph_shim.cc +++ b/storage/oqgraph/oqgraph_shim.cc @@ -26,3 +26,51 @@ #include "oqgraph_shim.h" +bool oqgraph3::edge_iterator::seek() +{ + if (!_graph->_cursor || + _graph->_rnd_pos > _offset || + _graph->_cursor != _graph->_rnd_cursor.operator->()) + { + _graph->_rnd_pos= 0; + _graph->_rnd_cursor= new cursor(_graph); + if (_graph->_rnd_cursor->seek_to(boost::none, boost::none)) + _graph->_rnd_pos= size_t(-1); + } + while (_graph->_rnd_pos < _offset) + { + if (_graph->_rnd_cursor->seek_next()) + { + _offset = size_t(-1); + return true; + } + _graph->_rnd_pos++; + } + return false; +} + +oqgraph3::edge_iterator::value_type oqgraph3::edge_iterator::operator*() +{ + seek(); + return *_graph->_rnd_cursor; +} + +bool oqgraph3::edge_iterator::operator==(const self& x) +{ + if (_offset == size_t(-1) && x._offset != size_t(-1)) + return const_cast(x).seek(); + if (_offset != size_t(-1) && x._offset == size_t(-1)) + return seek(); + + return _offset == x._offset; +} + +bool oqgraph3::edge_iterator::operator!=(const self& x) +{ + if (_offset == size_t(-1) && x._offset != size_t(-1)) + return !const_cast(x).seek(); + if (_offset != size_t(-1) && x._offset == size_t(-1)) + return !seek(); + + return _offset != x._offset; +} diff --git a/storage/oqgraph/oqgraph_shim.h b/storage/oqgraph/oqgraph_shim.h index 4e381d797c3..d3a5a359b97 100644 --- a/storage/oqgraph/oqgraph_shim.h +++ b/storage/oqgraph/oqgraph_shim.h @@ -53,62 +53,73 @@ namespace oqgraph3 struct edge_iterator { typedef edge_iterator self; - typedef edge_descriptor value_type; - typedef edge_descriptor& reference; - typedef edge_descriptor pointer; + typedef edge_info value_type; + typedef edge_info& reference; + typedef edge_info pointer; typedef std::ptrdiff_t difference_type; typedef std::input_iterator_tag iterator_category; edge_iterator() { } - edge_iterator(row_cursor iter) : _iter(iter) { } - edge_descriptor operator*() { return _iter->_current; } - self& operator++() { ++(*_iter); return *this; } - self operator++(int) { self t= *this; ++(*this); return t; } - bool operator==(const self& x) { return _iter == x._iter; } - bool operator!=(const self& x) { return _iter != x._iter; } - boost::optional _iter; + edge_iterator(const graph_ptr& graph, size_t offset=0) + : _graph(graph) + , _offset(offset) { } + edge_iterator(const edge_iterator& pos) + : _graph(pos._graph) + , _offset(pos._offset) { } + value_type operator*(); + self& operator+=(size_t n) { _offset+= n; return *this; } + self& operator++() { ++_offset; return *this; } + self operator++(int) + { size_t temp= _offset++; return edge_iterator(_graph, temp); } + bool seek(); + bool operator==(const self& x); + bool operator!=(const self& x); + graph_ptr _graph; + size_t _offset; }; struct vertex_iterator { typedef vertex_iterator self; - typedef vertex_descriptor value_type; - typedef vertex_descriptor& reference; - typedef vertex_descriptor pointer; + typedef vertex_id value_type; + typedef vertex_id& reference; + typedef vertex_id pointer; typedef std::ptrdiff_t difference_type; typedef std::input_iterator_tag iterator_category; vertex_iterator() { } - vertex_iterator(edge_iterator iter) : _iter(iter) { } - vertex_descriptor operator*() + vertex_iterator(const cursor_ptr& pos) : _cursor(pos.operator->()) { } + vertex_id operator*() const { - if (!_seen.test(_iter._iter->operator*().first)) - return _iter._iter->_cache->vertex(_iter._iter->operator*().first); + edge_info edge(*_cursor); + if (!_seen.test(edge.origid())) + return edge.origid(); else - return _iter._iter->_cache->vertex(_iter._iter->operator*().second); + return edge.destid(); } self& operator++() { - if (!_seen.test(_iter._iter->operator*().first)) + edge_info edge(*_cursor); + if (!_seen.test(edge.origid())) { - _seen.set(_iter._iter->operator*().first); + _seen.set(edge.origid()); } else { - _seen.set(_iter._iter->operator*().second); + _seen.set(edge.destid()); } - while (_iter._iter->_current && - _seen.test(_iter._iter->operator*().first) && - _seen.test(_iter._iter->operator*().second)) + while (_seen.test(edge.origid()) && _seen.test(edge.destid())) { - ++_iter; + if (_cursor->seek_next()) + break; + edge= _cursor; } return *this; } - self operator++(int) { self t= *this; ++(*this); return t; } - bool operator==(const self& x) { return _iter == x._iter; } - bool operator!=(const self& x) { return _iter != x._iter; } - edge_iterator _iter; + self operator++(int) { cursor* t(new cursor(*_cursor)); ++(*this); return vertex_iterator(t); } + bool operator==(const self& x) { return *_cursor == *x._cursor; } + bool operator!=(const self& x) { return *_cursor != *x._cursor; } + cursor_ptr _cursor; open_query::judy_bitset _seen; }; @@ -116,74 +127,70 @@ namespace oqgraph3 struct out_edge_iterator { typedef out_edge_iterator self; - typedef vertex_info::edge_list_type::const_iterator iter_type; - - typedef edge_descriptor value_type; - typedef edge_descriptor& reference; - typedef edge_descriptor pointer; + typedef edge_info value_type; + typedef edge_info& reference; + typedef edge_info pointer; typedef std::ptrdiff_t difference_type; typedef std::input_iterator_tag iterator_category; out_edge_iterator() { } - out_edge_iterator(iter_type iter, const vertex_descriptor& v) - : _iter(iter), _v(v) { } - edge_descriptor operator*() - { return _v->_cache->edge(edge_key(*_iter)); } - self& operator++() { ++_iter; return *this; } - self operator++(int) { self t= *this; ++(*this); return t; } - bool operator==(const self& x) { return _iter == x._iter; } - bool operator!=(const self& x) { return _iter != x._iter; } - iter_type _iter; - vertex_descriptor _v; + out_edge_iterator(const cursor_ptr& cursor) : _cursor(cursor) { } + value_type operator*() { return value_type(_cursor); } + self& operator++() { _cursor->seek_next(); return *this; } + self operator++(int) + { cursor_ptr t(new cursor(*_cursor)); ++(*this); return out_edge_iterator(t); } + bool operator==(const self& x) { return _cursor == x._cursor; } + bool operator!=(const self& x) { return _cursor != x._cursor; } + cursor_ptr _cursor; }; struct in_edge_iterator { typedef in_edge_iterator self; - typedef vertex_info::edge_list_type::const_iterator iter_type; - - typedef edge_descriptor value_type; - typedef edge_descriptor& reference; - typedef edge_descriptor pointer; + typedef edge_info value_type; + typedef edge_info& reference; + typedef edge_info pointer; typedef std::ptrdiff_t difference_type; typedef std::input_iterator_tag iterator_category; in_edge_iterator() { } - in_edge_iterator(iter_type iter, const vertex_descriptor& v) - : _iter(iter), _v(v) { } - edge_descriptor operator*() - { return _v->_cache->edge(edge_key(*_iter)); } - self& operator++() { ++_iter; return *this; } - self operator++(int) { self t= *this; ++(*this); return t; } - bool operator==(const self& x) { return _iter == x._iter; } - bool operator!=(const self& x) { return _iter != x._iter; } - iter_type _iter; - vertex_descriptor _v; + in_edge_iterator(const cursor_ptr& cursor) : _cursor(cursor) { } + value_type operator*() { return value_type(_cursor); } + self& operator++() { _cursor->seek_next(); return *this; } + self operator++(int) + { cursor_ptr t(new cursor(*_cursor)); ++(*this); return in_edge_iterator(t); } + bool operator==(const self& x) { return _cursor == x._cursor; } + bool operator!=(const self& x) { return _cursor != x._cursor; } + cursor_ptr _cursor; }; struct vertex_index_property_map { typedef vertex_id value_type; typedef value_type reference; - typedef vertex_descriptor key_type; + typedef vertex_id key_type; typedef boost::readable_property_map_tag category; vertex_index_property_map(const graph& g) : _g(g) { } const graph& _g; + + friend inline reference + get(const vertex_index_property_map&, key_type key) + { return key; } }; struct edge_weight_property_map { typedef weight_t value_type; typedef value_type reference; - typedef edge_descriptor key_type; + typedef edge_info key_type; typedef boost::readable_property_map_tag category; edge_weight_property_map(const graph& g) : _g(g) { } const graph& _g; }; - + struct edge_index_property_map { - typedef edge_key::ref_type value_type; - typedef const edge_key::ref_type& reference; - typedef edge_descriptor key_type; + typedef cursor_ptr value_type; + typedef cursor_ptr reference; + typedef edge_info key_type; typedef boost::readable_property_map_tag category; edge_index_property_map(const graph& g) : _g(g) { } const graph& _g; @@ -196,17 +203,17 @@ namespace boost template<> struct graph_traits { - typedef oqgraph3::vertex_descriptor vertex_descriptor; - typedef oqgraph3::edge_descriptor edge_descriptor; + typedef oqgraph3::vertex_id vertex_descriptor; + typedef oqgraph3::edge_info edge_descriptor; typedef boost::adjacency_iterator_generator< oqgraph3::graph, - oqgraph3::vertex_descriptor, + oqgraph3::vertex_id, oqgraph3::out_edge_iterator>::type adjacency_iterator; typedef oqgraph3::out_edge_iterator out_edge_iterator; typedef oqgraph3::in_edge_iterator in_edge_iterator; typedef oqgraph3::vertex_iterator vertex_iterator; typedef oqgraph3::edge_iterator edge_iterator; - + typedef boost::directed_tag directed_category; typedef boost::allow_parallel_edge_tag edge_parallel_category; typedef oqgraph3::traversal_category traversal_category; @@ -214,16 +221,16 @@ namespace boost typedef oqgraph3::vertices_size_type vertices_size_type; typedef oqgraph3::edges_size_type edges_size_type; typedef oqgraph3::degree_size_type degree_size_type; - - static inline vertex_descriptor null_vertex() - { return oqgraph3::vertex_descriptor(); } + + static inline oqgraph3::vertex_id null_vertex() + { return oqgraph3::vertex_id(-1); } }; - + template<> struct graph_traits : public graph_traits { }; - + template <> struct graph_property_type { @@ -235,7 +242,7 @@ namespace boost { typedef no_property type; }; - + template <> struct edge_property_type { @@ -253,53 +260,110 @@ namespace boost { typedef no_vertex_bundle type; }; - + template <> struct edge_bundle_type { typedef no_edge_bundle type; }; + inline graph_traits::vertex_descriptor + source( + const graph_traits::edge_descriptor& e, + const oqgraph3::graph&) + { return e.origid(); } + + inline graph_traits::vertex_descriptor + target( + const graph_traits::edge_descriptor& e, + const oqgraph3::graph&) + { return e.destid(); } + inline std::pair< graph_traits::out_edge_iterator, graph_traits::out_edge_iterator> out_edges( graph_traits::vertex_descriptor v, - const oqgraph3::graph&) + const oqgraph3::graph& g) { - const oqgraph3::vertex_info::edge_list_type& - iter= v->out_edges(); + oqgraph3::cursor* + end= new oqgraph3::cursor(const_cast(&g)); + oqgraph3::cursor* + start= new oqgraph3::cursor(const_cast(&g)); + start->seek_to(v, boost::none); return std::make_pair( - graph_traits::out_edge_iterator(iter.begin(), v), - graph_traits::out_edge_iterator(iter.end(), v)); + graph_traits::out_edge_iterator(start), + graph_traits::out_edge_iterator(end)); } + inline graph_traits::degree_size_type + out_degree( + graph_traits::vertex_descriptor v, + const oqgraph3::graph& g) + { + std::size_t count = 0; + for (std::pair< + graph_traits::out_edge_iterator, + graph_traits::out_edge_iterator> i= out_edges(v, g); + i.first != i.second; ++i.first) + { + ++count; + } + return count; + } + + inline std::pair< graph_traits::in_edge_iterator, graph_traits::in_edge_iterator> in_edges( graph_traits::vertex_descriptor v, - const oqgraph3::graph&) + const oqgraph3::graph& g) { - const oqgraph3::vertex_info::edge_list_type& - iter= v->out_edges(); + oqgraph3::cursor* + end= new oqgraph3::cursor(const_cast(&g)); + oqgraph3::cursor* + start= new oqgraph3::cursor(const_cast(&g)); + start->seek_to(boost::none, v); return std::make_pair( - graph_traits::in_edge_iterator(iter.begin(), v), - graph_traits::in_edge_iterator(iter.end(), v)); + graph_traits::in_edge_iterator(start), + graph_traits::in_edge_iterator(end)); } + inline graph_traits::degree_size_type + in_degree( + graph_traits::vertex_descriptor v, + const oqgraph3::graph& g) + { + std::size_t count = 0; + for (std::pair< + graph_traits::in_edge_iterator, + graph_traits::in_edge_iterator> it= in_edges(v, g); + it.first != it.second; ++it.first) + { + ++count; + } + return count; + } + + // EdgeListGraph concepts inline std::pair< graph_traits::edge_iterator, graph_traits::edge_iterator> - edges(const oqgraph3::graph& _g) + edges(const oqgraph3::graph& g) { - oqgraph3::graph& g= const_cast(_g); + std::size_t end= std::size_t(-1); + std::size_t start= end; + + if (g.num_edges()) + start= 0; + return std::make_pair( graph_traits::edge_iterator( - oqgraph3::row_cursor(&g).first()), + const_cast(&g), start), graph_traits::edge_iterator( - oqgraph3::row_cursor(&g).end())); + const_cast(&g), end)); } inline std::pair< @@ -307,12 +371,13 @@ namespace boost graph_traits::vertex_iterator> vertices(const oqgraph3::graph& g) { - std::pair< - graph_traits::edge_iterator, - graph_traits::edge_iterator> epair= edges(g); + oqgraph3::cursor* + start= new oqgraph3::cursor(const_cast(&g)); + start->seek_to(boost::none, boost::none); return std::make_pair( - graph_traits::vertex_iterator(epair.first), - graph_traits::vertex_iterator(epair.second)); + graph_traits::vertex_iterator(start), + graph_traits::vertex_iterator( + new oqgraph3::cursor(const_cast(&g)))); } inline graph_traits::vertices_size_type @@ -335,7 +400,7 @@ namespace boost typedef void type; typedef oqgraph3::edge_weight_property_map const_type; }; - + template<> struct property_map { @@ -349,17 +414,17 @@ namespace boost typedef void type; typedef oqgraph3::edge_index_property_map const_type; }; - + inline property_map< oqgraph3::graph, edge_weight_t>::const_type::reference get( edge_weight_t, - const oqgraph3::graph& g, + const oqgraph3::graph& g, const property_map< oqgraph3::graph, edge_weight_t>::const_type::key_type& key) - { return oqgraph3::row_cursor(key, const_cast(&g))->_weight; } + { return key.weight(); } inline property_map< oqgraph3::graph, @@ -371,365 +436,48 @@ namespace boost inline property_map< oqgraph3::graph, edge_weight_t>::const_type::reference - get(property_map::const_type p, + get(const property_map::const_type& p, const property_map< oqgraph3::graph, edge_weight_t>::const_type::key_type& key) - { return oqgraph3::row_cursor( - key, const_cast(&p._g))->_weight; } + { return key.weight(); } inline property_map< oqgraph3::graph, edge_index_t>::const_type::reference get(edge_index_t, - const oqgraph3::graph&, + const oqgraph3::graph&, const property_map< - oqgraph3::graph, + oqgraph3::graph, edge_index_t>::const_type::key_type& key) - { return key->_ref; } + { return key._cursor; } inline property_map::const_type get(edge_index_t, const oqgraph3::graph& g) { return property_map::const_type(g); } inline property_map::const_type::reference - get(property_map::const_type, + get(const property_map::const_type&, const property_map::const_type::key_type& key) - { return key->_ref; } - + { return key._cursor; } + inline property_map::const_type::reference - get(vertex_index_t, const oqgraph3::graph&, + get(vertex_index_t, const oqgraph3::graph&, const property_map::const_type::key_type& key) - { return key->id; } + { return key; } inline property_map::const_type get(vertex_index_t, const oqgraph3::graph& g) { return property_map::const_type(g); } - inline property_map::const_type::reference - get(property_map::const_type, - const property_map::const_type::key_type& key) - { return key->id; } - - inline optional::vertex_descriptor> find_vertex(oqgraph3::vertex_id id, const oqgraph3::graph& g) { - graph_traits::vertex_descriptor tmp( - const_cast(g).vertex(id)); - if (tmp) - return tmp; - else - return none; + return id; } - } -#if 0 - - - class OQGraph - { - public: - - typedef OQGraph graph_type; - - // more commonly used graph types - typedef void stored_vertex; - typedef std::size_t vertices_size_type; - typedef std::size_t edges_size_type; - typedef std::size_t degree_size_type; - typedef oqgraph3::vertex_descriptor vertex_descriptor; - typedef oqgraph3::edge_descriptor edge_descriptor; - - // iterator types - - - typedef boost::adjacency_iterator_generator< - OQGraph, - vertex_descriptor, - out_edge_iterator>::type adjacency_iterator; - - // miscellaneous types - typedef boost::directed_graph_tag graph_tag; - typedef boost::directed_tag directed_category; - typedef boost::allow_parallel_edge_tag edge_parallel_category; - typedef OQGraphTraversalCategory traversal_category; - - typedef oqgraph3::vertex_id vertex_index_type; - typedef oqgraph3::edge_key::ref_type edge_index_type; - - typedef void edge_property_type; - typedef void vertex_property_type; - typedef void graph_property_type; - - // Graph concepts - static vertex_descriptor null_vertex() - { return vertex_descriptor(); } - - oqgraph3::graph_cache_ptr _cache; - - vertex_descriptor source(edge_descriptor e) const - { return _cache->vertex(oqgraph3::row_cursor(e)->first); } - vertex_descriptor target(edge_descriptor e) const - { return _cache->vertex(oqgraph3::row_cursor(e)->second); } - degree_size_type out_degree(vertex_descriptor v) const - { return v->out_edges().size(); } - std::pair - out_edges(vertex_descriptor v) const - { - const oqgraph3::vertex_info::edge_list_type& - iter= v->out_edges(); - return std::make_pair( - out_edge_iterator(iter.begin(), v), - out_edge_iterator(iter.end(), v)); - } - degree_size_type in_degree(vertex_descriptor v) const - { return v->in_edges().size(); } - std::pair - in_edges(vertex_descriptor v) const - { - const oqgraph3::vertex_info::edge_list_type& - iter= v->out_edges(); - return std::make_pair( - in_edge_iterator(iter.begin(), v), - in_edge_iterator(iter.end(), v)); - } - degree_size_type degree(vertex_descriptor v) const - { return v->degree(); } - vertex_descriptor vertex() const - { return null_vertex(); } - std::pair edge( - vertex_descriptor u, vertex_descriptor v) const - { edge_descriptor result= _cache->edge(u, v); - return std::make_pair(result, bool(result)); } - edges_size_type num_edges() const - { return _cache->num_edges(); } - std::pair - edges() const - { - return std::make_pair( - edge_iterator(oqgraph3::row_cursor(_cache).first()), - edge_iterator(oqgraph3::row_cursor(_cache).end())); - } - }; - - - struct vertex_index_property_map - { - typedef oqgraph3::vertex_id value_type; - typedef value_type reference; - typedef OQGraph::vertex_descriptor key_type; - typedef boost::readable_property_map_tag category; - }; - - struct edge_weight_property_map - { - typedef oqgraph3::weight_t value_type; - typedef value_type reference; - typedef OQGraph::edge_descriptor key_type; - typedef boost::readable_property_map_tag category; - }; - - struct edge_index_property_map - { - typedef oqgraph3::edge_key::ref_type value_type; - typedef const oqgraph3::edge_key::ref_type& reference; - typedef OQGraph::edge_descriptor key_type; - typedef boost::readable_property_map_tag category; - }; -} - -namespace boost -{ - template<> - struct property_map - { - typedef void type; - typedef open_query::edge_weight_property_map const_type; - }; - - template<> - struct property_map - { - typedef void type; - typedef open_query::vertex_index_property_map const_type; - }; - - template<> - struct property_map - { - typedef void type; - typedef open_query::edge_index_property_map const_type; - }; - - property_map< - open_query::OQGraph, - edge_weight_t>::const_type::reference - get( - edge_weight_t, - const open_query::OQGraph&, - const property_map< - open_query::OQGraph, - edge_weight_t>::const_type::key_type& key) - { return oqgraph3::row_cursor(key)->_weight; } - - property_map< - open_query::OQGraph, - edge_weight_t>::const_type - get(edge_weight_t, - const open_query::OQGraph&) - { return property_map::const_type(); } - - property_map< - open_query::OQGraph, - edge_weight_t>::const_type::reference - get(property_map::const_type, - const property_map< - open_query::OQGraph, - edge_weight_t>::const_type::key_type& key) - { return oqgraph3::row_cursor(key)->_weight; } - - property_map< - open_query::OQGraph, - edge_index_t>::const_type::reference - get(edge_index_t, - const open_query::OQGraph&, - const property_map< - open_query::OQGraph, - edge_index_t>::const_type::key_type& key) - { return key->_ref; } - - property_map::const_type - get(edge_index_t, const open_query::OQGraph&) - { return property_map::const_type(); } - - property_map::const_type::reference - get(property_map::const_type, - const property_map::const_type::key_type& key) - { return key->_ref; } - - property_map::const_type::reference - get(vertex_index_t, const open_query::OQGraph&, - const property_map::const_type::key_type& key) - { return key->id; } - - property_map::const_type - get(vertex_index_t, const open_query::OQGraph&) - { return property_map::const_type(); } - - property_map::const_type::reference - get(property_map::const_type, - const property_map::const_type::key_type& key) - { return key->id; } - - - optional - find_vertex(oqgraph3::vertex_id id, const open_query::OQGraph& g) - { open_query::OQGraph::vertex_descriptor tmp(g._cache->vertex(id)); - if (tmp) - return tmp; - else - return none; - } - - - - - // IncidenceGraph concepts - inline open_query::OQGraph::vertex_descriptor - source( - open_query::OQGraph::edge_descriptor e, - open_query::OQGraph const& g) - { return g.source(e); } - - inline open_query::OQGraph::vertex_descriptor - target( - open_query::OQGraph::edge_descriptor e, - open_query::OQGraph const& g) - { return g.target(e); } - - inline open_query::OQGraph::degree_size_type - out_degree( - open_query::OQGraph::vertex_descriptor v, - open_query::OQGraph const& g) - { return g.out_degree(v); } - - inline std::pair< - open_query::OQGraph::out_edge_iterator, - open_query::OQGraph::out_edge_iterator - > - out_edges( - open_query::OQGraph::vertex_descriptor v, - open_query::OQGraph const& g) - { return g.out_edges(v); } - - // BidirectionalGraph concepts - inline open_query::OQGraph::degree_size_type - in_degree( - open_query::OQGraph::vertex_descriptor v, - open_query::OQGraph const& g) - { return g.in_degree(v); } - - inline std::pair< - open_query::OQGraph::in_edge_iterator, - open_query::OQGraph::in_edge_iterator - > - in_edges( - open_query::OQGraph::vertex_descriptor v, - open_query::OQGraph const& g) - { return g.in_edges(v); } - - - inline open_query::OQGraph::degree_size_type - degree( - open_query::OQGraph::vertex_descriptor v, - open_query::OQGraph const& g) - { return g.degree(v); } - - // AdjacencyGraph concepts - //inline std::pair< - // open_query::OQGraph::adjacency_iterator, - // open_query::OQGraph::adjacency_iterator - // > - //adjacent_vertices( - // open_query::OQGraph::vertex_descriptor v, - // open_query::OQGraph const& g) - //{ return g.adjacent_vertices(v, g.impl()); } - - open_query::OQGraph::vertex_descriptor - vertex( - open_query::OQGraph::vertices_size_type n, - open_query::OQGraph const& g) - { return g.vertex(); } - - std::pair - edge( - open_query::OQGraph::vertex_descriptor u, - open_query::OQGraph::vertex_descriptor v, - open_query::OQGraph const& g) - { return g.edge(u, v); } - - - // Vertex index management - inline open_query::OQGraph::vertex_index_type - get_vertex_index( - open_query::OQGraph::vertex_descriptor v, - open_query::OQGraph const& g) - { return get(boost::vertex_index, g, v); } - - // Edge index management - inline const open_query::OQGraph::edge_index_type& - get_edge_index( - open_query::OQGraph::edge_descriptor v, - open_query::OQGraph const& g) - { return get(boost::edge_index, g, v); } -} - -#endif diff --git a/storage/oqgraph/oqgraph_thunk.cc b/storage/oqgraph/oqgraph_thunk.cc index d815e674b08..7739d26b296 100644 --- a/storage/oqgraph/oqgraph_thunk.cc +++ b/storage/oqgraph/oqgraph_thunk.cc @@ -31,74 +31,495 @@ #define MYSQL_SERVER #include "mysql_priv.h" -oqgraph3::vertex_info::~vertex_info() +static int debugid = 0; + +oqgraph3::vertex_id oqgraph3::edge_info::origid() const +{ return _cursor->get_origid(); } + +oqgraph3::vertex_id oqgraph3::edge_info::destid() const +{ return _cursor->get_destid(); } + +oqgraph3::weight_t oqgraph3::edge_info::weight() const +{ return _cursor->get_weight(); } + +bool oqgraph3::cursor_ptr::operator==(const cursor_ptr& x) const +{ + if (get() == x.get()) + return true; + return (*this)->record_position() == x->_position; +} + +bool oqgraph3::cursor_ptr::operator!=(const cursor_ptr& x) const +{ + if (get() == x.get()) + return false; + return (*this)->record_position() != x->_position; +} + +oqgraph3::cursor::cursor(const graph_ptr& graph) + : _ref_count(0) + , _graph(graph) + , _index(-1) + , _parts(0) + , _key() + , _position() + , _debugid(++debugid) { } -void oqgraph3::vertex_info::release() +oqgraph3::cursor::cursor(const cursor& src) + : _ref_count(0) + , _graph(src._graph) + , _index(src._index) + , _parts(src._parts) + , _key(src._key) + , _position(src.record_position()) + , _debugid(++debugid) +{ } + +oqgraph3::cursor::~cursor() { - if (!--(_ref_count)) + if (this == _graph->_cursor) { - oqgraph3::graph& cache= *_cache; - oqgraph3::graph::vertex_cache_type::const_iterator it; - - if (!_on_gc) - { - cache._gc_vertices.push(this); - _on_gc= true; - } - - while (!cache._gc_running && cache._gc_vertices.size() > 64) - { - cache._gc_running= true; - if (cache._gc_vertices.front()->_ref_count || - (it= cache._cache_vertices.find(*cache._gc_vertices.front())) - == cache._cache_vertices.end()) - { - cache._gc_vertices.front()->_on_gc= false; - } - else - { - cache._cache_vertices.quick_erase(it); - } - cache._gc_vertices.pop(); - cache._gc_running= false; - } + if (_graph->_cursor->_index >= 0) + _graph->_table->file->ha_index_end(); + else + _graph->_table->file->ha_rnd_end(); + _graph->_cursor= 0; + _graph->_stale= false; } } -oqgraph3::edge_key::~edge_key() -{ } - -void oqgraph3::edge_key::release() const +const std::string& oqgraph3::cursor::record_position() const { - if (!--(_ref_count)) + if (_graph->_stale && _graph->_cursor) { - oqgraph3::graph& cache= *_cache; - oqgraph3::graph::edge_cache_type::const_iterator it; + TABLE& table= *_graph->_table; + table.file->position(table.record[0]); + _graph->_cursor->_position.assign( + (const char*) table.file->ref, table.file->ref_length); - if (!_on_gc) + if (_graph->_cursor->_index >= 0) { - cache._gc_edges.push(const_cast(this)); - _on_gc= true; + key_copy((uchar*) _graph->_cursor->_key.data(), table.record[0], + table.s->key_info + _index, table.s->key_info[_index].key_length, true); } - while (!cache._gc_running && cache._gc_edges.size() > 512) + _graph->_stale= false; + } + return _position; +} + +void oqgraph3::cursor::clear_position() +{ + _position.clear(); + if (this == _graph->_cursor) + { + _graph->_cursor= 0; + _graph->_stale= false; + } +} + +void oqgraph3::cursor::save_position() +{ + record_position(); + + if (this == _graph->_cursor) + { + TABLE& table= *_graph->_table; + + if (_graph->_cursor->_index >= 0) + table.file->ha_index_end(); + else + table.file->ha_rnd_end(); + _graph->_cursor= 0; + _graph->_stale= false; + } +} + +int oqgraph3::cursor::restore_position() +{ + TABLE& table= *_graph->_table; + + if (!_position.size()) + return ENOENT; + + if (this == _graph->_cursor) + return 0; + + if (_graph->_cursor) + _graph->_cursor->save_position(); + + if (_origid || _destid) + { + if (int rc= table.file->ha_index_init(_index, 1)) + return rc; + + restore_record(&table, s->default_values); + + if (_origid) { - cache._gc_running= true; - if (cache._gc_edges.front()->_ref_count || - (it= cache._cache_edges.find(*cache._gc_edges.front())) - == cache._cache_edges.end()) + bitmap_set_bit(table.write_set, _graph->_source->field_index); + _graph->_source->store(*_origid, 1); + bitmap_clear_bit(table.write_set, _graph->_source->field_index); + } + + if (_destid) + { + bitmap_set_bit(table.write_set, _graph->_target->field_index); + _graph->_target->store(*_destid, 1); + bitmap_clear_bit(table.write_set, _graph->_target->field_index); + } + + if (int rc= table.file->ha_index_init(_index, 1)) + return rc; + + if (int rc= table.file->ha_index_read_map( + table.record[0], (const uchar*) _key.data(), + (key_part_map)(1 << _parts) - 1, + table.s->key_info[_index].key_parts == _parts ? + HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT)) + { + table.file->ha_index_end(); + return rc; + } + + update_virtual_fields(table.in_use, &table); + table.file->position(table.record[0]); + + while (memcmp(table.file->ref, _position.data(), table.file->ref_length)) + { + if (int rc= table.file->ha_index_next(table.record[0])) { - cache._gc_edges.front()->_on_gc= false; + table.file->ha_index_end(); + return rc; } - else + update_virtual_fields(table.in_use, &table); + + if ((_origid && vertex_id(_graph->_source->val_int()) != *_origid) || + (_destid && vertex_id(_graph->_target->val_int()) != *_destid)) { - cache._cache_edges.quick_erase(it); + table.file->ha_index_end(); + return ENOENT; } - cache._gc_edges.pop(); - cache._gc_running= false; + table.file->position(table.record[0]); + } + update_virtual_fields(table.in_use, &table); + + } + else + { + if (int rc= table.file->ha_rnd_init(1)) + return rc; + + if (int rc= table.file->ha_rnd_pos( + table.record[0], (uchar*) _position.data())) + { + table.file->ha_rnd_end(); + return rc; + } + update_virtual_fields(table.in_use, &table); + } + + _graph->_cursor= this; + _graph->_stale= false; + + return 0; +} + +oqgraph3::vertex_id oqgraph3::cursor::get_origid() +{ + if (_origid) + return *_origid; + + if (this != _graph->_cursor) + { + if (restore_position()) + return -1; + } + return static_cast(_graph->_source->val_int()); +} + +oqgraph3::vertex_id oqgraph3::cursor::get_destid() +{ + if (_destid) + return *_destid; + + if (this != _graph->_cursor) + { + if (restore_position()) + return -1; + } + return static_cast(_graph->_target->val_int()); +} + + +oqgraph3::weight_t oqgraph3::cursor::get_weight() +{ + if (!_graph->_weight) + return 1.0; + + if (this != _graph->_cursor) + { + if (restore_position()) + return -1; + } + return static_cast(_graph->_weight->val_int()); +} + +int oqgraph3::cursor::seek_next() +{ + if (this != _graph->_cursor) + { + if (int rc= restore_position()) + return rc; + } + + TABLE& table= *_graph->_table; + + if (_index < 0) + { + if (int rc= table.file->ha_rnd_next(table.record[0])) + { + table.file->ha_rnd_end(); + return clear_position(rc); + } + return 0; + } + + if (int rc= table.file->ha_index_next(table.record[0])) + { + table.file->ha_index_end(); + return clear_position(rc); + } + + update_virtual_fields(table.in_use, &table); + _graph->_stale= true; + + if ((_origid && vertex_id(_graph->_source->val_int()) != *_origid) || + (_destid && vertex_id(_graph->_target->val_int()) != *_destid)) + { + table.file->ha_index_end(); + return clear_position(ENOENT); + } + + return 0; +} + +int oqgraph3::cursor::seek_prev() +{ + if (this != _graph->_cursor) + { + if (int rc= restore_position()) + return rc; + } + + TABLE& table= *_graph->_table; + + if (_index < 0) + { + return -1; // not supported + } + + if (int rc= table.file->ha_index_prev(table.record[0])) + { + table.file->ha_index_end(); + return clear_position(rc); + } + + update_virtual_fields(table.in_use, &table); + _graph->_stale= true; + + if ((_origid && vertex_id(_graph->_source->val_int()) != *_origid) || + (_destid && vertex_id(_graph->_target->val_int()) != *_destid)) + { + table.file->ha_index_end(); + return clear_position(ENOENT); + } + + return 0; +} + + +int oqgraph3::cursor::seek_to( + boost::optional origid, + boost::optional destid) +{ + if (_graph->_cursor && this != _graph->_cursor) + _graph->_cursor->save_position(); + + TABLE& table= *_graph->_table; + _index= -1; + _origid= origid; + _destid= destid; + + if (origid || destid) + { + Field *source= _graph->_source; + Field *target= _graph->_target; + + uint source_fieldpos= _graph->_source->offset(table.record[0]); + uint target_fieldpos= _graph->_target->offset(table.record[0]); + + if (!destid) + { + int i= 0; + for( ::KEY *key_info= table.s->key_info, + *key_end= key_info + table.s->keys; + key_info < key_end; ++key_info, ++i) + { + if (key_info->key_part[0].offset != source_fieldpos) + continue; + + if (table.file->ha_index_init(i, 1)) + continue; + + restore_record(&table, s->default_values); + + bitmap_set_bit(table.write_set, source->field_index); + source->store(*_origid, 1); + bitmap_clear_bit(table.write_set, source->field_index); + + uchar* buff= (uchar*) my_alloca(source->pack_length()); + source->get_key_image(buff, source->pack_length(), Field::itRAW); + _key.clear(); + _key.append((char*) buff, source->pack_length()); + _key.resize(key_info->key_length, '\0'); + my_afree(buff); + + _parts= 1; + _index= i; + break; + } + } + else if (!origid) + { + int i= 0; + for( ::KEY *key_info= table.s->key_info, + *key_end= key_info + table.s->keys; + key_info < key_end; ++key_info, ++i) + { + if (key_info->key_part[0].offset != target_fieldpos) + continue; + + if (table.file->ha_index_init(i, 1)) + continue; + + restore_record(&table, s->default_values); + + bitmap_set_bit(table.write_set, target->field_index); + target->store(*_destid, 1); + bitmap_clear_bit(table.write_set, target->field_index); + + uchar* buff= (uchar*) my_alloca(target->pack_length()); + target->get_key_image(buff, target->pack_length(), Field::itRAW); + _key.clear(); + _key.append((char*) buff, target->pack_length()); + _key.resize(key_info->key_length, '\0'); + my_afree(buff); + + _parts= 1; + _index= i; + break; + } + } + else + { + int i= 0; + for( ::KEY *key_info= table.s->key_info, + *key_end= key_info + table.s->keys; + key_info < key_end; ++key_info, ++i) + { + if (key_info->key_parts < 2) + continue; + if (!((key_info->key_part[0].offset == target_fieldpos && + key_info->key_part[1].offset == source_fieldpos) || + (key_info->key_part[1].offset == target_fieldpos && + key_info->key_part[0].offset == source_fieldpos))) + continue; + + if (table.file->ha_index_init(i, 1)) + continue; + + restore_record(&table, s->default_values); + + bitmap_set_bit(table.write_set, source->field_index); + source->store(*_origid, 1); + bitmap_clear_bit(table.write_set, source->field_index); + + bitmap_set_bit(table.write_set, target->field_index); + target->store(*_destid, 1); + bitmap_clear_bit(table.write_set, target->field_index); + + Field* first= + key_info->key_part[0].offset == source_fieldpos ? + source : target; + Field* second= + key_info->key_part[0].offset == target_fieldpos ? + target : source; + + uchar* buff= (uchar*) my_alloca( + source->pack_length() + target->pack_length()); + first->get_key_image(buff, first->pack_length(), Field::itRAW); + second->get_key_image(buff + first->pack_length(), second->pack_length(), Field::itRAW); + _key.clear(); + _key.append((char*) buff, source->pack_length() + target->pack_length()); + _key.resize(key_info->key_length, '\0'); + my_afree(buff); + + _parts= 2; + _index= i; + break; + } + } + if (_index < 0) + { + // no suitable index found + return clear_position(ENXIO); + } + + if (int rc= table.file->ha_index_read_map( + table.record[0], (uchar*) _key.data(), + (key_part_map) ((1U << _parts) - 1), + table.s->key_info[_index].key_parts == _parts ? + HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT)) + { + table.file->ha_index_end(); + return clear_position(rc); + } + + update_virtual_fields(table.in_use, &table); + + if ((_origid && vertex_id(_graph->_source->val_int()) != *_origid) || + (_destid && vertex_id(_graph->_target->val_int()) != *_destid)) + { + table.file->ha_index_end(); + return clear_position(ENOENT); } } + else + { + if (int rc= table.file->ha_rnd_init(true)) + return clear_position(rc); + if (int rc= table.file->ha_rnd_next(table.record[0])) + { + table.file->ha_rnd_end(); + return clear_position(rc); + } + } + + _graph->_cursor= this; + _graph->_stale= true; + return 0; +} + +bool oqgraph3::cursor::operator==(const cursor& x) const +{ + return record_position() == x._position; +} + +bool oqgraph3::cursor::operator!=(const cursor& x) const +{ + return record_position() != x._position; } oqgraph3::graph::graph( @@ -106,8 +527,9 @@ oqgraph3::graph::graph( ::Field* source, ::Field* target, ::Field* weight) - : _gc_running(false) - , _ref_count(0) + : _ref_count(0) + , _cursor(0) + , _stale(false) , _table(table) , _source(source) , _target(target) @@ -124,889 +546,8 @@ oqgraph3::graph::graph( oqgraph3::graph::~graph() { } -oqgraph3::row_cursor& oqgraph3::row_cursor::operator++() -{ - printf("%s:%d\n", __func__, __LINE__); - if (!_current) - return *this; - - graph::edge_cache_type::iterator - current= _cache->_cache_edges.find(*_current); - - if (current->second._next) - { - graph::edge_cache_type::iterator next= - _cache->_cache_edges.find(edge_key(*current->second._next)); - if (_cache->_cache_edges.end() != next) - { - _current.reset(&next->first); - return *this; - } - } - - TABLE& table= *_cache->_table; - - table.file->ha_index_init(0, 1); - - printf("%s:%d - %s\n", __func__, __LINE__, "ha_index_read_map"); - if (table.file->ha_index_read_map( - table.record[0], - reinterpret_cast(current->first._ref.data()), - (key_part_map)((1 << table.key_info->key_parts) - 1), - HA_READ_AFTER_KEY)) - { - table.file->ha_index_end(); - _current.reset(0); - return *this; - } - - update_virtual_fields(table.in_use, &table); - - table.file->ha_index_end(); - - edge_key tmp(table.key_info->key_length, _cache); - - key_copy( - reinterpret_cast(const_cast(tmp._ref.data())), - table.record[0], - table.key_info, - tmp._ref.size(), true); - - graph::edge_cache_type::iterator - found= _cache->_cache_edges.find(tmp); - if (_cache->_cache_edges.end() != found) - { - // we already had a row, link them together - found->second._prev= ¤t->first._ref; - current->second._next= &found->first._ref; - _current.reset(&found->first); - return *this; - } - - _current.reset(&_cache->_cache_edges.insert( - std::make_pair( - tmp, - row_info( - _cache->_source->val_int(), - _cache->_target->val_int(), - _cache->_weight ? _cache->_weight->val_real() : 1.0, - &_current->_ref, - 0 - ) - )).first->first); - return *this; -} - -oqgraph3::row_cursor& oqgraph3::row_cursor::first() -{ - printf("%s:%d\n", __func__, __LINE__); - TABLE& table= *_cache->_table; - - table.file->ha_index_init(0, 1); - - printf("%s:%d - %s\n", __func__, __LINE__, "ha_index_first"); - if (!table.file->ha_index_first(table.record[0])) - { - update_virtual_fields(table.in_use, &table); - - edge_key tmp(table.key_info->key_length, _cache); - - key_copy( - reinterpret_cast(const_cast(tmp._ref.data())), - table.record[0], - table.key_info, - tmp._ref.size(), true); - - graph::edge_cache_type::iterator - found= _cache->_cache_edges.find(tmp); - if (found != _cache->_cache_edges.end()) - { - // we already had a row - _current.reset(&found->first); - } - else - { - _current.reset(&_cache->_cache_edges.insert( - std::make_pair( - tmp, - row_info( - _cache->_source->val_int(), - _cache->_target->val_int(), - _cache->_weight ? _cache->_weight->val_real() : 1.0, - 0, - 0 - ) - )).first->first); - } - } - - table.file->ha_index_end(); - - return *this; -} - -oqgraph3::row_cursor& oqgraph3::row_cursor::last() -{ - printf("%s:%d\n", __func__, __LINE__); - TABLE& table= *_cache->_table; - - table.file->ha_index_init(0, 1); - - printf("%s:%d - %s\n", __func__, __LINE__, "ha_index_last"); - if (!table.file->ha_index_last(table.record[0])) - { - update_virtual_fields(table.in_use, &table); - - edge_key tmp(table.key_info->key_length, _cache); - - key_copy( - reinterpret_cast(const_cast(tmp._ref.data())), - table.record[0], - table.key_info, - tmp._ref.size(), true); - - graph::edge_cache_type::iterator - found= _cache->_cache_edges.find(tmp); - if (found != _cache->_cache_edges.end()) - { - // we already had a row - _current.reset(&found->first); - } - else - { - _current.reset(&_cache->_cache_edges.insert( - std::make_pair( - tmp, - row_info( - _cache->_source->val_int(), - _cache->_target->val_int(), - _cache->_weight ? _cache->_weight->val_real() : 1.0, - 0, - 0 - ) - )).first->first); - } - } - - table.file->ha_index_end(); - - return *this; -} - -oqgraph3::row_cursor& oqgraph3::row_cursor::operator--() -{ - printf("%s:%d\n", __func__, __LINE__); - if (!_current) - return last(); - - graph::edge_cache_type::iterator - current= _cache->_cache_edges.find(*_current); - - if (current->second._prev) - { - graph::edge_cache_type::iterator prev= - _cache->_cache_edges.find(edge_key(*current->second._prev)); - if (_cache->_cache_edges.end() != prev) - { - _current.reset(&prev->first); - return *this; - } - } - - TABLE& table= *_cache->_table; - table.file->ha_index_init(0, 1); - - printf("%s:%d - %s\n", __func__, __LINE__, "ha_index_read_map"); - if (table.file->ha_index_read_map( - table.record[0], - reinterpret_cast(current->first._ref.data()), - (key_part_map)((1 << table.key_info->key_parts) - 1), - HA_READ_BEFORE_KEY)) - { - table.file->ha_index_end(); - _current.reset(); - return *this; - } - - update_virtual_fields(table.in_use, &table); - - table.file->ha_index_end(); - - edge_key tmp(table.key_info->key_length, _cache); - - key_copy( - reinterpret_cast(const_cast(tmp._ref.data())), - table.record[0], - table.key_info, - tmp._ref.size(), true); - - graph::edge_cache_type::iterator - found= _cache->_cache_edges.find(tmp); - if (_cache->_cache_edges.end() != found) - { - // we already had a row, link them together - found->second._next= ¤t->first._ref; - current->second._prev= &found->first._ref; - _current.reset(&found->first); - return *this; - } - - _current.reset(&_cache->_cache_edges.insert( - std::make_pair( - tmp, - row_info( - _cache->_source->val_int(), - _cache->_target->val_int(), - _cache->_weight ? _cache->_weight->val_real() : 1.0, - 0, - &_current->_ref - ) - )).first->first); - return *this; -} - -oqgraph3::row_cursor& oqgraph3::row_cursor::operator+=(difference_type delta) -{ - printf("%s:%d\n", __func__, __LINE__); - if (!delta || !_current) - return *this; - - if (delta < 0) - return *this -= (-delta); - - graph::edge_cache_type::iterator - current= _cache->_cache_edges.find(*_current); - - bool index_started= false; - TABLE& table= *_cache->_table; - - while (delta-- > 0) - { - if (_cache->_cache_edges.end() != current) - { - if (current->second._next) - { - graph::edge_cache_type::iterator - next= _cache->_cache_edges.find(edge_key(*current->second._next)); - - if (_cache->_cache_edges.end() != next) - { - current= next; - continue; - } - - if (!index_started) - { - table.file->ha_index_init(0, 1); - index_started= true; - } - - printf("%s:%d - %s\n", __func__, __LINE__, "ha_index_read_map"); - if (table.file->ha_index_read_map( - table.record[0], - reinterpret_cast(current->second._next->data()), - (key_part_map)((1 << table.key_info->key_parts) - 1), - HA_READ_KEY_OR_NEXT)) - { - table.file->ha_index_end(); - _current.reset(); - return *this; - } - } - else - { - if (!index_started) - { - table.file->ha_index_init(0, 1); - index_started= true; - } - - printf("%s:%d - %s\n", __func__, __LINE__, "ha_index_read_map"); - if (table.file->ha_index_read_map( - table.record[0], - reinterpret_cast(current->first._ref.data()), - (key_part_map)((1 << table.key_info->key_parts) - 1), - HA_READ_AFTER_KEY)) - { - table.file->ha_index_end(); - _current.reset(); - return *this; - } - } - - edge_key tmp(table.key_info->key_length); - - key_copy( - reinterpret_cast(const_cast(tmp._ref.data())), - table.record[0], - table.key_info, - tmp._ref.size(), true); - - graph::edge_cache_type::iterator - found= _cache->_cache_edges.find(tmp); - if (found != _cache->_cache_edges.end()) - { - // we already had a row, link them together - found->second._next= ¤t->first._ref; - current->second._prev= &found->first._ref; - } - current= found; - } - else - { - if (!index_started) - return *this; - - printf("%s:%d - %s\n", __func__, __LINE__, "ha_index_next"); - if (table.file->ha_index_next(table.record[0])) - { - table.file->ha_index_end(); - _current.reset(); - return *this; - } - - edge_key tmp(table.key_info->key_length); - - key_copy( - reinterpret_cast(const_cast(tmp._ref.data())), - table.record[0], - table.key_info, - tmp._ref.size(), true); - - current= _cache->_cache_edges.find(tmp); - } - } - - if (index_started) - { - table.file->ha_index_end(); - } - - return *this; -} - -oqgraph3::row_cursor& oqgraph3::row_cursor::operator-=(difference_type delta) -{ - printf("%s:%d\n", __func__, __LINE__); - if (!delta || !_current) - return *this; - - if (delta < 0) - return *this += (-delta); - - graph::edge_cache_type::iterator - current= _cache->_cache_edges.find(*_current); - - bool index_started= false; - TABLE& table= *_cache->_table; - - while (delta-- > 0) - { - if (_cache->_cache_edges.end() != current) - { - if (current->second._next) - { - graph::edge_cache_type::iterator next= - _cache->_cache_edges.find(edge_key(*current->second._next)); - - if (_cache->_cache_edges.end() != next) - { - current= next; - continue; - } - - if (!index_started) - { - table.file->ha_index_init(0, 1); - index_started= true; - } - - printf("%s:%d - %s\n", __func__, __LINE__, "ha_index_read_map"); - if (table.file->ha_index_read_map( - table.record[0], - reinterpret_cast(current->second._next->data()), - (key_part_map)((1 << table.key_info->key_parts) - 1), - HA_READ_KEY_OR_PREV)) - { - table.file->ha_index_end(); - return first(); - } - } - else - { - if (!index_started) - { - table.file->ha_index_init(0, 1); - index_started= true; - } - - printf("%s:%d - %s\n", __func__, __LINE__, "ha_index_read_map"); - if (table.file->ha_index_read_map( - table.record[0], - reinterpret_cast(current->first._ref.data()), - (key_part_map)((1 << table.key_info->key_parts) - 1), - HA_READ_BEFORE_KEY)) - { - table.file->ha_index_end(); - return first(); - } - } - - edge_key tmp(table.key_info->key_length); - - key_copy( - reinterpret_cast(const_cast(tmp._ref.data())), - table.record[0], - table.key_info, - tmp._ref.size(), true); - - graph::edge_cache_type::iterator - found= _cache->_cache_edges.find(tmp); - if (_cache->_cache_edges.end() != found) - { - // we already had a row, link them together - found->second._next= ¤t->first._ref; - current->second._prev= &found->first._ref; - } - current= found; - } - else - { - if (!index_started) - return first(); - - printf("%s:%d - %s\n", __func__, __LINE__, "ha_index_prev"); - if (table.file->ha_index_prev(table.record[0])) - { - table.file->ha_index_end(); - return first(); - } - - edge_key tmp(table.key_info->key_length); - - key_copy( - reinterpret_cast(const_cast(tmp._ref.data())), - table.record[0], - table.key_info, - tmp._ref.size(), true); - - current= _cache->_cache_edges.find(tmp); - } - } - - if (index_started) - { - table.file->ha_index_end(); - } - - return *this; -} - -oqgraph3::vertex_descriptor oqgraph3::graph::vertex(vertex_id id) -{ - printf("%s:%d\n", __func__, __LINE__); - vertex_cache_type::const_iterator - found= _cache_vertices.find(vertex_info(id)); - - if (_cache_vertices.end() != found) - return vertex_descriptor(const_cast(found.operator->())); - - return vertex_descriptor(const_cast( - _cache_vertices.insert(vertex_info(id, this)).first.operator->())); -} - -oqgraph3::edge_descriptor oqgraph3::graph::edge(const edge_key& key) -{ - printf("%s:%d\n", __func__, __LINE__); - edge_cache_type::const_iterator - found= _cache_edges.find(key); - - if (_cache_edges.end() != found) - return edge_descriptor(&found->first); - - TABLE& table= *_table; - - table.file->ha_index_init(0, 0); - - printf("%s:%d - %s\n", __func__, __LINE__, "ha_index_read_map"); - if (table.file->ha_index_read_map( - table.record[0], - reinterpret_cast(key._ref.data()), - (key_part_map)((1 << table.key_info->key_parts) - 1), - HA_READ_KEY_EXACT)) - { - table.file->ha_index_end(); - return edge_descriptor(); - } - - update_virtual_fields(table.in_use, &table); - - table.file->ha_index_end(); - - return edge_descriptor(&_cache_edges.insert( - std::make_pair( - edge_key(key, this), - row_info( - _source->val_int(), - _target->val_int(), - _weight ? _weight->val_real() : 1.0, - 0, - 0 - ) - )).first->first); -} - -oqgraph3::edge_descriptor oqgraph3::graph::edge( - const vertex_descriptor& source, - const vertex_descriptor& target) -{ - printf("%s:%d\n", __func__, __LINE__); - vertex_cache_type::const_iterator xsource= _cache_vertices.find(*source); - - if (_cache_vertices.end() != xsource && xsource->_out_edges) - { - const vertex_info::edge_list_type& edges= *xsource->_out_edges; - for (vertex_info::edge_list_type::const_iterator - it= edges.begin(), end= edges.end(); end != it; ++it) - { - edge_cache_type::const_iterator - found= _cache_edges.find(edge_key(*it)); - - if (_cache_edges.end() != found && - target->id == found->second.second) - { - return edge_descriptor(&found->first); - } - } - return edge_descriptor(); - } - - vertex_cache_type::const_iterator xtarget= _cache_vertices.find(*target); - - if (_cache_vertices.end() != xtarget && xtarget->_in_edges) - { - const vertex_info::edge_list_type& edges= *xtarget->_in_edges; - for (vertex_info::edge_list_type::const_iterator - it= edges.begin(), end= edges.end(); end != it; ++it) - { - edge_cache_type::const_iterator - found= _cache_edges.find(edge_key(*it)); - - if (_cache_edges.end() != found && - source->id == found->second.first) - { - return edge_descriptor(&found->first); - } - } - return edge_descriptor(); - } - - // If we have an index which has both key parts, we can use that - // to quickly retrieve the edge descriptor. - - TABLE& table= *_table; - - uint source_fieldpos= _source->offset(table.record[0]); - uint target_fieldpos= _target->offset(table.record[0]); - int i= 0; - for( ::KEY *key_info= table.s->key_info, - *key_end= key_info + table.s->keys; - key_info < key_end; ++key_info, ++i) - { - if (key_info->key_parts < 2) - continue; - if ((key_info->key_part[0].offset == source_fieldpos && - key_info->key_part[1].offset == target_fieldpos) || - (key_info->key_part[0].offset == target_fieldpos && - key_info->key_part[1].offset == source_fieldpos)) - { - // we can use this key - restore_record(&table, s->default_values); - - bitmap_set_bit(table.write_set, _source->field_index); - bitmap_set_bit(table.write_set, _target->field_index); - _source->store(source->id, 1); - _target->store(target->id, 1); - bitmap_clear_bit(table.write_set, _source->field_index); - bitmap_clear_bit(table.write_set, _target->field_index); - - uint key_len= key_info->key_length; - uchar* key_prefix= (uchar*) my_alloca(key_len); - - table.file->ha_index_init(i, 0); - - key_copy(key_prefix, table.record[0], key_info, key_len, 1); - - printf("%s:%d - %s\n", __func__, __LINE__, "ha_index_read_map"); - if (!table.file->ha_index_read_map( - table.record[0], key_prefix, (key_part_map)3, - key_info->key_parts == 2 ? - HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT) && - _source->val_int() == source->id && - _target->val_int() == target->id) - { - // We have found the edge, - - update_virtual_fields(table.in_use, &table); - - table.file->ha_index_end(); - my_afree(key_prefix); - - edge_key tmp(table.key_info->key_length, this); - - key_copy( - reinterpret_cast(const_cast(tmp._ref.data())), - table.record[0], - table.key_info, - tmp._ref.size(), true); - - graph::edge_cache_type::iterator - found= _cache_edges.find(tmp); - if (_cache_edges.end() != found) - { - // we already had the edge - return edge_descriptor(&found->first); - } - - return edge_descriptor(&_cache_edges.insert( - std::make_pair( - tmp, - row_info( - _source->val_int(), - _target->val_int(), - _weight ? _weight->val_real() : 1.0, - 0, - 0 - ) - )).first->first); - } - } - } - - const vertex_info::edge_list_type& edges= vertex(source->id)->out_edges(); - for (vertex_info::edge_list_type::const_iterator - it= edges.begin(), end= edges - .end(); end != it; ++it) - { - edge_cache_type::const_iterator - found= _cache_edges.find(edge_key(*it)); - - if (_cache_edges.end() != found && - target->id == found->second.second) - { - return edge_descriptor(&found->first); - } - } - - return edge_descriptor(); -} - oqgraph3::edges_size_type oqgraph3::graph::num_edges() const { return _table->file->stats.records; } -const oqgraph3::vertex_info::edge_list_type& -oqgraph3::vertex_info::out_edges() -{ - printf("%s:%d id=%lld\n", __func__, __LINE__, id); - if (!_out_edges) - { - _out_edges = edge_list_type(); - TABLE& table= *_cache->_table; - - uint source_fieldpos= _cache->_source->offset(table.record[0]); - int i= 0; - for( ::KEY *key_info= table.s->key_info, - *key_end= key_info + table.s->keys; - key_info < key_end; ++key_info, ++i) - { - if (key_info->key_part[0].offset == source_fieldpos) - { - // we can use this key - restore_record(&table, s->default_values); - - bitmap_set_bit(table.write_set, _cache->_source->field_index); - _cache->_source->store(id, 1); - bitmap_clear_bit(table.write_set, _cache->_source->field_index); - - uint key_len= key_info->key_length; - uchar* key= (uchar*) my_alloca(key_len); - - table.file->ha_index_init(i, 1); - - key_copy(key, table.record[0], key_info, key_len, true); - - printf("%s:%d - %s\n", __func__, __LINE__, "ha_index_read_map"); - if (!table.file->ha_index_read_map( - table.record[0], key, (key_part_map)1, - key_info->key_parts == 1 ? - HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT)) - { - // We have found an edge, - do - { - update_virtual_fields(table.in_use, &table); - - edge_key tmp(table.key_info->key_length, _cache); - - key_copy( - reinterpret_cast(const_cast(tmp._ref.data())), - table.record[0], - table.key_info, - tmp._ref.size(), true); - - graph::edge_cache_type::iterator - found= _cache->_cache_edges.find(tmp); - if (_cache->_cache_edges.end() == found) - { - found= _cache->_cache_edges.insert( - std::make_pair( - tmp, - row_info( - _cache->_source->val_int(), - _cache->_target->val_int(), - _cache->_weight ? _cache->_weight->val_real() : 1.0, - 0, - 0 - ) - )).first; - } - _out_edges->push_back(found->first._ref); - - printf("%s:%d - %s\n", __func__, __LINE__, "ha_index_next"); - if (table.file->ha_index_next(table.record[0])) - { - break; - } - } - while (_cache->_source->val_int() == id); - - table.file->ha_index_end(); - my_afree(key); - break; - } - table.file->ha_index_end(); - } - } - } - return *_out_edges; -} - -const oqgraph3::vertex_info::edge_list_type& -oqgraph3::vertex_info::in_edges() -{ - printf("%s:%d\n", __func__, __LINE__); - if (!_in_edges) - { - _in_edges = edge_list_type(); - TABLE& table= *_cache->_table; - - uint target_fieldpos= _cache->_target->offset(table.record[0]); - int i= 0; - for( ::KEY *key_info= table.s->key_info, - *key_end= key_info + table.s->keys; - key_info < key_end; ++key_info, ++i) - { - if (key_info->key_part[0].offset == target_fieldpos) - { - // we can use this key - restore_record(&table, s->default_values); - - bitmap_set_bit(table.write_set, _cache->_target->field_index); - _cache->_target->store(id, 1); - bitmap_clear_bit(table.write_set, _cache->_target->field_index); - - uint key_len= key_info->key_length; - uchar* key= (uchar*) my_alloca(key_len); - - table.file->ha_index_init(i, 1); - - key_copy(key, table.record[0], key_info, key_len, true); - - printf("%s:%d - %s\n", __func__, __LINE__, "ha_index_read_map"); - if (!table.file->ha_index_read_map( - table.record[0], key, (key_part_map)1, - key_info->key_parts == 1 ? - HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT)) - { - // We have found an edge, - do - { - update_virtual_fields(table.in_use, &table); - - edge_key tmp(table.key_info->key_length, _cache); - - key_copy( - reinterpret_cast(const_cast(tmp._ref.data())), - table.record[0], - table.key_info, - tmp._ref.size(), true); - - graph::edge_cache_type::iterator - found= _cache->_cache_edges.find(tmp); - if (_cache->_cache_edges.end() == found) - { - found= _cache->_cache_edges.insert( - std::make_pair( - tmp, - row_info( - _cache->_source->val_int(), - _cache->_target->val_int(), - _cache->_weight ? _cache->_weight->val_real() : 1.0, - 0, - 0 - ) - )).first; - } - _in_edges->push_back(found->first._ref); - - printf("%s:%d - %s\n", __func__, __LINE__, "ha_index_next"); - if (table.file->ha_index_next(table.record[0])) - break; - } - while (_cache->_target->val_int() == id); - - table.file->ha_index_end(); - my_afree(key); - break; - } - table.file->ha_index_end(); - } - } - } - return *_in_edges; -} - -std::size_t oqgraph3::vertex_info::degree() -{ - printf("%s:%d\n", __func__, __LINE__); - return out_edges().size() + in_edges().size(); -} - -oqgraph3::degree_size_type oqgraph3::vertex_descriptor::in_degree() const -{ - printf("%s:%d\n", __func__, __LINE__); - return (*this)->in_edges().size(); -} - -oqgraph3::degree_size_type oqgraph3::vertex_descriptor::out_degree() const -{ - printf("%s:%d\n", __func__, __LINE__); - return (*this)->out_edges().size(); -} - -oqgraph3::vertex_descriptor oqgraph3::edge_descriptor::source() const -{ - printf("%s:%d\n", __func__, __LINE__); - return (*this)->_cache->vertex( - oqgraph3::row_cursor(*this, (*this)->_cache)->first); -} - -oqgraph3::vertex_descriptor oqgraph3::edge_descriptor::target() const -{ - printf("%s:%d\n", __func__, __LINE__); - return (*this)->_cache->vertex( - oqgraph3::row_cursor(*this, (*this)->_cache)->second); -} - diff --git a/storage/oqgraph/oqgraph_thunk.h b/storage/oqgraph/oqgraph_thunk.h index 193144ded08..5965bc2dfb0 100644 --- a/storage/oqgraph/oqgraph_thunk.h +++ b/storage/oqgraph/oqgraph_thunk.h @@ -44,292 +44,114 @@ namespace oqgraph3 { typedef open_query::VertexID vertex_id; typedef open_query::EdgeWeight weight_t; - + typedef size_t vertices_size_type; typedef size_t edges_size_type; typedef size_t degree_size_type; struct graph; - struct vertex_info; + struct cursor; typedef boost::intrusive_ptr graph_ptr; - struct edge_key + struct cursor_ptr : public boost::intrusive_ptr + { + cursor_ptr() : boost::intrusive_ptr() { } + cursor_ptr(cursor* pos) : boost::intrusive_ptr(pos) { } + + operator const std::string&() const; + bool operator==(const cursor_ptr&) const; + bool operator!=(const cursor_ptr&) const; + }; + + struct edge_info + { + cursor_ptr _cursor; + + edge_info() : _cursor(0) { } + explicit edge_info(const cursor_ptr& pos) : _cursor(pos) { } + edge_info& operator=(const cursor_ptr& pos) { _cursor= pos; return *this; } + + vertex_id origid() const; + vertex_id destid() const; + weight_t weight() const; + + bool operator==(const edge_info&) const; + bool operator!=(const edge_info&) const; + }; + + struct cursor { - typedef std::string ref_type; - - ref_type _ref; mutable int _ref_count; + graph_ptr _graph; - graph_ptr _cache; - mutable bool _on_gc; - - operator const ref_type&() const { return _ref; } - - explicit edge_key( - std::size_t length, - const graph_ptr& cache= graph_ptr()) - : _ref(length, '\0') - , _ref_count(0) - , _cache(cache) - { } + int _index; + unsigned _parts; + std::string _key; + std::string _position; - template - explicit edge_key(const std::basic_string& ref) - : _ref(ref.begin(), ref.end()) - , _ref_count(0) - , _cache(0) - { } - - edge_key(const edge_key& src) - : _ref(src._ref) - , _ref_count(0) - , _cache(src._cache) - { } + int _debugid; - edge_key(const edge_key& src, const graph_ptr& cache) - : _ref(src._ref) - , _ref_count(0) - , _cache(cache) - { } - - ~edge_key(); - - void release() const; + boost::optional _origid; + boost::optional _destid; - friend void intrusive_ptr_add_ref(const edge_key* ptr) + cursor(const graph_ptr& graph); + cursor(const cursor& src); + + ~cursor(); + + operator bool() const + { return !_position.empty(); } + + operator edge_info() const + { return edge_info(const_cast(this)); } + + vertex_id get_origid(); + vertex_id get_destid(); + weight_t get_weight(); + + int seek_to( + boost::optional origid, + boost::optional destid); + + int seek_next(); + int seek_prev(); + + void save_position(); + int restore_position(); + const std::string& record_position() const; + void clear_position(); + int clear_position(int rc) { clear_position(); return rc; } + + bool operator==(const cursor& x) const; + bool operator!=(const cursor& x) const; + + friend void intrusive_ptr_add_ref(cursor* ptr) { ++ptr->_ref_count; } - friend void intrusive_ptr_release(const edge_key* ptr) - { ptr->release(); } - }; - - struct vertex_info - { - typedef vertex_id vertex_id_type; - typedef std::list edge_list_type; - - const vertex_id_type id; - mutable int _ref_count; - boost::optional _in_edges; - boost::optional _out_edges; - - graph_ptr _cache; - mutable bool _on_gc; - - explicit vertex_info( - vertex_id_type i, - const graph_ptr& cache= graph_ptr()) - : id(i) - , _ref_count(0) - , _cache(cache) - , _on_gc(false) - { } - ~vertex_info(); - - const edge_list_type& out_edges(); - const edge_list_type& in_edges(); - std::size_t degree(); - - void release(); - - friend void intrusive_ptr_add_ref(vertex_info* ptr) - { ++ptr->_ref_count; } - friend void intrusive_ptr_release(vertex_info* ptr) - { ptr->release(); } - }; - - struct vertex_descriptor - : public boost::intrusive_ptr - { - vertex_descriptor() - : boost::intrusive_ptr() - { } - - vertex_descriptor(vertex_info* v) - : boost::intrusive_ptr(v) - { } - - vertex_descriptor(const vertex_descriptor& v) - : boost::intrusive_ptr(v) - { } - - degree_size_type in_degree() const; - degree_size_type out_degree() const; - - friend degree_size_type in_degree(const vertex_descriptor& v, const graph&) - { return v.in_degree(); } - friend degree_size_type out_degree(const vertex_descriptor& v, const graph&) - { return v.out_degree(); } + friend void intrusive_ptr_release(cursor* ptr) + { if (!--(ptr->_ref_count)) delete ptr; } }; - struct edge_descriptor - : public boost::intrusive_ptr - { - edge_descriptor() - : boost::intrusive_ptr() - { } - - edge_descriptor(const edge_key* e) - : boost::intrusive_ptr(e) - { } - - edge_descriptor(const edge_descriptor& e) - : boost::intrusive_ptr(e) - { } - - vertex_descriptor source() const; - vertex_descriptor target() const; - - friend vertex_descriptor source(const edge_descriptor& e, const graph&) - { return e.source(); } - - friend vertex_descriptor target(const edge_descriptor& e, const graph&) - { return e.target(); } - }; - - struct row_info - : public std::pair - { - weight_t _weight; - - const edge_key::ref_type* _prev; - const edge_key::ref_type* _next; - - row_info( - first_type source, - second_type target, - weight_t weight, - const edge_key::ref_type* prev, - const edge_key::ref_type* next) - : std::pair(source, target) - , _weight(weight) - , _prev(prev) - , _next(next) - { printf("row_info(%lld,%lld,%f)\n", source, target, weight);} - }; - - namespace internal - { - template struct hash - : public std::unary_function - { - boost::hash ref_hasher; - std::size_t operator()(const Value& v) const - { - return ref_hasher(v); - } - }; - - template struct equal_to - : public std::binary_function - { - std::equal_to ref_equals; - bool operator()(const Value& x, const Value& y) const - { - return ref_equals(x, y); - } - }; - - template <> struct hash - : public std::unary_function - { - boost::hash ref_hasher; - std::size_t operator()(edge_key const& v) const - { - return ref_hasher(v._ref); - } - }; - - template <> struct hash - : public std::unary_function - { - boost::hash ref_hasher; - std::size_t operator()(const edge_key* const& v) const - { - return ref_hasher(v->_ref); - } - }; - - template <> struct hash - : public std::unary_function - { - boost::hash id_hasher; - std::size_t operator()(vertex_info const& v) const - { - return id_hasher(v.id); - } - }; - - template <> struct equal_to - : public std::binary_function - { - std::equal_to ref_equals; - bool operator()(const edge_key& x, const edge_key& y) const - { - return ref_equals(x._ref, y._ref); - } - }; - - template <> struct equal_to - : public std::binary_function - { - std::equal_to ref_equals; - bool operator()(const edge_key*& x, const edge_key*& y) const - { - return ref_equals(x->_ref, y->_ref); - } - }; - - - template <> struct equal_to - : public std::binary_function - { - std::equal_to id_equals; - bool operator()(const vertex_info& x, const vertex_info& y) const - { - return id_equals(x.id, y.id); - } - }; - } - struct graph { - typedef boost::unordered_map< - edge_key, - row_info, - internal::hash, - internal::equal_to > edge_cache_type; - typedef boost::unordered_set< - vertex_info, - internal::hash, - internal::equal_to > vertex_cache_type; - - bool _gc_running; mutable int _ref_count; + cursor* _cursor; + bool _stale; - edge_cache_type _cache_edges; - boost::queue _gc_edges; + cursor_ptr _rnd_cursor; + size_t _rnd_pos; - vertex_cache_type _cache_vertices; - boost::queue _gc_vertices; - ::TABLE* _table; ::Field* _source; ::Field* _target; ::Field* _weight; - + graph( ::TABLE* table, ::Field* source, ::Field* target, ::Field* weight= 0); ~graph(); - - vertex_descriptor vertex(vertex_id); - edge_descriptor edge(const edge_key&); - edge_descriptor edge( - const vertex_descriptor&, - const vertex_descriptor&); edges_size_type num_edges() const; @@ -343,73 +165,5 @@ namespace oqgraph3 { ptr->_ref_count--; } }; - struct row_cursor - { - typedef std::random_access_iterator_tag iterator_category; - typedef graph::edge_cache_type::value_type::second_type value_type; - typedef value_type* pointer; - typedef const value_type* const_pointer; - typedef value_type& reference; - typedef const value_type& const_reference; - typedef graph::edge_cache_type::size_type size_type; - typedef graph::edge_cache_type::difference_type difference_type; - - graph_ptr _cache; - edge_descriptor _current; - - explicit row_cursor(graph* cache) - : _cache(cache) - { } - - explicit row_cursor(const graph_ptr& cache) - : _cache(cache) - { } - - explicit row_cursor(const edge_descriptor& e, const graph_ptr& cache) - : _cache(cache) - , _current(e) - { } - - reference operator*() const - { return _cache->_cache_edges.find(*_current)->second; } - - pointer operator->() const - { return &_cache->_cache_edges.find(*_current)->second; } - - row_cursor& operator++(); - - row_cursor operator++(int) - { row_cursor tmp= *this; ++*this; return tmp; } - - row_cursor& operator--(); - - row_cursor operator--(int) - { row_cursor tmp= *this; --*this; return tmp; } - - row_cursor& operator+=(difference_type delta); - - row_cursor operator+(difference_type delta) const - { row_cursor tmp= *this; return tmp += delta; } - - row_cursor& operator-=(difference_type delta); - - row_cursor operator-(difference_type delta) const - { row_cursor tmp= *this; return tmp -= delta; } - - reference operator[](difference_type offset) const - { return *(*this + offset); } - - row_cursor& first(); - row_cursor& last(); - row_cursor& end() - { _current.reset(); return *this; } - - bool operator==(const row_cursor& x) const - { return _current == x._current; } - - bool operator!=(const row_cursor& x) const - { return _current != x._current; } - }; - }