Merge pull request #830 from jackygurui/add-and-get-for-mapcache

fix the #827
pull/856/head
Nikita Koksharov 8 years ago committed by GitHub
commit e35737e08b

@ -51,6 +51,10 @@ import org.redisson.eviction.EvictionScheduler;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
import java.io.IOException;
import java.math.BigDecimal;
import org.redisson.client.codec.StringCodec;
import org.redisson.client.protocol.convertor.NumberConvertor;
/**
* <p>Map-based cache with ability to set TTL for each entry via
@ -364,7 +368,7 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
return commandExecutor.evalWriteAsync(getName(key), codec, EVAL_PUT,
"local value = struct.pack('dLc0', 0, string.len(ARGV[2]), ARGV[2]); "
+ "if redis.call('hsetnx', KEYS[1], ARGV[1], value) == 1 then "
+ "return nil "
+ "return nil;"
+ "else "
+ "local v = redis.call('hget', KEYS[1], ARGV[1]); "
+ "if v == false then "
@ -376,6 +380,56 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
Collections.<Object>singletonList(getName(key)), key, value);
}
@Override
public V addAndGet(K key, Number value) {
return get(addAndGetAsync(key, value));
}
@Override
public RFuture<V> addAndGetAsync(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]); "
+ "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 expireDate >= tonumber(ARGV[1]) then "
+ "newValue = tonumber(val) + newValue; "
+ "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.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key)), System.currentTimeMillis(), keyState, valueState);
}
@Override
public boolean fastPut(K key, V value, long ttl, TimeUnit ttlUnit) {
return get(fastPutAsync(key, value, ttl, ttlUnit));

@ -20,6 +20,8 @@ import org.junit.Test;
import org.redisson.api.RFuture;
import org.redisson.api.RMap;
import org.redisson.api.RMapCache;
import org.redisson.client.codec.LongCodec;
import org.redisson.client.codec.StringCodec;
import org.redisson.codec.JsonJacksonCodec;
import org.redisson.codec.MsgPackJacksonCodec;
@ -839,6 +841,31 @@ public class RedissonMapCacheTest extends BaseTest {
}
}
@Test
public void testIssue827() {
RMapCache<String, Object> mapCache = redisson.getMapCache("test_put_if_absent", StringCodec.INSTANCE);
mapCache.putIfAbsent("4", 0L, 10000L, TimeUnit.SECONDS);
mapCache.addAndGet("4", 1L);
mapCache.putIfAbsent("4", 0L);
Assert.assertEquals("1", mapCache.get("4"));
mapCache = redisson.getMapCache("test_put_if_absent_1", StringCodec.INSTANCE);
mapCache.putIfAbsent("4", 0L);
mapCache.addAndGet("4", 1L);
mapCache.putIfAbsent("4", 0L);
Assert.assertEquals("1", mapCache.get("4"));
RMap map = redisson.getMap("test_put_if_absent_2", StringCodec.INSTANCE);
map.putIfAbsent("4", 0L);
map.addAndGet("4", 1L);
map.putIfAbsent("4", 0L);
Assert.assertEquals("1", map.get("4"));
RMapCache<String, Object> mapCache1 = redisson.getMapCache("test_put_if_absent_3");
Object currValue = mapCache1.putIfAbsent("4", 1.23, 10000L, TimeUnit.SECONDS);
Object updatedValue = mapCache1.addAndGet("4", 1D);
System.out.println("updatedValue: " + updatedValue);
Assert.assertEquals(2.23, mapCache1.get("4"));
}
@Test
public void testFastPutIfAbsentWithTTL() throws Exception {
RMapCache<SimpleKey, SimpleValue> map = redisson.getMapCache("simpleTTL");

Loading…
Cancel
Save