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
         '''
     }