Alexey Kukushkin created IGNITE-12898: -----------------------------------------
Summary: Server node with CacheStore fails to re-join the cluster: IgniteCheckedException: Cannot enable read-through (loader or store is not provided) for cache Key: IGNITE-12898 URL: https://issues.apache.org/jira/browse/IGNITE-12898 Project: Ignite Issue Type: Bug Affects Versions: 2.8 Reporter: Alexey Kukushkin If a cache with external persistence is dynamically created on a non-affinity node then the cache affinity node cannot join the cluster after restart. h2. Repro Steps # Run an "empty" Ignite node where no cache is going to be started # Run a cache affinity node having the "ROLE" attribute set to "DATA" # Create the cache from the "empty" node and use a Node Filter to limit the cache to the "data" node. External persistence is configured for the cache. # Restart the "data" node h3. Actual Result {{IgniteCheckedException: Cannot enable read-through (loader or store is not provided) for cache}} h2. Reproducer h3. Reproducer.java {code:java} public class Reproducer { @Test public void test() throws Exception { final String DB_URL = "jdbc:h2:mem:test"; final String ENTITY_NAME = "Person"; Function<String, IgniteConfiguration> igniteCfgFactory = instanceName -> new IgniteConfiguration() .setIgniteInstanceName(instanceName) .setDiscoverySpi(new TcpDiscoverySpi() .setIpFinder(new TcpDiscoveryVmIpFinder().setAddresses(Collections.singleton("127.0.0.1:47500"))) ); // 1. Run an "empty" Ignite node where no cache is going to be started try (Connection dbConn = DriverManager.getConnection(DB_URL, "sa", ""); Statement dbStmt = dbConn.createStatement(); Ignite emptyNode = Ignition.start(igniteCfgFactory.apply("emptyyNode"))) { // 2. Run a "Person" cache affinity node having the "ROLE" attribute set to "DATA" Map<String, Object> dataNodeAttrs = new HashMap<>(1); dataNodeAttrs.put(DataNodeFilter.ATTR_NAME, DataNodeFilter.ATTR_VAL); Ignite dataNode = Ignition.start(igniteCfgFactory.apply("dataNode").setUserAttributes(dataNodeAttrs)); // 3. Create the "Person" cache from the "empty" node and use a Node Filter to limit the cache to the // "data" node. External persistence to the "Person" table in H2 DB is configured for the cache. dbStmt.execute("CREATE TABLE " + ENTITY_NAME + " (id int PRIMARY KEY, name varchar)"); CacheJdbcPojoStoreFactory<Integer, BinaryObject> igniteStoreFactory = new CacheJdbcPojoStoreFactory<>(); igniteStoreFactory.setDataSourceFactory(() -> JdbcConnectionPool.create(DB_URL, "sa", "")) .setTypes( new JdbcType() .setCacheName(ENTITY_NAME) .setDatabaseTable(ENTITY_NAME) .setKeyType(Integer.class) .setValueType(ENTITY_NAME) .setKeyFields(new JdbcTypeField(java.sql.Types.INTEGER, "id", Integer.class, "id")) .setValueFields( new JdbcTypeField(java.sql.Types.INTEGER, "id", Integer.class, "id"), new JdbcTypeField(java.sql.Types.VARCHAR, "name", String.class, "name") ) ); CacheConfiguration<Integer, BinaryObject> cacheCfg = new CacheConfiguration<Integer, BinaryObject>(ENTITY_NAME) .setCacheMode(CacheMode.REPLICATED) .setCacheStoreFactory(igniteStoreFactory) .setWriteThrough(true) .setReadThrough(true) .setNodeFilter(new DataNodeFilter()); emptyNode.createCache(cacheCfg).withKeepBinary(); // 4. Restart the "data" node dataNode.close(); dataNode = Ignition.start(igniteCfgFactory.apply("node2").setUserAttributes(dataNodeAttrs)); dataNode.close(); } } private static class DataNodeFilter implements IgnitePredicate<ClusterNode> { public static final String ATTR_NAME = "ROLE"; public static final String ATTR_VAL = "DATA"; @Override public boolean apply(ClusterNode node) { Object role = node.attributes().get(ATTR_NAME); return role != null && ATTR_VAL.equalsIgnoreCase(role.toString()); } } } {code} h3. build.gradle {code:groovy} dependencies { compile group: 'org.apache.ignite', name: 'ignite-core', version: '2.8.0' compile group: 'com.h2database', name: 'h2', version: '1.4.200' testCompile group: 'junit', name: 'junit', version: '4.12' } {code} h2. Workaround Create dynamic caches only on the affinity nodes or use "static" caches defined in ignite node configuration. h2. Stack Trace {code} class org.apache.ignite.IgniteCheckedException: Cannot enable read-through (loader or store is not provided) for cache: Person at org.apache.ignite.internal.processors.cache.ValidationOnNodeJoinUtils.validate(ValidationOnNodeJoinUtils.java:348) at org.apache.ignite.internal.processors.cache.GridCacheProcessor.createCacheContext(GridCacheProcessor.java:1201) at org.apache.ignite.internal.processors.cache.GridCacheProcessor.prepareCacheContext(GridCacheProcessor.java:1995) at org.apache.ignite.internal.processors.cache.GridCacheProcessor.lambda$prepareStartCaches$d40a1773$1(GridCacheProcessor.java:1830) at org.apache.ignite.internal.processors.cache.GridCacheProcessor.lambda$prepareStartCaches$8(GridCacheProcessor.java:1754) at org.apache.ignite.internal.processors.cache.GridCacheProcessor.lambda$prepareStartCaches$926b6886$1(GridCacheProcessor.java:1827) at org.apache.ignite.internal.util.IgniteUtils.doInParallel(IgniteUtils.java:11157) at org.apache.ignite.internal.util.IgniteUtils.doInParallel(IgniteUtils.java:11059) at org.apache.ignite.internal.processors.cache.GridCacheProcessor.prepareStartCaches(GridCacheProcessor.java:1822) at org.apache.ignite.internal.processors.cache.GridCacheProcessor.prepareStartCaches(GridCacheProcessor.java:1753) at org.apache.ignite.internal.processors.cache.GridCacheProcessor.startCachesOnLocalJoin(GridCacheProcessor.java:1699) at org.apache.ignite.internal.processors.cache.distributed.dht.preloader.GridDhtPartitionsExchangeFuture.initCachesOnLocalJoin(GridDhtPartitionsExchangeFuture.java:994) at org.apache.ignite.internal.processors.cache.distributed.dht.preloader.GridDhtPartitionsExchangeFuture.init(GridDhtPartitionsExchangeFuture.java:847) at org.apache.ignite.internal.processors.cache.GridCachePartitionExchangeManager$ExchangeWorker.body0(GridCachePartitionExchangeManager.java:3172) at org.apache.ignite.internal.processors.cache.GridCachePartitionExchangeManager$ExchangeWorker.body(GridCachePartitionExchangeManager.java:3021) at org.apache.ignite.internal.util.worker.GridWorker.run(GridWorker.java:120) at java.base/java.lang.Thread.run(Thread.java:834) {code} -- This message was sent by Atlassian Jira (v8.3.4#803005)