RMapCache.trySetMaxSize method added. #1027

pull/1034/merge
Nikita 8 years ago
parent 39c4b29565
commit 6043b1f7c1

@ -15,9 +15,16 @@
*/ */
package org.redisson; package org.redisson;
import io.netty.buffer.ByteBuf; import java.math.BigDecimal;
import io.netty.util.concurrent.Future; import java.net.InetSocketAddress;
import io.netty.util.concurrent.FutureListener; 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.MapOptions;
import org.redisson.api.RFuture; import org.redisson.api.RFuture;
import org.redisson.api.RMapCache; import org.redisson.api.RMapCache;
@ -51,15 +58,9 @@ import org.redisson.command.CommandAsyncExecutor;
import org.redisson.connection.decoder.MapGetAllDecoder; import org.redisson.connection.decoder.MapGetAllDecoder;
import org.redisson.eviction.EvictionScheduler; import org.redisson.eviction.EvictionScheduler;
import java.math.BigDecimal; import io.netty.buffer.ByteBuf;
import java.net.InetSocketAddress; import io.netty.util.concurrent.Future;
import java.util.ArrayList; import io.netty.util.concurrent.FutureListener;
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;
/** /**
* <p>Map-based cache with ability to set TTL for each entry via * <p>Map-based cache with ability to set TTL for each entry via
@ -82,32 +83,39 @@ import java.util.concurrent.TimeUnit;
*/ */
public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCache<K, V> { public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCache<K, V> {
private final int maxSize;
public RedissonMapCache(EvictionScheduler evictionScheduler, CommandAsyncExecutor commandExecutor, public RedissonMapCache(EvictionScheduler evictionScheduler, CommandAsyncExecutor commandExecutor,
String name, RedissonClient redisson, MapOptions<K, V> options) { String name, RedissonClient redisson, MapOptions<K, V> options) {
super(commandExecutor, name, redisson, options); super(commandExecutor, name, redisson, options);
evictionScheduler.schedule(getName(), getTimeoutSetName(), getIdleSetName(), getExpiredChannelName()); 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, public RedissonMapCache(Codec codec, EvictionScheduler evictionScheduler, CommandAsyncExecutor commandExecutor,
String name, RedissonClient redisson, MapOptions<K, V> options) { String name, RedissonClient redisson, MapOptions<K, V> options) {
super(codec, commandExecutor, name, redisson, options); super(codec, commandExecutor, name, redisson, options);
evictionScheduler.schedule(getName(), getTimeoutSetName(), getIdleSetName(), getExpiredChannelName()); evictionScheduler.schedule(getName(), getTimeoutSetName(), getIdleSetName(), getExpiredChannelName());
}
if (options != null) { @Override
this.maxSize = options.getMaxSize(); public boolean trySetMaxSize(int permits) {
} else { return get(trySetMaxSizeAsync(permits));
this.maxSize = 0; }
@Override
public RFuture<Boolean> trySetMaxSizeAsync(int maxSize) {
if (maxSize <= 0) {
throw new IllegalArgumentException("maxSize should be greater than zero");
} }
return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
"local value = redis.call('hget', KEYS[1], 'max-size'); " +
"if (value == false) then "
+ "redis.call('hset', KEYS[1], 'max-size', ARGV[1]); "
+ "return 1;"
+ "end;"
+ "return 0;",
Arrays.<Object>asList(getOptionsName()), maxSize);
} }
@Override @Override
public RFuture<Boolean> containsKeyAsync(Object key) { public RFuture<Boolean> containsKeyAsync(Object key) {
checkKey(key); checkKey(key);
@ -117,8 +125,8 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
"local expireDate = 92233720368547758; " + "local expireDate = 92233720368547758; " +
"if value ~= false then " + "if value ~= false then " +
"" + "" +
" local maxSize = tonumber(ARGV[3]); " + " local maxSize = tonumber(redis.call('hget', KEYS[5], 'max-size')); " +
" if maxSize ~= 0 then " + " if maxSize ~= nil and maxSize ~= 0 then " +
" redis.call('zadd', KEYS[4], tonumber(ARGV[1]), ARGV[2]); " + " redis.call('zadd', KEYS[4], tonumber(ARGV[1]), ARGV[2]); " +
" end;" + " end;" +
"" + "" +
@ -144,8 +152,8 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
" return 1;" + " return 1;" +
"end;" + "end;" +
"return 0; ", "return 0; ",
Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getLastAccessTimeSetNameByKey(key)), Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getLastAccessTimeSetNameByKey(key), getOptionsName()),
System.currentTimeMillis(), encodeMapKey(key), maxSize); System.currentTimeMillis(), encodeMapKey(key));
} }
@Override @Override
@ -160,8 +168,8 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
" if ARGV[2] == val then " + " if ARGV[2] == val then " +
" local key = s[i - 1]; " + " local key = s[i - 1]; " +
"" + "" +
" local maxSize = tonumber(ARGV[3]); " + " local maxSize = tonumber(redis.call('hget', KEYS[5], 'max-size')); " +
" if maxSize ~= 0 then " + " if maxSize ~= nil and maxSize ~= 0 then " +
" redis.call('zadd', KEYS[4], tonumber(ARGV[1]), key); " + " redis.call('zadd', KEYS[4], tonumber(ARGV[1]), key); " +
" end; " + " end; " +
"" + "" +
@ -189,30 +197,34 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
" end;" + " end;" +
"end;" + "end;" +
"return 0;", "return 0;",
Arrays.<Object>asList(getName(), getTimeoutSetName(), getIdleSetName(), getLastAccessTimeSetName()), Arrays.<Object>asList(getName(), getTimeoutSetName(), getIdleSetName(), getLastAccessTimeSetName(), getOptionsName()),
System.currentTimeMillis(), encodeMapValue(value), maxSize); System.currentTimeMillis(), encodeMapValue(value));
} }
@Override @Override
protected RFuture<Map<K, V>> getAllOperationAsync(Set<K> keys) { protected RFuture<Map<K, V>> getAllOperationAsync(Set<K> keys) {
List<Object> args = new ArrayList<Object>(keys.size() + 2); List<Object> args = new ArrayList<Object>(keys.size() + 1);
List<Object> plainKeys = new ArrayList<Object>(keys.size());
args.add(System.currentTimeMillis()); args.add(System.currentTimeMillis());
args.add(maxSize); for (K key : keys) {
args.addAll(keys); plainKeys.add(key);
args.add(encodeMapKey(key));
}
return commandExecutor.evalWriteAsync(getName(), codec, new RedisCommand<Map<Object, Object>>("EVAL", new MapGetAllDecoder(args, 2), 8, ValueType.MAP_KEY, ValueType.MAP_VALUE), return commandExecutor.evalWriteAsync(getName(), codec, new RedisCommand<Map<Object, Object>>("EVAL", new MapGetAllDecoder(plainKeys, 0), ValueType.MAP_VALUE),
"local expireHead = redis.call('zrange', KEYS[2], 0, 0, 'withscores'); " + "local expireHead = redis.call('zrange', KEYS[2], 0, 0, 'withscores'); " +
"local currentTime = tonumber(table.remove(ARGV, 1)); " + // index is the first parameter "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 hasExpire = #expireHead == 2 and tonumber(expireHead[2]) <= currentTime; " +
"local map = redis.call('hmget', KEYS[1], unpack(ARGV)); " + "local map = redis.call('hmget', KEYS[1], unpack(ARGV)); " +
"local maxSize = tonumber(redis.call('hget', KEYS[5], 'max-size'));" +
"for i = #map, 1, -1 do " + "for i = #map, 1, -1 do " +
" local value = map[i]; " + " local value = map[i]; " +
" if value ~= false then " + " if value ~= false then " +
" local key = ARGV[i]; " + " local key = ARGV[i]; " +
" local t, val = struct.unpack('dLc0', value); " + " local t, val = struct.unpack('dLc0', value); " +
" map[i] = val; " + " map[i] = val; " +
" if maxSize ~= 0 then " + " if maxSize ~= nil and maxSize ~= 0 then " +
" redis.call('zadd', KEYS[4], currentTime, key); " + " redis.call('zadd', KEYS[4], currentTime, key); " +
" end; " + " end; " +
" if hasExpire then " + " if hasExpire then " +
@ -236,7 +248,8 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
" end; " + " end; " +
"end; " + "end; " +
"return map;", "return map;",
Arrays.<Object>asList(getName(), getTimeoutSetName(), getIdleSetName(), getLastAccessTimeSetName()), args.toArray()); Arrays.<Object>asList(getName(), getTimeoutSetName(), getIdleSetName(), getLastAccessTimeSetName(), getOptionsName()),
args.toArray());
} }
@Override @Override
@ -328,8 +341,8 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
+ "end; " + "end; "
// last access time // last access time
+ "local maxSize = tonumber(ARGV[7]); " + + "local maxSize = tonumber(redis.call('hget', KEYS[7], 'max-size')); " +
"if maxSize ~= 0 then " + "if maxSize ~= nil and maxSize ~= 0 then " +
" local currentTime = tonumber(ARGV[1]); " + " local currentTime = tonumber(ARGV[1]); " +
" local lastAccessTimeSetName = KEYS[5]; " + " local lastAccessTimeSetName = KEYS[5]; " +
" redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[5]); " + " redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[5]); " +
@ -365,8 +378,8 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
+ "return val; " + "return val; "
+ "end; ", + "end; ",
Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key), Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key),
getLastAccessTimeSetNameByKey(key), getRemovedChannelNameByKey(key)), getLastAccessTimeSetNameByKey(key), getRemovedChannelNameByKey(key), getOptionsName(key)),
System.currentTimeMillis(), ttlTimeout, maxIdleTimeout, maxIdleDelta, encodeMapKey(key), encodeMapValue(value), maxSize); System.currentTimeMillis(), ttlTimeout, maxIdleTimeout, maxIdleDelta, encodeMapKey(key), encodeMapValue(value));
if (hasNoWriter()) { if (hasNoWriter()) {
return future; return future;
} }
@ -411,8 +424,8 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
+ "if val == ARGV[3] then " + "if val == ARGV[3] then "
+ "redis.call('zrem', KEYS[2], ARGV[2]); " + "redis.call('zrem', KEYS[2], ARGV[2]); "
+ "redis.call('zrem', KEYS[3], ARGV[2]); " + "redis.call('zrem', KEYS[3], ARGV[2]); "
+ "local maxSize = tonumber(ARGV[4]); " + + "local maxSize = tonumber(redis.call('hget', KEYS[6], 'max-size')); " +
"if maxSize ~= 0 then " + "if maxSize ~= nil and maxSize ~= 0 then " +
" redis.call('zrem', KEYS[5], ARGV[2]); " + " redis.call('zrem', KEYS[5], ARGV[2]); " +
"end; " "end; "
+ "redis.call('hdel', KEYS[1], ARGV[2]); " + "redis.call('hdel', KEYS[1], ARGV[2]); "
@ -423,8 +436,8 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
+ "return 0; " + "return 0; "
+ "end", + "end",
Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getRemovedChannelNameByKey(key), Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getRemovedChannelNameByKey(key),
getLastAccessTimeSetNameByKey(key)), getLastAccessTimeSetNameByKey(key), getOptionsName(key)),
System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value), maxSize); System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value));
} }
@Override @Override
@ -456,13 +469,13 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
+ "if expireDate <= tonumber(ARGV[1]) then " + "if expireDate <= tonumber(ARGV[1]) then "
+ "return nil; " + "return nil; "
+ "end; " + "end; "
+ "local maxSize = tonumber(ARGV[3]); " + + "local maxSize = tonumber(redis.call('hget', KEYS[5], 'max-size')); " +
"if maxSize ~= 0 then " + "if maxSize ~= nil and maxSize ~= 0 then " +
" redis.call('zadd', KEYS[4], tonumber(ARGV[1]), ARGV[2]); " + " redis.call('zadd', KEYS[4], tonumber(ARGV[1]), ARGV[2]); " +
"end; " "end; "
+ "return val; ", + "return val; ",
Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getLastAccessTimeSetNameByKey(key)), Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getLastAccessTimeSetNameByKey(key), getOptionsName(key)),
System.currentTimeMillis(), encodeMapKey(key), maxSize); System.currentTimeMillis(), encodeMapKey(key));
} }
@Override @Override
@ -497,9 +510,9 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
"redis.call('hset', KEYS[1], ARGV[2], value);" + "redis.call('hset', KEYS[1], ARGV[2], value);" +
"local currentTime = tonumber(ARGV[1]);" + "local currentTime = tonumber(ARGV[1]);" +
"local lastAccessTimeSetName = KEYS[6];" + "local lastAccessTimeSetName = KEYS[6];" +
"local maxSize = tonumber(ARGV[4]);" + "local maxSize = tonumber(redis.call('hget', KEYS[8], 'max-size'));" +
"if exists == false then" + "if exists == false then" +
" if maxSize ~= 0 then" + " if maxSize ~= nil and maxSize ~= 0 then" +
" redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[2]);" + " redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[2]);" +
" local cacheSize = tonumber(redis.call('hlen', KEYS[1]));" + " local cacheSize = tonumber(redis.call('hlen', KEYS[1]));" +
" if cacheSize >= maxSize then" + " if cacheSize >= maxSize then" +
@ -522,7 +535,7 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
" redis.call('publish', KEYS[4], msg);" + " redis.call('publish', KEYS[4], msg);" +
" return nil;" + " return nil;" +
"else" + "else" +
" if maxSize ~= 0 then" + " if maxSize ~= nil and maxSize ~= 0 then" +
" redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[2]);" + " redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[2]);" +
" end;" + " end;" +
"end;" + "end;" +
@ -532,15 +545,15 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
"redis.call('publish', KEYS[5], msg);" + "redis.call('publish', KEYS[5], msg);" +
"return val;", "return val;",
Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key), Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key),
getUpdatedChannelNameByKey(key), getLastAccessTimeSetNameByKey(key), getRemovedChannelNameByKey(key)), getUpdatedChannelNameByKey(key), getLastAccessTimeSetNameByKey(key), getRemovedChannelNameByKey(key), getOptionsName(key)),
System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value), maxSize); System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value));
} }
@Override @Override
protected RFuture<V> putIfAbsentOperationAsync(K key, V value) { protected RFuture<V> putIfAbsentOperationAsync(K key, V value) {
return commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_MAP_VALUE, return commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_MAP_VALUE,
"local value = redis.call('hget', KEYS[1], ARGV[2]); " "local value = redis.call('hget', KEYS[1], ARGV[2]); "
+ "local maxSize = tonumber(ARGV[4]); " + "local maxSize = tonumber(redis.call('hget', KEYS[7], 'max-size'));"
+ "local lastAccessTimeSetName = KEYS[5]; " + "local lastAccessTimeSetName = KEYS[5]; "
+ "local currentTime = tonumber(ARGV[1]); " + "local currentTime = tonumber(ARGV[1]); "
+ "if value ~= false then " + "if value ~= false then "
@ -557,7 +570,7 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
+ "end; " + "end; "
+ "end; " + "end; "
+ "if expireDate > tonumber(ARGV[1]) then " + "if expireDate > tonumber(ARGV[1]) then "
+ "if maxSize ~= 0 then " + "if maxSize ~= nil and maxSize ~= 0 then "
+ " redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[2]); " + " redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[2]); "
+ "end; " + "end; "
+ "return val; " + "return val; "
@ -568,7 +581,7 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
+ "redis.call('hset', KEYS[1], ARGV[2], value); " + "redis.call('hset', KEYS[1], ARGV[2], value); "
// last access time // last access time
+ "if maxSize ~= 0 then " + + "if maxSize ~= nil and maxSize ~= 0 then " +
" redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[2]); " + " redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[2]); " +
" local cacheSize = tonumber(redis.call('hlen', KEYS[1])); " + " local cacheSize = tonumber(redis.call('hlen', KEYS[1])); " +
" if cacheSize >= maxSize then " + " if cacheSize >= maxSize then " +
@ -592,8 +605,8 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
+ "redis.call('publish', KEYS[4], msg); " + "redis.call('publish', KEYS[4], msg); "
+ "return nil;", + "return nil;",
Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key), Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key),
getLastAccessTimeSetNameByKey(key), getRemovedChannelNameByKey(key)), getLastAccessTimeSetNameByKey(key), getRemovedChannelNameByKey(key), getOptionsName(key)),
System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value), maxSize); System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value));
} }
@Override @Override
@ -643,8 +656,8 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
+ "redis.call('hset', KEYS[1], ARGV[2], newValuePack); " + "redis.call('hset', KEYS[1], ARGV[2], newValuePack); "
// last access time // last access time
+ "local maxSize = tonumber(ARGV[4]); " + + "local maxSize = tonumber(redis.call('hget', KEYS[8], 'max-size')); " +
"if maxSize ~= 0 then " + "if maxSize ~= nil and maxSize ~= 0 then " +
" local currentTime = tonumber(ARGV[1]); " + " local currentTime = tonumber(ARGV[1]); " +
" local lastAccessTimeSetName = KEYS[6]; " + " local lastAccessTimeSetName = KEYS[6]; " +
" redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[2]); " + " redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[2]); " +
@ -668,8 +681,8 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
+ "return tostring(newValue); ", + "return tostring(newValue); ",
Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key), Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key),
getUpdatedChannelNameByKey(key), getLastAccessTimeSetNameByKey(key), getRemovedChannelNameByKey(key)), getUpdatedChannelNameByKey(key), getLastAccessTimeSetNameByKey(key), getRemovedChannelNameByKey(key), getOptionsName(key)),
System.currentTimeMillis(), keyState, new BigDecimal(value.toString()).toPlainString(), maxSize); System.currentTimeMillis(), keyState, new BigDecimal(value.toString()).toPlainString());
} }
@Override @Override
@ -775,8 +788,8 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
+ "end; " + + "end; " +
// last access time // last access time
"local maxSize = tonumber(ARGV[7]); " + "local maxSize = tonumber(redis.call('hget', KEYS[8], 'max-size')); " +
"if maxSize ~= 0 then " + "if maxSize ~= nil and maxSize ~= 0 then " +
" local currentTime = tonumber(ARGV[1]); " + " local currentTime = tonumber(ARGV[1]); " +
" local lastAccessTimeSetName = KEYS[6]; " + " local lastAccessTimeSetName = KEYS[6]; " +
" redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[5]); " + " redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[5]); " +
@ -810,8 +823,8 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
+ "return 0;" + "return 0;"
+ "end;", + "end;",
Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key), Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key),
getUpdatedChannelNameByKey(key), getLastAccessTimeSetNameByKey(key), getRemovedChannelNameByKey(key)), getUpdatedChannelNameByKey(key), getLastAccessTimeSetNameByKey(key), getRemovedChannelNameByKey(key), getOptionsName(key)),
System.currentTimeMillis(), ttlTimeout, maxIdleTimeout, maxIdleDelta, encodeMapKey(key), encodeMapValue(value), maxSize); System.currentTimeMillis(), ttlTimeout, maxIdleTimeout, maxIdleDelta, encodeMapKey(key), encodeMapValue(value));
return future; return future;
} }
@ -911,8 +924,8 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
+ "end; " + "end; "
// last access time // last access time
+ "local maxSize = tonumber(ARGV[7]); " + + "local maxSize = tonumber(redis.call('hget', KEYS[8], 'max-size')); " +
"if maxSize ~= 0 then " + "if maxSize ~= nil and maxSize ~= 0 then " +
" local currentTime = tonumber(ARGV[1]); " + " local currentTime = tonumber(ARGV[1]); " +
" local lastAccessTimeSetName = KEYS[6]; " + " local lastAccessTimeSetName = KEYS[6]; " +
" redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[5]); " + " redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[5]); " +
@ -950,8 +963,8 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
+ "return val", + "return val",
Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key), Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key),
getUpdatedChannelNameByKey(key), getLastAccessTimeSetNameByKey(key), getRemovedChannelNameByKey(key)), getUpdatedChannelNameByKey(key), getLastAccessTimeSetNameByKey(key), getRemovedChannelNameByKey(key), getOptionsName(key)),
System.currentTimeMillis(), ttlTimeout, maxIdleTimeout, maxIdleDelta, encodeMapKey(key), encodeMapValue(value), maxSize); System.currentTimeMillis(), ttlTimeout, maxIdleTimeout, maxIdleDelta, encodeMapKey(key), encodeMapValue(value));
return future; return future;
} }
@ -966,6 +979,14 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
String getTimeoutSetName() { String getTimeoutSetName() {
return prefixName("redisson__timeout__set", getName()); return prefixName("redisson__timeout__set", getName());
} }
String getLastAccessTimeSetNameByKey(Object key) {
return prefixName("redisson__map_cache__last_access__set", getName(key));
}
String getLastAccessTimeSetName() {
return prefixName("redisson__map_cache__last_access__set", getName());
}
String getIdleSetNameByKey(Object key) { String getIdleSetNameByKey(Object key) {
return prefixName("redisson__idle__set", getName(key)); return prefixName("redisson__idle__set", getName(key));
@ -979,6 +1000,14 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
return prefixName("redisson__idle__set", getName()); return prefixName("redisson__idle__set", getName());
} }
String getOptionsName() {
return suffixName(getName(), "redisson_options");
}
String getOptionsName(Object key) {
return suffixName(getName(key), "redisson_options");
}
String getCreatedChannelNameByKey(Object key) { String getCreatedChannelNameByKey(Object key) {
return prefixName("redisson_map_cache_created", getName(key)); return prefixName("redisson_map_cache_created", getName(key));
} }
@ -1054,8 +1083,8 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
+ "redis.call('zrem', KEYS[2], ARGV[2]); " + "redis.call('zrem', KEYS[2], ARGV[2]); "
+ "redis.call('zrem', KEYS[3], ARGV[2]); " + "redis.call('zrem', KEYS[3], ARGV[2]); "
+ "local maxSize = tonumber(ARGV[3])" + "local maxSize = tonumber(redis.call('hget', KEYS[6], 'max-size'));"
+ "if maxSize ~= 0 then" + "if maxSize ~= nil and maxSize ~= 0 then"
+ " redis.call('zrem', KEYS[5], ARGV[2]); " + " redis.call('zrem', KEYS[5], ARGV[2]); "
+ "end;" + "end;"
+ "redis.call('hdel', KEYS[1], ARGV[2]); " + "redis.call('hdel', KEYS[1], ARGV[2]); "
@ -1064,21 +1093,20 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
+ "redis.call('publish', KEYS[4], msg); " + "redis.call('publish', KEYS[4], msg); "
+ "return val; ", + "return val; ",
Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getRemovedChannelNameByKey(key), Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getRemovedChannelNameByKey(key),
getLastAccessTimeSetNameByKey(key)), getLastAccessTimeSetNameByKey(key), getOptionsName(key)),
System.currentTimeMillis(), encodeMapKey(key), maxSize); System.currentTimeMillis(), encodeMapKey(key));
} }
@Override @Override
protected RFuture<List<Long>> fastRemoveOperationBatchAsync(K... keys) { protected RFuture<List<Long>> fastRemoveOperationBatchAsync(K... keys) {
List<Object> args = new ArrayList<Object>(keys.length + 1); List<Object> args = new ArrayList<Object>(keys.length);
args.add(maxSize);
for (K key : keys) { for (K key : keys) {
args.add(encodeMapKey(key)); args.add(encodeMapKey(key));
} }
RFuture<List<Long>> future = commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_LIST, RFuture<List<Long>> future = commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_LIST,
"local maxSize = tonumber(table.remove(ARGV, 1)); " "local maxSize = tonumber(redis.call('hget', KEYS[6], 'max-size')); "
+ "if maxSize ~= 0 then " + "if maxSize ~= nil and maxSize ~= 0 then "
+ " redis.call('zrem', KEYS[5], unpack(ARGV)); " + " redis.call('zrem', KEYS[5], unpack(ARGV)); "
+ "end; " + + "end; " +
"redis.call('zrem', KEYS[3], unpack(ARGV)); " + "redis.call('zrem', KEYS[3], unpack(ARGV)); " +
@ -1098,22 +1126,21 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
+ "table.insert(result, val); " + "table.insert(result, val); "
+ "end;" + "end;"
+ "return result;", + "return result;",
Arrays.<Object>asList(getName(), getTimeoutSetName(), getIdleSetName(), getRemovedChannelName(), getLastAccessTimeSetName()), Arrays.<Object>asList(getName(), getTimeoutSetName(), getIdleSetName(), getRemovedChannelName(), getLastAccessTimeSetName(), getOptionsName()),
args.toArray()); args.toArray());
return future; return future;
} }
@Override @Override
protected RFuture<Long> fastRemoveOperationAsync(K ... keys) { protected RFuture<Long> fastRemoveOperationAsync(K ... keys) {
List<Object> params = new ArrayList<Object>(keys.length + 1); List<Object> params = new ArrayList<Object>(keys.length);
params.add(maxSize);
for (K key : keys) { for (K key : keys) {
params.add(encodeMapKey(key)); params.add(encodeMapKey(key));
} }
return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_LONG, return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_LONG,
"local maxSize = tonumber(table.remove(ARGV, 1)); " "local maxSize = tonumber(redis.call('hget', KEYS[6], 'max-size')); "
+ "if maxSize ~= 0 then " + "if maxSize ~= nil and maxSize ~= 0 then "
+ " redis.call('zrem', KEYS[5], unpack(ARGV)); " + " redis.call('zrem', KEYS[5], unpack(ARGV)); "
+ "end; " + + "end; " +
"redis.call('zrem', KEYS[3], unpack(ARGV)); " + "redis.call('zrem', KEYS[3], unpack(ARGV)); " +
@ -1127,7 +1154,7 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
+ "end; " + + "end; " +
"end; " + "end; " +
"return redis.call('hdel', KEYS[1], unpack(ARGV)); ", "return redis.call('hdel', KEYS[1], unpack(ARGV)); ",
Arrays.<Object>asList(getName(), getTimeoutSetName(), getIdleSetName(), getRemovedChannelName(), getLastAccessTimeSetName()), Arrays.<Object>asList(getName(), getTimeoutSetName(), getIdleSetName(), getRemovedChannelName(), getLastAccessTimeSetName(), getOptionsName()),
params.toArray()); params.toArray());
} }
@ -1260,8 +1287,8 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
+ "redis.call('hset', KEYS[1], ARGV[2], val); " + + "redis.call('hset', KEYS[1], ARGV[2], val); " +
// last access time // last access time
"local maxSize = tonumber(ARGV[4]);" + "local maxSize = tonumber(redis.call('hget', KEYS[8], 'max-size'));" +
"if maxSize ~= 0 then " + "if maxSize ~= nil and maxSize ~= 0 then " +
" local currentTime = tonumber(ARGV[1]); " + " local currentTime = tonumber(ARGV[1]); " +
" local lastAccessTimeSetName = KEYS[6]; " + " local lastAccessTimeSetName = KEYS[6]; " +
" redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[2]); " + " redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[2]); " +
@ -1294,8 +1321,8 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
+ "return 0;" + "return 0;"
+ "end;", + "end;",
Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key), Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key),
getUpdatedChannelNameByKey(key), getLastAccessTimeSetNameByKey(key), getRemovedChannelNameByKey(key)), getUpdatedChannelNameByKey(key), getLastAccessTimeSetNameByKey(key), getRemovedChannelNameByKey(key), getOptionsName(key)),
System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value), maxSize); System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value));
} }
@Override @Override
@ -1303,7 +1330,7 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
return commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_BOOLEAN, return commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_BOOLEAN,
"local value = redis.call('hget', KEYS[1], ARGV[2]); " "local value = redis.call('hget', KEYS[1], ARGV[2]); "
+ "local lastAccessTimeSetName = KEYS[5]; " + "local lastAccessTimeSetName = KEYS[5]; "
+ "local maxSize = tonumber(ARGV[4]); " + "local maxSize = tonumber(redis.call('hget', KEYS[7], 'max-size')); "
+ "local currentTime = tonumber(ARGV[1]); " + "local currentTime = tonumber(ARGV[1]); "
+ "if value == false then " + "if value == false then "
+ "local val = struct.pack('dLc0', 0, string.len(ARGV[3]), ARGV[3]); " + "local val = struct.pack('dLc0', 0, string.len(ARGV[3]), ARGV[3]); "
@ -1313,7 +1340,7 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
// last access time // last access time
"if maxSize ~= 0 then " + "if maxSize ~= nil and maxSize ~= 0 then " +
" redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[2]); " + " redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[2]); " +
" local cacheSize = tonumber(redis.call('hlen', KEYS[1])); " + " local cacheSize = tonumber(redis.call('hlen', KEYS[1])); " +
" if cacheSize >= maxSize then " + " if cacheSize >= maxSize then " +
@ -1336,7 +1363,7 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
+ "return 1; " + "return 1; "
+ "end; " + "end; "
+ "if maxSize ~= 0 then " + "if maxSize ~= nil and maxSize ~= 0 then "
+ " redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[2]); " + " redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[2]); "
+ "end; " + "end; "
+ "local t, val = struct.unpack('dLc0', value); " + "local t, val = struct.unpack('dLc0', value); "
@ -1369,8 +1396,8 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
+ "redis.call('publish', KEYS[4], msg); " + "redis.call('publish', KEYS[4], msg); "
+ "return 1; ", + "return 1; ",
Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key), Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key),
getLastAccessTimeSetNameByKey(key), getRemovedChannelNameByKey(key)), getLastAccessTimeSetNameByKey(key), getRemovedChannelNameByKey(key), getOptionsName(key)),
System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value), maxSize); System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value));
} }
@Override @Override
@ -1456,8 +1483,8 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
" redis.call('zrem', KEYS[3], ARGV[5]); " + " redis.call('zrem', KEYS[3], ARGV[5]); " +
" end; " + " end; " +
// last access time // last access time
" local maxSize = tonumber(ARGV[7]); " + " local maxSize = tonumber(redis.call('hget', KEYS[7], 'max-size')); " +
" if maxSize ~= 0 then " + " if maxSize ~= nil and maxSize ~= 0 then " +
" local currentTime = tonumber(ARGV[1]); " + " local currentTime = tonumber(ARGV[1]); " +
" local lastAccessTimeSetName = KEYS[5]; " + " local lastAccessTimeSetName = KEYS[5]; " +
" redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[5]); " + " redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[5]); " +
@ -1488,8 +1515,8 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
" return 0; " + " return 0; " +
"end; ", "end; ",
Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key), Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key),
getLastAccessTimeSetNameByKey(key), getRemovedChannelNameByKey(key)), getLastAccessTimeSetNameByKey(key), getRemovedChannelNameByKey(key), getOptionsName(key)),
System.currentTimeMillis(), ttlTimeout, maxIdleTimeout, maxIdleDelta, encodeMapKey(key), encodeMapValue(value), maxSize); System.currentTimeMillis(), ttlTimeout, maxIdleTimeout, maxIdleDelta, encodeMapKey(key), encodeMapValue(value));
if (hasNoWriter()) { if (hasNoWriter()) {
return future; return future;
} }
@ -1507,14 +1534,6 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
return mapWriterFuture(future, listener); 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 @Override
protected RFuture<Boolean> replaceOperationAsync(K key, V oldValue, V newValue) { protected RFuture<Boolean> replaceOperationAsync(K key, V oldValue, V newValue) {
return commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_BOOLEAN, return commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_BOOLEAN,
@ -1679,14 +1698,17 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
@Override @Override
public RFuture<Boolean> deleteAsync() { public RFuture<Boolean> deleteAsync() {
return commandExecutor.writeAsync(getName(), RedisCommands.DEL_OBJECTS, getName(), getTimeoutSetName(), getIdleSetName(), getLastAccessTimeSetName()); return commandExecutor.writeAsync(getName(), RedisCommands.DEL_OBJECTS,
getName(), getTimeoutSetName(), getIdleSetName(), getLastAccessTimeSetName(), getOptionsName());
} }
@Override @Override
public RFuture<Boolean> expireAsync(long timeToLive, TimeUnit timeUnit) { public RFuture<Boolean> expireAsync(long timeToLive, TimeUnit timeUnit) {
return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN, return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
"local maxSize = tonumber(ARGV[2]); " + "local maxSize = tonumber(redis.call('hget', KEYS[5], 'max-size')); " +
"if maxSize ~= 0 then " + "if maxSize ~= nil and maxSize ~= 0 then " +
" redis.call('pexpire', KEYS[5], ARGV[1]); " +
" redis.call('zadd', KEYS[4], 92233720368547758, 'redisson__expiretag'); " +
" redis.call('pexpire', KEYS[4], ARGV[1]); " + " redis.call('pexpire', KEYS[4], ARGV[1]); " +
"end; " + "end; " +
"redis.call('zadd', KEYS[2], 92233720368547758, 'redisson__expiretag'); " + "redis.call('zadd', KEYS[2], 92233720368547758, 'redisson__expiretag'); " +
@ -1694,24 +1716,26 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
"redis.call('zadd', KEYS[3], 92233720368547758, 'redisson__expiretag'); " + "redis.call('zadd', KEYS[3], 92233720368547758, 'redisson__expiretag'); " +
"redis.call('pexpire', KEYS[3], ARGV[1]); " + "redis.call('pexpire', KEYS[3], ARGV[1]); " +
"return redis.call('pexpire', KEYS[1], ARGV[1]); ", "return redis.call('pexpire', KEYS[1], ARGV[1]); ",
Arrays.<Object>asList(getName(), getTimeoutSetName(), getIdleSetName(), getLastAccessTimeSetName()), Arrays.<Object>asList(getName(), getTimeoutSetName(), getIdleSetName(), getLastAccessTimeSetName(), getOptionsName()),
timeUnit.toMillis(timeToLive), maxSize); timeUnit.toMillis(timeToLive));
} }
@Override @Override
public RFuture<Boolean> expireAtAsync(long timestamp) { public RFuture<Boolean> expireAtAsync(long timestamp) {
return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN, return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
"local maxSize = tonumber(ARGV[2]); " + "local maxSize = tonumber(redis.call('hget', KEYS[5], 'max-size')); " +
"if maxSize ~= 0 then " + "if maxSize ~= nil and maxSize ~= 0 then " +
" redis.call('pexpire', KEYS[4], ARGV[1]); " + " redis.call('pexpire', KEYS[5], ARGV[1]); " +
" redis.call('zadd', KEYS[4], 92233720368547758, 'redisson__expiretag'); " +
" redis.call('pexpire', KEYS[4], ARGV[1]); " +
"end; " + "end; " +
"redis.call('zadd', KEYS[2], 92233720368547758, 'redisson__expiretag'); " + "redis.call('zadd', KEYS[2], 92233720368547758, 'redisson__expiretag'); " +
"redis.call('pexpireat', KEYS[2], ARGV[1]); " + "redis.call('pexpireat', KEYS[2], ARGV[1]); " +
"redis.call('zadd', KEYS[3], 92233720368547758, 'redisson__expiretag'); " + "redis.call('zadd', KEYS[3], 92233720368547758, 'redisson__expiretag'); " +
"redis.call('pexpire', KEYS[3], ARGV[1]); " + "redis.call('pexpire', KEYS[3], ARGV[1]); " +
"return redis.call('pexpireat', KEYS[1], ARGV[1]); ", "return redis.call('pexpireat', KEYS[1], ARGV[1]); ",
Arrays.<Object>asList(getName(), getTimeoutSetName(), getIdleSetName(), getLastAccessTimeSetName()), Arrays.<Object>asList(getName(), getTimeoutSetName(), getIdleSetName(), getLastAccessTimeSetName(), getOptionsName()),
timestamp, maxSize); timestamp);
} }
@Override @Override
@ -1728,7 +1752,8 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
@Override @Override
public RFuture<Set<K>> readAllKeySetAsync() { public RFuture<Set<K>> readAllKeySetAsync() {
return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_MAP_KEY_SET, return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_MAP_KEY_SET,
"local s = redis.call('hgetall', KEYS[1]); " "local s = redis.call('hgetall', KEYS[1]); " +
"local maxSize = tonumber(redis.call('hget', KEYS[5], 'max-size'));"
+ "local result = {}; " + "local result = {}; "
+ "for i, v in ipairs(s) do " + "for i, v in ipairs(s) do "
+ "if i % 2 == 0 then " + "if i % 2 == 0 then "
@ -1746,8 +1771,7 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
+ "local value = struct.pack('dLc0', t, string.len(val), val); " + "local value = struct.pack('dLc0', t, string.len(val), val); "
+ "redis.call('hset', KEYS[1], key, value); " + "redis.call('hset', KEYS[1], key, value); "
+ "redis.call('zadd', KEYS[3], t + tonumber(ARGV[1]), key); " + "redis.call('zadd', KEYS[3], t + tonumber(ARGV[1]), key); "
+ "local maxSize = tonumber(ARGV[2]); " + "if maxSize ~= nil and maxSize ~= 0 then "
+ "if maxSize ~= 0 then "
+ " redis.call('zadd', KEYS[4], tonumber(ARGV[1]), key); " + " redis.call('zadd', KEYS[4], tonumber(ARGV[1]), key); "
+ "end; " + "end; "
+ "end; " + "end; "
@ -1760,8 +1784,8 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
+ "end; " + "end; "
+ "end;" + + "end;" +
"return result;", "return result;",
Arrays.<Object>asList(getName(), getTimeoutSetName(), getIdleSetName(), getLastAccessTimeSetName()), Arrays.<Object>asList(getName(), getTimeoutSetName(), getIdleSetName(), getLastAccessTimeSetName(), getOptionsName()),
System.currentTimeMillis(), maxSize); System.currentTimeMillis());
} }
@Override @Override
@ -1773,6 +1797,7 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
return commandExecutor.evalWriteAsync(getName(), codec, evalCommandType, return commandExecutor.evalWriteAsync(getName(), codec, evalCommandType,
"local s = redis.call('hgetall', KEYS[1]); " "local s = redis.call('hgetall', KEYS[1]); "
+ "local result = {}; " + "local result = {}; "
+ "local maxSize = tonumber(redis.call('hget', KEYS[5], 'max-size'));"
+ "for i, v in ipairs(s) do " + "for i, v in ipairs(s) do "
+ "if i % 2 == 0 then " + "if i % 2 == 0 then "
+ "local t, val = struct.unpack('dLc0', v); " + "local t, val = struct.unpack('dLc0', v); "
@ -1789,8 +1814,7 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
+ "local value = struct.pack('dLc0', t, string.len(val), val); " + "local value = struct.pack('dLc0', t, string.len(val), val); "
+ "redis.call('hset', KEYS[1], key, value); " + "redis.call('hset', KEYS[1], key, value); "
+ "redis.call('zadd', KEYS[3], t + tonumber(ARGV[1]), key); " + "redis.call('zadd', KEYS[3], t + tonumber(ARGV[1]), key); "
+ "local maxSize = tonumber(ARGV[2]); " + "if maxSize ~= nil and maxSize ~= 0 then "
+ "if maxSize ~= 0 then "
+ " redis.call('zadd', KEYS[4], tonumber(ARGV[1]), key); " + " redis.call('zadd', KEYS[4], tonumber(ARGV[1]), key); "
+ "end; " + "end; "
+ "end; " + "end; "
@ -1804,8 +1828,8 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
+ "end; " + "end; "
+ "end;" + + "end;" +
"return result;", "return result;",
Arrays.<Object>asList(getName(), getTimeoutSetName(), getIdleSetName(), getLastAccessTimeSetName()), Arrays.<Object>asList(getName(), getTimeoutSetName(), getIdleSetName(), getLastAccessTimeSetName(), getOptionsName()),
System.currentTimeMillis(), maxSize); System.currentTimeMillis());
} }
@Override @Override
@ -1819,6 +1843,7 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_MAP_VALUE_LIST, return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_MAP_VALUE_LIST,
"local s = redis.call('hgetall', KEYS[1]); " "local s = redis.call('hgetall', KEYS[1]); "
+ "local result = {}; " + "local result = {}; "
+ "local maxSize = tonumber(redis.call('hget', KEYS[5], 'max-size')); "
+ "for i, v in ipairs(s) do " + "for i, v in ipairs(s) do "
+ "if i % 2 == 0 then " + "if i % 2 == 0 then "
+ "local t, val = struct.unpack('dLc0', v); " + "local t, val = struct.unpack('dLc0', v); "
@ -1835,8 +1860,7 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
+ "local value = struct.pack('dLc0', t, string.len(val), val); " + "local value = struct.pack('dLc0', t, string.len(val), val); "
+ "redis.call('hset', KEYS[1], key, value); " + "redis.call('hset', KEYS[1], key, value); "
+ "redis.call('zadd', KEYS[3], t + tonumber(ARGV[1]), key); " + "redis.call('zadd', KEYS[3], t + tonumber(ARGV[1]), key); "
+ "local maxSize = tonumber(ARGV[2]); " + "if maxSize ~= nil and maxSize ~= 0 then "
+ "if maxSize ~= 0 then "
+ " redis.call('zadd', KEYS[4], tonumber(ARGV[1]), key); " + " redis.call('zadd', KEYS[4], tonumber(ARGV[1]), key); "
+ "end; " + "end; "
+ "end; " + "end; "
@ -1849,7 +1873,7 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
+ "end; " + "end; "
+ "end;" + + "end;" +
"return result;", "return result;",
Arrays.<Object>asList(getName(), getTimeoutSetName(), getIdleSetName(), getLastAccessTimeSetName()), Arrays.<Object>asList(getName(), getTimeoutSetName(), getIdleSetName(), getLastAccessTimeSetName(), getOptionsName()),
System.currentTimeMillis(), maxSize); System.currentTimeMillis());
} }
} }

@ -49,7 +49,6 @@ public class MapOptions<K, V> {
private MapWriter<K, V> writer; private MapWriter<K, V> writer;
private WriteMode writeMode = WriteMode.WRITE_THROUGH; private WriteMode writeMode = WriteMode.WRITE_THROUGH;
private int writeBehindThreads = 1; private int writeBehindThreads = 1;
private int maxSize = 0;
protected MapOptions() { protected MapOptions() {
} }
@ -136,19 +135,4 @@ public class MapOptions<K, V> {
return loader; return loader;
} }
/**
* Sets max size of the map.
* <p>
* Currently only RedissonMapCache is supported.
*
* @param maxSize - max size
* @return MapOptions instance
*/
public MapOptions<K, V> maxSize(int maxSize) {
this.maxSize = maxSize;
return this;
}
public int getMaxSize() {
return maxSize;
}
} }

@ -39,6 +39,14 @@ import org.redisson.api.map.event.MapEntryListener;
*/ */
public interface RMapCache<K, V> extends RMap<K, V>, RMapCacheAsync<K, V> { public interface RMapCache<K, V> extends RMap<K, V>, RMapCacheAsync<K, V> {
/**
* Tries to set max size of the map.
*
* @param maxSize - max size
* @return <code>true</code> if max size has been successfully set, otherwise <code>false</code>.
*/
boolean trySetMaxSize(int maxSize);
/** /**
* If the specified key is not already associated * If the specified key is not already associated
* with a value, associate it with the given value. * with a value, associate it with the given value.

@ -37,6 +37,14 @@ import java.util.concurrent.TimeUnit;
*/ */
public interface RMapCacheAsync<K, V> extends RMapAsync<K, V> { public interface RMapCacheAsync<K, V> extends RMapAsync<K, V> {
/**
* Tries to set max size of the map.
*
* @param maxSize - max size
* @return <code>true</code> if max size has been successfully set, otherwise <code>false</code>.
*/
RFuture<Boolean> trySetMaxSizeAsync(int maxSize);
/** /**
* If the specified key is not already associated * If the specified key is not already associated
* with a value, associate it with the given value. * with a value, associate it with the given value.

@ -217,7 +217,7 @@ public class RedissonMapCacheTest extends BaseMapTest {
} }
@Test @Test
public void testFastPutMaxSize() { public void testMaxSize() {
final int maxSize = 2; final int maxSize = 2;
Map<String, String> store = new LinkedHashMap<String, String>() { Map<String, String> store = new LinkedHashMap<String, String>() {
@Override @Override
@ -226,12 +226,16 @@ public class RedissonMapCacheTest extends BaseMapTest {
} }
}; };
MapOptions<String, String> options = MapOptions.<String, String>defaults().writer(createMapWriter(store)); MapOptions<String, String> options = MapOptions.<String, String>defaults().writer(createMapWriter(store));
options.maxSize(maxSize);
RMapCache<String, String> map = redisson.getMapCache("test", options); RMapCache<String, String> map = redisson.getMapCache("test", options);
map.trySetMaxSize(maxSize);
map.fastPut("1", "11", 10, TimeUnit.SECONDS); assertThat(map.fastPutIfAbsent("01", "00")).isTrue();
map.fastPut("2", "22", 10, TimeUnit.SECONDS); assertThat(map.fastPutIfAbsent("02", "00")).isTrue();
map.fastPut("3", "33", 10, TimeUnit.SECONDS); assertThat(map.put("03", "00")).isNull();
assertThat(map.fastPutIfAbsent("04", "00", 10, TimeUnit.SECONDS)).isTrue();
assertThat(map.fastPut("1", "11", 10, TimeUnit.SECONDS)).isTrue();
assertThat(map.fastPut("2", "22", 10, TimeUnit.SECONDS)).isTrue();
assertThat(map.fastPut("3", "33", 10, TimeUnit.SECONDS)).isTrue();
assertThat(map.size()).isEqualTo(maxSize); assertThat(map.size()).isEqualTo(maxSize);
@ -239,6 +243,20 @@ public class RedissonMapCacheTest extends BaseMapTest {
expected.put("2", "22"); expected.put("2", "22");
expected.put("3", "33"); expected.put("3", "33");
assertThat(store).isEqualTo(expected); assertThat(store).isEqualTo(expected);
assertThat(map.get("2")).isEqualTo("22");
assertThat(map.get("0")).isNull();
assertThat(map.putIfAbsent("2", "3")).isEqualTo("22");
assertThat(map.putIfAbsent("3", "4", 10, TimeUnit.SECONDS, 10, TimeUnit.SECONDS)).isEqualTo("33");
assertThat(map.containsKey("2")).isTrue();
assertThat(map.containsKey("0")).isFalse();
assertThat(map.containsValue("22")).isTrue();
assertThat(map.containsValue("00")).isFalse();
assertThat(map.getAll(new HashSet<String>(Arrays.asList("2", "3")))).isEqualTo(expected);
assertThat(map.remove("2", "33")).isFalse();
assertThat(map.remove("2", "22")).isTrue();
assertThat(map.remove("0")).isNull();
assertThat(map.remove("3")).isEqualTo("33");
} }
@Test @Test
@ -1243,3 +1261,4 @@ public class RedissonMapCacheTest extends BaseMapTest {
} }
} }

Loading…
Cancel
Save