DATAREDIS-523 - Read back TTL into property.

We now read back TTL value from Redis for explicitly @TimeToLive annotated properties.

Original pull request: #208.
This commit is contained in:
Christoph Strobl
2016-07-08 14:03:22 +02:00
committed by Mark Paluch
parent e8a30a79a0
commit c4ddc9e125
5 changed files with 164 additions and 18 deletions

View File

@@ -23,6 +23,7 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import org.slf4j.Logger;
@@ -39,6 +40,7 @@ import org.springframework.dao.DataAccessException;
import org.springframework.data.keyvalue.core.AbstractKeyValueAdapter;
import org.springframework.data.keyvalue.core.KeyValueAdapter;
import org.springframework.data.keyvalue.core.mapping.KeyValuePersistentProperty;
import org.springframework.data.mapping.PersistentProperty;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.data.redis.connection.RedisConnection;
@@ -58,6 +60,7 @@ import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.util.ByteUtils;
import org.springframework.data.util.CloseableIterator;
import org.springframework.util.Assert;
import org.springframework.util.NumberUtils;
import org.springframework.util.ObjectUtils;
/**
@@ -295,7 +298,7 @@ public class RedisKeyValueAdapter extends AbstractKeyValueAdapter
data.setId(stringId);
data.setKeyspace(stringKeyspace);
return converter.read(type, data);
return readBackTimeToLiveIfSet(binId, converter.read(type, data));
}
/*
@@ -346,29 +349,18 @@ public class RedisKeyValueAdapter extends AbstractKeyValueAdapter
final byte[] binKeyspace = toBytes(keyspace);
List<Map<byte[], byte[]>> raw = redisOps.execute(new RedisCallback<List<Map<byte[], byte[]>>>() {
Set<byte[]> ids = redisOps.execute(new RedisCallback<Set<byte[]>>() {
@Override
public List<Map<byte[], byte[]>> doInRedis(RedisConnection connection) throws DataAccessException {
final List<Map<byte[], byte[]>> rawData = new ArrayList<Map<byte[], byte[]>>();
Set<byte[]> members = connection.sMembers(binKeyspace);
for (byte[] id : members) {
rawData.add(connection
.hGetAll(createKey(asString(keyspace), getConverter().getConversionService().convert(id, String.class))));
}
return rawData;
public Set<byte[]> doInRedis(RedisConnection connection) throws DataAccessException {
return connection.sMembers(binKeyspace);
}
});
List<Object> result = new ArrayList<Object>(raw.size());
for (Map<byte[], byte[]> rawData : raw) {
result.add(converter.read(Object.class, new RedisData(rawData)));
List<Object> result = new ArrayList<Object>();
for (byte[] key : ids) {
result.add(get(key, keyspace));
}
return result;
}
@@ -579,6 +571,49 @@ public class RedisKeyValueAdapter extends AbstractKeyValueAdapter
return converter.getConversionService().convert(source, byte[].class);
}
/**
* Read back and set {@link TimeToLive} for the property.
*
* @param key
* @param target
* @return
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
private <T> T readBackTimeToLiveIfSet(final byte[] key, T target) {
if (target == null || key == null) {
return target;
}
RedisPersistentEntity<?> entity = this.converter.getMappingContext().getPersistentEntity(target.getClass());
if (entity.hasExplictTimeToLiveProperty()) {
PersistentProperty<?> ttlProperty = entity.getExplicitTimeToLiveProperty();
final TimeToLive ttl = ttlProperty.findAnnotation(TimeToLive.class);
Long timeout = redisOps.execute(new RedisCallback<Long>() {
@Override
public Long doInRedis(RedisConnection connection) throws DataAccessException {
if (ObjectUtils.nullSafeEquals(TimeUnit.SECONDS, ttl.unit())) {
return connection.ttl(key);
}
return connection.pTtl(key, ttl.unit());
}
});
if (timeout != null || (timeout == null && !ttlProperty.getType().isPrimitive())) {
entity.getPropertyAccessor(target).setProperty(ttlProperty,
NumberUtils.convertNumberToTargetClass(timeout, (Class) ttlProperty.getType()));
}
}
return target;
}
/**
* Configure usage of {@link KeyExpirationEventMessageListener}.
*

View File

@@ -20,6 +20,7 @@ import org.springframework.data.keyvalue.core.mapping.BasicKeyValuePersistentEnt
import org.springframework.data.keyvalue.core.mapping.KeySpaceResolver;
import org.springframework.data.keyvalue.core.mapping.KeyValuePersistentProperty;
import org.springframework.data.mapping.model.MappingException;
import org.springframework.data.redis.core.TimeToLive;
import org.springframework.data.redis.core.TimeToLiveAccessor;
import org.springframework.data.util.TypeInformation;
import org.springframework.util.Assert;
@@ -59,6 +60,24 @@ public class BasicRedisPersistentEntity<T> extends BasicKeyValuePersistentEntity
return this.timeToLiveAccessor;
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.mapping.RedisPersistentEntity#hasExplictTimeToLiveProperty()
*/
@Override
public boolean hasExplictTimeToLiveProperty() {
return getExplicitTimeToLiveProperty() != null;
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.mapping.RedisPersistentEntity#getExplicitTimeToLiveProperty()
*/
@Override
public RedisPersistentProperty getExplicitTimeToLiveProperty() {
return (RedisPersistentProperty) this.getPersistentProperty(TimeToLive.class);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.model.BasicPersistentEntity#returnPropertyIfBetterIdPropertyCandidateOrNull(org.springframework.data.mapping.PersistentProperty)

View File

@@ -17,6 +17,7 @@ package org.springframework.data.redis.core.mapping;
import org.springframework.data.keyvalue.core.mapping.KeyValuePersistentEntity;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.PersistentProperty;
import org.springframework.data.redis.core.TimeToLiveAccessor;
/**
@@ -35,4 +36,18 @@ public interface RedisPersistentEntity<T> extends KeyValuePersistentEntity<T> {
*/
TimeToLiveAccessor getTimeToLiveAccessor();
/**
* @return {@literal true} when a property is annotated with {@link org.springframework.data.redis.core.TimeToLive}.
* @since 1.8
*/
boolean hasExplictTimeToLiveProperty();
/**
* Get the {@link PersistentProperty}
*
* @return can be {@null}.
* @since 1.8
*/
PersistentProperty<? extends PersistentProperty<?>> getExplicitTimeToLiveProperty();
}