DATAREDIS-661 - Refactor RedisServerCommands.getConfig(…) output to Properties.

Use Properties instead of List of Strings arranged as sequence of key-value pairs to improve value lookup. Properties allows direct value lookup whereas the List previously required List scanning for an index and another index access to retrieve the actual value.

Original Pull Request: #255
This commit is contained in:
Mark Paluch
2017-07-14 15:02:33 +02:00
committed by Christoph Strobl
parent 50551fd182
commit 8f88b78eeb
21 changed files with 165 additions and 200 deletions

View File

@@ -1,12 +1,12 @@
/*
* Copyright 2011-2016 the original author or authors.
*
* Copyright 2011-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -15,17 +15,8 @@
*/
package org.springframework.data.redis.connection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.apache.commons.logging.Log;
@@ -52,7 +43,7 @@ import org.springframework.util.Assert;
/**
* Default implementation of {@link StringRedisConnection}.
*
*
* @author Costin Leau
* @author Jennifer Hickey
* @author Christoph Strobl
@@ -122,7 +113,7 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco
/**
* Constructs a new <code>DefaultStringRedisConnection</code> instance. Uses {@link StringRedisSerializer} as
* underlying serializer.
*
*
* @param connection Redis connection
*/
public DefaultStringRedisConnection(RedisConnection connection) {
@@ -131,7 +122,7 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco
/**
* Constructs a new <code>DefaultStringRedisConnection</code> instance.
*
*
* @param connection Redis connection
* @param serializer String serializer
*/
@@ -308,8 +299,8 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco
return result;
}
public List<String> getConfig(String pattern) {
List<String> results = delegate.getConfig(pattern);
public Properties getConfig(String pattern) {
Properties results = delegate.getConfig(pattern);
if (isFutureConversion()) {
addResultConverter(identityConverter);
}
@@ -939,7 +930,7 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco
return result;
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisKeyCommands#ttl(byte[])
*/
@@ -953,7 +944,7 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco
return result;
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisKeyCommands#ttl(byte[], java.util.concurrent.TimeUnit)
*/
@@ -1351,7 +1342,7 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco
return result;
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisKeyCommands#pTtl(byte[])
*/
@@ -1366,7 +1357,7 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco
return result;
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisKeyCommands#pTtl(byte[], java.util.concurrent.TimeUnit)
*/
@@ -2103,7 +2094,7 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco
return result;
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.StringRedisConnection#ttl(java.lang.String)
*/
@@ -2112,7 +2103,7 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco
return ttl(serialize(key));
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.StringRedisConnection#ttl(java.lang.String, java.util.concurrent.TimeUnit)
*/
@@ -2743,7 +2734,7 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco
return pExpireAt(serialize(key), unixTimeInMillis);
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.StringRedisConnection#pTtl(java.lang.String)
*/
@@ -2752,7 +2743,7 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco
return pTtl(serialize(key));
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.StringRedisConnection#pTtl(java.lang.String, java.util.concurrent.TimeUnit)
*/
@@ -2835,7 +2826,7 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco
}
/*
*
*
*/
@Override
public Cursor<Tuple> zScan(byte[] key, ScanOptions options) {
@@ -2863,7 +2854,7 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco
/**
* Specifies if pipelined and tx results should be deserialized to Strings. If false, results of
* {@link #closePipeline()} and {@link #exec()} will be of the type returned by the underlying connection
*
*
* @param deserializePipelineAndTxResults Whether or not to deserialize pipeline and tx results
*/
public void setDeserializePipelineAndTxResults(boolean deserializePipelineAndTxResults) {

View File

@@ -100,7 +100,7 @@ public interface DefaultedRedisClusterConnection extends RedisClusterConnection,
/** @deprecated in favor of {@link RedisConnection#serverCommands()}. */
@Override
@Deprecated
default List<String> getConfig(RedisClusterNode node, String pattern) {
default Properties getConfig(RedisClusterNode node, String pattern) {
return serverCommands().getConfig(node, pattern);
}

View File

@@ -1107,7 +1107,7 @@ public interface DefaultedRedisConnection extends RedisConnection {
/** @deprecated in favor of {@link RedisConnection#serverCommands()}. */
@Override
@Deprecated
default List<String> getConfig(String pattern) {
default Properties getConfig(String pattern) {
return serverCommands().getConfig(pattern);
}

View File

@@ -97,7 +97,7 @@ public interface RedisClusterServerCommands extends RedisServerCommands {
* @return
* @see RedisServerCommands#getConfig(String)
*/
List<String> getConfig(RedisClusterNode node, String pattern);
Properties getConfig(RedisClusterNode node, String pattern);
/**
* @param node must not be {@literal null}.

View File

@@ -148,7 +148,7 @@ public interface RedisServerCommands {
* @return
* @see <a href="http://redis.io/commands/config-get">Redis Documentation: CONFIG GET</a>
*/
List<String> getConfig(String pattern);
Properties getConfig(String pattern);
/**
* Set server configuration for {@code param} to {@code value}.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2016 the original author or authors.
* Copyright 2013-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,16 +15,9 @@
*/
package org.springframework.data.redis.connection.convert;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import java.util.*;
import java.util.concurrent.TimeUnit;
import org.springframework.core.convert.converter.Converter;
@@ -50,8 +43,6 @@ import org.springframework.util.NumberUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import lombok.RequiredArgsConstructor;
/**
* Common type converters
*
@@ -70,6 +61,7 @@ abstract public class Converters {
private static final Converter<String, DataType> STRING_TO_DATA_TYPE = new StringToDataTypeConverter();
private static final Converter<Map<?, ?>, Properties> MAP_TO_PROPERTIES = MapToPropertiesConverter.INSTANCE;
private static final Converter<String, RedisClusterNode> STRING_TO_CLUSTER_NODE_CONVERTER;
private static final Converter<List<String>, Properties> STRING_LIST_TO_PROPERTIES_CONVERTER;
private static final Map<String, Flag> flagLookupMap;
static {
@@ -172,6 +164,21 @@ abstract public class Converters {
}
};
STRING_LIST_TO_PROPERTIES_CONVERTER = input -> {
Assert.notNull(input, "Input list must not be null!");
Assert.isTrue(input.size() % 2 == 0, "Input list must contain an even number of entries!");
Properties properties = new Properties();
for (int i = 0; i < input.size(); i += 2) {
properties.setProperty(input.get(i), input.get(i + 1));
}
return properties;
};
}
public static Boolean stringToBoolean(String s) {
@@ -224,7 +231,7 @@ abstract public class Converters {
/**
* Converts lines from the result of {@code CLUSTER NODES} into {@link RedisClusterNode}s.
*
* @param clusterNodes
* @param lines
* @return
* @since 1.7
*/
@@ -302,7 +309,7 @@ abstract public class Converters {
/**
* Creates a new {@link Converter} to convert from seconds to the given {@link TimeUnit}.
*
*
* @param timeUnit muist not be {@literal null}.
* @return
* @since 1.8
@@ -378,6 +385,29 @@ abstract public class Converters {
return DistanceConverterFactory.INSTANCE.forMetric(metric);
}
/**
* Converts array outputs with key-value sequences (such as produced by {@code CONFIG GET}) from a {@link List} to
* {@link Properties}.
*
* @param input must not be {@literal null}.
* @return the mapped result.
* @since 2.0
*/
public static Properties toProperties(List<String> input) {
return STRING_LIST_TO_PROPERTIES_CONVERTER.convert(input);
}
/**
* Returns a converter to convert array outputs with key-value sequences (such as produced by {@code CONFIG GET}) from
* a {@link List} to {@link Properties}.
*
* @return the converter.
* @since 2.0
*/
public static Converter<List<String>, Properties> listToPropertiesConverter() {
return STRING_LIST_TO_PROPERTIES_CONVERTER;
}
/**
* @author Christoph Strobl
* @since 1.8
@@ -436,5 +466,4 @@ abstract public class Converters {
return new GeoResults<GeoLocation<V>>(values, source.getAverageDistance().getMetric());
}
}
}

View File

@@ -300,7 +300,7 @@ class JedisClusterServerCommands implements RedisClusterServerCommands {
* @see org.springframework.data.redis.connection.RedisServerCommands#getConfig(java.lang.String)
*/
@Override
public List<String> getConfig(final String pattern) {
public Properties getConfig(final String pattern) {
List<NodeResult<List<String>>> mapResult = connection.getClusterCommandExecutor()
.executeCommandOnAllNodes((JedisClusterCommandCallback<List<String>>) client -> client.configGet(pattern))
@@ -316,7 +316,7 @@ class JedisClusterServerCommands implements RedisClusterServerCommands {
}
}
return result;
return Converters.toProperties(result);
}
/*
@@ -324,10 +324,11 @@ class JedisClusterServerCommands implements RedisClusterServerCommands {
* @see org.springframework.data.redis.connection.RedisClusterServerCommands#getConfig(org.springframework.data.redis.connection.RedisClusterNode, java.lang.String)
*/
@Override
public List<String> getConfig(RedisClusterNode node, final String pattern) {
public Properties getConfig(RedisClusterNode node, final String pattern) {
return connection.getClusterCommandExecutor().executeCommandOnSingleNode(
(JedisClusterCommandCallback<List<String>>) client -> client.configGet(pattern), node).getValue();
(JedisClusterCommandCallback<Properties>) client -> Converters.toProperties(client.configGet(pattern)), node)
.getValue();
}
/*

View File

@@ -21,6 +21,7 @@ import java.util.Properties;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.RedisServerCommands;
import org.springframework.data.redis.connection.ReturnType;
import org.springframework.data.redis.connection.convert.Converters;
import org.springframework.data.redis.connection.jedis.JedisConnection.JedisResult;
import org.springframework.data.redis.core.types.RedisClientInfo;
import org.springframework.util.Assert;
@@ -39,7 +40,7 @@ class JedisServerCommands implements RedisServerCommands {
this.connection = connection;
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisServerCommands#bgReWriteAof()
*/
@@ -60,7 +61,7 @@ class JedisServerCommands implements RedisServerCommands {
}
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisServerCommands#bgSave()
*/
@@ -81,7 +82,7 @@ class JedisServerCommands implements RedisServerCommands {
}
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisServerCommands#lastSave()
*/
@@ -102,7 +103,7 @@ class JedisServerCommands implements RedisServerCommands {
}
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisServerCommands#save()
*/
@@ -123,7 +124,7 @@ class JedisServerCommands implements RedisServerCommands {
}
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisServerCommands#dbSize()
*/
@@ -144,7 +145,7 @@ class JedisServerCommands implements RedisServerCommands {
}
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisServerCommands#flushDb()
*/
@@ -165,7 +166,7 @@ class JedisServerCommands implements RedisServerCommands {
}
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisServerCommands#flushAll()
*/
@@ -186,7 +187,7 @@ class JedisServerCommands implements RedisServerCommands {
}
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisServerCommands#info()
*/
@@ -207,7 +208,7 @@ class JedisServerCommands implements RedisServerCommands {
}
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisServerCommands#info(java.lang.String)
*/
@@ -226,7 +227,7 @@ class JedisServerCommands implements RedisServerCommands {
}
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisServerCommands#shutdown()
*/
@@ -247,7 +248,7 @@ class JedisServerCommands implements RedisServerCommands {
}
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisServerCommands#shutdown(org.springframework.data.redis.connection.RedisServerCommands.ShutdownOption)
*/
@@ -262,28 +263,30 @@ class JedisServerCommands implements RedisServerCommands {
connection.eval(String.format(SHUTDOWN_SCRIPT, option.name()).getBytes(), ReturnType.STATUS, 0);
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisServerCommands#getConfig(java.lang.String)
*/
@Override
public List<String> getConfig(String param) {
public Properties getConfig(String param) {
try {
if (isPipelined()) {
pipeline(connection.newJedisResult(connection.getPipeline().configGet(param)));
pipeline(connection.newJedisResult(connection.getPipeline().configGet(param),
Converters.listToPropertiesConverter()));
return null;
}
if (isQueueing()) {
transaction(connection.newJedisResult(connection.getTransaction().configGet(param)));
transaction(connection.newJedisResult(connection.getTransaction().configGet(param),
Converters.listToPropertiesConverter()));
return null;
}
return connection.getJedis().configGet(param);
return Converters.toProperties(connection.getJedis().configGet(param));
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisServerCommands#setConfig(java.lang.String, java.lang.String)
*/
@@ -304,7 +307,7 @@ class JedisServerCommands implements RedisServerCommands {
}
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisServerCommands#resetConfigStats()
*/
@@ -325,7 +328,7 @@ class JedisServerCommands implements RedisServerCommands {
}
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisServerCommands#time()
*/
@@ -349,7 +352,7 @@ class JedisServerCommands implements RedisServerCommands {
}
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisServerCommands#killClient(java.lang.String, int)
*/
@@ -369,7 +372,7 @@ class JedisServerCommands implements RedisServerCommands {
}
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisServerCommands#setClientName(byte[])
*/
@@ -383,7 +386,7 @@ class JedisServerCommands implements RedisServerCommands {
connection.getJedis().clientSetname(name);
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisServerCommands#getClientName()
*/
@@ -397,7 +400,7 @@ class JedisServerCommands implements RedisServerCommands {
return connection.getJedis().clientGetname();
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisServerCommands#getClientList()
*/
@@ -410,7 +413,7 @@ class JedisServerCommands implements RedisServerCommands {
return JedisConverters.toListOfRedisClientInformation(this.connection.getJedis().clientList());
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisServerCommands#slaveOf(java.lang.String, int)
*/
@@ -428,7 +431,7 @@ class JedisServerCommands implements RedisServerCommands {
}
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisServerCommands#slaveOfNoOne()
*/
@@ -445,7 +448,7 @@ class JedisServerCommands implements RedisServerCommands {
}
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisServerCommands#migrate(byte[], org.springframework.data.redis.connection.RedisNode, int, org.springframework.data.redis.connection.RedisServerCommands.MigrateOption)
*/
@@ -454,7 +457,7 @@ class JedisServerCommands implements RedisServerCommands {
migrate(key, target, dbIndex, option, Long.MAX_VALUE);
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisServerCommands#migrate(byte[], org.springframework.data.redis.connection.RedisNode, int, org.springframework.data.redis.connection.RedisServerCommands.MigrateOption, long)
*/

View File

@@ -226,7 +226,7 @@ class LettuceClusterServerCommands extends LettuceServerCommands implements Redi
* @see org.springframework.data.redis.connection.lettuce.LettuceServerCommands#getConfig(java.lang.String)
*/
@Override
public List<String> getConfig(final String pattern) {
public Properties getConfig(final String pattern) {
List<NodeResult<List<String>>> mapResult = executeCommandOnAllNodes(client -> client.configGet(pattern))
.getResults();
@@ -241,7 +241,7 @@ class LettuceClusterServerCommands extends LettuceServerCommands implements Redi
}
}
return result;
return Converters.toProperties(result);
}
/*
@@ -249,8 +249,8 @@ class LettuceClusterServerCommands extends LettuceServerCommands implements Redi
* @see org.springframework.data.redis.connection.RedisClusterServerCommands#getConfig(org.springframework.data.redis.connection.RedisClusterNode, java.lang.String)
*/
@Override
public List<String> getConfig(RedisClusterNode node, final String pattern) {
return executeCommandOnSingleNode(client -> client.configGet(pattern), node).getValue();
public Properties getConfig(RedisClusterNode node, final String pattern) {
return executeCommandOnSingleNode(client -> Converters.toProperties(client.configGet(pattern)), node).getValue();
}
/*

View File

@@ -811,27 +811,6 @@ abstract public class LettuceConverters extends Converters {
return geoArgs;
}
/**
* Convert {@code CONFIG GET} output from a {@link List} to {@link Properties}.
*
* @param input must not be {@literal null}.
* @return the mapped result.
*/
public static Properties toProperties(List<String> input) {
Assert.notNull(input, "Input list must not be null!");
Assert.isTrue(input.size() % 2 == 0, "Input list must contain an even number of entries!");
Properties properties = new Properties();
for (int i = 0; i < input.size(); i += 2) {
properties.setProperty(input.get(i), input.get(i + 1));
}
return properties;
}
/**
* Get {@link Converter} capable of {@link Set} of {@link Byte} into {@link GeoResults}.
*

View File

@@ -24,6 +24,7 @@ import java.util.Properties;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.RedisServerCommands;
import org.springframework.data.redis.connection.convert.Converters;
import org.springframework.data.redis.connection.lettuce.LettuceConnection.LettuceResult;
import org.springframework.data.redis.connection.lettuce.LettuceConnection.LettuceTxResult;
import org.springframework.data.redis.core.types.RedisClientInfo;
@@ -276,17 +277,19 @@ class LettuceServerCommands implements RedisServerCommands {
* @see org.springframework.data.redis.connection.RedisServerCommands#getConfig(java.lang.String)
*/
@Override
public List<String> getConfig(String param) {
public Properties getConfig(String param) {
try {
if (isPipelined()) {
pipeline(connection.newLettuceResult(getAsyncConnection().configGet(param)));
pipeline(
connection.newLettuceResult(getAsyncConnection().configGet(param), Converters.listToPropertiesConverter()));
return null;
}
if (isQueueing()) {
transaction(connection.newLettuceTxResult(getConnection().configGet(param)));
transaction(
connection.newLettuceTxResult(getConnection().configGet(param), Converters.listToPropertiesConverter()));
return null;
}
return getConnection().configGet(param);
return Converters.toProperties(getConnection().configGet(param));
} catch (Exception ex) {
throw convertLettuceAccessException(ex);
}

View File

@@ -15,7 +15,7 @@
*/
package org.springframework.data.redis.listener;
import java.util.List;
import java.util.Properties;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
@@ -27,8 +27,9 @@ import org.springframework.util.StringUtils;
/**
* Base {@link MessageListener} implementation for listening to Redis keyspace notifications.
*
*
* @author Christoph Strobl
* @author Mark Paluch
* @since 1.7
*/
public abstract class KeyspaceEventMessageListener implements MessageListener, InitializingBean, DisposableBean {
@@ -39,7 +40,7 @@ public abstract class KeyspaceEventMessageListener implements MessageListener, I
/**
* Creates new {@link KeyspaceEventMessageListener}.
*
*
* @param listenerContainer must not be {@literal null}.
*/
public KeyspaceEventMessageListener(RedisMessageListenerContainer listenerContainer) {
@@ -64,7 +65,7 @@ public abstract class KeyspaceEventMessageListener implements MessageListener, I
/**
* Handle the actual message
*
*
* @param message never {@literal null}.
*/
protected abstract void doHandleMessage(Message message);
@@ -81,9 +82,9 @@ public abstract class KeyspaceEventMessageListener implements MessageListener, I
try {
List<String> config = connection.getConfig("notify-keyspace-events");
Properties config = connection.getConfig("notify-keyspace-events");
if (config.size() == 2 && !StringUtils.hasText(config.get(1))) {
if (!StringUtils.hasText(config.getProperty("notify-keyspace-events"))) {
connection.setConfig("notify-keyspace-events", keyspaceNotificationsConfigParameter);
}
@@ -97,7 +98,7 @@ public abstract class KeyspaceEventMessageListener implements MessageListener, I
/**
* Register instance within the container.
*
*
* @param container never {@literal null}.
*/
protected void doRegister(RedisMessageListenerContainer container) {