Merge branch 'master' of github.com:redisson/redisson

pull/6442/head
mrniko 1 week ago
commit 042b660185

@ -218,7 +218,7 @@ public class RedissonFairLock extends RedissonLock implements RLock {
// threadWaitTime // threadWaitTime
"local lastThreadId = redis.call('lindex', KEYS[2], -1);" + "local lastThreadId = redis.call('lindex', KEYS[2], -1);" +
"local ttl;" + "local ttl;" +
"if lastThreadId ~= false and lastThreadId ~= ARGV[2] then " + "if lastThreadId ~= false and lastThreadId ~= ARGV[2] and redis.call('zscore', KEYS[3], lastThreadId) ~= false then " +
"ttl = tonumber(redis.call('zscore', KEYS[3], lastThreadId)) - tonumber(ARGV[4]);" + "ttl = tonumber(redis.call('zscore', KEYS[3], lastThreadId)) - tonumber(ARGV[4]);" +
"else " + "else " +
"ttl = redis.call('pttl', KEYS[1]);" + "ttl = redis.call('pttl', KEYS[1]);" +

@ -27,6 +27,7 @@ import org.redisson.client.protocol.RedisCommands;
import org.redisson.client.protocol.pubsub.PubSubType; import org.redisson.client.protocol.pubsub.PubSubType;
import org.redisson.command.BatchService; import org.redisson.command.BatchService;
import org.redisson.command.CommandAsyncExecutor; import org.redisson.command.CommandAsyncExecutor;
import org.redisson.api.ObjectEncoding;
import org.redisson.connection.ServiceManager; import org.redisson.connection.ServiceManager;
import org.redisson.misc.CompletableFutureWrapper; import org.redisson.misc.CompletableFutureWrapper;
import org.redisson.misc.Hash; import org.redisson.misc.Hash;
@ -606,11 +607,41 @@ public abstract class RedissonObject implements RObject {
return get(getIdleTimeAsync()); return get(getIdleTimeAsync());
} }
@Override
public int getReferenceCount() {
return get(getReferenceCountAsync());
}
@Override
public int getAccessFrequency() {
return get(getAccessFrequencyAsync());
}
@Override
public ObjectEncoding getInternalEncoding() {
return get(getInternalEncodingAsync());
}
@Override @Override
public RFuture<Long> getIdleTimeAsync() { public RFuture<Long> getIdleTimeAsync() {
return commandExecutor.writeAsync(getRawName(), StringCodec.INSTANCE, RedisCommands.OBJECT_IDLETIME, getRawName()); return commandExecutor.writeAsync(getRawName(), StringCodec.INSTANCE, RedisCommands.OBJECT_IDLETIME, getRawName());
} }
@Override
public RFuture<Integer> getReferenceCountAsync() {
return commandExecutor.readAsync(getRawName(), StringCodec.INSTANCE, RedisCommands.OBJECT_REFCOUNT, getRawName());
}
@Override
public RFuture<Integer> getAccessFrequencyAsync() {
return commandExecutor.readAsync(getRawName(), StringCodec.INSTANCE, RedisCommands.OBJECT_FREQ, getRawName());
}
@Override
public RFuture<ObjectEncoding> getInternalEncodingAsync() {
return commandExecutor.readAsync(getRawName(), StringCodec.INSTANCE, RedisCommands.OBJECT_ENCODING, getRawName());
}
protected final void removeListener(int listenerId, String... names) { protected final void removeListener(int listenerId, String... names) {
for (String name : names) { for (String name : names) {
RPatternTopic topic = new RedissonPatternTopic(StringCodec.INSTANCE, commandExecutor, name); RPatternTopic topic = new RedissonPatternTopic(StringCodec.INSTANCE, commandExecutor, name);

@ -495,6 +495,9 @@ public class RedissonSearch implements RSearch {
args.add(options.getCount()); args.add(options.getCount());
} }
if (!options.getParams().isEmpty()) { if (!options.getParams().isEmpty()) {
if (options.getDialect() == null || options.getDialect() < 2) {
throw new IllegalArgumentException("When use 'PARAMS', you should set DIALECT to 2 or greater than 2.");
}
args.add("PARAMS"); args.add("PARAMS");
args.add(options.getParams().size()*2); args.add(options.getParams().size()*2);
for (Map.Entry<String, Object> entry : options.getParams().entrySet()) { for (Map.Entry<String, Object> entry : options.getParams().entrySet()) {

@ -0,0 +1,119 @@
/**
* Copyright (c) 2013-2024 Nikita Koksharov
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.api;
/**
* enum type from https://redis.io/docs/latest/commands/object-encoding/
*
* @author seakider
*/
public enum ObjectEncoding {
/**
* Normal string encoding.
*/
RAW("raw"),
/**
* Strings representing integers in a 64-bit signed interval.
*/
INT("int"),
/**
* Strings with lengths up to the hardcoded limit of OBJ_ENCODING_EMBSTR_SIZE_LIMIT or 44 bytes.
*/
EMBSTR("embstr"),
/**
* An old list encoding.
* No longer used.
*/
LINKEDLIST("linkedlist"),
/**
* A space-efficient encoding used for small lists.
* Redis <= 6.2
*/
ZIPLIST("ziplist"),
/**
* A space-efficient encoding used for small lists.
* Redis >= 7.0
*/
LISTPACK("listpack"),
/**
* Encoded as linkedlist of ziplists or listpacks.
*/
QUICKLIST("quicklist"),
/**
* Normal set encoding.
*/
HASHTABLE("hashtable"),
/**
* Small sets composed solely of integers encoding.
*/
INTSET("intset"),
/**
* An old hash encoding.
* No longer used
*/
ZIPMAP("zipmap"),
/**
* Normal sorted set encoding
*/
SKIPLIST("skiplist"),
/**
* Encoded as a radix tree of listpacks
*/
STREAM("stream"),
/**
* Key is not exist.
*/
NULL("nonexistence"),
/**
* This means redis support new type and this Enum not defined.
*/
UNKNOWN("unknown");
private final String type;
ObjectEncoding(String type) {
this.type = type;
}
public String getType() {
return type;
}
public static ObjectEncoding valueOfEncoding(Object object) {
if (object == null) {
return NULL;
}
String value = (String) object;
for (ObjectEncoding encoding : ObjectEncoding.values()) {
if (value.equals(encoding.getType()))
return encoding;
}
return UNKNOWN;
}
}

@ -34,6 +34,26 @@ public interface RObject extends RObjectAsync {
*/ */
Long getIdleTime(); Long getIdleTime();
/**
* Returns count of references over this object.
*
* @return count of reference
*/
int getReferenceCount();
/**
* Returns the logarithmic access frequency counter over this object.
*
* @return frequency counter
*/
int getAccessFrequency();
/**
* Returns the internal encoding for the Redis object
*
* @return internal encoding
*/
ObjectEncoding getInternalEncoding();
/** /**
* Returns bytes amount used by object in Redis memory. * Returns bytes amount used by object in Redis memory.
* *

@ -32,6 +32,27 @@ public interface RObjectAsync {
*/ */
RFuture<Long> getIdleTimeAsync(); RFuture<Long> getIdleTimeAsync();
/**
* Returns count of references over this object.
*
* @return count of reference
*/
RFuture<Integer> getReferenceCountAsync();
/**
* Returns the logarithmic access frequency counter over this object.
*
* @return frequency counter
*/
RFuture<Integer> getAccessFrequencyAsync();
/**
* Returns the internal encoding for the Redis object
*
* @return internal encoding
*/
RFuture<ObjectEncoding> getInternalEncodingAsync();
/** /**
* Returns bytes amount used by object in Redis memory. * Returns bytes amount used by object in Redis memory.
* *

@ -36,6 +36,27 @@ public interface RObjectReactive {
*/ */
Mono<Long> getIdleTime(); Mono<Long> getIdleTime();
/**
* Returns count of references over this object.
*
* @return count of reference
*/
Mono<Integer> getReferenceCount();
/**
* Returns the logarithmic access frequency counter over this object.
*
* @return frequency counter
*/
Mono<Integer> getAccessFrequency();
/**
* Returns the internal encoding for the Redis object
*
* @return internal encoding
*/
Mono<ObjectEncoding> getInternalEncoding();
String getName(); String getName();
Codec getCodec(); Codec getCodec();

@ -37,6 +37,27 @@ public interface RObjectRx {
*/ */
Single<Long> getIdleTime(); Single<Long> getIdleTime();
/**
* Returns count of references over this object.
*
* @return count of reference
*/
Single<Integer> getReferenceCount();
/**
* Returns the logarithmic access frequency counter over this object.
*
* @return frequency counter
*/
Single<Integer> getAccessFrequency();
/**
* Returns the internal encoding for the Redis object
*
* @return internal encoding
*/
Single<ObjectEncoding> getInternalEncoding();
String getName(); String getName();
Codec getCodec(); Codec getCodec();

@ -26,6 +26,7 @@ import org.redisson.client.protocol.decoder.*;
import org.redisson.client.protocol.pubsub.PubSubStatusDecoder; import org.redisson.client.protocol.pubsub.PubSubStatusDecoder;
import org.redisson.cluster.ClusterNodeInfo; import org.redisson.cluster.ClusterNodeInfo;
import org.redisson.codec.CompositeCodec; import org.redisson.codec.CompositeCodec;
import org.redisson.api.ObjectEncoding;
import java.time.Duration; import java.time.Duration;
import java.time.Instant; import java.time.Instant;
@ -733,6 +734,15 @@ public interface RedisCommands {
RedisStrictCommand<Boolean> NOT_EXISTS = new RedisStrictCommand<Boolean>("EXISTS", new BooleanNumberReplayConvertor(1L)); RedisStrictCommand<Boolean> NOT_EXISTS = new RedisStrictCommand<Boolean>("EXISTS", new BooleanNumberReplayConvertor(1L));
RedisStrictCommand<Long> OBJECT_IDLETIME = new RedisStrictCommand<Long>("OBJECT", "IDLETIME", new LongReplayConvertor()); RedisStrictCommand<Long> OBJECT_IDLETIME = new RedisStrictCommand<Long>("OBJECT", "IDLETIME", new LongReplayConvertor());
RedisStrictCommand<Integer> OBJECT_REFCOUNT = new RedisStrictCommand<Integer>("OBJECT", "REFCOUNT", new IntegerReplayConvertor(0));
RedisStrictCommand<Integer> OBJECT_FREQ = new RedisStrictCommand<Integer>("OBJECT", "FREQ", new IntegerReplayConvertor(0));
RedisStrictCommand<ObjectEncoding> OBJECT_ENCODING = new RedisStrictCommand<>("OBJECT", "ENCODING", new Convertor<ObjectEncoding>() {
@Override
public ObjectEncoding convert(Object obj) {
return ObjectEncoding.valueOfEncoding(obj);
}
});
RedisStrictCommand<Long> MEMORY_USAGE = new RedisStrictCommand<Long>("MEMORY", "USAGE", new LongReplayConvertor()); RedisStrictCommand<Long> MEMORY_USAGE = new RedisStrictCommand<Long>("MEMORY", "USAGE", new LongReplayConvertor());
RedisStrictCommand<Map<String, String>> MEMORY_STATS = new RedisStrictCommand<>("MEMORY", "STATS", new StringMapReplayDecoder()); RedisStrictCommand<Map<String, String>> MEMORY_STATS = new RedisStrictCommand<>("MEMORY", "STATS", new StringMapReplayDecoder());
RedisStrictCommand<Boolean> RENAMENX = new RedisStrictCommand<Boolean>("RENAMENX", new BooleanReplayConvertor()); RedisStrictCommand<Boolean> RENAMENX = new RedisStrictCommand<Boolean>("RENAMENX", new BooleanReplayConvertor());

@ -36,6 +36,8 @@ public class RedisDockerTest {
protected static final String NOTIFY_KEYSPACE_EVENTS = "--notify-keyspace-events"; protected static final String NOTIFY_KEYSPACE_EVENTS = "--notify-keyspace-events";
protected static final String MAXMEMORY_POLICY = "--maxmemory-policy";
protected static final GenericContainer<?> REDIS = createRedis(); protected static final GenericContainer<?> REDIS = createRedis();
protected static final Protocol protocol = Protocol.RESP2; protected static final Protocol protocol = Protocol.RESP2;

@ -6,14 +6,13 @@ import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.MethodSource;
import org.redisson.api.DeletedObjectListener; import org.redisson.api.*;
import org.redisson.api.ExpiredObjectListener;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.redisson.api.listener.SetObjectListener; import org.redisson.api.listener.SetObjectListener;
import org.redisson.api.listener.TrackingListener; import org.redisson.api.listener.TrackingListener;
import org.redisson.api.options.PlainOptions; import org.redisson.api.options.PlainOptions;
import org.redisson.client.RedisResponseTimeoutException; import org.redisson.client.RedisResponseTimeoutException;
import org.redisson.client.codec.IntegerCodec;
import org.redisson.client.codec.LongCodec;
import org.redisson.client.codec.StringCodec; import org.redisson.client.codec.StringCodec;
import org.redisson.config.Config; import org.redisson.config.Config;
import org.redisson.config.Protocol; import org.redisson.config.Protocol;
@ -298,6 +297,58 @@ public class RedissonBucketTest extends RedisDockerTest {
assertThat(al.getIdleTime()).isBetween(4L, 6L); assertThat(al.getIdleTime()).isBetween(4L, 6L);
} }
@Test
public void testReferenceCount() {
RBucket<Integer> al = redisson.getBucket("test");
assertThat(al.getReferenceCount()).isEqualTo(0);
al.set(10000);
assertThat(al.getReferenceCount()).isEqualTo(1);
}
@Test
public void testAccessFrequency() {
testWithParams(redisson -> {
RBucket<Integer> al = redisson.getBucket("test");
assertThat(al.getAccessFrequency()).isEqualTo(0);
al.set(10000);
al.get();
assertThat(al.getAccessFrequency()).isGreaterThan(1);
}, MAXMEMORY_POLICY, "allkeys-lfu");
}
@Test
public void testInternalEncoding() {
RBucket<Integer> al = redisson.getBucket("test");
assertThat(al.getInternalEncoding()).isEqualTo(ObjectEncoding.NULL);
al.set(123);
assertThat(al.getInternalEncoding()).isEqualTo(ObjectEncoding.EMBSTR);
RList<String> list=redisson.getList("list");
list.addAll(Arrays.asList("a","b","c"));
assertThat(list.getInternalEncoding()).isEqualTo(ObjectEncoding.LISTPACK);
RMap<Integer, String> map = redisson.getMap("map");
map.put(1, "12");
map.put(2, "33");
map.put(3, "43");
assertThat(map.getInternalEncoding()).isEqualTo(ObjectEncoding.LISTPACK);
RSet<Integer> set = redisson.getSet("set", IntegerCodec.INSTANCE);
set.add(1);
set.add(2);
set.add(3);
assertThat(set.getInternalEncoding()).isEqualTo(ObjectEncoding.INTSET);
RSortedSet<Long> sortedSet = redisson.getSortedSet("sortedSet", LongCodec.INSTANCE);
sortedSet.add(2L);
sortedSet.add(0L);
sortedSet.add(1L);
sortedSet.add(5L);
assertThat(sortedSet.getInternalEncoding()).isEqualTo(ObjectEncoding.LISTPACK);
}
@Test @Test
public void testDeletedListener() { public void testDeletedListener() {
testWithParams(redisson -> { testWithParams(redisson -> {

@ -1,6 +1,7 @@
package org.redisson; package org.redisson;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.redisson.api.RJsonBucket; import org.redisson.api.RJsonBucket;
import org.redisson.api.RMap; import org.redisson.api.RMap;
@ -49,6 +50,19 @@ public class RedissonSearchTest extends DockerRedisStackTest {
} }
} }
@Test
public void testSearchWithParam() {
RJsonBucket<String> b = redisson.getJsonBucket("doc:1", StringCodec.INSTANCE);
b.set("[{\"arr\": [1, 2, 3]}, {\"val\": \"hello\"}, {\"val\": \"world\"}]");
RSearch s = redisson.getSearch(StringCodec.INSTANCE);
Assertions.assertThrows(IllegalArgumentException.class, () ->
s.search("idx", "*", QueryOptions.defaults()
.returnAttributes(new ReturnAttribute("arr"),
new ReturnAttribute("val"))
.params(Collections.singletonMap("12", "323"))));
}
@Test @Test
public void testSearchNoContent() { public void testSearchNoContent() {
RMap<String, SimpleObject> m = redisson.getMap("doc:1", new CompositeCodec(StringCodec.INSTANCE, redisson.getConfig().getCodec())); RMap<String, SimpleObject> m = redisson.getMap("doc:1", new CompositeCodec(StringCodec.INSTANCE, redisson.getConfig().getCodec()));

Loading…
Cancel
Save