Add support for microseconds using TIME.

Closes #526.
Original pull request: #526.
This commit is contained in:
Mark Paluch
2021-03-02 14:51:18 +01:00
parent 773acd09b2
commit 102ee017aa
17 changed files with 154 additions and 47 deletions

View File

@@ -3353,6 +3353,15 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco
return convertAndReturn(this.delegate.time(), Converters.identityConverter());
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisServerCommands#time(TimeUnit)
*/
@Override
public Long time(TimeUnit timeUnit) {
return convertAndReturn(this.delegate.time(timeUnit), Converters.identityConverter());
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.StringRedisConnection#getClientList()

View File

@@ -18,6 +18,7 @@ package org.springframework.data.redis.connection;
import java.util.Collection;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import org.springframework.data.redis.core.types.RedisClientInfo;
import org.springframework.lang.Nullable;
@@ -128,6 +129,13 @@ public interface DefaultedRedisClusterConnection extends RedisClusterConnection,
return serverCommands().time(node);
}
/** @deprecated in favor of {@link RedisConnection#serverCommands()}. */
@Override
@Deprecated
default Long time(RedisClusterNode node, TimeUnit timeUnit) {
return serverCommands().time(node, timeUnit);
}
/** @deprecated in favor of {@link RedisConnection#serverCommands()}. */
@Override
@Deprecated

View File

@@ -1437,6 +1437,13 @@ public interface DefaultedRedisConnection extends RedisConnection {
return serverCommands().time();
}
/** @deprecated in favor of {@link RedisConnection#serverCommands()}. */
@Override
@Deprecated
default Long time(TimeUnit timeUnit) {
return serverCommands().time(timeUnit);
}
/** @deprecated in favor of {@link RedisConnection#serverCommands()}. */
@Override
@Deprecated

View File

