/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.ignite.internal.processors.cache.distributed.dht; import java.util.concurrent.Callable; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.ReentrantLock; import javax.cache.processor.EntryProcessor; import javax.cache.processor.MutableEntry; import org.apache.ignite.IgniteCache; import org.apache.ignite.cache.CacheAtomicityMode; import org.apache.ignite.cache.CacheMode; import org.apache.ignite.cache.affinity.Affinity; import org.apache.ignite.configuration.CacheConfiguration; import org.apache.ignite.configuration.NearCacheConfiguration; import org.apache.ignite.internal.IgniteEx; import org.apache.ignite.internal.IgniteInternalFuture; import org.apache.ignite.internal.processors.cache.IgniteCacheAbstractTest; import org.apache.ignite.internal.util.typedef.PA; import static org.apache.ignite.cache.CacheAtomicityMode.ATOMIC; import static org.apache.ignite.cache.CacheMode.PARTITIONED; import static org.apache.ignite.cache.CacheRebalanceMode.SYNC; import static org.apache.ignite.cache.CacheWriteSynchronizationMode.PRIMARY_SYNC; import static org.apache.ignite.testframework.GridTestUtils.runAsync; import static org.apache.ignite.testframework.GridTestUtils.waitForCondition; /** */ public class IgniteCachePartitionedBackupNodeFailureRecoveryTest extends IgniteCacheAbstractTest { /** {@inheritDoc}*/ @Override protected int gridCount() { return 3; } /** {@inheritDoc}*/ @Override protected CacheMode cacheMode() { return PARTITIONED; } /** {@inheritDoc}*/ @Override protected CacheAtomicityMode atomicityMode() { return ATOMIC; } /** {@inheritDoc}*/ @Override protected NearCacheConfiguration nearConfiguration() { return new NearCacheConfiguration(); } /** {@inheritDoc}*/ @Override protected CacheConfiguration cacheConfiguration(String igniteInstanceName) throws Exception { CacheConfiguration ccfg = super.cacheConfiguration(igniteInstanceName); ccfg.setBackups(1); ccfg.setWriteSynchronizationMode(PRIMARY_SYNC); ccfg.setRebalanceMode(SYNC); return ccfg; } /** * Test stops and restarts backup node. * * @throws Exception If failed. */ public void testBackUpFail() throws Exception { final IgniteEx node1 = grid(0); final IgniteEx node2 = grid(1); final IgniteEx node3 = grid(2); awaitPartitionMapExchange(); final IgniteCache<Integer, Integer> cache1 = node1.cache(DEFAULT_CACHE_NAME); Affinity<Integer> aff = node1.affinity(DEFAULT_CACHE_NAME); Integer key0 = null; for (int key = 0; key < 10_000; key++) { if (aff.isPrimary(node2.cluster().localNode(), key) && aff.isBackup(node3.cluster().localNode(), key)) { key0 = key; break; } } assertNotNull(key0); cache1.put(key0, 0); final AtomicBoolean finished = new AtomicBoolean(); final ReentrantLock lock = new ReentrantLock(); final AtomicInteger cntr = new AtomicInteger(); final Integer finalKey = key0; IgniteInternalFuture<Void> primaryFut; IgniteInternalFuture<Void> backupFut; try { primaryFut = runAsync(new Callable<Void>() { @Override public Void call() throws Exception { while (!finished.get()) { lock.lock(); try { cache1.invoke(finalKey, new TestEntryProcessor()); cntr.getAndIncrement(); } finally { lock.unlock(); } } return null; } }); backupFut = runAsync(new Callable<Void>() { @Override public Void call() throws Exception { while (!finished.get()) { stopGrid(2); IgniteEx backUp = startGrid(2); final IgniteCache<Integer, Integer> cache3 = backUp.cache(DEFAULT_CACHE_NAME); lock.lock(); try { boolean res = waitForCondition(new PA() { @Override public boolean apply() { Integer actl = cache3.localPeek(finalKey); Integer exp = cntr.get(); return exp.equals(actl); } }, 1000); assertTrue(res); } finally { lock.unlock(); } } return null; } }); Thread.sleep(30_000); } finally { finished.set(true); } primaryFut.get(); backupFut.get(); } /** * */ static class TestEntryProcessor implements EntryProcessor<Integer, Integer, Void> { /** {@inheritDoc}*/ @Override public Void process(MutableEntry<Integer, Integer> entry, Object... args) { Integer v = entry.getValue() + 1; entry.setValue(v); return null; } } }