in evcache-core/src/main/java/com/netflix/evcache/EVCacheImpl.java [1056:1134]
public <T> T get(String key, Transcoder<T> tc, Policy policy) throws EVCacheException {
if (null == key) throw new IllegalArgumentException();
final boolean throwExc = doThrowException();
final EVCacheClient[] clients = _pool.getEVCacheClientForWrite();
if (clients.length == 0) {
incrementFastFail(EVCacheMetricsFactory.NULL_CLIENT, Call.GET);
if (throwExc) throw new EVCacheException("Could not find a client to asynchronously get the data");
return null; // Fast failure
}
final int expectedSuccessCount = policyToCount(policy, clients.length);
if(expectedSuccessCount <= 1) return get(key, tc);
final long startTime = EVCacheMetricsFactory.getInstance().getRegistry().clock().wallTime();
String status = EVCacheMetricsFactory.SUCCESS;
String cacheOperation = EVCacheMetricsFactory.YES;
int tries = 1;
try {
final List<Future<T>> futureList = new ArrayList<Future<T>>(clients.length);
final long endTime = startTime + _pool.getReadTimeout().get().intValue();
for (EVCacheClient client : clients) {
final Future<T> future = getGetFuture(client, key, tc, throwExc);
futureList.add(future);
if (log.isDebugEnabled() && shouldLog()) log.debug("GET : CONSISTENT : APP " + _appName + ", Future " + future + " for key : " + key + " with policy : " + policy + " for client : " + client);
}
final Map<T, List<EVCacheClient>> evcacheClientMap = new HashMap<T, List<EVCacheClient>>();
//final Map<T, Integer> tMap = new HashMap<T,Integer>();
if (log.isDebugEnabled() && shouldLog()) log.debug("GET : CONSISTENT : Total Requests " + clients.length + "; Expected Success Count : " + expectedSuccessCount);
for(Future<T> future : futureList) {
try {
if(future instanceof EVCacheOperationFuture) {
EVCacheOperationFuture<T> evcacheOperationFuture = (EVCacheOperationFuture<T>)future;
long duration = endTime - System.currentTimeMillis();
if(duration < 20) duration = 20;
if (log.isDebugEnabled() && shouldLog()) log.debug("GET : CONSISTENT : block duration : " + duration);
final T t = evcacheOperationFuture.get(duration, TimeUnit.MILLISECONDS, throwExc, false);
if (log.isTraceEnabled() && shouldLog()) log.trace("GET : CONSISTENT : value : " + t);
if(t != null) {
final List<EVCacheClient> cList = evcacheClientMap.computeIfAbsent(t, k -> new ArrayList<EVCacheClient>(clients.length));
cList.add(evcacheOperationFuture.getEVCacheClient());
if (log.isDebugEnabled() && shouldLog()) log.debug("GET : CONSISTENT : Added Client to ArrayList " + cList);
}
}
} catch (Exception e) {
log.error("Exception",e);
}
}
T retVal = null;
/* TODO : use metaget to get TTL and set it. For now we will delete the inconsistent value */
for(Entry<T, List<EVCacheClient>> entry : evcacheClientMap.entrySet()) {
if (log.isDebugEnabled() && shouldLog()) log.debug("GET : CONSISTENT : Existing Count for Value : " + entry.getValue().size() + "; expectedSuccessCount : " + expectedSuccessCount);
if(entry.getValue().size() >= expectedSuccessCount) {
retVal = entry.getKey();
} else {
for(EVCacheClient client : entry.getValue()) {
if (log.isDebugEnabled() && shouldLog()) log.debug("GET : CONSISTENT : Delete in-consistent vale from : " + client);
client.delete(key);
}
}
}
if(retVal != null) {
if (log.isDebugEnabled() && shouldLog()) log.debug("GET : CONSISTENT : policy : " + policy + " was met. Will return the value. Total Duration : " + (System.currentTimeMillis() - startTime) + " milli Seconds.");
return retVal;
}
if (log.isDebugEnabled() && shouldLog()) log.debug("GET : CONSISTENT : policy : " + policy + " was NOT met. Will return NULL. Total Duration : " + (System.currentTimeMillis() - startTime) + " milli Seconds.");
return null;
} catch (Exception ex) {
status = EVCacheMetricsFactory.ERROR;
if (!throwExc) return null;
throw new EVCacheException("Exception getting data for APP " + _appName + ", key = " + key, ex);
} finally {
final long duration = EVCacheMetricsFactory.getInstance().getRegistry().clock().wallTime()- startTime;
getTimer(Call.GET_ALL.name(), EVCacheMetricsFactory.READ, cacheOperation, status, tries, maxReadDuration.get().intValue(), null).record(duration, TimeUnit.MILLISECONDS);
if (log.isDebugEnabled() && shouldLog()) log.debug("GET : CONSISTENT : APP " + _appName + ", Took " + duration + " milliSec.");
}
}