package com.jivesoftware.os.amza.client.aquarium;
import com.jivesoftware.os.amza.api.PartitionClient;
import com.jivesoftware.os.amza.api.PartitionClientProvider;
import com.jivesoftware.os.amza.api.RingPartitionProperties;
import com.jivesoftware.os.amza.api.partition.PartitionName;
import com.jivesoftware.os.amza.api.partition.PartitionProperties;
import com.jivesoftware.os.amza.api.ring.RingMember;
import com.jivesoftware.os.amza.api.wal.KeyUtil;
import com.jivesoftware.os.amza.client.test.InMemoryPartitionClient;
import com.jivesoftware.os.aquarium.AquariumStats;
import com.jivesoftware.os.aquarium.LivelyEndState;
import com.jivesoftware.os.aquarium.Member;
import com.jivesoftware.os.aquarium.State;
import com.jivesoftware.os.jive.utils.ordered.id.ConstantWriterIdProvider;
import com.jivesoftware.os.jive.utils.ordered.id.JiveEpochTimestampProvider;
import com.jivesoftware.os.jive.utils.ordered.id.OrderIdProviderImpl;
import com.jivesoftware.os.jive.utils.ordered.id.SnowflakeIdPacker;
import com.jivesoftware.os.jive.utils.ordered.id.TimestampedOrderIdProvider;
import java.nio.charset.StandardCharsets;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.Executors;
import org.apache.commons.lang.ArrayUtils;
import org.testng.annotations.Test;
import static org.testng.Assert.assertNotEquals;
/**
*
*/
public class AmzaClientAquariumProviderTest {
@Test(enabled = false, description = "Slow sanity test")
public void testLeaderFailover() throws Exception {
final String serviceName = "test";
final int ringSize = 3;
final int numAquariums = 3;
TimestampedOrderIdProvider orderIdProvider = new OrderIdProviderImpl(
new ConstantWriterIdProvider(1),
new SnowflakeIdPacker(),
new JiveEpochTimestampProvider());
Map<PartitionName, PartitionClient> indexes = new ConcurrentHashMap<>();
PartitionClientProvider partitionClientProvider = new PartitionClientProvider() {
@Override
public PartitionClient getPartition(PartitionName partitionName) throws Exception {
return indexes.computeIfAbsent(partitionName,
partitionName1 -> new InMemoryPartitionClient(new RingMember("member1"),
new ConcurrentSkipListMap<>(),
new ConcurrentSkipListMap<>(KeyUtil.lexicographicalComparator()), orderIdProvider));
}
@Override
public PartitionClient getPartition(PartitionName partitionName, int desiredRingSize, PartitionProperties partitionProperties) throws Exception {
return getPartition(partitionName);
}
@Override
public RingPartitionProperties getProperties(PartitionName partitionName) throws Exception {
return null;
}
};
AquariumStats aquariumStats = new AquariumStats();
Set<Member> members = new HashSet<>();
AmzaClientAquariumProvider[] providers = new AmzaClientAquariumProvider[ringSize];
for (int i = 0; i < ringSize; i++) {
Member m = new Member(("member" + i).getBytes(StandardCharsets.UTF_8));
members.add(m);
providers[i] = new AmzaClientAquariumProvider(aquariumStats,
serviceName,
partitionClientProvider,
orderIdProvider,
m,
count -> count > ringSize / 2,
() -> members,
128,
128,
1_000L,
100L,
10_000L,
2_000L,
Executors.newSingleThreadExecutor(),
100L,
1_000L,
10_000L,
false);
providers[i].start();
for (int j = 0; j < numAquariums; j++) {
providers[i].register("aquarium" + j);
}
}
boolean[] leaders = monitorAquariums(providers, numAquariums, ringSize, 20_000L, 1_000L);
int stopIndex = ArrayUtils.indexOf(leaders, true);
assertNotEquals(stopIndex, -1);
System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
providers[stopIndex].stop();
System.out.println("STOPPED index " + stopIndex);
leaders = monitorAquariums(providers, numAquariums, ringSize, 40_000L, 1_000L);
for (int i = 0; i < ringSize; i++) {
providers[i].stop();
}
}
private boolean[] monitorAquariums(AmzaClientAquariumProvider[] providers, int numAquariums, int ringSize, long duration, long interval) throws Exception {
boolean[] leaders = new boolean[providers.length];
long start = System.currentTimeMillis();
while (true) {
System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
System.out.println("t=" + (System.currentTimeMillis() - start));
for (int j = 0; j < numAquariums; j++) {
System.out.println("\ta=" + j);
for (int i = 0; i < ringSize; i++) {
LivelyEndState livelyEndState = providers[i].livelyEndState("aquarium" + j);
if (livelyEndState == null) {
System.out.println("\t\t" + i + ": offline");
} else {
System.out.println("\t\t" + i + ": " + (livelyEndState.isOnline() ? livelyEndState.getCurrentState() : "dead"));
leaders[i] |= livelyEndState.isOnline() && livelyEndState.getCurrentState() == State.leader;
}
}
}
if (System.currentTimeMillis() - start > duration) {
break;
} else {
Thread.sleep(interval);
}
}
return leaders;
}
}