in evcache-core/src/main/java/com/netflix/evcache/EVCacheImpl.java [433:529]
<T> T doGet(EVCacheKey evcKey , Transcoder<T> tc) throws EVCacheException {
final boolean throwExc = doThrowException();
EVCacheClient client = _pool.getEVCacheClientForRead();
if (client == null) {
incrementFastFail(EVCacheMetricsFactory.NULL_CLIENT, Call.GET);
if (throwExc) throw new EVCacheException("Could not find a client to get the data APP " + _appName);
return null; // Fast failure
}
final EVCacheEvent event = createEVCacheEvent(Collections.singletonList(client), Call.GET);
if (event != null) {
event.setEVCacheKeys(Arrays.asList(evcKey));
try {
if (shouldThrottle(event)) {
incrementFastFail(EVCacheMetricsFactory.THROTTLED, Call.GET);
if (throwExc) throw new EVCacheException("Request Throttled for app " + _appName + " & key " + evcKey);
return null;
}
} catch(EVCacheException ex) {
if(throwExc) throw ex;
incrementFastFail(EVCacheMetricsFactory.THROTTLED, Call.GET);
return null;
}
startEvent(event);
}
final long start = EVCacheMetricsFactory.getInstance().getRegistry().clock().wallTime();
String status = EVCacheMetricsFactory.SUCCESS;
String cacheOperation = EVCacheMetricsFactory.YES;
int tries = 1;
try {
final boolean hasZF = hasZoneFallback();
boolean throwEx = hasZF ? false : throwExc;
T data = getData(client, evcKey, tc, throwEx, hasZF);
if (data == null && hasZF) {
final List<EVCacheClient> fbClients = _pool.getEVCacheClientsForReadExcluding(client.getServerGroup());
if (fbClients != null && !fbClients.isEmpty()) {
for (int i = 0; i < fbClients.size(); i++) {
final EVCacheClient fbClient = fbClients.get(i);
if(i >= fbClients.size() - 1) throwEx = throwExc;
if (event != null) {
try {
if (shouldThrottle(event)) {
status = EVCacheMetricsFactory.THROTTLED;
if (throwExc) throw new EVCacheException("Request Throttled for app " + _appName + " & key " + evcKey);
return null;
}
} catch(EVCacheException ex) {
if(throwExc) throw ex;
status = EVCacheMetricsFactory.THROTTLED;
return null;
}
}
tries++;
data = getData(fbClient, evcKey, tc, throwEx, (i < fbClients.size() - 1) ? true : false);
if (log.isDebugEnabled() && shouldLog()) log.debug("Retry for APP " + _appName + ", key [" + evcKey + (log.isTraceEnabled() ? "], Value [" + data : "") + "], ServerGroup : " + fbClient.getServerGroup());
if (data != null) {
client = fbClient;
break;
}
}
}
}
if (data != null) {
if (event != null) event.setAttribute("status", "GHIT");
} else {
cacheOperation = EVCacheMetricsFactory.NO;
if (event != null) event.setAttribute("status", "GMISS");
if (log.isInfoEnabled() && shouldLog()) log.info("GET : APP " + _appName + " ; cache miss for key : " + evcKey);
}
if (log.isDebugEnabled() && shouldLog()) log.debug("GET : APP " + _appName + ", key [" + evcKey + (log.isTraceEnabled() ? "], Value [" + data : "") + "], ServerGroup : " + client.getServerGroup());
if (event != null) endEvent(event);
return data;
} catch (net.spy.memcached.internal.CheckedOperationTimeoutException ex) {
status = EVCacheMetricsFactory.TIMEOUT;
if (event != null) {
event.setStatus(status);
eventError(event, ex);
}
if (!throwExc) return null;
throw new EVCacheException("CheckedOperationTimeoutException getting data for APP " + _appName + ", key = " + evcKey
+ ".\nYou can set the following property to increase the timeout " + _appName
+ ".EVCacheClientPool.readTimeout=<timeout in milli-seconds>", ex);
} catch (Exception ex) {
status = EVCacheMetricsFactory.ERROR;
if (event != null) {
event.setStatus(status);
eventError(event, ex);
}
if (!throwExc) return null;
throw new EVCacheException("Exception getting data for APP " + _appName + ", key = " + evcKey, ex);
} finally {
final long duration = EVCacheMetricsFactory.getInstance().getRegistry().clock().wallTime()- start;
getTimer(Call.GET.name(), EVCacheMetricsFactory.READ, cacheOperation, status, tries, maxReadDuration.get().intValue(), client.getServerGroup()).record(duration, TimeUnit.MILLISECONDS);
if (log.isDebugEnabled() && shouldLog()) log.debug("GET : APP " + _appName + ", Took " + duration + " milliSec.");
}
}