DATAREDIS-1091 - Add configuration to disable storage of shadow copies for entities using TimeToLive.

Original pull request: #517.
This commit is contained in:
Christoph Strobl
2020-03-19 14:33:18 +01:00
committed by Mark Paluch
parent 2f0a5600dc
commit 546ebda2f2
5 changed files with 136 additions and 13 deletions

View File

@@ -117,6 +117,7 @@ public class RedisKeyValueAdapter extends AbstractKeyValueAdapter
private EnableKeyspaceEvents enableKeyspaceEvents = EnableKeyspaceEvents.OFF;
private @Nullable String keyspaceNotificationsConfigParameter = null;
private ShadowCopy shadowCopy = ShadowCopy.DEFAULT;
/**
* Creates new {@link RedisKeyValueAdapter} with default {@link RedisMappingContext} and default
@@ -238,11 +239,13 @@ public class RedisKeyValueAdapter extends AbstractKeyValueAdapter
connection.expire(objectKey, rdo.getTimeToLive());
// add phantom key so values can be restored
byte[] phantomKey = ByteUtils.concat(objectKey, BinaryKeyspaceIdentifier.PHANTOM_SUFFIX);
connection.del(phantomKey);
connection.hMSet(phantomKey, rdo.getBucket().rawMap());
connection.expire(phantomKey, rdo.getTimeToLive() + PHANTOM_KEY_TTL);
if (keepShadowCopy()) { // add phantom key so values can be restored
byte[] phantomKey = ByteUtils.concat(objectKey, BinaryKeyspaceIdentifier.PHANTOM_SUFFIX);
connection.del(phantomKey);
connection.hMSet(phantomKey, rdo.getBucket().rawMap());
connection.expire(phantomKey, rdo.getTimeToLive() + PHANTOM_KEY_TTL);
}
}
connection.sAdd(toBytes(rdo.getKeyspace()), key);
@@ -475,10 +478,12 @@ public class RedisKeyValueAdapter extends AbstractKeyValueAdapter
connection.expire(redisKey, rdo.getTimeToLive());
// add phantom key so values can be restored
byte[] phantomKey = ByteUtils.concat(redisKey, BinaryKeyspaceIdentifier.PHANTOM_SUFFIX);
connection.hMSet(phantomKey, rdo.getBucket().rawMap());
connection.expire(phantomKey, rdo.getTimeToLive() + PHANTOM_KEY_TTL);
if (keepShadowCopy()) { // add phantom key so values can be restored
byte[] phantomKey = ByteUtils.concat(redisKey, BinaryKeyspaceIdentifier.PHANTOM_SUFFIX);
connection.hMSet(phantomKey, rdo.getBucket().rawMap());
connection.expire(phantomKey, rdo.getTimeToLive() + PHANTOM_KEY_TTL);
}
} else {
@@ -661,6 +666,16 @@ public class RedisKeyValueAdapter extends AbstractKeyValueAdapter
this.keyspaceNotificationsConfigParameter = keyspaceNotificationsConfigParameter;
}
/**
* Configure storage of phantom keys (shadow copies) of expiring entities.
*
* @param shadowCopy must not be {@literal null}.
* @since 2.3
*/
public void setShadowCopy(ShadowCopy shadowCopy) {
this.shadowCopy = shadowCopy;
}
/**
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
* @since 1.8
@@ -773,7 +788,8 @@ public class RedisKeyValueAdapter extends AbstractKeyValueAdapter
byte[] key = message.getBody();
byte[] phantomKey = ByteUtils.concat(key, converter.getConversionService().convert(KeyspaceIdentifier.PHANTOM_SUFFIX, byte[].class));
byte[] phantomKey = ByteUtils.concat(key,
converter.getConversionService().convert(KeyspaceIdentifier.PHANTOM_SUFFIX, byte[].class));
Map<byte[], byte[]> hash = ops.execute((RedisCallback<Map<byte[], byte[]>>) connection -> {
@@ -789,7 +805,8 @@ public class RedisKeyValueAdapter extends AbstractKeyValueAdapter
Object value = converter.read(Object.class, new RedisData(hash));
String channel = !ObjectUtils.isEmpty(message.getChannel())
? converter.getConversionService().convert(message.getChannel(), String.class) : null;
? converter.getConversionService().convert(message.getChannel(), String.class)
: null;
RedisKeyExpiredEvent event = new RedisKeyExpiredEvent(channel, key, value);
@@ -813,6 +830,18 @@ public class RedisKeyValueAdapter extends AbstractKeyValueAdapter
}
}
private boolean keepShadowCopy() {
switch (shadowCopy) {
case OFF:
return false;
case ON:
return true;
default:
return this.expirationListener.get() != null;
}
}
/**
* @author Christoph Strobl
* @since 1.8
@@ -835,6 +864,31 @@ public class RedisKeyValueAdapter extends AbstractKeyValueAdapter
OFF
}
/**
* Configuration flag controlling storage of phantom keys (shadow copies) of expiring entities to read them later when
* publishing {@link RedisKeyspaceEvent}.
*
* @author Christoph Strobl
* @since 2.3
*/
public enum ShadowCopy {
/**
* Store shadow copies of expiring entities depending on the {@link EnableKeyspaceEvents}.
*/
DEFAULT,
/**
* Store shadow copies of expiring entities.
*/
ON,
/**
* Do not store shadow copies.
*/
OFF
}
/**
* Container holding update information like fields to remove from the Redis Hash.
*

View File

@@ -28,6 +28,7 @@ import org.springframework.context.annotation.Import;
import org.springframework.data.keyvalue.core.KeyValueOperations;
import org.springframework.data.keyvalue.repository.config.QueryCreatorType;
import org.springframework.data.redis.core.RedisKeyValueAdapter.EnableKeyspaceEvents;
import org.springframework.data.redis.core.RedisKeyValueAdapter.ShadowCopy;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.convert.KeyspaceConfiguration;
import org.springframework.data.redis.core.index.IndexConfiguration;
@@ -166,6 +167,15 @@ public @interface EnableRedisRepositories {
*/
EnableKeyspaceEvents enableKeyspaceEvents() default EnableKeyspaceEvents.OFF;
/**
* Configuration flag controlling storage of phantom keys (shadow copies) of expiring entities to read them later when
* publishing {@link org.springframework.data.redis.core.RedisKeyspaceEvent keyspace events}.
*
* @return
* @since 2.3
*/
ShadowCopy shadowCopy() default ShadowCopy.DEFAULT;
/**
* Configure the {@literal notify-keyspace-events} property if not already set. <br />
* Use an empty {@link String} to keep (<b>not</b> alter) existing server configuration.

View File

@@ -28,6 +28,7 @@ import org.springframework.data.keyvalue.repository.config.KeyValueRepositoryCon
import org.springframework.data.redis.core.RedisHash;
import org.springframework.data.redis.core.RedisKeyValueAdapter;
import org.springframework.data.redis.core.RedisKeyValueAdapter.EnableKeyspaceEvents;
import org.springframework.data.redis.core.RedisKeyValueAdapter.ShadowCopy;
import org.springframework.data.redis.core.RedisKeyValueTemplate;
import org.springframework.data.redis.core.convert.MappingConfiguration;
import org.springframework.data.redis.core.convert.MappingRedisConverter;
@@ -145,6 +146,8 @@ public class RedisRepositoryConfigurationExtension extends KeyValueRepositoryCon
configuration.getRequiredAttribute("enableKeyspaceEvents", EnableKeyspaceEvents.class)) //
.addPropertyValue("keyspaceNotificationsConfigParameter",
configuration.getAttribute("keyspaceNotificationsConfigParameter", String.class).orElse("")) //
.addPropertyValue("shadowCopy",
configuration.getRequiredAttribute("shadowCopy", ShadowCopy.class)) //
.getBeanDefinition();
}