|
|
|
@ -15,7 +15,6 @@
|
|
|
|
|
*/
|
|
|
|
|
package org.redisson;
|
|
|
|
|
|
|
|
|
|
import java.io.IOException;
|
|
|
|
|
import java.math.BigDecimal;
|
|
|
|
|
import java.net.InetSocketAddress;
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
@ -24,6 +23,7 @@ import java.util.Collection;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
import java.util.Set;
|
|
|
|
|
import java.util.concurrent.ExecutorService;
|
|
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
|
|
|
|
|
|
import org.redisson.api.RFuture;
|
|
|
|
@ -47,7 +47,6 @@ import org.redisson.client.protocol.RedisCommand;
|
|
|
|
|
import org.redisson.client.protocol.RedisCommand.ValueType;
|
|
|
|
|
import org.redisson.client.protocol.RedisCommands;
|
|
|
|
|
import org.redisson.client.protocol.convertor.NumberConvertor;
|
|
|
|
|
import org.redisson.client.protocol.convertor.VoidReplayConvertor;
|
|
|
|
|
import org.redisson.client.protocol.decoder.ListMultiDecoder;
|
|
|
|
|
import org.redisson.client.protocol.decoder.LongMultiDecoder;
|
|
|
|
|
import org.redisson.client.protocol.decoder.MapCacheScanResult;
|
|
|
|
@ -60,6 +59,7 @@ import org.redisson.codec.MapCacheEventCodec;
|
|
|
|
|
import org.redisson.command.CommandAsyncExecutor;
|
|
|
|
|
import org.redisson.connection.decoder.MapGetAllDecoder;
|
|
|
|
|
import org.redisson.eviction.EvictionScheduler;
|
|
|
|
|
import org.redisson.misc.RPromise;
|
|
|
|
|
|
|
|
|
|
import io.netty.util.concurrent.Future;
|
|
|
|
|
import io.netty.util.concurrent.FutureListener;
|
|
|
|
@ -85,16 +85,6 @@ import io.netty.util.concurrent.FutureListener;
|
|
|
|
|
*/
|
|
|
|
|
public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCache<K, V> {
|
|
|
|
|
|
|
|
|
|
static final RedisCommand<Object> EVAL_REPLACE = new RedisCommand<Object>("EVAL", 7, ValueType.MAP, ValueType.MAP_VALUE);
|
|
|
|
|
static final RedisCommand<Void> EVAL_HMSET = new RedisCommand<Void>("EVAL", new VoidReplayConvertor(), 5, ValueType.MAP);
|
|
|
|
|
private static final RedisCommand<Object> EVAL_REMOVE = new RedisCommand<Object>("EVAL", 7, ValueType.MAP_KEY, ValueType.MAP_VALUE);
|
|
|
|
|
private static final RedisCommand<Object> EVAL_PUT_TTL = new RedisCommand<Object>("EVAL", 12, ValueType.MAP, ValueType.MAP_VALUE);
|
|
|
|
|
private static final RedisCommand<Object> EVAL_PUT_TTL_IF_ABSENT = new RedisCommand<Object>("EVAL", 11, ValueType.MAP, ValueType.MAP_VALUE);
|
|
|
|
|
private static final RedisCommand<Object> EVAL_GET_TTL = new RedisCommand<Object>("EVAL", 7, ValueType.MAP_KEY, ValueType.MAP_VALUE);
|
|
|
|
|
static final RedisCommand<Long> EVAL_FAST_REMOVE = new RedisCommand<Long>("EVAL", 7, ValueType.MAP_KEY);
|
|
|
|
|
static final RedisCommand<Object> EVAL_PUT = new RedisCommand<Object>("EVAL", 6, ValueType.MAP, ValueType.MAP_VALUE);
|
|
|
|
|
static final RedisCommand<Object> EVAL_PUT_IF_ABSENT = new RedisCommand<Object>("EVAL", 5, ValueType.MAP, ValueType.MAP_VALUE);
|
|
|
|
|
|
|
|
|
|
public RedissonMapCache(EvictionScheduler evictionScheduler, CommandAsyncExecutor commandExecutor,
|
|
|
|
|
String name, RedissonClient redisson, MapLoader<K, V> mapLoader, MapWriter<K, V> mapWriter) {
|
|
|
|
|
super(commandExecutor, name, redisson, mapLoader, mapWriter);
|
|
|
|
@ -239,7 +229,7 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public RFuture<V> putIfAbsentAsync(K key, V value, long ttl, TimeUnit ttlUnit, long maxIdleTime, TimeUnit maxIdleUnit) {
|
|
|
|
|
public RFuture<V> putIfAbsentAsync(final K key, final V value, long ttl, TimeUnit ttlUnit, long maxIdleTime, TimeUnit maxIdleUnit) {
|
|
|
|
|
checkKey(key);
|
|
|
|
|
checkValue(value);
|
|
|
|
|
|
|
|
|
@ -273,7 +263,7 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
|
|
|
|
|
maxIdleTimeout = System.currentTimeMillis() + maxIdleDelta;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return commandExecutor.evalWriteAsync(getName(key), codec, EVAL_PUT_TTL_IF_ABSENT,
|
|
|
|
|
RFuture<V> 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 "
|
|
|
|
@ -325,14 +315,34 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
|
|
|
|
|
+ "return val;"
|
|
|
|
|
+ "end; ",
|
|
|
|
|
Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key)),
|
|
|
|
|
System.currentTimeMillis(), ttlTimeout, maxIdleTimeout, maxIdleDelta, key, value);
|
|
|
|
|
System.currentTimeMillis(), ttlTimeout, maxIdleTimeout, maxIdleDelta, encodeMapKey(key), encodeMapValue(value));
|
|
|
|
|
if (mapWriter == null) {
|
|
|
|
|
return future;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RPromise<V> result = new MapWriterPromise<V>(future, commandExecutor) {
|
|
|
|
|
@Override
|
|
|
|
|
public void execute(final Future<V> future, ExecutorService executorService) {
|
|
|
|
|
if (future.getNow() == null) {
|
|
|
|
|
commandExecutor.getConnectionManager().getExecutor().execute(new Runnable() {
|
|
|
|
|
@Override
|
|
|
|
|
public void run() {
|
|
|
|
|
mapWriter.write(key, value);
|
|
|
|
|
trySuccess(future.getNow());
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
trySuccess(future.getNow());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public RFuture<Boolean> removeAsync(Object key, Object value) {
|
|
|
|
|
checkKey(key);
|
|
|
|
|
checkValue(value);
|
|
|
|
|
|
|
|
|
|
protected RFuture<Boolean> removeOperationAsync(Object key, Object value) {
|
|
|
|
|
return commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_BOOLEAN,
|
|
|
|
|
"local value = redis.call('hget', KEYS[1], ARGV[1]); "
|
|
|
|
|
+ "if value == false then "
|
|
|
|
@ -354,10 +364,10 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
protected RFuture<V> getValueAsync(K key) {
|
|
|
|
|
protected RFuture<V> getOperationAsync(K key) {
|
|
|
|
|
checkKey(key);
|
|
|
|
|
|
|
|
|
|
return commandExecutor.evalWriteAsync(getName(key), codec, EVAL_GET_TTL,
|
|
|
|
|
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; "
|
|
|
|
@ -383,7 +393,8 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
|
|
|
|
|
+ "return nil; "
|
|
|
|
|
+ "end; "
|
|
|
|
|
+ "return val; ",
|
|
|
|
|
Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key)), System.currentTimeMillis(), key);
|
|
|
|
|
Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key)),
|
|
|
|
|
System.currentTimeMillis(), encodeMapKey(key));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@ -392,11 +403,8 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public RFuture<V> putAsync(K key, V value) {
|
|
|
|
|
checkKey(key);
|
|
|
|
|
checkValue(value);
|
|
|
|
|
|
|
|
|
|
return commandExecutor.evalWriteAsync(getName(key), codec, EVAL_PUT,
|
|
|
|
|
protected RFuture<V> putOperationAsync(K key, V value) {
|
|
|
|
|
return commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_MAP_VALUE,
|
|
|
|
|
"local v = redis.call('hget', KEYS[1], ARGV[1]); "
|
|
|
|
|
+ "local value = struct.pack('dLc0', 0, string.len(ARGV[2]), ARGV[2]); "
|
|
|
|
|
+ "redis.call('hset', KEYS[1], ARGV[1], value); "
|
|
|
|
@ -410,15 +418,12 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
|
|
|
|
|
+ "redis.call('publish', KEYS[3], msg); "
|
|
|
|
|
+ "return val; ",
|
|
|
|
|
Arrays.<Object>asList(getName(key), getCreatedChannelNameByKey(key), getUpdatedChannelNameByKey(key)),
|
|
|
|
|
key, value);
|
|
|
|
|
encodeMapKey(key), encodeMapValue(value));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public RFuture<V> putIfAbsentAsync(K key, V value) {
|
|
|
|
|
checkKey(key);
|
|
|
|
|
checkValue(value);
|
|
|
|
|
|
|
|
|
|
return commandExecutor.evalWriteAsync(getName(key), codec, EVAL_PUT_IF_ABSENT,
|
|
|
|
|
public RFuture<V> putIfAbsentOperationAsync(K key, V value) {
|
|
|
|
|
return commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_MAP_VALUE,
|
|
|
|
|
"local value = struct.pack('dLc0', 0, string.len(ARGV[2]), ARGV[2]); "
|
|
|
|
|
+ "if redis.call('hsetnx', KEYS[1], ARGV[1], value) == 1 then "
|
|
|
|
|
+ "local msg = struct.pack('Lc0Lc0', string.len(ARGV[1]), ARGV[1], string.len(ARGV[2]), ARGV[2]); "
|
|
|
|
@ -433,7 +438,7 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
|
|
|
|
|
+ "return val; "
|
|
|
|
|
+ "end",
|
|
|
|
|
Arrays.<Object>asList(getName(key), getCreatedChannelNameByKey(key)),
|
|
|
|
|
key, value);
|
|
|
|
|
encodeMapKey(key), encodeMapValue(value));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@ -442,19 +447,8 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public RFuture<V> addAndGetAsync(K key, Number value) {
|
|
|
|
|
checkKey(key);
|
|
|
|
|
checkValue(value);
|
|
|
|
|
|
|
|
|
|
public RFuture<V> addAndGetOperationAsync(K key, Number value) {
|
|
|
|
|
byte[] keyState = encodeMapKey(key);
|
|
|
|
|
byte[] valueState;
|
|
|
|
|
try {
|
|
|
|
|
valueState = StringCodec.INSTANCE
|
|
|
|
|
.getMapValueEncoder()
|
|
|
|
|
.encode(new BigDecimal(value.toString()).toPlainString());
|
|
|
|
|
} catch (IOException e) {
|
|
|
|
|
throw new IllegalArgumentException(e);
|
|
|
|
|
}
|
|
|
|
|
return commandExecutor.evalWriteAsync(getName(key), StringCodec.INSTANCE,
|
|
|
|
|
new RedisCommand<Object>("EVAL", new NumberConvertor(value.getClass())),
|
|
|
|
|
"local value = redis.call('hget', KEYS[1], ARGV[2]); "
|
|
|
|
@ -494,7 +488,7 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
|
|
|
|
|
+ "redis.call('hset', KEYS[1], ARGV[2], newValuePack); "
|
|
|
|
|
+ "return tostring(newValue); ",
|
|
|
|
|
Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key), getUpdatedChannelNameByKey(key)),
|
|
|
|
|
System.currentTimeMillis(), keyState, valueState);
|
|
|
|
|
System.currentTimeMillis(), keyState, new BigDecimal(value.toString()).toPlainString());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@ -513,7 +507,7 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public RFuture<Boolean> fastPutAsync(K key, V value, long ttl, TimeUnit ttlUnit, long maxIdleTime, TimeUnit maxIdleUnit) {
|
|
|
|
|
public RFuture<Boolean> fastPutAsync(final K key, final V value, long ttl, TimeUnit ttlUnit, long maxIdleTime, TimeUnit maxIdleUnit) {
|
|
|
|
|
checkKey(key);
|
|
|
|
|
checkValue(value);
|
|
|
|
|
|
|
|
|
@ -547,7 +541,7 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
|
|
|
|
|
maxIdleTimeout = System.currentTimeMillis() + maxIdleDelta;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_BOOLEAN,
|
|
|
|
|
RFuture<Boolean> future = commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_BOOLEAN,
|
|
|
|
|
"local insertable = false; "
|
|
|
|
|
+ "local value = redis.call('hget', KEYS[1], ARGV[5]); "
|
|
|
|
|
+ "local t, val;"
|
|
|
|
@ -594,6 +588,24 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
|
|
|
|
|
+ "end;",
|
|
|
|
|
Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key), getUpdatedChannelNameByKey(key)),
|
|
|
|
|
System.currentTimeMillis(), ttlTimeout, maxIdleTimeout, maxIdleDelta, encodeMapKey(key), encodeMapValue(value));
|
|
|
|
|
|
|
|
|
|
if (mapWriter == null) {
|
|
|
|
|
return future;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RPromise<Boolean> result = new MapWriterPromise<Boolean>(future, commandExecutor) {
|
|
|
|
|
@Override
|
|
|
|
|
public void execute(final Future<Boolean> future, ExecutorService executorService) {
|
|
|
|
|
executorService.execute(new Runnable() {
|
|
|
|
|
@Override
|
|
|
|
|
public void run() {
|
|
|
|
|
mapWriter.write(key, value);
|
|
|
|
|
trySuccess(future.getNow());
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@ -607,7 +619,7 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public RFuture<V> putAsync(K key, V value, long ttl, TimeUnit ttlUnit, long maxIdleTime, TimeUnit maxIdleUnit) {
|
|
|
|
|
public RFuture<V> putAsync(final K key, final V value, long ttl, TimeUnit ttlUnit, long maxIdleTime, TimeUnit maxIdleUnit) {
|
|
|
|
|
checkKey(key);
|
|
|
|
|
checkValue(value);
|
|
|
|
|
|
|
|
|
@ -641,7 +653,7 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
|
|
|
|
|
maxIdleTimeout = System.currentTimeMillis() + maxIdleDelta;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return commandExecutor.evalWriteAsync(getName(key), codec, EVAL_PUT_TTL,
|
|
|
|
|
RFuture<V> 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 "
|
|
|
|
@ -691,7 +703,26 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
|
|
|
|
|
|
|
|
|
|
+ "return val",
|
|
|
|
|
Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key), getUpdatedChannelNameByKey(key)),
|
|
|
|
|
System.currentTimeMillis(), ttlTimeout, maxIdleTimeout, maxIdleDelta, key, value);
|
|
|
|
|
System.currentTimeMillis(), ttlTimeout, maxIdleTimeout, maxIdleDelta, encodeMapKey(key), encodeMapValue(value));
|
|
|
|
|
if (mapWriter == null) {
|
|
|
|
|
return future;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RPromise<V> result = new MapWriterPromise<V>(future, commandExecutor) {
|
|
|
|
|
@Override
|
|
|
|
|
public void execute(final Future<V> future, ExecutorService executorService) {
|
|
|
|
|
executorService.execute(new Runnable() {
|
|
|
|
|
@Override
|
|
|
|
|
public void run() {
|
|
|
|
|
mapWriter.write(key, value);
|
|
|
|
|
trySuccess(future.getNow());
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String getTimeoutSetNameByKey(Object key) {
|
|
|
|
@ -768,10 +799,8 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public RFuture<V> removeAsync(K key) {
|
|
|
|
|
checkKey(key);
|
|
|
|
|
|
|
|
|
|
return commandExecutor.evalWriteAsync(getName(key), codec, EVAL_REMOVE,
|
|
|
|
|
public RFuture<V> removeOperationAsync(K key) {
|
|
|
|
|
return commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_MAP_VALUE,
|
|
|
|
|
"local v = redis.call('hget', KEYS[1], ARGV[1]); "
|
|
|
|
|
+ "redis.call('zrem', KEYS[2], ARGV[1]); "
|
|
|
|
|
+ "redis.call('zrem', KEYS[3], ARGV[1]); "
|
|
|
|
@ -784,16 +813,47 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
|
|
|
|
|
+ "end; "
|
|
|
|
|
+ "return v",
|
|
|
|
|
Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getRemovedChannelNameByKey(key)),
|
|
|
|
|
key);
|
|
|
|
|
encodeMapKey(key));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public RFuture<Long> fastRemoveAsync(K ... keys) {
|
|
|
|
|
if (keys == null || keys.length == 0) {
|
|
|
|
|
return newSucceededFuture(0L);
|
|
|
|
|
protected RFuture<List<Long>> fastRemoveOperationBatchAsync(K... keys) {
|
|
|
|
|
List<Object> args = new ArrayList<Object>(keys.length);
|
|
|
|
|
for (K key : keys) {
|
|
|
|
|
args.add(encodeMapKey(key));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return commandExecutor.evalWriteAsync(getName(), codec, EVAL_FAST_REMOVE,
|
|
|
|
|
RFuture<List<Long>> future = commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_LIST,
|
|
|
|
|
"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;" +
|
|
|
|
|
|
|
|
|
|
"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.<Object>asList(getName(), getTimeoutSetName(), getIdleSetName(), getRemovedChannelName()),
|
|
|
|
|
args.toArray());
|
|
|
|
|
return future;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
protected RFuture<Long> fastRemoveOperationAsync(K ... keys) {
|
|
|
|
|
List<Object> params = new ArrayList<Object>(keys.length);
|
|
|
|
|
for (K key : keys) {
|
|
|
|
|
params.add(encodeMapKey(key));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_LONG,
|
|
|
|
|
"redis.call('zrem', KEYS[3], unpack(ARGV)); " +
|
|
|
|
|
"redis.call('zrem', KEYS[2], unpack(ARGV)); " +
|
|
|
|
|
"for i, key in ipairs(ARGV) do "
|
|
|
|
@ -806,7 +866,7 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
|
|
|
|
|
"end;" +
|
|
|
|
|
"return redis.call('hdel', KEYS[1], unpack(ARGV)); ",
|
|
|
|
|
Arrays.<Object>asList(getName(), getTimeoutSetName(), getIdleSetName(), getRemovedChannelName()),
|
|
|
|
|
keys);
|
|
|
|
|
params.toArray());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@ -896,10 +956,7 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public RFuture<Boolean> fastPutAsync(K key, V value) {
|
|
|
|
|
checkKey(key);
|
|
|
|
|
checkValue(value);
|
|
|
|
|
|
|
|
|
|
protected RFuture<Boolean> 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]); "
|
|
|
|
@ -941,10 +998,7 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public RFuture<Boolean> fastPutIfAbsentAsync(K key, V value) {
|
|
|
|
|
checkKey(key);
|
|
|
|
|
checkValue(value);
|
|
|
|
|
|
|
|
|
|
protected RFuture<Boolean> fastPutIfAbsentOperationAsync(K key, V value) {
|
|
|
|
|
return commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_BOOLEAN,
|
|
|
|
|
"local value = redis.call('hget', KEYS[1], ARGV[2]); "
|
|
|
|
|
+ "if value == false then "
|
|
|
|
@ -998,7 +1052,7 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public RFuture<Boolean> fastPutIfAbsentAsync(K key, V value, long ttl, TimeUnit ttlUnit, long maxIdleTime, TimeUnit maxIdleUnit) {
|
|
|
|
|
public RFuture<Boolean> fastPutIfAbsentAsync(final K key, final V value, long ttl, TimeUnit ttlUnit, long maxIdleTime, TimeUnit maxIdleUnit) {
|
|
|
|
|
checkKey(key);
|
|
|
|
|
checkValue(value);
|
|
|
|
|
|
|
|
|
@ -1032,7 +1086,7 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
|
|
|
|
|
maxIdleTimeout = System.currentTimeMillis() + maxIdleDelta;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_BOOLEAN,
|
|
|
|
|
RFuture<Boolean> 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 "
|
|
|
|
@ -1085,18 +1139,32 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
|
|
|
|
|
+ "end; ",
|
|
|
|
|
Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key)),
|
|
|
|
|
System.currentTimeMillis(), ttlTimeout, maxIdleTimeout, maxIdleDelta, encodeMapKey(key), encodeMapValue(value));
|
|
|
|
|
if (mapWriter == null) {
|
|
|
|
|
return future;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RPromise<Boolean> result = new MapWriterPromise<Boolean>(future, commandExecutor) {
|
|
|
|
|
@Override
|
|
|
|
|
public void execute(final Future<Boolean> future, ExecutorService executorService) {
|
|
|
|
|
if (future.getNow()) {
|
|
|
|
|
commandExecutor.getConnectionManager().getExecutor().execute(new Runnable() {
|
|
|
|
|
@Override
|
|
|
|
|
public void run() {
|
|
|
|
|
mapWriter.write(key, value);
|
|
|
|
|
trySuccess(future.getNow());
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
trySuccess(future.getNow());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public RFuture<Boolean> replaceAsync(K key, V oldValue, V newValue) {
|
|
|
|
|
checkKey(key);
|
|
|
|
|
if (oldValue == null) {
|
|
|
|
|
throw new NullPointerException("map old value can't be null");
|
|
|
|
|
}
|
|
|
|
|
if (newValue == null) {
|
|
|
|
|
throw new NullPointerException("map new value can't be null");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected RFuture<Boolean> 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 "
|
|
|
|
@ -1134,11 +1202,8 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public RFuture<V> replaceAsync(K key, V value) {
|
|
|
|
|
checkKey(key);
|
|
|
|
|
checkValue(value);
|
|
|
|
|
|
|
|
|
|
return commandExecutor.evalWriteAsync(getName(key), codec, EVAL_REPLACE,
|
|
|
|
|
public RFuture<V> replaceOperationAsync(K key, V value) {
|
|
|
|
|
return commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_MAP_VALUE,
|
|
|
|
|
"local v = redis.call('hget', KEYS[1], ARGV[2]); "
|
|
|
|
|
+ "if v ~= false then "
|
|
|
|
|
+ "local t, val = struct.unpack('dLc0', v); "
|
|
|
|
@ -1156,15 +1221,11 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
|
|
|
|
|
+ "return nil; "
|
|
|
|
|
+ "end",
|
|
|
|
|
Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getUpdatedChannelNameByKey(key)),
|
|
|
|
|
System.currentTimeMillis(), key, value);
|
|
|
|
|
System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public RFuture<Void> putAllAsync(final Map<? extends K, ? extends V> map) {
|
|
|
|
|
if (map.isEmpty()) {
|
|
|
|
|
return newSucceededFuture(null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public RFuture<Void> putAllOperationAsync(Map<? extends K, ? extends V> map) {
|
|
|
|
|
List<Object> params = new ArrayList<Object>(map.size()*2);
|
|
|
|
|
for (java.util.Map.Entry<? extends K, ? extends V> t : map.entrySet()) {
|
|
|
|
|
if (t.getKey() == null) {
|
|
|
|
@ -1174,11 +1235,11 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
|
|
|
|
|
throw new NullPointerException("map value can't be null");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
params.add(t.getKey());
|
|
|
|
|
params.add(t.getValue());
|
|
|
|
|
params.add(encodeMapKey(t.getKey()));
|
|
|
|
|
params.add(encodeMapValue(t.getValue()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return commandExecutor.evalWriteAsync(getName(), codec, EVAL_HMSET,
|
|
|
|
|
return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_VOID,
|
|
|
|
|
"for i, value in ipairs(ARGV) do "
|
|
|
|
|
+ "if i % 2 == 0 then "
|
|
|
|
|
+ "local val = struct.pack('dLc0', 0, string.len(value), value); "
|
|
|
|
|