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

asf-gitbox-commits pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git


The following commit(s) were added to refs/heads/master by this push:
     new 21eccc4ad07 IGNITE-28623 SQL Calcite: Fix premature orphan iterator 
closing by GC - Fixes #13089.
21eccc4ad07 is described below

commit 21eccc4ad073a0675738a413394e015f3cd96572
Author: Aleksey Plekhanov <[email protected]>
AuthorDate: Wed May 6 12:41:49 2026 +0300

    IGNITE-28623 SQL Calcite: Fix premature orphan iterator closing by GC - 
Fixes #13089.
    
    Signed-off-by: Aleksey Plekhanov <[email protected]>
---
 .../calcite/exec/ClosableIteratorsHolder.java      | 64 ++++++++++++++++++----
 .../query/calcite/exec/rel/RootNode.java           |  9 +--
 .../processors/query/calcite/CancelTest.java       |  3 +-
 3 files changed, 57 insertions(+), 19 deletions(-)

diff --git 
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ClosableIteratorsHolder.java
 
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ClosableIteratorsHolder.java
index caae30f12d9..e6c0b499190 100644
--- 
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ClosableIteratorsHolder.java
+++ 
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ClosableIteratorsHolder.java
@@ -28,6 +28,7 @@ import java.util.function.Consumer;
 import org.apache.ignite.IgniteLogger;
 import org.apache.ignite.internal.processors.query.calcite.util.Commons;
 import org.apache.ignite.internal.util.typedef.internal.U;
+import org.jetbrains.annotations.Nullable;
 
 /**
  */
@@ -37,7 +38,7 @@ public class ClosableIteratorsHolder {
     private final ReferenceQueue refQueue;
 
     /** */
-    private final Map<Reference, Object> refMap;
+    private final Map<Reference, Iterator<?>> refMap;
 
     /** */
     private final IgniteLogger log;
@@ -97,11 +98,15 @@ public class ClosableIteratorsHolder {
     }
 
     /** */
-    private AutoCloseable closeable(Object referent, Object resource) {
-        if (!(resource instanceof AutoCloseable))
+    private @Nullable AutoCloseable closeable(Object referent, Iterator<?> 
rsrc) {
+        if (!(rsrc instanceof AutoCloseable))
             return null;
 
-        return new CloseableReference(referent, resource);
+        CloseableReference ref = new CloseableReference(referent);
+
+        refMap.put(ref, rsrc);
+
+        return ref;
     }
 
     /** */
@@ -109,6 +114,14 @@ public class ClosableIteratorsHolder {
         /** */
         private final Iterator<T> delegate;
 
+        /**
+         * This variable is required to keep reference to current instance 
while delegate call
+         * (hasNext/next/remove/forEachRemaining) is not completed. We 
actually don't care about variable value and
+         * thread safety, it's only to prevent premature garbage collection 
and iterator closing before returning
+         * result to the user.
+         */
+        private boolean inUse;
+
         /** */
         private final AutoCloseable closeable;
 
@@ -119,26 +132,57 @@ public class ClosableIteratorsHolder {
 
         /** {@inheritDoc} */
         @Override public boolean hasNext() {
-            return delegate.hasNext();
+            inUse = true;
+
+            try {
+                return delegate.hasNext();
+            }
+            finally {
+                inUse = false;
+            }
         }
 
         /** {@inheritDoc} */
         @Override public T next() {
-            return delegate.next();
+            inUse = true;
+
+            try {
+                return delegate.next();
+            }
+            finally {
+                inUse = false;
+            }
         }
 
         /** {@inheritDoc} */
         @Override public void remove() {
-            delegate.remove();
+            inUse = true;
+
+            try {
+                delegate.remove();
+            }
+            finally {
+                inUse = false;
+            }
         }
 
         /** {@inheritDoc} */
         @Override public void forEachRemaining(Consumer<? super T> action) {
-            delegate.forEachRemaining(action);
+            inUse = true;
+
+            try {
+                delegate.forEachRemaining(action);
+            }
+            finally {
+                inUse = false;
+            }
         }
 
         /** {@inheritDoc} */
         @Override public void close() throws Exception {
+            if (log.isDebugEnabled())
+                log.debug("Closing iterator [delegate=" + delegate + ", 
inUse=" + inUse + ']');
+
             Commons.close(closeable);
         }
     }
@@ -146,10 +190,8 @@ public class ClosableIteratorsHolder {
     /** */
     private final class CloseableReference extends WeakReference implements 
AutoCloseable {
         /** */
-        private CloseableReference(Object referent, Object resource) {
+        private CloseableReference(Object referent) {
             super(referent, refQueue);
-
-            refMap.put(this, resource);
         }
 
         /** {@inheritDoc} */
diff --git 
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/rel/RootNode.java
 
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/rel/RootNode.java
index 891cff97c79..2c401bcd592 100644
--- 
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/rel/RootNode.java
+++ 
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/rel/RootNode.java
@@ -28,7 +28,6 @@ import java.util.concurrent.locks.Condition;
 import java.util.concurrent.locks.ReentrantLock;
 import java.util.function.Consumer;
 import java.util.function.Function;
-
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.ignite.IgniteInterruptedException;
 import org.apache.ignite.cache.query.QueryCancelledException;
@@ -205,8 +204,6 @@ public class RootNode<Row> extends AbstractNode<Row> 
implements SingleNode<Row>,
 
     /** {@inheritDoc} */
     @Override public boolean hasNext() {
-        checkException();
-
         if (!outBuff.isEmpty())
             return true;
 
@@ -324,9 +321,7 @@ public class RootNode<Row> extends AbstractNode<Row> 
implements SingleNode<Row>,
         if (e == null)
             return;
 
-        if (e instanceof IgniteSQLException)
-            throw (IgniteSQLException)e;
-        else
-            throw new IgniteSQLException("An error occurred while query 
executing - " + e.getMessage(), IgniteQueryErrorCode.UNKNOWN, e);
+        throw new IgniteSQLException("An error occurred while query executing 
- " + e.getMessage(),
+            e instanceof IgniteSQLException ? 
((IgniteSQLException)e).statusCode() : IgniteQueryErrorCode.UNKNOWN, e);
     }
 }
diff --git 
a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/CancelTest.java
 
b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/CancelTest.java
index 4e78cbe40fd..c57f4ff77b5 100644
--- 
a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/CancelTest.java
+++ 
b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/CancelTest.java
@@ -102,7 +102,8 @@ public class CancelTest extends GridCommonAbstractTest {
         cursors.forEach(QueryCursor::close);
 
         GridTestUtils.assertThrows(log, () -> {
-                it.next();
+                while (it.hasNext())
+                    it.next();
 
                 return null;
             },

Reply via email to