mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'devel' of github.com:triAGENS/ArangoDB into devel
This commit is contained in:
commit
bad4c293ad
|
@ -327,6 +327,49 @@ static bool EqualName (TRI_associative_pointer_t* array,
|
|||
/// @{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief check if we have a matching restriction we can use to optimise
|
||||
/// a PATHS query
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool CheckPathRestriction (TRI_aql_field_access_t* fieldAccess,
|
||||
TRI_aql_context_t* const context,
|
||||
TRI_aql_node_t* vertexCollection,
|
||||
const char* lookFor,
|
||||
char* name,
|
||||
const size_t n) {
|
||||
size_t len;
|
||||
|
||||
assert(fieldAccess);
|
||||
assert(lookFor);
|
||||
|
||||
len = strlen(lookFor);
|
||||
if (len == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (n > fieldAccess->_variableNameLength + len &&
|
||||
memcmp((void*) lookFor, (void*) name, len) == 0) {
|
||||
// we'll now patch the collection hint
|
||||
TRI_aql_collection_hint_t* hint;
|
||||
|
||||
// field name is collection.source.XXX, e.g. users.source._id
|
||||
LOG_DEBUG("optimising PATHS() field access %s", fieldAccess->_fullName);
|
||||
|
||||
// we can now modify this fieldaccess in place to collection.XXX, e.g. users._id
|
||||
// copy trailing \0 byte as well
|
||||
memmove(name, name + len - 1, n - fieldAccess->_variableNameLength - len + 2);
|
||||
|
||||
// attach the modified fieldaccess to the collection
|
||||
hint = (TRI_aql_collection_hint_t*) (TRI_AQL_NODE_DATA(vertexCollection));
|
||||
hint->_ranges = TRI_AddAccessAql(context, hint->_ranges, fieldAccess);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief optimise callback function for PATHS() AQL function
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -340,8 +383,6 @@ static void OptimisePaths (const TRI_aql_node_t* const fcallNode,
|
|||
TRI_aql_node_t* direction;
|
||||
char* directionValue;
|
||||
char* name;
|
||||
const char* lookFor;
|
||||
size_t len;
|
||||
size_t n;
|
||||
|
||||
args = TRI_AQL_NODE_MEMBER(fcallNode, 0);
|
||||
|
@ -366,37 +407,17 @@ static void OptimisePaths (const TRI_aql_node_t* const fcallNode,
|
|||
|
||||
// try to optimise the vertex collection access
|
||||
if (TRI_EqualString(directionValue, "outbound")) {
|
||||
lookFor = ".source.";
|
||||
len = strlen(lookFor);
|
||||
CheckPathRestriction(fieldAccess, context, vertexCollection, ".source.", name, n);
|
||||
}
|
||||
else if (TRI_EqualString(directionValue, "inbound")) {
|
||||
lookFor = ".destination.";
|
||||
len = strlen(lookFor);
|
||||
CheckPathRestriction(fieldAccess, context, vertexCollection, ".destination.", name, n);
|
||||
}
|
||||
else {
|
||||
// "any" will not be optimised
|
||||
lookFor = NULL;
|
||||
len = 0;
|
||||
}
|
||||
|
||||
if (len > 0 &&
|
||||
n > fieldAccess->_variableNameLength + len &&
|
||||
memcmp((void*) lookFor, (void*) name, len) == 0) {
|
||||
// we'll now patch the collection hint
|
||||
TRI_aql_collection_hint_t* hint;
|
||||
|
||||
// field name is collection.source.XXX, e.g. users.source._id
|
||||
LOG_DEBUG("optimising PATHS() field access %s", fieldAccess->_fullName);
|
||||
|
||||
// we can now modify this fieldaccess in place to collection.XXX, e.g. users._id
|
||||
// copy trailing \0 byte as well
|
||||
memmove(name, name + len - 1, n - fieldAccess->_variableNameLength - len + 2);
|
||||
|
||||
// attach the modified fieldaccess to the collection
|
||||
hint = (TRI_aql_collection_hint_t*) (TRI_AQL_NODE_DATA(vertexCollection));
|
||||
hint->_ranges = TRI_AddAccessAql(context, hint->_ranges, fieldAccess);
|
||||
else if (TRI_EqualString(directionValue, "any")) {
|
||||
CheckPathRestriction(fieldAccess, context, vertexCollection, ".source.", name, n);
|
||||
CheckPathRestriction(fieldAccess, context, vertexCollection, ".destination.", name, n);
|
||||
}
|
||||
|
||||
// check if we have a filter on LENGTH(edges)
|
||||
if (args->_members._length <= 4 &&
|
||||
TRI_EqualString(name, ".edges.LENGTH()")) {
|
||||
// length restriction, can only be applied if length parameters are not already set
|
||||
|
@ -603,6 +624,7 @@ TRI_associative_pointer_t* TRI_InitialiseFunctionsAql (void) {
|
|||
|
||||
// graph functions
|
||||
REGISTER_FUNCTION("PATHS", "GRAPH_PATHS", false, false, "c,h|s,b", &OptimisePaths);
|
||||
REGISTER_FUNCTION("TRAVERSE", "GRAPH_TRAVERSE", false, false, "h,h,s,s,a", NULL);
|
||||
|
||||
// misc functions
|
||||
REGISTER_FUNCTION("FAIL", "FAIL", false, false, "|s", NULL); // FAIL is non-deterministic, otherwise query optimisation will fail!
|
||||
|
|
|
@ -678,10 +678,10 @@ static TRI_datafile_t* OpenDatafile (char const* filename, bool ignoreErrors) {
|
|||
|
||||
// check the maximal size
|
||||
if (size > header._maximalSize) {
|
||||
LOG_WARNING("datafile '%s' has size '%u', but maximal size is '%u'",
|
||||
filename,
|
||||
(unsigned int) size,
|
||||
(unsigned int) header._maximalSize);
|
||||
LOG_DEBUG("datafile '%s' has size '%u', but maximal size is '%u'",
|
||||
filename,
|
||||
(unsigned int) size,
|
||||
(unsigned int) header._maximalSize);
|
||||
}
|
||||
|
||||
// map datafile into memory
|
||||
|
|
|
@ -430,8 +430,13 @@ function CollectionOutboundExpander (config, vertex, path) {
|
|||
}
|
||||
|
||||
outEdges.forEach(function (edge) {
|
||||
var vertex = internal.db._document(edge._to);
|
||||
connections.push({ edge: edge, vertex: vertex });
|
||||
try {
|
||||
var vertex = internal.db._document(edge._to);
|
||||
connections.push({ edge: edge, vertex: vertex });
|
||||
}
|
||||
catch (e) {
|
||||
// continue even in the face of non-existing documents
|
||||
}
|
||||
});
|
||||
|
||||
return connections;
|
||||
|
@ -450,8 +455,13 @@ function CollectionInboundExpander (config, vertex, path) {
|
|||
}
|
||||
|
||||
inEdges.forEach(function (edge) {
|
||||
var vertex = internal.db._document(edge._from);
|
||||
connections.push({ edge: edge, vertex: vertex });
|
||||
try {
|
||||
var vertex = internal.db._document(edge._from);
|
||||
connections.push({ edge: edge, vertex: vertex });
|
||||
}
|
||||
catch (e) {
|
||||
// continue even in the face of non-existing documents
|
||||
}
|
||||
});
|
||||
|
||||
return connections;
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var internal = require("internal");
|
||||
var traversal = require("org/arangodb/graph/traversal");
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief type weight used for sorting and comparing
|
||||
|
@ -2209,8 +2210,6 @@ function AHUACATL_GRAPH_PATHS () {
|
|||
followCycles : followCycles
|
||||
};
|
||||
|
||||
// TODO: restrict allEdges to edges with certain _from values etc.
|
||||
|
||||
var result = [ ];
|
||||
var n = vertices.length;
|
||||
for (var i = 0; i < n; ++i) {
|
||||
|
@ -2304,6 +2303,96 @@ function AHUACATL_GRAPH_SUBNODES (searchAttributes, vertexId, visited, edges, ve
|
|||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief visitor callback function for traversal
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function AHUACATL_TRAVERSE_VISITOR (config, result, vertex, path) {
|
||||
result.vertices.push(AHUACATL_CLONE(vertex));
|
||||
if (config.trackPaths) {
|
||||
result.paths.push(AHUACATL_CLONE(path));
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief filter callback function for traversal
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function AHUACATL_TRAVERSE_FILTER (config, vertex, path) {
|
||||
if (config.maxDepth != null && config.maxDepth != undefined && path.edges.length > config.maxDepth) {
|
||||
return "prune";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief traverse a graph
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function AHUACATL_GRAPH_TRAVERSE () {
|
||||
var vertexCollection = AHUACATL_COLLECTION(arguments[0]);
|
||||
var edgeCollection = AHUACATL_COLLECTION(arguments[1]);
|
||||
var startVertex = arguments[2];
|
||||
var direction = arguments[3];
|
||||
var params = arguments[4];
|
||||
|
||||
function validate (value, map) {
|
||||
if (value == null || value == undefined) {
|
||||
// use first key from map
|
||||
for (var m in map) {
|
||||
if (map.hasOwnProperty(m)) {
|
||||
value = m;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (typeof value === 'string') {
|
||||
value = value.toLowerCase().replace(/-/, "");
|
||||
if (map[value] != null) {
|
||||
return map[value];
|
||||
}
|
||||
}
|
||||
|
||||
AHUACATL_THROW(internal.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, "TRAVERSE");
|
||||
}
|
||||
|
||||
var config = {
|
||||
edgeCollection: edgeCollection,
|
||||
strategy: validate(params.strategy, {
|
||||
'depthfirst': traversal.Traverser.DEPTH_FIRST,
|
||||
'breadthfirst': traversal.Traverser.BREADTH_FIRST
|
||||
}),
|
||||
order: validate(params.order, {
|
||||
'preorder': traversal.Traverser.PRE_ORDER,
|
||||
'postorder': traversal.Traverser.POST_ORDER
|
||||
}),
|
||||
itemOrder: validate(params.itemOrder, {
|
||||
'forward': traversal.Traverser.FORWARD,
|
||||
'backward': traversal.Traverser.BACKWARD
|
||||
}),
|
||||
maxDepth: params.maxDepth,
|
||||
trackPaths: params.returnPaths || false,
|
||||
visitor: AHUACATL_TRAVERSE_VISITOR,
|
||||
filter: AHUACATL_TRAVERSE_FILTER,
|
||||
expander: validate(direction, {
|
||||
'outbound': traversal.CollectionOutboundExpander,
|
||||
'inbound': traversal.CollectionInboundExpander
|
||||
})
|
||||
};
|
||||
|
||||
var result = {
|
||||
vertices: [ ]
|
||||
};
|
||||
if (config.trackPaths) {
|
||||
result.paths = [ ];
|
||||
}
|
||||
|
||||
var traverser = new traversal.Traverser(config);
|
||||
traverser.traverse(result, vertexCollection.document(startVertex));
|
||||
|
||||
return [ result ];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
Loading…
Reference in New Issue