Merge "Adding cache support to the jmx proxy" from Amnon

"Some of the nodetool commands calls multiple time to the same methods,
 specifically nodetool status and ring calls the endpoint snitch get rack
 and datacenter many times during the same command. It result in a long
 execution time.

 This series adds the ability to cache results when needed. Typically
 cached result will be for a few seconds, there is no need to a clean up
 mechanism as we don't expect there will be too much information in the
 cache.

 Currently the only cached results are for the endpoint snitch but it is
 easy to add more if we see that it is needed."
This commit is contained in:
Pekka Enberg 2015-10-07 12:32:59 +03:00
commit be8eea6bd4
3 changed files with 80 additions and 12 deletions

View File

@ -22,6 +22,7 @@ import javax.json.JsonReaderFactory;
import javax.json.JsonString;
import javax.management.openmbean.TabularData;
import javax.management.openmbean.TabularDataSupport;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.UriBuilder;
@ -33,9 +34,29 @@ import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.yammer.metrics.core.HistogramValues;
import javax.ws.rs.core.MediaType;
public class APIClient {
Map<String, CacheEntry> cache = new HashMap<String, CacheEntry>();
String getCacheKey(String key, MultivaluedMap<String, String> param, long duration) {
if (duration <= 0) {
return null;
}
if (param != null) {
StringBuilder sb = new StringBuilder(key);
sb.append("?");
for (String k : param.keySet()) {
sb.append(k).append('=').append(param.get(k)).append('&');
}
return sb.toString();
}
return key;
}
String getFromCache(String key, long duration) {
if (key == null) {
return null;
}
CacheEntry value = cache.get(key);
return (value!= null && value.valid(duration))? value.value : null;
}
JsonReaderFactory factory = Json.createReaderFactory(null);
private static final java.util.logging.Logger logger = java.util.logging.Logger
.getLogger(APIClient.class.getName());
@ -105,15 +126,34 @@ public class APIClient {
}
public String getRawValue(String string,
MultivaluedMap<String, String> queryParams) {
if (!string.equals("")) {
return get(string, queryParams).get(String.class);
MultivaluedMap<String, String> queryParams, long duration) {
if (string.equals("")) {
return "";
}
return "";
String key = getCacheKey(string, queryParams, duration);
String res = getFromCache(key, duration);
if (res != null) {
return res;
}
res = get(string, queryParams).get(String.class);
if (duration > 0) {
cache.put(key, new CacheEntry(res));
}
return res;
}
public String getRawValue(String string,
MultivaluedMap<String, String> queryParams) {
return getRawValue(string, queryParams, 0);
}
public String getRawValue(String string, long duration) {
return getRawValue(string, null, duration);
}
public String getRawValue(String string) {
return getRawValue(string, null);
return getRawValue(string, null, 0);
}
public String getStringValue(String string, MultivaluedMap<String, String> queryParams) {
@ -121,6 +161,11 @@ public class APIClient {
queryParams).replaceAll("^\"|\"$", "");
}
public String getStringValue(String string, MultivaluedMap<String, String> queryParams, long duration) {
return getRawValue(string,
queryParams, duration).replaceAll("^\"|\"$", "");
}
public String getStringValue(String string) {
return getStringValue(string, null);
}

View File

@ -0,0 +1,20 @@
/*
* Copyright 2015 Cloudius Systems
*/
package com.cloudius.urchin.api;
public class CacheEntry {
long time;
public String value;
CacheEntry(String value) {
time = System.currentTimeMillis();
this.value = value;
}
public boolean valid(long duration) {
return (System.currentTimeMillis() - time) < duration;
}
}

View File

@ -57,10 +57,11 @@ public class EndpointSnitchInfo implements EndpointSnitchInfoMBean {
/**
* Provides the Rack name depending on the respective snitch used, given the
* host name/ip
*
*
* @param host
* @throws UnknownHostException
*/
@Override
public String getRack(String host) throws UnknownHostException {
log("getRack(String host) throws UnknownHostException");
MultivaluedMap<String, String> queryParams = new MultivaluedMapImpl();
@ -68,16 +69,17 @@ public class EndpointSnitchInfo implements EndpointSnitchInfoMBean {
host = InetAddress.getLoopbackAddress().getHostAddress();
}
queryParams.add("host", host);
return c.getStringValue("/snitch/rack", queryParams);
return c.getStringValue("/snitch/rack", queryParams, 10000);
}
/**
* Provides the Datacenter name depending on the respective snitch used,
* given the hostname/ip
*
*
* @param host
* @throws UnknownHostException
*/
@Override
public String getDatacenter(String host) throws UnknownHostException {
log(" getDatacenter(String host) throws UnknownHostException");
MultivaluedMap<String, String> queryParams = new MultivaluedMapImpl();
@ -85,14 +87,15 @@ public class EndpointSnitchInfo implements EndpointSnitchInfoMBean {
host = InetAddress.getLoopbackAddress().getHostAddress();
}
queryParams.add("host", host);
return c.getStringValue("/snitch/datacenter", queryParams);
return c.getStringValue("/snitch/datacenter", queryParams, 10000);
}
/**
* Provides the snitch name of the cluster
*
*
* @return Snitch name
*/
@Override
public String getSnitchName() {
log(" getSnitchName()");
return c.getStringValue("/snitch/name");