diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcThinDriverBestEffordAffinityTestSuite.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcThinDriverBestEffordAffinityTestSuite.java index 95f6875102bec..0706386f6ad46 100644 --- a/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcThinDriverBestEffordAffinityTestSuite.java +++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcThinDriverBestEffordAffinityTestSuite.java @@ -17,8 +17,8 @@ package org.apache.ignite.jdbc.suite; -import org.apache.ignite.internal.jdbc.thin.JdbcThinConnection; import org.apache.ignite.jdbc.thin.JdbcThinAbstractSelfTest; +import org.apache.ignite.jdbc.thin.JdbcThinBestEffortAffinitySelfTest; import org.apache.ignite.jdbc.thin.JdbcThinBestEffortAffinityTransactionsSelfTest; import org.apache.ignite.jdbc.thin.JdbcThinConnectionSelfTest; import org.apache.ignite.jdbc.thin.JdbcThinStatementSelfTest; @@ -36,6 +36,7 @@ JdbcThinConnectionSelfTest.class, JdbcThinTcpIoTest.class, JdbcThinStatementSelfTest.class, + JdbcThinBestEffortAffinitySelfTest.class, JdbcThinBestEffortAffinityTransactionsSelfTest.class, }) public class IgniteJdbcThinDriverBestEffordAffinityTestSuite { @@ -45,7 +46,6 @@ public class IgniteJdbcThinDriverBestEffordAffinityTestSuite { */ @BeforeClass public static void setupBestEffortAffinity() { - GridTestUtils.setFieldValue(JdbcThinConnection.class, "bestEffortAffinity", true); - GridTestUtils.setFieldValue(JdbcThinAbstractSelfTest.class, "bestEffortAffinity", true); + GridTestUtils.setFieldValue(JdbcThinAbstractSelfTest.class, "affinityAwareness", true); } } \ No newline at end of file diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinAbstractSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinAbstractSelfTest.java index cdfbb3fe31adb..4450be2b7d5f5 100644 --- a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinAbstractSelfTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinAbstractSelfTest.java @@ -43,7 +43,7 @@ public class JdbcThinAbstractSelfTest extends GridCommonAbstractTest { /** Signals that tests should start in best effort affinity mode. */ - public static boolean bestEffortAffinity; + public static boolean affinityAwareness; /** * @param r Runnable to check support. diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinBestEffortAffinitySelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinBestEffortAffinitySelfTest.java new file mode 100644 index 0000000000000..5916d0da4b9ea --- /dev/null +++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinBestEffortAffinitySelfTest.java @@ -0,0 +1,856 @@ +/* + * 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.jdbc.thin; + +import java.io.Serializable; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.Callable; +import java.util.stream.Collectors; +import org.apache.ignite.IgniteCache; +import org.apache.ignite.cache.affinity.AffinityFunction; +import org.apache.ignite.cache.affinity.AffinityFunctionContext; +import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction; +import org.apache.ignite.cache.query.annotations.QuerySqlField; +import org.apache.ignite.cluster.ClusterNode; +import org.apache.ignite.configuration.CacheConfiguration; +import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.internal.jdbc.thin.AffinityCache; +import org.apache.ignite.internal.jdbc.thin.JdbcThinPartitionResultDescriptor; +import org.apache.ignite.internal.jdbc.thin.QualifiedSQLQuery; +import org.apache.ignite.internal.processors.query.QueryHistoryMetrics; +import org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing; +import org.apache.ignite.internal.sql.optimizer.affinity.PartitionResult; +import org.apache.ignite.internal.util.GridBoundedLinkedHashMap; +import org.apache.ignite.internal.util.typedef.F; +import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.lang.IgnitePredicate; +import org.apache.ignite.testframework.GridTestUtils; +import org.junit.Test; + +import static org.apache.ignite.cache.CacheMode.PARTITIONED; + +/** + * Jdbc thin best effort affinity test. + */ +@SuppressWarnings({"ThrowableNotThrown"}) +public class JdbcThinBestEffortAffinitySelfTest extends JdbcThinAbstractSelfTest { + /** URL. */ + private static final String URL = "jdbc:ignite:thin://127.0.0.1:10800..10802?affinityAwareness=true"; + + /** Nodes count. */ + private static final int NODES_CNT = 3; + + /** Query execution multiplier. */ + private static final int QUERY_EXECUTION_MULTIPLIER = 5; + + /** Rows count. */ + private static final int ROWS_COUNT = 100; + + /** Connection. */ + private Connection conn; + + /** Statement. */ + private Statement stmt; + + /** {@inheritDoc} */ + @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { + IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName); + + CacheConfiguration cache = defaultCacheConfiguration(); + + cache.setCacheMode(PARTITIONED); + cache.setBackups(1); + cache.setIndexedTypes( + Integer.class, Person.class + ); + + cfg.setCacheConfiguration(cache); + + return cfg; + } + + /** {@inheritDoc} */ + @Override protected void beforeTestsStarted() throws Exception { + super.beforeTestsStarted(); + + startGridsMultiThreaded(NODES_CNT); + + fillCache(DEFAULT_CACHE_NAME); + } + + /** {@inheritDoc} */ + @Override protected void beforeTest() throws Exception { + conn = DriverManager.getConnection(URL); + + conn.setSchema('"' + DEFAULT_CACHE_NAME + '"'); + + stmt = conn.createStatement(); + + assert stmt != null; + assert !stmt.isClosed(); + } + + /** {@inheritDoc} */ + @Override protected void afterTest() throws Exception { + U.closeQuiet(stmt); + + conn.close(); + + assert stmt.isClosed(); + assert conn.isClosed(); + } + + /** + * Check that queries goes to expected number of nodes. + * + * @throws Exception If failed. + */ + @Test + public void testExecuteQueries() throws Exception { + checkNodesUsage(null, "select * from Person where _key = 1", 1, 1, + false); + + checkNodesUsage(null, "select * from Person where _key = 1 or _key = 2", 2, + 2, false); + + checkNodesUsage(null, "select * from Person where _key in (1, 2)", 2, 2, + false); + } + + /** + * Check that parameterised queries goes to expected number of nodes. + * + * @throws Exception If failed. + */ + @Test + public void testExecuteParametrizedQueries() throws Exception { + // Use case 1. + PreparedStatement ps = conn.prepareStatement("select * from Person where _key = ?"); + + ps.setInt(1, 2); + + checkNodesUsage(ps, null, 1, 1, false); + + // Use case 2. + ps = conn.prepareStatement("select * from Person where _key = ? or _key = ?"); + + ps.setInt(1, 1); + + ps.setInt(2, 2); + + checkNodesUsage(ps, null, 2, 2, false); + + // Use case 3. + ps = conn.prepareStatement("select * from Person where _key in (?, ?)"); + + ps.setInt(1, 1); + + ps.setInt(2, 2); + + checkNodesUsage(ps, null, 2, 2, false); + } + + /** + * Check that dml queries(updates) goes to expected number of nodes. + * + * @throws Exception If failed. + */ + @Test + public void testUpdateQueries() throws Exception { + checkNodesUsage(null, "update Person set firstName = 'TestFirstName' where _key = 1", + 1, 1, true); + + checkNodesUsage(null, "update Person set firstName = 'TestFirstName' where _key = 1 or _key = 2", + 2, 2, true); + + checkNodesUsage(null, "update Person set firstName = 'TestFirstName' where _key in (1, 2)", + 2, 2, true); + } + + /** + * Check that parameterised dml queries(updates) goes to expected number of nodes. + * + * @throws Exception If failed. + */ + @Test + public void testUpdateParametrizedQueries() throws Exception { + // Use case 1. + PreparedStatement ps = conn.prepareStatement( + "update Person set firstName = 'TestFirstName' where _key = ?"); + + ps.setInt(1, 2); + + checkNodesUsage(ps, null, 1, 1, true); + + // Use case 2. + ps = conn.prepareStatement("update Person set firstName = 'TestFirstName' where _key = ? or _key = ?"); + + ps.setInt(1, 1); + + ps.setInt(2, 2); + + checkNodesUsage(ps, null, 2, 2, true); + + // Use case 3. + ps = conn.prepareStatement("update Person set firstName = 'TestFirstName' where _key in (?, ?)"); + + ps.setInt(1, 1); + + ps.setInt(2, 2); + + checkNodesUsage(ps, null, 2, 2, true); + } + + /** + * Check that dml queries(delete) goes to expected number of nodes. + * + * @throws Exception If failed. + */ + @Test + public void testDeleteQueries() throws Exception { + // In case of simple query like "delete from Person where _key = 1" fast update logic is used, + // so parition result is not calculated on the server side - nothing to check. + + checkNodesUsage(null, "delete from Person where _key = 10000 or _key = 20000", + 2, 0, true); + + checkNodesUsage(null, "delete from Person where _key in (10000, 20000)", + 2, 0, true); + } + + /** + * Check that parameterised dml queries(delete) goes to expected number of nodes. + * + * @throws Exception If failed. + */ + @Test + public void testDeleteParametrizedQueries() throws Exception { + // In case of simple query like "delete from Person where _key = ?" fast update logic is used, + // so parition result is not calculated on the server side - nothing to check. + + // Use case 1. + PreparedStatement ps = conn.prepareStatement("delete from Person where _key = ? or _key = ?"); + + ps.setInt(1, 1000); + + ps.setInt(2, 2000); + + checkNodesUsage(ps, null, 2, 0, true); + + // Use case 2. + ps = conn.prepareStatement("delete from Person where _key in (?, ?)"); + + ps.setInt(1, 1000); + + ps.setInt(2, 2000); + + checkNodesUsage(ps, null, 2, 0, true); + } + + /** + * Check that request/response functionality works fine if server response lacks partition result, + * i.e. partitionResult is null. AllNode tes. + * + * @throws Exception If failed. + */ + @Test + public void testQueryWithNullPartitionResponseBasedOnAllNode() throws Exception { + verifyPartitionResultIsNull("select * from Person where age > 15", 85); + } + + /** + * Check that request/response functionality works fine if server response lacks partition result, + * i.e. partitionResult is null. NoneNode tes. + * + * @throws Exception If failed. + */ + @Test + public void testQueryWithNullPartitionResponseBasedOnNoneNode() throws Exception { + verifyPartitionResultIsNull("select * from Person where _key = 1 and _key = 2", 0); + } + + + /** + * Check that in case of non-rendezvous affinity function, client side best effort affinity is skipped. + * + * @throws Exception If failed. + */ + @Test + public void testCacheWithNonRendezvousAffinityFunction() throws Exception { + final String cacheName = "cacheWithCustomAffinityFunction"; + + CacheConfiguration cache = prepareCacheConfig(cacheName); + cache.setAffinity(new DummyAffinity()); + + ignite(0).createCache(cache); + + fillCache(cacheName); + + verifyPartitionResultIsNull("select * from \"" + cacheName + "\".Person where _key = 1", + 1); + } + + /** + * Check that in case of custom filters, client side best effort affinity is skipped. + * + * @throws Exception If failed. + */ + @Test + public void testCacheWithCustomNodeFilter() throws Exception { + final String cacheName = "cacheWithCustomNodeFilter"; + + CacheConfiguration cache = prepareCacheConfig(cacheName); + cache.setNodeFilter(new CustomNodeFilter()); + + ignite(0).createCache(cache); + + fillCache(cacheName); + + verifyPartitionResultIsNull("select * from \"" + cacheName + "\".Person where _key = 1", + 1); + } + + /** + * Check that best effort functionality works fine for custom partitions count. + * + * @throws Exception If failed. + */ + @Test + public void testCacheWithRendezvousCustomPartitionsCount() throws Exception { + final String cacheName = "cacheWithRendezvousCustomPartitionsCount"; + + CacheConfiguration cache = prepareCacheConfig(cacheName); + cache.setAffinity(new RendezvousAffinityFunction(false, 10)); + + ignite(0).createCache(cache); + + fillCache(cacheName); + + checkNodesUsage(null, + "select * from \"" + cacheName + "\".Person where _key = 1", + 1, 1, false); + } + + /** + * Check that affinity cache is invalidated in case of changing topology, + * detected during partions destribution retrieval. + * + * @throws Exception If failed. + */ + @Test + public void testChangeTopologyDetectionWithinPartitionDistributionResponse() throws Exception { + final String sqlQry = "select * from Person where _key = 1"; + + stmt.executeQuery(sqlQry); + + AffinityCache affinityCache = GridTestUtils.getFieldValue(conn, "affinityCache"); + + startGrid(3); + + stmt.executeQuery(sqlQry); + + AffinityCache recreatedAffinityCache = GridTestUtils.getFieldValue(conn, "affinityCache"); + + assertTrue(recreatedAffinityCache.version().compareTo(affinityCache.version()) > 0); + } + + /** + * Check that affinity cache is invalidated in case of changing topology, + * detected during query response retrieval. + * + * @throws Exception If failed. + */ + @Test + public void testChangeTopologyDetectionWithinQueryExecutionResponse() throws Exception { + final String sqlQry = "select * from Person where _key = 1"; + + stmt.executeQuery(sqlQry); + stmt.executeQuery(sqlQry); + + AffinityCache affinityCache = GridTestUtils.getFieldValue(conn, "affinityCache"); + + startGrid(4); + + stmt.executeQuery("select * from Person where _key = 2"); + + AffinityCache recreatedAffinityCache = GridTestUtils.getFieldValue(conn, "affinityCache"); + + assertTrue(recreatedAffinityCache.version().compareTo(affinityCache.version()) > 0); + } + + /** + * Check that affinity cache is invalidated in case of changing topology, + * detected during best-effort-affinity-unrelated-query response retrieval. + * + * @throws Exception If failed. + */ + @Test + public void testChangeTopologyDetectionWithinBestEffortAffinityUnrelatedQuery() throws Exception { + final String sqlQry = "select * from Person where _key = 1"; + + ResultSet rs = stmt.executeQuery(sqlQry); + + AffinityCache affinityCache = GridTestUtils.getFieldValue(conn, "affinityCache"); + + startGrid(5); + + rs.getMetaData(); + + AffinityCache recreatedAffinityCache = GridTestUtils.getFieldValue(conn, "affinityCache"); + + assertTrue(recreatedAffinityCache.version().compareTo(affinityCache.version()) > 0); + } + + /** + * Check that client side best effort affinity optimizations are skipped if affinityAwareness is switched off. + * + * @throws Exception If failed. + */ + @Test + public void testBestEffortAffinityIsSkippedIfItIsSwitchedOff() throws Exception { + Connection conn = DriverManager.getConnection( + "jdbc:ignite:thin://127.0.0.1:10800..10802?affinityAwareness=false"); + + Statement stmt = conn.createStatement(); + + final String cacheName = "yac"; + + CacheConfiguration cache = prepareCacheConfig(cacheName); + + ignite(0).createCache(cache); + + stmt.executeQuery("select * from \"" + cacheName + "\".Person where _key = 1"); + + AffinityCache affinityCache = GridTestUtils.getFieldValue(conn, "affinityCache"); + + assertNull("Affinity cache is not null.", affinityCache); + } + + /** + * Check that client side best effort affinity optimizations are skipped by default. + * + * @throws Exception If failed. + */ + @Test + public void testBestEffortAffinityIsSkippedByDefault() throws Exception { + Connection conn = DriverManager.getConnection( + "jdbc:ignite:thin://127.0.0.1:10800..10802"); + + Statement stmt = conn.createStatement(); + + final String cacheName = "yacccc"; + + CacheConfiguration cache = prepareCacheConfig(cacheName); + + ignite(0).createCache(cache); + + stmt.executeQuery("select * from \"" + cacheName + "\".Person where _key = 1"); + + AffinityCache affinityCache = GridTestUtils.getFieldValue(conn, "affinityCache"); + + assertNull("Affinity cache is not null.", affinityCache); + } + + /** + * Check that affinity cache stores sql queries with their schemas. + * + * @throws Exception If failed. + */ + @Test + public void testAffinityCacheStoresSchemaBindedQuries() throws Exception { + final String cacheName = "yacc"; + + CacheConfiguration cache = prepareCacheConfig(cacheName); + cache.setSqlSchema(cacheName); + + ignite(0).createCache(cache); + + fillCache(cacheName); + + stmt.execute("select * from \"" + cacheName.toUpperCase() + "\".Person where _key = 1"); + + conn.setSchema(cacheName.toUpperCase()); + + stmt = conn.createStatement(); + + stmt.execute("select * from \"" + cacheName.toUpperCase() + "\".Person where _key = 1"); + + AffinityCache affinityCache = GridTestUtils.getFieldValue(conn, "affinityCache"); + + GridBoundedLinkedHashMap sqlCache = + GridTestUtils.getFieldValue(affinityCache, "sqlCache"); + + Set schemas = sqlCache.keySet().stream().map(QualifiedSQLQuery::schemaName).collect(Collectors.toSet()); + + assertTrue("Affinity cache doesn't contain query sent to 'default' schema.", + schemas.contains("default")); + assertTrue("Affinity cache doesn't contain query sent to '" + cacheName.toUpperCase() + "' schema.", + schemas.contains(cacheName.toUpperCase())); + } + + /** + * Check that affinity cache stores compacted version of partitoins destributions. + * + * @throws Exception If failed. + */ + @Test + public void testAffinityCacheCompactsPartitonDestributions() throws Exception { + final String cacheName = "yaccc"; + + CacheConfiguration cache = prepareCacheConfig(cacheName); + + ignite(0).createCache(cache); + + fillCache(cacheName); + + stmt.execute("select * from Person where _key = 2"); + stmt.execute("select * from Person where _key = 2"); + + stmt.execute("select * from \"" + cacheName + "\".Person where _key = 2"); + stmt.execute("select * from \"" + cacheName + "\".Person where _key = 2"); + + AffinityCache affinityCache = GridTestUtils.getFieldValue(conn, "affinityCache"); + + GridBoundedLinkedHashMap sqlCache = + GridTestUtils.getFieldValue(affinityCache, "sqlCache"); + + GridBoundedLinkedHashMap cachePartitionsDistribution = + GridTestUtils.getFieldValue(affinityCache, "cachePartitionsDistribution"); + + assertEquals("Sql sub-cache of affinity cache has unexpected number of elements.", + 2, sqlCache.size()); + + assertEquals("Partitions destribution sub-cache of affinity cache has unexpected number of elements.", + 2, cachePartitionsDistribution.size()); + + // Main assertition of the test: we are checking that partitions destributions for different caches + // are equal in therms of (==) + assertTrue("Partitions distributions are not the same.", + cachePartitionsDistribution.get(0) == cachePartitionsDistribution.get(1)); + } + + /** + * Check that best effort affinity works fine after reconnection. + * + * @throws Exception If failed. + */ + @Test + public void testReconnect() throws Exception { + checkNodesUsage(null, "select * from Person where _key = 3", 1, 1, + false); + + startGrid(7); + + for(int i = 0; i < NODES_CNT; i++) + stopGrid(i); + + GridTestUtils.assertThrows(log, new Callable() { + @Override public Object call() throws Exception { + stmt.execute("select * from Person where _key = 3"); + + return null; + } + }, SQLException.class, "Failed to communicate with Ignite cluster."); + + for(int i = 0; i < NODES_CNT; i++) + startGrid(i); + + stopGrid(4); + stopGrid(5); + stopGrid(6); + stopGrid(7); + + stmt = conn.createStatement(); + + // We need this extra query to invalidate obsolete affinity cache + stmt.execute("select * from Person where _key = 3"); + + checkNodesUsage(null, "select * from Person where _key = 3", 1, 1, + false); + } + + /** + * Prepares default cache configuration with given name. + * + * @param cacheName Cache name. + * @return Cache configuration. + */ + @SuppressWarnings("unchecked") + protected CacheConfiguration prepareCacheConfig(String cacheName) { + CacheConfiguration cache = defaultCacheConfiguration(); + + cache.setName(cacheName); + cache.setCacheMode(PARTITIONED); + cache.setIndexedTypes( + Integer.class, Person.class + ); + + return cache; + } + + /** + * Utitlity method that executes given query and verifies that expeted number of records was returned. + * Besides that given method verified that partitoin result for corresponding query is null. + * + * @param sqlQry Sql query. + * @param expRowsCnt Expected rows count. + * @throws SQLException If failed. + */ + protected void verifyPartitionResultIsNull(String sqlQry, int expRowsCnt) throws SQLException { + ResultSet rs = stmt.executeQuery(sqlQry); + + assert rs != null; + + int rowCntr = 0; + + while (rs.next()) + rowCntr++; + + assertEquals("Rows counter doesn't match expected value.", expRowsCnt, rowCntr); + + AffinityCache affinityCache = GridTestUtils.getFieldValue(conn, "affinityCache"); + + PartitionResult gotPartRes = affinityCache.partitionResult( + new QualifiedSQLQuery("default", sqlQry)).partitionResult(); + + assertNull("Partition result descriptor is not null.", gotPartRes); + } + + /** + * Utility method that: + * 1. warms up an affinity cache; + * 2. resets query history; + * 3. executes given query multiple times; + * 4. checks query history metrics in order to verify that not more than expected nodes were used. + * + * @param ps Prepared statement, either prepared statement or sql query should be used. + * @param sql Sql query, either prepared statement or sql query should be used. + * @param maxNodesUsedCnt Expected maximum number of used nodes. + * @param expRowsCnt Expected rows count within result. + * @param dml Flag that signals whether we execute dml or not. + * @throws Exception If failed. + */ + private void checkNodesUsage(PreparedStatement ps, String sql, int maxNodesUsedCnt, int expRowsCnt, boolean dml) + throws Exception { + // Warm up an affinity cache. + if (ps != null) + if (dml) + ps.executeUpdate(); + else + ps.executeQuery(); + else { + if (dml) + stmt.executeUpdate(sql); + else + stmt.executeQuery(sql); + } + + // Reset query history. + for (int i = 0; i < NODES_CNT; i++) { + ((IgniteH2Indexing)grid(i).context().query().getIndexing()) + .runningQueryManager().resetQueryHistoryMetrics(); + } + + // Execute query multiple times + for (int i = 0; i < NODES_CNT * QUERY_EXECUTION_MULTIPLIER; i++) { + ResultSet rs = null; + + int updatedRowsCnt = 0; + + if (ps != null) + if (dml) + updatedRowsCnt = ps.executeUpdate(); + else + rs = ps.executeQuery(); + else { + if (dml) + updatedRowsCnt = stmt.executeUpdate(sql); + else + rs = stmt.executeQuery(sql); + } + + if (dml) { + assertEquals("Unexpected updated rows count: expected [" + expRowsCnt + "]," + + " got [" + updatedRowsCnt + "]", expRowsCnt, updatedRowsCnt); + } + else { + assert rs != null; + + int gotRowsCnt = 0; + + while (rs.next()) + gotRowsCnt++; + + assertEquals("Unexpected rows count: expected [" + expRowsCnt + "], got [" + gotRowsCnt + "]", + expRowsCnt, gotRowsCnt); + } + } + + // Check query history metrics in order to verify that not more than expected nodes were used. + int nonEmptyMetricsCntr = 0; + int qryExecutionsCntr = 0; + for (int i = 0; i < NODES_CNT; i++) { + Collection metrics = ((IgniteH2Indexing)grid(i).context().query().getIndexing()) + .runningQueryManager().queryHistoryMetrics().values(); + + if (!metrics.isEmpty()) { + nonEmptyMetricsCntr++; + qryExecutionsCntr += new ArrayList<>(metrics).get(0).executions(); + } + } + + assertTrue("Unexpected amount of used nodes: expected [0 < nodesCnt <= " + maxNodesUsedCnt + + "], got [" + nonEmptyMetricsCntr + "]", + nonEmptyMetricsCntr > 0 && nonEmptyMetricsCntr <= maxNodesUsedCnt); + + assertEquals("Executions count doesn't match expeted value: expected [" + + NODES_CNT * QUERY_EXECUTION_MULTIPLIER + "], got [" + qryExecutionsCntr + "]", + NODES_CNT * QUERY_EXECUTION_MULTIPLIER, qryExecutionsCntr); + } + + /** + * Fills cache with test data. + * + * @param cacheName Cache name. + */ + private void fillCache(String cacheName) { + IgniteCache cachePerson = grid(0).cache(cacheName); + + assert cachePerson != null; + + for (int i = 0; i < ROWS_COUNT; i++) + cachePerson.put(i, new Person(i, "John" + i, "White" + i, i + 1)); + } + + /** + * Person. + */ + @SuppressWarnings("unused") + private static class Person implements Serializable { + /** ID. */ + @QuerySqlField + private final int id; + + /** First name. */ + @QuerySqlField + private final String firstName; + + /** Last name. */ + @QuerySqlField + private final String lastName; + + /** Age. */ + @QuerySqlField + private final int age; + + /** + * @param id ID. + * @param firstName First name. + * @param lastName Last name. + * @param age Age. + */ + private Person(int id, String firstName, String lastName, int age) { + assert !F.isEmpty(firstName); + assert !F.isEmpty(lastName); + assert age > 0; + + this.id = id; + this.firstName = firstName; + this.lastName = lastName; + this.age = age; + } + } + + /** + * Dummy affinity function. + */ + private static class DummyAffinity implements AffinityFunction { + /** {@inheritDoc} */ + @Override public void reset() { + // No-op. + } + + /** {@inheritDoc} */ + @Override public int partitions() { + return 1; + } + + /** {@inheritDoc} */ + @Override public int partition(Object key) { + return 0; + } + + /** + * Default constructor. + */ + public DummyAffinity() { + // No-op. + } + + /** {@inheritDoc} */ + @Override public List> assignPartitions(AffinityFunctionContext affCtx) { + List nodes = affCtx.currentTopologySnapshot(); + + List> assign = new ArrayList<>(partitions()); + + for (int i = 0; i < partitions(); ++i) + assign.add(Collections.singletonList(nodes.get(0))); + + return assign; + } + + /** {@inheritDoc} */ + @Override public void removeNode(UUID nodeId) { + // No-op. + } + } + + /** + * Filter that accepts all nodes. + */ + public static class CustomNodeFilter implements IgnitePredicate { + /** */ + private static final long serialVersionUID = 0L; + + /** {@inheritDoc} */ + @Override public boolean apply(ClusterNode node) { + return true; + } + + /** {@inheritDoc} */ + @Override public boolean equals(Object obj) { + return false; + } + + /** {@inheritDoc} */ + @Override public String toString() { + return "CustomNodeFilter"; + } + } +} diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinBestEffortAffinityTransactionsSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinBestEffortAffinityTransactionsSelfTest.java index 5abfc7f223e5a..85290f3c6ce72 100644 --- a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinBestEffortAffinityTransactionsSelfTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinBestEffortAffinityTransactionsSelfTest.java @@ -31,6 +31,7 @@ import org.apache.ignite.internal.processors.query.NestedTxMode; import org.apache.ignite.internal.processors.query.QueryHistoryMetrics; import org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing; +import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.testframework.GridStringLogger; import org.jetbrains.annotations.NotNull; import org.junit.Test; @@ -40,7 +41,7 @@ */ public class JdbcThinBestEffortAffinityTransactionsSelfTest extends JdbcThinAbstractSelfTest { /** */ - private static final String URL = "jdbc:ignite:thin://127.0.0.1:10800..10802"; + private static final String URL = "jdbc:ignite:thin://127.0.0.1:10800..10802?affinityAwareness=true"; /** Nodes count. */ private static final int NODES_CNT = 3; @@ -103,11 +104,7 @@ private CacheConfiguration cacheConfiguration(@NotNull String name) { /** {@inheritDoc} */ @Override protected void afterTest() throws Exception { - if (stmt != null && !stmt.isClosed()) { - stmt.close(); - - assert stmt.isClosed(); - } + U.closeQuiet(stmt); conn.close(); @@ -122,7 +119,7 @@ private CacheConfiguration cacheConfiguration(@NotNull String name) { * @throws SQLException if failed. */ private static Connection prepareConnection(boolean autoCommit, NestedTxMode nestedTxMode) throws SQLException { - Connection res = DriverManager.getConnection(URL + "?nestedTransactionsMode=" + nestedTxMode.name()); + Connection res = DriverManager.getConnection(URL + "&nestedTransactionsMode=" + nestedTxMode.name()); res.setAutoCommit(autoCommit); diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinConnectionMultipleAddressesTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinConnectionMultipleAddressesTest.java index 6aa08e8713bf6..1edae3a328f69 100644 --- a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinConnectionMultipleAddressesTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinConnectionMultipleAddressesTest.java @@ -535,7 +535,7 @@ private void stop(Connection conn, boolean all) { stopAllGrids(); else { - if (bestEffortAffinity) { + if (affinityAwareness) { for (int i = 0; i < NODES_CNT - 1; i++) stopGrid(i); } diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinConnectionSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinConnectionSelfTest.java index 0150e13c0377d..bcae0b4243749 100644 --- a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinConnectionSelfTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinConnectionSelfTest.java @@ -85,12 +85,18 @@ public class JdbcThinConnectionSelfTest extends JdbcThinAbstractSelfTest { private static final String LOCALHOST = "127.0.0.1"; /** URL. */ - private String url = bestEffortAffinity ? + private String url = affinityAwareness ? "jdbc:ignite:thin://127.0.0.1:10800..10802" : "jdbc:ignite:thin://127.0.0.1"; + /** URL with best effort affinity flag. */ + private String urlWithBestEffortAffinityFlag = url + "?affinityAwareness=" + affinityAwareness; + + /** URL with best effort affinity flag and semicolon as delimeter. */ + private String urlWithBestEffortAffinityFlagSemicolon = url + ";affinityAwareness=" + affinityAwareness; + /** Nodes count. */ - private int nodesCnt = bestEffortAffinity ? 4 : 2; + private int nodesCnt = affinityAwareness ? 4 : 2; /** {@inheritDoc} */ @SuppressWarnings("deprecation") @@ -165,13 +171,13 @@ public void testInvalidEndpoint() { public void testSocketBuffers() throws Exception { final int dfltDufSize = 64 * 1024; - assertInvalid(url + "?socketSendBuffer=-1", + assertInvalid(urlWithBestEffortAffinityFlag + "&socketSendBuffer=-1", "Property cannot be lower than 0 [name=socketSendBuffer, value=-1]"); - assertInvalid(url + "?socketReceiveBuffer=-1", + assertInvalid(urlWithBestEffortAffinityFlag + "&socketReceiveBuffer=-1", "Property cannot be lower than 0 [name=socketReceiveBuffer, value=-1]"); - try (Connection conn = DriverManager.getConnection(url)) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { for (JdbcThinTcpIo io: ios(conn)) { assertEquals(dfltDufSize, io.connectionProperties().getSocketSendBuffer()); assertEquals(dfltDufSize, io.connectionProperties().getSocketReceiveBuffer()); @@ -179,21 +185,21 @@ public void testSocketBuffers() throws Exception { } // Note that SO_* options are hints, so we check that value is equals to either what we set or to default. - try (Connection conn = DriverManager.getConnection(url + "?socketSendBuffer=1024")) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag + "&socketSendBuffer=1024")) { for (JdbcThinTcpIo io: ios(conn)) { assertEquals(1024, io.connectionProperties().getSocketSendBuffer()); assertEquals(dfltDufSize, io.connectionProperties().getSocketReceiveBuffer()); } } - try (Connection conn = DriverManager.getConnection(url + "?socketReceiveBuffer=1024")) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag + "&socketReceiveBuffer=1024")) { for (JdbcThinTcpIo io: ios(conn)) { assertEquals(dfltDufSize, io.connectionProperties().getSocketSendBuffer()); assertEquals(1024, io.connectionProperties().getSocketReceiveBuffer()); } } - try (Connection conn = DriverManager.getConnection(url+ "?" + + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag + "&" + "socketSendBuffer=1024&socketReceiveBuffer=2048")) { for (JdbcThinTcpIo io: ios(conn)) { assertEquals(1024, io.connectionProperties().getSocketSendBuffer()); @@ -211,28 +217,28 @@ public void testSocketBuffers() throws Exception { public void testSocketBuffersSemicolon() throws Exception { final int dfltDufSize = 64 * 1024; - assertInvalid(url + ";socketSendBuffer=-1", + assertInvalid(urlWithBestEffortAffinityFlagSemicolon + ";socketSendBuffer=-1", "Property cannot be lower than 0 [name=socketSendBuffer, value=-1]"); - assertInvalid(url + ";socketReceiveBuffer=-1", + assertInvalid(urlWithBestEffortAffinityFlagSemicolon + ";socketReceiveBuffer=-1", "Property cannot be lower than 0 [name=socketReceiveBuffer, value=-1]"); // Note that SO_* options are hints, so we check that value is equals to either what we set or to default. - try (Connection conn = DriverManager.getConnection(url + ";socketSendBuffer=1024")) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlagSemicolon + ";socketSendBuffer=1024")) { for (JdbcThinTcpIo io: ios(conn)) { assertEquals(1024, io.connectionProperties().getSocketSendBuffer()); assertEquals(dfltDufSize, io.connectionProperties().getSocketReceiveBuffer()); } } - try (Connection conn = DriverManager.getConnection(url + ";socketReceiveBuffer=1024")) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlagSemicolon + ";socketReceiveBuffer=1024")) { for (JdbcThinTcpIo io: ios(conn)) { assertEquals(dfltDufSize, io.connectionProperties().getSocketSendBuffer()); assertEquals(1024, io.connectionProperties().getSocketReceiveBuffer()); } } - try (Connection conn = DriverManager.getConnection(url + ";" + + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlagSemicolon + ";" + "socketSendBuffer=1024;socketReceiveBuffer=2048")) { for (JdbcThinTcpIo io: ios(conn)) { assertEquals(1024, io.connectionProperties().getSocketSendBuffer()); @@ -248,37 +254,45 @@ public void testSocketBuffersSemicolon() throws Exception { */ @Test public void testSqlHints() throws Exception { - try (Connection conn = DriverManager.getConnection(url)) { - assertHints(conn, false, false, false, false, false, false); + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { + assertHints(conn, false, false, false, false, false, + false, affinityAwareness); } - try (Connection conn = DriverManager.getConnection(url + "?distributedJoins=true")) { - assertHints(conn, true, false, false, false, false, false); + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag + "&distributedJoins=true")) { + assertHints(conn, true, false, false, false, false, + false, affinityAwareness); } - try (Connection conn = DriverManager.getConnection(url + "?enforceJoinOrder=true")) { - assertHints(conn, false, true, false, false, false, false); + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag + "&enforceJoinOrder=true")) { + assertHints(conn, false, true, false, false, false, + false, affinityAwareness); } - try (Connection conn = DriverManager.getConnection(url + "?collocated=true")) { - assertHints(conn, false, false, true, false, false, false); + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag + "&collocated=true")) { + assertHints(conn, false, false, true, false, false, + false, affinityAwareness); } - try (Connection conn = DriverManager.getConnection(url + "?replicatedOnly=true")) { - assertHints(conn, false, false, false, true, false, false); + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag + "&replicatedOnly=true")) { + assertHints(conn, false, false, false, true, false, + false, affinityAwareness); } - try (Connection conn = DriverManager.getConnection(url + "?lazy=true")) { - assertHints(conn, false, false, false, false, true, false); + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag + "&lazy=true")) { + assertHints(conn, false, false, false, false, true, + false, affinityAwareness); } - try (Connection conn = DriverManager.getConnection(url + "?skipReducerOnUpdate=true")) { - assertHints(conn, false, false, false, false, false, true); + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag + "&skipReducerOnUpdate=true")) { + assertHints(conn, false, false, false, false, false, + true, affinityAwareness); } - try (Connection conn = DriverManager.getConnection(url + "?distributedJoins=true&" + + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag + "&distributedJoins=true&" + "enforceJoinOrder=true&collocated=true&replicatedOnly=true&lazy=true&skipReducerOnUpdate=true")) { - assertHints(conn, true, true, true, true, true, true); + assertHints(conn, true, true, true, true, true, + true, affinityAwareness); } } @@ -289,33 +303,40 @@ public void testSqlHints() throws Exception { */ @Test public void testSqlHintsSemicolon() throws Exception { - try (Connection conn = DriverManager.getConnection(url + ";distributedJoins=true")) { - assertHints(conn, true, false, false, false, false, false); + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlagSemicolon + ";distributedJoins=true")) { + assertHints(conn, true, false, false, false, false, + false, affinityAwareness); } - try (Connection conn = DriverManager.getConnection(url + ";enforceJoinOrder=true")) { - assertHints(conn, false, true, false, false, false, false); + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlagSemicolon + ";enforceJoinOrder=true")) { + assertHints(conn, false, true, false, false, false, + false, affinityAwareness); } - try (Connection conn = DriverManager.getConnection(url + ";collocated=true")) { - assertHints(conn, false, false, true, false, false, false); + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlagSemicolon + ";collocated=true")) { + assertHints(conn, false, false, true, false, false, + false, affinityAwareness); } - try (Connection conn = DriverManager.getConnection(url + ";replicatedOnly=true")) { - assertHints(conn, false, false, false, true, false, false); + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlagSemicolon + ";replicatedOnly=true")) { + assertHints(conn, false, false, false, true, false, + false, affinityAwareness); } - try (Connection conn = DriverManager.getConnection(url + ";lazy=true")) { - assertHints(conn, false, false, false, false, true, false); + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlagSemicolon + ";lazy=true")) { + assertHints(conn, false, false, false, false, true, + false, affinityAwareness); } - try (Connection conn = DriverManager.getConnection(url + ";skipReducerOnUpdate=true")) { - assertHints(conn, false, false, false, false, false, true); + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlagSemicolon + ";skipReducerOnUpdate=true")) { + assertHints(conn, false, false, false, false, false, + true, affinityAwareness); } - try (Connection conn = DriverManager.getConnection(url + ";distributedJoins=true;" + + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlagSemicolon + ";distributedJoins=true;" + "enforceJoinOrder=true;collocated=true;replicatedOnly=true;lazy=true;skipReducerOnUpdate=true")) { - assertHints(conn, true, true, true, true, true, true); + assertHints(conn, true, true, true, true, true, + true, affinityAwareness); } } @@ -332,7 +353,7 @@ public void testSqlHintsSemicolon() throws Exception { * @throws Exception If failed. */ private void assertHints(Connection conn, boolean distributedJoins, boolean enforceJoinOrder, boolean collocated, - boolean replicatedOnly, boolean lazy, boolean skipReducerOnUpdate)throws Exception { + boolean replicatedOnly, boolean lazy, boolean skipReducerOnUpdate, boolean bestEffortAffinityEnabled)throws Exception { for (JdbcThinTcpIo io: ios(conn)) { assertEquals(distributedJoins, io.connectionProperties().isDistributedJoins()); assertEquals(enforceJoinOrder, io.connectionProperties().isEnforceJoinOrder()); @@ -340,6 +361,7 @@ private void assertHints(Connection conn, boolean distributedJoins, boolean enfo assertEquals(replicatedOnly, io.connectionProperties().isReplicatedOnly()); assertEquals(lazy, io.connectionProperties().isLazy()); assertEquals(skipReducerOnUpdate, io.connectionProperties().isSkipReducerOnUpdate()); + assertEquals(bestEffortAffinityEnabled, io.connectionProperties().isAffinityAwareness()); } } @@ -350,39 +372,39 @@ private void assertHints(Connection conn, boolean distributedJoins, boolean enfo */ @Test public void testTcpNoDelay() throws Exception { - assertInvalid(url + "?tcpNoDelay=0", + assertInvalid(urlWithBestEffortAffinityFlag + "&tcpNoDelay=0", "Invalid property value. [name=tcpNoDelay, val=0, choices=[true, false]]"); - assertInvalid(url + "?tcpNoDelay=1", + assertInvalid(urlWithBestEffortAffinityFlag + "&tcpNoDelay=1", "Invalid property value. [name=tcpNoDelay, val=1, choices=[true, false]]"); - assertInvalid(url + "?tcpNoDelay=false1", + assertInvalid(urlWithBestEffortAffinityFlag + "&tcpNoDelay=false1", "Invalid property value. [name=tcpNoDelay, val=false1, choices=[true, false]]"); - assertInvalid(url + "?tcpNoDelay=true1", + assertInvalid(urlWithBestEffortAffinityFlag + "&tcpNoDelay=true1", "Invalid property value. [name=tcpNoDelay, val=true1, choices=[true, false]]"); - try (Connection conn = DriverManager.getConnection(url)) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { for (JdbcThinTcpIo io: ios(conn)) assertTrue(io.connectionProperties().isTcpNoDelay()); } - try (Connection conn = DriverManager.getConnection(url + "?tcpNoDelay=true")) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag + "&tcpNoDelay=true")) { for (JdbcThinTcpIo io: ios(conn)) assertTrue(io.connectionProperties().isTcpNoDelay()); } - try (Connection conn = DriverManager.getConnection(url + "?tcpNoDelay=True")) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag + "&tcpNoDelay=True")) { for (JdbcThinTcpIo io: ios(conn)) assertTrue(io.connectionProperties().isTcpNoDelay()); } - try (Connection conn = DriverManager.getConnection(url + "?tcpNoDelay=false")) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag + "&tcpNoDelay=false")) { for (JdbcThinTcpIo io: ios(conn)) assertFalse(io.connectionProperties().isTcpNoDelay()); } - try (Connection conn = DriverManager.getConnection(url + "?tcpNoDelay=False")) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag + "&tcpNoDelay=False")) { for (JdbcThinTcpIo io: ios(conn)) assertFalse(io.connectionProperties().isTcpNoDelay()); } @@ -395,34 +417,34 @@ public void testTcpNoDelay() throws Exception { */ @Test public void testTcpNoDelaySemicolon() throws Exception { - assertInvalid(url + ";tcpNoDelay=0", + assertInvalid(urlWithBestEffortAffinityFlagSemicolon + ";tcpNoDelay=0", "Invalid property value. [name=tcpNoDelay, val=0, choices=[true, false]]"); - assertInvalid(url + ";tcpNoDelay=1", + assertInvalid(urlWithBestEffortAffinityFlagSemicolon + ";tcpNoDelay=1", "Invalid property value. [name=tcpNoDelay, val=1, choices=[true, false]]"); - assertInvalid(url + ";tcpNoDelay=false1", + assertInvalid(urlWithBestEffortAffinityFlagSemicolon + ";tcpNoDelay=false1", "Invalid property value. [name=tcpNoDelay, val=false1, choices=[true, false]]"); - assertInvalid(url + ";tcpNoDelay=true1", + assertInvalid(urlWithBestEffortAffinityFlagSemicolon + ";tcpNoDelay=true1", "Invalid property value. [name=tcpNoDelay, val=true1, choices=[true, false]]"); - try (Connection conn = DriverManager.getConnection(url + ";tcpNoDelay=true")) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlagSemicolon + ";tcpNoDelay=true")) { for (JdbcThinTcpIo io: ios(conn)) assertTrue(io.connectionProperties().isTcpNoDelay()); } - try (Connection conn = DriverManager.getConnection(url + ";tcpNoDelay=True")) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlagSemicolon + ";tcpNoDelay=True")) { for (JdbcThinTcpIo io: ios(conn)) assertTrue(io.connectionProperties().isTcpNoDelay()); } - try (Connection conn = DriverManager.getConnection(url + ";tcpNoDelay=false")) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlagSemicolon + ";tcpNoDelay=false")) { for (JdbcThinTcpIo io: ios(conn)) assertFalse(io.connectionProperties().isTcpNoDelay()); } - try (Connection conn = DriverManager.getConnection(url + ";tcpNoDelay=False")) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlagSemicolon + ";tcpNoDelay=False")) { for (JdbcThinTcpIo io: ios(conn)) assertFalse(io.connectionProperties().isTcpNoDelay()); } @@ -435,7 +457,7 @@ public void testTcpNoDelaySemicolon() throws Exception { */ @Test public void testAutoCloseServerCursorProperty() throws Exception { - String url = this.url + "?autoCloseServerCursor"; + String url = urlWithBestEffortAffinityFlag + "&autoCloseServerCursor"; String err = "Invalid property value. [name=autoCloseServerCursor"; @@ -444,7 +466,7 @@ public void testAutoCloseServerCursorProperty() throws Exception { assertInvalid(url + "=false1", err); assertInvalid(url + "=true1", err); - try (Connection conn = DriverManager.getConnection(this.url)) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { for (JdbcThinTcpIo io: ios(conn)) assertFalse(io.connectionProperties().isAutoCloseServerCursor()); } @@ -477,7 +499,7 @@ public void testAutoCloseServerCursorProperty() throws Exception { */ @Test public void testAutoCloseServerCursorPropertySemicolon() throws Exception { - String url = this.url + ";autoCloseServerCursor"; + String url = urlWithBestEffortAffinityFlagSemicolon + ";autoCloseServerCursor"; String err = "Invalid property value. [name=autoCloseServerCursor"; @@ -537,15 +559,15 @@ public void testSchema() throws Exception { */ @Test public void testSchemaSemicolon() throws Exception { - try (Connection conn = DriverManager.getConnection(url + ";schema=public")) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlagSemicolon + ";schema=public")) { assertEquals("Invalid schema", "PUBLIC", conn.getSchema()); } - try (Connection conn = DriverManager.getConnection(url + ";schema=\"" + DEFAULT_CACHE_NAME + '"')) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlagSemicolon + ";schema=\"" + DEFAULT_CACHE_NAME + '"')) { assertEquals("Invalid schema", DEFAULT_CACHE_NAME, conn.getSchema()); } - try (Connection conn = DriverManager.getConnection(url + ";schema=_not_exist_schema_")) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlagSemicolon + ";schema=_not_exist_schema_")) { assertEquals("Invalid schema", "_NOT_EXIST_SCHEMA_", conn.getSchema()); } } @@ -560,7 +582,7 @@ public void testSchemaSemicolon() throws Exception { private static Collection ios(Connection conn) throws Exception { JdbcThinConnection conn0 = conn.unwrap(JdbcThinConnection.class); - Collection ios = bestEffortAffinity ? ((Map) + Collection ios = affinityAwareness ? ((Map) GridTestUtils.getFieldValue(conn0, JdbcThinConnection.class, "ios")).values() : Collections.singleton(GridTestUtils.getFieldValue(conn0, JdbcThinConnection.class, "singleIo")); @@ -594,7 +616,7 @@ private void assertInvalid(final String url, String errMsg) { public void testClose() throws Exception { final Connection conn; - try (Connection conn0 = DriverManager.getConnection(url)) { + try (Connection conn0 = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { conn = conn0; assert conn != null; @@ -619,7 +641,7 @@ public void testClose() throws Exception { */ @Test public void testCreateStatement() throws Exception { - try (Connection conn = DriverManager.getConnection(url)) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { try (Statement stmt = conn.createStatement()) { assertNotNull(stmt); @@ -642,7 +664,7 @@ public void testCreateStatement() throws Exception { */ @Test public void testCreateStatement2() throws Exception { - try (Connection conn = DriverManager.getConnection(url)) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { int [] rsTypes = new int[] {TYPE_FORWARD_ONLY, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.TYPE_SCROLL_SENSITIVE}; @@ -696,7 +718,7 @@ public void testCreateStatement2() throws Exception { */ @Test public void testCreateStatement3() throws Exception { - try (Connection conn = DriverManager.getConnection(url)) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { int [] rsTypes = new int[] {TYPE_FORWARD_ONLY, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.TYPE_SCROLL_SENSITIVE}; @@ -756,7 +778,7 @@ public void testCreateStatement3() throws Exception { */ @Test public void testPrepareStatement() throws Exception { - try (Connection conn = DriverManager.getConnection(url)) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { // null query text GridTestUtils.assertThrows(log, new Callable() { @@ -790,7 +812,7 @@ public void testPrepareStatement() throws Exception { */ @Test public void testPrepareStatement3() throws Exception { - try (Connection conn = DriverManager.getConnection(url)) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { final String sqlText = "select * from test where param = ?"; int [] rsTypes = new int[] @@ -851,7 +873,7 @@ public void testPrepareStatement3() throws Exception { */ @Test public void testPrepareStatement4() throws Exception { - try (Connection conn = DriverManager.getConnection(url)) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { final String sqlText = "select * from test where param = ?"; int [] rsTypes = new int[] @@ -917,7 +939,7 @@ public void testPrepareStatement4() throws Exception { */ @Test public void testPrepareStatementAutoGeneratedKeysUnsupported() throws Exception { - try (Connection conn = DriverManager.getConnection(url)) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { final String sqlText = "insert into test (val) values (?)"; GridTestUtils.assertThrows(log, @@ -967,7 +989,7 @@ public void testPrepareStatementAutoGeneratedKeysUnsupported() throws Exception */ @Test public void testPrepareCallUnsupported() throws Exception { - try (Connection conn = DriverManager.getConnection(url)) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { final String sqlText = "exec test()"; GridTestUtils.assertThrows(log, @@ -1008,7 +1030,7 @@ public void testPrepareCallUnsupported() throws Exception { */ @Test public void testNativeSql() throws Exception { - try (Connection conn = DriverManager.getConnection(url)) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { // null query text GridTestUtils.assertThrows(log, new Callable() { @@ -1040,7 +1062,7 @@ public void testNativeSql() throws Exception { */ @Test public void testGetSetAutoCommit() throws Exception { - try (Connection conn = DriverManager.getConnection(url)) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { boolean ac0 = conn.getAutoCommit(); conn.setAutoCommit(!ac0); @@ -1065,7 +1087,7 @@ public void testGetSetAutoCommit() throws Exception { */ @Test public void testCommit() throws Exception { - try (Connection conn = DriverManager.getConnection(url)) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { // Should not be called in auto-commit mode GridTestUtils.assertThrows(log, new Callable() { @@ -1110,7 +1132,7 @@ public void testCommit() throws Exception { */ @Test public void testRollback() throws Exception { - try (Connection conn = DriverManager.getConnection(url)) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { // Should not be called in auto-commit mode GridTestUtils.assertThrows(log, new Callable() { @@ -1140,7 +1162,7 @@ public void testRollback() throws Exception { */ @Test public void testBeginFailsWhenMvccIsDisabled() throws Exception { - try (Connection conn = DriverManager.getConnection(url)) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { conn.createStatement().execute("BEGIN"); fail("Exception is expected"); @@ -1155,7 +1177,7 @@ public void testBeginFailsWhenMvccIsDisabled() throws Exception { */ @Test public void testCommitIgnoredWhenMvccIsDisabled() throws Exception { - try (Connection conn = DriverManager.getConnection(url)) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { conn.setAutoCommit(false); conn.createStatement().execute("COMMIT"); @@ -1169,7 +1191,7 @@ public void testCommitIgnoredWhenMvccIsDisabled() throws Exception { */ @Test public void testRollbackIgnoredWhenMvccIsDisabled() throws Exception { - try (Connection conn = DriverManager.getConnection(url)) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { conn.setAutoCommit(false); conn.createStatement().execute("ROLLBACK"); @@ -1184,7 +1206,7 @@ public void testRollbackIgnoredWhenMvccIsDisabled() throws Exception { */ @Test public void testGetMetaData() throws Exception { - try (Connection conn = DriverManager.getConnection(url)) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { DatabaseMetaData meta = conn.getMetaData(); assertNotNull(meta); @@ -1205,7 +1227,7 @@ public void testGetMetaData() throws Exception { */ @Test public void testGetSetReadOnly() throws Exception { - try (Connection conn = DriverManager.getConnection(url)) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { conn.close(); // Exception when called on closed connection @@ -1229,7 +1251,7 @@ public void testGetSetReadOnly() throws Exception { */ @Test public void testGetSetCatalog() throws Exception { - try (Connection conn = DriverManager.getConnection(url)) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { assert !conn.getMetaData().supportsCatalogsInDataManipulation(); assertNull(conn.getCatalog()); @@ -1261,7 +1283,7 @@ public void testGetSetCatalog() throws Exception { */ @Test public void testGetSetTransactionIsolation() throws Exception { - try (Connection conn = DriverManager.getConnection(url)) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { // Invalid parameter value GridTestUtils.assertThrows(log, new Callable() { @@ -1312,7 +1334,7 @@ public void testGetSetTransactionIsolation() throws Exception { */ @Test public void testClearGetWarnings() throws Exception { - try (Connection conn = DriverManager.getConnection(url)) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { SQLWarning warn = conn.getWarnings(); assertNull(warn); @@ -1346,7 +1368,7 @@ public void testClearGetWarnings() throws Exception { */ @Test public void testGetSetTypeMap() throws Exception { - try (Connection conn = DriverManager.getConnection(url)) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { GridTestUtils.assertThrows(log, new Callable() { @Override public Object call() throws Exception { @@ -1402,7 +1424,7 @@ public void testGetSetTypeMap() throws Exception { */ @Test public void testGetSetHoldability() throws Exception { - try (Connection conn = DriverManager.getConnection(url)) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { // default value assertEquals(conn.getMetaData().getResultSetHoldability(), conn.getHoldability()); @@ -1456,7 +1478,7 @@ public void testGetSetHoldability() throws Exception { */ @Test public void testSetSavepoint() throws Exception { - try (Connection conn = DriverManager.getConnection(url)) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { assert !conn.getMetaData().supportsSavepoints(); // Disallowed in auto-commit mode @@ -1487,7 +1509,7 @@ public void testSetSavepoint() throws Exception { */ @Test public void testSetSavepointName() throws Exception { - try (Connection conn = DriverManager.getConnection(url)) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { assert !conn.getMetaData().supportsSavepoints(); // Invalid arg @@ -1533,7 +1555,7 @@ public void testSetSavepointName() throws Exception { */ @Test public void testRollbackSavePoint() throws Exception { - try (Connection conn = DriverManager.getConnection(url)) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { assert !conn.getMetaData().supportsSavepoints(); // Invalid arg @@ -1579,7 +1601,7 @@ public void testRollbackSavePoint() throws Exception { */ @Test public void testReleaseSavepoint() throws Exception { - try (Connection conn = DriverManager.getConnection(url)) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { assert !conn.getMetaData().supportsSavepoints(); // Invalid arg @@ -1618,7 +1640,7 @@ public void testReleaseSavepoint() throws Exception { */ @Test public void testCreateClob() throws Exception { - try (Connection conn = DriverManager.getConnection(url)) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { // Unsupported GridTestUtils.assertThrows(log, new Callable() { @@ -1649,7 +1671,7 @@ public void testCreateClob() throws Exception { */ @Test public void testCreateBlob() throws Exception { - try (Connection conn = DriverManager.getConnection(url)) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { // Unsupported GridTestUtils.assertThrows(log, new Callable() { @@ -1680,7 +1702,7 @@ public void testCreateBlob() throws Exception { */ @Test public void testCreateNClob() throws Exception { - try (Connection conn = DriverManager.getConnection(url)) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { // Unsupported GridTestUtils.assertThrows(log, new Callable() { @@ -1711,7 +1733,7 @@ public void testCreateNClob() throws Exception { */ @Test public void testCreateSQLXML() throws Exception { - try (Connection conn = DriverManager.getConnection(url)) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { // Unsupported GridTestUtils.assertThrows(log, new Callable() { @@ -1744,7 +1766,7 @@ public void testCreateSQLXML() throws Exception { public void testGetSetClientInfoPair() throws Exception { // fail("https://issues.apache.org/jira/browse/IGNITE-5425"); - try (Connection conn = DriverManager.getConnection(url)) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { final String name = "ApplicationName"; final String val = "SelfTest"; @@ -1778,7 +1800,7 @@ public void testGetSetClientInfoPair() throws Exception { */ @Test public void testGetSetClientInfoProperties() throws Exception { - try (Connection conn = DriverManager.getConnection(url)) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { final String name = "ApplicationName"; final String val = "SelfTest"; @@ -1817,7 +1839,7 @@ public void testGetSetClientInfoProperties() throws Exception { */ @Test public void testCreateArrayOf() throws Exception { - try (Connection conn = DriverManager.getConnection(url)) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { final String typeName = "varchar"; final String[] elements = new String[] {"apple", "pear"}; @@ -1858,7 +1880,7 @@ public void testCreateArrayOf() throws Exception { */ @Test public void testCreateStruct() throws Exception { - try (Connection conn = DriverManager.getConnection(url)) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { // Invalid typename GridTestUtils.assertThrows(log, new Callable() { @@ -1895,7 +1917,7 @@ public void testCreateStruct() throws Exception { */ @Test public void testGetSetSchema() throws Exception { - try (Connection conn = DriverManager.getConnection(url)) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { assertEquals("PUBLIC", conn.getSchema()); final String schema = "test"; @@ -1929,7 +1951,7 @@ public void testGetSetSchema() throws Exception { */ @Test public void testAbort() throws Exception { - try (Connection conn = DriverManager.getConnection(url)) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { //Invalid executor GridTestUtils.assertThrows(log, new Callable() { @@ -1956,7 +1978,7 @@ public void testAbort() throws Exception { */ @Test public void testGetSetNetworkTimeout() throws Exception { - try (Connection conn = DriverManager.getConnection(url)) { + try (Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { // default assertEquals(0, conn.getNetworkTimeout()); @@ -2004,7 +2026,7 @@ public void testGetSetNetworkTimeout() throws Exception { public void testInvalidNestedTxMode() { GridTestUtils.assertThrows(null, new Callable() { @Override public Object call() throws Exception { - DriverManager.getConnection(url + "/?nestedTransactionsMode=invalid"); + DriverManager.getConnection(urlWithBestEffortAffinityFlag + "&nestedTransactionsMode=invalid"); return null; } @@ -2024,6 +2046,8 @@ public void testInvalidNestedTxModeOnServerSide() { connProps.nestedTxMode("invalid"); + connProps.setAffinityAwareness(affinityAwareness); + GridTestUtils.assertThrows(null, new Callable() { @SuppressWarnings("ResultOfObjectAllocationIgnored") @Override public Object call() throws Exception { @@ -2040,7 +2064,7 @@ public void testInvalidNestedTxModeOnServerSide() { public void testSslClientAndPlainServer() { Throwable e = GridTestUtils.assertThrows(log, new Callable() { @Override public Object call() throws Exception { - DriverManager.getConnection(url + "/?sslMode=require" + + DriverManager.getConnection(urlWithBestEffortAffinityFlag + "&sslMode=require" + "&sslClientCertificateKeyStoreUrl=" + CLI_KEY_STORE_PATH + "&sslClientCertificateKeyStorePassword=123456" + "&sslTrustCertificateKeyStoreUrl=" + SRV_KEY_STORE_PATH + @@ -2048,9 +2072,9 @@ public void testSslClientAndPlainServer() { return null; } - }, SQLException.class, bestEffortAffinity ? "Failed to connect to server" : "Failed to SSL connect to server"); + }, SQLException.class, affinityAwareness ? "Failed to connect to server" : "Failed to SSL connect to server"); - if (bestEffortAffinity) { + if (affinityAwareness) { for (Throwable t: e.getSuppressed()) { assertEquals(SQLException.class, t.getClass()); assertTrue(t.getMessage().contains("Failed to SSL connect to server")); @@ -2071,7 +2095,7 @@ public void testMultithreadingException() throws Exception { final AtomicInteger exCnt = new AtomicInteger(0); - try (final Connection conn = DriverManager.getConnection(url)) { + try (final Connection conn = DriverManager.getConnection(urlWithBestEffortAffinityFlag)) { final IgniteInternalFuture f = GridTestUtils.runMultiThreadedAsync(new Runnable() { @Override public void run() { try { diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinDataSourceSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinDataSourceSelfTest.java index 86ec178c6f2a5..b2de045536435 100644 --- a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinDataSourceSelfTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinDataSourceSelfTest.java @@ -283,7 +283,7 @@ public static class JndiContextMockFactory implements InitialContextFactory { private static Collection ios(Connection conn) throws Exception { JdbcThinConnection conn0 = conn.unwrap(JdbcThinConnection.class); - Collection ios = bestEffortAffinity ? ((Map) + Collection ios = affinityAwareness ? ((Map) GridTestUtils.getFieldValue(conn0, JdbcThinConnection.class, "ios")).values() : Collections.singleton(GridTestUtils.getFieldValue(conn0, JdbcThinConnection.class, "singleIo")); diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinStatementSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinStatementSelfTest.java index 93a120cd0f0ae..c319907169ea8 100644 --- a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinStatementSelfTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinStatementSelfTest.java @@ -43,12 +43,12 @@ @SuppressWarnings({"ThrowableNotThrown"}) public class JdbcThinStatementSelfTest extends JdbcThinAbstractSelfTest { /** URL. */ - private String url = bestEffortAffinity ? - "jdbc:ignite:thin://127.0.0.1:10800..10802" : - "jdbc:ignite:thin://127.0.0.1"; + private String url = affinityAwareness ? + "jdbc:ignite:thin://127.0.0.1:10800..10802?affinityAwareness=true" : + "jdbc:ignite:thin://127.0.0.1?affinityAwareness=false"; /** Nodes count. */ - private int nodesCnt = bestEffortAffinity ? 4 : 3; + private int nodesCnt = affinityAwareness ? 4 : 3; /** SQL query. */ private static final String SQL = "select * from Person where age > 30"; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/ConnectionProperties.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/ConnectionProperties.java index d59e9793ebc7e..400bf8e2db7e0 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/ConnectionProperties.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/ConnectionProperties.java @@ -395,14 +395,26 @@ public interface ConnectionProperties { public String getPassword(); /** - * @return {@code True} if data page scan support is enabled for this connection, {@code false} if it's disabled + * @return {@code true} if data page scan support is enabled for this connection, {@code false} if it's disabled * and {@code null} for server default. */ @Nullable public Boolean isDataPageScanEnabled(); /** - * @param dataPageScanEnabled {@code True} if data page scan support is enabled for this connection, + * @param dataPageScanEnabled {@code true} if data page scan support is enabled for this connection, * if {@code false} then it's disabled, if {@code null} then server should use its default settings. */ public void setDataPageScanEnabled(@Nullable Boolean dataPageScanEnabled); + + /** + * @return {@code true} if jdbc thin affinity awareness is enabled for this connection, + * {@code false} if it's disabled. + */ + public boolean isAffinityAwareness(); + + /** + * @param affinityAwareness {@code true} if jdbc thin affinity awareness is enabled + * for this connection, if {@code false} then it's disabled. + */ + public void setAffinityAwareness(boolean affinityAwareness); } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/ConnectionPropertiesImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/ConnectionPropertiesImpl.java index 0a0ff8a4b01dc..ac65b2078acab 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/ConnectionPropertiesImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/ConnectionPropertiesImpl.java @@ -189,6 +189,12 @@ false, new PropertyValidator() { "Whether data page scan for queries is allowed. If not specified, server defines the default behaviour.", null, false); + /** affinity awareness flag. */ + private BooleanProperty affinityAwareness = new BooleanProperty( + "affinityAwareness", + "Whether jdbc thin affinity awareness is enabled.", + false, false); + /** Properties array. */ private final ConnectionProperty [] propsArray = { distributedJoins, enforceJoinOrder, collocated, replicatedOnly, autoCloseServerCursor, @@ -198,7 +204,8 @@ false, new PropertyValidator() { sslTrustCertificateKeyStoreUrl, sslTrustCertificateKeyStorePassword, sslTrustCertificateKeyStoreType, sslTrustAll, sslFactory, user, passwd, - dataPageScanEnabled + dataPageScanEnabled, + affinityAwareness }; /** {@inheritDoc} */ @@ -504,6 +511,16 @@ false, new PropertyValidator() { this.dataPageScanEnabled.setValue(dataPageScanEnabled); } + /** {@inheritDoc} */ + @Override public boolean isAffinityAwareness() { + return affinityAwareness.value(); + } + + /** {@inheritDoc} */ + @Override public void setAffinityAwareness(boolean affinityAwareness) { + this.affinityAwareness.setValue(affinityAwareness); + } + /** * @param url URL connection. * @param props Environment properties. diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinConnection.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinConnection.java index 057d65fd46739..a841b814b7519 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinConnection.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinConnection.java @@ -116,10 +116,8 @@ public class JdbcThinConnection implements Connection { /** Index generator. */ private static final AtomicLong IDX_GEN = new AtomicLong(); - /** Best effort affinity enabled flag. */ - // TODO: 13.02.19 IGNITE-11309 JDBC Thin: add flag or property to disable best effort affinity - @SuppressWarnings("unused") - private static boolean bestEffortAffinity; + /** Affinity awareness enabled flag. */ + private final boolean affinityAwareness; /** Statements modification mutex. */ private final Object stmtsMux = new Object(); @@ -207,6 +205,8 @@ public JdbcThinConnection(ConnectionProperties connProps) throws SQLException { timer = new Timer("query-timeout-timer"); + affinityAwareness = connProps.isAffinityAwareness(); + ensureConnected(); } @@ -225,7 +225,7 @@ private void ensureConnected() throws SQLException { HostAndPortRange[] srvs = connProps.getAddresses(); - if (bestEffortAffinity) + if (affinityAwareness) connectInBestEffortAffinityMode(srvs); else connectInCommonMode(srvs); @@ -459,7 +459,7 @@ private void doCommit() throws SQLException { closed = true; - if (bestEffortAffinity) { + if (affinityAwareness) { for (JdbcThinTcpIo clioIo : ios.values()) clioIo.close(); @@ -794,7 +794,7 @@ private void doCommit() throws SQLException { netTimeout = ms; - if (bestEffortAffinity) { + if (affinityAwareness) { for (JdbcThinTcpIo clioIo : ios.values()) clioIo.timeout(ms); } @@ -936,7 +936,7 @@ else if (res.status() != ClientListenerResponse.STATUS_SUCCESS) * @throws SQLException If Failed to calculate derived partitions. */ @Nullable private List calculateNodeIds(JdbcRequest req) throws IOException, SQLException { - if (!bestEffortAffinity || !(req instanceof JdbcQueryExecuteRequest)) + if (!affinityAwareness || !(req instanceof JdbcQueryExecuteRequest)) return null; JdbcQueryExecuteRequest qry = (JdbcQueryExecuteRequest)req; @@ -1130,7 +1130,7 @@ private void onDisconnect() { if (!connected) return; - if (bestEffortAffinity) { + if (affinityAwareness) { for (JdbcThinTcpIo clioIo : ios.values()) clioIo.close(); @@ -1397,7 +1397,7 @@ boolean isQueryCancellationSupported() { */ @SuppressWarnings("ZeroLengthArrayAllocation") private JdbcThinTcpIo cliIo(List nodeIds) { - if (!bestEffortAffinity) + if (!affinityAwareness) return singleIo; if (txIo != null) @@ -1672,7 +1672,7 @@ private class RequestTimeoutTimerTask extends TimerTask { * @param res Jdbc Response. */ private void updateAffinityCache(JdbcQueryExecuteRequest qryReq, JdbcResponse res) { - if (bestEffortAffinity) { + if (affinityAwareness) { AffinityTopologyVersion resAffVer = res.affinityVersion(); if (resAffVer != null && (affinityCache == null || affinityCache.version().compareTo(resAffVer) < 0))