package net.rubyeye.xmemcached.aws;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* AWS ElastiCache configuration poller
*
* @author dennis
*
*/
public class ConfigurationPoller implements Runnable {
/**
* Return current ClusterConfigration.
*
* @return
*/
public ClusterConfigration getClusterConfiguration() {
return clusterConfigration;
}
private final AtomicInteger serverOrderCounter = new AtomicInteger(0);
private Map<String, Integer> ordersMap = new HashMap<String, Integer>();
public synchronized int getCacheNodeOrder(CacheNode node) {
Integer order = this.ordersMap.get(node.getCacheKey());
if (order != null) {
return order;
}
order = this.serverOrderCounter.incrementAndGet();
this.ordersMap.put(node.getCacheKey(), order);
return order;
}
public synchronized void removeCacheNodeOrder(CacheNode node) {
this.ordersMap.remove(node.getCacheKey());
}
private static final Logger log = LoggerFactory
.getLogger(ConfigurationPoller.class);
private final AWSElasticCacheClient client;
private final long pollIntervalMills;
private ScheduledExecutorService scheduledExecutorService;
private volatile ClusterConfigration clusterConfigration = null;
public ConfigurationPoller(AWSElasticCacheClient client,
long pollIntervalMills) {
super();
this.client = client;
this.pollIntervalMills = pollIntervalMills;
this.scheduledExecutorService = Executors
.newSingleThreadScheduledExecutor(new ThreadFactory() {
public Thread newThread(Runnable r) {
Thread t = new Thread(r, "AWSElasticCacheConfigPoller");
t.setDaemon(true);
if (t.getPriority() != Thread.NORM_PRIORITY) {
t.setPriority(Thread.NORM_PRIORITY);
}
return t;
}
});
}
public void start() {
this.scheduledExecutorService.scheduleWithFixedDelay(this,
this.pollIntervalMills, this.pollIntervalMills,
TimeUnit.MILLISECONDS);
}
public void stop() {
this.scheduledExecutorService.shutdown();
}
public void run() {
try {
ClusterConfigration newConfig = this.client.getConfig();
if (newConfig != null) {
ClusterConfigration currentConfig = this.clusterConfigration;
if (currentConfig == null) {
this.clusterConfigration = newConfig;
} else {
if (newConfig.getVersion() < currentConfig.getVersion()) {
log.warn("Ignored new config from ElasticCache node, it's too old, current version is: "
+ currentConfig.getVersion()
+ ", but the new version is: "
+ newConfig.getVersion());
return;
} else {
this.clusterConfigration = newConfig;
}
}
log.info("Retrieved new config from ElasticCache node: "
+ this.clusterConfigration);
this.client.onUpdate(newConfig);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (Exception e) {
log.error("Poll config from ElasticCache node failed", e);
}
}
}