>() {
+ });
+
+ log.info("Version command response is: " + myMap);
+
+ assertTrue(myMap.containsKey("response"));
+ assertEquals(0, myMap.get("successStatus"));
+ }
+ }
+ catch (IOException e) {
+ fail(e.toString());
+ }
+
+ });
+
+ latch.countDown();
+
+ srv.get();
+
+ client.get();
+
+ assertEquals(0, this.srv.cacheNames().size());
+
+ this.srv.createCache(CACHE_GROUP_NAME);
+ }
+
+ /**
+ * Create and destroy caches:
+ *
+ * Prerequisites:
+ * Start server node, create 1 cache in a single cache group.
+ *
+ * Steps:
+ *
+ * Start Thick client.
+ * Create new cache with an existing cache group on server side.
+ * Destroy newly created cache through client.
+ *
+ *
+ * Expected:
+ * Only one cache, initially created within server node is expected.
+ */
+ @Test
+ public void testCreateOnSrvDestroyOnThickClient() {
+ srv.createCache(cacheConfig().setName(ANOTHER_CACHE_NAME));
+
+ srv.createCache(cacheConfig());
+
+ thickClient.destroyCache(CACHE_NAME);
+
+ assertEquals(1, srv.cacheNames().size());
+
+ assertEquals(ANOTHER_CACHE_NAME, srv.cacheNames().iterator().next());
+ }
+
+ /**
+ * Create and destroy caches:
+ *
+ * Prerequisites:
+ * Start server node, create 1 cache in a single cache group.
+ *
+ * Steps:
+ *
+ * Start Thin client.
+ * Create new cache with an existing cache group on server side.
+ * Destroy newly created cache through client.
+ *
+ *
+ * Expected:
+ * Only one cache, initially created within server node is expected.
+ */
+ @Test
+ public void testCreateOnSrvDestroyOnThinClient() {
+ srv.createCache(cacheConfig().setName(ANOTHER_CACHE_NAME));
+
+ srv.createCache(cacheConfig());
+
+ thinClient.destroyCache(CACHE_NAME);
+
+ assertEquals(1, srv.cacheNames().size());
+
+ assertEquals(ANOTHER_CACHE_NAME, srv.cacheNames().iterator().next());
+ }
+
+ /**
+ * Create and destroy caches:
+ *
+ * Prerequisites:
+ * Start server node, create 1 cache in a single cache group.
+ *
+ * Steps:
+ *
+ * Start Rest client.
+ * Create new cache with an existing cache group on server side.
+ * Destroy newly created cache through client.
+ *
+ *
+ * Expected:
+ * Only one cache, initially created within server node is expected.
+ */
+ @Test
+ public void testCreateOnSrvDestroyOnRestClient() throws Exception {
+ srv.createCache(cacheConfig().setName(ANOTHER_CACHE_NAME));
+
+ srv.createCache(cacheConfig());
+
+ destroyCacheWithRestClient(CACHE_NAME);
+
+ assertEquals(1, srv.cacheNames().size());
+
+ assertEquals(ANOTHER_CACHE_NAME, srv.cacheNames().iterator().next());
+ }
+
+ /**
+ * Create and destroy caches:
+ *
+ * Prerequisites:
+ * Start server node, create 1 cache in a single cache group.
+ *
+ * Steps:
+ *
+ * Start Thick client.
+ * Create new cache with an existing cache group on client side.
+ * Destroy newly created cache through server node.
+ *
+ *
+ * Expected:
+ * Only one cache, initially created within server node is expected.
+ */
+ @Test
+ public void testCreateOnThickClientDestroyOnSrv() {
+ srv.createCache(cacheConfig().setName(ANOTHER_CACHE_NAME));
+
+ thickClient.createCache(cacheConfig());
+
+ srv.destroyCache(CACHE_NAME);
+
+ assertEquals(1, srv.cacheNames().size());
+
+ assertEquals(ANOTHER_CACHE_NAME, srv.cacheNames().iterator().next());
+ }
+
+ /**
+ * Create and destroy caches:
+ *
+ * Prerequisites:
+ * Start server node, create 1 cache in a single cache group.
+ *
+ * Steps:
+ *
+ * Start Thin client.
+ * Create new cache with an existing cache group on client side.
+ * Destroy newly created cache through server node.
+ *
+ *
+ * Expected:
+ * Only one cache, initially created within server node is expected.
+ */
+ @Test
+ public void testCreateOnThinClientSrvDestroyOnSrv() {
+ srv.createCache(cacheConfig().setName(ANOTHER_CACHE_NAME));
+
+ thinClient.createCache(clientCacheConfig());
+
+ srv.destroyCache(CACHE_NAME);
+
+ assertEquals(1, srv.cacheNames().size());
+
+ assertEquals(ANOTHER_CACHE_NAME, srv.cacheNames().iterator().next());
+ }
+
+ /**
+ * Create and destroy caches:
+ *
+ * Prerequisites:
+ * Start server node, create 1 cache in a single cache group.
+ *
+ * Steps:
+ *
+ * Start jdbc client.
+ * Create new cache with an existing cache group on client side.
+ * Destroy newly created cache through server node.
+ *
+ *
+ * Expected: Only one cache, initially created within server node is expected.
+ */
+ @Test
+ public void testCreateOnJdbcClientDestroyOnSrv() throws Exception {
+ srv.createCache(cacheConfig().setName(ANOTHER_CACHE_NAME));
+
+ createCache(jdbcConn, cacheConfig());
+
+ srv.destroyCache("SQL_PUBLIC_" + CACHE_NAME.toUpperCase());
+
+ assertEquals(1, srv.cacheNames().size());
+
+ assertEquals(ANOTHER_CACHE_NAME, srv.cacheNames().iterator().next());
+ }
+
+ /**
+ * Create and destroy caches:
+ *
+ * Prerequisites:
+ * Start server node, create 1 cache in a single cache group.
+ *
+ * Steps:
+ *
+ * Start Rest client.
+ * Create new cache with an existing cache group on client side.
+ * Destroy newly created cache through server node.
+ *
+ *
+ * Expected: Only one cache, initially created within server node is expected.
+ */
+ @Test
+ public void testCreateOnRestClientDestroyOnSrv() throws Exception {
+ srv.createCache(cacheConfig().setName(ANOTHER_CACHE_NAME));
+
+ createCacheWithRestClient(cacheConfig());
+
+ srv.destroyCache(CACHE_NAME);
+
+ assertEquals(1, srv.cacheNames().size());
+
+ assertEquals(ANOTHER_CACHE_NAME, srv.cacheNames().iterator().next());
+ }
+
+ /**
+ * Create and destroy caches:
+ *
+ * Prerequisites:
+ * Start server node, create 1 cache in a single cache group.
+ *
+ * Steps:
+ *
+ * Start Thick client.
+ * Create new cache with an existing cache group on client side.
+ * Destroy newly created cache through some other, previously created, Thin client node.
+ *
+ *
+ * Expected: Only one cache, initially created within server node is expected.
+ */
+ @Test
+ public void testCreateOnThickClientDestroyThinClient() {
+ srv.createCache(cacheConfig().setName(ANOTHER_CACHE_NAME));
+
+ thickClient.createCache(cacheConfig());
+
+ thinClient.destroyCache(CACHE_NAME);
+
+ assertEquals(1, srv.cacheNames().size());
+
+ assertEquals(ANOTHER_CACHE_NAME, srv.cacheNames().iterator().next());
+ }
+
+ /**
+ * Create and destroy caches:
+ *
+ * Prerequisites:
+ * Start server node, create 1 cache in a single cache group.
+ *
+ * Steps:
+ *
+ * Start Thin client.
+ * Create new cache with an existing cache group on client side.
+ * Destroy newly created cache through some other, previously created, Rest client node.
+ *
+ *
+ * Expected: Only one cache, initially created within server node is expected.
+ */
+ @Test
+ public void testCreateOnThinClientSrvDestroyOnRestClient() throws Exception{
+ srv.createCache(cacheConfig().setName(ANOTHER_CACHE_NAME));
+
+ thinClient.createCache(clientCacheConfig());
+
+ destroyCacheWithRestClient(CACHE_NAME);
+
+ assertEquals(1, srv.cacheNames().size());
+
+ assertEquals(ANOTHER_CACHE_NAME, srv.cacheNames().iterator().next());
+ }
+
+ /**
+ * Create and destroy caches:
+ *
+ * Prerequisites:
+ * Start server node, create 1 cache in a single cache group.
+ *
+ * Steps:
+ *
+ * Start Jdbc Thin client.
+ * Create new cache with an existing cache group on client side.
+ * Destroy newly created cache through some other, previously created, Thin client node.
+ *
+ *
+ * Expected: Only one cache, initially created within server node is expected.
+ */
+ @Test
+ public void testCreateOnJdbcClientDestroyOnThinClient() throws Exception {
+ srv.createCache(cacheConfig().setName(ANOTHER_CACHE_NAME));
+
+ createCache(jdbcConn, cacheConfig());
+
+ thinClient.destroyCache("SQL_PUBLIC_" + CACHE_NAME.toUpperCase());
+
+ assertEquals(1, srv.cacheNames().size());
+
+ assertEquals(ANOTHER_CACHE_NAME, srv.cacheNames().iterator().next());
+ }
+
+ /**
+ * Create and destroy caches:
+ *
+ * Prerequisites:
+ * Start server node, create 1 cache in a single cache group.
+ *
+ * Steps:
+ *
+ * Start Jdbc Thin client.
+ * Create new cache with an existing cache group on client side.
+ * Destroy newly created cache through some other, previously created, Thick client node.
+ *
+ *
+ * Expected: Only one cache, initially created within server node is expected.
+ * @throws Exception If failed.
+ */
+ @Test
+ public void testCreateOnRestClientDestroyOnThickClient() throws Exception {
+ srv.createCache(cacheConfig().setName(ANOTHER_CACHE_NAME));
+
+ createCacheWithRestClient(cacheConfig());
+
+ thickClient.destroyCache(CACHE_NAME);
+
+ assertEquals(1, srv.cacheNames().size());
+
+ assertEquals(ANOTHER_CACHE_NAME, srv.cacheNames().iterator().next());
+ }
+
+ /**
+ * Create cache with specified configuration through thin/thick client or jdbc thin.
+ *
+ * @param node Cluster node or jdbc connection.
+ * @param cacheCfg Cache or ClientCache configuration
+ * @throws SQLException If failed to create cache through Jdbc Thin connection.
+ */
+ private void createCache(AutoCloseable node, Serializable cacheCfg) throws SQLException {
+ if (node instanceof IgniteClient)
+ ((IgniteClient)node).createCache((ClientCacheConfiguration)cacheCfg);
+ else if (node instanceof Ignite)
+ ((Ignite)node).createCache((CacheConfiguration)cacheCfg);
+ else if (node instanceof JdbcThinConnection) {
+ CacheConfiguration jdbcCacheCfg = (CacheConfiguration)cacheCfg;
+
+ srv.addCacheConfiguration(jdbcCacheCfg);
+
+ try (Statement stmt = jdbcConn.createStatement()) {
+ stmt.execute("CREATE TABLE " + jdbcCacheCfg.getName() +
+ " (id int, name varchar, primary key (id)) WITH \"template=" + jdbcCacheCfg.getName() + "\"");
+ }
+ }
+ else
+ fail(" Unexpected node/client type");
+ }
+
+ /**
+ * Create cache with specified configuration through rest client.
+ * @param cacheCfg Cache configuration.
+ * @throws Exception If failed.
+ */
+ private void createCacheWithRestClient(CacheConfiguration cacheCfg) throws Exception {
+ srv.addCacheConfiguration(cacheCfg);
+
+ URLConnection conn = new URL("http://localhost:8080/ignite?cmd=getorcreate&cacheName=" +
+ cacheCfg.getName() + "&templateName=" + cacheCfg.getName()).openConnection();
+
+ conn.connect();
+
+ try (InputStreamReader streamReader = new InputStreamReader(conn.getInputStream())) {
+ ObjectMapper objMapper = new ObjectMapper();
+ Map myMap = objMapper.readValue(streamReader,
+ new TypeReference>() {
+ });
+
+ log.info("Version command response is: " + myMap);
+
+ assertTrue(myMap.containsKey("response"));
+ assertEquals(0, myMap.get("successStatus"));
+ }
+ }
+
+ /**
+ * Destroy cache from within rest client.
+ * @param cacheName Cache name.
+ * @throws Exception If failed.
+ */
+ private void destroyCacheWithRestClient(String cacheName) throws Exception {
+ URLConnection conn = new URL("http://localhost:8080/ignite?cmd=destcache&cacheName=" + cacheName).
+ openConnection();
+
+ conn.connect();
+
+ try (InputStreamReader streamReader = new InputStreamReader(conn.getInputStream())) {
+ ObjectMapper objMapper = new ObjectMapper();
+ Map myMap = objMapper.readValue(streamReader,
+ new TypeReference>() {
+ });
+
+ log.info("Version command response is: " + myMap);
+
+ assertTrue(myMap.containsKey("response"));
+ assertEquals(0, myMap.get("successStatus"));
+ }
+ }
+
+ /**
+ * @return Default client cache configuration.
+ */
+ private ClientCacheConfiguration clientCacheConfig() {
+ return new ClientCacheConfiguration().
+ setGroupName(CACHE_GROUP_NAME).
+ setName(CACHE_NAME).
+ setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL).
+ setCacheMode(CacheMode.PARTITIONED);
+ }
+
+ /**
+ * @return Default cache configuration.
+ */
+ private CacheConfiguration cacheConfig() {
+ return new CacheConfiguration().
+ setGroupName(CACHE_GROUP_NAME).
+ setName(CACHE_NAME).
+ setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL).
+ setCacheMode(CacheMode.PARTITIONED);
+ }
+
+ /**
+ * @return Default cache configuration without cache group.
+ */
+ private CacheConfiguration cacheConfigWithoutCacheGroup() {
+ return new CacheConfiguration().
+ setName(CACHE_NAME).
+ setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL).
+ setCacheMode(CacheMode.PARTITIONED);
+ }
+}
diff --git a/modules/clients/src/test/java/org/apache/ignite/internal/TaskEventSubjectIdSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/internal/TaskEventSubjectIdSelfTest.java
index 0c272b9866e14..26cd5f538d24f 100644
--- a/modules/clients/src/test/java/org/apache/ignite/internal/TaskEventSubjectIdSelfTest.java
+++ b/modules/clients/src/test/java/org/apache/ignite/internal/TaskEventSubjectIdSelfTest.java
@@ -36,6 +36,7 @@
import org.apache.ignite.configuration.ConnectorConfiguration;
import org.apache.ignite.configuration.IgniteConfiguration;
import org.apache.ignite.events.Event;
+import org.apache.ignite.events.EventType;
import org.apache.ignite.events.TaskEvent;
import org.apache.ignite.internal.client.GridClient;
import org.apache.ignite.internal.client.GridClientConfiguration;
@@ -76,6 +77,8 @@ public class TaskEventSubjectIdSelfTest extends GridCommonAbstractTest {
cfg.setConnectorConfiguration(new ConnectorConfiguration());
+ cfg.setIncludeEventTypes(EventType.EVTS_ALL);
+
return cfg;
}
diff --git a/modules/clients/src/test/java/org/apache/ignite/internal/client/suite/IgniteClientTestSuite.java b/modules/clients/src/test/java/org/apache/ignite/internal/client/suite/IgniteClientTestSuite.java
index d6ef9f9e208fa..a35c49ec22738 100644
--- a/modules/clients/src/test/java/org/apache/ignite/internal/client/suite/IgniteClientTestSuite.java
+++ b/modules/clients/src/test/java/org/apache/ignite/internal/client/suite/IgniteClientTestSuite.java
@@ -18,6 +18,8 @@
package org.apache.ignite.internal.client.suite;
import junit.framework.TestSuite;
+import org.apache.ignite.common.ClientSideCacheCreationDestructionWileTopologyChangeTest;
+import org.apache.ignite.common.ClientSizeCacheCreationDestructionTest;
import org.apache.ignite.internal.IgniteClientFailuresTest;
import org.apache.ignite.internal.TaskEventSubjectIdSelfTest;
import org.apache.ignite.internal.client.ClientDefaultCacheSelfTest;
@@ -169,6 +171,9 @@ public static TestSuite suite() {
suite.addTestSuite(IgniteClientFailuresTest.class);
+ suite.addTestSuite(ClientSizeCacheCreationDestructionTest.class);
+ suite.addTestSuite(ClientSideCacheCreationDestructionWileTopologyChangeTest.class);
+
return suite;
}
}
diff --git a/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcDynamicIndexAbstractSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcDynamicIndexAbstractSelfTest.java
index 9485d0d54212c..652d635cbe4a1 100644
--- a/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcDynamicIndexAbstractSelfTest.java
+++ b/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcDynamicIndexAbstractSelfTest.java
@@ -31,6 +31,7 @@
import org.apache.ignite.configuration.CacheConfiguration;
import org.apache.ignite.configuration.NearCacheConfiguration;
import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.testframework.GridTestUtils;
/**
* Test that checks indexes handling with JDBC.
@@ -168,9 +169,9 @@ public void testCreateIndex() throws SQLException {
public void testCreateIndexWithDuplicateName() throws SQLException {
jdbcRun(CREATE_INDEX);
- assertSqlException(new RunnableX() {
+ assertSqlException(new GridTestUtils.RunnableX() {
/** {@inheritDoc} */
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
jdbcRun(CREATE_INDEX);
}
});
@@ -219,9 +220,9 @@ public void testDropIndex() throws SQLException {
* Test that dropping a non-existent index yields an error.
*/
public void testDropMissingIndex() {
- assertSqlException(new RunnableX() {
+ assertSqlException(new GridTestUtils.RunnableX() {
/** {@inheritDoc} */
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
jdbcRun(DROP_INDEX);
}
});
@@ -310,11 +311,11 @@ private IgniteCache cache() {
*
* @param r Runnable.
*/
- private static void assertSqlException(RunnableX r) {
+ private static void assertSqlException(GridTestUtils.RunnableX r) {
// We expect IgniteSQLException with given code inside CacheException inside JDBC SQLException.
try {
- r.run();
+ r.runx();
}
catch (SQLException e) {
return;
@@ -325,16 +326,4 @@ private static void assertSqlException(RunnableX r) {
fail(SQLException.class.getSimpleName() + " is not thrown.");
}
-
- /**
- * Runnable which can throw checked exceptions.
- */
- private interface RunnableX {
- /**
- * Do run.
- *
- * @throws Exception If failed.
- */
- public void run() throws Exception;
- }
}
diff --git a/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcStreamingSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcStreamingSelfTest.java
index e302529404d70..eaf81ec205e81 100644
--- a/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcStreamingSelfTest.java
+++ b/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcStreamingSelfTest.java
@@ -20,19 +20,21 @@
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.Collections;
import java.util.Properties;
import org.apache.ignite.IgniteCache;
import org.apache.ignite.IgniteJdbcDriver;
-import org.apache.ignite.IgniteLogger;
import org.apache.ignite.binary.BinaryObject;
import org.apache.ignite.binary.BinaryObjectBuilder;
import org.apache.ignite.configuration.CacheConfiguration;
import org.apache.ignite.configuration.ConnectorConfiguration;
import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.processors.cache.distributed.dht.IgniteClusterReadOnlyException;
import org.apache.ignite.internal.processors.query.QueryUtils;
+import org.apache.ignite.internal.util.typedef.X;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.lang.IgniteCallable;
import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
@@ -166,6 +168,41 @@ protected Connection createStreamedConnection(boolean allowOverwrite, long flush
super.afterTest();
}
+ /**
+ * @throws Exception if failed.
+ */
+ public void testStreamedInsertFailsOnReadOnlyMode() throws Exception {
+ try (Connection conn = createStreamedConnection(true)) {
+ populateData(conn, 0, 1);
+
+ grid(0).cluster().readOnly(true);
+
+ try {
+ assertTrue(grid(0).cluster().readOnly());
+
+ try (Connection ordinalCon = createOrdinaryConnection()) {
+ assertEquals(1, countPersons(ordinalCon));
+
+ try {
+ populateData(conn, 1, 100);
+
+ fail("Insert should be failed!");
+ }
+ catch (Exception e) {
+ log.error("Insert failed", e);
+
+ assertTrue("Wrong exception", X.hasCause(e, IgniteClusterReadOnlyException.class));
+ }
+
+ assertEquals("Insert should be failed", 1, countPersons(ordinalCon));
+ }
+ }
+ finally {
+ grid(0).cluster().readOnly(false);
+ }
+ }
+ }
+
/**
* @throws Exception if failed.
*/
@@ -174,15 +211,7 @@ public void testStreamedInsert() throws Exception {
put(i, nameForId(i * 100));
try (Connection conn = createStreamedConnection(false)) {
- try (PreparedStatement stmt = conn.prepareStatement("insert into PUBLIC.Person(\"id\", \"name\") " +
- "values (?, ?)")) {
- for (int i = 1; i <= 100; i++) {
- stmt.setInt(1, i);
- stmt.setString(2, nameForId(i));
-
- stmt.executeUpdate();
- }
- }
+ populateData(conn, 1, 100);
}
U.sleep(500);
@@ -204,15 +233,7 @@ public void testStreamedInsertWithoutColumnsList() throws Exception {
put(i, nameForId(i * 100));
try (Connection conn = createStreamedConnection(false)) {
- try (PreparedStatement stmt = conn.prepareStatement("insert into PUBLIC.Person(\"id\", \"name\") " +
- "values (?, ?)")) {
- for (int i = 1; i <= 100; i++) {
- stmt.setInt(1, i);
- stmt.setString(2, nameForId(i));
-
- stmt.executeUpdate();
- }
- }
+ populateData(conn, 1, 100);
}
U.sleep(500);
@@ -234,15 +255,7 @@ public void testStreamedInsertWithOverwritesAllowed() throws Exception {
put(i, nameForId(i * 100));
try (Connection conn = createStreamedConnection(true)) {
- try (PreparedStatement stmt = conn.prepareStatement("insert into PUBLIC.Person(\"id\", \"name\") " +
- "values (?, ?)")) {
- for (int i = 1; i <= 100; i++) {
- stmt.setInt(1, i);
- stmt.setString(2, nameForId(i));
-
- stmt.executeUpdate();
- }
- }
+ populateData(conn, 1, 100);
}
U.sleep(500);
@@ -327,4 +340,38 @@ protected String nameForIdInCache(int id) {
return ((BinaryObject)o).field("name");
}
+
+ /**
+ * Populates data to the table.
+ *
+ * @param conn Connection.
+ * @param from First person id.
+ * @param count Number of persons.
+ * @throws SQLException If something goes wrong.
+ */
+ private void populateData(Connection conn, int from, int count) throws SQLException {
+ try (PreparedStatement stmt = conn.prepareStatement("insert into PUBLIC.Person(\"id\", \"name\") values (?, ?)")) {
+ for (int i = from; i < from + count; i++) {
+ stmt.setInt(1, i);
+ stmt.setString(2, nameForId(i));
+
+ stmt.executeUpdate();
+ }
+ }
+ }
+
+ /**
+ * @param conn Connection.
+ * @return Size of PUBLIC.Person table.
+ * @throws SQLException If something goes wrong.
+ */
+ private long countPersons(Connection conn) throws SQLException {
+ try (Statement selectStmt = conn.createStatement()) {
+ try (ResultSet rs = selectStmt.executeQuery("select count(*) from PUBLIC.Person")) {
+ assertTrue("Result set is empty!", rs.next());
+
+ return rs.getLong(1);
+ }
+ }
+ }
}
diff --git a/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorAbstractSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorAbstractSelfTest.java
index bcd66f0a4de8a..9f3c71b9951de 100644
--- a/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorAbstractSelfTest.java
+++ b/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorAbstractSelfTest.java
@@ -137,6 +137,8 @@
import org.apache.ignite.lang.IgnitePredicate;
import org.apache.ignite.lang.IgniteUuid;
import org.apache.ignite.testframework.GridTestUtils;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import static org.apache.ignite.cache.CacheMode.PARTITIONED;
import static org.apache.ignite.cache.CacheMode.REPLICATED;
@@ -280,6 +282,31 @@ protected JsonNode jsonTaskResult(String content) throws IOException {
return res.get("result");
}
+ /**
+ * Check task result with expected failure.
+ *
+ * @param content Content to check.
+ * @return Node with failure result.
+ */
+ protected JsonNode jsonTaskErrorResult(String content) throws IOException {
+ assertNotNull(content);
+ assertFalse(content.isEmpty());
+
+ JsonNode node = JSON_MAPPER.readTree(content);
+
+ assertEquals(STATUS_FAILED, node.get("successStatus").asInt());
+ assertFalse(node.get("error").isNull());
+ assertTrue(node.get("response").isNull());
+
+ assertEquals(securityEnabled(), !node.get("sessionToken").isNull());
+
+ JsonNode error = node.get("error");
+
+ assertTrue(error.isTextual());
+
+ return error;
+ }
+
/**
* @throws Exception If failed.
*/
@@ -1567,161 +1594,161 @@ public void testVisorGateway() throws Exception {
final IgniteUuid cid = grid(1).context().cache().internalCache("person").context().dynamicDeploymentId();
String ret = content(new VisorGatewayArgument(VisorCacheConfigurationCollectorTask.class)
- .forNode(locNode)
- .argument(VisorCacheConfigurationCollectorTaskArg.class)
- .collection(IgniteUuid.class, cid));
+ .setNode(locNode)
+ .setTaskArgument(VisorCacheConfigurationCollectorTaskArg.class)
+ .addCollectionArgument(IgniteUuid.class, cid));
info("VisorCacheConfigurationCollectorTask result: " + ret);
jsonTaskResult(ret);
ret = content(new VisorGatewayArgument(VisorCacheNodesTask.class)
- .forNode(locNode)
- .argument(VisorCacheNodesTaskArg.class, "person"));
+ .setNode(locNode)
+ .setTaskArgument(VisorCacheNodesTaskArg.class, "person"));
info("VisorCacheNodesTask result: " + ret);
jsonTaskResult(ret);
ret = content(new VisorGatewayArgument(VisorCachePartitionsTask.class)
- .forNode(locNode)
- .argument(VisorCachePartitionsTaskArg.class, "person"));
+ .setNode(locNode)
+ .setTaskArgument(VisorCachePartitionsTaskArg.class, "person"));
info("VisorCachePartitionsTask result: " + ret);
jsonTaskResult(ret);
ret = content(new VisorGatewayArgument(VisorCacheLoadTask.class)
- .forNode(locNode)
- .argument(VisorCacheLoadTaskArg.class)
- .set(String.class, "person")
- .arguments(0, "null"));
+ .setNode(locNode)
+ .setTaskArgument(VisorCacheLoadTaskArg.class)
+ .addSetArgument(String.class, "person")
+ .addArguments(0, "null"));
info("VisorCacheLoadTask result: " + ret);
jsonTaskResult(ret);
ret = content(new VisorGatewayArgument(VisorCacheRebalanceTask.class)
- .forNode(locNode)
- .argument(VisorCacheRebalanceTaskArg.class)
- .set(String.class, "person"));
+ .setNode(locNode)
+ .setTaskArgument(VisorCacheRebalanceTaskArg.class)
+ .addSetArgument(String.class, "person"));
info("VisorCacheRebalanceTask result: " + ret);
jsonTaskResult(ret);
ret = content(new VisorGatewayArgument(VisorCacheMetadataTask.class)
- .forNode(locNode)
- .argument(VisorCacheMetadataTaskArg.class, "person"));
+ .setNode(locNode)
+ .setTaskArgument(VisorCacheMetadataTaskArg.class, "person"));
info("VisorCacheMetadataTask result: " + ret);
jsonTaskResult(ret);
ret = content(new VisorGatewayArgument(VisorCacheResetMetricsTask.class)
- .forNode(locNode)
- .argument(VisorCacheResetMetricsTaskArg.class, "person"));
+ .setNode(locNode)
+ .setTaskArgument(VisorCacheResetMetricsTaskArg.class, "person"));
info("VisorCacheResetMetricsTask result: " + ret);
jsonTaskResult(ret);
ret = content(new VisorGatewayArgument(VisorIgfsSamplingStateTask.class)
- .forNode(locNode)
- .argument(VisorIgfsSamplingStateTaskArg.class, "igfs", false));
+ .setNode(locNode)
+ .setTaskArgument(VisorIgfsSamplingStateTaskArg.class, "igfs", false));
info("VisorIgfsSamplingStateTask result: " + ret);
jsonTaskResult(ret);
ret = content(new VisorGatewayArgument(VisorIgfsProfilerClearTask.class)
- .forNode(locNode)
- .argument(VisorIgfsProfilerClearTaskArg.class, "igfs"));
+ .setNode(locNode)
+ .setTaskArgument(VisorIgfsProfilerClearTaskArg.class, "igfs"));
info("VisorIgfsProfilerClearTask result: " + ret);
jsonTaskResult(ret);
ret = content(new VisorGatewayArgument(VisorIgfsProfilerTask.class)
- .forNode(locNode)
- .argument(VisorIgfsProfilerTaskArg.class, "igfs"));
+ .setNode(locNode)
+ .setTaskArgument(VisorIgfsProfilerTaskArg.class, "igfs"));
info("VisorIgfsProfilerTask result: " + ret);
jsonTaskResult(ret);
ret = content(new VisorGatewayArgument(VisorIgfsFormatTask.class)
- .forNode(locNode)
- .argument(VisorIgfsFormatTaskArg.class, "igfs"));
+ .setNode(locNode)
+ .setTaskArgument(VisorIgfsFormatTaskArg.class, "igfs"));
info("VisorIgfsFormatTask result: " + ret);
jsonTaskResult(ret);
ret = content(new VisorGatewayArgument(VisorIgfsResetMetricsTask.class)
- .forNode(locNode)
- .argument(VisorIgfsResetMetricsTaskArg.class)
- .set(String.class, "igfs"));
+ .setNode(locNode)
+ .setTaskArgument(VisorIgfsResetMetricsTaskArg.class)
+ .addSetArgument(String.class, "igfs"));
info("VisorIgfsResetMetricsTask result: " + ret);
jsonTaskResult(ret);
ret = content(new VisorGatewayArgument(VisorThreadDumpTask.class)
- .forNode(locNode));
+ .setNode(locNode));
info("VisorThreadDumpTask result: " + ret);
jsonTaskResult(ret);
ret = content(new VisorGatewayArgument(VisorLatestTextFilesTask.class)
- .forNode(locNode)
- .argument(VisorLatestTextFilesTaskArg.class, "", ""));
+ .setNode(locNode)
+ .setTaskArgument(VisorLatestTextFilesTaskArg.class, "", ""));
info("VisorLatestTextFilesTask result: " + ret);
jsonTaskResult(ret);
ret = content(new VisorGatewayArgument(VisorLatestVersionTask.class)
- .forNode(locNode));
+ .setNode(locNode));
info("VisorLatestVersionTask result: " + ret);
jsonTaskResult(ret);
ret = content(new VisorGatewayArgument(VisorFileBlockTask.class)
- .forNode(locNode)
- .argument(VisorFileBlockTaskArg.class, "", 0L, 1, 0L));
+ .setNode(locNode)
+ .setTaskArgument(VisorFileBlockTaskArg.class, "", 0L, 1, 0L));
info("VisorFileBlockTask result: " + ret);
jsonTaskResult(ret);
ret = content(new VisorGatewayArgument(VisorNodePingTask.class)
- .forNode(locNode)
- .argument(VisorNodePingTaskArg.class, locNode.id()));
+ .setNode(locNode)
+ .setTaskArgument(VisorNodePingTaskArg.class, locNode.id()));
info("VisorNodePingTask result: " + ret);
jsonTaskResult(ret);
ret = content(new VisorGatewayArgument(VisorNodeConfigurationCollectorTask.class)
- .forNode(locNode));
+ .setNode(locNode));
info("VisorNodeConfigurationCollectorTask result: " + ret);
jsonTaskResult(ret);
ret = content(new VisorGatewayArgument(VisorComputeResetMetricsTask.class)
- .forNode(locNode));
+ .setNode(locNode));
info("VisorComputeResetMetricsTask result: " + ret);
jsonTaskResult(ret);
ret = content(new VisorGatewayArgument(VisorQueryTask.class)
- .forNode(locNode)
- .argument(VisorQueryTaskArg.class, "person", URLEncoder.encode("select * from Person", CHARSET),
+ .setNode(locNode)
+ .setTaskArgument(VisorQueryTaskArg.class, "person", URLEncoder.encode("select * from Person", CHARSET),
false, false, false, false, 1));
info("VisorQueryTask result: " + ret);
@@ -1731,51 +1758,51 @@ public void testVisorGateway() throws Exception {
final String qryId = res.get("result").get("queryId").asText();
ret = content(new VisorGatewayArgument(VisorQueryNextPageTask.class)
- .forNode(locNode)
- .argument(VisorQueryNextPageTaskArg.class, qryId, 1));
+ .setNode(locNode)
+ .setTaskArgument(VisorQueryNextPageTaskArg.class, qryId, 1));
info("VisorQueryNextPageTask result: " + ret);
jsonTaskResult(ret);
ret = content(new VisorGatewayArgument(VisorQueryCleanupTask.class)
- .argument(VisorQueryCleanupTaskArg.class)
- .map(UUID.class, Set.class, F.asMap(locNode.id(), qryId)));
+ .setTaskArgument(VisorQueryCleanupTaskArg.class)
+ .addMapArgument(UUID.class, Set.class, F.asMap(locNode.id(), qryId)));
info("VisorQueryCleanupTask result: " + ret);
jsonTaskResult(ret);
ret = content(new VisorGatewayArgument(VisorResolveHostNameTask.class)
- .forNode(locNode));
+ .setNode(locNode));
info("VisorResolveHostNameTask result: " + ret);
jsonTaskResult(ret);
ret = content(new VisorGatewayArgument(VisorQueryCancelTask.class)
- .argument(VisorQueryCancelTaskArg.class, 0L));
+ .setTaskArgument(VisorQueryCancelTaskArg.class, 0L));
info("VisorResolveHostNameTask result: " + ret);
jsonTaskResult(ret);
ret = content(new VisorGatewayArgument(VisorQueryResetMetricsTask.class)
- .argument(VisorQueryResetMetricsTaskArg.class, "person"));
+ .setTaskArgument(VisorQueryResetMetricsTaskArg.class, "person"));
info("VisorResolveHostNameTask result: " + ret);
jsonTaskResult(ret);
ret = content(new VisorGatewayArgument(VisorQueryCancelTask.class)
- .argument(VisorQueryCancelTaskArg.class, 0L));
+ .setTaskArgument(VisorQueryCancelTaskArg.class, 0L));
info("VisorResolveHostNameTask result: " + ret);
jsonTaskResult(ret);
ret = content(new VisorGatewayArgument(VisorQueryResetMetricsTask.class)
- .argument(VisorQueryResetMetricsTaskArg.class, "person"));
+ .setTaskArgument(VisorQueryResetMetricsTaskArg.class, "person"));
info("VisorResolveHostNameTask result: " + ret);
@@ -1784,30 +1811,30 @@ public void testVisorGateway() throws Exception {
// Multinode tasks
ret = content(new VisorGatewayArgument(VisorComputeCancelSessionsTask.class)
- .argument(VisorComputeCancelSessionsTaskArg.class)
- .set(IgniteUuid.class, IgniteUuid.randomUuid()));
+ .setTaskArgument(VisorComputeCancelSessionsTaskArg.class)
+ .addSetArgument(IgniteUuid.class, IgniteUuid.randomUuid()));
info("VisorComputeCancelSessionsTask result: " + ret);
jsonTaskResult(ret);
ret = content(new VisorGatewayArgument(VisorCacheMetricsCollectorTask.class)
- .argument(VisorCacheMetricsCollectorTaskArg.class, false)
- .collection(String.class, "person"));
+ .setTaskArgument(VisorCacheMetricsCollectorTaskArg.class, false)
+ .addCollectionArgument(String.class, "person"));
info("VisorCacheMetricsCollectorTask result: " + ret);
ret = content(new VisorGatewayArgument(VisorCacheMetricsCollectorTask.class)
- .forNodes(grid(1).cluster().nodes())
- .argument(VisorCacheMetricsCollectorTaskArg.class, false)
- .collection(String.class, "person"));
+ .setNodes(grid(1).cluster().nodes())
+ .setTaskArgument(VisorCacheMetricsCollectorTaskArg.class, false)
+ .addCollectionArgument(String.class, "person"));
info("VisorCacheMetricsCollectorTask (with nodes) result: " + ret);
jsonTaskResult(ret);
ret = content(new VisorGatewayArgument(VisorLogSearchTask.class)
- .argument(VisorLogSearchTaskArg.class, ".", ".", "abrakodabra.txt", 1));
+ .setTaskArgument(VisorLogSearchTaskArg.class, ".", ".", "abrakodabra.txt", 1));
info("VisorLogSearchTask result: " + ret);
@@ -1820,14 +1847,14 @@ public void testVisorGateway() throws Exception {
jsonTaskResult(ret);
ret = content(new VisorGatewayArgument(VisorAckTask.class)
- .argument(VisorAckTaskArg.class, "MSG"));
+ .setTaskArgument(VisorAckTaskArg.class, "MSG"));
info("VisorAckTask result: " + ret);
jsonTaskResult(ret);
ret = content(new VisorGatewayArgument(VisorNodeEventsCollectorTask.class)
- .argument(VisorNodeEventsCollectorTaskArg.class,
+ .setTaskArgument(VisorNodeEventsCollectorTaskArg.class,
"null", "null", "null", "taskName", "null"));
info("VisorNodeEventsCollectorTask result: " + ret);
@@ -1835,7 +1862,7 @@ public void testVisorGateway() throws Exception {
jsonTaskResult(ret);
ret = content(new VisorGatewayArgument(VisorNodeDataCollectorTask.class)
- .argument(VisorNodeDataCollectorTaskArg.class, false,
+ .setTaskArgument(VisorNodeDataCollectorTaskArg.class, false,
"CONSOLE_" + UUID.randomUUID(), UUID.randomUUID(), false));
info("VisorNodeDataCollectorTask result: " + ret);
@@ -1843,23 +1870,23 @@ public void testVisorGateway() throws Exception {
jsonTaskResult(ret);
ret = content(new VisorGatewayArgument(VisorComputeToggleMonitoringTask.class)
- .argument(VisorComputeToggleMonitoringTaskArg.class, UUID.randomUUID(), false));
+ .setTaskArgument(VisorComputeToggleMonitoringTaskArg.class, UUID.randomUUID(), false));
info("VisorComputeToggleMonitoringTask result: " + ret);
jsonTaskResult(ret);
ret = content(new VisorGatewayArgument(VisorNodeSuppressedErrorsTask.class)
- .argument(VisorNodeSuppressedErrorsTaskArg.class)
- .map(UUID.class, Long.class, new HashMap()));
+ .setTaskArgument(VisorNodeSuppressedErrorsTaskArg.class)
+ .addMapArgument(UUID.class, Long.class, new HashMap()));
info("VisorNodeSuppressedErrorsTask result: " + ret);
jsonTaskResult(ret);
ret = content(new VisorGatewayArgument(VisorCacheClearTask.class)
- .forNode(locNode)
- .argument(VisorCacheClearTaskArg.class, "person"));
+ .setNode(locNode)
+ .setTaskArgument(VisorCacheClearTaskArg.class, "person"));
info("VisorCacheClearTask result: " + ret);
@@ -1878,7 +1905,7 @@ public void testVisorGateway() throws Exception {
"";
ret = content(new VisorGatewayArgument(VisorCacheStartTask.class)
- .argument(VisorCacheStartTaskArg.class, false, "person2",
+ .setTaskArgument(VisorCacheStartTaskArg.class, false, "person2",
URLEncoder.encode(START_CACHE, CHARSET)));
info("VisorCacheStartTask result: " + ret);
@@ -1886,29 +1913,29 @@ public void testVisorGateway() throws Exception {
jsonTaskResult(ret);
ret = content(new VisorGatewayArgument(VisorCacheStopTask.class)
- .forNode(locNode)
- .argument(VisorCacheStopTaskArg.class, "c"));
+ .setNode(locNode)
+ .setTaskArgument(VisorCacheStopTaskArg.class, "c"));
info("VisorCacheStopTask result: " + ret);
jsonTaskResult(ret);
ret = content(new VisorGatewayArgument(VisorQueryDetailMetricsCollectorTask.class)
- .argument(VisorQueryDetailMetricsCollectorTaskArg.class, 0));
+ .setTaskArgument(VisorQueryDetailMetricsCollectorTaskArg.class, 0));
info("VisorQueryDetailMetricsCollectorTask result: " + ret);
jsonTaskResult(ret);
ret = content(new VisorGatewayArgument(VisorRunningQueriesCollectorTask.class)
- .argument(VisorRunningQueriesCollectorTaskArg.class, 0L));
+ .setTaskArgument(VisorRunningQueriesCollectorTaskArg.class, 0L));
info("VisorQueryDetailMetricsCollectorTask result: " + ret);
jsonTaskResult(ret);
ret = content(new VisorGatewayArgument(VisorChangeGridActiveStateTask.class)
- .argument(VisorChangeGridActiveStateTaskArg.class, true));
+ .setTaskArgument(VisorChangeGridActiveStateTaskArg.class, true));
info("VisorQueryDetailMetricsCollectorTask result: " + ret);
@@ -2830,24 +2857,24 @@ public VisorGatewayArgument(Class cls) {
}
/**
- * Execute task on node.
+ * Execute task on specified node.
*
* @param node Node.
* @return This helper for chaining method calls.
*/
- public VisorGatewayArgument forNode(ClusterNode node) {
- put("p1", node != null ? node.id().toString() : null);
+ public VisorGatewayArgument setNode(ClusterNode node) {
+ put("p1", node != null ? node.id().toString() : null);
return this;
}
/**
- * Prepare list of node IDs.
+ * Execute task on specified nodes.
*
* @param nodes Collection of nodes.
* @return This helper for chaining method calls.
*/
- public VisorGatewayArgument forNodes(Collection nodes) {
+ public VisorGatewayArgument setNodes(Collection nodes) {
put("p1", concat(F.transform(nodes, new C1() {
/** {@inheritDoc} */
@Override public UUID apply(ClusterNode node) {
@@ -2859,43 +2886,48 @@ public VisorGatewayArgument forNodes(Collection nodes) {
}
/**
- * Add custom argument.
+ * Add custom arguments.
*
- * @param vals Values.
+ * @param vals Array of values or {@code null}.
* @return This helper for chaining method calls.
*/
- public VisorGatewayArgument arguments(Object... vals) {
- for (Object val : vals)
- put("p" + idx++, String.valueOf(val));
+ public VisorGatewayArgument addArguments(@Nullable Object... vals) {
+ if (idx == 3)
+ throw new IllegalStateException("Task argument class should be declared before adding of additional arguments. " +
+ "Use VisorGatewayArgument.setTaskArgument first");
- return this;
- }
+ if (vals != null && F.isEmpty(vals))
+ throw new IllegalArgumentException("Additional arguments should be configured as null or not empty array of arguments");
- /**
- * Add string argument.
- *
- * @param val Value.
- * @return This helper for chaining method calls.
- */
- public VisorGatewayArgument argument(String val) {
- put("p" + idx++, String.class.getName());
- put("p" + idx++, val);
+ if (vals != null) {
+ for (Object val : vals)
+ put("p" + idx++, String.valueOf(val));
+ }
+ else
+ put("p" + idx++, null);
return this;
}
/**
- * Add custom class argument.
+ * Add task argument class with custom arguments.
*
* @param cls Class.
* @param vals Values.
* @return This helper for chaining method calls.
*/
- public VisorGatewayArgument argument(Class cls, Object... vals) {
+ public VisorGatewayArgument setTaskArgument(Class cls, @Nullable Object... vals) {
+ if (idx != 3)
+ throw new IllegalStateException("Task argument class should be declared before adding of additional arguments");
+
put("p" + idx++, cls.getName());
- for (Object val : vals)
- put("p" + idx++, val != null ? val.toString() : null);
+ if (vals != null) {
+ for (Object val : vals)
+ put("p" + idx++, val != null ? val.toString() : null);
+ }
+ else
+ put("p" + idx++, null);
return this;
}
@@ -2907,7 +2939,11 @@ public VisorGatewayArgument argument(Class cls, Object... vals) {
* @param vals Values.
* @return This helper for chaining method calls.
*/
- public VisorGatewayArgument collection(Class cls, Object... vals) {
+ public VisorGatewayArgument addCollectionArgument(Class cls, @Nullable Object... vals) {
+ if (idx == 3)
+ throw new IllegalStateException("Task argument class should be declared before adding of additional arguments. " +
+ "Use VisorGatewayArgument.setTaskArgument first");
+
put("p" + idx++, Collection.class.getName());
put("p" + idx++, cls.getName());
put("p" + idx++, concat(vals, ";"));
@@ -2922,7 +2958,11 @@ public VisorGatewayArgument collection(Class cls, Object... vals) {
* @param vals Values.
* @return This helper for chaining method calls.
*/
- public VisorGatewayArgument set(Class cls, Object... vals) {
+ public VisorGatewayArgument addSetArgument(Class cls, @Nullable Object... vals) {
+ if (idx == 3)
+ throw new IllegalStateException("Task argument class should be declared before adding of additional argument. " +
+ "Use VisorGatewayArgument.setTaskArgument first");
+
put("p" + idx++, Set.class.getName());
put("p" + idx++, cls.getName());
put("p" + idx++, concat(vals, ";"));
@@ -2937,7 +2977,14 @@ public VisorGatewayArgument set(Class cls, Object... vals) {
* @param valCls Value class.
* @param map Map.
*/
- public VisorGatewayArgument map(Class keyCls, Class valCls, Map, ?> map) throws UnsupportedEncodingException {
+ public VisorGatewayArgument addMapArgument(Class keyCls, Class valCls, @NotNull Map, ?> map) throws UnsupportedEncodingException {
+ if (idx == 3)
+ throw new IllegalStateException("Task argument class should be declared before adding of additional arguments. " +
+ "Use VisorGatewayArgument.setTaskArgument first");
+
+ if (map == null)
+ throw new IllegalArgumentException("Map argument should be specified");
+
put("p" + idx++, Map.class.getName());
put("p" + idx++, keyCls.getName());
put("p" + idx++, valCls.getName());
@@ -2974,14 +3021,18 @@ private static String concat(Object[] vals, String delim) {
boolean first = true;
- for (Object val : vals) {
- if (!first)
- sb.a(delim);
+ if (vals != null) {
+ for (Object val : vals) {
+ if (!first)
+ sb.a(delim);
- sb.a(val);
+ sb.a(val);
- first = false;
+ first = false;
+ }
}
+ else
+ sb.a(vals);
return sb.toString();
}
diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcErrorsAbstractSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcErrorsAbstractSelfTest.java
index 5e0350e61f734..d5ec9d7a0af53 100644
--- a/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcErrorsAbstractSelfTest.java
+++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcErrorsAbstractSelfTest.java
@@ -712,6 +712,59 @@ public void testDdlWrongSyntax() throws SQLException {
"Failed to parse query. Syntax error in SQL statement \"ALTER TABLE TEST DROP COLUMN [*]");
}
+ /**
+ * Checks execution DML request on read-only cluster error code and message.
+ *
+ * @throws Exception If failed.
+ */
+ public void testUpdatesRejectedInReadOnlyMode() throws Exception {
+ try (Connection conn = getConnection()) {
+ try (Statement statement = conn.createStatement()) {
+ statement.executeUpdate("CREATE TABLE PUBLIC.TEST_READ_ONLY (ID LONG PRIMARY KEY, VAL LONG)");
+ }
+ }
+
+ grid(0).cluster().readOnly(true);
+
+ try {
+ checkErrorState((conn) -> {
+ try (Statement statement = conn.createStatement()) {
+ statement.executeUpdate("INSERT INTO PUBLIC.TEST_READ_ONLY VALUES (1, 2)");
+ }
+ }, "90097", "Failed to execute DML statement. Cluster in read-only mode");
+ }
+ finally {
+ grid(0).cluster().readOnly(false);
+ }
+ }
+
+ /**
+ * Checks execution batch DML request on read-only cluster error code and message.
+ *
+ * @throws Exception If failed.
+ */
+ public void testBatchUpdatesRejectedInReadOnlyMode() throws Exception {
+ try (Connection conn = getConnection()) {
+ try (Statement statement = conn.createStatement()) {
+ statement.executeUpdate("CREATE TABLE PUBLIC.TEST_READ_ONLY_BATCH (ID LONG PRIMARY KEY, VAL LONG)");
+ }
+ }
+
+ grid(0).cluster().readOnly(true);
+
+ try {
+ checkErrorState((conn) -> {
+ try (Statement statement = conn.createStatement()) {
+ statement.addBatch("INSERT INTO PUBLIC.TEST_READ_ONLY_BATCH VALUES (1, 2)");
+ statement.executeBatch();
+ }
+ }, "90097", null);
+ }
+ finally {
+ grid(0).cluster().readOnly(false);
+ }
+ }
+
/**
* @return Connection to execute statements on.
* @throws SQLException if failed.
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 2ba36c369c227..7ac96990a01eb 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
@@ -28,12 +28,12 @@
import java.util.Collection;
import java.util.Collections;
import java.util.List;
-import java.util.concurrent.Callable;
import org.apache.ignite.internal.IgniteEx;
import org.apache.ignite.internal.processors.odbc.ClientListenerProcessor;
import org.apache.ignite.internal.processors.port.GridPortRecord;
import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.GridTestUtils.RunnableX;
import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
/**
@@ -45,27 +45,18 @@ public class JdbcThinAbstractSelfTest extends GridCommonAbstractTest {
* @param r Runnable to check support.
*/
protected void checkNotSupported(final RunnableX r) {
- GridTestUtils.assertThrows(log,
- new Callable() {
- @Override public Object call() throws Exception {
- r.run();
-
- return null;
- }
- }, SQLFeatureNotSupportedException.class, null);
+ GridTestUtils.assertThrowsWithCause(r, SQLFeatureNotSupportedException.class);
}
/**
* @param r Runnable to check on closed connection.
*/
protected void checkConnectionClosed(final RunnableX r) {
- GridTestUtils.assertThrows(log,
- new Callable() {
- @Override public Object call() throws Exception {
- r.run();
+ GridTestUtils.assertThrowsAnyCause(log,
+ () -> {
+ r.run();
- return null;
- }
+ return null;
}, SQLException.class, "Connection is closed");
}
@@ -73,13 +64,11 @@ protected void checkConnectionClosed(final RunnableX r) {
* @param r Runnable to check on closed statement.
*/
protected void checkStatementClosed(final RunnableX r) {
- GridTestUtils.assertThrows(log,
- new Callable() {
- @Override public Object call() throws Exception {
- r.run();
+ GridTestUtils.assertThrowsAnyCause(log,
+ () -> {
+ r.run();
- return null;
- }
+ return null;
}, SQLException.class, "Statement is closed");
}
@@ -87,26 +76,14 @@ protected void checkStatementClosed(final RunnableX r) {
* @param r Runnable to check on closed result set.
*/
protected void checkResultSetClosed(final RunnableX r) {
- GridTestUtils.assertThrows(log,
- new Callable() {
- @Override public Object call() throws Exception {
- r.run();
+ GridTestUtils.assertThrowsAnyCause(log,
+ () -> {
+ r.run();
- return null;
- }
+ return null;
}, SQLException.class, "Result set is closed");
}
- /**
- * Runnable that can throw an exception.
- */
- interface RunnableX {
- /**
- * @throws Exception On error.
- */
- void run() throws Exception;
- }
-
/**
* @param node Node to connect to.
* @param params Connection parameters.
diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinComplexQuerySelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinComplexQuerySelfTest.java
index ad1e3126c88aa..22d7d71ea8f1f 100644
--- a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinComplexQuerySelfTest.java
+++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinComplexQuerySelfTest.java
@@ -21,6 +21,7 @@
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
+import java.sql.SQLException;
import java.sql.Statement;
import org.apache.ignite.IgniteCache;
import org.apache.ignite.cache.affinity.AffinityKey;
@@ -31,6 +32,7 @@
import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.testframework.GridTestUtils;
import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
import static org.apache.ignite.cache.CacheMode.PARTITIONED;
@@ -266,6 +268,37 @@ public void testCalculatedValue() throws Exception {
assert cnt == 3;
}
+ /**
+ * @throws Exception If failed.
+ */
+ public void testWrongArgumentType() throws Exception {
+ try (ResultSet rs = stmt.executeQuery("select * from \"org\".Organization where name = '2'")) {
+ assertFalse(rs.next());
+ }
+
+ // Check non-indexed field.
+ GridTestUtils.assertThrowsWithCause(() -> {
+ try (ResultSet rs = stmt.executeQuery("select * from \"org\".Organization where name = 2")) {
+ assertFalse(rs.next());
+ }
+
+ return null;
+ }, SQLException.class);
+
+ // Check indexed field.
+ try (ResultSet rs = stmt.executeQuery("select * from \"pers\".Person where name = '2'")) {
+ assertFalse(rs.next());
+ }
+
+ GridTestUtils.assertThrowsWithCause(() -> {
+ try (ResultSet rs = stmt.executeQuery("select * from \"pers\".Person where name = 2")) {
+ assertFalse(rs.next());
+ }
+
+ return null;
+ }, SQLException.class);
+ }
+
/**
* Person.
*/
@@ -276,7 +309,7 @@ private static class Person implements Serializable {
private final int id;
/** Name. */
- @QuerySqlField(index = false)
+ @QuerySqlField(index = true)
private final String name;
/** Age. */
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 6403cac5037f1..bd816e6ef5d2c 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
@@ -58,6 +58,7 @@
import static java.sql.ResultSet.TYPE_FORWARD_ONLY;
import static java.sql.Statement.NO_GENERATED_KEYS;
import static java.sql.Statement.RETURN_GENERATED_KEYS;
+import static org.apache.ignite.testframework.GridTestUtils.RunnableX;
/**
* Connection test.
@@ -570,7 +571,7 @@ public void testCreateStatement() throws Exception {
// Exception when called on closed connection
checkConnectionClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
conn.createStatement();
}
});
@@ -623,7 +624,7 @@ public void testCreateStatement2() throws Exception {
// Exception when called on closed connection
checkConnectionClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
conn.createStatement(TYPE_FORWARD_ONLY,
CONCUR_READ_ONLY);
}
@@ -682,7 +683,7 @@ public void testCreateStatement3() throws Exception {
// Exception when called on closed connection
checkConnectionClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
conn.createStatement(TYPE_FORWARD_ONLY,
CONCUR_READ_ONLY, HOLD_CURSORS_OVER_COMMIT);
}
@@ -716,7 +717,7 @@ public void testPrepareStatement() throws Exception {
// Exception when called on closed connection
checkConnectionClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
conn.prepareStatement(sqlText);
}
});
@@ -774,7 +775,7 @@ public void testPrepareStatement3() throws Exception {
// Exception when called on closed connection
checkConnectionClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
conn.prepareStatement(sqlText, TYPE_FORWARD_ONLY, CONCUR_READ_ONLY);
}
});
@@ -839,7 +840,7 @@ public void testPrepareStatement4() throws Exception {
// Exception when called on closed connection
checkConnectionClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
conn.prepareStatement(sqlText, TYPE_FORWARD_ONLY, CONCUR_READ_ONLY, HOLD_CURSORS_OVER_COMMIT);
}
});
@@ -961,7 +962,7 @@ public void testNativeSql() throws Exception {
// Exception when called on closed connection
checkConnectionClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
conn.nativeSQL(sqlText);
}
});
@@ -987,7 +988,7 @@ public void testGetSetAutoCommit() throws Exception {
// Exception when called on closed connection
checkConnectionClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
conn.setAutoCommit(true);
}
});
@@ -1022,7 +1023,7 @@ public void testCommit() throws Exception {
// Exception when called on closed connection
checkConnectionClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
conn.commit();
}
});
@@ -1057,7 +1058,7 @@ public void testRollback() throws Exception {
// Exception when called on closed connection
checkConnectionClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
conn.rollback();
}
});
@@ -1077,7 +1078,7 @@ public void testGetMetaData() throws Exception {
// Exception when called on closed connection
checkConnectionClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
conn.getMetaData();
}
});
@@ -1093,14 +1094,14 @@ public void testGetSetReadOnly() throws Exception {
// Exception when called on closed connection
checkConnectionClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
conn.setReadOnly(true);
}
});
// Exception when called on closed connection
checkConnectionClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
conn.isReadOnly();
}
});
@@ -1124,14 +1125,14 @@ public void testGetSetCatalog() throws Exception {
// Exception when called on closed connection
checkConnectionClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
conn.setCatalog("");
}
});
// Exception when called on closed connection
checkConnectionClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
conn.getCatalog();
}
});
@@ -1176,14 +1177,14 @@ public void testGetSetTransactionIsolation() throws Exception {
// Exception when called on closed connection
checkConnectionClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
conn.getTransactionIsolation();
}
});
// Exception when called on closed connection
checkConnectionClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
conn.setTransactionIsolation(TRANSACTION_SERIALIZABLE);
}
});
@@ -1209,14 +1210,14 @@ public void testClearGetWarnings() throws Exception {
// Exception when called on closed connection
checkConnectionClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
conn.getWarnings();
}
});
// Exception when called on closed connection
checkConnectionClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
conn.clearWarnings();
}
});
@@ -1355,7 +1356,7 @@ public void testSetSavepoint() throws Exception {
// Unsupported
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
conn.setSavepoint();
}
});
@@ -1363,7 +1364,7 @@ public void testSetSavepoint() throws Exception {
conn.close();
checkConnectionClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
conn.setSavepoint();
}
});
@@ -1409,7 +1410,7 @@ public void testSetSavepointName() throws Exception {
// Unsupported
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
conn.setSavepoint(name);
}
});
@@ -1417,7 +1418,7 @@ public void testSetSavepointName() throws Exception {
conn.close();
checkConnectionClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
conn.setSavepoint(name);
}
});
@@ -1463,7 +1464,7 @@ public void testRollbackSavePoint() throws Exception {
// Unsupported
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
conn.rollback(savepoint);
}
});
@@ -1471,7 +1472,7 @@ public void testRollbackSavePoint() throws Exception {
conn.close();
checkConnectionClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
conn.rollback(savepoint);
}
});
@@ -1501,7 +1502,7 @@ public void testReleaseSavepoint() throws Exception {
final Savepoint savepoint = getFakeSavepoint();
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
conn.releaseSavepoint(savepoint);
}
});
@@ -1509,7 +1510,7 @@ public void testReleaseSavepoint() throws Exception {
conn.close();
checkConnectionClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
conn.releaseSavepoint(savepoint);
}
});
@@ -1655,7 +1656,7 @@ public void testGetSetClientInfoPair() throws Exception {
conn.close();
checkConnectionClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
conn.getClientInfo(name);
}
});
@@ -1693,7 +1694,7 @@ public void testGetSetClientInfoProperties() throws Exception {
conn.close();
checkConnectionClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
conn.getClientInfo();
}
});
@@ -1734,7 +1735,7 @@ public void testCreateArrayOf() throws Exception {
// Unsupported
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
conn.createArrayOf(typeName, elements);
}
});
@@ -1742,7 +1743,7 @@ public void testCreateArrayOf() throws Exception {
conn.close();
checkConnectionClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
conn.createArrayOf(typeName, elements);
}
});
@@ -1770,7 +1771,7 @@ public void testCreateStruct() throws Exception {
final Object[] attrs = new Object[] {100, "Tom"};
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
conn.createStruct(typeName, attrs);
}
});
@@ -1778,7 +1779,7 @@ public void testCreateStruct() throws Exception {
conn.close();
checkConnectionClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
conn.createStruct(typeName, attrs);
}
});
@@ -1805,13 +1806,13 @@ public void testGetSetSchema() throws Exception {
conn.close();
checkConnectionClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
conn.setSchema(schema);
}
});
checkConnectionClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
conn.getSchema();
}
});
@@ -1889,13 +1890,13 @@ public void testGetSetNetworkTimeout() throws Exception {
conn.close();
checkConnectionClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
conn.getNetworkTimeout();
}
});
checkConnectionClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
conn.setNetworkTimeout(executor, timeout);
}
});
@@ -1980,4 +1981,4 @@ private Savepoint getFakeSavepoint() {
}
};
}
-}
\ No newline at end of file
+}
diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinPreparedStatementSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinPreparedStatementSelfTest.java
index c5778537096f1..4635702a9dd78 100644
--- a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinPreparedStatementSelfTest.java
+++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinPreparedStatementSelfTest.java
@@ -797,146 +797,146 @@ public void testClearParameter() throws Exception {
public void testNotSupportedTypes() throws Exception {
stmt = conn.prepareStatement("");
- checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ checkNotSupported(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.setArray(1, null);
}
});
- checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ checkNotSupported(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.setAsciiStream(1, null);
}
});
- checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ checkNotSupported(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.setAsciiStream(1, null, 0);
}
});
- checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ checkNotSupported(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.setAsciiStream(1, null, 0L);
}
});
- checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ checkNotSupported(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.setBinaryStream(1, null);
}
});
- checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ checkNotSupported(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.setBinaryStream(1, null, 0);
}
});
- checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ checkNotSupported(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.setBinaryStream(1, null, 0L);
}
});
- checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ checkNotSupported(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.setBlob(1, (Blob)null);
}
});
- checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ checkNotSupported(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.setBlob(1, (InputStream)null);
}
});
- checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ checkNotSupported(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.setBlob(1, null, 0L);
}
});
- checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ checkNotSupported(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.setCharacterStream(1, null);
}
});
- checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ checkNotSupported(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.setCharacterStream(1, null, 0);
}
});
- checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ checkNotSupported(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.setCharacterStream(1, null, 0L);
}
});
- checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ checkNotSupported(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.setClob(1, (Clob)null);
}
});
- checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ checkNotSupported(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.setClob(1, (Reader)null);
}
});
- checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ checkNotSupported(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.setClob(1, null, 0L);
}
});
- checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ checkNotSupported(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.setNCharacterStream(1, null);
}
});
- checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ checkNotSupported(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.setNCharacterStream(1, null, 0L);
}
});
- checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ checkNotSupported(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.setNClob(1, (NClob)null);
}
});
- checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ checkNotSupported(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.setNClob(1, (Reader)null);
}
});
- checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ checkNotSupported(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.setNClob(1, null, 0L);
}
});
- checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ checkNotSupported(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.setRowId(1, null);
}
});
- checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ checkNotSupported(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.setRef(1, null);
}
});
- checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ checkNotSupported(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.setSQLXML(1, null);
}
});
@@ -1055,4 +1055,4 @@ private TestObject(int id) {
this.id = id;
}
}
-}
\ No newline at end of file
+}
diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinResultSetSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinResultSetSelfTest.java
index 4f9480261c66b..94713afe873fa 100644
--- a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinResultSetSelfTest.java
+++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinResultSetSelfTest.java
@@ -49,6 +49,9 @@
import static org.apache.ignite.cache.CacheMode.PARTITIONED;
import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC;
+import static org.apache.ignite.testframework.GridTestUtils.RunnableX;
+import static org.apache.ignite.testframework.GridTestUtils.assertThrows;
+import static org.apache.ignite.testframework.GridTestUtils.assertThrowsAnyCause;
/**
* Result set test.
@@ -772,133 +775,133 @@ public void testNotSupportedTypes() throws Exception {
assert rs.next();
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getArray(1);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getArray("id");
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getAsciiStream(1);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getAsciiStream("id");
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getBinaryStream(1);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getBinaryStream("id");
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getBlob(1);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getBlob("id");
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getClob(1);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getClob("id");
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getCharacterStream(1);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getCharacterStream("id");
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getNCharacterStream(1);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getNCharacterStream("id");
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getNClob(1);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getNClob("id");
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getRef(1);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getRef("id");
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getRowId(1);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getRowId("id");
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getSQLXML(1);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getSQLXML("id");
}
});
@@ -913,499 +916,499 @@ public void testUpdateNotSupported() throws Exception {
assert rs.next();
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateBoolean(1, true);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateBoolean("id", true);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateByte(1, (byte)0);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateByte("id", (byte)0);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateShort(1, (short)0);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateShort("id", (short)0);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateInt(1, 0);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateInt("id", 0);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateLong(1, 0);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateLong("id", 0);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateFloat(1, (float)0.0);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateFloat("id", (float)0.0);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateDouble(1, 0.0);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateDouble("id", 0.0);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateString(1, "");
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateString("id", "");
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateTime(1, new Time(0));
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateTime("id", new Time(0));
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateDate(1, new Date(0));
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateDate("id", new Date(0));
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateTimestamp(1, new Timestamp(0));
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateTimestamp("id", new Timestamp(0));
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateBytes(1, new byte[]{});
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateBytes("id", new byte[]{});
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateArray(1, null);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateArray("id", null);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateBlob(1, (Blob)null);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateBlob(1, (InputStream)null);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateBlob(1, null, 0L);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateBlob("id", (Blob)null);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateBlob("id", (InputStream)null);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateBlob("id", null, 0L);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateClob(1, (Clob)null);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateClob(1, (Reader)null);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateClob(1, null, 0L);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateClob("id", (Clob)null);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateClob("id", (Reader)null);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateClob("id", null, 0L);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateNClob(1, (NClob)null);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateNClob(1, (Reader)null);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateNClob(1, null, 0L);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateNClob("id", (NClob)null);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateNClob("id", (Reader)null);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateNClob("id", null, 0L);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateAsciiStream(1, null);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateAsciiStream(1, null, 0);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateAsciiStream(1, null, 0L);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateAsciiStream("id", null);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateAsciiStream("id", null, 0);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateAsciiStream("id", null, 0L);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateCharacterStream(1, null);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateCharacterStream(1, null, 0);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateCharacterStream(1, null, 0L);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateCharacterStream("id", null);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateCharacterStream("id", null, 0);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateCharacterStream("id", null, 0L);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateNCharacterStream(1, null);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateNCharacterStream(1, null, 0);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateNCharacterStream(1, null, 0L);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateNCharacterStream("id", null);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateNCharacterStream("id", null, 0);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateNCharacterStream("id", null, 0L);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateRef(1, null);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateRef("id", null);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateRowId(1, null);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateRowId("id", null);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateNString(1, null);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateNString("id", null);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateSQLXML(1, null);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateSQLXML("id", null);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateObject(1, null);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateObject(1, null, 0);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateObject("id", null);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateObject("id", null, 0);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateBigDecimal(1, null);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateBigDecimal("id", null);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateNull(1);
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateNull("id");
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.cancelRowUpdates();
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.updateRow();
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.deleteRow();
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.insertRow();
}
});
checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.moveToInsertRow();
}
});
@@ -1423,235 +1426,235 @@ public void testExceptionOnClosedResultSet() throws Exception {
rs.close();
checkResultSetClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getBoolean(1);
}
});
checkResultSetClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getBoolean("id");
}
});
checkResultSetClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getByte(1);
}
});
checkResultSetClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getByte("id");
}
});
checkResultSetClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getShort(1);
}
});
checkResultSetClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getShort("id");
}
});
checkResultSetClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getInt(1);
}
});
checkResultSetClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getInt("id");
}
});
checkResultSetClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getLong(1);
}
});
checkResultSetClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getLong("id");
}
});
checkResultSetClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getFloat(1);
}
});
checkResultSetClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getFloat("id");
}
});
checkResultSetClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getDouble(1);
}
});
checkResultSetClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getDouble("id");
}
});
checkResultSetClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getString(1);
}
});
checkResultSetClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getString("id");
}
});
checkResultSetClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getBytes(1);
}
});
checkResultSetClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getBytes("id");
}
});
checkResultSetClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getDate(1);
}
});
checkResultSetClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getDate(1, new GregorianCalendar());
}
});
checkResultSetClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getDate("id");
}
});
checkResultSetClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getDate("id", new GregorianCalendar());
}
});
checkResultSetClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getTime(1);
}
});
checkResultSetClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getTime(1, new GregorianCalendar());
}
});
checkResultSetClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getTime("id");
}
});
checkResultSetClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getTime("id", new GregorianCalendar());
}
});
checkResultSetClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getTimestamp(1);
}
});
checkResultSetClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getTimestamp(1, new GregorianCalendar());
}
});
checkResultSetClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getTimestamp("id");
}
});
checkResultSetClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getTimestamp("id", new GregorianCalendar());
}
});
checkResultSetClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.wasNull();
}
});
checkResultSetClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getMetaData();
}
});
checkResultSetClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.next();
}
});
checkResultSetClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.last();
}
});
checkResultSetClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.afterLast();
}
});
checkResultSetClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.beforeFirst();
}
});
checkResultSetClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.first();
}
});
checkResultSetClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.findColumn("id");
}
});
checkResultSetClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ @Override public void runx() throws Exception {
rs.getRow();
}
});
@@ -1847,4 +1850,4 @@ private TestObjectField(int a, String b) {
return S.toString(TestObjectField.class, this);
}
}
-}
\ No newline at end of file
+}
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 82c0512c7ab70..10dad914960cd 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
@@ -132,7 +132,7 @@ public class JdbcThinStatementSelfTest extends JdbcThinAbstractSelfTest {
public void testExecuteQuery0() throws Exception {
ResultSet rs = stmt.executeQuery(SQL);
- assert rs != null;
+ assertNotNull(rs);
int cnt = 0;
@@ -140,22 +140,22 @@ public void testExecuteQuery0() throws Exception {
int id = rs.getInt("id");
if (id == 2) {
- assert "Joe".equals(rs.getString("firstName"));
- assert "Black".equals(rs.getString("lastName"));
- assert rs.getInt("age") == 35;
+ assertEquals("Joe", rs.getString("firstName"));
+ assertEquals("Black", rs.getString("lastName"));
+ assertEquals(35, rs.getInt("age"));
}
else if (id == 3) {
- assert "Mike".equals(rs.getString("firstName"));
- assert "Green".equals(rs.getString("lastName"));
- assert rs.getInt("age") == 40;
+ assertEquals("Mike", rs.getString("firstName"));
+ assertEquals("Green", rs.getString("lastName"));
+ assertEquals(40, rs.getInt("age"));
}
else
- assert false : "Wrong ID: " + id;
+ fail("Wrong ID: " + id);
cnt++;
}
- assert cnt == 2;
+ assertEquals(2, cnt);
}
/**
@@ -177,8 +177,8 @@ public void testExecuteQuery1() throws Exception {
stmt.close();
// Call on a closed statement
- checkStatementClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ checkStatementClosed(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.executeQuery(sqlText);
}
});
@@ -188,15 +188,13 @@ public void testExecuteQuery1() throws Exception {
* @throws Exception If failed.
*/
public void testExecute() throws Exception {
- assert stmt.execute(SQL);
+ assertTrue(stmt.execute(SQL));
- assert stmt.getUpdateCount() == -1 : "Update count must be -1 for SELECT query";
+ assertEquals("Update count must be -1 for SELECT query", -1, stmt.getUpdateCount());
ResultSet rs = stmt.getResultSet();
- assert rs != null;
-
- assert stmt.getResultSet() == null;
+ assertNotNull(rs);
int cnt = 0;
@@ -204,22 +202,24 @@ public void testExecute() throws Exception {
int id = rs.getInt("id");
if (id == 2) {
- assert "Joe".equals(rs.getString("firstName"));
- assert "Black".equals(rs.getString("lastName"));
- assert rs.getInt("age") == 35;
+ assertEquals("Joe", rs.getString("firstName"));
+ assertEquals("Black", rs.getString("lastName"));
+ assertEquals(35, rs.getInt("age"));
}
else if (id == 3) {
- assert "Mike".equals(rs.getString("firstName"));
- assert "Green".equals(rs.getString("lastName"));
- assert rs.getInt("age") == 40;
+ assertEquals( "Mike", rs.getString("firstName"));
+ assertEquals( "Green", rs.getString("lastName"));
+ assertEquals(40, rs.getInt("age"));
}
else
- assert false : "Wrong ID: " + id;
+ fail("Wrong ID: " + id);
cnt++;
}
- assert cnt == 2;
+ assertEquals(2, cnt);
+
+ assertFalse("Statement has more results.", stmt.getMoreResults());
}
/**
@@ -228,11 +228,11 @@ else if (id == 3) {
public void testMaxRows() throws Exception {
stmt.setMaxRows(1);
- assert stmt.getMaxRows() == 1;
+ assertEquals(1, stmt.getMaxRows());
ResultSet rs = stmt.executeQuery(SQL);
- assert rs != null;
+ assertNotNull(rs);
int cnt = 0;
@@ -240,28 +240,28 @@ public void testMaxRows() throws Exception {
int id = rs.getInt("id");
if (id == 2) {
- assert "Joe".equals(rs.getString("firstName"));
- assert "Black".equals(rs.getString("lastName"));
- assert rs.getInt("age") == 35;
+ assertEquals("Joe", rs.getString("firstName"));
+ assertEquals("Black", rs.getString("lastName"));
+ assertEquals(35, rs.getInt("age"));
}
else if (id == 3) {
- assert "Mike".equals(rs.getString("firstName"));
- assert "Green".equals(rs.getString("lastName"));
- assert rs.getInt("age") == 40;
+ assertEquals( "Mike", rs.getString("firstName"));
+ assertEquals( "Green", rs.getString("lastName"));
+ assertEquals(40, rs.getInt("age"));
}
else
- assert false : "Wrong ID: " + id;
+ fail("Wrong ID: " + id);
cnt++;
}
- assert cnt == 1;
+ assertEquals(1, cnt);
stmt.setMaxRows(0);
rs = stmt.executeQuery(SQL);
- assert rs != null;
+ assertNotNull(rs);
cnt = 0;
@@ -269,22 +269,22 @@ else if (id == 3) {
int id = rs.getInt("id");
if (id == 2) {
- assert "Joe".equals(rs.getString("firstName"));
- assert "Black".equals(rs.getString("lastName"));
- assert rs.getInt("age") == 35;
+ assertEquals("Joe", rs.getString("firstName"));
+ assertEquals("Black", rs.getString("lastName"));
+ assertEquals(35, rs.getInt("age"));
}
else if (id == 3) {
- assert "Mike".equals(rs.getString("firstName"));
- assert "Green".equals(rs.getString("lastName"));
- assert rs.getInt("age") == 40;
+ assertEquals( "Mike", rs.getString("firstName"));
+ assertEquals( "Green", rs.getString("lastName"));
+ assertEquals(40, rs.getInt("age"));
}
else
- assert false : "Wrong ID: " + id;
+ fail("Wrong ID: " + id);
cnt++;
}
- assert cnt == 2;
+ assertEquals(2, cnt);
}
/**
@@ -295,14 +295,14 @@ public void testCloseResultSet0() throws Exception {
ResultSet rs1 = stmt.executeQuery(SQL);
ResultSet rs2 = stmt.executeQuery(SQL);
- assert rs0.isClosed() : "ResultSet must be implicitly closed after re-execute statement";
- assert rs1.isClosed() : "ResultSet must be implicitly closed after re-execute statement";
+ assertTrue("ResultSet must be implicitly closed after re-execute statement", rs0.isClosed());
+ assertTrue("ResultSet must be implicitly closed after re-execute statement", rs1.isClosed());
- assert !rs2.isClosed() : "Last result set must be available";
+ assertFalse("Last result set must be available", rs2.isClosed());
stmt.close();
- assert rs2.isClosed() : "ResultSet must be explicitly closed after close statement";
+ assertTrue("ResultSet must be explicitly closed after close statement", rs2.isClosed());
}
/**
@@ -315,7 +315,7 @@ public void testCloseResultSet1() throws Exception {
stmt.close();
- assert rs.isClosed() : "ResultSet must be explicitly closed after close statement";
+ assertTrue("ResultSet must be explicitly closed after close statement", rs.isClosed());
}
/**
@@ -326,66 +326,66 @@ public void testCloseResultSetByConnectionClose() throws Exception {
conn.close();
- assert stmt.isClosed() : "Statement must be implicitly closed after close connection";
- assert rs.isClosed() : "ResultSet must be implicitly closed after close connection";
+ assertTrue("Statement must be implicitly closed after close connection", stmt.isClosed());
+ assertTrue("ResultSet must be implicitly closed after close connection", rs.isClosed());
}
/**
* @throws Exception If failed.
*/
public void testCloseOnCompletionAfterQuery() throws Exception {
- assert !stmt.isCloseOnCompletion() : "Invalid default closeOnCompletion";
+ assertFalse("Invalid default closeOnCompletion", stmt.isCloseOnCompletion());
ResultSet rs0 = stmt.executeQuery(SQL);
ResultSet rs1 = stmt.executeQuery(SQL);
- assert rs0.isClosed() : "Result set must be closed implicitly";
+ assertTrue("Result set must be closed implicitly", rs0.isClosed());
- assert !stmt.isClosed() : "Statement must not be closed";
+ assertFalse("Statement must not be closed", stmt.isClosed());
rs1.close();
- assert !stmt.isClosed() : "Statement must not be closed";
+ assertFalse("Statement must not be closed", stmt.isClosed());
ResultSet rs2 = stmt.executeQuery(SQL);
stmt.closeOnCompletion();
- assert stmt.isCloseOnCompletion() : "Invalid closeOnCompletion";
+ assertTrue("Invalid closeOnCompletion", stmt.isCloseOnCompletion());
rs2.close();
- assert stmt.isClosed() : "Statement must be closed";
+ assertTrue("Statement must be closed", stmt.isClosed());
}
/**
* @throws Exception If failed.
*/
public void testCloseOnCompletionBeforeQuery() throws Exception {
- assert !stmt.isCloseOnCompletion() : "Invalid default closeOnCompletion";
+ assertFalse("Invalid default closeOnCompletion", stmt.isCloseOnCompletion());
ResultSet rs0 = stmt.executeQuery(SQL);
ResultSet rs1 = stmt.executeQuery(SQL);
- assert rs0.isClosed() : "Result set must be closed implicitly";
+ assertTrue("Result set must be closed implicitly", rs0.isClosed());
- assert !stmt.isClosed() : "Statement must not be closed";
+ assertFalse("Statement must not be closed", stmt.isClosed());
rs1.close();
- assert !stmt.isClosed() : "Statement must not be closed";
+ assertFalse("Statement must not be closed", stmt.isClosed());
stmt.closeOnCompletion();
ResultSet rs2 = stmt.executeQuery(SQL);
- assert stmt.isCloseOnCompletion() : "Invalid closeOnCompletion";
+ assertTrue("Invalid closeOnCompletion", stmt.isCloseOnCompletion());
rs2.close();
- assert stmt.isClosed() : "Statement must be closed";
+ assertTrue("Statement must be closed", stmt.isClosed());
}
/**
@@ -414,7 +414,7 @@ public void testExecuteQueryTimeout() throws Exception {
* @throws Exception If failed.
*/
public void testExecuteQueryMultipleOnlyResultSets() throws Exception {
- assert conn.getMetaData().supportsMultipleResultSets();
+ assertTrue(conn.getMetaData().supportsMultipleResultSets());
int stmtCnt = 10;
@@ -543,8 +543,8 @@ public void testExecuteUpdate() throws Exception {
stmt.close();
- checkStatementClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ checkStatementClosed(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.executeUpdate(sqlText);
}
});
@@ -634,15 +634,15 @@ public void testGetSetMaxFieldSizeUnsupported() throws Exception {
stmt.close();
// Call on a closed statement
- checkStatementClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ checkStatementClosed(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.getMaxFieldSize();
}
});
// Call on a closed statement
- checkStatementClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ checkStatementClosed(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.setMaxFieldSize(100);
}
});
@@ -684,15 +684,15 @@ public void testGetSetMaxRows() throws Exception {
stmt.close();
// Call on a closed statement
- checkStatementClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ checkStatementClosed(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.getMaxRows();
}
});
// Call on a closed statement
- checkStatementClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ checkStatementClosed(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.setMaxRows(maxRows);
}
});
@@ -728,8 +728,8 @@ public void testSetEscapeProcessing() throws Exception {
stmt.close();
- checkStatementClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ checkStatementClosed(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.setEscapeProcessing(true);
}
});
@@ -765,15 +765,15 @@ public void testGetSetQueryTimeout() throws Exception {
stmt.close();
// Call on a closed statement
- checkStatementClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ checkStatementClosed(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.getQueryTimeout();
}
});
// Call on a closed statement
- checkStatementClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ checkStatementClosed(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.setQueryTimeout(timeout);
}
});
@@ -783,7 +783,7 @@ public void testGetSetQueryTimeout() throws Exception {
* @throws Exception If failed.
*/
public void testMaxFieldSize() throws Exception {
- assert stmt.getMaxFieldSize() >= 0;
+ assertTrue(stmt.getMaxFieldSize() >= 0);
GridTestUtils.assertThrows(log,
new Callable() {
@@ -797,8 +797,8 @@ public void testMaxFieldSize() throws Exception {
"Invalid field limit"
);
- checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ checkNotSupported(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.setMaxFieldSize(100);
}
});
@@ -808,22 +808,22 @@ public void testMaxFieldSize() throws Exception {
* @throws Exception If failed.
*/
public void testQueryTimeout() throws Exception {
- assert stmt.getQueryTimeout() == 0 : "Default timeout invalid: " + stmt.getQueryTimeout();
+ assertEquals("Default timeout invalid: " + stmt.getQueryTimeout(), 0, stmt.getQueryTimeout());
stmt.setQueryTimeout(10);
- assert stmt.getQueryTimeout() == 10;
+ assertEquals(10, stmt.getQueryTimeout());
stmt.close();
- checkStatementClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ checkStatementClosed(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.getQueryTimeout();
}
});
- checkStatementClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ checkStatementClosed(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.setQueryTimeout(10);
}
});
@@ -835,18 +835,18 @@ public void testQueryTimeout() throws Exception {
public void testWarningsOnClosedStatement() throws Exception {
stmt.clearWarnings();
- assert stmt.getWarnings() == null;
+ assertNull(null, stmt.getWarnings());
stmt.close();
- checkStatementClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ checkStatementClosed(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.getWarnings();
}
});
- checkStatementClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ checkStatementClosed(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.clearWarnings();
}
});
@@ -856,16 +856,16 @@ public void testWarningsOnClosedStatement() throws Exception {
* @throws Exception If failed.
*/
public void testCursorName() throws Exception {
- checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ checkNotSupported(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.setCursorName("test");
}
});
stmt.close();
- checkStatementClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ checkStatementClosed(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.setCursorName("test");
}
});
@@ -875,22 +875,22 @@ public void testCursorName() throws Exception {
* @throws Exception If failed.
*/
public void testGetMoreResults() throws Exception {
- assert !stmt.getMoreResults();
+ assertFalse(stmt.getMoreResults());
stmt.execute("select 1; ");
ResultSet rs = stmt.getResultSet();
- assert !stmt.getMoreResults();
+ assertFalse(stmt.getMoreResults());
- assert stmt.getResultSet() == null;
+ assertNull(stmt.getResultSet());
- assert rs.isClosed();
+ assertTrue(rs.isClosed());
stmt.close();
- checkStatementClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ checkStatementClosed(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.getMoreResults();
}
});
@@ -899,37 +899,59 @@ public void testGetMoreResults() throws Exception {
/**
* @throws Exception If failed.
*/
- public void testGetMoreResults1() throws Exception {
- assert !stmt.getMoreResults(Statement.CLOSE_CURRENT_RESULT);
- assert !stmt.getMoreResults(Statement.KEEP_CURRENT_RESULT);
- assert !stmt.getMoreResults(Statement.CLOSE_ALL_RESULTS);
+ public void testGetMoreResultsKeepCurrent() throws Exception {
+ assertFalse(stmt.getMoreResults(Statement.CLOSE_CURRENT_RESULT));
+ assertFalse(stmt.getMoreResults(Statement.KEEP_CURRENT_RESULT));
+ assertFalse(stmt.getMoreResults(Statement.CLOSE_ALL_RESULTS));
stmt.execute("select 1; ");
ResultSet rs = stmt.getResultSet();
- assert !stmt.getMoreResults(Statement.KEEP_CURRENT_RESULT);
+ assertFalse(stmt.getMoreResults(Statement.KEEP_CURRENT_RESULT));
- assert !rs.isClosed();
+ assertFalse(rs.isClosed());
- assert !stmt.getMoreResults(Statement.CLOSE_ALL_RESULTS);
+ stmt.close();
- assert rs.isClosed();
+ checkStatementClosed(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
+ stmt.getMoreResults(Statement.KEEP_CURRENT_RESULT);
+ }
+ });
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ @org.junit.Test
+ public void testGetMoreResultsCloseAll() throws Exception {
+ assertFalse(stmt.getMoreResults(Statement.CLOSE_CURRENT_RESULT));
+ assertFalse(stmt.getMoreResults(Statement.KEEP_CURRENT_RESULT));
+ assertFalse(stmt.getMoreResults(Statement.CLOSE_ALL_RESULTS));
+
+ stmt.execute("select 1; ");
+
+ ResultSet rs = stmt.getResultSet();
+
+ assertFalse(stmt.getMoreResults(Statement.CLOSE_ALL_RESULTS));
stmt.close();
- checkStatementClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ checkStatementClosed(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.getMoreResults(Statement.KEEP_CURRENT_RESULT);
}
});
}
/**
+ * Verifies that emty batch can be performed.
+ *
* @throws Exception If failed.
*/
public void testBatchEmpty() throws Exception {
- assert conn.getMetaData().supportsBatchUpdates();
+ assertTrue(conn.getMetaData().supportsBatchUpdates());
stmt.addBatch("");
stmt.clearBatch();
@@ -951,7 +973,7 @@ public void testBatchEmpty() throws Exception {
* @throws Exception If failed.
*/
public void testFetchDirection() throws Exception {
- assert stmt.getFetchDirection() == ResultSet.FETCH_FORWARD;
+ assertEquals(ResultSet.FETCH_FORWARD, stmt.getFetchDirection());
GridTestUtils.assertThrows(log,
new Callable() {
@@ -967,14 +989,14 @@ public void testFetchDirection() throws Exception {
stmt.close();
- checkStatementClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ checkStatementClosed(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.setFetchDirection(-1);
}
});
- checkStatementClosed(new RunnableX() {
- @Override public void run() throws Exception {
+ checkStatementClosed(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.getFetchDirection();
}
});
@@ -1006,46 +1028,46 @@ public void testAutogenerated() throws Exception {
SQLException.class,
"Invalid autoGeneratedKeys value");
- assert !conn.getMetaData().supportsGetGeneratedKeys();
+ assertFalse(conn.getMetaData().supportsGetGeneratedKeys());
- checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ checkNotSupported(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.getGeneratedKeys();
}
});
- checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ checkNotSupported(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.executeUpdate("select 1", Statement.RETURN_GENERATED_KEYS);
}
});
- checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ checkNotSupported(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.executeUpdate("select 1", new int[] {1, 2});
}
});
- checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ checkNotSupported(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.executeUpdate("select 1", new String[] {"a", "b"});
}
});
- checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ checkNotSupported(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.execute("select 1", Statement.RETURN_GENERATED_KEYS);
}
});
- checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ checkNotSupported(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.execute("select 1", new int[] {1, 2});
}
});
- checkNotSupported(new RunnableX() {
- @Override public void run() throws Exception {
+ checkNotSupported(new GridTestUtils.RunnableX() {
+ @Override public void runx() throws Exception {
stmt.execute("select 1", new String[] {"a", "b"});
}
});
@@ -1115,7 +1137,7 @@ public void testStatementTypeMismatchSelectForCachedQuery() throws Exception {
SQLException.class,
"Given statement type does not match that declared by JDBC driver");
- assert stmt.getResultSet() == null : "Not results expected. Last statement is executed with exception";
+ assertNull("Not results expected. Last statement is executed with exception", stmt.getResultSet());
}
/**
@@ -1137,18 +1159,20 @@ public void testStatementTypeMismatchUpdate() throws Exception {
boolean next = rs.next();
- assert next;
+ assertTrue(next);
- assert rs.getInt(1) == 1 : "The data must not be updated. " +
+ assertEquals("The data must not be updated. " +
"Because update statement is executed via 'executeQuery' method." +
- " Data [val=" + rs.getInt(1) + ']';
+ " Data [val=" + rs.getInt(1) + ']',
+ 1,
+ rs.getInt(1));
}
/** */
private void fillCache() {
IgniteCache cachePerson = grid(0).cache(DEFAULT_CACHE_NAME);
- assert cachePerson != null;
+ assertNotNull(cachePerson);
cachePerson.put("p1", new Person(1, "John", "White", 25));
cachePerson.put("p2", new Person(2, "Joe", "Black", 35));
@@ -1229,4 +1253,4 @@ private Person(int id, String firstName, String lastName, int age) {
this.age = age;
}
}
-}
\ No newline at end of file
+}
diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinStreamingAbstractSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinStreamingAbstractSelfTest.java
index 70046356b210b..7222074b3b848 100644
--- a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinStreamingAbstractSelfTest.java
+++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinStreamingAbstractSelfTest.java
@@ -198,6 +198,13 @@ public void testSimultaneousStreaming() throws Exception {
assertEquals(i, grid(0).cache("T").get(i));
}
+ /** {@inheritDoc} */
+ @Override public void testStreamedInsertFailsOnReadOnlyMode() throws Exception {
+ fail("https://ggsystems.atlassian.net/browse/GG-17406");
+
+ super.testStreamedInsertFailsOnReadOnlyMode();
+ }
+
/**
*
*/
@@ -502,4 +509,4 @@ static final class IndexingWithContext extends IgniteH2Indexing {
return super.querySqlFields(schemaName, qry, cliCtx, keepBinary, failOnMultipleStmts, cancel);
}
}
-}
\ No newline at end of file
+}
diff --git a/modules/codegen/src/main/java/org/apache/ignite/codegen/MessageCodeGenerator.java b/modules/codegen/src/main/java/org/apache/ignite/codegen/MessageCodeGenerator.java
index 9ecc46a72713b..54ad3c8f0e399 100644
--- a/modules/codegen/src/main/java/org/apache/ignite/codegen/MessageCodeGenerator.java
+++ b/modules/codegen/src/main/java/org/apache/ignite/codegen/MessageCodeGenerator.java
@@ -348,13 +348,13 @@ else if (line.startsWith(TAB + "}")) {
}
if (!writeFound)
- System.out.println(" writeTo method doesn't exist.");
+ System.out.println(" writeTo method doesn't exist for " + cls.getSimpleName());
if (!readFound)
- System.out.println(" readFrom method doesn't exist.");
+ System.out.println(" readFrom method doesn't exist for " + cls.getSimpleName());
if (!fieldCntFound)
- System.out.println(" fieldCount method doesn't exist.");
+ System.out.println(" fieldCount method doesn't exist for " + cls.getSimpleName());
}
finally {
if (rdr != null)
diff --git a/modules/compatibility/src/test/java/org/apache/ignite/compatibility/PdsWithTtlCompatibilityTest.java b/modules/compatibility/src/test/java/org/apache/ignite/compatibility/PdsWithTtlCompatibilityTest.java
deleted file mode 100644
index 946caddb5f203..0000000000000
--- a/modules/compatibility/src/test/java/org/apache/ignite/compatibility/PdsWithTtlCompatibilityTest.java
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * 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.compatibility;
-
-import java.util.Collection;
-import java.util.concurrent.TimeUnit;
-import javax.cache.Cache;
-import javax.cache.expiry.AccessedExpiryPolicy;
-import javax.cache.expiry.Duration;
-import org.apache.ignite.Ignite;
-import org.apache.ignite.IgniteCache;
-import org.apache.ignite.cache.CacheAtomicityMode;
-import org.apache.ignite.cache.CacheWriteSynchronizationMode;
-import org.apache.ignite.compatibility.persistence.IgnitePersistenceCompatibilityAbstractTest;
-import org.apache.ignite.configuration.CacheConfiguration;
-import org.apache.ignite.configuration.DataRegionConfiguration;
-import org.apache.ignite.configuration.DataStorageConfiguration;
-import org.apache.ignite.configuration.IgniteConfiguration;
-import org.apache.ignite.configuration.MemoryConfiguration;
-import org.apache.ignite.configuration.PersistentStoreConfiguration;
-import org.apache.ignite.configuration.WALMode;
-import org.apache.ignite.internal.IgniteEx;
-import org.apache.ignite.internal.IgniteInterruptedCheckedException;
-import org.apache.ignite.internal.processors.cache.GridCacheAbstractFullApiSelfTest;
-import org.apache.ignite.internal.processors.cache.persistence.migration.UpgradePendingTreeToPerPartitionTask;
-import org.apache.ignite.internal.util.typedef.PA;
-import org.apache.ignite.lang.IgniteFuture;
-import org.apache.ignite.lang.IgniteInClosure;
-import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
-import org.apache.ignite.testframework.GridTestUtils;
-
-/**
- * Test PendingTree upgrading to per-partition basis. Test fill cache with persistence enabled and with ExpirePolicy
- * configured on ignite-2.1 version and check if entries will be correctly expired when a new version node started.
- *
- * Note: Test for ignite-2.3 version will always fails due to entry ttl update fails with assertion on checkpoint lock
- * check.
- */
-public class PdsWithTtlCompatibilityTest extends IgnitePersistenceCompatibilityAbstractTest {
- /** */
- static final String TEST_CACHE_NAME = PdsWithTtlCompatibilityTest.class.getSimpleName();
-
- /** */
- static final int DURATION_SEC = 10;
-
- /** */
- private static final int ENTRIES_CNT = 100;
-
- /** {@inheritDoc} */
- @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
- IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
-
- cfg.setPeerClassLoadingEnabled(false);
-
- cfg.setDataStorageConfiguration(
- new DataStorageConfiguration()
- .setDefaultDataRegionConfiguration(
- new DataRegionConfiguration()
- .setMaxSize(32L * 1024 * 1024)
- .setPersistenceEnabled(true)
- .setCheckpointPageBufferSize(16L * 1024 * 1024)
- ).setWalMode(WALMode.LOG_ONLY));
-
- return cfg;
- }
-
- /**
- * Tests opportunity to read data from previous Ignite DB version.
- *
- * @throws Exception If failed.
- */
- public void testNodeStartByOldVersionPersistenceData_2_1() throws Exception {
- doTestStartupWithOldVersion("2.1.0");
- }
-
- /**
- * Tests opportunity to read data from previous Ignite DB version.
- *
- * @param igniteVer 3-digits version of ignite
- * @throws Exception If failed.
- */
- protected void doTestStartupWithOldVersion(String igniteVer) throws Exception {
- try {
- startGrid(1, igniteVer, new ConfigurationClosure(), new PostStartupClosure());
-
- stopAllGrids();
-
- IgniteEx ignite = startGrid(0);
-
- assertEquals(1, ignite.context().discovery().topologyVersion());
-
- ignite.active(true);
-
- validateResultingCacheData(ignite, ignite.cache(TEST_CACHE_NAME));
- }
- finally {
- stopAllGrids();
- }
- }
-
- /**
- * @param cache to be filled by different keys and values. Results may be validated in {@link
- * #validateResultingCacheData(Ignite, IgniteCache)}.
- */
- public static void saveCacheData(Cache cache) {
- for (int i = 0; i < ENTRIES_CNT; i++)
- cache.put(i, "data-" + i);
-
- //Touch
- for (int i = 0; i < ENTRIES_CNT; i++)
- assertNotNull(cache.get(i));
- }
-
- /**
- * Asserts cache contained all expected values as it was saved before.
- *
- * @param cache cache should be filled using {@link #saveCacheData(Cache)}.
- */
- public static void validateResultingCacheData(Ignite ignite,
- IgniteCache cache) throws IgniteInterruptedCheckedException {
-
- final long expireTime = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(DURATION_SEC + 1);
-
- final IgniteFuture> future = ignite.compute().broadcastAsync(new UpgradePendingTreeToPerPartitionTask());
-
- GridTestUtils.waitForCondition(new PA() {
- @Override public boolean apply() {
- return future.isDone() && expireTime < System.currentTimeMillis();
- }
- }, TimeUnit.SECONDS.toMillis(DURATION_SEC + 2));
-
- for (Boolean res : future.get())
- assertTrue(res);
-
- for (int i = 0; i < ENTRIES_CNT; i++)
- assertNull(cache.get(i));
- }
-
- /** */
- public static class ConfigurationClosure implements IgniteInClosure {
- /** {@inheritDoc} */
- @Override public void apply(IgniteConfiguration cfg) {
- cfg.setLocalHost("127.0.0.1");
-
- TcpDiscoverySpi disco = new TcpDiscoverySpi();
- disco.setIpFinder(GridCacheAbstractFullApiSelfTest.LOCAL_IP_FINDER);
-
- cfg.setDiscoverySpi(disco);
-
- cfg.setPeerClassLoadingEnabled(false);
-
- cfg.setMemoryConfiguration(new MemoryConfiguration().setDefaultMemoryPolicySize(256L * 1024 * 1024));
- cfg.setPersistentStoreConfiguration(new PersistentStoreConfiguration().setWalMode(WALMode.LOG_ONLY)
- .setCheckpointingPageBufferSize(16L * 1024 * 1024));
- }
- }
-
- /** */
- public static class PostStartupClosure implements IgniteInClosure {
- /** {@inheritDoc} */
- @Override public void apply(Ignite ignite) {
- ignite.active(true);
-
- CacheConfiguration cacheCfg = new CacheConfiguration<>();
- cacheCfg.setName(TEST_CACHE_NAME);
- cacheCfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL);
- cacheCfg.setBackups(1);
- cacheCfg.setWriteSynchronizationMode(CacheWriteSynchronizationMode.FULL_SYNC);
- cacheCfg.setExpiryPolicyFactory(AccessedExpiryPolicy.factoryOf(new Duration(TimeUnit.SECONDS, DURATION_SEC)));
- cacheCfg.setEagerTtl(true);
- cacheCfg.setGroupName("myGroup");
-
- IgniteCache cache = ignite.createCache(cacheCfg);
-
- saveCacheData(cache);
-
- ignite.active(false);
- }
- }
-}
diff --git a/modules/compatibility/src/test/java/org/apache/ignite/compatibility/testsuites/IgniteCompatibilityBasicTestSuite.java b/modules/compatibility/src/test/java/org/apache/ignite/compatibility/testsuites/IgniteCompatibilityBasicTestSuite.java
index fcfd5a7939ca4..eaa38afdd6d61 100644
--- a/modules/compatibility/src/test/java/org/apache/ignite/compatibility/testsuites/IgniteCompatibilityBasicTestSuite.java
+++ b/modules/compatibility/src/test/java/org/apache/ignite/compatibility/testsuites/IgniteCompatibilityBasicTestSuite.java
@@ -19,7 +19,6 @@
import junit.framework.TestSuite;
import org.apache.ignite.compatibility.persistence.DummyPersistenceCompatibilityTest;
-import org.apache.ignite.compatibility.PdsWithTtlCompatibilityTest;
import org.apache.ignite.compatibility.persistence.FoldersReuseCompatibilityTest;
import org.apache.ignite.compatibility.persistence.IgniteUuidCompatibilityTest;
import org.apache.ignite.compatibility.persistence.MigratingToWalV2SerializerWithCompactionTest;
@@ -37,8 +36,6 @@ public static TestSuite suite() throws Exception {
suite.addTestSuite(DummyPersistenceCompatibilityTest.class);
- suite.addTestSuite(PdsWithTtlCompatibilityTest.class);
-
suite.addTestSuite(FoldersReuseCompatibilityTest.class);
suite.addTestSuite(MigratingToWalV2SerializerWithCompactionTest.class);
diff --git a/modules/core/src/main/java/org/apache/ignite/IgniteCluster.java b/modules/core/src/main/java/org/apache/ignite/IgniteCluster.java
index fc0e81bcae2ba..f0492f4321195 100644
--- a/modules/core/src/main/java/org/apache/ignite/IgniteCluster.java
+++ b/modules/core/src/main/java/org/apache/ignite/IgniteCluster.java
@@ -457,6 +457,21 @@ public IgniteFuture> startNodesAsync(Collecti
*/
public void active(boolean active);
+ /**
+ * Checks Ignite grid is in read-only mode or not.
+ *
+ * @return {@code True} if grid is in read-only mode and {@code False} otherwise.
+ */
+ public boolean readOnly();
+
+ /**
+ * Enable or disable Ignite grid read-only mode.
+ *
+ * @param readOnly If {@code True} enable read-only mode. If {@code False} disable read-only mode.
+ * @throws IgniteException If Ignite grid isn't active.
+ */
+ public void readOnly(boolean readOnly) throws IgniteException;
+
/**
* Gets current baseline topology. If baseline topology was not set, will return {@code null}.
*
diff --git a/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java b/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java
index 4f8d06238099f..6d9c4cb23a128 100644
--- a/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java
+++ b/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java
@@ -17,13 +17,13 @@
package org.apache.ignite;
+import javax.net.ssl.HostnameVerifier;
import java.io.Serializable;
import java.lang.management.RuntimeMXBean;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
-import javax.net.ssl.HostnameVerifier;
import org.apache.ignite.cache.CacheEntryProcessor;
import org.apache.ignite.cluster.ClusterGroup;
import org.apache.ignite.configuration.CacheConfiguration;
@@ -33,6 +33,7 @@
import org.apache.ignite.internal.client.GridClient;
import org.apache.ignite.internal.marshaller.optimized.OptimizedMarshaller;
import org.apache.ignite.internal.processors.rest.GridRestCommand;
+import org.apache.ignite.spi.communication.tcp.TcpCommunicationMetricsListener;
import org.apache.ignite.stream.StreamTransformer;
import org.jetbrains.annotations.Nullable;
@@ -89,8 +90,12 @@ public final class IgniteSystemProperties {
/**
* If this system property is set to {@code false} - no checks for new versions will
* be performed by Ignite. By default, Ignite periodically checks for the new
- * version and prints out the message into the log if new version of Ignite is
+ * version and prints out the message into the log if a new version of Ignite is
* available for download.
+ *
+ * Update notifier enabled flag is a cluster-wide value and determined according to the local setting
+ * during the start of the first node in the cluster. The chosen value will survive the first node shutdown
+ * and will override the property value on all newly joining nodes.
*/
public static final String IGNITE_UPDATE_NOTIFIER = "IGNITE_UPDATE_NOTIFIER";
@@ -785,8 +790,10 @@ public final class IgniteSystemProperties {
*/
public static final String IGNITE_WAL_LOG_TX_RECORDS = "IGNITE_WAL_LOG_TX_RECORDS";
- /** If this property is set, {@link DataStorageConfiguration#writeThrottlingEnabled} will be overridden to true
- * independent of initial value in configuration. */
+ /**
+ * If this property is set, {@link DataStorageConfiguration#isWriteThrottlingEnabled()}
+ * will be overridden to {@code true} regardless the initial value in the configuration.
+ */
public static final String IGNITE_OVERRIDE_WRITE_THROTTLING_ENABLED = "IGNITE_OVERRIDE_WRITE_THROTTLING_ENABLED";
/**
@@ -882,6 +889,24 @@ public final class IgniteSystemProperties {
*/
public static final String IGNITE_LOADED_PAGES_BACKWARD_SHIFT_MAP = "IGNITE_LOADED_PAGES_BACKWARD_SHIFT_MAP";
+ /**
+ * Property for setup percentage of archive size for checkpoint trigger. Default value is 0.25
+ */
+ public static final String IGNITE_CHECKPOINT_TRIGGER_ARCHIVE_SIZE_PERCENTAGE = "IGNITE_CHECKPOINT_TRIGGER_ARCHIVE_SIZE_PERCENTAGE";
+
+ /**
+ * Property for setup percentage of WAL archive size to calculate threshold since which removing of old archive should be started.
+ * Default value is 0.5
+ */
+ public static final String IGNITE_THRESHOLD_WAL_ARCHIVE_SIZE_PERCENTAGE = "IGNITE_THRESHOLD_WAL_ARCHIVE_SIZE_PERCENTAGE";
+
+ /**
+ * Threshold time (in millis) to print warning to log if waiting for next wal segment took longer than the threshold.
+ *
+ * Default value is 1000 ms.
+ */
+ public static final String IGNITE_THRESHOLD_WAIT_TIME_NEXT_WAL_SEGMENT = "IGNITE_THRESHOLD_WAIT_TIME_NEXT_WAL_SEGMENT";
+
/**
* Count of WAL compressor worker threads. Default value is 4.
*/
@@ -941,7 +966,7 @@ public final class IgniteSystemProperties {
*/
public static final String IGNITE_DUMP_THREADS_ON_FAILURE = "IGNITE_DUMP_THREADS_ON_FAILURE";
- /**
+ /**
* Throttling timeout in millis which avoid excessive PendingTree access on unwind if there is nothing to clean yet.
*
* Default is 500 ms.
@@ -1004,6 +1029,13 @@ public final class IgniteSystemProperties {
*/
public static final String IGNITE_ALLOW_START_CACHES_IN_PARALLEL = "IGNITE_ALLOW_START_CACHES_IN_PARALLEL";
+ /**
+ * Allows to log additional information about all restored partitions after binary and logical recovery phases.
+ *
+ * Default is {@code true}.
+ */
+ public static final String IGNITE_RECOVERY_VERBOSE_LOGGING = "IGNITE_RECOVERY_VERBOSE_LOGGING";
+
/**
* Disables cache interceptor triggering in case of conflicts.
*
@@ -1121,6 +1153,68 @@ public final class IgniteSystemProperties {
*/
public static final String IGNITE_LOG_CLASSPATH_CONTENT_ON_STARTUP = "IGNITE_LOG_CLASSPATH_CONTENT_ON_STARTUP";
+ /**
+ * Index rebuilding parallelism level. If specified, sets the count of threads that are used for index rebuilding
+ * and can only be greater than 0, otherwise default value will be used. Maximum count of threads
+ * can't be greater than total available processors count.
+ * Default value is minimum of 4 and processors count / 4, but always greater than 0.
+ */
+ public static final String INDEX_REBUILDING_PARALLELISM = "INDEX_REBUILDING_PARALLELISM";
+
+ /** Enable write rebalnce statistics into log. Default: false */
+ public static final String IGNITE_WRITE_REBALANCE_STATISTICS = "IGNITE_WRITE_REBALANCE_STATISTICS";
+
+ /** Enable write rebalnce statistics by partitions into log. Default: false */
+ public static final String IGNITE_WRITE_REBALANCE_PARTITION_STATISTICS =
+ "IGNITE_WRITE_REBALANCE_PARTITION_STATISTICS";
+
+ /**
+ * Threshold timeout for long transactions, if transaction exceeds it, it will be dumped in log with
+ * information about how much time did it spent in system time (time while aquiring locks, preparing,
+ * commiting, etc) and user time (time when client node runs some code while holding transaction and not
+ * waiting it). Equals 0 if not set. No long transactions are dumped in log if nor this parameter
+ * neither {@link #IGNITE_TRANSACTION_TIME_DUMP_SAMPLES_COEFFICIENT} is set.
+ */
+ public static final String IGNITE_LONG_TRANSACTION_TIME_DUMP_THRESHOLD = "IGNITE_LONG_TRANSACTION_TIME_DUMP_THRESHOLD";
+
+ /**
+ * The coefficient for samples of completed transactions that will be dumped in log. Must be float value
+ * between 0.0 and 1.0 inclusive. Default value is 0.0.
+ */
+ public static final String IGNITE_TRANSACTION_TIME_DUMP_SAMPLES_COEFFICIENT =
+ "IGNITE_TRANSACTION_TIME_DUMP_SAMPLES_COEFFICIENT";
+
+ /**
+ * The limit of samples of completed transactions that will be dumped in log per second, if
+ * {@link #IGNITE_TRANSACTION_TIME_DUMP_SAMPLES_COEFFICIENT} is above 0.0. Must be integer value
+ * greater than 0. Default value is 5.
+ */
+ public static final String IGNITE_TRANSACTION_TIME_DUMP_SAMPLES_PER_SECOND_LIMIT =
+ "IGNITE_TRANSACTION_TIME_DUMP_SAMPLES_PER_SECOND_LIMIT";
+
+ /**
+ * Disables smart DR throttling. Default value is false.
+ */
+ public static final String IGNITE_DISABLE_SMART_DR_THROTTLING =
+ "IGNITE_DISABLE_SMART_DR_THROTTLING";
+
+ /** */
+ public static final String IGNITE_USE_POOL_FOR_LAZY_QUERIES = "IGNITE_USE_POOL_FOR_LAZY_QUERIES";
+
+ /**
+ * Enables logging time between request and response messages.
+ * Default: {@code false}
+ * {see {@link TcpCommunicationMetricsListener}}
+ */
+ public static final String IGNITE_ENABLE_MESSAGES_TIME_LOGGING = "IGNITE_ENABLE_MESSAGES_TIME_LOGGING";
+
+ /**
+ * Bounds for histogram metrics in milliseconds.
+ * Default: {10, 20, 40, 80, 160, 320, 500, 1000, 2000, 4000}
+ * {see {@link TcpCommunicationMetricsListener}}
+ */
+ public static final String IGNITE_COMM_SPI_TIME_HIST_BOUNDS = "IGNITE_COMM_SPI_TIME_HIST_BOUNDS";
+
/**
* Enforces singleton.
*/
diff --git a/modules/core/src/main/java/org/apache/ignite/cache/CacheMetrics.java b/modules/core/src/main/java/org/apache/ignite/cache/CacheMetrics.java
index 951b48bd1f678..714303f58129e 100644
--- a/modules/core/src/main/java/org/apache/ignite/cache/CacheMetrics.java
+++ b/modules/core/src/main/java/org/apache/ignite/cache/CacheMetrics.java
@@ -238,6 +238,7 @@ public interface CacheMetrics {
/**
* Gets number of non-{@code null} values in the cache.
+ * Note this method will always return {@code 0}
*
* @return Number of non-{@code null} values in the cache.
* @deprecated Can overflow. Use {@link CacheMetrics#getCacheSize()} instead.
@@ -254,6 +255,7 @@ public interface CacheMetrics {
/**
* Gets number of keys in the cache, possibly with {@code null} values.
+ * Note this method will always return {@code 0}
*
* @return Number of keys in the cache.
* @deprecated Can overflow. Use {@link CacheMetrics#getCacheSize()} instead.
diff --git a/modules/core/src/main/java/org/apache/ignite/cache/QueryEntity.java b/modules/core/src/main/java/org/apache/ignite/cache/QueryEntity.java
index 81fd50b8ee5fa..e20224746991b 100644
--- a/modules/core/src/main/java/org/apache/ignite/cache/QueryEntity.java
+++ b/modules/core/src/main/java/org/apache/ignite/cache/QueryEntity.java
@@ -686,13 +686,10 @@ private static QueryEntity convert(QueryEntityTypeDescriptor desc) {
* @return Type descriptor.
*/
private static QueryEntityTypeDescriptor processKeyAndValueClasses(
- Class> keyCls,
- Class> valCls
+ @NotNull Class> keyCls,
+ @NotNull Class> valCls
) {
- QueryEntityTypeDescriptor d = new QueryEntityTypeDescriptor();
-
- d.keyClass(keyCls);
- d.valueClass(valCls);
+ QueryEntityTypeDescriptor d = new QueryEntityTypeDescriptor(keyCls, valCls);
processAnnotationsInClass(true, d.keyClass(), d, null);
processAnnotationsInClass(false, d.valueClass(), d, null);
diff --git a/modules/core/src/main/java/org/apache/ignite/cache/query/ContinuousQuery.java b/modules/core/src/main/java/org/apache/ignite/cache/query/ContinuousQuery.java
index 549be542fdedf..b0ec17016a60d 100644
--- a/modules/core/src/main/java/org/apache/ignite/cache/query/ContinuousQuery.java
+++ b/modules/core/src/main/java/org/apache/ignite/cache/query/ContinuousQuery.java
@@ -30,22 +30,22 @@
/**
* API for configuring continuous cache queries.
*
- * Continuous queries allow to register a remote filter and a local listener
+ * Continuous queries allow registering a remote filter and a local listener
* for cache updates. If an update event passes the filter, it will be sent to
- * the node that executed the query and local listener will be notified.
+ * the node that executed the query, and local listener will be notified.
*
- * Additionally, you can execute initial query to get currently existing data.
+ * Additionally, you can execute an initial query to get currently existing data.
* Query can be of any type (SQL, TEXT or SCAN) and can be set via {@link #setInitialQuery(Query)}
* method.
*
* Query can be executed either on all nodes in topology using {@link IgniteCache#query(Query)}
* method, or only on the local node, if {@link Query#setLocal(boolean)} parameter is set to {@code true}.
- * Note that in case query is distributed and a new node joins, it will get the remote
- * filter for the query during discovery process before it actually joins topology,
+ * Note that if the query is distributed and a new node joins, it will get the remote
+ * filter for the query during discovery process before it actually joins a topology,
* so no updates will be missed.
*
- * As an example, suppose we have cache with {@code 'Person'} objects and we need
- * to query all persons with salary above 1000.
+ * As an example, suppose we have a cache with {@code 'Person'} objects and we need
+ * to query for all people with salary above 1000.
*
* Here is the {@code Person} class:
*
@@ -60,17 +60,17 @@
* }
*
*
- * You can create and execute continuous query like so:
+ * You can create and execute a continuous query like so:
*
- * // Create new continuous query.
+ * // Create a new continuous query.
* ContinuousQuery<Long, Person> qry = new ContinuousQuery<>();
*
- * // Initial iteration query will return all persons with salary above 1000.
+ * // Initial iteration query will return all people with salary above 1000.
* qry.setInitialQuery(new ScanQuery<>((id, p) -> p.getSalary() > 1000));
*
*
* // Callback that is called locally when update notifications are received.
- * // It simply prints out information about all created persons.
+ * // It simply prints out information about all created or modified records.
* qry.setLocalListener((evts) -> {
* for (CacheEntryEvent<? extends Long, ? extends Person> e : evts) {
* Person p = e.getValue();
@@ -79,29 +79,29 @@
* }
* });
*
- * // Continuous listener will be notified for persons with salary above 1000.
+ * // The continuous listener will be notified for people with salary above 1000.
* qry.setRemoteFilter(evt -> evt.getValue().getSalary() > 1000);
*
- * // Execute query and get cursor that iterates through initial data.
+ * // Execute the query and get a cursor that iterates through the initial data.
* QueryCursor<Cache.Entry<Long, Person>> cur = cache.query(qry);
*
- * This will execute query on all nodes that have cache you are working with and
- * listener will start to receive notifications for cache updates.
+ * This will execute query on all nodes that have the cache you are working with and
+ * listener will start receiving notifications for cache updates.
*
* To stop receiving updates call {@link QueryCursor#close()} method:
*
* cur.close();
*
- * Note that this works even if you didn't provide initial query. Cursor will
+ * Note that this works even if you didn't provide the initial query. Cursor will
* be empty in this case, but it will still unregister listeners when {@link QueryCursor#close()}
* is called.
*
* {@link IgniteAsyncCallback} annotation is supported for {@link CacheEntryEventFilter}
* (see {@link #setRemoteFilterFactory(Factory)}) and {@link CacheEntryUpdatedListener}
* (see {@link #setLocalListener(CacheEntryUpdatedListener)}).
- * If filter and/or listener are annotated with {@link IgniteAsyncCallback} then annotated callback
- * is executed in async callback pool (see {@link IgniteConfiguration#getAsyncCallbackPoolSize()})
- * and notification order is kept the same as update order for given cache key.
+ * If a filter and/or listener are annotated with {@link IgniteAsyncCallback} then the annotated callback
+ * is executed in an async callback pool (see {@link IgniteConfiguration#getAsyncCallbackPoolSize()})
+ * and a notification order is kept the same as an update order for a given cache key.
*
* @see ContinuousQueryWithTransformer
* @see IgniteAsyncCallback
@@ -130,10 +130,10 @@ public ContinuousQuery setInitialQuery(Query> initQry) {
}
/**
- * Sets local callback. This callback is called only in local node when new updates are received.
+ * Sets a local callback. This callback is called only on local node when new updates are received.
*
- * The callback predicate accepts ID of the node from where updates are received and collection
- * of received entries. Note that for removed entries value will be {@code null}.
+ * The callback predicate accepts ID of the node from where updates are received and a collection
+ * of the received entries. Note that for removed entries values will be {@code null}.
*
* If the predicate returns {@code false}, query execution will be cancelled.
*
@@ -141,7 +141,7 @@ public ContinuousQuery setInitialQuery(Query> initQry) {
* synchronization or transactional cache operations), should be executed asynchronously without
* blocking the thread that called the callback. Otherwise, you can get deadlocks.
*
- * If local listener are annotated with {@link IgniteAsyncCallback} then it is executed in async callback pool
+ * If local listener are annotated with {@link IgniteAsyncCallback} then it is executed in an async callback pool
* (see {@link IgniteConfiguration#getAsyncCallbackPoolSize()}) that allow to perform a cache operations.
*
* @param locLsnr Local callback.
@@ -157,8 +157,6 @@ public ContinuousQuery setLocalListener(CacheEntryUpdatedListener lo
}
/**
- * Gets local listener.
- *
* @return Local listener.
*/
public CacheEntryUpdatedListener getLocalListener() {
@@ -214,7 +212,7 @@ public ContinuousQuery setAutoUnsubscribe(boolean autoUnsubscribe) {
}
/**
- * Sets whether this query should be executed on local node only.
+ * Sets whether this query should be executed on a local node only.
*
* Note: backup event queues are not kept for local continuous queries. It may lead to loss of notifications in case
* of node failures. Use {@link ContinuousQuery#setRemoteFilterFactory(Factory)} to register cache event listeners
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2KeyValueIterator.java b/modules/core/src/main/java/org/apache/ignite/cache/query/QueryRetryException.java
similarity index 54%
rename from modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2KeyValueIterator.java
rename to modules/core/src/main/java/org/apache/ignite/cache/query/QueryRetryException.java
index 4bca779a5c892..1574385e79f85 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2KeyValueIterator.java
+++ b/modules/core/src/main/java/org/apache/ignite/cache/query/QueryRetryException.java
@@ -15,34 +15,21 @@
* limitations under the License.
*/
-package org.apache.ignite.internal.processors.query.h2;
+package org.apache.ignite.cache.query;
-import org.apache.ignite.IgniteCheckedException;
-import org.apache.ignite.lang.IgniteBiTuple;
-
-import java.sql.ResultSet;
+import org.apache.ignite.IgniteException;
/**
- * Special key/value iterator based on database result set.
+ * The exception is thrown if a query must be retried because database schema or topology are changed.
*/
-public class H2KeyValueIterator extends H2ResultSetIterator> {
+public class QueryRetryException extends IgniteException {
/** */
private static final long serialVersionUID = 0L;
/**
- * @param data Data array.
- * @throws IgniteCheckedException If failed.
+ * @param tableName Table name.
*/
- protected H2KeyValueIterator(ResultSet data) throws IgniteCheckedException {
- super(data, null, null, null);
- }
-
- /** {@inheritDoc} */
- @SuppressWarnings("unchecked")
- @Override protected IgniteBiTuple createRow() {
- K key = (K)row[0];
- V val = (V)row[1];
-
- return new IgniteBiTuple<>(key, val);
+ public QueryRetryException(String tableName) {
+ super("Table was modified concurrently (please retry the query): " + tableName);
}
-}
+}
\ No newline at end of file
diff --git a/modules/core/src/main/java/org/apache/ignite/configuration/DefaultCommunicationFailureResolver.java b/modules/core/src/main/java/org/apache/ignite/configuration/DefaultCommunicationFailureResolver.java
index 7db42d3b239cf..46c79cb41cb25 100644
--- a/modules/core/src/main/java/org/apache/ignite/configuration/DefaultCommunicationFailureResolver.java
+++ b/modules/core/src/main/java/org/apache/ignite/configuration/DefaultCommunicationFailureResolver.java
@@ -49,11 +49,12 @@ public class DefaultCommunicationFailureResolver implements CommunicationFailure
if (largestCluster == null)
return;
- log.info("Communication problem resolver found fully connected independent cluster ["
- + "serverNodesCnt=" + largestCluster.srvNodesCnt + ", "
- + "clientNodesCnt=" + largestCluster.connectedClients.size() + ", "
- + "totalAliveNodes=" + ctx.topologySnapshot().size() + ", "
- + "serverNodesIds=" + clusterNodeIds(largestCluster.srvNodesSet, ctx.topologySnapshot(), 1000) + "]");
+ if (log.isInfoEnabled())
+ log.info("Communication problem resolver found fully connected independent cluster ["
+ + "serverNodesCnt=" + largestCluster.srvNodesCnt + ", "
+ + "clientNodesCnt=" + largestCluster.connectedClients.size() + ", "
+ + "totalAliveNodes=" + ctx.topologySnapshot().size() + ", "
+ + "serverNodesIds=" + clusterNodeIds(largestCluster.srvNodesSet, ctx.topologySnapshot(), 1000) + "]");
keepCluster(ctx, largestCluster);
}
diff --git a/modules/core/src/main/java/org/apache/ignite/configuration/IgniteConfiguration.java b/modules/core/src/main/java/org/apache/ignite/configuration/IgniteConfiguration.java
index db0a118eb97be..ef5930cb16d97 100644
--- a/modules/core/src/main/java/org/apache/ignite/configuration/IgniteConfiguration.java
+++ b/modules/core/src/main/java/org/apache/ignite/configuration/IgniteConfiguration.java
@@ -223,6 +223,9 @@ public class IgniteConfiguration {
@SuppressWarnings("UnnecessaryBoxing")
public static final Long DFLT_FAILURE_DETECTION_TIMEOUT = new Long(10_000);
+ /** Default system worker blocked timeout in millis. */
+ public static final Long DFLT_SYS_WORKER_BLOCKED_TIMEOUT = 2 * 60 * 1000L;
+
/** Default failure detection timeout for client nodes in millis. */
@SuppressWarnings("UnnecessaryBoxing")
public static final Long DFLT_CLIENT_FAILURE_DETECTION_TIMEOUT = new Long(30_000);
@@ -433,7 +436,7 @@ public class IgniteConfiguration {
private Long failureDetectionTimeout = DFLT_FAILURE_DETECTION_TIMEOUT;
/** Timeout for blocked system workers detection. */
- private Long sysWorkerBlockedTimeout;
+ private Long sysWorkerBlockedTimeout = DFLT_SYS_WORKER_BLOCKED_TIMEOUT;
/** Failure detection timeout for client nodes. */
private Long clientFailureDetectionTimeout = DFLT_CLIENT_FAILURE_DETECTION_TIMEOUT;
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/ComputeTaskInternalFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/ComputeTaskInternalFuture.java
index 2cb3dfad5e487..6ce9001138b1b 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/ComputeTaskInternalFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/ComputeTaskInternalFuture.java
@@ -234,7 +234,7 @@ public ComputeTaskSession getTaskSession() {
/** {@inheritDoc} */
@Override public boolean cancel() throws IgniteCheckedException {
- ctx.security().authorize(ses.getTaskName(), SecurityPermission.TASK_CANCEL, null);
+ ctx.security().authorize(ses.getTaskName(), SecurityPermission.TASK_CANCEL);
if (onCancelled()) {
ctx.task().onCancelled(ses.getId());
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/GridEventConsumeHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/GridEventConsumeHandler.java
index ac568f065bcc7..7d9f74e5e6273 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/GridEventConsumeHandler.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/GridEventConsumeHandler.java
@@ -44,6 +44,8 @@
import org.apache.ignite.internal.processors.continuous.GridContinuousBatchAdapter;
import org.apache.ignite.internal.processors.continuous.GridContinuousHandler;
import org.apache.ignite.internal.processors.platform.PlatformEventFilterListener;
+import org.apache.ignite.internal.util.future.GridFinishedFuture;
+import org.apache.ignite.internal.util.future.GridFutureAdapter;
import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.internal.util.typedef.P2;
import org.apache.ignite.internal.util.typedef.T2;
@@ -92,6 +94,9 @@ class GridEventConsumeHandler implements GridContinuousHandler {
/** Listener. */
private GridLocalEventListener lsnr;
+ /** P2P unmarshalling future. */
+ private IgniteInternalFuture p2pUnmarshalFut = new GridFinishedFuture<>();
+
/**
* Required by {@link Externalizable}.
*/
@@ -142,6 +147,21 @@ public GridEventConsumeHandler() {
// No-op.
}
+ /**
+ * Performs remote filter initialization.
+ *
+ * @param filter Remote filter.
+ * @param ctx Kernal context.
+ * @throws IgniteCheckedException In case if initialization failed.
+ */
+ private void initFilter(IgnitePredicate filter, GridKernalContext ctx) throws IgniteCheckedException {
+ if (filter != null)
+ ctx.resource().injectGeneric(filter);
+
+ if (filter instanceof PlatformEventFilterListener)
+ ((PlatformEventFilterListener)filter).initialize(ctx);
+ }
+
/** {@inheritDoc} */
@Override public RegisterStatus register(final UUID nodeId, final UUID routineId, final GridKernalContext ctx)
throws IgniteCheckedException {
@@ -152,12 +172,6 @@ public GridEventConsumeHandler() {
if (cb != null)
ctx.resource().injectGeneric(cb);
- if (filter != null)
- ctx.resource().injectGeneric(filter);
-
- if (filter instanceof PlatformEventFilterListener)
- ((PlatformEventFilterListener)filter).initialize(ctx);
-
final boolean loc = nodeId.equals(ctx.localNodeId());
lsnr = new GridLocalEventListener() {
@@ -257,7 +271,18 @@ public GridEventConsumeHandler() {
if (F.isEmpty(types))
types = EVTS_ALL;
- ctx.event().addLocalEventListener(lsnr, types);
+ p2pUnmarshalFut.listen((fut) -> {
+ if (fut.error() == null) {
+ try {
+ initFilter(filter, ctx);
+ }
+ catch (IgniteCheckedException e) {
+ throw F.wrap(e);
+ }
+
+ ctx.event().addLocalEventListener(lsnr, types);
+ }
+ });
return RegisterStatus.REGISTERED;
}
@@ -382,13 +407,22 @@ public GridEventConsumeHandler() {
assert ctx.config().isPeerClassLoadingEnabled();
if (filterBytes != null) {
- GridDeployment dep = ctx.deploy().getGlobalDeployment(depInfo.deployMode(), clsName, clsName,
- depInfo.userVersion(), nodeId, depInfo.classLoaderId(), depInfo.participants(), null);
+ try {
+ GridDeployment dep = ctx.deploy().getGlobalDeployment(depInfo.deployMode(), clsName, clsName,
+ depInfo.userVersion(), nodeId, depInfo.classLoaderId(), depInfo.participants(), null);
- if (dep == null)
- throw new IgniteDeploymentCheckedException("Failed to obtain deployment for class: " + clsName);
+ if (dep == null)
+ throw new IgniteDeploymentCheckedException("Failed to obtain deployment for class: " + clsName);
+
+ filter = U.unmarshal(ctx, filterBytes, U.resolveClassLoader(dep.classLoader(), ctx.config()));
- filter = U.unmarshal(ctx, filterBytes, U.resolveClassLoader(dep.classLoader(), ctx.config()));
+ ((GridFutureAdapter)p2pUnmarshalFut).onDone();
+ }
+ catch (IgniteCheckedException e) {
+ ((GridFutureAdapter)p2pUnmarshalFut).onDone(e);
+
+ throw e;
+ }
}
}
@@ -449,6 +483,7 @@ public GridEventConsumeHandler() {
boolean b = in.readBoolean();
if (b) {
+ p2pUnmarshalFut = new GridFutureAdapter<>();
filterBytes = U.readByteArray(in);
clsName = U.readString(in);
depInfo = (GridDeploymentInfo)in.readObject();
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContext.java b/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContext.java
index c38486a27a72d..9061e9927e635 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContext.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContext.java
@@ -61,7 +61,7 @@
import org.apache.ignite.internal.processors.resource.GridResourceProcessor;
import org.apache.ignite.internal.processors.rest.GridRestProcessor;
import org.apache.ignite.internal.processors.schedule.IgniteScheduleProcessorAdapter;
-import org.apache.ignite.internal.processors.security.GridSecurityProcessor;
+import org.apache.ignite.internal.processors.security.IgniteSecurity;
import org.apache.ignite.internal.processors.segmentation.GridSegmentationProcessor;
import org.apache.ignite.internal.processors.service.GridServiceProcessor;
import org.apache.ignite.internal.processors.session.GridTaskSessionProcessor;
@@ -405,11 +405,11 @@ public interface GridKernalContext extends Iterable {
public GridCollisionManager collision();
/**
- * Gets authentication processor.
+ * Gets instance of {@link IgniteSecurity}.
*
- * @return Authentication processor.
+ * @return Ignite security.
*/
- public GridSecurityProcessor security();
+ public IgniteSecurity security();
/**
* Gets load balancing manager.
@@ -620,6 +620,13 @@ public interface GridKernalContext extends Iterable {
*/
public ExecutorService getSchemaExecutorService();
+ /**
+ * Executor service that is in charge of processing rebalance messages.
+ *
+ * @return Executor service that is in charge of processing rebalance messages.
+ */
+ public ExecutorService getRebalanceExecutorService();
+
/**
* Gets exception registry.
*
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java
index b05d10913cb9d..8bdbf8a5dff3b 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java
@@ -80,7 +80,7 @@
import org.apache.ignite.internal.processors.resource.GridResourceProcessor;
import org.apache.ignite.internal.processors.rest.GridRestProcessor;
import org.apache.ignite.internal.processors.schedule.IgniteScheduleProcessorAdapter;
-import org.apache.ignite.internal.processors.security.GridSecurityProcessor;
+import org.apache.ignite.internal.processors.security.IgniteSecurity;
import org.apache.ignite.internal.processors.segmentation.GridSegmentationProcessor;
import org.apache.ignite.internal.processors.service.GridServiceProcessor;
import org.apache.ignite.internal.processors.session.GridTaskSessionProcessor;
@@ -157,7 +157,7 @@ public class GridKernalContextImpl implements GridKernalContext, Externalizable
/** */
@GridToStringExclude
- private GridSecurityProcessor securityProc;
+ private IgniteSecurity security;
/** */
@GridToStringExclude
@@ -362,7 +362,11 @@ public class GridKernalContextImpl implements GridKernalContext, Externalizable
/** */
@GridToStringExclude
- Map customExecSvcs;
+ protected ExecutorService rebalanceExecSvc;
+
+ /** */
+ @GridToStringExclude
+ private Map customExecSvcs;
/** */
@GridToStringExclude
@@ -449,6 +453,7 @@ public GridKernalContextImpl() {
* @param callbackExecSvc Callback executor service.
* @param qryExecSvc Query executor service.
* @param schemaExecSvc Schema executor service.
+ * @param rebalanceExecSvc Rebalance executor service.
* @param customExecSvcs Custom named executors.
* @param plugins Plugin providers.
* @param workerRegistry Worker registry.
@@ -476,6 +481,7 @@ protected GridKernalContextImpl(
IgniteStripedThreadPoolExecutor callbackExecSvc,
ExecutorService qryExecSvc,
ExecutorService schemaExecSvc,
+ ExecutorService rebalanceExecSvc,
@Nullable Map customExecSvcs,
List plugins,
IgnitePredicate clsFilter,
@@ -505,6 +511,7 @@ protected GridKernalContextImpl(
this.callbackExecSvc = callbackExecSvc;
this.qryExecSvc = qryExecSvc;
this.schemaExecSvc = schemaExecSvc;
+ this.rebalanceExecSvc = rebalanceExecSvc;
this.customExecSvcs = customExecSvcs;
this.workersRegistry = workerRegistry;
this.hnd = hnd;
@@ -567,8 +574,6 @@ else if (comp instanceof GridFailoverManager)
failoverMgr = (GridFailoverManager)comp;
else if (comp instanceof GridCollisionManager)
colMgr = (GridCollisionManager)comp;
- else if (comp instanceof GridSecurityProcessor)
- securityProc = (GridSecurityProcessor)comp;
else if (comp instanceof GridLoadBalancerManager)
loadMgr = (GridLoadBalancerManager)comp;
else if (comp instanceof GridIndexingManager)
@@ -643,6 +648,8 @@ else if (comp instanceof GridInternalSubscriptionProcessor)
internalSubscriptionProc = (GridInternalSubscriptionProcessor)comp;
else if (comp instanceof IgniteAuthenticationProcessor)
authProc = (IgniteAuthenticationProcessor)comp;
+ else if (comp instanceof IgniteSecurity)
+ security = (IgniteSecurity)comp;
else if (comp instanceof DiagnosticProcessor)
diagnosticProcessor = (DiagnosticProcessor)comp;
else if (!(comp instanceof DiscoveryNodeValidationProcessor
@@ -803,8 +810,8 @@ else if (helper instanceof HadoopHelper)
}
/** {@inheritDoc} */
- @Override public GridSecurityProcessor security() {
- return securityProc;
+ @Override public IgniteSecurity security() {
+ return security;
}
/** {@inheritDoc} */
@@ -1087,6 +1094,11 @@ protected Object readResolve() throws ObjectStreamException {
return schemaExecSvc;
}
+ /** {@inheritDoc} */
+ @Override public ExecutorService getRebalanceExecutorService() {
+ return rebalanceExecSvc;
+ }
+
/** {@inheritDoc} */
@Override public Map customExecutors() {
return customExecSvcs;
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/GridMessageListenHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/GridMessageListenHandler.java
index c146eca255aba..688ca17fad53b 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/GridMessageListenHandler.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/GridMessageListenHandler.java
@@ -25,12 +25,15 @@
import java.util.Map;
import java.util.UUID;
import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.IgniteException;
import org.apache.ignite.internal.managers.deployment.GridDeployment;
import org.apache.ignite.internal.managers.deployment.GridDeploymentInfoBean;
import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
import org.apache.ignite.internal.processors.continuous.GridContinuousBatch;
import org.apache.ignite.internal.processors.continuous.GridContinuousBatchAdapter;
import org.apache.ignite.internal.processors.continuous.GridContinuousHandler;
+import org.apache.ignite.internal.util.future.GridFinishedFuture;
+import org.apache.ignite.internal.util.future.GridFutureAdapter;
import org.apache.ignite.internal.util.lang.GridPeerDeployAware;
import org.apache.ignite.internal.util.typedef.T2;
import org.apache.ignite.internal.util.typedef.internal.S;
@@ -66,6 +69,9 @@ public class GridMessageListenHandler implements GridContinuousHandler {
/** */
private boolean depEnabled;
+ /** P2P unmarshalling future. */
+ private IgniteInternalFuture p2pUnmarshalFut = new GridFinishedFuture<>();
+
/**
* Required by {@link Externalizable}.
*/
@@ -84,22 +90,6 @@ public GridMessageListenHandler(@Nullable Object topic, IgniteBiPredicate {
+ if (fut.error() == null)
+ ctx.io().addUserMessageListener(topic, pred, nodeId);
+ });
return RegisterStatus.REGISTERED;
}
@@ -180,18 +172,27 @@ public GridMessageListenHandler(GridMessageListenHandler orig) {
assert ctx != null;
assert ctx.config().isPeerClassLoadingEnabled();
- GridDeployment dep = ctx.deploy().getGlobalDeployment(depInfo.deployMode(), clsName, clsName,
- depInfo.userVersion(), nodeId, depInfo.classLoaderId(), depInfo.participants(), null);
+ try {
+ GridDeployment dep = ctx.deploy().getGlobalDeployment(depInfo.deployMode(), clsName, clsName,
+ depInfo.userVersion(), nodeId, depInfo.classLoaderId(), depInfo.participants(), null);
- if (dep == null)
- throw new IgniteDeploymentCheckedException("Failed to obtain deployment for class: " + clsName);
+ if (dep == null)
+ throw new IgniteDeploymentCheckedException("Failed to obtain deployment for class: " + clsName);
+
+ ClassLoader ldr = dep.classLoader();
- ClassLoader ldr = dep.classLoader();
+ if (topicBytes != null)
+ topic = U.unmarshal(ctx, topicBytes, U.resolveClassLoader(ldr, ctx.config()));
- if (topicBytes != null)
- topic = U.unmarshal(ctx, topicBytes, U.resolveClassLoader(ldr, ctx.config()));
+ pred = U.unmarshal(ctx, predBytes, U.resolveClassLoader(ldr, ctx.config()));
+ }
+ catch (IgniteCheckedException | IgniteException e) {
+ ((GridFutureAdapter)p2pUnmarshalFut).onDone(e);
+
+ throw e;
+ }
- pred = U.unmarshal(ctx, predBytes, U.resolveClassLoader(ldr, ctx.config()));
+ ((GridFutureAdapter)p2pUnmarshalFut).onDone();
}
/** {@inheritDoc} */
@@ -250,6 +251,7 @@ public GridMessageListenHandler(GridMessageListenHandler orig) {
depEnabled = in.readBoolean();
if (depEnabled) {
+ p2pUnmarshalFut = new GridFutureAdapter<>();
topicBytes = U.readByteArray(in);
predBytes = U.readByteArray(in);
clsName = U.readString(in);
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgniteEventsImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/IgniteEventsImpl.java
index 030e2dbe05956..f19fd4e56142f 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/IgniteEventsImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/IgniteEventsImpl.java
@@ -172,6 +172,9 @@ public IgniteEventsImpl(GridKernalContext ctx, ClusterGroupAdapter prj, boolean
autoUnsubscribe,
prj.predicate()));
}
+ catch (IgniteCheckedException e) {
+ throw U.convertException(e);
+ }
finally {
unguard();
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgniteFeatures.java b/modules/core/src/main/java/org/apache/ignite/internal/IgniteFeatures.java
index 188a538a998cd..9ec670dfad761 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/IgniteFeatures.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/IgniteFeatures.java
@@ -22,6 +22,7 @@
import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi;
import org.apache.ignite.spi.communication.tcp.messages.HandshakeWaitMessage;
+import static org.apache.ignite.IgniteSystemProperties.getBoolean;
import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_IGNITE_FEATURES;
/**
@@ -55,8 +56,34 @@ public enum IgniteFeatures {
/** Command which allow to detect and cleanup garbage which could left after destroying caches in shared groups */
FIND_AND_DELETE_GARBAGE_COMMAND(8),
+ /** Support of cluster read-only mode. */
+ CLUSTER_READ_ONLY_MODE(9),
+
/** Supports tracking update counter for transactions. */
- TX_TRACKING_UPDATE_COUNTER(12);
+ TX_TRACKING_UPDATE_COUNTER(12),
+
+ /** Distributed metastorage. */
+ IGNITE_SECURITY_PROCESSOR(13),
+
+ /** Replacing TcpDiscoveryNode field with nodeId field in discovery messages. */
+ TCP_DISCOVERY_MESSAGE_NODE_COMPACT_REPRESENTATION(14),
+
+ /** LRT system and user time dump settings. */
+ LRT_SYSTEM_USER_TIME_DUMP_SETTINGS(18),
+
+ /**
+ * A mode when data nodes throttle update rate regarding to DR sender load
+ */
+ DR_DATA_NODE_SMART_THROTTLING(19),
+
+ /** Support of DR events from Web Console. */
+ WC_DR_EVENTS(20),
+
+ /** Support of chain parameter in snapshot delete task for Web Console. */
+ WC_SNAPSHOT_CHAIN_MODE(22),
+
+ /** Support of DR-specific visor tasks used by control utility. */
+ DR_CONTROL_UTILITY(25);
/**
* Unique feature identifier.
@@ -101,6 +128,9 @@ public static boolean nodeSupports(ClusterNode clusterNode, IgniteFeatures featu
* @return {@code True} if feature is declared to be supported by remote node.
*/
public static boolean nodeSupports(byte[] featuresAttrBytes, IgniteFeatures feature) {
+ if (featuresAttrBytes == null)
+ return false;
+
int featureId = feature.getFeatureId();
// Same as "BitSet.valueOf(features).get(featureId)"
@@ -139,6 +169,10 @@ public static byte[] allFeatures() {
final BitSet set = new BitSet();
for (IgniteFeatures value : IgniteFeatures.values()) {
+ // After rolling upgrade, our security has more strict validation. This may come as a surprise to customers.
+ if (IGNITE_SECURITY_PROCESSOR == value && !getBoolean(IGNITE_SECURITY_PROCESSOR.name(), false))
+ continue;
+
final int featureId = value.getFeatureId();
assert !set.get(featureId) : "Duplicate feature ID found for [" + value + "] having same ID ["
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
index 867d6039ae0f7..0e30ae3b5a721 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
@@ -161,6 +161,9 @@
import org.apache.ignite.internal.processors.resource.GridSpringResourceContext;
import org.apache.ignite.internal.processors.rest.GridRestProcessor;
import org.apache.ignite.internal.processors.security.GridSecurityProcessor;
+import org.apache.ignite.internal.processors.security.IgniteSecurityProcessor;
+import org.apache.ignite.internal.processors.security.IgniteSecurity;
+import org.apache.ignite.internal.processors.security.NoOpIgniteSecurityProcessor;
import org.apache.ignite.internal.processors.segmentation.GridSegmentationProcessor;
import org.apache.ignite.internal.processors.service.GridServiceProcessor;
import org.apache.ignite.internal.processors.session.GridTaskSessionProcessor;
@@ -171,6 +174,7 @@
import org.apache.ignite.internal.suggestions.JvmConfigurationSuggestions;
import org.apache.ignite.internal.suggestions.OsConfigurationSuggestions;
import org.apache.ignite.internal.util.StripedExecutor;
+import org.apache.ignite.internal.util.TimeBag;
import org.apache.ignite.internal.util.future.GridCompoundFuture;
import org.apache.ignite.internal.util.future.GridFinishedFuture;
import org.apache.ignite.internal.util.future.GridFutureAdapter;
@@ -218,6 +222,7 @@
import static org.apache.ignite.IgniteSystemProperties.IGNITE_SKIP_CONFIGURATION_CONSISTENCY_CHECK;
import static org.apache.ignite.IgniteSystemProperties.IGNITE_STARVATION_CHECK_INTERVAL;
import static org.apache.ignite.IgniteSystemProperties.IGNITE_SUCCESS_FILE;
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_USE_POOL_FOR_LAZY_QUERIES;
import static org.apache.ignite.IgniteSystemProperties.getBoolean;
import static org.apache.ignite.IgniteSystemProperties.snapshot;
import static org.apache.ignite.internal.GridKernalState.DISCONNECTED;
@@ -264,6 +269,7 @@
import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_SPI_CLASS;
import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_TX_CONFIG;
import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_USER_NAME;
+import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_USE_POOL_FOR_LAZY_QUERIES;
import static org.apache.ignite.internal.IgniteVersionUtils.ACK_VER_STR;
import static org.apache.ignite.internal.IgniteVersionUtils.BUILD_TSTAMP_STR;
import static org.apache.ignite.internal.IgniteVersionUtils.COPYRIGHT;
@@ -863,6 +869,7 @@ private void ackClassPathContent() {
* @param callbackExecSvc Callback executor service.
* @param qryExecSvc Query executor service.
* @param schemaExecSvc Schema executor service.
+ * @param rebalanceExecSvc Rebalance excutor service.
* @param customExecSvcs Custom named executors.
* @param errHnd Error handler to use for notification about startup problems.
* @param workerRegistry Worker registry.
@@ -887,10 +894,12 @@ public void start(
IgniteStripedThreadPoolExecutor callbackExecSvc,
ExecutorService qryExecSvc,
ExecutorService schemaExecSvc,
+ ExecutorService rebalanceExecSvc,
@Nullable final Map customExecSvcs,
GridAbsClosure errHnd,
WorkersRegistry workerRegistry,
- Thread.UncaughtExceptionHandler hnd
+ Thread.UncaughtExceptionHandler hnd,
+ TimeBag startTimer
)
throws IgniteCheckedException {
gw.compareAndSet(null, new GridKernalGatewayImpl(cfg.getIgniteInstanceName()));
@@ -1008,6 +1017,7 @@ public void start(
callbackExecSvc,
qryExecSvc,
schemaExecSvc,
+ rebalanceExecSvc,
customExecSvcs,
plugins,
MarshallerUtils.classNameFilter(this.getClass().getClassLoader()),
@@ -1079,7 +1089,7 @@ public void start(
startProcessor(new GridTimeoutProcessor(ctx));
// Start security processors.
- startProcessor(createComponent(GridSecurityProcessor.class, ctx));
+ startProcessor(securityProcessor());
// Start SPI managers.
// NOTE: that order matters as there are dependencies between managers.
@@ -1108,7 +1118,13 @@ public void start(
startProcessor(createComponent(DiscoveryNodeValidationProcessor.class, ctx));
startProcessor(new GridAffinityProcessor(ctx));
startProcessor(createComponent(GridSegmentationProcessor.class, ctx));
+
+ startTimer.finishGlobalStage("Start managers");
+
startProcessor(createComponent(IgniteCacheObjectProcessor.class, ctx));
+
+ startTimer.finishGlobalStage("Configure binary metadata");
+
startProcessor(createComponent(IGridClusterStateProcessor.class, ctx));
startProcessor(new IgniteAuthenticationProcessor(ctx));
startProcessor(new GridCacheProcessor(ctx));
@@ -1128,11 +1144,15 @@ public void start(
startProcessor(createComponent(PlatformProcessor.class, ctx));
startProcessor(new GridMarshallerMappingProcessor(ctx));
+ startTimer.finishGlobalStage("Start processors");
+
// Start plugins.
for (PluginProvider provider : ctx.plugins().allProviders()) {
ctx.add(new GridPluginComponent(provider));
provider.start(ctx.plugins().pluginContextForProvider(provider));
+
+ startTimer.finishGlobalStage("Start '"+ provider.name() + "' plugin");
}
// Start platform plugins.
@@ -1143,9 +1163,11 @@ public void start(
fillNodeAttributes(clusterProc.updateNotifierEnabled());
- ctx.cache().context().database().startMemoryRestore(ctx);
+ ctx.cache().context().database().startMemoryRestore(ctx, startTimer);
ctx.recoveryMode(false);
+
+ startTimer.finishGlobalStage("Finish recovery");
}
catch (Throwable e) {
U.error(
@@ -1169,6 +1191,8 @@ public void start(
gw.writeUnlock();
}
+ startTimer.finishGlobalStage("Join topology");
+
// Check whether physical RAM is not exceeded.
checkPhysicalRam();
@@ -1206,6 +1230,8 @@ public void start(
else
active = joinData.active();
+ startTimer.finishGlobalStage("Await transition");
+
boolean recon = false;
// Callbacks.
@@ -1252,7 +1278,7 @@ public void start(
// Register MBeans.
mBeansMgr.registerAllMBeans(utilityCachePool, execSvc, svcExecSvc, sysExecSvc, stripedExecSvc, p2pExecSvc,
mgmtExecSvc, igfsExecSvc, dataStreamExecSvc, restExecSvc, affExecSvc, idxExecSvc, callbackExecSvc,
- qryExecSvc, schemaExecSvc, customExecSvcs, ctx.workersRegistry());
+ qryExecSvc, schemaExecSvc, rebalanceExecSvc, customExecSvcs, ctx.workersRegistry());
// Lifecycle bean notifications.
notifyLifecycleBeans(AFTER_NODE_START);
@@ -1416,7 +1442,8 @@ private long checkPoolStarvation(
dblFmt.format(freeNonHeapPct) + "%, comm=" + dblFmt.format(nonHeapCommInMBytes) + "MB]" + NL +
" ^-- Outbound messages queue [size=" + m.getOutboundMessagesQueueSize() + "]" + NL +
" ^-- " + createExecutorDescription("Public thread pool", execSvc) + NL +
- " ^-- " + createExecutorDescription("System thread pool", sysExecSvc);
+ " ^-- " + createExecutorDescription("System thread pool", sysExecSvc) + NL +
+ " ^-- " + createExecutorDescription("Striped thread pool", stripedExecSvc);
if (customExecSvcs != null) {
StringBuilder customSvcsMsg = new StringBuilder();
@@ -1472,6 +1499,19 @@ private long checkPoolStarvation(
if (!isDaemon())
ctx.discovery().ackTopology(ctx.discovery().localJoin().joinTopologyVersion().topologyVersion(),
EventType.EVT_NODE_JOINED, localNode());
+
+ startTimer.finishGlobalStage("Await exchange");
+ }
+
+ /**
+ * @return GridProcessor that implements {@link IgniteSecurity}
+ */
+ private GridProcessor securityProcessor() throws IgniteCheckedException {
+ GridSecurityProcessor prc = createComponent(GridSecurityProcessor.class, ctx);
+
+ return prc != null && prc.enabled()
+ ? new IgniteSecurityProcessor(ctx, prc)
+ : new NoOpIgniteSecurityProcessor(ctx, prc);
}
/**
@@ -1481,19 +1521,26 @@ private long checkPoolStarvation(
* @param execSvc service to create a description for
*/
private String createExecutorDescription(String execSvcName, ExecutorService execSvc) {
+ int poolSize = 0;
int poolActiveThreads = 0;
- int poolIdleThreads = 0;
int poolQSize = 0;
if (execSvc instanceof ThreadPoolExecutor) {
ThreadPoolExecutor exec = (ThreadPoolExecutor)execSvc;
- int poolSize = exec.getPoolSize();
-
+ poolSize = exec.getPoolSize();
poolActiveThreads = Math.min(poolSize, exec.getActiveCount());
- poolIdleThreads = poolSize - poolActiveThreads;
poolQSize = exec.getQueue().size();
}
+ else if (execSvc instanceof StripedExecutor) {
+ StripedExecutor exec = (StripedExecutor) execSvc;
+
+ poolSize = exec.stripes();
+ poolActiveThreads = exec.activeStripesCount();
+ poolQSize = exec.queueSize();
+ }
+
+ int poolIdleThreads = poolSize - poolActiveThreads;
return execSvcName + " [active=" + poolActiveThreads + ", idle=" + poolIdleThreads + ", qSize=" + poolQSize + "]";
}
@@ -1652,6 +1699,7 @@ private void suggestOptimizations(IgniteConfiguration cfg) {
private void fillNodeAttributes(boolean notifyEnabled) throws IgniteCheckedException {
ctx.addNodeAttribute(ATTR_REBALANCE_POOL_SIZE, configuration().getRebalanceThreadPoolSize());
ctx.addNodeAttribute(ATTR_DATA_STREAMER_POOL_SIZE, configuration().getDataStreamerThreadPoolSize());
+ ctx.addNodeAttribute(ATTR_USE_POOL_FOR_LAZY_QUERIES, IgniteSystemProperties.getBoolean(IGNITE_USE_POOL_FOR_LAZY_QUERIES));
final String[] incProps = cfg.getIncludeProperties();
@@ -2565,10 +2613,6 @@ private void ackRebalanceConfiguration() throws IgniteCheckedException {
U.warn(log, "Setting the rebalance pool size has no effect on the client mode");
}
else {
- if (cfg.getSystemThreadPoolSize() <= cfg.getRebalanceThreadPoolSize())
- throw new IgniteCheckedException("Rebalance thread pool size exceed or equals System thread pool size. " +
- "Change IgniteConfiguration.rebalanceThreadPoolSize property before next start.");
-
if (cfg.getRebalanceThreadPoolSize() < 1)
throw new IgniteCheckedException("Rebalance thread pool size minimal allowed value is 1. " +
"Change IgniteConfiguration.rebalanceThreadPoolSize property before next start.");
@@ -3566,6 +3610,7 @@ public IgniteInternalFuture> getOrCreateCacheAsync(String cacheName, String te
Ignition.stop(igniteInstanceName, true);
}
+ /** {@inheritDoc} */
@Override public Affinity affinity(String cacheName) {
CU.validateCacheName(cacheName);
checkClusterState();
@@ -4086,6 +4131,9 @@ private static T createComponent(Class cls, GridKer
if (cls.equals(IGridClusterStateProcessor.class))
return (T)new GridClusterStateProcessor(ctx);
+ if(cls.equals(GridSecurityProcessor.class))
+ return null;
+
Class implCls = null;
try {
@@ -4279,6 +4327,24 @@ void waitPreviousReconnect() {
ctx.cluster().get().clearNodeMap();
}
+ /** {@inheritDoc} */
+ @Override public boolean readOnlyMode() {
+ return ctx.state().publicApiReadOnlyMode();
+ }
+
+ /** {@inheritDoc} */
+ @Override public void readOnlyMode(boolean readOnly) {
+ ctx.state().changeGlobalState(readOnly);
+ }
+
+ /** {@inheritDoc} */
+ @Override public long getReadOnlyModeDuration() {
+ if (ctx.state().publicApiReadOnlyMode())
+ return U.currentTimeMillis() - ctx.state().readOnlyModeStateChangeTime();
+ else
+ return 0;
+ }
+
/** {@inheritDoc} */
@Override public String toString() {
return S.toString(IgniteKernal.class, this);
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgniteMessagingImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/IgniteMessagingImpl.java
index 4c23dd5a24397..8d992a870ade1 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/IgniteMessagingImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/IgniteMessagingImpl.java
@@ -241,6 +241,9 @@ private void send0(@Nullable Object topic, Collection> msgs, boolean async) th
false,
prj.predicate()));
}
+ catch (IgniteCheckedException e) {
+ throw U.convertException(e);
+ }
finally {
unguard();
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgniteNodeAttributes.java b/modules/core/src/main/java/org/apache/ignite/internal/IgniteNodeAttributes.java
index da791fd84813f..802e6262cf0e4 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/IgniteNodeAttributes.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/IgniteNodeAttributes.java
@@ -211,6 +211,8 @@ public final class IgniteNodeAttributes {
/** Supported features. */
public static final String ATTR_IGNITE_FEATURES = ATTR_PREFIX + ".features";
+ /** */
+ public static final String ATTR_USE_POOL_FOR_LAZY_QUERIES = ATTR_PREFIX + ".query.lazy.usepool";
/**
* Enforces singleton.
*/
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java b/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java
index 641dde3cf34d9..ca76464009cb2 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java
@@ -17,6 +17,9 @@
package org.apache.ignite.internal;
+import javax.management.JMException;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@@ -46,9 +49,6 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Handler;
-import javax.management.JMException;
-import javax.management.MBeanServer;
-import javax.management.ObjectName;
import org.apache.ignite.Ignite;
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.IgniteException;
@@ -84,6 +84,7 @@
import org.apache.ignite.internal.util.GridConcurrentHashSet;
import org.apache.ignite.internal.util.IgniteUtils;
import org.apache.ignite.internal.util.StripedExecutor;
+import org.apache.ignite.internal.util.TimeBag;
import org.apache.ignite.internal.util.spring.IgniteSpringHelper;
import org.apache.ignite.internal.util.typedef.CA;
import org.apache.ignite.internal.util.typedef.F;
@@ -125,6 +126,7 @@
import org.apache.ignite.thread.IgniteThreadPoolExecutor;
import org.jetbrains.annotations.Nullable;
+import static java.util.stream.Collectors.joining;
import static org.apache.ignite.IgniteState.STARTED;
import static org.apache.ignite.IgniteState.STOPPED;
import static org.apache.ignite.IgniteState.STOPPED_ON_FAILURE;
@@ -138,6 +140,7 @@
import static org.apache.ignite.IgniteSystemProperties.IGNITE_RESTART_CODE;
import static org.apache.ignite.IgniteSystemProperties.IGNITE_SUCCESS_FILE;
import static org.apache.ignite.IgniteSystemProperties.IGNITE_SYSTEM_WORKER_BLOCKED_TIMEOUT;
+import static org.apache.ignite.IgniteSystemProperties.getLong;
import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
import static org.apache.ignite.cache.CacheMode.REPLICATED;
import static org.apache.ignite.cache.CacheRebalanceMode.SYNC;
@@ -1614,6 +1617,9 @@ private static final class IgniteNamedInstance {
/** Query executor service. */
private ThreadPoolExecutor schemaExecSvc;
+ /** Rebalance executor service. */
+ private ThreadPoolExecutor rebalanceExecSvc;
+
/** Executor service. */
private Map customExecSvcs;
@@ -1726,7 +1732,17 @@ synchronized void start(GridStartContext startCtx) throws IgniteCheckedException
try {
starterThread = Thread.currentThread();
- start0(startCtx);
+ IgniteConfiguration myCfg = initializeConfiguration(
+ startCtx.config() != null ? startCtx.config() : new IgniteConfiguration()
+ );
+
+ TimeBag startNodeTimer = new TimeBag(TimeUnit.MILLISECONDS);
+
+ start0(startCtx, myCfg, startNodeTimer);
+
+ if (log.isInfoEnabled())
+ log.info("Node started : "
+ + startNodeTimer.stagesTimings().stream().collect(joining(",", "[", "]")));
}
catch (Exception e) {
if (log != null)
@@ -1747,27 +1763,24 @@ synchronized void start(GridStartContext startCtx) throws IgniteCheckedException
* @throws IgniteCheckedException If start failed.
*/
@SuppressWarnings({"unchecked", "TooBroadScope"})
- private void start0(GridStartContext startCtx) throws IgniteCheckedException {
+ private void start0(GridStartContext startCtx, IgniteConfiguration cfg, TimeBag startTimer)
+ throws IgniteCheckedException {
assert grid == null : "Grid is already started: " + name;
- IgniteConfiguration cfg = startCtx.config() != null ? startCtx.config() : new IgniteConfiguration();
-
- IgniteConfiguration myCfg = initializeConfiguration(cfg);
-
// Set configuration URL, if any, into system property.
if (startCtx.configUrl() != null)
System.setProperty(IGNITE_CONFIG_URL, startCtx.configUrl().toString());
// Ensure that SPIs support multiple grid instances, if required.
if (!startCtx.single()) {
- ensureMultiInstanceSupport(myCfg.getDeploymentSpi());
- ensureMultiInstanceSupport(myCfg.getCommunicationSpi());
- ensureMultiInstanceSupport(myCfg.getDiscoverySpi());
- ensureMultiInstanceSupport(myCfg.getCheckpointSpi());
- ensureMultiInstanceSupport(myCfg.getEventStorageSpi());
- ensureMultiInstanceSupport(myCfg.getCollisionSpi());
- ensureMultiInstanceSupport(myCfg.getFailoverSpi());
- ensureMultiInstanceSupport(myCfg.getLoadBalancingSpi());
+ ensureMultiInstanceSupport(cfg.getDeploymentSpi());
+ ensureMultiInstanceSupport(cfg.getCommunicationSpi());
+ ensureMultiInstanceSupport(cfg.getDiscoverySpi());
+ ensureMultiInstanceSupport(cfg.getCheckpointSpi());
+ ensureMultiInstanceSupport(cfg.getEventStorageSpi());
+ ensureMultiInstanceSupport(cfg.getCollisionSpi());
+ ensureMultiInstanceSupport(cfg.getFailoverSpi());
+ ensureMultiInstanceSupport(cfg.getLoadBalancingSpi());
}
validateThreadPoolSize(cfg.getPublicThreadPoolSize(), "public");
@@ -1830,11 +1843,9 @@ private void start0(GridStartContext startCtx) throws IgniteCheckedException {
new IgniteException(S.toString(GridWorker.class, deadWorker))));
}
},
- IgniteSystemProperties.getLong(IGNITE_SYSTEM_WORKER_BLOCKED_TIMEOUT,
- cfg.getSystemWorkerBlockedTimeout() != null
- ? cfg.getSystemWorkerBlockedTimeout()
- : cfg.getFailureDetectionTimeout()),
- log);
+ getLong(IGNITE_SYSTEM_WORKER_BLOCKED_TIMEOUT, cfg.getSystemWorkerBlockedTimeout()),
+ log
+ );
stripedExecSvc = new StripedExecutor(
cfg.getStripedPoolSize(),
@@ -1917,16 +1928,18 @@ private void start0(GridStartContext startCtx) throws IgniteCheckedException {
cfg.getAsyncCallbackPoolSize(),
cfg.getIgniteInstanceName(),
"callback",
- oomeHnd);
+ oomeHnd,
+ false,
+ 0);
- if (myCfg.getConnectorConfiguration() != null) {
- validateThreadPoolSize(myCfg.getConnectorConfiguration().getThreadPoolSize(), "connector");
+ if (cfg.getConnectorConfiguration() != null) {
+ validateThreadPoolSize(cfg.getConnectorConfiguration().getThreadPoolSize(), "connector");
restExecSvc = new IgniteThreadPoolExecutor(
"rest",
- myCfg.getIgniteInstanceName(),
- myCfg.getConnectorConfiguration().getThreadPoolSize(),
- myCfg.getConnectorConfiguration().getThreadPoolSize(),
+ cfg.getIgniteInstanceName(),
+ cfg.getConnectorConfiguration().getThreadPoolSize(),
+ cfg.getConnectorConfiguration().getThreadPoolSize(),
DFLT_THREAD_KEEP_ALIVE_TIME,
new LinkedBlockingQueue<>(),
GridIoPolicy.UNDEFINED,
@@ -1936,14 +1949,14 @@ private void start0(GridStartContext startCtx) throws IgniteCheckedException {
restExecSvc.allowCoreThreadTimeOut(true);
}
- validateThreadPoolSize(myCfg.getUtilityCacheThreadPoolSize(), "utility cache");
+ validateThreadPoolSize(cfg.getUtilityCacheThreadPoolSize(), "utility cache");
utilityCacheExecSvc = new IgniteThreadPoolExecutor(
"utility",
cfg.getIgniteInstanceName(),
- myCfg.getUtilityCacheThreadPoolSize(),
- myCfg.getUtilityCacheThreadPoolSize(),
- myCfg.getUtilityCacheKeepAliveTime(),
+ cfg.getUtilityCacheThreadPoolSize(),
+ cfg.getUtilityCacheThreadPoolSize(),
+ cfg.getUtilityCacheKeepAliveTime(),
new LinkedBlockingQueue<>(),
GridIoPolicy.UTILITY_CACHE_POOL,
oomeHnd);
@@ -2003,6 +2016,18 @@ private void start0(GridStartContext startCtx) throws IgniteCheckedException {
schemaExecSvc.allowCoreThreadTimeOut(true);
+ validateThreadPoolSize(cfg.getRebalanceThreadPoolSize(), "rebalance");
+
+ rebalanceExecSvc = new IgniteThreadPoolExecutor(
+ "rebalance",
+ cfg.getIgniteInstanceName(),
+ cfg.getRebalanceThreadPoolSize(),
+ cfg.getRebalanceThreadPoolSize(),
+ DFLT_THREAD_KEEP_ALIVE_TIME,
+ new LinkedBlockingQueue<>(),
+ GridIoPolicy.UNDEFINED,
+ oomeHnd);
+
if (!F.isEmpty(cfg.getExecutorConfiguration())) {
validateCustomExecutorsConfiguration(cfg.getExecutorConfiguration());
@@ -2024,7 +2049,7 @@ private void start0(GridStartContext startCtx) throws IgniteCheckedException {
}
// Register Ignite MBean for current grid instance.
- registerFactoryMbean(myCfg.getMBeanServer());
+ registerFactoryMbean(cfg.getMBeanServer());
boolean started = false;
@@ -2034,8 +2059,10 @@ private void start0(GridStartContext startCtx) throws IgniteCheckedException {
// Init here to make grid available to lifecycle listeners.
grid = grid0;
+ startTimer.finishGlobalStage("Configure system pool");
+
grid0.start(
- myCfg,
+ cfg,
utilityCacheExecSvc,
execSvc,
svcExecSvc,
@@ -2051,6 +2078,7 @@ private void start0(GridStartContext startCtx) throws IgniteCheckedException {
callbackExecSvc,
qryExecSvc,
schemaExecSvc,
+ rebalanceExecSvc,
customExecSvcs,
new CA() {
@Override public void apply() {
@@ -2058,7 +2086,8 @@ private void start0(GridStartContext startCtx) throws IgniteCheckedException {
}
},
workerRegistry,
- oomeHnd
+ oomeHnd,
+ startTimer
);
state = STARTED;
@@ -2171,8 +2200,10 @@ private IgniteConfiguration initializeConfiguration(IgniteConfiguration cfg)
// If user provided IGNITE_HOME - set it as a system property.
U.setIgniteHome(ggHome);
+ String userProvidedWorkDir = cfg.getWorkDirectory();
+
// Correctly resolve work directory and set it back to configuration.
- String workDir = U.workDirectory(cfg.getWorkDirectory(), ggHome);
+ String workDir = U.workDirectory(userProvidedWorkDir, ggHome);
myCfg.setWorkDirectory(workDir);
@@ -2196,6 +2227,9 @@ private IgniteConfiguration initializeConfiguration(IgniteConfiguration cfg)
myCfg.setGridLogger(cfgLog);
+ if(F.isEmpty(userProvidedWorkDir) && F.isEmpty(U.IGNITE_WORK_DIR))
+ log.warning("Ignite work directory is not provided, automatically resolved to: " + workDir);
+
// Check Ignite home folder (after log is available).
if (ggHome != null) {
File ggHomeFile = new File(ggHome);
@@ -2678,6 +2712,10 @@ private void stopExecutors0(IgniteLogger log) {
schemaExecSvc = null;
+ U.shutdownNow(getClass(), rebalanceExecSvc, log);
+
+ rebalanceExecSvc = null;
+
U.shutdownNow(getClass(), stripedExecSvc, log);
stripedExecSvc = null;
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/TransactionMetricsMxBeanImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/TransactionMetricsMxBeanImpl.java
index 58b58672faa9d..916f5c10d990c 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/TransactionMetricsMxBeanImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/TransactionMetricsMxBeanImpl.java
@@ -99,6 +99,26 @@ public TransactionMetricsMxBeanImpl(TransactionMetrics transactionMetrics) {
@Override public long getOwnerTransactionsNumber() {
return transactionMetrics.getOwnerTransactionsNumber();
}
+
+ /** {@inheritDoc} */
+ @Override public long getTotalNodeSystemTime() {
+ return transactionMetrics.getTotalNodeSystemTime();
+ }
+
+ /** {@inheritDoc} */
+ @Override public long getTotalNodeUserTime() {
+ return transactionMetrics.getTotalNodeUserTime();
+ }
+
+ /** {@inheritDoc} */
+ @Override public String getNodeSystemTimeHistogram() {
+ return transactionMetrics.getNodeSystemTimeHistogram();
+ }
+
+ /** {@inheritDoc} */
+ @Override public String getNodeUserTimeHistogram() {
+ return transactionMetrics.getNodeUserTimeHistogram();
+ }
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/TransactionsMXBeanImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/TransactionsMXBeanImpl.java
index 1969d292cd70b..f4304396eb9b9 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/TransactionsMXBeanImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/TransactionsMXBeanImpl.java
@@ -141,6 +141,36 @@ else if ("servers".equals(prj))
ctx.cache().setTxOwnerDumpRequestsAllowed(allowed);
}
+ /** {@inheritDoc} */
+ @Override public long getLongTransactionTimeDumpThreshold() {
+ return ctx.cache().context().tm().longTransactionTimeDumpThreshold();
+ }
+
+ /** {@inheritDoc} */
+ @Override public void setLongTransactionTimeDumpThreshold(long threshold) {
+ ctx.cache().longTransactionTimeDumpThreshold(threshold);
+ }
+
+ /** {@inheritDoc} */
+ @Override public double getTransactionTimeDumpSamplesCoefficient() {
+ return ctx.cache().context().tm().transactionTimeDumpSamplesCoefficient();
+ }
+
+ /** {@inheritDoc} */
+ @Override public void setTransactionTimeDumpSamplesCoefficient(double coefficient) {
+ ctx.cache().transactionTimeDumpSamplesCoefficient(coefficient);
+ }
+
+ /** {@inheritDoc} */
+ @Override public int getTransactionTimeDumpSamplesPerSecondLimit() {
+ return ctx.cache().context().tm().transactionTimeDumpSamplesPerSecondLimit();
+ }
+
+ /** {@inheritDoc} */
+ @Override public void setTransactionTimeDumpSamplesPerSecondLimit(int limit) {
+ ctx.cache().longTransactionTimeDumpSamplesPerSecondLimit(limit);
+ }
+
/** {@inheritDoc} */
@Override public String toString() {
return S.toString(TransactionsMXBeanImpl.class, this);
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryClassDescriptor.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryClassDescriptor.java
index 7f86391d52748..e23b4f42f50ac 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryClassDescriptor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryClassDescriptor.java
@@ -404,6 +404,20 @@ boolean isEnum() {
return mode == BinaryWriteMode.ENUM;
}
+ /**
+ * @return {@code True} if the type is registered as an OBJECT.
+ */
+ boolean isObject() {
+ return mode == BinaryWriteMode.OBJECT;
+ }
+
+ /**
+ * @return {@code True} if the type is registered as a BINARY object.
+ */
+ boolean isBinary() {
+ return mode == BinaryWriteMode.BINARY;
+ }
+
/**
* @return Described class.
*/
@@ -915,6 +929,56 @@ Object read(BinaryReaderExImpl reader) throws BinaryObjectException {
}
}
+ /**
+ * @return A copy of this {@code BinaryClassDescriptor} marked as registered.
+ */
+ BinaryClassDescriptor makeRegistered() {
+ if (registered)
+ return this;
+ else
+ return new BinaryClassDescriptor(ctx,
+ cls,
+ userType,
+ typeId,
+ typeName,
+ affKeyFieldName,
+ mapper,
+ initialSerializer,
+ stableFieldsMeta != null,
+ true);
+ }
+
+ /**
+ * @return Instance of {@link BinaryMetadata} for this type.
+ */
+ BinaryMetadata metadata() {
+ return new BinaryMetadata(
+ typeId,
+ typeName,
+ stableFieldsMeta,
+ affKeyFieldName,
+ null,
+ isEnum(),
+ cls.isEnum() ? enumMap(cls) : null);
+ }
+
+ /**
+ * @param cls Enum class.
+ * @return Enum name to ordinal mapping.
+ */
+ private static Map enumMap(Class> cls) {
+ assert cls.isEnum();
+
+ Object[] enumVals = cls.getEnumConstants();
+
+ Map enumMap = new LinkedHashMap<>(enumVals.length);
+
+ for (Object enumVal : enumVals)
+ enumMap.put(((Enum)enumVal).name(), ((Enum)enumVal).ordinal());
+
+ return enumMap;
+ }
+
/**
* Pre-write phase.
*
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryContext.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryContext.java
index c263def8aae75..ca792f2c1c317 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryContext.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryContext.java
@@ -48,10 +48,6 @@
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.IgniteException;
import org.apache.ignite.IgniteLogger;
-import org.apache.ignite.internal.UnregisteredBinaryTypeException;
-import org.apache.ignite.internal.UnregisteredClassException;
-import org.apache.ignite.internal.processors.marshaller.MappingExchangeResult;
-import org.apache.ignite.internal.util.IgniteUtils;
import org.apache.ignite.binary.BinaryBasicIdMapper;
import org.apache.ignite.binary.BinaryBasicNameMapper;
import org.apache.ignite.binary.BinaryIdMapper;
@@ -69,6 +65,8 @@
import org.apache.ignite.configuration.IgniteConfiguration;
import org.apache.ignite.igfs.IgfsPath;
import org.apache.ignite.internal.DuplicateTypeIdException;
+import org.apache.ignite.internal.UnregisteredBinaryTypeException;
+import org.apache.ignite.internal.UnregisteredClassException;
import org.apache.ignite.internal.marshaller.optimized.OptimizedMarshaller;
import org.apache.ignite.internal.processors.cache.binary.BinaryMetadataKey;
import org.apache.ignite.internal.processors.closure.GridClosureProcessor;
@@ -109,10 +107,12 @@
import org.apache.ignite.internal.processors.igfs.meta.IgfsMetaFileUnlockProcessor;
import org.apache.ignite.internal.processors.igfs.meta.IgfsMetaUpdatePropertiesProcessor;
import org.apache.ignite.internal.processors.igfs.meta.IgfsMetaUpdateTimesProcessor;
+import org.apache.ignite.internal.processors.marshaller.MappingExchangeResult;
import org.apache.ignite.internal.processors.platform.PlatformJavaObjectFactoryProxy;
import org.apache.ignite.internal.processors.platform.websession.PlatformDotNetSessionData;
import org.apache.ignite.internal.processors.platform.websession.PlatformDotNetSessionLockResult;
import org.apache.ignite.internal.processors.query.QueryUtils;
+import org.apache.ignite.internal.util.IgniteUtils;
import org.apache.ignite.internal.util.lang.GridMapEntry;
import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.internal.util.typedef.T2;
@@ -121,6 +121,7 @@
import org.apache.ignite.lang.IgniteUuid;
import org.apache.ignite.marshaller.MarshallerContext;
import org.apache.ignite.marshaller.MarshallerUtils;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static org.apache.ignite.internal.MarshallerPlatformIds.JAVA_ID;
@@ -612,76 +613,112 @@ else if (cpElement.isFile()) {
}
/**
- * @param cls Class.
+ * Attempts registration of the provided class. If the type is already registered, then an existing descriptor is
+ * returned.
+ *
+ * @param cls Class to register.
+ * @param registerMeta If {@code true}, then metadata will be registered along with the class descriptor.
* @param failIfUnregistered Throw exception if class isn't registered.
* @return Class descriptor.
* @throws BinaryObjectException In case of error.
*/
- public BinaryClassDescriptor descriptorForClass(Class> cls, boolean deserialize, boolean failIfUnregistered)
- throws BinaryObjectException {
+ @NotNull public BinaryClassDescriptor registerClass(
+ Class> cls,
+ boolean registerMeta,
+ boolean failIfUnregistered
+ ) throws BinaryObjectException {
assert cls != null;
- BinaryClassDescriptor desc = descByCls.get(cls);
+ BinaryClassDescriptor desc = descriptorForClass(cls);
- if (desc == null) {
+ if (!desc.registered()) {
if (failIfUnregistered)
throw new UnregisteredClassException(cls);
-
- desc = registerClassDescriptor(cls, deserialize);
+ else
+ desc = registerDescriptor(desc, registerMeta);
}
- else if (!desc.registered()) {
- if (!desc.userType()) {
- BinaryClassDescriptor desc0 = new BinaryClassDescriptor(
- this,
- desc.describedClass(),
- false,
- desc.typeId(),
- desc.typeName(),
- desc.affFieldKeyName(),
- desc.mapper(),
- desc.initialSerializer(),
- false,
- true
- );
-
- if (descByCls.replace(cls, desc, desc0)) {
- Collection schemas =
- desc0.schema() != null ? Collections.singleton(desc.schema()) : null;
-
- BinaryMetadata meta = new BinaryMetadata(desc0.typeId(),
- desc0.typeName(),
- desc0.fieldsMeta(),
- desc0.affFieldKeyName(),
- schemas, desc0.isEnum(),
- cls.isEnum() ? enumMap(cls) : null);
-
- metaHnd.addMeta(desc0.typeId(), meta.wrap(this), false);
-
- return desc0;
- }
- }
- else {
- if (failIfUnregistered)
- throw new UnregisteredClassException(cls);
- desc = registerUserClassDescriptor(desc);
- }
+ return desc;
+ }
+
+ /**
+ * @param cls Class.
+ * @return A descriptor for the given class. If the class hasn't been registered yet, then a new descriptor will be
+ * created, but its {@link BinaryClassDescriptor#registered()} will be {@code false}.
+ */
+ @NotNull BinaryClassDescriptor descriptorForClass(Class> cls) {
+ assert cls != null;
+
+ BinaryClassDescriptor desc = descByCls.get(cls);
+
+ if (desc != null)
+ return desc;
+ else
+ return createDescriptorForClass(cls);
+ }
+
+ /**
+ * @param cls Class to create a descriptor for.
+ * @return A descriptor for the given class. The descriptor needs to be registered in order to be used.
+ */
+ @NotNull private BinaryClassDescriptor createDescriptorForClass(Class> cls) {
+ String clsName = cls.getName();
+
+ if (marshCtx.isSystemType(clsName)) {
+ BinarySerializer serializer = null;
+
+ if (BINARYLIZABLE_SYS_CLSS.contains(clsName))
+ serializer = new BinaryReflectiveSerializer();
+
+ return new BinaryClassDescriptor(this,
+ cls,
+ false,
+ clsName.hashCode(),
+ clsName,
+ null,
+ SIMPLE_NAME_LOWER_CASE_MAPPER,
+ serializer,
+ false,
+ false
+ );
}
+ else {
+ BinaryInternalMapper mapper = userTypeMapper(clsName);
- return desc;
+ final String typeName = mapper.typeName(clsName);
+
+ final int typeId = mapper.typeId(clsName);
+
+ BinarySerializer serializer = serializerForClass(cls);
+
+ String affFieldName = affinityFieldName(cls);
+
+ return new BinaryClassDescriptor(this,
+ cls,
+ true,
+ typeId,
+ typeName,
+ affFieldName,
+ mapper,
+ serializer,
+ true,
+ false
+ );
+ }
}
/**
* @param userType User type or not.
* @param typeId Type ID.
* @param ldr Class loader.
+ * @param registerMeta If {@code true}, then metadata will be registered along with the type descriptor.
* @return Class descriptor.
*/
public BinaryClassDescriptor descriptorForTypeId(
boolean userType,
int typeId,
ClassLoader ldr,
- boolean deserialize
+ boolean registerMeta
) {
assert typeId != GridBinaryMarshaller.UNREGISTERED_TYPE_ID;
@@ -703,21 +740,21 @@ public BinaryClassDescriptor descriptorForTypeId(
}
catch (ClassNotFoundException e) {
// Class might have been loaded by default class loader.
- if (userType && !ldr.equals(sysLdr) && (desc = descriptorForTypeId(true, typeId, sysLdr, deserialize)) != null)
+ if (userType && !ldr.equals(sysLdr) && (desc = descriptorForTypeId(true, typeId, sysLdr, registerMeta)) != null)
return desc;
throw new BinaryInvalidTypeException(e);
}
catch (IgniteCheckedException e) {
// Class might have been loaded by default class loader.
- if (userType && !ldr.equals(sysLdr) && (desc = descriptorForTypeId(true, typeId, sysLdr, deserialize)) != null)
+ if (userType && !ldr.equals(sysLdr) && (desc = descriptorForTypeId(true, typeId, sysLdr, registerMeta)) != null)
return desc;
throw new BinaryObjectException("Failed resolve class for ID: " + typeId, e);
}
if (desc == null) {
- desc = registerClassDescriptor(cls, deserialize);
+ desc = registerClass(cls, registerMeta, false);
assert desc.typeId() == typeId : "Duplicate typeId [typeId=" + typeId + ", cls=" + cls
+ ", desc=" + desc + "]";
@@ -727,125 +764,63 @@ public BinaryClassDescriptor descriptorForTypeId(
}
/**
- * Creates and registers {@link BinaryClassDescriptor} for the given {@code class}.
+ * Attempts registration of the provided {@link BinaryClassDescriptor} in the cluster.
*
- * @param cls Class.
- * @return Class descriptor.
+ * @param desc Class descriptor to register.
+ * @param registerMeta If {@code true}, then metadata will be registered along with the class descriptor.
+ * @return Registered class descriptor.
*/
- private BinaryClassDescriptor registerClassDescriptor(Class> cls, boolean deserialize) {
- BinaryClassDescriptor desc;
-
- String clsName = cls.getName();
-
- if (marshCtx.isSystemType(clsName)) {
- BinarySerializer serializer = null;
-
- if (BINARYLIZABLE_SYS_CLSS.contains(clsName))
- serializer = new BinaryReflectiveSerializer();
-
- desc = new BinaryClassDescriptor(this,
- cls,
- false,
- clsName.hashCode(),
- clsName,
- null,
- SIMPLE_NAME_LOWER_CASE_MAPPER,
- serializer,
- false,
- true /* registered */
- );
+ @NotNull public BinaryClassDescriptor registerDescriptor(
+ BinaryClassDescriptor desc,
+ boolean registerMeta
+ ) {
+ if (desc.userType())
+ return registerUserClassDescriptor(desc, registerMeta);
+ else {
+ BinaryClassDescriptor regDesc = desc.makeRegistered();
- BinaryClassDescriptor old = descByCls.putIfAbsent(cls, desc);
+ BinaryClassDescriptor old = descByCls.putIfAbsent(desc.describedClass(), regDesc);
- if (old != null)
- desc = old;
+ return old != null
+ ? old
+ : regDesc;
}
- else
- desc = registerUserClassDescriptor(cls, deserialize);
-
- return desc;
}
/**
- * Creates and registers {@link BinaryClassDescriptor} for the given user {@code class}.
+ * Attempts registration of the provided {@link BinaryClassDescriptor} in the cluster. The provided descriptor should correspond
+ * to a user class.
*
- * @param cls Class.
+ * @param desc Class descriptor to register.
+ * @param registerMeta If {@code true}, then metadata will be registered along with the class descriptor.
* @return Class descriptor.
*/
- private BinaryClassDescriptor registerUserClassDescriptor(Class> cls, boolean deserialize) {
- boolean registered;
-
- final String clsName = cls.getName();
-
- BinaryInternalMapper mapper = userTypeMapper(clsName);
-
- final String typeName = mapper.typeName(clsName);
-
- final int typeId = mapper.typeId(clsName);
-
- registered = registerUserClassName(typeId, cls.getName(), false);
-
- BinarySerializer serializer = serializerForClass(cls);
-
- String affFieldName = affinityFieldName(cls);
-
- BinaryClassDescriptor desc = new BinaryClassDescriptor(this,
- cls,
- true,
- typeId,
- typeName,
- affFieldName,
- mapper,
- serializer,
- true,
- registered
- );
+ @NotNull private BinaryClassDescriptor registerUserClassDescriptor(
+ BinaryClassDescriptor desc,
+ boolean registerMeta
+ ) {
+ assert desc.userType() : "The descriptor doesn't correspond to a user class.";
- if (!deserialize)
- metaHnd.addMeta(typeId, new BinaryMetadata(typeId, typeName, desc.fieldsMeta(), affFieldName, null,
- desc.isEnum(), cls.isEnum() ? enumMap(cls) : null).wrap(this), false);
+ Class> cls = desc.describedClass();
- descByCls.put(cls, desc);
+ int typeId = desc.typeId();
- typeId2Mapper.putIfAbsent(typeId, mapper);
-
- return desc;
- }
-
- /**
- * Creates and registers {@link BinaryClassDescriptor} for the given user {@code class}.
- *
- * @param desc Old descriptor that should be re-registered.
- * @return Class descriptor.
- */
- private BinaryClassDescriptor registerUserClassDescriptor(BinaryClassDescriptor desc) {
- boolean registered;
-
- registered = registerUserClassName(desc.typeId(), desc.describedClass().getName(), false);
+ boolean registered = registerUserClassName(typeId, cls.getName(), false);
if (registered) {
- BinarySerializer serializer = desc.initialSerializer();
+ BinaryClassDescriptor regDesc = desc.makeRegistered();
- if (serializer == null)
- serializer = serializerForClass(desc.describedClass());
+ if (registerMeta)
+ metaHnd.addMeta(typeId, regDesc.metadata().wrap(this), false);
- desc = new BinaryClassDescriptor(
- this,
- desc.describedClass(),
- true,
- desc.typeId(),
- desc.typeName(),
- desc.affFieldKeyName(),
- desc.mapper(),
- serializer,
- true,
- true
- );
+ descByCls.put(cls, regDesc);
- descByCls.put(desc.describedClass(), desc);
- }
+ typeId2Mapper.putIfAbsent(typeId, regDesc.mapper());
- return desc;
+ return regDesc;
+ }
+ else
+ return desc;
}
/**
@@ -1188,7 +1163,7 @@ public void registerUserTypesSchema() {
/**
* Register "type ID to class name" mapping on all nodes to allow for mapping requests resolution form client.
* Other {@link BinaryContext}'s "register" methods and method
- * {@link BinaryContext#descriptorForClass(Class, boolean, boolean)} already call this functionality
+ * {@link BinaryContext#registerClass(Class, boolean, boolean)} already call this functionality
* so use this method only when registering class names whose {@link Class} is unknown.
*
* @param typeId Type ID.
@@ -1442,24 +1417,6 @@ public void onUndeploy(ClassLoader ldr) {
U.clearClassCache(ldr);
}
- /**
- *
- * @param cls Class
- * @return Enum name to ordinal mapping.
- */
- private static Map enumMap(Class> cls) {
- assert cls.isEnum();
-
- Object[] enumVals = cls.getEnumConstants();
-
- Map enumMap = new LinkedHashMap<>(enumVals.length);
-
- for (Object enumVal : enumVals)
- enumMap.put(((Enum)enumVal).name(), ((Enum)enumVal).ordinal());
-
- return enumMap;
- }
-
/**
* Type descriptors.
*/
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryEnumObjectImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryEnumObjectImpl.java
index 275169561fd56..96d0551fa96da 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryEnumObjectImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryEnumObjectImpl.java
@@ -176,7 +176,7 @@ public BinaryEnumObjectImpl(BinaryContext ctx, byte[] arr) {
/** {@inheritDoc} */
@SuppressWarnings("unchecked")
@Override public T deserialize() throws BinaryObjectException {
- Class cls = BinaryUtils.resolveClass(ctx, typeId, clsName, ctx.configuration().getClassLoader(), true);
+ Class cls = BinaryUtils.resolveClass(ctx, typeId, clsName, ctx.configuration().getClassLoader(), false);
return (T)BinaryEnumCache.get(cls, ord);
}
@@ -430,13 +430,4 @@ public BinaryEnumObjectImpl(BinaryContext ctx, byte[] arr) {
return reader.afterMessageRead(BinaryEnumObjectImpl.class);
}
-
- /**
- * @param cls type to examine.
- * @return true if typeId equals for passed type and current
- * binary enum.
- */
- public boolean isTypeEquals(final Class> cls) {
- return ctx.descriptorForClass(cls, false, false).typeId() == typeId();
- }
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryFieldImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryFieldImpl.java
index de0b2d0d3d3cc..acd3678d50d88 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryFieldImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryFieldImpl.java
@@ -26,6 +26,7 @@
import java.util.Date;
import java.util.UUID;
import org.apache.ignite.binary.BinaryObjectException;
+import org.apache.ignite.binary.BinaryType;
import org.apache.ignite.internal.binary.streams.BinaryByteBufferInputStream;
import org.apache.ignite.internal.util.tostring.GridToStringExclude;
import org.apache.ignite.internal.util.typedef.internal.S;
@@ -33,6 +34,7 @@
import org.apache.ignite.binary.BinaryField;
import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.util.Objects.nonNull;
/**
* Implementation of binary field descriptor.
@@ -282,9 +284,28 @@ public int fieldId() {
*/
public int fieldOrder(BinaryObjectExImpl obj) {
if (typeId != obj.typeId()) {
- throw new BinaryObjectException("Failed to get field because type ID of passed object differs" +
- " from type ID this " + BinaryField.class.getSimpleName() + " belongs to [expected=" + typeId +
- ", actual=" + obj.typeId() + ']');
+ BinaryType expType = ctx.metadata(typeId);
+ BinaryType actualType = obj.type();
+
+ String actualTypeName = null;
+
+ Exception actualTypeNameEx = null;
+
+ try {
+ actualTypeName = actualType.typeName();
+ }
+ catch (BinaryObjectException e) {
+ actualTypeNameEx = new BinaryObjectException("Failed to get actual binary type name.", e);
+ }
+
+ throw new BinaryObjectException(
+ "Failed to get field because type ID of passed object differs from type ID this " +
+ BinaryField.class.getSimpleName() + " belongs to [expected=[typeId=" + typeId + ", typeName=" +
+ (nonNull(expType) ? expType.typeName() : null) + "], actual=[typeId=" + actualType.typeId() +
+ ", typeName=" + actualTypeName + "], fieldId=" + fieldId + ", fieldName=" + fieldName +
+ ", fieldType=" + (nonNull(expType) ? expType.fieldTypeName(fieldName) : null) + ']',
+ actualTypeNameEx
+ );
}
int schemaId = obj.schemaId();
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryObjectImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryObjectImpl.java
index 65fb349e84d9e..243c21f6a278b 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryObjectImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryObjectImpl.java
@@ -189,7 +189,11 @@ public BinaryObjectImpl(BinaryContext ctx, byte[] arr, int start) {
/** {@inheritDoc} */
@Override public void finishUnmarshal(CacheObjectValueContext ctx, ClassLoader ldr) throws IgniteCheckedException {
- this.ctx = ((CacheObjectBinaryProcessorImpl)ctx.kernalContext().cacheObjects()).binaryContext();
+ CacheObjectBinaryProcessorImpl binaryProc = (CacheObjectBinaryProcessorImpl)ctx.kernalContext().cacheObjects();
+
+ this.ctx = binaryProc.binaryContext();
+
+ binaryProc.waitMetadataWriteIfNeeded(typeId());
}
/** {@inheritDoc} */
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryReaderExImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryReaderExImpl.java
index 601141c306416..10d7569fcb804 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryReaderExImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryReaderExImpl.java
@@ -265,7 +265,7 @@ public BinaryReaderExImpl(BinaryContext ctx,
if (forUnmarshal) {
// Registers class by type ID, at least locally if the cache is not ready yet.
- desc = ctx.descriptorForClass(BinaryUtils.doReadClass(in, ctx, ldr, typeId0), false, false);
+ desc = ctx.registerClass(BinaryUtils.doReadClass(in, ctx, ldr, typeId0), true, false);
typeId = desc.typeId();
}
@@ -314,7 +314,7 @@ public BinaryInputStream in() {
*/
BinaryClassDescriptor descriptor() {
if (desc == null)
- desc = ctx.descriptorForTypeId(userType, typeId, ldr, true);
+ desc = ctx.descriptorForTypeId(userType, typeId, ldr, false);
return desc;
}
@@ -1754,7 +1754,7 @@ private String fieldFlagName(byte flag) {
case OBJ:
if (desc == null)
- desc = ctx.descriptorForTypeId(userType, typeId, ldr, true);
+ desc = ctx.descriptorForTypeId(userType, typeId, ldr, false);
streamPosition(dataStart);
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryUtils.java
index 77dce5602ec4e..0086b73fdabaa 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryUtils.java
@@ -1637,7 +1637,7 @@ public static Class doReadClass(BinaryInputStream in, BinaryContext ctx, ClassLo
Class cls;
if (typeId != GridBinaryMarshaller.UNREGISTERED_TYPE_ID)
- cls = ctx.descriptorForTypeId(true, typeId, ldr, true).describedClass();
+ cls = ctx.descriptorForTypeId(true, typeId, ldr, false).describedClass();
else {
String clsName = doReadClassName(in);
@@ -1648,8 +1648,7 @@ public static Class doReadClass(BinaryInputStream in, BinaryContext ctx, ClassLo
throw new BinaryInvalidTypeException("Failed to load the class: " + clsName, e);
}
- // forces registering of class by type id, at least locally
- ctx.descriptorForClass(cls, true, false);
+ ctx.registerClass(cls, false, false);
}
return cls;
@@ -1665,11 +1664,11 @@ public static Class doReadClass(BinaryInputStream in, BinaryContext ctx, ClassLo
* @return Resovled class.
*/
public static Class resolveClass(BinaryContext ctx, int typeId, @Nullable String clsName,
- @Nullable ClassLoader ldr, boolean deserialize) {
+ @Nullable ClassLoader ldr, boolean registerMeta) {
Class cls;
if (typeId != GridBinaryMarshaller.UNREGISTERED_TYPE_ID)
- cls = ctx.descriptorForTypeId(true, typeId, ldr, deserialize).describedClass();
+ cls = ctx.descriptorForTypeId(true, typeId, ldr, registerMeta).describedClass();
else {
try {
cls = U.forName(clsName, ldr);
@@ -1678,8 +1677,7 @@ public static Class resolveClass(BinaryContext ctx, int typeId, @Nullable String
throw new BinaryInvalidTypeException("Failed to load the class: " + clsName, e);
}
- // forces registering of class by type id, at least locally
- ctx.descriptorForClass(cls, true, false);
+ ctx.registerClass(cls, false, false);
}
return cls;
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryWriterExImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryWriterExImpl.java
index e6efb0c509a52..be66fc48c8878 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryWriterExImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryWriterExImpl.java
@@ -33,6 +33,7 @@
import org.apache.ignite.binary.BinaryObjectException;
import org.apache.ignite.binary.BinaryRawWriter;
import org.apache.ignite.binary.BinaryWriter;
+import org.apache.ignite.internal.UnregisteredClassException;
import org.apache.ignite.internal.binary.streams.BinaryHeapOutputStream;
import org.apache.ignite.internal.binary.streams.BinaryOutputStream;
import org.apache.ignite.internal.util.IgniteUtils;
@@ -178,10 +179,18 @@ private void marshal0(Object obj, boolean enableReplace) throws BinaryObjectExce
Class> cls = obj.getClass();
- BinaryClassDescriptor desc = ctx.descriptorForClass(cls, false, failIfUnregistered);
+ BinaryClassDescriptor desc = ctx.descriptorForClass(cls);
- if (desc == null)
- throw new BinaryObjectException("Object is not binary: [class=" + cls + ']');
+ if (!desc.registered()) {
+ if (failIfUnregistered)
+ throw new UnregisteredClassException(cls);
+ else {
+ // Metadata is registered for OBJECT and BINARY during actual writing.
+ boolean registerMeta = !(desc.isObject() || desc.isBinary());
+
+ desc = ctx.registerDescriptor(desc, registerMeta);
+ }
+ }
if (desc.excluded()) {
out.writeByte(GridBinaryMarshaller.NULL);
@@ -743,9 +752,9 @@ void doWriteObjectArray(@Nullable Object[] val) throws BinaryObjectException {
if (tryWriteAsHandle(val))
return;
- BinaryClassDescriptor desc = ctx.descriptorForClass(
+ BinaryClassDescriptor desc = ctx.registerClass(
val.getClass().getComponentType(),
- false,
+ true,
failIfUnregistered);
out.unsafeEnsure(1 + 4);
@@ -817,7 +826,7 @@ void doWriteEnum(@Nullable Enum> val) {
if (val == null)
out.writeByte(GridBinaryMarshaller.NULL);
else {
- BinaryClassDescriptor desc = ctx.descriptorForClass(val.getDeclaringClass(), false, failIfUnregistered);
+ BinaryClassDescriptor desc = ctx.registerClass(val.getDeclaringClass(), true, failIfUnregistered);
out.unsafeEnsure(1 + 4);
@@ -870,9 +879,9 @@ void doWriteEnumArray(@Nullable Object[] val) {
if (val == null)
out.writeByte(GridBinaryMarshaller.NULL);
else {
- BinaryClassDescriptor desc = ctx.descriptorForClass(
+ BinaryClassDescriptor desc = ctx.registerClass(
val.getClass().getComponentType(),
- false,
+ true,
failIfUnregistered);
out.unsafeEnsure(1 + 4);
@@ -902,7 +911,7 @@ void doWriteClass(@Nullable Class val) {
if (val == null)
out.writeByte(GridBinaryMarshaller.NULL);
else {
- BinaryClassDescriptor desc = ctx.descriptorForClass(val, false, failIfUnregistered);
+ BinaryClassDescriptor desc = ctx.registerClass(val, true, failIfUnregistered);
out.unsafeEnsure(1 + 4);
@@ -931,7 +940,7 @@ public void doWriteProxy(Proxy proxy, Class>[] intfs) {
out.unsafeWriteInt(intfs.length);
for (Class> intf : intfs) {
- BinaryClassDescriptor desc = ctx.descriptorForClass(intf, false, failIfUnregistered);
+ BinaryClassDescriptor desc = ctx.registerClass(intf, true, failIfUnregistered);
if (desc.registered())
out.writeInt(desc.typeId());
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryBuilderEnum.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryBuilderEnum.java
index 3930c463528e2..25f17d573c9da 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryBuilderEnum.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryBuilderEnum.java
@@ -63,7 +63,7 @@ public BinaryBuilderEnum(BinaryBuilderReader reader) {
throw new BinaryInvalidTypeException("Failed to load the class: " + clsName, e);
}
- this.typeId = reader.binaryContext().descriptorForClass(cls, false, false).typeId();
+ this.typeId = reader.binaryContext().registerClass(cls, true, false).typeId();
}
else {
this.typeId = typeId;
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryBuilderSerializer.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryBuilderSerializer.java
index edc80b6feccef..9e6411fe6824a 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryBuilderSerializer.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryBuilderSerializer.java
@@ -129,7 +129,7 @@ public void writeValue(BinaryWriterExImpl writer, Object val, boolean forceCol,
writer.context().updateMetadata(typeId, meta, writer.failIfUnregistered());
// Need register class for marshaller to be able to deserialize enum value.
- writer.context().descriptorForClass(((Enum)val).getDeclaringClass(), false, false);
+ writer.context().registerClass(((Enum)val).getDeclaringClass(), true, false);
writer.writeByte(GridBinaryMarshaller.ENUM);
writer.writeInt(typeId);
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryEnumArrayLazyValue.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryEnumArrayLazyValue.java
index c0e79ec760594..eaacbd561b7fd 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryEnumArrayLazyValue.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryEnumArrayLazyValue.java
@@ -56,7 +56,7 @@ protected BinaryEnumArrayLazyValue(BinaryBuilderReader reader) {
throw new BinaryInvalidTypeException("Failed to load the class: " + clsName, e);
}
- compTypeId = reader.binaryContext().descriptorForClass(cls, true, false).typeId();
+ compTypeId = reader.binaryContext().registerClass(cls, false, false).typeId();
}
else {
compTypeId = typeId;
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryObjectArrayLazyValue.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryObjectArrayLazyValue.java
index d4882dc6fb462..bd90569ffd961 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryObjectArrayLazyValue.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryObjectArrayLazyValue.java
@@ -55,7 +55,7 @@ protected BinaryObjectArrayLazyValue(BinaryBuilderReader reader) {
throw new BinaryInvalidTypeException("Failed to load the class: " + clsName, e);
}
- compTypeId = reader.binaryContext().descriptorForClass(cls, true, false).typeId();
+ compTypeId = reader.binaryContext().registerClass(cls, false, false).typeId();
}
else {
compTypeId = typeId;
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryObjectBuilderImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryObjectBuilderImpl.java
index d3b0973ca3533..ba36d858436c4 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryObjectBuilderImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryObjectBuilderImpl.java
@@ -158,7 +158,7 @@ public BinaryObjectBuilderImpl(BinaryObjectImpl obj) {
throw new BinaryInvalidTypeException("Failed to load the class: " + clsNameToWrite, e);
}
- this.typeId = ctx.descriptorForClass(cls, false, false).typeId();
+ this.typeId = ctx.registerClass(cls, true, false).typeId();
registeredType = false;
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/client/GridClientClusterState.java b/modules/core/src/main/java/org/apache/ignite/internal/client/GridClientClusterState.java
index 4fa25cec6b8f7..8a029da7e5524 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/client/GridClientClusterState.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/client/GridClientClusterState.java
@@ -18,7 +18,7 @@
package org.apache.ignite.internal.client;
/**
- * Interface for manage state of grid cluster.
+ * Interface for manage state of grid cluster and obtain information about it: ID and tag.
*/
public interface GridClientClusterState {
/**
@@ -30,4 +30,26 @@ public interface GridClientClusterState {
* @return {@code Boolean} - Current cluster state. {@code True} active, {@code False} inactive.
*/
public boolean active() throws GridClientException;
+
+ /**
+ * @return {@code True} if the cluster is in read-only mode and {@code False} otherwise.
+ * @throws GridClientException If request current cluster read-only mode failed.
+ */
+ public boolean readOnly() throws GridClientException;
+
+ /**
+ * Enable or disable Ignite grid read-only mode.
+ *
+ * @param readOnly If {@code True} enable read-only mode. If {@code False} disable read-only mode.
+ * @throws GridClientException If change of read-only mode is failed.
+ */
+ public void readOnly(boolean readOnly) throws GridClientException;
+
+ /**
+ * Get the cluster name.
+ *
+ * @return The name of the cluster.
+ * @throws GridClientException If the request to get the cluster name failed.
+ * */
+ String clusterName() throws GridClientException;
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/client/impl/GridClientClusterStateImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/client/impl/GridClientClusterStateImpl.java
index 2dcf06d619822..4c1331cfbcedb 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/client/impl/GridClientClusterStateImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/client/impl/GridClientClusterStateImpl.java
@@ -55,7 +55,8 @@ public GridClientClusterStateImpl(
@Override public void active(final boolean active) throws GridClientException {
withReconnectHandling(new ClientProjectionClosure() {
@Override public GridClientFuture apply(
- GridClientConnection conn, UUID nodeId
+ GridClientConnection conn,
+ UUID nodeId
) throws GridClientConnectionResetException, GridClientClosedException {
return conn.changeState(active, nodeId);
}
@@ -64,12 +65,28 @@ public GridClientClusterStateImpl(
/** {@inheritDoc} */
@Override public boolean active() throws GridClientException {
- return withReconnectHandling(new ClientProjectionClosure() {
- @Override public GridClientFuture apply(
- GridClientConnection conn, UUID nodeId
+ return withReconnectHandling(GridClientConnection::currentState).get();
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean readOnly() throws GridClientException {
+ return withReconnectHandling(GridClientConnection::readOnlyState).get();
+ }
+
+ /** {@inheritDoc} */
+ @Override public void readOnly(boolean readOnly) throws GridClientException {
+ withReconnectHandling(new ClientProjectionClosure() {
+ @Override public GridClientFuture apply(
+ GridClientConnection conn,
+ UUID nodeId
) throws GridClientConnectionResetException, GridClientClosedException {
- return conn.currentState(nodeId);
+ return conn.changeReadOnlyState(readOnly, nodeId);
}
}).get();
}
+
+ /** {@inheritDoc} */
+ @Override public String clusterName() throws GridClientException {
+ return withReconnectHandling(GridClientConnection::clusterName).get();
+ }
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/client/impl/connection/GridClientConnection.java b/modules/core/src/main/java/org/apache/ignite/internal/client/impl/connection/GridClientConnection.java
index c75bd24185bf0..306cc1fbf7b30 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/client/impl/connection/GridClientConnection.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/client/impl/connection/GridClientConnection.java
@@ -324,6 +324,39 @@ public abstract GridClientFuture> changeState(boolean active, UUID destNodeId)
public abstract GridClientFuture currentState(UUID destNodeId)
throws GridClientClosedException, GridClientConnectionResetException;
+ /**
+ * Get current read-only mode status. If future contains {@code True} - read-only mode enabled, and {@code False}
+ * otherwise.
+ *
+ * @param destNodeId Destination node id.
+ * @throws GridClientConnectionResetException In case of error.
+ * @throws GridClientClosedException If client was manually closed before request was sent over network.
+ */
+ public abstract GridClientFuture readOnlyState(UUID destNodeId)
+ throws GridClientClosedException, GridClientConnectionResetException;
+
+ /**
+ * Change read-only mode. Cluster must be activated.
+ *
+ * @param readOnly Read-only mode enabled flag.
+ * @param destNodeId Destination node id.
+ * @throws GridClientConnectionResetException In case of error.
+ * @throws GridClientClosedException If client was manually closed before request was sent over network.
+ */
+ public abstract GridClientFuture> changeReadOnlyState(boolean readOnly, UUID destNodeId)
+ throws GridClientClosedException, GridClientConnectionResetException;
+
+ /**
+ * Get a cluster name.
+ *
+ * @param destNodeId Destination node id.
+ * @return Future to get the cluster name.
+ * @throws GridClientConnectionResetException In case of error.
+ * @throws GridClientClosedException If client was manually closed before request was sent over network.
+ */
+ public abstract GridClientFuture clusterName(UUID destNodeId)
+ throws GridClientClosedException, GridClientConnectionResetException;
+
/**
* Gets node by node ID.
*
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/client/impl/connection/GridClientNioTcpConnection.java b/modules/core/src/main/java/org/apache/ignite/internal/client/impl/connection/GridClientNioTcpConnection.java
index ecc1cdf32154a..a788dddc1f9ce 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/client/impl/connection/GridClientNioTcpConnection.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/client/impl/connection/GridClientNioTcpConnection.java
@@ -59,6 +59,8 @@
import org.apache.ignite.internal.client.marshaller.optimized.GridClientZipOptimizedMarshaller;
import org.apache.ignite.internal.processors.rest.client.message.GridClientAuthenticationRequest;
import org.apache.ignite.internal.processors.rest.client.message.GridClientCacheRequest;
+import org.apache.ignite.internal.processors.rest.client.message.GridClientClusterNameRequest;
+import org.apache.ignite.internal.processors.rest.client.message.GridClientReadOnlyModeRequest;
import org.apache.ignite.internal.processors.rest.client.message.GridClientStateRequest;
import org.apache.ignite.internal.processors.rest.client.message.GridClientHandshakeRequest;
import org.apache.ignite.internal.processors.rest.client.message.GridClientMessage;
@@ -816,6 +818,23 @@ private GridClientAuthenticationRequest buildAuthRequest() {
return makeRequest(msg, destNodeId);
}
+ /** {@inheritDoc} */
+ @Override public GridClientFuture> changeReadOnlyState(
+ boolean readOnly,
+ UUID destNodeId
+ ) throws GridClientClosedException, GridClientConnectionResetException {
+ return readOnly ?
+ makeRequest(GridClientReadOnlyModeRequest.enableReadOnly(), destNodeId) :
+ makeRequest(GridClientReadOnlyModeRequest.disableReadOnly(), destNodeId);
+ }
+
+ /** {@inheritDoc} */
+ @Override public GridClientFuture readOnlyState(
+ UUID destNodeId
+ ) throws GridClientClosedException, GridClientConnectionResetException {
+ return makeRequest(GridClientReadOnlyModeRequest.currentReadOnlyMode(), destNodeId);
+ }
+
/** {@inheritDoc} */
@Override public GridClientFuture currentState(UUID destNodeId)
throws GridClientClosedException, GridClientConnectionResetException {
@@ -931,6 +950,12 @@ private GridClientAuthenticationRequest buildAuthRequest() {
return res;
}
+ /** {@inheritDoc} */
+ @Override public GridClientFuture clusterName(UUID destNodeId)
+ throws GridClientClosedException, GridClientConnectionResetException {
+ return makeRequest(new GridClientClusterNameRequest(), destNodeId);
+ }
+
/**
* Creates client node instance from message.
*
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/cluster/DetachedClusterNode.java b/modules/core/src/main/java/org/apache/ignite/internal/cluster/DetachedClusterNode.java
index 2c72bb02ed2f5..a3a69e19d9659 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/cluster/DetachedClusterNode.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/cluster/DetachedClusterNode.java
@@ -30,7 +30,9 @@
import org.jetbrains.annotations.Nullable;
/**
- * Representation of cluster node that isn't currently present in cluster.
+ * Representation of cluster node that either isn't currently present in cluster, or semantically detached.
+ * For example nodes returned from {@code BaselineTopology.currentBaseline()} are always considered as
+ * semantically detached, even if they are currently present in cluster.
*/
public class DetachedClusterNode implements ClusterNode {
/** */
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterAsyncImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterAsyncImpl.java
index d79710db8759c..df49800404dcd 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterAsyncImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterAsyncImpl.java
@@ -369,4 +369,14 @@ public IgniteClusterAsyncImpl(IgniteClusterImpl cluster) {
@Override public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(cluster);
}
-}
\ No newline at end of file
+
+ /** {@inheritDoc} */
+ @Override public boolean readOnly() {
+ return cluster.readOnly();
+ }
+
+ /** {@inheritDoc} */
+ @Override public void readOnly(boolean readOnly) throws IgniteException {
+ cluster.readOnly(readOnly);
+ }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterImpl.java
index 82779dab6089d..7440cef20efcf 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterImpl.java
@@ -29,7 +29,10 @@
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentLinkedQueue;
@@ -68,6 +71,8 @@
import org.apache.ignite.lang.IgniteProductVersion;
import org.jetbrains.annotations.Nullable;
+import static org.apache.ignite.internal.IgniteFeatures.CLUSTER_READ_ONLY_MODE;
+import static org.apache.ignite.internal.IgniteFeatures.allNodesSupports;
import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_IPS;
import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_MACS;
import static org.apache.ignite.internal.util.nodestart.IgniteNodeStartUtils.parseFile;
@@ -319,6 +324,41 @@ public IgniteClusterImpl(GridKernalContext ctx) {
}
}
+ /** {@inheritDoc} */
+ @Override public boolean readOnly() {
+ guard();
+
+ try {
+ return ctx.state().publicApiReadOnlyMode();
+ }
+ finally {
+ unguard();
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override public void readOnly(boolean readOnly) throws IgniteException {
+ guard();
+
+ try {
+ verifyReadOnlyModeSupport();
+
+ ctx.state().changeGlobalState(readOnly).get();
+ }
+ catch (IgniteCheckedException e) {
+ throw U.convertException(e);
+ }
+ finally {
+ unguard();
+ }
+ }
+
+ /** */
+ private void verifyReadOnlyModeSupport() {
+ if (!allNodesSupports(ctx.discovery().discoCache().serverNodes(), CLUSTER_READ_ONLY_MODE))
+ throw new IgniteException("Not all nodes in cluster supports cluster read-only mode");
+ }
+
/** */
private Collection baselineNodes() {
Collection srvNodes = ctx.cluster().get().forServers().nodes();
@@ -409,6 +449,22 @@ private void validateBeforeBaselineChange(Collection extends BaselineNode> bas
if (baselineTop.isEmpty())
throw new IgniteException("BaselineTopology must contain at least one node.");
+ List currBlT = Optional.ofNullable(ctx.state().clusterState().baselineTopology()).
+ map(BaselineTopology::currentBaseline).orElse(Collections.emptyList());
+
+ Collection srvrs = ctx.cluster().get().forServers().nodes();
+
+ for (BaselineNode node : baselineTop) {
+ Object consistentId = node.consistentId();
+
+ if (currBlT.stream().noneMatch(
+ currBlTNode -> Objects.equals(currBlTNode.consistentId(), consistentId)) &&
+ srvrs.stream().noneMatch(
+ currServersNode -> Objects.equals(currServersNode.consistentId(), consistentId)))
+ throw new IgniteException("Check arguments. Node with consistent ID [" + consistentId +
+ "] not found in server nodes.");
+ }
+
Collection onlineNodes = onlineBaselineNodesRequestedForRemoval(baselineTop);
if (onlineNodes != null) {
@@ -470,7 +526,7 @@ private Collection getConsistentIds(Collection extends BaselineNode> n
Collection target = new ArrayList<>(top.size());
for (ClusterNode node : top) {
- if (!node.isClient())
+ if (!node.isClient() && !node.isDaemon())
target.add(node);
}
@@ -709,7 +765,7 @@ IgniteInternalFuture> startNodesAsync0(
Collections.emptyList());
// Exceeding max line width for readability.
- GridCompoundFuture> fut =
+ GridCompoundFuture> fut =
new GridCompoundFuture<>(CU.objectsReducer());
AtomicInteger cnt = new AtomicInteger(nodeCallCnt);
@@ -828,4 +884,4 @@ public void clientReconnectFuture(IgniteFuture> reconnecFut) {
public String toString() {
return "IgniteCluster [igniteInstanceName=" + ctx.igniteInstanceName() + ']';
}
-}
\ No newline at end of file
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/BaselineCommand.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/BaselineCommand.java
index 4eb3cd359c685..af63a4f31bfb2 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/commandline/BaselineCommand.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/BaselineCommand.java
@@ -69,7 +69,7 @@ public class BaselineCommand implements Command {
/** {@inheritDoc} */
@Override public String confirmationPrompt() {
- if (BaselineSubcommands.COLLECT != baselineArgs.getCmd())
+ if (baselineArgs != null && BaselineSubcommands.COLLECT != baselineArgs.getCmd())
return "Warning: the command will perform changes in baseline.";
return null;
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/ClusterReadOnlyModeDisableCommand.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/ClusterReadOnlyModeDisableCommand.java
new file mode 100644
index 0000000000000..fca9832c818bc
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/ClusterReadOnlyModeDisableCommand.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.commandline;
+
+import java.util.logging.Logger;
+import org.apache.ignite.internal.client.GridClient;
+import org.apache.ignite.internal.client.GridClientConfiguration;
+
+import static org.apache.ignite.internal.commandline.CommandList.READ_ONLY_DISABLE;
+import static org.apache.ignite.internal.commandline.CommandLogger.optional;
+import static org.apache.ignite.internal.commandline.CommonArgParser.CMD_AUTO_CONFIRMATION;
+
+/**
+ * Command to disable cluster read-only mode.
+ */
+public class ClusterReadOnlyModeDisableCommand implements Command {
+ /** {@inheritDoc} */
+ @Override public Object execute(GridClientConfiguration clientCfg, Logger log) throws Exception {
+ try (GridClient client = Command.startClient(clientCfg)) {
+ client.state().readOnly(false);
+
+ log.info("Cluster read-only mode disabled");
+ }
+ catch (Throwable e) {
+ log.info("Failed to disable read-only mode");
+
+ throw e;
+ }
+
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ @Override public String confirmationPrompt() {
+ return "Warning: the command will disable read-only mode on a cluster.";
+ }
+
+ /** {@inheritDoc} */
+ @Override public Void arg() {
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void printUsage(Logger log) {
+ Command.usage(
+ log,
+ "Disable read-only mode on active cluster:",
+ READ_ONLY_DISABLE,
+ optional(CMD_AUTO_CONFIRMATION)
+ );
+ }
+
+ /** {@inheritDoc} */
+ @Override public String name() {
+ return READ_ONLY_DISABLE.toCommandName();
+ }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/ClusterReadOnlyModeEnableCommand.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/ClusterReadOnlyModeEnableCommand.java
new file mode 100644
index 0000000000000..ca3fe6b5b2ad3
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/ClusterReadOnlyModeEnableCommand.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.commandline;
+
+import java.util.logging.Logger;
+import org.apache.ignite.internal.client.GridClient;
+import org.apache.ignite.internal.client.GridClientConfiguration;
+
+import static org.apache.ignite.internal.commandline.CommandList.READ_ONLY_ENABLE;
+import static org.apache.ignite.internal.commandline.CommandLogger.optional;
+import static org.apache.ignite.internal.commandline.CommonArgParser.CMD_AUTO_CONFIRMATION;
+
+/**
+ * Command to enable cluster read-only mode.
+ */
+public class ClusterReadOnlyModeEnableCommand implements Command {
+ /** {@inheritDoc} */
+ @Override public Object execute(GridClientConfiguration clientCfg, Logger log) throws Exception {
+ try (GridClient client = Command.startClient(clientCfg)) {
+ client.state().readOnly(true);
+
+ log.info("Cluster read-only mode enabled");
+ }
+ catch (Throwable e) {
+ log.info("Failed to enable read-only mode");
+
+ throw e;
+ }
+
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ @Override public String confirmationPrompt() {
+ return "Warning: the command will enable read-only mode on a cluster.";
+ }
+
+ /** {@inheritDoc} */
+ @Override public Void arg() {
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void printUsage(Logger log) {
+ Command.usage(
+ log,
+ "Enable read-only mode on active cluster:",
+ READ_ONLY_ENABLE,
+ optional(CMD_AUTO_CONFIRMATION)
+ );
+ }
+
+ /** {@inheritDoc} */
+ @Override public String name() {
+ return READ_ONLY_ENABLE.toCommandName();
+ }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/Command.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/Command.java
index c1f382e98554e..6f033a224ca56 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/commandline/Command.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/Command.java
@@ -73,6 +73,16 @@ public static void usage(Logger logger, String desc, CommandList cmd, String...
*/
public Object execute(GridClientConfiguration clientCfg, Logger logger) throws Exception;
+ /**
+ * Prepares confirmation for the command.
+ *
+ * @param clientCfg Thin client configuration.
+ * @throws Exception If error occur.
+ */
+ default void prepareConfirmation(GridClientConfiguration clientCfg) throws Exception{
+ //no-op
+ }
+
/**
* @return Message text to show user for. If null it means that confirmantion is not needed.
*/
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommandArgIterator.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommandArgIterator.java
index ae36596a59df7..cb409708912d1 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommandArgIterator.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommandArgIterator.java
@@ -117,6 +117,25 @@ public long nextLongArg(String argName) {
}
}
+ /**
+ * @return Numeric value.
+ */
+ public byte nextByteArg(String argName) {
+ String str = nextArg("Expecting " + argName);
+
+ try {
+ byte val = Byte.parseByte(str);
+
+ if (val < 0)
+ throw new IllegalArgumentException("Invalid value for " + argName + ": " + val);
+
+ return val;
+ }
+ catch (NumberFormatException ignored) {
+ throw new IllegalArgumentException("Invalid value for " + argName + ": " + str);
+ }
+ }
+
/**
* @param argName Name of argument.
*/
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommandHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommandHandler.java
index 152fee0b16478..6f82259fcec56 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommandHandler.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommandHandler.java
@@ -18,6 +18,7 @@
package org.apache.ignite.internal.commandline;
import java.io.File;
+import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Collections;
@@ -43,6 +44,7 @@
import org.apache.ignite.internal.client.ssl.GridSslBasicContextFactory;
import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.internal.util.typedef.X;
+import org.apache.ignite.internal.util.typedef.internal.SB;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.logger.java.JavaLoggerFileHandler;
import org.apache.ignite.logger.java.JavaLoggerFormatter;
@@ -53,6 +55,7 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import static java.lang.System.lineSeparator;
import static org.apache.ignite.internal.IgniteVersionUtils.ACK_VER_STR;
import static org.apache.ignite.internal.IgniteVersionUtils.COPYRIGHT;
import static org.apache.ignite.internal.commandline.CommandLogger.INDENT;
@@ -75,7 +78,7 @@ public class CommandHandler {
public static final String CONFIRM_MSG = "y";
/** */
- static final String DELIM = "--------------------------------------------------------------------------------";
+ public static final String DELIM = "--------------------------------------------------------------------------------";
/** */
public static final int EXIT_CODE_OK = 0;
@@ -98,15 +101,15 @@ public class CommandHandler {
/** */
private static final long DFLT_PING_TIMEOUT = 30_000L;
- /** */
- private static final Scanner IN = new Scanner(System.in);
-
/** Utility name. */
public static final String UTILITY_NAME = "control.(sh|bat)";
/** */
public static final String NULL = "null";
+ /** */
+ private final Scanner in = new Scanner(System.in);
+
/** JULs logger. */
private final Logger logger;
@@ -205,12 +208,14 @@ public CommandHandler(Logger logger) {
* @return Exit code.
*/
public int execute(List rawArgs) {
+ LocalDateTime startTime = LocalDateTime.now();
+
Thread.currentThread().setName("session=" + ses);
logger.info("Control utility [ver. " + ACK_VER_STR + "]");
logger.info(COPYRIGHT);
logger.info("User: " + System.getProperty("user.name"));
- logger.info("Time: " + LocalDateTime.now());
+ logger.info("Time: " + startTime);
String commandName = "";
@@ -226,11 +231,7 @@ public int execute(List rawArgs) {
Command command = args.command();
commandName = command.name();
- if (!args.autoConfirmation() && !confirm(command.confirmationPrompt())) {
- logger.info("Operation cancelled.");
-
- return EXIT_CODE_OK;
- }
+ GridClientConfiguration clientCfg = getClientConfiguration(args);
boolean tryConnectAgain = true;
@@ -238,15 +239,25 @@ public int execute(List rawArgs) {
boolean suppliedAuth = !F.isEmpty(args.userName()) && !F.isEmpty(args.password());
- GridClientConfiguration clientCfg = getClientConfiguration(args);
-
while (tryConnectAgain) {
tryConnectAgain = false;
try {
+ if (!args.autoConfirmation()) {
+ command.prepareConfirmation(clientCfg);
+
+ if (!confirm(command.confirmationPrompt())) {
+ logger.info("Operation cancelled.");
+
+ return EXIT_CODE_OK;
+ }
+ }
+
logger.info("Command [" + commandName + "] started");
- logger.info("Arguments: " + String.join(" ", rawArgs));
+ logger.info("Arguments: " + argumentsToString(rawArgs));
+
logger.info(DELIM);
+
lastOperationRes = command.execute(clientCfg, logger);
}
catch (Throwable e) {
@@ -297,10 +308,17 @@ public int execute(List rawArgs) {
if (isConnectionError(e)) {
IgniteCheckedException cause = X.cause(e, IgniteCheckedException.class);
- if (cause != null && cause.getMessage() != null && cause.getMessage().contains("SSL"))
- e = cause;
+ if (isConnectionClosedSilentlyException(e))
+ logger.severe("Connection to cluster failed. Please check firewall settings and " +
+ "client and server are using the same SSL configuration.");
+ else {
+ if (isSSLMisconfigurationError(cause))
+ e = cause;
+
+ logger.severe("Connection to cluster failed. " + CommandLogger.errorMessage(e));
+
+ }
- logger.severe("Connection to cluster failed. " + CommandLogger.errorMessage(e));
logger.info("Command [" + commandName + "] finished with code: " + EXIT_CODE_CONNECTION_FAILED);
return EXIT_CODE_CONNECTION_FAILED;
@@ -312,12 +330,118 @@ public int execute(List rawArgs) {
return EXIT_CODE_UNEXPECTED_ERROR;
}
finally {
+ LocalDateTime endTime = LocalDateTime.now();
+
+ Duration diff = Duration.between(startTime, endTime);
+
+ logger.info("Control utility has completed execution at: " + endTime);
+ logger.info("Execution time: " + diff.toMillis() + " ms");
+
Arrays.stream(logger.getHandlers())
.filter(handler -> handler instanceof FileHandler)
.forEach(Handler::close);
}
}
+ /**
+ * Analyses passed exception to find out whether it is related to SSL misconfiguration issues.
+ *
+ * (!) Implementation depends heavily on structure of exception stack trace
+ * thus is very fragile to any changes in that structure.
+ *
+ * @param e Exception to analyze.
+ *
+ * @return {@code True} if exception may be related to SSL misconfiguration issues.
+ */
+ private boolean isSSLMisconfigurationError(Throwable e) {
+ return e != null && e.getMessage() != null && e.getMessage().contains("SSL");
+ }
+
+ /**
+ * Analyses passed exception to find out whether it is caused by server closing connection silently.
+ * This happens when client tries to establish unprotected connection
+ * to the cluster supporting only secured communications (e.g. when server is configured to use SSL certificates
+ * and client is not).
+ *
+ * (!) Implementation depends heavily on structure of exception stack trace
+ * thus is very fragile to any changes in that structure.
+ *
+ * @param e Exception to analyse.
+ * @return {@code True} if exception may be related to the attempt to establish unprotected connection
+ * to secured cluster.
+ */
+ private boolean isConnectionClosedSilentlyException(Throwable e) {
+ if (!(e instanceof GridClientDisconnectedException))
+ return false;
+
+ Throwable cause = e.getCause();
+
+ if (cause == null)
+ return false;
+
+ cause = cause.getCause();
+
+ if (cause instanceof GridClientConnectionResetException &&
+ cause.getMessage() != null &&
+ cause.getMessage().contains("Failed to perform handshake")
+ )
+ return true;
+
+ return false;
+ }
+
+ /**
+ * @param rawArgs Arguments which user has provided.
+ * @return String which could be shown in console and pritned to log.
+ */
+ private String argumentsToString(List rawArgs) {
+ boolean hide = false;
+
+ SB sb = new SB();
+
+ for (int i = 0; i < rawArgs.size(); i++) {
+ if (hide) {
+ sb.a("***** ");
+
+ hide = false;
+
+ continue;
+ }
+
+ String arg = rawArgs.get(i);
+
+ sb.a(arg).a(' ');
+
+ hide = CommonArgParser.isSensitiveArgument(arg);
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Does one of three things:
+ *
+ * returns user name from connection parameters if it is there;
+ * returns user name from client configuration if it is there;
+ * requests user input and returns entered name.
+ *
+ *
+ * @param args Connection parameters.
+ * @param clientCfg Client configuration.
+ * @throws IgniteCheckedException If security credetials cannot be provided from client configuration.
+ */
+ private String retrieveUserName(
+ ConnectionAndSslParameters args,
+ GridClientConfiguration clientCfg
+ ) throws IgniteCheckedException {
+ if (!F.isEmpty(args.userName()))
+ return args.userName();
+ else if (clientCfg.getSecurityCredentialsProvider() == null)
+ return requestDataFromConsole("user: ");
+ else
+ return (String)clientCfg.getSecurityCredentialsProvider().credentials().getLogin();
+ }
+
/**
* @param args Common arguments.
* @return Thin client configuration to connect to cluster.
@@ -444,7 +568,7 @@ public T getLastOperationResult() {
private String readLine(String prompt) {
System.out.print(prompt);
- return IN.nextLine();
+ return in.nextLine();
}
@@ -453,11 +577,11 @@ private String readLine(String prompt) {
*
* @return {@code true} if operation confirmed (or not needed), {@code false} otherwise.
*/
- private boolean confirm(String str) {
+ private boolean confirm(String str) {
if (str == null)
return true;
- String prompt = str + "\nPress '" + CONFIRM_MSG + "' to continue . . . ";
+ String prompt = str + lineSeparator() + "Press '" + CONFIRM_MSG + "' to continue . . . ";
return CONFIRM_MSG.equalsIgnoreCase(readLine(prompt));
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommandList.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommandList.java
index 5e5d4f0cb5a6c..151227a1ee764 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommandList.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommandList.java
@@ -22,6 +22,7 @@
import org.apache.ignite.internal.commandline.cache.CacheCommands;
import org.apache.ignite.internal.commandline.diagnostic.DiagnosticCommand;
+import org.apache.ignite.internal.commandline.dr.DrCommand;
/**
* High-level commands.
@@ -49,7 +50,16 @@ public enum CommandList {
WAL("--wal", new WalCommands()),
/** */
- DIAGNOSTIC("--diagnostic", new DiagnosticCommand());
+ DIAGNOSTIC("--diagnostic", new DiagnosticCommand()),
+
+ /** */
+ DATA_CENTER_REPLICATION("--dr", new DrCommand()),
+
+ /** */
+ READ_ONLY_ENABLE("--read-only-on", new ClusterReadOnlyModeEnableCommand()),
+
+ /** */
+ READ_ONLY_DISABLE("--read-only-off", new ClusterReadOnlyModeDisableCommand());
/** Private values copy so there's no need in cloning it every time. */
private static final CommandList[] VALUES = CommandList.values();
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommandLogger.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommandLogger.java
index 64ae204f7b406..17ff0f4d0684a 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommandLogger.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommandLogger.java
@@ -44,7 +44,7 @@ public class CommandLogger {
* @param params Other input parameter.
* @return Joined paramaters with specified {@code delimeter}.
*/
- public static String join(String delimeter, Object... params) {
+ public static String join(String delimeter, T... params) {
return join(new SB(), "", delimeter, params).toString();
}
@@ -57,7 +57,7 @@ public static String join(String delimeter, Object... params) {
* @param params Other input parameter.
* @return SB with appended to the end joined paramaters with specified {@code delimeter}.
*/
- public static SB join(SB sb, String sbDelimeter, String delimeter, Object... params) {
+ public static SB join(SB sb, String sbDelimeter, String delimeter, T... params) {
if (!F.isEmpty(params)) {
sb.a(sbDelimeter);
@@ -77,7 +77,7 @@ public static SB join(SB sb, String sbDelimeter, String delimeter, Object... par
* @param params Other input parameter.
* @return Joined parameters wrapped optional braces.
*/
- public static String optional(Object... params) {
+ public static String optional(Object... params) {
return join(new SB(), "[", " ", params).a("]").toString();
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommonArgParser.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommonArgParser.java
index f8d3372e71fdc..f4ddf8d174225 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommonArgParser.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommonArgParser.java
@@ -56,7 +56,7 @@ public class CommonArgParser {
static final String CMD_USER = "--user";
/** Option is used for auto confirmation. */
- static final String CMD_AUTO_CONFIRMATION = "--yes";
+ public static final String CMD_AUTO_CONFIRMATION = "--yes";
/** */
static final String CMD_PING_INTERVAL = "--ping-interval";
@@ -96,6 +96,9 @@ public class CommonArgParser {
/** List of optional auxiliary commands. */
private static final Set AUX_COMMANDS = new HashSet<>();
+ /** Set of sensitive arguments */
+ private static final Set SENSITIVE_ARGUMENTS = new HashSet<>();
+
static {
AUX_COMMANDS.add(CMD_HOST);
AUX_COMMANDS.add(CMD_PORT);
@@ -119,8 +122,21 @@ public class CommonArgParser {
AUX_COMMANDS.add(CMD_TRUSTSTORE);
AUX_COMMANDS.add(CMD_TRUSTSTORE_PASSWORD);
AUX_COMMANDS.add(CMD_TRUSTSTORE_TYPE);
+
+ SENSITIVE_ARGUMENTS.add(CMD_PASSWORD);
+ SENSITIVE_ARGUMENTS.add(CMD_KEYSTORE_PASSWORD);
+ SENSITIVE_ARGUMENTS.add(CMD_TRUSTSTORE_PASSWORD);
}
+ /**
+ * @param arg To check.
+ * @return True if provided argument is among sensitive one and not should be displayed.
+ */
+ public static boolean isSensitiveArgument(String arg) {
+ return SENSITIVE_ARGUMENTS.contains(arg);
+ }
+
+
/**
* @param logger Logger.
*/
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/ConnectionAndSslParameters.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/ConnectionAndSslParameters.java
index befe4510d6e42..b73c0fd739087 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/commandline/ConnectionAndSslParameters.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/ConnectionAndSslParameters.java
@@ -18,6 +18,8 @@
package org.apache.ignite.internal.commandline;
import org.apache.ignite.internal.client.GridClientConfiguration;
+import org.apache.ignite.internal.util.tostring.GridToStringExclude;
+import org.apache.ignite.internal.util.typedef.internal.S;
/**
* Container with common parsed and validated arguments.
@@ -33,6 +35,7 @@ public class ConnectionAndSslParameters {
private String user;
/** Password. */
+ @GridToStringExclude
private String pwd;
/** Force option is used for auto confirmation. */
@@ -60,6 +63,7 @@ public class ConnectionAndSslParameters {
private String sslKeyStoreType;
/** Keystore Password. */
+ @GridToStringExclude
private char[] sslKeyStorePassword;
/** Truststore. */
@@ -69,6 +73,7 @@ public class ConnectionAndSslParameters {
private String sslTrustStoreType;
/** Truststore Password. */
+ @GridToStringExclude
private char[] sslTrustStorePassword;
/** High-level command. */
@@ -259,4 +264,13 @@ public String sslTrustStoreType() {
public char[] sslTrustStorePassword() {
return sslTrustStorePassword;
}
+
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return S.toString(ConnectionAndSslParameters.class, this,
+ "password", pwd == null ? null : "*****",
+ "sslKeyStorePassword", sslKeyStorePassword == null ? null: "*****",
+ "sslTrustStorePassword", sslTrustStorePassword == null? null: "*****"
+ );
+ }
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/DeactivateCommand.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/DeactivateCommand.java
index 0d90c35264982..32185849ef713 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/commandline/DeactivateCommand.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/DeactivateCommand.java
@@ -33,14 +33,24 @@
* Command to deactivate cluster.
*/
public class DeactivateCommand implements Command {
+ /** Cluster name. */
+ private String clusterName;
+
/** {@inheritDoc} */
@Override public void printUsage(Logger logger) {
Command.usage(logger, "Deactivate cluster:", DEACTIVATE, optional(CMD_AUTO_CONFIRMATION));
}
+ /** {@inheritDoc} */
+ @Override public void prepareConfirmation(GridClientConfiguration clientCfg) throws Exception {
+ try (GridClient client = Command.startClient(clientCfg)) {
+ clusterName = client.state().clusterName();
+ }
+ }
+
/** {@inheritDoc} */
@Override public String confirmationPrompt() {
- return "Warning: the command will deactivate a cluster.";
+ return "Warning: the command will deactivate a cluster \"" + clusterName + "\".";
}
/**
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/StateCommand.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/StateCommand.java
index d3c730638b47b..c6523e01b8fd9 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/commandline/StateCommand.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/StateCommand.java
@@ -42,14 +42,21 @@ public class StateCommand implements Command {
* @param clientCfg Client configuration.
* @throws Exception If failed to print state.
*/
- @Override public Object execute(GridClientConfiguration clientCfg, Logger logger) throws Exception {
+ @Override public Object execute(GridClientConfiguration clientCfg, Logger log) throws Exception {
try (GridClient client = Command.startClient(clientCfg)){
GridClientClusterState state = client.state();
- logger.info("Cluster is " + (state.active() ? "active" : "inactive"));
+ if (state.active()) {
+ if (state.readOnly())
+ log.info("Cluster is active (read-only)");
+ else
+ log.info("Cluster is active");
+ }
+ else
+ log.info("Cluster is inactive");
}
catch (Throwable e) {
- logger.severe("Failed to get cluster state.");
+ log.severe("Failed to get cluster state.");
throw e;
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/TxCommands.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/TxCommands.java
index c88e928b55e61..c66037e3bf342 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/commandline/TxCommands.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/TxCommands.java
@@ -194,7 +194,7 @@ private void transactions(GridClient client, GridClientConfiguration conf) throw
/** {@inheritDoc} */
@Override public String confirmationPrompt() {
- if (args.getOperation() == VisorTxOperation.KILL)
+ if (args != null && args.getOperation() == VisorTxOperation.KILL)
return "Warning: the command will kill some transactions.";
return null;
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/WalCommands.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/WalCommands.java
index e2489cf0c99a1..2ac9c8794d896 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/commandline/WalCommands.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/WalCommands.java
@@ -39,6 +39,7 @@
import static org.apache.ignite.IgniteSystemProperties.IGNITE_ENABLE_EXPERIMENTAL_COMMAND;
import static org.apache.ignite.internal.commandline.CommandArgIterator.isCommandOrOption;
+import static org.apache.ignite.internal.commandline.CommandHandler.UTILITY_NAME;
import static org.apache.ignite.internal.commandline.CommandList.WAL;
import static org.apache.ignite.internal.commandline.CommandLogger.DOUBLE_INDENT;
import static org.apache.ignite.internal.commandline.CommandLogger.INDENT;
@@ -69,13 +70,15 @@ public class WalCommands implements Command> {
*/
private String walArgs;
+ /** {@inheritDoc} */
@Override public void printUsage(Logger logger) {
- if (IgniteSystemProperties.getBoolean(IGNITE_ENABLE_EXPERIMENTAL_COMMAND, false)) {
- Command.usage(logger, "Print absolute paths of unused archived wal segments on each node:", WAL,
- WAL_PRINT, "[consistentId1,consistentId2,....,consistentIdN]");
- Command.usage(logger, "Delete unused archived wal segments on each node:", WAL, WAL_DELETE,
- "[consistentId1,consistentId2,....,consistentIdN]", optional(CMD_AUTO_CONFIRMATION));
- }
+ if (!enableExperimental())
+ return;
+
+ Command.usage(logger, "Print absolute paths of unused archived wal segments on each node:", WAL,
+ WAL_PRINT, "[consistentId1,consistentId2,....,consistentIdN]");
+ Command.usage(logger, "Delete unused archived wal segments on each node:", WAL, WAL_DELETE,
+ "[consistentId1,consistentId2,....,consistentIdN]", optional(CMD_AUTO_CONFIRMATION));
}
/**
@@ -85,21 +88,26 @@ public class WalCommands implements Command> {
* @throws Exception If failed to execute wal action.
*/
@Override public Object execute(GridClientConfiguration clientCfg, Logger logger) throws Exception {
- this.logger = logger;
+ if (enableExperimental()) {
+ this.logger = logger;
- try (GridClient client = Command.startClient(clientCfg)) {
- switch (walAct) {
- case WAL_DELETE:
- deleteUnusedWalSegments(client, walArgs, clientCfg);
+ try (GridClient client = Command.startClient(clientCfg)) {
+ switch (walAct) {
+ case WAL_DELETE:
+ deleteUnusedWalSegments(client, walArgs, clientCfg);
- break;
+ break;
- case WAL_PRINT:
- default:
- printUnusedWalSegments(client, walArgs, clientCfg);
+ case WAL_PRINT:
+ default:
+ printUnusedWalSegments(client, walArgs, clientCfg);
- break;
+ break;
+ }
}
+ } else {
+ logger.warning(String.format("For use experimental command add %s=true to JVM_OPTS in %s",
+ IGNITE_ENABLE_EXPERIMENTAL_COMMAND, UTILITY_NAME));
}
return null;
@@ -124,8 +132,10 @@ public class WalCommands implements Command> {
? argIter.nextArg("Unexpected argument for " + WAL.text() + ": " + walAct)
: "";
- this.walAct = walAct;
- this.walArgs = walArgs;
+ if (enableExperimental()) {
+ this.walAct = walAct;
+ this.walArgs = walArgs;
+ }
}
else
throw new IllegalArgumentException("Unexpected action " + walAct + " for " + WAL.text());
@@ -268,4 +278,11 @@ private void printDeleteWalSegments0(VisorWalTaskResult taskRes) {
@Override public String name() {
return WAL.toCommandName();
}
+
+ /**
+ * @return Value of {@link IgniteSystemProperties#IGNITE_ENABLE_EXPERIMENTAL_COMMAND}
+ */
+ private boolean enableExperimental() {
+ return IgniteSystemProperties.getBoolean(IGNITE_ENABLE_EXPERIMENTAL_COMMAND, false);
+ }
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/baseline/BaselineArguments.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/baseline/BaselineArguments.java
index 395a4ef04ede0..22938856cc061 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/commandline/baseline/BaselineArguments.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/baseline/BaselineArguments.java
@@ -21,6 +21,8 @@
package org.apache.ignite.internal.commandline.baseline;
import java.util.List;
+import org.apache.ignite.internal.util.tostring.GridToStringInclude;
+import org.apache.ignite.internal.util.typedef.internal.S;
/**
* This class contains all possible arguments after parsing baseline command input.
@@ -38,6 +40,7 @@ public class BaselineArguments {
/** Requested topology version. */
private long topVer = -1;
/** List of consistent ids for operation. */
+ @GridToStringInclude
List consistentIds;
/**
@@ -92,6 +95,11 @@ public List getConsistentIds() {
return consistentIds;
}
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return S.toString(BaselineArguments.class, this);
+ }
+
/**
* Builder of {@link BaselineArguments}.
*/
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/CacheCommands.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/CacheCommands.java
index a7b6b7d8f059f..0c00fbbbac948 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/CacheCommands.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/CacheCommands.java
@@ -42,7 +42,6 @@
import static org.apache.ignite.internal.commandline.cache.CacheSubcommands.HELP;
import static org.apache.ignite.internal.commandline.cache.CacheSubcommands.LIST;
import static org.apache.ignite.internal.commandline.cache.CacheSubcommands.VALIDATE_INDEXES;
-import static org.apache.ignite.spi.discovery.tcp.ipfinder.sharedfs.TcpDiscoverySharedFsIpFinder.DELIM;
/**
* High-level "cache" command implementation.
@@ -160,7 +159,7 @@ protected static void usageCache(
Map paramsDesc,
String... args
) {
- logger.info(INDENT + DELIM);
+ logger.info("");
logger.info(INDENT + CommandLogger.join(" ", CACHE, cmd, CommandLogger.join(" ", args)));
logger.info(DOUBLE_INDENT + description);
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/CacheContention.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/CacheContention.java
index 458c9a19245ae..10c615d9cfa6f 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/CacheContention.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/CacheContention.java
@@ -29,6 +29,7 @@
import org.apache.ignite.internal.commandline.CommandArgIterator;
import org.apache.ignite.internal.commandline.CommandLogger;
import org.apache.ignite.internal.processors.cache.verify.ContentionInfo;
+import org.apache.ignite.internal.util.typedef.internal.S;
import org.apache.ignite.internal.visor.verify.VisorContentionTask;
import org.apache.ignite.internal.visor.verify.VisorContentionTaskArg;
import org.apache.ignite.internal.visor.verify.VisorContentionTaskResult;
@@ -93,6 +94,11 @@ public int minQueueSize() {
public int maxPrint() {
return maxPrint;
}
+
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return S.toString(Arguments.class, this);
+ }
}
/**
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/CacheDistribution.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/CacheDistribution.java
index 320f19b6f530f..64552d1b3f584 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/CacheDistribution.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/CacheDistribution.java
@@ -36,6 +36,7 @@
import org.apache.ignite.internal.commandline.cache.distribution.CacheDistributionTask;
import org.apache.ignite.internal.commandline.cache.distribution.CacheDistributionTaskArg;
import org.apache.ignite.internal.commandline.cache.distribution.CacheDistributionTaskResult;
+import org.apache.ignite.internal.util.typedef.internal.S;
import static org.apache.ignite.internal.commandline.CommandHandler.NULL;
import static org.apache.ignite.internal.commandline.CommandLogger.optional;
@@ -102,6 +103,11 @@ public UUID nodeId() {
public Set getUserAttributes() {
return userAttributes;
}
+
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return S.toString(Arguments.class, this);
+ }
}
/** Command parsed arguments */
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/CacheValidateIndexes.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/CacheValidateIndexes.java
index fdbf74283d3e8..eb8595da25282 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/CacheValidateIndexes.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/CacheValidateIndexes.java
@@ -36,6 +36,7 @@
import org.apache.ignite.internal.commandline.cache.argument.ValidateIndexesCommandArg;
import org.apache.ignite.internal.processors.cache.verify.PartitionKey;
import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.internal.S;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.internal.visor.verify.IndexIntegrityCheckIssue;
import org.apache.ignite.internal.visor.verify.IndexValidationIssue;
@@ -137,6 +138,11 @@ public int checkThrough() {
public UUID nodeId() {
return nodeId;
}
+
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return S.toString(Arguments.class, this);
+ }
}
/** Command parsed arguments. */
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/CacheViewer.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/CacheViewer.java
index eb83cf66ce808..55ed3740e3555 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/CacheViewer.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/CacheViewer.java
@@ -36,6 +36,7 @@
import org.apache.ignite.internal.commandline.argument.CommandArgUtils;
import org.apache.ignite.internal.commandline.cache.argument.ListCommandArg;
import org.apache.ignite.internal.processors.cache.verify.CacheInfo;
+import org.apache.ignite.internal.util.typedef.internal.S;
import org.apache.ignite.internal.util.typedef.internal.SB;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.internal.visor.cache.VisorCacheAffinityConfiguration;
@@ -149,6 +150,11 @@ public VisorViewCacheCmd cacheCommand() {
* @return Full config flag.
*/
public boolean fullConfig(){ return fullConfig; }
+
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return S.toString(Arguments.class, this);
+ }
}
/** Command parsed arguments */
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/FindAndDeleteGarbage.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/FindAndDeleteGarbage.java
index 0814dcd5f69cb..5006f075cd009 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/FindAndDeleteGarbage.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/FindAndDeleteGarbage.java
@@ -32,6 +32,7 @@
import org.apache.ignite.internal.commandline.CommandLogger;
import org.apache.ignite.internal.commandline.argument.CommandArgUtils;
import org.apache.ignite.internal.commandline.cache.argument.FindAndDeleteGarbageArg;
+import org.apache.ignite.internal.util.typedef.internal.S;
import org.apache.ignite.internal.visor.cache.VisorFindAndDeleteGarbageInPersistenceJobResult;
import org.apache.ignite.internal.visor.cache.VisorFindAndDeleteGarbageInPersistenceTask;
import org.apache.ignite.internal.visor.cache.VisorFindAndDeleteGarbageInPersistenceTaskArg;
@@ -100,6 +101,11 @@ public Set groups() {
public boolean delete() {
return delete;
}
+
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return S.toString(Arguments.class, this);
+ }
}
/** Command parsed arguments. */
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/IdleVerify.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/IdleVerify.java
index f0a2058c3d1f9..63afa6d894f7b 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/IdleVerify.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/IdleVerify.java
@@ -27,8 +27,8 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.logging.Logger;
import java.util.function.Consumer;
+import java.util.logging.Logger;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import org.apache.ignite.IgniteException;
@@ -46,6 +46,7 @@
import org.apache.ignite.internal.processors.cache.verify.PartitionKey;
import org.apache.ignite.internal.processors.cache.verify.VerifyBackupPartitionsTaskV2;
import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.internal.S;
import org.apache.ignite.internal.util.typedef.internal.SB;
import org.apache.ignite.internal.visor.verify.CacheFilterEnum;
import org.apache.ignite.internal.visor.verify.VisorIdleVerifyDumpTask;
@@ -179,6 +180,11 @@ public boolean idleCheckCrc() {
public boolean isSkipZeros() {
return skipZeros;
}
+
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return S.toString(Arguments.class, this);
+ }
}
/** Command parsed arguments. */
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/diagnostic/PageLocksCommand.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/diagnostic/PageLocksCommand.java
index 65d60a03f7390..cd6dc77677d91 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/commandline/diagnostic/PageLocksCommand.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/diagnostic/PageLocksCommand.java
@@ -32,6 +32,7 @@
import org.apache.ignite.internal.commandline.TaskExecutor;
import org.apache.ignite.internal.commandline.argument.CommandArg;
import org.apache.ignite.internal.commandline.argument.CommandArgUtils;
+import org.apache.ignite.internal.util.typedef.internal.S;
import org.apache.ignite.internal.visor.diagnostic.Operation;
import org.apache.ignite.internal.visor.diagnostic.VisorPageLocksResult;
import org.apache.ignite.internal.visor.diagnostic.VisorPageLocksTask;
@@ -43,10 +44,10 @@
import static org.apache.ignite.internal.commandline.CommandLogger.optional;
import static org.apache.ignite.internal.commandline.diagnostic.DiagnosticSubCommand.PAGE_LOCKS;
import static org.apache.ignite.internal.commandline.diagnostic.PageLocksCommand.PageLocksCommandArg.ALL;
-import static org.apache.ignite.internal.commandline.diagnostic.PageLocksCommand.PageLocksCommandArg.NODES;
-import static org.apache.ignite.internal.commandline.diagnostic.PageLocksCommand.PageLocksCommandArg.PATH;
import static org.apache.ignite.internal.commandline.diagnostic.PageLocksCommand.PageLocksCommandArg.DUMP;
import static org.apache.ignite.internal.commandline.diagnostic.PageLocksCommand.PageLocksCommandArg.DUMP_LOG;
+import static org.apache.ignite.internal.commandline.diagnostic.PageLocksCommand.PageLocksCommandArg.NODES;
+import static org.apache.ignite.internal.commandline.diagnostic.PageLocksCommand.PageLocksCommandArg.PATH;
import static org.apache.ignite.internal.processors.diagnostic.DiagnosticProcessor.DEFAULT_TARGET_FOLDER;
/**
@@ -76,7 +77,7 @@ public class PageLocksCommand implements Command {
});
}
- VisorPageLocksTrackerArgs taskArg = new VisorPageLocksTrackerArgs(arguments.op, arguments.filePath, nodeIds);
+ VisorPageLocksTrackerArgs taskArg = new VisorPageLocksTrackerArgs(arguments.operation, arguments.filePath, nodeIds);
res = TaskExecutor.executeTask(
client,
@@ -180,7 +181,7 @@ private void printResult(Map res) {
/** */
public static class Arguments {
/** */
- private final Operation op;
+ private final Operation operation;
/** */
private final String filePath;
/** */
@@ -189,22 +190,27 @@ public static class Arguments {
private final Set nodeIds;
/**
- * @param op Operation.
+ * @param operation Operation.
* @param filePath File path.
* @param allNodes If {@code True} include all available nodes for command. If {@code False} include only subset.
* @param nodeIds Node ids.
*/
public Arguments(
- Operation op,
+ Operation operation,
String filePath,
boolean allNodes,
Set nodeIds
) {
- this.op = op;
+ this.operation = operation;
this.filePath = filePath;
this.allNodes = allNodes;
this.nodeIds = nodeIds;
}
+
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return S.toString(Arguments.class, this);
+ }
}
enum PageLocksCommandArg implements CommandArg {
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/dr/DrCommand.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/dr/DrCommand.java
new file mode 100644
index 0000000000000..9cddab745432f
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/dr/DrCommand.java
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.commandline.dr;
+
+import java.util.logging.Logger;
+import org.apache.ignite.internal.client.GridClientConfiguration;
+import org.apache.ignite.internal.commandline.Command;
+import org.apache.ignite.internal.commandline.CommandArgIterator;
+import org.apache.ignite.internal.commandline.dr.subcommands.DrCacheCommand;
+import org.apache.ignite.internal.commandline.dr.subcommands.DrNodeCommand;
+import org.apache.ignite.internal.commandline.dr.subcommands.DrStateCommand;
+import org.apache.ignite.internal.commandline.dr.subcommands.DrTopologyCommand;
+
+import static org.apache.ignite.internal.commandline.Command.usage;
+import static org.apache.ignite.internal.commandline.CommandList.DATA_CENTER_REPLICATION;
+import static org.apache.ignite.internal.commandline.CommandLogger.join;
+import static org.apache.ignite.internal.commandline.CommandLogger.optional;
+import static org.apache.ignite.internal.commandline.CommonArgParser.CMD_AUTO_CONFIRMATION;
+import static org.apache.ignite.internal.commandline.dr.DrSubCommandsList.CACHE;
+import static org.apache.ignite.internal.commandline.dr.DrSubCommandsList.FULL_STATE_TRANSFER;
+import static org.apache.ignite.internal.commandline.dr.DrSubCommandsList.HELP;
+import static org.apache.ignite.internal.commandline.dr.DrSubCommandsList.NODE;
+import static org.apache.ignite.internal.commandline.dr.DrSubCommandsList.PAUSE;
+import static org.apache.ignite.internal.commandline.dr.DrSubCommandsList.RESUME;
+import static org.apache.ignite.internal.commandline.dr.DrSubCommandsList.STATE;
+import static org.apache.ignite.internal.commandline.dr.DrSubCommandsList.TOPOLOGY;
+
+/** */
+public class DrCommand implements Command {
+ /** */
+ private Command> delegate;
+
+ /** {@inheritDoc} */
+ @Override public void printUsage(Logger log) {
+ usage(log, "Print data center replication command help:",
+ DATA_CENTER_REPLICATION,
+ HELP.toString()
+ );
+
+ usage(log, "Print state of data center replication:",
+ DATA_CENTER_REPLICATION,
+ STATE.toString(),
+ optional(DrStateCommand.VERBOSE_PARAM)
+ );
+
+ usage(log, "Print topology of the cluster with the data center replication related details:",
+ DATA_CENTER_REPLICATION,
+ TOPOLOGY.toString(),
+ optional(DrTopologyCommand.SENDER_HUBS_PARAM),
+ optional(DrTopologyCommand.RECEIVER_HUBS_PARAM),
+ optional(DrTopologyCommand.DATA_NODES_PARAM),
+ optional(DrTopologyCommand.OTHER_NODES_PARAM)
+ );
+
+ usage(log, "Print node specific data center replication related details and clear node's DR store:",
+ DATA_CENTER_REPLICATION,
+ NODE.toString(),
+ "",
+ optional(DrNodeCommand.CONFIG_PARAM),
+ optional(DrNodeCommand.METRICS_PARAM),
+ optional(DrNodeCommand.CLEAR_STORE_PARAM),
+ optional(CMD_AUTO_CONFIRMATION)
+ );
+
+ usage(log, "Print cache specific data center replication related details about caches and maybe change replication state on them:",
+ DATA_CENTER_REPLICATION,
+ CACHE.toString(),
+ "",
+ optional(DrCacheCommand.CONFIG_PARAM),
+ optional(DrCacheCommand.METRICS_PARAM),
+ optional(DrCacheCommand.CACHE_FILTER_PARAM, join("|", DrCacheCommand.CacheFilter.values())),
+ optional(DrCacheCommand.SENDER_GROUP_PARAM, "|" + join("|", DrCacheCommand.SenderGroup.values())),
+ optional(DrCacheCommand.ACTION_PARAM, join("|", DrCacheCommand.Action.values())),
+ optional(CMD_AUTO_CONFIRMATION)
+ );
+
+ usage(log, "Execute full state transfer on all caches in cluster if data center replication is configured:",
+ DATA_CENTER_REPLICATION,
+ FULL_STATE_TRANSFER.toString(),
+ optional(CMD_AUTO_CONFIRMATION)
+ );
+
+ usage(log, "Stop data center replication on all caches in cluster:",
+ DATA_CENTER_REPLICATION,
+ PAUSE.toString(),
+ "",
+ optional(CMD_AUTO_CONFIRMATION)
+ );
+
+ usage(log, "Start data center replication on all caches in cluster:",
+ DATA_CENTER_REPLICATION,
+ RESUME.toString(),
+ "",
+ optional(CMD_AUTO_CONFIRMATION)
+ );
+ }
+
+ /** {@inheritDoc} */
+ @Override public String name() {
+ return DATA_CENTER_REPLICATION.toCommandName();
+ }
+
+ /** {@inheritDoc} */
+ @Override public void parseArguments(CommandArgIterator argIter) {
+ DrSubCommandsList subcommand = DrSubCommandsList.parse(argIter.nextArg("Expected dr action."));
+
+ if (subcommand == null)
+ throw new IllegalArgumentException("Expected correct dr action.");
+
+ delegate = subcommand.command();
+
+ delegate.parseArguments(argIter);
+ }
+
+ /** {@inheritDoc} */
+ @Override public String confirmationPrompt() {
+ return delegate != null ? delegate.confirmationPrompt() : null;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Object execute(GridClientConfiguration clientCfg, Logger log) throws Exception {
+ return delegate.execute(clientCfg, log);
+ }
+
+ /** {@inheritDoc} */
+ @Override public Object arg() {
+ return delegate.arg();
+ }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/dr/DrSubCommandsList.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/dr/DrSubCommandsList.java
new file mode 100644
index 0000000000000..b70f8ecc22ba7
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/dr/DrSubCommandsList.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.commandline.dr;
+
+import org.apache.ignite.internal.commandline.Command;
+import org.apache.ignite.internal.commandline.dr.subcommands.DrCacheCommand;
+import org.apache.ignite.internal.commandline.dr.subcommands.DrFullStateTransferCommand;
+import org.apache.ignite.internal.commandline.dr.subcommands.DrHelpCommand;
+import org.apache.ignite.internal.commandline.dr.subcommands.DrNodeCommand;
+import org.apache.ignite.internal.commandline.dr.subcommands.DrPauseCommand;
+import org.apache.ignite.internal.commandline.dr.subcommands.DrResumeCommand;
+import org.apache.ignite.internal.commandline.dr.subcommands.DrStateCommand;
+import org.apache.ignite.internal.commandline.dr.subcommands.DrTopologyCommand;
+import org.jetbrains.annotations.NotNull;
+
+/** */
+public enum DrSubCommandsList {
+ /** */
+ HELP("help", new DrHelpCommand()),
+ /** */
+ STATE("state", new DrStateCommand()),
+ /** */
+ TOPOLOGY("topology", new DrTopologyCommand()),
+ /** */
+ NODE("node", new DrNodeCommand()),
+ /** */
+ CACHE("cache", new DrCacheCommand()),
+ /** */
+ FULL_STATE_TRANSFER("full-state-transfer", new DrFullStateTransferCommand()),
+ /** */
+ PAUSE("pause", new DrPauseCommand()),
+ /** */
+ RESUME("resume", new DrResumeCommand());
+
+ /** */
+ private final String name;
+
+ /** */
+ private final Command> cmd;
+
+ /** */
+ DrSubCommandsList(String name, Command> cmd) {
+ this.name = name;
+ this.cmd = cmd;
+ }
+
+ /** */
+ public String text() {
+ return name;
+ }
+
+ /** */
+ @NotNull
+ public Command> command() {
+ return cmd;
+ }
+
+ /** */
+ public static DrSubCommandsList parse(String name) {
+ for (DrSubCommandsList cmd : values()) {
+ if (cmd.name.equalsIgnoreCase(name))
+ return cmd;
+ }
+
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return name;
+ }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/dr/subcommands/DrAbstractRemoteSubCommand.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/dr/subcommands/DrAbstractRemoteSubCommand.java
new file mode 100644
index 0000000000000..e618adc2f4720
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/dr/subcommands/DrAbstractRemoteSubCommand.java
@@ -0,0 +1,151 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.commandline.dr.subcommands;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.UUID;
+import java.util.logging.Logger;
+import org.apache.ignite.internal.IgniteNodeAttributes;
+import org.apache.ignite.internal.client.GridClient;
+import org.apache.ignite.internal.client.GridClientCompute;
+import org.apache.ignite.internal.client.GridClientConfiguration;
+import org.apache.ignite.internal.client.GridClientDisconnectedException;
+import org.apache.ignite.internal.client.GridClientNode;
+import org.apache.ignite.internal.commandline.Command;
+import org.apache.ignite.internal.commandline.CommandArgIterator;
+import org.apache.ignite.internal.commandline.CommandLogger;
+import org.apache.ignite.internal.dto.IgniteDataTransferObject;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.visor.VisorTaskArgument;
+
+import static java.util.stream.Collectors.toCollection;
+import static java.util.stream.Collectors.toList;
+import static org.apache.ignite.internal.IgniteFeatures.DR_CONTROL_UTILITY;
+import static org.apache.ignite.internal.IgniteFeatures.nodeSupports;
+import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_IGNITE_FEATURES;
+import static org.apache.ignite.internal.commandline.CommandLogger.INDENT;
+
+/** */
+public abstract class DrAbstractRemoteSubCommand<
+ VisorArgsDto extends IgniteDataTransferObject,
+ VisorResultDto extends IgniteDataTransferObject,
+ DrArgs extends DrAbstractRemoteSubCommand.Arguments
+> implements Command {
+ /** */
+ protected static boolean drControlUtilitySupported(GridClientNode node) {
+ return nodeSupports((byte[])node.attribute(ATTR_IGNITE_FEATURES), DR_CONTROL_UTILITY);
+ }
+
+ /** */
+ private DrArgs args;
+
+ /** */
+ private final List nodesWithoutDrTasks = new ArrayList<>();
+
+ /** {@inheritDoc} */
+ @Override public final void printUsage(Logger log) {
+ throw new UnsupportedOperationException("printUsage");
+ }
+
+ /** {@inheritDoc} */
+ @Override public final void parseArguments(CommandArgIterator argIter) {
+ args = parseArguments0(argIter);
+ }
+
+ /** {@inheritDoc} */
+ @Override public final Object execute(GridClientConfiguration clientCfg, Logger log) throws Exception {
+ try (GridClient client = Command.startClient(clientCfg)) {
+ VisorResultDto res = execute0(clientCfg, client);
+
+ printResult(res, log);
+ }
+ catch (Throwable e) {
+ log.severe("Failed to execute dr command='" + name() + "'");
+ log.severe(CommandLogger.errorMessage(e));
+
+ throw e;
+ }
+
+ return null;
+ }
+
+ /** */
+ protected VisorResultDto execute0(
+ GridClientConfiguration clientCfg,
+ GridClient client
+ ) throws Exception {
+ GridClientCompute compute = client.compute();
+
+ Collection nodes = compute.nodes();
+
+ nodes.stream()
+ .filter(node -> !drControlUtilitySupported(node))
+ .collect(toCollection(() -> nodesWithoutDrTasks));
+
+ List nodeIds = nodes.stream()
+ .filter(DrAbstractRemoteSubCommand::drControlUtilitySupported)
+ .map(GridClientNode::nodeId)
+ .collect(toList());
+
+ if (F.isEmpty(nodeIds))
+ throw new GridClientDisconnectedException("Connectable nodes not found", null);
+
+ return compute.projection(DrAbstractRemoteSubCommand::drControlUtilitySupported)
+ .execute(visorTaskName(), new VisorTaskArgument<>(nodeIds, args.toVisorArgs(), false));
+ }
+
+ /** */
+ protected void printUnrecognizedNodesMessage(Logger log, boolean verbose) {
+ if (!nodesWithoutDrTasks.isEmpty()) {
+ log.warning("Unrecognized nodes found that have no DR API for control utility: " + nodesWithoutDrTasks.size());
+
+ if (verbose) {
+ for (GridClientNode node : nodesWithoutDrTasks) {
+ boolean clientNode = node.attribute(IgniteNodeAttributes.ATTR_CLIENT_MODE);
+
+ log.warning(String.format(INDENT + "nodeId=%s, Mode=%s", node.nodeId(), clientNode ? "Client" : "Server"));
+ }
+ }
+ else
+ log.warning("Please use \"--dr topology\" command to see full list.");
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override public final DrArgs arg() {
+ return args;
+ }
+
+ /** */
+ protected abstract String visorTaskName();
+
+ /** */
+ protected abstract DrArgs parseArguments0(CommandArgIterator argIter);
+
+ /** */
+ protected abstract void printResult(VisorResultDto res, Logger log);
+
+ /** */
+ @SuppressWarnings("PublicInnerClass")
+ public interface Arguments {
+ /** */
+ ArgsDto toVisorArgs();
+ }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/dr/subcommands/DrCacheCommand.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/dr/subcommands/DrCacheCommand.java
new file mode 100644
index 0000000000000..e0184c54fe77d
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/dr/subcommands/DrCacheCommand.java
@@ -0,0 +1,422 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.commandline.dr.subcommands;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.UUID;
+import java.util.logging.Logger;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+import java.util.stream.Collectors;
+import org.apache.ignite.internal.client.GridClient;
+import org.apache.ignite.internal.client.GridClientCompute;
+import org.apache.ignite.internal.client.GridClientConfiguration;
+import org.apache.ignite.internal.client.GridClientDisconnectedException;
+import org.apache.ignite.internal.client.GridClientException;
+import org.apache.ignite.internal.client.GridClientNode;
+import org.apache.ignite.internal.commandline.CommandArgIterator;
+import org.apache.ignite.internal.commandline.dr.DrSubCommandsList;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.T2;
+import org.apache.ignite.internal.visor.VisorTaskArgument;
+import org.apache.ignite.internal.visor.dr.VisorDrCacheTaskArgs;
+import org.apache.ignite.internal.visor.dr.VisorDrCacheTaskResult;
+
+import static org.apache.ignite.internal.commandline.CommandHandler.DELIM;
+import static org.apache.ignite.internal.commandline.CommandLogger.INDENT;
+
+/** */
+public class DrCacheCommand extends
+ DrAbstractRemoteSubCommand
+{
+ /** Config parameter. */
+ public static final String CONFIG_PARAM = "--config";
+ /** Metrics parameter. */
+ public static final String METRICS_PARAM = "--metrics";
+ /** Cache filter parameter. */
+ public static final String CACHE_FILTER_PARAM = "--cache-filter";
+ /** Sender group parameter. */
+ public static final String SENDER_GROUP_PARAM = "--sender-group";
+ /** Action parameter. */
+ public static final String ACTION_PARAM = "--action";
+
+ /** {@inheritDoc} */
+ @Override protected String visorTaskName() {
+ throw new UnsupportedOperationException("visorTaskName");
+ }
+
+ /** {@inheritDoc} */
+ @Override public DrCacheArguments parseArguments0(CommandArgIterator argIter) {
+ String regex = argIter.nextArg("Cache name regex expected.");
+
+ if (CommandArgIterator.isCommandOrOption(regex))
+ throw new IllegalArgumentException("Cache name regex expected.");
+
+ Pattern pattern;
+
+ try {
+ pattern = Pattern.compile(regex);
+ }
+ catch (PatternSyntaxException e) {
+ throw new IllegalArgumentException("Cache name regex is not valid.", e);
+ }
+
+ boolean cfg = false;
+ boolean metrics = false;
+ CacheFilter cacheFilter = CacheFilter.ALL;
+ SenderGroup sndGrp = SenderGroup.ALL;
+ String sndGrpName = null;
+ Action act = null;
+
+ String nextArg;
+
+ //noinspection LabeledStatement
+ args_loop: while ((nextArg = argIter.peekNextArg()) != null) {
+ switch (nextArg.toLowerCase(Locale.ENGLISH)) {
+ case CONFIG_PARAM:
+ argIter.nextArg(null);
+ cfg = true;
+
+ break;
+
+ case METRICS_PARAM:
+ argIter.nextArg(null);
+ metrics = true;
+
+ break;
+
+ case CACHE_FILTER_PARAM: {
+ argIter.nextArg(null);
+
+ String errorMsg = "--cache-filter parameter value required.";
+
+ String cacheFilterStr = argIter.nextArg(errorMsg);
+ cacheFilter = CacheFilter.valueOf(cacheFilterStr.toUpperCase(Locale.ENGLISH));
+
+ if (cacheFilter == null)
+ throw new IllegalArgumentException(errorMsg);
+
+ break;
+ }
+
+ case SENDER_GROUP_PARAM: {
+ argIter.nextArg(null);
+
+ String arg = argIter.nextArg("--sender-group parameter value required.");
+
+ sndGrp = SenderGroup.parse(arg);
+
+ if (sndGrp == null)
+ sndGrpName = arg;
+
+ break;
+ }
+
+ case ACTION_PARAM: {
+ argIter.nextArg(null);
+
+ String errorMsg = "--action parameter value required.";
+
+ act = Action.parse(argIter.nextArg(errorMsg));
+
+ if (act == null)
+ throw new IllegalArgumentException(errorMsg);
+
+ break;
+ }
+
+ default:
+ //noinspection BreakStatementWithLabel
+ break args_loop;
+ }
+ }
+
+ return new DrCacheArguments(regex, pattern, cfg, metrics, cacheFilter, sndGrp, sndGrpName, act, (byte)0);
+ }
+
+ /** {@inheritDoc} */
+ @Override public String confirmationPrompt() {
+ if (arg().action != null)
+ return "Warning: this command will change data center replication state for selected caches.";
+
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected VisorDrCacheTaskResult execute0(GridClientConfiguration clientCfg, GridClient client) throws Exception {
+ return execute0(client, arg());
+ }
+
+ /** */
+ public static VisorDrCacheTaskResult execute0(
+ GridClient client,
+ DrCacheArguments arg
+ ) throws GridClientException {
+ GridClientCompute compute = client.compute();
+
+ Collection nodes = compute.nodes();
+
+ Pattern cacheNamePattern = arg.pattern;
+
+ List nodeIds = nodes.stream()
+ .filter(DrAbstractRemoteSubCommand::drControlUtilitySupported)
+ .map(GridClientNode::nodeId)
+ .collect(Collectors.toList());
+
+ if (F.isEmpty(nodeIds))
+ throw new GridClientDisconnectedException("Connectable nodes not found", null);
+
+ if (arg.remoteDataCenterId == 0 && arg.action != null) {
+ Map cacheNameToNodeMap = new HashMap<>();
+
+ for (GridClientNode node : nodes) {
+ for (String cacheName : node.caches().keySet()) {
+ if (cacheNamePattern.matcher(cacheName).matches())
+ cacheNameToNodeMap.putIfAbsent(cacheName, node.nodeId());
+ }
+ }
+
+ arg.cacheNamesMap = cacheNameToNodeMap;
+ }
+ else if (arg.remoteDataCenterId != 0) {
+ for (GridClientNode node : nodes) {
+ if (node.attribute("plugins.gg.replication.snd.hub") != null) {
+ arg.actionCoordinator = node.nodeId();
+
+ break;
+ }
+ }
+ }
+
+ return compute.projection(DrAbstractRemoteSubCommand::drControlUtilitySupported).execute(
+ "org.gridgain.grid.internal.visor.dr.console.VisorDrCacheTask",
+ new VisorTaskArgument<>(nodeIds, arg.toVisorArgs(), false)
+ );
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void printResult(VisorDrCacheTaskResult res, Logger log) {
+ printUnrecognizedNodesMessage(log, false);
+
+ log.info("Data Center ID: " + res.getDataCenterId());
+
+ log.info(DELIM);
+
+ if (res.getDataCenterId() == 0) {
+ log.info("Data Replication state: is not configured.");
+
+ return;
+ }
+
+ List cacheNames = res.getCacheNames();
+ if (cacheNames.isEmpty()) {
+ log.info("No matching caches found");
+
+ return;
+ }
+
+ log.info(String.format("%d matching cache(s): %s", cacheNames.size(), cacheNames));
+
+ for (String cacheName : cacheNames) {
+ List> cacheSndCfg = res.getSenderConfig().get(cacheName);
+
+ printList(log, cacheSndCfg, String.format(
+ "Sender configuration for cache \"%s\":",
+ cacheName
+ ));
+
+ List> cacheRcvCfg = res.getReceiverConfig().get(cacheName);
+
+ printList(log, cacheRcvCfg, String.format(
+ "Receiver configuration for cache \"%s\":",
+ cacheName
+ ));
+ }
+
+ for (String cacheName : cacheNames) {
+ List> cacheSndMetrics = res.getSenderMetrics().get(cacheName);
+
+ printList(log, cacheSndMetrics, String.format(
+ "Sender metrics for cache \"%s\":",
+ cacheName
+ ));
+
+ List> cacheRcvMetrics = res.getReceiverMetrics().get(cacheName);
+
+ printList(log, cacheRcvMetrics, String.format(
+ "Receiver metrics for cache \"%s\":",
+ cacheName
+ ));
+ }
+
+ for (String msg : res.getResultMessages())
+ log.info(msg);
+ }
+
+ /** */
+ private static void printList(Logger log, List> cfg, String s) {
+ if (cfg != null && !cfg.isEmpty()) {
+ log.info(s);
+
+ for (T2 t2 : cfg)
+ log.info(String.format(INDENT + "%s=%s", t2.toArray()));
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override public String name() {
+ return DrSubCommandsList.CACHE.text();
+ }
+
+ /** */
+ @SuppressWarnings("PublicInnerClass") public enum CacheFilter {
+ /** All. */ ALL,
+ /** Sending. */ SENDING,
+ /** Receiving. */ RECEIVING,
+ /** Paused. */ PAUSED,
+ /** Error. */ ERROR
+ }
+
+ /** */
+ @SuppressWarnings("PublicInnerClass") public enum SenderGroup {
+ /** All. */ ALL,
+ /** Default. */ DEFAULT,
+ /** None. */ NONE;
+
+ /** */
+ public static SenderGroup parse(String text) {
+ try {
+ return valueOf(text.toUpperCase(Locale.ENGLISH));
+ }
+ catch (IllegalArgumentException e) {
+ return null;
+ }
+ }
+ }
+
+ /** */
+ @SuppressWarnings("PublicInnerClass") public enum Action {
+ /** Stop. */ STOP("stop"),
+ /** Start. */ START("start"),
+ /** Full state transfer. */ FULL_STATE_TRANSFER("full-state-transfer");
+
+ /** String representation. */
+ private final String text;
+
+ /** */
+ Action(String text) {
+ this.text = text;
+ }
+
+ /** */
+ public String text() {
+ return text;
+ }
+
+ /** */
+ public static Action parse(String text) {
+ for (Action action : values()) {
+ if (action.text.equalsIgnoreCase(text))
+ return action;
+ }
+
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return text;
+ }
+ }
+
+ /** */
+ @SuppressWarnings("PublicInnerClass")
+ public static class DrCacheArguments implements DrAbstractRemoteSubCommand.Arguments {
+ /** Regex. */
+ private final String regex;
+ /** Pattern. */
+ private final Pattern pattern;
+ /** Config. */
+ private final boolean config;
+ /** Metrics. */
+ private final boolean metrics;
+ /** Filter. */
+ private final CacheFilter filter;
+ /** Sender group. */
+ private final SenderGroup senderGroup;
+ /** Sender group name. */
+ private final String senderGroupName;
+ /** Action. */
+ private final Action action;
+ /** Remote data center id. */
+ private final byte remoteDataCenterId;
+ /** Cache names map. */
+ private Map cacheNamesMap;
+ /** Action coordinator. */
+ private UUID actionCoordinator;
+
+ /** */
+ public DrCacheArguments(
+ String regex,
+ Pattern pattern,
+ boolean config,
+ boolean metrics,
+ CacheFilter filter,
+ SenderGroup senderGroup,
+ String senderGroupName,
+ Action action,
+ byte remoteDataCenterId
+ ) {
+ this.regex = regex;
+ this.pattern = pattern;
+ this.config = config;
+ this.metrics = metrics;
+ this.filter = filter;
+ this.senderGroup = senderGroup;
+ this.senderGroupName = senderGroupName;
+ this.action = action;
+ this.remoteDataCenterId = remoteDataCenterId;
+ }
+
+ /** */
+ public UUID getActionCoordinator() {
+ return actionCoordinator;
+ }
+
+ /** {@inheritDoc} */
+ @Override public VisorDrCacheTaskArgs toVisorArgs() {
+ return new VisorDrCacheTaskArgs(
+ regex,
+ config,
+ metrics,
+ filter.ordinal(),
+ senderGroup == null ? VisorDrCacheTaskArgs.SENDER_GROUP_NAMED : senderGroup.ordinal(),
+ senderGroupName,
+ action == null ? VisorDrCacheTaskArgs.ACTION_NONE : action.ordinal(),
+ remoteDataCenterId,
+ cacheNamesMap,
+ actionCoordinator
+ );
+ }
+ }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/dr/subcommands/DrFullStateTransferCommand.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/dr/subcommands/DrFullStateTransferCommand.java
new file mode 100644
index 0000000000000..d038ba894cde5
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/dr/subcommands/DrFullStateTransferCommand.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.commandline.dr.subcommands;
+
+import java.util.logging.Logger;
+import java.util.regex.Pattern;
+import org.apache.ignite.internal.client.GridClient;
+import org.apache.ignite.internal.client.GridClientConfiguration;
+import org.apache.ignite.internal.commandline.CommandArgIterator;
+import org.apache.ignite.internal.commandline.dr.DrSubCommandsList;
+import org.apache.ignite.internal.visor.dr.VisorDrCacheTaskArgs;
+import org.apache.ignite.internal.visor.dr.VisorDrCacheTaskResult;
+
+import static org.apache.ignite.internal.commandline.CommandHandler.DELIM;
+
+/** */
+public class DrFullStateTransferCommand extends
+ DrAbstractRemoteSubCommand
+{
+ /** {@inheritDoc} */
+ @Override protected String visorTaskName() {
+ throw new UnsupportedOperationException("visorTaskName");
+ }
+
+ /** {@inheritDoc} */
+ @Override public DrCacheCommand.DrCacheArguments parseArguments0(CommandArgIterator argIter) {
+ return new DrCacheCommand.DrCacheArguments(
+ ".*",
+ Pattern.compile(".*"),
+ false,
+ false,
+ DrCacheCommand.CacheFilter.SENDING,
+ DrCacheCommand.SenderGroup.ALL,
+ null,
+ DrCacheCommand.Action.FULL_STATE_TRANSFER,
+ (byte)0
+ );
+ }
+
+ /** {@inheritDoc} */
+ @Override public String confirmationPrompt() {
+ return "Warning: this command will execute full state transfer for all caches. This migth take a long time.";
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected VisorDrCacheTaskResult execute0(GridClientConfiguration clientCfg, GridClient client) throws Exception {
+ return DrCacheCommand.execute0(client, arg());
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void printResult(VisorDrCacheTaskResult res, Logger log) {
+ printUnrecognizedNodesMessage(log, false);
+
+ log.info("Data Center ID: " + res.getDataCenterId());
+
+ log.info(DELIM);
+
+ if (res.getDataCenterId() == 0) {
+ log.info("Data Replication state: is not configured.");
+
+ return;
+ }
+
+ if (res.getCacheNames().isEmpty())
+ log.info("No suitable caches found for transfer.");
+ else if (res.getResultMessages().isEmpty())
+ log.info("Full state transfer command completed successfully for caches " + res.getCacheNames());
+ else {
+ for (String msg : res.getResultMessages())
+ log.info(msg);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override public String name() {
+ return DrSubCommandsList.FULL_STATE_TRANSFER.text();
+ }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/dr/subcommands/DrHelpCommand.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/dr/subcommands/DrHelpCommand.java
new file mode 100644
index 0000000000000..94a66fe7a5331
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/dr/subcommands/DrHelpCommand.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.commandline.dr.subcommands;
+
+import java.util.logging.Logger;
+import org.apache.ignite.internal.client.GridClientConfiguration;
+import org.apache.ignite.internal.commandline.Command;
+import org.apache.ignite.internal.commandline.dr.DrCommand;
+import org.apache.ignite.internal.commandline.dr.DrSubCommandsList;
+
+/** */
+public class DrHelpCommand implements Command {
+ /** {@inheritDoc} */
+ @Override public void printUsage(Logger log) {
+ throw new UnsupportedOperationException("printUsage");
+ }
+
+ /** {@inheritDoc} */
+ @Override public Object execute(GridClientConfiguration clientCfg, Logger log) throws Exception {
+ new DrCommand().printUsage(log);
+
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Void arg() {
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ @Override public String name() {
+ return DrSubCommandsList.HELP.text();
+ }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/dr/subcommands/DrNodeCommand.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/dr/subcommands/DrNodeCommand.java
new file mode 100644
index 0000000000000..edf8992f3167b
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/dr/subcommands/DrNodeCommand.java
@@ -0,0 +1,226 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.commandline.dr.subcommands;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Locale;
+import java.util.UUID;
+import java.util.logging.Logger;
+import org.apache.ignite.internal.client.GridClient;
+import org.apache.ignite.internal.client.GridClientCompute;
+import org.apache.ignite.internal.client.GridClientConfiguration;
+import org.apache.ignite.internal.client.GridClientDisconnectedException;
+import org.apache.ignite.internal.client.GridClientNode;
+import org.apache.ignite.internal.commandline.CommandArgIterator;
+import org.apache.ignite.internal.commandline.dr.DrSubCommandsList;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.T2;
+import org.apache.ignite.internal.visor.VisorTaskArgument;
+import org.apache.ignite.internal.visor.dr.VisorDrNodeTaskArgs;
+import org.apache.ignite.internal.visor.dr.VisorDrNodeTaskResult;
+
+import static org.apache.ignite.internal.commandline.CommandHandler.DELIM;
+import static org.apache.ignite.internal.commandline.CommandLogger.INDENT;
+
+/** */
+public class DrNodeCommand
+ extends DrAbstractRemoteSubCommand
+{
+ /** Config parameter. */
+ public static final String CONFIG_PARAM = "--config";
+ /** Metrics parameter. */
+ public static final String METRICS_PARAM = "--metrics";
+ /** Clear store parameter. */
+ public static final String CLEAR_STORE_PARAM = "--clear-store";
+ /** Node Id. */
+ private UUID nodeId;
+
+ /** {@inheritDoc} */
+ @Override protected String visorTaskName() {
+ return "org.gridgain.grid.internal.visor.dr.console.VisorDrNodeTask";
+ }
+
+ /** {@inheritDoc} */
+ @Override public DrNodeArguments parseArguments0(CommandArgIterator argIter) {
+ String nodeIdStr = argIter.nextArg("nodeId value expected.");
+
+ try {
+ nodeId = UUID.fromString(nodeIdStr);
+ }
+ catch (IllegalArgumentException e) {
+ throw new IllegalArgumentException("nodeId must be UUID.", e);
+ }
+
+ boolean config = false;
+ boolean metrics = false;
+ boolean clearStore = false;
+
+ String nextArg;
+
+ //noinspection LabeledStatement
+ args_loop: while ((nextArg = argIter.peekNextArg()) != null) {
+ switch (nextArg.toLowerCase(Locale.ENGLISH)) {
+ case CONFIG_PARAM:
+ config = true;
+
+ break;
+
+ case METRICS_PARAM:
+ metrics = true;
+
+ break;
+
+ case CLEAR_STORE_PARAM:
+ clearStore = true;
+
+ break;
+
+ default:
+ //noinspection BreakStatementWithLabel
+ break args_loop;
+ }
+
+ // Skip peeked argument.
+ argIter.nextArg(null);
+ }
+
+ return new DrNodeArguments(config, metrics, clearStore);
+ }
+
+ /** {@inheritDoc} */
+ @Override public String confirmationPrompt() {
+ if (arg().clearStore)
+ return "Warning: this command will clear DR store.";
+
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ @Override protected VisorDrNodeTaskResult execute0(
+ GridClientConfiguration clientCfg,
+ GridClient client
+ ) throws Exception {
+ GridClientCompute compute = client.compute();
+
+ Collection connectableNodes = compute.nodes(GridClientNode::connectable);
+
+ if (F.isEmpty(connectableNodes))
+ throw new GridClientDisconnectedException("Connectable nodes not found", null);
+
+ GridClientNode node = connectableNodes.stream()
+ .filter(n -> nodeId.equals(n.nodeId()))
+ .findAny().orElse(null);
+
+ if (node == null)
+ node = compute.balancer().balancedNode(connectableNodes);
+
+ return compute.projection(node).execute(
+ visorTaskName(),
+ new VisorTaskArgument<>(nodeId, arg().toVisorArgs(), false)
+ );
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void printResult(VisorDrNodeTaskResult res, Logger log) {
+ log.info("Data Center ID: " + res.getDataCenterId());
+
+ log.info("Node addresses: " + res.getAddresses());
+
+ log.info("Mode=" + res.getMode() + (res.getDataNode() ? ", Baseline node" : ""));
+
+ log.info(DELIM);
+
+ if (res.getDataCenterId() == 0) {
+ log.info("Data Replication state: is not configured.");
+
+ return;
+ }
+
+ List>> sndDataCenters = res.getSenderDataCenters();
+ if (sndDataCenters != null && !sndDataCenters.isEmpty()) {
+ log.info("Node is configured to send data to:");
+
+ for (T2> dataCenter : sndDataCenters)
+ log.info(String.format(INDENT + "DataCenterId=%d, Addresses=%s", dataCenter.toArray()));
+ }
+
+ String receiverAddr = res.getReceiverAddress();
+ if (receiverAddr != null) {
+ log.info("Node is configured to receive data:");
+
+ log.info(INDENT + "Address=" + receiverAddr);
+ }
+
+ if (!res.getResponseMsgs().isEmpty()) {
+ log.info(DELIM);
+
+ for (String responseMsg : res.getResponseMsgs())
+ log.info(responseMsg);
+ }
+
+ printList(log, res.getCommonConfig(), "Common configuration:");
+ printList(log, res.getSenderConfig(), "Sender configuration:");
+ printList(log, res.getReceiverConfig(), "Receiver configuration:");
+
+ printList(log, res.getSenderMetrics(), "Sender metrics:");
+ printList(log, res.getReceiverMetrics(), "Receiver metrics:");
+ }
+
+ /** */
+ private static void printList(Logger log, List> cfg, String s) {
+ if (cfg != null && !cfg.isEmpty()) {
+ log.info(s);
+
+ for (T2 t2 : cfg)
+ log.info(String.format(INDENT + "%s=%s", t2.toArray()));
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override public String name() {
+ return DrSubCommandsList.NODE.text();
+ }
+
+ /** */
+ @SuppressWarnings("PublicInnerClass")
+ public static class DrNodeArguments implements DrAbstractRemoteSubCommand.Arguments {
+ /** Config. */
+ private final boolean config;
+ /** Metrics. */
+ private final boolean metrics;
+ /** Clear store. */
+ private final boolean clearStore;
+
+ /**
+ * @param config Config.
+ * @param metrics Metrics.
+ * @param clearStore Clear store.
+ */
+ public DrNodeArguments(boolean config, boolean metrics, boolean clearStore) {
+ this.config = config;
+ this.metrics = metrics;
+ this.clearStore = clearStore;
+ }
+
+ /** {@inheritDoc} */
+ @Override public VisorDrNodeTaskArgs toVisorArgs() {
+ return new VisorDrNodeTaskArgs(config, metrics, clearStore);
+ }
+ }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/dr/subcommands/DrPauseCommand.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/dr/subcommands/DrPauseCommand.java
new file mode 100644
index 0000000000000..4ac1098dd829b
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/dr/subcommands/DrPauseCommand.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.commandline.dr.subcommands;
+
+import java.util.logging.Logger;
+import java.util.regex.Pattern;
+import org.apache.ignite.internal.client.GridClient;
+import org.apache.ignite.internal.client.GridClientConfiguration;
+import org.apache.ignite.internal.commandline.CommandArgIterator;
+import org.apache.ignite.internal.commandline.dr.DrSubCommandsList;
+import org.apache.ignite.internal.visor.dr.VisorDrCacheTaskArgs;
+import org.apache.ignite.internal.visor.dr.VisorDrCacheTaskResult;
+
+import static org.apache.ignite.internal.commandline.CommandHandler.DELIM;
+
+/** */
+public class DrPauseCommand extends
+ DrAbstractRemoteSubCommand
+{
+ /** {@inheritDoc} */
+ @Override protected String visorTaskName() {
+ throw new UnsupportedOperationException("visorTaskName");
+ }
+
+ /** {@inheritDoc} */
+ @Override public DrCacheCommand.DrCacheArguments parseArguments0(CommandArgIterator argIter) {
+ return new DrCacheCommand.DrCacheArguments(
+ ".*",
+ Pattern.compile(".*"),
+ false,
+ false,
+ DrCacheCommand.CacheFilter.ALL,
+ DrCacheCommand.SenderGroup.ALL,
+ null,
+ DrCacheCommand.Action.STOP,
+ argIter.nextByteArg("remoteDataCenterId")
+ );
+ }
+
+ /** {@inheritDoc} */
+ @Override public String confirmationPrompt() {
+ return "Warning: this command will pause data center replication for all caches.";
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected VisorDrCacheTaskResult execute0(GridClientConfiguration clientCfg, GridClient client) throws Exception {
+ return DrCacheCommand.execute0(client, arg());
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void printResult(VisorDrCacheTaskResult res, Logger log) {
+ printUnrecognizedNodesMessage(log, false);
+
+ log.info("Data Center ID: " + res.getDataCenterId());
+
+ log.info(DELIM);
+
+ if (res.getDataCenterId() == 0) {
+ log.info("Data Replication state: is not configured.");
+
+ return;
+ }
+
+ if (arg().getActionCoordinator() == null)
+ log.info("Cannot find sender hub node to execute action.");
+
+ for (String msg : res.getResultMessages())
+ log.info(msg);
+ }
+
+ /** {@inheritDoc} */
+ @Override public String name() {
+ return DrSubCommandsList.PAUSE.text();
+ }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/dr/subcommands/DrResumeCommand.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/dr/subcommands/DrResumeCommand.java
new file mode 100644
index 0000000000000..878022344bf82
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/dr/subcommands/DrResumeCommand.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.commandline.dr.subcommands;
+
+import java.util.logging.Logger;
+import java.util.regex.Pattern;
+import org.apache.ignite.internal.client.GridClient;
+import org.apache.ignite.internal.client.GridClientConfiguration;
+import org.apache.ignite.internal.commandline.CommandArgIterator;
+import org.apache.ignite.internal.commandline.dr.DrSubCommandsList;
+import org.apache.ignite.internal.visor.dr.VisorDrCacheTaskArgs;
+import org.apache.ignite.internal.visor.dr.VisorDrCacheTaskResult;
+
+import static org.apache.ignite.internal.commandline.CommandHandler.DELIM;
+
+/** */
+public class DrResumeCommand extends
+ DrAbstractRemoteSubCommand
+{
+ /** {@inheritDoc} */
+ @Override protected String visorTaskName() {
+ throw new UnsupportedOperationException("visorTaskName");
+ }
+
+ /** {@inheritDoc} */
+ @Override public DrCacheCommand.DrCacheArguments parseArguments0(CommandArgIterator argIter) {
+ return new DrCacheCommand.DrCacheArguments(
+ ".*",
+ Pattern.compile(".*"),
+ false,
+ false,
+ DrCacheCommand.CacheFilter.ALL,
+ DrCacheCommand.SenderGroup.ALL,
+ null,
+ DrCacheCommand.Action.START,
+ argIter.nextByteArg("remoteDataCenterId")
+ );
+ }
+
+ /** {@inheritDoc} */
+ @Override public String confirmationPrompt() {
+ return "Warning: this command will resume data center replication for all caches.";
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected VisorDrCacheTaskResult execute0(GridClientConfiguration clientCfg, GridClient client) throws Exception {
+ return DrCacheCommand.execute0(client, arg());
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void printResult(VisorDrCacheTaskResult res, Logger log) {
+ printUnrecognizedNodesMessage(log, false);
+
+ log.info("Data Center ID: " + res.getDataCenterId());
+
+ log.info(DELIM);
+
+ if (res.getDataCenterId() == 0) {
+ log.info("Data Replication state: is not configured.");
+
+ return;
+ }
+
+ if (arg().getActionCoordinator() == null)
+ log.info("Cannot find sender hub node to execute action.");
+
+ for (String msg : res.getResultMessages())
+ log.info(msg);
+ }
+
+ /** {@inheritDoc} */
+ @Override public String name() {
+ return DrSubCommandsList.RESUME.text();
+ }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/dr/subcommands/DrStateCommand.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/dr/subcommands/DrStateCommand.java
new file mode 100644
index 0000000000000..cda589a6a1f3f
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/dr/subcommands/DrStateCommand.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.commandline.dr.subcommands;
+
+import java.util.logging.Logger;
+import org.apache.ignite.internal.commandline.CommandArgIterator;
+import org.apache.ignite.internal.commandline.dr.DrSubCommandsList;
+import org.apache.ignite.internal.visor.dr.VisorDrStateTaskArgs;
+import org.apache.ignite.internal.visor.dr.VisorDrStateTaskResult;
+
+import static org.apache.ignite.internal.commandline.CommandHandler.DELIM;
+
+/** */
+public class DrStateCommand extends
+ DrAbstractRemoteSubCommand
+{
+ /** Verbose parameter. */
+ public static final String VERBOSE_PARAM = "--verbose";
+
+ /** {@inheritDoc} */
+ @Override protected String visorTaskName() {
+ return "org.gridgain.grid.internal.visor.dr.console.VisorDrStateTask";
+ }
+
+ /** {@inheritDoc} */
+ @Override protected DrStateArguments parseArguments0(CommandArgIterator argIter) {
+ boolean verbose = false;
+
+ if (VERBOSE_PARAM.equalsIgnoreCase(argIter.peekNextArg())) {
+ argIter.nextArg("--verbose is expected");
+
+ verbose = true;
+ }
+
+ return new DrStateArguments(verbose);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void printResult(VisorDrStateTaskResult res, Logger log) {
+ printUnrecognizedNodesMessage(log, false);
+
+ log.info("Data Center ID: " + res.getDataCenterId());
+
+ log.info(DELIM);
+
+ if (res.getDataCenterId() == 0) {
+ log.info("Data Replication state: is not configured.");
+
+ return;
+ }
+
+ for (String msg : res.getResultMessages())
+ log.info(msg);
+ }
+
+ /** {@inheritDoc} */
+ @Override public String name() {
+ return DrSubCommandsList.STATE.text();
+ }
+
+ /** */
+ @SuppressWarnings("PublicInnerClass")
+ public static class DrStateArguments implements DrAbstractRemoteSubCommand.Arguments {
+ /** */
+ public final boolean verbose;
+
+ /** */
+ public DrStateArguments(boolean verbose) {
+ this.verbose = verbose;
+ }
+
+ /** {@inheritDoc} */
+ @Override public VisorDrStateTaskArgs toVisorArgs() {
+ return new VisorDrStateTaskArgs(verbose);
+ }
+ }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/dr/subcommands/DrTopologyCommand.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/dr/subcommands/DrTopologyCommand.java
new file mode 100644
index 0000000000000..cb4b36b67e37a
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/dr/subcommands/DrTopologyCommand.java
@@ -0,0 +1,217 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.commandline.dr.subcommands;
+
+import java.util.List;
+import java.util.Locale;
+import java.util.UUID;
+import java.util.logging.Logger;
+import org.apache.ignite.internal.commandline.CommandArgIterator;
+import org.apache.ignite.internal.commandline.dr.DrSubCommandsList;
+import org.apache.ignite.internal.util.typedef.T2;
+import org.apache.ignite.internal.util.typedef.T3;
+import org.apache.ignite.internal.visor.dr.VisorDrTopologyTaskArgs;
+import org.apache.ignite.internal.visor.dr.VisorDrTopologyTaskResult;
+
+import static org.apache.ignite.internal.commandline.CommandHandler.DELIM;
+import static org.apache.ignite.internal.commandline.CommandLogger.INDENT;
+import static org.apache.ignite.internal.visor.dr.VisorDrTopologyTaskArgs.DATA_NODES_FLAG;
+import static org.apache.ignite.internal.visor.dr.VisorDrTopologyTaskArgs.OTHER_NODES_FLAG;
+import static org.apache.ignite.internal.visor.dr.VisorDrTopologyTaskArgs.RECEIVER_HUBS_FLAG;
+import static org.apache.ignite.internal.visor.dr.VisorDrTopologyTaskArgs.SENDER_HUBS_FLAG;
+
+/** */
+public class DrTopologyCommand extends
+ DrAbstractRemoteSubCommand
+{
+ /** Sender hubs parameter. */
+ public static final String SENDER_HUBS_PARAM = "--sender-hubs";
+ /** Receiver hubs parameter. */
+ public static final String RECEIVER_HUBS_PARAM = "--receiver-hubs";
+ /** Data nodes parameter. */
+ public static final String DATA_NODES_PARAM = "--data-nodes";
+ /** Other nodes parameter. */
+ public static final String OTHER_NODES_PARAM = "--other-nodes";
+
+ /** {@inheritDoc} */
+ @Override protected String visorTaskName() {
+ return "org.gridgain.grid.internal.visor.dr.console.VisorDrTopologyTask";
+ }
+
+ /** {@inheritDoc} */
+ @Override protected DrTopologyArguments parseArguments0(CommandArgIterator argIter) {
+ boolean senderHubs = false;
+ boolean receiverHubs = false;
+ boolean dataNodes = false;
+ boolean otherNodes = false;
+
+ String nextArg;
+
+ //noinspection LabeledStatement
+ args_loop: while ((nextArg = argIter.peekNextArg()) != null) {
+ switch (nextArg.toLowerCase(Locale.ENGLISH)) {
+ case SENDER_HUBS_PARAM:
+ senderHubs = true;
+ break;
+
+ case RECEIVER_HUBS_PARAM:
+ receiverHubs = true;
+ break;
+
+ case DATA_NODES_PARAM:
+ dataNodes = true;
+ break;
+
+ case OTHER_NODES_PARAM:
+ otherNodes = true;
+ break;
+
+ default:
+ //noinspection BreakStatementWithLabel
+ break args_loop;
+ }
+
+ argIter.nextArg(null); // Skip peeked argument.
+ }
+
+ if (!senderHubs && !receiverHubs && !dataNodes && !otherNodes)
+ senderHubs = receiverHubs = dataNodes = otherNodes = true;
+
+ return new DrTopologyArguments(senderHubs, receiverHubs, dataNodes, otherNodes);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void printResult(VisorDrTopologyTaskResult res, Logger log) {
+ log.info("Data Center ID: " + res.getDataCenterId());
+
+ log.info(String.format(
+ "Topology: %d server(s), %d client(s)",
+ res.getServerNodesCount(),
+ res.getClientNodesCount()
+ ));
+
+ if (res.getDataCenterId() == 0) {
+ log.info("Data Replication state: is not configured.");
+
+ return;
+ }
+
+ if (arg().dataNodes) {
+ List> dataNodes = res.getDataNodes();
+
+ if (dataNodes.isEmpty())
+ log.info("Data nodes: not found");
+ else
+ log.info("Data nodes: " + dataNodes.size());
+
+ for (T2 dataNode : dataNodes)
+ log.info(String.format(INDENT + "nodeId=%s, Address=%s", dataNode.toArray()));
+
+ log.info(DELIM);
+ }
+
+ if (arg().senderHubs) {
+ List> senderHubs = res.getSenderHubs();
+
+ if (senderHubs.isEmpty())
+ log.info("Sender hubs: not found");
+ else
+ log.info("Sender hubs: " + senderHubs.size());
+
+ for (T3 senderHub : senderHubs)
+ log.info(String.format(INDENT + "nodeId=%s, Address=%s, Mode=%s", senderHub.toArray()));
+
+ log.info(DELIM);
+ }
+
+ if (arg().receiverHubs) {
+ List> receiverHubs = res.getReceiverHubs();
+
+ if (receiverHubs.isEmpty())
+ log.info("Receiver hubs: not found");
+ else
+ log.info("Receiver hubs: " + receiverHubs.size());
+
+ for (T3 receiverHub : receiverHubs)
+ log.info(String.format(INDENT + "nodeId=%s, Address=%s, Mode=%s", receiverHub.toArray()));
+
+ log.info(DELIM);
+ }
+
+ if (arg().otherNodes) {
+ List> otherNodes = res.getOtherNodes();
+
+ if (otherNodes.isEmpty())
+ log.info("Other nodes: not found");
+ else
+ log.info("Other nodes: " + otherNodes.size());
+
+ for (T3 otherNode : otherNodes)
+ log.info(String.format(INDENT + "nodeId=%s, Address=%s, Mode=%s", otherNode.toArray()));
+
+ log.info(DELIM);
+ }
+
+ printUnrecognizedNodesMessage(log, true);
+ }
+
+ /** {@inheritDoc} */
+ @Override public String name() {
+ return DrSubCommandsList.TOPOLOGY.text();
+ }
+
+ /** */
+ @SuppressWarnings("PublicInnerClass")
+ public static class DrTopologyArguments implements DrAbstractRemoteSubCommand.Arguments {
+ /** */
+ private final boolean senderHubs;
+ /** */
+ private final boolean receiverHubs;
+ /** */
+ private final boolean dataNodes;
+ /** */
+ private final boolean otherNodes;
+
+ /** */
+ public DrTopologyArguments(boolean senderHubs, boolean receiverHubs, boolean dataNodes, boolean otherNodes) {
+ this.senderHubs = senderHubs;
+ this.receiverHubs = receiverHubs;
+ this.dataNodes = dataNodes;
+ this.otherNodes = otherNodes;
+ }
+
+ /** {@inheritDoc} */
+ @Override public VisorDrTopologyTaskArgs toVisorArgs() {
+ int flags = 0;
+
+ if (senderHubs)
+ flags |= SENDER_HUBS_FLAG;
+
+ if (receiverHubs)
+ flags |= RECEIVER_HUBS_FLAG;
+
+ if (dataNodes)
+ flags |= DATA_NODES_FLAG;
+
+ if (otherNodes)
+ flags |= OTHER_NODES_FLAG;
+
+ return new VisorDrTopologyTaskArgs(flags);
+ }
+ }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/dto/IgniteDataTransferObject.java b/modules/core/src/main/java/org/apache/ignite/internal/dto/IgniteDataTransferObject.java
index 3441742dfabd6..3e0f6fb2ece94 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/dto/IgniteDataTransferObject.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/dto/IgniteDataTransferObject.java
@@ -117,7 +117,7 @@ public byte getProtocolVersion() {
@Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
int hdr = in.readInt();
- if ((hdr & MAGIC) != MAGIC)
+ if ((hdr & ~0xFF) != MAGIC)
throw new IOException("Unexpected IgniteDataTransferObject header " +
"[actual=" + Integer.toHexString(hdr) + ", expected=" + Integer.toHexString(MAGIC) + "]");
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/JdbcConnectionValidationTask.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/JdbcConnectionValidationTask.java
index f4a57bf304ad5..d35bfb86c84f1 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/JdbcConnectionValidationTask.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/JdbcConnectionValidationTask.java
@@ -1,11 +1,12 @@
/*
- * Copyright 2019 GridGain Systems, Inc. and Contributors.
+ * 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
*
- * Licensed under the GridGain Community Edition License (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.gridgain.com/products/software/community-edition/gridgain-community-edition-license
+ * 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,
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcBatchUpdateTask.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcBatchUpdateTask.java
index 774f9229babfc..6ea1bd2e494bf 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcBatchUpdateTask.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcBatchUpdateTask.java
@@ -30,7 +30,9 @@
import org.apache.ignite.internal.processors.cache.QueryCursorImpl;
import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode;
import org.apache.ignite.internal.processors.cache.query.SqlFieldsQueryEx;
+import org.apache.ignite.internal.processors.query.IgniteSQLException;
import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.X;
import org.apache.ignite.lang.IgniteCallable;
import org.apache.ignite.resources.IgniteInstanceResource;
@@ -147,7 +149,12 @@ public JdbcBatchUpdateTask(Ignite ignite, String cacheName, String schemaName, S
}
}
catch (Exception ex) {
- throw new BatchUpdateException(Arrays.copyOf(updCntrs, idx), ex);
+ IgniteSQLException sqlEx = X.cause(ex, IgniteSQLException.class);
+
+ if (sqlEx != null)
+ throw new BatchUpdateException(sqlEx.getMessage(), sqlEx.sqlState(), Arrays.copyOf(updCntrs, idx), ex);
+ else
+ throw new BatchUpdateException(Arrays.copyOf(updCntrs, idx), ex);
}
return updCntrs;
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/IgniteMBeansManager.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/IgniteMBeansManager.java
index 757e17d102739..0f4c780223e5e 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/managers/IgniteMBeansManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/IgniteMBeansManager.java
@@ -94,6 +94,7 @@ public IgniteMBeansManager(IgniteKernal kernal) {
* @param idxExecSvc Indexing executor service
* @param callbackExecSvc Callback executor service
* @param qryExecSvc Query executor service
+ * @param rebalanceExecSvc Rebalance executor service.
* @param schemaExecSvc Schema executor service
* @param customExecSvcs Custom named executors
* @throws IgniteCheckedException if fails to register any of the MBeans
@@ -114,6 +115,7 @@ public void registerAllMBeans(
IgniteStripedThreadPoolExecutor callbackExecSvc,
ExecutorService qryExecSvc,
ExecutorService schemaExecSvc,
+ ExecutorService rebalanceExecSvc,
@Nullable final Map customExecSvcs,
WorkersRegistry workersRegistry
) throws IgniteCheckedException {
@@ -158,6 +160,7 @@ public void registerAllMBeans(
registerExecutorMBean("GridCallbackExecutor", callbackExecSvc);
registerExecutorMBean("GridQueryExecutor", qryExecSvc);
registerExecutorMBean("GridSchemaExecutor", schemaExecSvc);
+ registerExecutorMBean("GridRebalanceExecutor", rebalanceExecSvc);
if (idxExecSvc != null)
registerExecutorMBean("GridIndexingExecutor", idxExecSvc);
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoManager.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoManager.java
index 267addb887169..2e9a52bb87963 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoManager.java
@@ -59,6 +59,7 @@
import org.apache.ignite.internal.IgniteClientDisconnectedCheckedException;
import org.apache.ignite.internal.IgniteComponentType;
import org.apache.ignite.internal.IgniteDeploymentCheckedException;
+import org.apache.ignite.internal.IgniteFeatures;
import org.apache.ignite.internal.IgniteInternalFuture;
import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException;
import org.apache.ignite.internal.direct.DirectMessageReader;
@@ -69,6 +70,8 @@
import org.apache.ignite.internal.managers.eventstorage.GridLocalEventListener;
import org.apache.ignite.internal.processors.platform.message.PlatformMessageFilter;
import org.apache.ignite.internal.processors.pool.PoolProcessor;
+import org.apache.ignite.internal.processors.security.OperationSecurityContext;
+import org.apache.ignite.internal.processors.security.SecurityContext;
import org.apache.ignite.internal.processors.timeout.GridTimeoutObject;
import org.apache.ignite.internal.util.GridBoundedConcurrentLinkedHashSet;
import org.apache.ignite.internal.util.StripedCompositeReadWriteLock;
@@ -78,6 +81,7 @@
import org.apache.ignite.internal.util.lang.IgnitePair;
import org.apache.ignite.internal.util.tostring.GridToStringInclude;
import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.T2;
import org.apache.ignite.internal.util.typedef.X;
import org.apache.ignite.internal.util.typedef.internal.LT;
import org.apache.ignite.internal.util.typedef.internal.S;
@@ -96,6 +100,7 @@
import org.apache.ignite.spi.communication.CommunicationListener;
import org.apache.ignite.spi.communication.CommunicationSpi;
import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static org.apache.ignite.events.EventType.EVT_NODE_FAILED;
@@ -103,6 +108,7 @@
import static org.apache.ignite.events.EventType.EVT_NODE_LEFT;
import static org.apache.ignite.internal.GridTopic.TOPIC_COMM_USER;
import static org.apache.ignite.internal.GridTopic.TOPIC_IO_TEST;
+import static org.apache.ignite.internal.IgniteFeatures.IGNITE_SECURITY_PROCESSOR;
import static org.apache.ignite.internal.managers.communication.GridIoPolicy.AFFINITY_POOL;
import static org.apache.ignite.internal.managers.communication.GridIoPolicy.DATA_STREAMER_POOL;
import static org.apache.ignite.internal.managers.communication.GridIoPolicy.IDX_POOL;
@@ -111,6 +117,7 @@
import static org.apache.ignite.internal.managers.communication.GridIoPolicy.P2P_POOL;
import static org.apache.ignite.internal.managers.communication.GridIoPolicy.PUBLIC_POOL;
import static org.apache.ignite.internal.managers.communication.GridIoPolicy.QUERY_POOL;
+import static org.apache.ignite.internal.managers.communication.GridIoPolicy.REBALANCE_POOL;
import static org.apache.ignite.internal.managers.communication.GridIoPolicy.SCHEMA_POOL;
import static org.apache.ignite.internal.managers.communication.GridIoPolicy.SERVICE_POOL;
import static org.apache.ignite.internal.managers.communication.GridIoPolicy.SYSTEM_POOL;
@@ -203,11 +210,7 @@ public class GridIoManager extends GridManagerAdapter {};
/**
* @param ctx Grid kernal context.
@@ -914,7 +917,7 @@ private void format(StringBuilder b, Collection> pairs, SimpleD
}
/**
- * @param nodeId Node ID.
+ * @param nodeId Sender node ID.
* @param msg Message bytes.
* @param msgC Closure to call when message processing finished.
*/
@@ -974,7 +977,11 @@ private void onMessage0(UUID nodeId, GridIoMessage msg, IgniteRunnable msgC) {
// If message is P2P, then process in P2P service.
// This is done to avoid extra waiting and potential deadlocks
// as thread pool may not have any available threads to give.
- byte plc = msg.policy();
+ byte plc = msg.message().policy();
+
+ // If override policy is not defined use sender defined policy.
+ if (plc == GridIoPolicy.UNDEFINED)
+ plc = msg.policy();
switch (plc) {
case P2P_POOL: {
@@ -994,6 +1001,7 @@ private void onMessage0(UUID nodeId, GridIoMessage msg, IgniteRunnable msgC) {
case QUERY_POOL:
case SCHEMA_POOL:
case SERVICE_POOL:
+ case REBALANCE_POOL:
{
if (msg.isOrdered())
processOrderedMessage(nodeId, msg, plc, msgC);
@@ -1048,7 +1056,7 @@ private void processP2PMessage(
assert obj != null;
- invokeListener(msg.policy(), lsnr, nodeId, obj);
+ invokeListener(msg.policy(), lsnr, nodeId, obj, secSubj(msg));
}
finally {
threadProcessingMessage(false, null);
@@ -1090,7 +1098,11 @@ private void processRegularMessage(
processRegularMessage0(msg, nodeId);
}
- finally {
+ catch (Throwable e) {
+ log.error("An error occurred processing the message [msg=" + msg + ", nodeId=" + nodeId + "].", e);
+
+ throw e;
+ } finally {
threadProcessingMessage(false, null);
msgC.run();
@@ -1181,7 +1193,7 @@ private void processRegularMessage0(GridIoMessage msg, UUID nodeId) {
assert obj != null;
- invokeListener(msg.policy(), lsnr, nodeId, obj);
+ invokeListener(msg.policy(), lsnr, nodeId, obj, secSubj(msg));
}
/**
@@ -1543,8 +1555,9 @@ private void unwindMessageSet(GridCommunicationMessageSet msgSet, GridMessageLis
* @param lsnr Listener.
* @param nodeId Node ID.
* @param msg Message.
+ * @param secCtxMsg Security subject that will be used to open a security session.
*/
- private void invokeListener(Byte plc, GridMessageListener lsnr, UUID nodeId, Object msg) {
+ private void invokeListener(Byte plc, GridMessageListener lsnr, UUID nodeId, Object msg, @Nullable T2 secCtxMsg) {
Byte oldPlc = CUR_PLC.get();
boolean change = !F.eq(oldPlc, plc);
@@ -1552,7 +1565,10 @@ private void invokeListener(Byte plc, GridMessageListener lsnr, UUID nodeId, Obj
if (change)
CUR_PLC.set(plc);
- try {
+ SecurityContext secCtx = secCtxMsg != null ? secCtxMsg.get2() : null;
+ UUID newSecSubjId = secCtxMsg != null && secCtxMsg.get1() != null ? secCtxMsg.get1() : nodeId;
+
+ try (OperationSecurityContext s = secCtx != null ? ctx.security().withContext(secCtx) : ctx.security().withContext(newSecSubjId)) {
lsnr.onMessage(nodeId, msg, plc);
}
finally {
@@ -1614,7 +1630,7 @@ private void send(
assert !async || msg instanceof GridIoUserMessage : msg; // Async execution was added only for IgniteMessaging.
assert topicOrd >= 0 || !(topic instanceof GridTopic) : msg;
- GridIoMessage ioMsg = new GridIoMessage(plc, topic, topicOrd, msg, ordered, timeout, skipOnTimeout);
+ GridIoMessage ioMsg = createGridIoMessage(topic, topicOrd, msg, plc, ordered, timeout, skipOnTimeout);
if (locNodeId.equals(node.id())) {
assert plc != P2P_POOL;
@@ -1656,6 +1672,37 @@ else if (async)
}
}
+ /**
+ * @return One of two message wrappers. The first is {@link GridIoMessage}, the second is secured version {@link
+ * GridIoSecurityAwareMessage}.
+ */
+ private @NotNull GridIoMessage createGridIoMessage(
+ Object topic,
+ int topicOrd,
+ Message msg,
+ byte plc,
+ boolean ordered,
+ long timeout,
+ boolean skipOnTimeout) throws IgniteCheckedException {
+ if (ctx.security().enabled() &&
+ IgniteFeatures.allNodesSupports(ctx.discovery().allNodes(), IGNITE_SECURITY_PROCESSOR)) {
+ UUID secSubjId = null;
+
+ SecurityContext secCtx = ctx.security().securityContext();
+ UUID curSecSubjId = secCtx.subject().id();
+
+ if (!locNodeId.equals(curSecSubjId))
+ secSubjId = curSecSubjId;
+
+ //Network optimization
+ byte[] secSubject = secSubjId != null && ctx.discovery().node(secSubjId) == null ? U.marshal(marsh, secCtx) : null;
+
+ return new GridIoSecurityAwareMessage(secSubjId, secSubject, plc, topic, topicOrd, msg, ordered, timeout, skipOnTimeout);
+ }
+
+ return new GridIoMessage(plc, topic, topicOrd, msg, ordered, timeout, skipOnTimeout);
+ }
+
/**
* @param nodeId Id of destination node.
* @param topic Topic to send the message to.
@@ -1964,11 +2011,24 @@ else if (loc) {
}
/**
+ * Subscribe at messages from a topic.
+ *
* @param topic Topic to subscribe to.
* @param p Message predicate.
*/
- @SuppressWarnings("unchecked")
- public void addUserMessageListener(@Nullable final Object topic, @Nullable final IgniteBiPredicate p) {
+ public void addUserMessageListener(final @Nullable Object topic, final @Nullable IgniteBiPredicate p) {
+ addUserMessageListener(topic, p, ctx.localNodeId());
+ }
+
+ /**
+ * @param topic Topic to subscribe to.
+ * @param p Message predicate.
+ */
+ public void addUserMessageListener(
+ final @Nullable Object topic,
+ final @Nullable IgniteBiPredicate p,
+ final UUID nodeId
+ ) {
if (p != null) {
try {
if (p instanceof PlatformMessageFilter)
@@ -1977,7 +2037,7 @@ public void addUserMessageListener(@Nullable final Object topic, @Nullable final
ctx.resource().injectGeneric(p);
addMessageListener(TOPIC_COMM_USER,
- new GridUserMessageListener(topic, (IgniteBiPredicate)p));
+ new GridUserMessageListener(topic, (IgniteBiPredicate)p, nodeId));
}
catch (IgniteCheckedException e) {
throw new IgniteException(e);
@@ -1991,13 +2051,8 @@ public void addUserMessageListener(@Nullable final Object topic, @Nullable final
*/
@SuppressWarnings("unchecked")
public void removeUserMessageListener(@Nullable Object topic, IgniteBiPredicate p) {
- try {
- removeMessageListener(TOPIC_COMM_USER,
- new GridUserMessageListener(topic, (IgniteBiPredicate)p));
- }
- catch (IgniteCheckedException e) {
- throw new IgniteException(e);
- }
+ removeMessageListener(TOPIC_COMM_USER,
+ new GridUserMessageListener(topic, (IgniteBiPredicate)p));
}
/**
@@ -2416,15 +2471,27 @@ private class GridUserMessageListener implements GridMessageListener {
/** User message topic. */
private final Object topic;
+ /** Initial node id. */
+ private final UUID initNodeId;
+
/**
* @param topic User topic.
* @param predLsnr Predicate listener.
- * @throws IgniteCheckedException If failed to inject resources to predicates.
+ * @param initNodeId Node id that registered given listener.
*/
- GridUserMessageListener(@Nullable Object topic, @Nullable IgniteBiPredicate predLsnr)
- throws IgniteCheckedException {
+ GridUserMessageListener(@Nullable Object topic, @Nullable IgniteBiPredicate predLsnr,
+ @Nullable UUID initNodeId) {
this.topic = topic;
this.predLsnr = predLsnr;
+ this.initNodeId = initNodeId;
+ }
+
+ /**
+ * @param topic User topic.
+ * @param predLsnr Predicate listener.
+ */
+ GridUserMessageListener(@Nullable Object topic, @Nullable IgniteBiPredicate predLsnr) {
+ this(topic, predLsnr, null);
}
/** {@inheritDoc} */
@@ -2521,8 +2588,10 @@ private class GridUserMessageListener implements GridMessageListener {
if (msgBody != null) {
if (predLsnr != null) {
- if (!predLsnr.apply(nodeId, msgBody))
- removeMessageListener(TOPIC_COMM_USER, this);
+ try(OperationSecurityContext s = ctx.security().withContext(initNodeId)) {
+ if (!predLsnr.apply(nodeId, msgBody))
+ removeMessageListener(TOPIC_COMM_USER, this);
+ }
}
}
}
@@ -2749,7 +2818,7 @@ void unwind(GridMessageListener lsnr) {
for (GridTuple3 t = msgs.poll(); t != null; t = msgs.poll()) {
try {
- invokeListener(plc, lsnr, nodeId, t.get1().message());
+ invokeListener(plc, lsnr, nodeId, t.get1().message(), secSubj(t.get1()));
}
finally {
if (t.get3() != null)
@@ -3145,4 +3214,31 @@ public long binLatencyMcs() {
return latencyLimit / (1000 * (resLatency.length - 1));
}
}
+
+ /**
+ * @param msg Communication message.
+ * @return A pair that represents a security subject id and security context. The returned value can be {@code null}
+ * in case of security context is not enabled.
+ */
+ private T2 secSubj(GridIoMessage msg) {
+ if (ctx.security().enabled() && msg instanceof GridIoSecurityAwareMessage) {
+ GridIoSecurityAwareMessage secMsg = (GridIoSecurityAwareMessage)msg;
+
+ SecurityContext secCtx = null;
+
+ try {
+ secCtx = secMsg.getSecCtx() != null ? U.unmarshal(marsh, secMsg.getSecCtx(), U.resolveClassLoader(ctx.config())) : null;
+ }
+ catch (IgniteCheckedException e) {
+ log.error("Security context unmarshaled with error.", e);
+ }
+
+ return new T2<>(
+ secMsg.secSubjId(),
+ secCtx
+ );
+ }
+
+ return null;
+ }
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessage.java
index fe61aec834672..fc7cd13d33ea7 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessage.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessage.java
@@ -109,7 +109,7 @@ public GridIoMessage(
/**
* @return Policy.
*/
- byte policy() {
+ @Override public byte policy() {
return plc;
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessageFactory.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessageFactory.java
index 0b296acf194f2..3c3f2a0f59c8d 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessageFactory.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessageFactory.java
@@ -958,6 +958,11 @@ public GridIoMessageFactory(MessageFactory[] ext) {
break;
+ case GridIoSecurityAwareMessage.TYPE_CODE:
+ msg = new GridIoSecurityAwareMessage();
+
+ break;
+
// [-3..119] [124..129] [-23..-28] [-36..-55] - this
// [120..123] - DR
// [-4..-22, -30..-35] - SQL
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoPolicy.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoPolicy.java
index 3f31f92088315..990dfabec667c 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoPolicy.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoPolicy.java
@@ -61,6 +61,9 @@ public class GridIoPolicy {
/** Schema pool. */
public static final byte SCHEMA_POOL = 12;
+ /** Rebalance pool. */
+ public static final byte REBALANCE_POOL = 13;
+
/**
* Defines the range of reserved pools that are not available for plugins.
* @param key The key.
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoSecurityAwareMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoSecurityAwareMessage.java
new file mode 100644
index 0000000000000..825644ddb0bf7
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoSecurityAwareMessage.java
@@ -0,0 +1,163 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.managers.communication;
+
+import java.io.Externalizable;
+import java.nio.ByteBuffer;
+import java.util.UUID;
+import org.apache.ignite.plugin.extensions.communication.Message;
+import org.apache.ignite.plugin.extensions.communication.MessageReader;
+import org.apache.ignite.plugin.extensions.communication.MessageWriter;
+
+/**
+ * Represents a security communication message.
+ */
+public class GridIoSecurityAwareMessage extends GridIoMessage {
+ /** */
+ private static final long serialVersionUID = 0L;
+ /** */
+ public static final short TYPE_CODE = 174;
+
+ /** Security subject id that will be used during message processing on an remote node. */
+ private UUID secSubjId;
+
+ /** Security context transmitting from node initiator of action. */
+ private byte[] secCtx;
+
+ /**
+ * No-op constructor to support {@link Externalizable} interface.
+ * This constructor is not meant to be used for other purposes.
+ */
+ public GridIoSecurityAwareMessage() {
+ // No-op.
+ }
+
+ /**
+ * @param secSubjId Security subject id.
+ * @param plc Policy.
+ * @param topic Communication topic.
+ * @param topicOrd Topic ordinal value.
+ * @param msg Message.
+ * @param ordered Message ordered flag.
+ * @param timeout Timeout.
+ * @param skipOnTimeout Whether message can be skipped on timeout.
+ */
+ public GridIoSecurityAwareMessage(
+ UUID secSubjId,
+ byte[] secSubject,
+ byte plc,
+ Object topic,
+ int topicOrd,
+ Message msg,
+ boolean ordered,
+ long timeout,
+ boolean skipOnTimeout) {
+ super(plc, topic, topicOrd, msg, ordered, timeout, skipOnTimeout);
+
+ this.secSubjId = secSubjId;
+ this.secCtx = secSubject;
+ }
+
+ /**
+ * @return Security subject id.
+ */
+ UUID secSubjId() {
+ return secSubjId;
+ }
+
+ /**
+ * @return Security context
+ */
+ public byte[] getSecCtx() {
+ return secCtx;
+ }
+
+ /** {@inheritDoc} */
+ @Override public short directType() {
+ return TYPE_CODE;
+ }
+
+ /** {@inheritDoc} */
+ @Override public byte fieldsCount() {
+ return 9;
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean writeTo(ByteBuffer buf, MessageWriter writer) {
+ writer.setBuffer(buf);
+
+ if (!super.writeTo(buf, writer))
+ return false;
+
+ if (!writer.isHeaderWritten()) {
+ if (!writer.writeHeader(directType(), fieldsCount()))
+ return false;
+
+ writer.onHeaderWritten();
+ }
+
+ switch (writer.state()) {
+ case 7:
+ if (!writer.writeByteArray("secCtx", secCtx))
+ return false;
+
+ writer.incrementState();
+
+ case 8:
+ if (!writer.writeUuid("secSubjId", secSubjId))
+ return false;
+
+ writer.incrementState();
+
+ }
+
+ return true;
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean readFrom(ByteBuffer buf, MessageReader reader) {
+ reader.setBuffer(buf);
+
+ if (!reader.beforeMessageRead())
+ return false;
+
+ if (!super.readFrom(buf, reader))
+ return false;
+
+ switch (reader.state()) {
+ case 7:
+ secCtx = reader.readByteArray("secCtx");
+
+ if (!reader.isLastRead())
+ return false;
+
+ reader.incrementState();
+
+ case 8:
+ secSubjId = reader.readUuid("secSubjId");
+
+ if (!reader.isLastRead())
+ return false;
+
+ reader.incrementState();
+
+ }
+
+ return reader.afterMessageRead(GridIoSecurityAwareMessage.class);
+ }
+}
\ No newline at end of file
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeployment.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeployment.java
index 3450aa5195c4a..053cc6cad5566 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeployment.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeployment.java
@@ -30,8 +30,10 @@
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicStampedReference;
import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.IgniteException;
import org.apache.ignite.compute.ComputeTask;
import org.apache.ignite.configuration.DeploymentMode;
import org.apache.ignite.internal.processors.task.GridInternal;
@@ -42,6 +44,7 @@
import org.apache.ignite.internal.util.lang.GridTuple;
import org.apache.ignite.internal.util.tostring.GridToStringExclude;
import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.X;
import org.apache.ignite.internal.util.typedef.internal.S;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.lang.IgniteBiTuple;
@@ -457,7 +460,7 @@ public Class> existingDeployedClass(String clsName) {
if (cls == null) {
try {
- cls = Class.forName(clsName, true, clsLdr);
+ cls = U.forName(clsName, clsLdr);
Class> cur = clss.putIfAbsent(clsName, cls);
@@ -478,7 +481,7 @@ public Class> existingDeployedClass(String clsName) {
return cls;
else if (!a.equals(clsName)) {
try {
- cls = Class.forName(a, true, clsLdr);
+ cls = U.forName(a, clsLdr);
}
catch (ClassNotFoundException ignored0) {
continue;
@@ -501,6 +504,10 @@ else if (!a.equals(clsName)) {
}
}
}
+ catch (IgniteException e) {
+ if (!X.hasCause(e, TimeoutException.class))
+ throw e;
+ }
}
return cls;
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeploymentClassLoader.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeploymentClassLoader.java
index ca9ce328b6b5c..531d6c254f0d3 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeploymentClassLoader.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeploymentClassLoader.java
@@ -28,7 +28,9 @@
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.TimeoutException;
import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.IgniteException;
import org.apache.ignite.IgniteLogger;
import org.apache.ignite.cluster.ClusterNode;
import org.apache.ignite.configuration.DeploymentMode;
@@ -37,6 +39,7 @@
import org.apache.ignite.internal.util.GridByteArrayList;
import org.apache.ignite.internal.util.tostring.GridToStringExclude;
import org.apache.ignite.internal.util.tostring.GridToStringInclude;
+import org.apache.ignite.internal.util.typedef.X;
import org.apache.ignite.internal.util.typedef.internal.S;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.lang.IgniteUuid;
@@ -445,6 +448,9 @@ private boolean isLocallyExcluded(String name) {
// Catch Throwable to secure against any errors resulted from
// corrupted class definitions or other user errors.
catch (Exception e) {
+ if (X.hasCause(e, TimeoutException.class))
+ throw e;
+
throw new ClassNotFoundException("Failed to load class due to unexpected error: " + name, e);
}
@@ -581,6 +587,8 @@ private GridByteArrayList sendClassRequest(String name, String path) throws Clas
IgniteCheckedException err = null;
+ TimeoutException te = null;
+
for (UUID nodeId : nodeListCp) {
if (nodeId.equals(ctx.discovery().localNode().id()))
// Skip local node as it is already used as parent class loader.
@@ -598,7 +606,14 @@ private GridByteArrayList sendClassRequest(String name, String path) throws Clas
}
try {
- GridDeploymentResponse res = comm.sendResourceRequest(path, ldrId, node, endTime);
+ GridDeploymentResponse res = null;
+
+ try {
+ res = comm.sendResourceRequest(path, ldrId, node, endTime);
+ }
+ catch (TimeoutException e) {
+ te = e;
+ }
if (res == null) {
String msg = "Failed to send class-loading request to node (is node alive?) [node=" +
@@ -657,12 +672,28 @@ else if (log.isDebugEnabled())
}
}
+ if (te != null) {
+ err.addSuppressed(te);
+
+ throw new IgniteException(err);
+ }
+
throw new ClassNotFoundException("Failed to peer load class [class=" + name + ", nodeClsLdrs=" +
nodeLdrMapCp + ", parentClsLoader=" + getParent() + ']', err);
}
/** {@inheritDoc} */
@Nullable @Override public InputStream getResourceAsStream(String name) {
+ try {
+ return getResourceAsStreamEx(name);
+ }
+ catch (TimeoutException ignore) {
+ return null;
+ }
+ }
+
+ /** */
+ @Nullable public InputStream getResourceAsStreamEx(String name) throws TimeoutException {
assert !Thread.holdsLock(mux);
if (byteMap != null && name.endsWith(".class")) {
@@ -702,7 +733,7 @@ else if (log.isDebugEnabled())
* @param name Resource name.
* @return InputStream for resource or {@code null} if resource could not be found.
*/
- @Nullable private InputStream sendResourceRequest(String name) {
+ @Nullable private InputStream sendResourceRequest(String name) throws TimeoutException {
assert !Thread.holdsLock(mux);
long endTime = computeEndTime(p2pTimeout);
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeploymentCommunication.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeploymentCommunication.java
index e14c8dfafcb10..973c51ecfe02f 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeploymentCommunication.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeploymentCommunication.java
@@ -22,6 +22,7 @@
import java.util.Collection;
import java.util.HashSet;
import java.util.UUID;
+import java.util.concurrent.TimeoutException;
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.IgniteLogger;
import org.apache.ignite.cluster.ClusterNode;
@@ -355,7 +356,7 @@ void sendUndeployRequest(String rsrcName, Collection rmtNodes) thro
*/
@SuppressWarnings({"SynchronizationOnLocalVariableOrMethodParameter"})
GridDeploymentResponse sendResourceRequest(final String rsrcName, IgniteUuid clsLdrId,
- final ClusterNode dstNode, long threshold) throws IgniteCheckedException {
+ final ClusterNode dstNode, long threshold) throws IgniteCheckedException, TimeoutException {
assert rsrcName != null;
assert dstNode != null;
assert clsLdrId != null;
@@ -472,13 +473,21 @@ GridDeploymentResponse sendResourceRequest(final String rsrcName, IgniteUuid cls
timeout = threshold - U.currentTimeMillis();
}
+
+ if (timeout <= 0)
+ throw new TimeoutException();
}
catch (InterruptedException e) {
// Interrupt again to get it in the users code.
Thread.currentThread().interrupt();
- throw new IgniteCheckedException("Got interrupted while waiting for response from node: " +
- dstNode.id(), e);
+ TimeoutException te = new TimeoutException(
+ "Got interrupted while waiting for response from node: " + dstNode.id()
+ );
+
+ te.initCause(e);
+
+ throw te;
}
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeploymentLocalStore.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeploymentLocalStore.java
index b27cc4bd0275f..1d36571e7b1bd 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeploymentLocalStore.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeploymentLocalStore.java
@@ -188,7 +188,7 @@ class GridDeploymentLocalStore extends GridDeploymentStoreAdapter {
// Check that class can be loaded.
String clsName = meta.className();
- Class> cls = Class.forName(clsName != null ? clsName : alias, true, ldr);
+ Class> cls = U.forName(clsName != null ? clsName : alias, ldr);
spi.register(ldr, cls);
@@ -227,6 +227,11 @@ class GridDeploymentLocalStore extends GridDeploymentStoreAdapter {
return dep;
}
+ /** {@inheritDoc} */
+ @Override public GridDeployment searchDeploymentCache(GridDeploymentMetadata meta) {
+ return deployment(meta.alias());
+ }
+
/**
* @param alias Class alias.
* @return Deployment.
@@ -446,7 +451,7 @@ private void recordDeployFailed(Class> cls, ClassLoader clsLdr, boolean record
evt.message(msg);
evt.node(ctx.discovery().localNode());
- evt.type(isTask(cls) ? EVT_CLASS_DEPLOY_FAILED : EVT_TASK_DEPLOY_FAILED);
+ evt.type(isTask ? EVT_CLASS_DEPLOY_FAILED : EVT_TASK_DEPLOY_FAILED);
evt.alias(taskName);
ctx.event().record(evt);
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeploymentManager.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeploymentManager.java
index 01d8604ceaffd..04cfd60610b42 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeploymentManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeploymentManager.java
@@ -458,6 +458,11 @@ else if (locDep != null) {
}
}
+ GridDeployment dep = verStore.searchDeploymentCache(meta);
+
+ if (dep != null)
+ return dep;
+
if (reuse) {
GridDeployment locDep = locStore.getDeployment(meta);
@@ -496,7 +501,12 @@ else if (locDep != null) {
// Private or Isolated mode.
meta.record(false);
- GridDeployment dep = locStore.getDeployment(meta);
+ GridDeployment dep = ldrStore.searchDeploymentCache(meta);
+
+ if (dep != null)
+ return dep;
+
+ dep = locStore.getDeployment(meta);
if (sndNodeId.equals(ctx.localNodeId())) {
if (dep == null)
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeploymentPerLoaderStore.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeploymentPerLoaderStore.java
index 4ba308c9ef6ef..0477523949fce 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeploymentPerLoaderStore.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeploymentPerLoaderStore.java
@@ -219,7 +219,7 @@ public class GridDeploymentPerLoaderStore extends GridDeploymentStoreAdapter {
IsolatedDeployment dep;
synchronized (mux) {
- dep = cache.get(meta.classLoaderId());
+ dep = (IsolatedDeployment)searchDeploymentCache(meta);
if (dep == null) {
long undeployTimeout = 0;
@@ -331,6 +331,11 @@ else if (d.sequenceNumber() > meta.sequenceNumber()) {
return dep;
}
+ /** {@inheritDoc} */
+ @Override public GridDeployment searchDeploymentCache(GridDeploymentMetadata meta) {
+ return cache.get(meta.classLoaderId());
+ }
+
/** {@inheritDoc} */
@Override public void addParticipants(Map allParticipants,
Map addedParticipants) {
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeploymentPerVersionStore.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeploymentPerVersionStore.java
index 56a3f3e026fb0..0c5964d8fdbeb 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeploymentPerVersionStore.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeploymentPerVersionStore.java
@@ -29,6 +29,7 @@
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.TimeoutException;
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.configuration.DeploymentMode;
import org.apache.ignite.events.DeploymentEvent;
@@ -277,6 +278,24 @@ else if (log.isDebugEnabled())
}
}
+ /** {@inheritDoc} */
+ @Override public GridDeployment searchDeploymentCache(GridDeploymentMetadata meta) {
+ synchronized (mux) {
+ List deps = cache.get(meta.userVersion());
+
+ if (deps != null) {
+ assert !deps.isEmpty();
+
+ for (SharedDeployment d : deps) {
+ if (d.hasParticipant(meta.senderNodeId(), meta.classLoaderId()))
+ return d;
+ }
+ }
+ }
+
+ return null;
+ }
+
/** {@inheritDoc} */
@Override @Nullable public GridDeployment getDeployment(GridDeploymentMetadata meta) {
assert meta != null;
@@ -356,22 +375,14 @@ else if (ctx.discovery().node(meta.senderNodeId()) == null) {
return null;
}
- List deps = cache.get(meta.userVersion());
+ dep = (SharedDeployment)searchDeploymentCache(meta);
- if (deps != null) {
- assert !deps.isEmpty();
+ if (dep == null) {
+ List deps = cache.get(meta.userVersion());
- for (SharedDeployment d : deps) {
- if (d.hasParticipant(meta.senderNodeId(), meta.classLoaderId()) ||
- meta.senderNodeId().equals(ctx.localNodeId())) {
- // Done.
- dep = d;
+ if (deps != null) {
+ assert !deps.isEmpty();
- break;
- }
- }
-
- if (dep == null) {
checkRedeploy(meta);
// Find existing deployments that need to be checked
@@ -413,12 +424,12 @@ else if (ctx.discovery().node(meta.senderNodeId()) == null) {
deps.add(dep);
}
}
- }
- else {
- checkRedeploy(meta);
+ else {
+ checkRedeploy(meta);
- // Create peer class loader.
- dep = createNewDeployment(meta, true);
+ // Create peer class loader.
+ dep = createNewDeployment(meta, true);
+ }
}
}
@@ -689,7 +700,7 @@ private boolean checkLoadRemoteClass(String clsName, GridDeploymentMetadata meta
return false;
// Temporary class loader.
- ClassLoader temp = new GridDeploymentClassLoader(
+ GridDeploymentClassLoader temp = new GridDeploymentClassLoader(
IgniteUuid.fromUuid(ctx.localNodeId()),
meta.userVersion(),
meta.deploymentMode(),
@@ -712,7 +723,14 @@ private boolean checkLoadRemoteClass(String clsName, GridDeploymentMetadata meta
InputStream rsrcIn = null;
try {
- rsrcIn = temp.getResourceAsStream(path);
+ boolean timeout = false;
+
+ try {
+ rsrcIn = temp.getResourceAsStreamEx(path);
+ }
+ catch (TimeoutException e) {
+ timeout = true;
+ }
boolean found = rsrcIn != null;
@@ -732,7 +750,7 @@ private boolean checkLoadRemoteClass(String clsName, GridDeploymentMetadata meta
return false;
}
- else
+ else if (!timeout)
// Cache result if classloader is still alive.
ldrRsrcCache.put(clsName, found);
}
@@ -1190,8 +1208,6 @@ boolean hasParticipant(UUID nodeId, IgniteUuid ldrId) {
assert nodeId != null;
assert ldrId != null;
- assert Thread.holdsLock(mux);
-
return classLoader().hasRegisteredNode(nodeId, ldrId);
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeploymentStore.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeploymentStore.java
index 07e1e22750a5f..d529eaf47a1b9 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeploymentStore.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeploymentStore.java
@@ -58,6 +58,12 @@ public interface GridDeploymentStore {
*/
@Nullable public GridDeployment getDeployment(GridDeploymentMetadata meta);
+ /**
+ * @param meta Deployment meatdata.
+ * @return Grid deployment instance if it was finded in cache, {@code null} otherwise.
+ */
+ @Nullable public GridDeployment searchDeploymentCache(GridDeploymentMetadata meta);
+
/**
* Gets class loader based on ID.
*
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java
index 0fed03ce86542..748261608cc5c 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java
@@ -2600,6 +2600,23 @@ public void resolveCommunicationError(ClusterNode node, Exception err) {
((IgniteDiscoverySpi)spi).resolveCommunicationFailure(node, err);
}
+ /**
+ * Resolves by ID cluster node which is alive or has recently left the cluster.
+ *
+ * @param nodeId Node id.
+ * @return resolved node, or null if node not found.
+ */
+ public ClusterNode historicalNode(UUID nodeId) {
+ for (DiscoCache discoCache : discoCacheHist.descendingValues()) {
+ ClusterNode node = discoCache.node(nodeId);
+
+ if (node != null)
+ return node;
+ }
+
+ return null;
+ }
+
/** Worker for network segment checks. */
private class SegmentCheckWorker extends GridWorker {
/** */
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/IncompleteDeserializationException.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/IncompleteDeserializationException.java
new file mode 100644
index 0000000000000..5a440cefa1cca
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/IncompleteDeserializationException.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.managers.discovery;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Exception which can be used to access a message which failed to be deserialized completely using Java serialization.
+ * Throwed from deserialization methods it can be caught by a caller.
+ *
+ * Should be {@link RuntimeException} because of limitations of Java serialization mechanisms.
+ *
+ * Catching {@link ClassNotFoundException} inside deserialization methods cannot do the same trick because
+ * Java deserialization remembers such exception internally and will rethrow it anyway upon returing to a user.
+ */
+public class IncompleteDeserializationException extends RuntimeException {
+ /** */
+ private static final long serialVersionUID = 0L;
+
+ /** */
+ private final DiscoveryCustomMessage m;
+
+ /**
+ * @param m Message.
+ */
+ public IncompleteDeserializationException(@NotNull DiscoveryCustomMessage m) {
+ super(null, null, false, false);
+
+ this.m = m;
+ }
+
+ /**
+ * @return Message.
+ */
+ @NotNull public DiscoveryCustomMessage message() {
+ return m;
+ }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/eventstorage/GridEventStorageManager.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/eventstorage/GridEventStorageManager.java
index 793b4fc20a97e..92963403f97f6 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/managers/eventstorage/GridEventStorageManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/eventstorage/GridEventStorageManager.java
@@ -72,9 +72,12 @@
import static org.apache.ignite.events.EventType.EVTS_ALL;
import static org.apache.ignite.events.EventType.EVTS_DISCOVERY_ALL;
+import static org.apache.ignite.events.EventType.EVT_JOB_MAPPED;
import static org.apache.ignite.events.EventType.EVT_NODE_FAILED;
import static org.apache.ignite.events.EventType.EVT_NODE_LEFT;
import static org.apache.ignite.events.EventType.EVT_NODE_METRICS_UPDATED;
+import static org.apache.ignite.events.EventType.EVT_TASK_FAILED;
+import static org.apache.ignite.events.EventType.EVT_TASK_FINISHED;
import static org.apache.ignite.internal.GridTopic.TOPIC_EVENT;
import static org.apache.ignite.internal.events.DiscoveryCustomEvent.EVT_DISCOVERY_CUSTOM_EVT;
import static org.apache.ignite.internal.managers.communication.GridIoPolicy.PUBLIC_POOL;
@@ -375,7 +378,7 @@ public int[] enabledEvents() {
public synchronized void enableEvents(int[] types) {
assert types != null;
- ctx.security().authorize(null, SecurityPermission.EVENTS_ENABLE, null);
+ ctx.security().authorize(SecurityPermission.EVENTS_ENABLE);
boolean[] userRecordableEvts0 = userRecordableEvts;
boolean[] recordableEvts0 = recordableEvts;
@@ -418,7 +421,7 @@ public synchronized void enableEvents(int[] types) {
public synchronized void disableEvents(int[] types) {
assert types != null;
- ctx.security().authorize(null, SecurityPermission.EVENTS_DISABLE, null);
+ ctx.security().authorize(SecurityPermission.EVENTS_DISABLE);
boolean[] userRecordableEvts0 = userRecordableEvts;
boolean[] recordableEvts0 = recordableEvts;
@@ -507,7 +510,16 @@ private boolean isHiddenEvent(int type) {
* @return {@code true} if this is an internal event.
*/
private boolean isInternalEvent(int type) {
- return type == EVT_DISCOVERY_CUSTOM_EVT || F.contains(EVTS_DISCOVERY_ALL, type);
+ switch (type) {
+ case EVT_DISCOVERY_CUSTOM_EVT:
+ case EVT_TASK_FINISHED:
+ case EVT_TASK_FAILED:
+ case EVT_JOB_MAPPED:
+ return true;
+
+ default:
+ return F.contains(EVTS_DISCOVERY_ALL, type);
+ }
}
/**
@@ -562,13 +574,8 @@ public boolean hasListener(int type) {
public boolean isAllUserRecordable(int[] types) {
assert types != null;
- boolean[] userRecordableEvts0 = userRecordableEvts;
-
for (int type : types) {
- if (type < 0 || type >= len)
- throw new IllegalArgumentException("Invalid event type: " + type);
-
- if (!userRecordableEvts0[type])
+ if (!isUserRecordable(type))
return false;
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/FullPageId.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/FullPageId.java
index 17c552d9ddecf..fce50a90e3c8b 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/FullPageId.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/FullPageId.java
@@ -123,6 +123,13 @@ public long pageId() {
return pageId;
}
+ /**
+ * @return Effective page ID.
+ */
+ public long effectivePageId() {
+ return effectivePageId;
+ }
+
/**
* @return Cache group ID.
*/
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/IgniteWriteAheadLogManager.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/IgniteWriteAheadLogManager.java
index 56ddf5a1b5338..83c01d76d57cc 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/IgniteWriteAheadLogManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/IgniteWriteAheadLogManager.java
@@ -72,8 +72,10 @@ public interface IgniteWriteAheadLogManager extends GridCacheSharedManager, Igni
* @throws IgniteCheckedException If failed to write.
* @throws StorageException If IO exception occurred during the write. If an exception is thrown from this
* method, the WAL will be invalidated and the node will be stopped.
+ * @return Last WAL position which was flushed to WAL segment file. May be greater than or equal to a {@code ptr}.
+ * May be {@code null}, it means nothing has been flushed.
*/
- public void flush(WALPointer ptr, boolean explicitFsync) throws IgniteCheckedException, StorageException;
+ public WALPointer flush(WALPointer ptr, boolean explicitFsync) throws IgniteCheckedException, StorageException;
/**
* Reads WAL record by the specified pointer.
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/PageSnapshot.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/PageSnapshot.java
index 1aa065e10df40..8957d9b6ec27b 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/PageSnapshot.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/PageSnapshot.java
@@ -19,8 +19,6 @@
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
-import java.util.Arrays;
-import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.internal.pagemem.FullPageId;
import org.apache.ignite.internal.processors.cache.persistence.tree.io.PageIO;
import org.apache.ignite.internal.util.GridUnsafe;
@@ -92,10 +90,6 @@ public FullPageId fullPageId() {
+ "],\nsuper = ["
+ super.toString() + "]]";
}
- catch (IgniteCheckedException ignored) {
- return "Error during call'toString' of PageSnapshot [fullPageId=" + fullPageId() +
- ", pageData = " + Arrays.toString(pageData) + ", super=" + super.toString() + "]";
- }
finally {
GridUnsafe.cleanDirectBuffer(buf);
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/WALRecord.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/WALRecord.java
index 0031b22efa478..87ca9d689f9c4 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/WALRecord.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/WALRecord.java
@@ -32,126 +32,126 @@ public abstract class WALRecord {
*/
public enum RecordType {
/** */
- TX_RECORD,
+ TX_RECORD (0),
/** */
- PAGE_RECORD,
+ PAGE_RECORD (1),
/** */
- DATA_RECORD,
+ DATA_RECORD (2),
/** Checkpoint (begin) record */
- CHECKPOINT_RECORD,
+ CHECKPOINT_RECORD (3),
/** WAL segment header record. */
- HEADER_RECORD,
+ HEADER_RECORD (4),
// Delta records.
/** */
- INIT_NEW_PAGE_RECORD,
+ INIT_NEW_PAGE_RECORD (5),
/** */
- DATA_PAGE_INSERT_RECORD,
+ DATA_PAGE_INSERT_RECORD (6),
/** */
- DATA_PAGE_INSERT_FRAGMENT_RECORD,
+ DATA_PAGE_INSERT_FRAGMENT_RECORD (7),
/** */
- DATA_PAGE_REMOVE_RECORD,
+ DATA_PAGE_REMOVE_RECORD (8),
/** */
- DATA_PAGE_SET_FREE_LIST_PAGE,
+ DATA_PAGE_SET_FREE_LIST_PAGE (9),
/** */
- BTREE_META_PAGE_INIT_ROOT,
+ BTREE_META_PAGE_INIT_ROOT (10),
/** */
- BTREE_META_PAGE_ADD_ROOT,
+ BTREE_META_PAGE_ADD_ROOT (11),
/** */
- BTREE_META_PAGE_CUT_ROOT,
+ BTREE_META_PAGE_CUT_ROOT (12),
/** */
- BTREE_INIT_NEW_ROOT,
+ BTREE_INIT_NEW_ROOT (13),
/** */
- BTREE_PAGE_RECYCLE,
+ BTREE_PAGE_RECYCLE (14),
/** */
- BTREE_PAGE_INSERT,
+ BTREE_PAGE_INSERT (15),
/** */
- BTREE_FIX_LEFTMOST_CHILD,
+ BTREE_FIX_LEFTMOST_CHILD (16),
/** */
- BTREE_FIX_COUNT,
+ BTREE_FIX_COUNT (17),
/** */
- BTREE_PAGE_REPLACE,
+ BTREE_PAGE_REPLACE (18),
/** */
- BTREE_PAGE_REMOVE,
+ BTREE_PAGE_REMOVE (19),
/** */
- BTREE_PAGE_INNER_REPLACE,
+ BTREE_PAGE_INNER_REPLACE (20),
/** */
- BTREE_FIX_REMOVE_ID,
+ BTREE_FIX_REMOVE_ID (21),
/** */
- BTREE_FORWARD_PAGE_SPLIT,
+ BTREE_FORWARD_PAGE_SPLIT (22),
/** */
- BTREE_EXISTING_PAGE_SPLIT,
+ BTREE_EXISTING_PAGE_SPLIT (23),
/** */
- BTREE_PAGE_MERGE,
+ BTREE_PAGE_MERGE (24),
/** */
- PAGES_LIST_SET_NEXT,
+ PAGES_LIST_SET_NEXT (25),
/** */
- PAGES_LIST_SET_PREVIOUS,
+ PAGES_LIST_SET_PREVIOUS (26),
/** */
- PAGES_LIST_INIT_NEW_PAGE,
+ PAGES_LIST_INIT_NEW_PAGE (27),
/** */
- PAGES_LIST_ADD_PAGE,
+ PAGES_LIST_ADD_PAGE (28),
/** */
- PAGES_LIST_REMOVE_PAGE,
+ PAGES_LIST_REMOVE_PAGE (29),
/** */
- META_PAGE_INIT,
+ META_PAGE_INIT (30),
/** */
- PARTITION_META_PAGE_UPDATE_COUNTERS,
+ PARTITION_META_PAGE_UPDATE_COUNTERS (31),
/** Memory recovering start marker */
- MEMORY_RECOVERY,
+ MEMORY_RECOVERY (32),
/** */
- TRACKING_PAGE_DELTA,
+ TRACKING_PAGE_DELTA (33),
/** Meta page update last successful snapshot id. */
- META_PAGE_UPDATE_LAST_SUCCESSFUL_SNAPSHOT_ID,
+ META_PAGE_UPDATE_LAST_SUCCESSFUL_SNAPSHOT_ID (34),
/** Meta page update last successful full snapshot id. */
- META_PAGE_UPDATE_LAST_SUCCESSFUL_FULL_SNAPSHOT_ID,
+ META_PAGE_UPDATE_LAST_SUCCESSFUL_FULL_SNAPSHOT_ID (35),
/** Meta page update next snapshot id. */
- META_PAGE_UPDATE_NEXT_SNAPSHOT_ID,
+ META_PAGE_UPDATE_NEXT_SNAPSHOT_ID (36),
/** Meta page update last allocated index. */
- META_PAGE_UPDATE_LAST_ALLOCATED_INDEX,
+ META_PAGE_UPDATE_LAST_ALLOCATED_INDEX (37),
/** Partition meta update state. */
- PART_META_UPDATE_STATE,
+ PART_META_UPDATE_STATE (38),
/** Page list meta reset count record. */
- PAGE_LIST_META_RESET_COUNT_RECORD,
+ PAGE_LIST_META_RESET_COUNT_RECORD (39),
/** Switch segment record.
* Marker record for indicate end of segment.
@@ -160,41 +160,74 @@ public enum RecordType {
* that one byte in the end,then we write SWITCH_SEGMENT_RECORD as marker end of segment.
* No need write CRC or WAL pointer for this record. It is byte marker record.
* */
- SWITCH_SEGMENT_RECORD,
+ SWITCH_SEGMENT_RECORD (40),
/** */
- DATA_PAGE_UPDATE_RECORD,
+ DATA_PAGE_UPDATE_RECORD (41),
/** init */
- BTREE_META_PAGE_INIT_ROOT2,
+ BTREE_META_PAGE_INIT_ROOT2 (42),
/** Partition destroy. */
- PARTITION_DESTROY,
+ PARTITION_DESTROY (43),
/** Snapshot record. */
- SNAPSHOT,
+ SNAPSHOT (44),
/** Metastore data record. */
- METASTORE_DATA_RECORD,
+ METASTORE_DATA_RECORD (45),
/** Exchange record. */
- EXCHANGE,
+ EXCHANGE (46),
/** Reserved for future record. */
- RESERVED,
+ RESERVED (47),
/** Rollback tx record. */
- ROLLBACK_TX_RECORD,
+ ROLLBACK_TX_RECORD (57),
/** */
- PARTITION_META_PAGE_UPDATE_COUNTERS_V2;
+ PARTITION_META_PAGE_UPDATE_COUNTERS_V2 (58),
+
+ /** Init root meta page (with flags and created version) */
+ BTREE_META_PAGE_INIT_ROOT_V3 (59);
+
+ /** Index for serialization. Should be consistent throughout all versions. */
+ private final int idx;
+
+ /**
+ * @param idx Index for serialization.
+ */
+ RecordType(int idx) {
+ this.idx = idx;
+ }
+
+ /**
+ * @return Index for serialization.
+ */
+ public int index() {
+ return idx;
+ }
/** */
- private static final RecordType[] VALS = RecordType.values();
+ private static final RecordType[] VALS;
+
+ static {
+ RecordType[] recordTypes = RecordType.values();
+
+ int maxIdx = 0;
+ for (RecordType recordType : recordTypes)
+ maxIdx = Math.max(maxIdx, recordType.idx);
+
+ VALS = new RecordType[maxIdx + 1];
+
+ for (RecordType recordType : recordTypes)
+ VALS[recordType.idx] = recordType;
+ }
/** */
- public static RecordType fromOrdinal(int ord) {
- return ord < 0 || ord >= VALS.length ? null : VALS[ord];
+ public static RecordType fromIndex(int idx) {
+ return idx < 0 || idx >= VALS.length ? null : VALS[idx];
}
/**
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageInitRootInlineFlagsCreatedVersionRecord.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageInitRootInlineFlagsCreatedVersionRecord.java
new file mode 100644
index 0000000000000..1163f1f7e6d05
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageInitRootInlineFlagsCreatedVersionRecord.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.pagemem.wal.record.delta;
+
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.internal.IgniteVersionUtils;
+import org.apache.ignite.internal.pagemem.PageMemory;
+import org.apache.ignite.internal.processors.cache.persistence.tree.io.BPlusMetaIO;
+import org.apache.ignite.internal.util.typedef.internal.S;
+import org.apache.ignite.lang.IgniteProductVersion;
+
+/**
+ *
+ */
+public class MetaPageInitRootInlineFlagsCreatedVersionRecord extends MetaPageInitRootInlineRecord {
+ /** Created version. */
+ private final long flags;
+
+ /** Created version. */
+ private final IgniteProductVersion createdVer;
+
+ /**
+ * @param grpId Cache group ID.
+ * @param pageId Meta page ID.
+ * @param rootId Root id.
+ * @param inlineSize Inline size.
+ */
+ public MetaPageInitRootInlineFlagsCreatedVersionRecord(int grpId, long pageId, long rootId, int inlineSize) {
+ super(grpId, pageId, rootId, inlineSize);
+
+ createdVer = IgniteVersionUtils.VER;
+ flags = BPlusMetaIO.FLAGS_DEFAULT;
+ }
+
+ /**
+ * @param grpId Cache group ID.
+ * @param pageId Meta page ID.
+ * @param rootId Root id.
+ * @param inlineSize Inline size.
+ * @param flags Flags.
+ * @param createdVer The version of ignite that creates this tree.
+ */
+ public MetaPageInitRootInlineFlagsCreatedVersionRecord(int grpId, long pageId, long rootId, int inlineSize,
+ long flags, IgniteProductVersion createdVer) {
+ super(grpId, pageId, rootId, inlineSize);
+
+ this.flags = flags;
+ this.createdVer = createdVer;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void applyDelta(PageMemory pageMem, long pageAddr) throws IgniteCheckedException {
+ super.applyDelta(pageMem, pageAddr);
+
+ BPlusMetaIO io = BPlusMetaIO.VERSIONS.forPage(pageAddr);
+
+ io.initFlagsAndVersion(pageAddr, flags, createdVer);
+ }
+
+ /** {@inheritDoc} */
+ @Override public RecordType type() {
+ return RecordType.BTREE_META_PAGE_INIT_ROOT_V3;
+ }
+
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return S.toString(MetaPageInitRootInlineFlagsCreatedVersionRecord.class, this, "super", super.toString());
+ }
+
+ /**
+ * @return Created version.
+ */
+ public IgniteProductVersion createdVersion() {
+ return createdVer;
+ }
+
+ /**
+ * @return Meta page flags.
+ */
+ public long flags() {
+ return flags;
+ }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/affinity/AffinityTopologyVersion.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/affinity/AffinityTopologyVersion.java
index 2c02f26be6641..3b9119b6d5b92 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/affinity/AffinityTopologyVersion.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/affinity/AffinityTopologyVersion.java
@@ -117,10 +117,26 @@ public int minorTopologyVersion() {
* @param upper Upper bound.
* @return {@code True} if this topology version is within provided bounds (inclusive).
*/
- public boolean isBetween(AffinityTopologyVersion lower, AffinityTopologyVersion upper) {
+ public final boolean isBetween(AffinityTopologyVersion lower, AffinityTopologyVersion upper) {
return compareTo(lower) >= 0 && compareTo(upper) <= 0;
}
+ /**
+ * @param topVer Test version.
+ * @return {@code True} if this topology happens strictly after than {@code topVer}.
+ */
+ public final boolean after(AffinityTopologyVersion topVer) {
+ return compareTo(topVer) > 0;
+ }
+
+ /**
+ * @param topVer Test version.
+ * @return {@code True} if this topology happens strictly before than {@code topVer}.
+ */
+ public final boolean before(AffinityTopologyVersion topVer) {
+ return compareTo(topVer) < 0;
+ }
+
/** {@inheritDoc} */
@Override public void onAckReceived() {
// No-op.
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/affinity/GridAffinityAssignmentCache.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/affinity/GridAffinityAssignmentCache.java
index 6aee4b2b08967..fb5a7b9966ace 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/affinity/GridAffinityAssignmentCache.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/affinity/GridAffinityAssignmentCache.java
@@ -43,6 +43,7 @@
import org.apache.ignite.internal.IgniteInternalFuture;
import org.apache.ignite.internal.managers.discovery.DiscoCache;
import org.apache.ignite.internal.processors.cache.ExchangeDiscoveryEvents;
+import org.apache.ignite.internal.processors.cache.GridCachePartitionExchangeManager;
import org.apache.ignite.internal.processors.cluster.BaselineTopology;
import org.apache.ignite.internal.util.future.GridFutureAdapter;
import org.apache.ignite.internal.util.typedef.F;
@@ -61,11 +62,27 @@
* Affinity cached function.
*/
public class GridAffinityAssignmentCache {
- /** Cleanup history size. */
- private final int MAX_HIST_SIZE = getInteger(IGNITE_AFFINITY_HISTORY_SIZE, 50);
+ /**
+ * Affinity cache will shrink when total number of non-shallow (see {@link HistoryAffinityAssignmentImpl})
+ * historical instances will be greater than value of this constant.
+ */
+ private final int MAX_NON_SHALLOW_HIST_SIZE = getInteger(IGNITE_AFFINITY_HISTORY_SIZE, 25);
- /** Cleanup history links size (calculated by both real entries and shallow copies). */
- private final int MAX_HIST_LINKS_SIZE = MAX_HIST_SIZE * 10;
+ /**
+ * Affinity cache will also shrink when total number of both shallow ({@link HistoryAffinityAssignmentShallowCopy})
+ * and non-shallow (see {@link HistoryAffinityAssignmentImpl}) historical instances will be greater than
+ * value of this constant.
+ */
+ private final int MAX_TOTAL_HIST_SIZE = MAX_NON_SHALLOW_HIST_SIZE * 10;
+
+ /**
+ * Independent of {@link #MAX_NON_SHALLOW_HIST_SIZE} and {@link #MAX_TOTAL_HIST_SIZE}, affinity cache will always
+ * keep this number of non-shallow (see {@link HistoryAffinityAssignmentImpl}) instances.
+ * We need at least one real instance, otherwise we won't be able to get affinity cache for
+ * {@link GridCachePartitionExchangeManager#lastAffinityChangedTopologyVersion} in case cluster has experienced
+ * too many client joins / client leaves / local cache starts.
+ */
+ private final int MIN_NON_SHALLOW_HIST_SIZE = 2;
/** Group name if specified or cache name. */
private final String cacheOrGrpName;
@@ -118,8 +135,8 @@ public class GridAffinityAssignmentCache {
/** Node stop flag. */
private volatile IgniteCheckedException stopErr;
- /** Full history size. */
- private final AtomicInteger fullHistSize = new AtomicInteger();
+ /** Numner of non-shallow (see {@link HistoryAffinityAssignmentImpl}) affinity cache instances. */
+ private final AtomicInteger nonShallowHistSize = new AtomicInteger();
/** */
private final Object similarAffKey;
@@ -270,7 +287,7 @@ public void onReconnected() {
affCache.clear();
- fullHistSize.set(0);
+ nonShallowHistSize.set(0);
head.set(new GridAffinityAssignmentV2(AffinityTopologyVersion.NONE));
@@ -675,8 +692,8 @@ public AffinityAssignment cachedAffinity(
cache = e.getValue();
if (cache == null) {
- throw new IllegalStateException("Getting affinity for too old topology version that is already " +
- "out of history [locNode=" + ctx.discovery().localNode() +
+ throw new IllegalStateException("Getting affinity for topology version earlier than affinity is " +
+ "calculated [locNode=" + ctx.discovery().localNode() +
", grp=" + cacheOrGrpName +
", topVer=" + topVer +
", lastAffChangeTopVer=" + lastAffChangeTopVer +
@@ -686,8 +703,8 @@ public AffinityAssignment cachedAffinity(
}
if (cache.topologyVersion().compareTo(topVer) > 0) {
- throw new IllegalStateException("Getting affinity for topology version earlier than affinity is " +
- "calculated [locNode=" + ctx.discovery().localNode() +
+ throw new IllegalStateException("Getting affinity for too old topology version that is already " +
+ "out of history [locNode=" + ctx.discovery().localNode() +
", grp=" + cacheOrGrpName +
", topVer=" + topVer +
", lastAffChangeTopVer=" + lastAffChangeTopVer +
@@ -803,58 +820,73 @@ private void onHistoryAdded(
cleanupNeeded = true;
if (added.requiresHistoryCleanup())
- fullHistSize.incrementAndGet();
+ nonShallowHistSize.incrementAndGet();
}
else {
if (replaced.requiresHistoryCleanup() != added.requiresHistoryCleanup()) {
if (added.requiresHistoryCleanup()) {
cleanupNeeded = true;
- fullHistSize.incrementAndGet();
+ nonShallowHistSize.incrementAndGet();
}
else
- fullHistSize.decrementAndGet();
+ nonShallowHistSize.decrementAndGet();
}
}
if (!cleanupNeeded)
return;
- int fullSize = fullHistSize.get();
-
- int linksSize = affCache.size();
+ int nonShallowSize = nonShallowHistSize.get();
- int fullRmvCnt = fullSize > MAX_HIST_SIZE ? (MAX_HIST_SIZE / 2) : 0;
+ int totalSize = affCache.size();
- int linksRmvCnt = linksSize > MAX_HIST_LINKS_SIZE ? (MAX_HIST_LINKS_SIZE / 2) : 0;
+ if (shouldContinueCleanup(nonShallowSize, totalSize)) {
+ int initNonShallowSize = nonShallowSize;
- if (fullRmvCnt > 0 || linksRmvCnt > 0) {
Iterator it = affCache.values().iterator();
- AffinityTopologyVersion topVerRmv = null;
-
- while (it.hasNext() && (fullRmvCnt > 0 || linksRmvCnt > 0)) {
+ while (it.hasNext()) {
HistoryAffinityAssignment aff0 = it.next();
- if (aff0.requiresHistoryCleanup()) { // Don't decrement counter in case of fullHistoryCleanupRequired copy remove.
- fullRmvCnt--;
+ if (aff0.requiresHistoryCleanup()) {
+ // We can stop cleanup only on non-shallow item.
+ // Keeping part of shallow items chain if corresponding real item is missing makes no sense.
+ if (!shouldContinueCleanup(nonShallowSize, totalSize)) {
+ nonShallowHistSize.getAndAdd(nonShallowSize - initNonShallowSize);
+
+ // GridAffinityProcessor#affMap has the same size and instance set as #affCache.
+ ctx.affinity().removeCachedAffinity(aff0.topologyVersion());
- fullHistSize.decrementAndGet();
+ return;
+ }
+
+ nonShallowSize--;
}
- linksRmvCnt--;
+ totalSize--;
it.remove();
-
- topVerRmv = aff0.topologyVersion();
}
- topVerRmv = it.hasNext() ? it.next().topologyVersion() : topVerRmv;
-
- ctx.affinity().removeCachedAffinity(topVerRmv);
+ assert false : "All elements have been removed from affinity cache during cleanup";
}
}
+ /**
+ * Checks whether affinity cache size conditions are still unsatisfied.
+ *
+ * @param nonShallowSize Non shallow size.
+ * @param totalSize Total size.
+ * @return true if affinity cache cleanup is not finished yet.
+ */
+ private boolean shouldContinueCleanup(int nonShallowSize, int totalSize) {
+ if (nonShallowSize <= MIN_NON_SHALLOW_HIST_SIZE)
+ return false;
+
+ return nonShallowSize > MAX_NON_SHALLOW_HIST_SIZE || totalSize > MAX_TOTAL_HIST_SIZE;
+ }
+
/**
* @return All initialized versions.
*/
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheAffinitySharedManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheAffinitySharedManager.java
index 9594c40ce8c3b..24e6b195b7a20 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheAffinitySharedManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheAffinitySharedManager.java
@@ -57,11 +57,11 @@
import org.apache.ignite.internal.processors.cache.distributed.dht.preloader.GridDhtPartitionFullMap;
import org.apache.ignite.internal.processors.cache.distributed.dht.preloader.GridDhtPartitionMap;
import org.apache.ignite.internal.processors.cache.distributed.dht.preloader.GridDhtPartitionsExchangeFuture;
-import org.apache.ignite.internal.processors.cache.distributed.dht.preloader.GridDhtPartitionsFullMessage;
import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridClientPartitionTopology;
import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionState;
import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionTopology;
import org.apache.ignite.internal.processors.cluster.DiscoveryDataClusterState;
+import org.apache.ignite.internal.util.GridConcurrentHashSet;
import org.apache.ignite.internal.util.GridLongList;
import org.apache.ignite.internal.util.GridPartitionStateMap;
import org.apache.ignite.internal.util.future.GridCompoundFuture;
@@ -750,17 +750,15 @@ private void scheduleClientChangeMessage(Map startedCaches, Se
/**
* @param fut Exchange future.
- * @param crd Coordinator flag.
* @param exchActions Exchange actions.
*/
public void onCustomMessageNoAffinityChange(
GridDhtPartitionsExchangeFuture fut,
- boolean crd,
@Nullable final ExchangeActions exchActions
) {
final ExchangeDiscoveryEvents evts = fut.context().events();
- forAllCacheGroups(crd, new IgniteInClosureX() {
+ forAllCacheGroups(new IgniteInClosureX() {
@Override public void applyx(GridAffinityAssignmentCache aff) {
if (exchActions != null && exchActions.cacheGroupStopping(aff.groupId()))
return;
@@ -845,7 +843,7 @@ public IgniteInternalFuture> onCacheChangeRequest(
IgniteInternalFuture> res = cachesRegistry.update(exchActions);
// Affinity did not change for existing caches.
- onCustomMessageNoAffinityChange(fut, crd, exchActions);
+ onCustomMessageNoAffinityChange(fut, exchActions);
fut.timeBag().finishGlobalStage("Update caches registry");
@@ -1085,12 +1083,10 @@ public void clearGroupHoldersAndRegistry() {
* Called when received {@link CacheAffinityChangeMessage} which should complete exchange.
*
* @param exchFut Exchange future.
- * @param crd Coordinator flag.
* @param msg Affinity change message.
*/
public void onExchangeChangeAffinityMessage(
GridDhtPartitionsExchangeFuture exchFut,
- boolean crd,
CacheAffinityChangeMessage msg
) {
if (log.isDebugEnabled()) {
@@ -1106,8 +1102,8 @@ public void onExchangeChangeAffinityMessage(
assert assignment != null;
- forAllCacheGroups(crd, new IgniteInClosureX() {
- @Override public void applyx(GridAffinityAssignmentCache aff) throws IgniteCheckedException {
+ forAllCacheGroups(new IgniteInClosureX() {
+ @Override public void applyx(GridAffinityAssignmentCache aff) {
List> idealAssignment = aff.idealAssignment();
assert idealAssignment != null;
@@ -1137,13 +1133,10 @@ public void onExchangeChangeAffinityMessage(
* Called on exchange initiated by {@link CacheAffinityChangeMessage} which sent after rebalance finished.
*
* @param exchFut Exchange future.
- * @param crd Coordinator flag.
* @param msg Message.
- * @throws IgniteCheckedException If failed.
*/
public void onChangeAffinityMessage(
final GridDhtPartitionsExchangeFuture exchFut,
- boolean crd,
final CacheAffinityChangeMessage msg
) {
assert msg.topologyVersion() != null && msg.exchangeId() == null : msg;
@@ -1161,8 +1154,8 @@ public void onChangeAffinityMessage(
final Map deploymentIds = msg.cacheDeploymentIds();
- forAllCacheGroups(crd, new IgniteInClosureX() {
- @Override public void applyx(GridAffinityAssignmentCache aff) throws IgniteCheckedException {
+ forAllCacheGroups(new IgniteInClosureX() {
+ @Override public void applyx(GridAffinityAssignmentCache aff) {
AffinityTopologyVersion affTopVer = aff.lastVersion();
assert affTopVer.topologyVersion() > 0 : affTopVer;
@@ -1222,14 +1215,13 @@ public void onChangeAffinityMessage(
* Called on exchange initiated by client node join/fail.
*
* @param fut Exchange future.
- * @param crd Coordinator flag.
* @throws IgniteCheckedException If failed.
*/
- public void onClientEvent(final GridDhtPartitionsExchangeFuture fut, boolean crd) throws IgniteCheckedException {
+ public void onClientEvent(final GridDhtPartitionsExchangeFuture fut) throws IgniteCheckedException {
boolean locJoin = fut.firstEvent().eventNode().isLocal();
if (!locJoin) {
- forAllCacheGroups(crd, new IgniteInClosureX() {
+ forAllCacheGroups(new IgniteInClosureX() {
@Override public void applyx(GridAffinityAssignmentCache aff) throws IgniteCheckedException {
AffinityTopologyVersion topVer = fut.initialVersion();
@@ -1297,27 +1289,13 @@ private void forAllRegisteredCacheGroups(IgniteInClosureX
}
/**
- * @param crd Coordinator flag.
* @param c Closure.
*/
- private void forAllCacheGroups(boolean crd, IgniteInClosureX c) {
- Collection affinityCaches;
-
- Collection affinityCaches1 = grpHolders.values().stream()
+ private void forAllCacheGroups(IgniteInClosureX c) {
+ Collection affinityCaches = grpHolders.values().stream()
.map(CacheGroupHolder::affinity)
.collect(Collectors.toList());
- Collection affinityCaches2 = cctx.kernalContext().cache().cacheGroups().stream()
- .filter(grp -> !grp.isLocal())
- .filter(grp -> !grp.isRecoveryMode())
- .map(CacheGroupContext::affinity)
- .collect(Collectors.toList());
-
- if (!cctx.localNode().isClient())
- affinityCaches = affinityCaches1;
- else
- affinityCaches = affinityCaches2;
-
try {
U.doInParallel(cctx.kernalContext().getSystemExecutorService(), affinityCaches, t -> {
c.applyx(t);
@@ -1471,21 +1449,19 @@ public GridAffinityAssignmentCache affinity(Integer grpId) {
* Applies affinity diff from the received full message.
*
* @param fut Current exchange future.
- * @param msg Finish exchange message.
+ * @param idealAffDiff Map [Cache group id - Affinity distribution] which contains difference with ideal affinity.
*/
public void applyAffinityFromFullMessage(
final GridDhtPartitionsExchangeFuture fut,
- final GridDhtPartitionsFullMessage msg
+ final Map idealAffDiff
) {
// Please do not use following pattern of code (nodesByOrder, affCache). NEVER.
final Map nodesByOrder = new ConcurrentHashMap<>();
- forAllCacheGroups(false, new IgniteInClosureX() {
- @Override public void applyx(GridAffinityAssignmentCache aff) throws IgniteCheckedException {
+ forAllCacheGroups(new IgniteInClosureX() {
+ @Override public void applyx(GridAffinityAssignmentCache aff) {
ExchangeDiscoveryEvents evts = fut.context().events();
- Map idealAffDiff = msg.idealAffinityDiff();
-
List> idealAssignment = aff.calculate(evts.topologyVersion(), evts, evts.discoveryCache());
CacheGroupAffinityMessage affMsg = idealAffDiff != null ? idealAffDiff.get(aff.groupId()) : null;
@@ -1520,26 +1496,23 @@ public void applyAffinityFromFullMessage(
/**
* @param fut Current exchange future.
- * @param msg Message finish message.
+ * @param receivedAff Map [Cache group id - Affinity distribution] received from coordinator to apply.
* @param resTopVer Result topology version.
+ * @return Set of cache groups with no affinity localed in given {@code receivedAff}.
*/
- public void onLocalJoin(
+ public Set onLocalJoin(
final GridDhtPartitionsExchangeFuture fut,
- GridDhtPartitionsFullMessage msg,
+ final Map receivedAff,
final AffinityTopologyVersion resTopVer
) {
final Set affReq = fut.context().groupsAffinityRequestOnJoin();
- final Map receivedAff = msg.joinedNodeAffinity();
-
- assert F.isEmpty(affReq) || (!F.isEmpty(receivedAff) && receivedAff.size() >= affReq.size())
- : ("Requested and received affinity are different " +
- "[requestedCnt=" + (affReq != null ? affReq.size() : "none") +
- ", receivedCnt=" + (receivedAff != null ? receivedAff.size() : "none") +
- ", msg=" + msg + "]");
-
final Map nodesByOrder = new ConcurrentHashMap<>();
+ // Such cache group may exist if cache is already destroyed on server nodes
+ // and coordinator have no affinity for that group.
+ final Set noAffinityGroups = new GridConcurrentHashSet<>();
+
forAllRegisteredCacheGroups(new IgniteInClosureX() {
@Override public void applyx(CacheGroupDescriptor desc) throws IgniteCheckedException {
ExchangeDiscoveryEvents evts = fut.context().events();
@@ -1555,7 +1528,14 @@ public void onLocalJoin(
CacheGroupAffinityMessage affMsg = receivedAff.get(aff.groupId());
- assert affMsg != null;
+ if (affMsg == null) {
+ noAffinityGroups.add(aff.groupId());
+
+ // Use ideal affinity to resume cache initialize process.
+ calculateAndInit(evts, aff, evts.topologyVersion());
+
+ return;
+ }
List> assignments = affMsg.createAssignments(nodesByOrder, evts.discoveryCache());
@@ -1585,15 +1565,15 @@ else if (grp != null && fut.cacheGroupAddedOnExchange(aff.groupId(), grp.receive
"[grp=" + aff.cacheOrGroupName() + "]");
}
});
+
+ return noAffinityGroups;
}
/**
* @param fut Current exchange future.
* @param crd Coordinator flag.
- * @throws IgniteCheckedException If failed.
*/
- public void onServerJoinWithExchangeMergeProtocol(GridDhtPartitionsExchangeFuture fut, boolean crd)
- throws IgniteCheckedException {
+ public void onServerJoinWithExchangeMergeProtocol(GridDhtPartitionsExchangeFuture fut, boolean crd) {
final ExchangeDiscoveryEvents evts = fut.context().events();
assert fut.context().mergeExchanges();
@@ -1616,7 +1596,6 @@ public void onServerJoinWithExchangeMergeProtocol(GridDhtPartitionsExchangeFutur
/**
* @param fut Current exchange future.
* @return Computed difference with ideal affinity.
- * @throws IgniteCheckedException If failed.
*/
public Map onServerLeftWithExchangeMergeProtocol(
final GridDhtPartitionsExchangeFuture fut) throws IgniteCheckedException {
@@ -1625,9 +1604,7 @@ public Map onServerLeftWithExchangeMergeProt
assert fut.context().mergeExchanges();
assert evts.hasServerLeft();
- Map result = onReassignmentEnforced(fut);
-
- return result;
+ return onReassignmentEnforced(fut);
}
/**
@@ -1819,9 +1796,6 @@ private void fetchAffinityOnJoin(GridDhtPartitionsExchangeFuture fut) throws Ign
forAllRegisteredCacheGroups(new IgniteInClosureX() {
@Override public void applyx(CacheGroupDescriptor desc) throws IgniteCheckedException {
- if (cctx.kernalContext().clientNode() && cctx.cache().cacheGroup(desc.groupId()) == null)
- return; // Skip non-started caches on client nodes.
-
CacheGroupHolder holder = getOrCreateGroupHolder(topVer, desc);
if (fut.cacheGroupAddedOnExchange(desc.groupId(), desc.receivedFrom())) {
@@ -2150,9 +2124,6 @@ private CacheGroupHolder createGroupHolder(
forAllRegisteredCacheGroups(new IgniteInClosureX() {
@Override public void applyx(CacheGroupDescriptor desc) throws IgniteCheckedException {
- if (cctx.localNode().isClient() && cctx.cache().cacheGroup(desc.groupId()) == null)
- return;
-
CacheGroupHolder grpHolder = getOrCreateGroupHolder(evts.topologyVersion(), desc);
// Already calculated.
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheGroupContext.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheGroupContext.java
index 3206bae3c100f..01a5d87ba76fb 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheGroupContext.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheGroupContext.java
@@ -177,6 +177,9 @@ public class CacheGroupContext {
/** */
private volatile boolean hasAtomicCaches;
+ /** Store cache group metrics. */
+ private final CacheGroupMetricsImpl metrics;
+
/**
* @param ctx Context.
* @param grpId Group ID.
@@ -236,6 +239,8 @@ public class CacheGroupContext {
log = ctx.kernalContext().log(getClass());
+ metrics = new CacheGroupMetricsImpl();
+
mxBean = new CacheGroupMetricsMXBeanImpl(this);
if (systemCache()) {
@@ -931,8 +936,6 @@ public void onPartitionEvicted(int part) {
cctx.dr().partitionEvicted(part);
cctx.continuousQueries().onPartitionEvicted(part);
-
- cctx.dataStructures().onPartitionEvicted(part);
}
}
@@ -1107,6 +1110,8 @@ private void processAffinityAssignmentRequest0(UUID nodeId, final GridDhtAffinit
topVer,
assignment.assignment());
+ res.copyTimestamps(req);
+
if (aff.centralizedAffinityFunction()) {
assert assignment.idealAssignment() != null;
@@ -1192,8 +1197,9 @@ public boolean globalWalEnabled() {
*/
public void globalWalEnabled(boolean enabled) {
if (globalWalEnabled != enabled) {
- log.info("Global WAL state for group=" + cacheOrGroupName() +
- " changed from " + globalWalEnabled + " to " + enabled);
+ if (log.isInfoEnabled())
+ log.info("Global WAL state for group=" + cacheOrGroupName() +
+ " changed from " + globalWalEnabled + " to " + enabled);
persistGlobalWalState(enabled);
@@ -1206,8 +1212,9 @@ public void globalWalEnabled(boolean enabled) {
*/
public void localWalEnabled(boolean enabled) {
if (localWalEnabled != enabled){
- log.info("Local WAL state for group=" + cacheOrGroupName() +
- " changed from " + localWalEnabled + " to " + enabled);
+ if (log.isInfoEnabled())
+ log.info("Local WAL state for group=" + cacheOrGroupName() +
+ " changed from " + localWalEnabled + " to " + enabled);
persistLocalWalState(enabled);
@@ -1236,6 +1243,13 @@ public boolean hasAtomicCaches() {
return hasAtomicCaches;
}
+ /**
+ * @return Metrics.
+ */
+ public CacheGroupMetricsImpl metrics0() {
+ return metrics;
+ }
+
/**
* @return Statistics holder to track cache IO operations.
*/
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/CheckpointFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheGroupMetrics.java
similarity index 64%
rename from modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/CheckpointFuture.java
rename to modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheGroupMetrics.java
index 23287f195dc5b..6a79a54d4bda0 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/CheckpointFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheGroupMetrics.java
@@ -15,26 +15,16 @@
* limitations under the License.
*/
-package org.apache.ignite.internal.processors.cache.persistence;
-
-import org.apache.ignite.internal.util.future.GridFutureAdapter;
+package org.apache.ignite.internal.processors.cache;
/**
- * Checkpoint futures.
+ * Cache group metrics.
*/
-public interface CheckpointFuture {
- /**
- * @return Begin future.
- */
- public GridFutureAdapter beginFuture();
-
- /**
- * @return Finish future.
- */
- public GridFutureAdapter finishFuture();
-
+public interface CacheGroupMetrics {
/**
- * @return Checkpoint was already started.
+ * @return Number of partitions need processed for finished indexes create or rebuilding.
+ * It is calculated as the number of local partition minus the processed.
+ * A value of 0 indicates that the index is built.
*/
- public boolean started();
+ public long getIndexBuildCountPartitionsLeft();
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheGroupMetricsImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheGroupMetricsImpl.java
new file mode 100644
index 0000000000000..1eca7cf59f7a7
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheGroupMetricsImpl.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.cache;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * Cache group metrics.
+ */
+public class CacheGroupMetricsImpl implements CacheGroupMetrics {
+ /** Number of partitions need processed for finished indexes create or rebuilding. */
+ private final AtomicLong idxBuildCntPartitionsLeft;
+
+ /** */
+ public CacheGroupMetricsImpl() {
+ idxBuildCntPartitionsLeft = new AtomicLong();
+ }
+
+
+ /** {@inheritDoc} */
+ @Override public long getIndexBuildCountPartitionsLeft() {
+ return idxBuildCntPartitionsLeft.get();
+ }
+
+ /** Set number of partitions need processed for finished indexes create or rebuilding. */
+ public void setIndexBuildCountPartitionsLeft(long idxBuildCntPartitionsLeft) {
+ this.idxBuildCntPartitionsLeft.set(idxBuildCntPartitionsLeft);
+ }
+
+ /**
+ * Commit the complete index building for partition.
+ *
+ * @return Decrement number of partitions need processed for finished indexes create or rebuilding.
+ */
+ public long decrementIndexBuildCountPartitionsLeft() {
+ return idxBuildCntPartitionsLeft.decrementAndGet();
+ }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheGroupMetricsMXBeanImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheGroupMetricsMXBeanImpl.java
index 5ece77f57ba4d..5c6cdfaa4a1c9 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheGroupMetricsMXBeanImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheGroupMetricsMXBeanImpl.java
@@ -359,4 +359,9 @@ private Map> clusterPartitionsMapByState(GridDhtPartitionSt
@Override public long getTotalAllocatedSize() {
return getTotalAllocatedPages() * ctx.dataRegion().pageMemory().pageSize();
}
+
+ /** {@inheritDoc} */
+ @Override public long getIndexBuildCountPartitionsLeft() {
+ return ctx.metrics0().getIndexBuildCountPartitionsLeft();
+ }
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheJoinNodeDiscoveryData.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheJoinNodeDiscoveryData.java
index bb0b59bf9845e..c7a59a4606df7 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheJoinNodeDiscoveryData.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheJoinNodeDiscoveryData.java
@@ -161,6 +161,13 @@ public boolean isStaticallyConfigured() {
return staticallyConfigured;
}
+ /**
+ * @return Long which bits represent some flags.
+ */
+ public long getFlags() {
+ return flags;
+ }
+
/**
* @param ois ObjectInputStream.
*/
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectUtils.java
index aeca79e984809..329f141daee49 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectUtils.java
@@ -20,6 +20,8 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.binary.BinaryObject;
import org.apache.ignite.internal.binary.BinaryUtils;
import org.apache.ignite.internal.util.MutableSingletonList;
import org.apache.ignite.internal.util.typedef.F;
@@ -187,6 +189,32 @@ else if (o instanceof Object[])
return o;
}
+ /**
+ * Checks the cache object is binary object.
+ *
+ * @param o Cache object.
+ * @return {@code true} if the key is binary object. Otherwise (key's type is a platform type) returns false.
+ */
+ public static boolean isBinary(CacheObject o) {
+ return o instanceof BinaryObject
+ || (o instanceof KeyCacheObjectImpl
+ && o.value(null, false) instanceof BinaryObject);
+ }
+
+ /**
+ * @param o Cache object.
+ * @return Binary object.
+ * @throws IgniteException is the object is not binary object (e.g. platform / primitive type)
+ */
+ public static BinaryObject binary(CacheObject o) {
+ if (o instanceof BinaryObject)
+ return (BinaryObject)o;
+ else if (o instanceof KeyCacheObjectImpl && o.value(null, false) instanceof BinaryObject)
+ return o.value(null, false);
+
+ throw new IgniteException("The object is not binary object [obj=" + o + ']');
+ }
+
/**
* Private constructor.
*/
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CachesRegistry.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CachesRegistry.java
index d37f69ca5f6ad..649b4d1ecd20f 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CachesRegistry.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CachesRegistry.java
@@ -31,6 +31,7 @@
import org.apache.ignite.failure.FailureType;
import org.apache.ignite.internal.IgniteInternalFuture;
import org.apache.ignite.internal.util.future.GridFinishedFuture;
+import org.apache.ignite.internal.util.lang.GridPlainRunnable;
import org.apache.ignite.internal.util.typedef.internal.CU;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.jetbrains.annotations.Nullable;
@@ -257,7 +258,11 @@ private IgniteInternalFuture> registerAllCachesAndGroups(
if (cachesToPersist.isEmpty())
return cachesConfPersistFuture = new GridFinishedFuture<>();
- return cachesConfPersistFuture = persistCacheConfigurations(cachesToPersist);
+ List cacheConfigsToPersist = cacheDescriptors.stream()
+ .map(DynamicCacheDescriptor::toStoredData)
+ .collect(Collectors.toList());
+
+ return cachesConfPersistFuture = persistCacheConfigurations(cacheConfigsToPersist);
}
/**
@@ -273,16 +278,12 @@ private boolean shouldPersist(CacheConfiguration, ?> cacheCfg) {
}
/**
- * Persists cache configurations from given {@code cacheDescriptors}.
+ * Persists cache configurations.
*
- * @param cacheDescriptors Cache descriptors to retrieve cache configurations.
+ * @param cacheConfigsToPersist Cache configurations to persist.
* @return Future that will be completed when all cache configurations will be persisted to cache work directory.
*/
- private IgniteInternalFuture> persistCacheConfigurations(List cacheDescriptors) {
- List cacheConfigsToPersist = cacheDescriptors.stream()
- .map(DynamicCacheDescriptor::toStoredData)
- .collect(Collectors.toList());
-
+ private IgniteInternalFuture> persistCacheConfigurations(List cacheConfigsToPersist) {
// Pre-create cache work directories if they don't exist.
for (StoredCacheData data : cacheConfigsToPersist) {
try {
@@ -297,13 +298,15 @@ private IgniteInternalFuture> persistCacheConfigurations(List {
- try {
- for (StoredCacheData data : cacheConfigsToPersist)
- cctx.pageStore().storeCacheData(data, false);
- }
- catch (IgniteCheckedException e) {
- U.error(log, "Error while saving cache configurations on disk", e);
+ return cctx.kernalContext().closure().runLocalSafe(new GridPlainRunnable() {
+ @Override public void run() {
+ try {
+ for (StoredCacheData data : cacheConfigsToPersist)
+ cctx.cache().saveCacheConfiguration(data, false);
+ }
+ catch (IgniteCheckedException e) {
+ U.error(log, "Error while saving cache configurations on disk", e);
+ }
}
});
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java
index 81675bdd85111..a9d68aad0574e 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java
@@ -33,6 +33,7 @@
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
+import java.util.stream.Collectors;
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.IgniteLogger;
import org.apache.ignite.cache.CacheExistsException;
@@ -136,15 +137,13 @@ public ClusterCachesInfo(GridKernalContext ctx) {
* Filters all dynamic cache descriptors and groups that were not presented on node start
* and were received with grid discovery data.
*
- * @param localConfigData node's local cache configurations
- * (both from static config and stored with persistent caches).
- *
+ * @param localCachesOnStart Caches which were already presented on node start.
*/
- public void filterDynamicCacheDescriptors(CacheJoinNodeDiscoveryData localConfigData) {
+ public void filterDynamicCacheDescriptors(Set localCachesOnStart) {
if (ctx.isDaemon())
return;
- filterRegisteredCachesAndCacheGroups(localConfigData.caches());
+ filterRegisteredCachesAndCacheGroups(localCachesOnStart);
List> locJoinStartCaches = locJoinCachesCtx.caches();
@@ -163,14 +162,14 @@ public void filterDynamicCacheDescriptors(CacheJoinNodeDiscoveryData localConfig
*
* @param locCaches Caches from local node configuration (static configuration and persistent caches).
*/
- private void filterRegisteredCachesAndCacheGroups(Map locCaches) {
+ private void filterRegisteredCachesAndCacheGroups(Set locCaches) {
//filter registered caches
Iterator> cachesIter = registeredCaches.entrySet().iterator();
while (cachesIter.hasNext()) {
Map.Entry e = cachesIter.next();
- if (!locCaches.containsKey(e.getKey())) {
+ if (!locCaches.contains(e.getKey())) {
cachesIter.remove();
ctx.discovery().removeCacheFilter(e.getKey());
@@ -1660,6 +1659,53 @@ else if (joiningNodeData instanceof CacheJoinNodeDiscoveryData)
}
}
+ /**
+ * @param data Joining node data.
+ * @return Message with error or null if everything was OK.
+ */
+ public String validateJoiningNodeData(DiscoveryDataBag.JoiningNodeDiscoveryData data) {
+ if (data.hasJoiningNodeData()) {
+ Serializable joiningNodeData = data.joiningNodeData();
+
+ if (joiningNodeData instanceof CacheJoinNodeDiscoveryData) {
+ CacheJoinNodeDiscoveryData joinData = (CacheJoinNodeDiscoveryData)joiningNodeData;
+
+ Set problemCaches = null;
+
+ for (CacheJoinNodeDiscoveryData.CacheInfo cacheInfo : joinData.caches().values()) {
+ CacheConfiguration, ?> cfg = cacheInfo.cacheData().config();
+
+ if (!registeredCaches.containsKey(cfg.getName())) {
+ String conflictErr = checkCacheConflict(cfg);
+
+ if (conflictErr != null) {
+ U.warn(log, "Ignore cache received from joining node. " + conflictErr);
+
+ continue;
+ }
+
+ long flags = cacheInfo.getFlags();
+
+ if (flags == 1L) {
+ if (problemCaches == null)
+ problemCaches = new HashSet<>();
+
+ problemCaches.add(cfg.getName());
+ }
+ }
+ }
+
+ if (!F.isEmpty(problemCaches))
+ return problemCaches.stream().collect(Collectors.joining(", ",
+ "Joining node has caches with data which are not presented on cluster, " +
+ "it could mean that they were already destroyed, to add the node to cluster - " +
+ "remove directories with the caches[", "]"));
+ }
+ }
+
+ return null;
+ }
+
/**
* @param clientData Discovery data.
* @param clientNodeId Client node ID.
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DynamicCacheChangeRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DynamicCacheChangeRequest.java
index 268756238366b..3dbee2a9b140a 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DynamicCacheChangeRequest.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DynamicCacheChangeRequest.java
@@ -394,7 +394,7 @@ public void receivedFrom(UUID nodeId) {
/**
* @return ID of node provided cache configuration in discovery data.
*/
- @Nullable public UUID receivedFrom() {
+ public @Nullable UUID receivedFrom() {
return rcvdFrom;
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheContext.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheContext.java
index 7db59ca58c2fd..fa42caffda2a2 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheContext.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheContext.java
@@ -678,14 +678,14 @@ public boolean isLocal() {
* @return {@code True} if cache is replicated cache.
*/
public boolean isReplicated() {
- return cacheCfg.getCacheMode() == CacheMode.REPLICATED;
+ return config().getCacheMode() == CacheMode.REPLICATED;
}
/**
* @return {@code True} if cache is partitioned cache.
*/
public boolean isPartitioned() {
- return cacheCfg.getCacheMode() == CacheMode.PARTITIONED;
+ return config().getCacheMode() == CacheMode.PARTITIONED;
}
/**
@@ -699,7 +699,7 @@ public boolean isDrEnabled() {
* @return {@code True} in case cache supports query.
*/
public boolean isQueryEnabled() {
- return !F.isEmpty(cacheCfg.getQueryEntities());
+ return !F.isEmpty(config().getQueryEntities());
}
/**
@@ -824,7 +824,7 @@ public void checkSecurity(SecurityPermission op) throws SecurityException {
if (CU.isSystemCache(name()))
return;
- ctx.security().authorize(name(), op, null);
+ ctx.security().authorize(name(), op);
}
/**
@@ -852,14 +852,16 @@ public boolean rebalanceEnabled() {
* @return {@code True} if atomic.
*/
public boolean atomic() {
- return cacheCfg.getAtomicityMode() == ATOMIC;
+ return config().getAtomicityMode() == ATOMIC;
}
/**
* @return {@code True} if transactional.
*/
public boolean transactional() {
- return cacheCfg.getAtomicityMode() == TRANSACTIONAL;
+ CacheConfiguration cfg = config();
+
+ return cfg.getAtomicityMode() == TRANSACTIONAL;
}
/**
@@ -1039,9 +1041,15 @@ public GridCacheAdapter cache() {
/**
* @return Cache configuration for given cache instance.
+ * @throws IllegalStateException If this cache context was cleaned up.
*/
public CacheConfiguration config() {
- return cacheCfg;
+ CacheConfiguration res = cacheCfg;
+
+ if (res == null)
+ throw new IllegalStateException((new CacheStoppedException(name())));
+
+ return res;
}
/**
@@ -1050,7 +1058,7 @@ public CacheConfiguration config() {
* are set to {@code true} or the store is local.
*/
public boolean writeToStoreFromDht() {
- return store().isLocal() || cacheCfg.isWriteBehindEnabled();
+ return store().isLocal() || config().isWriteBehindEnabled();
}
/**
@@ -1502,56 +1510,56 @@ public boolean deploymentEnabled() {
* @return {@code True} if store read-through mode is enabled.
*/
public boolean readThrough() {
- return cacheCfg.isReadThrough() && !skipStore();
+ return config().isReadThrough() && !skipStore();
}
/**
* @return {@code True} if store and read-through mode are enabled in configuration.
*/
public boolean readThroughConfigured() {
- return store().configured() && cacheCfg.isReadThrough();
+ return store().configured() && config().isReadThrough();
}
/**
* @return {@code True} if {@link CacheConfiguration#isLoadPreviousValue()} flag is set.
*/
public boolean loadPreviousValue() {
- return cacheCfg.isLoadPreviousValue();
+ return config().isLoadPreviousValue();
}
/**
* @return {@code True} if store write-through is enabled.
*/
public boolean writeThrough() {
- return cacheCfg.isWriteThrough() && !skipStore();
+ return config().isWriteThrough() && !skipStore();
}
/**
* @return {@code True} if invalidation is enabled.
*/
public boolean isInvalidate() {
- return cacheCfg.isInvalidate();
+ return config().isInvalidate();
}
/**
* @return {@code True} if synchronous commit is enabled.
*/
public boolean syncCommit() {
- return cacheCfg.getWriteSynchronizationMode() == FULL_SYNC;
+ return config().getWriteSynchronizationMode() == FULL_SYNC;
}
/**
* @return {@code True} if synchronous rollback is enabled.
*/
public boolean syncRollback() {
- return cacheCfg.getWriteSynchronizationMode() == FULL_SYNC;
+ return config().getWriteSynchronizationMode() == FULL_SYNC;
}
/**
* @return {@code True} if only primary node should be updated synchronously.
*/
public boolean syncPrimary() {
- return cacheCfg.getWriteSynchronizationMode() == PRIMARY_SYNC;
+ return config().getWriteSynchronizationMode() == PRIMARY_SYNC;
}
/**
@@ -1767,7 +1775,7 @@ public boolean keepBinary() {
* of {@link CacheConfiguration#isCopyOnRead()}.
*/
public boolean needValueCopy() {
- return affNode && cacheCfg.isCopyOnRead();
+ return affNode && config().isCopyOnRead();
}
/**
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheDeploymentManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheDeploymentManager.java
index 3df507a4434ba..56f1592f74a4c 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheDeploymentManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheDeploymentManager.java
@@ -232,8 +232,16 @@ public void onUndeploy(final ClassLoader ldr, final GridCacheContext ctx)
// Unwind immediately for local and replicate caches.
// We go through preloader for proper synchronization.
- if (ctx.isLocal())
- ctx.preloader().unwindUndeploys();
+ if (ctx.isLocal()) {
+ ctx.preloader().pause();
+
+ try {
+ ctx.group().unwindUndeploys();
+ }
+ finally {
+ ctx.preloader().resume();
+ }
+ }
}
/**
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEntryEx.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEntryEx.java
index 1ae1b8d9269d3..4d9bf4795d5cf 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEntryEx.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEntryEx.java
@@ -865,12 +865,11 @@ public Collection localCandidates(@Nullable GridCacheVer
/**
* Update index from within entry lock, passing key, value, and expiration time to provided closure.
*
- * @param filter Row filter.
* @param clo Closure to apply to key, value, and expiration time.
* @throws IgniteCheckedException If failed.
* @throws GridCacheEntryRemovedException If entry was removed.
*/
- public void updateIndex(SchemaIndexCacheFilter filter, SchemaIndexCacheVisitorClosure clo)
+ public void updateIndex(SchemaIndexCacheVisitorClosure clo)
throws IgniteCheckedException, GridCacheEntryRemovedException;
/**
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEventManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEventManager.java
index 726a6c88c1804..c095ebe27fdc7 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEventManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEventManager.java
@@ -20,6 +20,7 @@
import java.util.Collection;
import java.util.UUID;
import org.apache.ignite.cluster.ClusterNode;
+import org.apache.ignite.configuration.CacheConfiguration;
import org.apache.ignite.events.CacheEvent;
import org.apache.ignite.internal.managers.eventstorage.GridLocalEventListener;
import org.apache.ignite.internal.processors.cache.transactions.IgniteInternalTx;
@@ -388,11 +389,18 @@ public boolean isRecordable(int type) {
GridCacheContext cctx0 = cctx;
// Event recording is impossible in recovery mode.
- if (cctx0 != null && cctx0.kernalContext().recoveryMode())
+ if (cctx0 == null || cctx0.kernalContext().recoveryMode())
return false;
- return cctx0 != null && cctx0.userCache() && cctx0.gridEvents().isRecordable(type)
- && !cctx0.config().isEventsDisabled();
+ try {
+ CacheConfiguration cfg = cctx0.config();
+
+ return cctx0.userCache() && cctx0.gridEvents().isRecordable(type) && !cfg.isEventsDisabled();
+ }
+ catch (IllegalStateException e) {
+ // Cache context was cleaned up.
+ return false;
+ }
}
/** {@inheritDoc} */
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEvictionManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEvictionManager.java
index 2853f00d0dd86..33f529279477b 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEvictionManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEvictionManager.java
@@ -27,8 +27,8 @@
import org.apache.ignite.internal.processors.cache.version.GridCacheVersionManager;
import org.apache.ignite.internal.util.GridBusyLock;
import org.apache.ignite.internal.util.typedef.X;
+import org.apache.ignite.internal.util.typedef.internal.LT;
import org.apache.ignite.internal.util.typedef.internal.U;
-import org.apache.ignite.lang.IgniteUuid;
import org.jetbrains.annotations.Nullable;
import static org.apache.ignite.events.EventType.EVT_CACHE_ENTRY_EVICTED;
@@ -313,8 +313,20 @@ private void notifyPolicy(GridCacheEntryEx e) {
if (log.isDebugEnabled())
log.debug("Notifying eviction policy with entry: " + e);
- if (filter == null || filter.evictAllowed(e.wrapLazyValue(cctx.keepBinary())))
- plc.onEntryAccessed(e.obsoleteOrDeleted(), e.wrapEviction());
+ if (filter == null || filter.evictAllowed(e.wrapLazyValue(cctx.keepBinary()))) {
+ try {
+ plc.onEntryAccessed(e.obsoleteOrDeleted(), e.wrapEviction());
+ }
+ catch (RuntimeException ex) {
+ if (!e.obsoleteOrDeleted()) {
+ U.ignoreRuntimeException(() -> plc.onEntryAccessed(true, e.wrapEviction()));
+ e.wrapEviction().evict();
+ }
+
+ LT.warn(log, "Eviction manager caught an error [msg=" + ex.getMessage() + "]." +
+ " Entry [key=" + e.key() + "] wasn't inserted.");
+ }
+ }
}
/** {@inheritDoc} */
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheGateway.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheGateway.java
index 658ca2a8de039..7e1d867c4ec21 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheGateway.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheGateway.java
@@ -133,6 +133,8 @@ public void leaveNoLock() {
ctx.tm().resetContext();
ctx.mvcc().contextReset();
+ ctx.tm().leaveNearTxSystemSection();
+
// Unwind eviction notifications.
if (!ctx.shared().closed(ctx))
CU.unwindEvicts(ctx);
@@ -172,6 +174,8 @@ public void leave() {
onEnter();
+ ctx.tm().enterNearTxSystemSection();
+
Lock lock = rwLock.readLock();
lock.lock();
@@ -239,6 +243,8 @@ public void leaveNoLock(CacheOperationContext prev) {
// Unwind eviction notifications.
CU.unwindEvicts(ctx);
+ ctx.tm().leaveNearTxSystemSection();
+
// Return back previous thread local operation context per call.
ctx.operationContextPerCall(prev);
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheIdMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheIdMessage.java
index e0944397ecf3d..84d890c56dc18 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheIdMessage.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheIdMessage.java
@@ -112,6 +112,6 @@ public void cacheId(int cacheId) {
/** {@inheritDoc} */
@Override public String toString() {
- return S.toString(GridCacheIdMessage.class, this);
+ return S.toString(GridCacheIdMessage.class, this, "super", super.toString());
}
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheIoManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheIoManager.java
index 08af2a39693c1..34495ac012829 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheIoManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheIoManager.java
@@ -229,7 +229,7 @@ else if (desc.receivedFromStartVersion() != null)
else {
AffinityTopologyVersion locAffVer = cctx.exchange().readyAffinityVersion();
- if (locAffVer.compareTo(lastAffChangedVer) < 0) {
+ if (locAffVer.before(lastAffChangedVer)) {
IgniteLogger log = cacheMsg.messageLogger(cctx);
if (log.isDebugEnabled()) {
@@ -413,6 +413,8 @@ private boolean processMissedHandler(UUID nodeId, GridCacheMessage cacheMsg) {
dhtRes.nearEvicted(nearEvicted);
+ dhtRes.copyTimestamps(req);
+
sendMessageForMissedHandler(cacheMsg,
nodeId,
dhtRes,
@@ -752,6 +754,8 @@ private void processFailedMessage(UUID nodeId,
0,
false);
+ res.copyTimestamps(req);
+
sendResponseOnFailedMessage(nodeId, res, cctx, plc);
}
@@ -767,6 +771,8 @@ private void processFailedMessage(UUID nodeId,
req.miniId(),
req.deployInfo() != null);
+ res.copyTimestamps(req);
+
res.error(req.classError());
sendResponseOnFailedMessage(nodeId, res, cctx, req.policy());
@@ -783,6 +789,8 @@ private void processFailedMessage(UUID nodeId,
req.futureId(),
false);
+ res.copyTimestamps(req);
+
res.onError(req.classError());
sendResponseOnFailedMessage(nodeId, res, cctx, plc);
@@ -813,6 +821,8 @@ private void processFailedMessage(UUID nodeId,
false,
false);
+ res.copyTimestamps(req);
+
res.error(req.classError());
sendResponseOnFailedMessage(nodeId, res, cctx, plc);
@@ -830,6 +840,8 @@ private void processFailedMessage(UUID nodeId,
false
);
+ res.copyTimestamps(req);
+
res.error(req.classError());
sendResponseOnFailedMessage(nodeId, res, cctx, plc);
@@ -847,6 +859,8 @@ private void processFailedMessage(UUID nodeId,
req.version(),
req.deployInfo() != null);
+ res.copyTimestamps(req);
+
res.error(req.classError());
sendResponseOnFailedMessage(nodeId, res, cctx, plc);
@@ -885,8 +899,11 @@ private void processFailedMessage(UUID nodeId,
0,
req.classError(),
null,
+ false,
false);
+ res.copyTimestamps(req);
+
sendResponseOnFailedMessage(nodeId, res, cctx, plc);
}
@@ -910,6 +927,8 @@ private void processFailedMessage(UUID nodeId,
res.error(req.classError());
+ res.copyTimestamps(req);
+
sendResponseOnFailedMessage(nodeId, res, cctx, req.policy());
}
@@ -954,6 +973,8 @@ private void processFailedMessage(UUID nodeId,
res.error(req.classError());
+ res.copyTimestamps(req);
+
sendResponseOnFailedMessage(nodeId, res, cctx, plc);
}
@@ -990,6 +1011,8 @@ private void processFailedMessage(UUID nodeId,
false,
false);
+ res.copyTimestamps(req);
+
res.error(req.classError());
sendResponseOnFailedMessage(nodeId, res, cctx, plc);
@@ -1008,6 +1031,8 @@ private void processFailedMessage(UUID nodeId,
false,
false);
+ res.copyTimestamps(req);
+
res.error(req.classError());
sendResponseOnFailedMessage(nodeId, res, cctx, plc);
@@ -1026,6 +1051,8 @@ private void processFailedMessage(UUID nodeId,
false,
false);
+ res.copyTimestamps(req);
+
res.error(req.classError());
sendResponseOnFailedMessage(nodeId, res, cctx, plc);
@@ -1042,6 +1069,8 @@ private void processFailedMessage(UUID nodeId,
req.futureId(),
false);
+ res.copyTimestamps(req);
+
res.onError(req.classError());
sendResponseOnFailedMessage(nodeId, res, cctx, plc);
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMapEntry.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMapEntry.java
index 1fdbed59742e5..f0945d3f804ac 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMapEntry.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMapEntry.java
@@ -96,6 +96,7 @@
import static org.apache.ignite.internal.processors.cache.GridCacheOperation.DELETE;
import static org.apache.ignite.internal.processors.cache.GridCacheOperation.TRANSFORM;
import static org.apache.ignite.internal.processors.cache.GridCacheOperation.UPDATE;
+import static org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionState.RENTING;
import static org.apache.ignite.internal.processors.dr.GridDrType.DR_NONE;
/**
@@ -1124,8 +1125,6 @@ else if (interceptorVal != val0)
null,
topVer);
}
-
- cctx.dataStructures().onEntryUpdated(key, false, keepBinary);
}
finally {
unlockEntry();
@@ -1348,8 +1347,6 @@ else if (log.isDebugEnabled())
topVer);
}
- cctx.dataStructures().onEntryUpdated(key, true, keepBinary);
-
deferred = cctx.deferredDelete() && !detached() && !isInternal();
if (intercept)
@@ -1730,8 +1727,6 @@ else if (ttl != CU.TTL_ZERO)
onUpdateFinished(updateCntr);
}
- cctx.dataStructures().onEntryUpdated(key, op == DELETE, keepBinary);
-
if (intercept) {
if (op == UPDATE)
cctx.config().getInterceptor().onAfterPut(new CacheLazyEntry(cctx, key, key0, updated, updated0, keepBinary, 0L));
@@ -2018,8 +2013,6 @@ else if (ttl != CU.TTL_ZERO)
topVer);
}
- cctx.dataStructures().onEntryUpdated(key, c.op == DELETE, keepBinary);
-
if (intercept && c.wasIntercepted) {
assert c.op == UPDATE || c.op == DELETE : c.op;
@@ -2821,7 +2814,7 @@ private boolean skipInterceptor(@Nullable GridCacheVersion explicitVer) {
val = cctx.kernalContext().cacheObjects().prepareForCache(val, cctx);
- final boolean unswapped = ((flags & IS_UNSWAPPED_MASK) != 0);
+ final boolean unswapped = (flags & IS_UNSWAPPED_MASK) != 0;
boolean update;
@@ -2829,16 +2822,16 @@ private boolean skipInterceptor(@Nullable GridCacheVersion explicitVer) {
@Override public boolean apply(@Nullable CacheDataRow row) {
boolean update0;
- GridCacheVersion currentVer = row != null ? row.version() : GridCacheMapEntry.this.ver;
+ GridCacheVersion currVer = row != null ? row.version() : GridCacheMapEntry.this.ver;
- boolean isStartVer = cctx.shared().versions().isStartVersion(currentVer);
+ boolean isStartVer = cctx.shared().versions().isStartVersion(currVer);
if (cctx.group().persistenceEnabled()) {
if (!isStartVer) {
if (cctx.atomic())
- update0 = ATOMIC_VER_COMPARATOR.compare(currentVer, ver) < 0;
+ update0 = ATOMIC_VER_COMPARATOR.compare(currVer, ver) < 0;
else
- update0 = currentVer.compareTo(ver) < 0;
+ update0 = currVer.compareTo(ver) < 0;
}
else
update0 = true;
@@ -2873,8 +2866,14 @@ else if (val == null)
storeValue(val, expTime, ver);
}
}
- else // Optimization to access storage only once.
- update = storeValue(val, expTime, ver, p);
+ else {
+ // Optimization to access storage only once.
+ UpdateClosure c = storeValue(val, expTime, ver, p);
+
+ // Update if tree is changed or removal is replicated from supplier node and is absent locally.
+ update = c.operationType() != IgniteTree.OperationType.NOOP ||
+ preload && val == null && !c.filtered() && c.oldRow() == null;
+ }
if (update) {
update(val, expTime, ttl, ver, true);
@@ -2923,8 +2922,6 @@ else if (deletedUnlocked())
updateCntr,
null,
topVer);
-
- cctx.dataStructures().onEntryUpdated(key, false, false);
}
onUpdateFinished(updateCntr);
@@ -3697,10 +3694,10 @@ private IgniteTxLocalAdapter currentTx() {
* @param ver New entry version.
* @throws IgniteCheckedException If update failed.
*/
- protected boolean storeValue(@Nullable CacheObject val,
+ protected void storeValue(@Nullable CacheObject val,
long expireTime,
GridCacheVersion ver) throws IgniteCheckedException {
- return storeValue(val, expireTime, ver, null);
+ storeValue(val, expireTime, ver, null);
}
/**
@@ -3709,23 +3706,26 @@ protected boolean storeValue(@Nullable CacheObject val,
* @param val Value.
* @param expireTime Expire time.
* @param ver New entry version.
- * @param predicate Optional predicate.
+ * @param pred Optional predicate.
*
* @return {@code True} if storage was modified.
+ * @param pred Optional predicate.
+ * @return Update closure containing invocation context.
* @throws IgniteCheckedException If update failed.
*/
- protected boolean storeValue(
+ protected UpdateClosure storeValue(
@Nullable CacheObject val,
long expireTime,
GridCacheVersion ver,
- @Nullable IgnitePredicate predicate) throws IgniteCheckedException {
+ @Nullable IgnitePredicate pred) throws IgniteCheckedException {
assert lock.isHeldByCurrentThread();
+ assert localPartition() == null || localPartition().state() != RENTING : localPartition();
- UpdateClosure closure = new UpdateClosure(this, val, ver, expireTime, predicate);
+ UpdateClosure c = new UpdateClosure(this, val, ver, expireTime, pred);
- cctx.offheap().invoke(cctx, key, localPartition(), closure);
+ cctx.offheap().invoke(cctx, key, localPartition(), c);
- return closure.treeOp != IgniteTree.OperationType.NOOP;
+ return c;
}
/**
@@ -3800,6 +3800,7 @@ protected WALPointer logTxUpdate(IgniteInternalTx tx, CacheObject val, long expi
protected void removeValue() throws IgniteCheckedException {
assert lock.isHeldByCurrentThread();
+ // Removals are possible from RENTING partition on clearing/evicting.
cctx.offheap().remove(cctx, key, partition(), localPartition());
}
@@ -3870,8 +3871,8 @@ protected void removeValue() throws IgniteCheckedException {
}
/** {@inheritDoc} */
- @Override public void updateIndex(SchemaIndexCacheFilter filter, SchemaIndexCacheVisitorClosure clo)
- throws IgniteCheckedException, GridCacheEntryRemovedException {
+ @Override public void updateIndex(SchemaIndexCacheVisitorClosure clo) throws IgniteCheckedException,
+ GridCacheEntryRemovedException {
lockEntry();
try {
@@ -3882,7 +3883,7 @@ protected void removeValue() throws IgniteCheckedException {
CacheDataRow row = cctx.offheap().read(this);
- if (row != null && (filter == null || filter.apply(row)))
+ if (row != null)
clo.apply(row);
}
finally {
@@ -4270,9 +4271,25 @@ private void obsoleteVersionExtras(@Nullable GridCacheVersion obsoleteVer, GridC
* @param owners Current owners.
* @param val Entry value.
*/
- protected final void checkOwnerChanged(@Nullable CacheLockCandidates prevOwners,
+ protected final void checkOwnerChanged(
+ @Nullable CacheLockCandidates prevOwners,
+ @Nullable CacheLockCandidates owners,
+ CacheObject val
+ ) {
+ checkOwnerChanged(prevOwners, owners, val, false);
+ }
+ /**
+ * @param prevOwners Previous owners.
+ * @param owners Current owners.
+ * @param val Entry value.
+ * @param inThreadChain {@code True} if called during thread chain checking.
+ */
+ protected final void checkOwnerChanged(
+ @Nullable CacheLockCandidates prevOwners,
@Nullable CacheLockCandidates owners,
- CacheObject val) {
+ CacheObject val,
+ boolean inThreadChain
+ ) {
assert !lock.isHeldByCurrentThread();
if (prevOwners != null && owners == null) {
@@ -4308,7 +4325,7 @@ protected final void checkOwnerChanged(@Nullable CacheLockCandidates prevOwners,
if (locked) {
cctx.mvcc().callback().onOwnerChanged(this, owner);
- if (owner.local())
+ if (owner.local() && !inThreadChain)
checkThreadChain(owner);
if (cctx.events().isRecordable(EVT_CACHE_OBJECT_LOCKED)) {
@@ -4547,6 +4564,9 @@ private static class UpdateClosure implements IgniteCacheOffheapManager.OffheapI
/** */
private IgniteTree.OperationType treeOp = IgniteTree.OperationType.PUT;
+ /** */
+ private boolean filtered;
+
/**
* @param entry Entry.
* @param val New value.
@@ -4574,6 +4594,8 @@ private static class UpdateClosure implements IgniteCacheOffheapManager.OffheapI
this.oldRow = oldRow;
if (predicate != null && !predicate.apply(oldRow)) {
+ filtered = true;
+
treeOp = IgniteTree.OperationType.NOOP;
return;
@@ -4610,6 +4632,13 @@ private static class UpdateClosure implements IgniteCacheOffheapManager.OffheapI
return oldRow;
}
+ /**
+ * @return {@code True} if update was filtered by predicate.
+ */
+ protected boolean filtered() {
+ return filtered;
+ }
+
/**
* Checks row for expiration and fire expire events if needed.
*
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvcc.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvcc.java
index 9ba8c63342059..6a471e98f2287 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvcc.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvcc.java
@@ -122,8 +122,7 @@ public GridCacheMvcc(GridCacheContext, ?> cctx) {
}
/**
- * @return Remote candidate only if it's first in the list and is marked
- * as 'used' .
+ * @return Remote candidate only if it's first in the list and is marked as 'used' .
*/
@Nullable private GridCacheMvccCandidate remoteOwner() {
if (rmts != null) {
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePartitionExchangeManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePartitionExchangeManager.java
index 108bc21cf1d0f..2d5baffd11b33 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePartitionExchangeManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePartitionExchangeManager.java
@@ -96,6 +96,7 @@
import org.apache.ignite.internal.processors.cache.distributed.dht.preloader.latch.ExchangeLatchManager;
import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridClientPartitionTopology;
import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionTopology;
+import org.apache.ignite.internal.processors.cache.distributed.near.GridNearTxLocal;
import org.apache.ignite.internal.processors.cache.persistence.snapshot.IgniteCacheSnapshotManager;
import org.apache.ignite.internal.processors.cache.persistence.snapshot.SnapshotDiscoveryMessage;
import org.apache.ignite.internal.processors.cache.transactions.IgniteInternalTx;
@@ -107,6 +108,7 @@
import org.apache.ignite.internal.processors.timeout.GridTimeoutObject;
import org.apache.ignite.internal.util.GridListSet;
import org.apache.ignite.internal.util.GridPartitionStateMap;
+import org.apache.ignite.internal.util.GridStringBuilder;
import org.apache.ignite.internal.util.IgniteUtils;
import org.apache.ignite.internal.util.future.GridCompoundFuture;
import org.apache.ignite.internal.util.future.GridFinishedFuture;
@@ -447,18 +449,18 @@ else if (exchangeInProgress()) {
if (grp != null) {
if (m instanceof GridDhtPartitionSupplyMessage) {
- grp.preloader().handleSupplyMessage(idx, id, (GridDhtPartitionSupplyMessage) m);
+ grp.preloader().handleSupplyMessage(id, (GridDhtPartitionSupplyMessage)m);
return;
}
else if (m instanceof GridDhtPartitionDemandMessage) {
- grp.preloader().handleDemandMessage(idx, id, (GridDhtPartitionDemandMessage) m);
+ grp.preloader().handleDemandMessage(idx, id, (GridDhtPartitionDemandMessage)m);
return;
}
else if (m instanceof GridDhtPartitionDemandLegacyMessage) {
grp.preloader().handleDemandMessage(idx, id,
- new GridDhtPartitionDemandMessage((GridDhtPartitionDemandLegacyMessage) m));
+ new GridDhtPartitionDemandMessage((GridDhtPartitionDemandLegacyMessage)m));
return;
}
@@ -939,7 +941,7 @@ public void lastFinishedFuture(GridDhtPartitionsExchangeFuture fut) {
* @param ver Topology version.
* @return Future or {@code null} is future is already completed.
*/
- @Nullable public IgniteInternalFuture affinityReadyFuture(AffinityTopologyVersion ver) {
+ @NotNull public IgniteInternalFuture affinityReadyFuture(AffinityTopologyVersion ver) {
GridDhtPartitionsExchangeFuture lastInitializedFut0 = lastInitializedFut;
if (lastInitializedFut0 != null && lastInitializedFut0.initialVersion().compareTo(ver) == 0
@@ -1979,6 +1981,41 @@ public void dumpDebugInfo(@Nullable GridDhtPartitionsExchangeFuture exchFut) thr
diagCtx.send(cctx.kernalContext(), null);
}
+ /**
+ * Builds warning string for long running transaction.
+ *
+ * @param tx Transaction.
+ * @param curTime Current timestamp.
+ * @return Warning string.
+ */
+ private String longRunningTransactionWarning(IgniteInternalTx tx, long curTime) {
+ GridStringBuilder warning = new GridStringBuilder()
+ .a(">>> Transaction [startTime=")
+ .a(formatTime(tx.startTime()))
+ .a(", curTime=")
+ .a(formatTime(curTime));
+
+ if (tx instanceof GridNearTxLocal) {
+ GridNearTxLocal nearTxLoc = (GridNearTxLocal)tx;
+
+ long sysTimeCurr = nearTxLoc.systemTimeCurrent();
+
+ //in some cases totalTimeMillis can be less than systemTimeMillis, as they are calculated with different precision
+ long userTime = Math.max(curTime - nearTxLoc.startTime() - sysTimeCurr, 0);
+
+ warning.a(", systemTime=")
+ .a(sysTimeCurr)
+ .a(", userTime=")
+ .a(userTime);
+ }
+
+ warning.a(", tx=")
+ .a(tx)
+ .a("]");
+
+ return warning.toString();
+ }
+
/**
* @param timeout Operation timeout.
* @return {@code True} if found long running operations.
@@ -2005,8 +2042,7 @@ private boolean dumpLongRunningOperations0(long timeout) {
found = true;
if (warnings.canAddMessage()) {
- warnings.add(">>> Transaction [startTime=" + formatTime(tx.startTime()) +
- ", curTime=" + formatTime(curTime) + ", tx=" + tx + ']');
+ warnings.add(longRunningTransactionWarning(tx, curTime));
if (ltrDumpLimiter.allowAction(tx))
dumpLongRunningTransaction(tx);
@@ -3044,7 +3080,7 @@ else if (task instanceof ForceRebalanceExchangeTask) {
? Math.min(curTimeout, dumpTimeout)
: dumpTimeout;
- blockingSectionEnd();
+ blockingSectionBegin();
try {
resVer = exchFut.get(exchTimeout, TimeUnit.MILLISECONDS);
@@ -3106,7 +3142,6 @@ else if (task instanceof ForceRebalanceExchangeTask) {
// Just pick first worker to do this, so we don't
// invoke topology callback more than once for the
// same event.
-
boolean changed = false;
for (CacheGroupContext grp : cctx.cache().cacheGroups()) {
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePreloader.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePreloader.java
index 3eac9b0900db6..825d573e349ab 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePreloader.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePreloader.java
@@ -162,19 +162,13 @@ public GridDhtFuture request(GridCacheContext cctx,
*/
public IgniteInternalFuture