You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by sk...@apache.org on 2020/04/08 17:10:41 UTC

[ignite] branch master updated: IGNITE-12805 Fixed NullPointerException when memory restore is in progress. Fixes #7562

This is an automated email from the ASF dual-hosted git repository.

sk0x50 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git


The following commit(s) were added to refs/heads/master by this push:
     new b816729  IGNITE-12805 Fixed NullPointerException when memory restore is in progress. Fixes #7562
b816729 is described below

commit b8167296b13c8ecb0b035f5495d65039a3a86105
Author: Slava Koptilin <sl...@gmail.com>
AuthorDate: Wed Apr 8 20:10:13 2020 +0300

    IGNITE-12805 Fixed NullPointerException when memory restore is in progress. Fixes #7562
---
 .../cache/ValidationOnNodeJoinUtils.java           | 14 +++--
 .../db/IgniteCacheGroupsWithRestartsTest.java      | 66 ++++++++++++++++++++++
 2 files changed, 75 insertions(+), 5 deletions(-)

diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ValidationOnNodeJoinUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ValidationOnNodeJoinUtils.java
index 78e8b3f..ed3ea76 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ValidationOnNodeJoinUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ValidationOnNodeJoinUtils.java
@@ -50,6 +50,7 @@ import org.apache.ignite.internal.GridKernalContext;
 import org.apache.ignite.internal.IgniteFeatures;
 import org.apache.ignite.internal.IgniteNodeAttributes;
 import org.apache.ignite.internal.binary.BinaryMarshaller;
+import org.apache.ignite.internal.cluster.DetachedClusterNode;
 import org.apache.ignite.internal.processors.affinity.LocalAffinityFunction;
 import org.apache.ignite.internal.processors.cache.persistence.DataRegion;
 import org.apache.ignite.internal.processors.datastructures.DataStructuresProcessor;
@@ -328,7 +329,12 @@ public class ValidationOnNodeJoinUtils {
                 "Custom IndexingSpi cannot be used with TRANSACTIONAL_SNAPSHOT atomicity mode");
         }
 
-        if (cc.isWriteBehindEnabled() && ctx.discovery().cacheAffinityNode(ctx.discovery().localNode(), cc.getName())) {
+        // This method can be called when memory recovery is in progress,
+        // which means that the GridDiscovery manager is not started, and therefore localNode is also not initialized.
+        ClusterNode locNode = ctx.discovery().localNode() != null ? ctx.discovery().localNode():
+            new DetachedClusterNode(ctx.pdsFolderResolver().resolveFolders().consistentId(), ctx.nodeAttributes());
+
+        if (cc.isWriteBehindEnabled() && ctx.discovery().cacheAffinityNode(locNode, cc.getName())) {
             if (cfgStore == null)
                 throw new IgniteCheckedException("Cannot enable write-behind (writer or store is not provided) " +
                     "for cache: " + U.maskName(cc.getName()));
@@ -343,13 +349,11 @@ public class ValidationOnNodeJoinUtils {
                     "'writeBehindFlushSize' parameters to 0 for cache: " + U.maskName(cc.getName()));
         }
 
-        if (cc.isReadThrough() && cfgStore == null
-            && ctx.discovery().cacheAffinityNode(ctx.discovery().localNode(), cc.getName()))
+        if (cc.isReadThrough() && cfgStore == null && ctx.discovery().cacheAffinityNode(locNode, cc.getName()))
             throw new IgniteCheckedException("Cannot enable read-through (loader or store is not provided) " +
                 "for cache: " + U.maskName(cc.getName()));
 
-        if (cc.isWriteThrough() && cfgStore == null
-            && ctx.discovery().cacheAffinityNode(ctx.discovery().localNode(), cc.getName()))
+        if (cc.isWriteThrough() && cfgStore == null && ctx.discovery().cacheAffinityNode(locNode, cc.getName()))
             throw new IgniteCheckedException("Cannot enable write-through (writer or store is not provided) " +
                 "for cache: " + U.maskName(cc.getName()));
 
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/IgniteCacheGroupsWithRestartsTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/IgniteCacheGroupsWithRestartsTest.java
index c6851c6..0520153 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/IgniteCacheGroupsWithRestartsTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/IgniteCacheGroupsWithRestartsTest.java
@@ -26,12 +26,18 @@ import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.ThreadLocalRandom;
 import java.util.function.BiFunction;
+import javax.cache.Cache;
+import javax.cache.configuration.Factory;
+import javax.cache.integration.CacheLoaderException;
+import javax.cache.integration.CacheWriterException;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.cache.QueryEntity;
 import org.apache.ignite.cache.QueryIndex;
 import org.apache.ignite.cache.QueryIndexType;
 import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction;
+import org.apache.ignite.cache.store.CacheStore;
+import org.apache.ignite.cache.store.CacheStoreAdapter;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.ConnectorConfiguration;
 import org.apache.ignite.configuration.DataRegionConfiguration;
@@ -55,6 +61,7 @@ import org.junit.Assert;
 import org.junit.Ignore;
 import org.junit.Test;
 
+import static org.apache.ignite.cluster.ClusterState.ACTIVE;
 import static org.apache.ignite.internal.processors.cache.persistence.GridCacheDatabaseSharedManager.IGNITE_PDS_SKIP_CHECKPOINT_ON_NODE_STOP;
 import static org.apache.ignite.internal.processors.cache.persistence.file.FilePageStoreManager.DFLT_STORE_DIR;
 
@@ -266,6 +273,37 @@ public class IgniteCacheGroupsWithRestartsTest extends GridCommonAbstractTest {
     }
 
     /**
+     * @throws Exception If failed.
+     */
+    @Test
+    public void testNodeRestartWith3rdPartyCacheStoreAndPersistenceEnabled() throws Exception {
+        IgniteEx crd = startGrid(0);
+
+        crd.cluster().state(ACTIVE);
+
+        String cacheName = "test-cache-3rd-party-write-behind-and-ignite-persistence";
+        CacheConfiguration  ccfg = new CacheConfiguration(cacheName)
+            .setWriteBehindEnabled(true)
+            .setWriteThrough(true)
+            .setReadThrough(true)
+            .setCacheStoreFactory(new StoreFactory());
+
+        IgniteCache cache = crd.getOrCreateCache(ccfg);
+
+        cache.put(12, 42);
+
+        stopGrid(0);
+
+        crd = startGrid(0);
+
+        crd.cluster().state(ACTIVE);
+
+        cache = crd.cache(cacheName);
+
+        assertEquals("Cache was not properly restored or required key is lost.", 42, cache.get(12));
+    }
+
+    /**
      * @param doFindAndRemove Do find and remove.
      */
     private void testFindAndDeleteGarbage(
@@ -400,4 +438,32 @@ public class IgniteCacheGroupsWithRestartsTest extends GridCommonAbstractTest {
             return S.toString(Account.class, this);
         }
     }
+
+    /**
+     * Test store factory.
+     */
+    private static class StoreFactory implements Factory<CacheStore> {
+        /** {@inheritDoc} */
+        @Override public CacheStore create() {
+            return new TestStore();
+        }
+    }
+
+    /**
+     * Test store.
+     */
+    private static class TestStore extends CacheStoreAdapter {
+        /** {@inheritDoc} */
+        @Override public Object load(Object key) throws CacheLoaderException {
+            return null;
+        }
+
+        /** {@inheritDoc} */
+        @Override public void write(Cache.Entry entry) throws CacheWriterException {
+        }
+
+        /** {@inheritDoc} */
+        @Override public void delete(Object key) throws CacheWriterException {
+        }
+    }
 }