/* * 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; import com.hazelcast.config.Config; import com.hazelcast.config.MapStoreConfig; import com.hazelcast.config.NearCacheConfig; import com.hazelcast.core.HazelcastInstance; import com.hazelcast.core.IMap; import com.hazelcast.internal.nearcache.NearCache; import com.hazelcast.map.EntryBackupProcessor; import com.hazelcast.map.EntryProcessor; import com.hazelcast.map.impl.MapService; import com.hazelcast.map.impl.proxy.NearCachedMapProxyImpl; import com.hazelcast.monitor.NearCacheStats; import com.hazelcast.nio.serialization.Data; import com.hazelcast.spi.impl.SerializationServiceSupport; import com.hazelcast.spi.serialization.SerializationService; import com.hazelcast.test.AssertTask; import com.hazelcast.test.HazelcastParallelClassRunner; import com.hazelcast.test.TestHazelcastInstanceFactory; import com.hazelcast.test.annotation.ParallelTest; import com.hazelcast.test.annotation.QuickTest; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; import java.io.Serializable; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import static com.hazelcast.test.HazelcastTestSupport.assertTrueEventually; import static com.hazelcast.test.HazelcastTestSupport.getNodeEngineImpl; import static com.hazelcast.test.HazelcastTestSupport.randomMapName; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @RunWith(HazelcastParallelClassRunner.class) @Category({QuickTest.class, ParallelTest.class}) public class NearCacheLiteMemberTest { private String mapName; private TestHazelcastInstanceFactory factory; private HazelcastInstance instance; private HazelcastInstance lite; @Before public void init() { mapName = randomMapName(); factory = new TestHazelcastInstanceFactory(2); instance = factory.newHazelcastInstance(createConfig(mapName, false)); lite = factory.newHazelcastInstance(createConfig(mapName, true)); } @After public void destroy() { factory.terminateAll(); } @Test public void testPut() { testPut(instance, lite, mapName); } @Test public void testPutAll() { testPutAll(instance, lite, mapName); } @Test public void testPutTransient() { testPutTransient(instance, lite, mapName); } @Test public void testSet() { testSet(instance, lite, mapName); } @Test public void testUpdate() { testUpdate(instance, lite, mapName); } @Test public void testUpdateWithSet() { testUpdateWithSet(instance, lite, mapName); } @Test public void testUpdateWithPutAll() { testUpdateWithPutAll(instance, lite, mapName); } @Test public void testEvict() { testEvict(instance, lite, mapName); } @Test public void testRemove() { testRemove(instance, lite, mapName); } @Test public void testDelete() { testDelete(instance, lite, mapName); } @Test public void testClear() { testClear(instance, lite, mapName); } @Test public void testEvictAll() { testEvictAll(instance, lite, mapName); } @Test public void testExecuteOnKey() { testExecuteOnKey(instance, lite, mapName); } @Test public void testExecuteOnKeys() { testExecuteOnKeys(instance, lite, mapName); } @Test public void testLoadAll() { initWithMapStore(); testLoadAll(instance, lite, mapName); } @Test public void testLoadAllWithKeySet() { initWithMapStore(); testLoadAllWithKeySet(instance, lite, mapName); } public static void testPut(HazelcastInstance instance, HazelcastInstance lite, String mapName) { IMap<Object, Object> map = instance.getMap(mapName); int count = 100; for (int i = 0; i < count; i++) { map.put(i, i); } IMap<Object, Object> liteMap = lite.getMap(mapName); for (int i = 0; i < count; i++) { liteMap.get(i); } assertLiteMemberNearCacheNonEmpty(lite, mapName); } public static void testPutAll(HazelcastInstance instance, HazelcastInstance lite, String mapName) { IMap<Object, Object> map = instance.getMap(mapName); IMap<Object, Object> liteMap = lite.getMap(mapName); NearCachedMapProxyImpl proxy = (NearCachedMapProxyImpl) liteMap; NearCache liteNearCache = proxy.getNearCache(); SerializationService serializationService = ((SerializationServiceSupport) instance).getSerializationService(); int count = 100; // fill the Near Cache with the same data as below so we can detect when it is emptied for (int i = 0; i < count; i++) { liteNearCache.put(serializationService.toData(i), i); } final NearCacheStats stats = liteNearCache.getNearCacheStats(); assertEquals(100, stats.getOwnedEntryCount()); Map<Object, Object> localMap = new HashMap<Object, Object>(); for (int i = 0; i < count; i++) { localMap.put(i, i); } map.putAll(localMap); assertTrueEventually(new AssertTask() { @Override public void run() throws Exception { assertEquals(0, stats.getOwnedEntryCount()); } }); for (int i = 0; i < count; i++) { liteMap.get(i); } assertLiteMemberNearCacheNonEmpty(lite, mapName); } public static void testPutTransient(HazelcastInstance instance, HazelcastInstance lite, String mapName) { IMap<Object, Object> map = instance.getMap(mapName); int count = 100; for (int i = 0; i < count; i++) { map.putTransient(i, i, 0, MILLISECONDS); } IMap<Object, Object> liteMap = lite.getMap(mapName); for (int i = 0; i < count; i++) { liteMap.get(i); } assertLiteMemberNearCacheNonEmpty(lite, mapName); } public static void testSet(HazelcastInstance instance, HazelcastInstance lite, String mapName) { IMap<Object, Object> map = instance.getMap(mapName); int count = 100; for (int i = 0; i < count; i++) { map.set(i, i); } IMap<Object, Object> liteMap = lite.getMap(mapName); for (int i = 0; i < count; i++) { liteMap.get(i); } assertLiteMemberNearCacheNonEmpty(lite, mapName); } public static void testUpdate(HazelcastInstance instance, HazelcastInstance lite, String mapName) { IMap<Object, Object> map = instance.getMap(mapName); map.put(1, 1); IMap<Object, Object> liteMap = lite.getMap(mapName); liteMap.get(1); map.put(1, 2); assertNullNearCacheEntryEventually(lite, mapName, 1); } public static void testUpdateWithSet(HazelcastInstance instance, HazelcastInstance lite, String mapName) { IMap<Object, Object> map = instance.getMap(mapName); map.put(1, 1); IMap<Object, Object> liteMap = lite.getMap(mapName); liteMap.get(1); map.set(1, 2); assertNullNearCacheEntryEventually(lite, mapName, 1); } public static void testUpdateWithPutAll(HazelcastInstance instance, HazelcastInstance lite, String mapName) { IMap<Object, Object> map = instance.getMap(mapName); map.put(1, 1); IMap<Object, Object> liteMap = lite.getMap(mapName); liteMap.get(1); Map<Object, Object> localMap = new HashMap<Object, Object>(); localMap.put(1, 2); map.putAll(localMap); assertNullNearCacheEntryEventually(lite, mapName, 1); } public static void testEvict(HazelcastInstance instance, HazelcastInstance lite, String mapName) { IMap<Object, Object> map = instance.getMap(mapName); map.put(1, 1); IMap<Object, Object> liteMap = lite.getMap(mapName); liteMap.get(1); map.evict(1); assertNearCacheIsEmptyEventually(lite, mapName); } public static void testRemove(HazelcastInstance instance, HazelcastInstance lite, String mapName) { IMap<Object, Object> map = instance.getMap(mapName); map.put(1, 1); IMap<Object, Object> liteMap = lite.getMap(mapName); liteMap.get(1); map.remove(1); assertNearCacheIsEmptyEventually(lite, mapName); } public static void testDelete(HazelcastInstance instance, HazelcastInstance lite, String mapName) { IMap<Object, Object> map = instance.getMap(mapName); map.put(1, 1); IMap<Object, Object> liteMap = lite.getMap(mapName); liteMap.get(1); map.delete(1); assertNearCacheIsEmptyEventually(lite, mapName); } public static void testClear(HazelcastInstance instance, HazelcastInstance lite, String mapName) { IMap<Object, Object> map = instance.getMap(mapName); int count = 100; for (int i = 0; i < count; i++) { map.put(i, i); } IMap<Object, Object> liteMap = lite.getMap(mapName); for (int i = 0; i < count; i++) { liteMap.get(i); } map.clear(); assertNearCacheIsEmptyEventually(lite, mapName); } public static void testEvictAll(HazelcastInstance instance, HazelcastInstance lite, String mapName) { IMap<Object, Object> map = instance.getMap(mapName); int count = 100; for (int i = 0; i < count; i++) { map.put(i, i); } IMap<Object, Object> liteMap = lite.getMap(mapName); for (int i = 0; i < count; i++) { liteMap.get(i); } map.evictAll(); assertNearCacheIsEmptyEventually(lite, mapName); } public static void testExecuteOnKey(HazelcastInstance instance, HazelcastInstance lite, String mapName) { IMap<Object, Object> map = instance.getMap(mapName); map.put(1, 1); IMap<Object, Object> liteMap = lite.getMap(mapName); liteMap.get(1); map.executeOnKey(1, new DummyEntryProcessor(2)); assertNearCacheIsEmptyEventually(lite, mapName); } public static void testExecuteOnKeys(HazelcastInstance instance, HazelcastInstance lite, String mapName) { IMap<Object, Object> map = instance.getMap(mapName); map.put(1, 1); IMap<Object, Object> liteMap = lite.getMap(mapName); liteMap.get(1); Set<Object> keySet = new HashSet<Object>(); keySet.add(1); map.executeOnKeys(keySet, new DummyEntryProcessor(2)); assertNearCacheIsEmptyEventually(lite, mapName); } public static void testLoadAll(HazelcastInstance instance, HazelcastInstance lite, String mapName) { IMap<Object, Object> map = instance.getMap(mapName); map.put(1, 1); IMap<Object, Object> liteMap = lite.getMap(mapName); liteMap.get(1); map.loadAll(true); assertNearCacheIsEmptyEventually(lite, mapName); } public static void testLoadAllWithKeySet(HazelcastInstance instance, HazelcastInstance lite, String mapName) { IMap<Object, Object> map = instance.getMap(mapName); map.put(1, 1); IMap<Object, Object> liteMap = lite.getMap(mapName); liteMap.get(1); Set<Object> keySet = map.keySet(); map.loadAll(keySet, true); assertNearCacheIsEmptyEventually(lite, mapName); } private void initWithMapStore() { factory.terminateAll(); instance = factory.newHazelcastInstance(createNearCachedMapConfigWithMapStoreConfig(mapName, false)); lite = factory.newHazelcastInstance(createNearCachedMapConfigWithMapStoreConfig(mapName, true)); } private static class DummyEntryProcessor implements EntryProcessor<Object, Object>, Serializable { private final Object newValue; DummyEntryProcessor(Object newValue) { this.newValue = newValue; } @Override public Object process(Map.Entry<Object, Object> entry) { return entry.setValue(newValue); } @Override public EntryBackupProcessor<Object, Object> getBackupProcessor() { return null; } } public static Config createConfig(String mapName, boolean liteMember) { NearCacheConfig nearCacheConfig = new NearCacheConfig(); nearCacheConfig.setInvalidateOnChange(true); Config config = new Config(); config.setLiteMember(liteMember); config.getMapConfig(mapName).setNearCacheConfig(nearCacheConfig); return config; } public static Config createNearCachedMapConfigWithMapStoreConfig(String mapName, boolean liteMember) { NearCacheTestSupport.SimpleMapStore store = new NearCacheTestSupport.SimpleMapStore(); MapStoreConfig mapStoreConfig = new MapStoreConfig(); mapStoreConfig.setEnabled(true); mapStoreConfig.setImplementation(store); NearCacheConfig nearCacheConfig = new NearCacheConfig(); nearCacheConfig.setInvalidateOnChange(true); Config config = new Config(); config.setLiteMember(liteMember); config.getMapConfig(mapName) .setMapStoreConfig(mapStoreConfig) .setNearCacheConfig(nearCacheConfig); return config; } private static MapService getMapService(HazelcastInstance instance) { return getNodeEngineImpl(instance).getService(MapService.SERVICE_NAME); } private static NearCache<Object, Object> getNearCache(HazelcastInstance instance, String mapName) { IMap<Data, Object> map = instance.getMap(mapName); return ((NearCachedMapProxyImpl<Data, Object>) map).getNearCache(); } private static void assertNullNearCacheEntryEventually(final HazelcastInstance instance, String mapName, Object key) { final NearCache<Object, Object> nearCache = getNearCache(instance, mapName); final Data keyData = toData(instance, key); assertTrueEventually(new AssertTask() { @Override public void run() { assertNull(toObject(instance, nearCache.get(keyData))); } }); } private static void assertLiteMemberNearCacheNonEmpty(HazelcastInstance instance, String mapName) { NearCache nearCache = getNearCache(instance, mapName); int sizeAfterPut = nearCache.size(); assertTrue("Near Cache size should be > 0 but was " + sizeAfterPut, sizeAfterPut > 0); } private static void assertNearCacheIsEmptyEventually(HazelcastInstance instance, String mapName) { final NearCache nearCache = getNearCache(instance, mapName); assertTrueEventually(new AssertTask() { @Override public void run() { int size = nearCache.size(); assertEquals("Lite member Near Cache size should be 0 after evict but was " + size, 0, size); } }); } private static Data toData(HazelcastInstance instance, Object obj) { return getMapService(instance).getMapServiceContext().toData(obj); } private static Object toObject(HazelcastInstance instance, Object obj) { return getMapService(instance).getMapServiceContext().toObject(obj); } }