/* * Copyright (c) 2008-2017, Hazelcast, Inc. All Rights Reserved. * * Licensed 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 com.hazelcast.map.impl.nearcache.invalidation; import com.hazelcast.config.Config; import com.hazelcast.config.EvictionPolicy; import com.hazelcast.config.MapConfig; import com.hazelcast.config.NearCacheConfig; import com.hazelcast.core.HazelcastInstance; import com.hazelcast.core.IMap; import com.hazelcast.internal.nearcache.impl.invalidation.Invalidator; import com.hazelcast.internal.nearcache.impl.invalidation.MetaDataGenerator; import com.hazelcast.internal.partition.InternalPartitionService; import com.hazelcast.map.impl.MapService; import com.hazelcast.map.impl.MapServiceContext; import com.hazelcast.map.impl.nearcache.MapNearCacheManager; import com.hazelcast.map.impl.nearcache.NearCacheTestSupport; import com.hazelcast.spi.impl.NodeEngineImpl; import com.hazelcast.test.AssertTask; import com.hazelcast.test.HazelcastParallelClassRunner; import com.hazelcast.test.TestHazelcastInstanceFactory; import com.hazelcast.test.annotation.NightlyTest; import com.hazelcast.util.UuidUtil; import org.junit.After; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; import java.util.concurrent.atomic.AtomicBoolean; import static com.hazelcast.map.impl.MapService.SERVICE_NAME; import static com.hazelcast.util.RandomPicker.getInt; import static java.lang.Integer.MAX_VALUE; import static org.junit.Assert.assertEquals; @RunWith(HazelcastParallelClassRunner.class) @Category(NightlyTest.class) public class InvalidationMetadataDistortionTest extends NearCacheTestSupport { private final TestHazelcastInstanceFactory factory = new TestHazelcastInstanceFactory(); @After public void tearDown() throws Exception { factory.shutdownAll(); } protected Config createConfig() { Config config = new Config(); config.setProperty("hazelcast.invalidation.max.tolerated.miss.count", "0"); config.setProperty("hazelcast.map.invalidation.batch.enabled", "true"); config.setProperty("hazelcast.map.invalidation.batch.size", "10000"); config.setProperty("hazelcast.partition.count", "271"); return config; } protected MapConfig createMapConfig(String mapName) { MapConfig mapConfig = new MapConfig(mapName); mapConfig.setBackupCount(0); return mapConfig; } protected NearCacheConfig createNearCacheConfig(String mapName) { NearCacheConfig nearCacheConfig = newNearCacheConfig(); nearCacheConfig.setInvalidateOnChange(true); nearCacheConfig.setName(mapName); nearCacheConfig.getEvictionConfig() .setSize(Integer.MAX_VALUE) .setEvictionPolicy(EvictionPolicy.NONE); return nearCacheConfig; } @Test public void lostInvalidation() throws Exception { final String mapName = "origin-map"; final int mapSize = 100000; final AtomicBoolean stopTest = new AtomicBoolean(); // members are created final Config config = createConfig().addMapConfig(createMapConfig(mapName)); final HazelcastInstance member = factory.newHazelcastInstance(config); factory.newHazelcastInstance(config); // map is populated form member final IMap<Integer, Integer> memberMap = member.getMap(mapName); for (int i = 0; i < mapSize; i++) { memberMap.put(i, i); } // a new member comes with Near Cache configured final Config config2 = createConfig().addMapConfig(createMapConfig(mapName).setNearCacheConfig(createNearCacheConfig(mapName))); final HazelcastInstance nearCachedMember = factory.newHazelcastInstance(config2); final IMap<Integer, Integer> nearCachedMap = nearCachedMember.getMap(mapName); Thread populateNearCache = new Thread(new Runnable() { public void run() { while (!stopTest.get()) { for (int i = 0; i < mapSize; i++) { nearCachedMap.get(i); } } } }); Thread distortSequence = new Thread(new Runnable() { @Override public void run() { while (!stopTest.get()) { distortRandomPartitionSequence(mapName, member); sleepSeconds(1); } } }); Thread distortUuid = new Thread(new Runnable() { @Override public void run() { while (!stopTest.get()) { distortRandomPartitionUuid(member); sleepSeconds(3); } } }); Thread put = new Thread(new Runnable() { public void run() { // change some data while (!stopTest.get()) { int key = getInt(mapSize); int value = getInt(Integer.MAX_VALUE); memberMap.put(key, value); sleepAtLeastMillis(10); } } }); // start threads put.start(); populateNearCache.start(); distortSequence.start(); distortUuid.start(); sleepSeconds(60); // stop threads stopTest.set(true); distortUuid.join(); distortSequence.join(); populateNearCache.join(); put.join(); assertTrueEventually(new AssertTask() { @Override public void run() throws Exception { for (int i = 0; i < mapSize; i++) { Integer valueSeenFromMember = memberMap.get(i); Integer valueSeenFromNearCachedSide = nearCachedMap.get(i); assertEquals(valueSeenFromMember, valueSeenFromNearCachedSide); } } }); } private void distortRandomPartitionSequence(String mapName, HazelcastInstance member) { NodeEngineImpl nodeEngineImpl = getNodeEngineImpl(member); MapService mapService = nodeEngineImpl.getService(SERVICE_NAME); MapServiceContext mapServiceContext = mapService.getMapServiceContext(); MapNearCacheManager mapNearCacheManager = mapServiceContext.getMapNearCacheManager(); Invalidator invalidator = mapNearCacheManager.getInvalidator(); MetaDataGenerator metaDataGenerator = invalidator.getMetaDataGenerator(); InternalPartitionService partitionService = nodeEngineImpl.getPartitionService(); int partitionCount = partitionService.getPartitionCount(); metaDataGenerator.setCurrentSequence(mapName, getInt(partitionCount), getInt(MAX_VALUE)); } private void distortRandomPartitionUuid(HazelcastInstance member) { NodeEngineImpl nodeEngineImpl = getNodeEngineImpl(member); int partitionCount = nodeEngineImpl.getPartitionService().getPartitionCount(); int partitionId = getInt(partitionCount); MapService mapService = nodeEngineImpl.getService(SERVICE_NAME); MapServiceContext mapServiceContext = mapService.getMapServiceContext(); MapNearCacheManager mapNearCacheManager = mapServiceContext.getMapNearCacheManager(); Invalidator invalidator = mapNearCacheManager.getInvalidator(); MetaDataGenerator metaDataGenerator = invalidator.getMetaDataGenerator(); metaDataGenerator.setUuid(partitionId, UuidUtil.newUnsecureUUID()); } }