From 2ee3c3ea48e35bb17891d2cb410ebea6aa22765b Mon Sep 17 00:00:00 2001 From: animovscw Date: Fri, 12 Dec 2025 14:15:22 +0700 Subject: [PATCH 1/8] IGNITE-26758: Add test to verify qryResCache and executeFieldsQuery not used for SqlFieldsQuery --- .../cache/query/GridCacheQueryManager.java | 15 ++ ...cheQueryManagerExecuteFieldsQueryTest.java | 167 ++++++++++++++++++ 2 files changed, 182 insertions(+) create mode 100644 modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManagerExecuteFieldsQueryTest.java diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java index dca2630eb61f1..2fc717c518db2 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java @@ -41,6 +41,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.BiFunction; import javax.cache.Cache; import org.apache.ignite.Ignite; @@ -639,6 +640,19 @@ private QueryResult executeQuery(CacheQuery qry, return res; } + /** Test-only hook: how many times executeFieldsQuery was hit. */ + private static final AtomicInteger EXECUTE_FIELDS_QRY_HITS = new AtomicInteger(); + + /** Test-only hook. */ + static void resetExecuteFieldsQueryHitCount() { + EXECUTE_FIELDS_QRY_HITS.set(0); + } + + /** Test-only hook. */ + static int executeFieldsQueryHitCount() { + return EXECUTE_FIELDS_QRY_HITS.get(); + } + /** * Performs fields query. * @@ -652,6 +666,7 @@ private QueryResult executeQuery(CacheQuery qry, */ private FieldsResult executeFieldsQuery(CacheQuery qry, @Nullable Object[] args, boolean loc, @Nullable String taskName, Object rcpt) throws IgniteCheckedException { + EXECUTE_FIELDS_QRY_HITS.incrementAndGet(); assert qry != null; assert qry.type() == SQL_FIELDS : "Unexpected query type: " + qry.type(); diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManagerExecuteFieldsQueryTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManagerExecuteFieldsQueryTest.java new file mode 100644 index 0000000000000..23f81409401d7 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManagerExecuteFieldsQueryTest.java @@ -0,0 +1,167 @@ +package org.apache.ignite.internal.processors.cache.query; + +import java.io.Serializable; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import org.apache.ignite.Ignite; +import org.apache.ignite.IgniteCache; +import org.apache.ignite.cache.CacheAtomicityMode; +import org.apache.ignite.cache.query.QueryCursor; +import org.apache.ignite.cache.query.SqlFieldsQuery; +import org.apache.ignite.cache.query.annotations.QuerySqlField; +import org.apache.ignite.configuration.CacheConfiguration; +import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; +import org.junit.Test; + +/** + * Reproducer: verify that GridCacheQueryManager.executeFieldsQuery(...) is never called + * for local SQL fields queries (and parallel local SQL fields queries). + */ +public class GridCacheQueryManagerExecuteFieldsQueryTest extends GridCommonAbstractTest { + private static final String CACHE_NAME = "testCache"; + + @Override + protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { + IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName); + + CacheConfiguration ccfg = new CacheConfiguration<>(CACHE_NAME); + ccfg.setAtomicityMode(CacheAtomicityMode.ATOMIC); + + ccfg.setIndexedTypes(Integer.class, Person.class); + + cfg.setCacheConfiguration(ccfg); + + return cfg; + } + + @Override + protected void afterTest() throws Exception { + stopAllGrids(); + super.afterTest(); + } + + @Test + public void testLocalSqlFieldsQueryDoesNotHitExecuteFieldsQuery() throws Exception { + Ignite ignite = startGrid(0); + + IgniteCache cache = ignite.cache(CACHE_NAME); + assertNotNull(cache); + + cache.put(1, new Person("Alice", 10)); + cache.put(2, new Person("Bob", 20)); + + GridCacheQueryManager.resetExecuteFieldsQueryHitCount(); + + SqlFieldsQuery qry = new SqlFieldsQuery( + "select _key, name, age from Person order by _key" + ); + qry.setLocal(true); + + List> rows; + try (QueryCursor> cur = cache.query(qry)) { + rows = cur.getAll(); + } + + assertEquals(2, rows.size()); + assertEquals(0, GridCacheQueryManager.executeFieldsQueryHitCount()); + } + + @Test + public void testTwoParallelLocalSqlFieldsQueriesDoNotHitExecuteFieldsQuery() throws Exception { + Ignite ignite = startGrid(0); + + IgniteCache cache = ignite.cache(CACHE_NAME); + assertNotNull(cache); + + cache.put(1, new Person("Kirill", 10)); + cache.put(2, new Person("Michailo", 20)); + + GridCacheQueryManager.resetExecuteFieldsQueryHitCount(); + + ExecutorService pool = Executors.newFixedThreadPool(2); + try { + Callable>> task = () -> { + SqlFieldsQuery qry = new SqlFieldsQuery("select _key, name from Person order by _key"); + qry.setLocal(true); + + try (QueryCursor> cur = cache.query(qry)) { + return (List>) (List) cur.getAll(); + } + }; + + Future>> f1 = pool.submit(task); + Future>> f2 = pool.submit(task); + + List> r1 = f1.get(); + List> r2 = f2.get(); + + assertEquals(2, r1.size()); + assertEquals(2, r2.size()); + + assertEquals(0, GridCacheQueryManager.executeFieldsQueryHitCount()); + } finally { + pool.shutdownNow(); + } + } + + @Test + public void testNonLocalSqlFieldsQueryHitsExecuteFieldsQuery() throws Exception { + startGrids(2); + + Ignite ignite0 = grid(0); + Ignite ignite1 = grid(1); + + IgniteCache cache0 = ignite0.cache(CACHE_NAME); + + awaitPartitionMapExchange(); + + int kOn1 = 0; + while (!ignite1.affinity(CACHE_NAME).isPrimary(ignite1.cluster().localNode(), kOn1)) + kOn1++; + + int kOn0 = 0; + while (!ignite0.affinity(CACHE_NAME).isPrimary(ignite0.cluster().localNode(), kOn0)) + kOn0++; + + cache0.put(kOn0, new Person("On0", 10)); + cache0.put(kOn1, new Person("On1", 20)); + + GridCacheQueryManager.resetExecuteFieldsQueryHitCount(); + + SqlFieldsQuery qry = new SqlFieldsQuery("select _key, name from Person order by _key"); + qry.setLocal(false); + + try (QueryCursor> cur = cache0.query(qry)) { + List> rows = cur.getAll(); + assertEquals(2, rows.size()); + } + assertTrue(ignite1.affinity(CACHE_NAME).isPrimary(ignite1.cluster().localNode(), kOn1)); + assertTrue(ignite0.affinity(CACHE_NAME).isPrimary(ignite0.cluster().localNode(), kOn0)); + + assertFalse(ignite0.affinity(CACHE_NAME).isPrimary(ignite0.cluster().localNode(), kOn1)); + assertFalse(ignite1.affinity(CACHE_NAME).isPrimary(ignite1.cluster().localNode(), kOn0)); + + assertEquals(0, GridCacheQueryManager.executeFieldsQueryHitCount()); + } + + /** + * Simple SQL-mapped object. + */ + private static class Person implements Serializable { + @QuerySqlField(index = true) + private String name; + + @QuerySqlField(index = true) + private int age; + + Person(String name, int age) { + this.name = name; + this.age = age; + } + } +} From d14d02674d8cfbad8606b579955930fd734a3e93 Mon Sep 17 00:00:00 2001 From: animovscw Date: Mon, 22 Dec 2025 11:32:34 +0700 Subject: [PATCH 2/8] Moved the test to the correct module --- .../cache/query/GridCacheQueryManagerExecuteFieldsQueryTest.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename modules/{core => indexing}/src/test/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManagerExecuteFieldsQueryTest.java (100%) diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManagerExecuteFieldsQueryTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManagerExecuteFieldsQueryTest.java similarity index 100% rename from modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManagerExecuteFieldsQueryTest.java rename to modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManagerExecuteFieldsQueryTest.java From b188797d60c5a34862972c85a1a20639c2636bdd Mon Sep 17 00:00:00 2001 From: animovscw Date: Mon, 22 Dec 2025 16:30:16 +0700 Subject: [PATCH 3/8] Added verification of the SqlQuery execution path (updated) --- ...cheQueryManagerExecuteFieldsQueryTest.java | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManagerExecuteFieldsQueryTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManagerExecuteFieldsQueryTest.java index 23f81409401d7..32ac51f42106d 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManagerExecuteFieldsQueryTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManagerExecuteFieldsQueryTest.java @@ -2,16 +2,21 @@ import java.io.Serializable; import java.util.List; +import java.util.Set; +import java.util.UUID; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; +import java.util.stream.Collectors; +import javax.cache.Cache; import org.apache.ignite.Ignite; import org.apache.ignite.IgniteCache; import org.apache.ignite.cache.CacheAtomicityMode; import org.apache.ignite.cache.query.QueryCursor; import org.apache.ignite.cache.query.SqlFieldsQuery; +import org.apache.ignite.cache.query.SqlQuery; import org.apache.ignite.cache.query.annotations.QuerySqlField; import org.apache.ignite.configuration.CacheConfiguration; import org.apache.ignite.configuration.IgniteConfiguration; @@ -32,6 +37,8 @@ protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws CacheConfiguration ccfg = new CacheConfiguration<>(CACHE_NAME); ccfg.setAtomicityMode(CacheAtomicityMode.ATOMIC); + ccfg.setBackups(0); + ccfg.setIndexedTypes(Integer.class, Person.class); cfg.setCacheConfiguration(ccfg); @@ -149,6 +156,111 @@ public void testNonLocalSqlFieldsQueryHitsExecuteFieldsQuery() throws Exception assertEquals(0, GridCacheQueryManager.executeFieldsQueryHitCount()); } + @Test + public void testLocalSqlQueryDoesNotHitExecuteFieldsQuery() throws Exception { + startGrids(2); + + Ignite ignite0 = grid(0); + Ignite ignite1 = grid(1); + + awaitPartitionMapExchange(); + + IgniteCache cache0 = ignite0.cache(CACHE_NAME); + + int[] keys = pickKeysForDifferentPrimaries(ignite0, ignite1); + int k0 = keys[0]; + int k1 = keys[1]; + + cache0.put(k0, new Person("On0", 10)); + cache0.put(k1, new Person("On1", 20)); + + GridCacheQueryManager.resetExecuteFieldsQueryHitCount(); + + SqlQuery qry = new SqlQuery<>(Person.class, "age >= ?"); + qry.setArgs(0); + qry.setLocal(true); + + List> res0; + try (QueryCursor> cur = ignite0.cache(CACHE_NAME).query(qry)) { + res0 = cur.getAll(); + } + + List> res1; + try (QueryCursor> cur = ignite1.cache(CACHE_NAME).query(qry)) { + res1 = cur.getAll(); + } + + assertEquals(1, res0.size()); + assertEquals(1, res1.size()); + + assertEquals(k0, res0.get(0).getKey().intValue()); + assertEquals(k1, res1.get(0).getKey().intValue()); + + assertEquals(0, GridCacheQueryManager.executeFieldsQueryHitCount()); + } + + /** + * The same intent, but also verify we got exactly the keys we inserted. + */ + @Test + public void testDistributedSqlQueryDoesNotHitExecuteFieldsQuery() throws Exception { + Ignite ignite0 = startGrid(0); + Ignite ignite1 = startGrid(1); + + awaitPartitionMapExchange(); + + IgniteCache cache0 = ignite0.cache(CACHE_NAME); + + int[] keys = pickKeysForDifferentPrimaries(ignite0, ignite1); + int k0 = keys[0]; + int k1 = keys[1]; + + cache0.put(k0, new Person("Kirill", 10)); + cache0.put(k1, new Person("Michailo", 20)); + + GridCacheQueryManager.resetExecuteFieldsQueryHitCount(); + + SqlQuery qry = new SqlQuery<>(Person.class, "age >= ?"); + qry.setArgs(0); + qry.setLocal(false); + + List> res; + try (QueryCursor> cur = cache0.query(qry)) { + res = cur.getAll(); + } + + assertEquals(2, res.size()); + + Set gotKeys = res.stream().map(Cache.Entry::getKey).collect(Collectors.toSet()); + + assertTrue("Expected to get both keys back [k0 = " + k0 + ", k1 = " + k1 + ", got = " + gotKeys + ']', + gotKeys.contains(k0) && gotKeys.contains(k1)); + + assertEquals(0, GridCacheQueryManager.executeFieldsQueryHitCount()); + } + + private int[] pickKeysForDifferentPrimaries(Ignite ignite0, Ignite ignite1) { + int k0 = -1, k1 = -1; + + UUID id0 = ignite0.cluster().localNode().id(); + UUID id1 = ignite1.cluster().localNode().id(); + + for (int k = 1; k < 100000; k++) { + UUID primaryId = ignite0.affinity(CACHE_NAME).mapKeyToNode(k).id(); + + if (primaryId.equals(id0) && k0 < 0) k0 = k; + if (primaryId.equals(id1) && k1 < 0) k1 = k; + + if (k0 > 0 && k1 > 0) + break; + } + + assertTrue("Failed to pick keys for different primaries [k0 = " + k0 + ", k1 = " + k1 + ']', + k0 > 0 && k1 > 0); + + return new int[]{k0, k1}; + } + /** * Simple SQL-mapped object. */ From f872f4b4cc2c5089ecc9de16a0f6df604f4afd95 Mon Sep 17 00:00:00 2001 From: animovscw Date: Fri, 26 Dec 2025 13:26:46 +0700 Subject: [PATCH 4/8] Deleted the unused code --- .../cache/query/GridCacheQueryManager.java | 117 +------- ...cheQueryManagerExecuteFieldsQueryTest.java | 279 ------------------ 2 files changed, 2 insertions(+), 394 deletions(-) delete mode 100644 modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManagerExecuteFieldsQueryTest.java diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java index 2fc717c518db2..d304e5c6a9d94 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java @@ -41,7 +41,6 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.atomic.AtomicInteger; import java.util.function.BiFunction; import javax.cache.Cache; import org.apache.ignite.Ignite; @@ -207,8 +206,6 @@ public abstract class GridCacheQueryManager extends GridCacheManagerAdapte private final ConcurrentMap>> fieldsQryRes = new ConcurrentHashMap<>(); - /** */ - private volatile ConcurrentMap> qryResCache = new ConcurrentHashMap<>(); /** */ private final GridSpinBusyLock busyLock = new GridSpinBusyLock(); @@ -373,14 +370,6 @@ private boolean isIndexingSpiEnabled() { return cctx.kernalContext().indexing().enabled(); } - /** - * - */ - private void invalidateResultCache() { - if (!qryResCache.isEmpty()) - qryResCache = new ConcurrentHashMap<>(); - } - /** * @param newRow New row. * @param prevRow Previous row. @@ -410,8 +399,6 @@ public void store(CacheDataRow newRow, @Nullable CacheDataRow prevRow, qryProc.store(cctx, newRow, prevRow, prevRowAvailable); } finally { - invalidateResultCache(); - leaveBusy(); } } @@ -441,8 +428,6 @@ public void remove(KeyCacheObject key, @Nullable CacheDataRow prevRow) qryProc.remove(cctx, prevRow); } finally { - invalidateResultCache(); - leaveBusy(); } } @@ -640,79 +625,6 @@ private QueryResult executeQuery(CacheQuery qry, return res; } - /** Test-only hook: how many times executeFieldsQuery was hit. */ - private static final AtomicInteger EXECUTE_FIELDS_QRY_HITS = new AtomicInteger(); - - /** Test-only hook. */ - static void resetExecuteFieldsQueryHitCount() { - EXECUTE_FIELDS_QRY_HITS.set(0); - } - - /** Test-only hook. */ - static int executeFieldsQueryHitCount() { - return EXECUTE_FIELDS_QRY_HITS.get(); - } - - /** - * Performs fields query. - * - * @param qry Query. - * @param args Arguments. - * @param loc Local query or not. - * @param taskName Task name. - * @param rcpt ID of the recipient. - * @return Collection of found keys. - * @throws IgniteCheckedException In case of error. - */ - private FieldsResult executeFieldsQuery(CacheQuery qry, @Nullable Object[] args, - boolean loc, @Nullable String taskName, Object rcpt) throws IgniteCheckedException { - EXECUTE_FIELDS_QRY_HITS.incrementAndGet(); - assert qry != null; - assert qry.type() == SQL_FIELDS : "Unexpected query type: " + qry.type(); - - if (qry.clause() == null) { - assert !loc; - - throw new IgniteCheckedException("Received next page request after iterator was removed. " + - "Consider increasing maximum number of stored iterators (see " + - "CacheConfiguration.getMaxQueryIteratorsCount() configuration property)."); - } - - if (cctx.events().isRecordable(EVT_CACHE_QUERY_EXECUTED)) { - cctx.gridEvents().record(new CacheQueryExecutedEvent<>( - cctx.localNode(), - "SQL fields query executed.", - EVT_CACHE_QUERY_EXECUTED, - CacheQueryType.SQL_FIELDS.name(), - cctx.name(), - null, - qry.clause(), - null, - null, - args, - securitySubjectId(cctx), - taskName)); - } - - // Attempt to get result from cache. - T2> resKey = new T2<>(qry.clause(), F.asList(args)); - - FieldsResult res = (FieldsResult)qryResCache.get(resKey); - - if (res != null && res.addRecipient(rcpt)) - return res; // Cached result found. - - res = new FieldsResult(rcpt); - - if (qryResCache.putIfAbsent(resKey, res) != null) - resKey = null; // Failed to cache result. - - if (resKey != null) - qryResCache.remove(resKey, res); - - return res; - } - /** * @param qry Query. * @return Cache set items iterator. @@ -907,10 +819,7 @@ protected void runFieldsQuery(final GridCacheQueryInfo qryInfo) { String taskName = cctx.kernalContext().task().resolveTaskName(qry.taskHash()); - res = qryInfo.local() ? - executeFieldsQuery(qry, qryInfo.arguments(), qryInfo.local(), taskName, - recipient(qryInfo.senderId(), qryInfo.requestId())) : - fieldsQueryResult(qryInfo, taskName); + res = fieldsQueryResult(qryInfo, taskName); // If metadata needs to be returned to user and cleaned from internal fields - copy it. List meta = qryInfo.includeMetaData() ? @@ -1030,19 +939,7 @@ protected void runFieldsQuery(final GridCacheQueryInfo qryInfo) { throw (Error)e; } finally { - if (qryInfo.local()) { - // Don't we need to always remove local iterators? - if (rmvRes && res != null) { - try { - res.closeIfNotShared(recipient(qryInfo.senderId(), qryInfo.requestId())); - } - catch (IgniteCheckedException e) { - U.error(log, "Failed to close local iterator [qry=" + qryInfo + ", node=" + - cctx.nodeId() + "]", e); - } - } - } - else if (rmvRes) + if (rmvRes) removeFieldsQueryResult(qryInfo.senderId(), qryInfo.requestId()); } } @@ -1643,16 +1540,6 @@ private FieldsResult fieldsQueryResult(Map } } - if (exec) { - try { - fut.onDone(executeFieldsQuery(qryInfo.query(), qryInfo.arguments(), false, - taskName, recipient(qryInfo.senderId(), qryInfo.requestId()))); - } - catch (IgniteCheckedException e) { - fut.onDone(e); - } - } - return fut.get(); } diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManagerExecuteFieldsQueryTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManagerExecuteFieldsQueryTest.java deleted file mode 100644 index 32ac51f42106d..0000000000000 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManagerExecuteFieldsQueryTest.java +++ /dev/null @@ -1,279 +0,0 @@ -package org.apache.ignite.internal.processors.cache.query; - -import java.io.Serializable; -import java.util.List; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.stream.Collectors; -import javax.cache.Cache; - -import org.apache.ignite.Ignite; -import org.apache.ignite.IgniteCache; -import org.apache.ignite.cache.CacheAtomicityMode; -import org.apache.ignite.cache.query.QueryCursor; -import org.apache.ignite.cache.query.SqlFieldsQuery; -import org.apache.ignite.cache.query.SqlQuery; -import org.apache.ignite.cache.query.annotations.QuerySqlField; -import org.apache.ignite.configuration.CacheConfiguration; -import org.apache.ignite.configuration.IgniteConfiguration; -import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; -import org.junit.Test; - -/** - * Reproducer: verify that GridCacheQueryManager.executeFieldsQuery(...) is never called - * for local SQL fields queries (and parallel local SQL fields queries). - */ -public class GridCacheQueryManagerExecuteFieldsQueryTest extends GridCommonAbstractTest { - private static final String CACHE_NAME = "testCache"; - - @Override - protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { - IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName); - - CacheConfiguration ccfg = new CacheConfiguration<>(CACHE_NAME); - ccfg.setAtomicityMode(CacheAtomicityMode.ATOMIC); - - ccfg.setBackups(0); - - ccfg.setIndexedTypes(Integer.class, Person.class); - - cfg.setCacheConfiguration(ccfg); - - return cfg; - } - - @Override - protected void afterTest() throws Exception { - stopAllGrids(); - super.afterTest(); - } - - @Test - public void testLocalSqlFieldsQueryDoesNotHitExecuteFieldsQuery() throws Exception { - Ignite ignite = startGrid(0); - - IgniteCache cache = ignite.cache(CACHE_NAME); - assertNotNull(cache); - - cache.put(1, new Person("Alice", 10)); - cache.put(2, new Person("Bob", 20)); - - GridCacheQueryManager.resetExecuteFieldsQueryHitCount(); - - SqlFieldsQuery qry = new SqlFieldsQuery( - "select _key, name, age from Person order by _key" - ); - qry.setLocal(true); - - List> rows; - try (QueryCursor> cur = cache.query(qry)) { - rows = cur.getAll(); - } - - assertEquals(2, rows.size()); - assertEquals(0, GridCacheQueryManager.executeFieldsQueryHitCount()); - } - - @Test - public void testTwoParallelLocalSqlFieldsQueriesDoNotHitExecuteFieldsQuery() throws Exception { - Ignite ignite = startGrid(0); - - IgniteCache cache = ignite.cache(CACHE_NAME); - assertNotNull(cache); - - cache.put(1, new Person("Kirill", 10)); - cache.put(2, new Person("Michailo", 20)); - - GridCacheQueryManager.resetExecuteFieldsQueryHitCount(); - - ExecutorService pool = Executors.newFixedThreadPool(2); - try { - Callable>> task = () -> { - SqlFieldsQuery qry = new SqlFieldsQuery("select _key, name from Person order by _key"); - qry.setLocal(true); - - try (QueryCursor> cur = cache.query(qry)) { - return (List>) (List) cur.getAll(); - } - }; - - Future>> f1 = pool.submit(task); - Future>> f2 = pool.submit(task); - - List> r1 = f1.get(); - List> r2 = f2.get(); - - assertEquals(2, r1.size()); - assertEquals(2, r2.size()); - - assertEquals(0, GridCacheQueryManager.executeFieldsQueryHitCount()); - } finally { - pool.shutdownNow(); - } - } - - @Test - public void testNonLocalSqlFieldsQueryHitsExecuteFieldsQuery() throws Exception { - startGrids(2); - - Ignite ignite0 = grid(0); - Ignite ignite1 = grid(1); - - IgniteCache cache0 = ignite0.cache(CACHE_NAME); - - awaitPartitionMapExchange(); - - int kOn1 = 0; - while (!ignite1.affinity(CACHE_NAME).isPrimary(ignite1.cluster().localNode(), kOn1)) - kOn1++; - - int kOn0 = 0; - while (!ignite0.affinity(CACHE_NAME).isPrimary(ignite0.cluster().localNode(), kOn0)) - kOn0++; - - cache0.put(kOn0, new Person("On0", 10)); - cache0.put(kOn1, new Person("On1", 20)); - - GridCacheQueryManager.resetExecuteFieldsQueryHitCount(); - - SqlFieldsQuery qry = new SqlFieldsQuery("select _key, name from Person order by _key"); - qry.setLocal(false); - - try (QueryCursor> cur = cache0.query(qry)) { - List> rows = cur.getAll(); - assertEquals(2, rows.size()); - } - assertTrue(ignite1.affinity(CACHE_NAME).isPrimary(ignite1.cluster().localNode(), kOn1)); - assertTrue(ignite0.affinity(CACHE_NAME).isPrimary(ignite0.cluster().localNode(), kOn0)); - - assertFalse(ignite0.affinity(CACHE_NAME).isPrimary(ignite0.cluster().localNode(), kOn1)); - assertFalse(ignite1.affinity(CACHE_NAME).isPrimary(ignite1.cluster().localNode(), kOn0)); - - assertEquals(0, GridCacheQueryManager.executeFieldsQueryHitCount()); - } - - @Test - public void testLocalSqlQueryDoesNotHitExecuteFieldsQuery() throws Exception { - startGrids(2); - - Ignite ignite0 = grid(0); - Ignite ignite1 = grid(1); - - awaitPartitionMapExchange(); - - IgniteCache cache0 = ignite0.cache(CACHE_NAME); - - int[] keys = pickKeysForDifferentPrimaries(ignite0, ignite1); - int k0 = keys[0]; - int k1 = keys[1]; - - cache0.put(k0, new Person("On0", 10)); - cache0.put(k1, new Person("On1", 20)); - - GridCacheQueryManager.resetExecuteFieldsQueryHitCount(); - - SqlQuery qry = new SqlQuery<>(Person.class, "age >= ?"); - qry.setArgs(0); - qry.setLocal(true); - - List> res0; - try (QueryCursor> cur = ignite0.cache(CACHE_NAME).query(qry)) { - res0 = cur.getAll(); - } - - List> res1; - try (QueryCursor> cur = ignite1.cache(CACHE_NAME).query(qry)) { - res1 = cur.getAll(); - } - - assertEquals(1, res0.size()); - assertEquals(1, res1.size()); - - assertEquals(k0, res0.get(0).getKey().intValue()); - assertEquals(k1, res1.get(0).getKey().intValue()); - - assertEquals(0, GridCacheQueryManager.executeFieldsQueryHitCount()); - } - - /** - * The same intent, but also verify we got exactly the keys we inserted. - */ - @Test - public void testDistributedSqlQueryDoesNotHitExecuteFieldsQuery() throws Exception { - Ignite ignite0 = startGrid(0); - Ignite ignite1 = startGrid(1); - - awaitPartitionMapExchange(); - - IgniteCache cache0 = ignite0.cache(CACHE_NAME); - - int[] keys = pickKeysForDifferentPrimaries(ignite0, ignite1); - int k0 = keys[0]; - int k1 = keys[1]; - - cache0.put(k0, new Person("Kirill", 10)); - cache0.put(k1, new Person("Michailo", 20)); - - GridCacheQueryManager.resetExecuteFieldsQueryHitCount(); - - SqlQuery qry = new SqlQuery<>(Person.class, "age >= ?"); - qry.setArgs(0); - qry.setLocal(false); - - List> res; - try (QueryCursor> cur = cache0.query(qry)) { - res = cur.getAll(); - } - - assertEquals(2, res.size()); - - Set gotKeys = res.stream().map(Cache.Entry::getKey).collect(Collectors.toSet()); - - assertTrue("Expected to get both keys back [k0 = " + k0 + ", k1 = " + k1 + ", got = " + gotKeys + ']', - gotKeys.contains(k0) && gotKeys.contains(k1)); - - assertEquals(0, GridCacheQueryManager.executeFieldsQueryHitCount()); - } - - private int[] pickKeysForDifferentPrimaries(Ignite ignite0, Ignite ignite1) { - int k0 = -1, k1 = -1; - - UUID id0 = ignite0.cluster().localNode().id(); - UUID id1 = ignite1.cluster().localNode().id(); - - for (int k = 1; k < 100000; k++) { - UUID primaryId = ignite0.affinity(CACHE_NAME).mapKeyToNode(k).id(); - - if (primaryId.equals(id0) && k0 < 0) k0 = k; - if (primaryId.equals(id1) && k1 < 0) k1 = k; - - if (k0 > 0 && k1 > 0) - break; - } - - assertTrue("Failed to pick keys for different primaries [k0 = " + k0 + ", k1 = " + k1 + ']', - k0 > 0 && k1 > 0); - - return new int[]{k0, k1}; - } - - /** - * Simple SQL-mapped object. - */ - private static class Person implements Serializable { - @QuerySqlField(index = true) - private String name; - - @QuerySqlField(index = true) - private int age; - - Person(String name, int age) { - this.name = name; - this.age = age; - } - } -} From 101eed43aee6b2dca3c9d05ff4a569cd476f3093 Mon Sep 17 00:00:00 2001 From: animovscw Date: Fri, 26 Dec 2025 15:27:45 +0700 Subject: [PATCH 5/8] Removed dead fields-query execution path --- .../GridCacheDistributedQueryManager.java | 10 +- .../query/GridCacheLocalQueryFuture.java | 5 +- .../cache/query/GridCacheQueryManager.java | 207 ------------------ 3 files changed, 3 insertions(+), 219 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheDistributedQueryManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheDistributedQueryManager.java index 36d04fc6191be..9a9c6b4d00ce3 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheDistributedQueryManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheDistributedQueryManager.java @@ -183,10 +183,7 @@ protected void removeQueryFuture(long reqId) { if (req.cancel()) { cancelIds.add(new CancelMessageId(req.id(), sndId)); - if (req.fields()) - removeFieldsQueryResult(sndId, req.id()); - else - removeQueryResult(sndId, req.id()); + removeQueryResult(sndId, req.id()); } else { if (!cancelIds.contains(new CancelMessageId(req.id(), sndId))) { @@ -209,10 +206,7 @@ protected void removeQueryFuture(long reqId) { if (info == null) return; - if (req.fields()) - runFieldsQuery(info); - else - runQuery(info); + runQuery(info); } catch (Throwable e) { U.error(log(), "Failed to run query.", e); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheLocalQueryFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheLocalQueryFuture.java index d8fd4f2b5a71f..8ae320c835b77 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheLocalQueryFuture.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheLocalQueryFuture.java @@ -98,10 +98,7 @@ private class LocalQueryRunnable implements GridPlainRunnable { try { qry.query().validate(); - if (fields()) - cctx.queries().runFieldsQuery(localQueryInfo()); - else - cctx.queries().runQuery(localQueryInfo()); + cctx.queries().runQuery(localQueryInfo()); } catch (Throwable e) { onDone(e); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java index d304e5c6a9d94..346df9ffa111b 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java @@ -772,182 +772,6 @@ static R injectResources(@Nullable R o, GridCacheContext cctx) throws return o; } - /** - * Processes fields query request. - * - * @param qryInfo Query info. - */ - protected void runFieldsQuery(final GridCacheQueryInfo qryInfo) { - assert qryInfo != null; - - if (!enterBusy()) { - if (cctx.localNodeId().equals(qryInfo.senderId())) - throw new IllegalStateException("Failed to process query request (grid is stopping)."); - - return; // Ignore remote requests when when node is stopping. - } - - try { - if (log.isDebugEnabled()) - log.debug("Running query: " + qryInfo); - - boolean rmvRes = true; - - FieldsResult res = null; - - final boolean statsEnabled = cctx.statisticsEnabled(); - - final boolean readEvt = cctx.events().isRecordable(EVT_CACHE_QUERY_OBJECT_READ); - - try { - // Preparing query closures. - final IgniteReducer rdc = injectResources((IgniteReducer)qryInfo.reducer(), cctx); - - CacheQuery qry = qryInfo.query(); - - int pageSize = qry.pageSize(); - - Collection data = null; - Collection entities = null; - - boolean isWriteData = qryInfo.local() || rdc != null || cctx.isLocalNode(qryInfo.senderId()); - - if (isWriteData) - data = new ArrayList<>(pageSize); - else - entities = new ArrayList<>(pageSize); - - String taskName = cctx.kernalContext().task().resolveTaskName(qry.taskHash()); - - res = fieldsQueryResult(qryInfo, taskName); - - // If metadata needs to be returned to user and cleaned from internal fields - copy it. - List meta = qryInfo.includeMetaData() ? - (res.metaData() != null ? new ArrayList<>(res.metaData()) : null) : - res.metaData(); - - if (!qryInfo.includeMetaData()) - meta = null; - - GridCloseableIterator it = new GridSpiCloseableIteratorWrapper( - res.iterator(recipient(qryInfo.senderId(), qryInfo.requestId()))); - - if (log.isDebugEnabled()) - log.debug("Received fields iterator [iterHasNext=" + it.hasNext() + ']'); - - if (!it.hasNext()) { - if (rdc != null) - data = Collections.singletonList(rdc.reduce()); - - onFieldsPageReady(qryInfo.local(), qryInfo, meta, entities, data, true, null); - - return; - } - - int cnt = 0; - boolean metaSent = false; - - while (!Thread.currentThread().isInterrupted() && it.hasNext()) { - long start = statsEnabled ? System.nanoTime() : 0L; - - Object row = it.next(); - - // Query is cancelled. - if (row == null) { - onPageReady(qryInfo.local(), qryInfo, null, null, true, null); - - break; - } - - if (statsEnabled) { - CacheMetricsImpl metrics = cctx.cache().metrics0(); - - metrics.onRead(true); - - metrics.addGetTimeNanos(System.nanoTime() - start); - } - - if (readEvt && cctx.gridEvents().hasListener(EVT_CACHE_QUERY_OBJECT_READ)) { - cctx.gridEvents().record(new CacheQueryReadEvent( - cctx.localNode(), - "SQL fields query result set row read.", - EVT_CACHE_QUERY_OBJECT_READ, - CacheQueryType.SQL_FIELDS.name(), - cctx.name(), - null, - qry.clause(), - null, - null, - qryInfo.arguments(), - securitySubjectId(cctx), - taskName, - null, - null, - null, - row)); - } - - if (isWriteData) { - // Reduce. - if (rdc != null) { - if (!rdc.collect(row)) - break; - } - else - data.add(row); - } - else - entities.add(row); - - if (rdc == null && ((!qryInfo.allPages() && ++cnt == pageSize) || !it.hasNext())) { - onFieldsPageReady(qryInfo.local(), qryInfo, !metaSent ? meta : null, - entities, data, !it.hasNext(), null); - - if (it.hasNext()) - rmvRes = false; - - if (!qryInfo.allPages()) - return; - } - } - - if (rdc != null) { - onFieldsPageReady(qryInfo.local(), qryInfo, meta, null, - Collections.singletonList(rdc.reduce()), true, null); - } - } - catch (IgniteCheckedException e) { - if (log.isDebugEnabled() || !e.hasCause(SQLException.class)) - U.error(log, "Failed to run fields query [qry=" + qryInfo + ", node=" + cctx.nodeId() + ']', e); - else { - if (e.hasCause(SQLException.class)) - U.error(log, "Failed to run fields query [node=" + cctx.nodeId() + - ", msg=" + e.getCause(SQLException.class).getMessage() + ']'); - else - U.error(log, "Failed to run fields query [node=" + cctx.nodeId() + - ", msg=" + e.getMessage() + ']'); - } - - onFieldsPageReady(qryInfo.local(), qryInfo, null, null, null, true, e); - } - catch (Throwable e) { - U.error(log, "Failed to run fields query [qry=" + qryInfo + ", node=" + cctx.nodeId() + "]", e); - - onFieldsPageReady(qryInfo.local(), qryInfo, null, null, null, true, e); - - if (e instanceof Error) - throw (Error)e; - } - finally { - if (rmvRes) - removeFieldsQueryResult(qryInfo.senderId(), qryInfo.requestId()); - } - } - finally { - leaveBusy(); - } - } - /** * Processes cache query request. * @@ -1543,37 +1367,6 @@ private FieldsResult fieldsQueryResult(Map return fut.get(); } - /** - * @param sndId Sender node ID. - * @param reqId Request ID. - */ - @SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter") - protected void removeFieldsQueryResult(@Nullable UUID sndId, long reqId) { - if (sndId == null) - return; - - Map> futs = fieldsQryRes.get(sndId); - - if (futs != null) { - IgniteInternalFuture fut; - - synchronized (futs) { - fut = futs.remove(reqId); - } - - if (fut != null) { - assert fut.isDone(); - - try { - fut.get().closeIfNotShared(recipient(sndId, reqId)); - } - catch (IgniteCheckedException e) { - U.error(log, "Failed to close iterator.", e); - } - } - } - } - /** * Called when data for page is ready. * From da920f500993a423b246839b0519269440557d01 Mon Sep 17 00:00:00 2001 From: animovscw Date: Fri, 26 Dec 2025 16:14:46 +0700 Subject: [PATCH 6/8] Removed unused method fieldsQueryResult --- .../cache/query/GridCacheQueryManager.java | 76 ------------------- 1 file changed, 76 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java index 7caa6d067313f..3a54bbe33dde4 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java @@ -21,7 +21,6 @@ import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; -import java.sql.SQLException; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; @@ -95,7 +94,6 @@ import org.apache.ignite.internal.util.GridConcurrentHashSet; import org.apache.ignite.internal.util.GridEmptyCloseableIterator; import org.apache.ignite.internal.util.GridLeanMap; -import org.apache.ignite.internal.util.GridSpiCloseableIteratorWrapper; import org.apache.ignite.internal.util.GridSpinBusyLock; import org.apache.ignite.internal.util.future.GridFinishedFuture; import org.apache.ignite.internal.util.future.GridFutureAdapter; @@ -1292,80 +1290,6 @@ private static Object recipient(UUID sndId, long reqId) { return new IgniteBiTuple<>(sndId, reqId); } - /** - * @param qryInfo Info. - * @return Iterator. - * @throws IgniteCheckedException In case of error. - */ - private FieldsResult fieldsQueryResult(GridCacheQueryInfo qryInfo, String taskName) - throws IgniteCheckedException { - final UUID sndId = qryInfo.senderId(); - - assert sndId != null; - - Map> iters = fieldsQryRes.get(sndId); - - if (iters == null) { - iters = new LinkedHashMap>(16, 0.75f, true) { - @Override protected boolean removeEldestEntry(Map.Entry> e) { - boolean rmv = size() > maxIterCnt; - - if (rmv) { - try { - e.getValue().get().closeIfNotShared(recipient(sndId, e.getKey())); - } - catch (IgniteCheckedException ex) { - U.error(log, "Failed to close fields query iterator.", ex); - } - } - - return rmv; - } - - @Override public boolean equals(Object o) { - return o == this; - } - }; - - Map> old = fieldsQryRes.putIfAbsent(sndId, iters); - - if (old != null) - iters = old; - } - - return fieldsQueryResult(iters, qryInfo, taskName); - } - - /** - * @param resMap Results map. - * @param qryInfo Info. - * @return Fields query result. - * @throws IgniteCheckedException In case of error. - */ - @SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter") - private FieldsResult fieldsQueryResult(Map> resMap, - GridCacheQueryInfo qryInfo, String taskName) throws IgniteCheckedException { - assert resMap != null; - assert qryInfo != null; - - GridFutureAdapter fut; - - boolean exec = false; - - synchronized (resMap) { - fut = resMap.get(qryInfo.requestId()); - - if (fut == null) { - resMap.put(qryInfo.requestId(), fut = new GridFutureAdapter<>()); - - exec = true; - } - } - - return fut.get(); - } - /** * Called when data for page is ready. * From 2fb6c2549cf4f8568fec6f6e13a4ab2081b606ad Mon Sep 17 00:00:00 2001 From: animovscw Date: Fri, 26 Dec 2025 16:46:08 +0700 Subject: [PATCH 7/8] Removed unused import --- .../internal/processors/cache/query/GridCacheQueryManager.java | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java index 3a54bbe33dde4..12fe6e3f8a7af 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java @@ -30,7 +30,6 @@ import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedList; -import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Queue; From 5cd37b776e815088247e843608660694dbe63ce6 Mon Sep 17 00:00:00 2001 From: animovscw Date: Tue, 30 Dec 2025 15:44:46 +0700 Subject: [PATCH 8/8] checkstyle --- .../internal/processors/cache/query/GridCacheQueryManager.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java index 12fe6e3f8a7af..8fe2c925bb10b 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java @@ -201,8 +201,7 @@ public abstract class GridCacheQueryManager extends GridCacheManagerAdapte /** */ private final ConcurrentMap>> fieldsQryRes = new ConcurrentHashMap<>(); - - + /** */ private final GridSpinBusyLock busyLock = new GridSpinBusyLock();