mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'devel' of https://github.com/triAGENS/ArangoDB into devel
Conflicts: arangod/Aql/ExecutionNode.h
This commit is contained in:
commit
9e47f3ca27
|
@ -28,6 +28,7 @@
|
|||
#include "Aql/ExecutionBlock.h"
|
||||
#include "Aql/ExecutionEngine.h"
|
||||
#include "Basics/StringUtils.h"
|
||||
#include "Basics/StringBuffer.h"
|
||||
#include "Basics/json-utilities.h"
|
||||
#include "HashIndex/hash-index.h"
|
||||
#include "Utils/Exception.h"
|
||||
|
@ -40,6 +41,7 @@ using namespace triagens::aql;
|
|||
|
||||
using Json = triagens::basics::Json;
|
||||
using JsonHelper = triagens::basics::JsonHelper;
|
||||
using StringBuffer = triagens::basics::StringBuffer;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- struct AggregatorGroup
|
||||
|
@ -3932,6 +3934,34 @@ size_t ScatterBlock::skipSomeForShard (size_t atLeast, size_t atMost, std::strin
|
|||
// --SECTION-- class RemoteBlock
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief timeout
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
double const RemoteBlock::defaultTimeOut = 3600.0;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief local helper to throw an exception if a HTTP request went wrong
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void throwExceptionAfterBadSyncRequest (ClusterCommResult* res) {
|
||||
if (res->status == CL_COMM_TIMEOUT) {
|
||||
// No reply, we give up:
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_CLUSTER_TIMEOUT,
|
||||
"timeout in cluster AQL operation");
|
||||
}
|
||||
if (res->status == CL_COMM_ERROR) {
|
||||
// This could be a broken connection or an Http error:
|
||||
if (res->result == nullptr || ! res->result->isComplete()) {
|
||||
// there is no result
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_CLUSTER_CONNECTION_LOST,
|
||||
"lost connection within cluster");
|
||||
}
|
||||
// In this case a proper HTTP error was reported by the DBserver,
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_CLUSTER_AQL_COMMUNICATION);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief initialize
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -3969,15 +3999,103 @@ int RemoteBlock::shutdown () {
|
|||
AqlItemBlock* RemoteBlock::getSome (size_t atLeast,
|
||||
size_t atMost) {
|
||||
|
||||
return nullptr;
|
||||
// For every call we simply forward via HTTP
|
||||
|
||||
ClusterComm* cc = ClusterComm::instance();
|
||||
std::unique_ptr<ClusterCommResult> res;
|
||||
|
||||
// Later, we probably want to set these sensibly:
|
||||
ClientTransactionID const clientTransactionId = "AQL";
|
||||
CoordTransactionID const coordTransactionId = 1;
|
||||
|
||||
Json body(Json::Array, 2);
|
||||
body("atLeast", Json(static_cast<double>(atLeast)))
|
||||
("atMost", Json(static_cast<double>(atMost)));
|
||||
std::string bodyString(body.toString());
|
||||
std::map<std::string, std::string> headers;
|
||||
|
||||
res.reset(cc->syncRequest(clientTransactionId,
|
||||
coordTransactionId,
|
||||
_server,
|
||||
rest::HttpRequest::HTTP_REQUEST_PUT,
|
||||
std::string("/_db/")
|
||||
+ _engine->getTransaction()->vocbase()->_name
|
||||
+ "/_api/aql/getSome/" + _queryId,
|
||||
bodyString,
|
||||
headers,
|
||||
3600.0));
|
||||
|
||||
throwExceptionAfterBadSyncRequest(res.get());
|
||||
|
||||
// If we get here, then res->result is the response which will be
|
||||
// a serialized AqlItemBlock:
|
||||
StringBuffer const& responseBodyBuf(res->result->getBody());
|
||||
Json responseBodyJson(TRI_UNKNOWN_MEM_ZONE,
|
||||
TRI_JsonString(TRI_UNKNOWN_MEM_ZONE,
|
||||
responseBodyBuf.begin()));
|
||||
if (JsonHelper::getBooleanValue(responseBodyJson.json(), "exhausted", true)) {
|
||||
return nullptr;
|
||||
}
|
||||
else {
|
||||
auto items = new triagens::aql::AqlItemBlock(responseBodyJson);
|
||||
return items;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief skipSome
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ClusterCommResult* RemoteBlock::sendRequest (
|
||||
rest::HttpRequest::HttpRequestType type,
|
||||
std::string urlPart,
|
||||
std::string const& body) {
|
||||
|
||||
ClusterComm* cc = ClusterComm::instance();
|
||||
|
||||
// Later, we probably want to set these sensibly:
|
||||
ClientTransactionID const clientTransactionId = "AQL";
|
||||
CoordTransactionID const coordTransactionId = 1;
|
||||
std::map<std::string, std::string> headers;
|
||||
|
||||
return cc->syncRequest(clientTransactionId,
|
||||
coordTransactionId,
|
||||
_server,
|
||||
type,
|
||||
std::string("/_db/")
|
||||
+ _engine->getTransaction()->vocbase()->_name
|
||||
+ urlPart + _queryId,
|
||||
body,
|
||||
headers,
|
||||
defaultTimeOut);
|
||||
}
|
||||
|
||||
size_t RemoteBlock::skipSome (size_t atLeast, size_t atMost) {
|
||||
return 0;
|
||||
// For every call we simply forward via HTTP
|
||||
|
||||
Json body(Json::Array, 2);
|
||||
body("atLeast", Json(static_cast<double>(atLeast)))
|
||||
("atMost", Json(static_cast<double>(atMost)));
|
||||
std::string bodyString(body.toString());
|
||||
|
||||
std::unique_ptr<ClusterCommResult> res;
|
||||
res.reset(sendRequest(rest::HttpRequest::HTTP_REQUEST_PUT,
|
||||
"/_api/aql/skipSome/",
|
||||
bodyString));
|
||||
throwExceptionAfterBadSyncRequest(res.get());
|
||||
|
||||
// If we get here, then res->result is the response which will be
|
||||
// a serialized AqlItemBlock:
|
||||
StringBuffer const& responseBodyBuf(res->result->getBody());
|
||||
Json responseBodyJson(TRI_UNKNOWN_MEM_ZONE,
|
||||
TRI_JsonString(TRI_UNKNOWN_MEM_ZONE,
|
||||
responseBodyBuf.begin()));
|
||||
if (JsonHelper::getBooleanValue(responseBodyJson.json(), "error", true)) {
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_CLUSTER_AQL_COMMUNICATION);
|
||||
}
|
||||
size_t skipped = JsonHelper::getNumericValue<size_t>(responseBodyJson.json(),
|
||||
"skipped", 0);
|
||||
return skipped;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "Utils/AqlTransaction.h"
|
||||
#include "Utils/transactions.h"
|
||||
#include "Utils/V8TransactionContext.h"
|
||||
#include "Cluster/ClusterComm.h"
|
||||
|
||||
namespace triagens {
|
||||
namespace aql {
|
||||
|
@ -1638,20 +1639,33 @@ public:
|
|||
|
||||
class RemoteBlock : public ExecutionBlock {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief constructors/destructors
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public:
|
||||
|
||||
RemoteBlock (ExecutionEngine* engine,
|
||||
RemoteNode const* en,
|
||||
std::string const& server,
|
||||
std::string const& ownName)
|
||||
std::string const& ownName,
|
||||
std::string const& queryId)
|
||||
: ExecutionBlock(engine, en),
|
||||
_server(server),
|
||||
_ownName(ownName) {
|
||||
_ownName(ownName),
|
||||
_queryId(queryId) {
|
||||
TRI_ASSERT(! queryId.empty());
|
||||
}
|
||||
|
||||
~RemoteBlock () {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief timeout
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static double const defaultTimeOut;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief initialize
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1702,19 +1716,35 @@ public:
|
|||
int64_t remaining () final;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief our server, can be like "shard:S1000" or like "server:Claus"
|
||||
/// @brief internal method to send a request
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private:
|
||||
|
||||
std::string _server;
|
||||
triagens::arango::ClusterCommResult* sendRequest (
|
||||
rest::HttpRequest::HttpRequestType type,
|
||||
std::string urlPart,
|
||||
std::string const& body);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief our server, can be like "shard:S1000" or like "server:Claus"
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::string _server;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief our own identity, in case of the coordinator this is empty,
|
||||
/// in case of the DBservers, this is the shard ID as a string
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::string _ownName;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief the ID of the query on the server as a string
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::string _queryId;
|
||||
|
||||
};
|
||||
|
||||
} // namespace triagens::aql
|
||||
|
|
|
@ -451,7 +451,8 @@ struct CoordinatorInstanciator : public WalkerWorker<ExecutionNode> {
|
|||
// now we'll create a remote node for each shard and add it to the gather node
|
||||
auto&& shardIds = static_cast<GatherNode const*>((*en))->collection()->shardIds();
|
||||
for (auto shardId : shardIds) {
|
||||
ExecutionBlock* r = new RemoteBlock(engine.get(), remoteNode, "shard:" + shardId, "");
|
||||
// TODO: pass actual queryId into RemoteBlock
|
||||
ExecutionBlock* r = new RemoteBlock(engine.get(), remoteNode, "shard:" + shardId, "", "" /*TODO*/);
|
||||
|
||||
try {
|
||||
engine.get()->addBlock(r);
|
||||
|
|
|
@ -114,6 +114,22 @@ namespace triagens {
|
|||
return _query;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief initializeCursor, could be called multiple times
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int initializeCursor (AqlItemBlock* items, size_t pos) {
|
||||
return _root->initializeCursor(items, pos);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief shutdown, will be called exactly once for the whole query
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int shutdown () {
|
||||
return _root->shutdown();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief getSome
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -122,6 +138,14 @@ namespace triagens {
|
|||
return _root->getSome(atLeast, atMost);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief skipSome
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
size_t skipSome (size_t atLeast, size_t atMost) {
|
||||
return _root->skipSome(atLeast, atMost);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief getOne
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -93,10 +93,10 @@ void ExecutionNode::validateType (int type) {
|
|||
}
|
||||
}
|
||||
|
||||
void ExecutionNode::getSortElements(SortElementVector elements,
|
||||
ExecutionPlan* plan,
|
||||
triagens::basics::Json const& oneNode,
|
||||
char const* which)
|
||||
void ExecutionNode::getSortElements(SortElementVector& elements,
|
||||
ExecutionPlan* plan,
|
||||
triagens::basics::Json const& oneNode,
|
||||
char const* which)
|
||||
{
|
||||
triagens::basics::Json jsonElements = oneNode.get("elements");
|
||||
if (! jsonElements.isList()){
|
||||
|
|
|
@ -505,17 +505,17 @@ namespace triagens {
|
|||
|
||||
static Variable* varFromJson (Ast* ast,
|
||||
triagens::basics::Json const& base,
|
||||
const char *variableName,
|
||||
char const* variableName,
|
||||
bool optional = false);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief factory for sort Elements from json.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void getSortElements(SortElementVector elements,
|
||||
ExecutionPlan* plan,
|
||||
triagens::basics::Json const& oneNode,
|
||||
char const* which);
|
||||
static void getSortElements (SortElementVector& elements,
|
||||
ExecutionPlan* plan,
|
||||
triagens::basics::Json const& oneNode,
|
||||
char const* which);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief toJsonHelper, for a generic node
|
||||
|
@ -1697,7 +1697,7 @@ namespace triagens {
|
|||
/// @brief get Variables Used Here including ASC/DESC
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SortElementVector getElements () const {
|
||||
SortElementVector const & getElements () const {
|
||||
return _elements;
|
||||
}
|
||||
|
||||
|
@ -2866,11 +2866,11 @@ namespace triagens {
|
|||
/// @brief get Variables Used Here including ASC/DESC
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SortElementVector getElements () const {
|
||||
SortElementVector const & getElements () const {
|
||||
return _elements;
|
||||
}
|
||||
|
||||
void setElements (SortElementVector const src) {
|
||||
void setElements (SortElementVector const & src) {
|
||||
_elements = src;
|
||||
}
|
||||
|
||||
|
@ -2890,7 +2890,6 @@ namespace triagens {
|
|||
return _collection;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -381,7 +381,8 @@ void RestAqlHandler::deleteQuery (std::string const& idString) {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief PUT method for /_api/aql/<operation>/<queryId>, this is using
|
||||
/// the part of the cursor API with side effects.
|
||||
/// <operation>: can be "getSome" or "skip".
|
||||
/// <operation>: can be "getSome" or "skip" or "initializeCursor" or
|
||||
/// "shutdown".
|
||||
/// The body must be a Json with the following attributes:
|
||||
/// For the "getSome" operation one has to give:
|
||||
/// "atLeast":
|
||||
|
@ -395,6 +396,19 @@ void RestAqlHandler::deleteQuery (std::string const& idString) {
|
|||
/// AqlItemBlock.
|
||||
/// If "atLeast" is not given it defaults to 1, if "atMost" is not
|
||||
/// given it defaults to ExecutionBlock::DefaultBatchSize.
|
||||
/// For the "skipSome" operation one has to give:
|
||||
/// "atLeast":
|
||||
/// "atMost": both must be positive integers, the cursor skips never
|
||||
/// more than "atMost" items and tries to skip at least
|
||||
/// "atLeast". Note that it is possible to skip fewer than
|
||||
/// "atLeast", for example if there are only fewer items
|
||||
/// left. However, the implementation may skip fewer items
|
||||
/// than "atLeast" for internal reasons, for example to avoid
|
||||
/// excessive copying. The result is a JSON object with a
|
||||
/// single attribute "skipped" containing the number of
|
||||
/// skipped items.
|
||||
/// If "atLeast" is not given it defaults to 1, if "atMost" is not
|
||||
/// given it defaults to ExecutionBlock::DefaultBatchSize.
|
||||
/// For the "skip" operation one should give:
|
||||
/// "number": must be a positive integer, the cursor skips as many items,
|
||||
/// possibly exhausting the cursor.
|
||||
|
@ -402,6 +416,13 @@ void RestAqlHandler::deleteQuery (std::string const& idString) {
|
|||
/// "errorMessage" (if applicable) and "exhausted" (boolean)
|
||||
/// to indicate whether or not the cursor is exhausted.
|
||||
/// If "number" is not given it defaults to 1.
|
||||
/// For the "initializeCursor" operation, one has to bind the following
|
||||
/// attributes:
|
||||
/// "items": This is a serialised AqlItemBlock with usually only one row
|
||||
/// and the correct number of columns.
|
||||
/// "pos": The number of the row in "items" to take, usually 0.
|
||||
/// For the "shutdown" operation no additional arguments are required and
|
||||
/// an empty JSON object in the body is OK.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void RestAqlHandler::useQuery (std::string const& operation,
|
||||
|
@ -447,9 +468,27 @@ void RestAqlHandler::useQuery (std::string const& operation,
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (operation == "getSome") {
|
||||
auto atLeast = JsonHelper::getNumericValue<uint64_t>(queryJson.json(),
|
||||
"atLeast", 1);
|
||||
auto atMost = JsonHelper::getNumericValue<uint64_t>(queryJson.json(),
|
||||
"atMost", ExecutionBlock::DefaultBatchSize);
|
||||
size_t skipped;
|
||||
try {
|
||||
skipped = query->engine()->skipSome(atLeast, atMost);
|
||||
}
|
||||
catch (...) {
|
||||
_queryRegistry->close(vocbase, qId);
|
||||
generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_HTTP_SERVER_ERROR,
|
||||
"skipSome lead to an exception");
|
||||
return;
|
||||
}
|
||||
answerBody("skipped", Json(static_cast<double>(skipped)))
|
||||
("error", Json(false));
|
||||
}
|
||||
else if (operation == "skip") {
|
||||
auto number = JsonHelper::getNumericValue<uint64_t>(queryJson.json(),
|
||||
"number", 1);
|
||||
"number", 1);
|
||||
try {
|
||||
bool exhausted = query->engine()->skip(number);
|
||||
answerBody("exhausted", Json(exhausted))
|
||||
|
@ -462,6 +501,38 @@ void RestAqlHandler::useQuery (std::string const& operation,
|
|||
return;
|
||||
}
|
||||
}
|
||||
else if (operation == "initializeCursor") {
|
||||
auto pos = JsonHelper::getNumericValue<size_t>(queryJson.json(),
|
||||
"pos", 0);
|
||||
std::unique_ptr<AqlItemBlock> items;
|
||||
int res;
|
||||
try {
|
||||
items.reset(new AqlItemBlock(queryJson.get("items")));
|
||||
res = query->engine()->initializeCursor(items.get(), pos);
|
||||
}
|
||||
catch (...) {
|
||||
_queryRegistry->close(vocbase, qId);
|
||||
generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_HTTP_SERVER_ERROR,
|
||||
"initializeCursor lead to an exception");
|
||||
return;
|
||||
}
|
||||
answerBody("error", res == TRI_ERROR_NO_ERROR ? Json(false) : Json(true))
|
||||
("code", Json(static_cast<double>(res)));
|
||||
}
|
||||
else if (operation == "shutdown") {
|
||||
int res;
|
||||
try {
|
||||
res = query->engine()->shutdown();
|
||||
}
|
||||
catch (...) {
|
||||
_queryRegistry->close(vocbase, qId);
|
||||
generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_HTTP_SERVER_ERROR,
|
||||
"shutdown lead to an exception");
|
||||
return;
|
||||
}
|
||||
answerBody("error", res == TRI_ERROR_NO_ERROR ? Json(false) : Json(true))
|
||||
("code", Json(static_cast<double>(res)));
|
||||
}
|
||||
else {
|
||||
_queryRegistry->close(vocbase, qId);
|
||||
generateError(HttpResponse::NOT_FOUND, TRI_ERROR_HTTP_NOT_FOUND);
|
||||
|
|
|
@ -860,7 +860,7 @@ void RestReplicationHandler::handleTrampolineCoordinator () {
|
|||
}
|
||||
if (res->status == CL_COMM_ERROR) {
|
||||
// This could be a broken connection or an Http error:
|
||||
if (res->result == 0 || !res->result->isComplete()) {
|
||||
if (res->result == nullptr || !res->result->isComplete()) {
|
||||
// there is no result
|
||||
delete res;
|
||||
generateError(HttpResponse::BAD, TRI_ERROR_CLUSTER_CONNECTION_LOST,
|
||||
|
|
|
@ -144,6 +144,7 @@
|
|||
"ERROR_CLUSTER_ONLY_ON_COORDINATOR" : { "code" : 1471, "message" : "this operation is only valid on a coordinator in a cluster" },
|
||||
"ERROR_CLUSTER_READING_PLAN_AGENCY" : { "code" : 1472, "message" : "error reading Plan in agency" },
|
||||
"ERROR_CLUSTER_COULD_NOT_TRUNCATE_COLLECTION" : { "code" : 1473, "message" : "could not truncate collection" },
|
||||
"ERROR_CLUSTER_AQL_COMMUNICATION" : { "code" : 1474, "message" : "error in cluster internal communication for AQL" },
|
||||
"ERROR_QUERY_KILLED" : { "code" : 1500, "message" : "query killed" },
|
||||
"ERROR_QUERY_PARSE" : { "code" : 1501, "message" : "%s" },
|
||||
"ERROR_QUERY_EMPTY" : { "code" : 1502, "message" : "query is empty" },
|
||||
|
|
|
@ -144,6 +144,7 @@
|
|||
"ERROR_CLUSTER_ONLY_ON_COORDINATOR" : { "code" : 1471, "message" : "this operation is only valid on a coordinator in a cluster" },
|
||||
"ERROR_CLUSTER_READING_PLAN_AGENCY" : { "code" : 1472, "message" : "error reading Plan in agency" },
|
||||
"ERROR_CLUSTER_COULD_NOT_TRUNCATE_COLLECTION" : { "code" : 1473, "message" : "could not truncate collection" },
|
||||
"ERROR_CLUSTER_AQL_COMMUNICATION" : { "code" : 1474, "message" : "error in cluster internal communication for AQL" },
|
||||
"ERROR_QUERY_KILLED" : { "code" : 1500, "message" : "query killed" },
|
||||
"ERROR_QUERY_PARSE" : { "code" : 1501, "message" : "%s" },
|
||||
"ERROR_QUERY_EMPTY" : { "code" : 1502, "message" : "query is empty" },
|
||||
|
|
|
@ -86,6 +86,7 @@ var _ = require("underscore");
|
|||
|
||||
var testFuncs = {};
|
||||
var print = require("internal").print;
|
||||
var time = require("internal").time;
|
||||
var fs = require("fs");
|
||||
var download = require("internal").download;
|
||||
var wait = require("internal").wait;
|
||||
|
@ -398,17 +399,34 @@ function runThere (options, instanceInfo, file) {
|
|||
|
||||
function executeAndWait (cmd, args) {
|
||||
var pid = executeExternal(cmd, args);
|
||||
var startTime = time();
|
||||
var res = statusExternal(pid, true);
|
||||
var deltaTime = time() - startTime;
|
||||
|
||||
if (res.status === "TERMINATED") {
|
||||
print("Finished: " + res.status + " Exitcode: " + res.exit + " Time Elapsed: " + deltaTime);
|
||||
if (res.exit === 0) {
|
||||
return { status: true, message: "" };
|
||||
return { status: true, message: "", duration: deltaTime};
|
||||
}
|
||||
else {
|
||||
return { status: false, message: "exit code was " + res.exit};
|
||||
return { status: false, message: "exit code was " + res.exit, duration: deltaTime};
|
||||
}
|
||||
}
|
||||
else if (res.status === "ABORTED") {
|
||||
print("Finished: " + res.status + " Signal: " + res.signal + " Time Elapsed: " + deltaTime);
|
||||
return {
|
||||
status: false,
|
||||
message: "irregular termination: " + res.status + " Exit-Signal: " + res.signal,
|
||||
duration: deltaTime
|
||||
};
|
||||
}
|
||||
else {
|
||||
return { status: false, message: "irregular termination: " + res.status};
|
||||
print("Finished: " + res.status + " Exitcode: " + res.exit + " Time Elapsed: " + deltaTime);
|
||||
return {
|
||||
status: false,
|
||||
message: "irregular termination: " + res.status + " Exit-Code: " + res.exit,
|
||||
duration: deltaTime
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -671,19 +689,35 @@ function rubyTests (options, ssl) {
|
|||
"--format", "d", "--require", tmpname,
|
||||
fs.join("UnitTests","HttpInterface",n)];
|
||||
var pid = executeExternal("rspec", args);
|
||||
var startTime = time();
|
||||
var r = statusExternal(pid, true);
|
||||
|
||||
var deltaTime = time() - startTime;
|
||||
if (r.status === "TERMINATED") {
|
||||
print("Finished: " + r.status + " Signal: " + r.exit + " Time Elapsed: " + deltaTime);
|
||||
if (r.exit === 0) {
|
||||
result[n] = { status: true, message: "" };
|
||||
result[n] = { status: true, message: "", duration: deltaTime };
|
||||
}
|
||||
else {
|
||||
result[n] = { status: false, message: "exit code was " + r.exit};
|
||||
result[n] = { status: false, message: " exit code was " + r.exit, duration: deltaTime};
|
||||
}
|
||||
}
|
||||
else {
|
||||
result[n] = { status: false, message: "irregular termination: " + r.status};
|
||||
else if (r.status === "ABORTED") {
|
||||
print("Finished: " + r.status + " Signal: " + r.exit + " Time Elapsed: " + deltaTime);
|
||||
result[n] = {
|
||||
status: false,
|
||||
message: "irregular termination: " + r.status + " Exit-Signal: " + r.signal,
|
||||
duration: deltaTime
|
||||
};
|
||||
}
|
||||
else {
|
||||
print("Finished: " + r.status + " Exit Status: " + r.exit + " Time Elapsed: " + deltaTime);
|
||||
result[n] = {
|
||||
status: false,
|
||||
message: "irregular termination: " + r.status + " Exit-code: " + r.exit,
|
||||
duration: deltaTime
|
||||
};
|
||||
}
|
||||
|
||||
if (r.status === false && !options.force) {
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -180,6 +180,7 @@ ERROR_CLUSTER_UNSUPPORTED,1470,"unsupported operation or parameter","Will be rai
|
|||
ERROR_CLUSTER_ONLY_ON_COORDINATOR,1471,"this operation is only valid on a coordinator in a cluster","Will be raised if there is an attempt to run a coordinator-only operation on a different type of node."
|
||||
ERROR_CLUSTER_READING_PLAN_AGENCY,1472,"error reading Plan in agency","Will be raised if a coordinator or DBserver cannot read the Plan in the agency."
|
||||
ERROR_CLUSTER_COULD_NOT_TRUNCATE_COLLECTION,1473,"could not truncate collection","Will be raised if a coordinator cannot truncate all shards of a cluster collection."
|
||||
ERROR_CLUSTER_AQL_COMMUNICATION,1474,"error in cluster internal communication for AQL","Will be raised if the internal communication of the cluster for AQL produces an error."
|
||||
|
||||
################################################################################
|
||||
## ArangoDB query errors
|
||||
|
|
|
@ -140,6 +140,7 @@ void TRI_InitialiseErrorMessages (void) {
|
|||
REG_ERROR(ERROR_CLUSTER_ONLY_ON_COORDINATOR, "this operation is only valid on a coordinator in a cluster");
|
||||
REG_ERROR(ERROR_CLUSTER_READING_PLAN_AGENCY, "error reading Plan in agency");
|
||||
REG_ERROR(ERROR_CLUSTER_COULD_NOT_TRUNCATE_COLLECTION, "could not truncate collection");
|
||||
REG_ERROR(ERROR_CLUSTER_AQL_COMMUNICATION, "error in cluster internal communication for AQL");
|
||||
REG_ERROR(ERROR_QUERY_KILLED, "query killed");
|
||||
REG_ERROR(ERROR_QUERY_PARSE, "%s");
|
||||
REG_ERROR(ERROR_QUERY_EMPTY, "query is empty");
|
||||
|
|
|
@ -341,6 +341,9 @@
|
|||
/// - 1473: @LIT{could not truncate collection}
|
||||
/// Will be raised if a coordinator cannot truncate all shards of a cluster
|
||||
/// collection.
|
||||
/// - 1474: @LIT{error in cluster internal communication for AQL}
|
||||
/// Will be raised if the internal communication of the cluster for AQL
|
||||
/// produces an error.
|
||||
/// - 1500: @LIT{query killed}
|
||||
/// Will be raised when a running query is killed by an explicit admin
|
||||
/// command.
|
||||
|
@ -1996,6 +1999,17 @@ void TRI_InitialiseErrorMessages (void);
|
|||
|
||||
#define TRI_ERROR_CLUSTER_COULD_NOT_TRUNCATE_COLLECTION (1473)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief 1474: ERROR_CLUSTER_AQL_COMMUNICATION
|
||||
///
|
||||
/// error in cluster internal communication for AQL
|
||||
///
|
||||
/// Will be raised if the internal communication of the cluster for AQL
|
||||
/// produces an error.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define TRI_ERROR_CLUSTER_AQL_COMMUNICATION (1474)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief 1500: ERROR_QUERY_KILLED
|
||||
///
|
||||
|
|
|
@ -31,7 +31,9 @@ function resultsToXml(results, baseName) {
|
|||
.text(xmlEscape(String(attrs[a]))).text("\"");
|
||||
}
|
||||
|
||||
close && this.text("/");
|
||||
if (close) {
|
||||
this.text("/");
|
||||
}
|
||||
this.text(">\n");
|
||||
|
||||
return this;
|
||||
|
@ -64,6 +66,13 @@ function resultsToXml(results, baseName) {
|
|||
}
|
||||
}
|
||||
|
||||
if ((!results[testrun][test].status) &&
|
||||
results[testrun][test].hasOwnProperty('message'))
|
||||
{
|
||||
xml.elem("failure");
|
||||
xml.text('<![CDATA[' + JSON.stringify(results[testrun][test].message) + ']]>\n');
|
||||
xml.elem("/failure");
|
||||
}
|
||||
xml.elem("/testsuite");
|
||||
var fn = baseName + testrun.replace(/\//g, '_') + '_' + test.replace(/\//g, '_') + ".xml";
|
||||
//print('Writing: '+ fn);
|
||||
|
|
Loading…
Reference in New Issue