diff --git a/redisson/src/main/java/org/redisson/RedissonMapCache.java b/redisson/src/main/java/org/redisson/RedissonMapCache.java index 6f9b9910f..ef56a5a6f 100644 --- a/redisson/src/main/java/org/redisson/RedissonMapCache.java +++ b/redisson/src/main/java/org/redisson/RedissonMapCache.java @@ -15,8 +15,16 @@ */ package org.redisson; -import io.netty.util.concurrent.Future; -import io.netty.util.concurrent.FutureListener; +import java.math.BigDecimal; +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; + import org.redisson.api.MapOptions; import org.redisson.api.RFuture; import org.redisson.api.RMapCache; @@ -50,15 +58,8 @@ import org.redisson.command.CommandAsyncExecutor; import org.redisson.connection.decoder.MapGetAllDecoder; import org.redisson.eviction.EvictionScheduler; -import java.math.BigDecimal; -import java.net.InetSocketAddress; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.TimeUnit; +import io.netty.util.concurrent.Future; +import io.netty.util.concurrent.FutureListener; /** *

Map-based cache with ability to set TTL for each entry via @@ -81,161 +82,134 @@ import java.util.concurrent.TimeUnit; */ public class RedissonMapCache extends RedissonMap implements RMapCache { - private final int maxSize; - - public RedissonMapCache(EvictionScheduler evictionScheduler, CommandAsyncExecutor commandExecutor, - String name, RedissonClient redisson, MapOptions options) { + public RedissonMapCache(EvictionScheduler evictionScheduler, CommandAsyncExecutor commandExecutor, + String name, RedissonClient redisson, MapOptions options) { super(commandExecutor, name, redisson, options); evictionScheduler.schedule(getName(), getTimeoutSetName(), getIdleSetName(), getExpiredChannelName()); - - if (options != null) { - this.maxSize = options.getMaxSize(); - } else { - this.maxSize = 0; - } } - public RedissonMapCache(Codec codec, EvictionScheduler evictionScheduler, CommandAsyncExecutor commandExecutor, - String name, RedissonClient redisson, MapOptions options) { + public RedissonMapCache(Codec codec, EvictionScheduler evictionScheduler, CommandAsyncExecutor commandExecutor, + String name, RedissonClient redisson, MapOptions options) { super(codec, commandExecutor, name, redisson, options); evictionScheduler.schedule(getName(), getTimeoutSetName(), getIdleSetName(), getExpiredChannelName()); - - if (options != null) { - this.maxSize = options.getMaxSize(); - } else { - this.maxSize = 0; - } } - + @Override public RFuture containsKeyAsync(Object key) { checkKey(key); - + return commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_BOOLEAN, - "local value = redis.call('hget', KEYS[1], ARGV[2]);" + - "local expireDate = 92233720368547758;" + - "if value ~= false then" + - " local maxSize = tonumber(ARGV[3]);" + - " if maxSize ~= 0 then" + - " redis.call('zadd', KEYS[4], tonumber(ARGV[1]), ARGV[2]);" + - " end;" + - " local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]);" + - " if expireDateScore ~= false then" + - " expireDate = tonumber(expireDateScore)" + - " end;" + - " local t, val = struct.unpack('dLc0', value);" + - " if t ~= 0 then" + - " local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]);" + - " if expireIdle ~= false then" + - " if tonumber(expireIdle) > tonumber(ARGV[1]) then" + - " local value = struct.pack('dLc0', t, string.len(val), val);" + - " redis.call('hset', KEYS[1], ARGV[2], value);" + - " redis.call('zadd', KEYS[3], t + tonumber(ARGV[1]), ARGV[2]);" + - " end;" + - " expireDate = math.min(expireDate, tonumber(expireIdle))" + - " end;" + - " end;" + - " if expireDate <= tonumber(ARGV[1]) then" + - " return 0;" + - " end;" + - " return 1;" + + "local value = redis.call('hget', KEYS[1], ARGV[2]); " + + "local expireDate = 92233720368547758; " + + "if value ~= false then " + + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]); " + + "if expireDateScore ~= false then " + + "expireDate = tonumber(expireDateScore) " + + "end; " + + "local t, val = struct.unpack('dLc0', value); " + + "if t ~= 0 then " + + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]); " + + "if expireIdle ~= false then " + + "if tonumber(expireIdle) > tonumber(ARGV[1]) then " + + "local value = struct.pack('dLc0', t, string.len(val), val); " + + "redis.call('hset', KEYS[1], ARGV[2], value); " + + "redis.call('zadd', KEYS[3], t + tonumber(ARGV[1]), ARGV[2]); " + + "end; " + + "expireDate = math.min(expireDate, tonumber(expireIdle)) " + + "end; " + + "end; " + + "if expireDate <= tonumber(ARGV[1]) then " + + "return 0;" + + "end; " + + "return 1;" + "end;" + "return 0; ", - Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getLastAccessTimeSetNameByKey(key)), - System.currentTimeMillis(), encodeMapKey(key), maxSize); + Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key)), + System.currentTimeMillis(), encodeMapKey(key)); } @Override public RFuture containsValueAsync(Object value) { checkValue(value); - + return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_BOOLEAN, - "local s = redis.call('hgetall', KEYS[1]);" + - "for i, v in ipairs(s) do" + - " if i % 2 == 0 then" + - " local t, val = struct.unpack('dLc0', v);" + - " if ARGV[2] == val then" + - " local key = s[i - 1];" + - "" + - " local maxSize = tonumber(ARGV[3]);" + - " if maxSize ~= 0 then" + - " redis.call('zadd', KEYS[4], tonumber(ARGV[1]), key);" + - " end;" + - "" + - " local expireDate = 92233720368547758;" + - " local expireDateScore = redis.call('zscore', KEYS[2], key);" + - " if expireDateScore ~= false then" + - " expireDate = tonumber(expireDateScore)" + - " end;" + - " if t ~= 0 then" + - " local expireIdle = redis.call('zscore', KEYS[3], key);" + - " if expireIdle ~= false then" + - " if tonumber(expireIdle) > tonumber(ARGV[1]) then" + - " local value = struct.pack('dLc0', t, string.len(val), val);" + - " redis.call('hset', KEYS[1], key, value);" + - " redis.call('zadd', KEYS[3], t + tonumber(ARGV[1]), key);" + - " end;" + - " expireDate = math.min(expireDate, tonumber(expireIdle))" + - " end;" + - " end;" + - " if expireDate <= tonumber(ARGV[1]) then" + - " return 0;" + - " end;" + - " return 1;" + - " end;" + - " end;" + - "end;" + - "return 0;", - Arrays.asList(getName(), getTimeoutSetName(), getIdleSetName(), getLastAccessTimeSetName()), - System.currentTimeMillis(), encodeMapValue(value), maxSize); + "local s = redis.call('hgetall', KEYS[1]); " + + "for i, v in ipairs(s) do " + + "if i % 2 == 0 then " + + "local t, val = struct.unpack('dLc0', v); " + + "if ARGV[2] == val then " + + "local key = s[i-1];" + + "local expireDate = 92233720368547758; " + + "local expireDateScore = redis.call('zscore', KEYS[2], key); " + + "if expireDateScore ~= false then " + + "expireDate = tonumber(expireDateScore) " + + "end; " + + "if t ~= 0 then " + + "local expireIdle = redis.call('zscore', KEYS[3], key); " + + "if expireIdle ~= false then " + + "if tonumber(expireIdle) > tonumber(ARGV[1]) then " + + "local value = struct.pack('dLc0', t, string.len(val), val); " + + "redis.call('hset', KEYS[1], key, value); " + + "redis.call('zadd', KEYS[3], t + tonumber(ARGV[1]), key); " + + "end; " + + "expireDate = math.min(expireDate, tonumber(expireIdle)) " + + "end; " + + "end; " + + "if expireDate <= tonumber(ARGV[1]) then " + + "return 0;" + + "end; " + + "return 1; " + + "end; " + + "end; " + + "end;" + + "return 0;", + Arrays.asList(getName(), getTimeoutSetName(), getIdleSetName()), System.currentTimeMillis(), encodeMapValue(value)); } @Override protected RFuture> getAllOperationAsync(Set keys) { - List args = new ArrayList(keys.size() + 2); + List args = new ArrayList(keys.size() + 1); args.add(System.currentTimeMillis()); - args.add(maxSize); args.addAll(keys); - return commandExecutor.evalWriteAsync(getName(), codec, new RedisCommand>("EVAL", new MapGetAllDecoder(args, 2), 7, ValueType.MAP_KEY, ValueType.MAP_VALUE), - "local expireHead = redis.call('zrange', KEYS[2], 0, 0, 'withscores');" + - "local currentTime = tonumber(table.remove(ARGV, 1));" + // index is the first parameter - "local maxSize = tonumber(table.remove(ARGV, 1));" + // index is the first parameter - "local hasExpire = #expireHead == 2 and tonumber(expireHead[2]) <= currentTime;" + - "local map = redis.call('hmget', KEYS[1], unpack(ARGV));" + - "for i = #map, 1, -1 do" + - " local value = map[i];" + - " if value ~= false then" + - " local key = ARGV[i];" + - " local t, val = struct.unpack('dLc0', value);" + - " map[i] = val;" + - " if maxSize ~= 0 then" + - " redis.call('zadd', KEYS[4], currentTime, key);" + - " end;" + - " if hasExpire then" + - " local expireDate = redis.call('zscore', KEYS[2], key);" + - " if expireDate ~= false and tonumber(expireDate) <= currentTime then" + - " map[i] = false;" + - " end;" + - " end;" + - " if t ~= 0 then" + - " local expireIdle = redis.call('zscore', KEYS[3], key);" + - " if expireIdle ~= false then" + - " if tonumber(expireIdle) > currentTime then" + - " local value = struct.pack('dLc0', t, string.len(val), val);" + - " redis.call('hset', KEYS[1], key, value);" + - " redis.call('zadd', KEYS[3], t + currentTime, key);" + - " else" + - " map[i] = false;" + - " end;" + - " end;" + - " end;" + - " end;" + - "end;" + - "return map;", - Arrays.asList(getName(), getTimeoutSetName(), getIdleSetName(), getLastAccessTimeSetName()), args.toArray()); + return commandExecutor.evalWriteAsync(getName(), codec, new RedisCommand>("EVAL", new MapGetAllDecoder(args, 1), 7, ValueType.MAP_KEY, ValueType.MAP_VALUE), + "local expireHead = redis.call('zrange', KEYS[2], 0, 0, 'withscores');" + + "local currentTime = tonumber(table.remove(ARGV, 1)); " // index is the first parameter + + "local hasExpire = #expireHead == 2 and tonumber(expireHead[2]) <= currentTime; " + + "local map = redis.call('hmget', KEYS[1], unpack(ARGV)); " + + "for i = #map, 1, -1 do " + + "local value = map[i]; " + + "if value ~= false then " + + "local key = ARGV[i]; " + + "local t, val = struct.unpack('dLc0', value); " + + "map[i] = val; " + + + "if hasExpire then " + + "local expireDate = redis.call('zscore', KEYS[2], key); " + + "if expireDate ~= false and tonumber(expireDate) <= currentTime then " + + "map[i] = false; " + + "end; " + + "end; " + + + "if t ~= 0 then " + + "local expireIdle = redis.call('zscore', KEYS[3], key); " + + "if expireIdle ~= false then " + + "if tonumber(expireIdle) > currentTime then " + + "local value = struct.pack('dLc0', t, string.len(val), val); " + + "redis.call('hset', KEYS[1], key, value); " + + "redis.call('zadd', KEYS[3], t + currentTime, key); " + + "else " + + "map[i] = false; " + + "end; " + + "end; " + + "end; " + + + "end; " + + "end; " + + "return map;", + Arrays.asList(getName(), getTimeoutSetName(), getIdleSetName()), args.toArray()); } - + @Override public V putIfAbsent(K key, V value, long ttl, TimeUnit ttlUnit) { return get(putIfAbsentAsync(key, value, ttl, ttlUnit)); @@ -287,93 +261,68 @@ public class RedissonMapCache extends RedissonMap implements RMapCac } RFuture future = commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_MAP_VALUE, - "local insertable = false; " - + "local value = redis.call('hget', KEYS[1], ARGV[5]); " - + "if value == false then " - + "insertable = true; " - + "else " - + "local t, val = struct.unpack('dLc0', value); " - + "local expireDate = 92233720368547758; " - + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[5]); " - + "if expireDateScore ~= false then " - + "expireDate = tonumber(expireDateScore) " - + "end; " - + "if t ~= 0 then " - + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[5]); " - + "if expireIdle ~= false then " - + "expireDate = math.min(expireDate, tonumber(expireIdle)) " - + "end; " - + "end; " - + "if expireDate <= tonumber(ARGV[1]) then " - + "insertable = true; " - + "end; " - + "end; " - - + "if insertable == true then " - // ttl - + "if tonumber(ARGV[2]) > 0 then " - + "redis.call('zadd', KEYS[2], ARGV[2], ARGV[5]); " - + "else " - + "redis.call('zrem', KEYS[2], ARGV[5]); " - + "end; " - - // idle - + "if tonumber(ARGV[3]) > 0 then " - + "redis.call('zadd', KEYS[3], ARGV[3], ARGV[5]); " - + "else " - + "redis.call('zrem', KEYS[3], ARGV[5]); " - + "end; " - - // last access time - + "local maxSize = tonumber(ARGV[7]);" + - "if maxSize ~= 0 then" + - " local currentTime = tonumber(ARGV[1]);" + - " local lastAccessTimeSetName = KEYS[5];" + - " redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[5]);" + - " local cacheSize = tonumber(redis.call('hlen', KEYS[1]));" + - " if cacheSize >= maxSize then" + - " local lruItems = redis.call('zrange', lastAccessTimeSetName, 0, cacheSize - maxSize);" + - " for index, lruItem in ipairs(lruItems) do" + - " if lruItem then" + - " local lruItemValue = redis.call('hget', KEYS[1], lruItem);" + - " redis.call('hdel', KEYS[1], lruItem);" + - " redis.call('zrem', KEYS[2], lruItem);" + - " redis.call('zrem', KEYS[3], lruItem);" + - " redis.call('zrem', lastAccessTimeSetName, lruItem);" + - " local removedChannelName = KEYS[6];" + - " local msg = struct.pack('Lc0Lc0', string.len(lruItem), lruItem, string.len(lruItemValue), lruItemValue);" + - " redis.call('publish', removedChannelName, msg);" + - " end;" + - " end" + - " end;" + - "end;" - - // value - + "local val = struct.pack('dLc0', tonumber(ARGV[4]), string.len(ARGV[6]), ARGV[6]); " - + "redis.call('hset', KEYS[1], ARGV[5], val); " - - + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[5]), ARGV[5], string.len(ARGV[6]), ARGV[6]); " - + "redis.call('publish', KEYS[4], msg); " - - + "return nil;" - + "else " - + "local t, val = struct.unpack('dLc0', value); " - + "redis.call('zadd', KEYS[3], t + ARGV[1], ARGV[5]); " - + "return val;" - + "end; ", - Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key), - getLastAccessTimeSetNameByKey(key), getRemovedChannelNameByKey(key)), - System.currentTimeMillis(), ttlTimeout, maxIdleTimeout, maxIdleDelta, encodeMapKey(key), encodeMapValue(value), maxSize); + "local insertable = false; " + + "local value = redis.call('hget', KEYS[1], ARGV[5]); " + + "if value == false then " + + "insertable = true; " + + "else " + + "local t, val = struct.unpack('dLc0', value); " + + "local expireDate = 92233720368547758; " + + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[5]); " + + "if expireDateScore ~= false then " + + "expireDate = tonumber(expireDateScore) " + + "end; " + + "if t ~= 0 then " + + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[5]); " + + "if expireIdle ~= false then " + + "expireDate = math.min(expireDate, tonumber(expireIdle)) " + + "end; " + + "end; " + + "if expireDate <= tonumber(ARGV[1]) then " + + "insertable = true; " + + "end; " + + "end; " + + + "if insertable == true then " + // ttl + + "if tonumber(ARGV[2]) > 0 then " + + "redis.call('zadd', KEYS[2], ARGV[2], ARGV[5]); " + + "else " + + "redis.call('zrem', KEYS[2], ARGV[5]); " + + "end; " + + // idle + + "if tonumber(ARGV[3]) > 0 then " + + "redis.call('zadd', KEYS[3], ARGV[3], ARGV[5]); " + + "else " + + "redis.call('zrem', KEYS[3], ARGV[5]); " + + "end; " + + // value + + "local val = struct.pack('dLc0', tonumber(ARGV[4]), string.len(ARGV[6]), ARGV[6]); " + + "redis.call('hset', KEYS[1], ARGV[5], val); " + + + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[5]), ARGV[5], string.len(ARGV[6]), ARGV[6]); " + + "redis.call('publish', KEYS[4], msg); " + + + "return nil;" + + "else " + + "local t, val = struct.unpack('dLc0', value); " + + "redis.call('zadd', KEYS[3], t + ARGV[1], ARGV[5]); " + + "return val;" + + "end; ", + Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key)), + System.currentTimeMillis(), ttlTimeout, maxIdleTimeout, maxIdleDelta, encodeMapKey(key), encodeMapValue(value)); if (hasNoWriter()) { return future; } - + MapWriterTask listener = new MapWriterTask() { @Override protected void execute() { options.getWriter().write(key, value); } - + @Override protected boolean condition(Future future) { return future.getNow() == null; @@ -385,81 +334,72 @@ public class RedissonMapCache extends RedissonMap implements RMapCac @Override protected RFuture removeOperationAsync(Object key, Object value) { return commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_BOOLEAN, - "local value = redis.call('hget', KEYS[1], ARGV[2]); " - + "if value == false then " - + "return 0; " - + "end; " - + "local t, val = struct.unpack('dLc0', value); " - + "local expireDate = 92233720368547758; " + - "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]); " - + "if expireDateScore ~= false then " - + "expireDate = tonumber(expireDateScore) " - + "end; " - + "if t ~= 0 then " - + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]); " - + "if expireIdle ~= false then " - + "expireDate = math.min(expireDate, tonumber(expireIdle)) " - + "end; " - + "end; " - + "if expireDate <= tonumber(ARGV[1]) then " - + "return 0; " - + "end; " - - + "if val == ARGV[3] then " - + "redis.call('zrem', KEYS[2], ARGV[2]); " - + "redis.call('zrem', KEYS[3], ARGV[2]); " - + "local maxSize = tonumber(ARGV[4]);" + - "if maxSize ~= 0 then" + - " redis.call('zrem', KEYS[5], ARGV[2]);" + - "end;" - + "redis.call('hdel', KEYS[1], ARGV[2]); " - + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(val), val); " - + "redis.call('publish', KEYS[4], msg); " - + "return 1; " - + "else " - + "return 0; " - + "end", - Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getRemovedChannelNameByKey(key), - getLastAccessTimeSetNameByKey(key)), - System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value), maxSize); + "local value = redis.call('hget', KEYS[1], ARGV[2]); " + + "if value == false then " + + "return 0; " + + "end; " + + "local t, val = struct.unpack('dLc0', value); " + + "local expireDate = 92233720368547758; " + + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]); " + + "if expireDateScore ~= false then " + + "expireDate = tonumber(expireDateScore) " + + "end; " + + "if t ~= 0 then " + + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]); " + + "if expireIdle ~= false then " + + "expireDate = math.min(expireDate, tonumber(expireIdle)) " + + "end; " + + "end; " + + "if expireDate <= tonumber(ARGV[1]) then " + + "return 0; " + + "end; " + + + "if val == ARGV[3] then " + + "redis.call('zrem', KEYS[2], ARGV[2]); " + + "redis.call('zrem', KEYS[3], ARGV[2]); " + + "redis.call('hdel', KEYS[1], ARGV[2]); " + + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(val), val); " + + "redis.call('publish', KEYS[4], msg); " + + "return 1; " + + "else " + + "return 0; " + + "end", + Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getRemovedChannelNameByKey(key)), + System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value)); } @Override protected RFuture getOperationAsync(K key) { checkKey(key); - + return commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_MAP_VALUE, - "local value = redis.call('hget', KEYS[1], ARGV[2]); " - + "if value == false then " - + "return nil; " - + "end; " - + "local t, val = struct.unpack('dLc0', value); " - + "local expireDate = 92233720368547758; " + - "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]); " - + "if expireDateScore ~= false then " - + "expireDate = tonumber(expireDateScore) " - + "end; " - + "if t ~= 0 then " - + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]); " - + "if expireIdle ~= false then " - + "if tonumber(expireIdle) > tonumber(ARGV[1]) then " - + "local value = struct.pack('dLc0', t, string.len(val), val); " - + "redis.call('hset', KEYS[1], ARGV[2], value); " - + "redis.call('zadd', KEYS[3], t + tonumber(ARGV[1]), ARGV[2]); " - + "end; " - + "expireDate = math.min(expireDate, tonumber(expireIdle)) " - + "end; " - + "end; " - + "if expireDate <= tonumber(ARGV[1]) then " - + "return nil; " - + "end; " - + "local maxSize = tonumber(ARGV[3]);" + - "if maxSize ~= 0 then" + - " redis.call('zadd', KEYS[4], tonumber(ARGV[1]), ARGV[2]);" + - "end;" - + "return val; ", - Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getLastAccessTimeSetNameByKey(key)), - System.currentTimeMillis(), encodeMapKey(key), maxSize); + "local value = redis.call('hget', KEYS[1], ARGV[2]); " + + "if value == false then " + + "return nil; " + + "end; " + + "local t, val = struct.unpack('dLc0', value); " + + "local expireDate = 92233720368547758; " + + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]); " + + "if expireDateScore ~= false then " + + "expireDate = tonumber(expireDateScore) " + + "end; " + + "if t ~= 0 then " + + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]); " + + "if expireIdle ~= false then " + + "if tonumber(expireIdle) > tonumber(ARGV[1]) then " + + "local value = struct.pack('dLc0', t, string.len(val), val); " + + "redis.call('hset', KEYS[1], ARGV[2], value); " + + "redis.call('zadd', KEYS[3], t + tonumber(ARGV[1]), ARGV[2]); " + + "end; " + + "expireDate = math.min(expireDate, tonumber(expireIdle)) " + + "end; " + + "end; " + + "if expireDate <= tonumber(ARGV[1]) then " + + "return nil; " + + "end; " + + "return val; ", + Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key)), + System.currentTimeMillis(), encodeMapKey(key)); } @Override @@ -470,202 +410,121 @@ public class RedissonMapCache extends RedissonMap implements RMapCac @Override protected RFuture putOperationAsync(K key, V value) { return commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_MAP_VALUE, - "local v = redis.call('hget', KEYS[1], ARGV[2]);" + - "local exists = false;" + - "if v ~= false then" + - " local t, val = struct.unpack('dLc0', v);" + - " local expireDate = 92233720368547758;" + - " local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]);" + - " if expireDateScore ~= false then" + - " expireDate = tonumber(expireDateScore)" + - " end;" + - " if t ~= 0 then" + - " local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]);" + - " if expireIdle ~= false then" + - " expireDate = math.min(expireDate, tonumber(expireIdle))" + - " end;" + - " end;" + - " if expireDate > tonumber(ARGV[1]) then" + - " exists = true;" + - " end;" + - "end;" + - "local value = struct.pack('dLc0', 0, string.len(ARGV[3]), ARGV[3]);" + - "redis.call('hset', KEYS[1], ARGV[2], value);" + - "local currentTime = tonumber(ARGV[1]);" + - "local lastAccessTimeSetName = KEYS[6];" + - "local maxSize = tonumber(ARGV[4]);" + - "if exists == false then" + - " if maxSize ~= 0 then" + - " redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[2]);" + - " local cacheSize = tonumber(redis.call('hlen', KEYS[1]));" + - " if cacheSize >= maxSize then" + - " local lruItems = redis.call('zrange', lastAccessTimeSetName, 0, cacheSize - maxSize);" + - " for index, lruItem in ipairs(lruItems) do" + - " if lruItem then" + - " local lruItemValue = redis.call('hget', KEYS[1], lruItem);" + - " redis.call('hdel', KEYS[1], lruItem);" + - " redis.call('zrem', KEYS[2], lruItem);" + - " redis.call('zrem', KEYS[3], lruItem);" + - " redis.call('zrem', lastAccessTimeSetName, lruItem);" + - " local removedChannelName = KEYS[7];" + - " local msg = struct.pack('Lc0Lc0', string.len(lruItem), lruItem, string.len(lruItemValue), lruItemValue);" + - " redis.call('publish', removedChannelName, msg);" + - " end;" + - " end" + - " end;" + - " end;" + - " local msg = struct.pack('Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3]);" + - " redis.call('publish', KEYS[4], msg);" + - " return nil;" + - "else" + - " if maxSize ~= 0 then" + - " redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[2]);" + - " end;" + - "end;" + - "" + - "local t, val = struct.unpack('dLc0', v);" + - "local msg = struct.pack('Lc0Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3], string.len(val), val);" + - "redis.call('publish', KEYS[5], msg);" + - "return val;", - Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key), - getUpdatedChannelNameByKey(key), getLastAccessTimeSetNameByKey(key), getRemovedChannelNameByKey(key)), - System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value), maxSize); + "local v = redis.call('hget', KEYS[1], ARGV[2]); " + + "local exists = false;" + + "if v ~= false then " + + "local t, val = struct.unpack('dLc0', v); " + + "local expireDate = 92233720368547758; " + + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]); " + + "if expireDateScore ~= false then " + + "expireDate = tonumber(expireDateScore) " + + "end; " + + "if t ~= 0 then " + + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]); " + + "if expireIdle ~= false then " + + "expireDate = math.min(expireDate, tonumber(expireIdle)) " + + "end; " + + "end; " + + "if expireDate > tonumber(ARGV[1]) then " + + "exists = true; " + + "end; " + + "end; " + + + "local value = struct.pack('dLc0', 0, string.len(ARGV[3]), ARGV[3]); " + + "redis.call('hset', KEYS[1], ARGV[2], value); " + + "if exists == false then " + + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3]); " + + "redis.call('publish', KEYS[4], msg); " + + "return nil; " + + "end; " + + + "local t, val = struct.unpack('dLc0', v); " + + "local msg = struct.pack('Lc0Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3], string.len(val), val); " + + "redis.call('publish', KEYS[5], msg); " + + "return val; ", + Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key), getUpdatedChannelNameByKey(key)), + System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value)); } @Override protected RFuture putIfAbsentOperationAsync(K key, V value) { return commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_MAP_VALUE, "local value = redis.call('hget', KEYS[1], ARGV[2]); " - + "local maxSize = tonumber(ARGV[4]);" - + "local lastAccessTimeSetName = KEYS[5];" - + "local currentTime = tonumber(ARGV[1]);" - + "if value ~= false then " - + "local t, val = struct.unpack('dLc0', value); " - + "local expireDate = 92233720368547758; " - + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]); " - + "if expireDateScore ~= false then " - + "expireDate = tonumber(expireDateScore) " - + "end; " - + "if t ~= 0 then " - + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]); " - + "if expireIdle ~= false then " - + "expireDate = math.min(expireDate, tonumber(expireIdle)) " - + "end; " - + "end; " - + "if expireDate > tonumber(ARGV[1]) then " - + "if maxSize ~= 0 then" - + " redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[2]);" - + "end;" - + "return val; " - + "end; " - + "end; " - - + "local value = struct.pack('dLc0', 0, string.len(ARGV[3]), ARGV[3]); " - + "redis.call('hset', KEYS[1], ARGV[2], value); " - - // last access time - + "if maxSize ~= 0 then" + - " redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[2]);" + - " local cacheSize = tonumber(redis.call('hlen', KEYS[1]));" + - " if cacheSize >= maxSize then" + - " local lruItems = redis.call('zrange', lastAccessTimeSetName, 0, cacheSize - maxSize);" + - " for index, lruItem in ipairs(lruItems) do" + - " if lruItem then" + - " local lruItemValue = redis.call('hget', KEYS[1], lruItem);" + - " redis.call('hdel', KEYS[1], lruItem);" + - " redis.call('zrem', KEYS[2], lruItem);" + - " redis.call('zrem', KEYS[3], lruItem);" + - " redis.call('zrem', lastAccessTimeSetName, lruItem);" + - " local removedChannelName = KEYS[6];" + - " local msg = struct.pack('Lc0Lc0', string.len(lruItem), lruItem, string.len(lruItemValue), lruItemValue);" + - " redis.call('publish', removedChannelName, msg);" + - " end;" + - " end" + - " end;" + - "end;" - - + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3]); " - + "redis.call('publish', KEYS[4], msg); " - + "return nil;", - Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key), - getLastAccessTimeSetNameByKey(key), getRemovedChannelNameByKey(key)), - System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value), maxSize); + + "if value ~= false then " + + "local t, val = struct.unpack('dLc0', value); " + + "local expireDate = 92233720368547758; " + + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]); " + + "if expireDateScore ~= false then " + + "expireDate = tonumber(expireDateScore) " + + "end; " + + "if t ~= 0 then " + + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]); " + + "if expireIdle ~= false then " + + "expireDate = math.min(expireDate, tonumber(expireIdle)) " + + "end; " + + "end; " + + "if expireDate > tonumber(ARGV[1]) then " + + "return val; " + + "end; " + + "end; " + + + "local value = struct.pack('dLc0', 0, string.len(ARGV[3]), ARGV[3]); " + + "redis.call('hset', KEYS[1], ARGV[2], value); " + + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3]); " + + "redis.call('publish', KEYS[4], msg); " + + "return nil;", + Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key)), + System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value)); } @Override public V addAndGet(K key, Number value) { return get(addAndGetAsync(key, value)); } - + @Override public RFuture addAndGetOperationAsync(K key, Number value) { byte[] keyState = encodeMapKey(key); return commandExecutor.evalWriteAsync(getName(key), StringCodec.INSTANCE, new RedisCommand("EVAL", new NumberConvertor(value.getClass())), - "local value = redis.call('hget', KEYS[1], ARGV[2]); " - + "local expireDate = 92233720368547758; " - + "local t = 0; " - + "local val = 0; " - + "if value ~= false then " - + "t, val = struct.unpack('dLc0', value); " - + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]); " - + "if expireDateScore ~= false then " - + "expireDate = tonumber(expireDateScore) " - + "end; " - + "if t ~= 0 then " - + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]); " - + "if expireIdle ~= false then " - + "if tonumber(expireIdle) > tonumber(ARGV[1]) then " - + "local value = struct.pack('dLc0', t, string.len(val), val); " - + "redis.call('hset', KEYS[1], ARGV[2], value); " - + "redis.call('zadd', KEYS[3], t + tonumber(ARGV[1]), ARGV[2]); " - + "end; " - + "expireDate = math.min(expireDate, tonumber(expireIdle)) " - + "end; " - + "end; " - + "end; " - - + "local newValue = tonumber(ARGV[3]); " - + "if value ~= false and expireDate > tonumber(ARGV[1]) then " - + "newValue = tonumber(val) + newValue; " - - + "local msg = struct.pack('Lc0Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(newValue), newValue, string.len(val), val); " - + "redis.call('publish', KEYS[5], msg); " - + "else " - + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3]); " - + "redis.call('publish', KEYS[4], msg); " - + "end; " - + "local newValuePack = struct.pack('dLc0', t + tonumber(ARGV[1]), string.len(newValue), newValue); " - + "redis.call('hset', KEYS[1], ARGV[2], newValuePack); " - - // last access time - + "local maxSize = tonumber(ARGV[4]);" + - "if maxSize ~= 0 then" + - " local currentTime = tonumber(ARGV[1]);" + - " local lastAccessTimeSetName = KEYS[6];" + - " redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[2]);" + - " local cacheSize = tonumber(redis.call('hlen', KEYS[1]));" + - " if cacheSize >= maxSize then" + - " local lruItems = redis.call('zrange', lastAccessTimeSetName, 0, cacheSize - maxSize);" + - " for index, lruItem in ipairs(lruItems) do" + - " if lruItem then" + - " local lruItemValue = redis.call('hget', KEYS[1], lruItem);" + - " redis.call('hdel', KEYS[1], lruItem);" + - " redis.call('zrem', KEYS[2], lruItem);" + - " redis.call('zrem', KEYS[3], lruItem);" + - " redis.call('zrem', lastAccessTimeSetName, lruItem);" + - " local removedChannelName = KEYS[7];" + - " local msg = struct.pack('Lc0Lc0', string.len(lruItem), lruItem, string.len(lruItemValue), lruItemValue);" + - " redis.call('publish', removedChannelName, msg);" + - " end;" + - " end" + - " end;" + - "end;" - - + "return tostring(newValue); ", - Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key), - getUpdatedChannelNameByKey(key), getLastAccessTimeSetNameByKey(key), getRemovedChannelNameByKey(key)), - System.currentTimeMillis(), keyState, new BigDecimal(value.toString()).toPlainString(), maxSize); + "local value = redis.call('hget', KEYS[1], ARGV[2]); " + + "local expireDate = 92233720368547758; " + + "local t = 0; " + + "local val = 0; " + + "if value ~= false then " + + "t, val = struct.unpack('dLc0', value); " + + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]); " + + "if expireDateScore ~= false then " + + "expireDate = tonumber(expireDateScore) " + + "end; " + + "if t ~= 0 then " + + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]); " + + "if expireIdle ~= false then " + + "if tonumber(expireIdle) > tonumber(ARGV[1]) then " + + "local value = struct.pack('dLc0', t, string.len(val), val); " + + "redis.call('hset', KEYS[1], ARGV[2], value); " + + "redis.call('zadd', KEYS[3], t + tonumber(ARGV[1]), ARGV[2]); " + + "end; " + + "expireDate = math.min(expireDate, tonumber(expireIdle)) " + + "end; " + + "end; " + + "end; " + + + "local newValue = tonumber(ARGV[3]); " + + "if value ~= false and expireDate > tonumber(ARGV[1]) then " + + "newValue = tonumber(val) + newValue; " + + + "local msg = struct.pack('Lc0Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(newValue), newValue, string.len(val), val); " + + "redis.call('publish', KEYS[5], msg); " + + "else " + + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3]); " + + "redis.call('publish', KEYS[4], msg); " + + "end; " + + "local newValuePack = struct.pack('dLc0', t + tonumber(ARGV[1]), string.len(newValue), newValue); " + + "redis.call('hset', KEYS[1], ARGV[2], newValuePack); " + + "return tostring(newValue); ", + Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key), getUpdatedChannelNameByKey(key)), + System.currentTimeMillis(), keyState, new BigDecimal(value.toString()).toPlainString()); } @Override @@ -687,7 +546,7 @@ public class RedissonMapCache extends RedissonMap implements RMapCac public RFuture fastPutAsync(final K key, final V value, long ttl, TimeUnit ttlUnit, long maxIdleTime, TimeUnit maxIdleUnit) { checkKey(key); checkValue(value); - + if (ttl < 0) { throw new IllegalArgumentException("ttl can't be negative"); } @@ -707,11 +566,11 @@ public class RedissonMapCache extends RedissonMap implements RMapCac } RFuture future = fastPutOperationAsync(key, value, ttl, ttlUnit, maxIdleTime, maxIdleUnit); - + if (hasNoWriter()) { return future; } - + MapWriterTask listener = new MapWriterTask() { @Override protected void execute() { @@ -737,77 +596,51 @@ public class RedissonMapCache extends RedissonMap implements RMapCac RFuture future = commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_BOOLEAN, "local insertable = false; " - + "local value = redis.call('hget', KEYS[1], ARGV[5]); " - + "local t, val;" - + "if value == false then " - + "insertable = true; " - + "else " - + "t, val = struct.unpack('dLc0', value); " - + "local expireDate = 92233720368547758; " - + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[5]); " - + "if expireDateScore ~= false then " - + "expireDate = tonumber(expireDateScore) " - + "end; " - + "if t ~= 0 then " - + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[5]); " - + "if expireIdle ~= false then " - + "expireDate = math.min(expireDate, tonumber(expireIdle)) " - + "end; " - + "end; " - + "if expireDate <= tonumber(ARGV[1]) then " - + "insertable = true; " - + "end; " - + "end; " + - - "if tonumber(ARGV[2]) > 0 then " - + "redis.call('zadd', KEYS[2], ARGV[2], ARGV[5]); " - + "else " - + "redis.call('zrem', KEYS[2], ARGV[5]); " - + "end; " - + "if tonumber(ARGV[3]) > 0 then " - + "redis.call('zadd', KEYS[3], ARGV[3], ARGV[5]); " - + "else " - + "redis.call('zrem', KEYS[3], ARGV[5]); " - + "end; " + - - // last access time - "local maxSize = tonumber(ARGV[7]);" + - "if maxSize ~= 0 then" + - " local currentTime = tonumber(ARGV[1]);" + - " local lastAccessTimeSetName = KEYS[6];" + - " redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[5]);" + - " local cacheSize = tonumber(redis.call('hlen', KEYS[1]));" + - " if cacheSize >= maxSize then" + - " local lruItems = redis.call('zrange', lastAccessTimeSetName, 0, cacheSize - maxSize);" + - " for index, lruItem in ipairs(lruItems) do" + - " if lruItem then" + - " local lruItemValue = redis.call('hget', KEYS[1], lruItem);" + - " redis.call('hdel', KEYS[1], lruItem);" + - " redis.call('zrem', KEYS[2], lruItem);" + - " redis.call('zrem', KEYS[3], lruItem);" + - " redis.call('zrem', lastAccessTimeSetName, lruItem);" + - " local removedChannelName = KEYS[7];" + - " local msg = struct.pack('Lc0Lc0', string.len(lruItem), lruItem, string.len(lruItemValue), lruItemValue);" + - " redis.call('publish', removedChannelName, msg);" + - " end;" + - " end" + - " end;" + - "end;" - - + "local value = struct.pack('dLc0', ARGV[4], string.len(ARGV[6]), ARGV[6]); " - + "redis.call('hset', KEYS[1], ARGV[5], value); " - + "if insertable == true then " - + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[5]), ARGV[5], string.len(ARGV[6]), ARGV[6]); " - + "redis.call('publish', KEYS[4], msg); " - + "return 1;" - + "else " - + "local msg = struct.pack('Lc0Lc0Lc0', string.len(ARGV[5]), ARGV[5], string.len(ARGV[6]), ARGV[6], string.len(val), val); " - + "redis.call('publish', KEYS[5], msg); " - + "return 0;" - + "end;", - Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key), - getUpdatedChannelNameByKey(key), getLastAccessTimeSetNameByKey(key), getRemovedChannelNameByKey(key)), - System.currentTimeMillis(), ttlTimeout, maxIdleTimeout, maxIdleDelta, encodeMapKey(key), encodeMapValue(value), maxSize); + + "local value = redis.call('hget', KEYS[1], ARGV[5]); " + + "local t, val;" + + "if value == false then " + + "insertable = true; " + + "else " + + "t, val = struct.unpack('dLc0', value); " + + "local expireDate = 92233720368547758; " + + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[5]); " + + "if expireDateScore ~= false then " + + "expireDate = tonumber(expireDateScore) " + + "end; " + + "if t ~= 0 then " + + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[5]); " + + "if expireIdle ~= false then " + + "expireDate = math.min(expireDate, tonumber(expireIdle)) " + + "end; " + + "end; " + + "if expireDate <= tonumber(ARGV[1]) then " + + "insertable = true; " + + "end; " + + "end; " + + + "if tonumber(ARGV[2]) > 0 then " + + "redis.call('zadd', KEYS[2], ARGV[2], ARGV[5]); " + + "else " + + "redis.call('zrem', KEYS[2], ARGV[5]); " + + "end; " + + "if tonumber(ARGV[3]) > 0 then " + + "redis.call('zadd', KEYS[3], ARGV[3], ARGV[5]); " + + "else " + + "redis.call('zrem', KEYS[3], ARGV[5]); " + + "end; " + + "local value = struct.pack('dLc0', ARGV[4], string.len(ARGV[6]), ARGV[6]); " + + "redis.call('hset', KEYS[1], ARGV[5], value); " + + "if insertable == true then " + + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[5]), ARGV[5], string.len(ARGV[6]), ARGV[6]); " + + "redis.call('publish', KEYS[4], msg); " + + "return 1;" + + "else " + + "local msg = struct.pack('Lc0Lc0Lc0', string.len(ARGV[5]), ARGV[5], string.len(ARGV[6]), ARGV[6], string.len(val), val); " + + "redis.call('publish', KEYS[5], msg); " + + "return 0;" + + "end;", + Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key), getUpdatedChannelNameByKey(key)), + System.currentTimeMillis(), ttlTimeout, maxIdleTimeout, maxIdleDelta, encodeMapKey(key), encodeMapValue(value)); return future; } @@ -825,7 +658,7 @@ public class RedissonMapCache extends RedissonMap implements RMapCac public RFuture putAsync(final K key, final V value, long ttl, TimeUnit ttlUnit, long maxIdleTime, TimeUnit maxIdleUnit) { checkKey(key); checkValue(value); - + if (ttl < 0) { throw new IllegalArgumentException("ttl can't be negative"); } @@ -860,7 +693,7 @@ public class RedissonMapCache extends RedissonMap implements RMapCac if (hasNoWriter()) { return future; } - + MapWriterTask listener = new MapWriterTask() { @Override protected void execute() { @@ -874,91 +707,66 @@ public class RedissonMapCache extends RedissonMap implements RMapCac long maxIdleDelta) { RFuture future = commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_MAP_VALUE, "local insertable = false; " - + "local v = redis.call('hget', KEYS[1], ARGV[5]); " - + "if v == false then " - + "insertable = true; " - + "else " - + "local t, val = struct.unpack('dLc0', v); " - + "local expireDate = 92233720368547758; " - + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[5]); " - + "if expireDateScore ~= false then " - + "expireDate = tonumber(expireDateScore) " - + "end; " - + "if t ~= 0 then " - + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[5]); " - + "if expireIdle ~= false then " - + "expireDate = math.min(expireDate, tonumber(expireIdle)) " - + "end; " - + "end; " - + "if expireDate <= tonumber(ARGV[1]) then " - + "insertable = true; " - + "end; " - + "end; " - - + "if tonumber(ARGV[2]) > 0 then " - + "redis.call('zadd', KEYS[2], ARGV[2], ARGV[5]); " - + "else " - + "redis.call('zrem', KEYS[2], ARGV[5]); " - + "end; " - + "if tonumber(ARGV[3]) > 0 then " - + "redis.call('zadd', KEYS[3], ARGV[3], ARGV[5]); " - + "else " - + "redis.call('zrem', KEYS[3], ARGV[5]); " - + "end; " - - // last access time - + "local maxSize = tonumber(ARGV[7]);" + - "if maxSize ~= 0 then" + - " local currentTime = tonumber(ARGV[1]);" + - " local lastAccessTimeSetName = KEYS[6];" + - " redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[5]);" + - " local cacheSize = tonumber(redis.call('hlen', KEYS[1]));" + - " if cacheSize >= maxSize then" + - " local lruItems = redis.call('zrange', lastAccessTimeSetName, 0, cacheSize - maxSize);" + - " for index, lruItem in ipairs(lruItems) do" + - " if lruItem then" + - " local lruItemValue = redis.call('hget', KEYS[1], lruItem);" + - " redis.call('hdel', KEYS[1], lruItem);" + - " redis.call('zrem', KEYS[2], lruItem);" + - " redis.call('zrem', KEYS[3], lruItem);" + - " redis.call('zrem', lastAccessTimeSetName, lruItem);" + - " local removedChannelName = KEYS[7];" + - " local msg = struct.pack('Lc0Lc0', string.len(lruItem), lruItem, string.len(lruItemValue), lruItemValue);" + - " redis.call('publish', removedChannelName, msg);" + - " end;" + - " end" + - " end;" + - "end;" - - + "local value = struct.pack('dLc0', ARGV[4], string.len(ARGV[6]), ARGV[6]); " - + "redis.call('hset', KEYS[1], ARGV[5], value); " - - + "if insertable == true then " - + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[5]), ARGV[5], string.len(ARGV[6]), ARGV[6]); " - + "redis.call('publish', KEYS[4], msg); " - + "return nil;" - + "end; " - - + "local t, val = struct.unpack('dLc0', v); " - - + "local msg = struct.pack('Lc0Lc0Lc0', string.len(ARGV[5]), ARGV[5], string.len(ARGV[6]), ARGV[6], string.len(val), val); " - + "redis.call('publish', KEYS[5], msg); " - - + "return val", - Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key), - getUpdatedChannelNameByKey(key), getLastAccessTimeSetNameByKey(key), getRemovedChannelNameByKey(key)), - System.currentTimeMillis(), ttlTimeout, maxIdleTimeout, maxIdleDelta, encodeMapKey(key), encodeMapValue(value), maxSize); + + "local v = redis.call('hget', KEYS[1], ARGV[5]); " + + "if v == false then " + + "insertable = true; " + + "else " + + "local t, val = struct.unpack('dLc0', v); " + + "local expireDate = 92233720368547758; " + + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[5]); " + + "if expireDateScore ~= false then " + + "expireDate = tonumber(expireDateScore) " + + "end; " + + "if t ~= 0 then " + + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[5]); " + + "if expireIdle ~= false then " + + "expireDate = math.min(expireDate, tonumber(expireIdle)) " + + "end; " + + "end; " + + "if expireDate <= tonumber(ARGV[1]) then " + + "insertable = true; " + + "end; " + + "end; " + + + "if tonumber(ARGV[2]) > 0 then " + + "redis.call('zadd', KEYS[2], ARGV[2], ARGV[5]); " + + "else " + + "redis.call('zrem', KEYS[2], ARGV[5]); " + + "end; " + + "if tonumber(ARGV[3]) > 0 then " + + "redis.call('zadd', KEYS[3], ARGV[3], ARGV[5]); " + + "else " + + "redis.call('zrem', KEYS[3], ARGV[5]); " + + "end; " + + + "local value = struct.pack('dLc0', ARGV[4], string.len(ARGV[6]), ARGV[6]); " + + "redis.call('hset', KEYS[1], ARGV[5], value); " + + + "if insertable == true then " + + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[5]), ARGV[5], string.len(ARGV[6]), ARGV[6]); " + + "redis.call('publish', KEYS[4], msg); " + + "return nil;" + + "end; " + + + "local t, val = struct.unpack('dLc0', v); " + + + "local msg = struct.pack('Lc0Lc0Lc0', string.len(ARGV[5]), ARGV[5], string.len(ARGV[6]), ARGV[6], string.len(val), val); " + + "redis.call('publish', KEYS[5], msg); " + + + "return val", + Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key), getUpdatedChannelNameByKey(key)), + System.currentTimeMillis(), ttlTimeout, maxIdleTimeout, maxIdleDelta, encodeMapKey(key), encodeMapValue(value)); return future; } String getTimeoutSetNameByKey(Object key) { return prefixName("redisson__timeout__set", getName(key)); } - + String getTimeoutSetName(String name) { return prefixName("redisson__timeout__set", name); } - + String getTimeoutSetName() { return prefixName("redisson__timeout__set", getName()); } @@ -966,11 +774,11 @@ public class RedissonMapCache extends RedissonMap implements RMapCac String getIdleSetNameByKey(Object key) { return prefixName("redisson__idle__set", getName(key)); } - + String getIdleSetName(String name) { return prefixName("redisson__idle__set", name); } - + String getIdleSetName() { return prefixName("redisson__idle__set", getName()); } @@ -978,7 +786,7 @@ public class RedissonMapCache extends RedissonMap implements RMapCac String getCreatedChannelNameByKey(Object key) { return prefixName("redisson_map_cache_created", getName(key)); } - + String getCreatedChannelName(String name) { return prefixName("redisson_map_cache_created", name); } @@ -1028,55 +836,45 @@ public class RedissonMapCache extends RedissonMap implements RMapCac public RFuture removeOperationAsync(K key) { return commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_MAP_VALUE, "local value = redis.call('hget', KEYS[1], ARGV[2]); " - + "if value == false then " - + "return nil; " - + "end; " - - + "local t, val = struct.unpack('dLc0', value); " - + "local expireDate = 92233720368547758; " + - "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]); " - + "if expireDateScore ~= false then " - + "expireDate = tonumber(expireDateScore) " - + "end; " - + "if t ~= 0 then " - + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]); " - + "if expireIdle ~= false then " - + "expireDate = math.min(expireDate, tonumber(expireIdle)) " - + "end; " - + "end; " - + "if expireDate <= tonumber(ARGV[1]) then " - + "return nil; " - + "end; " - - + "redis.call('zrem', KEYS[2], ARGV[2]); " - + "redis.call('zrem', KEYS[3], ARGV[2]); " - + "local maxSize = tonumber(ARGV[3])" - + "if maxSize ~= 0 then" - + " redis.call('zrem', KEYS[5], ARGV[2]); " - + "end;" - + "redis.call('hdel', KEYS[1], ARGV[2]); " - - + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(val), val); " - + "redis.call('publish', KEYS[4], msg); " - + "return val; ", - Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getRemovedChannelNameByKey(key), - getLastAccessTimeSetNameByKey(key)), - System.currentTimeMillis(), encodeMapKey(key), maxSize); + + "if value == false then " + + "return nil; " + + "end; " + + + "local t, val = struct.unpack('dLc0', value); " + + "local expireDate = 92233720368547758; " + + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]); " + + "if expireDateScore ~= false then " + + "expireDate = tonumber(expireDateScore) " + + "end; " + + "if t ~= 0 then " + + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]); " + + "if expireIdle ~= false then " + + "expireDate = math.min(expireDate, tonumber(expireIdle)) " + + "end; " + + "end; " + + "if expireDate <= tonumber(ARGV[1]) then " + + "return nil; " + + "end; " + + + "redis.call('zrem', KEYS[2], ARGV[2]); " + + "redis.call('zrem', KEYS[3], ARGV[2]); " + + "redis.call('hdel', KEYS[1], ARGV[2]); " + + + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(val), val); " + + "redis.call('publish', KEYS[4], msg); " + + "return val; ", + Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getRemovedChannelNameByKey(key)), + System.currentTimeMillis(), encodeMapKey(key)); } @Override protected RFuture> fastRemoveOperationBatchAsync(K... keys) { - List args = new ArrayList(keys.length + 1); - args.add(maxSize); + List args = new ArrayList(keys.length); for (K key : keys) { args.add(encodeMapKey(key)); } RFuture> future = commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_LIST, - "local maxSize = tonumber(table.remove(ARGV, 1));" - + "if maxSize ~= 0 then" - + " redis.call('zrem', KEYS[5], unpack(ARGV));" - + "end;" + "redis.call('zrem', KEYS[3], unpack(ARGV)); " + "redis.call('zrem', KEYS[2], unpack(ARGV)); " + "for i, key in ipairs(ARGV) do " @@ -1085,88 +883,84 @@ public class RedissonMapCache extends RedissonMap implements RMapCac + "local t, val = struct.unpack('dLc0', v); " + "local msg = struct.pack('Lc0Lc0', string.len(key), key, string.len(val), val); " + "redis.call('publish', KEYS[4], msg); " - + "end;" + + + "end;" + "end;" + - - "local result = {}; " + - "for i = 1, #ARGV, 1 do " - + "local val = redis.call('hdel', KEYS[1], ARGV[i]); " - + "table.insert(result, val); " - + "end;" - + "return result;", - Arrays.asList(getName(), getTimeoutSetName(), getIdleSetName(), getRemovedChannelName(), getLastAccessTimeSetName()), - args.toArray()); + + "local result = {}; " + + "for i = 1, #ARGV, 1 do " + + "local val = redis.call('hdel', KEYS[1], ARGV[i]); " + + "table.insert(result, val); " + + "end;" + + "return result;", + Arrays.asList(getName(), getTimeoutSetName(), getIdleSetName(), getRemovedChannelName()), + args.toArray()); return future; } - + @Override protected RFuture fastRemoveOperationAsync(K ... keys) { - List params = new ArrayList(keys.length + 1); - params.add(maxSize); + List params = new ArrayList(keys.length); for (K key : keys) { params.add(encodeMapKey(key)); } - + return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_LONG, - "local maxSize = tonumber(table.remove(ARGV, 1));" - + "if maxSize ~= 0 then" - + " redis.call('zrem', KEYS[5], unpack(ARGV));" - + "end;" + - "redis.call('zrem', KEYS[3], unpack(ARGV)); " + - "redis.call('zrem', KEYS[2], unpack(ARGV)); " + - "for i, key in ipairs(ARGV) do " - + "local v = redis.call('hget', KEYS[1], key); " - + "if v ~= false then " - + "local t, val = struct.unpack('dLc0', v); " - + "local msg = struct.pack('Lc0Lc0', string.len(key), key, string.len(val), val); " - + "redis.call('publish', KEYS[4], msg); " - + "end;" + - "end;" + - "return redis.call('hdel', KEYS[1], unpack(ARGV)); ", - Arrays.asList(getName(), getTimeoutSetName(), getIdleSetName(), getRemovedChannelName(), getLastAccessTimeSetName()), + "redis.call('zrem', KEYS[3], unpack(ARGV)); " + + "redis.call('zrem', KEYS[2], unpack(ARGV)); " + + "for i, key in ipairs(ARGV) do " + + "local v = redis.call('hget', KEYS[1], key); " + + "if v ~= false then " + + "local t, val = struct.unpack('dLc0', v); " + + "local msg = struct.pack('Lc0Lc0', string.len(key), key, string.len(val), val); " + + "redis.call('publish', KEYS[4], msg); " + + "end;" + + "end;" + + "return redis.call('hdel', KEYS[1], unpack(ARGV)); ", + Arrays.asList(getName(), getTimeoutSetName(), getIdleSetName(), getRemovedChannelName()), params.toArray()); } + @Override MapScanResult scanIterator(String name, InetSocketAddress client, long startPos) { return get(scanIteratorAsync(name, client, startPos)); } - + public RFuture> scanIteratorAsync(final String name, InetSocketAddress client, long startPos) { - RedisCommand> EVAL_HSCAN = new RedisCommand>("EVAL", + RedisCommand> EVAL_HSCAN = new RedisCommand>("EVAL", new ListMultiDecoder(new LongMultiDecoder(), new ObjectMapDecoder(new MapScanCodec(codec)), new ObjectListDecoder(codec), new MapCacheScanResultReplayDecoder()), ValueType.MAP); RFuture> f = commandExecutor.evalReadAsync(client, name, codec, EVAL_HSCAN, "local result = {}; " - + "local idleKeys = {}; " - + "local res = redis.call('hscan', KEYS[1], ARGV[2]); " - + "local currentTime = tonumber(ARGV[1]); " - + "for i, value in ipairs(res[2]) do " - + "if i % 2 == 0 then " - + "local key = res[2][i-1]; " + - "local expireDate = 92233720368547758; " + - "local expireDateScore = redis.call('zscore', KEYS[2], key); " - + "if expireDateScore ~= false then " - + "expireDate = tonumber(expireDateScore) " - + "end; " - - + "local t, val = struct.unpack('dLc0', value); " - + "if t ~= 0 then " - + "local expireIdle = redis.call('zscore', KEYS[3], key); " - + "if expireIdle ~= false then " - + "if tonumber(expireIdle) > currentTime and expireDate > currentTime then " - + "table.insert(idleKeys, key); " - + "end; " - + "expireDate = math.min(expireDate, tonumber(expireIdle)) " - + "end; " - + "end; " + + "local idleKeys = {}; " + + "local res = redis.call('hscan', KEYS[1], ARGV[2]); " + + "local currentTime = tonumber(ARGV[1]); " + + "for i, value in ipairs(res[2]) do " + + "if i % 2 == 0 then " + + "local key = res[2][i-1]; " + + "local expireDate = 92233720368547758; " + + "local expireDateScore = redis.call('zscore', KEYS[2], key); " + + "if expireDateScore ~= false then " + + "expireDate = tonumber(expireDateScore) " + + "end; " - + "if expireDate > currentTime then " - + "table.insert(result, key); " - + "table.insert(result, val); " + + "local t, val = struct.unpack('dLc0', value); " + + "if t ~= 0 then " + + "local expireIdle = redis.call('zscore', KEYS[3], key); " + + "if expireIdle ~= false then " + + "if tonumber(expireIdle) > currentTime and expireDate > currentTime then " + + "table.insert(idleKeys, key); " + "end; " + + "expireDate = math.min(expireDate, tonumber(expireIdle)) " + "end; " - + "end;" - + "return {res[1], result, idleKeys};", Arrays.asList(name, getTimeoutSetName(name), getIdleSetName(name)), System.currentTimeMillis(), startPos); + + "end; " + + "if expireDate > currentTime then " + + "table.insert(result, key); " + + "table.insert(result, val); " + + "end; " + + "end; " + + "end;" + + "return {res[1], result, idleKeys};", Arrays.asList(name, getTimeoutSetName(name), getIdleSetName(name)), System.currentTimeMillis(), startPos); + f.addListener(new FutureListener>() { @Override public void operationComplete(Future> future) @@ -1176,34 +970,34 @@ public class RedissonMapCache extends RedissonMap implements RMapCac if (res.getIdleKeys().isEmpty()) { return; } - + List args = new ArrayList(res.getIdleKeys().size() + 1); args.add(System.currentTimeMillis()); args.addAll(res.getIdleKeys()); commandExecutor.evalWriteAsync(name, codec, new RedisCommand>("EVAL", new MapGetAllDecoder(args, 1), 7, ValueType.MAP_KEY, ValueType.MAP_VALUE), - "local currentTime = tonumber(table.remove(ARGV, 1)); " // index is the first parameter - + "local map = redis.call('hmget', KEYS[1], unpack(ARGV)); " - + "for i = #map, 1, -1 do " - + "local value = map[i]; " - + "if value ~= false then " - + "local key = ARGV[i]; " - + "local t, val = struct.unpack('dLc0', value); " - - + "if t ~= 0 then " - + "local expireIdle = redis.call('zscore', KEYS[2], key); " - + "if expireIdle ~= false then " - + "if tonumber(expireIdle) > currentTime then " - + "local value = struct.pack('dLc0', t, string.len(val), val); " - + "redis.call('hset', KEYS[1], key, value); " - + "redis.call('zadd', KEYS[2], t + currentTime, key); " - + "end; " - + "end; " - + "end; " - + "end; " - + "end; ", + "local currentTime = tonumber(table.remove(ARGV, 1)); " // index is the first parameter + + "local map = redis.call('hmget', KEYS[1], unpack(ARGV)); " + + "for i = #map, 1, -1 do " + + "local value = map[i]; " + + "if value ~= false then " + + "local key = ARGV[i]; " + + "local t, val = struct.unpack('dLc0', value); " + + + "if t ~= 0 then " + + "local expireIdle = redis.call('zscore', KEYS[2], key); " + + "if expireIdle ~= false then " + + "if tonumber(expireIdle) > currentTime then " + + "local value = struct.pack('dLc0', t, string.len(val), val); " + + "redis.call('hset', KEYS[1], key, value); " + + "redis.call('zadd', KEYS[2], t + currentTime, key); " + + "end; " + + "end; " + + "end; " + + "end; " + + "end; ", Arrays.asList(name, getIdleSetName(name)), args.toArray()); - + } } }); @@ -1216,159 +1010,104 @@ public class RedissonMapCache extends RedissonMap implements RMapCac protected RFuture fastPutOperationAsync(K key, V value) { return commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_BOOLEAN, "local insertable = false; " - + "local v = redis.call('hget', KEYS[1], ARGV[2]); " - + "if v == false then " - + "insertable = true; " - + "else " - + "local t, val = struct.unpack('dLc0', v); " - + "local expireDate = 92233720368547758; " - + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]); " - + "if expireDateScore ~= false then " - + "expireDate = tonumber(expireDateScore) " - + "end; " - + "if t ~= 0 then " - + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]); " - + "if expireIdle ~= false then " - + "expireDate = math.min(expireDate, tonumber(expireIdle)) " - + "end; " - + "end; " - + "if expireDate <= tonumber(ARGV[1]) then " - + "insertable = true; " - + "end; " - + "end; " + - - "local val = struct.pack('dLc0', 0, string.len(ARGV[3]), ARGV[3]); " - + "redis.call('hset', KEYS[1], ARGV[2], val); " + - - // last access time - "local maxSize = tonumber(ARGV[4]);" + - "if maxSize ~= 0 then" + - " local currentTime = tonumber(ARGV[1]);" + - " local lastAccessTimeSetName = KEYS[6];" + - " redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[2]);" + - " local cacheSize = tonumber(redis.call('hlen', KEYS[1]));" + - " if cacheSize >= maxSize then" + - " local lruItems = redis.call('zrange', lastAccessTimeSetName, 0, cacheSize - maxSize);" + - " for index, lruItem in ipairs(lruItems) do" + - " if lruItem then" + - " local lruItemValue = redis.call('hget', KEYS[1], lruItem);" + - " redis.call('hdel', KEYS[1], lruItem);" + - " redis.call('zrem', KEYS[2], lruItem);" + - " redis.call('zrem', KEYS[3], lruItem);" + - " redis.call('zrem', lastAccessTimeSetName, lruItem);" + - " local removedChannelName = KEYS[7];" + - " local msg = struct.pack('Lc0Lc0', string.len(lruItem), lruItem, string.len(lruItemValue), lruItemValue);" + - " redis.call('publish', removedChannelName, msg);" + - " end;" + - " end" + - " end;" + - "end;" - - + "if insertable == true then " - + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3]); " - + "redis.call('publish', KEYS[4], msg); " - + "return 1;" - + "else " - + "local t, val = struct.unpack('dLc0', v); " - + "local msg = struct.pack('Lc0Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3], string.len(val), val); " - + "redis.call('publish', KEYS[5], msg); " - + "return 0;" - + "end;", - Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key), - getUpdatedChannelNameByKey(key), getLastAccessTimeSetNameByKey(key), getRemovedChannelNameByKey(key)), - System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value), maxSize); + + "local v = redis.call('hget', KEYS[1], ARGV[2]); " + + "if v == false then " + + "insertable = true; " + + "else " + + "local t, val = struct.unpack('dLc0', v); " + + "local expireDate = 92233720368547758; " + + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]); " + + "if expireDateScore ~= false then " + + "expireDate = tonumber(expireDateScore) " + + "end; " + + "if t ~= 0 then " + + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]); " + + "if expireIdle ~= false then " + + "expireDate = math.min(expireDate, tonumber(expireIdle)) " + + "end; " + + "end; " + + "if expireDate <= tonumber(ARGV[1]) then " + + "insertable = true; " + + "end; " + + "end; " + + + "local val = struct.pack('dLc0', 0, string.len(ARGV[3]), ARGV[3]); " + + "redis.call('hset', KEYS[1], ARGV[2], val); " + + + "if insertable == true then " + + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3]); " + + "redis.call('publish', KEYS[4], msg); " + + "return 1;" + + "else " + + "local t, val = struct.unpack('dLc0', v); " + + "local msg = struct.pack('Lc0Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3], string.len(val), val); " + + "redis.call('publish', KEYS[5], msg); " + + "return 0;" + + "end;", + Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key), getUpdatedChannelNameByKey(key)), + System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value)); } @Override protected RFuture fastPutIfAbsentOperationAsync(K key, V value) { return commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_BOOLEAN, "local value = redis.call('hget', KEYS[1], ARGV[2]); " - + "local lastAccessTimeSetName = KEYS[5];" - + "local maxSize = tonumber(ARGV[4]);" - + "local currentTime = tonumber(ARGV[1]);" - + "if value == false then " - + "local val = struct.pack('dLc0', 0, string.len(ARGV[3]), ARGV[3]); " - + "redis.call('hset', KEYS[1], ARGV[2], val); " - + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3]); " - + "redis.call('publish', KEYS[4], msg); "+ - - // last access time - - "if maxSize ~= 0 then" + - " redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[2]);" + - " local cacheSize = tonumber(redis.call('hlen', KEYS[1]));" + - " if cacheSize >= maxSize then" + - " local lruItems = redis.call('zrange', lastAccessTimeSetName, 0, cacheSize - maxSize);" + - " for index, lruItem in ipairs(lruItems) do" + - " if lruItem then" + - " local lruItemValue = redis.call('hget', KEYS[1], lruItem);" + - " redis.call('hdel', KEYS[1], lruItem);" + - " redis.call('zrem', KEYS[2], lruItem);" + - " redis.call('zrem', KEYS[3], lruItem);" + - " redis.call('zrem', lastAccessTimeSetName, lruItem);" + - " local removedChannelName = KEYS[6];" + - " local msg = struct.pack('Lc0Lc0', string.len(lruItem), lruItem, string.len(lruItemValue), lruItemValue);" + - " redis.call('publish', removedChannelName, msg);" + - " end;" + - " end" + - " end;" + - "end;" - - + "return 1; " - + "end; " - + "if maxSize ~= 0 then" - + " redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[2]);" - + "end;" - + "local t, val = struct.unpack('dLc0', value); " - + "local expireDate = 92233720368547758; " + - "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]); " - + "if expireDateScore ~= false then " - + "expireDate = tonumber(expireDateScore) " - + "end; " - + "if t ~= 0 then " - + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]); " - + "if expireIdle ~= false then " - + "if tonumber(expireIdle) > tonumber(ARGV[1]) then " - + "local value = struct.pack('dLc0', t, string.len(val), val); " - + "redis.call('hset', KEYS[1], ARGV[2], value); " - + "redis.call('zadd', KEYS[3], t + tonumber(ARGV[1]), ARGV[2]); " - + "end; " - + "expireDate = math.min(expireDate, tonumber(expireIdle)) " - + "end; " - + "end; " - + "if expireDate > tonumber(ARGV[1]) then " - + "return 0; " - + "end; " - - + "redis.call('zrem', KEYS[2], ARGV[2]); " - + "redis.call('zrem', KEYS[3], ARGV[2]); " - + "local val = struct.pack('dLc0', 0, string.len(ARGV[3]), ARGV[3]); " - + "redis.call('hset', KEYS[1], ARGV[2], val); " - - + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3]); " - + "redis.call('publish', KEYS[4], msg); " - + "return 1; ", - Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key), - getLastAccessTimeSetNameByKey(key), getRemovedChannelNameByKey(key)), - System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value), maxSize); + + "if value == false then " + + "local val = struct.pack('dLc0', 0, string.len(ARGV[3]), ARGV[3]); " + + "redis.call('hset', KEYS[1], ARGV[2], val); " + + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3]); " + + "redis.call('publish', KEYS[4], msg); " + + "return 1; " + + "end; " + + "local t, val = struct.unpack('dLc0', value); " + + "local expireDate = 92233720368547758; " + + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]); " + + "if expireDateScore ~= false then " + + "expireDate = tonumber(expireDateScore) " + + "end; " + + "if t ~= 0 then " + + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]); " + + "if expireIdle ~= false then " + + "if tonumber(expireIdle) > tonumber(ARGV[1]) then " + + "local value = struct.pack('dLc0', t, string.len(val), val); " + + "redis.call('hset', KEYS[1], ARGV[2], value); " + + "redis.call('zadd', KEYS[3], t + tonumber(ARGV[1]), ARGV[2]); " + + "end; " + + "expireDate = math.min(expireDate, tonumber(expireIdle)) " + + "end; " + + "end; " + + "if expireDate > tonumber(ARGV[1]) then " + + "return 0; " + + "end; " + + + "redis.call('zrem', KEYS[2], ARGV[2]); " + + "redis.call('zrem', KEYS[3], ARGV[2]); " + + "local val = struct.pack('dLc0', 0, string.len(ARGV[3]), ARGV[3]); " + + "redis.call('hset', KEYS[1], ARGV[2], val); " + + + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3]); " + + "redis.call('publish', KEYS[4], msg); " + + "return 1; ", + Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key)), + System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value)); } - + @Override - public boolean fastPutIfAbsent(K key, V value, long ttl, TimeUnit ttlUnit) { - return fastPutIfAbsent(key, value, ttl, ttlUnit, 0, null); - } - + public boolean fastPutIfAbsent(K key, V value, long ttl, TimeUnit ttlUnit) { + return fastPutIfAbsent(key, value, ttl, ttlUnit, 0, null); + } + @Override public boolean fastPutIfAbsent(K key, V value, long ttl, TimeUnit ttlUnit, long maxIdleTime, TimeUnit maxIdleUnit) { - return get(fastPutIfAbsentAsync(key, value, ttl, ttlUnit, maxIdleTime, maxIdleUnit)); + return get(fastPutIfAbsentAsync(key, value, ttl, ttlUnit, maxIdleTime, maxIdleUnit)); } - + @Override - public RFuture fastPutIfAbsentAsync(final K key, final V value, long ttl, TimeUnit ttlUnit, long maxIdleTime, TimeUnit maxIdleUnit) { + public RFuture fastPutIfAbsentAsync(final K key, final V value, long ttl, TimeUnit ttlUnit, long maxIdleTime, TimeUnit maxIdleUnit) { checkKey(key); checkValue(value); - - if (ttl < 0) { + + if (ttl < 0) { throw new IllegalArgumentException("ttl can't be negative"); } if (maxIdleTime < 0) { @@ -1399,81 +1138,62 @@ public class RedissonMapCache extends RedissonMap implements RMapCac } RFuture future = commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_BOOLEAN, - "local insertable = false;" + - "local value = redis.call('hget', KEYS[1], ARGV[5]);" + - "if value == false then" + - " insertable = true;" + - "else" + - " if insertable == false then" + - " local t, val = struct.unpack('dLc0', value);" + - " local expireDate = 92233720368547758;" + - " local expireDateScore = redis.call('zscore', KEYS[2], ARGV[5]);" + - " if expireDateScore ~= false then" + - " expireDate = tonumber(expireDateScore)" + - " end;" + - " if t ~= 0 then" + - " local expireIdle = redis.call('zscore', KEYS[3], ARGV[5]);" + - " if expireIdle ~= false then" + - " expireDate = math.min(expireDate, tonumber(expireIdle))" + - " end;" + - " end;" + - " if expireDate <= tonumber(ARGV[1]) then" + - " insertable = true;" + - " end;" + - " end;" + - "end;" + - "if insertable == true then" + - " -- ttl" + - " if tonumber(ARGV[2]) > 0 then" + - " redis.call('zadd', KEYS[2], ARGV[2], ARGV[5]);" + - " else" + - " redis.call('zrem', KEYS[2], ARGV[5]);" + - " end;" + - " -- idle" + - " if tonumber(ARGV[3]) > 0 then" + - " redis.call('zadd', KEYS[3], ARGV[3], ARGV[5]);" + - " else" + - " redis.call('zrem', KEYS[3], ARGV[5]);" + - " end;" + - " -- last access time" + - " local maxSize = tonumber(ARGV[7]);" + - " if maxSize ~= 0 then" + - " local currentTime = tonumber(ARGV[1]);" + - " local lastAccessTimeSetName = KEYS[5];" + - " redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[5]);" + - " local cacheSize = tonumber(redis.call('hlen', KEYS[1]));" + - " if cacheSize >= maxSize then" + - " local lruItems = redis.call('zrange', lastAccessTimeSetName, 0, cacheSize - maxSize);" + - " for index, lruItem in ipairs(lruItems) do" + - " if lruItem then" + - " local lruItemValue = redis.call('hget', KEYS[1], lruItem);" + - " redis.call('hdel', KEYS[1], lruItem);" + - " redis.call('zrem', KEYS[2], lruItem);" + - " redis.call('zrem', KEYS[3], lruItem);" + - " redis.call('zrem', lastAccessTimeSetName, lruItem);" + - " local removedChannelName = KEYS[6];" + - " local msg = struct.pack('Lc0Lc0', string.len(lruItem), lruItem, string.len(lruItemValue), lruItemValue);" + - " redis.call('publish', removedChannelName, msg);" + - " end;" + - " end" + - " end;" + - " end;" + - " -- value" + - " local val = struct.pack('dLc0', ARGV[4], string.len(ARGV[6]), ARGV[6]);" + - " redis.call('hset', KEYS[1], ARGV[5], val);" + - " local msg = struct.pack('Lc0Lc0', string.len(ARGV[5]), ARGV[5], string.len(ARGV[6]), ARGV[6]);" + - " redis.call('publish', KEYS[4], msg);" + - " return 1;" + - "else" + - " return 0;" + - "end;", - Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key), - getLastAccessTimeSetNameByKey(key), getRemovedChannelNameByKey(key)), - System.currentTimeMillis(), ttlTimeout, maxIdleTimeout, maxIdleDelta, encodeMapKey(key), encodeMapValue(value), maxSize); + "local insertable = false; " + + "local value = redis.call('hget', KEYS[1], ARGV[5]); " + + "if value == false then " + + "insertable = true; " + + "else " + + "if insertable == false then " + + "local t, val = struct.unpack('dLc0', value); " + + "local expireDate = 92233720368547758; " + + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[5]); " + + "if expireDateScore ~= false then " + + "expireDate = tonumber(expireDateScore) " + + "end; " + + "if t ~= 0 then " + + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[5]); " + + "if expireIdle ~= false then " + + "expireDate = math.min(expireDate, tonumber(expireIdle)) " + + "end; " + + "end; " + + "if expireDate <= tonumber(ARGV[1]) then " + + "insertable = true; " + + "end; " + + "end; " + + "end; " + + + "if insertable == true then " + // ttl + + "if tonumber(ARGV[2]) > 0 then " + + "redis.call('zadd', KEYS[2], ARGV[2], ARGV[5]); " + + "else " + + "redis.call('zrem', KEYS[2], ARGV[5]); " + + "end; " + + // idle + + "if tonumber(ARGV[3]) > 0 then " + + "redis.call('zadd', KEYS[3], ARGV[3], ARGV[5]); " + + "else " + + "redis.call('zrem', KEYS[3], ARGV[5]); " + + "end; " + + // value + + "local val = struct.pack('dLc0', ARGV[4], string.len(ARGV[6]), ARGV[6]); " + + "redis.call('hset', KEYS[1], ARGV[5], val); " + + + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[5]), ARGV[5], string.len(ARGV[6]), ARGV[6]); " + + "redis.call('publish', KEYS[4], msg); " + + + "return 1; " + + "else " + + "return 0; " + + "end; ", + Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key)), + System.currentTimeMillis(), ttlTimeout, maxIdleTimeout, maxIdleDelta, encodeMapKey(key), encodeMapValue(value)); if (hasNoWriter()) { return future; } - + MapWriterTask listener = new MapWriterTask() { @Override protected void execute() { @@ -1487,75 +1207,70 @@ public class RedissonMapCache extends RedissonMap implements RMapCac return mapWriterFuture(future, listener); } - private String getLastAccessTimeSetNameByKey(Object key) { - return prefixName("redisson__last_access__set", getName(key)); - } - - private String getLastAccessTimeSetName() { - return prefixName("redisson__last_access__set", getName()); - } - @Override protected RFuture replaceOperationAsync(K key, V oldValue, V newValue) { return commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_BOOLEAN, - "local v = redis.call('hget', KEYS[1], ARGV[2]);" + - "if v == false then" + - " return 0;" + - "end;" + - "local expireDate = 92233720368547758;" + - "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]);" + - "if expireDateScore ~= false then" + - " expireDate = tonumber(expireDateScore)" + - "end;" + - "" + - "local t, val = struct.unpack('dLc0', v);" + - "if t ~= 0 then" + - " local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]);" + - " if expireIdle ~= false then" + - " expireDate = math.min(expireDate, tonumber(expireIdle))" + - " end;" + - "end;" + - "if expireDate > tonumber(ARGV[1]) and val == ARGV[3] then" + - " local msg = struct.pack('Lc0Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[4]), ARGV[4], string.len(ARGV[3]), ARGV[3]);" + - " redis.call('publish', KEYS[4], msg);" + - "" + - " local value = struct.pack('dLc0', t, string.len(ARGV[4]), ARGV[4]);" + - " redis.call('hset', KEYS[1], ARGV[2], value);" + - " return 1;" + - "end;" + - "return 0;", - Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getUpdatedChannelNameByKey(key)), - System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(oldValue), encodeMapValue(newValue)); + "local v = redis.call('hget', KEYS[1], ARGV[2]); " + + "if v == false then " + + "return 0;" + + "end;" + + "local expireDate = 92233720368547758; " + + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]); " + + "if expireDateScore ~= false then " + + "expireDate = tonumber(expireDateScore) " + + "end; " + + + "local t, val = struct.unpack('dLc0', v); " + + "if t ~= 0 then " + + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]); " + + "if expireIdle ~= false then " + + "expireDate = math.min(expireDate, tonumber(expireIdle)) " + + "end; " + + "end; " + + "if expireDate > tonumber(ARGV[1]) and val == ARGV[3] then " + + "local msg = struct.pack('Lc0Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[4]), ARGV[4], string.len(ARGV[3]), ARGV[3]); " + + "redis.call('publish', KEYS[4], msg); " + + + "local value = struct.pack('dLc0', t, string.len(ARGV[4]), ARGV[4]); " + + "redis.call('hset', KEYS[1], ARGV[2], value); " + + "return 1; " + + "end; " + + "return 0; ", + Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getUpdatedChannelNameByKey(key)), + System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(oldValue), encodeMapValue(newValue)); } @Override protected RFuture replaceOperationAsync(K key, V value) { return commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_MAP_VALUE, - "local value = redis.call('hget', KEYS[1], ARGV[2]);" + - "if value == false then" + - " return nil;" + - "end;" + - "local t, val = struct.unpack('dLc0', value);" + - "local expireDate = 92233720368547758;" + - "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]);" + - "if expireDateScore ~= false then" + - " expireDate = tonumber(expireDateScore)" + - "end;" + - "if t ~= 0 then" + - " local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]);" + - " if expireIdle ~= false then" + - " expireDate = math.min(expireDate, tonumber(expireIdle))" + - " end;" + - "end;" + - "if expireDate <= tonumber(ARGV[1]) then" + - " return nil;" + - "end;" + - "local value = struct.pack('dLc0', t, string.len(ARGV[3]), ARGV[3]);" + - "redis.call('hset', KEYS[1], ARGV[2], value);" + - "local msg = struct.pack('Lc0Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3], string.len(val), val);" + - "redis.call('publish', KEYS[4], msg);" + - "return val;", - Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getUpdatedChannelNameByKey(key)), + "local value = redis.call('hget', KEYS[1], ARGV[2]); " + + "if value == false then " + + "return nil; " + + "end; " + + "local t, val = struct.unpack('dLc0', value); " + + "local expireDate = 92233720368547758; " + + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]); " + + "if expireDateScore ~= false then " + + "expireDate = tonumber(expireDateScore) " + + "end; " + + "if t ~= 0 then " + + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]); " + + "if expireIdle ~= false then " + + "expireDate = math.min(expireDate, tonumber(expireIdle)) " + + "end; " + + "end; " + + "if expireDate <= tonumber(ARGV[1]) then " + + "return nil; " + + "end; " + + + "local value = struct.pack('dLc0', t, string.len(ARGV[3]), ARGV[3]); " + + "redis.call('hset', KEYS[1], ARGV[2], value); " + + + "local msg = struct.pack('Lc0Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3], string.len(val), val); " + + "redis.call('publish', KEYS[4], msg); " + + + "return val; ", + Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getUpdatedChannelNameByKey(key)), System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value)); } @@ -1570,7 +1285,7 @@ public class RedissonMapCache extends RedissonMap implements RMapCac if (t.getValue() == null) { throw new NullPointerException("map value can't be null"); } - + params.add(encodeMapKey(t.getKey())); params.add(encodeMapValue(t.getValue())); } @@ -1585,20 +1300,20 @@ public class RedissonMapCache extends RedissonMap implements RMapCac + "local val = struct.pack('dLc0', 0, string.len(value), value); " + "ARGV[i] = val; " + "local key = ARGV[i-1];" - + + "local msg = struct.pack('Lc0Lc0', string.len(key), key, string.len(value), value); " + "redis.call('publish', KEYS[2], msg); " + "end;" + "end;", Arrays.asList(getName(), getCreatedChannelName()), params.toArray()); } - + @Override public int addListener(final MapEntryListener listener) { if (listener == null) { throw new NullPointerException(); } - + if (listener instanceof EntryRemovedListener) { RTopic> topic = redisson.getTopic(getRemovedChannelName(), new MapCacheEventCodec(codec)); return topic.addListener(new MessageListener>() { @@ -1609,7 +1324,7 @@ public class RedissonMapCache extends RedissonMap implements RMapCac } }); } - + if (listener instanceof EntryCreatedListener) { RTopic> topic = redisson.getTopic(getCreatedChannelName(), new MapCacheEventCodec(codec)); return topic.addListener(new MessageListener>() { @@ -1620,7 +1335,7 @@ public class RedissonMapCache extends RedissonMap implements RMapCac } }); } - + if (listener instanceof EntryUpdatedListener) { RTopic> topic = redisson.getTopic(getUpdatedChannelName(), new MapCacheEventCodec(codec)); return topic.addListener(new MessageListener>() { @@ -1631,7 +1346,7 @@ public class RedissonMapCache extends RedissonMap implements RMapCac } }); } - + if (listener instanceof EntryExpiredListener) { RTopic> topic = redisson.getTopic(getExpiredChannelName(), new MapCacheEventCodec(codec)); return topic.addListener(new MessageListener>() { @@ -1642,70 +1357,60 @@ public class RedissonMapCache extends RedissonMap implements RMapCac } }); } - + throw new IllegalArgumentException("Wrong listener type " + listener.getClass()); } - + @Override public void removeListener(int listenerId) { RTopic> removedTopic = redisson.getTopic(getRemovedChannelName(), new MapCacheEventCodec(codec)); removedTopic.removeListener(listenerId); - + RTopic> createdTopic = redisson.getTopic(getCreatedChannelName(), new MapCacheEventCodec(codec)); createdTopic.removeListener(listenerId); - + RTopic> updatedTopic = redisson.getTopic(getUpdatedChannelName(), new MapCacheEventCodec(codec)); updatedTopic.removeListener(listenerId); - + RTopic> expiredTopic = redisson.getTopic(getExpiredChannelName(), new MapCacheEventCodec(codec)); expiredTopic.removeListener(listenerId); } @Override public RFuture deleteAsync() { - return commandExecutor.writeAsync(getName(), RedisCommands.DEL_OBJECTS, getName(), getTimeoutSetName(), getIdleSetName(), getLastAccessTimeSetName()); + return commandExecutor.writeAsync(getName(), RedisCommands.DEL_OBJECTS, getName(), getTimeoutSetName(), getIdleSetName()); } @Override public RFuture expireAsync(long timeToLive, TimeUnit timeUnit) { return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN, - "local maxSize = tonumber(ARGV[2]);" + - "if maxSize ~= 0 then" + - " redis.call('pexpire', KEYS[4], ARGV[1]);" + - "end;" + - "redis.call('zadd', KEYS[2], 92233720368547758, 'redisson__expiretag');" + - "redis.call('pexpire', KEYS[2], ARGV[1]); " + - "redis.call('zadd', KEYS[3], 92233720368547758, 'redisson__expiretag');" + - "redis.call('pexpire', KEYS[3], ARGV[1]); " + - "return redis.call('pexpire', KEYS[1], ARGV[1]); ", - Arrays.asList(getName(), getTimeoutSetName(), getIdleSetName(), getLastAccessTimeSetName()), - timeUnit.toMillis(timeToLive), maxSize); + "redis.call('zadd', KEYS[2], 92233720368547758, 'redisson__expiretag');" + + "redis.call('pexpire', KEYS[2], ARGV[1]); " + + "redis.call('zadd', KEYS[3], 92233720368547758, 'redisson__expiretag');" + + "redis.call('pexpire', KEYS[3], ARGV[1]); " + + "return redis.call('pexpire', KEYS[1], ARGV[1]); ", + Arrays.asList(getName(), getTimeoutSetName(), getIdleSetName()), timeUnit.toMillis(timeToLive)); } @Override public RFuture expireAtAsync(long timestamp) { return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN, - "local maxSize = tonumber(ARGV[2]);" + - "if maxSize ~= 0 then" + - " redis.call('pexpire', KEYS[4], ARGV[1]);" + - "end;" + - "redis.call('zadd', KEYS[2], 92233720368547758, 'redisson__expiretag');" + - "redis.call('pexpireat', KEYS[2], ARGV[1]); " + - "redis.call('zadd', KEYS[3], 92233720368547758, 'redisson__expiretag');" + - "redis.call('pexpire', KEYS[3], ARGV[1]); " + - "return redis.call('pexpireat', KEYS[1], ARGV[1]); ", - Arrays.asList(getName(), getTimeoutSetName(), getIdleSetName(), getLastAccessTimeSetName()), - timestamp, maxSize); + "redis.call('zadd', KEYS[2], 92233720368547758, 'redisson__expiretag');" + + "redis.call('pexpireat', KEYS[2], ARGV[1]); " + + "redis.call('zadd', KEYS[3], 92233720368547758, 'redisson__expiretag');" + + "redis.call('pexpire', KEYS[3], ARGV[1]); " + + "return redis.call('pexpireat', KEYS[1], ARGV[1]); ", + Arrays.asList(getName(), getTimeoutSetName(), getIdleSetName()), timestamp); } @Override public RFuture clearExpireAsync() { return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN, - "redis.call('zrem', KEYS[2], 'redisson__expiretag'); " + - "redis.call('persist', KEYS[2]); " + - "redis.call('zrem', KEYS[3], 'redisson__expiretag'); " + - "redis.call('persist', KEYS[3]); " + - "return redis.call('persist', KEYS[1]); ", + "redis.call('zrem', KEYS[2], 'redisson__expiretag'); " + + "redis.call('persist', KEYS[2]); " + + "redis.call('zrem', KEYS[3], 'redisson__expiretag'); " + + "redis.call('persist', KEYS[3]); " + + "return redis.call('persist', KEYS[1]); ", Arrays.asList(getName(), getTimeoutSetName(), getIdleSetName())); } @@ -1713,41 +1418,36 @@ public class RedissonMapCache extends RedissonMap implements RMapCac public RFuture> readAllKeySetAsync() { return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_MAP_KEY_SET, "local s = redis.call('hgetall', KEYS[1]); " - + "local result = {}; " - + "for i, v in ipairs(s) do " - + "if i % 2 == 0 then " - + "local t, val = struct.unpack('dLc0', v); " - + "local key = s[i-1];" + - "local expireDate = 92233720368547758; " + - "local expireDateScore = redis.call('zscore', KEYS[2], key); " - + "if expireDateScore ~= false then " - + "expireDate = tonumber(expireDateScore) " - + "end; " - + "if t ~= 0 then " - + "local expireIdle = redis.call('zscore', KEYS[3], key); " - + "if expireIdle ~= false then " + + "local result = {}; " + + "for i, v in ipairs(s) do " + + "if i % 2 == 0 then " + + "local t, val = struct.unpack('dLc0', v); " + + "local key = s[i-1];" + + "local expireDate = 92233720368547758; " + + "local expireDateScore = redis.call('zscore', KEYS[2], key); " + + "if expireDateScore ~= false then " + + "expireDate = tonumber(expireDateScore) " + + "end; " + + "if t ~= 0 then " + + "local expireIdle = redis.call('zscore', KEYS[3], key); " + + "if expireIdle ~= false then " + "if tonumber(expireIdle) > tonumber(ARGV[1]) then " + "local value = struct.pack('dLc0', t, string.len(val), val); " + "redis.call('hset', KEYS[1], key, value); " + "redis.call('zadd', KEYS[3], t + tonumber(ARGV[1]), key); " - + "local maxSize = tonumber(ARGV[2]);" - + "if maxSize ~= 0 then" - + " redis.call('zadd', KEYS[4], tonumber(ARGV[1]), key);" - + "end;" + "end; " + "expireDate = math.min(expireDate, tonumber(expireIdle)) " - + "end; " - + "end; " - + "if expireDate > tonumber(ARGV[1]) then " - + "table.insert(result, key); " - + "end; " + "end; " - + "end;" + - "return result;", - Arrays.asList(getName(), getTimeoutSetName(), getIdleSetName(), getLastAccessTimeSetName()), - System.currentTimeMillis(), maxSize); + + "end; " + + "if expireDate > tonumber(ARGV[1]) then " + + "table.insert(result, key); " + + "end; " + + "end; " + + "end;" + + "return result;", + Arrays.asList(getName(), getTimeoutSetName(), getIdleSetName()), System.currentTimeMillis()); } - + @Override public RFuture>> readAllEntrySetAsync() { return readAll(RedisCommands.EVAL_MAP_ENTRY); @@ -1756,40 +1456,35 @@ public class RedissonMapCache extends RedissonMap implements RMapCac private RFuture readAll(RedisCommand evalCommandType) { return commandExecutor.evalWriteAsync(getName(), codec, evalCommandType, "local s = redis.call('hgetall', KEYS[1]); " - + "local result = {}; " - + "for i, v in ipairs(s) do " - + "if i % 2 == 0 then " - + "local t, val = struct.unpack('dLc0', v); " - + "local key = s[i-1];" + - "local expireDate = 92233720368547758; " + - "local expireDateScore = redis.call('zscore', KEYS[2], key); " - + "if expireDateScore ~= false then " - + "expireDate = tonumber(expireDateScore) " - + "end; " - + "if t ~= 0 then " - + "local expireIdle = redis.call('zscore', KEYS[3], key); " - + "if expireIdle ~= false then " - + "if tonumber(expireIdle) > tonumber(ARGV[1]) then " - + "local value = struct.pack('dLc0', t, string.len(val), val); " - + "redis.call('hset', KEYS[1], key, value); " - + "redis.call('zadd', KEYS[3], t + tonumber(ARGV[1]), key); " - + "local maxSize = tonumber(ARGV[2]);" - + "if maxSize ~= 0 then" - + " redis.call('zadd', KEYS[4], tonumber(ARGV[1]), key);" - + "end;" - + "end; " - + "expireDate = math.min(expireDate, tonumber(expireIdle)) " - + "end; " - + "end; " - + "if expireDate > tonumber(ARGV[1]) then " - + "table.insert(result, key); " - + "table.insert(result, val); " + + "local result = {}; " + + "for i, v in ipairs(s) do " + + "if i % 2 == 0 then " + + "local t, val = struct.unpack('dLc0', v); " + + "local key = s[i-1];" + + "local expireDate = 92233720368547758; " + + "local expireDateScore = redis.call('zscore', KEYS[2], key); " + + "if expireDateScore ~= false then " + + "expireDate = tonumber(expireDateScore) " + + "end; " + + "if t ~= 0 then " + + "local expireIdle = redis.call('zscore', KEYS[3], key); " + + "if expireIdle ~= false then " + + "if tonumber(expireIdle) > tonumber(ARGV[1]) then " + + "local value = struct.pack('dLc0', t, string.len(val), val); " + + "redis.call('hset', KEYS[1], key, value); " + + "redis.call('zadd', KEYS[3], t + tonumber(ARGV[1]), key); " + "end; " + + "expireDate = math.min(expireDate, tonumber(expireIdle)) " + "end; " - + "end;" + - "return result;", - Arrays.asList(getName(), getTimeoutSetName(), getIdleSetName(), getLastAccessTimeSetName()), - System.currentTimeMillis(), maxSize); + + "end; " + + "if expireDate > tonumber(ARGV[1]) then " + + "table.insert(result, key); " + + "table.insert(result, val); " + + "end; " + + "end; " + + "end;" + + "return result;", + Arrays.asList(getName(), getTimeoutSetName(), getIdleSetName()), System.currentTimeMillis()); } @Override @@ -1802,27 +1497,23 @@ public class RedissonMapCache extends RedissonMap implements RMapCac public RFuture> readAllValuesAsync() { return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_MAP_VALUE_LIST, "local s = redis.call('hgetall', KEYS[1]); " - + "local result = {}; " - + "for i, v in ipairs(s) do " - + "if i % 2 == 0 then " - + "local t, val = struct.unpack('dLc0', v); " - + "local key = s[i-1];" + - "local expireDate = 92233720368547758; " + - "local expireDateScore = redis.call('zscore', KEYS[2], key); " - + "if expireDateScore ~= false then " - + "expireDate = tonumber(expireDateScore) " - + "end; " - + "if t ~= 0 then " + + "local result = {}; " + + "for i, v in ipairs(s) do " + + "if i % 2 == 0 then " + + "local t, val = struct.unpack('dLc0', v); " + + "local key = s[i-1];" + + "local expireDate = 92233720368547758; " + + "local expireDateScore = redis.call('zscore', KEYS[2], key); " + + "if expireDateScore ~= false then " + + "expireDate = tonumber(expireDateScore) " + + "end; " + + "if t ~= 0 then " + "local expireIdle = redis.call('zscore', KEYS[3], key); " + "if expireIdle ~= false then " + "if tonumber(expireIdle) > tonumber(ARGV[1]) then " + "local value = struct.pack('dLc0', t, string.len(val), val); " + "redis.call('hset', KEYS[1], key, value); " + "redis.call('zadd', KEYS[3], t + tonumber(ARGV[1]), key); " - + "local maxSize = tonumber(ARGV[2]);" - + "if maxSize ~= 0 then" - + " redis.call('zadd', KEYS[4], tonumber(ARGV[1]), key);" - + "end;" + "end; " + "expireDate = math.min(expireDate, tonumber(expireIdle)) " + "end; " @@ -1830,10 +1521,9 @@ public class RedissonMapCache extends RedissonMap implements RMapCac + "if expireDate > tonumber(ARGV[1]) then " + "table.insert(result, val); " + "end; " - + "end; " - + "end;" + - "return result;", - Arrays.asList(getName(), getTimeoutSetName(), getIdleSetName(), getLastAccessTimeSetName()), - System.currentTimeMillis(), maxSize); + + "end; " + + "end;" + + "return result;", + Arrays.asList(getName(), getTimeoutSetName(), getIdleSetName()), System.currentTimeMillis()); } } diff --git a/redisson/src/main/java/org/redisson/api/MapOptions.java b/redisson/src/main/java/org/redisson/api/MapOptions.java index 2b45a69ba..0f49a3fcb 100644 --- a/redisson/src/main/java/org/redisson/api/MapOptions.java +++ b/redisson/src/main/java/org/redisson/api/MapOptions.java @@ -49,7 +49,6 @@ public class MapOptions { private MapWriter writer; private WriteMode writeMode = WriteMode.WRITE_THROUGH; private int writeBehindThreads = 1; - private int maxSize = 0; protected MapOptions() { } @@ -135,20 +134,5 @@ public class MapOptions { public MapLoader getLoader() { return loader; } - - /** - * Sets max size of the map. - *

- * Currently only RedissonMapCache is supported. - * - * @param maxSize - max size - * @return MapOptions instance - */ - public MapOptions maxSize(int maxSize) { - this.maxSize = maxSize; - return this; - } - public int getMaxSize() { - return maxSize; - } + } diff --git a/redisson/src/test/java/org/redisson/RedissonMapCacheTest.java b/redisson/src/test/java/org/redisson/RedissonMapCacheTest.java index ee019494c..89e3a4d4c 100644 --- a/redisson/src/test/java/org/redisson/RedissonMapCacheTest.java +++ b/redisson/src/test/java/org/redisson/RedissonMapCacheTest.java @@ -213,31 +213,6 @@ public class RedissonMapCacheTest extends BaseMapTest { expected.put("3", "33"); assertThat(store).isEqualTo(expected); } - - @Test - public void testFastPutMaxSize() { - final int maxSize = 2; - Map store = new LinkedHashMap() { - @Override - protected boolean removeEldestEntry(Entry eldest) { - return size() > maxSize; - } - }; - MapOptions options = MapOptions.defaults().writer(createMapWriter(store)); - options.maxSize(maxSize); - RMapCache map = redisson.getMapCache("test", options); - - map.fastPut("1", "11", 10, TimeUnit.SECONDS); - map.fastPut("2", "22", 10, TimeUnit.SECONDS); - map.fastPut("3", "33", 10, TimeUnit.SECONDS); - - assertThat(map.size()).isEqualTo(maxSize); - - Map expected = new HashMap<>(); - expected.put("2", "22"); - expected.put("3", "33"); - assertThat(store).isEqualTo(expected); - } @Test public void testOrdering() {