You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2020/11/07 09:08:48 UTC
[groovy] branch tweak-ginq-20201107 created (now cf0bb0f)
This is an automated email from the ASF dual-hosted git repository.
sunlan pushed a change to branch tweak-ginq-20201107
in repository https://gitbox.apache.org/repos/asf/groovy.git.
at cf0bb0f Share alias list with every records to reduce memory usage
This branch includes the following new commits:
new cf0bb0f Share alias list with every records to reduce memory usage
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
[groovy] 01/01: Share alias list with every records to reduce
memory usage
Posted by su...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
sunlan pushed a commit to branch tweak-ginq-20201107
in repository https://gitbox.apache.org/repos/asf/groovy.git
commit cf0bb0fe9f7fdb344aa4b1131899dbbed21c2849
Author: Daniel Sun <su...@apache.org>
AuthorDate: Sat Nov 7 17:05:31 2020 +0800
Share alias list with every records to reduce memory usage
---
.../ginq/provider/collection/GinqAstWalker.groovy | 58 +++++++++++++++++-----
.../test/org/apache/groovy/ginq/GinqTest.groovy | 8 +--
2 files changed, 48 insertions(+), 18 deletions(-)
diff --git a/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/GinqAstWalker.groovy b/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/GinqAstWalker.groovy
index f91ba37..2528a41 100644
--- a/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/GinqAstWalker.groovy
+++ b/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/GinqAstWalker.groovy
@@ -39,6 +39,7 @@ import org.apache.groovy.ginq.provider.collection.runtime.Queryable
import org.apache.groovy.ginq.provider.collection.runtime.QueryableHelper
import org.codehaus.groovy.GroovyBugError
import org.codehaus.groovy.ast.ClassHelper
+import org.codehaus.groovy.ast.ClassNode
import org.codehaus.groovy.ast.expr.ArgumentListExpression
import org.codehaus.groovy.ast.expr.BinaryExpression
import org.codehaus.groovy.ast.expr.CastExpression
@@ -60,14 +61,19 @@ import org.codehaus.groovy.syntax.Types
import java.util.stream.Collectors
+import static org.codehaus.groovy.ast.ClassHelper.make
import static org.codehaus.groovy.ast.tools.GeneralUtils.args
+import static org.codehaus.groovy.ast.tools.GeneralUtils.block
import static org.codehaus.groovy.ast.tools.GeneralUtils.callX
import static org.codehaus.groovy.ast.tools.GeneralUtils.ctorX
+import static org.codehaus.groovy.ast.tools.GeneralUtils.declS
import static org.codehaus.groovy.ast.tools.GeneralUtils.lambdaX
+import static org.codehaus.groovy.ast.tools.GeneralUtils.localVarX
import static org.codehaus.groovy.ast.tools.GeneralUtils.param
import static org.codehaus.groovy.ast.tools.GeneralUtils.params
import static org.codehaus.groovy.ast.tools.GeneralUtils.propX
import static org.codehaus.groovy.ast.tools.GeneralUtils.stmt
+import static org.codehaus.groovy.ast.tools.GeneralUtils.varX
/**
* Visit AST of GINQ to generate target method calls for GINQ
@@ -76,9 +82,6 @@ import static org.codehaus.groovy.ast.tools.GeneralUtils.stmt
*/
@CompileStatic
class GinqAstWalker implements GinqAstVisitor<Expression>, SyntaxErrorReportable {
- private final SourceUnit sourceUnit
- private final Deque<GinqExpression> ginqExpressionStack = new ArrayDeque<>()
-
GinqAstWalker(SourceUnit sourceUnit) {
this.sourceUnit = sourceUnit
}
@@ -149,9 +152,18 @@ class GinqAstWalker implements GinqAstVisitor<Expression>, SyntaxErrorReportable
MethodCallExpression selectMethodCallExpression = this.visitSelectExpression(selectExpression)
+ final Tuple2<String, ListExpression> aliasListExpression = this.aliasListExpression
ginqExpressionStack.pop()
- return selectMethodCallExpression
+ return callX(
+ lambdaX(block(
+ declS(
+ localVarX(aliasListExpression.v1),
+ callX(COLLECTIONS_TYPE, "unmodifiableList", aliasListExpression.v2)
+ ),
+ stmt(selectMethodCallExpression)
+ )),
+ "call")
}
@Override
@@ -315,7 +327,7 @@ class GinqAstWalker implements GinqAstVisitor<Expression>, SyntaxErrorReportable
LambdaExpression lambdaExpression = constructLambdaExpression(dataSourceExpression, target)
- return ctorX(ClassHelper.make(Queryable.Order.class), args(lambdaExpression, new ConstantExpression(asc)))
+ return ctorX(ORDER_TYPE, args(lambdaExpression, new ConstantExpression(asc)))
}).collect(Collectors.toList())
def orderMethodCallExpression = callX(orderMethodCallReceiver, "orderBy", args(orderCtorCallExpressions))
@@ -378,11 +390,23 @@ class GinqAstWalker implements GinqAstVisitor<Expression>, SyntaxErrorReportable
}
ConstructorCallExpression namedRecordCtorCallExpression =
- ctorX(ClassHelper.make(NamedRecord.class), args(new ListExpression(elementExpressionList),
- new ListExpression(nameExpressionList), new ListExpression(aliasExpressionList)))
+ ctorX(NAMEDRECORD_TYPE, args(new ListExpression(elementExpressionList),
+ new ListExpression(nameExpressionList), varX(aliasListExpression.v1)))
return namedRecordCtorCallExpression
}
+ private int aliasVarSeq = 0
+ private Tuple2<String, ListExpression> getAliasListExpression() {
+ Tuple2<String, ListExpression> aliasListExpression = (Tuple2<String, ListExpression>) currentGinqExpression.getNodeMetaData(__ALIAS_LIST)
+
+ if (!aliasListExpression) {
+ aliasListExpression = Tuple.tuple("${__ALIAS_LIST_VAR}${aliasVarSeq++}".toString(), new ListExpression(aliasExpressionList))
+ currentGinqExpression.putNodeMetaData(__ALIAS_LIST, aliasListExpression)
+ }
+
+ return aliasListExpression
+ }
+
private List<Expression> getAliasExpressionList() {
dataSourceAliasList.stream()
.map(e -> new ConstantExpression(e))
@@ -433,6 +457,7 @@ class GinqAstWalker implements GinqAstVisitor<Expression>, SyntaxErrorReportable
if (expression instanceof VariableExpression) {
if (expression.isThisExpression()) return expression
if (expression.text && Character.isUpperCase(expression.text.charAt(0))) return expression // type should not be transformed
+ if (expression.text.startsWith(__ALIAS_LIST_VAR)) return expression
if (groupByVisited) { // groupby
// in #1, we will correct receiver of built-in aggregate functions
@@ -442,9 +467,9 @@ class GinqAstWalker implements GinqAstVisitor<Expression>, SyntaxErrorReportable
if (_G == expression.text) {
transformedExpression =
callX(
- new ClassExpression(ClassHelper.make(QueryableHelper.class)),
+ new ClassExpression(QUERYABLE_HELPER_TYPE),
"navigate",
- args(new VariableExpression(lambdaParamName), new ListExpression(aliasExpressionList))
+ args(new VariableExpression(lambdaParamName), varX(aliasListExpression.v1))
)
} else {
transformedExpression = isJoin
@@ -563,9 +588,9 @@ class GinqAstWalker implements GinqAstVisitor<Expression>, SyntaxErrorReportable
)
}
- private int seq = 0
+ private int lambdaParamSeq = 0
private String generateLambdaParamName() {
- "__t_${seq++}"
+ "__t_${lambdaParamSeq++}"
}
private Tuple2<String, Expression> correctVariablesOfLambdaExpression(DataSourceExpression dataSourceExpression, Expression lambdaCode) {
@@ -608,7 +633,7 @@ class GinqAstWalker implements GinqAstVisitor<Expression>, SyntaxErrorReportable
}
private static ClassExpression makeQueryableCollectionClassExpression() {
- new ClassExpression(ClassHelper.make(Queryable.class))
+ new ClassExpression(QUERYABLE_TYPE)
}
@Override
@@ -616,8 +641,17 @@ class GinqAstWalker implements GinqAstVisitor<Expression>, SyntaxErrorReportable
sourceUnit
}
+ private final SourceUnit sourceUnit
+ private final Deque<GinqExpression> ginqExpressionStack = new ArrayDeque<>()
+ private static final ClassNode QUERYABLE_HELPER_TYPE = make(QueryableHelper.class)
+ private static final ClassNode COLLECTIONS_TYPE = make(Collections.class)
+ private static final ClassNode ORDER_TYPE = make(Queryable.Order.class)
+ private static final ClassNode NAMEDRECORD_TYPE = make(NamedRecord.class)
+ private static final ClassNode QUERYABLE_TYPE = make(Queryable.class)
private static final String __METHOD_CALL_RECEIVER = "__methodCallReceiver"
private static final String __GROUPBY_VISITED = "__groupByVisited"
private static final String __LAMBDA_PARAM_NAME = "__LAMBDA_PARAM_NAME"
+ private static final String __ALIAS_LIST = "__ALIAS_LIST"
+ private static final String __ALIAS_LIST_VAR = '__aliasList_'
private static final String _G = '_g' // the implicit variable representing grouped `Queryable` object
}
diff --git a/subprojects/groovy-ginq/src/spec/test/org/apache/groovy/ginq/GinqTest.groovy b/subprojects/groovy-ginq/src/spec/test/org/apache/groovy/ginq/GinqTest.groovy
index f09d6dc..675fd8e 100644
--- a/subprojects/groovy-ginq/src/spec/test/org/apache/groovy/ginq/GinqTest.groovy
+++ b/subprojects/groovy-ginq/src/spec/test/org/apache/groovy/ginq/GinqTest.groovy
@@ -2204,13 +2204,9 @@ class GinqTest {
}
@Test
- void "testGinq - as List - 2"() {
+ void "testGinq - as Set - 1"() {
assertScript '''
- @groovy.transform.CompileStatic
- def x() {
- GQ {from n in 1..<11 where n % 2 == 0 select n ** 2} as List
- }
- assert [4, 16, 36, 64, 100] == x()
+ assert [4, 16, 36, 64, 100] as Set == GQ {from n in 1..<11 where n % 2 == 0 select n ** 2} as Set
'''
}