Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
MariaDB
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
MariaDB
Commits
2037f387
Commit
2037f387
authored
Apr 12, 2011
by
Antony T Curtis
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit work for OQGraph v3
Todo: - Add #ifdefs for building in MySQL - Lots more testing
parent
64e43e1c
Changes
14
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
3044 additions
and
679 deletions
+3044
-679
storage/oqgraph/Makefile.am
storage/oqgraph/Makefile.am
+4
-4
storage/oqgraph/graphcore-graph.cc
storage/oqgraph/graphcore-graph.cc
+28
-0
storage/oqgraph/graphcore-graph.h
storage/oqgraph/graphcore-graph.h
+204
-17
storage/oqgraph/graphcore-types.h
storage/oqgraph/graphcore-types.h
+6
-0
storage/oqgraph/graphcore.cc
storage/oqgraph/graphcore.cc
+164
-170
storage/oqgraph/graphcore.h
storage/oqgraph/graphcore.h
+1
-1
storage/oqgraph/ha_oqgraph.cc
storage/oqgraph/ha_oqgraph.cc
+247
-480
storage/oqgraph/ha_oqgraph.h
storage/oqgraph/ha_oqgraph.h
+15
-7
storage/oqgraph/oqgraph_judy.cc
storage/oqgraph/oqgraph_judy.cc
+113
-0
storage/oqgraph/oqgraph_judy.h
storage/oqgraph/oqgraph_judy.h
+109
-0
storage/oqgraph/oqgraph_shim.cc
storage/oqgraph/oqgraph_shim.cc
+28
-0
storage/oqgraph/oqgraph_shim.h
storage/oqgraph/oqgraph_shim.h
+735
-0
storage/oqgraph/oqgraph_thunk.cc
storage/oqgraph/oqgraph_thunk.cc
+975
-0
storage/oqgraph/oqgraph_thunk.h
storage/oqgraph/oqgraph_thunk.h
+415
-0
No files found.
storage/oqgraph/Makefile.am
View file @
2037f387
...
...
@@ -54,13 +54,13 @@ EXTRA_DIST = ha_oqgraph.h ha_oqgraph.cc graphcore.cc \
# DTRACEFILES = .libs/libha_oqgraph_la-ha_oqgraph.o
ORIG_CXXFLAGS
=
@CXXFLAGS@
CXXFLAGS
=
CXXFLAGS
=
-DBOOST_ALL_NO_LIB
=
1
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
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,14 +73,14 @@ endif !BUILD_OQGRAPH_STANDALONE
EXTRA_LTLIBRARIES
=
ha_oqgraph.la
mysqlplugin_LTLIBRARIES
=
@plugin_oqgraph_shared_target@
ha_oqgraph_la_SOURCES
=
ha_oqgraph.cc
ha_oqgraph_la_SOURCES
=
ha_oqgraph.cc
oqgraph_judy.cc
ha_oqgraph_la_LIBADD
=
libgraphcore.la
# if HAVE_DTRACE
# ha_oqgraph_la_LIBADD += oqgraph_probes.o
# endif
ha_oqgraph_la_LDFLAGS
=
-shared
-module
-rpath
$(mysqlplugindir)
ha_oqgraph_la_LDFLAGS
=
-shared
-module
-rpath
$(mysqlplugindir)
-lJudy
-Wl
,-flat_namespace
ha_oqgraph_la_CFLAGS
=
$(ORIG_CFLAGS)
-DMYSQL_DYNAMIC_PLUGIN
ha_oqgraph_la_CXXFLAGS
=
$(ORIG_CXXFLAGS)
-DMYSQL_DYNAMIC_PLUGIN
...
...
storage/oqgraph/graphcore-graph.cc
0 → 100644
View file @
2037f387
/* Copyright (C) 2009-2011 Arjen G Lentz & Antony T Curtis for Open Query
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* ======================================================================
Open Query Graph Computation Engine, based on a concept by Arjen Lentz
Mk.III implementation by Antony Curtis & Arjen Lentz
For more information, documentation, support, enhancement engineering,
and non-GPL licensing, see http://openquery.com/graph
or contact graph@openquery.com
For packaged binaries, see http://ourdelta.org
======================================================================
*/
#include "graphcore-graph.h"
storage/oqgraph/graphcore-graph.h
View file @
2037f387
...
...
@@ -27,22 +27,209 @@
#ifndef oq_graphcore_graph_h_
#define oq_graphcore_graph_h_
typedef
adjacency_list
<
vecS
,
vecS
,
bidirectionalS
,
VertexInfo
,
EdgeInfo
>
Graph
;
#define GRAPH_WEIGHTMAP(G) get(&EdgeInfo::weight, G)
typedef
property_map
<
Graph
,
EdgeWeight
EdgeInfo
::*>::
type
weightmap_type
;
#define GRAPH_INDEXMAP(G) get(vertex_index, G)
typedef
property_map
<
Graph
,
vertex_index_t
>::
type
indexmap_type
;
#define GRAPH_IDMAP(G) get(&VertexInfo::id, G)
typedef
property_map
<
Graph
,
VertexID
VertexInfo
::*>::
type
idmap_type
;
#include "oqgraph_shim.h"
#include <boost/graph/two_bit_color_map.hpp>
namespace
boost
{
typedef
oqgraph3
::
graph
Graph
;
template
<
>
struct
hash
<
graph_traits
<
oqgraph3
::
graph
>::
vertex_descriptor
>
:
public
std
::
unary_function
<
graph_traits
<
oqgraph3
::
graph
>::
vertex_descriptor
,
std
::
size_t
>
{
std
::
size_t
operator
()(
const
graph_traits
<
oqgraph3
::
graph
>::
vertex_descriptor
&
v
)
const
{
return
boost
::
hash_value
(
v
->
id
);
}
};
template
<
typename
IndexMap
=
identity_property_map
>
struct
two_bit_judy_map
{
typedef
typename
property_traits
<
IndexMap
>::
key_type
key_type
;
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
<
IndexMap
>&
pm
,
typename
property_traits
<
IndexMap
>::
key_type
key
)
{
typename
property_traits
<
IndexMap
>::
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
<
IndexMap
>&
pm
,
typename
property_traits
<
IndexMap
>::
key_type
key
,
two_bit_color_type
value
)
{
typename
property_traits
<
IndexMap
>::
value_type
i
=
get
(
pm
.
index
,
key
);
pm
.
msb
.
set
(
i
,
value
&
2
);
pm
.
lsb
.
set
(
i
,
value
&
1
);
}
};
template
<
typename
IndexMap
>
inline
two_bit_judy_map
<
IndexMap
>
make_two_bit_judy_map
(
const
IndexMap
&
index
)
{
return
two_bit_judy_map
<
IndexMap
>
(
index
);
}
template
<
typename
Type
>
struct
default_lazy_initializer
{
template
<
typename
Key
>
Type
operator
()(
const
Key
&
)
const
{
return
Type
();
}
};
template
<
typename
Type
>
struct
copy_initializer
{
copy_initializer
(
const
Type
&
value
)
:
_
(
value
)
{
}
template
<
typename
Key
>
const
Type
&
operator
()(
const
Key
&
)
const
{
return
_
;
}
const
Type
&
_
;
};
template
<
typename
Type
>
copy_initializer
<
Type
>
make_copy_initializer
(
const
Type
&
value
)
{
return
copy_initializer
<
Type
>
(
value
);
}
template
<
typename
Type
>
struct
value_initializer
{
value_initializer
(
const
Type
&
value
)
:
_
(
value
)
{
}
template
<
typename
Key
>
const
Type
&
operator
()(
const
Key
&
)
const
{
return
_
;
}
const
Type
_
;
};
template
<
typename
Type
>
value_initializer
<
Type
>
make_value_initializer
(
const
Type
&
value
)
{
return
value_initializer
<
Type
>
(
value
);
}
template
<
typename
Key
>
struct
identity_initializer
{
const
Key
&
operator
()(
const
Key
&
_
)
const
{
return
_
;
}
};
template
<
class
Container
,
class
Generator
>
struct
lazy_property_map
{
typedef
lazy_property_map
<
Container
,
Generator
>
self
;
typedef
typename
Container
::
key_type
key_type
;
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
);
if
(
_m
.
end
()
==
found
)
{
found
=
_m
.
insert
(
std
::
make_pair
(
k
,
_g
(
k
))).
first
;
}
return
found
->
second
;
}
void
set
(
const
key_type
&
k
,
const
value_type
&
v
)
{
_m
[
k
]
=
v
;
}
friend
reference
get
(
const
self
&
s
,
const
key_type
&
k
)
{
return
s
[
k
];
}
friend
void
put
(
self
&
s
,
const
key_type
&
k
,
const
value_type
&
v
)
{
s
.
set
(
k
,
v
);
}
Container
&
_m
;
Generator
_g
;
};
template
<
class
Container
,
class
Generator
>
lazy_property_map
<
Container
,
Generator
>
make_lazy_property_map
(
Container
&
c
,
Generator
g
)
{
return
lazy_property_map
<
Container
,
Generator
>
(
c
,
g
);
}
#if 0
struct map_wra
struct property_traits< unordered_map_wrapper<K,T,H,P,A
template <class K, class T, class H, class P, class A>
struct property_traits< unordered_map<K,T,H,P,A> > {
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<K,T,H,P,A>& m,
const key_type& k)
{
return m[k];
}
friend void put(
unordered_map<K,T,H,P,A>& m,
const key_type& k,
const value_type& v)
{
m[k]= v;
}
};
//template <class K, class T, class H, class P, class A>
//property_traits< unordered_map<K,T,H,P,A> >::reference
//get(unordered_map<K,T,H,P,A>& m,
// const property_traits< unordered_map<K,T,H,P,A> >::key_type& k)
//{ return m[ k ]; }
//template <class K, class T, class H, class P, class A>
//void put(
// unordered_map<K,T,H,P,A>& m,
// const property_traits< unordered_map<K,T,H,P,A> >::key_type& k,
// const property_traits< unordered_map<K,T,H,P,A> >::value_type& v)
//{ m[ k ] = v; }
//template <class K, class T, class H, class P, class A>
//property_traits< unordered_map<K,T,H,P,A>::reference
//get(unordered_map<K,T,H,P,A>& m,
// const graph_traits<oqgraph3::graph>::vertex_descriptor& v)
//{ return m[ v->id ]; }
#endif
}
#endif
storage/oqgraph/graphcore-types.h
View file @
2037f387
...
...
@@ -26,6 +26,7 @@
#ifndef oq_graphcore_types_h_
#define oq_graphcore_types_h_
namespace
open_query
{
...
...
@@ -33,4 +34,9 @@ namespace open_query
typedef
double
EdgeWeight
;
}
class
Field
;
typedef
struct
st_table
TABLE
;
#endif
storage/oqgraph/graphcore.cc
View file @
2037f387
...
...
@@ -30,14 +30,13 @@
#include <boost/config.hpp>
#include "graphcore-graph.h"
#include <set>
#include <stack>
#include <boost/property_map/property_map.hpp>
#include <boost/graph/graph_concepts.hpp>
#include <boost/graph/graph_archetypes.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/breadth_first_search.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/graph/iteration_macros.hpp>
...
...
@@ -46,54 +45,16 @@
#include "graphcore.h"
#include <boost/unordered_map.hpp>
using
namespace
open_query
;
using
namespace
boost
;
static
const
row
empty_row
=
{
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
};
namespace
open_query
{
enum
vertex_id_t
{
vertex_id
};
struct
VertexInfo
{
inline
VertexInfo
()
{
}
inline
VertexInfo
(
VertexID
_id
)
:
id
(
_id
)
{
}
VertexID
id
;
};
struct
EdgeInfo
{
EdgeWeight
weight
;
};
}
namespace
boost
{
BOOST_INSTALL_PROPERTY
(
vertex
,
id
);
namespace
graph
{
template
<
>
struct
internal_vertex_name
<
VertexInfo
>
{
typedef
multi_index
::
member
<
VertexInfo
,
VertexID
,
&
VertexInfo
::
id
>
type
;
};
template
<
>
struct
internal_vertex_constructor
<
VertexInfo
>
{
typedef
vertex_from_name
<
VertexInfo
>
type
;
};
}
}
namespace
open_query
{
#include "graphcore-graph.h"
typedef
graph_traits
<
Graph
>::
vertex_descriptor
Vertex
;
typedef
graph_traits
<
Graph
>::
edge_descriptor
Edge
;
...
...
@@ -261,18 +222,15 @@ namespace open_query {
public:
Graph
g
;
weightmap_type
weightmap
;
idmap_type
idmap
;
indexmap_type
indexmap
;
optional
<
Vertex
>
find_vertex
(
VertexID
id
)
const
;
optional
<
Edge
>
find_edge
(
Vertex
,
Vertex
)
const
;
inline
oqgraph_share
()
throw
()
:
g
(),
weightmap
(
GRAPH_WEIGHTMAP
(
g
)),
idmap
(
GRAPH_IDMAP
(
g
)),
indexmap
(
GRAPH_INDEXMAP
(
g
))
inline
oqgraph_share
(
TABLE
*
table
,
Field
*
origid
,
Field
*
destid
,
Field
*
weight
)
throw
()
:
g
(
table
,
origid
,
destid
,
weight
)
{
}
inline
~
oqgraph_share
()
{
}
...
...
@@ -360,13 +318,13 @@ namespace open_query {
}
};
template
<
typename
P
,
typename
D
>
struct
GRAPHCORE_INTERNAL
oqgraph_visit_dist
:
public
base_visitor
<
oqgraph_visit_dist
>
:
public
base_visitor
<
oqgraph_visit_dist
<
P
,
D
>
>
{
typedef
on_finish_vertex
event_filter
;
oqgraph_visit_dist
(
std
::
vector
<
Vertex
>::
iterator
p
,
std
::
vector
<
EdgeWeight
>::
iterator
d
,
oqgraph_visit_dist
(
const
P
&
p
,
const
D
&
d
,
stack_cursor
*
cursor
)
:
seq
(
0
),
m_cursor
(
*
cursor
),
m_p
(
p
),
m_d
(
d
)
{
assert
(
cursor
);
}
...
...
@@ -374,22 +332,28 @@ namespace open_query {
template
<
class
T
,
class
Graph
>
void
operator
()(
T
u
,
Graph
&
g
)
{
m_cursor
.
results
.
push
(
reference
(
++
seq
,
u
,
m_d
[
GRAPH_INDEXMAP
(
g
)[
u
]
]));
m_cursor
.
results
.
push
(
reference
(
++
seq
,
u
,
m_d
[
u
]));
}
private:
int
seq
;
stack_cursor
&
m_cursor
;
std
::
vector
<
Vertex
>::
iterator
m_p
;
std
::
vector
<
EdgeWeight
>::
iterator
m_d
;
P
m_p
;
D
m_d
;
};
template
<
bool
record_weight
,
typename
goal_filter
>
template
<
typename
P
,
typename
D
>
oqgraph_visit_dist
<
P
,
D
>
make_oqgraph_visit_dist
(
const
P
&
p
,
const
D
&
d
,
stack_cursor
*
cursor
)
{
return
oqgraph_visit_dist
<
P
,
D
>
(
p
,
d
,
cursor
);
}
template
<
bool
record_weight
,
typename
goal_filter
,
typename
P
>
struct
GRAPHCORE_INTERNAL
oqgraph_goal
:
public
base_visitor
<
oqgraph_goal
<
record_weight
,
goal_filter
>
>
:
public
base_visitor
<
oqgraph_goal
<
record_weight
,
goal_filter
,
P
>
>
{
typedef
goal_filter
event_filter
;
oqgraph_goal
(
Vertex
goal
,
std
::
vector
<
Vertex
>::
iterator
p
,
oqgraph_goal
(
const
Vertex
&
goal
,
const
P
&
p
,
stack_cursor
*
cursor
)
:
m_goal
(
goal
),
m_cursor
(
*
cursor
),
m_p
(
p
)
{
assert
(
cursor
);
}
...
...
@@ -400,17 +364,16 @@ namespace open_query {
if
(
u
==
m_goal
)
{
int
seq
=
0
;
indexmap_type
indexmap
=
GRAPH_INDEXMAP
(
g
);
for
(
Vertex
q
,
v
=
u
;;
v
=
q
,
seq
++
)
if
((
q
=
m_p
[
indexmap
[
v
]
])
==
v
)
if
((
q
=
m_p
[
v
])
==
v
)
break
;
for
(
Vertex
v
=
u
;;
u
=
v
)
{
optional
<
Edge
>
edge
;
optional
<
EdgeWeight
>
weight
;
v
=
m_p
[
indexmap
[
u
]
];
v
=
m_p
[
u
];
if
(
record_weight
&&
u
!=
v
)
{
typename
graph_traits
<
Graph
>::
out_edge_iterator
ei
,
ei_end
;
...
...
@@ -419,7 +382,7 @@ namespace open_query {
if
(
target
(
*
ei
,
g
)
==
u
)
{
edge
=
*
ei
;
weight
=
GRAPH_WEIGHTMAP
(
g
)[
*
ei
]
;
weight
=
get
(
boost
::
edge_weight
,
g
,
*
ei
)
;
break
;
}
}
...
...
@@ -437,8 +400,14 @@ namespace open_query {
private:
Vertex
m_goal
;
stack_cursor
&
m_cursor
;
std
::
vector
<
Vertex
>::
iterator
m_p
;
P
m_p
;
};
template
<
bool
record_weight
,
typename
goal_filter
,
typename
P
>
oqgraph_goal
<
record_weight
,
goal_filter
,
P
>
make_oqgraph_goal
(
const
Vertex
&
goal
,
const
P
&
p
,
stack_cursor
*
cursor
)
{
return
oqgraph_goal
<
record_weight
,
goal_filter
,
P
>
(
goal
,
p
,
cursor
);
}
}
namespace
open_query
...
...
@@ -468,9 +437,14 @@ namespace open_query
return
new
(
std
::
nothrow
)
oqgraph
(
share
);
}
oqgraph_share
*
oqgraph
::
create
()
throw
()
oqgraph_share
*
oqgraph
::
create
(
TABLE
*
table
,
Field
*
origid
,
Field
*
destid
,
Field
*
weight
)
throw
()
{
return
new
(
std
::
nothrow
)
oqgraph_share
();
return
new
(
std
::
nothrow
)
oqgraph_share
(
table
,
origid
,
destid
,
weight
);
}
optional
<
Edge
>
...
...
@@ -480,14 +454,14 @@ namespace open_query
{
graph_traits
<
Graph
>::
out_edge_iterator
ei
,
ei_end
;
tie
(
ei
,
ei_end
)
=
out_edges
(
orig
,
g
);
if
((
ei
=
find_if
(
ei
,
ei_end
,
target_equals
(
dest
,
g
)))
!=
ei_end
)
if
((
ei
=
std
::
find_if
(
ei
,
ei_end
,
target_equals
(
dest
,
g
)))
!=
ei_end
)
return
*
ei
;
}
else
{
graph_traits
<
Graph
>::
in_edge_iterator
ei
,
ei_end
;
tie
(
ei
,
ei_end
)
=
in_edges
(
dest
,
g
);
if
((
ei
=
find_if
(
ei
,
ei_end
,
source_equals
(
orig
,
g
)))
!=
ei_end
)
if
((
ei
=
std
::
find_if
(
ei
,
ei_end
,
source_equals
(
orig
,
g
)))
!=
ei_end
)
return
*
ei
;
}
return
optional
<
Edge
>
();
...
...
@@ -496,9 +470,10 @@ namespace open_query
optional
<
Vertex
>
oqgraph_share
::
find_vertex
(
VertexID
id
)
const
{
return
boost
::
graph
::
find_vertex
(
id
,
g
);
return
::
boost
::
find_vertex
(
id
,
g
);
}
#if 0
int oqgraph::delete_all() throw()
{
share->g.clear();
...
...
@@ -598,8 +573,9 @@ namespace open_query
optional<Vertex> orig= source(*edge, share->g),
dest= target(*edge, share->g);
bool
orig_neq
=
orig_id
?
share
->
idmap
[
*
orig
]
!=
*
orig_id
:
0
;
bool
dest_neq
=
dest_id
?
share
->
idmap
[
*
dest
]
!=
*
dest_id
:
0
;
bool orig_neq= orig_id ? get(boost::vertex_index, share->g, *orig) != *orig_id : 0;
bool dest_neq= dest_id ? get(boost::vertex_index, share->g, *dest) != *dest_id : 0;
if (orig_neq || dest_neq)
{
optional<Edge> new_edge;
...
...
@@ -675,7 +651,6 @@ namespace open_query
return OK;
}
int oqgraph::delete_edge(VertexID orig_id, VertexID dest_id) throw()
{
optional<Vertex> orig, dest;
...
...
@@ -694,6 +669,7 @@ namespace open_query
remove_vertex(*dest, share->g);
return OK;
}
#endif
int
oqgraph
::
search
(
int
*
latch
,
VertexID
*
orig_id
,
VertexID
*
dest_id
)
throw
()
...
...
@@ -731,7 +707,8 @@ namespace open_query
{
Vertex
v
=
target
(
*
ei
,
share
->
g
);
static_cast
<
stack_cursor
*>
(
cursor
)
->
results
.
push
(
reference
(
++
seq
,
v
,
*
ei
,
share
->
weightmap
[
*
ei
]));
results
.
push
(
reference
(
++
seq
,
v
,
*
ei
,
get
(
boost
::
edge_weight
,
share
->
g
,
*
ei
)));
}
}
/* fall through */
...
...
@@ -745,7 +722,8 @@ namespace open_query
{
Vertex
v
=
source
(
*
ei
,
share
->
g
);
static_cast
<
stack_cursor
*>
(
cursor
)
->
results
.
push
(
reference
(
++
seq
,
v
,
*
ei
,
share
->
weightmap
[
*
ei
]));
results
.
push
(
reference
(
++
seq
,
v
,
*
ei
,
get
(
boost
::
edge_weight
,
share
->
g
,
*
ei
)));
}
}
break
;
...
...
@@ -757,27 +735,29 @@ namespace open_query
case
DIJKSTRAS
|
HAVE_ORIG
|
HAVE_DEST
:
if
((
cursor
=
new
(
std
::
nothrow
)
stack_cursor
(
share
))
&&
orig
&&
dest
)
{
std
::
vector
<
Vertex
>
p
(
num_vertices
(
share
->
g
));
std
::
vector
<
EdgeWeight
>
d
(
num_vertices
(
share
->
g
));
oqgraph_goal
<
true
,
on_finish_vertex
>
vis
(
*
dest
,
p
.
begin
(),
static_cast
<
stack_cursor
*>
(
cursor
));
p
[
share
->
indexmap
[
*
orig
]]
=
*
orig
;
boost
::
unordered_map
<
Vertex
,
Vertex
>
p
;
boost
::
unordered_map
<
Vertex
,
EdgeWeight
>
d
;
p
[
*
orig
]
=
*
orig
;
d
[
*
orig
]
=
EdgeWeight
();
try
{
dijkstra_shortest_paths
(
share
->
g
,
*
orig
,
weight_map
(
share
->
weightmap
).
distance_map
(
make_iterator_property_map
(
d
.
begin
(),
share
->
indexmap
)
).
predecessor_map
(
make_iterator_property_map
(
p
.
begin
(),
share
->
indexmap
)
).
visitor
(
make_dijkstra_visitor
(
vis
)
)
);
dijkstra_shortest_paths_no_init
(
share
->
g
,
*
orig
,
make_lazy_property_map
(
p
,
identity_initializer
<
Vertex
>
()),
make_lazy_property_map
(
d
,
value_initializer
<
EdgeWeight
>
(
(
std
::
numeric_limits
<
EdgeWeight
>::
max
)())),
get
(
edge_weight
,
share
->
g
),
get
(
vertex_index
,
share
->
g
),
std
::
less
<
EdgeWeight
>
(),
closed_plus
<
EdgeWeight
>
(),
EdgeWeight
(),
make_dijkstra_visitor
(
make_oqgraph_goal
<
true
,
on_finish_vertex
>
(
*
dest
,
boost
::
make_assoc_property_map
(
p
),
static_cast
<
stack_cursor
*>
(
cursor
)
)
),
make_two_bit_judy_map
(
get
(
vertex_index
,
share
->
g
)));
}
catch
(...)
{
/* printf("found\n"); */
}
...
...
@@ -787,23 +767,25 @@ namespace open_query
case
BREADTH_FIRST
|
HAVE_ORIG
|
HAVE_DEST
:
if
((
cursor
=
new
(
std
::
nothrow
)
stack_cursor
(
share
))
&&
orig
&&
dest
)
{
std
::
vector
<
Vertex
>
p
(
num_vertices
(
share
->
g
));
oqgraph_goal
<
false
,
on_discover_vertex
>
vis
(
*
dest
,
p
.
begin
(),
static_cast
<
stack_cursor
*>
(
cursor
));
p
[
share
->
indexmap
[
*
orig
]]
=
*
orig
;
boost
::
unordered_map
<
Vertex
,
Vertex
>
p
;
boost
::
queue
<
Vertex
>
Q
;
p
[
*
orig
]
=
*
orig
;
try
{
breadth_first_
search
(
share
->
g
,
*
orig
,
visitor
(
make_bfs_visitor
(
breadth_first_
visit
(
share
->
g
,
*
orig
,
Q
,
make_bfs_visitor
(
std
::
make_pair
(
record_predecessors
(
make_iterator_property_map
(
p
.
begin
(),
share
->
indexma
p
),
boost
::
make_assoc_property_map
(
p
),
on_tree_edge
()
),
vis
)
make_oqgraph_goal
<
false
,
on_discover_vertex
>
(
*
dest
,
boost
::
make_assoc_property_map
(
p
),
static_cast
<
stack_cursor
*>
(
cursor
)
)
)
)
);
)
,
make_two_bit_judy_map
(
get
(
vertex_index
,
share
->
g
))
);
}
catch
(...)
{
/* printf("found\n"); */
}
...
...
@@ -814,109 +796,121 @@ namespace open_query
case
BREADTH_FIRST
|
HAVE_ORIG
:
if
((
cursor
=
new
(
std
::
nothrow
)
stack_cursor
(
share
))
&&
(
orig
||
dest
))
{
std
::
vector
<
Vertex
>
p
(
num_vertices
(
share
->
g
))
;
std
::
vector
<
EdgeWeight
>
d
(
num_vertices
(
share
->
g
))
;
oqgraph_visit_dist
vis
(
p
.
begin
(),
d
.
begin
(),
static_cast
<
stack_cursor
*>
(
cursor
))
;
p
[
share
->
indexmap
[
*
orig
]]
=
*
orig
;
boost
::
unordered_map
<
Vertex
,
Vertex
>
p
;
boost
::
unordered_map
<
Vertex
,
EdgeWeight
>
d
;
boost
::
queue
<
Vertex
>
Q
;
p
[
*
orig
]
=
*
orig
;
d
[
*
orig
]
=
EdgeWeight
()
;
switch
(
ALGORITHM
&
op
)
{
case
DIJKSTRAS
:
dijkstra_shortest_paths
(
share
->
g
,
*
orig
,
weight_map
(
share
->
weightmap
).
distance_map
(
make_iterator_property_map
(
d
.
begin
(),
share
->
indexmap
)
).
predecessor_map
(
make_iterator_property_map
(
p
.
begin
(),
share
->
indexmap
)
).
visitor
(
make_dijkstra_visitor
(
vis
)
)
);
break
;
dijkstra_shortest_paths_no_init
(
share
->
g
,
*
orig
,
make_lazy_property_map
(
p
,
identity_initializer
<
Vertex
>
()),
make_lazy_property_map
(
d
,
value_initializer
<
EdgeWeight
>
(
(
std
::
numeric_limits
<
EdgeWeight
>::
max
)())),
get
(
edge_weight
,
share
->
g
),
get
(
vertex_index
,
share
->
g
),
std
::
less
<
EdgeWeight
>
(),
closed_plus
<
EdgeWeight
>
(),
EdgeWeight
(),
make_dijkstra_visitor
(
make_oqgraph_visit_dist
(
boost
::
make_assoc_property_map
(
p
),
d
,
static_cast
<
stack_cursor
*>
(
cursor
)
)
),
make_two_bit_judy_map
(
get
(
vertex_index
,
share
->
g
)));
break
;
case
BREADTH_FIRST
:
breadth_first_
search
(
share
->
g
,
*
orig
,
visitor
(
make_bfs_visitor
(
breadth_first_
visit
(
share
->
g
,
*
orig
,
Q
,
make_bfs_visitor
(
std
::
make_pair
(
record_predecessors
(
make_iterator_property_map
(
p
.
begin
(),
share
->
indexmap
),
boost
::
make_assoc_property_map
(
p
),
on_tree_edge
()
),
std
::
make_pair
(
record_distances
(
make_iterator_property_map
(
d
.
begin
(),
share
->
indexmap
),
boost
::
make_assoc_property_map
(
d
),
on_tree_edge
()
),
vis
make_oqgraph_visit_dist
(
boost
::
make_assoc_property_map
(
p
),
boost
::
make_assoc_property_map
(
d
),
static_cast
<
stack_cursor
*>
(
cursor
)
)
))
)
)
);
)
,
make_two_bit_judy_map
(
get
(
vertex_index
,
share
->
g
))
);
break
;
default:
abort
();
}
}
break
;
#if 0
case BREADTH_FIRST | HAVE_DEST:
case DIJKSTRAS | HAVE_DEST:
if ((cursor= new (std::nothrow) stack_cursor(share)) && (orig || dest))
{
std
::
vector
<
Vertex
>
p
(
num_vertices
(
share
->
g
));
std
::
vector
<
EdgeWeight
>
d
(
num_vertices
(
share
->
g
));
oqgraph_visit_dist
vis
(
p
.
begin
(),
d
.
begin
(),
static_cast
<
stack_cursor
*>
(
cursor
));
boost::unordered_map<Vertex, Vertex> p;
boost::unordered_map<Vertex, EdgeWeight> d;
boost::queue<Vertex> Q;
reverse_graph<Graph> r(share->g);
p
[
share
->
indexmap
[
*
dest
]]
=
*
dest
;
p[ *dest ]= *dest;
d[ *dest ] = EdgeWeight();
switch (ALGORITHM & op)
{
case DIJKSTRAS:
dijkstra_shortest_paths
(
r
,
*
dest
,
weight_map
(
share
->
weightmap
).
distance_map
(
make_iterator_property_map
(
d
.
begin
(),
share
->
indexmap
)
).
predecessor_map
(
make_iterator_property_map
(
p
.
begin
(),
share
->
indexmap
)
).
visitor
(
make_dijkstra_visitor
(
vis
)
)
);
dijkstra_shortest_paths_no_init(share->g, *dest,
make_lazy_property_map(p, identity_initializer<Vertex>()),
make_lazy_property_map(d, value_initializer<EdgeWeight>(
(std::numeric_limits<EdgeWeight>::max)())),
get(edge_weight, share->g),
get(vertex_index, share->g),
std::less<EdgeWeight>(),
closed_plus<EdgeWeight>(),
EdgeWeight(),
make_dijkstra_visitor(
make_dijkstra_visitor(
make_oqgraph_visit_dist(
boost::make_assoc_property_map(p),
boost::make_assoc_property_map(d),
static_cast<stack_cursor*>(cursor)
)
)
),
make_two_bit_judy_map(get(vertex_index, share->g)));
break;
case BREADTH_FIRST:
breadth_first_
search
(
r
,
*
dest
,
visitor
(
make_bfs_visitor
(
breadth_first_
visit(share->g, *dest, Q
,
make_bfs_visitor(
std::make_pair(
record_predecessors(
make_iterator_property_map
(
p
.
begin
(),
share
->
indexmap
),
boost::make_assoc_property_map(p),
on_tree_edge()
),
std::make_pair(
record_distances(
make_iterator_property_map
(
d
.
begin
(),
share
->
indexmap
),
boost::make_assoc_property_map(d),
on_tree_edge()
),
vis
make_oqgraph_visit_dist(
boost::make_assoc_property_map(p),
boost::make_assoc_property_map(d),
static_cast<stack_cursor*>(cursor)
)
))
)
)
);
)
,
make_two_bit_judy_map(get(vertex_index, share->g))
);
break;
default:
abort();
}
}
break;
#endif
default:
break
;
}
...
...
@@ -1006,7 +1000,7 @@ int stack_cursor::fetch_row(const row &row_info, row &result,
if
((
result
.
seq_indicator
=
seq
=
last
.
sequence
()))
result
.
seq
=
*
seq
;
if
((
result
.
link_indicator
=
v
=
last
.
vertex
()))
result
.
link
=
share
->
idmap
[
*
v
]
;
result
.
link
=
get
(
boost
::
vertex_index
,
share
->
g
,
*
v
)
;
if
((
result
.
weight_indicator
=
w
=
last
.
weight
()))
result
.
weight
=
*
w
;
return
oqgraph
::
OK
;
...
...
@@ -1040,7 +1034,7 @@ int vertices_cursor::fetch_row(const row &row_info, row &result,
if
(
v
)
{
result
.
link_indicator
=
1
;
result
.
link
=
share
->
idmap
[
*
v
]
;
result
.
link
=
get
(
boost
::
vertex_index
,
share
->
g
,
*
v
)
;
#ifdef DISPLAY_VERTEX_INFO
result
.
seq_indicator
=
1
;
if
((
result
.
seq
=
degree
(
*
v
,
share
->
g
)))
...
...
@@ -1048,10 +1042,10 @@ int vertices_cursor::fetch_row(const row &row_info, row &result,
EdgeWeight
weight
=
0
;
graph_traits
<
Graph
>::
in_edge_iterator
iei
,
iei_end
;
for
(
tie
(
iei
,
iei_end
)
=
in_edges
(
*
v
,
share
->
g
);
iei
!=
iei_end
;
++
iei
)
weight
+=
share
->
weightmap
[
*
iei
]
;
weight
+=
get
(
boost
::
edge_weight
,
share
->
g
,
*
iei
)
;
graph_traits
<
Graph
>::
out_edge_iterator
oei
,
oei_end
;
for
(
tie
(
oei
,
oei_end
)
=
out_edges
(
*
v
,
share
->
g
);
oei
!=
oei_end
;
++
oei
)
weight
+=
share
->
weightmap
[
*
oei
]
;
weight
+=
get
(
boost
::
edge_weight
,
share
->
g
,
*
oei
)
;
result
.
weight_indicator
=
1
;
result
.
weight
=
weight
/
result
.
seq
;
}
...
...
@@ -1085,9 +1079,9 @@ int edges_cursor::fetch_row(const row &row_info, row &result,
{
result
=
row_info
;
result
.
orig_indicator
=
result
.
dest_indicator
=
result
.
weight_indicator
=
1
;
result
.
orig
=
share
->
idmap
[
source
(
*
edge
,
share
->
g
)
]
;
result
.
dest
=
share
->
idmap
[
target
(
*
edge
,
share
->
g
)
]
;
result
.
weight
=
share
->
weightmap
[
*
edge
]
;
result
.
orig
=
get
(
boost
::
vertex_index
,
share
->
g
,
source
(
*
edge
,
share
->
g
)
)
;
result
.
dest
=
get
(
boost
::
vertex_index
,
share
->
g
,
target
(
*
edge
,
share
->
g
)
)
;
result
.
weight
=
get
(
boost
::
edge_weight
,
share
->
g
,
*
edge
)
;
return
oqgraph
::
OK
;
}
return
oqgraph
::
NO_MORE_DATA
;
...
...
storage/oqgraph/graphcore.h
View file @
2037f387
...
...
@@ -104,7 +104,7 @@ namespace open_query
void
row_ref
(
void
*
)
throw
();
static
oqgraph
*
create
(
oqgraph_share
*
)
throw
();
static
oqgraph_share
*
create
()
throw
();
static
oqgraph_share
*
create
(
TABLE
*
,
Field
*
,
Field
*
,
Field
*
)
throw
();
static
void
free
(
oqgraph
*
)
throw
();
static
void
free
(
oqgraph_share
*
)
throw
();
...
...
storage/oqgraph/ha_oqgraph.cc
View file @
2037f387
...
...
@@ -28,13 +28,12 @@
#pragma implementation // gcc: Class implementation
#endif
#include <stdarg.h>
#include <stdio.h>
#define MYSQL_SERVER // to have THD
#include "mysql_priv.h"
#if MYSQL_VERSION_ID >= 50100
#include <mysql/plugin.h>
#endif
#ifdef HAVE_OQGRAPH
#include "ha_oqgraph.h"
#include "graphcore.h"
...
...
@@ -44,77 +43,36 @@
using
namespace
open_query
;
struct
oqgraph_info_st
struct
oqgraph_table_option_struct
{
char
*
table_name
;
char
*
origid
;
// name of the origin id column
char
*
destid
;
// name of the target id column
char
*
weight
;
// name of the weight column (optional)
};
#define ha_table_option_struct oqgraph_table_option_struct
ha_create_table_option
oqgraph_table_option_list
[]
=
{
THR_LOCK
lock
;
oqgraph_share
*
graph
;
uint
use_count
;
uint
key_stat_version
;
uint
records
;
bool
dropped
;
char
name
[
FN_REFLEN
+
1
];
HA_TOPTION_STRING
(
"data_table"
,
table_name
),
HA_TOPTION_STRING
(
"origid"
,
origid
),
HA_TOPTION_STRING
(
"destid"
,
destid
),
HA_TOPTION_STRING
(
"weight"
,
weight
),
HA_TOPTION_END
};
static
const
char
oqgraph_description
[]
=
"Open Query Graph Computation Engine
, stored in memory
"
"Open Query Graph Computation Engine "
"(http://openquery.com/graph)"
;
#if MYSQL_VERSION_ID < 50100
static
bool
oqgraph_init
();
handlerton
oqgraph_hton
=
{
"OQGRAPH"
,
SHOW_OPTION_YES
,
oqgraph_description
,
DB_TYPE_OQGRAPH
,
oqgraph_init
,
0
,
/* slot */
0
,
/* savepoint size. */
NULL
,
/* close_connection */
NULL
,
/* savepoint */
NULL
,
/* rollback to savepoint */
NULL
,
/* release savepoint */
NULL
,
/* commit */
NULL
,
/* rollback */
NULL
,
/* prepare */
NULL
,
/* recover */
NULL
,
/* commit_by_xid */
NULL
,
/* rollback_by_xid */
NULL
,
/* create_cursor_read_view */
NULL
,
/* set_cursor_read_view */
NULL
,
/* close_cursor_read_view */
HTON_NO_FLAGS
};
#define STATISTIC_INCREMENT(X) \
statistic_increment(table->in_use->status_var.X, &LOCK_status)
#define MOVE(X) move_field(X)
#define RECORDS records
#else
#define STATISTIC_INCREMENT(X) ha_statistic_increment(&SSV::X)
#define MOVE(X) move_field_offset(X)
#define RECORDS stats.records
#endif
static
HASH
oqgraph_open_tables
;
static
pthread_mutex_t
LOCK_oqgraph
;
static
bool
oqgraph_init_done
=
0
;
#if MYSQL_VERSION_ID >= 50130
#define HASH_KEY_LENGTH size_t
#else
#define HASH_KEY_LENGTH uint
#endif
static
uchar
*
get_key
(
const
uchar
*
ptr
,
HASH_KEY_LENGTH
*
length
,
my_bool
)
{
const
OQGRAPH_INFO
*
share
=
(
const
OQGRAPH_INFO
*
)
ptr
;
*
length
=
strlen
(
share
->
name
);
return
(
uchar
*
)
share
->
name
;
}
#if MYSQL_VERSION_ID >= 50100
static
handler
*
oqgraph_create_handler
(
handlerton
*
hton
,
TABLE_SHARE
*
table
,
MEM_ROOT
*
mem_root
)
{
...
...
@@ -123,98 +81,20 @@ static handler* oqgraph_create_handler(handlerton *hton, TABLE_SHARE *table,
static
int
oqgraph_init
(
handlerton
*
hton
)
{
#else
static
bool
oqgraph_init
()
{
if
(
have_oqgraph
==
SHOW_OPTION_DISABLED
)
return
1
;
#endif
if
(
pthread_mutex_init
(
&
LOCK_oqgraph
,
MY_MUTEX_INIT_FAST
))
goto
error
;
if
(
hash_init
(
&
oqgraph_open_tables
,
&
my_charset_bin
,
32
,
0
,
0
,
get_key
,
0
,
0
))
{
pthread_mutex_destroy
(
&
LOCK_oqgraph
);
goto
error
;
}
#if MYSQL_VERSION_ID >= 50100
hton
->
state
=
SHOW_OPTION_YES
;
hton
->
db_type
=
DB_TYPE_AUTOASSIGN
;
hton
->
create
=
oqgraph_create_handler
;
hton
->
flags
=
HTON_NO_FLAGS
;
#endif
hton
->
table_options
=
oqgraph_table_option_list
;
oqgraph_init_done
=
TRUE
;
return
0
;
error:
#if MYSQL_VERSION_ID < 50100
have_oqgraph
=
SHOW_OPTION_DISABLED
;
#endif
return
1
;
}
#if MYSQL_VERSION_ID >= 50100
static
int
oqgraph_fini
(
void
*
)
{
hash_free
(
&
oqgraph_open_tables
);
pthread_mutex_destroy
(
&
LOCK_oqgraph
);
oqgraph_init_done
=
FALSE
;
return
0
;
}
#endif
static
OQGRAPH_INFO
*
get_share
(
const
char
*
name
,
TABLE
*
table
=
0
)
{
OQGRAPH_INFO
*
share
;
uint
length
=
strlen
(
name
);
safe_mutex_assert_owner
(
&
LOCK_oqgraph
);
if
(
!
(
share
=
(
OQGRAPH_INFO
*
)
hash_search
(
&
oqgraph_open_tables
,
(
byte
*
)
name
,
length
)))
{
if
(
!
table
||
!
(
share
=
new
OQGRAPH_INFO
))
return
0
;
share
->
use_count
=
share
->
key_stat_version
=
share
->
records
=
0
;
share
->
dropped
=
0
;
strmov
(
share
->
name
,
name
);
if
(
!
(
share
->
graph
=
oqgraph
::
create
()))
{
delete
share
;
return
0
;
}
if
(
my_hash_insert
(
&
oqgraph_open_tables
,
(
byte
*
)
share
))
{
oqgraph
::
free
(
share
->
graph
);
delete
share
;
return
0
;
}
thr_lock_init
(
&
share
->
lock
);
}
share
->
use_count
++
;
return
share
;
}
static
int
free_share
(
OQGRAPH_INFO
*
share
,
bool
drop
=
0
)
{
safe_mutex_assert_owner
(
&
LOCK_oqgraph
);
if
(
!
share
)
return
0
;
if
(
drop
)
{
share
->
dropped
=
true
;
hash_delete
(
&
oqgraph_open_tables
,
(
byte
*
)
share
);
}
if
(
!--
share
->
use_count
)
{
if
(
share
->
dropped
)
{
thr_lock_delete
(
&
share
->
lock
);
oqgraph
::
free
(
share
->
graph
);
delete
share
;
}
}
return
0
;
}
static
int
error_code
(
int
res
)
{
...
...
@@ -262,6 +142,9 @@ static int error_code(int res)
KEY (latch, origid, destid) USING HASH,
KEY (latch, destid, origid) USING HASH
) ENGINE=OQGRAPH
READ_TABLE=bar
ORIGID=src_id
DESTID=tgt_id
*/
static
int
oqgraph_check_table_structure
(
TABLE
*
table_arg
)
...
...
@@ -329,16 +212,15 @@ static int oqgraph_check_table_structure (TABLE *table_arg)
** OQGRAPH tables
*****************************************************************************/
#if MYSQL_VERSION_ID >= 50100
ha_oqgraph
::
ha_oqgraph
(
handlerton
*
hton
,
TABLE_SHARE
*
table_arg
)
:
handler
(
hton
,
table_arg
),
#else
ha_oqgraph
::
ha_oqgraph
(
TABLE
*
table_arg
)
:
handler
(
&
oqgraph_hton
,
table_arg
),
#endif
share
(
0
),
graph
(
0
),
records_changed
(
0
),
key_stat_version
(
0
)
:
handler
(
hton
,
table_arg
)
,
graph_share
(
0
)
,
graph
(
0
)
,
error_message
(
""
,
0
,
&
my_charset_latin1
)
{
}
ha_oqgraph
::~
ha_oqgraph
()
{
}
static
const
char
*
ha_oqgraph_exts
[]
=
{
...
...
@@ -350,11 +232,7 @@ const char **ha_oqgraph::bas_ext() const
return
ha_oqgraph_exts
;
}
#if MYSQL_VERSION_ID >= 50100
ulonglong
ha_oqgraph
::
table_flags
()
const
#else
ulong
ha_oqgraph
::
table_flags
()
const
#endif
{
return
(
HA_NO_BLOBS
|
HA_NULL_IN_KEY
|
HA_REC_NOT_IN_SEQ
|
HA_CAN_INSERT_DELAYED
|
...
...
@@ -366,278 +244,251 @@ ulong ha_oqgraph::index_flags(uint inx, uint part, bool all_parts) const
return
HA_ONLY_WHOLE_INDEX
|
HA_KEY_SCAN_NOT_ROR
;
}
int
ha_oqgraph
::
open
(
const
char
*
name
,
int
mode
,
uint
test_if_locked
)
bool
ha_oqgraph
::
get_error_message
(
int
error
,
String
*
buf
)
{
pthread_mutex_lock
(
&
LOCK_oqgraph
);
if
((
share
=
get_share
(
name
,
table
)))
{
ref_length
=
oqgraph
::
sizeof_ref
;
}
if
(
share
)
if
(
error
<
0
)
{
/* Initialize variables for the opened table */
thr_lock_data_init
(
&
share
->
lock
,
&
lock
,
NULL
);
graph
=
oqgraph
::
create
(
share
->
graph
);
/*
We cannot run update_key_stats() here because we do not have a
lock on the table. The 'records' count might just be changed
temporarily at this moment and we might get wrong statistics (Bug
#10178). Instead we request for update. This will be done in
ha_oqgraph::info(), which is always called before key statistics are
used.
*/
key_stat_version
=
share
->
key_stat_version
-
1
;
buf
->
append
(
error_message
);
buf
->
c_ptr_safe
();
error_message
.
length
(
0
);
}
pthread_mutex_unlock
(
&
LOCK_oqgraph
);
return
(
share
?
0
:
1
);
return
false
;
}
int
ha_oqgraph
::
close
(
void
)
void
ha_oqgraph
::
print_error
(
const
char
*
fmt
,
...
)
{
pthread_mutex_lock
(
&
LOCK_oqgraph
);
oqgraph
::
free
(
graph
);
graph
=
0
;
int
res
=
free_share
(
share
);
pthread_mutex_unlock
(
&
LOCK_oqgraph
);
return
error_code
(
res
);
va_list
ap
;
va_start
(
ap
,
fmt
);
error_message
.
reserve
(
256
);
size_t
len
=
error_message
.
length
();
len
+=
vsnprintf
(
&
error_message
[
len
],
255
,
fmt
,
ap
);
error_message
.
length
(
len
);
va_end
(
ap
);
}
void
ha_oqgraph
::
update_key_stats
()
int
ha_oqgraph
::
open
(
const
char
*
name
,
int
mode
,
uint
test_if_locked
)
{
for
(
uint
i
=
0
;
i
<
table
->
s
->
keys
;
i
++
)
{
KEY
*
key
=
table
->
key_info
+
i
;
if
(
!
key
->
rec_per_key
)
continue
;
if
(
key
->
algorithm
!=
HA_KEY_ALG_BTREE
)
{
if
(
key
->
flags
&
HA_NOSAME
)
key
->
rec_per_key
[
key
->
key_parts
-
1
]
=
1
;
else
{
unsigned
vertices
=
graph
->
vertices_count
();
unsigned
edges
=
graph
->
edges_count
();
uint
no_records
=
vertices
?
2
*
(
edges
+
vertices
)
/
vertices
:
2
;
if
(
no_records
<
2
)
no_records
=
2
;
key
->
rec_per_key
[
key
->
key_parts
-
1
]
=
no_records
;
}
}
}
records_changed
=
0
;
/* At the end of update_key_stats() we can proudly claim they are OK. */
key_stat_version
=
share
->
key_stat_version
;
}
THD
*
thd
=
current_thd
;
oqgraph_table_option_struct
*
options
=
reinterpret_cast
<
oqgraph_table_option_struct
*>
(
table
->
s
->
option_struct
);
error_message
.
length
(
0
);
const
char
*
p
=
strend
(
name
)
-
1
;
while
(
p
>
name
&&
*
p
!=
'\\'
&&
*
p
!=
'/'
)
--
p
;
int
ha_oqgraph
::
write_row
(
byte
*
buf
)
{
int
res
=
oqgraph
::
MISC_FAIL
;
Field
**
const
field
=
table
->
field
;
STATISTIC_INCREMENT
(
ha_write_count
);
init_tmp_table_share
(
thd
,
share
,
table
->
s
->
db
.
str
,
table
->
s
->
db
.
length
,
options
->
table_name
,
""
);
#if MYSQL_VERSION_ID >= 50100
my_bitmap_map
*
old_map
=
dbug_tmp_use_all_columns
(
table
,
table
->
read_set
);
#endif
my_ptrdiff_t
ptrdiff
=
buf
-
table
->
record
[
0
];
size_t
tlen
=
strlen
(
options
->
table_name
);
size_t
plen
=
(
int
)(
p
-
name
)
+
tlen
;
if
(
ptrdiff
)
{
field
[
1
]
->
MOVE
(
ptrdiff
);
field
[
2
]
->
MOVE
(
ptrdiff
);
field
[
3
]
->
MOVE
(
ptrdiff
);
}
share
->
path
.
str
=
(
char
*
)
alloc_root
(
&
share
->
mem_root
,
plen
+
1
);
if
(
!
field
[
1
]
->
is_null
()
&&
!
field
[
2
]
->
is_null
())
{
VertexID
orig_id
=
(
VertexID
)
field
[
1
]
->
val_int
();
VertexID
dest_id
=
(
VertexID
)
field
[
2
]
->
val_int
();
EdgeWeight
weight
=
1
;
strmov
(
strnmov
(
share
->
path
.
str
,
name
,
(
int
)(
p
-
name
)
+
1
),
options
->
table_name
);
share
->
normalized_path
.
str
=
share
->
path
.
str
;
share
->
path
.
length
=
share
->
normalized_path
.
length
=
plen
;
if
(
!
field
[
3
]
->
is_null
())
weight
=
(
EdgeWeight
)
field
[
3
]
->
val_real
();
origid
=
destid
=
weight
=
0
;
if
(
!
(
res
=
graph
->
insert_edge
(
orig_id
,
dest_id
,
weight
,
replace_dups
)))
while
(
open_table_def
(
thd
,
share
,
0
))
{
if
(
thd
->
is_error
()
&&
thd
->
main_da
.
sql_errno
()
!=
ER_NO_SUCH_TABLE
)
{
free_table_share
(
share
);
return
thd
->
main_da
.
sql_errno
();
}
if
(
ha_create_table_from_engine
(
thd
,
table
->
s
->
db
.
str
,
options
->
table_name
))
{
++
records_changed
;
share
->
records
++
;
free_table_share
(
share
)
;
return
thd
->
main_da
.
sql_errno
()
;
}
if
(
res
==
oqgraph
::
DUPLICATE_EDGE
&&
ignore_dups
&&
!
insert_dups
)
res
=
oqgraph
::
OK
;
mysql_reset_errors
(
thd
,
1
);
thd
->
clear_error
();
continue
;
}
if
(
ptrdiff
)
if
(
int
err
=
share
->
error
)
{
field
[
1
]
->
MOVE
(
-
ptrdiff
);
f
ield
[
2
]
->
MOVE
(
-
ptrdiff
);
field
[
3
]
->
MOVE
(
-
ptrdiff
)
;
open_table_error
(
share
,
share
->
error
,
share
->
open_errno
,
share
->
errarg
);
f
ree_table_share
(
share
);
return
err
;
}
#if MYSQL_VERSION_ID >= 50100
dbug_tmp_restore_column_map
(
table
->
read_set
,
old_map
);
#endif
if
(
!
res
&&
records_changed
*
OQGRAPH_STATS_UPDATE_THRESHOLD
>
share
->
records
)
if
(
share
->
is_view
)
{
/*
We can perform this safely since only one writer at the time is
allowed on the table.
*/
share
->
key_stat_version
++
;
open_table_error
(
share
,
1
,
EMFILE
,
0
);
free_table_share
(
share
);
print_error
(
"VIEWs are not supported for a backing store"
);
return
-
1
;
}
return
error_code
(
res
);
}
int
ha_oqgraph
::
update_row
(
const
byte
*
old
,
byte
*
buf
)
{
int
res
=
oqgraph
::
MISC_FAIL
;
VertexID
orig_id
,
dest_id
;
EdgeWeight
weight
=
1
;
Field
**
field
=
table
->
field
;
STATISTIC_INCREMENT
(
ha_update_count
);
#if MYSQL_VERSION_ID >= 50100
my_bitmap_map
*
old_map
=
dbug_tmp_use_all_columns
(
table
,
table
->
read_set
);
#endif
my_ptrdiff_t
ptrdiff
=
buf
-
table
->
record
[
0
];
if
(
ptrdiff
)
if
(
int
err
=
open_table_from_share
(
thd
,
share
,
""
,
(
uint
)
(
HA_OPEN_KEYFILE
|
HA_OPEN_RNDFILE
|
HA_GET_INDEX
|
HA_TRY_READ_ONLY
),
READ_KEYINFO
|
COMPUTE_TYPES
|
EXTRA_RECORD
,
thd
->
open_options
,
edges
,
FALSE
))
{
field
[
0
]
->
MOVE
(
ptrdiff
);
field
[
1
]
->
MOVE
(
ptrdiff
);
field
[
2
]
->
MOVE
(
ptrdiff
);
field
[
3
]
->
MOVE
(
ptrdiff
);
open_table_error
(
share
,
err
,
EMFILE
,
0
);
free_table_share
(
share
);
return
-
1
;
}
if
(
inited
==
INDEX
||
inited
==
RND
)
edges
->
reginfo
.
lock_type
=
TL_READ
;
edges
->
tablenr
=
thd
->
current_tablenr
++
;
edges
->
status
=
STATUS_NO_RECORD
;
edges
->
file
->
ha_start_of_new_statement
();
edges
->
file
->
ft_handler
=
0
;
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
);
// 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
)
{
VertexID
*
origp
=
0
,
*
destp
=
0
;
EdgeWeight
*
weightp
=
0
;
if
(
!
field
[
1
]
->
is_null
())
*
(
origp
=
&
orig_id
)
=
(
VertexID
)
field
[
1
]
->
val_int
();
if
(
!
field
[
2
]
->
is_null
())
*
(
destp
=
&
dest_id
)
=
(
VertexID
)
field
[
2
]
->
val_int
();
if
(
!
field
[
3
]
->
is_null
())
*
(
weightp
=
&
weight
)
=
(
EdgeWeight
)
field
[
3
]
->
val_real
();
my_ptrdiff_t
ptrdiff2
=
old
-
buf
;
field
[
0
]
->
MOVE
(
ptrdiff2
);
field
[
1
]
->
MOVE
(
ptrdiff2
);
field
[
2
]
->
MOVE
(
ptrdiff2
);
field
[
3
]
->
MOVE
(
ptrdiff2
);
if
(
field
[
0
]
->
is_null
())
if
(
strcmp
(
options
->
origid
,
(
*
field
)
->
field_name
))
continue
;
if
((
*
field
)
->
cmp_type
()
!=
INT_RESULT
||
!
((
*
field
)
->
flags
&
NOT_NULL_FLAG
))
{
if
(
!
origp
==
field
[
1
]
->
is_null
()
&&
*
origp
==
(
VertexID
)
field
[
1
]
->
val_int
())
origp
=
0
;
if
(
!
destp
==
field
[
2
]
->
is_null
()
&&
*
destp
==
(
VertexID
)
field
[
2
]
->
val_int
())
origp
=
0
;
if
(
!
weightp
==
field
[
3
]
->
is_null
()
&&
*
weightp
==
(
VertexID
)
field
[
3
]
->
val_real
())
weightp
=
0
;
if
(
!
(
res
=
graph
->
modify_edge
(
oqgraph
::
current_row
(),
origp
,
destp
,
weightp
,
replace_dups
)))
++
records_changed
;
else
if
(
ignore_dups
&&
res
==
oqgraph
::
DUPLICATE_EDGE
)
res
=
oqgraph
::
OK
;
print_error
(
"Column '%s.%s' is not a not-null integer type"
,
options
->
table_name
,
options
->
origid
);
closefrm
(
edges
,
0
);
free_table_share
(
share
);
return
-
1
;
}
field
[
0
]
->
MOVE
(
-
ptrdiff2
);
field
[
1
]
->
MOVE
(
-
ptrdiff2
);
field
[
2
]
->
MOVE
(
-
ptrdiff2
);
field
[
3
]
->
MOVE
(
-
ptrdiff2
);
origid
=
*
field
;
break
;
}
if
(
ptrdiff
)
for
(
Field
**
field
=
edges
->
field
;
*
field
;
++
field
)
{
field
[
0
]
->
MOVE
(
-
ptrdiff
);
field
[
1
]
->
MOVE
(
-
ptrdiff
);
field
[
2
]
->
MOVE
(
-
ptrdiff
);
field
[
3
]
->
MOVE
(
-
ptrdiff
);
if
(
strcmp
(
options
->
destid
,
(
*
field
)
->
field_name
))
continue
;
if
((
*
field
)
->
type
()
!=
origid
->
type
()
||
!
((
*
field
)
->
flags
&
NOT_NULL_FLAG
))
{
print_error
(
"Column '%s.%s' is not a not-null integer type"
,
options
->
table_name
,
options
->
destid
);
closefrm
(
edges
,
0
);
free_table_share
(
share
);
return
-
1
;
}
destid
=
*
field
;
break
;
}
#if MYSQL_VERSION_ID >= 50100
dbug_tmp_restore_column_map
(
table
->
read_set
,
old_map
);
#endif
if
(
!
res
&&
records_changed
*
OQGRAPH_STATS_UPDATE_THRESHOLD
>
share
->
records
)
for
(
Field
**
field
=
edges
->
field
;
options
->
weight
&&
*
field
;
++
field
)
{
if
(
strcmp
(
options
->
weight
,
(
*
field
)
->
field_name
))
continue
;
if
((
*
field
)
->
result_type
()
!=
REAL_RESULT
||
!
((
*
field
)
->
flags
&
NOT_NULL_FLAG
))
{
print_error
(
"Column '%s.%s' is not a not-null real type"
,
options
->
table_name
,
options
->
weight
);
closefrm
(
edges
,
0
);
free_table_share
(
share
);
return
-
1
;
}
weight
=
*
field
;
break
;
}
if
(
!
origid
||
!
destid
||
(
!
weight
&&
options
->
weight
))
{
/*
We can perform this safely since only one writer at the time is
allowed on the table.
*/
share
->
key_stat_version
++
;
print_error
(
"Data columns missing on table '%s'"
,
options
->
table_name
);
closefrm
(
edges
,
0
);
free_table_share
(
share
);
return
-
1
;
}
return
error_code
(
res
);
if
(
!
(
graph_share
=
oqgraph
::
create
(
edges
,
origid
,
destid
,
weight
)))
{
print_error
(
"Unable to create graph instance."
);
closefrm
(
edges
,
0
);
free_table_share
(
share
);
return
-
1
;
}
ref_length
=
oqgraph
::
sizeof_ref
;
graph
=
oqgraph
::
create
(
graph_share
);
return
0
;
}
int
ha_oqgraph
::
delete_row
(
const
byte
*
buf
)
int
ha_oqgraph
::
close
(
void
)
{
int
res
=
oqgraph
::
EDGE_NOT_FOUND
;
Field
**
field
=
table
->
field
;
STATISTIC_INCREMENT
(
ha_delete_count
);
oqgraph
::
free
(
graph
);
graph
=
0
;
oqgraph
::
free
(
graph_share
);
graph_share
=
0
;
if
(
inited
==
INDEX
||
inited
==
RND
)
if
(
share
)
{
if
((
res
=
graph
->
delete_edge
(
oqgraph
::
current_row
()))
==
oqgraph
::
OK
)
{
++
records_changed
;
share
->
records
--
;
}
if
(
edges
->
file
)
closefrm
(
edges
,
0
);
free_table_share
(
share
);
}
if
(
res
!=
oqgraph
::
OK
)
{
#if MYSQL_VERSION_ID >= 50100
my_bitmap_map
*
old_map
=
dbug_tmp_use_all_columns
(
table
,
table
->
read_set
);
#endif
my_ptrdiff_t
ptrdiff
=
buf
-
table
->
record
[
0
];
if
(
ptrdiff
)
{
field
[
0
]
->
MOVE
(
ptrdiff
);
field
[
1
]
->
MOVE
(
ptrdiff
);
field
[
2
]
->
MOVE
(
ptrdiff
);
}
return
0
;
}
if
(
field
[
0
]
->
is_null
()
&&
!
field
[
1
]
->
is_null
()
&&
!
field
[
2
]
->
is_null
())
void
ha_oqgraph
::
update_key_stats
()
{
for
(
uint
i
=
0
;
i
<
table
->
s
->
keys
;
i
++
)
{
KEY
*
key
=
table
->
key_info
+
i
;
if
(
!
key
->
rec_per_key
)
continue
;
if
(
key
->
algorithm
!=
HA_KEY_ALG_BTREE
)
{
VertexID
orig_id
=
(
VertexID
)
field
[
1
]
->
val_int
();
VertexID
dest_id
=
(
VertexID
)
field
[
2
]
->
val_int
();
if
((
res
=
graph
->
delete_edge
(
orig_id
,
dest_id
))
==
oqgraph
::
OK
)
if
(
key
->
flags
&
HA_NOSAME
)
key
->
rec_per_key
[
key
->
key_parts
-
1
]
=
1
;
else
{
++
records_changed
;
share
->
records
--
;
//unsigned vertices= graph->vertices_count();
//unsigned edges= graph->edges_count();
//uint no_records= vertices ? 2 * (edges + vertices) / vertices : 2;
//if (no_records < 2)
uint
no_records
=
2
;
key
->
rec_per_key
[
key
->
key_parts
-
1
]
=
no_records
;
}
}
if
(
ptrdiff
)
{
field
[
0
]
->
MOVE
(
-
ptrdiff
);
field
[
1
]
->
MOVE
(
-
ptrdiff
);
field
[
2
]
->
MOVE
(
-
ptrdiff
);
}
#if MYSQL_VERSION_ID >= 50100
dbug_tmp_restore_column_map
(
table
->
read_set
,
old_map
);
#endif
}
/* At the end of update_key_stats() we can proudly claim they are OK. */
//skey_stat_version= share->key_stat_version;
}
if
(
!
res
&&
table
->
s
->
tmp_table
==
NO_TMP_TABLE
&&
records_changed
*
OQGRAPH_STATS_UPDATE_THRESHOLD
>
share
->
records
)
{
/*
We can perform this safely since only one writer at the time is
allowed on the table.
*/
share
->
key_stat_version
++
;
}
return
error_code
(
res
);
int
ha_oqgraph
::
write_row
(
byte
*
buf
)
{
return
ER_OPEN_AS_READONLY
;
}
int
ha_oqgraph
::
update_row
(
const
byte
*
old
,
byte
*
buf
)
{
return
ER_OPEN_AS_READONLY
;
}
int
ha_oqgraph
::
delete_row
(
const
byte
*
buf
)
{
return
ER_OPEN_AS_READONLY
;
}
int
ha_oqgraph
::
index_read
(
byte
*
buf
,
const
byte
*
key
,
uint
key_len
,
...
...
@@ -675,9 +526,7 @@ int ha_oqgraph::index_read_idx(byte * buf, uint index, const byte * key,
bmove_align
(
buf
,
table
->
s
->
default_values
,
table
->
s
->
reclength
);
key_restore
(
buf
,
(
byte
*
)
key
,
key_info
,
key_len
);
#if MYSQL_VERSION_ID >= 50100
my_bitmap_map
*
old_map
=
dbug_tmp_use_all_columns
(
table
,
table
->
read_set
);
#endif
my_ptrdiff_t
ptrdiff
=
buf
-
table
->
record
[
0
];
if
(
ptrdiff
)
...
...
@@ -711,9 +560,7 @@ int ha_oqgraph::index_read_idx(byte * buf, uint index, const byte * key,
field
[
1
]
->
MOVE
(
-
ptrdiff
);
field
[
2
]
->
MOVE
(
-
ptrdiff
);
}
#if MYSQL_VERSION_ID >= 50100
dbug_tmp_restore_column_map
(
table
->
read_set
,
old_map
);
#endif
res
=
graph
->
search
(
latchp
,
orig_idp
,
dest_idp
);
...
...
@@ -729,9 +576,7 @@ int ha_oqgraph::fill_record(byte *record, const open_query::row &row)
bmove_align
(
record
,
table
->
s
->
default_values
,
table
->
s
->
reclength
);
#if MYSQL_VERSION_ID >= 50100
my_bitmap_map
*
old_map
=
dbug_tmp_use_all_columns
(
table
,
table
->
write_set
);
#endif
my_ptrdiff_t
ptrdiff
=
record
-
table
->
record
[
0
];
if
(
ptrdiff
)
...
...
@@ -790,15 +635,14 @@ int ha_oqgraph::fill_record(byte *record, const open_query::row &row)
field
[
4
]
->
MOVE
(
-
ptrdiff
);
field
[
5
]
->
MOVE
(
-
ptrdiff
);
}
#if MYSQL_VERSION_ID >= 50100
dbug_tmp_restore_column_map
(
table
->
write_set
,
old_map
);
#endif
return
0
;
}
int
ha_oqgraph
::
rnd_init
(
bool
scan
)
{
edges
->
prepare_for_position
();
return
error_code
(
graph
->
random
(
scan
));
}
...
...
@@ -836,75 +680,31 @@ int ha_oqgraph::cmp_ref(const byte *ref1, const byte *ref2)
int
ha_oqgraph
::
info
(
uint
flag
)
{
RECORDS
=
graph
->
vertices_count
()
+
graph
->
edges_count
();
#if 0
records= hp_info.records;
deleted= hp_info.deleted;
errkey= hp_info.errkey;
mean_rec_length= hp_info.reclength;
data_file_length= hp_info.data_length;
index_file_length= hp_info.index_length;
max_data_file_length= hp_info.max_records* hp_info.reclength;
delete_length= hp_info.deleted * hp_info.reclength;
#endif
RECORDS
=
graph
->
edges_count
();
/*
If info() is called for the first time after open(), we will still
have to update the key statistics. Hoping that a table lock is now
in place.
*/
if
(
key_stat_version
!=
share
->
key_stat_version
)
update_key_stats
();
//
if (key_stat_version != share->key_stat_version)
//
update_key_stats();
return
0
;
}
int
ha_oqgraph
::
extra
(
enum
ha_extra_function
operation
)
{
switch
(
operation
)
{
case
HA_EXTRA_IGNORE_DUP_KEY
:
ignore_dups
=
true
;
break
;
case
HA_EXTRA_NO_IGNORE_DUP_KEY
:
ignore_dups
=
false
;
insert_dups
=
false
;
break
;
case
HA_EXTRA_WRITE_CAN_REPLACE
:
replace_dups
=
true
;
break
;
case
HA_EXTRA_WRITE_CANNOT_REPLACE
:
replace_dups
=
false
;
break
;
case
HA_EXTRA_INSERT_WITH_UPDATE
:
insert_dups
=
true
;
break
;
default:
break
;
}
return
0
;
return
edges
->
file
->
extra
(
operation
);
}
int
ha_oqgraph
::
delete_all_rows
()
{
int
res
;
if
(
!
(
res
=
graph
->
delete_all
()))
{
share
->
records
=
0
;
}
if
(
!
res
&&
table
->
s
->
tmp_table
==
NO_TMP_TABLE
)
{
/*
We can perform this safely since only one writer at the time is
allowed on the table.
*/
share
->
key_stat_version
++
;
}
return
error_code
(
res
);
return
ER_OPEN_AS_READONLY
;
}
int
ha_oqgraph
::
external_lock
(
THD
*
thd
,
int
lock_type
)
{
return
0
;
// No external locking
return
edges
->
file
->
ha_external_lock
(
thd
,
lock_type
);
}
...
...
@@ -912,10 +712,7 @@ THR_LOCK_DATA **ha_oqgraph::store_lock(THD *thd,
THR_LOCK_DATA
**
to
,
enum
thr_lock_type
lock_type
)
{
if
(
lock_type
!=
TL_IGNORE
&&
lock
.
type
==
TL_UNLOCK
)
lock
.
type
=
lock_type
;
*
to
++=
&
lock
;
return
to
;
return
edges
->
file
->
store_lock
(
thd
,
to
,
lock_type
);
}
/*
...
...
@@ -923,29 +720,13 @@ THR_LOCK_DATA **ha_oqgraph::store_lock(THD *thd,
not when doing a CREATE on the table.
*/
int
ha_oqgraph
::
delete_table
(
const
char
*
name
)
int
ha_oqgraph
::
delete_table
(
const
char
*
)
{
int
res
=
0
;
OQGRAPH_INFO
*
share
;
pthread_mutex_lock
(
&
LOCK_oqgraph
);
if
((
share
=
get_share
(
name
)))
{
res
=
free_share
(
share
,
true
);
}
pthread_mutex_unlock
(
&
LOCK_oqgraph
);
return
error_code
(
res
);
return
0
;
}
int
ha_oqgraph
::
rename_table
(
const
char
*
from
,
const
char
*
to
)
int
ha_oqgraph
::
rename_table
(
const
char
*
,
const
char
*
)
{
pthread_mutex_lock
(
&
LOCK_oqgraph
);
if
(
OQGRAPH_INFO
*
share
=
get_share
(
from
))
{
strmov
(
share
->
name
,
to
);
hash_update
(
&
oqgraph_open_tables
,
(
byte
*
)
share
,
(
byte
*
)
from
,
strlen
(
from
));
}
pthread_mutex_unlock
(
&
LOCK_oqgraph
);
return
0
;
}
...
...
@@ -978,8 +759,9 @@ ha_rows ha_oqgraph::records_in_range(uint inx, key_range *min_key,
return
RECORDS
;
/* Assert that info() did run. We need current statistics here. */
DBUG_ASSERT
(
key_stat_version
==
share
->
key_stat_version
);
ha_rows
result
=
key
->
rec_per_key
[
key
->
key_parts
-
1
];
//DBUG_ASSERT(key_stat_version == share->key_stat_version);
//ha_rows result= key->rec_per_key[key->key_parts-1];
ha_rows
result
=
10
;
return
result
;
}
...
...
@@ -988,24 +770,13 @@ ha_rows ha_oqgraph::records_in_range(uint inx, key_range *min_key,
int
ha_oqgraph
::
create
(
const
char
*
name
,
TABLE
*
table_arg
,
HA_CREATE_INFO
*
create_info
)
{
int
res
=
-
1
;
OQGRAPH_INFO
*
share
;
oqgraph_table_option_struct
*
options
=
reinterpret_cast
<
oqgraph_table_option_struct
*>
(
table
->
s
->
option_struct
)
;
pthread_mutex_lock
(
&
LOCK_oqgraph
);
if
((
share
=
get_share
(
name
)))
{
free_share
(
share
);
}
else
{
if
(
!
oqgraph_check_table_structure
(
table_arg
))
res
=
0
;;
}
pthread_mutex_unlock
(
&
LOCK_oqgraph
);
if
(
int
res
=
oqgraph_check_table_structure
(
table_arg
))
return
error_code
(
res
);
if
(
this
->
share
)
info
(
HA_STATUS_NO_LOCK
|
HA_STATUS_CONST
|
HA_STATUS_VARIABLE
);
return
error_code
(
res
);
return
0
;
}
...
...
@@ -1016,7 +787,6 @@ void ha_oqgraph::update_create_info(HA_CREATE_INFO *create_info)
// create_info->auto_increment_value= auto_increment_value;
}
#if MYSQL_VERSION_ID >= 50100
struct
st_mysql_storage_engine
oqgraph_storage_engine
=
{
MYSQL_HANDLERTON_INTERFACE_VERSION
};
...
...
@@ -1030,12 +800,9 @@ mysql_declare_plugin(oqgraph)
PLUGIN_LICENSE_GPL
,
(
int
(
*
)(
void
*
))
oqgraph_init
,
/* Plugin Init */
oqgraph_fini
,
/* Plugin Deinit */
0x0
200
,
/* Version: 2
.0 */
0x0
300
,
/* Version: 3s
.0 */
NULL
,
/* status variables */
NULL
,
/* system variables */
NULL
/* config options */
}
mysql_declare_plugin_end
;
#endif
#endif
storage/oqgraph/ha_oqgraph.h
View file @
2037f387
...
...
@@ -39,19 +39,21 @@ namespace open_query
{
struct
row
;
class
oqgraph
;
class
oqgraph_share
;
}
/* class for the the Open Query Graph handler */
class
ha_oqgraph
:
public
handler
{
OQGRAPH_INFO
*
share
;
TABLE_SHARE
share
[
1
];
TABLE
edges
[
1
];
Field
*
origid
;
Field
*
destid
;
Field
*
weight
;
open_query
::
oqgraph_share
*
graph_share
;
open_query
::
oqgraph
*
graph
;
THR_LOCK_DATA
lock
;
/* number of records changed since last statistics update */
uint
records_changed
;
uint
key_stat_version
;
bool
replace_dups
,
ignore_dups
,
insert_dups
;
int
fill_record
(
byte
*
,
const
open_query
::
row
&
);
...
...
@@ -63,7 +65,7 @@ class ha_oqgraph: public handler
ha_oqgraph
(
TABLE
*
table
);
ulong
table_flags
()
const
;
#endif
~
ha_oqgraph
()
{}
~
ha_oqgraph
()
;
const
char
*
table_type
()
const
{
return
"OQGRAPH"
;
...
...
@@ -109,6 +111,12 @@ class ha_oqgraph: public handler
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
;
};
storage/oqgraph/oqgraph_judy.cc
0 → 100644
View file @
2037f387
/* Copyright (C) 2009-2011 Arjen G Lentz & Antony T Curtis for Open Query
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* ======================================================================
Open Query Graph Computation Engine, based on a concept by Arjen Lentz
Mk.III implementation by Antony Curtis & Arjen Lentz
For more information, documentation, support, enhancement engineering,
and non-GPL licensing, see http://openquery.com/graph
or contact graph@openquery.com
For packaged binaries, see http://ourdelta.org
======================================================================
*/
#include "oqgraph_judy.h"
#include <Judy.h>
void
open_query
::
judy_bitset
::
clear
()
{
int
rc
;
J1FA
(
rc
,
array
);
}
bool
open_query
::
judy_bitset
::
test
(
size_type
n
)
const
{
int
rc
;
J1T
(
rc
,
array
,
n
);
return
rc
==
1
;
}
open_query
::
judy_bitset
&
open_query
::
judy_bitset
::
setbit
(
size_type
n
)
{
int
rc
;
J1S
(
rc
,
array
,
n
);
return
*
this
;
}
open_query
::
judy_bitset
&
open_query
::
judy_bitset
::
reset
(
size_type
n
)
{
int
rc
;
J1U
(
rc
,
array
,
n
);
return
*
this
;
}
open_query
::
judy_bitset
&
open_query
::
judy_bitset
::
flip
(
size_type
n
)
{
int
rc
;
J1U
(
rc
,
array
,
n
);
if
(
!
rc
)
{
J1S
(
rc
,
array
,
n
);
}
return
*
this
;
}
open_query
::
judy_bitset
::
size_type
open_query
::
judy_bitset
::
num_blocks
()
const
{
Word_t
rc
;
J1MU
(
rc
,
array
);
return
rc
;
}
open_query
::
judy_bitset
::
size_type
open_query
::
judy_bitset
::
size
()
const
{
int
rc
;
Word_t
index
=
(
Word_t
)
-
1
;
J1L
(
rc
,
array
,
index
);
if
(
!
rc
)
return
index
;
else
return
npos
;
}
open_query
::
judy_bitset
::
size_type
open_query
::
judy_bitset
::
count
()
const
{
Word_t
rc
;
J1C
(
rc
,
array
,
0
,
-
1
);
return
rc
;
}
open_query
::
judy_bitset
::
size_type
open_query
::
judy_bitset
::
find_first
()
const
{
int
rc
;
Word_t
index
=
0
;
J1F
(
rc
,
array
,
index
);
if
(
!
rc
)
return
index
;
else
return
npos
;
}
open_query
::
judy_bitset
::
size_type
open_query
::
judy_bitset
::
find_next
(
size_type
n
)
const
{
int
rc
;
Word_t
index
=
(
Word_t
)
n
;
J1N
(
rc
,
array
,
index
);
if
(
!
rc
)
return
index
;
else
return
npos
;
}
storage/oqgraph/oqgraph_judy.h
0 → 100644
View file @
2037f387
/* Copyright (C) 2009-2011 Arjen G Lentz & Antony T Curtis for Open Query
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* ======================================================================
Open Query Graph Computation Engine, based on a concept by Arjen Lentz
Mk.III implementation by Antony Curtis & Arjen Lentz
For more information, documentation, support, enhancement engineering,
and non-GPL licensing, see http://openquery.com/graph
or contact graph@openquery.com
For packaged binaries, see http://ourdelta.org
======================================================================
*/
#pragma once
#include <cstddef>
namespace
open_query
{
class
judy_bitset
{
public:
typedef
std
::
size_t
size_type
;
enum
{
npos
=
(
size_type
)
-
1
};
judy_bitset
()
:
array
(
0
)
{
}
~
judy_bitset
()
{
clear
();
}
void
clear
();
bool
empty
()
const
{
return
!
array
;
}
bool
none
()
const
{
return
npos
==
find_first
();
}
inline
judy_bitset
&
set
(
size_type
n
,
bool
val
=
true
)
{
if
(
!
val
)
return
reset
(
n
);
else
return
setbit
(
n
);
}
judy_bitset
&
reset
(
size_type
n
);
judy_bitset
&
flip
(
size_type
n
);
bool
test
(
size_type
)
const
;
size_type
count
()
const
;
size_type
size
()
const
;
size_type
num_blocks
()
const
;
class
reference
{
friend
class
judy_bitset
;
reference
(
judy_bitset
&
array
,
size_type
pos
)
:
j
(
array
)
,
n
(
pos
)
{
}
void
operator
&
();
// not defined
public:
reference
&
operator
=
(
bool
value
)
{
j
.
set
(
n
,
value
);
return
*
this
;
}
reference
&
operator
=
(
const
reference
&
ref
)
{
j
.
set
(
n
,
ref
);
return
*
this
;
}
reference
&
operator
|=
(
bool
value
)
{
if
(
value
)
j
.
set
(
n
);
return
*
this
;
}
reference
&
operator
&=
(
bool
value
)
{
if
(
!
value
)
j
.
reset
(
n
);
return
*
this
;
}
reference
&
operator
^=
(
bool
value
)
{
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
;
}
private:
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:
mutable
void
*
array
;
judy_bitset
&
setbit
(
size_type
n
);
};
}
storage/oqgraph/oqgraph_shim.cc
0 → 100644
View file @
2037f387
/* Copyright (C) 2009-2011 Arjen G Lentz & Antony T Curtis for Open Query
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* ======================================================================
Open Query Graph Computation Engine, based on a concept by Arjen Lentz
Mk.III implementation by Antony Curtis & Arjen Lentz
For more information, documentation, support, enhancement engineering,
and non-GPL licensing, see http://openquery.com/graph
or contact graph@openquery.com
For packaged binaries, see http://ourdelta.org
======================================================================
*/
#include "oqgraph_shim.h"
storage/oqgraph/oqgraph_shim.h
0 → 100644
View file @
2037f387
/* Copyright (C) 2009-2011 Arjen G Lentz & Antony T Curtis for Open Query
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* ======================================================================
Open Query Graph Computation Engine, based on a concept by Arjen Lentz
Mk.III implementation by Antony Curtis & Arjen Lentz
For more information, documentation, support, enhancement engineering,
and non-GPL licensing, see http://openquery.com/graph
or contact graph@openquery.com
For packaged binaries, see http://ourdelta.org
======================================================================
*/
#pragma once
#include "oqgraph_thunk.h"
#include "oqgraph_judy.h"
#include <boost/graph/directed_graph.hpp>
#include <boost/graph/adjacency_iterator.hpp>
namespace
open_query
{
struct
OQGraphTraversalCategory
:
public
boost
::
bidirectional_graph_tag
,
public
boost
::
adjacency_graph_tag
,
public
boost
::
edge_list_graph_tag
{
};
}
namespace
oqgraph3
{
struct
traversal_category
:
public
boost
::
adjacency_graph_tag
,
public
boost
::
bidirectional_graph_tag
,
public
boost
::
edge_list_graph_tag
{
};
struct
edge_iterator
{
typedef
edge_iterator
self
;
typedef
edge_descriptor
value_type
;
typedef
edge_descriptor
&
reference
;
typedef
edge_descriptor
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
<
row_cursor
>
_iter
;
};
struct
vertex_iterator
{
typedef
vertex_iterator
self
;
typedef
vertex_descriptor
value_type
;
typedef
vertex_descriptor
&
reference
;
typedef
vertex_descriptor
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
*
()
{
if
(
!
_seen
.
test
(
_iter
.
_iter
->
operator
*
().
first
))
return
_iter
.
_iter
->
_cache
->
vertex
(
_iter
.
_iter
->
operator
*
().
first
);
else
return
_iter
.
_iter
->
_cache
->
vertex
(
_iter
.
_iter
->
operator
*
().
second
);
}
self
&
operator
++
()
{
if
(
!
_seen
.
test
(
_iter
.
_iter
->
operator
*
().
first
))
{
_seen
.
set
(
_iter
.
_iter
->
operator
*
().
first
);
}
else
{
_seen
.
set
(
_iter
.
_iter
->
operator
*
().
second
);
}
while
(
_iter
.
_iter
->
_current
&&
_seen
.
test
(
_iter
.
_iter
->
operator
*
().
first
)
&&
_seen
.
test
(
_iter
.
_iter
->
operator
*
().
second
))
{
++
_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
;
}
edge_iterator
_iter
;
open_query
::
judy_bitset
_seen
;
};
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
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
;
};
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
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
;
};
struct
vertex_index_property_map
{
typedef
vertex_id
value_type
;
typedef
value_type
reference
;
typedef
vertex_descriptor
key_type
;
typedef
boost
::
readable_property_map_tag
category
;
vertex_index_property_map
(
const
graph
&
g
)
:
_g
(
g
)
{
}
const
graph
&
_g
;
};
struct
edge_weight_property_map
{
typedef
weight_t
value_type
;
typedef
value_type
reference
;
typedef
edge_descriptor
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
boost
::
readable_property_map_tag
category
;
edge_index_property_map
(
const
graph
&
g
)
:
_g
(
g
)
{
}
const
graph
&
_g
;
};
}
namespace
boost
{
template
<
>
struct
graph_traits
<
oqgraph3
::
graph
>
{
typedef
oqgraph3
::
vertex_descriptor
vertex_descriptor
;
typedef
oqgraph3
::
edge_descriptor
edge_descriptor
;
typedef
boost
::
adjacency_iterator_generator
<
oqgraph3
::
graph
,
oqgraph3
::
vertex_descriptor
,
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
;
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
();
}
};
template
<
>
struct
graph_traits
<
const
oqgraph3
::
graph
>
:
public
graph_traits
<
oqgraph3
::
graph
>
{
};
template
<
>
struct
graph_property_type
<
oqgraph3
::
graph
>
{
typedef
no_property
type
;
};
template
<
>
struct
vertex_property_type
<
oqgraph3
::
graph
>
{
typedef
no_property
type
;
};
template
<
>
struct
edge_property_type
<
oqgraph3
::
graph
>
{
typedef
no_property
type
;
};
template
<
>
struct
graph_bundle_type
<
oqgraph3
::
graph
>
{
typedef
no_graph_bundle
type
;
};
template
<
>
struct
vertex_bundle_type
<
oqgraph3
::
graph
>
{
typedef
no_vertex_bundle
type
;
};
template
<
>
struct
edge_bundle_type
<
oqgraph3
::
graph
>
{
typedef
no_edge_bundle
type
;
};
inline
std
::
pair
<
graph_traits
<
oqgraph3
::
graph
>::
out_edge_iterator
,
graph_traits
<
oqgraph3
::
graph
>::
out_edge_iterator
>
out_edges
(
graph_traits
<
oqgraph3
::
graph
>::
vertex_descriptor
v
,
const
oqgraph3
::
graph
&
)
{
const
oqgraph3
::
vertex_info
::
edge_list_type
&
iter
=
v
->
out_edges
();
return
std
::
make_pair
(
graph_traits
<
oqgraph3
::
graph
>::
out_edge_iterator
(
iter
.
begin
(),
v
),
graph_traits
<
oqgraph3
::
graph
>::
out_edge_iterator
(
iter
.
end
(),
v
));
}
inline
std
::
pair
<
graph_traits
<
oqgraph3
::
graph
>::
in_edge_iterator
,
graph_traits
<
oqgraph3
::
graph
>::
in_edge_iterator
>
in_edges
(
graph_traits
<
oqgraph3
::
graph
>::
vertex_descriptor
v
,
const
oqgraph3
::
graph
&
)
{
const
oqgraph3
::
vertex_info
::
edge_list_type
&
iter
=
v
->
out_edges
();
return
std
::
make_pair
(
graph_traits
<
oqgraph3
::
graph
>::
in_edge_iterator
(
iter
.
begin
(),
v
),
graph_traits
<
oqgraph3
::
graph
>::
in_edge_iterator
(
iter
.
end
(),
v
));
}
// EdgeListGraph concepts
inline
std
::
pair
<
graph_traits
<
oqgraph3
::
graph
>::
edge_iterator
,
graph_traits
<
oqgraph3
::
graph
>::
edge_iterator
>
edges
(
const
oqgraph3
::
graph
&
_g
)
{
oqgraph3
::
graph
&
g
=
const_cast
<
oqgraph3
::
graph
&>
(
_g
);
return
std
::
make_pair
(
graph_traits
<
oqgraph3
::
graph
>::
edge_iterator
(
oqgraph3
::
row_cursor
(
&
g
).
first
()),
graph_traits
<
oqgraph3
::
graph
>::
edge_iterator
(
oqgraph3
::
row_cursor
(
&
g
).
end
()));
}
inline
std
::
pair
<
graph_traits
<
oqgraph3
::
graph
>::
vertex_iterator
,
graph_traits
<
oqgraph3
::
graph
>::
vertex_iterator
>
vertices
(
const
oqgraph3
::
graph
&
g
)
{
std
::
pair
<
graph_traits
<
oqgraph3
::
graph
>::
edge_iterator
,
graph_traits
<
oqgraph3
::
graph
>::
edge_iterator
>
epair
=
edges
(
g
);
return
std
::
make_pair
(
graph_traits
<
oqgraph3
::
graph
>::
vertex_iterator
(
epair
.
first
),
graph_traits
<
oqgraph3
::
graph
>::
vertex_iterator
(
epair
.
second
));
}
inline
graph_traits
<
oqgraph3
::
graph
>::
vertices_size_type
num_vertices
(
const
oqgraph3
::
graph
&
g
)
{
std
::
size_t
count
=
0
;
for
(
std
::
pair
<
graph_traits
<
oqgraph3
::
graph
>::
vertex_iterator
,
graph_traits
<
oqgraph3
::
graph
>::
vertex_iterator
>
i
=
vertices
(
g
);
i
.
first
!=
i
.
second
;
++
i
.
first
)
{
++
count
;
}
return
count
;
}
template
<
>
struct
property_map
<
oqgraph3
::
graph
,
edge_weight_t
>
{
typedef
void
type
;
typedef
oqgraph3
::
edge_weight_property_map
const_type
;
};
template
<
>
struct
property_map
<
oqgraph3
::
graph
,
vertex_index_t
>
{
typedef
void
type
;
typedef
oqgraph3
::
vertex_index_property_map
const_type
;
};
template
<
>
struct
property_map
<
oqgraph3
::
graph
,
edge_index_t
>
{
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
property_map
<
oqgraph3
::
graph
,
edge_weight_t
>::
const_type
::
key_type
&
key
)
{
return
oqgraph3
::
row_cursor
(
key
,
const_cast
<
oqgraph3
::
graph
*>
(
&
g
))
->
_weight
;
}
inline
property_map
<
oqgraph3
::
graph
,
edge_weight_t
>::
const_type
get
(
edge_weight_t
,
const
oqgraph3
::
graph
&
g
)
{
return
property_map
<
oqgraph3
::
graph
,
edge_weight_t
>::
const_type
(
g
);
}
inline
property_map
<
oqgraph3
::
graph
,
edge_weight_t
>::
const_type
::
reference
get
(
property_map
<
oqgraph3
::
graph
,
edge_weight_t
>::
const_type
p
,
const
property_map
<
oqgraph3
::
graph
,
edge_weight_t
>::
const_type
::
key_type
&
key
)
{
return
oqgraph3
::
row_cursor
(
key
,
const_cast
<
oqgraph3
::
graph
*>
(
&
p
.
_g
))
->
_weight
;
}
inline
property_map
<
oqgraph3
::
graph
,
edge_index_t
>::
const_type
::
reference
get
(
edge_index_t
,
const
oqgraph3
::
graph
&
,
const
property_map
<
oqgraph3
::
graph
,
edge_index_t
>::
const_type
::
key_type
&
key
)
{
return
key
->
_ref
;
}
inline
property_map
<
oqgraph3
::
graph
,
edge_index_t
>::
const_type
get
(
edge_index_t
,
const
oqgraph3
::
graph
&
g
)
{
return
property_map
<
oqgraph3
::
graph
,
edge_index_t
>::
const_type
(
g
);
}
inline
property_map
<
oqgraph3
::
graph
,
edge_index_t
>::
const_type
::
reference
get
(
property_map
<
oqgraph3
::
graph
,
edge_index_t
>::
const_type
,
const
property_map
<
oqgraph3
::
graph
,
edge_index_t
>::
const_type
::
key_type
&
key
)
{
return
key
->
_ref
;
}
inline
property_map
<
oqgraph3
::
graph
,
vertex_index_t
>::
const_type
::
reference
get
(
vertex_index_t
,
const
oqgraph3
::
graph
&
,
const
property_map
<
oqgraph3
::
graph
,
vertex_index_t
>::
const_type
::
key_type
&
key
)
{
return
key
->
id
;
}
inline
property_map
<
oqgraph3
::
graph
,
vertex_index_t
>::
const_type
get
(
vertex_index_t
,
const
oqgraph3
::
graph
&
g
)
{
return
property_map
<
oqgraph3
::
graph
,
vertex_index_t
>::
const_type
(
g
);
}
inline
property_map
<
oqgraph3
::
graph
,
vertex_index_t
>::
const_type
::
reference
get
(
property_map
<
oqgraph3
::
graph
,
vertex_index_t
>::
const_type
,
const
property_map
<
oqgraph3
::
graph
,
vertex_index_t
>::
const_type
::
key_type
&
key
)
{
return
key
->
id
;
}
inline
optional
<
graph_traits
<
oqgraph3
::
graph
>::
vertex_descriptor
>
find_vertex
(
oqgraph3
::
vertex_id
id
,
const
oqgraph3
::
graph
&
g
)
{
graph_traits
<
oqgraph3
::
graph
>::
vertex_descriptor
tmp
(
const_cast
<
oqgraph3
::
graph
&>
(
g
).
vertex
(
id
));
if
(
tmp
)
return
tmp
;
else
return
none
;
}
}
#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_edge_iterator,out_edge_iterator>
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_edge_iterator,in_edge_iterator>
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_descriptor, bool> 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<edge_iterator,edge_iterator>
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<open_query::OQGraph, edge_weight_t>
{
typedef void type;
typedef open_query::edge_weight_property_map const_type;
};
template<>
struct property_map<open_query::OQGraph, vertex_index_t>
{
typedef void type;
typedef open_query::vertex_index_property_map const_type;
};
template<>
struct property_map<open_query::OQGraph, edge_index_t>
{
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<open_query::OQGraph, edge_weight_t>::const_type(); }
property_map<
open_query::OQGraph,
edge_weight_t>::const_type::reference
get(property_map<open_query::OQGraph,
edge_weight_t>::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<open_query::OQGraph, edge_index_t>::const_type
get(edge_index_t, const open_query::OQGraph&)
{ return property_map<open_query::OQGraph, edge_index_t>::const_type(); }
property_map<open_query::OQGraph, edge_index_t>::const_type::reference
get(property_map<open_query::OQGraph, edge_index_t>::const_type,
const property_map<open_query::OQGraph, edge_index_t>::const_type::key_type& key)
{ return key->_ref; }
property_map<open_query::OQGraph, vertex_index_t>::const_type::reference
get(vertex_index_t, const open_query::OQGraph&,
const property_map<open_query::OQGraph, vertex_index_t>::const_type::key_type& key)
{ return key->id; }
property_map<open_query::OQGraph, vertex_index_t>::const_type
get(vertex_index_t, const open_query::OQGraph&)
{ return property_map<open_query::OQGraph, vertex_index_t>::const_type(); }
property_map<open_query::OQGraph, vertex_index_t>::const_type::reference
get(property_map<open_query::OQGraph, vertex_index_t>::const_type,
const property_map<open_query::OQGraph, vertex_index_t>::const_type::key_type& key)
{ return key->id; }
optional<open_query::OQGraph::vertex_descriptor>
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<open_query::OQGraph::edge_descriptor, bool>
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
storage/oqgraph/oqgraph_thunk.cc
0 → 100644
View file @
2037f387
/* Copyright (C) 2009-2011 Arjen G Lentz & Antony T Curtis for Open Query
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* ======================================================================
Open Query Graph Computation Engine, based on a concept by Arjen Lentz
Mk.III implementation by Antony Curtis & Arjen Lentz
For more information, documentation, support, enhancement engineering,
and non-GPL licensing, see http://openquery.com/graph
or contact graph@openquery.com
For packaged binaries, see http://ourdelta.org
======================================================================
*/
#include "oqgraph_thunk.h"
#include <boost/tuple/tuple.hpp>
#define MYSQL_SERVER
#include "mysql_priv.h"
oqgraph3
::
vertex_info
::~
vertex_info
()
{
}
void
oqgraph3
::
vertex_info
::
release
()
{
if
(
!--
(
_ref_count
))
{
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
;
}
}
}
oqgraph3
::
edge_key
::~
edge_key
()
{
}
void
oqgraph3
::
edge_key
::
release
()
const
{
if
(
!--
(
_ref_count
))
{
oqgraph3
::
graph
&
cache
=
*
_cache
;
oqgraph3
::
graph
::
edge_cache_type
::
const_iterator
it
;
if
(
!
_on_gc
)
{
cache
.
_gc_edges
.
push
(
const_cast
<
edge_key
*>
(
this
));
_on_gc
=
true
;
}
while
(
!
cache
.
_gc_running
&&
cache
.
_gc_edges
.
size
()
>
512
)
{
cache
.
_gc_running
=
true
;
if
(
cache
.
_gc_edges
.
front
()
->
_ref_count
||
(
it
=
cache
.
_cache_edges
.
find
(
*
cache
.
_gc_edges
.
front
()))
==
cache
.
_cache_edges
.
end
())
{
cache
.
_gc_edges
.
front
()
->
_on_gc
=
false
;
}
else
{
cache
.
_cache_edges
.
quick_erase
(
it
);
}
cache
.
_gc_edges
.
pop
();
cache
.
_gc_running
=
false
;
}
}
}
oqgraph3
::
graph
::
graph
(
::
TABLE
*
table
,
::
Field
*
source
,
::
Field
*
target
,
::
Field
*
weight
)
:
_gc_running
(
false
)
,
_ref_count
(
0
)
,
_table
(
table
)
,
_source
(
source
)
,
_target
(
target
)
,
_weight
(
weight
)
{
bitmap_set_bit
(
table
->
read_set
,
source
->
field_index
);
bitmap_set_bit
(
table
->
read_set
,
target
->
field_index
);
if
(
weight
)
bitmap_set_bit
(
table
->
read_set
,
weight
->
field_index
);
table
->
file
->
column_bitmaps_signal
();
}
oqgraph3
::
graph
::~
graph
()
{
}
oqgraph3
::
row_cursor
&
oqgraph3
::
row_cursor
::
operator
++
()
{
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
);
if
(
table
.
file
->
ha_index_read_map
(
table
.
record
[
0
],
reinterpret_cast
<
const
uchar
*>
(
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
<
uchar
*>
(
const_cast
<
char
*>
(
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
=
&
current
->
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
()
{
TABLE
&
table
=
*
_cache
->
_table
;
printf
(
"%s:%d
\n
"
,
__func__
,
__LINE__
);
table
.
file
->
ha_index_init
(
0
,
1
);
printf
(
"%s:%d
\n
"
,
__func__
,
__LINE__
);
if
(
!
table
.
file
->
ha_index_first
(
table
.
record
[
0
]))
{
printf
(
"%s:%d
\n
"
,
__func__
,
__LINE__
);
update_virtual_fields
(
table
.
in_use
,
&
table
);
printf
(
"%s:%d
\n
"
,
__func__
,
__LINE__
);
edge_key
tmp
(
table
.
key_info
->
key_length
,
_cache
);
printf
(
"%s:%d
\n
"
,
__func__
,
__LINE__
);
key_copy
(
reinterpret_cast
<
uchar
*>
(
const_cast
<
char
*>
(
tmp
.
_ref
.
data
())),
table
.
record
[
0
],
table
.
key_info
,
tmp
.
_ref
.
size
(),
true
);
printf
(
"%s:%d
\n
"
,
__func__
,
__LINE__
);
graph
::
edge_cache_type
::
iterator
found
=
_cache
->
_cache_edges
.
find
(
tmp
);
printf
(
"%s:%d
\n
"
,
__func__
,
__LINE__
);
if
(
found
!=
_cache
->
_cache_edges
.
end
())
{
// we already had a row
printf
(
"%s:%d
\n
"
,
__func__
,
__LINE__
);
_current
.
reset
(
&
found
->
first
);
}
else
{
printf
(
"%s:%d
\n
"
,
__func__
,
__LINE__
);
_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
);
}
}
printf
(
"%s:%d
\n
"
,
__func__
,
__LINE__
);
table
.
file
->
ha_index_end
();
printf
(
"%s:%d
\n
"
,
__func__
,
__LINE__
);
return
*
this
;
}
oqgraph3
::
row_cursor
&
oqgraph3
::
row_cursor
::
last
()
{
TABLE
&
table
=
*
_cache
->
_table
;
table
.
file
->
ha_index_init
(
0
,
1
);
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
<
uchar
*>
(
const_cast
<
char
*>
(
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
--
()
{
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
);
if
(
table
.
file
->
ha_index_read_map
(
table
.
record
[
0
],
reinterpret_cast
<
const
uchar
*>
(
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
<
uchar
*>
(
const_cast
<
char
*>
(
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
=
&
current
->
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
)
{
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
;
}
if
(
table
.
file
->
ha_index_read_map
(
table
.
record
[
0
],
reinterpret_cast
<
const
uchar
*>
(
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
;
}
if
(
table
.
file
->
ha_index_read_map
(
table
.
record
[
0
],
reinterpret_cast
<
const
uchar
*>
(
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
<
uchar
*>
(
const_cast
<
char
*>
(
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
=
&
current
->
first
.
_ref
;
current
->
second
.
_prev
=
&
found
->
first
.
_ref
;
}
current
=
found
;
}
else
{
if
(
!
index_started
)
return
*
this
;
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
<
uchar
*>
(
const_cast
<
char
*>
(
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
)
{
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
;
}
if
(
table
.
file
->
ha_index_read_map
(
table
.
record
[
0
],
reinterpret_cast
<
const
uchar
*>
(
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
;
}
if
(
table
.
file
->
ha_index_read_map
(
table
.
record
[
0
],
reinterpret_cast
<
const
uchar
*>
(
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
<
uchar
*>
(
const_cast
<
char
*>
(
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
=
&
current
->
first
.
_ref
;
current
->
second
.
_prev
=
&
found
->
first
.
_ref
;
}
current
=
found
;
}
else
{
if
(
!
index_started
)
return
first
();
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
<
uchar
*>
(
const_cast
<
char
*>
(
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
)
{
vertex_cache_type
::
const_iterator
found
=
_cache_vertices
.
find
(
vertex_info
(
id
));
if
(
_cache_vertices
.
end
()
!=
found
)
return
vertex_descriptor
(
const_cast
<
vertex_info
*>
(
found
.
operator
->
()));
return
vertex_descriptor
(
const_cast
<
vertex_info
*>
(
_cache_vertices
.
insert
(
vertex_info
(
id
,
this
)).
first
.
operator
->
()));
}
oqgraph3
::
edge_descriptor
oqgraph3
::
graph
::
edge
(
const
edge_key
&
key
)
{
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
);
if
(
table
.
file
->
ha_index_read_map
(
table
.
record
[
0
],
reinterpret_cast
<
const
uchar
*>
(
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
)
{
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_part
[
0
].
store_length
+
key_info
->
key_part
[
1
].
store_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
);
if
(
!
table
.
file
->
ha_index_read_map
(
table
.
record
[
0
],
key_prefix
,
(
key_part_map
)
3
,
HA_READ_KEY_EXACT
))
{
// 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
<
uchar
*>
(
const_cast
<
char
*>
(
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
()
{
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_part
[
0
].
store_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
);
if
(
!
table
.
file
->
ha_index_read_map
(
table
.
record
[
0
],
key
,
(
key_part_map
)
1
,
HA_READ_KEY_EXACT
))
{
// 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
<
uchar
*>
(
const_cast
<
char
*>
(
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
);
}
while
(
!
table
.
file
->
ha_index_next_same
(
table
.
record
[
0
],
key
,
key_len
));
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
()
{
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_part
[
0
].
store_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
);
if
(
!
table
.
file
->
ha_index_read_map
(
table
.
record
[
0
],
key
,
(
key_part_map
)
1
,
HA_READ_KEY_EXACT
))
{
// 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
<
uchar
*>
(
const_cast
<
char
*>
(
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
);
}
while
(
!
table
.
file
->
ha_index_next_same
(
table
.
record
[
0
],
key
,
key_len
));
table
.
file
->
ha_index_end
();
my_afree
(
key
);
break
;
}
table
.
file
->
ha_index_end
();
}
}
}
return
*
_in_edges
;
}
std
::
size_t
oqgraph3
::
vertex_info
::
degree
()
{
return
out_edges
().
size
()
+
in_edges
().
size
();
}
oqgraph3
::
degree_size_type
oqgraph3
::
vertex_descriptor
::
in_degree
()
const
{
return
(
*
this
)
->
in_edges
().
size
();
}
oqgraph3
::
degree_size_type
oqgraph3
::
vertex_descriptor
::
out_degree
()
const
{
return
(
*
this
)
->
out_edges
().
size
();
}
oqgraph3
::
vertex_descriptor
oqgraph3
::
edge_descriptor
::
source
()
const
{
return
(
*
this
)
->
_cache
->
vertex
(
oqgraph3
::
row_cursor
(
*
this
,
(
*
this
)
->
_cache
)
->
first
);
}
oqgraph3
::
vertex_descriptor
oqgraph3
::
edge_descriptor
::
target
()
const
{
return
(
*
this
)
->
_cache
->
vertex
(
oqgraph3
::
row_cursor
(
*
this
,
(
*
this
)
->
_cache
)
->
second
);
}
storage/oqgraph/oqgraph_thunk.h
0 → 100644
View file @
2037f387
/* Copyright (C) 2009-2011 Arjen G Lentz & Antony T Curtis for Open Query
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* ======================================================================
Open Query Graph Computation Engine, based on a concept by Arjen Lentz
Mk.III implementation by Antony Curtis & Arjen Lentz
For more information, documentation, support, enhancement engineering,
and non-GPL licensing, see http://openquery.com/graph
or contact graph@openquery.com
For packaged binaries, see http://ourdelta.org
======================================================================
*/
#pragma once
#include <list>
#include <queue>
#include <string>
#include <utility>
#include <boost/intrusive_ptr.hpp>
#include <boost/optional.hpp>
#include <boost/unordered_map.hpp>
#include <boost/unordered_set.hpp>
#include <boost/pending/queue.hpp>
#include <boost/ptr_container/ptr_deque.hpp>
#include "graphcore-types.h"
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
;
typedef
boost
::
intrusive_ptr
<
graph
>
graph_ptr
;
struct
edge_key
{
typedef
std
::
string
ref_type
;
ref_type
_ref
;
mutable
int
_ref_count
;
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
)
{
}
template
<
typename
C
,
typename
T
,
typename
A
>
explicit
edge_key
(
const
std
::
basic_string
<
C
,
T
,
A
>&
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
)
{
}
edge_key
(
const
edge_key
&
src
,
const
graph_ptr
&
cache
)
:
_ref
(
src
.
_ref
)
,
_ref_count
(
0
)
,
_cache
(
cache
)
{
}
~
edge_key
();
void
release
()
const
;
friend
void
intrusive_ptr_add_ref
(
const
edge_key
*
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_key
::
ref_type
>
edge_list_type
;
const
vertex_id_type
id
;
mutable
int
_ref_count
;
boost
::
optional
<
edge_list_type
>
_in_edges
;
boost
::
optional
<
edge_list_type
>
_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_info
>
{
vertex_descriptor
()
:
boost
::
intrusive_ptr
<
vertex_info
>
()
{
}
vertex_descriptor
(
vertex_info
*
v
)
:
boost
::
intrusive_ptr
<
vertex_info
>
(
v
)
{
}
vertex_descriptor
(
const
vertex_descriptor
&
v
)
:
boost
::
intrusive_ptr
<
vertex_info
>
(
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
();
}
};
struct
edge_descriptor
:
public
boost
::
intrusive_ptr
<
const
edge_key
>
{
edge_descriptor
()
:
boost
::
intrusive_ptr
<
const
edge_key
>
()
{
}
edge_descriptor
(
const
edge_key
*
e
)
:
boost
::
intrusive_ptr
<
const
edge_key
>
(
e
)
{
}
edge_descriptor
(
const
edge_descriptor
&
e
)
:
boost
::
intrusive_ptr
<
const
edge_key
>
(
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
<
vertex_id
,
vertex_id
>
{
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
<
first_type
,
second_type
>
(
source
,
target
)
,
_weight
(
weight
)
,
_prev
(
prev
)
,
_next
(
next
)
{
}
};
namespace
internal
{
template
<
typename
Value
>
struct
hash
:
public
std
::
unary_function
<
Value
,
std
::
size_t
>
{
boost
::
hash
<
Value
>
ref_hasher
;
std
::
size_t
operator
()(
const
Value
&
v
)
const
{
return
ref_hasher
(
v
);
}
};
template
<
typename
Value
>
struct
equal_to
:
public
std
::
binary_function
<
Value
,
Value
,
bool
>
{
std
::
equal_to
<
Value
>
ref_equals
;
bool
operator
()(
const
Value
&
x
,
const
Value
&
y
)
const
{
return
ref_equals
(
x
,
y
);
}
};
template
<
>
struct
hash
<
edge_key
>
:
public
std
::
unary_function
<
edge_key
,
std
::
size_t
>
{
boost
::
hash
<
edge_key
::
ref_type
>
ref_hasher
;
std
::
size_t
operator
()(
edge_key
const
&
v
)
const
{
return
ref_hasher
(
v
.
_ref
);
}
};
template
<
>
struct
hash
<
const
edge_key
*>
:
public
std
::
unary_function
<
const
edge_key
*
,
std
::
size_t
>
{
boost
::
hash
<
edge_key
::
ref_type
>
ref_hasher
;
std
::
size_t
operator
()(
const
edge_key
*
const
&
v
)
const
{
return
ref_hasher
(
v
->
_ref
);
}
};
template
<
>
struct
hash
<
vertex_info
>
:
public
std
::
unary_function
<
vertex_info
,
std
::
size_t
>
{
boost
::
hash
<
vertex_info
::
vertex_id_type
>
id_hasher
;
std
::
size_t
operator
()(
vertex_info
const
&
v
)
const
{
return
id_hasher
(
v
.
id
);
}
};
template
<
>
struct
equal_to
<
edge_key
>
:
public
std
::
binary_function
<
edge_key
,
edge_key
,
bool
>
{
std
::
equal_to
<
edge_key
::
ref_type
>
ref_equals
;
bool
operator
()(
const
edge_key
&
x
,
const
edge_key
&
y
)
const
{
return
ref_equals
(
x
.
_ref
,
y
.
_ref
);
}
};
template
<
>
struct
equal_to
<
const
edge_key
*>
:
public
std
::
binary_function
<
const
edge_key
*
,
edge_key
,
bool
>
{
std
::
equal_to
<
edge_key
::
ref_type
>
ref_equals
;
bool
operator
()(
const
edge_key
*&
x
,
const
edge_key
*&
y
)
const
{
return
ref_equals
(
x
->
_ref
,
y
->
_ref
);
}
};
template
<
>
struct
equal_to
<
vertex_info
>
:
public
std
::
binary_function
<
vertex_info
,
vertex_info
,
bool
>
{
std
::
equal_to
<
vertex_info
::
vertex_id_type
>
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
<
edge_key
>
,
internal
::
equal_to
<
edge_key
>
>
edge_cache_type
;
typedef
boost
::
unordered_set
<
vertex_info
,
internal
::
hash
<
vertex_info
>
,
internal
::
equal_to
<
vertex_info
>
>
vertex_cache_type
;
bool
_gc_running
;
mutable
int
_ref_count
;
edge_cache_type
_cache_edges
;
boost
::
queue
<
edge_key
*>
_gc_edges
;
vertex_cache_type
_cache_vertices
;
boost
::
queue
<
vertex_info
*>
_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
;
friend
edges_size_type
num_edges
(
const
graph
&
g
)
{
return
g
.
num_edges
();
}
friend
void
intrusive_ptr_add_ref
(
graph
*
ptr
)
{
ptr
->
_ref_count
++
;
}
friend
void
intrusive_ptr_release
(
graph
*
ptr
)
{
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
;
}
};
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment