You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by ko...@apache.org on 2025/04/10 06:12:49 UTC

(ignite-3) branch main updated: IGNITE-24918 Sql. Prevent MergeJoin from scheduling more tasks when it's going to finish (#5595)

This is an automated email from the ASF dual-hosted git repository.

korlov pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git


The following commit(s) were added to refs/heads/main by this push:
     new 6ca607daa0f IGNITE-24918 Sql. Prevent MergeJoin from scheduling more tasks when it's going to finish (#5595)
6ca607daa0f is described below

commit 6ca607daa0fd9bc3ceefbdd7464f36cc8ef85f80
Author: korlov42 <ko...@apache.org>
AuthorDate: Thu Apr 10 09:12:45 2025 +0300

    IGNITE-24918 Sql. Prevent MergeJoin from scheduling more tasks when it's going to finish (#5595)
---
 .../sql/engine/ItDeleteWithSubQueryTest.java       |  60 +++++++++++++
 .../sql/engine/exec/rel/MergeJoinNode.java         | 100 ++++++++++++---------
 .../internal/sql/engine/exec/rel/ScanNode.java     |   2 +-
 3 files changed, 121 insertions(+), 41 deletions(-)

diff --git a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDeleteWithSubQueryTest.java b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDeleteWithSubQueryTest.java
new file mode 100644
index 00000000000..0090ef3cf74
--- /dev/null
+++ b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDeleteWithSubQueryTest.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.sql.engine;
+
+import static org.apache.ignite.internal.sql.engine.util.QueryChecker.matchesOnce;
+
+import org.apache.ignite.internal.sql.BaseSqlIntegrationTest;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Test in this class requires special conditions to met to highlight the problem.
+ *
+ * <p>First condition is operation must be in RW transaction. Second, custer should be of
+ * size of a single node, so transaction finalisation doesn't involve any network calls.
+ * Last but not least, operation must involve MergeJoin node which is source of problem. 
+ */
+public class ItDeleteWithSubQueryTest extends BaseSqlIntegrationTest {
+
+    @Override
+    protected int initialNodes() {
+        return 1;
+    }
+
+    @AfterEach
+    public void dropTables() {
+        dropAllTables();
+    }
+
+    @Test
+    void test() {
+        //noinspection ConcatenationWithEmptyString
+        sqlScript("" 
+                + "CREATE TABLE t1 (id INT PRIMARY KEY, val INT);"
+                + "CREATE TABLE t2 (id INT PRIMARY KEY, val INT);"
+        );
+
+        for (int i = 0; i < 100; i++) {
+            assertQuery("DELETE FROM t1 WHERE id IN (SELECT id FROM t2 WHERE val > 10)")
+                    .matches(matchesOnce("MergeJoin"))
+                    .returns(0L)
+                    .check();
+        }
+    }
+}
diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/rel/MergeJoinNode.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/rel/MergeJoinNode.java
index 6cc06028b7d..0b70cb40ef9 100644
--- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/rel/MergeJoinNode.java
+++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/rel/MergeJoinNode.java
@@ -146,7 +146,9 @@ public abstract class MergeJoinNode<RowT> extends AbstractNode<RowT> {
 
         leftInBuf.add(row);
 
-        join();
+        if (waitingLeft == 0 && waitingRight <= 0) {
+            join();
+        }
     }
 
     private void pushRight(RowT row) throws Exception {
@@ -157,7 +159,9 @@ public abstract class MergeJoinNode<RowT> extends AbstractNode<RowT> {
 
         rightInBuf.add(row);
 
-        join();
+        if (waitingRight == 0 && waitingLeft <= 0) {
+            join();
+        }
     }
 
     private void endLeft() throws Exception {
@@ -166,7 +170,9 @@ public abstract class MergeJoinNode<RowT> extends AbstractNode<RowT> {
 
         waitingLeft = NOT_WAITING;
 
-        join();
+        if (waitingRight <= 0) {
+            join();
+        }
     }
 
     private void endRight() throws Exception {
@@ -175,7 +181,9 @@ public abstract class MergeJoinNode<RowT> extends AbstractNode<RowT> {
 
         waitingRight = NOT_WAITING;
 
-        join();
+        if (waitingLeft <= 0) {
+            join();
+        }
     }
 
     protected Node<RowT> leftSource() {
@@ -400,6 +408,15 @@ public abstract class MergeJoinNode<RowT> extends AbstractNode<RowT> {
                 inLoop = false;
             }
 
+            if (requested > 0 && ((waitingLeft == NOT_WAITING && left == null && leftInBuf.isEmpty())
+                    || (waitingRight == NOT_WAITING && right == null && rightInBuf.isEmpty() && rightMaterialization == null))
+            ) {
+                requested = 0;
+                downstream().end();
+
+                return;
+            }
+
             if (waitingRight == 0) {
                 rightSource().request(waitingRight = inBufSize);
             }
@@ -407,13 +424,6 @@ public abstract class MergeJoinNode<RowT> extends AbstractNode<RowT> {
             if (waitingLeft == 0) {
                 leftSource().request(waitingLeft = inBufSize);
             }
-
-            if (requested > 0 && ((waitingLeft == NOT_WAITING && left == null && leftInBuf.isEmpty())
-                    || (waitingRight == NOT_WAITING && right == null && rightInBuf.isEmpty() && rightMaterialization == null))
-            ) {
-                requested = 0;
-                downstream().end();
-            }
         }
     }
 
@@ -597,6 +607,13 @@ public abstract class MergeJoinNode<RowT> extends AbstractNode<RowT> {
                 inLoop = false;
             }
 
+            if (requested > 0 && waitingLeft == NOT_WAITING && left == null && leftInBuf.isEmpty()) {
+                requested = 0;
+                downstream().end();
+
+                return;
+            }
+
             if (waitingRight == 0) {
                 rightSource().request(waitingRight = inBufSize);
             }
@@ -604,11 +621,6 @@ public abstract class MergeJoinNode<RowT> extends AbstractNode<RowT> {
             if (waitingLeft == 0) {
                 leftSource().request(waitingLeft = inBufSize);
             }
-
-            if (requested > 0 && waitingLeft == NOT_WAITING && left == null && leftInBuf.isEmpty()) {
-                requested = 0;
-                downstream().end();
-            }
         }
     }
 
@@ -804,6 +816,13 @@ public abstract class MergeJoinNode<RowT> extends AbstractNode<RowT> {
                 inLoop = false;
             }
 
+            if (requested > 0 && waitingRight == NOT_WAITING && right == null && rightInBuf.isEmpty() && rightMaterialization == null) {
+                requested = 0;
+                downstream().end();
+
+                return;
+            }
+
             if (waitingRight == 0) {
                 rightSource().request(waitingRight = inBufSize);
             }
@@ -811,11 +830,6 @@ public abstract class MergeJoinNode<RowT> extends AbstractNode<RowT> {
             if (waitingLeft == 0) {
                 leftSource().request(waitingLeft = inBufSize);
             }
-
-            if (requested > 0 && waitingRight == NOT_WAITING && right == null && rightInBuf.isEmpty() && rightMaterialization == null) {
-                requested = 0;
-                downstream().end();
-            }
         }
     }
 
@@ -1049,6 +1063,15 @@ public abstract class MergeJoinNode<RowT> extends AbstractNode<RowT> {
                 inLoop = false;
             }
 
+            if (requested > 0 && waitingLeft == NOT_WAITING && left == null && leftInBuf.isEmpty()
+                    && waitingRight == NOT_WAITING && right == null && rightInBuf.isEmpty() && rightMaterialization == null
+            ) {
+                requested = 0;
+                downstream().end();
+
+                return;
+            }
+
             if (waitingRight == 0) {
                 rightSource().request(waitingRight = inBufSize);
             }
@@ -1056,13 +1079,6 @@ public abstract class MergeJoinNode<RowT> extends AbstractNode<RowT> {
             if (waitingLeft == 0) {
                 leftSource().request(waitingLeft = inBufSize);
             }
-
-            if (requested > 0 && waitingLeft == NOT_WAITING && left == null && leftInBuf.isEmpty()
-                    && waitingRight == NOT_WAITING && right == null && rightInBuf.isEmpty() && rightMaterialization == null
-            ) {
-                requested = 0;
-                downstream().end();
-            }
         }
     }
 
@@ -1133,6 +1149,15 @@ public abstract class MergeJoinNode<RowT> extends AbstractNode<RowT> {
                 inLoop = false;
             }
 
+            if (requested > 0 && ((waitingLeft == NOT_WAITING && left == null && leftInBuf.isEmpty()
+                    || (waitingRight == NOT_WAITING && right == null && rightInBuf.isEmpty())))
+            ) {
+                requested = 0;
+                downstream().end();
+
+                return;
+            }
+
             if (waitingRight == 0) {
                 rightSource().request(waitingRight = inBufSize);
             }
@@ -1140,13 +1165,6 @@ public abstract class MergeJoinNode<RowT> extends AbstractNode<RowT> {
             if (waitingLeft == 0) {
                 leftSource().request(waitingLeft = inBufSize);
             }
-
-            if (requested > 0 && ((waitingLeft == NOT_WAITING && left == null && leftInBuf.isEmpty()
-                    || (waitingRight == NOT_WAITING && right == null && rightInBuf.isEmpty())))
-            ) {
-                requested = 0;
-                downstream().end();
-            }
         }
     }
 
@@ -1220,6 +1238,13 @@ public abstract class MergeJoinNode<RowT> extends AbstractNode<RowT> {
                 inLoop = false;
             }
 
+            if (requested > 0 && waitingLeft == NOT_WAITING && left == null && leftInBuf.isEmpty()) {
+                requested = 0;
+                downstream().end();
+
+                return;
+            }
+
             if (waitingRight == 0) {
                 rightSource().request(waitingRight = inBufSize);
             }
@@ -1227,11 +1252,6 @@ public abstract class MergeJoinNode<RowT> extends AbstractNode<RowT> {
             if (waitingLeft == 0) {
                 leftSource().request(waitingLeft = inBufSize);
             }
-
-            if (requested > 0 && waitingLeft == NOT_WAITING && left == null && leftInBuf.isEmpty()) {
-                requested = 0;
-                downstream().end();
-            }
         }
     }
 }
diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/rel/ScanNode.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/rel/ScanNode.java
index 8b5d6f59489..ee7e24e7fc3 100644
--- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/rel/ScanNode.java
+++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/rel/ScanNode.java
@@ -114,7 +114,7 @@ public class ScanNode<RowT> extends AbstractNode<RowT> implements SingleNode<Row
                 requested--;
                 downstream().push(inst.next());
 
-                if (++processed == inBufSize) {
+                if (++processed == inBufSize && requested > 0) {
                     // allow others to do their job
                     this.execute(this::push);