DATAREDIS-414 - Serialization now occurs after pooled connection was released.

Moved key serialization and value deserialization outside of callback so that pooled connections get released more quickly.

Original pull request: #153.
This commit is contained in:
Christoph Strobl
2015-07-23 11:08:08 +02:00
committed by Oliver Gierke
parent 7073502e42
commit a08e90a1f7

View File

@@ -101,18 +101,17 @@ public class RedisCache implements Cache {
public RedisCacheElement get(final RedisCacheKey cacheKey) {
notNull(cacheKey, "CacheKey must not be null!");
return (RedisCacheElement) redisOperations.execute(new AbstractRedisCacheCallback<RedisCacheElement>(
new RedisCacheElement(cacheKey, null), cacheMetadata) {
byte[] bytes = (byte[]) redisOperations.execute(new AbstractRedisCacheCallback<byte[]>(new BinaryRedisCacheElement(
new RedisCacheElement(cacheKey, null), cacheValueAccessor), cacheMetadata) {
@Override
public RedisCacheElement doInRedis(RedisCacheElement element, RedisConnection connection)
throws DataAccessException {
byte[] bs = connection.get(element.getKeyBytes());
Object value = redisOperations.getValueSerializer() != null ? redisOperations.getValueSerializer().deserialize(bs) : bs;
return (bs == null ? null : new RedisCacheElement(element.getKey(), value));
public byte[] doInRedis(BinaryRedisCacheElement element, RedisConnection connection) throws DataAccessException {
return connection.get(element.getKeyBytes());
}
});
return (bytes == null ? null : new RedisCacheElement(cacheKey, cacheValueAccessor.deserializeIfNecessary(bytes)));
}
/*
@@ -137,7 +136,9 @@ public class RedisCache implements Cache {
public void put(RedisCacheElement element) {
notNull(element, "Element must not be null!");
redisOperations.execute(new RedisCachePutCallback(element, cacheValueAccessor, cacheMetadata));
redisOperations.execute(new RedisCachePutCallback(new BinaryRedisCacheElement(element, cacheValueAccessor),
cacheMetadata));
}
/*
@@ -147,7 +148,8 @@ public class RedisCache implements Cache {
public ValueWrapper putIfAbsent(Object key, final Object value) {
return putIfAbsent(new RedisCacheElement(new RedisCacheKey(key).usePrefix(cacheMetadata.getKeyPrefix())
.withKeySerializer(redisOperations.getKeySerializer()), value).expireAfter(cacheMetadata.getDefaultExpiration()));
.withKeySerializer(redisOperations.getKeySerializer()), value)
.expireAfter(cacheMetadata.getDefaultExpiration()));
}
/**
@@ -161,7 +163,12 @@ public class RedisCache implements Cache {
public ValueWrapper putIfAbsent(RedisCacheElement element) {
notNull(element, "Element must not be null!");
return toWrapper(redisOperations.execute(new RedisCachePutIfAbsentCallback(element, cacheValueAccessor, cacheMetadata)));
new RedisCachePutIfAbsentCallback(new BinaryRedisCacheElement(element, cacheValueAccessor), cacheMetadata);
return toWrapper(cacheValueAccessor.deserializeIfNecessary((byte[]) redisOperations
.execute(new RedisCachePutIfAbsentCallback(new BinaryRedisCacheElement(element, cacheValueAccessor),
cacheMetadata))));
}
/*
@@ -180,7 +187,8 @@ public class RedisCache implements Cache {
public void evict(final RedisCacheElement element) {
notNull(element, "Element must not be null!");
redisOperations.execute(new RedisCacheEvictCallback(element, cacheMetadata));
redisOperations.execute(new RedisCacheEvictCallback(new BinaryRedisCacheElement(element, cacheValueAccessor),
cacheMetadata));
}
/*
@@ -323,6 +331,10 @@ public class RedisCache implements Cache {
byte[] convertToBytesIfNecessary(Object value) {
if (value == null) {
return new byte[0];
}
if (valueSerializer == null && value instanceof byte[]) {
return (byte[]) value;
}
@@ -340,6 +352,52 @@ public class RedisCache implements Cache {
}
}
/**
* @author Christoph Strobl
* @since 1.6
*/
static class BinaryRedisCacheElement extends RedisCacheElement {
private byte[] keyBytes;
private byte[] valueBytes;
private RedisCacheElement element;
public BinaryRedisCacheElement(RedisCacheElement element, CacheValueAccessor accessor) {
super(element.getKey(), element.get());
this.element = element;
this.keyBytes = element.getKeyBytes();
this.valueBytes = accessor.convertToBytesIfNecessary(element.get());
}
@Override
public byte[] getKeyBytes() {
return keyBytes;
}
public long getTimeToLive() {
return element.getTimeToLive();
}
public boolean hasKeyPrefix() {
return element.hasKeyPrefix();
}
public boolean isEternal() {
return element.isEternal();
}
public RedisCacheElement expireAfter(long seconds) {
return element.expireAfter(seconds);
}
@Override
public byte[] get() {
return valueBytes;
}
}
/**
* @author Christoph Strobl
* @since 1.5
@@ -348,10 +406,10 @@ public class RedisCache implements Cache {
static abstract class AbstractRedisCacheCallback<T> implements RedisCallback<T> {
private long WAIT_FOR_LOCK_TIMEOUT = 300;
private final RedisCacheElement element;
private final BinaryRedisCacheElement element;
private final RedisCacheMetadata cacheMetadata;
public AbstractRedisCacheCallback(RedisCacheElement element, RedisCacheMetadata metadata) {
public AbstractRedisCacheCallback(BinaryRedisCacheElement element, RedisCacheMetadata metadata) {
this.element = element;
this.cacheMetadata = metadata;
}
@@ -366,7 +424,7 @@ public class RedisCache implements Cache {
return doInRedis(element, connection);
}
public abstract T doInRedis(RedisCacheElement element, RedisConnection connection) throws DataAccessException;
public abstract T doInRedis(BinaryRedisCacheElement element, RedisConnection connection) throws DataAccessException;
protected void processKeyExpiration(RedisCacheElement element, RedisConnection connection) {
if (!element.isEternal()) {
@@ -526,7 +584,7 @@ public class RedisCache implements Cache {
*/
static class RedisCacheEvictCallback extends AbstractRedisCacheCallback<Void> {
public RedisCacheEvictCallback(RedisCacheElement element, RedisCacheMetadata metadata) {
public RedisCacheEvictCallback(BinaryRedisCacheElement element, RedisCacheMetadata metadata) {
super(element, metadata);
}
@@ -535,7 +593,7 @@ public class RedisCache implements Cache {
* @see org.springframework.data.redis.cache.RedisCache.AbstractRedisCacheCallback#doInRedis(org.springframework.data.redis.cache.RedisCacheElement, org.springframework.data.redis.connection.RedisConnection)
*/
@Override
public Void doInRedis(RedisCacheElement element, RedisConnection connection) throws DataAccessException {
public Void doInRedis(BinaryRedisCacheElement element, RedisConnection connection) throws DataAccessException {
connection.del(element.getKeyBytes());
cleanKnownKeys(element, connection);
@@ -549,13 +607,9 @@ public class RedisCache implements Cache {
*/
static class RedisCachePutCallback extends AbstractRedisCacheCallback<Void> {
private final CacheValueAccessor valueAccessor;
public RedisCachePutCallback(RedisCacheElement element, CacheValueAccessor valueAccessor,
RedisCacheMetadata metadata) {
public RedisCachePutCallback(BinaryRedisCacheElement element, RedisCacheMetadata metadata) {
super(element, metadata);
this.valueAccessor = valueAccessor;
}
/*
@@ -563,11 +617,11 @@ public class RedisCache implements Cache {
* @see org.springframework.data.redis.cache.RedisCache.AbstractRedisPutCallback#doInRedis(org.springframework.data.redis.cache.RedisCache.RedisCacheElement, org.springframework.data.redis.connection.RedisConnection)
*/
@Override
public Void doInRedis(RedisCacheElement element, RedisConnection connection) throws DataAccessException {
public Void doInRedis(BinaryRedisCacheElement element, RedisConnection connection) throws DataAccessException {
connection.multi();
connection.set(element.getKeyBytes(), valueAccessor.convertToBytesIfNecessary(element.get()));
connection.set(element.getKeyBytes(), element.get());
processKeyExpiration(element, connection);
maintainKnownKeys(element, connection);
@@ -581,15 +635,10 @@ public class RedisCache implements Cache {
* @author Christoph Strobl
* @since 1.5
*/
static class RedisCachePutIfAbsentCallback extends AbstractRedisCacheCallback<Object> {
private final CacheValueAccessor valueAccessor;
public RedisCachePutIfAbsentCallback(RedisCacheElement element, CacheValueAccessor valueAccessor,
RedisCacheMetadata metadata) {
static class RedisCachePutIfAbsentCallback extends AbstractRedisCacheCallback<byte[]> {
public RedisCachePutIfAbsentCallback(BinaryRedisCacheElement element, RedisCacheMetadata metadata) {
super(element, metadata);
this.valueAccessor = valueAccessor;
}
/*
@@ -597,10 +646,10 @@ public class RedisCache implements Cache {
* @see org.springframework.data.redis.cache.RedisCache.AbstractRedisPutCallback#doInRedis(org.springframework.data.redis.cache.RedisCache.RedisCacheElement, org.springframework.data.redis.connection.RedisConnection)
*/
@Override
public Object doInRedis(RedisCacheElement element, RedisConnection connection) throws DataAccessException {
public byte[] doInRedis(BinaryRedisCacheElement element, RedisConnection connection) throws DataAccessException {
waitForLock(connection);
Object resultValue = put(element, connection);
byte[] resultValue = put(element, connection);
if (nullSafeEquals(element.get(), resultValue)) {
processKeyExpiration(element, connection);
@@ -610,11 +659,10 @@ public class RedisCache implements Cache {
return resultValue;
}
private Object put(RedisCacheElement element, RedisConnection connection) {
private byte[] put(BinaryRedisCacheElement element, RedisConnection connection) {
boolean valueWasSet = connection.setNX(element.getKeyBytes(),
valueAccessor.convertToBytesIfNecessary(element.get()));
return valueWasSet ? null : valueAccessor.deserializeIfNecessary(connection.get(element.getKeyBytes()));
boolean valueWasSet = connection.setNX(element.getKeyBytes(), element.get());
return valueWasSet ? null : connection.get(element.getKeyBytes());
}
}