import com.hazelcast.cache.ICache;
import com.hazelcast.client.HazelcastClient;
import com.hazelcast.client.cache.impl.HazelcastClientCachingProvider;
import com.hazelcast.client.config.ClientConfig;
import com.hazelcast.client.config.XmlClientConfigBuilder;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.logging.ILogger;
import com.hazelcast.logging.Logger;
import com.hazelcast.memory.NativeOutOfMemoryError;
import com.hazelcast.util.EmptyStatement;
import org.HdrHistogram.AbstractHistogram;
import org.HdrHistogram.AtomicHistogram;
import org.HdrHistogram.Histogram;
import javax.cache.CacheManager;
import java.io.IOException;
import java.io.InputStream;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import static com.hazelcast.examples.helper.LicenseUtils.ENTERPRISE_LICENSE_KEY;
/**
* You have to set your Hazelcast Enterprise license key to make this code sample work.
* Please have a look at {@link com.hazelcast.examples.helper.LicenseUtils} for details.
*/
public final class EnterpriseCacheTestClient {
private static final String NAMESPACE = "test";
private static final long STATS_SECONDS = 10;
private final String[] values = new String[500];
private final AtomicBoolean live = new AtomicBoolean(true);
private final HazelcastInstance instance;
private final CacheManager cacheManager;
private final ExecutorService executorService;
private final ILogger logger;
private final Stats[] allStats;
private final int threadCount;
private final int getPercentage;
private final int putPercentage;
private final int keyRange;
private final long duration;
static {
System.setProperty("hazelcast.version.check.enabled", "false");
System.setProperty("hazelcast.socket.bind.any", "false");
System.setProperty("java.net.preferIPv4Stack", "true");
System.setProperty("hazelcast.multicast.group", "224.35.57.79");
}
private EnterpriseCacheTestClient(int threadCount, int getPercentage, int putPercentage, int keyRange,
int valueMin, int valueMax, long duration) throws IOException {
InputStream configInputStream = EnterpriseCacheTestClient.class.getResourceAsStream("/hazelcast-client-hd-memory.xml");
ClientConfig clientConfig = new XmlClientConfigBuilder(configInputStream).build();
clientConfig.setLicenseKey(ENTERPRISE_LICENSE_KEY);
this.instance = HazelcastClient.newHazelcastClient(clientConfig);
this.cacheManager = HazelcastClientCachingProvider.createCachingProvider(instance).getCacheManager();
this.executorService = Executors.newFixedThreadPool(threadCount);
this.logger = Logger.getLogger(getClass());
this.allStats = new Stats[threadCount];
for (int i = 0; i < threadCount; i++) {
allStats[i] = new Stats();
}
this.threadCount = threadCount;
this.getPercentage = getPercentage;
this.putPercentage = putPercentage;
this.keyRange = keyRange;
this.duration = duration;
buildRandomValues(valueMin, valueMax);
}
private void buildRandomValues(int valueMin, int valueMax) {
Random random = new Random();
for (int i = 0; i < values.length; i++) {
int size = random.nextInt(valueMax - valueMin) + valueMin;
byte[] bb = new byte[size];
random.nextBytes(bb);
values[i] = new String(bb);
}
}
@SuppressWarnings("checkstyle:cyclomaticcomplexity")
public static void main(String[] input) throws Exception {
int threadCount = 40;
int valueMin = 100;
int valueMax = 101;
int getPercentage = 40;
int putPercentage = 40;
int keyRange = Integer.MAX_VALUE;
long duration = Long.MAX_VALUE;
if (input != null && input.length > 0) {
for (String arg : input) {
arg = arg.trim();
if (arg.startsWith("vs")) {
valueMin = Integer.parseInt(arg.substring(2));
} else if (arg.startsWith("vx")) {
valueMax = Integer.parseInt(arg.substring(2));
} else if (arg.startsWith("t")) {
threadCount = Integer.parseInt(arg.substring(1));
} else if (arg.startsWith("g")) {
getPercentage = Integer.parseInt(arg.substring(1));
} else if (arg.startsWith("p")) {
putPercentage = Integer.parseInt(arg.substring(1));
} else if (arg.startsWith("k")) {
keyRange = Integer.parseInt(arg.substring(1));
if (keyRange <= 0) {
keyRange = Integer.MAX_VALUE;
}
} else if (arg.startsWith("d")) {
duration = TimeUnit.MINUTES.toMillis(Integer.parseInt(arg.substring(1)));
if (duration <= 0) {
duration = Long.MAX_VALUE;
}
}
}
}
EnterpriseCacheTestClient test = new EnterpriseCacheTestClient(threadCount, getPercentage, putPercentage, keyRange,
valueMin, valueMax, duration);
test.start();
}
private void start() {
printVariables();
startPrintStats();
run();
}
private void printVariables() {
logger.info("Starting Test with ");
logger.info("Thread Count: " + threadCount);
logger.info("Get Percentage: " + getPercentage);
logger.info("Put Percentage: " + putPercentage);
logger.info("Remove Percentage: " + (100 - (putPercentage + getPercentage)));
}
private void startPrintStats() {
new StatsThread().start();
}
private void run() {
ICache<Object, Object> cache = cacheManager.getCache(NAMESPACE).unwrap(ICache.class);
for (int i = 0; i < threadCount; i++) {
executorService.execute(new CacheTestRunnable(allStats[i], cache));
}
}
private class StatsThread extends Thread {
StatsThread() {
setDaemon(true);
setName("PrintStats." + instance.getName());
}
@Override
public void run() {
long terminate = System.currentTimeMillis() + duration;
if (terminate < 0) {
terminate = Long.MAX_VALUE;
}
AbstractHistogram totalHistogram = new Histogram(1, TimeUnit.MINUTES.toNanos(1), 3);
while (true) {
try {
long start = System.currentTimeMillis();
if (start >= terminate) {
live.set(false);
executorService.shutdown();
executorService.awaitTermination(2, TimeUnit.MINUTES);
instance.shutdown();
break;
}
Thread.sleep(STATS_SECONDS * 1000);
long end = System.currentTimeMillis();
long interval = end - start;
totalHistogram.reset();
long getsNow = 0;
long putsNow = 0;
long removesNow = 0;
for (int i = 0; i < threadCount; i++) {
Stats stats = allStats[i];
getsNow += stats.gets.getAndSet(0);
putsNow += stats.puts.getAndSet(0);
removesNow += stats.removes.getAndSet(0);
totalHistogram.add(stats.histogram);
stats.histogram.reset();
}
long totalOps = getsNow + putsNow + removesNow;
totalHistogram.reestablishTotalCount();
totalHistogram.outputPercentileDistribution(System.out, 1, 1000d);
System.out.println();
System.out.println("total-ops= " + (totalOps * 1000 / interval) + ", gets:" + (getsNow * 1000 / interval)
+ ", puts:" + (putsNow * 1000 / interval) + ", removes:" + (removesNow * 1000 / interval));
System.out.println();
System.out.println();
} catch (InterruptedException ignored) {
return;
}
}
}
}
private class CacheTestRunnable implements Runnable {
private final Random random = new Random();
private final Stats stats;
private final ICache<Object, Object> cache;
CacheTestRunnable(Stats stats, ICache<Object, Object> cache) {
this.stats = stats;
this.cache = cache;
}
@Override
public void run() {
int stopCounter = 0;
while (true) {
if (stopCounter++ == 5000) {
stopCounter = 0;
if (!live.get()) {
return;
}
}
try {
Object key = newKey(random);
int operation = random.nextInt(100);
long start = System.nanoTime();
if (operation < getPercentage) {
cache.get(key);
stats.gets.incrementAndGet();
} else if (operation < getPercentage + putPercentage) {
try {
cache.put(key, values[random.nextInt(values.length)]);
} catch (NativeOutOfMemoryError e) {
System.err.println(e.getMessage());
}
stats.puts.incrementAndGet();
} else {
cache.remove(key);
stats.removes.incrementAndGet();
}
long end = System.nanoTime();
try {
stats.histogram.recordValue(end - start);
} catch (IndexOutOfBoundsException e) {
EmptyStatement.ignore(e);
}
} catch (Throwable e) {
if (e.getCause() instanceof InterruptedException) {
return;
}
if (!instance.getLifecycleService().isRunning()) {
return;
}
logger.warning(e.getClass().getName() + ": " + e.getMessage(), e);
}
}
}
private Object newKey(Random rand) {
return (keyRange <= 0 || keyRange == Integer.MAX_VALUE) ? rand.nextLong() : rand.nextInt(keyRange);
}
}
private static class Stats {
final AbstractHistogram histogram = new AtomicHistogram(1, TimeUnit.MINUTES.toNanos(1), 3);
final AtomicInteger gets = new AtomicInteger();
final AtomicInteger puts = new AtomicInteger();
final AtomicInteger removes = new AtomicInteger();
}
}