diff --git a/arangod/Aql/Ast.cpp b/arangod/Aql/Ast.cpp index bc3f6c3f74..238953c843 100644 --- a/arangod/Aql/Ast.cpp +++ b/arangod/Aql/Ast.cpp @@ -33,6 +33,7 @@ #include "VocBase/collection.h" #include +#include #include using namespace arangodb::aql; @@ -1046,25 +1047,22 @@ AstNode* Ast::createNodeIntersectedArray(AstNode const* lhs, size_t const nl = lhs->numMembers(); size_t const nr = rhs->numMembers(); - std::unordered_map - cache(nl + nr, arangodb::basics::JsonHash(), - arangodb::basics::JsonEqual()); + std::unordered_map cache(nl + nr); for (size_t i = 0; i < nl; ++i) { auto member = lhs->getMemberUnchecked(i); - auto json = member->computeJson(); + VPackSlice slice = member->computeValue(); - cache.emplace(json, member); + cache.emplace(slice, member); } auto node = createNodeArray(); for (size_t i = 0; i < nr; ++i) { auto member = rhs->getMemberUnchecked(i); - auto json = member->computeJson(); + VPackSlice slice = member->computeValue(); - auto it = cache.find(json); + auto it = cache.find(slice); if (it != cache.end()) { node->addMember((*it).second); @@ -1085,10 +1083,7 @@ AstNode* Ast::createNodeUnionizedArray(AstNode const* lhs, AstNode const* rhs) { size_t const nl = lhs->numMembers(); size_t const nr = rhs->numMembers(); - std::unordered_map - cache(nl + nr, arangodb::basics::JsonHash(), - arangodb::basics::JsonEqual()); + std::unordered_map cache(nl + nr); for (size_t i = 0; i < nl + nr; ++i) { AstNode* member; @@ -1097,9 +1092,9 @@ AstNode* Ast::createNodeUnionizedArray(AstNode const* lhs, AstNode const* rhs) { } else { member = rhs->getMemberUnchecked(i - nl); } - auto json = member->computeJson(); + VPackSlice slice = member->computeValue(); - cache.emplace(json, member); + cache.emplace(slice, member); } auto node = createNodeArray(); @@ -2039,16 +2034,14 @@ AstNode const* Ast::deduplicateArray(AstNode const* node) { // TODO: sort values in place first and compare two adjacent members each - std::unordered_map - cache(n, arangodb::basics::JsonHash(), arangodb::basics::JsonEqual()); + std::unordered_map cache(n); for (size_t i = 0; i < n; ++i) { auto member = node->getMemberUnchecked(i); - auto json = member->computeJson(); + VPackSlice slice = member->computeValue(); - if (cache.find(json) == cache.end()) { - cache.emplace(json, member); + if (cache.find(slice) == cache.end()) { + cache.emplace(slice, member); } } diff --git a/arangod/Aql/AstNode.cpp b/arangod/Aql/AstNode.cpp index 64881ef966..198779e5da 100644 --- a/arangod/Aql/AstNode.cpp +++ b/arangod/Aql/AstNode.cpp @@ -40,6 +40,7 @@ #endif #include +#include #include #include @@ -432,7 +433,7 @@ static bool IsEmptyString(char const* p, size_t length) { //////////////////////////////////////////////////////////////////////////////// AstNode::AstNode(AstNodeType type) - : type(type), flags(0), computedJson(nullptr) {} + : type(type), flags(0), computedValue(nullptr) {} //////////////////////////////////////////////////////////////////////////////// /// @brief create a node, with defining a value type @@ -441,7 +442,7 @@ AstNode::AstNode(AstNodeType type) AstNode::AstNode(AstNodeType type, AstNodeValueType valueType) : AstNode(type) { value.type = valueType; TRI_ASSERT(flags == 0); - TRI_ASSERT(computedJson == nullptr); + TRI_ASSERT(computedValue == nullptr); } //////////////////////////////////////////////////////////////////////////////// @@ -453,7 +454,7 @@ AstNode::AstNode(bool v, AstNodeValueType valueType) TRI_ASSERT(valueType == VALUE_TYPE_BOOL); value.value._bool = v; TRI_ASSERT(flags == 0); - TRI_ASSERT(computedJson == nullptr); + TRI_ASSERT(computedValue == nullptr); } //////////////////////////////////////////////////////////////////////////////// @@ -465,7 +466,7 @@ AstNode::AstNode(int64_t v, AstNodeValueType valueType) TRI_ASSERT(valueType == VALUE_TYPE_INT); value.value._int = v; TRI_ASSERT(flags == 0); - TRI_ASSERT(computedJson == nullptr); + TRI_ASSERT(computedValue == nullptr); } //////////////////////////////////////////////////////////////////////////////// @@ -477,7 +478,7 @@ AstNode::AstNode(char const* v, size_t length, AstNodeValueType valueType) TRI_ASSERT(valueType == VALUE_TYPE_STRING); setStringValue(v, length); TRI_ASSERT(flags == 0); - TRI_ASSERT(computedJson == nullptr); + TRI_ASSERT(computedValue == nullptr); } //////////////////////////////////////////////////////////////////////////////// @@ -487,7 +488,7 @@ AstNode::AstNode(char const* v, size_t length, AstNodeValueType valueType) AstNode::AstNode(Ast* ast, arangodb::basics::Json const& json) : AstNode(getNodeTypeFromJson(json)) { TRI_ASSERT(flags == 0); - TRI_ASSERT(computedJson == nullptr); + TRI_ASSERT(computedValue == nullptr); auto query = ast->query(); @@ -676,7 +677,7 @@ AstNode::AstNode(std::function registerNode, arangodb::basics::Json const& json) : AstNode(getNodeTypeFromJson(json)) { TRI_ASSERT(flags == 0); - TRI_ASSERT(computedJson == nullptr); + TRI_ASSERT(computedValue == nullptr); switch (type) { case NODE_TYPE_ATTRIBUTE_ACCESS: { @@ -830,9 +831,8 @@ AstNode::AstNode(std::function registerNode, //////////////////////////////////////////////////////////////////////////////// AstNode::~AstNode() { - if (computedJson != nullptr) { - TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, computedJson); - computedJson = nullptr; + if (computedValue != nullptr) { + delete[] computedValue; } } @@ -936,21 +936,23 @@ void AstNode::dump(int level) const { #endif //////////////////////////////////////////////////////////////////////////////// -/// @brief compute the JSON for a constant value node -/// the JSON is owned by the node and must not be freed by the caller +/// @brief compute the value for a constant value node +/// the value is owned by the node and must not be freed by the caller /// note that the return value might be NULL in case of OOM //////////////////////////////////////////////////////////////////////////////// -TRI_json_t* AstNode::computeJson() const { +VPackSlice AstNode::computeValue() const { TRI_ASSERT(isConstant()); - if (computedJson == nullptr) { - // note: the following may fail but we do not need to - // check that here - computedJson = toJsonValue(TRI_UNKNOWN_MEM_ZONE); + if (computedValue == nullptr) { + VPackBuilder builder; + toVelocyPackValue(builder); + + computedValue = new uint8_t[builder.size()]; + memcpy(computedValue, builder.data(), builder.size()); } - return computedJson; + return VPackSlice(computedValue); } //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/Aql/AstNode.h b/arangod/Aql/AstNode.h index 5cc72f19e8..1de9ee5df8 100644 --- a/arangod/Aql/AstNode.h +++ b/arangod/Aql/AstNode.h @@ -30,6 +30,8 @@ #include "Basics/json.h" #include "Basics/JsonHelper.h" +#include + #include #include @@ -291,12 +293,12 @@ struct AstNode { #endif ////////////////////////////////////////////////////////////////////////////// - /// @brief compute the JSON for a constant value node - /// the JSON is owned by the node and must not be freed by the caller + /// @brief compute the value for a constant value node + /// the value is owned by the node and must not be freed by the caller /// note that the return value might be NULL in case of OOM ////////////////////////////////////////////////////////////////////////////// - TRI_json_t* computeJson() const; + arangodb::velocypack::Slice computeValue() const; ////////////////////////////////////////////////////////////////////////////// /// @brief sort the members of an (array) node @@ -932,10 +934,10 @@ struct AstNode { private: ////////////////////////////////////////////////////////////////////////////// - /// @brief precomputed JSON value (used when executing expressions) + /// @brief precomputed VPack value (used when executing expressions) ////////////////////////////////////////////////////////////////////////////// - TRI_json_t mutable* computedJson; + uint8_t mutable* computedValue; ////////////////////////////////////////////////////////////////////////////// /// @brief the node's sub nodes diff --git a/arangod/Aql/Expression.cpp b/arangod/Aql/Expression.cpp index bc8409addc..52cf021de6 100644 --- a/arangod/Aql/Expression.cpp +++ b/arangod/Aql/Expression.cpp @@ -104,7 +104,7 @@ Expression::~Expression() { switch (_type) { case JSON: TRI_ASSERT(_data != nullptr); - TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, _data); + delete[] _data; break; case ATTRIBUTE: { @@ -154,9 +154,7 @@ AqlValue$ Expression::execute(arangodb::AqlTransaction* trx, case JSON: { // TODO TRI_ASSERT(_data != nullptr); - VPackBuilder builder; - JsonHelper::toVelocyPack(_data, builder); - return AqlValue$(builder); + return AqlValue$(VPackSlice(_data), AqlValue$::AqlValueType::REFERENCE_STICKY); } case SIMPLE: { @@ -171,22 +169,8 @@ AqlValue$ Expression::execute(arangodb::AqlTransaction* trx, case V8: { TRI_ASSERT(_func != nullptr); - try { - ISOLATE; - return _func->execute(isolate, _ast->query(), trx, argv, startPos, vars, - regs); - } catch (arangodb::basics::Exception& ex) { - if (_ast->query()->verboseErrors()) { - ex.addToMessage(" while evaluating expression "); - auto json = _node->toJson(TRI_UNKNOWN_MEM_ZONE, false); - - if (json != nullptr) { - ex.addToMessage(arangodb::basics::JsonHelper::toString(json)); - TRI_Free(TRI_UNKNOWN_MEM_ZONE, json); - } - } - throw; - } + ISOLATE; + return _func->execute(isolate, _ast->query(), trx, argv, startPos, vars, regs); } case UNPROCESSED: { @@ -408,12 +392,11 @@ void Expression::buildExpression() { if (_type == JSON) { TRI_ASSERT(_data == nullptr); // generate a constant value - _data = _node->toJsonValue(TRI_UNKNOWN_MEM_ZONE); + VPackBuilder builder; + _node->toVelocyPackValue(builder); - if (_data == nullptr) { - THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, - "invalid json in simple expression"); - } + _data = new uint8_t[builder.size()]; + memcpy(_data, builder.data(), builder.size()); } else if (_type == V8) { // generate a V8 expression _func = _executor->generateExpression(_node); @@ -651,16 +634,7 @@ AqlValue$ Expression::executeSimpleExpressionArray( std::vector const& vars, std::vector const& regs) { if (node->isConstant()) { - auto json = node->computeJson(); - - if (json == nullptr) { - THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY); - } - - VPackBuilder builder; - JsonHelper::toVelocyPack(json, builder); - - return AqlValue$(builder); + return AqlValue$(node->computeValue(), AqlValue$::AqlValueType::REFERENCE_STICKY); } size_t const n = node->numMembers(); @@ -689,16 +663,7 @@ AqlValue$ Expression::executeSimpleExpressionObject( std::vector const& vars, std::vector const& regs) { if (node->isConstant()) { - auto json = node->computeJson(); - - if (json == nullptr) { - THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY); - } - - VPackBuilder builder; - JsonHelper::toVelocyPack(json, builder); - - return AqlValue$(builder); + return AqlValue$(node->computeValue(), AqlValue$::AqlValueType::REFERENCE_STICKY); } VPackBuilder builder; @@ -725,15 +690,7 @@ AqlValue$ Expression::executeSimpleExpressionObject( //////////////////////////////////////////////////////////////////////////////// AqlValue$ Expression::executeSimpleExpressionValue(AstNode const* node) { - auto json = node->computeJson(); - - if (json == nullptr) { - THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY); - } - - VPackBuilder builder; - JsonHelper::toVelocyPack(json, builder); - return AqlValue$(builder); + return AqlValue$(node->computeValue(), AqlValue$::AqlValueType::REFERENCE_STICKY); } //////////////////////////////////////////////////////////////////////////////// @@ -1270,14 +1227,14 @@ AqlValue$ Expression::executeSimpleExpressionArithmetic( trx, argv, startPos, vars, regs, true); if (lhs.isObject()) { - return AqlValue$(VelocyPackHelper::NullValue(), AqlValue$::AqlValueType::REFERENCE_STICKY); + return AqlValue$(VelocyPackHelper::NullValue()); } AqlValue$ rhs = executeSimpleExpression(node->getMember(1), trx, argv, startPos, vars, regs, true); if (rhs.isObject()) { - return AqlValue$(VelocyPackHelper::NullValue(), AqlValue$::AqlValueType::REFERENCE_STICKY); + return AqlValue$(VelocyPackHelper::NullValue()); } double const l = lhs.toDouble(); @@ -1298,17 +1255,17 @@ AqlValue$ Expression::executeSimpleExpressionArithmetic( case NODE_TYPE_OPERATOR_BINARY_DIV: if (r == 0.0) { RegisterWarning(_ast, "/", TRI_ERROR_QUERY_DIVISION_BY_ZERO); - return AqlValue$(VelocyPackHelper::NullValue(), AqlValue$::AqlValueType::REFERENCE_STICKY); + return AqlValue$(VelocyPackHelper::NullValue()); } return AqlValue$(builder); case NODE_TYPE_OPERATOR_BINARY_MOD: if (r == 0.0) { RegisterWarning(_ast, "/", TRI_ERROR_QUERY_DIVISION_BY_ZERO); - return AqlValue$(VelocyPackHelper::NullValue(), AqlValue$::AqlValueType::REFERENCE_STICKY); + return AqlValue$(VelocyPackHelper::NullValue()); } builder.add(VPackValue(fmod(l, r))); return AqlValue$(builder); default: - return AqlValue$(VelocyPackHelper::NullValue(), AqlValue$::AqlValueType::REFERENCE_STICKY); + return AqlValue$(VelocyPackHelper::NullValue()); } } diff --git a/arangod/Aql/Expression.h b/arangod/Aql/Expression.h index 89bdfe4108..1b73bc7eb5 100644 --- a/arangod/Aql/Expression.h +++ b/arangod/Aql/Expression.h @@ -490,7 +490,7 @@ class Expression { union { V8Expression* _func; - struct TRI_json_t* _data; + uint8_t* _data; AttributeAccessor* _accessor; }; diff --git a/arangod/Aql/OptimizerRules.cpp b/arangod/Aql/OptimizerRules.cpp index 6b2ede4efe..998f2e8ac2 100644 --- a/arangod/Aql/OptimizerRules.cpp +++ b/arangod/Aql/OptimizerRules.cpp @@ -668,8 +668,7 @@ class PropagateConstantAttributesHelper { return; } - if (TRI_CompareValuesJson(value->computeJson(), previous->computeJson(), - true) != 0) { + if (!value->computeValue().equals(previous->computeValue())) { // different value found for an already tracked attribute. better not // use this attribute (*it2).second = nullptr;