/*
* 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.client.map.impl.nearcache;
import com.hazelcast.client.config.ClientConfig;
import com.hazelcast.client.impl.protocol.ClientMessage;
import com.hazelcast.client.impl.protocol.codec.MapAddNearCacheEntryListenerCodec;
import com.hazelcast.client.proxy.NearCachedClientMapProxy;
import com.hazelcast.client.spi.EventHandler;
import com.hazelcast.client.test.TestHazelcastFactory;
import com.hazelcast.config.Config;
import com.hazelcast.config.EvictionPolicy;
import com.hazelcast.config.InMemoryFormat;
import com.hazelcast.config.MapConfig;
import com.hazelcast.config.MapStoreConfig;
import com.hazelcast.config.NearCacheConfig;
import com.hazelcast.core.ExecutionCallback;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.IMap;
import com.hazelcast.core.MapStoreAdapter;
import com.hazelcast.internal.nearcache.NearCache;
import com.hazelcast.map.impl.nearcache.NearCacheTestSupport;
import com.hazelcast.monitor.NearCacheStats;
import com.hazelcast.nio.serialization.Data;
import com.hazelcast.spi.properties.GroupProperty;
import com.hazelcast.test.AssertTask;
import com.hazelcast.test.HazelcastParametersRunnerFactory;
import com.hazelcast.test.annotation.ParallelTest;
import com.hazelcast.test.annotation.QuickTest;
import org.junit.After;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import static com.hazelcast.spi.properties.GroupProperty.MAP_INVALIDATION_MESSAGE_BATCH_ENABLED;
import static java.lang.Boolean.FALSE;
import static java.lang.Boolean.TRUE;
import static java.lang.String.format;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@RunWith(Parameterized.class)
@Parameterized.UseParametersRunnerFactory(HazelcastParametersRunnerFactory.class)
@Category({QuickTest.class, ParallelTest.class})
public class ClientMapNearCacheTest extends NearCacheTestSupport {
@Parameterized.Parameter
public boolean batchInvalidationEnabled;
@Parameterized.Parameters(name = "batchInvalidationEnabled:{0}")
public static Iterable<Object[]> parameters() {
return Arrays.asList(new Object[]{TRUE}, new Object[]{FALSE});
}
protected final TestHazelcastFactory hazelcastFactory = new TestHazelcastFactory();
@After
public void tearDown() {
hazelcastFactory.shutdownAll();
}
@Test
public void testGetAllChecksNearCacheFirst() {
IMap<Integer, Integer> map = getNearCachedMapFromClient(newNoInvalidationNearCacheConfig());
HashSet<Integer> keys = new HashSet<Integer>();
int size = 1003;
for (int i = 0; i < size; i++) {
map.put(i, i);
keys.add(i);
}
// populate Near Cache
for (int i = 0; i < size; i++) {
map.get(i);
}
// getAll() generates the Near Cache hits
map.getAll(keys);
NearCacheStats stats = getNearCacheStats(map);
assertEquals(size, stats.getOwnedEntryCount());
assertEquals(size, stats.getHits());
}
@Test
public void testGetAllPopulatesNearCache() {
IMap<Integer, Integer> map = getNearCachedMapFromClient(newNoInvalidationNearCacheConfig());
HashSet<Integer> keys = new HashSet<Integer>();
int size = 1214;
for (int i = 0; i < size; i++) {
map.put(i, i);
keys.add(i);
}
// getAll() populates Near Cache
map.getAll(keys);
assertThatOwnedEntryCountEquals(map, size);
}
@Test
public void testGetAsync() throws Exception {
IMap<Integer, Integer> map = getNearCachedMapFromClient(newNoInvalidationNearCacheConfig());
int size = 1009;
populateMap(map, size);
populateNearCache(map, size);
// generate Near Cache hits with async call
for (int i = 0; i < size; i++) {
Future future = map.getAsync(i);
future.get();
}
NearCacheStats stats = getNearCacheStats(map);
assertEquals(size, stats.getOwnedEntryCount());
assertEquals(size, stats.getHits());
}
@Test
public void testAfterRemoveNearCacheIsInvalidated() {
int mapSize = 1000;
String mapName = randomMapName();
hazelcastFactory.newHazelcastInstance(newConfig());
HazelcastInstance client = getClient(hazelcastFactory, newInvalidationOnChangeEnabledNearCacheConfig(mapName));
final IMap<Integer, Integer> clientMap = client.getMap(mapName);
populateMap(clientMap, mapSize);
populateNearCache(clientMap, mapSize);
for (int i = 0; i < mapSize; i++) {
clientMap.remove(i, i);
}
assertTrueEventually(new AssertTask() {
public void run() {
assertThatOwnedEntryCountEquals(clientMap, 0);
}
});
}
@Test
public void testAfterDeleteNearCacheIsInvalidated() {
int mapSize = 1000;
String mapName = randomMapName();
hazelcastFactory.newHazelcastInstance(newConfig());
HazelcastInstance client = getClient(hazelcastFactory, newInvalidationOnChangeEnabledNearCacheConfig(mapName));
final IMap<Integer, Integer> clientMap = client.getMap(mapName);
populateMap(clientMap, mapSize);
populateNearCache(clientMap, mapSize);
for (int i = 0; i < mapSize; i++) {
clientMap.delete(i);
}
assertTrueEventually(new AssertTask() {
public void run() {
assertThatOwnedEntryCountEquals(clientMap, 0);
}
});
}
@Test
public void testAfterPutAsyncNearCacheIsInvalidated() {
int mapSize = 1000;
String mapName = randomMapName();
hazelcastFactory.newHazelcastInstance(newConfig());
HazelcastInstance client = getClient(hazelcastFactory, newInvalidationOnChangeEnabledNearCacheConfig(mapName));
final IMap<Integer, Integer> clientMap = client.getMap(mapName);
populateMap(clientMap, mapSize);
populateNearCache(clientMap, mapSize);
for (int i = 0; i < mapSize; i++) {
clientMap.putAsync(i, i, 1, TimeUnit.SECONDS);
}
assertTrueEventually(new AssertTask() {
public void run() {
assertThatOwnedEntryCountEquals(clientMap, 0);
}
});
}
@Test
public void testAfterSetAsyncNearCacheIsInvalidated() {
int mapSize = 1000;
String mapName = randomMapName();
hazelcastFactory.newHazelcastInstance(newConfig());
HazelcastInstance client = getClient(hazelcastFactory, newInvalidationOnChangeEnabledNearCacheConfig(mapName));
final IMap<Integer, Integer> clientMap = client.getMap(mapName);
populateMap(clientMap, mapSize);
populateNearCache(clientMap, mapSize);
for (int i = 0; i < mapSize; i++) {
clientMap.setAsync(i, i, 1, TimeUnit.SECONDS);
}
assertTrueEventually(new AssertTask() {
public void run() {
assertThatOwnedEntryCountEquals(clientMap, 0);
}
});
}
@Test
public void testAfterRemoveAsyncNearCacheIsInvalidated() {
int mapSize = 1000;
String mapName = randomMapName();
hazelcastFactory.newHazelcastInstance(newConfig());
HazelcastInstance client = getClient(hazelcastFactory, newInvalidationOnChangeEnabledNearCacheConfig(mapName));
final IMap<Integer, Integer> clientMap = client.getMap(mapName);
populateMap(clientMap, mapSize);
populateNearCache(clientMap, mapSize);
for (int i = 0; i < mapSize; i++) {
clientMap.removeAsync(i);
}
assertTrueEventually(new AssertTask() {
public void run() {
assertThatOwnedEntryCountEquals(clientMap, 0);
}
});
}
@Test
public void testAfterTryRemoveNearCacheIsInvalidated() {
int mapSize = 1000;
String mapName = randomMapName();
hazelcastFactory.newHazelcastInstance(newConfig());
HazelcastInstance client = getClient(hazelcastFactory, newInvalidationOnChangeEnabledNearCacheConfig(mapName));
final IMap<Integer, Integer> clientMap = client.getMap(mapName);
populateMap(clientMap, mapSize);
populateNearCache(clientMap, mapSize);
for (int i = 0; i < mapSize; i++) {
clientMap.tryRemove(i, 5, TimeUnit.SECONDS);
}
assertTrueEventually(new AssertTask() {
public void run() {
assertThatOwnedEntryCountEquals(clientMap, 0);
}
});
}
@Test
public void testAfterTryPutNearCacheIsInvalidated() {
int mapSize = 1000;
String mapName = randomMapName();
hazelcastFactory.newHazelcastInstance(newConfig());
HazelcastInstance client = getClient(hazelcastFactory, newInvalidationOnChangeEnabledNearCacheConfig(mapName));
final IMap<Integer, Integer> clientMap = client.getMap(mapName);
populateMap(clientMap, mapSize);
populateNearCache(clientMap, mapSize);
for (int i = 0; i < mapSize; i++) {
clientMap.tryPut(i, i, 5, TimeUnit.SECONDS);
}
assertTrueEventually(new AssertTask() {
public void run() {
assertThatOwnedEntryCountEquals(clientMap, 0);
}
});
}
@Test
public void testAfterPutTransientNearCacheIsInvalidated() {
int mapSize = 1000;
String mapName = randomMapName();
hazelcastFactory.newHazelcastInstance(newConfig());
HazelcastInstance client = getClient(hazelcastFactory, newInvalidationOnChangeEnabledNearCacheConfig(mapName));
final IMap<Integer, Integer> clientMap = client.getMap(mapName);
populateMap(clientMap, mapSize);
populateNearCache(clientMap, mapSize);
for (int i = 0; i < mapSize; i++) {
clientMap.putTransient(i, i, 10, TimeUnit.SECONDS);
}
assertTrueEventually(new AssertTask() {
public void run() {
assertThatOwnedEntryCountEquals(clientMap, 0);
}
});
}
@Test
public void testAfterPutIfAbsentNearCacheIsInvalidated() {
int mapSize = 1000;
String mapName = randomMapName();
hazelcastFactory.newHazelcastInstance(newConfig());
HazelcastInstance client = getClient(hazelcastFactory, newInvalidationOnChangeEnabledNearCacheConfig(mapName));
final IMap<Integer, Integer> clientMap = client.getMap(mapName);
populateMap(clientMap, mapSize);
populateNearCache(clientMap, mapSize);
for (int i = 0; i < mapSize; i++) {
clientMap.putIfAbsent(i, i, 1, TimeUnit.SECONDS);
}
assertTrueEventually(new AssertTask() {
public void run() {
assertThatOwnedEntryCountEquals(clientMap, 0);
}
});
}
@Test
public void testAfterSetNearCacheIsInvalidated() {
int mapSize = 1000;
String mapName = randomMapName();
hazelcastFactory.newHazelcastInstance(newConfig());
HazelcastInstance client = getClient(hazelcastFactory,
newInvalidationOnChangeEnabledNearCacheConfig(mapName));
final IMap<Integer, Integer> clientMap = client.getMap(mapName);
populateMap(clientMap, mapSize);
populateNearCache(clientMap, mapSize);
for (int i = 0; i < mapSize; i++) {
clientMap.set(i, i, 1, TimeUnit.SECONDS);
}
assertTrueEventually(new AssertTask() {
public void run() {
assertThatOwnedEntryCountEquals(clientMap, 0);
}
});
}
@Test
public void testAfterEvictNearCacheIsInvalidated() {
int mapSize = 1000;
String mapName = randomMapName();
hazelcastFactory.newHazelcastInstance(newConfig());
HazelcastInstance client = getClient(hazelcastFactory,
newInvalidationOnChangeEnabledNearCacheConfig(mapName));
final IMap<Integer, Integer> clientMap = client.getMap(mapName);
populateMap(clientMap, mapSize);
populateNearCache(clientMap, mapSize);
for (int i = 0; i < mapSize; i++) {
clientMap.evict(i);
}
assertTrueEventually(new AssertTask() {
public void run() {
assertThatOwnedEntryCountEquals(clientMap, 0);
}
});
}
@Test
public void testAfterEvictAllNearCacheIsInvalidated() {
int mapSize = 1000;
String mapName = randomMapName();
hazelcastFactory.newHazelcastInstance(newConfig());
HazelcastInstance client = getClient(hazelcastFactory,
newInvalidationOnChangeEnabledNearCacheConfig(mapName));
final IMap<Integer, Integer> clientMap = client.getMap(mapName);
populateMap(clientMap, mapSize);
populateNearCache(clientMap, mapSize);
clientMap.evictAll();
assertTrueEventually(new AssertTask() {
public void run() {
assertThatOwnedEntryCountEquals(clientMap, 0);
}
});
}
@Test
public void testAfterLoadAllNearCacheIsInvalidated() {
int mapSize = 1000;
String mapName = randomMapName();
HazelcastInstance server = hazelcastFactory.newHazelcastInstance(newConfig());
HazelcastInstance client = getClient(hazelcastFactory,
newInvalidationOnChangeEnabledNearCacheConfig(mapName));
Config config = server.getConfig();
SimpleMapStore store = new SimpleMapStore();
MapStoreConfig mapStoreConfig = new MapStoreConfig();
mapStoreConfig.setEnabled(true);
mapStoreConfig.setImplementation(store);
config.getMapConfig(mapName).setMapStoreConfig(mapStoreConfig);
final IMap<Integer, Integer> clientMap = client.getMap(mapName);
populateMap(clientMap, mapSize);
populateNearCache(clientMap, mapSize);
clientMap.loadAll(true);
assertTrueEventually(new AssertTask() {
public void run() {
assertThatOwnedEntryCountEquals(clientMap, 0);
}
});
}
@Test
public void testMemberLoadAll_invalidates_clientNearCache() {
int mapSize = 1000;
String mapName = randomMapName();
HazelcastInstance member = hazelcastFactory.newHazelcastInstance(newConfig());
HazelcastInstance client = getClient(hazelcastFactory,
newInvalidationOnChangeEnabledNearCacheConfig(mapName));
Config config = member.getConfig();
SimpleMapStore store = new SimpleMapStore();
MapStoreConfig mapStoreConfig = new MapStoreConfig();
mapStoreConfig.setEnabled(true);
mapStoreConfig.setImplementation(store);
config.getMapConfig(mapName).setMapStoreConfig(mapStoreConfig);
final IMap<Integer, Integer> clientMap = client.getMap(mapName);
populateMap(clientMap, mapSize);
populateNearCache(clientMap, mapSize);
IMap<Integer, Integer> map = member.getMap(mapName);
map.loadAll(true);
assertTrueEventually(new AssertTask() {
public void run() {
assertThatOwnedEntryCountEquals(clientMap, 0);
}
});
}
@Test
public void testAfterLoadAllWithDefinedKeysNearCacheIsInvalidated() {
int mapSize = 1000;
String mapName = randomMapName();
HazelcastInstance server = hazelcastFactory.newHazelcastInstance(newConfig());
HazelcastInstance client = getClient(hazelcastFactory,
newInvalidationOnChangeEnabledNearCacheConfig(mapName));
Config config = server.getConfig();
SimpleMapStore store = new SimpleMapStore();
MapStoreConfig mapStoreConfig = new MapStoreConfig();
mapStoreConfig.setEnabled(true);
mapStoreConfig.setImplementation(store);
config.getMapConfig(mapName).setMapStoreConfig(mapStoreConfig);
final IMap<Integer, Integer> clientMap = client.getMap(mapName);
HashSet<Integer> keys = new HashSet<Integer>();
for (int i = 0; i < mapSize; i++) {
clientMap.put(i, i);
keys.add(i);
}
for (int i = 0; i < mapSize; i++) {
clientMap.get(i);
}
clientMap.loadAll(keys, false);
assertTrueEventually(new AssertTask() {
public void run() {
assertThatOwnedEntryCountEquals(clientMap, 0);
}
});
}
@Test
public void testMemberPutAll_invalidates_clientNearCache() {
int mapSize = 1000;
String mapName = randomMapName();
HazelcastInstance member = hazelcastFactory.newHazelcastInstance(newConfig());
HazelcastInstance client = getClient(hazelcastFactory,
newInvalidationOnChangeEnabledNearCacheConfig(mapName));
final IMap<Integer, Integer> clientMap = client.getMap(mapName);
HashMap<Integer, Integer> hashMap = new HashMap<Integer, Integer>();
for (int i = 0; i < mapSize; i++) {
clientMap.put(i, i);
hashMap.put(i, i);
}
for (int i = 0; i < mapSize; i++) {
clientMap.get(i);
}
IMap<Integer, Integer> memberMap = member.getMap(mapName);
memberMap.putAll(hashMap);
assertTrueEventually(new AssertTask() {
public void run() {
assertThatOwnedEntryCountEquals(clientMap, 0);
}
});
}
@Test
public void testAfterSubmitToKeyKeyIsInvalidatedFromNearCache() {
final int mapSize = 1000;
String mapName = randomMapName();
Random random = new Random();
Config config = newConfig();
config.setProperty(GroupProperty.PARTITION_COUNT.getName(), "1");
HazelcastInstance member = hazelcastFactory.newHazelcastInstance(config);
IMap memberMap = member.getMap(mapName);
populateMap(memberMap, mapSize);
HazelcastInstance client = getClient(hazelcastFactory,
newInvalidationOnChangeEnabledNearCacheConfig(mapName));
final IMap<Integer, Integer> clientMap = client.getMap(mapName);
populateNearCache(clientMap, mapSize);
int randomKey = random.nextInt(mapSize);
clientMap.submitToKey(randomKey, new IncrementEntryProcessor());
assertTrueEventually(new AssertTask() {
public void run() {
assertThatOwnedEntryCountEquals(clientMap, mapSize - 1);
}
});
}
@Test
public void testAfterSubmitToKeyWithCallbackKeyIsInvalidatedFromNearCache() throws Exception {
final int mapSize = 1000;
String mapName = randomMapName("testAfterSubmitToKeyWithCallbackKeyIsInvalidatedFromNearCache");
Random random = new Random();
HazelcastInstance member = hazelcastFactory.newHazelcastInstance(newConfig());
IMap memberMap = member.getMap(mapName);
populateMap(memberMap, mapSize);
HazelcastInstance client = getClient(hazelcastFactory,
newInvalidationOnChangeEnabledNearCacheConfig(mapName));
final IMap<Integer, Integer> clientMap = client.getMap(mapName);
populateNearCache(clientMap, mapSize);
final CountDownLatch latch = new CountDownLatch(1);
ExecutionCallback<Integer> callback = new ExecutionCallback<Integer>() {
@Override
public void onResponse(Integer response) {
latch.countDown();
}
@Override
public void onFailure(Throwable t) {
}
};
int randomKey = random.nextInt(mapSize);
clientMap.submitToKey(randomKey, new IncrementEntryProcessor(), callback);
latch.await(3, TimeUnit.SECONDS);
assertTrueEventually(new AssertTask() {
public void run() {
assertThatOwnedEntryCountEquals(clientMap, mapSize - 1);
}
});
}
@Test
public void testAfterExecuteOnKeyKeyIsInvalidatedFromNearCache() {
final int mapSize = 1000;
String mapName = randomMapName();
Random random = new Random();
HazelcastInstance member = hazelcastFactory.newHazelcastInstance(newConfig());
IMap memberMap = member.getMap(mapName);
populateMap(memberMap, mapSize);
HazelcastInstance client = getClient(hazelcastFactory,
newInvalidationOnChangeEnabledNearCacheConfig(mapName));
final IMap<Integer, Integer> clientMap = client.getMap(mapName);
populateNearCache(clientMap, mapSize);
int randomKey = random.nextInt(mapSize);
clientMap.executeOnKey(randomKey, new IncrementEntryProcessor());
assertTrueEventually(new AssertTask() {
public void run() {
assertThatOwnedEntryCountEquals(clientMap, mapSize - 1);
}
});
}
@Test
public void testNearCacheIsRemoved_afterMapDestroy() {
int mapSize = 1000;
String mapName = randomMapName();
hazelcastFactory.newHazelcastInstance(newConfig());
NearCacheConfig nearCacheConfig = newInvalidationOnChangeEnabledNearCacheConfig(mapName);
HazelcastInstance client = getClient(hazelcastFactory, nearCacheConfig);
IMap<Integer, Integer> clientMap = client.getMap(mapName);
populateMap(clientMap, mapSize);
populateNearCache(clientMap, mapSize);
clientMap.destroy();
final IMap<Integer, Integer> map = client.getMap(mapName);
assertTrueEventually(new AssertTask() {
public void run() {
assertThatOwnedEntryCountEquals(map, 0);
}
});
}
@Test
public void testRemovedKeyValueNotInNearCache() {
IMap<Integer, Integer> map = getNearCachedMapFromClient(newInvalidationEnabledNearCacheConfig());
int size = 1247;
populateMap(map, size);
populateNearCache(map, size);
for (int i = 0; i < size; i++) {
map.remove(i);
assertNull(map.get(i));
}
}
@Test
public void testNearCachePopulatedAndHitsGenerated() {
IMap<Integer, Integer> map = getNearCachedMapFromClient(newNoInvalidationNearCacheConfig());
int size = 1278;
populateMap(map, size);
populateNearCache(map, size);
for (int i = 0; i < size; i++) {
// generate Near Cache hits
map.get(i);
}
NearCacheStats stats = getNearCacheStats(map);
assertEquals(size, stats.getOwnedEntryCount());
assertEquals(size, stats.getHits());
}
@Test
public void testNearCachePopulatedAndHitsGenerated_withInterleavedCacheHitGeneration() {
IMap<Integer, Integer> map = getNearCachedMapFromClient(newNoInvalidationNearCacheConfig());
int size = 1278;
for (int i = 0; i < size; i++) {
map.put(i, i);
// populate Near Cache
map.get(i);
// generate Near Cache hits
map.get(i);
}
NearCacheStats stats = getNearCacheStats(map);
System.out.println("stats = " + stats);
assertEquals(size, stats.getOwnedEntryCount());
assertEquals(size, stats.getHits());
}
@Test
public void testIssue2009() {
IMap<Integer, Integer> map = getNearCachedMapFromClient(newInvalidationEnabledNearCacheConfig());
NearCacheStats stats = getNearCacheStats(map);
assertNotNull(stats);
}
@Test
public void testGetNearCacheStatsBeforePopulation() {
IMap<Integer, Integer> map = getNearCachedMapFromClient(newNoInvalidationNearCacheConfig());
int size = 101;
for (int i = 0; i < size; i++) {
map.put(i, i);
}
NearCacheStats stats = getNearCacheStats(map);
assertNotNull(stats);
}
@Test
public void testNearCacheMisses() {
IMap<String, Integer> map = getNearCachedMapFromClient(newNoInvalidationNearCacheConfig());
int expectedCacheMisses = 1321;
for (int i = 0; i < expectedCacheMisses; i++) {
map.get("NOT_THERE" + i);
}
NearCacheStats stats = getNearCacheStats(map);
assertEquals(expectedCacheMisses, stats.getMisses());
assertEquals(expectedCacheMisses, stats.getOwnedEntryCount());
}
@Test
public void testNearCacheMisses_whenRepeatedOnSameKey() {
IMap<String, Integer> map = getNearCachedMapFromClient(newInvalidationEnabledNearCacheConfig());
int expectedCacheMisses = 17;
for (int i = 0; i < expectedCacheMisses; i++) {
assertNull(map.get("NOT_THERE"));
}
NearCacheStats stats = getNearCacheStats(map);
assertEquals(1, stats.getOwnedEntryCount());
assertEquals(expectedCacheMisses, stats.getMisses());
}
@Test
public void testMapRemove_WithNearCache() {
IMap<Integer, Integer> map = getNearCachedMapFromClient(newInvalidationEnabledNearCacheConfig());
int size = 1113;
populateMap(map, size);
populateNearCache(map, size);
for (int i = 0; i < size; i++) {
map.remove(i);
}
NearCacheStats stats = getNearCacheStats(map);
assertEquals(0, stats.getOwnedEntryCount());
assertEquals(size, stats.getMisses());
}
@Test
public void testNearCacheTTLExpiration() {
IMap<Integer, Integer> map = getNearCachedMapFromClient(newTTLNearCacheConfig());
testNearCacheExpiration(map, MAX_CACHE_SIZE, MAX_TTL_SECONDS);
}
@Test
public void testNearCacheMaxIdleRecordsExpired() {
IMap<Integer, Integer> map = getNearCachedMapFromClient(newMaxIdleSecondsNearCacheConfig());
testNearCacheExpiration(map, MAX_CACHE_SIZE, MAX_IDLE_SECONDS);
}
@Test
public void testNearCacheInvalidateOnChange() {
String mapName = randomMapName();
HazelcastInstance server = hazelcastFactory.newHazelcastInstance(newConfig());
ClientConfig clientConfig = newClientConfig();
clientConfig.addNearCacheConfig(newInvalidationEnabledNearCacheConfig());
IMap<Integer, Integer> serverMap = server.getMap(mapName);
int size = 118;
for (int i = 0; i < size; i++) {
serverMap.put(i, i);
}
HazelcastInstance newHazelcastClient = hazelcastFactory.newHazelcastClient(clientConfig);
final IMap<Integer, Integer> clientMap = newHazelcastClient.getMap(mapName);
// populate Near Cache
for (int i = 0; i < size; i++) {
clientMap.get(i);
}
assertThatOwnedEntryCountEquals(clientMap, size);
// invalidate Near Cache from server side
for (int i = 0; i < size; i++) {
serverMap.put(i, i);
}
assertTrueEventually(new AssertTask() {
public void run() {
assertThatOwnedEntryCountEquals(clientMap, 0);
}
});
}
@Test(expected = NullPointerException.class)
public void testNearCacheContainsNullKey() {
IMap<Integer, Integer> map = getNearCachedMapFromClient(newInvalidationEnabledNearCacheConfig());
map.containsKey(null);
}
@Test
public void testNearCacheContainsKey() {
IMap<String, String> map = getNearCachedMapFromClient(newInvalidationEnabledNearCacheConfig());
String key = "key";
map.put(key, "value");
map.get(key);
assertTrue(format("map doesn't contain expected key %s (map size: %d)", key, map.size()), map.containsKey(key));
}
@Test
public void testNearCacheContainsKey_whenKeyAbsent() {
IMap<String, String> map = getNearCachedMapFromClient(newInvalidationEnabledNearCacheConfig());
assertFalse(format("map contains unexpected key NOT_THERE (map size: %d)", map.size()), map.containsKey("NOT_THERE"));
}
@Test
public void testNearCacheContainsKey_afterRemove() {
IMap<String, String> map = getNearCachedMapFromClient(newInvalidationEnabledNearCacheConfig());
String key = "key";
map.put(key, "value");
map.get(key);
map.remove(key);
assertFalse(format("map contains unexpected key %s (map size: %d)", key, map.size()), map.containsKey(key));
}
@Test
public void testNearCache_clearFromRemote() {
String mapName = randomMapName();
HazelcastInstance server = hazelcastFactory.newHazelcastInstance(newConfig());
NearCacheConfig nearCacheConfig = newInvalidationEnabledNearCacheConfig();
ClientConfig clientConfig = newClientConfig();
clientConfig.addNearCacheConfig(nearCacheConfig);
HazelcastInstance client = hazelcastFactory.newHazelcastClient(clientConfig);
final IMap<Integer, Integer> map = client.getMap(mapName);
final int size = 147;
populateMap(map, size);
populateNearCache(map, size);
server.getMap(mapName).clear();
// Near Cache should be empty
assertTrueEventually(new AssertTask() {
public void run() {
for (int i = 0; i < size; i++) {
assertNull(map.get(i));
}
}
});
}
@Test
public void testNearCache_clearFromClient() {
IMap<Integer, Integer> map = getNearCachedMapFromClient(newInvalidationEnabledNearCacheConfig());
int size = 147;
populateMap(map, size);
populateNearCache(map, size);
map.clear();
// Near Cache should be empty
for (int i = 0; i < size; i++) {
assertNull(map.get(i));
}
}
@Test
public void receives_one_clearEvent_after_mapClear_call_from_client() {
// populate Near Cache
IMap<Integer, Integer> clientMap = getNearCachedMapFromClient(newNearCacheConfig());
populateMap(clientMap, 1000);
populateNearCache(clientMap, 1000);
// add test listener to count clear events
final ClearEventCounterEventHandler handler = new ClearEventCounterEventHandler();
((NearCachedClientMapProxy) clientMap).addNearCacheInvalidationListener(handler);
// create a new client to send events
HazelcastInstance anotherClient = hazelcastFactory.newHazelcastClient(newClientConfig());
IMap<Object, Object> anotherClientMap = anotherClient.getMap(clientMap.getName());
anotherClientMap.clear();
// sleep for a while to see there is another clear event coming
sleepSeconds(2);
assertTrueEventually(new AssertTask() {
@Override
public void run() {
assertEquals("Expecting only 1 clear event", 1, handler.getClearEventCount());
}
});
}
@Test
public void receives_one_clearEvent_after_mapClear_call_from_member() {
// start new member and populate map
HazelcastInstance member = hazelcastFactory.newHazelcastInstance(newConfig());
IMap<Integer, Integer> memberMap = member.getMap("test");
populateMap(memberMap, 1000);
// populate client Near Cache
NearCacheConfig nearCacheConfig = newNearCacheConfig();
ClientConfig clientConfig = newClientConfig();
clientConfig.addNearCacheConfig(nearCacheConfig);
HazelcastInstance client = hazelcastFactory.newHazelcastClient(clientConfig);
IMap<Integer, Integer> clientMap = client.getMap("test");
populateNearCache(clientMap, 1000);
// add test listener to count clear events
final ClearEventCounterEventHandler handler = new ClearEventCounterEventHandler();
((NearCachedClientMapProxy) clientMap).addNearCacheInvalidationListener(handler);
// clear map from member side
memberMap.clear();
// sleep for a while to see there is another clear event coming
sleepSeconds(2);
assertTrueEventually(new AssertTask() {
@Override
public void run() {
assertEquals("Expecting only 1 clear event", 1, handler.getClearEventCount());
}
});
}
@Test
public void receives_one_clearEvent_after_mapEvictAll_call_from_client() {
// populate Near Cache
IMap<Integer, Integer> clientMap = getNearCachedMapFromClient(newNearCacheConfig());
populateMap(clientMap, 1000);
populateNearCache(clientMap, 1000);
// add test listener to count clear events
final ClearEventCounterEventHandler handler = new ClearEventCounterEventHandler();
((NearCachedClientMapProxy) clientMap).addNearCacheInvalidationListener(handler);
// call evictAll
HazelcastInstance anotherClient = hazelcastFactory.newHazelcastClient(newClientConfig());
IMap<Object, Object> anotherClientMap = anotherClient.getMap(clientMap.getName());
anotherClientMap.evictAll();
// sleep for a while to see there is another clear event coming
sleepSeconds(2);
assertTrueEventually(new AssertTask() {
@Override
public void run() {
assertEquals("Expecting only 1 clear event", 1, handler.getClearEventCount());
}
});
}
@Test
public void receives_one_clearEvent_after_mapEvictAll_call_from_member() {
// populate Near Cache
IMap<Integer, Integer> clientMap = getNearCachedMapFromClient(newNearCacheConfig());
populateMap(clientMap, 1000);
populateNearCache(clientMap, 1000);
// member comes
HazelcastInstance member = hazelcastFactory.newHazelcastInstance(newConfig());
// add test listener to count clear events
final ClearEventCounterEventHandler handler = new ClearEventCounterEventHandler();
((NearCachedClientMapProxy) clientMap).addNearCacheInvalidationListener(handler);
// call evictAll
IMap memberMap = member.getMap(clientMap.getName());
memberMap.evictAll();
// sleep for a while to see there is another clear event coming
sleepSeconds(2);
assertTrueEventually(new AssertTask() {
@Override
public void run() {
assertEquals("Expecting only 1 clear event", 1, handler.getClearEventCount());
}
});
}
@Test
public void receives_one_clearEvent_after_mapLoadAll_call_from_client() {
// configure map-store
Config config = newConfig();
config.getMapConfig("default").getMapStoreConfig().setEnabled(true).setImplementation(new SimpleMapStore());
// populate Near Cache
final IMap<Integer, Integer> clientMap = getNearCachedMapFromClient(config, newNearCacheConfig());
populateMap(clientMap, 1000);
populateNearCache(clientMap, 1000);
// create a new client to send events
HazelcastInstance anotherClient = hazelcastFactory.newHazelcastClient(newClientConfig());
IMap<Object, Object> anotherClientMap = anotherClient.getMap(clientMap.getName());
anotherClientMap.loadAll(true);
assertTrueEventually(new AssertTask() {
@Override
public void run() {
NearCache nearCache = ((NearCachedClientMapProxy) clientMap).getNearCache();
for (int i = 0; i < 1000; i++) {
assertNull("Near-cache should be empty", nearCache.get(i));
}
}
});
}
@Test
public void receives_one_clearEvent_after_mapLoadAll_call_from_member() {
// configure map-store
Config config = newConfig();
config.getMapConfig("default").getMapStoreConfig().setEnabled(true).setImplementation(new SimpleMapStore());
// member comes
HazelcastInstance member = hazelcastFactory.newHazelcastInstance(config);
// populate Near Cache
final IMap<Integer, Integer> clientMap = getNearCachedMapFromClient(config, newNearCacheConfig());
populateMap(clientMap, 1000);
populateNearCache(clientMap, 1000);
// create a new client to send events
IMap<Object, Object> memberMap = member.getMap(clientMap.getName());
memberMap.loadAll(true);
assertTrueEventually(new AssertTask() {
@Override
public void run() {
NearCache nearCache = ((NearCachedClientMapProxy) clientMap).getNearCache();
for (int i = 0; i < 1000; i++) {
assertNull("Near-cache should be empty", nearCache.get(i));
}
}
});
}
@Test
public void testNearCacheInvalidation_WithLFU_whenMaxSizeExceeded() {
assertNearCacheInvalidation_whenMaxSizeExceeded(newLFUMaxSizeNearCacheConfig());
}
@Test
public void testNearCacheInvalidation_WithLRU_whenMaxSizeExceeded() {
assertNearCacheInvalidation_whenMaxSizeExceeded(newLRUMaxSizeConfig());
}
@Test
public void testNearCacheInvalidation_WithRandom_whenMaxSizeExceeded() {
assertNearCacheInvalidation_whenMaxSizeExceeded(newRandomNearCacheConfig());
}
@Test
public void testNearCacheInvalidation_WithNone_whenMaxSizeExceeded() {
final IMap<Integer, Integer> map = getNearCachedMapFromClient(newNoneNearCacheConfig());
int mapSize = MAX_CACHE_SIZE * 2;
populateMap(map, mapSize);
populateNearCache(map, mapSize);
assertTrueEventually(new AssertTask() {
@Override
public void run() {
assertThatOwnedEntryCountEquals(map, MAX_CACHE_SIZE);
}
});
}
@Test
public void testMapDestroy_succeeds_when_writeBehind_and_nearCache_enabled() {
Config config = newConfig();
MapConfig mapConfig = config.getMapConfig("default");
mapConfig.getMapStoreConfig()
.setEnabled(true)
.setWriteDelaySeconds(1)
.setImplementation(new MapStoreAdapter());
IMap<Integer, Integer> map = getNearCachedMapFromClient(config, newInvalidationEnabledNearCacheConfig());
populateMap(map, 10);
populateNearCache(map, 10);
map.destroy();
}
@Test
public void testNearCacheGetAsyncTwice() throws Exception {
NearCacheConfig nearCacheConfig = newNearCacheConfig();
nearCacheConfig.setInMemoryFormat(InMemoryFormat.OBJECT);
IMap<Integer, Integer> map = getNearCachedMapFromClient(nearCacheConfig);
map.getAsync(1).get();
sleepMillis(1000);
assertNull(map.getAsync(1).get());
}
@Test(expected = IllegalArgumentException.class)
public void testNearCache_whenInMemoryFormatIsNative_thenThrowIllegalArgumentException() {
NearCacheConfig nearCacheConfig = newNearCacheConfig();
nearCacheConfig.setInMemoryFormat(InMemoryFormat.NATIVE);
getNearCachedMapFromClient(nearCacheConfig);
}
@Override
protected NearCacheConfig newNearCacheConfigWithEntryCountEviction(EvictionPolicy evictionPolicy, int size) {
return super.newNearCacheConfigWithEntryCountEviction(evictionPolicy, size)
.setCacheLocalEntries(false);
}
protected NearCacheConfig newNoneNearCacheConfig() {
return newNearCacheConfigWithEntryCountEviction(EvictionPolicy.NONE, MAX_CACHE_SIZE)
.setInvalidateOnChange(true);
}
protected NearCacheConfig newRandomNearCacheConfig() {
return newNearCacheConfigWithEntryCountEviction(EvictionPolicy.RANDOM, MAX_CACHE_SIZE)
.setInvalidateOnChange(true);
}
protected NearCacheConfig newLRUMaxSizeConfig() {
return newNearCacheConfigWithEntryCountEviction(EvictionPolicy.LRU, MAX_CACHE_SIZE)
.setInvalidateOnChange(true);
}
protected NearCacheConfig newLFUMaxSizeNearCacheConfig() {
return newNearCacheConfigWithEntryCountEviction(EvictionPolicy.LFU, MAX_CACHE_SIZE)
.setInvalidateOnChange(true);
}
protected NearCacheConfig newTTLNearCacheConfig() {
NearCacheConfig nearCacheConfig = newNearCacheConfig();
nearCacheConfig.setInvalidateOnChange(false);
nearCacheConfig.setTimeToLiveSeconds(MAX_TTL_SECONDS);
return nearCacheConfig;
}
protected NearCacheConfig newMaxIdleSecondsNearCacheConfig() {
NearCacheConfig nearCacheConfig = newNearCacheConfig();
nearCacheConfig.setInvalidateOnChange(false);
nearCacheConfig.setMaxIdleSeconds(MAX_IDLE_SECONDS);
return nearCacheConfig;
}
protected NearCacheConfig newInvalidationEnabledNearCacheConfig() {
NearCacheConfig nearCacheConfig = newNearCacheConfig();
nearCacheConfig.setInvalidateOnChange(true);
return nearCacheConfig;
}
protected NearCacheConfig newInvalidationOnChangeEnabledNearCacheConfig(String name) {
NearCacheConfig nearCacheConfig = newNearCacheConfig();
nearCacheConfig.setInvalidateOnChange(true);
nearCacheConfig.setName(name);
return nearCacheConfig;
}
protected Config newConfig() {
Config config = new Config();
config.setProperty(MAP_INVALIDATION_MESSAGE_BATCH_ENABLED.getName(), String.valueOf(batchInvalidationEnabled));
return config;
}
protected NearCacheConfig newNoInvalidationNearCacheConfig() {
NearCacheConfig nearCacheConfig = newNearCacheConfig();
nearCacheConfig.setInMemoryFormat(InMemoryFormat.OBJECT);
nearCacheConfig.setInvalidateOnChange(false);
return nearCacheConfig;
}
protected HazelcastInstance getClient(TestHazelcastFactory testHazelcastFactory, NearCacheConfig nearCacheConfig) {
ClientConfig clientConfig = newClientConfig();
clientConfig.addNearCacheConfig(nearCacheConfig);
return testHazelcastFactory.newHazelcastClient(clientConfig);
}
protected <K, V> IMap<K, V> getNearCachedMapFromClient(NearCacheConfig nearCacheConfig) {
return getNearCachedMapFromClient(newConfig(), nearCacheConfig);
}
protected <K, V> IMap<K, V> getNearCachedMapFromClient(Config config, NearCacheConfig nearCacheConfig) {
String mapName = randomMapName();
hazelcastFactory.newHazelcastInstance(config);
nearCacheConfig.setName(mapName + "*");
ClientConfig clientConfig = newClientConfig();
clientConfig.addNearCacheConfig(nearCacheConfig);
HazelcastInstance client = hazelcastFactory.newHazelcastClient(clientConfig);
return client.getMap(mapName);
}
protected ClientConfig newClientConfig() {
return new ClientConfig();
}
protected void assertNearCacheInvalidation_whenMaxSizeExceeded(NearCacheConfig config) {
final IMap<Integer, Integer> map = getNearCachedMapFromClient(config);
populateMap(map, MAX_CACHE_SIZE);
populateNearCache(map, MAX_CACHE_SIZE);
triggerEviction(map);
assertTrueEventually(new AssertTask() {
@Override
public void run() {
assertThatOwnedEntryCountIsSmallerThan(map, MAX_CACHE_SIZE);
}
});
}
private static class ClearEventCounterEventHandler
extends MapAddNearCacheEntryListenerCodec.AbstractEventHandler implements EventHandler<ClientMessage> {
private final AtomicInteger clearEventCount = new AtomicInteger();
ClearEventCounterEventHandler() {
}
@Override
public void handle(Data key, String sourceUuid, UUID partitionUuid, long sequence) {
if (key == null) {
clearEventCount.incrementAndGet();
}
}
@Override
public void handle(Collection<Data> keys, Collection<String> sourceUuids,
Collection<UUID> partitionUuids, Collection<Long> sequences) {
}
@Override
public void beforeListenerRegister() {
}
@Override
public void onListenerRegister() {
}
int getClearEventCount() {
return clearEventCount.get();
}
}
}