Skip to content

Commit 265b74c

Browse files
committed
wip: memory-issue-root-and-sub-children
1 parent 6098d71 commit 265b74c

File tree

8 files changed

+299
-1
lines changed

8 files changed

+299
-1
lines changed

spec/regression/traversal-performance/model/model.graphqls

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,13 @@ type Root @rootEntity {
1212
children: [Child]
1313
grandchildren: [Grandchild] @collect(path: "children.children")
1414
extensionGrandchildren: [ExtensionGrandchild] @collect(path: "children.extension.children")
15+
16+
# 5 MB random string. Should not be queried because it's not stable
17+
# it's just used to we see whether the reduce-extraction-to-projection optimization works
1518
payload: String
19+
20+
# 100 KB predictable string. Can be queried.
21+
predictablePayload: String
1622
}
1723

1824
type Child @childEntity {

spec/regression/traversal-performance/test-data.ts

Lines changed: 5 additions & 0 deletions
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
LET v_root1 = FIRST((
2+
FOR v_root2
3+
IN @@roots
4+
FILTER (v_root2.`key` == @var1)
5+
LIMIT @var2
6+
RETURN v_root2
7+
))
8+
RETURN {
9+
"Root": (IS_NULL(v_root1) ? null : {
10+
"predictablePayload": v_root1.`predictablePayload`,
11+
"children": v_root1.`children`[* RETURN {
12+
"root": {
13+
"key": v_root1.`key`
14+
},
15+
"children": CURRENT.`children`[* RETURN {
16+
"key": CURRENT.`key`
17+
}]
18+
}]
19+
})
20+
}
21+
22+
// Peak memory usage: 10190848 bytes
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
LET v_root1 = FIRST((
2+
FOR v_root2
3+
IN @@roots
4+
FILTER (v_root2.`key` == @var1)
5+
LIMIT @var2
6+
RETURN v_root2
7+
))
8+
RETURN {
9+
"Root": (IS_NULL(v_root1) ? null : {
10+
"predictablePayload": v_root1.`predictablePayload`,
11+
"children": (
12+
FOR v_item1
13+
IN v_root1.`children`[*]
14+
RETURN {
15+
"root": {
16+
"key": v_root1.`key`
17+
},
18+
"children": (
19+
FOR v_item2
20+
IN v_item1.`children`[*]
21+
SORT (v_item2.`key`)
22+
RETURN {
23+
"key": v_item2.`key`
24+
}
25+
)
26+
}
27+
)
28+
})
29+
}
30+
31+
// Peak memory usage: 61243392 bytes
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"authRoles": ["user"],
3+
// we request the payload here. Pay close attention to actual memory usage in the .aql files
4+
"queryMemoryLimit": "100000000"
5+
}

spec/regression/traversal-performance/tests/root-and-sub-children/result.json

Lines changed: 157 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
query fieldTraversal_andChildEntitiesWithArrayExpansion {
2+
Root(key: "root1") {
3+
# this is a big field. query it so we're sure it is loaded from disk
4+
predictablePayload
5+
6+
children {
7+
# accessing root in a child entity subquery can lead to the root being copied into a
8+
# register for each child. This happens if there is another subquery, that's why we're
9+
# querying the children's children.
10+
root {
11+
key
12+
}
13+
children {
14+
key
15+
}
16+
}
17+
}
18+
}
19+
20+
query fieldTraversal_andChildEntitiesWithSubquery {
21+
Root(key: "root1") {
22+
predictablePayload
23+
24+
children {
25+
root {
26+
key
27+
}
28+
# without order, the children can be fetched via an array expansion expression, which
29+
# avoids the problem outlined above - but this no longer works if there is sorting
30+
# because SORT is not supported in array expansion expressions
31+
children(orderBy: key_ASC) {
32+
key
33+
}
34+
}
35+
}
36+
}
37+
38+
query relationAndFieldTraversal_andChildEntitiesWithSubquery {
39+
Super(key: "root1") {
40+
rootChildren {
41+
root {
42+
predictablePayload
43+
}
44+
45+
children(orderBy: key_ASC) {
46+
key
47+
}
48+
}
49+
}
50+
}

src/schema-generation/field-nodes.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,30 @@ export function createFieldNode(
138138
return createToNRelationNode(field, sourceNode);
139139
}
140140

141-
// there are no lists of references
141+
// note: there are no lists of references
142+
143+
// TraversalQueryNode has support for filtering, sorting, paging etc. and those cases
144+
// are optimized in the aql-generator
145+
if (field.type.isChildEntityType) {
146+
return new TraversalQueryNode({
147+
sourceEntityNode: sourceNode,
148+
fieldSegments: [
149+
{
150+
field,
151+
isListSegment: true,
152+
resultingType: field.type,
153+
isNullableSegment: false,
154+
resultIsList: true,
155+
kind: 'field',
156+
resultIsNullable: false,
157+
resultMayContainDuplicateEntities: false,
158+
},
159+
],
160+
relationSegments: [],
161+
});
162+
}
142163

164+
// TODO aql-perf can we use TraversalQueryNode for other lists too?
143165
return createSafeListQueryNode(new FieldQueryNode(sourceNode, field));
144166
}
145167

0 commit comments

Comments
 (0)