1
0
Fork 0

added possibility to kill JS traversals

This commit is contained in:
Jan Steemann 2015-03-20 23:05:41 +01:00
parent 075e1a0fb4
commit d63f47e840
7 changed files with 152 additions and 73 deletions

View File

@ -316,18 +316,27 @@ TRI_json_t* Executor::executeExpression (Query* query,
TRI_ASSERT(query != nullptr);
TRI_GET_GLOBALS();
v8::Handle<v8::Value> result;
auto old = v8g->_query;
v8g->_query = static_cast<void*>(query);
TRI_ASSERT(v8g->_query != nullptr);
try {
v8g->_query = static_cast<void*>(query);
TRI_ASSERT(v8g->_query != nullptr);
// execute the function
v8::Handle<v8::Value> args;
v8::Handle<v8::Value> result = v8::Handle<v8::Function>::Cast(func)->Call(v8::Object::New(isolate), 0, &args);
// execute the function
v8::Handle<v8::Value> args;
result = v8::Handle<v8::Function>::Cast(func)->Call(v8::Object::New(isolate), 0, &args);
v8g->_query = old;
v8g->_query = old;
// exit if execution raised an error
HandleV8Error(tryCatch, result);
// exit if execution raised an error
HandleV8Error(tryCatch, result);
}
catch (...) {
v8g->_query = old;
throw;
}
if (result->IsUndefined()) {
// undefined => null
@ -364,6 +373,7 @@ Function const* Executor::getFunctionByName (std::string const& name) {
void Executor::HandleV8Error (v8::TryCatch& tryCatch,
v8::Handle<v8::Value>& result) {
ISOLATE;
if (tryCatch.HasCaught()) {
// caught a V8 exception
if (! tryCatch.CanContinue()) {

View File

@ -110,49 +110,52 @@ AqlValue V8Expression::execute (v8::Isolate* isolate,
TRI_ASSERT(query != nullptr);
TRI_GET_GLOBALS();
v8::Handle<v8::Value> result;
auto old = v8g->_query;
v8g->_query = static_cast<void*>(query);
TRI_ASSERT(v8g->_query != nullptr);
// set function arguments
v8::Handle<v8::Value> args[] = { values };
try {
v8g->_query = static_cast<void*>(query);
TRI_ASSERT(v8g->_query != nullptr);
// execute the function
v8::TryCatch tryCatch;
// set function arguments
v8::Handle<v8::Value> args[] = { values };
auto func = v8::Local<v8::Function>::New(isolate, _func);
v8::Handle<v8::Value> result = func->Call(func, 1, args);
// execute the function
v8::TryCatch tryCatch;
v8g->_query = old;
auto func = v8::Local<v8::Function>::New(isolate, _func);
result = func->Call(func, 1, args);
Executor::HandleV8Error(tryCatch, result);
v8g->_query = old;
Executor::HandleV8Error(tryCatch, result);
}
catch (...) {
v8g->_query = old;
throw;
}
// no exception was thrown if we get here
TRI_json_t* json = nullptr;
std::unique_ptr<TRI_json_t> json;
if (result->IsUndefined()) {
// expression does not have any (defined) value. replace with null
json = TRI_CreateNullJson(TRI_UNKNOWN_MEM_ZONE);
json.reset(TRI_CreateNullJson(TRI_UNKNOWN_MEM_ZONE));
}
else {
// expression had a result. convert it to JSON
json = TRI_ObjectToJson(isolate, result);
// TODO: json = TRI_SimplifiedObjectToJson(isolate, result);
json.reset(TRI_ObjectToJson(isolate, result));
}
if (json == nullptr) {
if (json.get() == nullptr) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
}
try {
auto j = new triagens::basics::Json(TRI_UNKNOWN_MEM_ZONE, json);
return AqlValue(j);
}
catch (...) {
// prevent memleak
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
throw;
}
auto j = new triagens::basics::Json(TRI_UNKNOWN_MEM_ZONE, json.get());
json.release();
return AqlValue(j);
}
// -----------------------------------------------------------------------------

View File

@ -380,6 +380,7 @@ ApplicationV8::V8Context* ApplicationV8::enterContext (std::string const& name,
v8g->_vocbase = vocbase;
v8g->_allowUseDatabase = allowUseDatabase;
v8g->_query = nullptr;
LOG_TRACE("entering V8 context %d", (int) context->_id);
context->handleGlobalContextMethods();
@ -415,6 +416,7 @@ void ApplicationV8::exitContext (V8Context* context) {
// check for cancelation requests
bool const canceled = v8g->_canceled;
v8g->_canceled = false;
v8g->_query = nullptr;
// exit the context
{

View File

@ -1599,6 +1599,21 @@ static void JS_QueriesKillAql (const v8::FunctionCallbackInfo<v8::Value>& args)
TRI_V8_THROW_EXCEPTION(res);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief whether or not a query is killed
////////////////////////////////////////////////////////////////////////////////
static void JS_QueryIsKilledAql (const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();
v8::HandleScope scope(isolate);
TRI_GET_GLOBALS();
if (v8g->_query != nullptr && static_cast<triagens::aql::Query*>(v8g->_query)->killed()) {
TRI_V8_RETURN_TRUE();
}
TRI_V8_RETURN_FALSE();
}
////////////////////////////////////////////////////////////////////////////////
/// @brief sleeps and checks for query abortion in between
////////////////////////////////////////////////////////////////////////////////
@ -2913,6 +2928,7 @@ void TRI_InitV8VocBridge (v8::Isolate* isolate,
TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("AQL_QUERIES_SLOW"), JS_QueriesSlowAql, true);
TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("AQL_QUERIES_KILL"), JS_QueriesKillAql, true);
TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("AQL_QUERY_SLEEP"), JS_QuerySleepAql, true);
TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("AQL_QUERY_IS_KILLED"), JS_QueryIsKilledAql, true);
TRI_InitV8replication(isolate, context, server, vocbase, loader, threadNumber, v8g);

View File

@ -1,6 +1,6 @@
module.define("org/arangodb/graph/traversal", function(exports, module) {
/*jshint strict: false, unused: false */
/*global require, exports, ArangoClusterComm */
/*global require, exports, ArangoClusterComm, AQL_QUERY_IS_KILLED */
////////////////////////////////////////////////////////////////////////////////
/// @brief Traversal "classes"
@ -45,6 +45,30 @@ var ArangoTraverser;
// --SECTION-- helper functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief whether or not the query was aborted
/// use the AQL_QUERY_IS_KILLED function on the server side, and a dummy
/// function otherwise (ArangoShell etc.)
////////////////////////////////////////////////////////////////////////////////
var throwIfAborted = function () {
};
try {
if (typeof AQL_QUERY_IS_KILLED === "function") {
throwIfAborted = function () {
if (AQL_QUERY_IS_KILLED()) {
var err = new ArangoError();
err.errorNum = arangodb.errors.ERROR_QUERY_KILLED.code;
err.errorMessage = arangodb.errors.ERROR_QUERY_KILLED.message;
throw err;
}
};
}
}
catch (err) {
}
////////////////////////////////////////////////////////////////////////////////
/// @brief clone any object
////////////////////////////////////////////////////////////////////////////////
@ -900,6 +924,8 @@ function breadthFirstSearch () {
throw err;
}
throwIfAborted();
if (current.visit === null || current.visit === undefined) {
current.visit = false;
@ -1009,6 +1035,8 @@ function depthFirstSearch () {
err.errorMessage = arangodb.errors.ERROR_GRAPH_TOO_MANY_ITERATIONS.message;
throw err;
}
throwIfAborted();
// peek at the top of the stack
var current = toVisit[toVisit.length - 1];
@ -1153,6 +1181,8 @@ function dijkstraSearch () {
err.errorMessage = arangodb.errors.ERROR_GRAPH_TOO_MANY_ITERATIONS.message;
throw err;
}
throwIfAborted();
var currentNode = heap.pop();
var i, n;
@ -1291,6 +1321,8 @@ function astarSearch () {
throw err;
}
throwIfAborted();
var currentNode = heap.pop();
var i, n;

View File

@ -1,5 +1,5 @@
/*jshint strict: false, unused: false */
/*global require, exports, ArangoClusterComm */
/*global require, exports, ArangoClusterComm, AQL_QUERY_IS_KILLED */
////////////////////////////////////////////////////////////////////////////////
/// @brief Traversal "classes"
@ -44,6 +44,30 @@ var ArangoTraverser;
// --SECTION-- helper functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief whether or not the query was aborted
/// use the AQL_QUERY_IS_KILLED function on the server side, and a dummy
/// function otherwise (ArangoShell etc.)
////////////////////////////////////////////////////////////////////////////////
var throwIfAborted = function () {
};
try {
if (typeof AQL_QUERY_IS_KILLED === "function") {
throwIfAborted = function () {
if (AQL_QUERY_IS_KILLED()) {
var err = new ArangoError();
err.errorNum = arangodb.errors.ERROR_QUERY_KILLED.code;
err.errorMessage = arangodb.errors.ERROR_QUERY_KILLED.message;
throw err;
}
};
}
}
catch (err) {
}
////////////////////////////////////////////////////////////////////////////////
/// @brief clone any object
////////////////////////////////////////////////////////////////////////////////
@ -899,6 +923,8 @@ function breadthFirstSearch () {
throw err;
}
throwIfAborted();
if (current.visit === null || current.visit === undefined) {
current.visit = false;
@ -1008,6 +1034,8 @@ function depthFirstSearch () {
err.errorMessage = arangodb.errors.ERROR_GRAPH_TOO_MANY_ITERATIONS.message;
throw err;
}
throwIfAborted();
// peek at the top of the stack
var current = toVisit[toVisit.length - 1];
@ -1152,6 +1180,8 @@ function dijkstraSearch () {
err.errorMessage = arangodb.errors.ERROR_GRAPH_TOO_MANY_ITERATIONS.message;
throw err;
}
throwIfAborted();
var currentNode = heap.pop();
var i, n;
@ -1290,6 +1320,8 @@ function astarSearch () {
throw err;
}
throwIfAborted();
var currentNode = heap.pop();
var i, n;

View File

@ -5289,7 +5289,7 @@ function DOCUMENTS_BY_EXAMPLE (collectionList, example) {
return res;
}
function RESOLVE_GRAPH_TO_COLLECTIONS(graph, options) {
function RESOLVE_GRAPH_TO_COLLECTIONS (graph, options, funcname) {
var collections = {};
collections.fromCollections = [];
collections.toCollection = [];
@ -5329,7 +5329,7 @@ function RESOLVE_GRAPH_TO_COLLECTIONS(graph, options) {
);
}
else {
WARN("GRAPH_EDGES", INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH);
WARN(funcname, INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH);
// TODO: check if we need to return more data here
return collections;
}
@ -5340,13 +5340,13 @@ function RESOLVE_GRAPH_TO_COLLECTIONS(graph, options) {
return collections;
}
function RESOLVE_GRAPH_TO_FROM_VERTICES (graphname, options) {
var graph = DOCUMENT_HANDLE("_graphs/" + graphname), collections ;
function RESOLVE_GRAPH_TO_FROM_VERTICES (graphname, options, funcname) {
var graph = DOCUMENT_HANDLE("_graphs/" + graphname), collections;
if (! graph) {
THROW("GRAPH_EDGES", INTERNAL.errors.ERROR_GRAPH_INVALID_GRAPH, "GRAPH_EDGES");
THROW(funcname, INTERNAL.errors.ERROR_GRAPH_INVALID_GRAPH, funcname);
}
collections = RESOLVE_GRAPH_TO_COLLECTIONS(graph, options);
collections = RESOLVE_GRAPH_TO_COLLECTIONS(graph, options, funcname);
var removeDuplicates = function(elem, pos, self) {
return self.indexOf(elem) === pos;
};
@ -5358,13 +5358,13 @@ function RESOLVE_GRAPH_TO_FROM_VERTICES (graphname, options) {
);
}
function RESOLVE_GRAPH_TO_TO_VERTICES (graphname, options) {
function RESOLVE_GRAPH_TO_TO_VERTICES (graphname, options, funcname) {
var graph = DOCUMENT_HANDLE("_graphs/" + graphname), collections ;
if (! graph) {
THROW("GRAPH_EDGES", INTERNAL.errors.ERROR_GRAPH_INVALID_GRAPH, "GRAPH_EDGES");
THROW(funcname, INTERNAL.errors.ERROR_GRAPH_INVALID_GRAPH, funcname);
}
collections = RESOLVE_GRAPH_TO_COLLECTIONS(graph, options);
collections = RESOLVE_GRAPH_TO_COLLECTIONS(graph, options, funcname);
var removeDuplicates = function(elem, pos, self) {
return self.indexOf(elem) === pos;
};
@ -5374,34 +5374,18 @@ function RESOLVE_GRAPH_TO_TO_VERTICES (graphname, options) {
);
}
function RESOLVE_GRAPH_TO_EDGES (graphname, options) {
var graph = DOCUMENT_HANDLE("_graphs/" + graphname), collections ;
if (! graph) {
THROW("GRAPH_EDGES", INTERNAL.errors.ERROR_GRAPH_INVALID_GRAPH, "GRAPH_EDGES");
}
collections = RESOLVE_GRAPH_TO_COLLECTIONS(graph, options);
var removeDuplicates = function(elem, pos, self) {
return self.indexOf(elem) === pos;
};
return DOCUMENTS_BY_EXAMPLE(
collections.edgeCollections.filter(removeDuplicates), options.edgeExamples
);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief GET ALL EDGE and VERTEX COLLECTION ACCORDING TO DIRECTION
////////////////////////////////////////////////////////////////////////////////
function RESOLVE_GRAPH_START_VERTICES (graphName, options) {
function RESOLVE_GRAPH_START_VERTICES (graphName, options, funcname) {
// check graph exists and load edgeDefintions
var graph = DOCUMENT_HANDLE("_graphs/" + graphName), collections ;
if (! graph) {
THROW("GRAPH_EDGES", INTERNAL.errors.ERROR_GRAPH_INVALID_GRAPH, "GRAPH_EDGES");
THROW(funcname, INTERNAL.errors.ERROR_GRAPH_INVALID_GRAPH, funcname);
}
collections = RESOLVE_GRAPH_TO_COLLECTIONS(graph, options);
collections = RESOLVE_GRAPH_TO_COLLECTIONS(graph, options, funcname);
var removeDuplicates = function(elem, pos, self) {
return self.indexOf(elem) === pos;
};
@ -5414,15 +5398,15 @@ function RESOLVE_GRAPH_START_VERTICES (graphName, options) {
/// @brief GET ALL EDGE and VERTEX COLLECTION ACCORDING TO DIRECTION
////////////////////////////////////////////////////////////////////////////////
function RESOLVE_GRAPH_TO_DOCUMENTS (graphname, options) {
function RESOLVE_GRAPH_TO_DOCUMENTS (graphname, options, funcname) {
// check graph exists and load edgeDefintions
var graph = DOCUMENT_HANDLE("_graphs/" + graphname), collections ;
if (! graph) {
THROW("GRAPH_EDGES", INTERNAL.errors.ERROR_GRAPH_INVALID_GRAPH, "GRAPH_EDGES");
THROW(funcname, INTERNAL.errors.ERROR_GRAPH_INVALID_GRAPH, funcname);
}
collections = RESOLVE_GRAPH_TO_COLLECTIONS(graph, options);
collections = RESOLVE_GRAPH_TO_COLLECTIONS(graph, options, funcname);
var removeDuplicates = function(elem, pos, self) {
return self.indexOf(elem) === pos;
};
@ -5862,7 +5846,7 @@ function CALCULATE_SHORTEST_PATHES_WITH_DIJKSTRA (graphName, options) {
}
}
var result = [], fromVertices = RESOLVE_GRAPH_TO_FROM_VERTICES(graphName, options),
toVertices = RESOLVE_GRAPH_TO_TO_VERTICES(graphName, options);
toVertices = RESOLVE_GRAPH_TO_TO_VERTICES(graphName, options, "GRAPH_SHORTEST_PATH");
var calculated = {};
fromVertices.forEach(function (v) {
@ -6014,7 +5998,7 @@ function AQL_GRAPH_SHORTEST_PATH (graphName,
}
if (options.algorithm === "Floyd-Warshall") {
var graph = RESOLVE_GRAPH_TO_DOCUMENTS(graphName, options);
var graph = RESOLVE_GRAPH_TO_DOCUMENTS(graphName, options, "GRAPH_SHORTEST_PATH");
return CALCULATE_SHORTEST_PATHES_WITH_FLOYD_WARSHALL(graph, options);
}
@ -6123,7 +6107,7 @@ function AQL_GRAPH_TRAVERSAL (graphName,
options.fromVertexExample = startVertexExample;
options.direction = direction;
var startVertices = RESOLVE_GRAPH_START_VERTICES(graphName, options);
var startVertices = RESOLVE_GRAPH_START_VERTICES(graphName, options, "GRAPH_TRAVERSAL");
var factory = TRAVERSAL.generalGraphDatasourceFactory(graphName);
startVertices.forEach(function (f) {
@ -6330,7 +6314,7 @@ function AQL_GRAPH_TRAVERSAL_TREE (graphName,
options.fromVertexExample = startVertexExample;
options.direction = direction;
var startVertices = RESOLVE_GRAPH_START_VERTICES(graphName, options);
var startVertices = RESOLVE_GRAPH_START_VERTICES(graphName, options, "GRAPH_TRAVERSAL_TREE");
var factory = TRAVERSAL.generalGraphDatasourceFactory(graphName);
startVertices.forEach(function (f) {
@ -6529,7 +6513,7 @@ function AQL_GRAPH_NEIGHBORS (graphName,
params.visitor = TRAVERSAL_NEIGHBOR_VISITOR;
}
var fromVertices = RESOLVE_GRAPH_TO_FROM_VERTICES(graphName, options);
var fromVertices = RESOLVE_GRAPH_TO_FROM_VERTICES(graphName, options, "GRAPH_NEIGHBORS");
if (options.edgeExamples) {
params.followEdges = options.edgeExamples;
}
@ -6730,7 +6714,7 @@ function AQL_GRAPH_VERTICES (graphName,
}
options.fromVertexExample = vertexExamples;
return RESOLVE_GRAPH_TO_FROM_VERTICES(graphName, options);
return RESOLVE_GRAPH_TO_FROM_VERTICES(graphName, options, "GRAPH_VERTICES");
}
////////////////////////////////////////////////////////////////////////////////
@ -6923,8 +6907,8 @@ function AQL_GRAPH_COMMON_PROPERTIES (graphName,
options.startVertexCollectionRestriction = options.vertex1CollectionRestriction;
options.endVertexCollectionRestriction = options.vertex2CollectionRestriction;
var g = RESOLVE_GRAPH_TO_FROM_VERTICES(graphName, options);
var g2 = RESOLVE_GRAPH_TO_TO_VERTICES(graphName, options);
var g = RESOLVE_GRAPH_TO_FROM_VERTICES(graphName, options, "GRAPH_COMMON_PROPERTIES");
var g2 = RESOLVE_GRAPH_TO_TO_VERTICES(graphName, options, "GRAPH_COMMON_PROPERTIES");
var res = [];
var t = {};
g.forEach(function (n1) {