1
0
Fork 0

Merge branch 'devel' of github.com:triAGENS/ArangoDB into devel

This commit is contained in:
Frank Celler 2013-01-13 13:50:51 +01:00
commit bad4c293ad
4 changed files with 159 additions and 38 deletions

View File

@ -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!

View File

@ -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

View File

@ -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;

View File

@ -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 ];
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////