From 25d588b858929d56b6f154b1751ec61177732cc0 Mon Sep 17 00:00:00 2001 From: Max Neunhoeffer Date: Thu, 2 Oct 2014 09:28:00 +0200 Subject: [PATCH 1/4] Set _varUsageValid flag in Json constructor. --- arangod/Aql/ExecutionNode.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arangod/Aql/ExecutionNode.cpp b/arangod/Aql/ExecutionNode.cpp index c0944fb367..cbeda52e02 100644 --- a/arangod/Aql/ExecutionNode.cpp +++ b/arangod/Aql/ExecutionNode.cpp @@ -209,7 +209,7 @@ ExecutionNode::ExecutionNode (ExecutionPlan* plan, _id(JsonHelper::checkAndGetNumericValue(json.json(), "id")), _estimatedCost(0.0), _estimatedCostSet(false), - _varUsageValid(false), + _varUsageValid(true), _plan(plan), _depth(JsonHelper::checkAndGetNumericValue(json.json(), "depth")) { @@ -1808,6 +1808,7 @@ void ReturnNode::toJsonHelper (triagens::basics::Json& nodes, //////////////////////////////////////////////////////////////////////////////// /// @brief clone ExecutionNode recursively //////////////////////////////////////////////////////////////////////////////// + ExecutionNode* ReturnNode::clone (ExecutionPlan* plan, bool withDependencies, bool withProperties) const { From 162e0b3f71750013a37c76257f4ba56727334746 Mon Sep 17 00:00:00 2001 From: Jan Steemann Date: Thu, 2 Oct 2014 09:37:03 +0200 Subject: [PATCH 2/4] issue #1031: updated documentation for date functions --- Documentation/Books/Users/Aql/Functions.mdpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/Books/Users/Aql/Functions.mdpp b/Documentation/Books/Users/Aql/Functions.mdpp index 32c5fbbfec..29427fdf1d 100644 --- a/Documentation/Books/Users/Aql/Functions.mdpp +++ b/Documentation/Books/Users/Aql/Functions.mdpp @@ -193,7 +193,9 @@ a numeric timestamp to a string representation and vice versa. There are two date functions in AQL to create dates for further use: -- *DATE_TIMESTAMP(date)*: Creates a UTC timestamp value from *date*. +- *DATE_TIMESTAMP(date)*: Creates a UTC timestamp value from *date*. The return + value has millisecond precision. To convert the return value to seconds, divide + it by 1000. - *DATE_TIMESTAMP(year, month, day, hour, minute, second, millisecond)*: Same as before, but allows specifying the individual date components separately. @@ -294,6 +296,8 @@ The following date functions can be used with dates created by *DATE_TIMESTAMP* The following other date functions are also available: - *DATE_NOW()*: Returns the current time as a timestamp. + The return value has millisecond precision. To convert the return value to seconds, + divide it by 1000. Note that this function is evaluated on every invocation and may return different values when invoked multiple times in the same query. From a59d1e4448624bde2674e481bea05afb3c848d29 Mon Sep 17 00:00:00 2001 From: Max Neunhoeffer Date: Thu, 2 Oct 2014 09:55:15 +0200 Subject: [PATCH 3/4] Start to sort out ScatterBlock's special API. --- arangod/Aql/ExecutionBlock.cpp | 20 ++++++++++++++++++++ arangod/Aql/ExecutionBlock.h | 6 ++++++ arangod/Aql/RestAqlHandler.cpp | 24 ++++++++++++++++++++++-- 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/arangod/Aql/ExecutionBlock.cpp b/arangod/Aql/ExecutionBlock.cpp index 441678f57f..9fab3f1892 100644 --- a/arangod/Aql/ExecutionBlock.cpp +++ b/arangod/Aql/ExecutionBlock.cpp @@ -3758,6 +3758,23 @@ size_t ScatterBlock::skipSomeForShard (size_t atLeast, size_t atMost, std::strin return skipped; } +//////////////////////////////////////////////////////////////////////////////// +/// @brief skipForShard +//////////////////////////////////////////////////////////////////////////////// + +bool ScatterBlock::skipForShard (size_t number, std::string const& shardId) { + size_t skipped = skipSomeForShard(number, number, shardId); + size_t nr = skipped; + while ( nr != 0 && skipped < number ){ + nr = skipSomeForShard(number - skipped, number - skipped, shardId); + skipped += nr; + } + if (nr == 0) { + return true; + } + return ! hasMoreForShard(shardId); +} + //////////////////////////////////////////////////////////////////////////////// /// @brief getClientId: get the number (used internally) /// corresponding to @@ -3824,6 +3841,9 @@ ClusterCommResult* RemoteBlock::sendRequest ( ClientTransactionID const clientTransactionId = "AQL"; CoordTransactionID const coordTransactionId = 1; std::map headers; + if (! _ownName.empty()) { + headers.insert(make_pair("Shard-Id", _ownName)); + } std::cout << "SENDING REQUEST TO " << _server << ", URLPART: " << urlPart << ", QUERYID: " << _queryId << "\n"; return cc->syncRequest(clientTransactionId, diff --git a/arangod/Aql/ExecutionBlock.h b/arangod/Aql/ExecutionBlock.h index db4ebe03f0..702bf52bfb 100644 --- a/arangod/Aql/ExecutionBlock.h +++ b/arangod/Aql/ExecutionBlock.h @@ -1629,6 +1629,12 @@ namespace triagens { size_t skipSomeForShard (size_t atLeast, size_t atMost, std::string const& shardId); +//////////////////////////////////////////////////////////////////////////////// +/// @brief skipForShard +//////////////////////////////////////////////////////////////////////////////// + + bool skipForShard (size_t number, std::string const& shardId); + private: //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/Aql/RestAqlHandler.cpp b/arangod/Aql/RestAqlHandler.cpp index ea4b5a9638..400002fa2f 100644 --- a/arangod/Aql/RestAqlHandler.cpp +++ b/arangod/Aql/RestAqlHandler.cpp @@ -706,7 +706,16 @@ std::cout << "ANSWERBODY: " << JsonHelper::toString(answerBody.json()) << "\n\n" "atMost", ExecutionBlock::DefaultBatchSize); size_t skipped; try { - skipped = query->engine()->skipSome(atLeast, atMost); + if (shardId.empty()) { + skipped = query->engine()->skipSome(atLeast, atMost); + } + else { + auto scatter = static_cast(query->engine()->root()); + if (scatter->getPlanNode()->getType() != ExecutionNode::SCATTER) { + THROW_ARANGO_EXCEPTION(TRI_ERROR_INTERNAL); + } + skipped = scatter->skipSomeForShard(atLeast, atMost, shardId); + } } catch (...) { generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_HTTP_SERVER_ERROR, @@ -720,7 +729,18 @@ std::cout << "ANSWERBODY: " << JsonHelper::toString(answerBody.json()) << "\n\n" auto number = JsonHelper::getNumericValue(queryJson.json(), "number", 1); try { - bool exhausted = query->engine()->skip(number); + bool exhausted; + if (shardId.empty()) { + exhausted = query->engine()->skip(number); + } + else { + auto scatter = static_cast(query->engine()->root()); + if (scatter->getPlanNode()->getType() != ExecutionNode::SCATTER) { + THROW_ARANGO_EXCEPTION(TRI_ERROR_INTERNAL); + } + exhausted = scatter->skipForShard(number, shardId); + } + answerBody("exhausted", Json(exhausted)) ("error", Json(false)); } From d021bcf7200831c014fcce3ac35ee440bde2ee57 Mon Sep 17 00:00:00 2001 From: Max Neunhoeffer Date: Thu, 2 Oct 2014 10:24:47 +0200 Subject: [PATCH 4/4] Sort out shardId for ScatterBlock and HTTP API. --- arangod/Aql/RestAqlHandler.cpp | 89 +++++++++++++++++++++++++--------- 1 file changed, 66 insertions(+), 23 deletions(-) diff --git a/arangod/Aql/RestAqlHandler.cpp b/arangod/Aql/RestAqlHandler.cpp index 400002fa2f..6bdffadd85 100644 --- a/arangod/Aql/RestAqlHandler.cpp +++ b/arangod/Aql/RestAqlHandler.cpp @@ -488,6 +488,13 @@ void RestAqlHandler::getInfoQuery (std::string const& operation, std::string const& idString) { // the GET verb + bool found; + std::string shardId; + char const* shardIdCharP = _request->header("shard-id", found); + if (found && shardIdCharP != nullptr) { + shardId = shardIdCharP; + } + QueryId qId; Query* query = nullptr; if (findQuery(idString, qId, query)) { @@ -498,33 +505,69 @@ void RestAqlHandler::getInfoQuery (std::string const& operation, TRI_ASSERT(query->engine() != nullptr); - int64_t number; - if (operation == "count") { - number = query->engine()->count(); - if (number == -1) { - answerBody("count", Json("unknown")); + try { + int64_t number; + if (operation == "count") { + number = query->engine()->count(); + if (number == -1) { + answerBody("count", Json("unknown")); + } + else { + answerBody("count", Json(static_cast(number))); + } + } + else if (operation == "remaining") { + // FIXME: + // Do the !shardId.empty() case once the ScatterBlock has remainingForShard + number = query->engine()->remaining(); + if (number == -1) { + answerBody("remaining", Json("unknown")); + } + else { + answerBody("remaining", Json(static_cast(number))); + } + } + else if (operation == "hasMore") { + bool hasMore; + if (shardId.empty()) { + hasMore = query->engine()->hasMore(); + } + else { + auto scatter = static_cast(query->engine()->root()); + if (scatter->getPlanNode()->getType() != ExecutionNode::SCATTER) { + THROW_ARANGO_EXCEPTION(TRI_ERROR_INTERNAL); + } + hasMore = scatter->hasMoreForShard(shardId); + } + + answerBody("hasMore", Json(hasMore)); } else { - answerBody("count", Json(static_cast(number))); + _queryRegistry->close(_vocbase, qId); + generateError(HttpResponse::NOT_FOUND, TRI_ERROR_HTTP_NOT_FOUND); + return; } } - else if (operation == "remaining") { - number = query->engine()->remaining(); - if (number == -1) { - answerBody("remaining", Json("unknown")); - } - else { - answerBody("remaining", Json(static_cast(number))); - } - } - else if (operation == "hasMore") { - bool hasMore = query->engine()->hasMore(); - answerBody("hasMore", Json(hasMore)); - } - else { + catch (triagens::arango::Exception const& ex) { _queryRegistry->close(_vocbase, qId); - generateError(HttpResponse::NOT_FOUND, TRI_ERROR_HTTP_NOT_FOUND); - return; + + generateError(HttpResponse::SERVER_ERROR, + ex.code(), + ex.message()); + } + catch (std::exception const& ex) { + _queryRegistry->close(_vocbase, qId); + + generateError(HttpResponse::SERVER_ERROR, + TRI_ERROR_HTTP_SERVER_ERROR, + ex.what()); + } + catch (...) { + _queryRegistry->close(_vocbase, qId); + + generateError(HttpResponse::SERVER_ERROR, + TRI_ERROR_HTTP_SERVER_ERROR, + "an unknown exception occurred"); } _queryRegistry->close(_vocbase, qId); @@ -661,7 +704,7 @@ void RestAqlHandler::handleUseQuery (std::string const& operation, bool found; std::string shardId; char const* shardIdCharP = _request->header("shard-id", found); - if (shardIdCharP != nullptr) { + if (found && shardIdCharP != nullptr) { shardId = shardIdCharP; }