[ 
https://issues.apache.org/jira/browse/IGNITE-12898?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17107237#comment-17107237
 ] 

Ivan Daschinskiy edited comment on IGNITE-12898 at 5/14/20, 11:55 AM:
----------------------------------------------------------------------

The main reason of fail -- if coordinator is not an affinity node, it saves 
descriptor with not fully deserialized CacheConfiguration and small serialized 
part. Before fix if affinity node joins, coordinator send CacheConfiguration 
with missing CacheStore, because it obtain it not from saved binary data, but 
from reduced CacheConfiguration. So validation of CacheConfiguration fails on 
joining node and it fails. 

I proposed send to joined node previously saved binary data, that is correct. 

Workaround for current version same, as suggests [~kukushal]


was (Author: ivandasch):
The main reason of fail -- if coordinator is not an affinity node, it saves 
descriptor with not fully deserialized CacheConfiguration and small serialized 
part. Before fix if affinity node joins, coordinator send CacheConfiguration 
with missing CacheStore, because it obtain it not from saved binary data, but 
from reduced CacheConfiguration. So validation of CacheConfiguration fails on 
joining node and it fails. 

I proposed send to joined node previously saved binary data, that is correct. 

> 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)

Reply via email to