package org.infinispan.distribution.rehash;
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertFalse;
import static org.testng.AssertJUnit.assertNull;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.SerializeWith;
import org.infinispan.configuration.cache.CacheMode;
import org.infinispan.configuration.cache.ConfigurationBuilder;
import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.remoting.transport.Address;
import org.infinispan.test.MultipleCacheManagersTest;
import org.infinispan.util.BaseControlledConsistentHashFactory;
import org.testng.annotations.Test;
/**
* Tests rehashing with distributed caches with L1 enabled.
*
* @author Galder ZamarreƱo
* @since 5.2
*/
@Test(groups = "functional", testName = "distribution.rehash.RehashWithL1Test")
public class RehashWithL1Test extends MultipleCacheManagersTest {
ConfigurationBuilder builder;
@Override
protected void createCacheManagers() throws Throwable {
MyBaseControlledConsistentHashFactory chf = new MyBaseControlledConsistentHashFactory();
builder = getDefaultClusteredCacheConfig(CacheMode.DIST_SYNC, false);
builder.clustering().hash().numSegments(1).numOwners(1).consistentHashFactory(chf);
builder.clustering().l1().enable().lifespan(10, TimeUnit.MINUTES);
createClusteredCaches(3, builder);
}
public void testPutWithRehashAndCacheClear() throws Exception {
int opCount = 10;
for (int i = 0; i < opCount; i++) {
cache(1).put("k" + i, "some data");
}
for (int j = 0; j < caches().size(); j++) {
log.debugf("Populating L1 on %s", address(j));
for (int i = 0; i < opCount; i++) {
assertEquals("Wrong value for k" + i, "some data", cache(j).get("k" + i));
}
}
int killIndex = caches().size() - 1;
log.debugf("Killing node %s", address(killIndex));
killMember(killIndex);
// All entries were owned by the killed node, but they survive in the L1 of cache(1)
for (int j = 0; j < caches().size(); j++) {
log.debugf("Checking values on %s", address(j));
for (int i = 0; i < opCount; i++) {
String key = "k" + i;
assertEquals("Wrong value for key " + key, "some data", cache(j).get(key));
}
}
log.debugf("Starting a new joiner");
EmbeddedCacheManager cm = addClusterEnabledCacheManager(builder);
cm.getCache();
// State transfer won't copy L1 entries to cache(2), and they're deleted on cache(1) afterwards
// Note: we would need eventually() if we checked the data container directly
for (int j = 0; j < caches().size() - 1; j++) {
log.debugf("Checking values on %s", address(j));
for (int i = 0; i < opCount; i++) {
assertNull("wrong value for k" + i, cache(j).get("k" + i));
}
}
for (int i = 0; i < opCount; i++) {
cache(0).remove("k" + i);
}
for (int i = 0; i < opCount; i++) {
String key = "k" + i;
assertFalse(cache(0).containsKey(key));
assertFalse("Key: " + key + " is present in cache at " + cache(0),
cache(0).containsKey(key));
assertFalse("Key: " + key + " is present in cache at " + cache(1),
cache(1).containsKey(key));
assertFalse("Key: " + key + " is present in cache at " + cache(2),
cache(2).containsKey(key));
}
assertEquals(0, cache(0).size());
assertEquals(0, cache(1).size());
assertEquals(0, cache(2).size());
}
@SerializeWith(MyBaseControlledConsistentHashFactory.Ext.class)
private static class MyBaseControlledConsistentHashFactory extends BaseControlledConsistentHashFactory {
public MyBaseControlledConsistentHashFactory() {
super(1);
}
@Override
protected List<Address> createOwnersCollection(List<Address> members, int numberOfOwners, int segmentIndex) {
return Collections.singletonList(members.get(members.size() - 1));
}
public static final class Ext implements Externalizer<MyBaseControlledConsistentHashFactory> {
@Override
public void writeObject(ObjectOutput output, MyBaseControlledConsistentHashFactory object) {
// No-op
}
@Override
public MyBaseControlledConsistentHashFactory readObject(ObjectInput input) {
return new MyBaseControlledConsistentHashFactory();
}
}
}
}