package com.netflix.evcache.pool.observer;
import java.lang.management.ManagementFactory;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.netflix.appinfo.ApplicationInfoManager;
import com.netflix.appinfo.InstanceInfo;
import com.netflix.evcache.metrics.EVCacheMetricsFactory;
import com.netflix.evcache.pool.ServerGroup;
import com.netflix.servo.monitor.Monitors;
import com.netflix.servo.tag.BasicTag;
import com.netflix.servo.tag.Tag;
import net.spy.memcached.ConnectionObserver;
public class EVCacheConnectionObserver implements ConnectionObserver, EVCacheConnectionObserverMBean {
private static final Logger log = LoggerFactory.getLogger(EVCacheConnectionObserver.class);
private final InstanceInfo instanceInfo;
private final String appName;
private final ServerGroup serverGroup;
private final int id;
private long lostCount = 0;
private long connectCount = 0;
private final Set<SocketAddress> evCacheActiveSet;
private final Set<SocketAddress> evCacheInActiveSet;
private final Map<InetSocketAddress, Long> evCacheActiveStringSet;
private final Map<InetSocketAddress, Long> evCacheInActiveStringSet;
private final String monitorName;
@SuppressWarnings("deprecation")
public EVCacheConnectionObserver(String appName, ServerGroup serverGroup, int id) {
this.instanceInfo = ApplicationInfoManager.getInstance().getInfo();
this.appName = appName;
this.serverGroup = serverGroup;
this.evCacheActiveSet = Collections.newSetFromMap(new ConcurrentHashMap<SocketAddress, Boolean>());
this.evCacheInActiveSet = Collections.newSetFromMap(new ConcurrentHashMap<SocketAddress, Boolean>());
this.evCacheActiveStringSet = new ConcurrentHashMap<InetSocketAddress, Long>();
this.evCacheInActiveStringSet = new ConcurrentHashMap<InetSocketAddress, Long>();
this.id = id;
monitorName = appName + "_" + serverGroup.getName() + "_" + id + "_connections";
setupMonitoring(false);
}
public void connectionEstablished(SocketAddress sa, int reconnectCount) {
final String address = sa.toString();
evCacheActiveSet.add(sa);
evCacheInActiveSet.remove(sa);
final InetSocketAddress inetAdd = (InetSocketAddress) sa;
evCacheActiveStringSet.put(inetAdd, Long.valueOf(System.currentTimeMillis()));
evCacheInActiveStringSet.remove(inetAdd);
if (instanceInfo != null) {
if (log.isDebugEnabled()) log.debug(appName + ":CONNECTION ESTABLISHED : From " + instanceInfo.getHostName()
+ " to " + address + " was established after " + reconnectCount + " retries");
}
if(log.isTraceEnabled()) log.trace("Stack", new Exception());
EVCacheMetricsFactory.increment(appName, null, serverGroup.getName(), appName + "-CONNECT");
connectCount++;
}
public void connectionLost(SocketAddress sa) {
final String address = sa.toString();
evCacheInActiveSet.add(sa);
evCacheActiveSet.remove(sa);
final InetSocketAddress inetAdd = (InetSocketAddress) sa;
evCacheInActiveStringSet.put(inetAdd, Long.valueOf(System.currentTimeMillis()));
evCacheActiveStringSet.remove(inetAdd);
if (instanceInfo != null) {
if (log.isDebugEnabled()) log.debug(appName + ":CONNECTION LOST : From " + instanceInfo.getHostName()
+ " to " + address);
}
if(log.isTraceEnabled()) log.trace("Stack", new Exception());
final Tag tag = new BasicTag("HOST", inetAdd.getAddress().getHostAddress());
EVCacheMetricsFactory.getCounter(appName, null, serverGroup.getName(), appName + "-CONNECTION_LOST", tag).increment();
lostCount++;
}
public int getActiveServerCount() {
return evCacheActiveSet.size();
}
public Set<SocketAddress> getActiveServerNames() {
return evCacheActiveSet;
}
public int getInActiveServerCount() {
return evCacheInActiveSet.size();
}
public Set<SocketAddress> getInActiveServerNames() {
return evCacheInActiveSet;
}
public long getLostCount() {
return lostCount;
}
public long getConnectCount() {
return connectCount;
}
public Map<InetSocketAddress, Long> getInActiveServers() {
return evCacheInActiveStringSet;
}
public Map<InetSocketAddress, Long> getActiveServers() {
return evCacheActiveStringSet;
}
private void setupMonitoring(boolean shutdown) {
try {
final ObjectName mBeanName = ObjectName.getInstance("com.netflix.evcache:Group=" + appName
+ ",SubGroup=pool,SubSubGroup=" + serverGroup.getName() + ",SubSubSubGroup=" + id);
final MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
if (mbeanServer.isRegistered(mBeanName)) {
if (log.isDebugEnabled()) log.debug("MBEAN with name " + mBeanName
+ " has been registered. Will unregister the previous instance and register a new one.");
mbeanServer.unregisterMBean(mBeanName);
}
if (!shutdown) {
mbeanServer.registerMBean(this, mBeanName);
Monitors.registerObject(this);
} else {
Monitors.unregisterObject(this);
}
} catch (Exception e) {
if (log.isWarnEnabled()) log.warn(e.getMessage(), e);
}
}
private void unRegisterInActiveNodes() {
try {
for (SocketAddress sa : evCacheInActiveSet) {
final ObjectName mBeanName = ObjectName.getInstance("com.netflix.evcache:Group=" + appName
+ ",SubGroup=pool" + ",SubSubGroup=" + serverGroup.getName() + ",SubSubSubGroup=" + id
+ ",SubSubSubSubGroup=" + ((InetSocketAddress) sa).getHostName());
final MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
if (mbeanServer.isRegistered(mBeanName)) {
if (log.isDebugEnabled()) log.debug("MBEAN with name " + mBeanName
+ " has been registered. Will unregister the previous instance and register a new one.");
mbeanServer.unregisterMBean(mBeanName);
}
}
} catch (Exception e) {
if (log.isWarnEnabled()) log.warn(e.getMessage(), e);
}
}
public void shutdown() {
unRegisterInActiveNodes();
setupMonitoring(true);
}
public String toString() {
return "EVCacheConnectionObserver [instanceInfo=" + instanceInfo
+ ", appName=" + appName + ", ServerGroup=" + serverGroup.toString() + ", id=" + id
+ ", evCacheActiveSet=" + evCacheActiveSet
+ ", evCacheInActiveSet=" + evCacheInActiveSet
+ ", evCacheActiveStringSet=" + evCacheActiveStringSet
+ ", evCacheInActiveStringSet=" + evCacheInActiveStringSet
+ ", monitorName=" + monitorName + "]";
}
public String getAppName() {
return appName;
}
public String getServerGroup() {
return serverGroup.toString();
}
public int getId() {
return id;
}
}