diff --git a/redisson/src/main/java/org/redisson/RedissonLocalCachedMap.java b/redisson/src/main/java/org/redisson/RedissonLocalCachedMap.java index 0dfd43fceba2e691c28e66cab4e8a1c2e059cc27..003ed5c361636f6772f7199fa7c7952e9c4e5ff2 100644 --- a/redisson/src/main/java/org/redisson/RedissonLocalCachedMap.java +++ b/redisson/src/main/java/org/redisson/RedissonLocalCachedMap.java @@ -29,7 +29,10 @@ import org.redisson.client.codec.StringCodec; import org.redisson.client.protocol.RedisCommand; import org.redisson.client.protocol.RedisCommands; import org.redisson.client.protocol.convertor.NumberConvertor; -import org.redisson.client.protocol.decoder.*; +import org.redisson.client.protocol.decoder.MapKeyDecoder; +import org.redisson.client.protocol.decoder.ObjectMapEntryReplayDecoder; +import org.redisson.client.protocol.decoder.ObjectMapReplayDecoder; +import org.redisson.client.protocol.decoder.ObjectSetReplayDecoder; import org.redisson.command.CommandAsyncExecutor; import org.redisson.eviction.EvictionScheduler; import org.redisson.misc.RPromise; @@ -197,9 +200,28 @@ public class RedissonLocalCachedMap extends RedissonMap implements R checkKey(key); CacheKey cacheKey = localCacheView.toCacheKey(key); - if (!cache.containsKey(cacheKey)) { + CacheValue cacheValue = cache.get(cacheKey); + if (cacheValue == null) { if (storeMode == LocalCachedMapOptions.StoreMode.LOCALCACHE) { - return RedissonPromise.newSucceededFuture(false); + if (hasNoLoader()) { + return RedissonPromise.newSucceededFuture(false); + } + + RPromise result = new RedissonPromise<>(); + RPromise valuePromise = new RedissonPromise<>(); + loadValue((K) key, valuePromise, false); + valuePromise.onComplete((value, ex) -> { + if (ex != null) { + result.tryFailure(ex); + return; + } + + if (storeCacheMiss || value != null) { + cachePut(cacheKey, key, value); + } + result.trySuccess(value != null); + }); + return result; } RPromise promise = new RedissonPromise<>(); @@ -214,7 +236,8 @@ public class RedissonLocalCachedMap extends RedissonMap implements R }); return containsKeyAsync(key, promise); } - return RedissonPromise.newSucceededFuture(true); + + return RedissonPromise.newSucceededFuture(cacheValue.getValue() != null); } @Override @@ -243,7 +266,23 @@ public class RedissonLocalCachedMap extends RedissonMap implements R } if (storeMode == LocalCachedMapOptions.StoreMode.LOCALCACHE) { - return RedissonPromise.newSucceededFuture(null); + if (hasNoLoader()) { + return RedissonPromise.newSucceededFuture(null); + } + + RPromise result = new RedissonPromise<>(); + loadValue((K) key, result, false); + result.onComplete((value, ex) -> { + if (ex != null) { + result.tryFailure(ex); + return; + } + + if (storeCacheMiss || value != null) { + cachePut(cacheKey, key, value); + } + }); + return result; } RFuture future = super.getAsync((K) key); @@ -591,11 +630,30 @@ public class RedissonLocalCachedMap extends RedissonMap implements R } } + RPromise> promise = new RedissonPromise<>(); if (storeMode == LocalCachedMapOptions.StoreMode.LOCALCACHE) { - return RedissonPromise.newSucceededFuture(result); + if (hasNoLoader()) { + return RedissonPromise.newSucceededFuture(result); + } + + Set newKeys = new HashSet<>(keys); + newKeys.removeAll(result.keySet()); + + if (!newKeys.isEmpty()) { + loadAllAsync(newKeys, false, 1, result).onComplete((r, ex) -> { + if (ex != null) { + promise.tryFailure(ex); + return; + } + promise.trySuccess(result); + }); + } else { + promise.trySuccess(result); + } + + return promise; } - RPromise> promise = new RedissonPromise>(); RFuture> future = super.getAllAsync(mapKeys); future.onComplete((map, e) -> { if (e != null) { diff --git a/redisson/src/main/java/org/redisson/RedissonMap.java b/redisson/src/main/java/org/redisson/RedissonMap.java index bb8be2b933ffc2adf58065218f90cd07e546636b..b098286ed5a3fbcb974ea45cb0e731d11382b4ad 100644 --- a/redisson/src/main/java/org/redisson/RedissonMap.java +++ b/redisson/src/main/java/org/redisson/RedissonMap.java @@ -623,6 +623,11 @@ public class RedissonMap extends RedissonExpirable implements RMap { newKeys.removeAll(res.keySet()); loadAllAsync(newKeys, false, 1, res).onComplete((r, ex) -> { + if (ex != null) { + result.tryFailure(ex); + return; + } + result.trySuccess(res); }); } else { @@ -1212,7 +1217,7 @@ public class RedissonMap extends RedissonExpirable implements RMap { return loadAllAsync((Iterable) keys, replaceExistingValues, parallelism, null); } - private RFuture loadAllAsync(Iterable keys, boolean replaceExistingValues, int parallelism, Map loadedEntires) { + protected RFuture loadAllAsync(Iterable keys, boolean replaceExistingValues, int parallelism, Map loadedEntires) { if (parallelism < 1) { throw new IllegalArgumentException("parallelism can't be lower than 1"); } diff --git a/redisson/src/test/java/org/redisson/BaseMapTest.java b/redisson/src/test/java/org/redisson/BaseMapTest.java index a10d7441b287595ebd4d3202898e9f67838b7543..c20ed7b0eff9b73078653a04888b1705c7646d97 100644 --- a/redisson/src/test/java/org/redisson/BaseMapTest.java +++ b/redisson/src/test/java/org/redisson/BaseMapTest.java @@ -127,7 +127,7 @@ public abstract class BaseMapTest extends BaseTest { } - private void destroy(RMap map) { + protected void destroy(RMap map) { if (map instanceof RDestroyable) { ((RDestroyable) map).destroy(); } @@ -1479,6 +1479,9 @@ public abstract class BaseMapTest extends BaseTest { map.put("0", "00"); assertThat(map.get("0")).isEqualTo("00"); assertThat(map.size()).isEqualTo(2); + + assertThat(map.containsKey("2")).isTrue(); + assertThat(map.size()).isEqualTo(3); Map s = map.getAll(new HashSet<>(Arrays.asList("1", "2", "9", "3"))); Map expectedMap = new HashMap<>(); diff --git a/redisson/src/test/java/org/redisson/RedissonLocalCachedMapTest.java b/redisson/src/test/java/org/redisson/RedissonLocalCachedMapTest.java index ceb36b1681150152bc7619f548b268c708e25020..ab5a15e2e70b81460d3184e7f4d5e4c9658597f7 100644 --- a/redisson/src/test/java/org/redisson/RedissonLocalCachedMapTest.java +++ b/redisson/src/test/java/org/redisson/RedissonLocalCachedMapTest.java @@ -91,6 +91,38 @@ public class RedissonLocalCachedMapTest extends BaseMapTest { } + @Test + public void testMapLoaderGet() { + Map cache = new HashMap<>(); + cache.put("1", "11"); + cache.put("2", "22"); + cache.put("3", "33"); + + LocalCachedMapOptions options = LocalCachedMapOptions.defaults() + .storeMode(LocalCachedMapOptions.StoreMode.LOCALCACHE).loader(createMapLoader(cache)); + RMap map = redisson.getLocalCachedMap("test", options); + + assertThat(map.size()).isEqualTo(0); + assertThat(map.get("1")).isEqualTo("11"); + assertThat(map.size()).isEqualTo(1); + assertThat(map.get("0")).isNull(); + map.put("0", "00"); + assertThat(map.get("0")).isEqualTo("00"); + assertThat(map.size()).isEqualTo(2); + + assertThat(map.containsKey("2")).isTrue(); + assertThat(map.size()).isEqualTo(3); + + Map s = map.getAll(new HashSet<>(Arrays.asList("1", "2", "9", "3"))); + Map expectedMap = new HashMap<>(); + expectedMap.put("1", "11"); + expectedMap.put("2", "22"); + expectedMap.put("3", "33"); + assertThat(s).isEqualTo(expectedMap); + assertThat(map.size()).isEqualTo(4); + destroy(map); + } + @Override protected RMap getMap(String name) { return redisson.getLocalCachedMap(name, LocalCachedMapOptions.defaults()); @@ -328,7 +360,9 @@ public class RedissonLocalCachedMapTest extends BaseMapTest { assertThat(map2.get("1")).isEqualTo(1); assertThat(map2.get("2")).isEqualTo(2); - + + Thread.sleep(50); + assertThat(cache1.size()).isEqualTo(2); assertThat(cache2.size()).isEqualTo(2);