Improvement - JCache performance optimization. #1722

pull/1792/head
Nikita Koksharov 6 years ago
parent 182e377b90
commit a89f1a7f25

@ -15,6 +15,9 @@
*/
package org.redisson.jcache;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@ -82,6 +85,8 @@ import io.netty.util.internal.PlatformDependent;
*/
public class JCache<K, V> extends RedissonObject implements Cache<K, V> {
private final boolean v2 = System.getProperty("org.jsr107.tck.management.agentId") == null;
private final JCacheManager cacheManager;
private final JCacheConfiguration<K, V> config;
private final ConcurrentMap<CacheEntryListenerConfiguration<K, V>, Map<Integer, String>> listeners =
@ -93,6 +98,13 @@ public class JCache<K, V> extends RedissonObject implements Cache<K, V> {
private boolean closed;
private boolean hasOwnRedisson;
private static final RLock DUMMY_LOCK = (RLock) Proxy.newProxyInstance(JCache.class.getClassLoader(), new Class[] {RLock.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
});
public JCache(JCacheManager cacheManager, Redisson redisson, String name, JCacheConfiguration<K, V> config, boolean hasOwnRedisson) {
super(redisson.getConfig().getCodec(), redisson.getCommandExecutor(), name);
@ -176,7 +188,12 @@ public class JCache<K, V> extends RedissonObject implements Cache<K, V> {
long startTime = currentNanoTime();
RLock lock = getLockedLock(key);
try {
V value = getValueLocked(key);
V value;
if (v2) {
value = getValue(key);
} else {
value = getValueLocked(key);
}
if (value == null) {
cacheManager.getStatBean(this).addMisses(1);
if (config.isReadThrough()) {
@ -253,6 +270,29 @@ public class JCache<K, V> extends RedissonObject implements Cache<K, V> {
private V getValue(K key) {
Long accessTimeout = getAccessTimeout();
if (accessTimeout == -1) {
V value = evalRead(getName(), codec, RedisCommands.EVAL_MAP_VALUE,
"local value = redis.call('hget', KEYS[1], ARGV[3]); "
+ "if value == false then "
+ "return nil; "
+ "end; "
+ "local expireDate = 92233720368547758; "
+ "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[3]); "
+ "if expireDateScore ~= false then "
+ "expireDate = tonumber(expireDateScore); "
+ "end; "
+ "if expireDate <= tonumber(ARGV[2]) then "
+ "return nil; "
+ "end; "
+ "return value; ",
Arrays.<Object>asList(getName(), getTimeoutSetName(), getRemovedChannelName()),
accessTimeout, System.currentTimeMillis(), encodeMapKey(key));
return value;
}
V value = evalWrite(getName(), codec, RedisCommands.EVAL_MAP_VALUE,
"local value = redis.call('hget', KEYS[1], ARGV[3]); "
+ "if value == false then "
@ -301,7 +341,12 @@ public class JCache<K, V> extends RedissonObject implements Cache<K, V> {
V load(K key) {
RLock lock = getLockedLock(key);
try {
V value = getValueLocked(key);
V value;
if (v2) {
value = getValue(key);
} else {
value = getValueLocked(key);
}
if (value == null) {
value = loadValue(key);
}
@ -320,7 +365,11 @@ public class JCache<K, V> extends RedissonObject implements Cache<K, V> {
}
if (value != null) {
long startTime = currentNanoTime();
putValueLocked(key, value);
if (v2) {
putValue(key, value);
} else {
putValueLocked(key, value);
}
cacheManager.getStatBean(this).addGetTime(currentNanoTime() - startTime);
}
return value;
@ -518,14 +567,15 @@ public class JCache<K, V> extends RedissonObject implements Cache<K, V> {
private boolean putIfAbsentValue(K key, Object value) {
Long creationTimeout = getCreationTimeout();
if (creationTimeout == 0) {
return false;
}
return evalWrite(getName(), codec, RedisCommands.EVAL_BOOLEAN,
"if redis.call('hexists', KEYS[1], ARGV[2]) == 1 then "
+ "return 0; "
+ "else "
+ "if ARGV[1] == '0' then "
+ "return 0;"
+ "elseif ARGV[1] ~= '-1' then "
+ "if ARGV[1] ~= '-1' then "
+ "redis.call('hset', KEYS[1], ARGV[2], ARGV[3]); "
+ "redis.call('zadd', KEYS[2], ARGV[1], ARGV[2]); "
+ "local msg = struct.pack('Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3]); "
@ -548,10 +598,11 @@ public class JCache<K, V> extends RedissonObject implements Cache<K, V> {
}
Long creationTimeout = getCreationTimeout();
if (creationTimeout == 0) {
return false;
}
return evalWrite(getName(), codec, RedisCommands.EVAL_BOOLEAN,
"if ARGV[1] == '0' then "
+ "return 0;"
+ "elseif ARGV[1] ~= '-1' then "
"if ARGV[1] ~= '-1' then "
+ "redis.call('hset', KEYS[1], ARGV[2], ARGV[3]); "
+ "redis.call('zadd', KEYS[2], ARGV[1], ARGV[2]); "
+ "local msg = struct.pack('Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3]); "
@ -590,15 +641,18 @@ public class JCache<K, V> extends RedissonObject implements Cache<K, V> {
}
long startTime = currentNanoTime();
boolean exists = false;
for (K key : keys) {
if (containsKey(key)) {
exists = true;
if (!config.isReadThrough()) {
boolean exists = false;
for (K key : keys) {
if (containsKey(key)) {
exists = true;
break;
}
}
if (!exists) {
cacheManager.getStatBean(this).addGetTime(currentNanoTime() - startTime);
return Collections.emptyMap();
}
}
if (!exists && !config.isReadThrough()) {
cacheManager.getStatBean(this).addGetTime(currentNanoTime() - startTime);
return Collections.emptyMap();
}
@ -608,43 +662,75 @@ public class JCache<K, V> extends RedissonObject implements Cache<K, V> {
args.add(accessTimeout);
args.add(System.currentTimeMillis());
encode(args, keys);
Map<K, V> res;
if (accessTimeout == -1) {
res = evalRead(getName(), codec, new RedisCommand<Map<Object, Object>>("EVAL", new MapGetAllDecoder(new ArrayList<Object>(keys), 0, true), ValueType.MAP_VALUE),
"local expireHead = redis.call('zrange', KEYS[2], 0, 0, 'withscores');"
+ "local accessTimeout = ARGV[1]; "
+ "local currentTime = tonumber(ARGV[2]); "
+ "local hasExpire = #expireHead == 2 and tonumber(expireHead[2]) <= currentTime; "
+ "local map = redis.call('hmget', KEYS[1], unpack(ARGV, 3, #ARGV)); "
+ "local result = {};"
+ "for i, value in ipairs(map) do "
+ "if value ~= false then "
+ "local key = ARGV[i+2]; "
+ "if hasExpire then "
+ "local expireDate = 92233720368547758; "
+ "local expireDateScore = redis.call('zscore', KEYS[2], key); "
+ "if expireDateScore ~= false then "
+ "expireDate = tonumber(expireDateScore); "
+ "end; "
+ "if expireDate <= currentTime then "
+ "value = false; "
+ "end; "
+ "end; "
+ "end; "
Map<K, V> res = evalWrite(getName(), codec, new RedisCommand<Map<Object, Object>>("EVAL", new MapGetAllDecoder(new ArrayList<Object>(keys), 0, true), ValueType.MAP_VALUE),
"local expireHead = redis.call('zrange', KEYS[2], 0, 0, 'withscores');"
+ "local accessTimeout = ARGV[1]; "
+ "local currentTime = tonumber(ARGV[2]); "
+ "local hasExpire = #expireHead == 2 and tonumber(expireHead[2]) <= currentTime; "
+ "local map = redis.call('hmget', KEYS[1], unpack(ARGV, 3, #ARGV)); "
+ "local result = {};"
+ "for i, value in ipairs(map) do "
+ "if value ~= false then "
+ "local key = ARGV[i+2]; "
+ "if hasExpire then "
+ "local expireDate = 92233720368547758; "
+ "local expireDateScore = redis.call('zscore', KEYS[2], key); "
+ "if expireDateScore ~= false then "
+ "expireDate = tonumber(expireDateScore); "
+ "table.insert(result, value); "
+ "end; "
+ "return result;",
Arrays.<Object>asList(getName(), getTimeoutSetName(), getRemovedChannelName()), args.toArray());
} else {
res = evalWrite(getName(), codec, new RedisCommand<Map<Object, Object>>("EVAL", new MapGetAllDecoder(new ArrayList<Object>(keys), 0, true), ValueType.MAP_VALUE),
"local expireHead = redis.call('zrange', KEYS[2], 0, 0, 'withscores');"
+ "local accessTimeout = ARGV[1]; "
+ "local currentTime = tonumber(ARGV[2]); "
+ "local hasExpire = #expireHead == 2 and tonumber(expireHead[2]) <= currentTime; "
+ "local map = redis.call('hmget', KEYS[1], unpack(ARGV, 3, #ARGV)); "
+ "local result = {};"
+ "for i, value in ipairs(map) do "
+ "if value ~= false then "
+ "local key = ARGV[i+2]; "
+ "if hasExpire then "
+ "local expireDate = 92233720368547758; "
+ "local expireDateScore = redis.call('zscore', KEYS[2], key); "
+ "if expireDateScore ~= false then "
+ "expireDate = tonumber(expireDateScore); "
+ "end; "
+ "if expireDate <= currentTime then "
+ "value = false; "
+ "end; "
+ "end; "
+ "if expireDate <= currentTime then "
+ "value = false; "
+ "if accessTimeout == '0' then "
+ "redis.call('hdel', KEYS[1], key); "
+ "redis.call('zrem', KEYS[2], key); "
+ "local msg = struct.pack('Lc0Lc0', string.len(key), key, string.len(value), value); "
+ "redis.call('publish', KEYS[3], {key, value}); "
+ "elseif accessTimeout ~= '-1' then "
+ "redis.call('zadd', KEYS[2], accessTimeout, key); "
+ "end; "
+ "end; "
+ "if accessTimeout == '0' then "
+ "redis.call('hdel', KEYS[1], key); "
+ "redis.call('zrem', KEYS[2], key); "
+ "local msg = struct.pack('Lc0Lc0', string.len(key), key, string.len(value), value); "
+ "redis.call('publish', KEYS[3], {key, value}); "
+ "elseif accessTimeout ~= '-1' then "
+ "redis.call('zadd', KEYS[2], accessTimeout, key); "
+ "end; "
+ "table.insert(result, value); "
+ "end; "
+ "return result;",
Arrays.<Object>asList(getName(), getTimeoutSetName(), getRemovedChannelName()), args.toArray());
}
+ "table.insert(result, value); "
+ "end; "
+ "return result;",
Arrays.<Object>asList(getName(), getTimeoutSetName(), getRemovedChannelName()), args.toArray());
Map<K, V> result = new HashMap<K, V>();
for (Map.Entry<K, V> entry : res.entrySet()) {
@ -674,7 +760,7 @@ public class JCache<K, V> extends RedissonObject implements Cache<K, V> {
throw new NullPointerException();
}
return evalWrite(getName(), codec, RedisCommands.EVAL_BOOLEAN,
return evalRead(getName(), codec, RedisCommands.EVAL_BOOLEAN,
"if redis.call('hexists', KEYS[1], ARGV[2]) == 0 then "
+ "return 0;"
+ "end;"
@ -729,7 +815,11 @@ public class JCache<K, V> extends RedissonObject implements Cache<K, V> {
throw new CacheLoaderException(ex);
}
if (value != null) {
putValueLocked(key, value);
if (v2) {
putValue(key, value);
} else {
putValueLocked(key, value);
}
}
}
} finally {
@ -751,6 +841,10 @@ public class JCache<K, V> extends RedissonObject implements Cache<K, V> {
}
private RLock getLockedLock(K key) {
if (v2) {
return DUMMY_LOCK;
}
String lockName = getLockName(key);
RLock lock = redisson.getLock(lockName);
try {
@ -776,7 +870,12 @@ public class JCache<K, V> extends RedissonObject implements Cache<K, V> {
if (config.isWriteThrough()) {
RLock lock = getLockedLock(key);
try {
List<Object> result = getAndPutValueLocked(key, value);
List<Object> result;
if (v2) {
result = getAndPutValue(key, value);
} else {
result = getAndPutValueLocked(key, value);
}
if (result.isEmpty()) {
cacheManager.getStatBean(this).addPuts(1);
cacheManager.getStatBean(this).addPutTime(currentNanoTime() - startTime);
@ -821,7 +920,12 @@ public class JCache<K, V> extends RedissonObject implements Cache<K, V> {
} else {
RLock lock = getLockedLock(key);
try {
boolean result = putValueLocked(key, value);
boolean result;
if (v2) {
result = putValue(key, value);
} else {
result = putValueLocked(key, value);
}
if (result) {
cacheManager.getStatBean(this).addPuts(1);
}
@ -988,7 +1092,12 @@ public class JCache<K, V> extends RedissonObject implements Cache<K, V> {
if (config.isWriteThrough()) {
RLock lock = getLockedLock(key);
try {
List<Object> result = getAndPutValueLocked(key, value);
List<Object> result;
if (v2) {
result = getAndPutValue(key, value);
} else {
result = getAndPutValueLocked(key, value);
}
if (result.isEmpty()) {
cacheManager.getStatBean(this).addPuts(1);
cacheManager.getStatBean(this).addMisses(1);
@ -1037,7 +1146,12 @@ public class JCache<K, V> extends RedissonObject implements Cache<K, V> {
} else {
RLock lock = getLockedLock(key);
try {
List<Object> result = getAndPutValueLocked(key, value);
List<Object> result;
if (v2) {
result = getAndPutValue(key, value);
} else {
result = getAndPutValueLocked(key, value);
}
return getAndPutResult(startTime, result);
} finally {
lock.unlock();
@ -1190,7 +1304,12 @@ public class JCache<K, V> extends RedissonObject implements Cache<K, V> {
if (config.isWriteThrough()) {
RLock lock = getLockedLock(key);
try {
boolean result = putIfAbsentValueLocked(key, value);
boolean result;
if (v2) {
result = putIfAbsentValue(key, value);
} else {
result = putIfAbsentValueLocked(key, value);
}
if (result) {
cacheManager.getStatBean(this).addPuts(1);
try {
@ -1211,7 +1330,12 @@ public class JCache<K, V> extends RedissonObject implements Cache<K, V> {
} else {
RLock lock = getLockedLock(key);
try {
boolean result = putIfAbsentValueLocked(key, value);
boolean result;
if (v2) {
result = putIfAbsentValue(key, value);
} else {
result = putIfAbsentValueLocked(key, value);
}
if (result) {
cacheManager.getStatBean(this).addPuts(1);
}
@ -1271,8 +1395,7 @@ public class JCache<K, V> extends RedissonObject implements Cache<K, V> {
if (config.isWriteThrough()) {
RLock lock = getLockedLock(key);
try {
V oldValue = getValue(key);
boolean result = removeValue(key);
V oldValue = getAndRemoveValue(key);
try {
cacheWriter.delete(key);
} catch (CacheWriterException e) {
@ -1286,11 +1409,11 @@ public class JCache<K, V> extends RedissonObject implements Cache<K, V> {
}
throw new CacheWriterException(e);
}
if (result) {
if (oldValue != null) {
cacheManager.getStatBean(this).addRemovals(1);
}
cacheManager.getStatBean(this).addRemoveTime(currentNanoTime() - startTime);
return result;
return oldValue != null;
} finally {
lock.unlock();
}
@ -1412,7 +1535,11 @@ public class JCache<K, V> extends RedissonObject implements Cache<K, V> {
if (config.isWriteThrough()) {
RLock lock = getLockedLock(key);
try {
result = removeValueLocked(key, value);
if (v2) {
result = removeValue(key, value);
} else {
result = removeValueLocked(key, value);
}
if (result) {
try {
cacheWriter.delete(key);
@ -1438,7 +1565,11 @@ public class JCache<K, V> extends RedissonObject implements Cache<K, V> {
} else {
RLock lock = getLockedLock(key);
try {
result = removeValueLocked(key, value);
if (v2) {
result = removeValue(key, value);
} else {
result = removeValueLocked(key, value);
}
if (result) {
cacheManager.getStatBean(this).addHits(1);
cacheManager.getStatBean(this).addRemovals(1);
@ -1707,7 +1838,12 @@ public class JCache<K, V> extends RedissonObject implements Cache<K, V> {
if (config.isWriteThrough()) {
RLock lock = getLockedLock(key);
try {
long result = replaceValueLocked(key, oldValue, newValue);
long result;
if (v2) {
result = replaceValue(key, oldValue, newValue);
} else {
result = replaceValueLocked(key, oldValue, newValue);
}
if (result == 1) {
try {
cacheWriter.write(new JCacheEntry<K, V>(key, newValue));
@ -1739,7 +1875,12 @@ public class JCache<K, V> extends RedissonObject implements Cache<K, V> {
} else {
RLock lock = getLockedLock(key);
try {
long result = replaceValueLocked(key, oldValue, newValue);
long result;
if (v2) {
result = replaceValue(key, oldValue, newValue);
} else {
result = replaceValueLocked(key, oldValue, newValue);
}
if (result == 1) {
cacheManager.getStatBean(this).addHits(1);
cacheManager.getStatBean(this).addPuts(1);
@ -1950,7 +2091,12 @@ public class JCache<K, V> extends RedissonObject implements Cache<K, V> {
if (config.isWriteThrough()) {
RLock lock = getLockedLock(key);
try {
boolean result = replaceValueLocked(key, value);
boolean result;
if (v2) {
result = replaceValue(key, value);
} else {
result = replaceValueLocked(key, value);
}
if (result) {
cacheManager.getStatBean(this).addHits(1);
cacheManager.getStatBean(this).addPuts(1);
@ -1974,7 +2120,12 @@ public class JCache<K, V> extends RedissonObject implements Cache<K, V> {
} else {
RLock lock = getLockedLock(key);
try {
boolean result = replaceValueLocked(key, value);
boolean result;
if (v2) {
result = replaceValue(key, value);
} else {
result = replaceValueLocked(key, value);
}
if (result) {
cacheManager.getStatBean(this).addHits(1);
cacheManager.getStatBean(this).addPuts(1);
@ -2003,7 +2154,12 @@ public class JCache<K, V> extends RedissonObject implements Cache<K, V> {
if (config.isWriteThrough()) {
RLock lock = getLockedLock(key);
try {
V result = getAndReplaceValueLocked(key, value);
V result;
if (v2) {
result = getAndReplaceValue(key, value);
} else {
result = getAndReplaceValueLocked(key, value);
}
if (result != null) {
cacheManager.getStatBean(this).addHits(1);
cacheManager.getStatBean(this).addPuts(1);
@ -2028,7 +2184,12 @@ public class JCache<K, V> extends RedissonObject implements Cache<K, V> {
} else {
RLock lock = getLockedLock(key);
try {
V result = getAndReplaceValueLocked(key, value);
V result;
if (v2) {
result = getAndReplaceValue(key, value);
} else {
result = getAndReplaceValueLocked(key, value);
}
if (result != null) {
cacheManager.getStatBean(this).addHits(1);
cacheManager.getStatBean(this).addPuts(1);

Loading…
Cancel
Save