@@ -19,6 +19,7 @@ import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import org.springframework.data.redis.core.types.RedisClientInfo;
@@ -142,12 +143,24 @@ public interface ReactiveServerCommands {
Mono<String> resetConfigStats();
/**
* Request server timestamp using {@code TIME} command.
* Request server timestamp using {@code TIME} command in {@link TimeUnit#MILLISECONDS}.
*
* @return {@link Mono} wrapping current server time in milliseconds.
* @see <a href="https://redis.io/commands/time">Redis Documentation: TIME</a>
*/
Mono<Long> time();
default Mono<Long> time() {
return time(TimeUnit.MILLISECONDS);
}
/**
* Request server timestamp using {@code TIME} command.
*
* @param timeUnit target unit.
* @return {@link Mono} wrapping current server time in {@link TimeUnit}.
* @since 2.5
* @see <a href="https://redis.io/commands/time">Redis Documentation: TIME</a>
*/
Mono<Long> time(TimeUnit timeUnit);
/**
* Closes a given client connection identified by {@literal host:port}.

View File

@@ -17,6 +17,7 @@ package org.springframework.data.redis.connection;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import org.springframework.data.redis.core.types.RedisClientInfo;
@@ -118,7 +119,18 @@ public interface RedisClusterServerCommands extends RedisServerCommands {
* @return
* @see RedisServerCommands#time()
*/
Long time(RedisClusterNode node);
default Long time(RedisClusterNode node) {
return time(node, TimeUnit.MILLISECONDS);
}
/**
* @param node must not be {@literal null}.
* @param timeUnit must not be {@literal null}.
* @return
* @since 2.5
* @see RedisServerCommands#time(TimeUnit)
*/
Long time(RedisClusterNode node, TimeUnit timeUnit);
/**
* @param node must not be {@literal null}.

View File

@@ -17,6 +17,7 @@ package org.springframework.data.redis.connection;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import org.springframework.data.redis.core.types.RedisClientInfo;
import org.springframework.lang.Nullable;
@@ -174,14 +175,27 @@ public interface RedisServerCommands {
void resetConfigStats();
/**
* Request server timestamp using {@code TIME} command.
* Request server timestamp using {@code TIME} command in {@link TimeUnit#MILLISECONDS}.
*
* @return current server time in milliseconds or {@literal null} when used in pipeline / transaction.
* @since 1.1
* @see <a href="https://redis.io/commands/time">Redis Documentation: TIME</a>
*/
@Nullable
Long time();
default Long time() {
return time(TimeUnit.MILLISECONDS);
}
/**
* Request server timestamp using {@code TIME} command.
*
* @param timeUnit target unit.
* @return current server time in {@link TimeUnit} or {@literal null} when used in pipeline / transaction.
* @since 2.5
* @see <a href="https://redis.io/commands/time">Redis Documentation: TIME</a>
*/
@Nullable
Long time(TimeUnit timeUnit);
/**
* Closes a given client connection identified by {@literal host:port}.

View File

@@ -207,6 +207,23 @@ abstract public class Converters {
+ NumberUtils.parseNumber(microseconds, Long.class) / 1000L;
}
/**
* Returns the timestamp constructed from the given {@code seconds} and {@code microseconds}.
*
* @param seconds server time in seconds.
* @param microseconds elapsed microseconds in current second.
* @param unit target unit.
* @return
* @since 2.5
*/
public static Long toTimeMillis(String seconds, String microseconds, TimeUnit unit) {
long secondValue = TimeUnit.SECONDS.toMicros(NumberUtils.parseNumber(seconds, Long.class));
long microValue = NumberUtils.parseNumber(microseconds, Long.class);
return unit.convert(secondValue + microValue, TimeUnit.MICROSECONDS);
}
/**
* Converts {@code seconds} to the given {@link TimeUnit}.
*

View File

@@ -24,6 +24,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.redis.connection.ClusterCommandExecutor.MultiNodeResult;
@@ -391,24 +392,26 @@ class JedisClusterServerCommands implements RedisClusterServerCommands {
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisServerCommands#time()
* @see org.springframework.data.redis.connection.RedisServerCommands#time(TimeUnit)
*/
@Override
public Long time() {
public Long time(TimeUnit timeUnit) {
return convertListOfStringToTime(connection.getClusterCommandExecutor()
.executeCommandOnArbitraryNode((JedisClusterCommandCallback<List<String>>) BinaryJedis::time).getValue());
.executeCommandOnArbitraryNode((JedisClusterCommandCallback<List<String>>) BinaryJedis::time).getValue(),
timeUnit);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisClusterServerCommands#time(org.springframework.data.redis.connection.RedisClusterNode)
* @see org.springframework.data.redis.connection.RedisClusterServerCommands#time(org.springframework.data.redis.connection.RedisClusterNode, TimeUnit)
*/
@Override
public Long time(RedisClusterNode node) {
public Long time(RedisClusterNode node, TimeUnit timeUnit) {
return convertListOfStringToTime(connection.getClusterCommandExecutor()
.executeCommandOnSingleNode((JedisClusterCommandCallback<List<String>>) BinaryJedis::time, node).getValue());
.executeCommandOnSingleNode((JedisClusterCommandCallback<List<String>>) BinaryJedis::time, node).getValue(),
timeUnit);
}
/*
@@ -517,13 +520,13 @@ class JedisClusterServerCommands implements RedisClusterServerCommands {
node);
}
private Long convertListOfStringToTime(List<String> serverTimeInformation) {
private Long convertListOfStringToTime(List<String> serverTimeInformation, TimeUnit timeUnit) {
Assert.notEmpty(serverTimeInformation, "Received invalid result from server. Expected 2 items in collection.");
Assert.isTrue(serverTimeInformation.size() == 2,
"Received invalid number of arguments from redis server. Expected 2 received " + serverTimeInformation.size());
return Converters.toTimeMillis(serverTimeInformation.get(0), serverTimeInformation.get(1));
return Converters.toTimeMillis(serverTimeInformation.get(0), serverTimeInformation.get(1), timeUnit);
}
private <T> NodeResult<T> executeCommandOnSingleNode(JedisClusterCommandCallback<T> cmd, RedisClusterNode node) {

View File

@@ -547,13 +547,14 @@ public abstract class JedisConverters extends Converters {
return sp;
}
static Long toTime(List<String> source) {
static Long toTime(List<String> source, TimeUnit timeUnit) {
Assert.notEmpty(source, "Received invalid result from server. Expected 2 items in collection.");
Assert.isTrue(source.size() == 2,
"Received invalid nr of arguments from redis server. Expected 2 received " + source.size());
Assert.notNull(timeUnit, "TimeUnit must not be null.");
return toTimeMillis(source.get(0), source.get(1));
return toTimeMillis(source.get(0), source.get(1), timeUnit);
}
/**

View File

@@ -21,6 +21,7 @@ import redis.clients.jedis.MultiKeyPipelineBase;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.RedisServerCommands;
@@ -190,12 +191,15 @@ class JedisServerCommands implements RedisServerCommands {
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisServerCommands#time()
* @see org.springframework.data.redis.connection.RedisServerCommands#time(TimeUnit)
*/
@Override
public Long time() {
public Long time(TimeUnit timeUnit) {
Assert.notNull(timeUnit, "TimeUnit must not be null.");
return connection.invoke().from(BinaryJedis::time, MultiKeyPipelineBase::time)
.get(JedisConverters::toTime);
.get((List<String> source) -> JedisConverters.toTime(source, timeUnit));
}
/*

View File

@@ -23,6 +23,7 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.redis.connection.ClusterCommandExecutor.MultiNodeResult;
@@ -306,25 +307,13 @@ class LettuceClusterServerCommands extends LettuceServerCommands implements Redi
executeCommandOnSingleNode(RedisServerCommands::configResetstat, node);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.lettuce.LettuceServerCommands#time()
*/
@Override
public Long time() {
return convertListOfStringToTime(connection.getClusterCommandExecutor()
.executeCommandOnArbitraryNode((LettuceClusterCommandCallback<List<byte[]>>) RedisServerCommands::time)
.getValue());
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisClusterServerCommands#time(org.springframework.data.redis.connection.RedisClusterNode)
*/
@Override
public Long time(RedisClusterNode node) {
return convertListOfStringToTime(executeCommandOnSingleNode(RedisServerCommands::time, node).getValue());
public Long time(RedisClusterNode node, TimeUnit timeUnit) {
return convertListOfStringToTime(executeCommandOnSingleNode(RedisServerCommands::time, node).getValue(), timeUnit);
}
/*
@@ -383,13 +372,13 @@ class LettuceClusterServerCommands extends LettuceServerCommands implements Redi
return connection.getClusterCommandExecutor().executeCommandOnAllNodes(cmd);
}
private static Long convertListOfStringToTime(List<byte[]> serverTimeInformation) {
private static Long convertListOfStringToTime(List<byte[]> serverTimeInformation, TimeUnit timeUnit) {
Assert.notEmpty(serverTimeInformation, "Received invalid result from server. Expected 2 items in collection.");
Assert.isTrue(serverTimeInformation.size() == 2,
"Received invalid number of arguments from redis server. Expected 2 received " + serverTimeInformation.size());
return Converters.toTimeMillis(LettuceConverters.toString(serverTimeInformation.get(0)),
LettuceConverters.toString(serverTimeInformation.get(1)));
LettuceConverters.toString(serverTimeInformation.get(1)), timeUnit);
}
}

View File

@@ -725,7 +725,7 @@ public abstract class LettuceConverters extends Converters {
return args;
}
static Converter<List<byte[]>, Long> toTimeConverter() {
static Converter<List<byte[]>, Long> toTimeConverter(TimeUnit timeUnit) {
return source -> {
@@ -733,7 +733,7 @@ public abstract class LettuceConverters extends Converters {
Assert.isTrue(source.size() == 2,
"Received invalid nr of arguments from redis server. Expected 2 received " + source.size());
return toTimeMillis(toString(source.get(0)), toString(source.get(1)));
return toTimeMillis(toString(source.get(0)), toString(source.get(1)), timeUnit);
};
}

View File

@@ -30,6 +30,7 @@ import java.util.List;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
@@ -260,7 +261,7 @@ class LettuceReactiveClusterServerCommands extends LettuceReactiveServerCommands
return connection.execute(node, RedisServerReactiveCommands::time) //
.map(ByteUtils::getBytes) //
.collectList() //
.map(LettuceConverters.toTimeConverter()::convert);
.map(LettuceConverters.toTimeConverter(TimeUnit.MILLISECONDS)::convert);
}
/*

View File

@@ -22,6 +22,7 @@ import reactor.core.publisher.Mono;
import java.nio.ByteBuffer;
import java.util.Date;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import org.springframework.data.redis.connection.ReactiveServerCommands;
import org.springframework.data.redis.core.types.RedisClientInfo;
@@ -177,15 +178,15 @@ class LettuceReactiveServerCommands implements ReactiveServerCommands {
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.ReactiveServerCommands#time()
* @see org.springframework.data.redis.connection.ReactiveServerCommands#time(TimeUnit)
*/
@Override
public Mono<Long> time() {
public Mono<Long> time(TimeUnit timeUnit) {
return connection.execute(RedisServerReactiveCommands::time) //
.map(ByteUtils::getBytes) //
.collectList() //
.map(LettuceConverters.toTimeConverter()::convert);
.map(LettuceConverters.toTimeConverter(timeUnit)::convert);
}
/*

View File

@@ -201,11 +201,14 @@ class LettuceServerCommands implements RedisServerCommands {
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisServerCommands#time()
* @see org.springframework.data.redis.connection.RedisServerCommands#time(TimeUnit)
*/
@Override
public Long time() {
return connection.invoke().from(RedisServerAsyncCommands::time).get(LettuceConverters.toTimeConverter());
public Long time(TimeUnit timeUnit) {
Assert.notNull(timeUnit, "TimeUnit must not be null.");
return connection.invoke().from(RedisServerAsyncCommands::time).get(LettuceConverters.toTimeConverter(timeUnit));
}
/*