8000 speed up query string parsing (#7115) · sita1999/arangodb@7765a48 · GitHub
[go: up one dir, main page]

Skip to content

Commit 7765a48

Browse files
authored
speed up query string parsing (arangodb#7115)
1 parent d30cf31 commit 7765a48

19 files changed

+462
-306
lines changed

arangod/Aql/Ast.cpp

Lines changed: 233 additions & 164 deletions
Large diffs are not rendered by default.

arangod/Aql/Ast.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,9 @@ class Ast {
611611

612612
/// @brief whether or not the query contains a traversal
613613
bool _containsTraversal;
614+
615+
/// @brief whether or not the query contains bind parameters
616+
bool _containsBindParameters;
614617

615618
/// @brief a singleton no-op node instance
616619
static AstNode const NopNode;

arangod/Aql/AstNode.cpp

Lines changed: 30 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -374,42 +374,12 @@ AstNode::AstNode(AstNodeType type)
374374
value.type = VALUE_TYPE_NULL;
375375
}
376376

377-
/// @brief create a node, with defining a value type
378-
AstNode::AstNode(AstNodeType type, AstNodeValueType valueType) : AstNode(type) {
379-
value.type = valueType;
380-
TRI_ASSERT(flags == 0);
381-
TRI_ASSERT(computedValue == nullptr);
382-
}
383-
384-
/// @brief create a boolean node, with defining a value
385-
AstNode::AstNode(bool v, AstNodeValueType valueType)
386-
: AstNode(NODE_TYPE_VALUE, valueType) {
387-
TRI_ASSERT(valueType == VALUE_TYPE_BOOL);
388-
value.value._bool = v;
389-
TRI_ASSERT(flags == 0);
390-
TRI_ASSERT(computedValue == nullptr);
391-
setFlag(DETERMINED_CONSTANT, VALUE_CONSTANT);
392-
}
393-
394-
/// @brief create an int node, with defining a value
395-
AstNode::AstNode(int64_t v, AstNodeValueType valueType)
396-
: AstNode(NODE_TYPE_VALUE, valueType) {
397-
TRI_ASSERT(valueType == VALUE_TYPE_INT);
398-
value.value._int = v;
399-
TRI_ASSERT(flags == 0);
400-
TRI_ASSERT(computedValue == nullptr);
401-
setFlag(DETERMINED_CONSTANT, VALUE_CONSTANT);
402-
}
403-
404-
/// @brief create a string node, with defining a value
405-
AstNode::AstNode(char const* v, size_t length, AstNodeValueType valueType)
406-
: AstNode(NODE_TYPE_VALUE, valueType) {
407-
TRI_ASSERT(valueType == VALUE_TYPE_STRING);
408-
setStringValue(v, length);
409-
TRI_ASSERT(flags == 0);
410-
TRI_ASSERT(computedValue == nullptr);
411-
setFlag(DETERMINED_CONSTANT, VALUE_CONSTANT);
412-
}
377+
/// @brief create a node, with defining a value
378+
AstNode::AstNode(AstNodeValue value)
379+
: type(NODE_TYPE_VALUE),
380+
flags(makeFlags(DETERMINED_CONSTANT, VALUE_CONSTANT, DETERMINED_SIMPLE, VALUE_SIMPLE, DETERMINED_RUNONDBSERVER, VALUE_RUNONDBSERVER)),
381+
value(value),
382+
computedValue(nullptr) {}
413383

414384
/// @brief create the node from VPack
415385
AstNode::AstNode(Ast* ast, arangodb::velocypack::Slice const& slice)
@@ -619,7 +589,7 @@ AstNode::AstNode(Ast* ast, arangodb::velocypack::Slice const& slice)
619589
}
620590

621591
/// @brief create the node
622-
AstNode::AstNode(std::function<void(AstNode*)> registerNode,
592+
AstNode::AstNode(std::function<void(AstNode*)> const& registerNode,
623593
std::function<char const*(std::string const&)> registerString,
624594
arangodb::velocypack::Slice const& slice)
625595
: AstNode(getNodeTypeFromVPack(slice)) {
@@ -999,34 +969,31 @@ void AstNode::toVelocyPackValue(VPackBuilder& builder) const {
999969
return;
1000970
}
1001971
if (type == NODE_TYPE_ARRAY) {
1002-
{
1003-
VPackArrayBuilder guard(&builder);
1004-
size_t const n = numMembers();
1005-
for (size_t i = 0; i < n; ++i) {
1006-
auto member = getMemberUnchecked(i);
1007-
if (member != nullptr) {
1008-
member->toVelocyPackValue(builder);
1009-
}
972+
builder.openArray(false);
973+
size_t const n = numMembers();
974+
for (size_t i = 0; i < n; ++i) {
975+
auto member = getMemberUnchecked(i);
976+
if (member != nullptr) {
977+
member->toVelocyPackValue(builder);
1010978
}
1011979
}
980+
builder.close();
1012981
return;
1013982
}
1014983

1015984
if (type == NODE_TYPE_OBJECT) {
1016-
{
1017-
size_t const n = numMembers();
1018-
VPackObjectBuilder guard(&builder);
1019-
1020-
for (size_t i = 0; i < n; ++i) {
1021-
auto member = getMemberUnchecked(i);
1022-
if (member != nullptr) {
1023-
builder.add(VPackValuePair(member->getStringValue(),
1024-
member->getStringLength(),
1025-
VPackValueType::String));
1026-
member->getMember(0)->toVelocyPackValue(builder);
1027-
}
985+
builder.openObject();
986+
size_t const n = numMembers();
987+
for (size_t i = 0; i < n; ++i) {
988+
auto member = getMemberUnchecked(i);
989+
if (member != nullptr) {
990+
builder.add(VPackValuePair(member->getStringValue(),
991+
member->getStringLength(),
992+
VPackValueType::String));
993+
member->getMember(0)->toVelocyPackValue(builder);
1028994
}
1029995
}
996+
builder.close();
1030997
return;
1031998
}
1032999

@@ -1132,13 +1099,14 @@ void AstNode::toVelocyPack(VPackBuilder& builder, bool verbose) const {
11321099
size_t const n = members.size();
11331100
if (n > 0) {
11341101
builder.add(VPackValue("subNodes"));
1135-
VPackArrayBuilder guard(&builder);
1102+
builder.openArray(false);
11361103
for (size_t i = 0; i < n; ++i) {
11371104
AstNode* member = getMemberUnchecked(i);
11381105
if (member != nullptr) {
11391106
member->toVelocyPack(builder, verbose);
11401107
}
11411108
}
1109+
builder.close();
11421110
}
11431111
}
11441112

@@ -1151,13 +1119,11 @@ bool AstNode::containsNodeType(AstNodeType searchType) const {
11511119
// iterate sub-nodes
11521120
size_t const n = members.size();
11531121

1154-
if (n > 0) {
1155-
for (size_t i = 0; i < n; ++i) {
1156-
AstNode* member = getMemberUnchecked(i);
1122+
for (size_t i = 0; i < n; ++i) {
1123+
AstNode* member = getMemberUnchecked(i);
11571124

1158-
if (member != nullptr && member->containsNodeType(searchType)) {
1159-
return true;
1160-
}
1125+
if (member != nullptr && member->containsNodeType(searchType)) {
1126+
return true;
11611127
}
11621128
}
11631129

arangod/Aql/AstNode.h

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ enum AstNodeFlagType : AstNodeFlagsType {
7171
FLAG_BIND_PARAMETER = 0x0020000, // node was created from a bind parameter
7272
FLAG_FINALIZED = 0x0040000, // node has been finalized and should not be modified; only set and checked in maintainer mode
7373
};
74-
74+
7575
/// @brief enumeration of AST node value types
7676
/// note: these types must be declared in asc. sort order
7777
enum AstNodeValueType : uint8_t {
@@ -93,15 +93,29 @@ static_assert(VALUE_TYPE_DOUBLE < VALUE_TYPE_STRING,
9393

9494
/// @brief AST node value
9595
struct AstNodeValue {
96-
union {
96+
union Value {
9797
int64_t _int;
9898
double _double;
9999
bool _bool;
100100
char const* _string;
101101
void* _data;
102-
} value;
102+
103+
// constructors for union values
104+
explicit Value(int64_t value) : _int(value) {}
105+
explicit Value(double value) : _double(value) {}
106+
explicit Value(bool value) : _bool(value) {}
107+
explicit Value(char const* value) : _string(value) {}
108+
};
109+
110+
Value value;
103111
uint32_t length; // only used for string values
104112
AstNodeValueType type;
113+
114+
AstNodeValue() : value(int64_t(0)), length(0), type(VALUE_TYPE_NULL) {}
115+
explicit AstNodeValue(int64_t value) : value(value), length(0), type(VALUE_TYPE_INT) {}
116+
explicit AstNodeValue(double value) : value(value), length(0), type(VALUE_TYPE_DOUBLE) {}
117+
explicit AstNodeValue(bool value) : value(value), length(0), type(VALUE_TYPE_BOOL) {}
118+
explicit AstNodeValue(char const* value, uint32_t length) : value(value), length(length), type(VALUE_TYPE_STRING) {}
105119
};
106120

107121
/// @brief enumeration of AST node types
@@ -197,28 +211,29 @@ struct AstNode {
197211
static std::unordered_map<int, std::string const> const TypeNames;
198212
static std::unordered_map<int, std::string const> const ValueTypeNames;
199213

214+
/// @brief helper for building flags
215+
template <typename... Args>
216+
static inline std::underlying_type<AstNodeFlagType>::type makeFlags(AstNodeFlagType flag, Args... args) {
217+
return static_cast<std::underlying_type<AstNodeFlagType>::type>(flag) + makeFlags(args...);
218+
}
219+
220+
static inline std::underlying_type<AstNodeFlagType>::type makeFlags() {
221+
return static_cast<std::underlying_type<AstNodeFlagType>::type>(0);
222+
}
223+
200224
/// @brief create the node
201225
explicit AstNode(AstNodeType);
202-
203-
/// @brief create a node, with defining a value type
204-
AstNode(AstNodeType, AstNodeValueType);
205-
206-
/// @brief create a boolean node, with defining a value type
207-
AstNode(bool, AstNodeValueType);
208-
209-
/// @brief create a boolean node, with defining a value type
210-
AstNode(int64_t, AstNodeValueType);
211-
212-
/// @brief create a string node, with defining a value type
213-
AstNode(char const*, size_t, AstNodeValueType);
226+
227+
/// @brief create a node, with defining a value
228+
explicit AstNode(AstNodeValue value);
214229

215230
/// @brief create the node from VPack
216-
AstNode(Ast*, arangodb::velocypack::Slice const& slice);
231+
explicit AstNode(Ast*, arangodb::velocypack::Slice const& slice);
217232

218233
/// @brief create the node from VPack
219-
AstNode(std::function<void(AstNode*)> registerNode,
220-
std::function<char const*(std::string const&)> registerString,
221-
arangodb::velocypack::Slice const& slice);
234+
explicit AstNode(std::function<void(AstNode*)> const& registerNode,
235+
std::function<char const*(std::string const&)> registerString,
236+
arangodb::velocypack::Slice const& slice);
222237

223238
/// @brief destroy the node
224239
~AstNode();
@@ -314,6 +329,11 @@ struct AstNode {
314329
AstNodeFlagType valueFlag) const {
315330
flags |= (typeFlag | valueFlag);
316331
}
332+
333+
/// @brief remove a flag for the node
334+
inline void removeFlag(AstNodeFlagType flag) const {
335+
flags &= ~flag;
336+
}
317337

318338
/// @brief whether or not the node value is trueish
319339
bool isTrue() const;

arangod/Aql/ExecutionPlan.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,10 @@ ExecutionPlan* ExecutionPlan::clone(Query const& query) {
358358
/// @brief export to VelocyPack
359359
std::shared_ptr<VPackBuilder> ExecutionPlan::toVelocyPack(Ast* ast,
360360
bool verbose) const {
361-
auto builder = std::make_shared<VPackBuilder>();
361+
VPackOptions options;
362+
options.checkAttributeUniqueness = false;
363+
options.buildUnindexedArrays = true;
364+
auto builder = std::make_shared<VPackBuilder>(&options);
362365

363366
toVelocyPack(*builder, ast, verbose);
364367
return builder;

arangod/Aql/Parser.cpp

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ bool Parser::configureWriteQuery(AstNode const* collectionNode,
7575
}
7676

7777
/// @brief parse the query
78-
QueryResult Parser::parse(bool withDetails) {
78+
void Parser::parse() {
7979
if (queryString().empty() || remainingLength() == 0) {
8080
THROW_ARANGO_EXCEPTION(TRI_ERROR_QUERY_EMPTY);
8181
}
@@ -111,14 +111,16 @@ QueryResult Parser::parse(bool withDetails) {
111111
}
112112

113113
TRI_ASSERT(scopes->numActive() == 0);
114+
}
114115

115-
QueryResult result;
116+
/// @brief parse the query and retun parse details
117+
QueryResult Parser::parseWithDetails() {
118+
parse();
116119

117-
if (withDetails) {
118-
result.collectionNames = _query->collectionNames();
119-
result.bindParameters = _ast->bindParameters();
120-
result.result = _ast->toVelocyPack(false);
121-
}
120+
QueryResult result;
121+
result.collectionNames = _query->collectionNames();
122+
result.bindParameters = _ast->bindParameters();
123+
result.result = _ast->toVelocyPack(false);
122124

123125
return result;
124126
}
@@ -180,11 +182,31 @@ void Parser::registerWarning(int errorCode, char const* data, int line,
180182
_query->registerWarning(errorCode, data);
181183
}
182184

185+
/// @brief push an AstNode array element on top of the stack
186+
/// the array must be removed from the stack via popArray
187+
void Parser::pushArray(AstNode* array) {
188+
TRI_ASSERT(array->type == NODE_TYPE_ARRAY);
189+
array->setFlag(DETERMINED_CONSTANT, VALUE_CONSTANT);
190+
pushStack(array);
191+
}
192+
193+
/// @brief pop an array value from the parser's stack
194+
/// the array must have been added to the stack via pushArray
195+
AstNode* Parser::popArray() {
196+
AstNode* array = static_cast<AstNode*>(popStack());
197+
TRI_ASSERT(array->type == NODE_TYPE_ARRAY);
198+
return array;
199+
}
200+
183201
/// @brief push an AstNode into the array element on top of the stack
184202
void Parser::pushArrayElement(AstNode* node) {
185203
auto array = static_cast<AstNode*>(peekStack());
186204
TRI_ASSERT(array->type == NODE_TYPE_ARRAY);
187205
array->addMember(node);
206+
if (array->hasFlag(AstNodeFlagType::VALUE_CONSTANT) &&
207+
!node->isConstant()) {
208+
array->removeFlag(AstNodeFlagType::VALUE_CONSTANT);
209+
}
188210
}
189211

190212
/// @brief push an AstNode into the object element on top of the stack

arangod/Aql/Parser.h

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,10 @@ class Parser {
9494
bool configureWriteQuery(AstNode const*, AstNode* optionNode);
9595

9696
/// @brief parse the query
97-
QueryResult parse(bool);
97+
void parse();
98+
99+
/// @brief parse the query and return parse details
100+
QueryResult parseWithDetails();
98101

99102
/// @brief register a parse error, position is specified as line / column
100103
void registerParseError(int, char const*, char const*, int, int);
@@ -107,7 +110,15 @@ class Parser {
107110

108111
/// @brief register a warning
109112
void registerWarning(int, char const*, int, int);
110-
113+
114+
/// @brief push an AstNode array element on top of the stack
115+
/// the array must be removed from the stack via popArray
116+
void pushArray(AstNode* array);
117+
118+
/// @brief pop an array value from the parser's stack
119+
/// the array must have been added to the stack via pushArray
120+
AstNode* popArray();
121+
111122
/// @brief push an AstNode into the array element on top of the stack
112123
void pushArrayElement(AstNode*);
113124

arangod/Aql/Query.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -461,8 +461,8 @@ ExecutionPlan* Query::preparePlan() {
461461

462462
if (!_queryString.empty()) {
463463
Parser parser(this);
464+
parser.parse();
464465

465-
parser.parse(false);
466466
// put in bind parameters
467467
parser.ast()->injectBindParameters(_bindParameters, ctx->resolver());
468468
}
@@ -1004,7 +1004,7 @@ QueryResult Query::parse() {
10041004
try {
10051005
init();
10061006
Parser parser(this);
1007-
return parser.parse(true);
1007+
return parser.parseWithDetails();
10081008
} catch (arangodb::basics::Exception const& ex) {
10091009
return QueryResult(ex.code(), ex.message());
10101010
} catch (std::bad_alloc const&) {
@@ -1028,8 +1028,7 @@ QueryResult Query::explain() {
10281028

10291029
auto ctx = createTransactionContext();
10301030
Parser parser(this);
1031-
1032-
parser.parse(true);
1031+
parser.parse();
10331032

10341033
// put in bind parameters
10351034
parser.ast()->injectBindParameters(_bindParameters, ctx->resolver());

0 commit comments

Comments
 (0)
0