diff --git a/src/main/java/org/redisson/RedissonSetCache.java b/src/main/java/org/redisson/RedissonSetCache.java index 97f8526a7..34bc65af4 100644 --- a/src/main/java/org/redisson/RedissonSetCache.java +++ b/src/main/java/org/redisson/RedissonSetCache.java @@ -17,7 +17,6 @@ package org.redisson; import java.io.IOException; import java.net.InetSocketAddress; -import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -41,8 +40,6 @@ import org.redisson.core.RSetCache; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; -import io.netty.handler.codec.base64.Base64; -import io.netty.util.CharsetUtil; import io.netty.util.concurrent.Future; import net.openhft.hashing.LongHashFunction; @@ -320,13 +317,20 @@ public class RedissonSetCache extends RedissonExpirable implements RSetCache< long timeoutDate = System.currentTimeMillis() + unit.toMillis(ttl); return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_BOOLEAN, - "redis.call('zadd', KEYS[2], ARGV[1], ARGV[3]); " + - "if redis.call('hexists', KEYS[1], ARGV[3]) == 0 then " + - "redis.call('hset', KEYS[1], ARGV[3], ARGV[2]); " + - "return 1; " + - "end;" + - "return 0; ", - Arrays.asList(getName(), getTimeoutSetName()), timeoutDate, objectState, key); + "local value = redis.call('hexists', KEYS[1], ARGV[3]); " + + "if value == 1 then " + + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[3]); " + + "if expireDateScore ~= false and tonumber(expireDateScore) <= tonumber(ARGV[1]) then " + + "redis.call('zadd', KEYS[2], ARGV[2], ARGV[2]); " + + "return 1;" + + "else " + + "return 0;" + + "end; " + + "end;" + + "redis.call('zadd', KEYS[2], ARGV[2], ARGV[3]); " + + "redis.call('hset', KEYS[1], ARGV[3], ARGV[4]); " + + "return 1; ", + Arrays.asList(getName(), getTimeoutSetName()), System.currentTimeMillis(), timeoutDate, key, objectState); } catch (IOException e) { throw new RuntimeException(e); } @@ -342,12 +346,19 @@ public class RedissonSetCache extends RedissonExpirable implements RSetCache< byte[] objectState = encode(value); byte[] key = hash(objectState); return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_BOOLEAN, - "if redis.call('hexists', KEYS[1], ARGV[1]) == 0 then " + - "redis.call('hset', KEYS[1], ARGV[1], ARGV[2]); " + - "return 1; " + - "end; " + - "return 0; ", - Arrays.asList(getName()), key, objectState); + "local value = redis.call('hexists', KEYS[1], ARGV[2]); " + + "if value == 1 then " + + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]); " + + "if expireDateScore ~= false and tonumber(expireDateScore) <= tonumber(ARGV[1]) then " + + "redis.call('zrem', KEYS[2], ARGV[2]); " + + "return 1;" + + "else " + + "return 0;" + + "end; " + + "end;" + + "redis.call('hset', KEYS[1], ARGV[2], ARGV[3]); " + + "return 1; ", + Arrays.asList(getName(), getTimeoutSetName()), System.currentTimeMillis(), key, objectState); } catch (IOException e) { throw new RuntimeException(e); } diff --git a/src/test/java/org/redisson/RedissonSetCacheTest.java b/src/test/java/org/redisson/RedissonSetCacheTest.java index 9d7c71188..61e489e29 100644 --- a/src/test/java/org/redisson/RedissonSetCacheTest.java +++ b/src/test/java/org/redisson/RedissonSetCacheTest.java @@ -59,43 +59,64 @@ public class RedissonSetCacheTest extends BaseTest { @Test public void testAddExpire() throws InterruptedException, ExecutionException { RSetCache set = redisson.getSetCache("simple3"); - set.add("123", 1, TimeUnit.SECONDS); + assertThat(set.add("123", 500, TimeUnit.MILLISECONDS)).isTrue(); assertThat(set).contains("123"); - Thread.sleep(1000); - + Thread.sleep(500); + + assertThat(set.size()).isEqualTo(1); assertThat(set).doesNotContain("123"); + + assertThat(set.add("123", 1, TimeUnit.SECONDS)).isTrue(); + } @Test public void testAddExpireTwise() throws InterruptedException, ExecutionException { RSetCache set = redisson.getSetCache("simple31"); - set.add("123", 1, TimeUnit.SECONDS); + assertThat(set.add("123", 1, TimeUnit.SECONDS)).isTrue(); Thread.sleep(1000); Assert.assertFalse(set.contains("123")); - set.add("4341", 1, TimeUnit.SECONDS); + assertThat(set.add("4341", 1, TimeUnit.SECONDS)).isTrue(); Thread.sleep(1000); Assert.assertFalse(set.contains("4341")); } + + @Test + public void testAddExpireThenAdd() throws InterruptedException, ExecutionException { + RSetCache set = redisson.getSetCache("simple31"); + assertThat(set.add("123", 500, TimeUnit.MILLISECONDS)).isTrue(); + + Thread.sleep(500); + + assertThat(set.size()).isEqualTo(1); + assertThat(set.contains("123")).isFalse(); + + assertThat(set.add("123")).isTrue(); + Thread.sleep(1000); + + assertThat(set.contains("123")).isTrue(); + } + @Test public void testExpireOverwrite() throws InterruptedException, ExecutionException { RSetCache set = redisson.getSetCache("simple"); - set.add("123", 1, TimeUnit.SECONDS); + assertThat(set.add("123", 1, TimeUnit.SECONDS)).isTrue(); Thread.sleep(800); - set.add("123", 1, TimeUnit.SECONDS); + assertThat(set.add("123", 1, TimeUnit.SECONDS)).isFalse(); - Thread.sleep(800); - Assert.assertTrue(set.contains("123")); + Thread.sleep(100); + assertThat(set.contains("123")).isTrue(); - Thread.sleep(200); + Thread.sleep(100); - Assert.assertFalse(set.contains("123")); + assertThat(set.contains("123")).isFalse(); } @Test