[ https://issues.apache.org/jira/browse/IGNITE-12898?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17107304#comment-17107304 ]
Ivan Daschinskiy commented on IGNITE-12898: ------------------------------------------- [~daradurvs] Could you please make a review? > Server node with CacheStore fails to re-join the cluster: 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 > Assignee: Ivan Daschinskiy > Priority: Major > Labels: sbcf > Fix For: 2.9 > > Time Spent: 1h 50m > Remaining Estimate: 0h > > 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)