From 5490c7d927daca2d64f108b6c2eafe03bbd6f54e Mon Sep 17 00:00:00 2001 From: Sergey Chugunov Date: Wed, 11 Oct 2017 15:33:23 +0300 Subject: [PATCH] IGNITE-6536 Node fails when detects mapping storage corruption Signed-off-by: Andrey Gura --- .../internal/MarshallerMappingFileStore.java | 15 ++-- .../IgniteMarshallerCacheFSRestoreTest.java | 71 ++++++++++++++++++- 2 files changed, 77 insertions(+), 9 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/MarshallerMappingFileStore.java b/modules/core/src/main/java/org/apache/ignite/internal/MarshallerMappingFileStore.java index eabbdb81d2340..59a99b861751a 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/MarshallerMappingFileStore.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/MarshallerMappingFileStore.java @@ -167,16 +167,19 @@ void restoreMappings(MarshallerContext marshCtx) throws IgniteCheckedException { try (FileInputStream in = new FileInputStream(file)) { try (BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) { - String className = reader.readLine(); + String clsName = reader.readLine(); - marshCtx.registerClassNameLocally(platformId, typeId, className); + if (clsName == null) { + throw new IgniteCheckedException("Class name is null for [platformId=" + platformId + + ", typeId=" + typeId + "], marshaller mappings storage is broken. " + + "Clean up marshaller directory (/marshaller) and restart the node."); + } + + marshCtx.registerClassNameLocally(platformId, typeId, clsName); } } catch (IOException e) { - throw new IgniteCheckedException("Reading marshaller mapping from file " - + name - + " failed." - , e); + throw new IgniteCheckedException("Reading marshaller mapping from file " + name + " failed.", e); } } } diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteMarshallerCacheFSRestoreTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteMarshallerCacheFSRestoreTest.java index 21a3e4344ba85..ac15971f091ca 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteMarshallerCacheFSRestoreTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteMarshallerCacheFSRestoreTest.java @@ -23,13 +23,16 @@ import java.nio.charset.StandardCharsets; import java.util.Collection; import java.util.Map; +import org.apache.ignite.Ignite; import org.apache.ignite.IgniteCache; +import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.binary.BinaryObject; import org.apache.ignite.cache.CacheAtomicityMode; import org.apache.ignite.cache.CacheMode; import org.apache.ignite.cluster.ClusterNode; import org.apache.ignite.configuration.CacheConfiguration; import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.configuration.PersistentStoreConfiguration; import org.apache.ignite.internal.IgniteEx; import org.apache.ignite.internal.managers.discovery.DiscoveryCustomMessage; import org.apache.ignite.internal.processors.marshaller.MappingProposedMessage; @@ -47,6 +50,9 @@ public class IgniteMarshallerCacheFSRestoreTest extends GridCommonAbstractTest { /** */ private volatile boolean isDuplicateObserved = true; + /** */ + private boolean isPersistenceEnabled; + /** * */ @@ -67,6 +73,7 @@ private static class SimpleValue { } } + /** {@inheritDoc} */ @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName); @@ -75,13 +82,17 @@ private static class SimpleValue { cfg.setDiscoverySpi(discoSpi); - CacheConfiguration singleCacheConfig = new CacheConfiguration() + CacheConfiguration singleCacheCfg = new CacheConfiguration() .setName(DEFAULT_CACHE_NAME) .setCacheMode(CacheMode.PARTITIONED) .setBackups(1) .setAtomicityMode(CacheAtomicityMode.ATOMIC); - cfg.setCacheConfiguration(singleCacheConfig); + cfg.setCacheConfiguration(singleCacheCfg); + + //persistence must be enabled to verify restoring mappings from FS case + if (isPersistenceEnabled) + cfg.setPersistentStoreConfiguration(new PersistentStoreConfiguration()); return cfg; } @@ -110,11 +121,14 @@ private void cleanUpWorkDir() throws Exception { * In that case the request must not be marked as duplicate and must be processed in a regular way. * No hangs must take place. * - * @see IGNITE-5401 Take a look at JIRA ticket for more information about context of this test. + * @see IGNITE-5401 JIRA ticket + * provides more information about context of this test. * * This test must never hang on proposing of MarshallerMapping. */ public void testFileMappingReadAndPropose() throws Exception { + isPersistenceEnabled = false; + prepareMarshallerFileStore(); IgniteEx ignite0 = startGrid(0); @@ -162,6 +176,57 @@ private void prepareMarshallerFileStore() throws Exception { } } + /** + * Verifies scenario that node with corrupted marshaller mapping store must fail on startup + * with appropriate error message. + * + * @see IGNITE-6536 JIRA provides more information + * about this case. + */ + public void testNodeStartFailsOnCorruptedStorage() throws Exception { + isPersistenceEnabled = true; + + Ignite ig = startGrids(3); + + ig.active(true); + + ig.cache(DEFAULT_CACHE_NAME).put(0, new SimpleValue(0, "value0")); + + stopAllGrids(); + + corruptMarshallerStorage(); + + try { + startGrid(0); + } + catch (IgniteCheckedException e) { + verifyException((IgniteCheckedException) e.getCause()); + } + } + + /** + * Class name for CustomClass class mapping file gets cleaned up from file system. + */ + private void corruptMarshallerStorage() throws Exception { + String marshallerDir = U.defaultWorkDirectory() + File.separator + "marshaller"; + + File[] storedMappingsFiles = new File(marshallerDir).listFiles(); + + assert storedMappingsFiles.length == 1; + + try (FileOutputStream out = new FileOutputStream(storedMappingsFiles[0])) { + out.getChannel().truncate(0); + } + } + + /** */ + private void verifyException(IgniteCheckedException e) throws Exception { + String msg = e.getMessage(); + + if (msg == null || !msg.contains("Class name is null")) + throw new Exception("Exception with unexpected message was thrown: " + msg, e); + } + /** */ private class TestTcpDiscoverySpi extends TcpDiscoverySpi {