Test case: instantiate a client with near cache. put a map entry with ttl 2 seconds. get from map and populate near cache. Wait 2 seconds. The map.get should return null upon ttl expiry.
This test case fails. test code:
package com.hazelcast.client.map.impl.nearcache;
import com.hazelcast.client.HazelcastClient;
import com.hazelcast.client.config.ClientConfig;
import com.hazelcast.config.NearCacheConfig;
import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.IMap;
import com.hazelcast.test.AssertTask;
import com.hazelcast.test.HazelcastTestSupport;
import java.util.concurrent.TimeUnit;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
public class TTLTest {
public static void main(String[] args) {
Hazelcast.newHazelcastInstance();
int ttlTime = 2000; //msecs
String mapName = "SomeMap";
ClientConfig config = new ClientConfig();
config.addNearCacheConfig(new NearCacheConfig(mapName));
HazelcastInstance client = HazelcastClient.newHazelcastClient(config);
final IMap<Object, Object> map = client.getMap(mapName);
map.put(1, "value1", ttlTime, TimeUnit.MILLISECONDS);
Object firstValue = map.get(1);
System.out.println("First value:" + firstValue);
assertEquals("value1", firstValue);
try {
Thread.sleep(ttlTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
// trigger eviction
Object secondValue = map.get(1);
System.out.println("Second value:" + secondValue);
HazelcastTestSupport.assertTrueEventually(new AssertTask() {
@Override
public void run()
throws Exception {
Object value = map.get(1);
System.out.println("Value is " + value);
assertNull(value);
}
});
System.out.println("Test finished");
HazelcastClient.shutdownAll();
}
}
We analysed the case further and it comes out that the test were not correct. The map put with ttl behaves different when near cache is enabled.
When no-near cache, the client will see the eviction after the ttl expires when it does the next get.
When near cache is enabled, the client will NOT see the eviction after ttl passes and it will continue to see the value from local near-cache. Hence, the actual correct test is:
package com.hazelcast.client.map.impl.nearcache;
import com.hazelcast.client.HazelcastClient;
import com.hazelcast.client.config.ClientConfig;
import com.hazelcast.config.NearCacheConfig;
import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.IMap;
import com.hazelcast.test.AssertTask;
import com.hazelcast.test.HazelcastTestSupport;
import java.util.concurrent.TimeUnit;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
/**
* Created by ihsan on 17/01/17.
*/
public class TTLTest {
public static void main(String[] args) {
Hazelcast.newHazelcastInstance();
int ttlTime = 2000; //msecs
String mapName = "SomeMap";
ClientConfig config = new ClientConfig();
config.addNearCacheConfig(new NearCacheConfig(mapName));
HazelcastInstance client = HazelcastClient.newHazelcastClient(config);
final IMap<Object, Object> map = client.getMap(mapName);
map.put(1, "value1", ttlTime, TimeUnit.MILLISECONDS);
Object firstValue = map.get(1);
System.out.println("First value:" + firstValue);
assertEquals("value1", firstValue);
try {
Thread.sleep(ttlTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
// trigger eviction
Object secondValue = map.get(1);
System.out.println("Second value:" + secondValue);
HazelcastTestSupport.assertTrueAllTheTime(new AssertTask() {
@Override
public void run()
throws Exception {
Object value = map.get(1);
System.out.println("Value is " + value);
assertEquals("value1", value);
}
}, 20);
System.out.println("Test finished");
HazelcastClient.shutdownAll();
}
}
Despite of near cache doesn't guarantee strong consistency, would expect that it gets invalidated even in this case. Will appreciate any meaningful description. Couldn't find any so far.
Could solve the problem by adding a EntryExpiredListener to the map:
...
map.addEntryListener((EntryExpiredListener) event -> invalidateNearCache(map, event), false);
...
public static void invalidateNearCache(final IMap<Object, Object> map, EntryEvent event) {
if (map instanceof NearCachedClientMapProxy) {
System.out.println("Invalidating key " + event.getKey());
NearCachedClientMapProxy nearCache = (NearCachedClientMapProxy) map;
nearCache.getNearCache().invalidate(event.getKey());
}
}
Open issue for this problem: https://github.com/hazelcast/hazelcast/issues/10975