HTTPCLIENT-1395: added config parameter to skip an extra cache entry freshness check upon cache update in case of a cache miss
This commit is contained in:
parent
194e4f5289
commit
c78032d638
|
@ -486,72 +486,81 @@ public class AsyncCachingExec extends CachingExecBase implements AsyncExecChainH
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void completed() {
|
||||
void triggerNewCacheEntryResponse(final HttpResponse backendResponse, final Date responseDate, final ByteArrayBuffer buffer) {
|
||||
final ComplexFuture<?> future = scope.future;
|
||||
final CachingAsyncDataConsumer cachingDataConsumer = cachingConsumerRef.getAndSet(null);
|
||||
if (cachingDataConsumer != null && !cachingDataConsumer.writtenThrough.get()) {
|
||||
future.setDependency(responseCache.getCacheEntry(target, request, new FutureCallback<HttpCacheEntry>() {
|
||||
future.setDependency(responseCache.createCacheEntry(
|
||||
target,
|
||||
request,
|
||||
backendResponse,
|
||||
buffer,
|
||||
requestDate,
|
||||
responseDate,
|
||||
new FutureCallback<HttpCacheEntry>() {
|
||||
|
||||
@Override
|
||||
public void completed(final HttpCacheEntry existingEntry) {
|
||||
final HttpResponse backendResponse = cachingDataConsumer.backendResponse;
|
||||
if (DateUtils.isAfter(existingEntry, backendResponse, HttpHeaders.DATE)) {
|
||||
@Override
|
||||
public void completed(final HttpCacheEntry newEntry) {
|
||||
log.debug("Backend response successfully cached");
|
||||
try {
|
||||
final SimpleHttpResponse cacheResponse = responseGenerator.generateResponse(request, existingEntry);
|
||||
final SimpleHttpResponse cacheResponse = responseGenerator.generateResponse(request, newEntry);
|
||||
triggerResponse(cacheResponse, scope, asyncExecCallback);
|
||||
} catch (final ResourceIOException ex) {
|
||||
asyncExecCallback.failed(ex);
|
||||
}
|
||||
} else {
|
||||
final Date responseDate = cachingDataConsumer.responseDate;
|
||||
final ByteArrayBuffer buffer = cachingDataConsumer.bufferRef.getAndSet(null);
|
||||
future.setDependency(responseCache.createCacheEntry(
|
||||
target,
|
||||
request,
|
||||
backendResponse,
|
||||
buffer,
|
||||
requestDate,
|
||||
responseDate,
|
||||
new FutureCallback<HttpCacheEntry>() {
|
||||
|
||||
@Override
|
||||
public void completed(final HttpCacheEntry newEntry) {
|
||||
log.debug("Backend response successfully cached");
|
||||
try {
|
||||
final SimpleHttpResponse cacheResponse = responseGenerator.generateResponse(request, newEntry);
|
||||
triggerResponse(cacheResponse, scope, asyncExecCallback);
|
||||
} catch (final ResourceIOException ex) {
|
||||
asyncExecCallback.failed(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(final Exception ex) {
|
||||
asyncExecCallback.failed(ex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelled() {
|
||||
asyncExecCallback.failed(new InterruptedIOException());
|
||||
}
|
||||
|
||||
}));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(final Exception cause) {
|
||||
asyncExecCallback.failed(cause);
|
||||
}
|
||||
@Override
|
||||
public void failed(final Exception ex) {
|
||||
asyncExecCallback.failed(ex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelled() {
|
||||
asyncExecCallback.failed(new InterruptedIOException());
|
||||
}
|
||||
@Override
|
||||
public void cancelled() {
|
||||
asyncExecCallback.failed(new InterruptedIOException());
|
||||
}
|
||||
|
||||
}));
|
||||
}));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void completed() {
|
||||
final CachingAsyncDataConsumer cachingDataConsumer = cachingConsumerRef.getAndSet(null);
|
||||
if (cachingDataConsumer != null && !cachingDataConsumer.writtenThrough.get()) {
|
||||
final ByteArrayBuffer buffer = cachingDataConsumer.bufferRef.getAndSet(null);
|
||||
final HttpResponse backendResponse = cachingDataConsumer.backendResponse;
|
||||
if (cacheConfig.isFreshnessCheckEnabled()) {
|
||||
final ComplexFuture<?> future = scope.future;
|
||||
future.setDependency(responseCache.getCacheEntry(target, request, new FutureCallback<HttpCacheEntry>() {
|
||||
|
||||
@Override
|
||||
public void completed(final HttpCacheEntry existingEntry) {
|
||||
if (DateUtils.isAfter(existingEntry, backendResponse, HttpHeaders.DATE)) {
|
||||
log.debug("Backend already contains fresher cache entry");
|
||||
try {
|
||||
final SimpleHttpResponse cacheResponse = responseGenerator.generateResponse(request, existingEntry);
|
||||
triggerResponse(cacheResponse, scope, asyncExecCallback);
|
||||
} catch (final ResourceIOException ex) {
|
||||
asyncExecCallback.failed(ex);
|
||||
}
|
||||
} else {
|
||||
triggerNewCacheEntryResponse(backendResponse, responseDate, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(final Exception cause) {
|
||||
asyncExecCallback.failed(cause);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelled() {
|
||||
asyncExecCallback.failed(new InterruptedIOException());
|
||||
}
|
||||
|
||||
}));
|
||||
} else {
|
||||
triggerNewCacheEntryResponse(backendResponse, responseDate, buffer);
|
||||
}
|
||||
} else {
|
||||
asyncExecCallback.completed();
|
||||
}
|
||||
|
|
|
@ -168,7 +168,8 @@ public class CacheConfig implements Cloneable {
|
|||
private final boolean heuristicCachingEnabled;
|
||||
private final float heuristicCoefficient;
|
||||
private final long heuristicDefaultLifetime;
|
||||
private final boolean isSharedCache;
|
||||
private final boolean sharedCache;
|
||||
private final boolean freshnessCheckEnabled;
|
||||
private final int asynchronousWorkersMax;
|
||||
private final int asynchronousWorkersCore;
|
||||
private final int asynchronousWorkerIdleLifetimeSecs;
|
||||
|
@ -184,7 +185,8 @@ public class CacheConfig implements Cloneable {
|
|||
final boolean heuristicCachingEnabled,
|
||||
final float heuristicCoefficient,
|
||||
final long heuristicDefaultLifetime,
|
||||
final boolean isSharedCache,
|
||||
final boolean sharedCache,
|
||||
final boolean freshnessCheckEnabled,
|
||||
final int asynchronousWorkersMax,
|
||||
final int asynchronousWorkersCore,
|
||||
final int asynchronousWorkerIdleLifetimeSecs,
|
||||
|
@ -199,7 +201,8 @@ public class CacheConfig implements Cloneable {
|
|||
this.heuristicCachingEnabled = heuristicCachingEnabled;
|
||||
this.heuristicCoefficient = heuristicCoefficient;
|
||||
this.heuristicDefaultLifetime = heuristicDefaultLifetime;
|
||||
this.isSharedCache = isSharedCache;
|
||||
this.sharedCache = sharedCache;
|
||||
this.freshnessCheckEnabled = freshnessCheckEnabled;
|
||||
this.asynchronousWorkersMax = asynchronousWorkersMax;
|
||||
this.asynchronousWorkersCore = asynchronousWorkersCore;
|
||||
this.asynchronousWorkerIdleLifetimeSecs = asynchronousWorkerIdleLifetimeSecs;
|
||||
|
@ -285,7 +288,17 @@ public class CacheConfig implements Cloneable {
|
|||
* shared (private) cache
|
||||
*/
|
||||
public boolean isSharedCache() {
|
||||
return isSharedCache;
|
||||
return sharedCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the cache will perform an extra cache entry freshness check
|
||||
* upon cache update in case of a cache miss
|
||||
*
|
||||
* @since 5.0
|
||||
*/
|
||||
public boolean isFreshnessCheckEnabled() {
|
||||
return freshnessCheckEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -359,7 +372,8 @@ public class CacheConfig implements Cloneable {
|
|||
private boolean heuristicCachingEnabled;
|
||||
private float heuristicCoefficient;
|
||||
private long heuristicDefaultLifetime;
|
||||
private boolean isSharedCache;
|
||||
private boolean sharedCache;
|
||||
private boolean freshnessCheckEnabled;
|
||||
private int asynchronousWorkersMax;
|
||||
private int asynchronousWorkersCore;
|
||||
private int asynchronousWorkerIdleLifetimeSecs;
|
||||
|
@ -372,10 +386,11 @@ public class CacheConfig implements Cloneable {
|
|||
this.maxUpdateRetries = DEFAULT_MAX_UPDATE_RETRIES;
|
||||
this.allow303Caching = DEFAULT_303_CACHING_ENABLED;
|
||||
this.weakETagOnPutDeleteAllowed = DEFAULT_WEAK_ETAG_ON_PUTDELETE_ALLOWED;
|
||||
this.heuristicCachingEnabled = false;
|
||||
this.heuristicCachingEnabled = DEFAULT_HEURISTIC_CACHING_ENABLED;
|
||||
this.heuristicCoefficient = DEFAULT_HEURISTIC_COEFFICIENT;
|
||||
this.heuristicDefaultLifetime = DEFAULT_HEURISTIC_LIFETIME;
|
||||
this.isSharedCache = true;
|
||||
this.sharedCache = true;
|
||||
this.freshnessCheckEnabled = true;
|
||||
this.asynchronousWorkersMax = DEFAULT_ASYNCHRONOUS_WORKERS_MAX;
|
||||
this.asynchronousWorkersCore = DEFAULT_ASYNCHRONOUS_WORKERS_CORE;
|
||||
this.asynchronousWorkerIdleLifetimeSecs = DEFAULT_ASYNCHRONOUS_WORKER_IDLE_LIFETIME_SECS;
|
||||
|
@ -468,12 +483,12 @@ public class CacheConfig implements Cloneable {
|
|||
|
||||
/**
|
||||
* Sets whether the cache should behave as a shared cache or not.
|
||||
* @param isSharedCache true to behave as a shared cache, false to
|
||||
* @param sharedCache true to behave as a shared cache, false to
|
||||
* behave as a non-shared (private) cache. To have the cache
|
||||
* behave like a browser cache, you want to set this to {@code false}.
|
||||
*/
|
||||
public Builder setSharedCache(final boolean isSharedCache) {
|
||||
this.isSharedCache = isSharedCache;
|
||||
public Builder setSharedCache(final boolean sharedCache) {
|
||||
this.sharedCache = sharedCache;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -542,7 +557,8 @@ public class CacheConfig implements Cloneable {
|
|||
heuristicCachingEnabled,
|
||||
heuristicCoefficient,
|
||||
heuristicDefaultLifetime,
|
||||
isSharedCache,
|
||||
sharedCache,
|
||||
freshnessCheckEnabled,
|
||||
asynchronousWorkersMax,
|
||||
asynchronousWorkersCore,
|
||||
asynchronousWorkerIdleLifetimeSecs,
|
||||
|
@ -563,7 +579,8 @@ public class CacheConfig implements Cloneable {
|
|||
.append(", heuristicCachingEnabled=").append(this.heuristicCachingEnabled)
|
||||
.append(", heuristicCoefficient=").append(this.heuristicCoefficient)
|
||||
.append(", heuristicDefaultLifetime=").append(this.heuristicDefaultLifetime)
|
||||
.append(", isSharedCache=").append(this.isSharedCache)
|
||||
.append(", sharedCache=").append(this.sharedCache)
|
||||
.append(", freshnessCheckEnabled=").append(this.freshnessCheckEnabled)
|
||||
.append(", asynchronousWorkersMax=").append(this.asynchronousWorkersMax)
|
||||
.append(", asynchronousWorkersCore=").append(this.asynchronousWorkersCore)
|
||||
.append(", asynchronousWorkerIdleLifetimeSecs=").append(this.asynchronousWorkerIdleLifetimeSecs)
|
||||
|
|
|
@ -380,15 +380,22 @@ public class CachingExec extends CachingExecBase implements ExecChainHandler {
|
|||
buf = null;
|
||||
}
|
||||
backendResponse.close();
|
||||
final HttpCacheEntry existingEntry = responseCache.getCacheEntry(target, request);
|
||||
if (DateUtils.isAfter(existingEntry, backendResponse, HttpHeaders.DATE)) {
|
||||
return convert(responseGenerator.generateResponse(request, existingEntry));
|
||||
|
||||
final HttpCacheEntry cacheEntry;
|
||||
if (cacheConfig.isFreshnessCheckEnabled()) {
|
||||
final HttpCacheEntry existingEntry = responseCache.getCacheEntry(target, request);
|
||||
if (DateUtils.isAfter(existingEntry, backendResponse, HttpHeaders.DATE)) {
|
||||
log.debug("Backend already contains fresher cache entry");
|
||||
cacheEntry = existingEntry;
|
||||
} else {
|
||||
cacheEntry = responseCache.createCacheEntry(target, request, backendResponse, buf, requestSent, responseReceived);
|
||||
log.debug("Backend response successfully cached");
|
||||
}
|
||||
} else {
|
||||
final HttpCacheEntry newEntry = responseCache.createCacheEntry(
|
||||
target, request, backendResponse, buf, requestSent, responseReceived);
|
||||
log.debug("Backend response successfully cached");
|
||||
return convert(responseGenerator.generateResponse(request, newEntry));
|
||||
cacheEntry = responseCache.createCacheEntry(target, request, backendResponse, buf, requestSent, responseReceived);
|
||||
log.debug("Backend response successfully cached (freshness check skipped)");
|
||||
}
|
||||
return convert(responseGenerator.generateResponse(request, cacheEntry));
|
||||
}
|
||||
|
||||
private ClassicHttpResponse handleCacheMiss(
|
||||
|
|
Loading…
Reference in New Issue