/*
* Copyright (c) 2008-2012, Hazel Bilisim Ltd. 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.examples;
import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.HazelcastInstance;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Level;
import java.util.logging.Logger;
public class LongRunningTest {
private static final int STATS_SECONDS = 10;
private List<TheNode> nodes = new CopyOnWriteArrayList<TheNode>();
private int nodeIdGen = 0;
private final Logger logger = Logger.getLogger(LongRunningTest.class.getName());
private int starts, stops, restarts = 0;
public static void main(String[] args) {
LongRunningTest t = new LongRunningTest();
t.run();
}
public void run() {
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
log("Shutting down " + nodes.size());
while (nodes.size() > 0) {
removeNode();
}
}
});
while (true) {
if (nodes.size() > 4) {
removeNode();
} else if (nodes.size() == 0) {
addNode();
addNode();
addNode();
} else if (nodes.size() < 2) {
addNode();
} else {
int action = random(3);
switch (action) {
case 0:
removeNode();
break;
case 1:
addNode();
break;
case 2:
restartNode();
break;
}
}
try {
int nextSeconds = random(60, 260);
log("Next Action after " + nextSeconds + " seconds.");
log("members:" + nodes.size() + ", starts: " + starts + ", stops:" + stops + ", restart:" + restarts);
//noinspection BusyWait
Thread.sleep(nextSeconds * 1000);
} catch (InterruptedException e) {
}
}
}
void log(Object obj) {
logger.log(Level.INFO, "LRT-" + obj);
}
void addNode() {
starts++;
int entryCount = random(10000);
int threadCount = random(10, 50);
int valueSizeMax = (entryCount < 1000) ? 50000 : 1000;
int valueSize = random(10, valueSizeMax);
TheNode node = new TheNode(nodeIdGen++, entryCount, threadCount, valueSize);
nodes.add(node);
node.start();
log("Started " + node);
}
void restartNode() {
restarts++;
log("Restarting...");
removeNode();
try {
Thread.sleep(random(10) * 1000);
} catch (InterruptedException e) {
}
addNode();
}
void removeNode() {
stops++;
TheNode node = nodes.remove(random(nodes.size()));
node.stop();
log("Stopped " + node);
}
int random(int length) {
return ((int) (Math.random() * 10000000) % length);
}
int random(int from, int to) {
double diff = (to - from);
return (int) (diff * Math.random() + from);
}
class TheNode {
final int entryCount;
final int threadCount;
final int valueSize;
final int nodeId;
final long createTime;
final ExecutorService es;
final ExecutorService esStats;
final HazelcastInstance hazelcast;
volatile boolean running = true;
TheNode(int nodeId, int entryCount, int threadCount, int valueSize) {
this.entryCount = entryCount;
this.threadCount = threadCount;
this.valueSize = valueSize;
this.nodeId = nodeId;
es = Executors.newFixedThreadPool(threadCount);
hazelcast = Hazelcast.newHazelcastInstance(null);
esStats = Executors.newSingleThreadExecutor();
createTime = System.currentTimeMillis();
}
public void stop() {
try {
running = false;
es.shutdown();
es.awaitTermination(10, TimeUnit.SECONDS);
esStats.shutdown();
hazelcast.shutdown();
} catch (Throwable t) {
t.printStackTrace();
}
}
public void start() {
final Stats stats = new Stats();
for (int i = 0; i < threadCount; i++) {
es.submit(new Runnable() {
public void run() {
Map<String, byte[]> map = hazelcast.getMap("default");
while (running) {
try {
int key = (int) (Math.random() * entryCount);
int operation = ((int) (Math.random() * 100)) % 10;
if (operation < 4) {
map.put(String.valueOf(key), new byte[valueSize]);
stats.mapPuts.incrementAndGet();
} else if (operation < 8) {
map.get(String.valueOf(key));
stats.mapGets.incrementAndGet();
} else {
map.remove(String.valueOf(key));
stats.mapRemoves.incrementAndGet();
}
} catch (Throwable ignored) {
}
}
}
});
}
esStats.submit(new Runnable() {
public void run() {
while (running) {
try {
//noinspection BusyWait
Thread.sleep(STATS_SECONDS * 1000);
int clusterSize = hazelcast.getCluster().getMembers().size();
Stats currentStats = stats.getAndReset();
log("Cluster size: " + clusterSize + ", Operations per Second: "
+ (currentStats.total() / STATS_SECONDS));
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
}
@Override
public String toString() {
return "TheNode{" +
"nodeId=" + nodeId +
", entryCount=" + entryCount +
", threadCount=" + threadCount +
", valueSize=" + valueSize +
", liveSeconds=" + ((System.currentTimeMillis() - createTime) / 1000) +
", running=" + running +
'}';
}
}
class Stats {
public AtomicLong mapPuts = new AtomicLong();
public AtomicLong mapGets = new AtomicLong();
public AtomicLong mapRemoves = new AtomicLong();
public Stats getAndReset() {
long mapPutsNow = mapPuts.getAndSet(0);
long mapGetsNow = mapGets.getAndSet(0);
long mapRemovesNow = mapRemoves.getAndSet(0);
Stats newOne = new Stats();
newOne.mapPuts.set(mapPutsNow);
newOne.mapGets.set(mapGetsNow);
newOne.mapRemoves.set(mapRemovesNow);
return newOne;
}
public long total() {
return mapPuts.get() + mapGets.get() + mapRemoves.get();
}
public String toString() {
return "total= " + total() + ", puts:" + mapPuts.get() + ", gets:" + mapGets.get()
+ ", remove:" + mapRemoves.get();
}
}
}