From cb69d7bd9fa50272be80882b3d76e9d0c30bb19c Mon Sep 17 00:00:00 2001 From: Cory Sherman Date: Thu, 20 Apr 2017 20:15:07 -0700 Subject: [PATCH 01/65] add API RGeo.radiusStore() (interface only) These are mostly a copy of existing radius() methods. Since the result is stored in a GeoHash, the GeoOrder parameter is useless without the Count parameter. So we did not include the signatures from radius() with GeoOrder and no Count. --- .../src/main/java/org/redisson/api/RGeo.java | 96 ++++++++++++++++++- .../main/java/org/redisson/api/RGeoAsync.java | 96 ++++++++++++++++++- 2 files changed, 190 insertions(+), 2 deletions(-) diff --git a/redisson/src/main/java/org/redisson/api/RGeo.java b/redisson/src/main/java/org/redisson/api/RGeo.java index 2822a2a64..209a70ac6 100644 --- a/redisson/src/main/java/org/redisson/api/RGeo.java +++ b/redisson/src/main/java/org/redisson/api/RGeo.java @@ -444,5 +444,99 @@ public interface RGeo extends RScoredSortedSet, RGeoAsync { * @return geo position mapped by object */ Map radiusWithPosition(V member, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count); - + + /** + * Finds the members of a sorted set, which are within the + * borders of the area specified with the center location + * and the maximum distance from the center (the radius) + * in GeoUnit units. + * Store result to current Geo. + * + * @param longitude - longitude of object + * @param latitude - latitude of object + * @param radius - radius in geo units + * @param geoUnit - geo unit + * @return length of result + */ + int radiusStore(String fromKey, double longitude, double latitude, double radius, GeoUnit geoUnit); + + /** + * Finds the members of a sorted set, which are within the + * borders of the area specified with the center location + * and the maximum distance from the center (the radius) + * in GeoUnit units and limited by count + * Store result to current Geo. + * + * @param longitude - longitude of object + * @param latitude - latitude of object + * @param radius - radius in geo units + * @param geoUnit - geo unit + * @param count - result limit + * @return length of result + */ + int radiusStore(String fromKey, double longitude, double latitude, double radius, GeoUnit geoUnit, int count); + + /** + * Finds the members of a sorted set, which are within the + * borders of the area specified with the center location + * and the maximum distance from the center (the radius) + * in GeoUnit units with GeoOrder + * and limited by count + * Store result to current Geo. + * + * @param longitude - longitude of object + * @param latitude - latitude of object + * @param radius - radius in geo units + * @param geoUnit - geo unit + * @param geoOrder - order of result + * @param count - result limit + * @return length of result + */ + int radiusStore(String fromKey, double longitude, double latitude, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count); + + /** + * Finds the members of a sorted set, which are within the + * borders of the area specified with the defined member location + * and the maximum distance from the defined member location (the radius) + * in GeoUnit units. + * Store result to current Geo. + * + * @param member - object + * @param radius - radius in geo units + * @param geoUnit - geo unit + * @return length of result + */ + int radiusStore(String fromKey, V member, double radius, GeoUnit geoUnit); + + /** + * Finds the members of a sorted set, which are within the + * borders of the area specified with the defined member location + * and the maximum distance from the defined member location (the radius) + * in GeoUnit units and limited by count + * Store result to current Geo. + * + * @param member - object + * @param radius - radius in geo units + * @param geoUnit - geo unit + * @param count - result limit + * @return length of result + */ + int radiusStore(String fromKey, V member, double radius, GeoUnit geoUnit, int count); + + /** + * Finds the members of a sorted set, which are within the + * borders of the area specified with the defined member location + * and the maximum distance from the defined member location (the radius) + * in GeoUnit units with GeoOrder + * Store result to current Geo. + * + * @param member - object + * @param radius - radius in geo units + * @param geoUnit - geo unit + * @param geoOrder - geo order + * @param count - result limit + * @return length of result + */ + int radiusStore(String fromKey, V member, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count); + } diff --git a/redisson/src/main/java/org/redisson/api/RGeoAsync.java b/redisson/src/main/java/org/redisson/api/RGeoAsync.java index fe618cb5c..f3bf97064 100644 --- a/redisson/src/main/java/org/redisson/api/RGeoAsync.java +++ b/redisson/src/main/java/org/redisson/api/RGeoAsync.java @@ -442,5 +442,99 @@ public interface RGeoAsync extends RScoredSortedSetAsync { * @return geo position mapped by object */ RFuture> radiusWithPositionAsync(V member, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count); - + + /** + * Finds the members of a sorted set, which are within the + * borders of the area specified with the center location + * and the maximum distance from the center (the radius) + * in GeoUnit units. + * Store result to current Geo. + * + * @param longitude - longitude of object + * @param latitude - latitude of object + * @param radius - radius in geo units + * @param geoUnit - geo unit + * @return length of result + */ + RFuture radiusStoreAsync(String fromKey, double longitude, double latitude, double radius, GeoUnit geoUnit); + + /** + * Finds the members of a sorted set, which are within the + * borders of the area specified with the center location + * and the maximum distance from the center (the radius) + * in GeoUnit units and limited by count + * Store result to current Geo. + * + * @param longitude - longitude of object + * @param latitude - latitude of object + * @param radius - radius in geo units + * @param geoUnit - geo unit + * @param count - result limit + * @return length of result + */ + RFuture radiusStoreAsync(String fromKey, double longitude, double latitude, double radius, GeoUnit geoUnit, int count); + + /** + * Finds the members of a sorted set, which are within the + * borders of the area specified with the center location + * and the maximum distance from the center (the radius) + * in GeoUnit units with GeoOrder + * and limited by count + * Store result to current Geo. + * + * @param longitude - longitude of object + * @param latitude - latitude of object + * @param radius - radius in geo units + * @param geoUnit - geo unit + * @param geoOrder - order of result + * @param count - result limit + * @return length of result + */ + RFuture radiusStoreAsync(String fromKey, double longitude, double latitude, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count); + + /** + * Finds the members of a sorted set, which are within the + * borders of the area specified with the defined member location + * and the maximum distance from the defined member location (the radius) + * in GeoUnit units. + * Store result to current Geo. + * + * @param member - object + * @param radius - radius in geo units + * @param geoUnit - geo unit + * @return length of result + */ + RFuture radiusStoreAsync(String fromKey, V member, double radius, GeoUnit geoUnit); + + /** + * Finds the members of a sorted set, which are within the + * borders of the area specified with the defined member location + * and the maximum distance from the defined member location (the radius) + * in GeoUnit units and limited by count + * Store result to current Geo. + * + * @param member - object + * @param radius - radius in geo units + * @param geoUnit - geo unit + * @param count - result limit + * @return length of result + */ + RFuture radiusStoreAsync(String fromKey, V member, double radius, GeoUnit geoUnit, int count); + + /** + * Finds the members of a sorted set, which are within the + * borders of the area specified with the defined member location + * and the maximum distance from the defined member location (the radius) + * in GeoUnit units with GeoOrder + * Store result to current Geo. + * + * @param member - object + * @param radius - radius in geo units + * @param geoUnit - geo unit + * @param geoOrder - geo order + * @param count - result limit + * @return length of result + */ + RFuture radiusStoreAsync(String fromKey, V member, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count); + } From db2d8724560e80d6c4ef565c10b3bb6ad4fe18cd Mon Sep 17 00:00:00 2001 From: Cory Sherman Date: Thu, 20 Apr 2017 21:06:17 -0700 Subject: [PATCH 02/65] add tests for RGeo.radiusStore() --- .../java/org/redisson/RedissonGeoTest.java | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/redisson/src/test/java/org/redisson/RedissonGeoTest.java b/redisson/src/test/java/org/redisson/RedissonGeoTest.java index 42fef915d..87af69633 100644 --- a/redisson/src/test/java/org/redisson/RedissonGeoTest.java +++ b/redisson/src/test/java/org/redisson/RedissonGeoTest.java @@ -476,4 +476,88 @@ public class RedissonGeoTest extends BaseTest { assertThat(geo.radiusWithPosition("Palermo", 200, GeoUnit.KILOMETERS)).isEmpty(); } + @Test + public void testRadiusStore() { + RGeo geoSource = redisson.getGeo("test"); + RGeo geoDest = redisson.getGeo("test-store"); + geoSource.add(new GeoEntry(13.361389, 38.115556, "Palermo"), new GeoEntry(15.087269, 37.502669, "Catania")); + + assertThat(geoDest.radiusStore(geoSource.getName(), 15, 37, 200, GeoUnit.KILOMETERS)).isEqualTo(2); + assertThat(geoDest.readAll()).containsExactlyInAnyOrder("Palermo", "Catania"); + } + + @Test + public void testRadiusStoreCount() { + RGeo geoSource = redisson.getGeo("test"); + RGeo geoDest = redisson.getGeo("test-store"); + geoSource.add(new GeoEntry(13.361389, 38.115556, "Palermo"), new GeoEntry(15.087269, 37.502669, "Catania")); + + assertThat(geoDest.radiusStore(geoSource.getName(), 15, 37, 200, GeoUnit.KILOMETERS, 1)).isEqualTo(1); + assertThat(geoDest.readAll()).containsExactly("Catania"); + } + + @Test + public void testRadiusStoreOrderCount() { + RGeo geoSource = redisson.getGeo("test"); + RGeo geoDest = redisson.getGeo("test-store"); + geoSource.add(new GeoEntry(13.361389, 38.115556, "Palermo"), new GeoEntry(15.087269, 37.502669, "Catania")); + + assertThat(geoDest.radiusStore(geoSource.getName(), 15, 37, 200, GeoUnit.KILOMETERS, GeoOrder.DESC, 1)).isEqualTo(1); + assertThat(geoDest.readAll()).containsExactly("Palermo"); + + assertThat(geoDest.radiusStore(geoSource.getName(), 15, 37, 200, GeoUnit.KILOMETERS, GeoOrder.ASC, 1)).isEqualTo(1); + assertThat(geoDest.readAll()).containsExactly("Catania"); + } + + @Test + public void testRadiusStoreEmpty() { + RGeo geoSource = redisson.getGeo("test"); + RGeo geoDest = redisson.getGeo("test-store"); + + assertThat(geoDest.radiusStore(geoSource.getName(), 15, 37, 200, GeoUnit.KILOMETERS)).isEqualTo(0); + assertThat(geoDest.readAll()).isEmpty(); + } + + @Test + public void testRadiusStoreMember() { + RGeo geoSource = redisson.getGeo("test"); + RGeo geoDest = redisson.getGeo("test-store"); + geoSource.add(new GeoEntry(13.361389, 38.115556, "Palermo"), new GeoEntry(15.087269, 37.502669, "Catania")); + + assertThat(geoDest.radiusStore(geoSource.getName(), "Palermo", 200, GeoUnit.KILOMETERS)).isEqualTo(2); + assertThat(geoDest.readAll()).containsExactlyInAnyOrder("Palermo", "Catania"); + } + + @Test + public void testRadiusStoreMemberCount() { + RGeo geoSource = redisson.getGeo("test"); + RGeo geoDest = redisson.getGeo("test-store"); + geoSource.add(new GeoEntry(13.361389, 38.115556, "Palermo"), new GeoEntry(15.087269, 37.502669, "Catania")); + + assertThat(geoDest.radiusStore(geoSource.getName(), "Palermo", 200, GeoUnit.KILOMETERS, 1)).isEqualTo(1); + assertThat(geoDest.readAll()).containsExactly("Palermo"); + } + + @Test + public void testRadiusStoreMemberOrderCount() { + RGeo geoSource = redisson.getGeo("test"); + RGeo geoDest = redisson.getGeo("test-store"); + geoSource.add(new GeoEntry(13.361389, 38.115556, "Palermo"), new GeoEntry(15.087269, 37.502669, "Catania")); + + assertThat(geoDest.radiusStore(geoSource.getName(), "Palermo", 200, GeoUnit.KILOMETERS, GeoOrder.DESC, 1)).isEqualTo(1); + assertThat(geoDest.readAll()).containsExactly("Catania"); + + assertThat(geoDest.radiusStore(geoSource.getName(), "Palermo", 200, GeoUnit.KILOMETERS, GeoOrder.ASC, 1)).isEqualTo(1); + assertThat(geoDest.readAll()).containsExactly("Palermo"); + } + + @Test + public void testRadiusStoreMemberEmpty() { + RGeo geoSource = redisson.getGeo("test"); + RGeo geoDest = redisson.getGeo("test-store"); + + assertThat(geoDest.radiusStore(geoSource.getName(), "Palermo", 200, GeoUnit.KILOMETERS)).isEqualTo(0); + assertThat(geoDest.readAll()).isEmpty(); + } + } From 7a9305684948771273562e8d0d128f420775d474 Mon Sep 17 00:00:00 2001 From: Cory Sherman Date: Fri, 21 Apr 2017 08:55:32 -0700 Subject: [PATCH 03/65] WIP radiusStore() implementation "GEORADIUS ... STORE" passes tests "GEORADIUSBYMEMBER ... STORE" fails all tests. not sure why --- .../main/java/org/redisson/RedissonGeo.java | 63 ++++++++++++++++++- .../client/protocol/RedisCommands.java | 2 + 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/redisson/src/main/java/org/redisson/RedissonGeo.java b/redisson/src/main/java/org/redisson/RedissonGeo.java index f2939180b..6882e9281 100644 --- a/redisson/src/main/java/org/redisson/RedissonGeo.java +++ b/redisson/src/main/java/org/redisson/RedissonGeo.java @@ -30,6 +30,7 @@ import org.redisson.api.RGeo; import org.redisson.api.RedissonClient; import org.redisson.client.codec.Codec; import org.redisson.client.codec.GeoEntryCodec; +import org.redisson.client.codec.LongCodec; import org.redisson.client.codec.ScoredCodec; import org.redisson.client.protocol.RedisCommand; import org.redisson.client.protocol.RedisCommand.ValueType; @@ -404,5 +405,65 @@ public class RedissonGeo extends RedissonScoredSortedSet implements RGeo> command = new RedisCommand>("GEORADIUSBYMEMBER", postitionDecoder, 2); return commandExecutor.readAsync(getName(), codec, command, getName(), member, radius, geoUnit, "WITHCOORD", "COUNT", count, geoOrder); } - + + @Override + public int radiusStore(String fromKey, double longitude, double latitude, double radius, GeoUnit geoUnit) { + return get(radiusStoreAsync(fromKey, longitude, latitude, radius, geoUnit)); + } + + @Override + public RFuture radiusStoreAsync(String fromKey, double longitude, double latitude, double radius, GeoUnit geoUnit) { + return commandExecutor.writeAsync(fromKey, LongCodec.INSTANCE, RedisCommands.GEORADIUS_STORE_INT, fromKey, convert(longitude), convert(latitude), radius, geoUnit, "STORE", getName()); + } + + @Override + public int radiusStore(String fromKey, double longitude, double latitude, double radius, GeoUnit geoUnit, int count) { + return get(radiusStoreAsync(fromKey, longitude, latitude, radius, geoUnit, count)); + } + + @Override + public RFuture radiusStoreAsync(String fromKey, double longitude, double latitude, double radius, GeoUnit geoUnit, int count) { + return commandExecutor.writeAsync(fromKey, LongCodec.INSTANCE, RedisCommands.GEORADIUS_STORE_INT, fromKey, convert(longitude), convert(latitude), radius, geoUnit, "COUNT", count, "STORE", getName()); + } + + @Override + public int radiusStore(String fromKey, double longitude, double latitude, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count) { + return get(radiusStoreAsync(fromKey, longitude, latitude, radius, geoUnit, geoOrder, count)); + } + + @Override + public RFuture radiusStoreAsync(String fromKey, double longitude, double latitude, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count) { + return commandExecutor.writeAsync(fromKey, LongCodec.INSTANCE, RedisCommands.GEORADIUS_STORE_INT, fromKey, convert(longitude), convert(latitude), radius, geoUnit, geoOrder, "COUNT", count, "STORE", getName()); + } + + @Override + public int radiusStore(String fromKey, V member, double radius, GeoUnit geoUnit) { + return get(radiusStoreAsync(fromKey, member, radius, geoUnit)); + } + + @Override + public RFuture radiusStoreAsync(String fromKey, V member, double radius, GeoUnit geoUnit) { + return commandExecutor.writeAsync(fromKey, LongCodec.INSTANCE, RedisCommands.GEORADIUSBYMEMBER_STORE_INT, fromKey, member, radius, geoUnit, "STORE", getName()); + } + + @Override + public int radiusStore(String fromKey, V member, double radius, GeoUnit geoUnit, int count) { + return get(radiusStoreAsync(fromKey, member, radius, geoUnit, count)); + } + + @Override + public RFuture radiusStoreAsync(String fromKey, V member, double radius, GeoUnit geoUnit, int count) { + return commandExecutor.writeAsync(fromKey, LongCodec.INSTANCE, RedisCommands.GEORADIUSBYMEMBER_STORE_INT, fromKey, member, radius, geoUnit, "COUNT", count, "STORE", getName()); + } + + @Override + public int radiusStore(String fromKey, V member, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count) { + return get(radiusStoreAsync(fromKey, member, radius, geoUnit, count)); + } + + @Override + public RFuture radiusStoreAsync(String fromKey, V member, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count) { + return commandExecutor.writeAsync(fromKey, LongCodec.INSTANCE, RedisCommands.GEORADIUSBYMEMBER_STORE_INT, fromKey, member, radius, geoUnit, geoOrder, "COUNT", count, "STORE", getName()); + } + } diff --git a/redisson/src/main/java/org/redisson/client/protocol/RedisCommands.java b/redisson/src/main/java/org/redisson/client/protocol/RedisCommands.java index e9f40a102..9eabd6509 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/RedisCommands.java +++ b/redisson/src/main/java/org/redisson/client/protocol/RedisCommands.java @@ -76,6 +76,8 @@ public interface RedisCommands { RedisCommand GEODIST = new RedisCommand("GEODIST", new DoubleReplayConvertor(), 2, Arrays.asList(ValueType.OBJECT, ValueType.OBJECT, ValueType.STRING)); RedisCommand> GEORADIUS = new RedisCommand>("GEORADIUS", new ObjectListReplayDecoder()); RedisCommand> GEORADIUSBYMEMBER = new RedisCommand>("GEORADIUSBYMEMBER", new ObjectListReplayDecoder(), 2); + RedisCommand GEORADIUS_STORE_INT = new RedisStrictCommand("GEORADIUS", new IntegerReplayConvertor()); + RedisCommand GEORADIUSBYMEMBER_STORE_INT = new RedisStrictCommand("GEORADIUSBYMEMBER", new IntegerReplayConvertor(), 2); RedisStrictCommand KEYSLOT = new RedisStrictCommand("CLUSTER", "KEYSLOT", new IntegerReplayConvertor()); RedisStrictCommand TYPE = new RedisStrictCommand("TYPE", new TypeConvertor()); From ca23bb99a2982910fca524924c56efc35c0ed904 Mon Sep 17 00:00:00 2001 From: Cory Sherman Date: Fri, 21 Apr 2017 09:35:07 -0700 Subject: [PATCH 04/65] fix GEORADIUSBYMEMBER STORE it was using the wrong codec for member parameter --- redisson/src/main/java/org/redisson/RedissonGeo.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/redisson/src/main/java/org/redisson/RedissonGeo.java b/redisson/src/main/java/org/redisson/RedissonGeo.java index 6882e9281..9c5f3605d 100644 --- a/redisson/src/main/java/org/redisson/RedissonGeo.java +++ b/redisson/src/main/java/org/redisson/RedissonGeo.java @@ -443,7 +443,7 @@ public class RedissonGeo extends RedissonScoredSortedSet implements RGeo radiusStoreAsync(String fromKey, V member, double radius, GeoUnit geoUnit) { - return commandExecutor.writeAsync(fromKey, LongCodec.INSTANCE, RedisCommands.GEORADIUSBYMEMBER_STORE_INT, fromKey, member, radius, geoUnit, "STORE", getName()); + return commandExecutor.writeAsync(fromKey, codec, RedisCommands.GEORADIUSBYMEMBER_STORE_INT, fromKey, member, radius, geoUnit, "STORE", getName()); } @Override @@ -453,7 +453,7 @@ public class RedissonGeo extends RedissonScoredSortedSet implements RGeo radiusStoreAsync(String fromKey, V member, double radius, GeoUnit geoUnit, int count) { - return commandExecutor.writeAsync(fromKey, LongCodec.INSTANCE, RedisCommands.GEORADIUSBYMEMBER_STORE_INT, fromKey, member, radius, geoUnit, "COUNT", count, "STORE", getName()); + return commandExecutor.writeAsync(fromKey, codec, RedisCommands.GEORADIUSBYMEMBER_STORE_INT, fromKey, member, radius, geoUnit, "COUNT", count, "STORE", getName()); } @Override @@ -463,7 +463,7 @@ public class RedissonGeo extends RedissonScoredSortedSet implements RGeo radiusStoreAsync(String fromKey, V member, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count) { - return commandExecutor.writeAsync(fromKey, LongCodec.INSTANCE, RedisCommands.GEORADIUSBYMEMBER_STORE_INT, fromKey, member, radius, geoUnit, geoOrder, "COUNT", count, "STORE", getName()); + return commandExecutor.writeAsync(fromKey, codec, RedisCommands.GEORADIUSBYMEMBER_STORE_INT, fromKey, member, radius, geoUnit, geoOrder, "COUNT", count, "STORE", getName()); } } From fccab83a7a15c74bd4dbd4f1699fc833aa2e0148 Mon Sep 17 00:00:00 2001 From: Cory Sherman Date: Fri, 21 Apr 2017 11:13:26 -0700 Subject: [PATCH 05/65] WIP radiusStore() impl, only empty tests fail Failed Tests: 1. RedissonGeoTest.testRadiusStoreMemberEmpty org.redisson.client.RedisTimeoutException: Redis server response timeout (3000 ms) occured for command: (GEORADIUSBYMEMBER) with params: [test, Palermo, 200.0, km, STORE, test-store] at org.redisson.command.CommandAsyncService$10.run(CommandAsyncService.java:646) ... 2. RedissonGeoTest.testRadiusStoreEmpty org.redisson.client.RedisTimeoutException: Redis server response timeout (3000 ms) occured for command: (GEORADIUS) with params: [test, 15.0, 37.0, 200.0, km, STORE, test-store] at org.redisson.command.CommandAsyncService$10.run(CommandAsyncService.java:646) ... --- .../src/main/java/org/redisson/RedissonGeo.java | 14 +++++++------- .../redisson/client/protocol/RedisCommands.java | 4 ++-- .../redisson/RedissonScoredSortedSetTest.java | 16 ++++++++++++++++ 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/redisson/src/main/java/org/redisson/RedissonGeo.java b/redisson/src/main/java/org/redisson/RedissonGeo.java index 9c5f3605d..ae4c710eb 100644 --- a/redisson/src/main/java/org/redisson/RedissonGeo.java +++ b/redisson/src/main/java/org/redisson/RedissonGeo.java @@ -413,7 +413,7 @@ public class RedissonGeo extends RedissonScoredSortedSet implements RGeo radiusStoreAsync(String fromKey, double longitude, double latitude, double radius, GeoUnit geoUnit) { - return commandExecutor.writeAsync(fromKey, LongCodec.INSTANCE, RedisCommands.GEORADIUS_STORE_INT, fromKey, convert(longitude), convert(latitude), radius, geoUnit, "STORE", getName()); + return commandExecutor.writeAsync(getName(), LongCodec.INSTANCE, RedisCommands.GEORADIUS_STORE_INT, fromKey, convert(longitude), convert(latitude), radius, geoUnit, "STORE", getName()); } @Override @@ -423,7 +423,7 @@ public class RedissonGeo extends RedissonScoredSortedSet implements RGeo radiusStoreAsync(String fromKey, double longitude, double latitude, double radius, GeoUnit geoUnit, int count) { - return commandExecutor.writeAsync(fromKey, LongCodec.INSTANCE, RedisCommands.GEORADIUS_STORE_INT, fromKey, convert(longitude), convert(latitude), radius, geoUnit, "COUNT", count, "STORE", getName()); + return commandExecutor.writeAsync(getName(), LongCodec.INSTANCE, RedisCommands.GEORADIUS_STORE_INT, fromKey, convert(longitude), convert(latitude), radius, geoUnit, "COUNT", count, "STORE", getName()); } @Override @@ -433,7 +433,7 @@ public class RedissonGeo extends RedissonScoredSortedSet implements RGeo radiusStoreAsync(String fromKey, double longitude, double latitude, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count) { - return commandExecutor.writeAsync(fromKey, LongCodec.INSTANCE, RedisCommands.GEORADIUS_STORE_INT, fromKey, convert(longitude), convert(latitude), radius, geoUnit, geoOrder, "COUNT", count, "STORE", getName()); + return commandExecutor.writeAsync(getName(), LongCodec.INSTANCE, RedisCommands.GEORADIUS_STORE_INT, fromKey, convert(longitude), convert(latitude), radius, geoUnit, geoOrder, "COUNT", count, "STORE", getName()); } @Override @@ -443,7 +443,7 @@ public class RedissonGeo extends RedissonScoredSortedSet implements RGeo radiusStoreAsync(String fromKey, V member, double radius, GeoUnit geoUnit) { - return commandExecutor.writeAsync(fromKey, codec, RedisCommands.GEORADIUSBYMEMBER_STORE_INT, fromKey, member, radius, geoUnit, "STORE", getName()); + return commandExecutor.writeAsync(getName(), codec, RedisCommands.GEORADIUSBYMEMBER_STORE_INT, fromKey, member, radius, geoUnit, "STORE", getName()); } @Override @@ -453,17 +453,17 @@ public class RedissonGeo extends RedissonScoredSortedSet implements RGeo radiusStoreAsync(String fromKey, V member, double radius, GeoUnit geoUnit, int count) { - return commandExecutor.writeAsync(fromKey, codec, RedisCommands.GEORADIUSBYMEMBER_STORE_INT, fromKey, member, radius, geoUnit, "COUNT", count, "STORE", getName()); + return commandExecutor.writeAsync(getName(), codec, RedisCommands.GEORADIUSBYMEMBER_STORE_INT, fromKey, member, radius, geoUnit, "COUNT", count, "STORE", getName()); } @Override public int radiusStore(String fromKey, V member, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count) { - return get(radiusStoreAsync(fromKey, member, radius, geoUnit, count)); + return get(radiusStoreAsync(fromKey, member, radius, geoUnit, geoOrder, count)); } @Override public RFuture radiusStoreAsync(String fromKey, V member, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count) { - return commandExecutor.writeAsync(fromKey, codec, RedisCommands.GEORADIUSBYMEMBER_STORE_INT, fromKey, member, radius, geoUnit, geoOrder, "COUNT", count, "STORE", getName()); + return commandExecutor.writeAsync(getName(), codec, RedisCommands.GEORADIUSBYMEMBER_STORE_INT, fromKey, member, radius, geoUnit, geoOrder, "COUNT", count, "STORE", getName()); } } diff --git a/redisson/src/main/java/org/redisson/client/protocol/RedisCommands.java b/redisson/src/main/java/org/redisson/client/protocol/RedisCommands.java index 9eabd6509..c155aecc0 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/RedisCommands.java +++ b/redisson/src/main/java/org/redisson/client/protocol/RedisCommands.java @@ -76,8 +76,8 @@ public interface RedisCommands { RedisCommand GEODIST = new RedisCommand("GEODIST", new DoubleReplayConvertor(), 2, Arrays.asList(ValueType.OBJECT, ValueType.OBJECT, ValueType.STRING)); RedisCommand> GEORADIUS = new RedisCommand>("GEORADIUS", new ObjectListReplayDecoder()); RedisCommand> GEORADIUSBYMEMBER = new RedisCommand>("GEORADIUSBYMEMBER", new ObjectListReplayDecoder(), 2); - RedisCommand GEORADIUS_STORE_INT = new RedisStrictCommand("GEORADIUS", new IntegerReplayConvertor()); - RedisCommand GEORADIUSBYMEMBER_STORE_INT = new RedisStrictCommand("GEORADIUSBYMEMBER", new IntegerReplayConvertor(), 2); + RedisStrictCommand GEORADIUS_STORE_INT = new RedisStrictCommand("GEORADIUS", new IntegerReplayConvertor()); + RedisStrictCommand GEORADIUSBYMEMBER_STORE_INT = new RedisStrictCommand("GEORADIUSBYMEMBER", new IntegerReplayConvertor(), 2); RedisStrictCommand KEYSLOT = new RedisStrictCommand("CLUSTER", "KEYSLOT", new IntegerReplayConvertor()); RedisStrictCommand TYPE = new RedisStrictCommand("TYPE", new TypeConvertor()); diff --git a/redisson/src/test/java/org/redisson/RedissonScoredSortedSetTest.java b/redisson/src/test/java/org/redisson/RedissonScoredSortedSetTest.java index 0d9317848..cf7d0d3c6 100644 --- a/redisson/src/test/java/org/redisson/RedissonScoredSortedSetTest.java +++ b/redisson/src/test/java/org/redisson/RedissonScoredSortedSetTest.java @@ -974,6 +974,22 @@ public class RedissonScoredSortedSetTest extends BaseTest { assertThat(out.getScore("two")).isEqualTo(4); } + @Test + public void testIntersectionEmpty() { + RScoredSortedSet set1 = redisson.getScoredSortedSet("simple1"); + set1.add(1, "one"); + set1.add(2, "two"); + + RScoredSortedSet set2 = redisson.getScoredSortedSet("simple2"); + set2.add(3, "three"); + set2.add(4, "four"); + + RScoredSortedSet out = redisson.getScoredSortedSet("out"); + assertThat(out.intersection(set1.getName(), set2.getName())).isEqualTo(0); + + assertThat(out.readAll()).isEmpty(); + } + @Test public void testIntersectionWithWeight() { RScoredSortedSet set1 = redisson.getScoredSortedSet("simple1"); From 8efdec0ac28c0c678dc4d10c58918b5d8e3d3a1c Mon Sep 17 00:00:00 2001 From: Rui Gu Date: Tue, 25 Apr 2017 23:46:48 +0100 Subject: [PATCH 06/65] Changing data types in xsd file to all strings. Fix #848 added a test case to cover the change --- .../redisson/spring/support/redisson-1.0.xsd | 78 ++++++++-------- .../support/SpringNamespaceWikiTest.java | 90 ++++++++++++++++++- ...namespace_wiki_single_with_placeholder.xml | 57 ++++++++++++ 3 files changed, 184 insertions(+), 41 deletions(-) create mode 100644 redisson/src/test/resources/org/redisson/spring/support/namespace_wiki_single_with_placeholder.xml diff --git a/redisson/src/main/resources/org/redisson/spring/support/redisson-1.0.xsd b/redisson/src/main/resources/org/redisson/spring/support/redisson-1.0.xsd index 49d442556..c16b343ce 100644 --- a/redisson/src/main/resources/org/redisson/spring/support/redisson-1.0.xsd +++ b/redisson/src/main/resources/org/redisson/spring/support/redisson-1.0.xsd @@ -193,7 +193,7 @@ - + - + + type="xsd:string"> + type="xsd:string"> - + timeout time @@ -294,7 +294,7 @@ ]]> - + Node.ping and Node.pingAll @@ -304,7 +304,7 @@ ]]> - + - + - + - + - + - + - + + type="xsd:string"> each slave @@ -419,7 +419,7 @@ ]]> - + each slave @@ -430,7 +430,7 @@ + type="xsd:string"> each slave @@ -441,7 +441,7 @@ + type="xsd:string"> + type="xsd:string"> + type="xsd:string"> - + - + - + + type="xsd:string"> + type="xsd:string"> + type="xsd:string"> - + - + - + - + - + - + + type="xsd:string"> true then invalidation @@ -951,14 +951,14 @@ ]]> - + 0 then local cache is unbounded. ]]> - + - + - + - + - + - + []) null); + method.setAccessible(true); + SingleServerConfig single = (SingleServerConfig) method.invoke(config, (Object[]) null); + assertEquals(10000, single.getIdleConnectionTimeout()); + assertEquals(20000, single.getPingTimeout()); + assertEquals(30000, single.getConnectTimeout()); + assertEquals(40000, single.getTimeout()); + assertEquals(5, single.getRetryAttempts()); + assertEquals(60000, single.getRetryInterval()); + assertEquals(70000, single.getReconnectionTimeout()); + assertEquals(8, single.getFailedAttempts()); + assertEquals("do_not_use_if_it_is_not_set", single.getPassword()); + assertEquals(10, single.getSubscriptionsPerConnection()); + assertEquals("client_name", single.getClientName()); + assertEquals(11, single.getSubscriptionConnectionMinimumIdleSize()); + assertEquals(12, single.getSubscriptionConnectionPoolSize()); + assertEquals(13, single.getConnectionMinimumIdleSize()); + assertEquals(14, single.getConnectionPoolSize()); + assertEquals(15, single.getDatabase()); + assertEquals(false, single.isDnsMonitoring()); + assertEquals(80000, single.getDnsMonitoringInterval()); + ((ConfigurableApplicationContext) context).close(); + } finally { + run.stop(); + } + } + @Test public void testMasterSlave() throws Exception { RedisRunner.RedisProcess master = new RedisRunner() diff --git a/redisson/src/test/resources/org/redisson/spring/support/namespace_wiki_single_with_placeholder.xml b/redisson/src/test/resources/org/redisson/spring/support/namespace_wiki_single_with_placeholder.xml new file mode 100644 index 000000000..01962d373 --- /dev/null +++ b/redisson/src/test/resources/org/redisson/spring/support/namespace_wiki_single_with_placeholder.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + From 3329d1571bdbd4aab85b84e004f040fe6dbb825f Mon Sep 17 00:00:00 2001 From: Nikita Date: Wed, 26 Apr 2017 12:43:57 +0300 Subject: [PATCH 07/65] Comment added --- redisson/src/main/java/org/redisson/client/codec/Codec.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/redisson/src/main/java/org/redisson/client/codec/Codec.java b/redisson/src/main/java/org/redisson/client/codec/Codec.java index c7813c284..94c8c7bbb 100644 --- a/redisson/src/main/java/org/redisson/client/codec/Codec.java +++ b/redisson/src/main/java/org/redisson/client/codec/Codec.java @@ -19,7 +19,10 @@ import org.redisson.client.protocol.Decoder; import org.redisson.client.protocol.Encoder; /** - * Redis codec interface + * Redis codec interface. + *

+ * It's required for implementation to have two constructors + * default and with ClassLoader object as parameter. * * @author Nikita Koksharov * From f47bb511504e2f32fa3e2df7ba19617b93487e09 Mon Sep 17 00:00:00 2001 From: Nikita Date: Wed, 26 Apr 2017 20:00:20 +0300 Subject: [PATCH 08/65] JDK 1.6 compilation fixed --- .../org/redisson/spring/cache/RedissonSpringCacheManager.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/redisson/src/main/java/org/redisson/spring/cache/RedissonSpringCacheManager.java b/redisson/src/main/java/org/redisson/spring/cache/RedissonSpringCacheManager.java index c03924842..fea4663fa 100644 --- a/redisson/src/main/java/org/redisson/spring/cache/RedissonSpringCacheManager.java +++ b/redisson/src/main/java/org/redisson/spring/cache/RedissonSpringCacheManager.java @@ -19,6 +19,7 @@ import java.io.IOException; import java.util.Collection; import java.util.Collections; import java.util.Map; +import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentHashMap; import org.redisson.api.RMap; @@ -49,7 +50,7 @@ public class RedissonSpringCacheManager implements CacheManager, ResourceLoaderA private RedissonClient redisson; private Map configMap = new ConcurrentHashMap(); - private Map instanceMap = new ConcurrentHashMap(); + private ConcurrentMap instanceMap = new ConcurrentHashMap(); private String configLocation; From 351c36c700a64f816694a60ddcd660882f5ad2b6 Mon Sep 17 00:00:00 2001 From: Nikita Date: Wed, 26 Apr 2017 20:15:21 +0300 Subject: [PATCH 09/65] [maven-release-plugin] prepare release redisson-2.9.0 --- pom.xml | 4 ++-- redisson-all/pom.xml | 4 ++-- redisson-tomcat/pom.xml | 2 +- redisson-tomcat/redisson-tomcat-6/pom.xml | 2 +- redisson-tomcat/redisson-tomcat-7/pom.xml | 2 +- redisson-tomcat/redisson-tomcat-8/pom.xml | 2 +- redisson/pom.xml | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/pom.xml b/pom.xml index 716332c67..5b6cee6f7 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.redisson redisson-parent - 2.8.3-SNAPSHOT + 2.9.0 pom Redisson @@ -27,7 +27,7 @@ scm:git:git@github.com:redisson/redisson.git scm:git:git@github.com:redisson/redisson.git scm:git:git@github.com:redisson/redisson.git - HEAD + redisson-2.9.0 diff --git a/redisson-all/pom.xml b/redisson-all/pom.xml index f02132f22..319fdb176 100644 --- a/redisson-all/pom.xml +++ b/redisson-all/pom.xml @@ -4,7 +4,7 @@ org.redisson redisson-parent - 2.8.3-SNAPSHOT + 2.9.0 ../ @@ -26,7 +26,7 @@ scm:git:git@github.com:mrniko/redisson.git scm:git:git@github.com:mrniko/redisson.git scm:git:git@github.com:mrniko/redisson.git - redisson-parent-0.9.0 + redisson-2.9.0 diff --git a/redisson-tomcat/pom.xml b/redisson-tomcat/pom.xml index c74233f23..19780dfda 100644 --- a/redisson-tomcat/pom.xml +++ b/redisson-tomcat/pom.xml @@ -4,7 +4,7 @@ org.redisson redisson-parent - 2.8.3-SNAPSHOT + 2.9.0 ../ diff --git a/redisson-tomcat/redisson-tomcat-6/pom.xml b/redisson-tomcat/redisson-tomcat-6/pom.xml index 00c229ad3..a394375df 100644 --- a/redisson-tomcat/redisson-tomcat-6/pom.xml +++ b/redisson-tomcat/redisson-tomcat-6/pom.xml @@ -4,7 +4,7 @@ org.redisson redisson-tomcat - 2.8.3-SNAPSHOT + 2.9.0 ../ diff --git a/redisson-tomcat/redisson-tomcat-7/pom.xml b/redisson-tomcat/redisson-tomcat-7/pom.xml index c8b357e07..a487be3a5 100644 --- a/redisson-tomcat/redisson-tomcat-7/pom.xml +++ b/redisson-tomcat/redisson-tomcat-7/pom.xml @@ -4,7 +4,7 @@ org.redisson redisson-tomcat - 2.8.3-SNAPSHOT + 2.9.0 ../ diff --git a/redisson-tomcat/redisson-tomcat-8/pom.xml b/redisson-tomcat/redisson-tomcat-8/pom.xml index f592d9d91..6f6e6c368 100644 --- a/redisson-tomcat/redisson-tomcat-8/pom.xml +++ b/redisson-tomcat/redisson-tomcat-8/pom.xml @@ -4,7 +4,7 @@ org.redisson redisson-tomcat - 2.8.3-SNAPSHOT + 2.9.0 ../ diff --git a/redisson/pom.xml b/redisson/pom.xml index 19564494b..e4719c00d 100644 --- a/redisson/pom.xml +++ b/redisson/pom.xml @@ -4,7 +4,7 @@ org.redisson redisson-parent - 2.8.3-SNAPSHOT + 2.9.0 ../ From 30d0074e9a5cbc789791bc87aca85a687d7492df Mon Sep 17 00:00:00 2001 From: Nikita Date: Wed, 26 Apr 2017 20:15:29 +0300 Subject: [PATCH 10/65] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- redisson-all/pom.xml | 4 ++-- redisson-tomcat/pom.xml | 2 +- redisson-tomcat/redisson-tomcat-6/pom.xml | 2 +- redisson-tomcat/redisson-tomcat-7/pom.xml | 2 +- redisson-tomcat/redisson-tomcat-8/pom.xml | 2 +- redisson/pom.xml | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/pom.xml b/pom.xml index 5b6cee6f7..dc1a31cb8 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.redisson redisson-parent - 2.9.0 + 2.9.1-SNAPSHOT pom Redisson @@ -27,7 +27,7 @@ scm:git:git@github.com:redisson/redisson.git scm:git:git@github.com:redisson/redisson.git scm:git:git@github.com:redisson/redisson.git - redisson-2.9.0 + HEAD diff --git a/redisson-all/pom.xml b/redisson-all/pom.xml index 319fdb176..4fa84aaaa 100644 --- a/redisson-all/pom.xml +++ b/redisson-all/pom.xml @@ -4,7 +4,7 @@ org.redisson redisson-parent - 2.9.0 + 2.9.1-SNAPSHOT ../ @@ -26,7 +26,7 @@ scm:git:git@github.com:mrniko/redisson.git scm:git:git@github.com:mrniko/redisson.git scm:git:git@github.com:mrniko/redisson.git - redisson-2.9.0 + redisson-parent-0.9.0 diff --git a/redisson-tomcat/pom.xml b/redisson-tomcat/pom.xml index 19780dfda..3e86006d5 100644 --- a/redisson-tomcat/pom.xml +++ b/redisson-tomcat/pom.xml @@ -4,7 +4,7 @@ org.redisson redisson-parent - 2.9.0 + 2.9.1-SNAPSHOT ../ diff --git a/redisson-tomcat/redisson-tomcat-6/pom.xml b/redisson-tomcat/redisson-tomcat-6/pom.xml index a394375df..57ad5c99d 100644 --- a/redisson-tomcat/redisson-tomcat-6/pom.xml +++ b/redisson-tomcat/redisson-tomcat-6/pom.xml @@ -4,7 +4,7 @@ org.redisson redisson-tomcat - 2.9.0 + 2.9.1-SNAPSHOT ../ diff --git a/redisson-tomcat/redisson-tomcat-7/pom.xml b/redisson-tomcat/redisson-tomcat-7/pom.xml index a487be3a5..cfbbe1b89 100644 --- a/redisson-tomcat/redisson-tomcat-7/pom.xml +++ b/redisson-tomcat/redisson-tomcat-7/pom.xml @@ -4,7 +4,7 @@ org.redisson redisson-tomcat - 2.9.0 + 2.9.1-SNAPSHOT ../ diff --git a/redisson-tomcat/redisson-tomcat-8/pom.xml b/redisson-tomcat/redisson-tomcat-8/pom.xml index 6f6e6c368..68da67d25 100644 --- a/redisson-tomcat/redisson-tomcat-8/pom.xml +++ b/redisson-tomcat/redisson-tomcat-8/pom.xml @@ -4,7 +4,7 @@ org.redisson redisson-tomcat - 2.9.0 + 2.9.1-SNAPSHOT ../ diff --git a/redisson/pom.xml b/redisson/pom.xml index e4719c00d..acb4a3797 100644 --- a/redisson/pom.xml +++ b/redisson/pom.xml @@ -4,7 +4,7 @@ org.redisson redisson-parent - 2.9.0 + 2.9.1-SNAPSHOT ../ From 74b9b6221086478a7aceba2bcd0290c70721dd39 Mon Sep 17 00:00:00 2001 From: Nikita Koksharov Date: Wed, 26 Apr 2017 21:19:41 +0300 Subject: [PATCH 11/65] Update CHANGELOG.md --- CHANGELOG.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index caf082d79..07c8bceb3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,31 @@ Try __ULTRA-FAST__ [Redisson PRO](https://redisson.pro) edition. ## Please take part in [Redisson survey](https://www.surveymonkey.com/r/QXQZH5D) +### 26-Apr-2017 - versions 2.9.0 and 3.4.0 released + +Feature - __`MapReduceService` added__ More details [here](https://github.com/redisson/redisson/wiki/9.-distributed-services/#95-distributed-mapreduce-service) +Feature - `readAllMap` and `readAllMapAsync` methods added to `RMap` +Feature - `readAllKeySet` and `getReadWriteLock` methods added to `RMultimap` +Feature - `RKeys.delete` by objects method added +Feature - `RRemoteService.deregister` method added +Feature - `retryAttempts`, `retryInterval` and `timeout` methods added to `RBatch` object +Feature - `RMapCache.fastPutIfAbsent` with ttl added (thanks to Dobi) +Feature - `EvictionPolicy.WEAK` added for `RLocalCachedMap` +Feature - `LocalCachedMapOptions.invalidationPolicy` introduced for `RLocalCachedMap` +Feature - `expire`, `expireAt`, `move`, `migrate`, `clearExpire`, `renamenx`, `rename`, `remainTimeToLive` methods added to RKey +Improvement - `EvictionPolicy.LRU` optimization for `RLocalCachedMap` +Fixed - `RTopic.onSubscribe` should be invoked after failover process +Fixed - Spring boot with redisson 3.3.2 fails without optional actuator dependency (thanks to Rick Perkowski) +Fixed - `RedissonCacheMap.putIfAbsentAsync` doesn't take in account ttl and minIdleTime params (thanks to Dobi) +Fixed - Spring cache should put NullValue object instead of null +Fixed - Fixed error - No field factory in class Ljava/net/URL +Fixed - Spring cache's method with `@Cacheable(sync=true)` annotation never expires (thanks to Dobi) +Fixed - spring schema file corrected (thanks to Rui Gu) +Fixed - Prevent to set URL.factory to null in case of concurrent URL creation in the URLBuilder (thanks to Björn-Ole Ebers) +Fixed - `RMap.addAndGet` causes bad argument (thanks to Rui Gu) +Fixed - `RedissonSpringCacheManager` creates new cache on each `getCache` call +Fixed - wrong value codec encoder usage for `RedissonLocalCachedMap.fastPutAsync` method + ### 21-Mar-2017 - versions 2.8.2 and 3.3.2 released Feature - Redisson's Spring custom namespace support (thanks to Rui Gu) From d84f3f5aded8e5c9dd5bf0dc31d0978b74ed4e5a Mon Sep 17 00:00:00 2001 From: Nikita Koksharov Date: Wed, 26 Apr 2017 21:21:38 +0300 Subject: [PATCH 12/65] Update README.md --- README.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index eb5f8909a..f5d5f3f03 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,14 @@ Redisson: Redis based In-Memory Data Grid for Java. ==== -[Quick start](https://github.com/redisson/redisson#quick-start) | [Documentation](https://github.com/redisson/redisson/wiki) | [Javadocs](http://www.javadoc.io/doc/org.redisson/redisson/3.3.2) | [Changelog](https://github.com/redisson/redisson/blob/master/CHANGELOG.md) | [Code examples](https://github.com/redisson/redisson-examples) | [Support chat](https://gitter.im/mrniko/redisson) | [Ultra-fast version](https://redisson.pro) +[Quick start](https://github.com/redisson/redisson#quick-start) | [Documentation](https://github.com/redisson/redisson/wiki) | [Javadocs](http://www.javadoc.io/doc/org.redisson/redisson/3.4.0) | [Changelog](https://github.com/redisson/redisson/blob/master/CHANGELOG.md) | [Code examples](https://github.com/redisson/redisson-examples) | [Support chat](https://gitter.im/mrniko/redisson) | [Ultra-fast version](https://redisson.pro) Based on high-performance async and lock-free Java Redis client and [Netty](http://netty.io) framework. ## Please take part in [Redisson survey](https://www.surveymonkey.com/r/QXQZH5D) | Stable Release Version | JDK Version compatibility | Release Date | | ------------- | ------------- | ------------| -| 3.3.2 | 1.8+ | 21.03.2017 | -| 2.8.2 | 1.6, 1.7, 1.8 and Android | 21.03.2017 | +| 3.4.0 | 1.8+ | 26.04.2017 | +| 2.9.0 | 1.6, 1.7, 1.8 and Android | 26.04.2017 | __NOTE__: Both version lines have same features except `CompletionStage` interface added in 3.x.x @@ -47,7 +47,7 @@ Features * [Reactive Streams](https://github.com/redisson/redisson/wiki/3.-operations-execution#32-reactive-way) * [Redis pipelining](https://github.com/redisson/redisson/wiki/10.-additional-features#102-execution-batches-of-commands) (command batches) * Supports Android platform -* Supports auto-reconnect +* Supports auto-reconnection * Supports failed to send command auto-retry * Supports OSGi * Supports many popular codecs ([Jackson JSON](https://github.com/FasterXML/jackson), [Avro](http://avro.apache.org/), [Smile](http://wiki.fasterxml.com/SmileFormatSpec), [CBOR](http://cbor.io/), [MsgPack](http://msgpack.org/), [Kryo](https://github.com/EsotericSoftware/kryo), [FST](https://github.com/RuedigerMoeller/fast-serialization), [LZ4](https://github.com/jpountz/lz4-java), [Snappy](https://github.com/xerial/snappy-java) and JDK Serialization) @@ -82,23 +82,23 @@ Quick start org.redisson redisson - 3.3.2 + 3.4.0 org.redisson redisson - 2.8.2 + 2.9.0 #### Gradle // JDK 1.8+ compatible - compile 'org.redisson:redisson:3.3.2' + compile 'org.redisson:redisson:3.4.0' // JDK 1.6+ compatible - compile 'org.redisson:redisson:2.8.2' + compile 'org.redisson:redisson:2.9.0' #### Java @@ -123,11 +123,11 @@ RExecutorService executor = redisson.getExecutorService("myExecutorService"); Downloads =============================== -[Redisson 3.3.2](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson&v=3.3.2&e=jar), -[Redisson node 3.3.2](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-all&v=3.3.2&e=jar) +[Redisson 3.4.0](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson&v=3.4.0&e=jar), +[Redisson node 3.4.0](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-all&v=3.4.0&e=jar) -[Redisson 2.8.2](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson&v=2.8.2&e=jar), -[Redisson node 2.8.2](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-all&v=2.8.2&e=jar) +[Redisson 2.9.0](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson&v=2.9.0&e=jar), +[Redisson node 2.9.0](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-all&v=2.9.0&e=jar) ### Supported by From 5a4e268f9df5e98fa0d9730b572a33d9f5a355f8 Mon Sep 17 00:00:00 2001 From: Rui Gu Date: Thu, 27 Apr 2017 00:50:59 +0100 Subject: [PATCH 13/65] added map reduce service to service section --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f5d5f3f03..af443b9de 100644 --- a/README.md +++ b/README.md @@ -38,9 +38,9 @@ Features * [Distributed locks and synchronizers](https://github.com/redisson/redisson/wiki/8.-Distributed-locks-and-synchronizers) Lock, FairLock, MultiLock, RedLock, ReadWriteLock, Semaphore, PermitExpirableSemaphore, CountDownLatch * [Distributed services](https://github.com/redisson/redisson/wiki/9.-distributed-services) - Remote service, Live Object service, Executor service, Scheduler service -* [Spring Cache](https://github.com/redisson/redisson/wiki/14.-Integration%20with%20frameworks/#141-spring-cache) implementation -* [Hibernate Cache](https://github.com/redisson/redisson/wiki/14.-Integration%20with%20frameworks/#142-hibernate-cache) implementation +    Remote service, Live Object service, Executor service, Scheduler service, MapReduce service +* [Spring Cache](https://github.com/redisson/redisson/wiki/14.-Integration%20with%20frameworks/#141-spring-cache) implementation   +* [Hibernate Cache](https://github.com/redisson/redisson/wiki/14.-Integration%20with%20frameworks/#142-hibernate-cache) implementation * [JCache API (JSR-107)](https://github.com/redisson/redisson/wiki/14.-Integration%20with%20frameworks/#143-jcache-api-jsr-107-implementation) implementation * [Tomcat Session Manager](https://github.com/redisson/redisson/wiki/14.-Integration%20with%20frameworks#144-tomcat-redis-session-manager) implementation * [Spring Session](https://github.com/redisson/redisson/wiki/14.-Integration%20with%20frameworks/#145-spring-session) implementation From 205955f9a481ea43e1b9a4bb0232e4a26095cfc0 Mon Sep 17 00:00:00 2001 From: Rui Gu Date: Thu, 27 Apr 2017 00:52:32 +0100 Subject: [PATCH 14/65] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index af443b9de..18152d3bf 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Features * [Distributed locks and synchronizers](https://github.com/redisson/redisson/wiki/8.-Distributed-locks-and-synchronizers) Lock, FairLock, MultiLock, RedLock, ReadWriteLock, Semaphore, PermitExpirableSemaphore, CountDownLatch * [Distributed services](https://github.com/redisson/redisson/wiki/9.-distributed-services) -    Remote service, Live Object service, Executor service, Scheduler service, MapReduce service + Remote service, Live Object service, Executor service, Scheduler service, MapReduce service * [Spring Cache](https://github.com/redisson/redisson/wiki/14.-Integration%20with%20frameworks/#141-spring-cache) implementation   * [Hibernate Cache](https://github.com/redisson/redisson/wiki/14.-Integration%20with%20frameworks/#142-hibernate-cache) implementation * [JCache API (JSR-107)](https://github.com/redisson/redisson/wiki/14.-Integration%20with%20frameworks/#143-jcache-api-jsr-107-implementation) implementation From e7034f81aed8995e1b00dd26d4f2906400a4ee29 Mon Sep 17 00:00:00 2001 From: Steve Draper Date: Thu, 27 Apr 2017 08:55:10 -0500 Subject: [PATCH 15/65] Fixed local cache resolution of getAllAsync --- .../src/main/java/org/redisson/RedissonLocalCachedMap.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/redisson/src/main/java/org/redisson/RedissonLocalCachedMap.java b/redisson/src/main/java/org/redisson/RedissonLocalCachedMap.java index 0c332b689..d81febe2e 100644 --- a/redisson/src/main/java/org/redisson/RedissonLocalCachedMap.java +++ b/redisson/src/main/java/org/redisson/RedissonLocalCachedMap.java @@ -853,7 +853,8 @@ public class RedissonLocalCachedMap extends RedissonMap implements R Set mapKeys = new HashSet(keys); for (Iterator iterator = mapKeys.iterator(); iterator.hasNext();) { K key = iterator.next(); - CacheValue value = cache.get(key); + final CacheKey cacheKey = toCacheKey(key); + CacheValue value = cache.get(cacheKey); if (value != null) { result.put(key, (V)value.getValue()); iterator.remove(); From 5e34084161e3a0dc9599dbe04e49de02af58b6d8 Mon Sep 17 00:00:00 2001 From: Nikita Date: Thu, 27 Apr 2017 16:57:01 +0300 Subject: [PATCH 16/65] Fixed - reference to avro module has been removed. #865 --- redisson/src/main/java/org/redisson/codec/DefenceModule.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/redisson/src/main/java/org/redisson/codec/DefenceModule.java b/redisson/src/main/java/org/redisson/codec/DefenceModule.java index 377751b24..c24e624be 100644 --- a/redisson/src/main/java/org/redisson/codec/DefenceModule.java +++ b/redisson/src/main/java/org/redisson/codec/DefenceModule.java @@ -24,7 +24,6 @@ import com.fasterxml.jackson.databind.DeserializationConfig; import com.fasterxml.jackson.databind.deser.ValueInstantiator; import com.fasterxml.jackson.databind.deser.ValueInstantiators.Base; import com.fasterxml.jackson.databind.module.SimpleModule; -import com.fasterxml.jackson.dataformat.avro.PackageVersion; /** * Fix for https://github.com/FasterXML/jackson-databind/issues/1599 @@ -68,10 +67,6 @@ public class DefenceModule extends SimpleModule { } - public DefenceModule() { - super(PackageVersion.VERSION); - } - @Override public void setupModule(SetupContext context) { context.addValueInstantiators(new DefenceValueInstantiator()); From 61f070af4e7587e71e74184e950eca4c0a5ec581 Mon Sep 17 00:00:00 2001 From: Nikita Date: Thu, 27 Apr 2017 17:25:11 +0300 Subject: [PATCH 17/65] [maven-release-plugin] prepare release redisson-2.9.1 --- pom.xml | 4 ++-- redisson-all/pom.xml | 4 ++-- redisson-tomcat/pom.xml | 2 +- redisson-tomcat/redisson-tomcat-6/pom.xml | 2 +- redisson-tomcat/redisson-tomcat-7/pom.xml | 2 +- redisson-tomcat/redisson-tomcat-8/pom.xml | 2 +- redisson/pom.xml | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/pom.xml b/pom.xml index dc1a31cb8..feb386279 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.redisson redisson-parent - 2.9.1-SNAPSHOT + 2.9.1 pom Redisson @@ -27,7 +27,7 @@ scm:git:git@github.com:redisson/redisson.git scm:git:git@github.com:redisson/redisson.git scm:git:git@github.com:redisson/redisson.git - HEAD + redisson-2.9.1 diff --git a/redisson-all/pom.xml b/redisson-all/pom.xml index 4fa84aaaa..0bb68c47f 100644 --- a/redisson-all/pom.xml +++ b/redisson-all/pom.xml @@ -4,7 +4,7 @@ org.redisson redisson-parent - 2.9.1-SNAPSHOT + 2.9.1 ../ @@ -26,7 +26,7 @@ scm:git:git@github.com:mrniko/redisson.git scm:git:git@github.com:mrniko/redisson.git scm:git:git@github.com:mrniko/redisson.git - redisson-parent-0.9.0 + redisson-2.9.1 diff --git a/redisson-tomcat/pom.xml b/redisson-tomcat/pom.xml index 3e86006d5..00da8e954 100644 --- a/redisson-tomcat/pom.xml +++ b/redisson-tomcat/pom.xml @@ -4,7 +4,7 @@ org.redisson redisson-parent - 2.9.1-SNAPSHOT + 2.9.1 ../ diff --git a/redisson-tomcat/redisson-tomcat-6/pom.xml b/redisson-tomcat/redisson-tomcat-6/pom.xml index 57ad5c99d..104ee8ec4 100644 --- a/redisson-tomcat/redisson-tomcat-6/pom.xml +++ b/redisson-tomcat/redisson-tomcat-6/pom.xml @@ -4,7 +4,7 @@ org.redisson redisson-tomcat - 2.9.1-SNAPSHOT + 2.9.1 ../ diff --git a/redisson-tomcat/redisson-tomcat-7/pom.xml b/redisson-tomcat/redisson-tomcat-7/pom.xml index cfbbe1b89..9d85e0be3 100644 --- a/redisson-tomcat/redisson-tomcat-7/pom.xml +++ b/redisson-tomcat/redisson-tomcat-7/pom.xml @@ -4,7 +4,7 @@ org.redisson redisson-tomcat - 2.9.1-SNAPSHOT + 2.9.1 ../ diff --git a/redisson-tomcat/redisson-tomcat-8/pom.xml b/redisson-tomcat/redisson-tomcat-8/pom.xml index 68da67d25..326897e41 100644 --- a/redisson-tomcat/redisson-tomcat-8/pom.xml +++ b/redisson-tomcat/redisson-tomcat-8/pom.xml @@ -4,7 +4,7 @@ org.redisson redisson-tomcat - 2.9.1-SNAPSHOT + 2.9.1 ../ diff --git a/redisson/pom.xml b/redisson/pom.xml index acb4a3797..7d5adb9ab 100644 --- a/redisson/pom.xml +++ b/redisson/pom.xml @@ -4,7 +4,7 @@ org.redisson redisson-parent - 2.9.1-SNAPSHOT + 2.9.1 ../ From a704017ace43dd2ff09e6a7b55b7a67541c3ec62 Mon Sep 17 00:00:00 2001 From: Nikita Date: Thu, 27 Apr 2017 17:25:19 +0300 Subject: [PATCH 18/65] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- redisson-all/pom.xml | 4 ++-- redisson-tomcat/pom.xml | 2 +- redisson-tomcat/redisson-tomcat-6/pom.xml | 2 +- redisson-tomcat/redisson-tomcat-7/pom.xml | 2 +- redisson-tomcat/redisson-tomcat-8/pom.xml | 2 +- redisson/pom.xml | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/pom.xml b/pom.xml index feb386279..8f80aad73 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.redisson redisson-parent - 2.9.1 + 2.9.2-SNAPSHOT pom Redisson @@ -27,7 +27,7 @@ scm:git:git@github.com:redisson/redisson.git scm:git:git@github.com:redisson/redisson.git scm:git:git@github.com:redisson/redisson.git - redisson-2.9.1 + HEAD diff --git a/redisson-all/pom.xml b/redisson-all/pom.xml index 0bb68c47f..fd97ba4cd 100644 --- a/redisson-all/pom.xml +++ b/redisson-all/pom.xml @@ -4,7 +4,7 @@ org.redisson redisson-parent - 2.9.1 + 2.9.2-SNAPSHOT ../ @@ -26,7 +26,7 @@ scm:git:git@github.com:mrniko/redisson.git scm:git:git@github.com:mrniko/redisson.git scm:git:git@github.com:mrniko/redisson.git - redisson-2.9.1 + redisson-parent-0.9.0 diff --git a/redisson-tomcat/pom.xml b/redisson-tomcat/pom.xml index 00da8e954..77867c582 100644 --- a/redisson-tomcat/pom.xml +++ b/redisson-tomcat/pom.xml @@ -4,7 +4,7 @@ org.redisson redisson-parent - 2.9.1 + 2.9.2-SNAPSHOT ../ diff --git a/redisson-tomcat/redisson-tomcat-6/pom.xml b/redisson-tomcat/redisson-tomcat-6/pom.xml index 104ee8ec4..e68031e52 100644 --- a/redisson-tomcat/redisson-tomcat-6/pom.xml +++ b/redisson-tomcat/redisson-tomcat-6/pom.xml @@ -4,7 +4,7 @@ org.redisson redisson-tomcat - 2.9.1 + 2.9.2-SNAPSHOT ../ diff --git a/redisson-tomcat/redisson-tomcat-7/pom.xml b/redisson-tomcat/redisson-tomcat-7/pom.xml index 9d85e0be3..12f8db34a 100644 --- a/redisson-tomcat/redisson-tomcat-7/pom.xml +++ b/redisson-tomcat/redisson-tomcat-7/pom.xml @@ -4,7 +4,7 @@ org.redisson redisson-tomcat - 2.9.1 + 2.9.2-SNAPSHOT ../ diff --git a/redisson-tomcat/redisson-tomcat-8/pom.xml b/redisson-tomcat/redisson-tomcat-8/pom.xml index 326897e41..f8457da22 100644 --- a/redisson-tomcat/redisson-tomcat-8/pom.xml +++ b/redisson-tomcat/redisson-tomcat-8/pom.xml @@ -4,7 +4,7 @@ org.redisson redisson-tomcat - 2.9.1 + 2.9.2-SNAPSHOT ../ diff --git a/redisson/pom.xml b/redisson/pom.xml index 7d5adb9ab..9e96bcc9b 100644 --- a/redisson/pom.xml +++ b/redisson/pom.xml @@ -4,7 +4,7 @@ org.redisson redisson-parent - 2.9.1 + 2.9.2-SNAPSHOT ../ From f5735ee03a8bdaba2c46e4b37a870ac2d3ed5dbc Mon Sep 17 00:00:00 2001 From: Nikita Koksharov Date: Thu, 27 Apr 2017 18:23:40 +0300 Subject: [PATCH 19/65] Update README.md --- README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 18152d3bf..4f3b7f8b5 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,14 @@ Redisson: Redis based In-Memory Data Grid for Java. ==== -[Quick start](https://github.com/redisson/redisson#quick-start) | [Documentation](https://github.com/redisson/redisson/wiki) | [Javadocs](http://www.javadoc.io/doc/org.redisson/redisson/3.4.0) | [Changelog](https://github.com/redisson/redisson/blob/master/CHANGELOG.md) | [Code examples](https://github.com/redisson/redisson-examples) | [Support chat](https://gitter.im/mrniko/redisson) | [Ultra-fast version](https://redisson.pro) +[Quick start](https://github.com/redisson/redisson#quick-start) | [Documentation](https://github.com/redisson/redisson/wiki) | [Javadocs](http://www.javadoc.io/doc/org.redisson/redisson/3.4.1) | [Changelog](https://github.com/redisson/redisson/blob/master/CHANGELOG.md) | [Code examples](https://github.com/redisson/redisson-examples) | [Support chat](https://gitter.im/mrniko/redisson) | [Ultra-fast version](https://redisson.pro) Based on high-performance async and lock-free Java Redis client and [Netty](http://netty.io) framework. ## Please take part in [Redisson survey](https://www.surveymonkey.com/r/QXQZH5D) | Stable Release Version | JDK Version compatibility | Release Date | | ------------- | ------------- | ------------| -| 3.4.0 | 1.8+ | 26.04.2017 | -| 2.9.0 | 1.6, 1.7, 1.8 and Android | 26.04.2017 | +| 3.4.1 | 1.8+ | 27.04.2017 | +| 2.9.1 | 1.6, 1.7, 1.8 and Android | 27.04.2017 | __NOTE__: Both version lines have same features except `CompletionStage` interface added in 3.x.x @@ -82,23 +82,23 @@ Quick start org.redisson redisson - 3.4.0 + 3.4.1 org.redisson redisson - 2.9.0 + 2.9.1 #### Gradle // JDK 1.8+ compatible - compile 'org.redisson:redisson:3.4.0' + compile 'org.redisson:redisson:3.4.1' // JDK 1.6+ compatible - compile 'org.redisson:redisson:2.9.0' + compile 'org.redisson:redisson:2.9.1' #### Java @@ -123,11 +123,11 @@ RExecutorService executor = redisson.getExecutorService("myExecutorService"); Downloads =============================== -[Redisson 3.4.0](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson&v=3.4.0&e=jar), -[Redisson node 3.4.0](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-all&v=3.4.0&e=jar) +[Redisson 3.4.1](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson&v=3.4.1&e=jar), +[Redisson node 3.4.1](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-all&v=3.4.1&e=jar) -[Redisson 2.9.0](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson&v=2.9.0&e=jar), -[Redisson node 2.9.0](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-all&v=2.9.0&e=jar) +[Redisson 2.9.1](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson&v=2.9.1&e=jar), +[Redisson node 2.9.1](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-all&v=2.9.1&e=jar) ### Supported by From 35153462b07c3681ddc325fa6c599d7abd0330b9 Mon Sep 17 00:00:00 2001 From: Nikita Koksharov Date: Thu, 27 Apr 2017 18:26:02 +0300 Subject: [PATCH 20/65] Update CHANGELOG.md --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 07c8bceb3..c4be704fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ Try __ULTRA-FAST__ [Redisson PRO](https://redisson.pro) edition. ## Please take part in [Redisson survey](https://www.surveymonkey.com/r/QXQZH5D) +### 27-Apr-2017 - versions 2.9.1 and 3.4.1 released + +Fixed - `RLocalCachedMap.getAll` didn't use cache (thanks to Steve Draper) +Fixed - reference to avro module has been removed + ### 26-Apr-2017 - versions 2.9.0 and 3.4.0 released Feature - __`MapReduceService` added__ More details [here](https://github.com/redisson/redisson/wiki/9.-distributed-services/#95-distributed-mapreduce-service) From cbb485cb0bbba29ce279d4937ced7670a5d2efb9 Mon Sep 17 00:00:00 2001 From: Cory Sherman Date: Thu, 27 Apr 2017 10:59:23 -0700 Subject: [PATCH 21/65] add doc for RGeo.radiusStore fromKey --- redisson/src/main/java/org/redisson/api/RGeo.java | 6 ++++++ redisson/src/main/java/org/redisson/api/RGeoAsync.java | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/redisson/src/main/java/org/redisson/api/RGeo.java b/redisson/src/main/java/org/redisson/api/RGeo.java index 209a70ac6..ccc9ed113 100644 --- a/redisson/src/main/java/org/redisson/api/RGeo.java +++ b/redisson/src/main/java/org/redisson/api/RGeo.java @@ -452,6 +452,7 @@ public interface RGeo extends RScoredSortedSet, RGeoAsync { * in GeoUnit units. * Store result to current Geo. * + * @param fromKey - source Geo key * @param longitude - longitude of object * @param latitude - latitude of object * @param radius - radius in geo units @@ -467,6 +468,7 @@ public interface RGeo extends RScoredSortedSet, RGeoAsync { * in GeoUnit units and limited by count * Store result to current Geo. * + * @param fromKey - source Geo key * @param longitude - longitude of object * @param latitude - latitude of object * @param radius - radius in geo units @@ -484,6 +486,7 @@ public interface RGeo extends RScoredSortedSet, RGeoAsync { * and limited by count * Store result to current Geo. * + * @param fromKey - source Geo key * @param longitude - longitude of object * @param latitude - latitude of object * @param radius - radius in geo units @@ -501,6 +504,7 @@ public interface RGeo extends RScoredSortedSet, RGeoAsync { * in GeoUnit units. * Store result to current Geo. * + * @param fromKey - source Geo key * @param member - object * @param radius - radius in geo units * @param geoUnit - geo unit @@ -515,6 +519,7 @@ public interface RGeo extends RScoredSortedSet, RGeoAsync { * in GeoUnit units and limited by count * Store result to current Geo. * + * @param fromKey - source Geo key * @param member - object * @param radius - radius in geo units * @param geoUnit - geo unit @@ -530,6 +535,7 @@ public interface RGeo extends RScoredSortedSet, RGeoAsync { * in GeoUnit units with GeoOrder * Store result to current Geo. * + * @param fromKey - source Geo key * @param member - object * @param radius - radius in geo units * @param geoUnit - geo unit diff --git a/redisson/src/main/java/org/redisson/api/RGeoAsync.java b/redisson/src/main/java/org/redisson/api/RGeoAsync.java index f3bf97064..477a0d96c 100644 --- a/redisson/src/main/java/org/redisson/api/RGeoAsync.java +++ b/redisson/src/main/java/org/redisson/api/RGeoAsync.java @@ -450,6 +450,7 @@ public interface RGeoAsync extends RScoredSortedSetAsync { * in GeoUnit units. * Store result to current Geo. * + * @param fromKey - source Geo key * @param longitude - longitude of object * @param latitude - latitude of object * @param radius - radius in geo units @@ -465,6 +466,7 @@ public interface RGeoAsync extends RScoredSortedSetAsync { * in GeoUnit units and limited by count * Store result to current Geo. * + * @param fromKey - source Geo key * @param longitude - longitude of object * @param latitude - latitude of object * @param radius - radius in geo units @@ -482,6 +484,7 @@ public interface RGeoAsync extends RScoredSortedSetAsync { * and limited by count * Store result to current Geo. * + * @param fromKey - source Geo key * @param longitude - longitude of object * @param latitude - latitude of object * @param radius - radius in geo units @@ -499,6 +502,7 @@ public interface RGeoAsync extends RScoredSortedSetAsync { * in GeoUnit units. * Store result to current Geo. * + * @param fromKey - source Geo key * @param member - object * @param radius - radius in geo units * @param geoUnit - geo unit @@ -513,6 +517,7 @@ public interface RGeoAsync extends RScoredSortedSetAsync { * in GeoUnit units and limited by count * Store result to current Geo. * + * @param fromKey - source Geo key * @param member - object * @param radius - radius in geo units * @param geoUnit - geo unit @@ -528,6 +533,7 @@ public interface RGeoAsync extends RScoredSortedSetAsync { * in GeoUnit units with GeoOrder * Store result to current Geo. * + * @param fromKey - source Geo key * @param member - object * @param radius - radius in geo units * @param geoUnit - geo unit From df0d13598097989eb44bd20bac47dc713b6c26a0 Mon Sep 17 00:00:00 2001 From: Cory Sherman Date: Fri, 28 Apr 2017 09:21:53 -0700 Subject: [PATCH 22/65] change API "radiusStore()" -> "radiusStoreTo()" From @mrniko's feedback, to match RSortable API. Read from current Geo, store to destName. --- .../main/java/org/redisson/RedissonGeo.java | 48 +++++++++---------- .../src/main/java/org/redisson/api/RGeo.java | 36 +++++++------- .../main/java/org/redisson/api/RGeoAsync.java | 36 +++++++------- .../java/org/redisson/RedissonGeoTest.java | 20 ++++---- 4 files changed, 70 insertions(+), 70 deletions(-) diff --git a/redisson/src/main/java/org/redisson/RedissonGeo.java b/redisson/src/main/java/org/redisson/RedissonGeo.java index ae4c710eb..e7992e007 100644 --- a/redisson/src/main/java/org/redisson/RedissonGeo.java +++ b/redisson/src/main/java/org/redisson/RedissonGeo.java @@ -407,63 +407,63 @@ public class RedissonGeo extends RedissonScoredSortedSet implements RGeo radiusStoreAsync(String fromKey, double longitude, double latitude, double radius, GeoUnit geoUnit) { - return commandExecutor.writeAsync(getName(), LongCodec.INSTANCE, RedisCommands.GEORADIUS_STORE_INT, fromKey, convert(longitude), convert(latitude), radius, geoUnit, "STORE", getName()); + public RFuture radiusStoreToAsync(String destName, double longitude, double latitude, double radius, GeoUnit geoUnit) { + return commandExecutor.writeAsync(getName(), LongCodec.INSTANCE, RedisCommands.GEORADIUS_STORE_INT, getName(), convert(longitude), convert(latitude), radius, geoUnit, "STORE", destName); } @Override - public int radiusStore(String fromKey, double longitude, double latitude, double radius, GeoUnit geoUnit, int count) { - return get(radiusStoreAsync(fromKey, longitude, latitude, radius, geoUnit, count)); + public int radiusStoreTo(String destName, double longitude, double latitude, double radius, GeoUnit geoUnit, int count) { + return get(radiusStoreToAsync(destName, longitude, latitude, radius, geoUnit, count)); } @Override - public RFuture radiusStoreAsync(String fromKey, double longitude, double latitude, double radius, GeoUnit geoUnit, int count) { - return commandExecutor.writeAsync(getName(), LongCodec.INSTANCE, RedisCommands.GEORADIUS_STORE_INT, fromKey, convert(longitude), convert(latitude), radius, geoUnit, "COUNT", count, "STORE", getName()); + public RFuture radiusStoreToAsync(String destName, double longitude, double latitude, double radius, GeoUnit geoUnit, int count) { + return commandExecutor.writeAsync(getName(), LongCodec.INSTANCE, RedisCommands.GEORADIUS_STORE_INT, getName(), convert(longitude), convert(latitude), radius, geoUnit, "COUNT", count, "STORE", destName); } @Override - public int radiusStore(String fromKey, double longitude, double latitude, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count) { - return get(radiusStoreAsync(fromKey, longitude, latitude, radius, geoUnit, geoOrder, count)); + public int radiusStoreTo(String destName, double longitude, double latitude, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count) { + return get(radiusStoreToAsync(destName, longitude, latitude, radius, geoUnit, geoOrder, count)); } @Override - public RFuture radiusStoreAsync(String fromKey, double longitude, double latitude, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count) { - return commandExecutor.writeAsync(getName(), LongCodec.INSTANCE, RedisCommands.GEORADIUS_STORE_INT, fromKey, convert(longitude), convert(latitude), radius, geoUnit, geoOrder, "COUNT", count, "STORE", getName()); + public RFuture radiusStoreToAsync(String destName, double longitude, double latitude, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count) { + return commandExecutor.writeAsync(getName(), LongCodec.INSTANCE, RedisCommands.GEORADIUS_STORE_INT, getName(), convert(longitude), convert(latitude), radius, geoUnit, geoOrder, "COUNT", count, "STORE", destName); } @Override - public int radiusStore(String fromKey, V member, double radius, GeoUnit geoUnit) { - return get(radiusStoreAsync(fromKey, member, radius, geoUnit)); + public int radiusStoreTo(String destName, V member, double radius, GeoUnit geoUnit) { + return get(radiusStoreToAsync(destName, member, radius, geoUnit)); } @Override - public RFuture radiusStoreAsync(String fromKey, V member, double radius, GeoUnit geoUnit) { - return commandExecutor.writeAsync(getName(), codec, RedisCommands.GEORADIUSBYMEMBER_STORE_INT, fromKey, member, radius, geoUnit, "STORE", getName()); + public RFuture radiusStoreToAsync(String destName, V member, double radius, GeoUnit geoUnit) { + return commandExecutor.writeAsync(getName(), codec, RedisCommands.GEORADIUSBYMEMBER_STORE_INT, getName(), member, radius, geoUnit, "STORE", destName); } @Override - public int radiusStore(String fromKey, V member, double radius, GeoUnit geoUnit, int count) { - return get(radiusStoreAsync(fromKey, member, radius, geoUnit, count)); + public int radiusStoreTo(String destName, V member, double radius, GeoUnit geoUnit, int count) { + return get(radiusStoreToAsync(destName, member, radius, geoUnit, count)); } @Override - public RFuture radiusStoreAsync(String fromKey, V member, double radius, GeoUnit geoUnit, int count) { - return commandExecutor.writeAsync(getName(), codec, RedisCommands.GEORADIUSBYMEMBER_STORE_INT, fromKey, member, radius, geoUnit, "COUNT", count, "STORE", getName()); + public RFuture radiusStoreToAsync(String destName, V member, double radius, GeoUnit geoUnit, int count) { + return commandExecutor.writeAsync(getName(), codec, RedisCommands.GEORADIUSBYMEMBER_STORE_INT, getName(), member, radius, geoUnit, "COUNT", count, "STORE", destName); } @Override - public int radiusStore(String fromKey, V member, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count) { - return get(radiusStoreAsync(fromKey, member, radius, geoUnit, geoOrder, count)); + public int radiusStoreTo(String destName, V member, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count) { + return get(radiusStoreToAsync(destName, member, radius, geoUnit, geoOrder, count)); } @Override - public RFuture radiusStoreAsync(String fromKey, V member, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count) { - return commandExecutor.writeAsync(getName(), codec, RedisCommands.GEORADIUSBYMEMBER_STORE_INT, fromKey, member, radius, geoUnit, geoOrder, "COUNT", count, "STORE", getName()); + public RFuture radiusStoreToAsync(String destName, V member, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count) { + return commandExecutor.writeAsync(getName(), codec, RedisCommands.GEORADIUSBYMEMBER_STORE_INT, getName(), member, radius, geoUnit, geoOrder, "COUNT", count, "STORE", destName); } } diff --git a/redisson/src/main/java/org/redisson/api/RGeo.java b/redisson/src/main/java/org/redisson/api/RGeo.java index ccc9ed113..610cfd7fa 100644 --- a/redisson/src/main/java/org/redisson/api/RGeo.java +++ b/redisson/src/main/java/org/redisson/api/RGeo.java @@ -450,25 +450,25 @@ public interface RGeo extends RScoredSortedSet, RGeoAsync { * borders of the area specified with the center location * and the maximum distance from the center (the radius) * in GeoUnit units. - * Store result to current Geo. + * Store result to destName. * - * @param fromKey - source Geo key + * @param destName - Geo object destination * @param longitude - longitude of object * @param latitude - latitude of object * @param radius - radius in geo units * @param geoUnit - geo unit * @return length of result */ - int radiusStore(String fromKey, double longitude, double latitude, double radius, GeoUnit geoUnit); + int radiusStoreTo(String destName, double longitude, double latitude, double radius, GeoUnit geoUnit); /** * Finds the members of a sorted set, which are within the * borders of the area specified with the center location * and the maximum distance from the center (the radius) * in GeoUnit units and limited by count - * Store result to current Geo. + * Store result to destName. * - * @param fromKey - source Geo key + * @param destName - Geo object destination * @param longitude - longitude of object * @param latitude - latitude of object * @param radius - radius in geo units @@ -476,7 +476,7 @@ public interface RGeo extends RScoredSortedSet, RGeoAsync { * @param count - result limit * @return length of result */ - int radiusStore(String fromKey, double longitude, double latitude, double radius, GeoUnit geoUnit, int count); + int radiusStoreTo(String destName, double longitude, double latitude, double radius, GeoUnit geoUnit, int count); /** * Finds the members of a sorted set, which are within the @@ -484,9 +484,9 @@ public interface RGeo extends RScoredSortedSet, RGeoAsync { * and the maximum distance from the center (the radius) * in GeoUnit units with GeoOrder * and limited by count - * Store result to current Geo. + * Store result to destName. * - * @param fromKey - source Geo key + * @param destName - Geo object destination * @param longitude - longitude of object * @param latitude - latitude of object * @param radius - radius in geo units @@ -495,47 +495,47 @@ public interface RGeo extends RScoredSortedSet, RGeoAsync { * @param count - result limit * @return length of result */ - int radiusStore(String fromKey, double longitude, double latitude, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count); + int radiusStoreTo(String destName, double longitude, double latitude, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count); /** * Finds the members of a sorted set, which are within the * borders of the area specified with the defined member location * and the maximum distance from the defined member location (the radius) * in GeoUnit units. - * Store result to current Geo. + * Store result to destName. * - * @param fromKey - source Geo key + * @param destName - Geo object destination * @param member - object * @param radius - radius in geo units * @param geoUnit - geo unit * @return length of result */ - int radiusStore(String fromKey, V member, double radius, GeoUnit geoUnit); + int radiusStoreTo(String destName, V member, double radius, GeoUnit geoUnit); /** * Finds the members of a sorted set, which are within the * borders of the area specified with the defined member location * and the maximum distance from the defined member location (the radius) * in GeoUnit units and limited by count - * Store result to current Geo. + * Store result to destName. * - * @param fromKey - source Geo key + * @param destName - Geo object destination * @param member - object * @param radius - radius in geo units * @param geoUnit - geo unit * @param count - result limit * @return length of result */ - int radiusStore(String fromKey, V member, double radius, GeoUnit geoUnit, int count); + int radiusStoreTo(String destName, V member, double radius, GeoUnit geoUnit, int count); /** * Finds the members of a sorted set, which are within the * borders of the area specified with the defined member location * and the maximum distance from the defined member location (the radius) * in GeoUnit units with GeoOrder - * Store result to current Geo. + * Store result to destName. * - * @param fromKey - source Geo key + * @param destName - Geo object destination * @param member - object * @param radius - radius in geo units * @param geoUnit - geo unit @@ -543,6 +543,6 @@ public interface RGeo extends RScoredSortedSet, RGeoAsync { * @param count - result limit * @return length of result */ - int radiusStore(String fromKey, V member, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count); + int radiusStoreTo(String destName, V member, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count); } diff --git a/redisson/src/main/java/org/redisson/api/RGeoAsync.java b/redisson/src/main/java/org/redisson/api/RGeoAsync.java index 477a0d96c..8f9750a02 100644 --- a/redisson/src/main/java/org/redisson/api/RGeoAsync.java +++ b/redisson/src/main/java/org/redisson/api/RGeoAsync.java @@ -448,25 +448,25 @@ public interface RGeoAsync extends RScoredSortedSetAsync { * borders of the area specified with the center location * and the maximum distance from the center (the radius) * in GeoUnit units. - * Store result to current Geo. + * Store result to destName. * - * @param fromKey - source Geo key + * @param destName - Geo object destination * @param longitude - longitude of object * @param latitude - latitude of object * @param radius - radius in geo units * @param geoUnit - geo unit * @return length of result */ - RFuture radiusStoreAsync(String fromKey, double longitude, double latitude, double radius, GeoUnit geoUnit); + RFuture radiusStoreToAsync(String destName, double longitude, double latitude, double radius, GeoUnit geoUnit); /** * Finds the members of a sorted set, which are within the * borders of the area specified with the center location * and the maximum distance from the center (the radius) * in GeoUnit units and limited by count - * Store result to current Geo. + * Store result to destName. * - * @param fromKey - source Geo key + * @param destName - Geo object destination * @param longitude - longitude of object * @param latitude - latitude of object * @param radius - radius in geo units @@ -474,7 +474,7 @@ public interface RGeoAsync extends RScoredSortedSetAsync { * @param count - result limit * @return length of result */ - RFuture radiusStoreAsync(String fromKey, double longitude, double latitude, double radius, GeoUnit geoUnit, int count); + RFuture radiusStoreToAsync(String destName, double longitude, double latitude, double radius, GeoUnit geoUnit, int count); /** * Finds the members of a sorted set, which are within the @@ -482,9 +482,9 @@ public interface RGeoAsync extends RScoredSortedSetAsync { * and the maximum distance from the center (the radius) * in GeoUnit units with GeoOrder * and limited by count - * Store result to current Geo. + * Store result to destName. * - * @param fromKey - source Geo key + * @param destName - Geo object destination * @param longitude - longitude of object * @param latitude - latitude of object * @param radius - radius in geo units @@ -493,47 +493,47 @@ public interface RGeoAsync extends RScoredSortedSetAsync { * @param count - result limit * @return length of result */ - RFuture radiusStoreAsync(String fromKey, double longitude, double latitude, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count); + RFuture radiusStoreToAsync(String destName, double longitude, double latitude, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count); /** * Finds the members of a sorted set, which are within the * borders of the area specified with the defined member location * and the maximum distance from the defined member location (the radius) * in GeoUnit units. - * Store result to current Geo. + * Store result to destName. * - * @param fromKey - source Geo key + * @param destName - Geo object destination * @param member - object * @param radius - radius in geo units * @param geoUnit - geo unit * @return length of result */ - RFuture radiusStoreAsync(String fromKey, V member, double radius, GeoUnit geoUnit); + RFuture radiusStoreToAsync(String destName, V member, double radius, GeoUnit geoUnit); /** * Finds the members of a sorted set, which are within the * borders of the area specified with the defined member location * and the maximum distance from the defined member location (the radius) * in GeoUnit units and limited by count - * Store result to current Geo. + * Store result to destName. * - * @param fromKey - source Geo key + * @param destName - Geo object destination * @param member - object * @param radius - radius in geo units * @param geoUnit - geo unit * @param count - result limit * @return length of result */ - RFuture radiusStoreAsync(String fromKey, V member, double radius, GeoUnit geoUnit, int count); + RFuture radiusStoreToAsync(String destName, V member, double radius, GeoUnit geoUnit, int count); /** * Finds the members of a sorted set, which are within the * borders of the area specified with the defined member location * and the maximum distance from the defined member location (the radius) * in GeoUnit units with GeoOrder - * Store result to current Geo. + * Store result to destName. * - * @param fromKey - source Geo key + * @param destName - Geo object destination * @param member - object * @param radius - radius in geo units * @param geoUnit - geo unit @@ -541,6 +541,6 @@ public interface RGeoAsync extends RScoredSortedSetAsync { * @param count - result limit * @return length of result */ - RFuture radiusStoreAsync(String fromKey, V member, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count); + RFuture radiusStoreToAsync(String destName, V member, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count); } diff --git a/redisson/src/test/java/org/redisson/RedissonGeoTest.java b/redisson/src/test/java/org/redisson/RedissonGeoTest.java index 87af69633..69ab4fedf 100644 --- a/redisson/src/test/java/org/redisson/RedissonGeoTest.java +++ b/redisson/src/test/java/org/redisson/RedissonGeoTest.java @@ -482,7 +482,7 @@ public class RedissonGeoTest extends BaseTest { RGeo geoDest = redisson.getGeo("test-store"); geoSource.add(new GeoEntry(13.361389, 38.115556, "Palermo"), new GeoEntry(15.087269, 37.502669, "Catania")); - assertThat(geoDest.radiusStore(geoSource.getName(), 15, 37, 200, GeoUnit.KILOMETERS)).isEqualTo(2); + assertThat(geoSource.radiusStoreTo(geoDest.getName(), 15, 37, 200, GeoUnit.KILOMETERS)).isEqualTo(2); assertThat(geoDest.readAll()).containsExactlyInAnyOrder("Palermo", "Catania"); } @@ -492,7 +492,7 @@ public class RedissonGeoTest extends BaseTest { RGeo geoDest = redisson.getGeo("test-store"); geoSource.add(new GeoEntry(13.361389, 38.115556, "Palermo"), new GeoEntry(15.087269, 37.502669, "Catania")); - assertThat(geoDest.radiusStore(geoSource.getName(), 15, 37, 200, GeoUnit.KILOMETERS, 1)).isEqualTo(1); + assertThat(geoSource.radiusStoreTo(geoDest.getName(), 15, 37, 200, GeoUnit.KILOMETERS, 1)).isEqualTo(1); assertThat(geoDest.readAll()).containsExactly("Catania"); } @@ -502,10 +502,10 @@ public class RedissonGeoTest extends BaseTest { RGeo geoDest = redisson.getGeo("test-store"); geoSource.add(new GeoEntry(13.361389, 38.115556, "Palermo"), new GeoEntry(15.087269, 37.502669, "Catania")); - assertThat(geoDest.radiusStore(geoSource.getName(), 15, 37, 200, GeoUnit.KILOMETERS, GeoOrder.DESC, 1)).isEqualTo(1); + assertThat(geoSource.radiusStoreTo(geoDest.getName(), 15, 37, 200, GeoUnit.KILOMETERS, GeoOrder.DESC, 1)).isEqualTo(1); assertThat(geoDest.readAll()).containsExactly("Palermo"); - assertThat(geoDest.radiusStore(geoSource.getName(), 15, 37, 200, GeoUnit.KILOMETERS, GeoOrder.ASC, 1)).isEqualTo(1); + assertThat(geoSource.radiusStoreTo(geoDest.getName(), 15, 37, 200, GeoUnit.KILOMETERS, GeoOrder.ASC, 1)).isEqualTo(1); assertThat(geoDest.readAll()).containsExactly("Catania"); } @@ -514,7 +514,7 @@ public class RedissonGeoTest extends BaseTest { RGeo geoSource = redisson.getGeo("test"); RGeo geoDest = redisson.getGeo("test-store"); - assertThat(geoDest.radiusStore(geoSource.getName(), 15, 37, 200, GeoUnit.KILOMETERS)).isEqualTo(0); + assertThat(geoSource.radiusStoreTo(geoDest.getName(), 15, 37, 200, GeoUnit.KILOMETERS)).isEqualTo(0); assertThat(geoDest.readAll()).isEmpty(); } @@ -524,7 +524,7 @@ public class RedissonGeoTest extends BaseTest { RGeo geoDest = redisson.getGeo("test-store"); geoSource.add(new GeoEntry(13.361389, 38.115556, "Palermo"), new GeoEntry(15.087269, 37.502669, "Catania")); - assertThat(geoDest.radiusStore(geoSource.getName(), "Palermo", 200, GeoUnit.KILOMETERS)).isEqualTo(2); + assertThat(geoSource.radiusStoreTo(geoDest.getName(), "Palermo", 200, GeoUnit.KILOMETERS)).isEqualTo(2); assertThat(geoDest.readAll()).containsExactlyInAnyOrder("Palermo", "Catania"); } @@ -534,7 +534,7 @@ public class RedissonGeoTest extends BaseTest { RGeo geoDest = redisson.getGeo("test-store"); geoSource.add(new GeoEntry(13.361389, 38.115556, "Palermo"), new GeoEntry(15.087269, 37.502669, "Catania")); - assertThat(geoDest.radiusStore(geoSource.getName(), "Palermo", 200, GeoUnit.KILOMETERS, 1)).isEqualTo(1); + assertThat(geoSource.radiusStoreTo(geoDest.getName(), "Palermo", 200, GeoUnit.KILOMETERS, 1)).isEqualTo(1); assertThat(geoDest.readAll()).containsExactly("Palermo"); } @@ -544,10 +544,10 @@ public class RedissonGeoTest extends BaseTest { RGeo geoDest = redisson.getGeo("test-store"); geoSource.add(new GeoEntry(13.361389, 38.115556, "Palermo"), new GeoEntry(15.087269, 37.502669, "Catania")); - assertThat(geoDest.radiusStore(geoSource.getName(), "Palermo", 200, GeoUnit.KILOMETERS, GeoOrder.DESC, 1)).isEqualTo(1); + assertThat(geoSource.radiusStoreTo(geoDest.getName(), "Palermo", 200, GeoUnit.KILOMETERS, GeoOrder.DESC, 1)).isEqualTo(1); assertThat(geoDest.readAll()).containsExactly("Catania"); - assertThat(geoDest.radiusStore(geoSource.getName(), "Palermo", 200, GeoUnit.KILOMETERS, GeoOrder.ASC, 1)).isEqualTo(1); + assertThat(geoSource.radiusStoreTo(geoDest.getName(), "Palermo", 200, GeoUnit.KILOMETERS, GeoOrder.ASC, 1)).isEqualTo(1); assertThat(geoDest.readAll()).containsExactly("Palermo"); } @@ -556,7 +556,7 @@ public class RedissonGeoTest extends BaseTest { RGeo geoSource = redisson.getGeo("test"); RGeo geoDest = redisson.getGeo("test-store"); - assertThat(geoDest.radiusStore(geoSource.getName(), "Palermo", 200, GeoUnit.KILOMETERS)).isEqualTo(0); + assertThat(geoSource.radiusStoreTo(geoDest.getName(), "Palermo", 200, GeoUnit.KILOMETERS)).isEqualTo(0); assertThat(geoDest.readAll()).isEmpty(); } From 87bcfec6ede1da7bc2bdc906899ff94ac0fb6aeb Mon Sep 17 00:00:00 2001 From: Steve Draper Date: Fri, 28 Apr 2017 11:35:57 -0500 Subject: [PATCH 23/65] Added pre-warm mechanism for locally cached maps --- .../java/org/redisson/RedissonLocalCachedMap.java | 14 +++++++++++++- .../java/org/redisson/api/RLocalCachedMap.java | 7 ++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/redisson/src/main/java/org/redisson/RedissonLocalCachedMap.java b/redisson/src/main/java/org/redisson/RedissonLocalCachedMap.java index d81febe2e..efb981356 100644 --- a/redisson/src/main/java/org/redisson/RedissonLocalCachedMap.java +++ b/redisson/src/main/java/org/redisson/RedissonLocalCachedMap.java @@ -1084,7 +1084,19 @@ public class RedissonLocalCachedMap extends RedissonMap implements R return promise; } - + + @Override + public void preloadCache() { + // Best-attempt warmup - just enumerate as an uncached map (super) and + // add anything found into the cache. This does not guarantee to find + // entries added during the warmUp, but statistically the cache will have + // few misses after this process + for(Entry entry : super.entrySet()) { + CacheKey cacheKey = toCacheKey(entry.getKey()); + cache.put(cacheKey, new CacheValue(entry.getKey(), entry.getValue())); + } + } + @Override public RFuture>> readAllEntrySetAsync() { final Set> result = new HashSet>(); diff --git a/redisson/src/main/java/org/redisson/api/RLocalCachedMap.java b/redisson/src/main/java/org/redisson/api/RLocalCachedMap.java index a7f7ed9c6..43223cd1f 100644 --- a/redisson/src/main/java/org/redisson/api/RLocalCachedMap.java +++ b/redisson/src/main/java/org/redisson/api/RLocalCachedMap.java @@ -27,5 +27,10 @@ package org.redisson.api; * @param map value */ public interface RLocalCachedMap extends RMap, RDestroyable { - + /** + * Pre-warm the cached values. Not guaranteed to load ALL values, but statistically + * will preload approximately all (all if no concurrent mutating activity) + * Intended for use with no-eviction caches where entire maps are locally cached + */ + public void preloadCache(); } From b66be8983a5328e30d5d9202b5c19c7bf0366446 Mon Sep 17 00:00:00 2001 From: Nikita Date: Sat, 29 Apr 2017 14:06:41 +0300 Subject: [PATCH 24/65] refactoring --- .../connection/MasterSlaveConnectionManager.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/redisson/src/main/java/org/redisson/connection/MasterSlaveConnectionManager.java b/redisson/src/main/java/org/redisson/connection/MasterSlaveConnectionManager.java index b903de260..13ee7ad4c 100644 --- a/redisson/src/main/java/org/redisson/connection/MasterSlaveConnectionManager.java +++ b/redisson/src/main/java/org/redisson/connection/MasterSlaveConnectionManager.java @@ -137,7 +137,7 @@ public class MasterSlaveConnectionManager implements ConnectionManager { private final InfinitySemaphoreLatch shutdownLatch = new InfinitySemaphoreLatch(); - private final Set clients = Collections.newSetFromMap(PlatformDependent.newConcurrentHashMap()); + private final Map clientEntries = PlatformDependent.newConcurrentHashMap(); private IdleConnectionWatcher connectionWatcher; @@ -339,12 +339,13 @@ public class MasterSlaveConnectionManager implements ConnectionManager { @Override public RedisClient createClient(NodeType type, String host, int port) { RedisClient client = createClient(host, port, config.getConnectTimeout(), config.getRetryInterval() * config.getRetryAttempts()); - clients.add(new RedisClientEntry(client, commandExecutor, type)); + clientEntries.put(client, new RedisClientEntry(client, commandExecutor, type)); return client; } + @Override public void shutdownAsync(RedisClient client) { - clients.remove(new RedisClientEntry(client, commandExecutor, null)); + clientEntries.remove(client); client.shutdownAsync(); } @@ -782,7 +783,7 @@ public class MasterSlaveConnectionManager implements ConnectionManager { @Override public Collection getClients() { - return Collections.unmodifiableCollection(clients); + return Collections.unmodifiableCollection(clientEntries.values()); } @Override From 0149b05b6fa6d3bfde571149f84580444ce932b6 Mon Sep 17 00:00:00 2001 From: Nikita Date: Fri, 5 May 2017 13:56:01 +0300 Subject: [PATCH 25/65] RRemoteService.getFreeWorkers method added --- .../src/main/java/org/redisson/RedissonRemoteService.java | 6 ++++++ .../src/main/java/org/redisson/api/RRemoteService.java | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/redisson/src/main/java/org/redisson/RedissonRemoteService.java b/redisson/src/main/java/org/redisson/RedissonRemoteService.java index 17cf21b90..7148153f1 100644 --- a/redisson/src/main/java/org/redisson/RedissonRemoteService.java +++ b/redisson/src/main/java/org/redisson/RedissonRemoteService.java @@ -101,6 +101,12 @@ public class RedissonRemoteService extends BaseRemoteService implements RRemoteS } } + @Override + public int getFreeWorkers(Class remoteInterface) { + Set> futuresSet = futures.get(remoteInterface); + return futuresSet.size(); + } + @Override public void register(Class remoteInterface, T object, int workers) { register(remoteInterface, object, workers, commandExecutor.getConnectionManager().getExecutor()); diff --git a/redisson/src/main/java/org/redisson/api/RRemoteService.java b/redisson/src/main/java/org/redisson/api/RRemoteService.java index ea6db3219..20c99f4a5 100644 --- a/redisson/src/main/java/org/redisson/api/RRemoteService.java +++ b/redisson/src/main/java/org/redisson/api/RRemoteService.java @@ -57,6 +57,14 @@ import java.util.concurrent.TimeUnit; */ public interface RRemoteService { + /** + * Returns free workers amount available for tasks + * + * @param remoteInterface - remote service interface + * @return workers amount + */ + int getFreeWorkers(Class remoteInterface); + /** * Register remote service with single worker * From bf200044e864d634b98fb017f74a87076cd17739 Mon Sep 17 00:00:00 2001 From: Nikita Date: Fri, 5 May 2017 18:15:37 +0300 Subject: [PATCH 26/65] zero-allocation-hashing, byte-buddy and jodd-bean libraries can't be optional. #862 --- redisson/pom.xml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/redisson/pom.xml b/redisson/pom.xml index 9e96bcc9b..b920b9769 100644 --- a/redisson/pom.xml +++ b/redisson/pom.xml @@ -198,6 +198,7 @@ jackson-databind 2.6.7 + com.fasterxml.jackson.dataformat jackson-dataformat-cbor @@ -223,19 +224,16 @@ net.openhft zero-allocation-hashing 0.7 - true net.bytebuddy byte-buddy 1.6.8 - true org.jodd jodd-bean 3.7.1 - true org.springframework From f54c4622982e542b574f15558ad9c66e88575fb3 Mon Sep 17 00:00:00 2001 From: Nikita Date: Mon, 8 May 2017 11:26:07 +0300 Subject: [PATCH 27/65] Fixed empty result handling for RGeo.radiusStoreTo methods --- .../main/java/org/redisson/RedissonGeo.java | 36 +++++++++--------- .../src/main/java/org/redisson/api/RGeo.java | 12 +++--- .../main/java/org/redisson/api/RGeoAsync.java | 12 +++--- .../client/protocol/RedisCommands.java | 6 ++- .../client/protocol/decoder/DecoderState.java | 5 +++ .../protocol/decoder/GeoDistanceDecoder.java | 6 ++- .../decoder/GeoDistanceMapDecoder.java | 5 +++ .../protocol/decoder/GeoMapReplayDecoder.java | 5 +++ .../protocol/decoder/GeoPositionDecoder.java | 5 +++ .../decoder/GeoPositionMapDecoder.java | 5 +++ .../protocol/decoder/KeyValueMessage.java | 7 ++++ .../decoder/KeyValueObjectDecoder.java | 5 +++ .../decoder/ListFirstObjectDecoder.java | 5 +++ .../decoder/ListIteratorReplayDecoder.java | 5 +++ .../protocol/decoder/ListIteratorResult.java | 6 +++ .../protocol/decoder/ListMultiDecoder.java | 6 +++ .../decoder/ListResultReplayDecoder.java | 5 +++ .../protocol/decoder/ListScanResult.java | 6 +++ .../decoder/ListScanResultReplayDecoder.java | 5 +++ .../protocol/decoder/Long2MultiDecoder.java | 37 +++++++++++++++++++ .../protocol/decoder/LongMultiDecoder.java | 5 +++ .../protocol/decoder/MapCacheScanResult.java | 7 ++++ .../MapCacheScanResultReplayDecoder.java | 5 +++ .../protocol/decoder/MapScanResult.java | 7 ++++ .../decoder/MapScanResultReplayDecoder.java | 5 +++ .../ObjectFirstResultReplayDecoder.java | 6 +++ .../protocol/decoder/ObjectListDecoder.java | 6 +++ .../protocol/decoder/ScanObjectEntry.java | 5 +++ .../decoder/ScoredSortedSetReplayDecoder.java | 6 +++ .../decoder/ScoredSortedSetScanDecoder.java | 6 +++ .../ScoredSortedSetScanReplayDecoder.java | 5 +++ .../client/protocol/decoder/SlotsDecoder.java | 5 +++ .../protocol/decoder/StringDataDecoder.java | 5 +++ .../decoder/StringListReplayDecoder.java | 5 +++ .../decoder/StringMapDataDecoder.java | 5 +++ .../protocol/decoder/StringReplayDecoder.java | 5 +++ .../decoder/TTLMapValueReplayDecoder.java | 6 +++ 37 files changed, 245 insertions(+), 33 deletions(-) create mode 100644 redisson/src/main/java/org/redisson/client/protocol/decoder/Long2MultiDecoder.java diff --git a/redisson/src/main/java/org/redisson/RedissonGeo.java b/redisson/src/main/java/org/redisson/RedissonGeo.java index e7992e007..28c4b4546 100644 --- a/redisson/src/main/java/org/redisson/RedissonGeo.java +++ b/redisson/src/main/java/org/redisson/RedissonGeo.java @@ -407,63 +407,63 @@ public class RedissonGeo extends RedissonScoredSortedSet implements RGeo radiusStoreToAsync(String destName, double longitude, double latitude, double radius, GeoUnit geoUnit) { - return commandExecutor.writeAsync(getName(), LongCodec.INSTANCE, RedisCommands.GEORADIUS_STORE_INT, getName(), convert(longitude), convert(latitude), radius, geoUnit, "STORE", destName); + public RFuture radiusStoreToAsync(String destName, double longitude, double latitude, double radius, GeoUnit geoUnit) { + return commandExecutor.writeAsync(getName(), LongCodec.INSTANCE, RedisCommands.GEORADIUS_STORE, getName(), convert(longitude), convert(latitude), radius, geoUnit, "STORE", destName); } @Override - public int radiusStoreTo(String destName, double longitude, double latitude, double radius, GeoUnit geoUnit, int count) { + public long radiusStoreTo(String destName, double longitude, double latitude, double radius, GeoUnit geoUnit, int count) { return get(radiusStoreToAsync(destName, longitude, latitude, radius, geoUnit, count)); } @Override - public RFuture radiusStoreToAsync(String destName, double longitude, double latitude, double radius, GeoUnit geoUnit, int count) { - return commandExecutor.writeAsync(getName(), LongCodec.INSTANCE, RedisCommands.GEORADIUS_STORE_INT, getName(), convert(longitude), convert(latitude), radius, geoUnit, "COUNT", count, "STORE", destName); + public RFuture radiusStoreToAsync(String destName, double longitude, double latitude, double radius, GeoUnit geoUnit, int count) { + return commandExecutor.writeAsync(getName(), LongCodec.INSTANCE, RedisCommands.GEORADIUS_STORE, getName(), convert(longitude), convert(latitude), radius, geoUnit, "COUNT", count, "STORE", destName); } @Override - public int radiusStoreTo(String destName, double longitude, double latitude, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count) { + public long radiusStoreTo(String destName, double longitude, double latitude, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count) { return get(radiusStoreToAsync(destName, longitude, latitude, radius, geoUnit, geoOrder, count)); } @Override - public RFuture radiusStoreToAsync(String destName, double longitude, double latitude, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count) { - return commandExecutor.writeAsync(getName(), LongCodec.INSTANCE, RedisCommands.GEORADIUS_STORE_INT, getName(), convert(longitude), convert(latitude), radius, geoUnit, geoOrder, "COUNT", count, "STORE", destName); + public RFuture radiusStoreToAsync(String destName, double longitude, double latitude, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count) { + return commandExecutor.writeAsync(getName(), LongCodec.INSTANCE, RedisCommands.GEORADIUS_STORE, getName(), convert(longitude), convert(latitude), radius, geoUnit, geoOrder, "COUNT", count, "STORE", destName); } @Override - public int radiusStoreTo(String destName, V member, double radius, GeoUnit geoUnit) { + public long radiusStoreTo(String destName, V member, double radius, GeoUnit geoUnit) { return get(radiusStoreToAsync(destName, member, radius, geoUnit)); } @Override - public RFuture radiusStoreToAsync(String destName, V member, double radius, GeoUnit geoUnit) { - return commandExecutor.writeAsync(getName(), codec, RedisCommands.GEORADIUSBYMEMBER_STORE_INT, getName(), member, radius, geoUnit, "STORE", destName); + public RFuture radiusStoreToAsync(String destName, V member, double radius, GeoUnit geoUnit) { + return commandExecutor.writeAsync(getName(), codec, RedisCommands.GEORADIUSBYMEMBER_STORE, getName(), member, radius, geoUnit, "STORE", destName); } @Override - public int radiusStoreTo(String destName, V member, double radius, GeoUnit geoUnit, int count) { + public long radiusStoreTo(String destName, V member, double radius, GeoUnit geoUnit, int count) { return get(radiusStoreToAsync(destName, member, radius, geoUnit, count)); } @Override - public RFuture radiusStoreToAsync(String destName, V member, double radius, GeoUnit geoUnit, int count) { - return commandExecutor.writeAsync(getName(), codec, RedisCommands.GEORADIUSBYMEMBER_STORE_INT, getName(), member, radius, geoUnit, "COUNT", count, "STORE", destName); + public RFuture radiusStoreToAsync(String destName, V member, double radius, GeoUnit geoUnit, int count) { + return commandExecutor.writeAsync(getName(), codec, RedisCommands.GEORADIUSBYMEMBER_STORE, getName(), member, radius, geoUnit, "COUNT", count, "STORE", destName); } @Override - public int radiusStoreTo(String destName, V member, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count) { + public long radiusStoreTo(String destName, V member, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count) { return get(radiusStoreToAsync(destName, member, radius, geoUnit, geoOrder, count)); } @Override - public RFuture radiusStoreToAsync(String destName, V member, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count) { - return commandExecutor.writeAsync(getName(), codec, RedisCommands.GEORADIUSBYMEMBER_STORE_INT, getName(), member, radius, geoUnit, geoOrder, "COUNT", count, "STORE", destName); + public RFuture radiusStoreToAsync(String destName, V member, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count) { + return commandExecutor.writeAsync(getName(), codec, RedisCommands.GEORADIUSBYMEMBER_STORE, getName(), member, radius, geoUnit, geoOrder, "COUNT", count, "STORE", destName); } } diff --git a/redisson/src/main/java/org/redisson/api/RGeo.java b/redisson/src/main/java/org/redisson/api/RGeo.java index 610cfd7fa..0b29cce5f 100644 --- a/redisson/src/main/java/org/redisson/api/RGeo.java +++ b/redisson/src/main/java/org/redisson/api/RGeo.java @@ -459,7 +459,7 @@ public interface RGeo extends RScoredSortedSet, RGeoAsync { * @param geoUnit - geo unit * @return length of result */ - int radiusStoreTo(String destName, double longitude, double latitude, double radius, GeoUnit geoUnit); + long radiusStoreTo(String destName, double longitude, double latitude, double radius, GeoUnit geoUnit); /** * Finds the members of a sorted set, which are within the @@ -476,7 +476,7 @@ public interface RGeo extends RScoredSortedSet, RGeoAsync { * @param count - result limit * @return length of result */ - int radiusStoreTo(String destName, double longitude, double latitude, double radius, GeoUnit geoUnit, int count); + long radiusStoreTo(String destName, double longitude, double latitude, double radius, GeoUnit geoUnit, int count); /** * Finds the members of a sorted set, which are within the @@ -495,7 +495,7 @@ public interface RGeo extends RScoredSortedSet, RGeoAsync { * @param count - result limit * @return length of result */ - int radiusStoreTo(String destName, double longitude, double latitude, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count); + long radiusStoreTo(String destName, double longitude, double latitude, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count); /** * Finds the members of a sorted set, which are within the @@ -510,7 +510,7 @@ public interface RGeo extends RScoredSortedSet, RGeoAsync { * @param geoUnit - geo unit * @return length of result */ - int radiusStoreTo(String destName, V member, double radius, GeoUnit geoUnit); + long radiusStoreTo(String destName, V member, double radius, GeoUnit geoUnit); /** * Finds the members of a sorted set, which are within the @@ -526,7 +526,7 @@ public interface RGeo extends RScoredSortedSet, RGeoAsync { * @param count - result limit * @return length of result */ - int radiusStoreTo(String destName, V member, double radius, GeoUnit geoUnit, int count); + long radiusStoreTo(String destName, V member, double radius, GeoUnit geoUnit, int count); /** * Finds the members of a sorted set, which are within the @@ -543,6 +543,6 @@ public interface RGeo extends RScoredSortedSet, RGeoAsync { * @param count - result limit * @return length of result */ - int radiusStoreTo(String destName, V member, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count); + long radiusStoreTo(String destName, V member, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count); } diff --git a/redisson/src/main/java/org/redisson/api/RGeoAsync.java b/redisson/src/main/java/org/redisson/api/RGeoAsync.java index 8f9750a02..6d1700ed1 100644 --- a/redisson/src/main/java/org/redisson/api/RGeoAsync.java +++ b/redisson/src/main/java/org/redisson/api/RGeoAsync.java @@ -457,7 +457,7 @@ public interface RGeoAsync extends RScoredSortedSetAsync { * @param geoUnit - geo unit * @return length of result */ - RFuture radiusStoreToAsync(String destName, double longitude, double latitude, double radius, GeoUnit geoUnit); + RFuture radiusStoreToAsync(String destName, double longitude, double latitude, double radius, GeoUnit geoUnit); /** * Finds the members of a sorted set, which are within the @@ -474,7 +474,7 @@ public interface RGeoAsync extends RScoredSortedSetAsync { * @param count - result limit * @return length of result */ - RFuture radiusStoreToAsync(String destName, double longitude, double latitude, double radius, GeoUnit geoUnit, int count); + RFuture radiusStoreToAsync(String destName, double longitude, double latitude, double radius, GeoUnit geoUnit, int count); /** * Finds the members of a sorted set, which are within the @@ -493,7 +493,7 @@ public interface RGeoAsync extends RScoredSortedSetAsync { * @param count - result limit * @return length of result */ - RFuture radiusStoreToAsync(String destName, double longitude, double latitude, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count); + RFuture radiusStoreToAsync(String destName, double longitude, double latitude, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count); /** * Finds the members of a sorted set, which are within the @@ -508,7 +508,7 @@ public interface RGeoAsync extends RScoredSortedSetAsync { * @param geoUnit - geo unit * @return length of result */ - RFuture radiusStoreToAsync(String destName, V member, double radius, GeoUnit geoUnit); + RFuture radiusStoreToAsync(String destName, V member, double radius, GeoUnit geoUnit); /** * Finds the members of a sorted set, which are within the @@ -524,7 +524,7 @@ public interface RGeoAsync extends RScoredSortedSetAsync { * @param count - result limit * @return length of result */ - RFuture radiusStoreToAsync(String destName, V member, double radius, GeoUnit geoUnit, int count); + RFuture radiusStoreToAsync(String destName, V member, double radius, GeoUnit geoUnit, int count); /** * Finds the members of a sorted set, which are within the @@ -541,6 +541,6 @@ public interface RGeoAsync extends RScoredSortedSetAsync { * @param count - result limit * @return length of result */ - RFuture radiusStoreToAsync(String destName, V member, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count); + RFuture radiusStoreToAsync(String destName, V member, double radius, GeoUnit geoUnit, GeoOrder geoOrder, int count); } diff --git a/redisson/src/main/java/org/redisson/client/protocol/RedisCommands.java b/redisson/src/main/java/org/redisson/client/protocol/RedisCommands.java index c155aecc0..a91c4dda6 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/RedisCommands.java +++ b/redisson/src/main/java/org/redisson/client/protocol/RedisCommands.java @@ -45,6 +45,8 @@ import org.redisson.client.protocol.decoder.KeyValueObjectDecoder; import org.redisson.client.protocol.decoder.ListResultReplayDecoder; import org.redisson.client.protocol.decoder.ListScanResult; import org.redisson.client.protocol.decoder.ListScanResultReplayDecoder; +import org.redisson.client.protocol.decoder.Long2MultiDecoder; +import org.redisson.client.protocol.decoder.LongMultiDecoder; import org.redisson.client.protocol.decoder.MapScanResult; import org.redisson.client.protocol.decoder.MapScanResultReplayDecoder; import org.redisson.client.protocol.decoder.NestedMultiDecoder; @@ -76,8 +78,8 @@ public interface RedisCommands { RedisCommand GEODIST = new RedisCommand("GEODIST", new DoubleReplayConvertor(), 2, Arrays.asList(ValueType.OBJECT, ValueType.OBJECT, ValueType.STRING)); RedisCommand> GEORADIUS = new RedisCommand>("GEORADIUS", new ObjectListReplayDecoder()); RedisCommand> GEORADIUSBYMEMBER = new RedisCommand>("GEORADIUSBYMEMBER", new ObjectListReplayDecoder(), 2); - RedisStrictCommand GEORADIUS_STORE_INT = new RedisStrictCommand("GEORADIUS", new IntegerReplayConvertor()); - RedisStrictCommand GEORADIUSBYMEMBER_STORE_INT = new RedisStrictCommand("GEORADIUSBYMEMBER", new IntegerReplayConvertor(), 2); + RedisCommand GEORADIUS_STORE = new RedisCommand("GEORADIUS", new Long2MultiDecoder()); + RedisCommand GEORADIUSBYMEMBER_STORE = new RedisCommand("GEORADIUSBYMEMBER", new Long2MultiDecoder(), 2); RedisStrictCommand KEYSLOT = new RedisStrictCommand("CLUSTER", "KEYSLOT", new IntegerReplayConvertor()); RedisStrictCommand TYPE = new RedisStrictCommand("TYPE", new TypeConvertor()); diff --git a/redisson/src/main/java/org/redisson/client/protocol/decoder/DecoderState.java b/redisson/src/main/java/org/redisson/client/protocol/decoder/DecoderState.java index 10c3768f8..6c257f8a1 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/decoder/DecoderState.java +++ b/redisson/src/main/java/org/redisson/client/protocol/decoder/DecoderState.java @@ -15,6 +15,11 @@ */ package org.redisson.client.protocol.decoder; +/** + * + * @author Nikita Koksharov + * + */ public interface DecoderState { DecoderState copy(); diff --git a/redisson/src/main/java/org/redisson/client/protocol/decoder/GeoDistanceDecoder.java b/redisson/src/main/java/org/redisson/client/protocol/decoder/GeoDistanceDecoder.java index 12dac9242..970c99b89 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/decoder/GeoDistanceDecoder.java +++ b/redisson/src/main/java/org/redisson/client/protocol/decoder/GeoDistanceDecoder.java @@ -23,8 +23,12 @@ import org.redisson.client.codec.DoubleCodec; import org.redisson.client.handler.State; import io.netty.buffer.ByteBuf; -import io.netty.util.CharsetUtil; +/** + * + * @author Nikita Koksharov + * + */ public class GeoDistanceDecoder implements MultiDecoder> { private final ThreadLocal pos = new ThreadLocal(); diff --git a/redisson/src/main/java/org/redisson/client/protocol/decoder/GeoDistanceMapDecoder.java b/redisson/src/main/java/org/redisson/client/protocol/decoder/GeoDistanceMapDecoder.java index 0745b04c0..9d5bc3193 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/decoder/GeoDistanceMapDecoder.java +++ b/redisson/src/main/java/org/redisson/client/protocol/decoder/GeoDistanceMapDecoder.java @@ -26,6 +26,11 @@ import org.redisson.client.handler.State; import io.netty.buffer.ByteBuf; +/** + * + * @author Nikita Koksharov + * + */ public class GeoDistanceMapDecoder implements MultiDecoder> { private final ThreadLocal pos = new ThreadLocal(); diff --git a/redisson/src/main/java/org/redisson/client/protocol/decoder/GeoMapReplayDecoder.java b/redisson/src/main/java/org/redisson/client/protocol/decoder/GeoMapReplayDecoder.java index 418643b29..523b0225c 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/decoder/GeoMapReplayDecoder.java +++ b/redisson/src/main/java/org/redisson/client/protocol/decoder/GeoMapReplayDecoder.java @@ -23,6 +23,11 @@ import org.redisson.client.handler.State; import io.netty.buffer.ByteBuf; +/** + * + * @author Nikita Koksharov + * + */ public class GeoMapReplayDecoder implements MultiDecoder> { @Override diff --git a/redisson/src/main/java/org/redisson/client/protocol/decoder/GeoPositionDecoder.java b/redisson/src/main/java/org/redisson/client/protocol/decoder/GeoPositionDecoder.java index de373303a..54f756602 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/decoder/GeoPositionDecoder.java +++ b/redisson/src/main/java/org/redisson/client/protocol/decoder/GeoPositionDecoder.java @@ -24,6 +24,11 @@ import org.redisson.client.handler.State; import io.netty.buffer.ByteBuf; +/** + * + * @author Nikita Koksharov + * + */ public class GeoPositionDecoder implements MultiDecoder { @Override diff --git a/redisson/src/main/java/org/redisson/client/protocol/decoder/GeoPositionMapDecoder.java b/redisson/src/main/java/org/redisson/client/protocol/decoder/GeoPositionMapDecoder.java index def4343c1..907d218be 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/decoder/GeoPositionMapDecoder.java +++ b/redisson/src/main/java/org/redisson/client/protocol/decoder/GeoPositionMapDecoder.java @@ -25,6 +25,11 @@ import org.redisson.client.handler.State; import io.netty.buffer.ByteBuf; +/** + * + * @author Nikita Koksharov + * + */ public class GeoPositionMapDecoder implements MultiDecoder> { private final List args; diff --git a/redisson/src/main/java/org/redisson/client/protocol/decoder/KeyValueMessage.java b/redisson/src/main/java/org/redisson/client/protocol/decoder/KeyValueMessage.java index 1a52e1057..74b52886f 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/decoder/KeyValueMessage.java +++ b/redisson/src/main/java/org/redisson/client/protocol/decoder/KeyValueMessage.java @@ -15,6 +15,13 @@ */ package org.redisson.client.protocol.decoder; +/** + * + * @author Nikita Koksharov + * + * @param key type + * @param value type + */ public class KeyValueMessage { private K key; diff --git a/redisson/src/main/java/org/redisson/client/protocol/decoder/KeyValueObjectDecoder.java b/redisson/src/main/java/org/redisson/client/protocol/decoder/KeyValueObjectDecoder.java index 42ca5e798..5ac2d0c65 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/decoder/KeyValueObjectDecoder.java +++ b/redisson/src/main/java/org/redisson/client/protocol/decoder/KeyValueObjectDecoder.java @@ -22,6 +22,11 @@ import org.redisson.client.handler.State; import io.netty.buffer.ByteBuf; import io.netty.util.CharsetUtil; +/** + * + * @author Nikita Koksharov + * + */ public class KeyValueObjectDecoder implements MultiDecoder { @Override diff --git a/redisson/src/main/java/org/redisson/client/protocol/decoder/ListFirstObjectDecoder.java b/redisson/src/main/java/org/redisson/client/protocol/decoder/ListFirstObjectDecoder.java index ded8a9144..cffa3aa42 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/decoder/ListFirstObjectDecoder.java +++ b/redisson/src/main/java/org/redisson/client/protocol/decoder/ListFirstObjectDecoder.java @@ -21,6 +21,11 @@ import org.redisson.client.handler.State; import io.netty.buffer.ByteBuf; +/** + * + * @author Nikita Koksharov + * + */ public class ListFirstObjectDecoder implements MultiDecoder { @Override diff --git a/redisson/src/main/java/org/redisson/client/protocol/decoder/ListIteratorReplayDecoder.java b/redisson/src/main/java/org/redisson/client/protocol/decoder/ListIteratorReplayDecoder.java index 473a46ed1..8278cde72 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/decoder/ListIteratorReplayDecoder.java +++ b/redisson/src/main/java/org/redisson/client/protocol/decoder/ListIteratorReplayDecoder.java @@ -21,6 +21,11 @@ import org.redisson.client.handler.State; import io.netty.buffer.ByteBuf; +/** + * + * @author Nikita Koksharov + * + */ public class ListIteratorReplayDecoder implements MultiDecoder> { @Override diff --git a/redisson/src/main/java/org/redisson/client/protocol/decoder/ListIteratorResult.java b/redisson/src/main/java/org/redisson/client/protocol/decoder/ListIteratorResult.java index 4fc4ffb66..2ae392fa4 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/decoder/ListIteratorResult.java +++ b/redisson/src/main/java/org/redisson/client/protocol/decoder/ListIteratorResult.java @@ -15,6 +15,12 @@ */ package org.redisson.client.protocol.decoder; +/** + * + * @author Nikita Koksharov + * + * @param value type + */ public class ListIteratorResult { private final V element; diff --git a/redisson/src/main/java/org/redisson/client/protocol/decoder/ListMultiDecoder.java b/redisson/src/main/java/org/redisson/client/protocol/decoder/ListMultiDecoder.java index 48072d8cb..0ccbd404e 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/decoder/ListMultiDecoder.java +++ b/redisson/src/main/java/org/redisson/client/protocol/decoder/ListMultiDecoder.java @@ -22,6 +22,12 @@ import org.redisson.client.handler.State; import io.netty.buffer.ByteBuf; +/** + * + * @author Nikita Koksharov + * + * @param type + */ public class ListMultiDecoder implements MultiDecoder { private final MultiDecoder[] decoders; diff --git a/redisson/src/main/java/org/redisson/client/protocol/decoder/ListResultReplayDecoder.java b/redisson/src/main/java/org/redisson/client/protocol/decoder/ListResultReplayDecoder.java index ab75de8f0..75ef13dde 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/decoder/ListResultReplayDecoder.java +++ b/redisson/src/main/java/org/redisson/client/protocol/decoder/ListResultReplayDecoder.java @@ -24,6 +24,11 @@ import org.redisson.client.handler.State; import io.netty.buffer.ByteBuf; import io.netty.util.CharsetUtil; +/** + * + * @author Nikita Koksharov + * + */ public class ListResultReplayDecoder implements MultiDecoder>> { @Override diff --git a/redisson/src/main/java/org/redisson/client/protocol/decoder/ListScanResult.java b/redisson/src/main/java/org/redisson/client/protocol/decoder/ListScanResult.java index 75a97dd3a..269b86e64 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/decoder/ListScanResult.java +++ b/redisson/src/main/java/org/redisson/client/protocol/decoder/ListScanResult.java @@ -20,6 +20,12 @@ import java.util.List; import org.redisson.RedisClientResult; +/** + * + * @author Nikita Koksharov + * + * @param value type + */ public class ListScanResult implements RedisClientResult { private final Long pos; diff --git a/redisson/src/main/java/org/redisson/client/protocol/decoder/ListScanResultReplayDecoder.java b/redisson/src/main/java/org/redisson/client/protocol/decoder/ListScanResultReplayDecoder.java index b47af1ed0..a03e8dd02 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/decoder/ListScanResultReplayDecoder.java +++ b/redisson/src/main/java/org/redisson/client/protocol/decoder/ListScanResultReplayDecoder.java @@ -22,6 +22,11 @@ import org.redisson.client.handler.State; import io.netty.buffer.ByteBuf; import io.netty.util.CharsetUtil; +/** + * + * @author Nikita Koksharov + * + */ public class ListScanResultReplayDecoder implements MultiDecoder> { @Override diff --git a/redisson/src/main/java/org/redisson/client/protocol/decoder/Long2MultiDecoder.java b/redisson/src/main/java/org/redisson/client/protocol/decoder/Long2MultiDecoder.java new file mode 100644 index 000000000..a82d236b1 --- /dev/null +++ b/redisson/src/main/java/org/redisson/client/protocol/decoder/Long2MultiDecoder.java @@ -0,0 +1,37 @@ +/** + * Copyright 2016 Nikita Koksharov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.redisson.client.protocol.decoder; + +import java.util.List; + +import org.redisson.client.handler.State; + +/** + * + * @author Nikita Koksharov + * + */ +public class Long2MultiDecoder extends LongMultiDecoder { + + @Override + public Object decode(List parts, State state) { + if (parts.isEmpty()) { + return 0L; + } + return null; + } + +} diff --git a/redisson/src/main/java/org/redisson/client/protocol/decoder/LongMultiDecoder.java b/redisson/src/main/java/org/redisson/client/protocol/decoder/LongMultiDecoder.java index 0db640e7e..e8eca802b 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/decoder/LongMultiDecoder.java +++ b/redisson/src/main/java/org/redisson/client/protocol/decoder/LongMultiDecoder.java @@ -23,6 +23,11 @@ import org.redisson.client.handler.State; import io.netty.buffer.ByteBuf; +/** + * + * @author Nikita Koksharov + * + */ public class LongMultiDecoder implements MultiDecoder { @Override diff --git a/redisson/src/main/java/org/redisson/client/protocol/decoder/MapCacheScanResult.java b/redisson/src/main/java/org/redisson/client/protocol/decoder/MapCacheScanResult.java index 0aa07d843..e657207a0 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/decoder/MapCacheScanResult.java +++ b/redisson/src/main/java/org/redisson/client/protocol/decoder/MapCacheScanResult.java @@ -18,6 +18,13 @@ package org.redisson.client.protocol.decoder; import java.util.List; import java.util.Map; +/** + * + * @author Nikita Koksharov + * + * @param key type + * @param value type + */ public class MapCacheScanResult extends MapScanResult { private final List idleKeys; diff --git a/redisson/src/main/java/org/redisson/client/protocol/decoder/MapCacheScanResultReplayDecoder.java b/redisson/src/main/java/org/redisson/client/protocol/decoder/MapCacheScanResultReplayDecoder.java index a459a723c..5016751a9 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/decoder/MapCacheScanResultReplayDecoder.java +++ b/redisson/src/main/java/org/redisson/client/protocol/decoder/MapCacheScanResultReplayDecoder.java @@ -23,6 +23,11 @@ import org.redisson.client.handler.State; import io.netty.buffer.ByteBuf; +/** + * + * @author Nikita Koksharov + * + */ public class MapCacheScanResultReplayDecoder implements MultiDecoder> { @Override diff --git a/redisson/src/main/java/org/redisson/client/protocol/decoder/MapScanResult.java b/redisson/src/main/java/org/redisson/client/protocol/decoder/MapScanResult.java index f83c53ecb..d50c6b846 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/decoder/MapScanResult.java +++ b/redisson/src/main/java/org/redisson/client/protocol/decoder/MapScanResult.java @@ -20,6 +20,13 @@ import java.util.Map; import org.redisson.RedisClientResult; +/** + * + * @author Nikita Koksharov + * + * @param key type + * @param value type + */ public class MapScanResult implements RedisClientResult { private final Long pos; diff --git a/redisson/src/main/java/org/redisson/client/protocol/decoder/MapScanResultReplayDecoder.java b/redisson/src/main/java/org/redisson/client/protocol/decoder/MapScanResultReplayDecoder.java index 577f95feb..d7b5ff505 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/decoder/MapScanResultReplayDecoder.java +++ b/redisson/src/main/java/org/redisson/client/protocol/decoder/MapScanResultReplayDecoder.java @@ -23,6 +23,11 @@ import org.redisson.client.handler.State; import io.netty.buffer.ByteBuf; import io.netty.util.CharsetUtil; +/** + * + * @author Nikita Koksharov + * + */ public class MapScanResultReplayDecoder implements MultiDecoder> { @Override diff --git a/redisson/src/main/java/org/redisson/client/protocol/decoder/ObjectFirstResultReplayDecoder.java b/redisson/src/main/java/org/redisson/client/protocol/decoder/ObjectFirstResultReplayDecoder.java index e3c443d8a..de3b819be 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/decoder/ObjectFirstResultReplayDecoder.java +++ b/redisson/src/main/java/org/redisson/client/protocol/decoder/ObjectFirstResultReplayDecoder.java @@ -21,6 +21,12 @@ import org.redisson.client.handler.State; import io.netty.buffer.ByteBuf; +/** + * + * @author Nikita Koksharov + * + * @param type + */ public class ObjectFirstResultReplayDecoder implements MultiDecoder { @Override diff --git a/redisson/src/main/java/org/redisson/client/protocol/decoder/ObjectListDecoder.java b/redisson/src/main/java/org/redisson/client/protocol/decoder/ObjectListDecoder.java index a77636054..0cd24c467 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/decoder/ObjectListDecoder.java +++ b/redisson/src/main/java/org/redisson/client/protocol/decoder/ObjectListDecoder.java @@ -23,6 +23,12 @@ import org.redisson.client.handler.State; import io.netty.buffer.ByteBuf; +/** + * + * @author Nikita Koksharov + * + * @param type + */ public class ObjectListDecoder implements MultiDecoder> { private Codec codec; diff --git a/redisson/src/main/java/org/redisson/client/protocol/decoder/ScanObjectEntry.java b/redisson/src/main/java/org/redisson/client/protocol/decoder/ScanObjectEntry.java index 624fcfce9..b1bae6ab8 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/decoder/ScanObjectEntry.java +++ b/redisson/src/main/java/org/redisson/client/protocol/decoder/ScanObjectEntry.java @@ -17,6 +17,11 @@ package org.redisson.client.protocol.decoder; import io.netty.buffer.ByteBuf; +/** + * + * @author Nikita Koksharov + * + */ public class ScanObjectEntry { private final ByteBuf buf; diff --git a/redisson/src/main/java/org/redisson/client/protocol/decoder/ScoredSortedSetReplayDecoder.java b/redisson/src/main/java/org/redisson/client/protocol/decoder/ScoredSortedSetReplayDecoder.java index ed46da066..6f9411e34 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/decoder/ScoredSortedSetReplayDecoder.java +++ b/redisson/src/main/java/org/redisson/client/protocol/decoder/ScoredSortedSetReplayDecoder.java @@ -25,6 +25,12 @@ import org.redisson.client.protocol.ScoredEntry; import io.netty.buffer.ByteBuf; import io.netty.util.CharsetUtil; +/** + * + * @author Nikita Koksharov + * + * @param type + */ public class ScoredSortedSetReplayDecoder implements MultiDecoder>> { @Override diff --git a/redisson/src/main/java/org/redisson/client/protocol/decoder/ScoredSortedSetScanDecoder.java b/redisson/src/main/java/org/redisson/client/protocol/decoder/ScoredSortedSetScanDecoder.java index ba9c76caf..e9226e5df 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/decoder/ScoredSortedSetScanDecoder.java +++ b/redisson/src/main/java/org/redisson/client/protocol/decoder/ScoredSortedSetScanDecoder.java @@ -22,6 +22,12 @@ import org.redisson.client.handler.State; import io.netty.buffer.ByteBuf; import io.netty.util.CharsetUtil; +/** + * + * @author Nikita Koksharov + * + * @param type + */ public class ScoredSortedSetScanDecoder extends ObjectListReplayDecoder { @Override diff --git a/redisson/src/main/java/org/redisson/client/protocol/decoder/ScoredSortedSetScanReplayDecoder.java b/redisson/src/main/java/org/redisson/client/protocol/decoder/ScoredSortedSetScanReplayDecoder.java index 4145e9825..b92061fd2 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/decoder/ScoredSortedSetScanReplayDecoder.java +++ b/redisson/src/main/java/org/redisson/client/protocol/decoder/ScoredSortedSetScanReplayDecoder.java @@ -22,6 +22,11 @@ import org.redisson.client.handler.State; import io.netty.buffer.ByteBuf; import io.netty.util.CharsetUtil; +/** + * + * @author Nikita Koksharov + * + */ public class ScoredSortedSetScanReplayDecoder implements MultiDecoder> { @Override diff --git a/redisson/src/main/java/org/redisson/client/protocol/decoder/SlotsDecoder.java b/redisson/src/main/java/org/redisson/client/protocol/decoder/SlotsDecoder.java index cbd28efb1..8248a1106 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/decoder/SlotsDecoder.java +++ b/redisson/src/main/java/org/redisson/client/protocol/decoder/SlotsDecoder.java @@ -28,6 +28,11 @@ import org.redisson.cluster.ClusterSlotRange; import io.netty.buffer.ByteBuf; import io.netty.util.CharsetUtil; +/** + * + * @author Nikita Koksharov + * + */ public class SlotsDecoder implements MultiDecoder { @Override diff --git a/redisson/src/main/java/org/redisson/client/protocol/decoder/StringDataDecoder.java b/redisson/src/main/java/org/redisson/client/protocol/decoder/StringDataDecoder.java index 4a4298ba4..c5f70a20a 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/decoder/StringDataDecoder.java +++ b/redisson/src/main/java/org/redisson/client/protocol/decoder/StringDataDecoder.java @@ -21,6 +21,11 @@ import org.redisson.client.protocol.Decoder; import io.netty.buffer.ByteBuf; import io.netty.util.CharsetUtil; +/** + * + * @author Nikita Koksharov + * + */ public class StringDataDecoder implements Decoder { @Override diff --git a/redisson/src/main/java/org/redisson/client/protocol/decoder/StringListReplayDecoder.java b/redisson/src/main/java/org/redisson/client/protocol/decoder/StringListReplayDecoder.java index dc42489f4..89be7cdc8 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/decoder/StringListReplayDecoder.java +++ b/redisson/src/main/java/org/redisson/client/protocol/decoder/StringListReplayDecoder.java @@ -23,6 +23,11 @@ import org.redisson.client.handler.State; import io.netty.buffer.ByteBuf; import io.netty.util.CharsetUtil; +/** + * + * @author Nikita Koksharov + * + */ public class StringListReplayDecoder implements MultiDecoder> { @Override diff --git a/redisson/src/main/java/org/redisson/client/protocol/decoder/StringMapDataDecoder.java b/redisson/src/main/java/org/redisson/client/protocol/decoder/StringMapDataDecoder.java index 2d0c20e73..a7fe8e3fe 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/decoder/StringMapDataDecoder.java +++ b/redisson/src/main/java/org/redisson/client/protocol/decoder/StringMapDataDecoder.java @@ -24,6 +24,11 @@ import org.redisson.client.protocol.Decoder; import io.netty.buffer.ByteBuf; import io.netty.util.CharsetUtil; +/** + * + * @author Nikita Koksharov + * + */ public class StringMapDataDecoder implements Decoder> { @Override diff --git a/redisson/src/main/java/org/redisson/client/protocol/decoder/StringReplayDecoder.java b/redisson/src/main/java/org/redisson/client/protocol/decoder/StringReplayDecoder.java index b0b796af9..480d820e3 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/decoder/StringReplayDecoder.java +++ b/redisson/src/main/java/org/redisson/client/protocol/decoder/StringReplayDecoder.java @@ -21,6 +21,11 @@ import org.redisson.client.protocol.Decoder; import io.netty.buffer.ByteBuf; import io.netty.util.CharsetUtil; +/** + * + * @author Nikita Koksharov + * + */ public class StringReplayDecoder implements Decoder { @Override diff --git a/redisson/src/main/java/org/redisson/client/protocol/decoder/TTLMapValueReplayDecoder.java b/redisson/src/main/java/org/redisson/client/protocol/decoder/TTLMapValueReplayDecoder.java index 7d7cff0ec..038b28bf3 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/decoder/TTLMapValueReplayDecoder.java +++ b/redisson/src/main/java/org/redisson/client/protocol/decoder/TTLMapValueReplayDecoder.java @@ -22,6 +22,12 @@ import org.redisson.client.handler.State; import io.netty.buffer.ByteBuf; import io.netty.util.CharsetUtil; +/** + * + * @author Nikita Koksharov + * + * @param type + */ public class TTLMapValueReplayDecoder implements MultiDecoder> { @Override From 38efe7595dddb5fded4f1dc30f7059e3bf2b6c61 Mon Sep 17 00:00:00 2001 From: Nikita Date: Mon, 8 May 2017 11:26:16 +0300 Subject: [PATCH 28/65] netty updated --- redisson/pom.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/redisson/pom.xml b/redisson/pom.xml index b920b9769..5822c950a 100644 --- a/redisson/pom.xml +++ b/redisson/pom.xml @@ -34,33 +34,33 @@ io.netty netty-transport-native-epoll - 4.1.8.Final + 4.1.10.Final provided io.netty netty-common - 4.1.8.Final + 4.1.10.Final io.netty netty-codec - 4.1.8.Final + 4.1.10.Final io.netty netty-buffer - 4.1.8.Final + 4.1.10.Final io.netty netty-transport - 4.1.8.Final + 4.1.10.Final io.netty netty-handler - 4.1.8.Final + 4.1.10.Final From f53b5913bd6c054a4fe01c3836a31eb9035ea37c Mon Sep 17 00:00:00 2001 From: Nikita Date: Mon, 8 May 2017 12:35:28 +0300 Subject: [PATCH 29/65] zero-allocation-hashing updated to 0.8 --- redisson/pom.xml | 2 +- redisson/src/main/java/org/redisson/RedissonBloomFilter.java | 2 +- redisson/src/main/java/org/redisson/mapreduce/Collector.java | 2 +- redisson/src/main/java/org/redisson/misc/Hash.java | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/redisson/pom.xml b/redisson/pom.xml index 5822c950a..fa272faa2 100644 --- a/redisson/pom.xml +++ b/redisson/pom.xml @@ -223,7 +223,7 @@ net.openhft zero-allocation-hashing - 0.7 + 0.8 net.bytebuddy diff --git a/redisson/src/main/java/org/redisson/RedissonBloomFilter.java b/redisson/src/main/java/org/redisson/RedissonBloomFilter.java index 0818a0d92..5380dc3ce 100644 --- a/redisson/src/main/java/org/redisson/RedissonBloomFilter.java +++ b/redisson/src/main/java/org/redisson/RedissonBloomFilter.java @@ -113,7 +113,7 @@ public class RedissonBloomFilter extends RedissonExpirable implements RBloomF } private long[] hash(byte[] state, int iterations, long size) { - long hash1 = LongHashFunction.xx_r39().hashBytes(state); + long hash1 = LongHashFunction.xx().hashBytes(state); long hash2 = LongHashFunction.farmUo().hashBytes(state); long[] indexes = new long[iterations]; diff --git a/redisson/src/main/java/org/redisson/mapreduce/Collector.java b/redisson/src/main/java/org/redisson/mapreduce/Collector.java index 37f6f5836..f59dd04d9 100644 --- a/redisson/src/main/java/org/redisson/mapreduce/Collector.java +++ b/redisson/src/main/java/org/redisson/mapreduce/Collector.java @@ -56,7 +56,7 @@ public class Collector implements RCollector { public void emit(K key, V value) { try { byte[] encodedKey = codec.getValueEncoder().encode(key); - long hash = LongHashFunction.xx_r39().hashBytes(encodedKey); + long hash = LongHashFunction.xx().hashBytes(encodedKey); int part = (int) Math.abs(hash % parts); String partName = name + ":" + part; diff --git a/redisson/src/main/java/org/redisson/misc/Hash.java b/redisson/src/main/java/org/redisson/misc/Hash.java index df7da118c..c8024709e 100644 --- a/redisson/src/main/java/org/redisson/misc/Hash.java +++ b/redisson/src/main/java/org/redisson/misc/Hash.java @@ -28,7 +28,7 @@ public class Hash { public static byte[] hash(byte[] objectState) { long h1 = LongHashFunction.farmUo().hashBytes(objectState); - long h2 = LongHashFunction.xx_r39().hashBytes(objectState); + long h2 = LongHashFunction.xx().hashBytes(objectState); ByteBuf buf = Unpooled.buffer((2 * Long.SIZE) / Byte.SIZE).writeLong(h1).writeLong(h2); try { @@ -41,7 +41,7 @@ public class Hash { public static String hashToBase64(byte[] objectState) { long h1 = LongHashFunction.farmUo().hashBytes(objectState); - long h2 = LongHashFunction.xx_r39().hashBytes(objectState); + long h2 = LongHashFunction.xx().hashBytes(objectState); ByteBuf buf = Unpooled.buffer((2 * Long.SIZE) / Byte.SIZE).writeLong(h1).writeLong(h2); From 6b840af097e6e067731583e42d8dd6fca84c02a1 Mon Sep 17 00:00:00 2001 From: Nikita Date: Tue, 9 May 2017 17:24:36 +0300 Subject: [PATCH 30/65] netty updated --- redisson-all/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/redisson-all/pom.xml b/redisson-all/pom.xml index fd97ba4cd..ce4274481 100644 --- a/redisson-all/pom.xml +++ b/redisson-all/pom.xml @@ -87,7 +87,7 @@ io.netty netty-transport-native-epoll linux-x86_64 - 4.1.8.Final + 4.1.10.Final com.esotericsoftware From b5961401a8527a6cc670beb65455822317a96b86 Mon Sep 17 00:00:00 2001 From: Nikita Date: Tue, 9 May 2017 17:27:51 +0300 Subject: [PATCH 31/65] [maven-release-plugin] prepare release redisson-2.9.2 --- pom.xml | 4 ++-- redisson-all/pom.xml | 4 ++-- redisson-tomcat/pom.xml | 2 +- redisson-tomcat/redisson-tomcat-6/pom.xml | 2 +- redisson-tomcat/redisson-tomcat-7/pom.xml | 2 +- redisson-tomcat/redisson-tomcat-8/pom.xml | 2 +- redisson/pom.xml | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/pom.xml b/pom.xml index 8f80aad73..dfc6faeb2 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.redisson redisson-parent - 2.9.2-SNAPSHOT + 2.9.2 pom Redisson @@ -27,7 +27,7 @@ scm:git:git@github.com:redisson/redisson.git scm:git:git@github.com:redisson/redisson.git scm:git:git@github.com:redisson/redisson.git - HEAD + redisson-2.9.2 diff --git a/redisson-all/pom.xml b/redisson-all/pom.xml index ce4274481..4f7b5bd13 100644 --- a/redisson-all/pom.xml +++ b/redisson-all/pom.xml @@ -4,7 +4,7 @@ org.redisson redisson-parent - 2.9.2-SNAPSHOT + 2.9.2 ../ @@ -26,7 +26,7 @@ scm:git:git@github.com:mrniko/redisson.git scm:git:git@github.com:mrniko/redisson.git scm:git:git@github.com:mrniko/redisson.git - redisson-parent-0.9.0 + redisson-2.9.2 diff --git a/redisson-tomcat/pom.xml b/redisson-tomcat/pom.xml index 77867c582..7c3af9c0d 100644 --- a/redisson-tomcat/pom.xml +++ b/redisson-tomcat/pom.xml @@ -4,7 +4,7 @@ org.redisson redisson-parent - 2.9.2-SNAPSHOT + 2.9.2 ../ diff --git a/redisson-tomcat/redisson-tomcat-6/pom.xml b/redisson-tomcat/redisson-tomcat-6/pom.xml index e68031e52..728ea3d03 100644 --- a/redisson-tomcat/redisson-tomcat-6/pom.xml +++ b/redisson-tomcat/redisson-tomcat-6/pom.xml @@ -4,7 +4,7 @@ org.redisson redisson-tomcat - 2.9.2-SNAPSHOT + 2.9.2 ../ diff --git a/redisson-tomcat/redisson-tomcat-7/pom.xml b/redisson-tomcat/redisson-tomcat-7/pom.xml index 12f8db34a..42986dcad 100644 --- a/redisson-tomcat/redisson-tomcat-7/pom.xml +++ b/redisson-tomcat/redisson-tomcat-7/pom.xml @@ -4,7 +4,7 @@ org.redisson redisson-tomcat - 2.9.2-SNAPSHOT + 2.9.2 ../ diff --git a/redisson-tomcat/redisson-tomcat-8/pom.xml b/redisson-tomcat/redisson-tomcat-8/pom.xml index f8457da22..32527a8f8 100644 --- a/redisson-tomcat/redisson-tomcat-8/pom.xml +++ b/redisson-tomcat/redisson-tomcat-8/pom.xml @@ -4,7 +4,7 @@ org.redisson redisson-tomcat - 2.9.2-SNAPSHOT + 2.9.2 ../ diff --git a/redisson/pom.xml b/redisson/pom.xml index fa272faa2..1fecd9419 100644 --- a/redisson/pom.xml +++ b/redisson/pom.xml @@ -4,7 +4,7 @@ org.redisson redisson-parent - 2.9.2-SNAPSHOT + 2.9.2 ../ From 5b3bb847121b9c40b9ab3de3e28f92935677b418 Mon Sep 17 00:00:00 2001 From: Nikita Date: Tue, 9 May 2017 17:27:59 +0300 Subject: [PATCH 32/65] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- redisson-all/pom.xml | 4 ++-- redisson-tomcat/pom.xml | 2 +- redisson-tomcat/redisson-tomcat-6/pom.xml | 2 +- redisson-tomcat/redisson-tomcat-7/pom.xml | 2 +- redisson-tomcat/redisson-tomcat-8/pom.xml | 2 +- redisson/pom.xml | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/pom.xml b/pom.xml index dfc6faeb2..fcbefb595 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.redisson redisson-parent - 2.9.2 + 2.9.3-SNAPSHOT pom Redisson @@ -27,7 +27,7 @@ scm:git:git@github.com:redisson/redisson.git scm:git:git@github.com:redisson/redisson.git scm:git:git@github.com:redisson/redisson.git - redisson-2.9.2 + HEAD diff --git a/redisson-all/pom.xml b/redisson-all/pom.xml index 4f7b5bd13..8575da259 100644 --- a/redisson-all/pom.xml +++ b/redisson-all/pom.xml @@ -4,7 +4,7 @@ org.redisson redisson-parent - 2.9.2 + 2.9.3-SNAPSHOT ../ @@ -26,7 +26,7 @@ scm:git:git@github.com:mrniko/redisson.git scm:git:git@github.com:mrniko/redisson.git scm:git:git@github.com:mrniko/redisson.git - redisson-2.9.2 + redisson-parent-0.9.0 diff --git a/redisson-tomcat/pom.xml b/redisson-tomcat/pom.xml index 7c3af9c0d..65d35be3b 100644 --- a/redisson-tomcat/pom.xml +++ b/redisson-tomcat/pom.xml @@ -4,7 +4,7 @@ org.redisson redisson-parent - 2.9.2 + 2.9.3-SNAPSHOT ../ diff --git a/redisson-tomcat/redisson-tomcat-6/pom.xml b/redisson-tomcat/redisson-tomcat-6/pom.xml index 728ea3d03..be53cb9e7 100644 --- a/redisson-tomcat/redisson-tomcat-6/pom.xml +++ b/redisson-tomcat/redisson-tomcat-6/pom.xml @@ -4,7 +4,7 @@ org.redisson redisson-tomcat - 2.9.2 + 2.9.3-SNAPSHOT ../ diff --git a/redisson-tomcat/redisson-tomcat-7/pom.xml b/redisson-tomcat/redisson-tomcat-7/pom.xml index 42986dcad..b47cfd623 100644 --- a/redisson-tomcat/redisson-tomcat-7/pom.xml +++ b/redisson-tomcat/redisson-tomcat-7/pom.xml @@ -4,7 +4,7 @@ org.redisson redisson-tomcat - 2.9.2 + 2.9.3-SNAPSHOT ../ diff --git a/redisson-tomcat/redisson-tomcat-8/pom.xml b/redisson-tomcat/redisson-tomcat-8/pom.xml index 32527a8f8..58a5dcec5 100644 --- a/redisson-tomcat/redisson-tomcat-8/pom.xml +++ b/redisson-tomcat/redisson-tomcat-8/pom.xml @@ -4,7 +4,7 @@ org.redisson redisson-tomcat - 2.9.2 + 2.9.3-SNAPSHOT ../ diff --git a/redisson/pom.xml b/redisson/pom.xml index 1fecd9419..133e3b11d 100644 --- a/redisson/pom.xml +++ b/redisson/pom.xml @@ -4,7 +4,7 @@ org.redisson redisson-parent - 2.9.2 + 2.9.3-SNAPSHOT ../ From 8a691a6620890d90d1bd609914ddf7642d8d12d7 Mon Sep 17 00:00:00 2001 From: Nikita Koksharov Date: Thu, 11 May 2017 12:23:44 +0300 Subject: [PATCH 33/65] Update CHANGELOG.md --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c4be704fd..0cf579841 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,12 @@ Redisson Releases History Try __ULTRA-FAST__ [Redisson PRO](https://redisson.pro) edition. -## Please take part in [Redisson survey](https://www.surveymonkey.com/r/QXQZH5D) +### 10-Apr-2017 - versions 2.9.2 and 3.4.2 released + +Feature - __Dropwizard metrics integration__ More details [here](https://github.com/redisson/redisson/wiki/14.-Integration-with-frameworks#147-dropwizard-metrics) +Feature - `RLocalCachedMap.preloadCache` method added (thanks to Steve Draper) +Feature - `RGeo.radiusStoreTo` methods added (thanks to Cory Sherman) +Fixed - NoClassDefFoundError exception during using `redisson-all` module ### 27-Apr-2017 - versions 2.9.1 and 3.4.1 released From d98128cb69351fbd61aec8e62efe425ccc89bc42 Mon Sep 17 00:00:00 2001 From: Nikita Koksharov Date: Thu, 11 May 2017 22:03:47 +0300 Subject: [PATCH 34/65] Update README.md --- README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 4f3b7f8b5..56dde5c7b 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,8 @@ Based on high-performance async and lock-free Java Redis client and [Netty](http | Stable Release Version | JDK Version compatibility | Release Date | | ------------- | ------------- | ------------| -| 3.4.1 | 1.8+ | 27.04.2017 | -| 2.9.1 | 1.6, 1.7, 1.8 and Android | 27.04.2017 | +| 3.4.2 | 1.8+ | 10.05.2017 | +| 2.9.2 | 1.6, 1.7, 1.8 and Android | 10.05.2017 | __NOTE__: Both version lines have same features except `CompletionStage` interface added in 3.x.x @@ -82,23 +82,23 @@ Quick start org.redisson redisson - 3.4.1 + 3.4.2 org.redisson redisson - 2.9.1 + 2.9.2 #### Gradle // JDK 1.8+ compatible - compile 'org.redisson:redisson:3.4.1' + compile 'org.redisson:redisson:3.4.2' // JDK 1.6+ compatible - compile 'org.redisson:redisson:2.9.1' + compile 'org.redisson:redisson:2.9.2' #### Java @@ -123,11 +123,11 @@ RExecutorService executor = redisson.getExecutorService("myExecutorService"); Downloads =============================== -[Redisson 3.4.1](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson&v=3.4.1&e=jar), -[Redisson node 3.4.1](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-all&v=3.4.1&e=jar) +[Redisson 3.4.2](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson&v=3.4.2&e=jar), +[Redisson node 3.4.2](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-all&v=3.4.2&e=jar) -[Redisson 2.9.1](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson&v=2.9.1&e=jar), -[Redisson node 2.9.1](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-all&v=2.9.1&e=jar) +[Redisson 2.9.2](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson&v=2.9.2&e=jar), +[Redisson node 2.9.2](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-all&v=2.9.2&e=jar) ### Supported by From 96e7baad8406ff684b744f8881169541a31ddadf Mon Sep 17 00:00:00 2001 From: Nikita Date: Fri, 12 May 2017 15:49:25 +0300 Subject: [PATCH 35/65] JSR107 cache implementation should throw javax.cache.CacheException #850 --- .../main/java/org/redisson/jcache/JCache.java | 209 ++++++++++-------- 1 file changed, 111 insertions(+), 98 deletions(-) diff --git a/redisson/src/main/java/org/redisson/jcache/JCache.java b/redisson/src/main/java/org/redisson/jcache/JCache.java index cf898931d..46b3364ac 100644 --- a/redisson/src/main/java/org/redisson/jcache/JCache.java +++ b/redisson/src/main/java/org/redisson/jcache/JCache.java @@ -28,6 +28,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import javax.cache.Cache; +import javax.cache.CacheException; import javax.cache.CacheManager; import javax.cache.configuration.CacheEntryListenerConfiguration; import javax.cache.configuration.Configuration; @@ -57,6 +58,7 @@ import org.redisson.api.RLock; import org.redisson.api.RSemaphore; import org.redisson.api.RTopic; import org.redisson.api.listener.MessageListener; +import org.redisson.client.codec.Codec; import org.redisson.client.codec.MapScanCodec; import org.redisson.client.protocol.RedisCommand; import org.redisson.client.protocol.RedisCommand.ValueType; @@ -209,7 +211,7 @@ public class JCache extends RedissonObject implements Cache { V getValueLocked(K key) { - V value = (V) get(commandExecutor.evalWriteAsync(getName(), codec, EVAL_GET_TTL, + V value = evalWrite(getName(), codec, EVAL_GET_TTL, "local value = redis.call('hget', KEYS[1], ARGV[3]); " + "if value == false then " + "return nil; " @@ -226,7 +228,7 @@ public class JCache extends RedissonObject implements Cache { + "end; " + "return value; ", Arrays.asList(getName(), getTimeoutSetName(), getRemovedChannelName()), - 0, System.currentTimeMillis(), key)); + 0, System.currentTimeMillis(), key); if (value != null) { List result = new ArrayList(3); @@ -234,7 +236,7 @@ public class JCache extends RedissonObject implements Cache { Long accessTimeout = getAccessTimeout(); double syncId = ThreadLocalRandom.current().nextDouble(); - Long syncs = (Long) get(commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_LONG, + Long syncs = evalWrite(getName(), codec, RedisCommands.EVAL_LONG, "if ARGV[1] == '0' then " + "redis.call('hdel', KEYS[1], ARGV[3]); " + "redis.call('zrem', KEYS[2], ARGV[3]); " @@ -250,7 +252,7 @@ public class JCache extends RedissonObject implements Cache { + "end; ", Arrays.asList(getName(), getTimeoutSetName(), getRemovedChannelName(), getRemovedSyncChannelName()), - accessTimeout, System.currentTimeMillis(), encodeMapKey(key), syncId)); + accessTimeout, System.currentTimeMillis(), encodeMapKey(key), syncId); result.add(syncs); result.add(syncId); @@ -265,7 +267,7 @@ public class JCache extends RedissonObject implements Cache { private V getValue(K key) { Long accessTimeout = getAccessTimeout(); - V value = (V) get(commandExecutor.evalWriteAsync(getName(), codec, EVAL_GET_TTL, + V value = evalWrite(getName(), codec, EVAL_GET_TTL, "local value = redis.call('hget', KEYS[1], ARGV[3]); " + "if value == false then " + "return nil; " @@ -292,7 +294,7 @@ public class JCache extends RedissonObject implements Cache { + "return value; ", Arrays.asList(getName(), getTimeoutSetName(), getRemovedChannelName()), - accessTimeout, System.currentTimeMillis(), key)); + accessTimeout, System.currentTimeMillis(), key); return value; } @@ -311,8 +313,7 @@ public class JCache extends RedissonObject implements Cache { } V load(K key) { - RLock lock = getLock(key); - lock.lock(); + RLock lock = getLockedLock(key); try { V value = getValueLocked(key); if (value == null) { @@ -339,12 +340,30 @@ public class JCache extends RedissonObject implements Cache { return value; } + private R write(String key, RedisCommand command, Object ... params) { + RFuture future = commandExecutor.writeAsync(key, command, params); + try { + return get(future); + } catch (Exception e) { + throw new CacheException(e); + } + } + + private R evalWrite(String key, Codec codec, RedisCommand evalCommandType, String script, List keys, Object ... params) { + RFuture future = commandExecutor.evalWriteAsync(key, codec, evalCommandType, script, keys, params); + try { + return get(future); + } catch (Exception e) { + throw new CacheException(e); + } + } + private boolean putValueLocked(K key, Object value) { double syncId = ThreadLocalRandom.current().nextDouble(); if (containsKey(key)) { Long updateTimeout = getUpdateTimeout(); - List res = (List) get(commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_LIST, + List res = evalWrite(getName(), codec, RedisCommands.EVAL_LIST, "if ARGV[2] == '0' then " + "redis.call('hdel', KEYS[1], ARGV[4]); " + "redis.call('zrem', KEYS[2], ARGV[4]); " @@ -372,7 +391,7 @@ public class JCache extends RedissonObject implements Cache { + "end; ", Arrays.asList(getName(), getTimeoutSetName(), getCreatedChannelName(), getRemovedChannelName(), getUpdatedChannelName(), getCreatedSyncChannelName(), getRemovedSyncChannelName(), getUpdatedSyncChannelName()), - 0, updateTimeout, System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value), syncId)); + 0, updateTimeout, System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value), syncId); res.add(syncId); waitSync(res); @@ -381,7 +400,7 @@ public class JCache extends RedissonObject implements Cache { } Long creationTimeout = getCreationTimeout(); - List res = (List) get(commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_LIST, + List res = evalWrite(getName(), codec, RedisCommands.EVAL_LIST, "if ARGV[1] == '0' then " + "return {0};" + "elseif ARGV[1] ~= '-1' then " @@ -402,7 +421,7 @@ public class JCache extends RedissonObject implements Cache { + "end; ", Arrays.asList(getName(), getTimeoutSetName(), getCreatedChannelName(), getRemovedChannelName(), getUpdatedChannelName(), getCreatedSyncChannelName(), getRemovedSyncChannelName(), getUpdatedSyncChannelName()), - creationTimeout, 0, System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value), syncId)); + creationTimeout, 0, System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value), syncId); res.add(syncId); waitSync(res); @@ -417,7 +436,7 @@ public class JCache extends RedissonObject implements Cache { Long creationTimeout = getCreationTimeout(); Long updateTimeout = getUpdateTimeout(); - List res = (List) get(commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_LIST, + List res = evalWrite(getName(), codec, RedisCommands.EVAL_LIST, "if redis.call('hexists', KEYS[1], ARGV[4]) == 1 then " + "if ARGV[2] == '0' then " + "redis.call('hdel', KEYS[1], ARGV[4]); " @@ -466,7 +485,7 @@ public class JCache extends RedissonObject implements Cache { + "end; ", Arrays.asList(getName(), getTimeoutSetName(), getCreatedChannelName(), getRemovedChannelName(), getUpdatedChannelName(), getCreatedSyncChannelName(), getRemovedSyncChannelName(), getUpdatedSyncChannelName()), - creationTimeout, updateTimeout, System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value), syncId)); + creationTimeout, updateTimeout, System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value), syncId); res.add(syncId); waitSync(res); @@ -504,7 +523,7 @@ public class JCache extends RedissonObject implements Cache { private boolean putIfAbsentValue(K key, Object value) { Long creationTimeout = getCreationTimeout(); - return (Boolean) get(commandExecutor.evalWriteAsync(getName(), codec, EVAL_PUT_IF_ABSENT, + return evalWrite(getName(), codec, EVAL_PUT_IF_ABSENT, "if redis.call('hexists', KEYS[1], ARGV[2]) == 1 then " + "return 0; " + "else " @@ -524,7 +543,7 @@ public class JCache extends RedissonObject implements Cache { + "end; " + "end; ", Arrays.asList(getName(), getTimeoutSetName(), getCreatedChannelName()), - creationTimeout, key, value)); + creationTimeout, key, value); } private boolean putIfAbsentValueLocked(K key, Object value) { @@ -533,7 +552,7 @@ public class JCache extends RedissonObject implements Cache { } Long creationTimeout = getCreationTimeout(); - return (Boolean) get(commandExecutor.evalWriteAsync(getName(), codec, EVAL_PUT_IF_ABSENT, + return evalWrite(getName(), codec, EVAL_PUT_IF_ABSENT, "if ARGV[1] == '0' then " + "return 0;" + "elseif ARGV[1] ~= '-1' then " @@ -549,7 +568,7 @@ public class JCache extends RedissonObject implements Cache { + "return 1;" + "end; ", Arrays.asList(getName(), getTimeoutSetName(), getCreatedChannelName()), - creationTimeout, key, value)); + creationTimeout, key, value); } @@ -590,7 +609,7 @@ public class JCache extends RedissonObject implements Cache { args.add(System.currentTimeMillis()); args.addAll(keys); - Map res = (Map) get(commandExecutor.evalWriteAsync(getName(), codec, new RedisCommand>("EVAL", new MapGetAllDecoder(args, 2, true), 8, ValueType.MAP_KEY, ValueType.MAP_VALUE), + Map res = evalWrite(getName(), codec, new RedisCommand>("EVAL", new MapGetAllDecoder(args, 2, true), 8, ValueType.MAP_KEY, ValueType.MAP_VALUE), "local expireHead = redis.call('zrange', KEYS[2], 0, 0, 'withscores');" + "local accessTimeout = ARGV[1]; " + "local currentTime = tonumber(ARGV[2]); " @@ -625,7 +644,7 @@ public class JCache extends RedissonObject implements Cache { + "table.insert(result, value); " + "end; " + "return result;", - Arrays.asList(getName(), getTimeoutSetName(), getRemovedChannelName()), args.toArray())); + Arrays.asList(getName(), getTimeoutSetName(), getRemovedChannelName()), args.toArray()); Map result = new HashMap(); for (Map.Entry entry : res.entrySet()) { @@ -655,7 +674,7 @@ public class JCache extends RedissonObject implements Cache { throw new NullPointerException(); } - return (Boolean) get(commandExecutor.evalWriteAsync(getName(), codec, EVAL_CONTAINS_KEY, + return evalWrite(getName(), codec, EVAL_CONTAINS_KEY, "if redis.call('hexists', KEYS[1], ARGV[2]) == 0 then " + "return 0;" + "end;" @@ -671,7 +690,7 @@ public class JCache extends RedissonObject implements Cache { + "end; " + "return 1;", Arrays.asList(getName(), getTimeoutSetName()), - System.currentTimeMillis(), key)); + System.currentTimeMillis(), key); } @Override @@ -700,8 +719,7 @@ public class JCache extends RedissonObject implements Cache { for (K key : keys) { try { if (!containsKey(key) || replaceExistingValues) { - RLock lock = getLock(key); - lock.lock(); + RLock lock = getLockedLock(key); try { if (!containsKey(key)|| replaceExistingValues) { V value; @@ -732,16 +750,14 @@ public class JCache extends RedissonObject implements Cache { }); } - private RLock getLock(K key) { - String lockName = getLockName(key); - RLock lock = redisson.getLock(lockName); - return lock; - } - private RLock getLockedLock(K key) { String lockName = getLockName(key); RLock lock = redisson.getLock(lockName); - lock.lock(); + try { + lock.lock(); + } catch (Exception e) { + throw new CacheException(e); + } return lock; } @@ -758,8 +774,7 @@ public class JCache extends RedissonObject implements Cache { long startTime = currentNanoTime(); if (config.isWriteThrough()) { - RLock lock = getLock(key); - lock.lock(); + RLock lock = getLockedLock(key); try { List result = getAndPutValueLocked(key, value); if (result.isEmpty()) { @@ -818,17 +833,17 @@ public class JCache extends RedissonObject implements Cache { } private long removeValues(Object... keys) { - return (Long) get(commandExecutor.evalWriteAsync(getName(), codec, EVAL_REMOVE_VALUES, + return evalWrite(getName(), codec, EVAL_REMOVE_VALUES, "redis.call('zrem', KEYS[2], unpack(ARGV)); " + "return redis.call('hdel', KEYS[1], unpack(ARGV)); ", - Arrays.asList(getName(), getTimeoutSetName()), keys)); + Arrays.asList(getName(), getTimeoutSetName()), keys); } private List getAndPutValueLocked(K key, V value) { double syncId = ThreadLocalRandom.current().nextDouble(); if (containsKey(key)) { Long updateTimeout = getUpdateTimeout(); - List result = (List) get(commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_LIST, + List result = evalWrite(getName(), codec, RedisCommands.EVAL_LIST, "local value = redis.call('hget', KEYS[1], ARGV[4]);" + "if ARGV[2] == '0' then " + "redis.call('hdel', KEYS[1], ARGV[4]); " @@ -856,7 +871,7 @@ public class JCache extends RedissonObject implements Cache { + "end; ", Arrays.asList(getName(), getTimeoutSetName(), getRemovedChannelName(), getCreatedChannelName(), getUpdatedChannelName(), getRemovedSyncChannelName(), getCreatedSyncChannelName(), getUpdatedSyncChannelName()), - 0, updateTimeout, System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value), syncId)); + 0, updateTimeout, System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value), syncId); result.add(syncId); waitSync(result); @@ -864,7 +879,7 @@ public class JCache extends RedissonObject implements Cache { } Long creationTimeout = getCreationTimeout(); - List result = (List) get(commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_LIST, + List result = evalWrite(getName(), codec, RedisCommands.EVAL_LIST, "if ARGV[1] == '0' then " + "return {nil};" + "elseif ARGV[1] ~= '-1' then " @@ -884,7 +899,7 @@ public class JCache extends RedissonObject implements Cache { + "return {1, syncs};" + "end; ", Arrays.asList(getName(), getTimeoutSetName(), getCreatedChannelName(), getCreatedSyncChannelName()), - creationTimeout, 0, System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value), syncId)); + creationTimeout, 0, System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value), syncId); result.add(syncId); waitSync(result); @@ -898,7 +913,7 @@ public class JCache extends RedissonObject implements Cache { double syncId = ThreadLocalRandom.current().nextDouble(); - List result = (List) get(commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_LIST, + List result = evalWrite(getName(), codec, RedisCommands.EVAL_LIST, "local value = redis.call('hget', KEYS[1], ARGV[4]);" + "if value ~= false then " + "if ARGV[2] == '0' then " @@ -947,7 +962,7 @@ public class JCache extends RedissonObject implements Cache { + "end; ", Arrays.asList(getName(), getTimeoutSetName(), getRemovedChannelName(), getCreatedChannelName(), getUpdatedChannelName(), getRemovedSyncChannelName(), getCreatedSyncChannelName(), getUpdatedSyncChannelName()), - creationTimeout, updateTimeout, System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value), syncId)); + creationTimeout, updateTimeout, System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value), syncId); if (!result.isEmpty()) { result.add(syncId); @@ -968,8 +983,7 @@ public class JCache extends RedissonObject implements Cache { long startTime = currentNanoTime(); if (config.isWriteThrough()) { - RLock lock = getLock(key); - lock.lock(); + RLock lock = getLockedLock(key); try { List result = getAndPutValueLocked(key, value); if (result.isEmpty()) { @@ -1060,14 +1074,15 @@ public class JCache extends RedissonObject implements Cache { } } + List lockedLocks = new ArrayList(); for (Map.Entry entry : map.entrySet()) { K key = entry.getKey(); V value = entry.getValue(); long startTime = currentNanoTime(); if (config.isWriteThrough()) { - RLock lock = getLock(key); - lock.lock(); + RLock lock = getLockedLock(key); + lockedLocks.add(lock); List result = getAndPutValue(key, value); if (result.isEmpty()) { @@ -1133,8 +1148,8 @@ public class JCache extends RedissonObject implements Cache { throw new CacheWriterException(e); } } finally { - for (Map.Entry entry : map.entrySet()) { - getLock(entry.getKey()).unlock(); + for (RLock lock : lockedLocks) { + lock.unlock(); } } } @@ -1170,8 +1185,7 @@ public class JCache extends RedissonObject implements Cache { long startTime = currentNanoTime(); if (config.isWriteThrough()) { - RLock lock = getLock(key); - lock.lock(); + RLock lock = getLockedLock(key); try { boolean result = putIfAbsentValueLocked(key, value); if (result) { @@ -1209,7 +1223,7 @@ public class JCache extends RedissonObject implements Cache { private boolean removeValue(K key) { double syncId = ThreadLocalRandom.current().nextDouble(); - List res = (List) get(commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_LIST, + List res = evalWrite(getName(), codec, RedisCommands.EVAL_LIST, "local value = redis.call('hexists', KEYS[1], ARGV[2]); " + "if value == 0 then " + "return {0}; " @@ -1234,7 +1248,7 @@ public class JCache extends RedissonObject implements Cache { + "local syncs = redis.call('publish', KEYS[4], syncMsg); " + "return {1, syncs};", Arrays.asList(getName(), getTimeoutSetName(), getRemovedChannelName(), getRemovedSyncChannelName()), - System.currentTimeMillis(), encodeMapKey(key), syncId)); + System.currentTimeMillis(), encodeMapKey(key), syncId); res.add(syncId); waitSync(res); @@ -1252,8 +1266,7 @@ public class JCache extends RedissonObject implements Cache { long startTime = System.currentTimeMillis(); if (config.isWriteThrough()) { - RLock lock = getLock(key); - lock.lock(); + RLock lock = getLockedLock(key); try { V oldValue = getValue(key); boolean result = removeValue(key); @@ -1291,7 +1304,7 @@ public class JCache extends RedissonObject implements Cache { private boolean removeValueLocked(K key, V value) { - Boolean result = (Boolean) get(commandExecutor.evalWriteAsync(getName(), codec, EVAL_REMOVE_KEY_VALUE, + Boolean result = evalWrite(getName(), codec, EVAL_REMOVE_KEY_VALUE, "local value = redis.call('hget', KEYS[1], ARGV[3]); " + "if value == false then " + "return 0; " @@ -1316,12 +1329,12 @@ public class JCache extends RedissonObject implements Cache { + "end; " + "return nil;", Arrays.asList(getName(), getTimeoutSetName(), getRemovedChannelName()), - 0, System.currentTimeMillis(), key, value)); + 0, System.currentTimeMillis(), key, value); if (result == null) { Long accessTimeout = getAccessTimeout(); - return (Boolean) get(commandExecutor.evalWriteAsync(getName(), codec, EVAL_REMOVE_KEY_VALUE, + return evalWrite(getName(), codec, EVAL_REMOVE_KEY_VALUE, "if ARGV[1] == '0' then " + "redis.call('hdel', KEYS[1], ARGV[3]); " + "redis.call('zrem', KEYS[2], ARGV[3]); " @@ -1333,7 +1346,7 @@ public class JCache extends RedissonObject implements Cache { + "end; " + "return 0; ", Arrays.asList(getName(), getTimeoutSetName(), getRemovedChannelName()), - accessTimeout, System.currentTimeMillis(), key, value)); + accessTimeout, System.currentTimeMillis(), key, value); } return result; @@ -1342,7 +1355,7 @@ public class JCache extends RedissonObject implements Cache { private boolean removeValue(K key, V value) { Long accessTimeout = getAccessTimeout(); - return (Boolean) get(commandExecutor.evalWriteAsync(getName(), codec, EVAL_REMOVE_KEY_VALUE, + return evalWrite(getName(), codec, EVAL_REMOVE_KEY_VALUE, "local value = redis.call('hget', KEYS[1], ARGV[3]); " + "if value == false then " + "return 0; " @@ -1376,7 +1389,7 @@ public class JCache extends RedissonObject implements Cache { + "end; " + "return 0; ", Arrays.asList(getName(), getTimeoutSetName(), getRemovedChannelName()), - accessTimeout, System.currentTimeMillis(), key, value)); + accessTimeout, System.currentTimeMillis(), key, value); } @@ -1393,8 +1406,7 @@ public class JCache extends RedissonObject implements Cache { long startTime = currentNanoTime(); boolean result; if (config.isWriteThrough()) { - RLock lock = getLock(key); - lock.lock(); + RLock lock = getLockedLock(key); try { result = removeValueLocked(key, value); if (result) { @@ -1439,7 +1451,7 @@ public class JCache extends RedissonObject implements Cache { private V getAndRemoveValue(K key) { double syncId = ThreadLocalRandom.current().nextDouble(); - List result = (List) get(commandExecutor.evalWriteAsync(getName(), codec, EVAL_GET_REMOVE_VALUE_LIST, + List result = evalWrite(getName(), codec, EVAL_GET_REMOVE_VALUE_LIST, "local value = redis.call('hget', KEYS[1], ARGV[2]); " + "if value == false then " + "return {nil}; " @@ -1463,7 +1475,7 @@ public class JCache extends RedissonObject implements Cache { + "local syncs = redis.call('publish', KEYS[4], syncMsg); " + "return {value, syncs}; ", Arrays.asList(getName(), getTimeoutSetName(), getRemovedChannelName(), getRemovedSyncChannelName()), - System.currentTimeMillis(), encodeMapKey(key), syncId)); + System.currentTimeMillis(), encodeMapKey(key), syncId); if (result.isEmpty()) { return null; @@ -1485,8 +1497,7 @@ public class JCache extends RedissonObject implements Cache { long startTime = currentNanoTime(); if (config.isWriteThrough()) { - RLock lock = getLock(key); - lock.lock(); + RLock lock = getLockedLock(key); try { Object value = getAndRemoveValue(key); if (value != null) { @@ -1530,7 +1541,7 @@ public class JCache extends RedissonObject implements Cache { } private long replaceValueLocked(K key, V oldValue, V newValue) { - Long res = (Long) get(commandExecutor.evalWriteAsync(getName(), codec, EVAL_REPLACE_OLD_NEW_VALUE, + Long res = evalWrite(getName(), codec, EVAL_REPLACE_OLD_NEW_VALUE, "local value = redis.call('hget', KEYS[1], ARGV[4]); " + "if value == false then " + "return 0; " @@ -1551,12 +1562,12 @@ public class JCache extends RedissonObject implements Cache { + "end; " + "return -1;", Arrays.asList(getName(), getTimeoutSetName(), getRemovedChannelName(), getUpdatedChannelName()), - 0, 0, System.currentTimeMillis(), key, oldValue, newValue)); + 0, 0, System.currentTimeMillis(), key, oldValue, newValue); if (res == 1) { Long updateTimeout = getUpdateTimeout(); double syncId = ThreadLocalRandom.current().nextDouble(); - Long syncs = (Long) get(commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_LONG, + Long syncs = evalWrite(getName(), codec, RedisCommands.EVAL_LONG, "if ARGV[2] == '0' then " + "redis.call('hdel', KEYS[1], ARGV[4]); " + "redis.call('zrem', KEYS[2], ARGV[4]); " @@ -1581,7 +1592,7 @@ public class JCache extends RedissonObject implements Cache { + "end; ", Arrays.asList(getName(), getTimeoutSetName(), getRemovedChannelName(), getUpdatedChannelName(), getRemovedSyncChannelName(), getUpdatedSyncChannelName()), - 0, updateTimeout, System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(oldValue), encodeMapValue(newValue), syncId)); + 0, updateTimeout, System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(oldValue), encodeMapValue(newValue), syncId); List result = Arrays.asList(syncs, syncId); waitSync(result); @@ -1594,7 +1605,7 @@ public class JCache extends RedissonObject implements Cache { Long accessTimeout = getAccessTimeout(); double syncId = ThreadLocalRandom.current().nextDouble(); - List result = (List) get(commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_LIST, + List result = evalWrite(getName(), codec, RedisCommands.EVAL_LIST, "if ARGV[1] == '0' then " + "redis.call('hdel', KEYS[1], ARGV[4]); " + "redis.call('zrem', KEYS[2], ARGV[4]); " @@ -1610,7 +1621,7 @@ public class JCache extends RedissonObject implements Cache { + "end; " + "return {-1}; ", Arrays.asList(getName(), getTimeoutSetName(), getRemovedChannelName(), getRemovedSyncChannelName()), - accessTimeout, 0, System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(oldValue), encodeMapValue(newValue), syncId)); + accessTimeout, 0, System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(oldValue), encodeMapValue(newValue), syncId); result.add(syncId); waitSync(result); @@ -1623,7 +1634,7 @@ public class JCache extends RedissonObject implements Cache { Long updateTimeout = getUpdateTimeout(); - return (Long) get(commandExecutor.evalWriteAsync(getName(), codec, EVAL_REPLACE_OLD_NEW_VALUE, + return evalWrite(getName(), codec, EVAL_REPLACE_OLD_NEW_VALUE, "local value = redis.call('hget', KEYS[1], ARGV[4]); " + "if value == false then " + "return 0; " @@ -1669,7 +1680,7 @@ public class JCache extends RedissonObject implements Cache { + "end; " + "return -1; ", Arrays.asList(getName(), getTimeoutSetName(), getRemovedChannelName(), getUpdatedChannelName()), - accessTimeout, updateTimeout, System.currentTimeMillis(), key, oldValue, newValue)); + accessTimeout, updateTimeout, System.currentTimeMillis(), key, oldValue, newValue); } @@ -1688,8 +1699,7 @@ public class JCache extends RedissonObject implements Cache { long startTime = currentNanoTime(); if (config.isWriteThrough()) { - RLock lock = getLock(key); - lock.lock(); + RLock lock = getLockedLock(key); try { long result = replaceValueLocked(key, oldValue, newValue); if (result == 1) { @@ -1746,7 +1756,7 @@ public class JCache extends RedissonObject implements Cache { if (containsKey(key)) { double syncId = ThreadLocalRandom.current().nextDouble(); Long updateTimeout = getUpdateTimeout(); - Long syncs = (Long) get(commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_LONG, + Long syncs = evalWrite(getName(), codec, RedisCommands.EVAL_LONG, "if ARGV[1] == '0' then " + "redis.call('hdel', KEYS[1], ARGV[3]); " + "redis.call('zrem', KEYS[2], ARGV[3]); " @@ -1771,7 +1781,7 @@ public class JCache extends RedissonObject implements Cache { + "end; ", Arrays.asList(getName(), getTimeoutSetName(), getRemovedChannelName(), getUpdatedChannelName(), getRemovedSyncChannelName(), getUpdatedSyncChannelName()), - updateTimeout, System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value), syncId)); + updateTimeout, System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value), syncId); List result = Arrays.asList(syncs, syncId); waitSync(result); @@ -1786,7 +1796,7 @@ public class JCache extends RedissonObject implements Cache { private boolean replaceValue(K key, V value) { Long updateTimeout = getUpdateTimeout(); - return (Boolean) get(commandExecutor.evalWriteAsync(getName(), codec, EVAL_REPLACE_VALUE, + return evalWrite(getName(), codec, EVAL_REPLACE_VALUE, "local value = redis.call('hget', KEYS[1], ARGV[3]); " + "if value == false then " + "return 0; " @@ -1819,14 +1829,14 @@ public class JCache extends RedissonObject implements Cache { + "end; " + "return 1;", Arrays.asList(getName(), getTimeoutSetName(), getRemovedChannelName(), getUpdatedChannelName()), - updateTimeout, System.currentTimeMillis(), key, value)); + updateTimeout, System.currentTimeMillis(), key, value); } private V getAndReplaceValue(K key, V value) { Long updateTimeout = getUpdateTimeout(); - return (V) get(commandExecutor.evalWriteAsync(getName(), codec, EVAL_GET_REPLACE, + return evalWrite(getName(), codec, EVAL_GET_REPLACE, "local value = redis.call('hget', KEYS[1], ARGV[3]); " + "if value == false then " + "return nil; " @@ -1859,12 +1869,12 @@ public class JCache extends RedissonObject implements Cache { + "end; " + "return value;", Arrays.asList(getName(), getTimeoutSetName(), getRemovedChannelName(), getUpdatedChannelName()), - updateTimeout, System.currentTimeMillis(), key, value)); + updateTimeout, System.currentTimeMillis(), key, value); } private V getAndReplaceValueLocked(K key, V value) { - V oldValue = (V) get(commandExecutor.evalWriteAsync(getName(), codec, EVAL_GET_REPLACE, + V oldValue = evalWrite(getName(), codec, EVAL_GET_REPLACE, "local value = redis.call('hget', KEYS[1], ARGV[3]); " + "if value == false then " + "return nil; " @@ -1881,12 +1891,12 @@ public class JCache extends RedissonObject implements Cache { + "end; " + "return value;", Arrays.asList(getName(), getTimeoutSetName(), getRemovedChannelName(), getUpdatedChannelName()), - 0, System.currentTimeMillis(), key, value)); + 0, System.currentTimeMillis(), key, value); if (oldValue != null) { Long updateTimeout = getUpdateTimeout(); double syncId = ThreadLocalRandom.current().nextDouble(); - Long syncs = (Long) get(commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_LONG, + Long syncs = evalWrite(getName(), codec, RedisCommands.EVAL_LONG, "if ARGV[1] == '0' then " + "local value = redis.call('hget', KEYS[1], ARGV[3]); " + "redis.call('hdel', KEYS[1], ARGV[3]); " @@ -1911,7 +1921,7 @@ public class JCache extends RedissonObject implements Cache { + "end; ", Arrays.asList(getName(), getTimeoutSetName(), getRemovedChannelName(), getUpdatedChannelName(), getRemovedSyncChannelName(), getUpdatedSyncChannelName()), - updateTimeout, System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value), syncId)); + updateTimeout, System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value), syncId); List result = Arrays.asList(syncs, syncId); waitSync(result); @@ -1932,8 +1942,7 @@ public class JCache extends RedissonObject implements Cache { long startTime = currentNanoTime(); if (config.isWriteThrough()) { - RLock lock = getLock(key); - lock.lock(); + RLock lock = getLockedLock(key); try { boolean result = replaceValueLocked(key, value); if (result) { @@ -1986,8 +1995,7 @@ public class JCache extends RedissonObject implements Cache { long startTime = currentNanoTime(); if (config.isWriteThrough()) { - RLock lock = getLock(key); - lock.lock(); + RLock lock = getLockedLock(key); try { V result = getAndReplaceValueLocked(key, value); if (result != null) { @@ -2041,11 +2049,12 @@ public class JCache extends RedissonObject implements Cache { } } + List lockedLocks = new ArrayList(); long startTime = currentNanoTime(); if (config.isWriteThrough()) { for (K key : keys) { - RLock lock = getLock(key); - lock.lock(); + RLock lock = getLockedLock(key); + lockedLocks.add(lock); V result = getAndRemoveValue(key); if (result != null) { deletedKeys.put(key, result); @@ -2072,8 +2081,8 @@ public class JCache extends RedissonObject implements Cache { } cacheManager.getStatBean(this).addRemovals(deletedKeys.size()); } finally { - for (K key : keys) { - getLock(key).unlock(); + for (RLock lock : lockedLocks) { + lock.unlock(); } } } else { @@ -2086,7 +2095,11 @@ public class JCache extends RedissonObject implements Cache { MapScanResult scanIterator(String name, InetSocketAddress client, long startPos) { RFuture> f = commandExecutor.readAsync(client, name, new MapScanCodec(codec), RedisCommands.HSCAN, name, startPos); - return get(f); + try { + return get(f); + } catch (Exception e) { + throw new CacheException(e); + } } protected Iterator keyIterator() { @@ -2123,7 +2136,7 @@ public class JCache extends RedissonObject implements Cache { } } else { long startTime = currentNanoTime(); - long removedObjects = (Long) get(commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_LONG, + long removedObjects = evalWrite(getName(), codec, RedisCommands.EVAL_LONG, "local expiredEntriesCount = redis.call('zcount', KEYS[2], 0, ARGV[1]); " + "local result = 0; " + "if expiredEntriesCount > 0 then " @@ -2134,7 +2147,7 @@ public class JCache extends RedissonObject implements Cache { + "redis.call('del', KEYS[1], KEYS[2]); " + "return result; ", Arrays.asList(getName(), getTimeoutSetName()), - System.currentTimeMillis())); + System.currentTimeMillis()); cacheManager.getStatBean(this).addRemovals(removedObjects); cacheManager.getStatBean(this).addRemoveTime(currentNanoTime() - startTime); } @@ -2143,7 +2156,7 @@ public class JCache extends RedissonObject implements Cache { @Override public void clear() { checkNotClosed(); - get(commandExecutor.writeAsync(getName(), RedisCommands.DEL_OBJECTS, getName(), getTimeoutSetName())); + write(getName(), RedisCommands.DEL_OBJECTS, getName(), getTimeoutSetName()); } @Override @@ -2414,7 +2427,7 @@ public class JCache extends RedissonObject implements Cache { if (accessTimeout == 0) { remove(); } else if (accessTimeout != -1) { - get(commandExecutor.writeAsync(getName(), RedisCommands.ZADD_BOOL, getTimeoutSetName(), accessTimeout, entry.getKey().getObj())); + write(getName(), RedisCommands.ZADD_BOOL, getTimeoutSetName(), accessTimeout, entry.getKey().getObj()); } return je; } From f50aa24fff45fed39232bfd450bafe482a50c858 Mon Sep 17 00:00:00 2001 From: Nikita Date: Fri, 19 May 2017 12:52:36 +0300 Subject: [PATCH 36/65] NPE checking in RedissonMapCache added --- .../main/java/org/redisson/RedissonMap.java | 90 +++++++------------ .../java/org/redisson/RedissonMapCache.java | 56 ++++++++++++ 2 files changed, 87 insertions(+), 59 deletions(-) diff --git a/redisson/src/main/java/org/redisson/RedissonMap.java b/redisson/src/main/java/org/redisson/RedissonMap.java index d48f6d418..5eb7552a7 100644 --- a/redisson/src/main/java/org/redisson/RedissonMap.java +++ b/redisson/src/main/java/org/redisson/RedissonMap.java @@ -127,11 +127,15 @@ public class RedissonMap extends RedissonExpirable implements RMap { @Override public RFuture valueSizeAsync(K key) { + checkKey(key); + + return commandExecutor.readAsync(getName(), codec, RedisCommands.HSTRLEN, getName(key), key); + } + + protected void checkKey(Object key) { if (key == null) { throw new NullPointerException("map key can't be null"); } - - return commandExecutor.readAsync(getName(), codec, RedisCommands.HSTRLEN, getName(key), key); } @Override @@ -146,9 +150,7 @@ public class RedissonMap extends RedissonExpirable implements RMap { @Override public RFuture containsKeyAsync(Object key) { - if (key == null) { - throw new NullPointerException("map key can't be null"); - } + checkKey(key); return commandExecutor.readAsync(getName(key), codec, RedisCommands.HEXISTS, getName(key), key); } @@ -160,9 +162,7 @@ public class RedissonMap extends RedissonExpirable implements RMap { @Override public RFuture containsValueAsync(Object value) { - if (value == null) { - throw new NullPointerException("map value can't be null"); - } + checkValue(value); return commandExecutor.evalReadAsync(getName(), codec, new RedisCommand("EVAL", new BooleanReplayConvertor(), 4), "local s = redis.call('hvals', KEYS[1]);" + @@ -296,12 +296,8 @@ public class RedissonMap extends RedissonExpirable implements RMap { @Override public RFuture putIfAbsentAsync(K key, V value) { - if (key == null) { - throw new NullPointerException("map key can't be null"); - } - if (value == null) { - throw new NullPointerException("map value can't be null"); - } + checkKey(key); + checkValue(key); return commandExecutor.evalWriteAsync(getName(key), codec, EVAL_PUT, "if redis.call('hsetnx', KEYS[1], ARGV[1], ARGV[2]) == 1 then " @@ -319,12 +315,8 @@ public class RedissonMap extends RedissonExpirable implements RMap { @Override public RFuture fastPutIfAbsentAsync(K key, V value) { - if (key == null) { - throw new NullPointerException("map key can't be null"); - } - if (value == null) { - throw new NullPointerException("map value can't be null"); - } + checkKey(key); + checkValue(value); return commandExecutor.writeAsync(getName(key), codec, RedisCommands.HSETNX, getName(key), key, value); } @@ -336,12 +328,8 @@ public class RedissonMap extends RedissonExpirable implements RMap { @Override public RFuture removeAsync(Object key, Object value) { - if (key == null) { - throw new NullPointerException("map key can't be null"); - } - if (value == null) { - throw new NullPointerException("map value can't be null"); - } + checkKey(key); + checkValue(value); return commandExecutor.evalWriteAsync(getName(key), codec, EVAL_REMOVE_VALUE, "if redis.call('hget', KEYS[1], ARGV[1]) == ARGV[2] then " @@ -352,6 +340,12 @@ public class RedissonMap extends RedissonExpirable implements RMap { Collections.singletonList(getName(key)), key, value); } + protected void checkValue(Object value) { + if (value == null) { + throw new NullPointerException("map value can't be null"); + } + } + @Override public boolean replace(K key, V oldValue, V newValue) { return get(replaceAsync(key, oldValue, newValue)); @@ -359,9 +353,7 @@ public class RedissonMap extends RedissonExpirable implements RMap { @Override public RFuture replaceAsync(K key, V oldValue, V newValue) { - if (key == null) { - throw new NullPointerException("map key can't be null"); - } + checkKey(key); if (oldValue == null) { throw new NullPointerException("map oldValue can't be null"); } @@ -387,12 +379,8 @@ public class RedissonMap extends RedissonExpirable implements RMap { @Override public RFuture replaceAsync(K key, V value) { - if (key == null) { - throw new NullPointerException("map key can't be null"); - } - if (value == null) { - throw new NullPointerException("map value can't be null"); - } + checkKey(key); + checkValue(value); return commandExecutor.evalWriteAsync(getName(key), codec, EVAL_REPLACE, "if redis.call('hexists', KEYS[1], ARGV[1]) == 1 then " @@ -407,21 +395,15 @@ public class RedissonMap extends RedissonExpirable implements RMap { @Override public RFuture getAsync(K key) { - if (key == null) { - throw new NullPointerException("map key can't be null"); - } + checkKey(key); return commandExecutor.readAsync(getName(key), codec, RedisCommands.HGET, getName(key), key); } @Override public RFuture putAsync(K key, V value) { - if (key == null) { - throw new NullPointerException("map key can't be null"); - } - if (value == null) { - throw new NullPointerException("map value can't be null"); - } + checkKey(key); + checkValue(value); return commandExecutor.evalWriteAsync(getName(key), codec, EVAL_PUT, "local v = redis.call('hget', KEYS[1], ARGV[1]); " @@ -433,9 +415,7 @@ public class RedissonMap extends RedissonExpirable implements RMap { @Override public RFuture removeAsync(K key) { - if (key == null) { - throw new NullPointerException("map key can't be null"); - } + checkKey(key); return commandExecutor.evalWriteAsync(getName(key), codec, EVAL_REMOVE, "local v = redis.call('hget', KEYS[1], ARGV[1]); " @@ -446,12 +426,8 @@ public class RedissonMap extends RedissonExpirable implements RMap { @Override public RFuture fastPutAsync(K key, V value) { - if (key == null) { - throw new NullPointerException("map key can't be null"); - } - if (value == null) { - throw new NullPointerException("map value can't be null"); - } + checkKey(key); + checkValue(value); return commandExecutor.writeAsync(getName(key), codec, RedisCommands.HSET, getName(key), key, value); } @@ -491,12 +467,8 @@ public class RedissonMap extends RedissonExpirable implements RMap { @Override public RFuture addAndGetAsync(K key, Number value) { - if (key == null) { - throw new NullPointerException("map key can't be null"); - } - if (value == null) { - throw new NullPointerException("map value can't be null"); - } + checkKey(key); + checkValue(value); byte[] keyState = encodeMapKey(key); return commandExecutor.writeAsync(getName(key), StringCodec.INSTANCE, diff --git a/redisson/src/main/java/org/redisson/RedissonMapCache.java b/redisson/src/main/java/org/redisson/RedissonMapCache.java index 049dff84c..b7df19c49 100644 --- a/redisson/src/main/java/org/redisson/RedissonMapCache.java +++ b/redisson/src/main/java/org/redisson/RedissonMapCache.java @@ -113,6 +113,8 @@ public class RedissonMapCache extends RedissonMap implements RMapCac @Override public RFuture containsKeyAsync(Object key) { + checkKey(key); + return commandExecutor.evalWriteAsync(getName(key), codec, EVAL_CONTAINS_KEY, "local value = redis.call('hget', KEYS[1], ARGV[2]); " + "local expireDate = 92233720368547758; " + @@ -144,6 +146,8 @@ public class RedissonMapCache extends RedissonMap implements RMapCac @Override public RFuture containsValueAsync(Object value) { + checkValue(value); + return commandExecutor.evalWriteAsync(getName(), codec, EVAL_CONTAINS_VALUE, "local s = redis.call('hgetall', KEYS[1]); " + "for i, v in ipairs(s) do " @@ -244,6 +248,9 @@ public class RedissonMapCache extends RedissonMap implements RMapCac @Override public RFuture putIfAbsentAsync(K key, V value, long ttl, TimeUnit ttlUnit, long maxIdleTime, TimeUnit maxIdleUnit) { + checkKey(key); + checkValue(value); + if (ttl < 0) { throw new IllegalArgumentException("ttl can't be negative"); } @@ -329,6 +336,9 @@ public class RedissonMapCache extends RedissonMap implements RMapCac @Override public RFuture removeAsync(Object key, Object value) { + checkKey(key); + checkValue(value); + return commandExecutor.evalWriteAsync(getName(key), codec, EVAL_REMOVE_VALUE, "local value = redis.call('hget', KEYS[1], ARGV[1]); " + "if value == false then " @@ -347,6 +357,8 @@ public class RedissonMapCache extends RedissonMap implements RMapCac @Override public RFuture getAsync(K key) { + checkKey(key); + return commandExecutor.evalWriteAsync(getName(key), codec, EVAL_GET_TTL, "local value = redis.call('hget', KEYS[1], ARGV[2]); " + "if value == false then " @@ -383,6 +395,9 @@ public class RedissonMapCache extends RedissonMap implements RMapCac @Override public RFuture putAsync(K key, V value) { + checkKey(key); + checkValue(value); + return commandExecutor.evalWriteAsync(getName(key), codec, EVAL_PUT, "local v = redis.call('hget', KEYS[1], ARGV[1]); " + "local value = struct.pack('dLc0', 0, string.len(ARGV[2]), ARGV[2]); " @@ -397,6 +412,9 @@ public class RedissonMapCache extends RedissonMap implements RMapCac @Override public RFuture putIfAbsentAsync(K key, V value) { + checkKey(key); + checkValue(value); + 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 " @@ -419,6 +437,9 @@ public class RedissonMapCache extends RedissonMap implements RMapCac @Override public RFuture addAndGetAsync(K key, Number value) { + checkKey(key); + checkValue(value); + byte[] keyState = encodeMapKey(key); byte[] valueState; try { @@ -479,6 +500,9 @@ public class RedissonMapCache extends RedissonMap implements RMapCac @Override public RFuture fastPutAsync(K key, V value, long ttl, TimeUnit ttlUnit, long maxIdleTime, TimeUnit maxIdleUnit) { + checkKey(key); + checkValue(value); + if (ttl < 0) { throw new IllegalArgumentException("ttl can't be negative"); } @@ -537,6 +561,9 @@ public class RedissonMapCache extends RedissonMap implements RMapCac @Override public RFuture putAsync(K key, V value, long ttl, TimeUnit ttlUnit, long maxIdleTime, TimeUnit maxIdleUnit) { + checkKey(key); + checkValue(value); + if (ttl < 0) { throw new IllegalArgumentException("ttl can't be negative"); } @@ -616,6 +643,8 @@ public class RedissonMapCache extends RedissonMap implements RMapCac @Override public RFuture removeAsync(K key) { + checkKey(key); + return commandExecutor.evalWriteAsync(getName(key), codec, EVAL_REMOVE, "local v = redis.call('hget', KEYS[1], ARGV[1]); " + "redis.call('zrem', KEYS[2], ARGV[1]); " @@ -730,6 +759,9 @@ public class RedissonMapCache extends RedissonMap implements RMapCac @Override public RFuture fastPutAsync(K key, V value) { + checkKey(key); + checkValue(value); + return commandExecutor.evalWriteAsync(getName(key), codec, EVAL_HSET, "local val = struct.pack('dLc0', 0, string.len(ARGV[2]), ARGV[2]); " + "return redis.call('hset', KEYS[1], ARGV[1], val); ", @@ -738,6 +770,9 @@ public class RedissonMapCache extends RedissonMap implements RMapCac @Override public RFuture fastPutIfAbsentAsync(K key, V value) { + checkKey(key); + checkValue(value); + return commandExecutor.evalWriteAsync(getName(key), codec, EVAL_PUT_IF_ABSENT, "local value = redis.call('hget', KEYS[1], ARGV[2]); " + "if value == false then " @@ -786,6 +821,9 @@ public class RedissonMapCache extends RedissonMap implements RMapCac @Override public RFuture fastPutIfAbsentAsync(K key, V value, long ttl, TimeUnit ttlUnit, long maxIdleTime, TimeUnit maxIdleUnit) { + checkKey(key); + checkValue(value); + if (ttl < 0) { throw new IllegalArgumentException("ttl can't be negative"); } @@ -869,6 +907,14 @@ public class RedissonMapCache extends RedissonMap implements RMapCac @Override public RFuture 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"); + } + return commandExecutor.evalWriteAsync(getName(key), codec, EVAL_REPLACE_VALUE, "local v = redis.call('hget', KEYS[1], ARGV[2]); " + "if v == false then " @@ -903,6 +949,9 @@ public class RedissonMapCache extends RedissonMap implements RMapCac @Override public RFuture replaceAsync(K key, V value) { + checkKey(key); + checkValue(value); + return commandExecutor.evalWriteAsync(getName(key), codec, EVAL_REPLACE, "local v = redis.call('hget', KEYS[1], ARGV[2]); " + "if v ~= false then " @@ -927,6 +976,13 @@ public class RedissonMapCache extends RedissonMap implements RMapCac List params = new ArrayList(map.size()*2); for (java.util.Map.Entry t : map.entrySet()) { + if (t.getKey() == null) { + throw new NullPointerException("map key can't be null"); + } + if (t.getValue() == null) { + throw new NullPointerException("map value can't be null"); + } + params.add(t.getKey()); params.add(t.getValue()); } From d7fc13713781af294327d3c8f51a3cd65b21edb1 Mon Sep 17 00:00:00 2001 From: Nikita Date: Sat, 20 May 2017 14:08:19 +0300 Subject: [PATCH 37/65] enum Node.InfoSection should be public --- redisson/src/main/java/org/redisson/api/Node.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/redisson/src/main/java/org/redisson/api/Node.java b/redisson/src/main/java/org/redisson/api/Node.java index be2831b89..fa239c0fe 100644 --- a/redisson/src/main/java/org/redisson/api/Node.java +++ b/redisson/src/main/java/org/redisson/api/Node.java @@ -26,7 +26,7 @@ import java.util.Map; */ public interface Node extends NodeAsync { - enum InfoSection {ALL, DEFAULT, SERVER, CLIENTS, MEMORY, PERSISTENCE, STATS, REPLICATION, CPU, COMMANDSTATS, CLUSTER, KEYSPACE} + public enum InfoSection {ALL, DEFAULT, SERVER, CLIENTS, MEMORY, PERSISTENCE, STATS, REPLICATION, CPU, COMMANDSTATS, CLUSTER, KEYSPACE} Map info(InfoSection section); From adf072ec906a91de6f09ab618a40beab6589e617 Mon Sep 17 00:00:00 2001 From: Nikita Date: Sat, 20 May 2017 14:36:12 +0300 Subject: [PATCH 38/65] SSL support added. #842 --- .../main/java/org/redisson/RedisNodes.java | 21 +- .../src/main/java/org/redisson/Redisson.java | 4 +- .../java/org/redisson/api/NodesGroup.java | 2 +- .../java/org/redisson/api/RKeysAsync.java | 2 + .../api/mapreduce/RCollectionMapReduce.java | 4 +- .../redisson/api/mapreduce/RMapReduce.java | 4 +- .../java/org/redisson/client/RedisClient.java | 215 +++++++++++------- .../redisson/client/RedisClientConfig.java | 205 +++++++++++++++++ .../org/redisson/client/RedisConnection.java | 42 ++-- .../client/RedisPubSubConnection.java | 5 +- .../client/handler/BaseConnectionHandler.java | 108 +++++++++ .../client/handler/ConnectionWatchdog.java | 88 ++++--- .../handler/RedisChannelInitializer.java | 186 +++++++++++++++ .../handler/RedisConnectionHandler.java | 39 ++++ .../handler/RedisPubSubConnectionHandler.java | 39 ++++ .../redisson/client/protocol/CommandData.java | 2 +- .../client/protocol/CommandsData.java | 5 + .../client/protocol/QueueCommandHolder.java | 5 + .../protocol/decoder/ClusterNodesDecoder.java | 2 +- .../cluster/ClusterConnectionListener.java | 42 ---- .../cluster/ClusterConnectionManager.java | 103 ++++----- .../org/redisson/cluster/ClusterNodeInfo.java | 9 +- .../redisson/cluster/ClusterPartition.java | 29 +-- .../redisson/command/CommandAsyncService.java | 26 ++- .../java/org/redisson/config/BaseConfig.java | 117 ++++++++++ .../redisson/config/ClusterServersConfig.java | 12 +- .../org/redisson/config/ConfigSupport.java | 96 ++------ .../config/MasterSlaveServersConfig.java | 23 +- .../config/ReplicatedServersConfig.java | 12 +- .../config/SentinelServersConfig.java | 12 +- .../redisson/config/SingleServerConfig.java | 12 +- .../SslProvider.java} | 27 ++- .../connection/ClientConnectionsEntry.java | 44 +--- .../connection/ConnectionManager.java | 10 +- .../connection/DefaultConnectionListener.java | 46 ---- .../MasterSlaveConnectionManager.java | 59 +++-- .../redisson/connection/MasterSlaveEntry.java | 36 +-- .../ReplicatedConnectionManager.java | 46 ++-- .../connection/SentinelConnectionManager.java | 62 ++--- .../connection/SingleConnectionManager.java | 13 +- .../balancer/WeightedRoundRobinBalancer.java | 7 +- .../connection/pool/ConnectionPool.java | 19 +- .../java/org/redisson/misc/URLBuilder.java | 148 ------------ .../support/RedissonDefinitionParser.java | 5 +- .../java/org/redisson/RedisClientTest.java | 27 ++- .../test/java/org/redisson/RedisRunner.java | 9 +- .../redisson/RedissonBlockingQueueTest.java | 7 +- .../redisson/RedissonLocalCachedMapTest.java | 10 +- .../test/java/org/redisson/RedissonTest.java | 19 +- 49 files changed, 1249 insertions(+), 816 deletions(-) create mode 100644 redisson/src/main/java/org/redisson/client/RedisClientConfig.java create mode 100644 redisson/src/main/java/org/redisson/client/handler/BaseConnectionHandler.java create mode 100644 redisson/src/main/java/org/redisson/client/handler/RedisChannelInitializer.java create mode 100644 redisson/src/main/java/org/redisson/client/handler/RedisConnectionHandler.java create mode 100644 redisson/src/main/java/org/redisson/client/handler/RedisPubSubConnectionHandler.java delete mode 100644 redisson/src/main/java/org/redisson/cluster/ClusterConnectionListener.java rename redisson/src/main/java/org/redisson/{connection/ConnectionInitializer.java => config/SslProvider.java} (61%) delete mode 100644 redisson/src/main/java/org/redisson/connection/DefaultConnectionListener.java delete mode 100644 redisson/src/main/java/org/redisson/misc/URLBuilder.java diff --git a/redisson/src/main/java/org/redisson/RedisNodes.java b/redisson/src/main/java/org/redisson/RedisNodes.java index 0be49f734..e94bffdb0 100644 --- a/redisson/src/main/java/org/redisson/RedisNodes.java +++ b/redisson/src/main/java/org/redisson/RedisNodes.java @@ -16,6 +16,7 @@ package org.redisson; import java.net.InetSocketAddress; +import java.net.URI; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -33,8 +34,6 @@ import org.redisson.client.protocol.RedisCommands; import org.redisson.connection.ConnectionListener; import org.redisson.connection.ConnectionManager; import org.redisson.connection.RedisClientEntry; -import org.redisson.misc.RPromise; -import org.redisson.misc.URLBuilder; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.FutureListener; @@ -56,7 +55,8 @@ public class RedisNodes implements NodesGroup { @Override public N getNode(String address) { Collection clients = (Collection) connectionManager.getClients(); - InetSocketAddress addr = URLBuilder.toAddress(address); + URI uri = URI.create(address); + InetSocketAddress addr = new InetSocketAddress(uri.getHost(), uri.getPort()); for (N node : clients) { if (node.getAddr().equals(addr)) { return node; @@ -94,17 +94,10 @@ public class RedisNodes implements NodesGroup { @Override public void operationComplete(Future future) throws Exception { if (future.isSuccess()) { - final RedisConnection c = future.getNow(); - RPromise connectionFuture = connectionManager.newPromise(); - connectionManager.getConnectListener().onConnect(connectionFuture, c, null, connectionManager.getConfig()); - connectionFuture.addListener(new FutureListener() { - @Override - public void operationComplete(Future future) throws Exception { - RFuture r = c.async(connectionManager.getConfig().getPingTimeout(), RedisCommands.PING); - result.put(c, r); - latch.countDown(); - } - }); + RedisConnection c = future.getNow(); + RFuture r = c.async(connectionManager.getConfig().getPingTimeout(), RedisCommands.PING); + result.put(c, r); + latch.countDown(); } else { latch.countDown(); } diff --git a/redisson/src/main/java/org/redisson/Redisson.java b/redisson/src/main/java/org/redisson/Redisson.java index f3b225ed3..c8410d6e2 100755 --- a/redisson/src/main/java/org/redisson/Redisson.java +++ b/redisson/src/main/java/org/redisson/Redisson.java @@ -137,7 +137,7 @@ public class Redisson implements RedissonClient { */ public static RedissonClient create() { Config config = new Config(); - config.useSingleServer().setAddress("127.0.0.1:6379"); + config.useSingleServer().setAddress("redis://127.0.0.1:6379"); // config.useMasterSlaveConnection().setMasterAddress("127.0.0.1:6379").addSlaveAddress("127.0.0.1:6389").addSlaveAddress("127.0.0.1:6399"); // config.useSentinelConnection().setMasterName("mymaster").addSentinelAddress("127.0.0.1:26389", "127.0.0.1:26379"); // config.useClusterServers().addNodeAddress("127.0.0.1:7000"); @@ -165,7 +165,7 @@ public class Redisson implements RedissonClient { */ public static RedissonReactiveClient createReactive() { Config config = new Config(); - config.useSingleServer().setAddress("127.0.0.1:6379"); + config.useSingleServer().setAddress("redis://127.0.0.1:6379"); // config.useMasterSlaveConnection().setMasterAddress("127.0.0.1:6379").addSlaveAddress("127.0.0.1:6389").addSlaveAddress("127.0.0.1:6399"); // config.useSentinelConnection().setMasterName("mymaster").addSentinelAddress("127.0.0.1:26389", "127.0.0.1:26379"); // config.useClusterServers().addNodeAddress("127.0.0.1:7000"); diff --git a/redisson/src/main/java/org/redisson/api/NodesGroup.java b/redisson/src/main/java/org/redisson/api/NodesGroup.java index ff77e7b75..b0d20437d 100644 --- a/redisson/src/main/java/org/redisson/api/NodesGroup.java +++ b/redisson/src/main/java/org/redisson/api/NodesGroup.java @@ -43,7 +43,7 @@ public interface NodesGroup { void removeConnectionListener(int listenerId); /** - * Get Redis node by address in format: host:port + * Get Redis node by address in format: redis://host:port * * @param address of node * @return node diff --git a/redisson/src/main/java/org/redisson/api/RKeysAsync.java b/redisson/src/main/java/org/redisson/api/RKeysAsync.java index acfebd599..0f2e3cb7a 100644 --- a/redisson/src/main/java/org/redisson/api/RKeysAsync.java +++ b/redisson/src/main/java/org/redisson/api/RKeysAsync.java @@ -41,6 +41,7 @@ public interface RKeysAsync { * @param host - destination host * @param port - destination port * @param database - destination database + * @return void */ RFuture migrateAsync(String name, String host, int port, int database); @@ -89,6 +90,7 @@ public interface RKeysAsync { * * @param currentName - current name of object * @param newName - new name of object + * @return void */ RFuture renameAsync(String currentName, String newName); diff --git a/redisson/src/main/java/org/redisson/api/mapreduce/RCollectionMapReduce.java b/redisson/src/main/java/org/redisson/api/mapreduce/RCollectionMapReduce.java index dd212490f..c694d9fdd 100644 --- a/redisson/src/main/java/org/redisson/api/mapreduce/RCollectionMapReduce.java +++ b/redisson/src/main/java/org/redisson/api/mapreduce/RCollectionMapReduce.java @@ -93,8 +93,8 @@ public interface RCollectionMapReduce extends RMapReduceExecuto /** * Defines timeout for MapReduce process * - * @param timeout - * @param unit + * @param timeout for process + * @param unit of timeout * @return self instance */ RCollectionMapReduce timeout(long timeout, TimeUnit unit); diff --git a/redisson/src/main/java/org/redisson/api/mapreduce/RMapReduce.java b/redisson/src/main/java/org/redisson/api/mapreduce/RMapReduce.java index 4f6ad7b82..005ddd1d5 100644 --- a/redisson/src/main/java/org/redisson/api/mapreduce/RMapReduce.java +++ b/redisson/src/main/java/org/redisson/api/mapreduce/RMapReduce.java @@ -88,8 +88,8 @@ public interface RMapReduce extends RMapReduceExecutor0 means infinity timeout. * - * @param timeout - * @param unit + * @param timeout for process + * @param unit of timeout * @return self instance */ RMapReduce timeout(long timeout, TimeUnit unit); diff --git a/redisson/src/main/java/org/redisson/client/RedisClient.java b/redisson/src/main/java/org/redisson/client/RedisClient.java index 67f660b5d..077183eb1 100644 --- a/redisson/src/main/java/org/redisson/client/RedisClient.java +++ b/redisson/src/main/java/org/redisson/client/RedisClient.java @@ -16,28 +16,21 @@ package org.redisson.client; import java.net.InetSocketAddress; -import java.net.URL; -import java.util.Map; +import java.net.URI; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import org.redisson.api.RFuture; -import org.redisson.client.handler.CommandBatchEncoder; -import org.redisson.client.handler.CommandDecoder; -import org.redisson.client.handler.CommandEncoder; -import org.redisson.client.handler.CommandsQueue; -import org.redisson.client.handler.ConnectionWatchdog; -import org.redisson.client.protocol.RedisCommands; +import org.redisson.client.handler.RedisChannelInitializer; +import org.redisson.client.handler.RedisChannelInitializer.Type; import org.redisson.misc.RPromise; import org.redisson.misc.RedissonPromise; -import org.redisson.misc.URLBuilder; import io.netty.bootstrap.Bootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; -import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.group.ChannelGroup; @@ -61,6 +54,7 @@ import io.netty.util.concurrent.GlobalEventExecutor; public class RedisClient { private final Bootstrap bootstrap; + private final Bootstrap pubSubBootstrap; private final InetSocketAddress addr; private final ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); @@ -68,55 +62,116 @@ public class RedisClient { private final long commandTimeout; private Timer timer; private boolean hasOwnGroup; + private RedisClientConfig config; + public static RedisClient create(RedisClientConfig config) { + if (config.getTimer() == null) { + config.setTimer(new HashedWheelTimer()); + } + return new RedisClient(config); + } + + private RedisClient(RedisClientConfig config) { + this.config = config; + this.executor = config.getExecutor(); + this.timer = config.getTimer(); + + addr = new InetSocketAddress(config.getAddress().getHost(), config.getAddress().getPort()); + + bootstrap = createBootstrap(config, Type.PLAIN); + pubSubBootstrap = createBootstrap(config, Type.PUBSUB); + + this.commandTimeout = config.getCommandTimeout(); + } + + private Bootstrap createBootstrap(RedisClientConfig config, Type type) { + Bootstrap bootstrap = new Bootstrap() + .channel(config.getSocketChannelClass()) + .group(config.getGroup()) + .remoteAddress(addr); + + bootstrap.handler(new RedisChannelInitializer(bootstrap, config, this, channels, type)); + bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, config.getConnectTimeout()); + return bootstrap; + } + + /* + * Use {@link #create(RedisClientConfig)} + * + */ + @Deprecated public RedisClient(String address) { - this(URLBuilder.create(address)); + this(URI.create(address)); } - public RedisClient(URL address) { + /* + * Use {@link #create(RedisClientConfig)} + * + */ + @Deprecated + public RedisClient(URI address) { this(new HashedWheelTimer(), Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2), new NioEventLoopGroup(), address); hasOwnGroup = true; } - public RedisClient(Timer timer, ExecutorService executor, EventLoopGroup group, URL address) { + /* + * Use {@link #create(RedisClientConfig)} + * + */ + @Deprecated + public RedisClient(Timer timer, ExecutorService executor, EventLoopGroup group, URI address) { this(timer, executor, group, address.getHost(), address.getPort()); } + /* + * Use {@link #create(RedisClientConfig)} + * + */ + @Deprecated public RedisClient(String host, int port) { this(new HashedWheelTimer(), Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2), new NioEventLoopGroup(), NioSocketChannel.class, host, port, 10000, 10000); hasOwnGroup = true; } - + + /* + * Use {@link #create(RedisClientConfig)} + * + */ + @Deprecated public RedisClient(Timer timer, ExecutorService executor, EventLoopGroup group, String host, int port) { this(timer, executor, group, NioSocketChannel.class, host, port, 10000, 10000); } + /* + * Use {@link #create(RedisClientConfig)} + * + */ + @Deprecated public RedisClient(String host, int port, int connectTimeout, int commandTimeout) { this(new HashedWheelTimer(), Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2), new NioEventLoopGroup(), NioSocketChannel.class, host, port, connectTimeout, commandTimeout); } + /* + * Use {@link #create(RedisClientConfig)} + * + */ + @Deprecated public RedisClient(final Timer timer, ExecutorService executor, EventLoopGroup group, Class socketChannelClass, String host, int port, int connectTimeout, int commandTimeout) { - if (timer == null) { - throw new NullPointerException("timer param can't be null"); - } - this.executor = executor; - this.timer = timer; - addr = new InetSocketAddress(host, port); - bootstrap = new Bootstrap().channel(socketChannelClass).group(group).remoteAddress(addr); - bootstrap.handler(new ChannelInitializer() { - @Override - protected void initChannel(Channel ch) throws Exception { - ch.pipeline().addFirst(new ConnectionWatchdog(bootstrap, channels, timer), - CommandEncoder.INSTANCE, - CommandBatchEncoder.INSTANCE, - new CommandsQueue(), - new CommandDecoder(RedisClient.this.executor)); - } - }); - - bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, connectTimeout); - this.commandTimeout = commandTimeout; + RedisClientConfig config = new RedisClientConfig(); + config.setTimer(timer).setExecutor(executor).setGroup(group).setSocketChannelClass(socketChannelClass) + .setAddress(host, port).setConnectTimeout(connectTimeout).setCommandTimeout(commandTimeout); + + this.config = config; + this.executor = config.getExecutor(); + this.timer = config.getTimer(); + + addr = new InetSocketAddress(config.getAddress().getHost(), config.getAddress().getPort()); + + bootstrap = createBootstrap(config, Type.PLAIN); + pubSubBootstrap = createBootstrap(config, Type.PUBSUB); + + this.commandTimeout = config.getCommandTimeout(); } @@ -128,15 +183,17 @@ public class RedisClient { return commandTimeout; } - public Bootstrap getBootstrap() { - return bootstrap; + public EventLoopGroup getEventLoopGroup() { + return bootstrap.config().group(); + } + + public RedisClientConfig getConfig() { + return config; } public RedisConnection connect() { try { - ChannelFuture future = bootstrap.connect(); - future.syncUninterruptibly(); - return new RedisConnection(this, future.channel()); + return connectAsync().syncUninterruptibly().getNow(); } catch (Exception e) { throw new RedisConnectionException("Unable to connect to: " + addr, e); } @@ -149,16 +206,27 @@ public class RedisClient { @Override public void operationComplete(final ChannelFuture future) throws Exception { if (future.isSuccess()) { - final RedisConnection c = new RedisConnection(RedisClient.this, future.channel()); - bootstrap.group().execute(new Runnable() { - public void run() { - if (!f.trySuccess(c)) { - c.closeAsync(); - } + final RedisConnection c = RedisConnection.getFrom(future.channel()); + c.getConnectionPromise().addListener(new FutureListener() { + @Override + public void operationComplete(final Future future) throws Exception { + bootstrap.config().group().execute(new Runnable() { + @Override + public void run() { + if (future.isSuccess()) { + if (!f.trySuccess(c)) { + c.closeAsync(); + } + } else { + f.tryFailure(future.cause()); + c.closeAsync(); + } + } + }); } }); } else { - bootstrap.group().execute(new Runnable() { + bootstrap.config().group().execute(new Runnable() { public void run() { f.tryFailure(future.cause()); } @@ -171,9 +239,7 @@ public class RedisClient { public RedisPubSubConnection connectPubSub() { try { - ChannelFuture future = bootstrap.connect(); - future.syncUninterruptibly(); - return new RedisPubSubConnection(this, future.channel()); + return connectPubSubAsync().syncUninterruptibly().getNow(); } catch (Exception e) { throw new RedisConnectionException("Unable to connect to: " + addr, e); } @@ -181,21 +247,32 @@ public class RedisClient { public RFuture connectPubSubAsync() { final RPromise f = new RedissonPromise(); - ChannelFuture channelFuture = bootstrap.connect(); + ChannelFuture channelFuture = pubSubBootstrap.connect(); channelFuture.addListener(new ChannelFutureListener() { @Override public void operationComplete(final ChannelFuture future) throws Exception { if (future.isSuccess()) { - final RedisPubSubConnection c = new RedisPubSubConnection(RedisClient.this, future.channel()); - bootstrap.group().execute(new Runnable() { - public void run() { - if (!f.trySuccess(c)) { - c.closeAsync(); - } + final RedisPubSubConnection c = RedisPubSubConnection.getFrom(future.channel()); + c.getConnectionPromise().addListener(new FutureListener() { + @Override + public void operationComplete(final Future future) throws Exception { + bootstrap.config().group().execute(new Runnable() { + @Override + public void run() { + if (future.isSuccess()) { + if (!f.trySuccess(c)) { + c.closeAsync(); + } + } else { + f.tryFailure(future.cause()); + c.closeAsync(); + } + } + }); } }); } else { - bootstrap.group().execute(new Runnable() { + bootstrap.config().group().execute(new Runnable() { public void run() { f.tryFailure(future.cause()); } @@ -216,7 +293,7 @@ public class RedisClient { } catch (InterruptedException e) { Thread.currentThread().interrupt(); } - bootstrap.group().shutdownGracefully(); + bootstrap.config().group().shutdownGracefully(); } } @@ -231,28 +308,6 @@ public class RedisClient { return channels.close(); } - @Deprecated - public Map serverInfo() { - try { - return serverInfoAsync().sync().get(); - } catch (Exception e) { - throw new RedisConnectionException("Unable to retrieve server into from: " + addr, e); - } - } - - @Deprecated - public RFuture> serverInfoAsync() { - final RedisConnection connection = connect(); - RFuture> async = connection.async(RedisCommands.INFO_SERVER); - async.addListener(new FutureListener>() { - @Override - public void operationComplete(Future> future) throws Exception { - connection.closeAsync(); - } - }); - return async; - } - @Override public String toString() { return "[addr=" + addr + "]"; diff --git a/redisson/src/main/java/org/redisson/client/RedisClientConfig.java b/redisson/src/main/java/org/redisson/client/RedisClientConfig.java new file mode 100644 index 000000000..aaf8c29b1 --- /dev/null +++ b/redisson/src/main/java/org/redisson/client/RedisClientConfig.java @@ -0,0 +1,205 @@ +/** + * Copyright 2016 Nikita Koksharov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.redisson.client; + +import java.net.URI; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import org.redisson.config.SslProvider; + +import io.netty.channel.EventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioSocketChannel; +import io.netty.util.Timer; + +/** + * + * @author Nikita Koksharov + * + */ +public class RedisClientConfig { + + private URI address; + + private Timer timer; + private ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2); + private EventLoopGroup group = new NioEventLoopGroup(); + private Class socketChannelClass = NioSocketChannel.class; + private int connectTimeout = 10000; + private int commandTimeout = 10000; + + private String password; + private int database; + private String clientName; + private boolean readOnly; + + private boolean sslEnableEndpointIdentification = true; + private SslProvider sslProvider = SslProvider.JDK; + private URI sslTruststore; + private String sslTruststorePassword; + private URI sslKeystore; + private String sslKeystorePassword; + + public RedisClientConfig setAddress(String host, int port) { + this.address = URI.create("redis://" + host + ":" + port); + return this; + } + public RedisClientConfig setAddress(String address) { + this.address = URI.create(address); + return this; + } + public RedisClientConfig setAddress(URI address) { + this.address = address; + return this; + } + public URI getAddress() { + return address; + } + + + public Timer getTimer() { + return timer; + } + public RedisClientConfig setTimer(Timer timer) { + this.timer = timer; + return this; + } + + public ExecutorService getExecutor() { + return executor; + } + public RedisClientConfig setExecutor(ExecutorService executor) { + this.executor = executor; + return this; + } + + public EventLoopGroup getGroup() { + return group; + } + public RedisClientConfig setGroup(EventLoopGroup group) { + this.group = group; + return this; + } + + public Class getSocketChannelClass() { + return socketChannelClass; + } + public RedisClientConfig setSocketChannelClass(Class socketChannelClass) { + this.socketChannelClass = socketChannelClass; + return this; + } + + public int getConnectTimeout() { + return connectTimeout; + } + public RedisClientConfig setConnectTimeout(int connectTimeout) { + this.connectTimeout = connectTimeout; + return this; + } + + public int getCommandTimeout() { + return commandTimeout; + } + public RedisClientConfig setCommandTimeout(int commandTimeout) { + this.commandTimeout = commandTimeout; + return this; + } + + public SslProvider getSslProvider() { + return sslProvider; + } + public RedisClientConfig setSslProvider(SslProvider sslMode) { + this.sslProvider = sslMode; + return this; + } + + public URI getSslTruststore() { + return sslTruststore; + } + public RedisClientConfig setSslTruststore(URI sslTruststore) { + this.sslTruststore = sslTruststore; + return this; + } + + public URI getSslKeystore() { + return sslKeystore; + } + public RedisClientConfig setSslKeystore(URI sslKeystore) { + this.sslKeystore = sslKeystore; + return this; + } + + public String getSslKeystorePassword() { + return sslKeystorePassword; + } + public RedisClientConfig setSslKeystorePassword(String sslKeystorePassword) { + this.sslKeystorePassword = sslKeystorePassword; + return this; + } + + public String getSslTruststorePassword() { + return sslTruststorePassword; + } + public RedisClientConfig setSslTruststorePassword(String sslTruststorePassword) { + this.sslTruststorePassword = sslTruststorePassword; + return this; + } + + public boolean isSslEnableEndpointIdentification() { + return sslEnableEndpointIdentification; + } + public RedisClientConfig setSslEnableEndpointIdentification(boolean enableEndpointIdentification) { + this.sslEnableEndpointIdentification = enableEndpointIdentification; + return this; + } + + public String getPassword() { + return password; + } + public RedisClientConfig setPassword(String password) { + this.password = password; + return this; + } + + public int getDatabase() { + return database; + } + public RedisClientConfig setDatabase(int database) { + this.database = database; + return this; + } + + public String getClientName() { + return clientName; + } + public RedisClientConfig setClientName(String clientName) { + this.clientName = clientName; + return this; + } + + public boolean isReadOnly() { + return readOnly; + } + public RedisClientConfig setReadOnly(boolean readOnly) { + this.readOnly = readOnly; + return this; + } + + + +} diff --git a/redisson/src/main/java/org/redisson/client/RedisConnection.java b/redisson/src/main/java/org/redisson/client/RedisConnection.java index 003324b2f..eac5d2d52 100644 --- a/redisson/src/main/java/org/redisson/client/RedisConnection.java +++ b/redisson/src/main/java/org/redisson/client/RedisConnection.java @@ -15,6 +15,8 @@ */ package org.redisson.client; +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -25,6 +27,7 @@ import org.redisson.client.handler.CommandsQueue; import org.redisson.client.protocol.CommandData; import org.redisson.client.protocol.CommandsData; import org.redisson.client.protocol.QueueCommand; +import org.redisson.client.protocol.QueueCommandHolder; import org.redisson.client.protocol.RedisCommand; import org.redisson.client.protocol.RedisCommands; import org.redisson.client.protocol.RedisStrictCommand; @@ -49,24 +52,25 @@ public class RedisConnection implements RedisCommands { final RedisClient redisClient; - private volatile boolean fastReconnect; + private volatile RPromise fastReconnect; private volatile boolean closed; volatile Channel channel; - private ReconnectListener reconnectListener; + private RPromise connectionPromise; private long lastUsageTime; - public RedisConnection(RedisClient redisClient, Channel channel) { - this(redisClient); + public RedisConnection(RedisClient redisClient, Channel channel, RPromise connectionPromise) { + this.redisClient = redisClient; + this.connectionPromise = connectionPromise; updateChannel(channel); lastUsageTime = System.currentTimeMillis(); } - protected RedisConnection(RedisClient redisClient) { - this.redisClient = redisClient; + public RPromise getConnectionPromise() { + return (RPromise) connectionPromise; } - + public static C getFrom(Channel channel) { return (C) channel.attr(RedisConnection.CONNECTION).get(); } @@ -87,14 +91,6 @@ public class RedisConnection implements RedisCommands { this.lastUsageTime = lastUsageTime; } - public void setReconnectListener(ReconnectListener reconnectListener) { - this.reconnectListener = reconnectListener; - } - - public ReconnectListener getReconnectListener() { - return reconnectListener; - } - public boolean isOpen() { return channel.isOpen(); } @@ -182,12 +178,12 @@ public class RedisConnection implements RedisCommands { timeout = redisClient.getCommandTimeout(); } - if (redisClient.getBootstrap().group().isShuttingDown()) { + if (redisClient.getEventLoopGroup().isShuttingDown()) { RedissonShutdownException cause = new RedissonShutdownException("Redisson is shutdown"); return RedissonPromise.newFailedFuture(cause); } - final ScheduledFuture scheduledFuture = redisClient.getBootstrap().group().next().schedule(new Runnable() { + final ScheduledFuture scheduledFuture = redisClient.getEventLoopGroup().schedule(new Runnable() { @Override public void run() { RedisTimeoutException ex = new RedisTimeoutException("Command execution timeout for " + redisClient.getAddr()); @@ -219,16 +215,18 @@ public class RedisConnection implements RedisCommands { } public boolean isFastReconnect() { - return fastReconnect; + return fastReconnect != null; } public void clearFastReconnect() { - fastReconnect = false; + fastReconnect.trySuccess(null); + fastReconnect = null; } - public ChannelFuture forceFastReconnectAsync() { - fastReconnect = true; - return channel.close(); + public RFuture forceFastReconnectAsync() { + fastReconnect = new RedissonPromise(); + channel.close(); + return fastReconnect; } /** diff --git a/redisson/src/main/java/org/redisson/client/RedisPubSubConnection.java b/redisson/src/main/java/org/redisson/client/RedisPubSubConnection.java index ea8566ed2..d3c49bdb1 100644 --- a/redisson/src/main/java/org/redisson/client/RedisPubSubConnection.java +++ b/redisson/src/main/java/org/redisson/client/RedisPubSubConnection.java @@ -33,6 +33,7 @@ import org.redisson.client.protocol.pubsub.PubSubPatternMessage; import org.redisson.client.protocol.pubsub.PubSubPatternMessageDecoder; import org.redisson.client.protocol.pubsub.PubSubStatusMessage; import org.redisson.client.protocol.pubsub.PubSubType; +import org.redisson.misc.RPromise; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; @@ -53,8 +54,8 @@ public class RedisPubSubConnection extends RedisConnection { final Set unsubscibedChannels = new HashSet(); final Set punsubscibedChannels = new HashSet(); - public RedisPubSubConnection(RedisClient redisClient, Channel channel) { - super(redisClient, channel); + public RedisPubSubConnection(RedisClient redisClient, Channel channel, RPromise connectionPromise) { + super(redisClient, channel, connectionPromise); } public void addListener(RedisPubSubListener listener) { diff --git a/redisson/src/main/java/org/redisson/client/handler/BaseConnectionHandler.java b/redisson/src/main/java/org/redisson/client/handler/BaseConnectionHandler.java new file mode 100644 index 000000000..2fd0953ef --- /dev/null +++ b/redisson/src/main/java/org/redisson/client/handler/BaseConnectionHandler.java @@ -0,0 +1,108 @@ +/** + * Copyright 2016 Nikita Koksharov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.redisson.client.handler; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +import org.redisson.api.RFuture; +import org.redisson.client.RedisClient; +import org.redisson.client.RedisClientConfig; +import org.redisson.client.RedisConnection; +import org.redisson.client.protocol.RedisCommands; +import org.redisson.misc.RPromise; +import org.redisson.misc.RedissonPromise; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.util.concurrent.Future; +import io.netty.util.concurrent.FutureListener; + +/** + * + * @author Nikita Koksharov + * + */ +public abstract class BaseConnectionHandler extends ChannelInboundHandlerAdapter { + + final RedisClient redisClient; + final RPromise connectionPromise = new RedissonPromise(); + C connection; + + public BaseConnectionHandler(RedisClient redisClient) { + super(); + this.redisClient = redisClient; + } + + @Override + public void channelRegistered(ChannelHandlerContext ctx) throws Exception { + if (connection == null) { + connection = createConnection(ctx); + } + super.channelRegistered(ctx); + } + + abstract C createConnection(ChannelHandlerContext ctx); + + @Override + public void channelActive(final ChannelHandlerContext ctx) throws Exception { + final AtomicInteger commandsCounter = new AtomicInteger(); + List> futures = new ArrayList>(); + + RedisClientConfig config = redisClient.getConfig(); + if (config.getPassword() != null) { + RFuture future = connection.async(RedisCommands.AUTH, config.getPassword()); + futures.add(future); + } + if (config.getDatabase() != 0) { + RFuture future = connection.async(RedisCommands.SELECT, config.getDatabase()); + futures.add(future); + } + if (config.getClientName() != null) { + RFuture future = connection.async(RedisCommands.CLIENT_SETNAME, config.getDatabase()); + futures.add(future); + } + if (config.isReadOnly()) { + RFuture future = connection.async(RedisCommands.READONLY); + futures.add(future); + } + + if (futures.isEmpty()) { + connectionPromise.trySuccess(connection); + return; + } + + commandsCounter.set(futures.size()); + for (RFuture future : futures) { + future.addListener(new FutureListener() { + @Override + public void operationComplete(Future future) throws Exception { + if (!future.isSuccess()) { + connection.closeAsync(); + connectionPromise.tryFailure(future.cause()); + return; + } + if (commandsCounter.decrementAndGet() == 0) { + BaseConnectionHandler.super.channelActive(ctx); + connectionPromise.trySuccess(connection); + } + } + }); + } + } + +} diff --git a/redisson/src/main/java/org/redisson/client/handler/ConnectionWatchdog.java b/redisson/src/main/java/org/redisson/client/handler/ConnectionWatchdog.java index 43ce2a090..2a4330f79 100644 --- a/redisson/src/main/java/org/redisson/client/handler/ConnectionWatchdog.java +++ b/redisson/src/main/java/org/redisson/client/handler/ConnectionWatchdog.java @@ -16,15 +16,15 @@ package org.redisson.client.handler; import java.util.Map.Entry; +import java.util.Queue; +import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.TimeUnit; import org.redisson.client.RedisConnection; -import org.redisson.client.RedisException; import org.redisson.client.RedisPubSubConnection; import org.redisson.client.codec.Codec; import org.redisson.client.protocol.CommandData; -import org.redisson.misc.RPromise; -import org.redisson.misc.RedissonPromise; +import org.redisson.client.protocol.QueueCommandHolder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -70,7 +70,6 @@ public class ConnectionWatchdog extends ChannelInboundHandlerAdapter { if (!connection.isClosed()) { if (connection.isFastReconnect()) { tryReconnect(connection, 1); - connection.clearFastReconnect(); } else { reconnect(connection, 1); } @@ -81,7 +80,7 @@ public class ConnectionWatchdog extends ChannelInboundHandlerAdapter { private void reconnect(final RedisConnection connection, final int attempts){ int timeout = 2 << attempts; - if (bootstrap.group().isShuttingDown()) { + if (bootstrap.config().group().isShuttingDown()) { return; } @@ -94,51 +93,48 @@ public class ConnectionWatchdog extends ChannelInboundHandlerAdapter { } private void tryReconnect(final RedisConnection connection, final int nextAttempt) { - if (connection.isClosed() || bootstrap.group().isShuttingDown()) { + if (connection.isClosed() || bootstrap.config().group().isShuttingDown()) { return; } log.debug("reconnecting {} to {} ", connection, connection.getRedisClient().getAddr(), connection); - bootstrap.connect().addListener(new ChannelFutureListener() { + try { + bootstrap.connect().addListener(new ChannelFutureListener() { - @Override - public void operationComplete(final ChannelFuture future) throws Exception { - if (connection.isClosed() || bootstrap.group().isShuttingDown()) { - return; - } - - try { - if (future.isSuccess()) { - log.debug("{} connected to {}", connection, connection.getRedisClient().getAddr()); - reconnect(connection, future.channel()); + @Override + public void operationComplete(final ChannelFuture future) throws Exception { + if (connection.isClosed() || bootstrap.config().group().isShuttingDown()) { return; } - } catch (RedisException e) { - log.warn("Can't connect " + connection + " to " + connection.getRedisClient().getAddr(), e); - } - reconnect(connection, nextAttempt); - } - }); - } - - private void reconnect(final RedisConnection connection, final Channel channel) { - if (connection.getReconnectListener() != null) { - // new connection used only for channel init - RedisConnection rc = new RedisConnection(connection.getRedisClient(), channel); - RPromise connectionFuture = new RedissonPromise(); - connection.getReconnectListener().onReconnect(rc, connectionFuture); - connectionFuture.addListener(new FutureListener() { - @Override - public void operationComplete(Future future) throws Exception { if (future.isSuccess()) { - refresh(connection, channel); + final Channel channel = future.channel(); + + RedisConnection c = RedisConnection.getFrom(channel); + c.getConnectionPromise().addListener(new FutureListener() { + @Override + public void operationComplete(Future future) throws Exception { + if (future.isSuccess()) { + if (connection.isFastReconnect()) { + connection.clearFastReconnect(); + } + log.debug("{} connected to {}, command: {}", connection, connection.getRedisClient().getAddr(), connection.getCurrentCommand()); + refresh(connection, channel); + } else { + log.warn("Can't connect " + connection + " to " + connection.getRedisClient().getAddr(), future.cause()); + } + + } + }); + return; } + + reconnect(connection, nextAttempt); } }); - } else { - refresh(connection, channel); + } catch (RejectedExecutionException e) { + // skip } } @@ -155,26 +151,28 @@ public class ConnectionWatchdog extends ChannelInboundHandlerAdapter { } private void refresh(RedisConnection connection, Channel channel) { - CommandData commandData = connection.getCurrentCommand(); + CommandData currentCommand = connection.getCurrentCommand(); connection.updateChannel(channel); - reattachBlockingQueue(connection, commandData); + reattachBlockingQueue(connection, currentCommand); reattachPubSub(connection); } - private void reattachBlockingQueue(RedisConnection connection, final CommandData commandData) { - if (commandData == null - || !commandData.isBlockingCommand() - || commandData.getPromise().isDone()) { + private void reattachBlockingQueue(RedisConnection connection, CommandData currentCommand) { + if (currentCommand == null + || !currentCommand.isBlockingCommand() + || currentCommand.getPromise().isDone()) { return; } - ChannelFuture future = connection.send(commandData); + log.debug("blocking queue sent " + connection); + ChannelFuture future = connection.send(currentCommand); + final CommandData cd = currentCommand; future.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { if (!future.isSuccess()) { - log.error("Can't reconnect blocking queue to new connection. {}", commandData); + log.error("Can't reconnect blocking queue to new connection. {}", cd); } } }); diff --git a/redisson/src/main/java/org/redisson/client/handler/RedisChannelInitializer.java b/redisson/src/main/java/org/redisson/client/handler/RedisChannelInitializer.java new file mode 100644 index 000000000..6eefeef66 --- /dev/null +++ b/redisson/src/main/java/org/redisson/client/handler/RedisChannelInitializer.java @@ -0,0 +1,186 @@ +/** + * Copyright 2016 Nikita Koksharov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.redisson.client.handler; + +import java.io.IOException; +import java.io.InputStream; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLParameters; +import javax.net.ssl.TrustManagerFactory; + +import org.redisson.client.RedisClient; +import org.redisson.client.RedisClientConfig; +import org.redisson.client.RedisConnection; +import org.redisson.config.SslProvider; + +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.group.ChannelGroup; +import io.netty.handler.ssl.SslContext; +import io.netty.handler.ssl.SslContextBuilder; +import io.netty.handler.ssl.SslHandler; +import io.netty.handler.ssl.SslHandshakeCompletionEvent; +import io.netty.handler.ssl.util.InsecureTrustManagerFactory; + +/** + * + * @author Nikita Koksharov + * + */ +public class RedisChannelInitializer extends ChannelInitializer { + + public enum Type {PUBSUB, PLAIN} + + private final RedisClientConfig config; + private final RedisClient redisClient; + private final ChannelGroup channels; + private final Bootstrap bootstrap; + private final Type type; + + public RedisChannelInitializer(Bootstrap bootstrap, RedisClientConfig config, RedisClient redisClient, ChannelGroup channels, Type type) { + super(); + this.bootstrap = bootstrap; + this.config = config; + this.redisClient = redisClient; + this.channels = channels; + this.type = type; + } + + @Override + protected void initChannel(Channel ch) throws Exception { + initSsl(config, ch); + + if (type == Type.PLAIN) { + ch.pipeline().addLast(new RedisConnectionHandler(redisClient)); + } else { + ch.pipeline().addLast(new RedisPubSubConnectionHandler(redisClient)); + } + + ch.pipeline().addLast( + new ConnectionWatchdog(bootstrap, channels, config.getTimer()), + CommandEncoder.INSTANCE, + CommandBatchEncoder.INSTANCE, + new CommandsQueue(), + new CommandDecoder(config.getExecutor())); + } + + private void initSsl(final RedisClientConfig config, Channel ch) throws KeyStoreException, IOException, + NoSuchAlgorithmException, CertificateException, SSLException, UnrecoverableKeyException { + if (!"rediss".equals(config.getAddress().getScheme())) { + return; + } + + io.netty.handler.ssl.SslProvider provided = io.netty.handler.ssl.SslProvider.JDK; + if (config.getSslProvider() == SslProvider.OPENSSL) { + provided = io.netty.handler.ssl.SslProvider.OPENSSL; + } + + SslContextBuilder sslContextBuilder = SslContextBuilder.forClient().sslProvider(provided); + if (config.getSslTruststore() != null) { + KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + + InputStream stream = config.getSslTruststore().toURL().openStream(); + try { + char[] password = null; + if (config.getSslTruststorePassword() != null) { + password = config.getSslTruststorePassword().toCharArray(); + } + keyStore.load(stream, password); + } finally { + stream.close(); + } + + TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + trustManagerFactory.init(keyStore); + sslContextBuilder.trustManager(trustManagerFactory); + } + + if (config.getSslKeystore() != null){ + KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + + InputStream stream = config.getSslKeystore().toURL().openStream(); + try { + char[] password = null; + if (config.getSslKeystorePassword() != null) { + password = config.getSslKeystorePassword().toCharArray(); + } + keyStore.load(stream, password); + } finally { + stream.close(); + } + + KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + keyManagerFactory.init(keyStore, null); + sslContextBuilder.keyManager(keyManagerFactory); + } + + SSLParameters sslParams = new SSLParameters(); + if (config.isSslEnableEndpointIdentification()) { + sslParams.setEndpointIdentificationAlgorithm("HTTPS"); + } else { + if (config.getSslTruststore() == null) { + sslContextBuilder.trustManager(InsecureTrustManagerFactory.INSTANCE); + } + } + + SslContext sslContext = sslContextBuilder.build(); + SSLEngine sslEngine = sslContext.newEngine(ch.alloc(), config.getAddress().getHost(), config.getAddress().getPort()); + sslEngine.setSSLParameters(sslParams); + + SslHandler sslHandler = new SslHandler(sslEngine); + ch.pipeline().addLast(sslHandler); + ch.pipeline().addLast(new ChannelInboundHandlerAdapter() { + + volatile boolean sslInitDone; + + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception { + if (sslInitDone) { + super.channelActive(ctx); + } + } + + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + if (!sslInitDone && (evt instanceof SslHandshakeCompletionEvent)) { + SslHandshakeCompletionEvent e = (SslHandshakeCompletionEvent) evt; + if (e.isSuccess()) { + sslInitDone = true; + ctx.fireChannelActive(); + } else { + RedisConnection connection = RedisConnection.getFrom(ctx.channel()); + connection.getConnectionPromise().tryFailure(e.cause()); + } + } + + super.userEventTriggered(ctx, evt); + } + + }); + } + +} diff --git a/redisson/src/main/java/org/redisson/client/handler/RedisConnectionHandler.java b/redisson/src/main/java/org/redisson/client/handler/RedisConnectionHandler.java new file mode 100644 index 000000000..09fac487c --- /dev/null +++ b/redisson/src/main/java/org/redisson/client/handler/RedisConnectionHandler.java @@ -0,0 +1,39 @@ +/** + * Copyright 2016 Nikita Koksharov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.redisson.client.handler; + +import org.redisson.client.RedisClient; +import org.redisson.client.RedisConnection; + +import io.netty.channel.ChannelHandlerContext; + +/** + * + * @author Nikita Koksharov + * + */ +public class RedisConnectionHandler extends BaseConnectionHandler { + + public RedisConnectionHandler(RedisClient redisClient) { + super(redisClient); + } + + @Override + RedisConnection createConnection(ChannelHandlerContext ctx) { + return new RedisConnection(redisClient, ctx.channel(), connectionPromise); + } + +} diff --git a/redisson/src/main/java/org/redisson/client/handler/RedisPubSubConnectionHandler.java b/redisson/src/main/java/org/redisson/client/handler/RedisPubSubConnectionHandler.java new file mode 100644 index 000000000..96e6925d7 --- /dev/null +++ b/redisson/src/main/java/org/redisson/client/handler/RedisPubSubConnectionHandler.java @@ -0,0 +1,39 @@ +/** + * Copyright 2016 Nikita Koksharov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.redisson.client.handler; + +import org.redisson.client.RedisClient; +import org.redisson.client.RedisPubSubConnection; + +import io.netty.channel.ChannelHandlerContext; + +/** + * + * @author Nikita Koksharov + * + */ +public class RedisPubSubConnectionHandler extends BaseConnectionHandler { + + public RedisPubSubConnectionHandler(RedisClient redisClient) { + super(redisClient); + } + + @Override + RedisPubSubConnection createConnection(ChannelHandlerContext ctx) { + return new RedisPubSubConnection(redisClient, ctx.channel(), connectionPromise); + } + +} diff --git a/redisson/src/main/java/org/redisson/client/protocol/CommandData.java b/redisson/src/main/java/org/redisson/client/protocol/CommandData.java index 7c0ca6bf5..890a17a67 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/CommandData.java +++ b/redisson/src/main/java/org/redisson/client/protocol/CommandData.java @@ -97,7 +97,7 @@ public class CommandData implements QueueCommand { } public boolean isBlockingCommand() { - return RedisCommands.BLOCKING_COMMANDS.contains(command.getName()) && !promise.isDone(); + return RedisCommands.BLOCKING_COMMANDS.contains(command.getName()); } } diff --git a/redisson/src/main/java/org/redisson/client/protocol/CommandsData.java b/redisson/src/main/java/org/redisson/client/protocol/CommandsData.java index 8620cb025..982dea493 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/CommandsData.java +++ b/redisson/src/main/java/org/redisson/client/protocol/CommandsData.java @@ -70,4 +70,9 @@ public class CommandsData implements QueueCommand { return promise.tryFailure(cause); } + @Override + public String toString() { + return "CommandsData [commands=" + commands + "]"; + } + } diff --git a/redisson/src/main/java/org/redisson/client/protocol/QueueCommandHolder.java b/redisson/src/main/java/org/redisson/client/protocol/QueueCommandHolder.java index 8895b1b1e..c11aec73a 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/QueueCommandHolder.java +++ b/redisson/src/main/java/org/redisson/client/protocol/QueueCommandHolder.java @@ -43,4 +43,9 @@ public class QueueCommandHolder { return sended.compareAndSet(false, true); } + @Override + public String toString() { + return "QueueCommandHolder [command=" + command + "]"; + } + } diff --git a/redisson/src/main/java/org/redisson/client/protocol/decoder/ClusterNodesDecoder.java b/redisson/src/main/java/org/redisson/client/protocol/decoder/ClusterNodesDecoder.java index 128fc2191..dd8f278c9 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/decoder/ClusterNodesDecoder.java +++ b/redisson/src/main/java/org/redisson/client/protocol/decoder/ClusterNodesDecoder.java @@ -46,7 +46,7 @@ public class ClusterNodesDecoder implements Decoder> { String nodeId = params[0]; node.setNodeId(nodeId); - String addr = params[1]; + String addr = "redis://" + params[1].split("@")[0]; node.setAddress(addr); String flags = params[2]; diff --git a/redisson/src/main/java/org/redisson/cluster/ClusterConnectionListener.java b/redisson/src/main/java/org/redisson/cluster/ClusterConnectionListener.java deleted file mode 100644 index cd921f36d..000000000 --- a/redisson/src/main/java/org/redisson/cluster/ClusterConnectionListener.java +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Copyright 2016 Nikita Koksharov - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.redisson.cluster; - -import org.redisson.api.NodeType; -import org.redisson.client.RedisConnection; -import org.redisson.client.RedisException; -import org.redisson.client.protocol.RedisCommands; -import org.redisson.config.MasterSlaveServersConfig; -import org.redisson.connection.DefaultConnectionListener; -import org.redisson.connection.FutureConnectionListener; - -public class ClusterConnectionListener extends DefaultConnectionListener { - - private final boolean readFromSlaves; - - public ClusterConnectionListener(boolean readFromSlaves) { - this.readFromSlaves = readFromSlaves; - } - - @Override - public void doConnect(MasterSlaveServersConfig config, NodeType serverMode, FutureConnectionListener connectionListener) throws RedisException { - super.doConnect(config, serverMode, connectionListener); - if (serverMode == NodeType.SLAVE && readFromSlaves) { - connectionListener.addCommand(RedisCommands.READONLY); - } - } - -} diff --git a/redisson/src/main/java/org/redisson/cluster/ClusterConnectionManager.java b/redisson/src/main/java/org/redisson/cluster/ClusterConnectionManager.java index 4c4ee586d..e18b37d04 100644 --- a/redisson/src/main/java/org/redisson/cluster/ClusterConnectionManager.java +++ b/redisson/src/main/java/org/redisson/cluster/ClusterConnectionManager.java @@ -15,7 +15,7 @@ */ package org.redisson.cluster; -import java.net.URL; +import java.net.URI; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -31,8 +31,10 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; +import org.redisson.api.NodeType; import org.redisson.api.RFuture; import org.redisson.client.RedisClient; +import org.redisson.client.RedisClientConfig; import org.redisson.client.RedisConnection; import org.redisson.client.RedisConnectionException; import org.redisson.client.RedisException; @@ -67,17 +69,16 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager { private final Logger log = LoggerFactory.getLogger(getClass()); - private final Map nodeConnections = PlatformDependent.newConcurrentHashMap(); + private final Map nodeConnections = PlatformDependent.newConcurrentHashMap(); private final ConcurrentMap lastPartitions = PlatformDependent.newConcurrentHashMap(); private ScheduledFuture monitorFuture; - private volatile URL lastClusterNode; + private volatile URI lastClusterNode; public ClusterConnectionManager(ClusterServersConfig cfg, Config config) { super(config); - connectListener = new ClusterConnectionListener(cfg.getReadMode() != ReadMode.MASTER); this.config = create(cfg); initTimer(this.config); @@ -85,7 +86,7 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager { Throwable lastException = null; List failedMasters = new ArrayList(); - for (URL addr : cfg.getNodeAddresses()) { + for (URI addr : cfg.getNodeAddresses()) { RFuture connectionFuture = connect(cfg, addr); try { RedisConnection connection = connectionFuture.syncUninterruptibly().getNow(); @@ -153,19 +154,26 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager { scheduleClusterChangeCheck(cfg, null); } + @Override + protected RedisClientConfig createRedisConfig(NodeType type, URI address, int timeout, int commandTimeout) { + RedisClientConfig result = super.createRedisConfig(type, address, timeout, commandTimeout); + result.setReadOnly(type == NodeType.SLAVE && config.getReadMode() != ReadMode.MASTER); + return result; + } + private void close(RedisConnection conn) { if (nodeConnections.values().remove(conn)) { conn.closeAsync(); } } - private RFuture connect(ClusterServersConfig cfg, final URL addr) { + private RFuture connect(ClusterServersConfig cfg, final URI addr) { RedisConnection connection = nodeConnections.get(addr); if (connection != null) { return newSucceededFuture(connection); } - RedisClient client = createClient(addr.getHost(), addr.getPort(), cfg.getConnectTimeout(), cfg.getRetryInterval() * cfg.getRetryAttempts()); + RedisClient client = createClient(NodeType.MASTER, addr, cfg.getConnectTimeout(), cfg.getRetryInterval() * cfg.getRetryAttempts()); final RPromise result = newPromise(); RFuture future = client.connectAsync(); future.addListener(new FutureListener() { @@ -177,26 +185,13 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager { } RedisConnection connection = future.getNow(); - RPromise promise = newPromise(); - connectListener.onConnect(promise, connection, null, config); - promise.addListener(new FutureListener() { - @Override - public void operationComplete(Future future) throws Exception { - if (!future.isSuccess()) { - result.tryFailure(future.cause()); - return; - } - - RedisConnection connection = future.getNow(); - if (connection.isActive()) { - nodeConnections.put(addr, connection); - result.trySuccess(connection); - } else { - connection.closeAsync(); - result.tryFailure(new RedisException("Connection to " + connection.getRedisClient().getAddr() + " is not active!")); - } - } - }); + if (connection.isActive()) { + nodeConnections.put(addr, connection); + result.trySuccess(connection); + } else { + connection.closeAsync(); + result.tryFailure(new RedisException("Connection to " + connection.getRedisClient().getAddr() + " is not active!")); + } } }); @@ -275,7 +270,7 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager { } } - RFuture f = e.setupMasterEntry(config.getMasterAddress().getHost(), config.getMasterAddress().getPort()); + RFuture f = e.setupMasterEntry(config.getMasterAddress()); final RPromise initFuture = newPromise(); futures.add(initFuture); f.addListener(new FutureListener() { @@ -309,22 +304,22 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager { return result; } - private void scheduleClusterChangeCheck(final ClusterServersConfig cfg, final Iterator iterator) { + private void scheduleClusterChangeCheck(final ClusterServersConfig cfg, final Iterator iterator) { monitorFuture = GlobalEventExecutor.INSTANCE.schedule(new Runnable() { @Override public void run() { AtomicReference lastException = new AtomicReference(); - Iterator nodesIterator = iterator; + Iterator nodesIterator = iterator; if (nodesIterator == null) { - List nodes = new ArrayList(); - List slaves = new ArrayList(); + List nodes = new ArrayList(); + List slaves = new ArrayList(); for (ClusterPartition partition : getLastPartitions()) { if (!partition.isMasterFail()) { nodes.add(partition.getMasterAddress()); } - Set partitionSlaves = new HashSet(partition.getSlaveAddresses()); + Set partitionSlaves = new HashSet(partition.getSlaveAddresses()); partitionSlaves.removeAll(partition.getFailedSlaveAddresses()); slaves.addAll(partitionSlaves); } @@ -340,7 +335,7 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager { }, cfg.getScanInterval(), TimeUnit.MILLISECONDS); } - private void checkClusterState(final ClusterServersConfig cfg, final Iterator iterator, final AtomicReference lastException) { + private void checkClusterState(final ClusterServersConfig cfg, final Iterator iterator, final AtomicReference lastException) { if (!iterator.hasNext()) { log.error("Can't update cluster state", lastException.get()); scheduleClusterChangeCheck(cfg, null); @@ -349,7 +344,7 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager { if (!getShutdownLatch().acquire()) { return; } - final URL uri = iterator.next(); + final URI uri = iterator.next(); RFuture connectionFuture = connect(cfg, uri); connectionFuture.addListener(new FutureListener() { @Override @@ -367,7 +362,7 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager { }); } - private void updateClusterState(final ClusterServersConfig cfg, final RedisConnection connection, final Iterator iterator, final URL uri) { + private void updateClusterState(final ClusterServersConfig cfg, final RedisConnection connection, final Iterator iterator, final URI uri) { RFuture> future = connection.async(RedisCommands.CLUSTER_NODES); future.addListener(new FutureListener>() { @Override @@ -416,7 +411,7 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager { MasterSlaveEntry entry = getEntry(currentPart.getMasterAddr()); // should be invoked first in order to remove stale failedSlaveAddresses - Set addedSlaves = addRemoveSlaves(entry, currentPart, newPart); + Set addedSlaves = addRemoveSlaves(entry, currentPart, newPart); // Do some slaves have changed state from failed to alive? upDownSlaves(entry, currentPart, newPart, addedSlaves); @@ -425,20 +420,20 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager { } } - private void upDownSlaves(final MasterSlaveEntry entry, final ClusterPartition currentPart, final ClusterPartition newPart, Set addedSlaves) { - Set aliveSlaves = new HashSet(currentPart.getFailedSlaveAddresses()); + private void upDownSlaves(final MasterSlaveEntry entry, final ClusterPartition currentPart, final ClusterPartition newPart, Set addedSlaves) { + Set aliveSlaves = new HashSet(currentPart.getFailedSlaveAddresses()); aliveSlaves.removeAll(addedSlaves); aliveSlaves.removeAll(newPart.getFailedSlaveAddresses()); - for (URL uri : aliveSlaves) { + for (URI uri : aliveSlaves) { currentPart.removeFailedSlaveAddress(uri); if (entry.slaveUp(uri.getHost(), uri.getPort(), FreezeReason.MANAGER)) { log.info("slave: {} has up for slot ranges: {}", uri, currentPart.getSlotRanges()); } } - Set failedSlaves = new HashSet(newPart.getFailedSlaveAddresses()); + Set failedSlaves = new HashSet(newPart.getFailedSlaveAddresses()); failedSlaves.removeAll(currentPart.getFailedSlaveAddresses()); - for (URL uri : failedSlaves) { + for (URI uri : failedSlaves) { currentPart.addFailedSlaveAddress(uri); if (entry.slaveDown(uri.getHost(), uri.getPort(), FreezeReason.MANAGER)) { log.warn("slave: {} has down for slot ranges: {}", uri, currentPart.getSlotRanges()); @@ -446,11 +441,11 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager { } } - private Set addRemoveSlaves(final MasterSlaveEntry entry, final ClusterPartition currentPart, final ClusterPartition newPart) { - Set removedSlaves = new HashSet(currentPart.getSlaveAddresses()); + private Set addRemoveSlaves(final MasterSlaveEntry entry, final ClusterPartition currentPart, final ClusterPartition newPart) { + Set removedSlaves = new HashSet(currentPart.getSlaveAddresses()); removedSlaves.removeAll(newPart.getSlaveAddresses()); - for (URL uri : removedSlaves) { + for (URI uri : removedSlaves) { currentPart.removeSlaveAddress(uri); if (entry.slaveDown(uri.getHost(), uri.getPort(), FreezeReason.MANAGER)) { @@ -458,10 +453,10 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager { } } - Set addedSlaves = new HashSet(newPart.getSlaveAddresses()); + Set addedSlaves = new HashSet(newPart.getSlaveAddresses()); addedSlaves.removeAll(currentPart.getSlaveAddresses()); - for (final URL uri : addedSlaves) { - RFuture future = entry.addSlave(uri.getHost(), uri.getPort()); + for (final URI uri : addedSlaves) { + RFuture future = entry.addSlave(uri); future.addListener(new FutureListener() { @Override public void operationComplete(Future future) throws Exception { @@ -517,10 +512,10 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager { if (!newMasterPart.getMasterAddress().equals(currentPart.getMasterAddress())) { log.info("changing master from {} to {} for {}", currentPart.getMasterAddress(), newMasterPart.getMasterAddress(), slot); - URL newUri = newMasterPart.getMasterAddress(); - URL oldUri = currentPart.getMasterAddress(); + URI newUri = newMasterPart.getMasterAddress(); + URI oldUri = currentPart.getMasterAddress(); - changeMaster(slot, newUri.getHost(), newUri.getPort()); + changeMaster(slot, newUri); currentPart.setMasterAddress(newMasterPart.getMasterAddress()); } @@ -717,10 +712,10 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager { if (cp.getParent() != null && cp.getParent().getType() == Type.MASTER) { ClusterPartition parent = cp.getParent(); - for (URL addr : cp.getSlaveAddresses()) { + for (URI addr : cp.getSlaveAddresses()) { parent.addSlaveAddress(addr); } - for (URL addr : cp.getFailedSlaveAddresses()) { + for (URI addr : cp.getFailedSlaveAddresses()) { parent.addFailedSlaveAddress(addr); } } @@ -753,7 +748,7 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager { } @Override - public URL getLastClusterNode() { + public URI getLastClusterNode() { return lastClusterNode; } diff --git a/redisson/src/main/java/org/redisson/cluster/ClusterNodeInfo.java b/redisson/src/main/java/org/redisson/cluster/ClusterNodeInfo.java index 17a78c5ca..c98e23845 100644 --- a/redisson/src/main/java/org/redisson/cluster/ClusterNodeInfo.java +++ b/redisson/src/main/java/org/redisson/cluster/ClusterNodeInfo.java @@ -16,12 +16,9 @@ package org.redisson.cluster; import java.net.URI; -import java.net.URL; import java.util.HashSet; import java.util.Set; -import org.redisson.misc.URLBuilder; - /** * * @author Nikita Koksharov @@ -34,7 +31,7 @@ public class ClusterNodeInfo { private final String nodeInfo; private String nodeId; - private URL address; + private URI address; private final Set flags = new HashSet(); private String slaveOf; @@ -51,11 +48,11 @@ public class ClusterNodeInfo { this.nodeId = nodeId; } - public URL getAddress() { + public URI getAddress() { return address; } public void setAddress(String address) { - this.address = URLBuilder.create(address); + this.address = URI.create(address); } public void addSlotRange(ClusterSlotRange range) { diff --git a/redisson/src/main/java/org/redisson/cluster/ClusterPartition.java b/redisson/src/main/java/org/redisson/cluster/ClusterPartition.java index 651c178fa..92259ddc6 100644 --- a/redisson/src/main/java/org/redisson/cluster/ClusterPartition.java +++ b/redisson/src/main/java/org/redisson/cluster/ClusterPartition.java @@ -16,13 +16,11 @@ package org.redisson.cluster; import java.net.InetSocketAddress; -import java.net.URL; +import java.net.URI; import java.util.Collections; import java.util.HashSet; import java.util.Set; -import org.redisson.misc.URLBuilder; - /** * * @author Nikita Koksharov @@ -36,9 +34,9 @@ public class ClusterPartition { private final String nodeId; private boolean masterFail; - private URL masterAddress; - private final Set slaveAddresses = new HashSet(); - private final Set failedSlaves = new HashSet(); + private URI masterAddress; + private final Set slaveAddresses = new HashSet(); + private final Set failedSlaves = new HashSet(); private final Set slots = new HashSet(); private final Set slotRanges = new HashSet(); @@ -112,33 +110,30 @@ public class ClusterPartition { return new InetSocketAddress(masterAddress.getHost(), masterAddress.getPort()); } - public URL getMasterAddress() { + public URI getMasterAddress() { return masterAddress; } - public void setMasterAddress(String masterAddress) { - setMasterAddress(URLBuilder.create(masterAddress)); - } - public void setMasterAddress(URL masterAddress) { + public void setMasterAddress(URI masterAddress) { this.masterAddress = masterAddress; } - public void addFailedSlaveAddress(URL address) { + public void addFailedSlaveAddress(URI address) { failedSlaves.add(address); } - public Set getFailedSlaveAddresses() { + public Set getFailedSlaveAddresses() { return Collections.unmodifiableSet(failedSlaves); } - public void removeFailedSlaveAddress(URL uri) { + public void removeFailedSlaveAddress(URI uri) { failedSlaves.remove(uri); } - public void addSlaveAddress(URL address) { + public void addSlaveAddress(URI address) { slaveAddresses.add(address); } - public Set getSlaveAddresses() { + public Set getSlaveAddresses() { return Collections.unmodifiableSet(slaveAddresses); } - public void removeSlaveAddress(URL uri) { + public void removeSlaveAddress(URI uri) { slaveAddresses.remove(uri); failedSlaves.remove(uri); } diff --git a/redisson/src/main/java/org/redisson/command/CommandAsyncService.java b/redisson/src/main/java/org/redisson/command/CommandAsyncService.java index e7fde3197..7e7e26cf5 100644 --- a/redisson/src/main/java/org/redisson/command/CommandAsyncService.java +++ b/redisson/src/main/java/org/redisson/command/CommandAsyncService.java @@ -586,8 +586,8 @@ public class CommandAsyncService implements CommandAsyncExecutor { details.setWriteFuture(future); } else { if (log.isDebugEnabled()) { - log.debug("aquired connection for command {} and params {} from slot {} using node {}", - details.getCommand(), Arrays.toString(details.getParams()), details.getSource(), connection.getRedisClient().getAddr()); + log.debug("acquired connection for command {} and params {} from slot {} using node {}... {}", + details.getCommand(), Arrays.toString(details.getParams()), details.getSource(), connection.getRedisClient().getAddr(), connection); } ChannelFuture future = connection.send(new CommandData(details.getAttemptPromise(), details.getCodec(), details.getCommand(), details.getParams())); details.setWriteFuture(future); @@ -660,7 +660,6 @@ public class CommandAsyncService implements CommandAsyncExecutor { } }; - final AtomicBoolean canceledByScheduler = new AtomicBoolean(); final Timeout scheduledFuture; if (popTimeout != 0) { // to handle cases when connection has been lost @@ -668,15 +667,16 @@ public class CommandAsyncService implements CommandAsyncExecutor { scheduledFuture = connectionManager.newTimeout(new TimerTask() { @Override public void run(Timeout timeout) throws Exception { - // re-connection wasn't made + // re-connection hasn't been made // and connection is still active if (orignalChannel == connection.getChannel() && connection.isActive()) { return; } - canceledByScheduler.set(true); - details.getAttemptPromise().trySuccess(null); + if (details.getAttemptPromise().trySuccess(null)) { + connection.forceFastReconnectAsync(); + } } }, popTimeout, TimeUnit.SECONDS); } else { @@ -694,10 +694,14 @@ public class CommandAsyncService implements CommandAsyncExecutor { connectionManager.getShutdownPromise().removeListener(listener); } - // handling cancel operation for commands from skipTimeout collection - if ((future.isCancelled() && details.getAttemptPromise().cancel(true)) - || canceledByScheduler.get()) { - connection.forceFastReconnectAsync(); + // handling cancel operation for blocking commands + if (future.isCancelled() && !details.getAttemptPromise().isDone()) { + connection.forceFastReconnectAsync().addListener(new FutureListener() { + @Override + public void operationComplete(Future future) throws Exception { + details.getAttemptPromise().cancel(true); + } + }); return; } @@ -722,7 +726,7 @@ public class CommandAsyncService implements CommandAsyncExecutor { if (!connectionFuture.isSuccess()) { return; } - + RedisConnection connection = connectionFuture.getNow(); connectionManager.getShutdownLatch().release(); if (isReadOnly) { diff --git a/redisson/src/main/java/org/redisson/config/BaseConfig.java b/redisson/src/main/java/org/redisson/config/BaseConfig.java index 4d4915804..5f89230ed 100644 --- a/redisson/src/main/java/org/redisson/config/BaseConfig.java +++ b/redisson/src/main/java/org/redisson/config/BaseConfig.java @@ -15,6 +15,8 @@ */ package org.redisson.config; +import java.net.URI; + /** * * @author Nikita Koksharov @@ -91,6 +93,19 @@ class BaseConfig> { */ private String clientName; + private boolean sslEnableEndpointIdentification = true; + + private SslProvider sslProvider = SslProvider.JDK; + + private URI sslTruststore; + + private String sslTruststorePassword; + + private URI sslKeystore; + + private String sslKeystorePassword; + + BaseConfig() { } @@ -106,6 +121,12 @@ class BaseConfig> { setIdleConnectionTimeout(config.getIdleConnectionTimeout()); setFailedAttempts(config.getFailedAttempts()); setReconnectionTimeout(config.getReconnectionTimeout()); + setSslEnableEndpointIdentification(config.isSslEnableEndpointIdentification()); + setSslProvider(config.getSslProvider()); + setSslTruststore(config.getSslTruststore()); + setSslTruststorePassword(config.getSslTruststorePassword()); + setSslKeystore(config.getSslKeystore()); + setSslKeystorePassword(config.getSslKeystorePassword()); } /** @@ -304,4 +325,100 @@ class BaseConfig> { return failedAttempts; } + public boolean isSslEnableEndpointIdentification() { + return sslEnableEndpointIdentification; + } + + /** + * Enables SSL endpoint identification. + *

+ * Default is true + * + * @param sslEnableEndpointIdentification - boolean value + * @return config + */ + public T setSslEnableEndpointIdentification(boolean sslEnableEndpointIdentification) { + this.sslEnableEndpointIdentification = sslEnableEndpointIdentification; + return (T) this; + } + + public SslProvider getSslProvider() { + return sslProvider; + } + + /** + * Defines SSL provider used to handle SSL connections. + *

+ * Default is JDK + * + * @param sslProvider - ssl provider + * @return config + */ + public T setSslProvider(SslProvider sslProvider) { + this.sslProvider = sslProvider; + return (T) this; + } + + public URI getSslTruststore() { + return sslTruststore; + } + + /** + * Defines path to SSL truststore + * + * @param sslTruststore - path + * @return config + */ + public T setSslTruststore(URI sslTruststore) { + this.sslTruststore = sslTruststore; + return (T) this; + } + + public String getSslTruststorePassword() { + return sslTruststorePassword; + } + + /** + * Defines password for SSL truststore + * + * @param sslTruststorePassword - password + * @return config + */ + public T setSslTruststorePassword(String sslTruststorePassword) { + this.sslTruststorePassword = sslTruststorePassword; + return (T) this; + } + + public URI getSslKeystore() { + return sslKeystore; + } + + /** + * Defines path to SSL keystore + * + * @param sslKeystore - path to keystore + * @return config + */ + public T setSslKeystore(URI sslKeystore) { + this.sslKeystore = sslKeystore; + return (T) this; + } + + public String getSslKeystorePassword() { + return sslKeystorePassword; + } + + /** + * Defines password for SSL keystore + * + * @param sslKeystorePassword - password + * @return config + */ + public T setSslKeystorePassword(String sslKeystorePassword) { + this.sslKeystorePassword = sslKeystorePassword; + return (T) this; + } + + + } diff --git a/redisson/src/main/java/org/redisson/config/ClusterServersConfig.java b/redisson/src/main/java/org/redisson/config/ClusterServersConfig.java index 03ac2317a..6a9476ce6 100644 --- a/redisson/src/main/java/org/redisson/config/ClusterServersConfig.java +++ b/redisson/src/main/java/org/redisson/config/ClusterServersConfig.java @@ -15,12 +15,10 @@ */ package org.redisson.config; -import java.net.URL; +import java.net.URI; import java.util.ArrayList; import java.util.List; -import org.redisson.misc.URLBuilder; - /** * * @author Nikita Koksharov @@ -31,7 +29,7 @@ public class ClusterServersConfig extends BaseMasterSlaveServersConfig nodeAddresses = new ArrayList(); + private List nodeAddresses = new ArrayList(); /** * Redis cluster scan interval in milliseconds @@ -55,14 +53,14 @@ public class ClusterServersConfig extends BaseMasterSlaveServersConfig getNodeAddresses() { + public List getNodeAddresses() { return nodeAddresses; } - void setNodeAddresses(List nodeAddresses) { + void setNodeAddresses(List nodeAddresses) { this.nodeAddresses = nodeAddresses; } diff --git a/redisson/src/main/java/org/redisson/config/ConfigSupport.java b/redisson/src/main/java/org/redisson/config/ConfigSupport.java index 9e48cc479..05a8cddbe 100644 --- a/redisson/src/main/java/org/redisson/config/ConfigSupport.java +++ b/redisson/src/main/java/org/redisson/config/ConfigSupport.java @@ -35,7 +35,6 @@ import org.redisson.connection.SentinelConnectionManager; import org.redisson.connection.SingleConnectionManager; import org.redisson.connection.balancer.LoadBalancer; import org.redisson.liveobject.provider.ResolverProvider; -import org.redisson.misc.URLBuilder; import com.fasterxml.jackson.annotation.JsonFilter; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -123,12 +122,7 @@ public class ConfigSupport { private ObjectMapper yamlMapper = createMapper(new YAMLFactory(), null); public T fromJSON(String content, Class configType) throws IOException { - URLBuilder.replaceURLFactory(); - try { - return jsonMapper.readValue(content, configType); - } finally { - URLBuilder.restoreURLFactory(); - } + return jsonMapper.readValue(content, configType); } public T fromJSON(File file, Class configType) throws IOException { @@ -136,114 +130,54 @@ public class ConfigSupport { } public T fromJSON(File file, Class configType, ClassLoader classLoader) throws IOException { - URLBuilder.replaceURLFactory(); - try { - jsonMapper = createMapper(null, classLoader); - return jsonMapper.readValue(file, configType); - } finally { - URLBuilder.restoreURLFactory(); - } + jsonMapper = createMapper(null, classLoader); + return jsonMapper.readValue(file, configType); } public T fromJSON(URL url, Class configType) throws IOException { - URLBuilder.replaceURLFactory(); - try { - return jsonMapper.readValue(url, configType); - } finally { - URLBuilder.restoreURLFactory(); - } + return jsonMapper.readValue(url, configType); } public T fromJSON(Reader reader, Class configType) throws IOException { - URLBuilder.replaceURLFactory(); - try { - return jsonMapper.readValue(reader, configType); - } finally { - URLBuilder.restoreURLFactory(); - } + return jsonMapper.readValue(reader, configType); } public T fromJSON(InputStream inputStream, Class configType) throws IOException { - URLBuilder.replaceURLFactory(); - try { - return jsonMapper.readValue(inputStream, configType); - } finally { - URLBuilder.restoreURLFactory(); - } + return jsonMapper.readValue(inputStream, configType); } public String toJSON(Config config) throws IOException { - URLBuilder.replaceURLFactory(); - try { - return jsonMapper.writeValueAsString(config); - } finally { - URLBuilder.restoreURLFactory(); - } + return jsonMapper.writeValueAsString(config); } public T fromYAML(String content, Class configType) throws IOException { - URLBuilder.replaceURLFactory(); - try { - return yamlMapper.readValue(content, configType); - } finally { - URLBuilder.restoreURLFactory(); - } + return yamlMapper.readValue(content, configType); } public T fromYAML(File file, Class configType) throws IOException { - URLBuilder.replaceURLFactory(); - try { - return yamlMapper.readValue(file, configType); - } finally { - URLBuilder.restoreURLFactory(); - } + return yamlMapper.readValue(file, configType); } public T fromYAML(File file, Class configType, ClassLoader classLoader) throws IOException { - URLBuilder.replaceURLFactory(); - try { - yamlMapper = createMapper(new YAMLFactory(), classLoader); - return yamlMapper.readValue(file, configType); - } finally { - URLBuilder.restoreURLFactory(); - } + yamlMapper = createMapper(new YAMLFactory(), classLoader); + return yamlMapper.readValue(file, configType); } public T fromYAML(URL url, Class configType) throws IOException { - URLBuilder.replaceURLFactory(); - try { - return yamlMapper.readValue(url, configType); - } finally { - URLBuilder.restoreURLFactory(); - } + return yamlMapper.readValue(url, configType); } public T fromYAML(Reader reader, Class configType) throws IOException { - URLBuilder.replaceURLFactory(); - try { - return yamlMapper.readValue(reader, configType); - } finally { - URLBuilder.restoreURLFactory(); - } + return yamlMapper.readValue(reader, configType); } public T fromYAML(InputStream inputStream, Class configType) throws IOException { - URLBuilder.replaceURLFactory(); - try { - return yamlMapper.readValue(inputStream, configType); - } finally { - URLBuilder.restoreURLFactory(); - } + return yamlMapper.readValue(inputStream, configType); } public String toYAML(Config config) throws IOException { - URLBuilder.replaceURLFactory(); - try { - return yamlMapper.writeValueAsString(config); - } finally { - URLBuilder.restoreURLFactory(); - } + return yamlMapper.writeValueAsString(config); } public static ConnectionManager createConnectionManager(Config configCopy) { diff --git a/redisson/src/main/java/org/redisson/config/MasterSlaveServersConfig.java b/redisson/src/main/java/org/redisson/config/MasterSlaveServersConfig.java index 9a5023a94..3cb98bac3 100644 --- a/redisson/src/main/java/org/redisson/config/MasterSlaveServersConfig.java +++ b/redisson/src/main/java/org/redisson/config/MasterSlaveServersConfig.java @@ -15,12 +15,10 @@ */ package org.redisson.config; -import java.net.URL; +import java.net.URI; import java.util.HashSet; import java.util.Set; -import org.redisson.misc.URLBuilder; - /** * * @author Nikita Koksharov @@ -31,12 +29,12 @@ public class MasterSlaveServersConfig extends BaseMasterSlaveServersConfig slaveAddresses = new HashSet(); + private Set slaveAddresses = new HashSet(); /** * Redis master server address */ - private URL masterAddress; + private URI masterAddress; /** * Database index used for Redis connection @@ -62,20 +60,21 @@ public class MasterSlaveServersConfig extends BaseMasterSlaveServersConfig getSlaveAddresses() { + public Set getSlaveAddresses() { return slaveAddresses; } - public void setSlaveAddresses(Set readAddresses) { + public void setSlaveAddresses(Set readAddresses) { this.slaveAddresses = readAddresses; } diff --git a/redisson/src/main/java/org/redisson/config/ReplicatedServersConfig.java b/redisson/src/main/java/org/redisson/config/ReplicatedServersConfig.java index 541befbd6..dbb289edc 100644 --- a/redisson/src/main/java/org/redisson/config/ReplicatedServersConfig.java +++ b/redisson/src/main/java/org/redisson/config/ReplicatedServersConfig.java @@ -15,12 +15,10 @@ */ package org.redisson.config; -import java.net.URL; +import java.net.URI; import java.util.ArrayList; import java.util.List; -import org.redisson.misc.URLBuilder; - /** * Configuration for an Azure Redis Cache or AWS ElastiCache servers. * A replication group is composed of a single master endpoint and multiple read slaves. @@ -33,7 +31,7 @@ public class ReplicatedServersConfig extends BaseMasterSlaveServersConfig nodeAddresses = new ArrayList(); + private List nodeAddresses = new ArrayList(); /** * Replication group scan interval in milliseconds @@ -63,14 +61,14 @@ public class ReplicatedServersConfig extends BaseMasterSlaveServersConfig getNodeAddresses() { + public List getNodeAddresses() { return nodeAddresses; } - void setNodeAddresses(List nodeAddresses) { + void setNodeAddresses(List nodeAddresses) { this.nodeAddresses = nodeAddresses; } diff --git a/redisson/src/main/java/org/redisson/config/SentinelServersConfig.java b/redisson/src/main/java/org/redisson/config/SentinelServersConfig.java index f52741045..67f9465e4 100644 --- a/redisson/src/main/java/org/redisson/config/SentinelServersConfig.java +++ b/redisson/src/main/java/org/redisson/config/SentinelServersConfig.java @@ -15,12 +15,10 @@ */ package org.redisson.config; -import java.net.URL; +import java.net.URI; import java.util.ArrayList; import java.util.List; -import org.redisson.misc.URLBuilder; - /** * * @author Nikita Koksharov @@ -28,7 +26,7 @@ import org.redisson.misc.URLBuilder; */ public class SentinelServersConfig extends BaseMasterSlaveServersConfig { - private List sentinelAddresses = new ArrayList(); + private List sentinelAddresses = new ArrayList(); private String masterName; @@ -69,14 +67,14 @@ public class SentinelServersConfig extends BaseMasterSlaveServersConfig getSentinelAddresses() { + public List getSentinelAddresses() { return sentinelAddresses; } - void setSentinelAddresses(List sentinelAddresses) { + void setSentinelAddresses(List sentinelAddresses) { this.sentinelAddresses = sentinelAddresses; } diff --git a/redisson/src/main/java/org/redisson/config/SingleServerConfig.java b/redisson/src/main/java/org/redisson/config/SingleServerConfig.java index d5707ed6b..2adb1d039 100644 --- a/redisson/src/main/java/org/redisson/config/SingleServerConfig.java +++ b/redisson/src/main/java/org/redisson/config/SingleServerConfig.java @@ -15,9 +15,7 @@ */ package org.redisson.config; -import java.net.URL; - -import org.redisson.misc.URLBuilder; +import java.net.URI; /** * @@ -30,7 +28,7 @@ public class SingleServerConfig extends BaseConfig { * Redis server address * */ - private URL address; + private URI address; /** * Minimum idle subscription connection amount @@ -127,17 +125,17 @@ public class SingleServerConfig extends BaseConfig { */ public SingleServerConfig setAddress(String address) { if (address != null) { - this.address = URLBuilder.create(address); + this.address = URI.create(address); } return this; } - public URL getAddress() { + public URI getAddress() { if (address != null) { return address; } return null; } - void setAddress(URL address) { + void setAddress(URI address) { if (address != null) { this.address = address; } diff --git a/redisson/src/main/java/org/redisson/connection/ConnectionInitializer.java b/redisson/src/main/java/org/redisson/config/SslProvider.java similarity index 61% rename from redisson/src/main/java/org/redisson/connection/ConnectionInitializer.java rename to redisson/src/main/java/org/redisson/config/SslProvider.java index f9b98c35b..5585b2d19 100644 --- a/redisson/src/main/java/org/redisson/connection/ConnectionInitializer.java +++ b/redisson/src/main/java/org/redisson/config/SslProvider.java @@ -13,15 +13,24 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.redisson.connection; +package org.redisson.config; -import org.redisson.api.NodeType; -import org.redisson.client.RedisConnection; -import org.redisson.config.MasterSlaveServersConfig; -import org.redisson.misc.RPromise; - -public interface ConnectionInitializer { - - void onConnect(RPromise connectionFuture, T conn, NodeType nodeType, MasterSlaveServersConfig config); +/** + * + * @author Nikita Koksharov + * + */ +public enum SslProvider { + /** + * Use JDK default implementation to handle SSL connection + */ + JDK, + + /** + * Use OpenSSL-based implementation to handle SSL connection. + * netty-tcnative lib is required to be in classpath. + */ + OPENSSL + } diff --git a/redisson/src/main/java/org/redisson/connection/ClientConnectionsEntry.java b/redisson/src/main/java/org/redisson/connection/ClientConnectionsEntry.java index 86302a25f..45bc74c8b 100644 --- a/redisson/src/main/java/org/redisson/connection/ClientConnectionsEntry.java +++ b/redisson/src/main/java/org/redisson/connection/ClientConnectionsEntry.java @@ -21,12 +21,10 @@ import java.util.concurrent.atomic.AtomicInteger; import org.redisson.api.NodeType; import org.redisson.api.RFuture; -import org.redisson.client.ReconnectListener; import org.redisson.client.RedisClient; import org.redisson.client.RedisConnection; import org.redisson.client.RedisPubSubConnection; import org.redisson.config.MasterSlaveServersConfig; -import org.redisson.misc.RPromise; import org.redisson.pubsub.AsyncSemaphore; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -132,52 +130,21 @@ public class ClientConnectionsEntry { } public RFuture connect() { - final RPromise connectionFuture = connectionManager.newPromise(); RFuture future = client.connectAsync(); future.addListener(new FutureListener() { @Override public void operationComplete(Future future) throws Exception { if (!future.isSuccess()) { - connectionFuture.tryFailure(future.cause()); return; } RedisConnection conn = future.getNow(); log.debug("new connection created: {}", conn); - addReconnectListener(connectionFuture, conn); + connectionManager.getConnectionEventsHub().fireConnect(conn.getRedisClient().getAddr()); } }); - return connectionFuture; - } - - private void addReconnectListener(RPromise connectionFuture, T conn) { - addFireEventListener(conn, connectionFuture); - - conn.setReconnectListener(new ReconnectListener() { - @Override - public void onReconnect(RedisConnection conn, RPromise connectionFuture) { - addFireEventListener(conn, connectionFuture); - } - }); - } - - private void addFireEventListener(T conn, RPromise connectionFuture) { - connectionManager.getConnectListener().onConnect(connectionFuture, conn, nodeType, connectionManager.getConfig()); - - if (connectionFuture.isSuccess()) { - connectionManager.getConnectionEventsHub().fireConnect(connectionFuture.getNow().getRedisClient().getAddr()); - return; - } - - connectionFuture.addListener(new FutureListener() { - @Override - public void operationComplete(Future future) throws Exception { - if (future.isSuccess()) { - connectionManager.getConnectionEventsHub().fireConnect(future.getNow().getRedisClient().getAddr()); - } - } - }); + return future; } public MasterSlaveServersConfig getConfig() { @@ -185,26 +152,23 @@ public class ClientConnectionsEntry { } public RFuture connectPubSub() { - final RPromise connectionFuture = connectionManager.newPromise(); RFuture future = client.connectPubSubAsync(); future.addListener(new FutureListener() { @Override public void operationComplete(Future future) throws Exception { if (!future.isSuccess()) { - connectionFuture.tryFailure(future.cause()); return; } RedisPubSubConnection conn = future.getNow(); log.debug("new pubsub connection created: {}", conn); - addReconnectListener(connectionFuture, conn); - + connectionManager.getConnectionEventsHub().fireConnect(conn.getRedisClient().getAddr()); allSubscribeConnections.add(conn); } }); - return connectionFuture; + return future; } public Queue getAllSubscribeConnections() { diff --git a/redisson/src/main/java/org/redisson/connection/ConnectionManager.java b/redisson/src/main/java/org/redisson/connection/ConnectionManager.java index 0300a28d6..eb64cb0e8 100644 --- a/redisson/src/main/java/org/redisson/connection/ConnectionManager.java +++ b/redisson/src/main/java/org/redisson/connection/ConnectionManager.java @@ -16,7 +16,7 @@ package org.redisson.connection; import java.net.InetSocketAddress; -import java.net.URL; +import java.net.URI; import java.util.Collection; import java.util.Set; import java.util.concurrent.ExecutorService; @@ -50,7 +50,7 @@ public interface ConnectionManager { ExecutorService getExecutor(); - URL getLastClusterNode(); + URI getLastClusterNode(); boolean isClusterMode(); @@ -68,8 +68,6 @@ public interface ConnectionManager { RFuture subscribe(Codec codec, String channelName, AsyncSemaphore semaphore, RedisPubSubListener... listeners); - ConnectionInitializer getConnectListener(); - IdleConnectionWatcher getConnectionWatcher(); RFuture newFailedFuture(Throwable cause); @@ -98,9 +96,9 @@ public interface ConnectionManager { RFuture connectionWriteOp(NodeSource source, RedisCommand command); - RedisClient createClient(String host, int port, int timeout, int commandTimeout); + RedisClient createClient(NodeType type, URI address, int timeout, int commandTimeout); - RedisClient createClient(NodeType type, String host, int port); + RedisClient createClient(NodeType type, URI address); MasterSlaveEntry getEntry(InetSocketAddress addr); diff --git a/redisson/src/main/java/org/redisson/connection/DefaultConnectionListener.java b/redisson/src/main/java/org/redisson/connection/DefaultConnectionListener.java deleted file mode 100644 index 8dc8f3a3c..000000000 --- a/redisson/src/main/java/org/redisson/connection/DefaultConnectionListener.java +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Copyright 2016 Nikita Koksharov - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.redisson.connection; - -import org.redisson.api.NodeType; -import org.redisson.client.RedisConnection; -import org.redisson.client.RedisException; -import org.redisson.client.protocol.RedisCommands; -import org.redisson.config.MasterSlaveServersConfig; -import org.redisson.misc.RPromise; - -public class DefaultConnectionListener implements ConnectionInitializer { - - public final void onConnect(RPromise connectionFuture, T conn, NodeType nodeType, MasterSlaveServersConfig config) { - FutureConnectionListener listener = new FutureConnectionListener(connectionFuture, conn); - doConnect(config, nodeType, listener); - listener.executeCommands(); - } - - protected void doConnect(MasterSlaveServersConfig config, NodeType nodeType, FutureConnectionListener connectionListener) - throws RedisException { - if (config.getPassword() != null) { - connectionListener.addCommand(RedisCommands.AUTH, config.getPassword()); - } - if (config.getDatabase() != 0) { - connectionListener.addCommand(RedisCommands.SELECT, config.getDatabase()); - } - if (config.getClientName() != null) { - connectionListener.addCommand(RedisCommands.CLIENT_SETNAME, config.getClientName()); - } - } - -} diff --git a/redisson/src/main/java/org/redisson/connection/MasterSlaveConnectionManager.java b/redisson/src/main/java/org/redisson/connection/MasterSlaveConnectionManager.java index 13ee7ad4c..17bb6460f 100644 --- a/redisson/src/main/java/org/redisson/connection/MasterSlaveConnectionManager.java +++ b/redisson/src/main/java/org/redisson/connection/MasterSlaveConnectionManager.java @@ -17,7 +17,7 @@ package org.redisson.connection; import java.lang.reflect.Field; import java.net.InetSocketAddress; -import java.net.URL; +import java.net.URI; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -38,6 +38,7 @@ import org.redisson.api.NodeType; import org.redisson.api.RFuture; import org.redisson.client.BaseRedisPubSubListener; import org.redisson.client.RedisClient; +import org.redisson.client.RedisClientConfig; import org.redisson.client.RedisConnection; import org.redisson.client.RedisNodeNotFoundException; import org.redisson.client.RedisPubSubConnection; @@ -121,8 +122,6 @@ public class MasterSlaveConnectionManager implements ConnectionManager { protected EventLoopGroup group; - protected ConnectionInitializer connectListener = new DefaultConnectionListener(); - protected Class socketChannelClass; protected final ConcurrentMap name2PubSubConnection = PlatformDependent.newConcurrentHashMap(); @@ -275,10 +274,6 @@ public class MasterSlaveConnectionManager implements ConnectionManager { } - public ConnectionInitializer getConnectListener() { - return connectListener; - } - protected void initEntry(MasterSlaveServersConfig config) { HashSet slots = new HashSet(); slots.add(singleSlotRange); @@ -286,7 +281,7 @@ public class MasterSlaveConnectionManager implements ConnectionManager { MasterSlaveEntry entry; if (config.getReadMode() == ReadMode.MASTER) { entry = new SingleEntry(slots, this, config); - RFuture f = entry.setupMasterEntry(config.getMasterAddress().getHost(), config.getMasterAddress().getPort()); + RFuture f = entry.setupMasterEntry(config.getMasterAddress()); f.syncUninterruptibly(); } else { entry = createMasterSlaveEntry(config, slots); @@ -300,17 +295,25 @@ public class MasterSlaveConnectionManager implements ConnectionManager { protected MasterSlaveEntry createMasterSlaveEntry(MasterSlaveServersConfig config, HashSet slots) { MasterSlaveEntry entry = new MasterSlaveEntry(slots, this, config); - List> fs = entry.initSlaveBalancer(java.util.Collections.emptySet()); + List> fs = entry.initSlaveBalancer(java.util.Collections.emptySet()); for (RFuture future : fs) { future.syncUninterruptibly(); } - RFuture f = entry.setupMasterEntry(config.getMasterAddress().getHost(), config.getMasterAddress().getPort()); + RFuture f = entry.setupMasterEntry(config.getMasterAddress()); f.syncUninterruptibly(); return entry; } protected MasterSlaveServersConfig create(BaseMasterSlaveServersConfig cfg) { MasterSlaveServersConfig c = new MasterSlaveServersConfig(); + + c.setSslEnableEndpointIdentification(cfg.isSslEnableEndpointIdentification()); + c.setSslProvider(cfg.getSslProvider()); + c.setSslTruststore(cfg.getSslTruststore()); + c.setSslTruststorePassword(cfg.getSslTruststorePassword()); + c.setSslKeystore(cfg.getSslKeystore()); + c.setSslKeystorePassword(cfg.getSslKeystorePassword()); + c.setRetryInterval(cfg.getRetryInterval()); c.setRetryAttempts(cfg.getRetryAttempts()); c.setTimeout(cfg.getTimeout()); @@ -337,8 +340,8 @@ public class MasterSlaveConnectionManager implements ConnectionManager { } @Override - public RedisClient createClient(NodeType type, String host, int port) { - RedisClient client = createClient(host, port, config.getConnectTimeout(), config.getRetryInterval() * config.getRetryAttempts()); + public RedisClient createClient(NodeType type, URI address) { + RedisClient client = createClient(type, address, config.getConnectTimeout(), config.getRetryInterval() * config.getRetryAttempts()); clientEntries.put(client, new RedisClientEntry(client, commandExecutor, type)); return client; } @@ -350,8 +353,30 @@ public class MasterSlaveConnectionManager implements ConnectionManager { } @Override - public RedisClient createClient(String host, int port, int timeout, int commandTimeout) { - return new RedisClient(timer, executor, group, socketChannelClass, host, port, timeout, commandTimeout); + public RedisClient createClient(NodeType type, URI address, int timeout, int commandTimeout) { + RedisClientConfig redisConfig = createRedisConfig(type, address, timeout, commandTimeout); + return RedisClient.create(redisConfig); + } + + protected RedisClientConfig createRedisConfig(NodeType type, URI address, int timeout, int commandTimeout) { + RedisClientConfig redisConfig = new RedisClientConfig(); + redisConfig.setAddress(address) + .setTimer(timer) + .setExecutor(executor) + .setGroup(group) + .setSocketChannelClass(socketChannelClass) + .setConnectTimeout(timeout) + .setCommandTimeout(commandTimeout) + .setSslEnableEndpointIdentification(config.isSslEnableEndpointIdentification()) + .setSslProvider(config.getSslProvider()) + .setSslTruststore(config.getSslTruststore()) + .setSslTruststorePassword(config.getSslTruststorePassword()) + .setSslKeystore(config.getSslKeystore()) + .setSslKeystorePassword(config.getSslKeystorePassword()) + .setPassword(config.getPassword()) + .setDatabase(config.getDatabase()) + .setClientName(config.getClientName()); + return redisConfig; } @Override @@ -656,8 +681,8 @@ public class MasterSlaveConnectionManager implements ConnectionManager { getEntry(slotRange.getStartSlot()).slaveDown(host, port, freezeReason); } - protected void changeMaster(int slot, String host, int port) { - getEntry(slot).changeMaster(host, port); + protected void changeMaster(int slot, URI address) { + getEntry(slot).changeMaster(address); } protected void addEntry(Integer slot, MasterSlaveEntry entry) { @@ -846,7 +871,7 @@ public class MasterSlaveConnectionManager implements ConnectionManager { return executor; } - public URL getLastClusterNode() { + public URI getLastClusterNode() { return null; } } diff --git a/redisson/src/main/java/org/redisson/connection/MasterSlaveEntry.java b/redisson/src/main/java/org/redisson/connection/MasterSlaveEntry.java index dffca6a57..c0d5b7444 100644 --- a/redisson/src/main/java/org/redisson/connection/MasterSlaveEntry.java +++ b/redisson/src/main/java/org/redisson/connection/MasterSlaveEntry.java @@ -16,7 +16,7 @@ package org.redisson.connection; import java.net.InetSocketAddress; -import java.net.URL; +import java.net.URI; import java.util.Collection; import java.util.HashSet; import java.util.LinkedList; @@ -86,23 +86,23 @@ public class MasterSlaveEntry { pubSubConnectionHolder = new MasterPubSubConnectionPool(config, connectionManager, this); } - public List> initSlaveBalancer(Collection disconnectedNodes) { + public List> initSlaveBalancer(Collection disconnectedNodes) { boolean freezeMasterAsSlave = !config.getSlaveAddresses().isEmpty() && config.getReadMode() == ReadMode.SLAVE && disconnectedNodes.size() < config.getSlaveAddresses().size(); List> result = new LinkedList>(); - RFuture f = addSlave(config.getMasterAddress().getHost(), config.getMasterAddress().getPort(), freezeMasterAsSlave, NodeType.MASTER); + RFuture f = addSlave(config.getMasterAddress(), freezeMasterAsSlave, NodeType.MASTER); result.add(f); - for (URL address : config.getSlaveAddresses()) { - f = addSlave(address.getHost(), address.getPort(), disconnectedNodes.contains(address), NodeType.SLAVE); + for (URI address : config.getSlaveAddresses()) { + f = addSlave(address, disconnectedNodes.contains(address), NodeType.SLAVE); result.add(f); } return result; } - public RFuture setupMasterEntry(String host, int port) { - RedisClient client = connectionManager.createClient(NodeType.MASTER, host, port); + public RFuture setupMasterEntry(URI address) { + RedisClient client = connectionManager.createClient(NodeType.MASTER, address); masterEntry = new ClientConnectionsEntry( client, config.getMasterConnectionMinimumIdleSize(), @@ -264,7 +264,8 @@ public class MasterSlaveEntry { final CommandData commandData = connection.getCurrentCommand(); if (commandData == null - || !commandData.isBlockingCommand()) { + || !commandData.isBlockingCommand() + || commandData.getPromise().isDone()) { return; } @@ -309,12 +310,12 @@ public class MasterSlaveEntry { return slaveBalancer.contains(addr); } - public RFuture addSlave(String host, int port) { - return addSlave(host, port, true, NodeType.SLAVE); + public RFuture addSlave(URI address) { + return addSlave(address, true, NodeType.SLAVE); } - private RFuture addSlave(String host, int port, boolean freezed, NodeType mode) { - RedisClient client = connectionManager.createClient(NodeType.SLAVE, host, port); + private RFuture addSlave(URI address, boolean freezed, NodeType mode) { + RedisClient client = connectionManager.createClient(NodeType.SLAVE, address); ClientConnectionsEntry entry = new ClientConnectionsEntry(client, this.config.getSlaveConnectionMinimumIdleSize(), this.config.getSlaveConnectionPoolSize(), @@ -349,16 +350,15 @@ public class MasterSlaveEntry { } /** - * Freeze slave with host:port from slaves list. + * Freeze slave with redis(s)://host:port from slaves list. * Re-attach pub/sub listeners from it to other slave. * Shutdown old master client. * - * @param host of Redis - * @param port of Redis + * @param address of Redis */ - public void changeMaster(final String host, final int port) { + public void changeMaster(final URI address) { final ClientConnectionsEntry oldMaster = masterEntry; - RFuture future = setupMasterEntry(host, port); + RFuture future = setupMasterEntry(address); future.addListener(new FutureListener() { @Override public void operationComplete(Future future) throws Exception { @@ -369,7 +369,7 @@ public class MasterSlaveEntry { // more than one slave available, so master can be removed from slaves if (config.getReadMode() == ReadMode.SLAVE && slaveBalancer.getAvailableClients() > 1) { - slaveDown(host, port, FreezeReason.SYSTEM); + slaveDown(address.getHost(), address.getPort(), FreezeReason.SYSTEM); } connectionManager.shutdownAsync(oldMaster.getClient()); } diff --git a/redisson/src/main/java/org/redisson/connection/ReplicatedConnectionManager.java b/redisson/src/main/java/org/redisson/connection/ReplicatedConnectionManager.java index ca776ad4d..792c01484 100644 --- a/redisson/src/main/java/org/redisson/connection/ReplicatedConnectionManager.java +++ b/redisson/src/main/java/org/redisson/connection/ReplicatedConnectionManager.java @@ -15,13 +15,14 @@ */ package org.redisson.connection; -import java.net.URL; +import java.net.URI; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; +import org.redisson.api.NodeType; import org.redisson.api.RFuture; import org.redisson.client.RedisClient; import org.redisson.client.RedisConnection; @@ -55,9 +56,9 @@ public class ReplicatedConnectionManager extends MasterSlaveConnectionManager { private final Logger log = LoggerFactory.getLogger(getClass()); - private AtomicReference currentMaster = new AtomicReference(); + private AtomicReference currentMaster = new AtomicReference(); - private final Map nodeConnections = new HashMap(); + private final Map nodeConnections = new HashMap(); private ScheduledFuture monitorFuture; @@ -72,7 +73,7 @@ public class ReplicatedConnectionManager extends MasterSlaveConnectionManager { this.config = create(cfg); initTimer(this.config); - for (URL addr : cfg.getNodeAddresses()) { + for (URI addr : cfg.getNodeAddresses()) { RFuture connectionFuture = connect(cfg, addr); connectionFuture.awaitUninterruptibly(); RedisConnection connection = connectionFuture.getNow(); @@ -110,13 +111,13 @@ public class ReplicatedConnectionManager extends MasterSlaveConnectionManager { return res; } - private RFuture connect(BaseMasterSlaveServersConfig cfg, final URL addr) { + private RFuture connect(BaseMasterSlaveServersConfig cfg, final URI addr) { RedisConnection connection = nodeConnections.get(addr); if (connection != null) { return newSucceededFuture(connection); } - RedisClient client = createClient(addr.getHost(), addr.getPort(), cfg.getConnectTimeout(), cfg.getRetryInterval() * cfg.getRetryAttempts()); + RedisClient client = createClient(NodeType.MASTER, addr, cfg.getConnectTimeout(), cfg.getRetryInterval() * cfg.getRetryAttempts()); final RPromise result = newPromise(); RFuture future = client.connectAsync(); future.addListener(new FutureListener() { @@ -128,26 +129,13 @@ public class ReplicatedConnectionManager extends MasterSlaveConnectionManager { } RedisConnection connection = future.getNow(); - RPromise promise = newPromise(); - connectListener.onConnect(promise, connection, null, config); - promise.addListener(new FutureListener() { - @Override - public void operationComplete(Future future) throws Exception { - if (!future.isSuccess()) { - result.tryFailure(future.cause()); - return; - } - - RedisConnection connection = future.getNow(); - if (connection.isActive()) { - nodeConnections.put(addr, connection); - result.trySuccess(connection); - } else { - connection.closeAsync(); - result.tryFailure(new RedisException("Connection to " + connection.getRedisClient().getAddr() + " is not active!")); - } - } - }); + if (connection.isActive()) { + nodeConnections.put(addr, connection); + result.trySuccess(connection); + } else { + connection.closeAsync(); + result.tryFailure(new RedisException("Connection to " + connection.getRedisClient().getAddr() + " is not active!")); + } } }); @@ -158,11 +146,11 @@ public class ReplicatedConnectionManager extends MasterSlaveConnectionManager { monitorFuture = GlobalEventExecutor.INSTANCE.schedule(new Runnable() { @Override public void run() { - final URL master = currentMaster.get(); + final URI master = currentMaster.get(); log.debug("Current master: {}", master); final AtomicInteger count = new AtomicInteger(cfg.getNodeAddresses().size()); - for (final URL addr : cfg.getNodeAddresses()) { + for (final URI addr : cfg.getNodeAddresses()) { if (isShuttingDown()) { return; } @@ -203,7 +191,7 @@ public class ReplicatedConnectionManager extends MasterSlaveConnectionManager { log.debug("Current master {} unchanged", master); } else if (currentMaster.compareAndSet(master, addr)) { log.info("Master has changed from {} to {}", master, addr); - changeMaster(singleSlotRange.getStartSlot(), addr.getHost(), addr.getPort()); + changeMaster(singleSlotRange.getStartSlot(), addr); } } diff --git a/redisson/src/main/java/org/redisson/connection/SentinelConnectionManager.java b/redisson/src/main/java/org/redisson/connection/SentinelConnectionManager.java index 6974246d2..261041b9c 100755 --- a/redisson/src/main/java/org/redisson/connection/SentinelConnectionManager.java +++ b/redisson/src/main/java/org/redisson/connection/SentinelConnectionManager.java @@ -16,7 +16,7 @@ package org.redisson.connection; import java.net.InetSocketAddress; -import java.net.URL; +import java.net.URI; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -25,6 +25,7 @@ import java.util.Set; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicReference; +import org.redisson.api.NodeType; import org.redisson.api.RFuture; import org.redisson.client.BaseRedisPubSubListener; import org.redisson.client.RedisClient; @@ -41,7 +42,6 @@ import org.redisson.config.MasterSlaveServersConfig; import org.redisson.config.ReadMode; import org.redisson.config.SentinelServersConfig; import org.redisson.connection.ClientConnectionsEntry.FreezeReason; -import org.redisson.misc.URLBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -62,16 +62,16 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager { private final AtomicReference currentMaster = new AtomicReference(); private final ConcurrentMap slaves = PlatformDependent.newConcurrentHashMap(); - private final Set disconnectedSlaves = new HashSet(); + private final Set disconnectedSlaves = new HashSet(); public SentinelConnectionManager(SentinelServersConfig cfg, Config config) { super(config); - final MasterSlaveServersConfig c = create(cfg); - initTimer(c); + this.config = create(cfg); + initTimer(this.config); - for (URL addr : cfg.getSentinelAddresses()) { - RedisClient client = createClient(addr.getHost(), addr.getPort(), c.getConnectTimeout(), c.getRetryInterval() * c.getRetryAttempts()); + for (URI addr : cfg.getSentinelAddresses()) { + RedisClient client = createClient(NodeType.MASTER, addr, this.config.getConnectTimeout(), this.config.getRetryInterval() * this.config.getRetryAttempts()); try { RedisConnection connection = client.connect(); if (!connection.isActive()) { @@ -80,8 +80,8 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager { // TODO async List master = connection.sync(RedisCommands.SENTINEL_GET_MASTER_ADDR_BY_NAME, cfg.getMasterName()); - String masterHost = master.get(0) + ":" + master.get(1); - c.setMasterAddress(masterHost); + String masterHost = "redis://" + master.get(0) + ":" + master.get(1); + this.config.setMasterAddress(masterHost); currentMaster.set(masterHost); log.info("master: {} added", masterHost); slaves.put(masterHost, true); @@ -96,16 +96,16 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager { String port = map.get("port"); String flags = map.get("flags"); - String host = ip + ":" + port; + String host = "redis://" + ip + ":" + port; - c.addSlaveAddress(host); + this.config.addSlaveAddress(host); slaves.put(host, true); log.debug("slave {} state: {}", host, map); log.info("slave: {} added", host); if (flags.contains("s_down") || flags.contains("disconnected")) { - URL url = URLBuilder.create(host); - disconnectedSlaves.add(url); + URI uri = URI.create(host); + disconnectedSlaves.add(uri); log.warn("slave: {} is down", host); } } @@ -120,11 +120,11 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager { if (currentMaster.get() == null) { throw new RedisConnectionException("Can't connect to servers!"); } - init(c); + init(this.config); List> connectionFutures = new ArrayList>(cfg.getSentinelAddresses().size()); - for (URL addr : cfg.getSentinelAddresses()) { - RFuture future = registerSentinel(cfg, addr, c); + for (URI addr : cfg.getSentinelAddresses()) { + RFuture future = registerSentinel(cfg, addr, this.config); connectionFutures.add(future); } @@ -141,13 +141,13 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager { for (RFuture future : fs) { future.syncUninterruptibly(); } - RFuture f = entry.setupMasterEntry(config.getMasterAddress().getHost(), config.getMasterAddress().getPort()); + RFuture f = entry.setupMasterEntry(config.getMasterAddress()); f.syncUninterruptibly(); return entry; } - private RFuture registerSentinel(final SentinelServersConfig cfg, final URL addr, final MasterSlaveServersConfig c) { - RedisClient client = createClient(addr.getHost(), addr.getPort(), c.getConnectTimeout(), c.getRetryInterval() * c.getRetryAttempts()); + private RFuture registerSentinel(final SentinelServersConfig cfg, final URI addr, final MasterSlaveServersConfig c) { + RedisClient client = createClient(NodeType.MASTER, addr, c.getConnectTimeout(), c.getRetryInterval() * c.getRetryAttempts()); RedisClient oldClient = sentinels.putIfAbsent(addr.getHost() + ":" + addr.getPort(), client); if (oldClient != null) { return newSucceededFuture(null); @@ -207,13 +207,13 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager { String ip = parts[2]; String port = parts[3]; - String addr = ip + ":" + port; - URL uri = URLBuilder.create(addr); + String addr = "redis://" + ip + ":" + port; + URI uri = URI.create(addr); registerSentinel(cfg, uri, c); } } - protected void onSlaveAdded(URL addr, String msg) { + protected void onSlaveAdded(URI addr, String msg) { String[] parts = msg.split(" "); if (parts.length > 4 @@ -221,7 +221,7 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager { final String ip = parts[2]; final String port = parts[3]; - final String slaveAddr = ip + ":" + port; + final String slaveAddr = "redis://" + ip + ":" + port; if (!isUseSameMaster(parts)) { return; @@ -230,7 +230,7 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager { // to avoid addition twice if (slaves.putIfAbsent(slaveAddr, true) == null) { final MasterSlaveEntry entry = getEntry(singleSlotRange.getStartSlot()); - RFuture future = entry.addSlave(ip, Integer.valueOf(port)); + RFuture future = entry.addSlave(URI.create(slaveAddr)); future.addListener(new FutureListener() { @Override public void operationComplete(Future future) throws Exception { @@ -254,7 +254,7 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager { } } - private void onNodeDown(URL sentinelAddr, String msg) { + private void onNodeDown(URI sentinelAddr, String msg) { String[] parts = msg.split(" "); if (parts.length > 3) { @@ -309,7 +309,7 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager { String slaveAddr = ip + ":" + port; String master = currentMaster.get(); - String slaveMaster = parts[6] + ":" + parts[7]; + String slaveMaster = "redis://" + parts[6] + ":" + parts[7]; if (!master.equals(slaveMaster)) { log.warn("Skipped slave up {} for master {} differs from current {}", slaveAddr, slaveMaster, master); return false; @@ -317,7 +317,7 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager { return true; } - private void onNodeUp(URL addr, String msg) { + private void onNodeUp(URI addr, String msg) { String[] parts = msg.split(" "); if (parts.length > 3) { @@ -334,11 +334,11 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager { String ip = parts[2]; String port = parts[3]; - String masterAddr = ip + ":" + port; MasterSlaveEntry entry = getEntry(singleSlotRange.getStartSlot()); if (entry.isFreezed() && entry.getClient().getAddr().equals(new InetSocketAddress(ip, Integer.valueOf(port)))) { entry.unfreeze(); + String masterAddr = ip + ":" + port; log.info("master: {} has up", masterAddr); } } else { @@ -360,7 +360,7 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager { } } - private void onMasterChange(SentinelServersConfig cfg, URL addr, String msg) { + private void onMasterChange(SentinelServersConfig cfg, URI addr, String msg) { String[] parts = msg.split(" "); if (parts.length > 3) { @@ -369,10 +369,10 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager { String port = parts[4]; String current = currentMaster.get(); - String newMaster = ip + ":" + port; + String newMaster = "redis://" + ip + ":" + port; if (!newMaster.equals(current) && currentMaster.compareAndSet(current, newMaster)) { - changeMaster(singleSlotRange.getStartSlot(), ip, Integer.valueOf(port)); + changeMaster(singleSlotRange.getStartSlot(), URI.create(newMaster)); log.info("master {} changed to {}", current, newMaster); } } diff --git a/redisson/src/main/java/org/redisson/connection/SingleConnectionManager.java b/redisson/src/main/java/org/redisson/connection/SingleConnectionManager.java index b965b54b4..71027b9e0 100644 --- a/redisson/src/main/java/org/redisson/connection/SingleConnectionManager.java +++ b/redisson/src/main/java/org/redisson/connection/SingleConnectionManager.java @@ -61,7 +61,14 @@ public class SingleConnectionManager extends MasterSlaveConnectionManager { private static MasterSlaveServersConfig create(SingleServerConfig cfg) { MasterSlaveServersConfig newconfig = new MasterSlaveServersConfig(); - String addr = cfg.getAddress().getHost() + ":" + cfg.getAddress().getPort(); + + newconfig.setSslEnableEndpointIdentification(cfg.isSslEnableEndpointIdentification()); + newconfig.setSslProvider(cfg.getSslProvider()); + newconfig.setSslTruststore(cfg.getSslTruststore()); + newconfig.setSslTruststorePassword(cfg.getSslTruststorePassword()); + newconfig.setSslKeystore(cfg.getSslKeystore()); + newconfig.setSslKeystorePassword(cfg.getSslKeystorePassword()); + newconfig.setRetryAttempts(cfg.getRetryAttempts()); newconfig.setRetryInterval(cfg.getRetryInterval()); newconfig.setTimeout(cfg.getTimeout()); @@ -69,7 +76,7 @@ public class SingleConnectionManager extends MasterSlaveConnectionManager { newconfig.setPassword(cfg.getPassword()); newconfig.setDatabase(cfg.getDatabase()); newconfig.setClientName(cfg.getClientName()); - newconfig.setMasterAddress(addr); + newconfig.setMasterAddress(cfg.getAddress()); newconfig.setMasterConnectionPoolSize(cfg.getConnectionPoolSize()); newconfig.setSubscriptionsPerConnection(cfg.getSubscriptionsPerConnection()); newconfig.setSubscriptionConnectionPoolSize(cfg.getSubscriptionConnectionPoolSize()); @@ -95,7 +102,7 @@ public class SingleConnectionManager extends MasterSlaveConnectionManager { if (!now.getHostAddress().equals(master.getHostAddress())) { log.info("Detected DNS change. {} has changed from {} to {}", cfg.getAddress().getHost(), master.getHostAddress(), now.getHostAddress()); if (currentMaster.compareAndSet(master, now)) { - changeMaster(singleSlotRange.getStartSlot(), cfg.getAddress().getHost(), cfg.getAddress().getPort()); + changeMaster(singleSlotRange.getStartSlot(), cfg.getAddress()); log.info("Master has been changed"); } } diff --git a/redisson/src/main/java/org/redisson/connection/balancer/WeightedRoundRobinBalancer.java b/redisson/src/main/java/org/redisson/connection/balancer/WeightedRoundRobinBalancer.java index e5224013c..3ad542023 100644 --- a/redisson/src/main/java/org/redisson/connection/balancer/WeightedRoundRobinBalancer.java +++ b/redisson/src/main/java/org/redisson/connection/balancer/WeightedRoundRobinBalancer.java @@ -16,7 +16,7 @@ package org.redisson.connection.balancer; import java.net.InetSocketAddress; -import java.net.URL; +import java.net.URI; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -28,7 +28,6 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import org.redisson.connection.ClientConnectionsEntry; -import org.redisson.misc.URLBuilder; import io.netty.util.internal.PlatformDependent; @@ -73,12 +72,12 @@ public class WeightedRoundRobinBalancer implements LoadBalancer { /** * Creates weighted round robin balancer. * - * @param weights - weight mapped by slave node addr in host:port format + * @param weights - weight mapped by slave node addr in redis://host:port format * @param defaultWeight - default weight value assigns to slaves not defined in weights map */ public WeightedRoundRobinBalancer(Map weights, int defaultWeight) { for (Entry entry : weights.entrySet()) { - URL uri = URLBuilder.create(entry.getKey()); + URI uri = URI.create(entry.getKey()); InetSocketAddress addr = new InetSocketAddress(uri.getHost(), uri.getPort()); if (entry.getValue() <= 0) { throw new IllegalArgumentException("Weight can't be less than or equal zero"); diff --git a/redisson/src/main/java/org/redisson/connection/pool/ConnectionPool.java b/redisson/src/main/java/org/redisson/connection/pool/ConnectionPool.java index 695e8b086..ce8aa3ee9 100644 --- a/redisson/src/main/java/org/redisson/connection/pool/ConnectionPool.java +++ b/redisson/src/main/java/org/redisson/connection/pool/ConnectionPool.java @@ -20,7 +20,6 @@ import java.util.LinkedList; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import org.redisson.api.NodeType; @@ -100,8 +99,9 @@ abstract class ConnectionPool { final int minimumIdleSize, final AtomicInteger initializedConnections) { if ((checkFreezed && entry.isFreezed()) || !tryAcquireConnection(entry)) { + int totalInitializedConnections = minimumIdleSize - initializedConnections.get(); Throwable cause = new RedisConnectionException( - "Can't init enough connections amount! Only " + (minimumIdleSize - initializedConnections.get()) + " from " + minimumIdleSize + " were initialized. Server: " + "Unable to init enough connections amount! Only " + totalInitializedConnections + " from " + minimumIdleSize + " were initialized. Server: " + entry.getClient().getAddr()); initPromise.tryFailure(cause); return; @@ -125,9 +125,15 @@ abstract class ConnectionPool { releaseConnection(entry); if (!future.isSuccess()) { - Throwable cause = new RedisConnectionException( - "Can't init enough connections amount! Only " + (minimumIdleSize - initializedConnections.get()) + " from " + minimumIdleSize + " were initialized. Server: " - + entry.getClient().getAddr(), future.cause()); + int totalInitializedConnections = minimumIdleSize - initializedConnections.get(); + String errorMsg; + if (totalInitializedConnections == 0) { + errorMsg = "Unable to connect to Redis server: " + entry.getClient().getAddr(); + } else { + errorMsg = "Unable to init enough connections amount! Only " + totalInitializedConnections + + " from " + minimumIdleSize + " were initialized. Redis server: " + entry.getClient().getAddr(); + } + Throwable cause = new RedisConnectionException(errorMsg, future.cause()); initPromise.tryFailure(cause); return; } @@ -337,7 +343,8 @@ abstract class ConnectionPool { @Override public void run(Timeout timeout) throws Exception { if (entry.getFreezeReason() != FreezeReason.RECONNECT - || !entry.isFreezed()) { + || !entry.isFreezed() + || connectionManager.isShuttingDown()) { return; } diff --git a/redisson/src/main/java/org/redisson/misc/URLBuilder.java b/redisson/src/main/java/org/redisson/misc/URLBuilder.java deleted file mode 100644 index 9578cdf92..000000000 --- a/redisson/src/main/java/org/redisson/misc/URLBuilder.java +++ /dev/null @@ -1,148 +0,0 @@ -/** - * Copyright 2016 Nikita Koksharov - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.redisson.misc; - -import java.io.IOException; -import java.lang.reflect.Field; -import java.net.InetSocketAddress; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLConnection; -import java.net.URLStreamHandler; -import java.net.URLStreamHandlerFactory; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * - * @author Nikita Koksharov - * - */ -public class URLBuilder { - - private static URLStreamHandlerFactory currentFactory; - private static AtomicInteger refCounter = new AtomicInteger(); - - private final static URLStreamHandlerFactory newFactory = new URLStreamHandlerFactory() { - @Override - public URLStreamHandler createURLStreamHandler(String protocol) { - if ("redis".equals(protocol)) { - return new URLStreamHandler() { - @Override - protected URLConnection openConnection(URL u) throws IOException { - throw new UnsupportedOperationException(); - }; - - @Override - protected boolean equals(URL u1, URL u2) { - return u1.toString().equals(u2.toString()); - } - - @Override - protected int hashCode(URL u) { - return u.toString().hashCode(); - } - }; - } - - if (currentFactory != null) { - return currentFactory.createURLStreamHandler(protocol); - } - return null; - } - }; - - private static Field getFactoryField() { - Field field; - try { - field = URL.class.getDeclaredField("factory"); - } catch (NoSuchFieldException e) { - try { - // used in Android - field = URL.class.getDeclaredField("streamHandlerFactory"); - } catch (Exception e1) { - throw new IllegalStateException(e); - } - } - return field; - } - - public static synchronized void restoreURLFactory() { - if (refCounter.decrementAndGet() == 0) { - try { - Field field = getFactoryField(); - field.setAccessible(true); - field.set(null, currentFactory); - currentFactory = null; - } catch (Exception e) { - throw new IllegalStateException(e); - } - } - } - - public static synchronized void replaceURLFactory() { - try { - refCounter.incrementAndGet(); - Field field = getFactoryField(); - field.setAccessible(true); - final URLStreamHandlerFactory temp = (URLStreamHandlerFactory) field.get(null); - if (temp != newFactory) { - currentFactory = temp; - field.set(null, null); - URL.setURLStreamHandlerFactory(newFactory); - } - } catch (Exception e) { - throw new IllegalStateException(e); - } - } - - public static InetSocketAddress toAddress(String url) { - String[] parts = url.split(":"); - if (parts.length-1 >= 3) { - String port = parts[parts.length-1]; - String newPort = port.split("[^\\d]")[0]; - String host = url.replace(":" + port, ""); - return new InetSocketAddress(host, Integer.valueOf(newPort)); - } else { - String port = parts[parts.length-1]; - String newPort = port.split("[^\\d]")[0]; - String host = url.replace(":" + port, ""); - return new InetSocketAddress(host, Integer.valueOf(newPort)); - } - } - - public static URL create(String url) { - replaceURLFactory(); - try { - String[] parts = url.split(":"); - if (parts.length-1 >= 3) { - String port = parts[parts.length-1]; - String newPort = port.split("[^\\d]")[0]; - String host = url.replace(":" + port, ""); - return new URL("redis://[" + host + "]:" + newPort); - } else { - String port = parts[parts.length-1]; - String newPort = port.split("[^\\d]")[0]; - String host = url.replace(":" + port, ""); - return new URL("redis://" + host + ":" + newPort); - } - } catch (MalformedURLException e) { - throw new IllegalArgumentException(e); - } finally { - restoreURLFactory(); - } - } - -} diff --git a/redisson/src/main/java/org/redisson/spring/support/RedissonDefinitionParser.java b/redisson/src/main/java/org/redisson/spring/support/RedissonDefinitionParser.java index 7beef7354..911574b96 100644 --- a/redisson/src/main/java/org/redisson/spring/support/RedissonDefinitionParser.java +++ b/redisson/src/main/java/org/redisson/spring/support/RedissonDefinitionParser.java @@ -15,10 +15,11 @@ */ package org.redisson.spring.support; +import java.net.URI; import java.util.List; + import org.redisson.Redisson; import org.redisson.config.Config; -import org.redisson.misc.URLBuilder; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.parsing.BeanComponentDefinition; import org.springframework.beans.factory.parsing.CompositeComponentDefinition; @@ -166,7 +167,7 @@ public final class RedissonDefinitionParser && ConfigType.masterSlaveServers.name() .equals(localName)) { try { - value = URLBuilder.create((String) value); + value = URI.create((String) value); } catch (Exception e) { //value may be a placeholder value = "redis://" + value; diff --git a/redisson/src/test/java/org/redisson/RedisClientTest.java b/redisson/src/test/java/org/redisson/RedisClientTest.java index 93bf37600..8192f1a88 100644 --- a/redisson/src/test/java/org/redisson/RedisClientTest.java +++ b/redisson/src/test/java/org/redisson/RedisClientTest.java @@ -20,6 +20,7 @@ import org.junit.BeforeClass; import org.junit.Test; import org.redisson.api.RFuture; import org.redisson.client.RedisClient; +import org.redisson.client.RedisClientConfig; import org.redisson.client.RedisConnection; import org.redisson.client.RedisPubSubConnection; import org.redisson.client.RedisPubSubListener; @@ -36,6 +37,8 @@ import io.netty.util.concurrent.FutureListener; public class RedisClientTest { + private RedisClient redisClient; + @BeforeClass public static void beforeClass() throws IOException, InterruptedException { if (!RedissonRuntimeEnvironment.isTravis) { @@ -55,6 +58,9 @@ public class RedisClientTest { if (RedissonRuntimeEnvironment.isTravis) { RedisRunner.startDefaultRedisServerInstance(); } + RedisClientConfig config = new RedisClientConfig(); + config.setAddress(RedisRunner.getDefaultRedisServerBindAddressAndPort()); + redisClient = RedisClient.create(config); } @After @@ -62,12 +68,12 @@ public class RedisClientTest { if (RedissonRuntimeEnvironment.isTravis) { RedisRunner.shutDownDefaultRedisServerInstance(); } + redisClient.shutdown(); } @Test public void testConnectAsync() throws InterruptedException { - RedisClient c = new RedisClient(RedisRunner.getDefaultRedisServerBindAddressAndPort()); - RFuture f = c.connectAsync(); + RFuture f = redisClient.connectAsync(); final CountDownLatch l = new CountDownLatch(1); f.addListener((FutureListener) future -> { RedisConnection conn = future.get(); @@ -79,8 +85,7 @@ public class RedisClientTest { @Test public void testSubscribe() throws InterruptedException { - RedisClient c = new RedisClient(RedisRunner.getDefaultRedisServerBindAddressAndPort()); - RedisPubSubConnection pubSubConnection = c.connectPubSub(); + RedisPubSubConnection pubSubConnection = redisClient.connectPubSub(); final CountDownLatch latch = new CountDownLatch(2); pubSubConnection.addListener(new RedisPubSubListener() { @@ -107,10 +112,7 @@ public class RedisClientTest { @Test public void test() throws InterruptedException { - RedisClient c = new RedisClient(RedisRunner.getDefaultRedisServerInstance().getRedisServerBindAddress(), - RedisRunner.getDefaultRedisServerInstance().getRedisServerPort(), - 1000000, 1000000); - final RedisConnection conn = c.connect(); + final RedisConnection conn = redisClient.connect(); conn.sync(StringCodec.INSTANCE, RedisCommands.SET, "test", 0); ExecutorService pool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2); @@ -131,8 +133,7 @@ public class RedisClientTest { @Test public void testPipeline() throws InterruptedException, ExecutionException { - RedisClient c = new RedisClient(RedisRunner.getDefaultRedisServerBindAddressAndPort()); - RedisConnection conn = c.connect(); + RedisConnection conn = redisClient.connect(); conn.sync(StringCodec.INSTANCE, RedisCommands.SET, "test", 0); @@ -159,8 +160,7 @@ public class RedisClientTest { @Test public void testBigRequest() throws InterruptedException, ExecutionException { - RedisClient c = new RedisClient(RedisRunner.getDefaultRedisServerBindAddressAndPort()); - RedisConnection conn = c.connect(); + RedisConnection conn = redisClient.connect(); for (int i = 0; i < 50; i++) { conn.sync(StringCodec.INSTANCE, RedisCommands.HSET, "testmap", i, "2"); @@ -174,8 +174,7 @@ public class RedisClientTest { @Test public void testPipelineBigResponse() throws InterruptedException, ExecutionException { - RedisClient c = new RedisClient(RedisRunner.getDefaultRedisServerBindAddressAndPort()); - RedisConnection conn = c.connect(); + RedisConnection conn = redisClient.connect(); List> commands = new ArrayList>(); for (int i = 0; i < 1000; i++) { diff --git a/redisson/src/test/java/org/redisson/RedisRunner.java b/redisson/src/test/java/org/redisson/RedisRunner.java index 6f9190f8d..e57e10246 100644 --- a/redisson/src/test/java/org/redisson/RedisRunner.java +++ b/redisson/src/test/java/org/redisson/RedisRunner.java @@ -19,6 +19,7 @@ import java.util.UUID; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import org.redisson.client.RedisClient; +import org.redisson.client.RedisClientConfig; import org.redisson.client.RedisConnection; import org.redisson.client.protocol.RedisCommands; import org.redisson.client.protocol.RedisStrictCommand; @@ -928,7 +929,9 @@ public class RedisRunner { public RedisClient createRedisClientInstance() { if (redisProcess.isAlive()) { - return new RedisClient(runner.getInitialBindAddr(), runner.getPort()); + RedisClientConfig config = new RedisClientConfig(); + config.setAddress(runner.getInitialBindAddr(), runner.getPort()); + return RedisClient.create(config); } throw new IllegalStateException("Redis server instance is not running."); } @@ -952,7 +955,7 @@ public class RedisRunner { } public String getRedisServerAddressAndPort() { - return getRedisServerBindAddress() + ":" + getRedisServerPort(); + return "redis://" + getRedisServerBindAddress() + ":" + getRedisServerPort(); } public boolean isAlive() { @@ -995,7 +998,7 @@ public class RedisRunner { } public static String getDefaultRedisServerBindAddressAndPort() { - return defaultRedisInstance.getRedisServerBindAddress() + return "redis://" + defaultRedisInstance.getRedisServerBindAddress() + ":" + defaultRedisInstance.getRedisServerPort(); } diff --git a/redisson/src/test/java/org/redisson/RedissonBlockingQueueTest.java b/redisson/src/test/java/org/redisson/RedissonBlockingQueueTest.java index abf7774ca..54e4192ed 100644 --- a/redisson/src/test/java/org/redisson/RedissonBlockingQueueTest.java +++ b/redisson/src/test/java/org/redisson/RedissonBlockingQueueTest.java @@ -65,10 +65,12 @@ public class RedissonBlockingQueueTest extends BaseTest { .nosave() .randomDir() .randomPort() + .requirepass("1234") .run(); Config config = new Config(); - config.useSingleServer().setAddress(runner.getRedisServerAddressAndPort()); + config.useSingleServer().setAddress(runner.getRedisServerAddressAndPort()) + .setPassword("1234"); RedissonClient redisson = Redisson.create(config); final AtomicBoolean executed = new AtomicBoolean(); @@ -97,6 +99,7 @@ public class RedissonBlockingQueueTest extends BaseTest { .port(runner.getRedisServerPort()) .nosave() .randomDir() + .requirepass("1234") .run(); Thread.sleep(1000); @@ -106,7 +109,7 @@ public class RedissonBlockingQueueTest extends BaseTest { t.join(); - await().atMost(5, TimeUnit.SECONDS).until(() -> assertThat(executed.get()).isTrue()); + await().atMost(5, TimeUnit.SECONDS).until(() -> executed.get()); redisson.shutdown(); runner.stop(); diff --git a/redisson/src/test/java/org/redisson/RedissonLocalCachedMapTest.java b/redisson/src/test/java/org/redisson/RedissonLocalCachedMapTest.java index de663a22c..e1379f44d 100644 --- a/redisson/src/test/java/org/redisson/RedissonLocalCachedMapTest.java +++ b/redisson/src/test/java/org/redisson/RedissonLocalCachedMapTest.java @@ -26,21 +26,21 @@ import mockit.Deencapsulation; public class RedissonLocalCachedMapTest extends BaseTest { - // @Test + @Test public void testPerf() { - LocalCachedMapOptions options = LocalCachedMapOptions.defaults().evictionPolicy(EvictionPolicy.LFU).cacheSize(100000).invalidateEntryOnChange(true); + LocalCachedMapOptions options = LocalCachedMapOptions.defaults().evictionPolicy(EvictionPolicy.NONE).cacheSize(100000).invalidateEntryOnChange(true); Map map = redisson.getLocalCachedMap("test", options); // Map map = redisson.getMap("test"); - for (int i = 0; i < 100000; i++) { + for (int i = 0; i < 10000; i++) { map.put("" + i, i); } long s = System.currentTimeMillis(); - for (int i = 0; i < 100; i++) { - for (int j = 0; j < 100000; j++) { + for (int i = 0; i < 10; i++) { + for (int j = 0; j < 10000; j++) { map.get("" + j); } } diff --git a/redisson/src/test/java/org/redisson/RedissonTest.java b/redisson/src/test/java/org/redisson/RedissonTest.java index 2e611e44d..c6be7a759 100644 --- a/redisson/src/test/java/org/redisson/RedissonTest.java +++ b/redisson/src/test/java/org/redisson/RedissonTest.java @@ -351,10 +351,9 @@ public class RedissonTest { @Test public void testClusterConfig() throws IOException { Config originalConfig = new Config(); - originalConfig.useClusterServers().addNodeAddress("123.123.1.23:1902", "9.3.1.0:1902"); + originalConfig.useClusterServers().addNodeAddress("redis://123.123.1.23:1902", "redis://9.3.1.0:1902"); String t = originalConfig.toJSON(); Config c = Config.fromJSON(t); - System.out.println(t); assertThat(c.toJSON()).isEqualTo(t); } @@ -378,7 +377,7 @@ public class RedissonTest { @Test public void testMasterSlaveConfigJSON() throws IOException { Config c2 = new Config(); - c2.useMasterSlaveServers().setMasterAddress("123.1.1.1:1231").addSlaveAddress("82.12.47.12:1028"); + c2.useMasterSlaveServers().setMasterAddress("redis://123.1.1.1:1231").addSlaveAddress("redis://82.12.47.12:1028"); String t = c2.toJSON(); Config c = Config.fromJSON(t); assertThat(c.toJSON()).isEqualTo(t); @@ -387,7 +386,7 @@ public class RedissonTest { @Test public void testMasterSlaveConfigYAML() throws IOException { Config c2 = new Config(); - c2.useMasterSlaveServers().setMasterAddress("123.1.1.1:1231").addSlaveAddress("82.12.47.12:1028"); + c2.useMasterSlaveServers().setMasterAddress("redis://123.1.1.1:1231").addSlaveAddress("redis://82.12.47.12:1028"); String t = c2.toYAML(); Config c = Config.fromYAML(t); assertThat(c.toYAML()).isEqualTo(t); @@ -410,7 +409,7 @@ public class RedissonTest { @Test(expected = RedisConnectionException.class) public void testSingleConnectionFail() throws InterruptedException { Config config = new Config(); - config.useSingleServer().setAddress("127.99.0.1:1111"); + config.useSingleServer().setAddress("redis://127.99.0.1:1111"); Redisson.create(config); Thread.sleep(1500); @@ -419,7 +418,7 @@ public class RedissonTest { @Test(expected = RedisConnectionException.class) public void testClusterConnectionFail() throws InterruptedException { Config config = new Config(); - config.useClusterServers().addNodeAddress("127.99.0.1:1111"); + config.useClusterServers().addNodeAddress("redis://127.99.0.1:1111"); Redisson.create(config); Thread.sleep(1500); @@ -428,7 +427,7 @@ public class RedissonTest { @Test(expected = RedisConnectionException.class) public void testElasticacheConnectionFail() throws InterruptedException { Config config = new Config(); - config.useElasticacheServers().addNodeAddress("127.99.0.1:1111"); + config.useElasticacheServers().addNodeAddress("redis://127.99.0.1:1111"); Redisson.create(config); Thread.sleep(1500); @@ -437,7 +436,7 @@ public class RedissonTest { @Test(expected = RedisConnectionException.class) public void testReplicatedConnectionFail() throws InterruptedException { Config config = new Config(); - config.useReplicatedServers().addNodeAddress("127.99.0.1:1111"); + config.useReplicatedServers().addNodeAddress("redis://127.99.0.1:1111"); Redisson.create(config); Thread.sleep(1500); @@ -446,7 +445,7 @@ public class RedissonTest { @Test(expected = RedisConnectionException.class) public void testMasterSlaveConnectionFail() throws InterruptedException { Config config = new Config(); - config.useMasterSlaveServers().setMasterAddress("127.99.0.1:1111"); + config.useMasterSlaveServers().setMasterAddress("redis://127.99.0.1:1111"); Redisson.create(config); Thread.sleep(1500); @@ -455,7 +454,7 @@ public class RedissonTest { @Test(expected = RedisConnectionException.class) public void testSentinelConnectionFail() throws InterruptedException { Config config = new Config(); - config.useSentinelServers().addSentinelAddress("127.99.0.1:1111"); + config.useSentinelServers().addSentinelAddress("redis://127.99.0.1:1111"); Redisson.create(config); Thread.sleep(1500); From 9a756fb96a25ed7a99cc7b12d4e734c5f6befece Mon Sep 17 00:00:00 2001 From: Nikita Date: Mon, 22 May 2017 18:03:38 +0300 Subject: [PATCH 39/65] getClientName didn't set properly --- .../java/org/redisson/client/handler/BaseConnectionHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/redisson/src/main/java/org/redisson/client/handler/BaseConnectionHandler.java b/redisson/src/main/java/org/redisson/client/handler/BaseConnectionHandler.java index 2fd0953ef..63daa0a71 100644 --- a/redisson/src/main/java/org/redisson/client/handler/BaseConnectionHandler.java +++ b/redisson/src/main/java/org/redisson/client/handler/BaseConnectionHandler.java @@ -73,7 +73,7 @@ public abstract class BaseConnectionHandler extends C futures.add(future); } if (config.getClientName() != null) { - RFuture future = connection.async(RedisCommands.CLIENT_SETNAME, config.getDatabase()); + RFuture future = connection.async(RedisCommands.CLIENT_SETNAME, config.getClientName()); futures.add(future); } if (config.isReadOnly()) { From 946f712931fba6cbd7949747b9e2cc11063cdafc Mon Sep 17 00:00:00 2001 From: Nikita Date: Mon, 22 May 2017 18:19:50 +0300 Subject: [PATCH 40/65] RBlockingQueue.takeLastAndOfferFirstTo method added. #881 --- .../org/redisson/RedissonBlockingDeque.java | 11 +++++++ .../org/redisson/RedissonBlockingQueue.java | 11 +++++++ .../RedissonBoundedBlockingQueue.java | 14 ++++++++- .../java/org/redisson/api/RBlockingQueue.java | 2 ++ .../org/redisson/api/RBlockingQueueAsync.java | 2 ++ .../redisson/RedissonBlockingQueueTest.java | 30 +++++++++++++++++-- .../RedissonBoundedBlockingQueueTest.java | 30 ++++++++++++++++++- 7 files changed, 96 insertions(+), 4 deletions(-) diff --git a/redisson/src/main/java/org/redisson/RedissonBlockingDeque.java b/redisson/src/main/java/org/redisson/RedissonBlockingDeque.java index 5699208b0..b82bb0761 100644 --- a/redisson/src/main/java/org/redisson/RedissonBlockingDeque.java +++ b/redisson/src/main/java/org/redisson/RedissonBlockingDeque.java @@ -123,6 +123,17 @@ public class RedissonBlockingDeque extends RedissonDeque implements RBlock public V pollLastAndOfferFirstTo(String queueName, long timeout, TimeUnit unit) throws InterruptedException { return blockingQueue.pollLastAndOfferFirstTo(queueName, timeout, unit); } + + @Override + public V takeLastAndOfferFirstTo(String queueName) throws InterruptedException { + RFuture res = takeLastAndOfferFirstToAsync(queueName); + return res.await().getNow(); + } + + @Override + public RFuture takeLastAndOfferFirstToAsync(String queueName) { + return pollLastAndOfferFirstToAsync(queueName, 0, TimeUnit.SECONDS); + } @Override public int remainingCapacity() { diff --git a/redisson/src/main/java/org/redisson/RedissonBlockingQueue.java b/redisson/src/main/java/org/redisson/RedissonBlockingQueue.java index 46d8b6e0f..4f518e681 100644 --- a/redisson/src/main/java/org/redisson/RedissonBlockingQueue.java +++ b/redisson/src/main/java/org/redisson/RedissonBlockingQueue.java @@ -133,6 +133,17 @@ public class RedissonBlockingQueue extends RedissonQueue implements RBlock RFuture res = pollLastAndOfferFirstToAsync(queueName, timeout, unit); return res.await().getNow(); } + + @Override + public V takeLastAndOfferFirstTo(String queueName) throws InterruptedException { + RFuture res = takeLastAndOfferFirstToAsync(queueName); + return res.await().getNow(); + } + + @Override + public RFuture takeLastAndOfferFirstToAsync(String queueName) { + return pollLastAndOfferFirstToAsync(queueName, 0, TimeUnit.SECONDS); + } @Override public int remainingCapacity() { diff --git a/redisson/src/main/java/org/redisson/RedissonBoundedBlockingQueue.java b/redisson/src/main/java/org/redisson/RedissonBoundedBlockingQueue.java index f349774aa..ac309c5a9 100644 --- a/redisson/src/main/java/org/redisson/RedissonBoundedBlockingQueue.java +++ b/redisson/src/main/java/org/redisson/RedissonBoundedBlockingQueue.java @@ -33,6 +33,7 @@ import org.redisson.command.CommandExecutor; import org.redisson.connection.decoder.ListDrainToDecoder; import org.redisson.misc.PromiseDelegator; import org.redisson.misc.RPromise; +import org.redisson.misc.RedissonPromise; import org.redisson.pubsub.SemaphorePubSub; import io.netty.util.concurrent.Future; @@ -136,7 +137,7 @@ public class RedissonBoundedBlockingQueue extends RedissonQueue implements } private RPromise wrapTakeFuture(final RFuture takeFuture) { - final RPromise result = new PromiseDelegator(commandExecutor.getConnectionManager().newPromise()) { + final RPromise result = new RedissonPromise() { @Override public boolean cancel(boolean mayInterruptIfRunning) { super.cancel(mayInterruptIfRunning); @@ -253,6 +254,17 @@ public class RedissonBoundedBlockingQueue extends RedissonQueue implements return wrapTakeFuture(takeFuture); } + @Override + public V takeLastAndOfferFirstTo(String queueName) throws InterruptedException { + RFuture res = takeLastAndOfferFirstToAsync(queueName); + return res.await().getNow(); + } + + @Override + public RFuture takeLastAndOfferFirstToAsync(String queueName) { + return pollLastAndOfferFirstToAsync(queueName, 0, TimeUnit.SECONDS); + } + @Override public RFuture pollLastAndOfferFirstToAsync(String queueName, long timeout, TimeUnit unit) { RFuture takeFuture = commandExecutor.writeAsync(getName(), codec, RedisCommands.BRPOPLPUSH, getName(), queueName, unit.toSeconds(timeout)); diff --git a/redisson/src/main/java/org/redisson/api/RBlockingQueue.java b/redisson/src/main/java/org/redisson/api/RBlockingQueue.java index b39c79c5d..d259c316a 100644 --- a/redisson/src/main/java/org/redisson/api/RBlockingQueue.java +++ b/redisson/src/main/java/org/redisson/api/RBlockingQueue.java @@ -43,5 +43,7 @@ public interface RBlockingQueue extends BlockingQueue, RQueue, RBlockin V pollFromAny(long timeout, TimeUnit unit, String ... queueNames) throws InterruptedException; V pollLastAndOfferFirstTo(String queueName, long timeout, TimeUnit unit) throws InterruptedException; + + V takeLastAndOfferFirstTo(String queueName) throws InterruptedException; } diff --git a/redisson/src/main/java/org/redisson/api/RBlockingQueueAsync.java b/redisson/src/main/java/org/redisson/api/RBlockingQueueAsync.java index d52047bce..3e09054e6 100644 --- a/redisson/src/main/java/org/redisson/api/RBlockingQueueAsync.java +++ b/redisson/src/main/java/org/redisson/api/RBlockingQueueAsync.java @@ -93,6 +93,8 @@ public interface RBlockingQueueAsync extends RQueueAsync { RFuture drainToAsync(Collection c); RFuture pollLastAndOfferFirstToAsync(String queueName, long timeout, TimeUnit unit); + + RFuture takeLastAndOfferFirstToAsync(String queueName); /** * Retrieves and removes the head of this queue in async mode, waiting up to the diff --git a/redisson/src/test/java/org/redisson/RedissonBlockingQueueTest.java b/redisson/src/test/java/org/redisson/RedissonBlockingQueueTest.java index 54e4192ed..4dab4f004 100644 --- a/redisson/src/test/java/org/redisson/RedissonBlockingQueueTest.java +++ b/redisson/src/test/java/org/redisson/RedissonBlockingQueueTest.java @@ -296,16 +296,42 @@ public class RedissonBlockingQueueTest extends BaseTest { // TODO Auto-generated catch block e.printStackTrace(); } - }, 10, TimeUnit.SECONDS); + }, 5, TimeUnit.SECONDS); RBlockingQueue queue2 = redisson.getBlockingQueue("{queue}2"); queue2.put(4); queue2.put(5); queue2.put(6); - queue1.pollLastAndOfferFirstTo(queue2.getName(), 10, TimeUnit.SECONDS); + Integer value = queue1.pollLastAndOfferFirstTo(queue2.getName(), 5, TimeUnit.SECONDS); + assertThat(value).isEqualTo(3); assertThat(queue2).containsExactly(3, 4, 5, 6); } + + @Test + public void testTakeLastAndOfferFirstTo() throws InterruptedException { + final RBlockingQueue queue1 = redisson.getBlockingQueue("{queue}1"); + Executors.newSingleThreadScheduledExecutor().schedule(() -> { + try { + queue1.put(3); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + }, 3, TimeUnit.SECONDS); + + RBlockingQueue queue2 = redisson.getBlockingQueue("{queue}2"); + queue2.put(4); + queue2.put(5); + queue2.put(6); + + long startTime = System.currentTimeMillis(); + Integer value = queue1.takeLastAndOfferFirstTo(queue2.getName()); + assertThat(System.currentTimeMillis() - startTime).isBetween(2900L, 3200L); + assertThat(value).isEqualTo(3); + assertThat(queue2).containsExactly(3, 4, 5, 6); + } + @Test public void testAddOfferOrigin() { diff --git a/redisson/src/test/java/org/redisson/RedissonBoundedBlockingQueueTest.java b/redisson/src/test/java/org/redisson/RedissonBoundedBlockingQueueTest.java index 2e9cab970..3d533f5d4 100644 --- a/redisson/src/test/java/org/redisson/RedissonBoundedBlockingQueueTest.java +++ b/redisson/src/test/java/org/redisson/RedissonBoundedBlockingQueueTest.java @@ -509,10 +509,38 @@ public class RedissonBoundedBlockingQueueTest extends BaseTest { queue2.put(5); queue2.put(6); - queue1.pollLastAndOfferFirstTo(queue2.getName(), 10, TimeUnit.SECONDS); + Integer value = queue1.pollLastAndOfferFirstTo(queue2.getName(), 10, TimeUnit.SECONDS); + assertThat(value).isEqualTo(3); assertThat(queue2).containsExactly(3, 4, 5, 6); } + @Test + public void testTakeLastAndOfferFirstTo() throws InterruptedException { + final RBoundedBlockingQueue queue1 = redisson.getBoundedBlockingQueue("{queue}1"); + queue1.trySetCapacity(10); + Executors.newSingleThreadScheduledExecutor().schedule(() -> { + try { + queue1.put(3); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + }, 3, TimeUnit.SECONDS); + + RBoundedBlockingQueue queue2 = redisson.getBoundedBlockingQueue("{queue}2"); + queue2.trySetCapacity(10); + queue2.put(4); + queue2.put(5); + queue2.put(6); + + long startTime = System.currentTimeMillis(); + Integer value = queue1.takeLastAndOfferFirstTo(queue2.getName()); + assertThat(System.currentTimeMillis() - startTime).isBetween(3000L, 3200L); + assertThat(value).isEqualTo(3); + assertThat(queue2).containsExactly(3, 4, 5, 6); + } + + @Test public void testOffer() { RBoundedBlockingQueue queue = redisson.getBoundedBlockingQueue("blocking:queue"); From 4f5044995c72fad53e4c9761fe5c4b3fcd8039b5 Mon Sep 17 00:00:00 2001 From: Nikita Date: Tue, 23 May 2017 11:44:41 +0300 Subject: [PATCH 41/65] infinite scan fixed. #885 --- .../java/org/redisson/RedissonBaseIterator.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/redisson/src/main/java/org/redisson/RedissonBaseIterator.java b/redisson/src/main/java/org/redisson/RedissonBaseIterator.java index fc9151f8d..bccbd0f32 100644 --- a/redisson/src/main/java/org/redisson/RedissonBaseIterator.java +++ b/redisson/src/main/java/org/redisson/RedissonBaseIterator.java @@ -101,6 +101,7 @@ abstract class RedissonBaseIterator implements Iterator { currentElementRemoved = false; removeExecuted = false; + client = null; firstValues = null; lastValues = null; @@ -111,6 +112,19 @@ abstract class RedissonBaseIterator implements Iterator { } finished = true; return false; + } else if (!firstValues.isEmpty()) { + if (res.getPos() == 0) { + if (tryAgain()) { + client = null; + firstValues = null; + nextIterPos = 0; + prevIterPos = -1; + continue; + } + + finished = true; + return false; + } } } lastIter = res.getValues().iterator(); From 89689b44739cb92ff65917b6391cac6fdffe4cc7 Mon Sep 17 00:00:00 2001 From: Nikita Date: Tue, 23 May 2017 11:59:48 +0300 Subject: [PATCH 42/65] Yet another infinite scan fix. #885 --- .../org/redisson/RedissonBaseIterator.java | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/redisson/src/main/java/org/redisson/RedissonBaseIterator.java b/redisson/src/main/java/org/redisson/RedissonBaseIterator.java index bccbd0f32..9faa1d2b2 100644 --- a/redisson/src/main/java/org/redisson/RedissonBaseIterator.java +++ b/redisson/src/main/java/org/redisson/RedissonBaseIterator.java @@ -26,6 +26,12 @@ import org.redisson.client.protocol.decoder.ScanObjectEntry; import io.netty.buffer.ByteBuf; +/** + * + * @author Nikita Koksharov + * + * @param value type + */ abstract class RedissonBaseIterator implements Iterator { private List firstValues; @@ -112,19 +118,17 @@ abstract class RedissonBaseIterator implements Iterator { } finished = true; return false; - } else if (!firstValues.isEmpty()) { - if (res.getPos() == 0) { - if (tryAgain()) { - client = null; - firstValues = null; - nextIterPos = 0; - prevIterPos = -1; - continue; - } - - finished = true; - return false; + } else if (lastValues.isEmpty() && res.getPos() == 0) { + if (tryAgain()) { + client = null; + firstValues = null; + nextIterPos = 0; + prevIterPos = -1; + continue; } + + finished = true; + return false; } } lastIter = res.getValues().iterator(); From 51fc7ad6c0b905625655876e513a56a4e8796adb Mon Sep 17 00:00:00 2001 From: Nikita Date: Tue, 23 May 2017 12:51:17 +0300 Subject: [PATCH 43/65] underscore support for Uri object --- .../org/redisson/config/ConfigSupport.java | 42 +++++++++++++++++++ .../connection/SentinelConnectionManager.java | 19 ++++++--- 2 files changed, 55 insertions(+), 6 deletions(-) diff --git a/redisson/src/main/java/org/redisson/config/ConfigSupport.java b/redisson/src/main/java/org/redisson/config/ConfigSupport.java index 05a8cddbe..8a7cf8677 100644 --- a/redisson/src/main/java/org/redisson/config/ConfigSupport.java +++ b/redisson/src/main/java/org/redisson/config/ConfigSupport.java @@ -19,6 +19,9 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.Reader; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.net.URI; import java.net.URL; import java.util.List; @@ -121,62 +124,101 @@ public class ConfigSupport { private ObjectMapper jsonMapper = createMapper(null, null); private ObjectMapper yamlMapper = createMapper(new YAMLFactory(), null); + private void patchUriObject() throws IOException { + patchUriField("lowMask", "L_DASH"); + patchUriField("highMask", "H_DASH"); + } + + private void patchUriField(String methodName, String fieldName) + throws IOException { + try { + Method lowMask = URI.class.getDeclaredMethod(methodName, String.class); + lowMask.setAccessible(true); + long lowMaskValue = (long) lowMask.invoke(null, "-_"); + + Field lowDash = URI.class.getDeclaredField(fieldName); + + Field modifiers = Field.class.getDeclaredField("modifiers"); + modifiers.setAccessible(true); + modifiers.setInt(lowDash, lowDash.getModifiers() & ~Modifier.FINAL); + + lowDash.setAccessible(true); + lowDash.setLong(null, lowMaskValue); + } catch (Exception e) { + throw new IOException(e); + } + } + public T fromJSON(String content, Class configType) throws IOException { + patchUriObject(); return jsonMapper.readValue(content, configType); } public T fromJSON(File file, Class configType) throws IOException { + patchUriObject(); return fromJSON(file, configType, null); } public T fromJSON(File file, Class configType, ClassLoader classLoader) throws IOException { + patchUriObject(); jsonMapper = createMapper(null, classLoader); return jsonMapper.readValue(file, configType); } public T fromJSON(URL url, Class configType) throws IOException { + patchUriObject(); return jsonMapper.readValue(url, configType); } public T fromJSON(Reader reader, Class configType) throws IOException { + patchUriObject(); return jsonMapper.readValue(reader, configType); } public T fromJSON(InputStream inputStream, Class configType) throws IOException { + patchUriObject(); return jsonMapper.readValue(inputStream, configType); } public String toJSON(Config config) throws IOException { + patchUriObject(); return jsonMapper.writeValueAsString(config); } public T fromYAML(String content, Class configType) throws IOException { + patchUriObject(); return yamlMapper.readValue(content, configType); } public T fromYAML(File file, Class configType) throws IOException { + patchUriObject(); return yamlMapper.readValue(file, configType); } public T fromYAML(File file, Class configType, ClassLoader classLoader) throws IOException { + patchUriObject(); yamlMapper = createMapper(new YAMLFactory(), classLoader); return yamlMapper.readValue(file, configType); } public T fromYAML(URL url, Class configType) throws IOException { + patchUriObject(); return yamlMapper.readValue(url, configType); } public T fromYAML(Reader reader, Class configType) throws IOException { + patchUriObject(); return yamlMapper.readValue(reader, configType); } public T fromYAML(InputStream inputStream, Class configType) throws IOException { + patchUriObject(); return yamlMapper.readValue(inputStream, configType); } public String toYAML(Config config) throws IOException { + patchUriObject(); return yamlMapper.writeValueAsString(config); } diff --git a/redisson/src/main/java/org/redisson/connection/SentinelConnectionManager.java b/redisson/src/main/java/org/redisson/connection/SentinelConnectionManager.java index 261041b9c..2cbb7e64e 100755 --- a/redisson/src/main/java/org/redisson/connection/SentinelConnectionManager.java +++ b/redisson/src/main/java/org/redisson/connection/SentinelConnectionManager.java @@ -80,7 +80,7 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager { // TODO async List master = connection.sync(RedisCommands.SENTINEL_GET_MASTER_ADDR_BY_NAME, cfg.getMasterName()); - String masterHost = "redis://" + master.get(0) + ":" + master.get(1); + String masterHost = createAddress(master.get(0), master.get(1)); this.config.setMasterAddress(masterHost); currentMaster.set(masterHost); log.info("master: {} added", masterHost); @@ -96,7 +96,7 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager { String port = map.get("port"); String flags = map.get("flags"); - String host = "redis://" + ip + ":" + port; + String host = createAddress(ip, port); this.config.addSlaveAddress(host); slaves.put(host, true); @@ -132,6 +132,13 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager { future.awaitUninterruptibly(); } } + + private String createAddress(String host, Object port) { + if (host.contains(":")) { + host = "[" + host + "]"; + } + return "redis://" + host + ":" + port; + } @Override protected MasterSlaveEntry createMasterSlaveEntry(MasterSlaveServersConfig config, @@ -207,7 +214,7 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager { String ip = parts[2]; String port = parts[3]; - String addr = "redis://" + ip + ":" + port; + String addr = createAddress(ip, port); URI uri = URI.create(addr); registerSentinel(cfg, uri, c); } @@ -221,7 +228,7 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager { final String ip = parts[2]; final String port = parts[3]; - final String slaveAddr = "redis://" + ip + ":" + port; + final String slaveAddr = createAddress(ip, port); if (!isUseSameMaster(parts)) { return; @@ -309,7 +316,7 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager { String slaveAddr = ip + ":" + port; String master = currentMaster.get(); - String slaveMaster = "redis://" + parts[6] + ":" + parts[7]; + String slaveMaster = createAddress(parts[6], parts[7]); if (!master.equals(slaveMaster)) { log.warn("Skipped slave up {} for master {} differs from current {}", slaveAddr, slaveMaster, master); return false; @@ -369,7 +376,7 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager { String port = parts[4]; String current = currentMaster.get(); - String newMaster = "redis://" + ip + ":" + port; + String newMaster = createAddress(ip, port); if (!newMaster.equals(current) && currentMaster.compareAndSet(current, newMaster)) { changeMaster(singleSlotRange.getStartSlot(), URI.create(newMaster)); From 15b18abe74330112133031d2a1d48defb979966c Mon Sep 17 00:00:00 2001 From: Nikita Date: Wed, 24 May 2017 16:25:03 +0300 Subject: [PATCH 44/65] RScoredSortedSet.firstScore, lastScore methods added. #811 --- .../org/redisson/RedissonScoredSortedSet.java | 21 ++++++++ .../org/redisson/api/RScoredSortedSet.java | 4 ++ .../redisson/api/RScoredSortedSetAsync.java | 4 ++ .../client/protocol/RedisCommands.java | 3 +- .../ObjectFirstScoreReplayDecoder.java | 49 +++++++++++++++++++ .../redisson/RedissonScoredSortedSetTest.java | 11 +++++ 6 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 redisson/src/main/java/org/redisson/client/protocol/decoder/ObjectFirstScoreReplayDecoder.java diff --git a/redisson/src/main/java/org/redisson/RedissonScoredSortedSet.java b/redisson/src/main/java/org/redisson/RedissonScoredSortedSet.java index 7bf4a1521..01a6cc955 100644 --- a/redisson/src/main/java/org/redisson/RedissonScoredSortedSet.java +++ b/redisson/src/main/java/org/redisson/RedissonScoredSortedSet.java @@ -143,6 +143,27 @@ public class RedissonScoredSortedSet extends RedissonExpirable implements RSc public RFuture lastAsync() { return commandExecutor.readAsync(getName(), codec, RedisCommands.ZRANGE_SINGLE, getName(), -1, -1); } + + @Override + public Double firstScore() { + return get(firstScoreAsync()); + } + + @Override + public RFuture firstScoreAsync() { + return commandExecutor.readAsync(getName(), codec, RedisCommands.ZRANGE_SINGLE_SCORE, getName(), 0, 0, "WITHSCORES"); + } + + @Override + public Double lastScore() { + return get(lastScoreAsync()); + } + + @Override + public RFuture lastScoreAsync() { + return commandExecutor.readAsync(getName(), codec, RedisCommands.ZRANGE_SINGLE_SCORE, getName(), -1, -1, "WITHSCORES"); + } + @Override public RFuture addAsync(double score, V object) { diff --git a/redisson/src/main/java/org/redisson/api/RScoredSortedSet.java b/redisson/src/main/java/org/redisson/api/RScoredSortedSet.java index 72b548972..869ab8dcb 100644 --- a/redisson/src/main/java/org/redisson/api/RScoredSortedSet.java +++ b/redisson/src/main/java/org/redisson/api/RScoredSortedSet.java @@ -52,6 +52,10 @@ public interface RScoredSortedSet extends RScoredSortedSetAsync, Iterable< V first(); V last(); + + Double firstScore(); + + Double lastScore(); Long addAll(Map objects); diff --git a/redisson/src/main/java/org/redisson/api/RScoredSortedSetAsync.java b/redisson/src/main/java/org/redisson/api/RScoredSortedSetAsync.java index 25bcfe5e4..2a98c42d0 100644 --- a/redisson/src/main/java/org/redisson/api/RScoredSortedSetAsync.java +++ b/redisson/src/main/java/org/redisson/api/RScoredSortedSetAsync.java @@ -37,6 +37,10 @@ public interface RScoredSortedSetAsync extends RExpirableAsync, RSortableAsyn RFuture firstAsync(); RFuture lastAsync(); + + RFuture firstScoreAsync(); + + RFuture lastScoreAsync(); RFuture addAllAsync(Map objects); diff --git a/redisson/src/main/java/org/redisson/client/protocol/RedisCommands.java b/redisson/src/main/java/org/redisson/client/protocol/RedisCommands.java index a91c4dda6..b46ded991 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/RedisCommands.java +++ b/redisson/src/main/java/org/redisson/client/protocol/RedisCommands.java @@ -46,11 +46,11 @@ import org.redisson.client.protocol.decoder.ListResultReplayDecoder; import org.redisson.client.protocol.decoder.ListScanResult; import org.redisson.client.protocol.decoder.ListScanResultReplayDecoder; import org.redisson.client.protocol.decoder.Long2MultiDecoder; -import org.redisson.client.protocol.decoder.LongMultiDecoder; import org.redisson.client.protocol.decoder.MapScanResult; import org.redisson.client.protocol.decoder.MapScanResultReplayDecoder; import org.redisson.client.protocol.decoder.NestedMultiDecoder; import org.redisson.client.protocol.decoder.ObjectFirstResultReplayDecoder; +import org.redisson.client.protocol.decoder.ObjectFirstScoreReplayDecoder; import org.redisson.client.protocol.decoder.ObjectListReplayDecoder; import org.redisson.client.protocol.decoder.ObjectMapEntryReplayDecoder; import org.redisson.client.protocol.decoder.ObjectMapReplayDecoder; @@ -115,6 +115,7 @@ public interface RedisCommands { RedisCommand ZREVRANK_INT = new RedisCommand("ZREVRANK", new IntegerReplayConvertor(), 2); RedisStrictCommand ZRANK = new RedisStrictCommand("ZRANK", 2); RedisCommand ZRANGE_SINGLE = new RedisCommand("ZRANGE", new ObjectFirstResultReplayDecoder()); + RedisStrictCommand ZRANGE_SINGLE_SCORE = new RedisStrictCommand("ZRANGE", new ObjectFirstScoreReplayDecoder()); RedisCommand> ZRANGE = new RedisCommand>("ZRANGE", new ObjectListReplayDecoder()); RedisStrictCommand ZREMRANGEBYRANK = new RedisStrictCommand("ZREMRANGEBYRANK", new IntegerReplayConvertor()); RedisStrictCommand ZREMRANGEBYSCORE = new RedisStrictCommand("ZREMRANGEBYSCORE", new IntegerReplayConvertor()); diff --git a/redisson/src/main/java/org/redisson/client/protocol/decoder/ObjectFirstScoreReplayDecoder.java b/redisson/src/main/java/org/redisson/client/protocol/decoder/ObjectFirstScoreReplayDecoder.java new file mode 100644 index 000000000..19a0bf0c5 --- /dev/null +++ b/redisson/src/main/java/org/redisson/client/protocol/decoder/ObjectFirstScoreReplayDecoder.java @@ -0,0 +1,49 @@ +/** + * Copyright 2016 Nikita Koksharov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.redisson.client.protocol.decoder; + +import java.math.BigDecimal; +import java.util.List; + +import org.redisson.client.handler.State; + +import io.netty.buffer.ByteBuf; +import io.netty.util.CharsetUtil; + +/** + * + * @author Nikita Koksharov + * + * + */ +public class ObjectFirstScoreReplayDecoder implements MultiDecoder { + + @Override + public Object decode(ByteBuf buf, State state) { + return new BigDecimal(buf.toString(CharsetUtil.UTF_8)).doubleValue(); + } + + @Override + public Double decode(List parts, State state) { + return (Double) parts.get(1); + } + + @Override + public boolean isApplicable(int paramNum, State state) { + return paramNum % 2 != 0; + } + +} diff --git a/redisson/src/test/java/org/redisson/RedissonScoredSortedSetTest.java b/redisson/src/test/java/org/redisson/RedissonScoredSortedSetTest.java index cf7d0d3c6..e90447e83 100644 --- a/redisson/src/test/java/org/redisson/RedissonScoredSortedSetTest.java +++ b/redisson/src/test/java/org/redisson/RedissonScoredSortedSetTest.java @@ -274,7 +274,18 @@ public class RedissonScoredSortedSetTest extends BaseTest { Assert.assertEquals("a", set.first()); Assert.assertEquals("d", set.last()); } + + @Test + public void testFirstLastScore() { + RScoredSortedSet set = redisson.getScoredSortedSet("simple"); + set.add(0.1, "a"); + set.add(0.2, "b"); + set.add(0.3, "c"); + set.add(0.4, "d"); + assertThat(set.firstScore()).isEqualTo(0.1); + assertThat(set.lastScore()).isEqualTo(0.4); + } @Test public void testRemoveRangeByScore() { From ac1d075cd8b7588c888a3234a272b8dbe39a90e7 Mon Sep 17 00:00:00 2001 From: Himanshu Kansal Date: Wed, 24 May 2017 22:21:57 +0530 Subject: [PATCH 45/65] using scan command in delete by pattern --- .../main/java/org/redisson/RedissonKeys.java | 30 ++++++------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/redisson/src/main/java/org/redisson/RedissonKeys.java b/redisson/src/main/java/org/redisson/RedissonKeys.java index 863a787d2..c4517c39c 100644 --- a/redisson/src/main/java/org/redisson/RedissonKeys.java +++ b/redisson/src/main/java/org/redisson/RedissonKeys.java @@ -230,27 +230,15 @@ public class RedissonKeys implements RKeys { }; for (MasterSlaveEntry entry : entries) { - RFuture> findFuture = commandExecutor.readAsync(entry, null, RedisCommands.KEYS, pattern); - findFuture.addListener(new FutureListener>() { - @Override - public void operationComplete(Future> future) throws Exception { - if (!future.isSuccess()) { - failed.set(future.cause()); - checkExecution(result, failed, count, executed); - return; - } - - Collection keys = future.getNow(); - if (keys.isEmpty()) { - checkExecution(result, failed, count, executed); - return; - } - - RFuture deleteFuture = deleteAsync(keys.toArray(new String[keys.size()])); - deleteFuture.addListener(listener); - } - }); - } + Iterator keysIterator = createKeysIterator(entry, pattern, 10); + Collection keys = new HashSet(); + while (keysIterator.hasNext()) { + String key = keysIterator.next(); + keys.add(key); + } + RFuture deleteFuture = deleteAsync(keys.toArray(new String[keys.size()])); + deleteFuture.addListener(listener); + } return result; } From f2d1b9d8e5c4af16000fdcc5c77b4e79405fcd66 Mon Sep 17 00:00:00 2001 From: Nikita Date: Thu, 25 May 2017 16:43:18 +0300 Subject: [PATCH 46/65] null values checking in RDelayedQueue object fixed --- .../src/main/java/org/redisson/RedissonDelayedQueue.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/redisson/src/main/java/org/redisson/RedissonDelayedQueue.java b/redisson/src/main/java/org/redisson/RedissonDelayedQueue.java index cc1c8f684..e545ba1bc 100644 --- a/redisson/src/main/java/org/redisson/RedissonDelayedQueue.java +++ b/redisson/src/main/java/org/redisson/RedissonDelayedQueue.java @@ -25,7 +25,6 @@ import java.util.concurrent.TimeUnit; import org.redisson.api.RDelayedQueue; import org.redisson.api.RFuture; -import org.redisson.api.RQueue; import org.redisson.api.RTopic; import org.redisson.client.codec.Codec; import org.redisson.client.codec.LongCodec; @@ -417,7 +416,7 @@ public class RedissonDelayedQueue extends RedissonExpirable implements RDelay public RFuture peekAsync() { return commandExecutor.evalReadAsync(getName(), codec, RedisCommands.EVAL_OBJECT, "local v = redis.call('lindex', KEYS[1], 0); " - + "if v ~= nil then " + + "if v ~= false then " + "local randomId, value = struct.unpack('dLc0', v);" + "return value; " + "end " @@ -429,7 +428,7 @@ public class RedissonDelayedQueue extends RedissonExpirable implements RDelay public RFuture pollAsync() { return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_OBJECT, "local v = redis.call('lpop', KEYS[1]); " - + "if v ~= nil then " + + "if v ~= false then " + "redis.call('zrem', KEYS[2], v); " + "local randomId, value = struct.unpack('dLc0', v);" + "return value; " @@ -447,7 +446,7 @@ public class RedissonDelayedQueue extends RedissonExpirable implements RDelay public RFuture pollLastAndOfferFirstToAsync(String queueName) { return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_OBJECT, "local v = redis.call('rpop', KEYS[1]); " - + "if v ~= nil then " + + "if v ~= false then " + "redis.call('zrem', KEYS[2], v); " + "local randomId, value = struct.unpack('dLc0', v);" + "redis.call('lpush', KEYS[3], value); " From 4ef3d60ac7faef3e0e241eb6a0b932fa0fe3d4b9 Mon Sep 17 00:00:00 2001 From: Nikita Date: Thu, 25 May 2017 17:05:51 +0300 Subject: [PATCH 47/65] Compilation fixed --- redisson/src/main/java/org/redisson/RedissonKeys.java | 1 + 1 file changed, 1 insertion(+) diff --git a/redisson/src/main/java/org/redisson/RedissonKeys.java b/redisson/src/main/java/org/redisson/RedissonKeys.java index c4517c39c..8cc9d8e1d 100644 --- a/redisson/src/main/java/org/redisson/RedissonKeys.java +++ b/redisson/src/main/java/org/redisson/RedissonKeys.java @@ -20,6 +20,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; From 803fc814e88ec99e4726e0fa100534271927742a Mon Sep 17 00:00:00 2001 From: Nikita Date: Fri, 26 May 2017 12:01:08 +0300 Subject: [PATCH 48/65] Iterator infinite scan bug fixed #885 --- .../org/redisson/RedissonBaseIterator.java | 30 +++---------- .../org/redisson/RedissonBaseMapIterator.java | 32 ++++++++------ .../java/org/redisson/RedissonKeysTest.java | 1 + .../test/java/org/redisson/RedissonTest.java | 43 ++++++++++++++++++- 4 files changed, 66 insertions(+), 40 deletions(-) diff --git a/redisson/src/main/java/org/redisson/RedissonBaseIterator.java b/redisson/src/main/java/org/redisson/RedissonBaseIterator.java index 9faa1d2b2..4410270cf 100644 --- a/redisson/src/main/java/org/redisson/RedissonBaseIterator.java +++ b/redisson/src/main/java/org/redisson/RedissonBaseIterator.java @@ -42,7 +42,6 @@ abstract class RedissonBaseIterator implements Iterator { private boolean finished; private boolean currentElementRemoved; - private boolean removeExecuted; private V value; @Override @@ -53,7 +52,6 @@ abstract class RedissonBaseIterator implements Iterator { free(lastValues); currentElementRemoved = false; - removeExecuted = false; client = null; firstValues = null; lastValues = null; @@ -64,9 +62,7 @@ abstract class RedissonBaseIterator implements Iterator { } finished = false; } - long prevIterPos; do { - prevIterPos = nextIterPos; ListScanResult res = iterator(client, nextIterPos); if (lastValues != null) { free(lastValues); @@ -82,7 +78,6 @@ abstract class RedissonBaseIterator implements Iterator { client = null; firstValues = null; nextIterPos = 0; - prevIterPos = -1; } } else { if (firstValues.isEmpty()) { @@ -93,39 +88,30 @@ abstract class RedissonBaseIterator implements Iterator { client = null; firstValues = null; nextIterPos = 0; - prevIterPos = -1; continue; } if (res.getPos() == 0) { + free(firstValues); + free(lastValues); + finished = true; return false; } } - } else if (lastValues.removeAll(firstValues)) { + } else if (lastValues.removeAll(firstValues) + || (lastValues.isEmpty() && nextIterPos == 0)) { free(firstValues); free(lastValues); currentElementRemoved = false; - removeExecuted = false; client = null; firstValues = null; lastValues = null; nextIterPos = 0; - prevIterPos = -1; if (tryAgain()) { continue; } - finished = true; - return false; - } else if (lastValues.isEmpty() && res.getPos() == 0) { - if (tryAgain()) { - client = null; - firstValues = null; - nextIterPos = 0; - prevIterPos = -1; - continue; - } finished = true; return false; @@ -133,10 +119,7 @@ abstract class RedissonBaseIterator implements Iterator { } lastIter = res.getValues().iterator(); nextIterPos = res.getPos(); - } while (!lastIter.hasNext() && nextIterPos != prevIterPos); - if (prevIterPos == nextIterPos && !removeExecuted) { - finished = true; - } + } while (!lastIter.hasNext()); } return lastIter.hasNext(); } @@ -188,7 +171,6 @@ abstract class RedissonBaseIterator implements Iterator { lastIter.remove(); remove(value); currentElementRemoved = true; - removeExecuted = true; } abstract void remove(V value); diff --git a/redisson/src/main/java/org/redisson/RedissonBaseMapIterator.java b/redisson/src/main/java/org/redisson/RedissonBaseMapIterator.java index f2924e205..de2363299 100644 --- a/redisson/src/main/java/org/redisson/RedissonBaseMapIterator.java +++ b/redisson/src/main/java/org/redisson/RedissonBaseMapIterator.java @@ -28,6 +28,14 @@ import org.redisson.client.protocol.decoder.ScanObjectEntry; import io.netty.buffer.ByteBuf; +/** + * + * @author Nikita Koksharov + * + * @param key type + * @param value type + * @param loaded value type + */ public abstract class RedissonBaseMapIterator implements Iterator { private Map firstValues; @@ -38,7 +46,6 @@ public abstract class RedissonBaseMapIterator implements Iterator { private boolean finished; private boolean currentElementRemoved; - private boolean removeExecuted; protected Map.Entry entry; @Override @@ -49,7 +56,6 @@ public abstract class RedissonBaseMapIterator implements Iterator { free(lastValues); currentElementRemoved = false; - removeExecuted = false; client = null; firstValues = null; lastValues = null; @@ -60,15 +66,15 @@ public abstract class RedissonBaseMapIterator implements Iterator { } finished = false; } - long prevIterPos; do { - prevIterPos = nextIterPos; MapScanResult res = iterator(); if (lastValues != null) { free(lastValues); } + lastValues = convert(res.getMap()); client = res.getRedisClient(); + if (nextIterPos == 0 && firstValues == null) { firstValues = lastValues; lastValues = null; @@ -76,7 +82,6 @@ public abstract class RedissonBaseMapIterator implements Iterator { client = null; firstValues = null; nextIterPos = 0; - prevIterPos = -1; } } else { if (firstValues.isEmpty()) { @@ -87,38 +92,38 @@ public abstract class RedissonBaseMapIterator implements Iterator { client = null; firstValues = null; nextIterPos = 0; - prevIterPos = -1; continue; } if (res.getPos() == 0) { + free(firstValues); + free(lastValues); + finished = true; return false; } } - } else if (lastValues.keySet().removeAll(firstValues.keySet())) { + } else if (lastValues.keySet().removeAll(firstValues.keySet()) + || (lastValues.isEmpty() && nextIterPos == 0)) { free(firstValues); free(lastValues); currentElementRemoved = false; - removeExecuted = false; + client = null; firstValues = null; lastValues = null; nextIterPos = 0; - prevIterPos = -1; if (tryAgain()) { continue; } + finished = true; return false; } } lastIter = res.getMap().entrySet().iterator(); nextIterPos = res.getPos(); - } while (!lastIter.hasNext() && nextIterPos != prevIterPos); - if (prevIterPos == nextIterPos && !removeExecuted) { - finished = true; - } + } while (!lastIter.hasNext()); } return lastIter.hasNext(); @@ -184,7 +189,6 @@ public abstract class RedissonBaseMapIterator implements Iterator { lastIter.remove(); removeKey(); currentElementRemoved = true; - removeExecuted = true; entry = null; } diff --git a/redisson/src/test/java/org/redisson/RedissonKeysTest.java b/redisson/src/test/java/org/redisson/RedissonKeysTest.java index c19d167c5..6c13be4d2 100644 --- a/redisson/src/test/java/org/redisson/RedissonKeysTest.java +++ b/redisson/src/test/java/org/redisson/RedissonKeysTest.java @@ -66,6 +66,7 @@ public class RedissonKeysTest extends BaseTest { for (int i = 0; i < 115; i++) { String key = "key" + Math.random(); RBucket bucket = redisson.getBucket(key); + keys.add(key); bucket.set("someValue"); } diff --git a/redisson/src/test/java/org/redisson/RedissonTest.java b/redisson/src/test/java/org/redisson/RedissonTest.java index c6be7a759..38843b04a 100644 --- a/redisson/src/test/java/org/redisson/RedissonTest.java +++ b/redisson/src/test/java/org/redisson/RedissonTest.java @@ -6,6 +6,7 @@ import static org.redisson.BaseTest.createInstance; import java.io.IOException; import java.net.InetSocketAddress; +import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.Map; @@ -33,10 +34,13 @@ import org.redisson.client.RedisConnectionException; import org.redisson.client.RedisException; import org.redisson.client.RedisOutOfMemoryException; import org.redisson.client.protocol.decoder.ListScanResult; +import org.redisson.client.protocol.decoder.ScanObjectEntry; import org.redisson.codec.SerializationCodec; import org.redisson.config.Config; import org.redisson.connection.ConnectionListener; +import io.netty.buffer.Unpooled; + public class RedissonTest { protected RedissonClient redisson; @@ -76,7 +80,7 @@ public class RedissonTest { } @Test - public void testIterator() { + public void testIteratorNotLooped() { RedissonBaseIterator iter = new RedissonBaseIterator() { int i; @Override @@ -101,6 +105,41 @@ public class RedissonTest { Assert.assertFalse(iter.hasNext()); } + @Test + public void testIteratorNotLooped2() { + RedissonBaseIterator iter = new RedissonBaseIterator() { + int i; + @Override + ListScanResult iterator(InetSocketAddress client, long nextIterPos) { + i++; + if (i == 1) { + return new ListScanResult(14L, Arrays.asList(new ScanObjectEntry(Unpooled.wrappedBuffer(new byte[] {1}), 1))); + } + if (i == 2) { + return new ListScanResult(7L, Collections.emptyList()); + } + if (i == 3) { + return new ListScanResult(0L, Collections.emptyList()); + } + if (i == 4) { + return new ListScanResult(14L, Collections.emptyList()); + } + Assert.fail(); + return null; + } + + @Override + void remove(Integer value) { + } + + }; + + Assert.assertTrue(iter.hasNext()); + assertThat(iter.next()).isEqualTo(1); + Assert.assertFalse(iter.hasNext()); + } + + @BeforeClass public static void beforeClass() throws IOException, InterruptedException { if (!RedissonRuntimeEnvironment.isTravis) { @@ -250,7 +289,7 @@ public class RedissonTest { Assert.assertEquals(0, pp.stop()); - await().atMost(1, TimeUnit.SECONDS).until(() -> assertThat(connectCounter.get()).isEqualTo(1)); + await().atMost(2, TimeUnit.SECONDS).until(() -> assertThat(connectCounter.get()).isEqualTo(1)); await().until(() -> assertThat(disconnectCounter.get()).isEqualTo(1)); } From aa79c51f548f88b7f0e4e732f532870023c3e76f Mon Sep 17 00:00:00 2001 From: Nikita Date: Fri, 26 May 2017 12:01:24 +0300 Subject: [PATCH 49/65] compilation fixed --- redisson/src/main/java/org/redisson/config/ConfigSupport.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/redisson/src/main/java/org/redisson/config/ConfigSupport.java b/redisson/src/main/java/org/redisson/config/ConfigSupport.java index 8a7cf8677..b61437af0 100644 --- a/redisson/src/main/java/org/redisson/config/ConfigSupport.java +++ b/redisson/src/main/java/org/redisson/config/ConfigSupport.java @@ -134,7 +134,7 @@ public class ConfigSupport { try { Method lowMask = URI.class.getDeclaredMethod(methodName, String.class); lowMask.setAccessible(true); - long lowMaskValue = (long) lowMask.invoke(null, "-_"); + Long lowMaskValue = (Long) lowMask.invoke(null, "-_"); Field lowDash = URI.class.getDeclaredField(fieldName); From f6b288d3dd83aa5d5e819c40d0c0f57578cc2577 Mon Sep 17 00:00:00 2001 From: Nikita Date: Fri, 26 May 2017 12:03:13 +0300 Subject: [PATCH 50/65] Spring Cache dynamic resolving. #886 --- .../cache/RedissonSpringCacheManager.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/redisson/src/main/java/org/redisson/spring/cache/RedissonSpringCacheManager.java b/redisson/src/main/java/org/redisson/spring/cache/RedissonSpringCacheManager.java index fea4663fa..78d1fd449 100644 --- a/redisson/src/main/java/org/redisson/spring/cache/RedissonSpringCacheManager.java +++ b/redisson/src/main/java/org/redisson/spring/cache/RedissonSpringCacheManager.java @@ -45,6 +45,8 @@ public class RedissonSpringCacheManager implements CacheManager, ResourceLoaderA private ResourceLoader resourceLoader; + private boolean dynamic = true; + private Codec codec; private RedissonClient redisson; @@ -123,6 +125,25 @@ public class RedissonSpringCacheManager implements CacheManager, ResourceLoaderA this.codec = codec; } + /** + * Defines 'fixed' cache names. + * A new cache instance will not be created in dynamic for non-defined names. + *

+ * `null` parameter setups dynamic mode + * + * @param names of caches + */ + public void setCacheNames(Collection names) { + if (names != null) { + for (String name : names) { + getCache(name); + } + dynamic = false; + } else { + dynamic = true; + } + } + /** * Set cache config location * @@ -165,6 +186,9 @@ public class RedissonSpringCacheManager implements CacheManager, ResourceLoaderA if (cache != null) { return cache; } + if (!dynamic) { + return cache; + } CacheConfig config = configMap.get(name); if (config == null) { From aac6de5a619c96ed22ad303bdfd2eed882b42dbb Mon Sep 17 00:00:00 2001 From: Nikita Date: Fri, 26 May 2017 12:28:05 +0300 Subject: [PATCH 51/65] RedissonCacheManager.setAllowNullValues method added. #882 --- .../redisson/spring/cache/RedissonCache.java | 34 +++++++++++++++---- .../cache/RedissonSpringCacheManager.java | 17 ++++++++-- 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/redisson/src/main/java/org/redisson/spring/cache/RedissonCache.java b/redisson/src/main/java/org/redisson/spring/cache/RedissonCache.java index bc648735d..5ae73e626 100644 --- a/redisson/src/main/java/org/redisson/spring/cache/RedissonCache.java +++ b/redisson/src/main/java/org/redisson/spring/cache/RedissonCache.java @@ -39,18 +39,22 @@ public class RedissonCache implements Cache { private CacheConfig config; + private final boolean allowNullValues; + private final AtomicLong hits = new AtomicLong(); private final AtomicLong misses = new AtomicLong(); - public RedissonCache(RMapCache mapCache, CacheConfig config) { + public RedissonCache(RMapCache mapCache, CacheConfig config, boolean allowNullValues) { this.mapCache = mapCache; this.map = mapCache; this.config = config; + this.allowNullValues = allowNullValues; } - public RedissonCache(RMap map) { + public RedissonCache(RMap map, boolean allowNullValues) { this.map = map; + this.allowNullValues = allowNullValues; } @Override @@ -92,6 +96,15 @@ public class RedissonCache implements Cache { @Override public void put(Object key, Object value) { + if (!allowNullValues && value == null) { + if (mapCache != null) { + mapCache.remove(key); + } else { + map.remove(key); + } + return; + } + value = toStoreValue(value); if (mapCache != null) { mapCache.fastPut(key, value, config.getTTL(), TimeUnit.MILLISECONDS, config.getMaxIdleTime(), TimeUnit.MILLISECONDS); @@ -101,13 +114,22 @@ public class RedissonCache implements Cache { } public ValueWrapper putIfAbsent(Object key, Object value) { - value = toStoreValue(value); Object prevValue; - if (mapCache != null) { - prevValue = mapCache.putIfAbsent(key, value, config.getTTL(), TimeUnit.MILLISECONDS, config.getMaxIdleTime(), TimeUnit.MILLISECONDS); + if (!allowNullValues && value == null) { + if (mapCache != null) { + prevValue = mapCache.get(key); + } else { + prevValue = map.get(key); + } } else { - prevValue = map.putIfAbsent(key, value); + value = toStoreValue(value); + if (mapCache != null) { + prevValue = mapCache.putIfAbsent(key, value, config.getTTL(), TimeUnit.MILLISECONDS, config.getMaxIdleTime(), TimeUnit.MILLISECONDS); + } else { + prevValue = map.putIfAbsent(key, value); + } } + return toValueWrapper(prevValue); } diff --git a/redisson/src/main/java/org/redisson/spring/cache/RedissonSpringCacheManager.java b/redisson/src/main/java/org/redisson/spring/cache/RedissonSpringCacheManager.java index 78d1fd449..c8a31de97 100644 --- a/redisson/src/main/java/org/redisson/spring/cache/RedissonSpringCacheManager.java +++ b/redisson/src/main/java/org/redisson/spring/cache/RedissonSpringCacheManager.java @@ -47,6 +47,8 @@ public class RedissonSpringCacheManager implements CacheManager, ResourceLoaderA private boolean dynamic = true; + private boolean allowNullValues = true; + private Codec codec; private RedissonClient redisson; @@ -124,6 +126,17 @@ public class RedissonSpringCacheManager implements CacheManager, ResourceLoaderA this.configLocation = configLocation; this.codec = codec; } + + /** + * Defines possibility of storing {@code null} values. + *

+ * Default is true + * + * @param allowNullValues - stores if true + */ + public void setAllowNullValues(boolean allowNullValues) { + this.allowNullValues = allowNullValues; + } /** * Defines 'fixed' cache names. @@ -213,7 +226,7 @@ public class RedissonSpringCacheManager implements CacheManager, ResourceLoaderA map = redisson.getMap(name); } - Cache cache = new RedissonCache(map); + Cache cache = new RedissonCache(map, allowNullValues); Cache oldCache = instanceMap.putIfAbsent(name, cache); if (oldCache != null) { cache = oldCache; @@ -229,7 +242,7 @@ public class RedissonSpringCacheManager implements CacheManager, ResourceLoaderA map = redisson.getMapCache(name); } - Cache cache = new RedissonCache(map, config); + Cache cache = new RedissonCache(map, config, allowNullValues); Cache oldCache = instanceMap.putIfAbsent(name, cache); if (oldCache != null) { cache = oldCache; From 4ac9b3e30a1eeef8a5b5b6584d60fec778fec283 Mon Sep 17 00:00:00 2001 From: Nikita Koksharov Date: Fri, 26 May 2017 12:35:21 +0300 Subject: [PATCH 52/65] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 56dde5c7b..9a1b5be20 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ Redisson: Redis based In-Memory Data Grid for Java. ==== -[Quick start](https://github.com/redisson/redisson#quick-start) | [Documentation](https://github.com/redisson/redisson/wiki) | [Javadocs](http://www.javadoc.io/doc/org.redisson/redisson/3.4.1) | [Changelog](https://github.com/redisson/redisson/blob/master/CHANGELOG.md) | [Code examples](https://github.com/redisson/redisson-examples) | [Support chat](https://gitter.im/mrniko/redisson) | [Ultra-fast version](https://redisson.pro) +[Quick start](https://github.com/redisson/redisson#quick-start) | [Documentation](https://github.com/redisson/redisson/wiki) | [Javadocs](http://www.javadoc.io/doc/org.redisson/redisson/3.4.1) | [Changelog](https://github.com/redisson/redisson/blob/master/CHANGELOG.md) | [Code examples](https://github.com/redisson/redisson-examples) | [Support chat](https://gitter.im/mrniko/redisson) | **[Ultra-fast version](https://redisson.pro)** Based on high-performance async and lock-free Java Redis client and [Netty](http://netty.io) framework. ## Please take part in [Redisson survey](https://www.surveymonkey.com/r/QXQZH5D) From 0693ef74a52ef9a8b518f44050a59f5a2e10f8c1 Mon Sep 17 00:00:00 2001 From: Nikita Koksharov Date: Fri, 26 May 2017 12:51:17 +0300 Subject: [PATCH 53/65] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0cf579841..77b46d7f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ Redisson Releases History Try __ULTRA-FAST__ [Redisson PRO](https://redisson.pro) edition. -### 10-Apr-2017 - versions 2.9.2 and 3.4.2 released +### 10-May-2017 - versions 2.9.2 and 3.4.2 released Feature - __Dropwizard metrics integration__ More details [here](https://github.com/redisson/redisson/wiki/14.-Integration-with-frameworks#147-dropwizard-metrics) Feature - `RLocalCachedMap.preloadCache` method added (thanks to Steve Draper) From e63fe6fd6ce31c1afb070da58f5b2e99a1085212 Mon Sep 17 00:00:00 2001 From: Rui Gu Date: Sat, 27 May 2017 00:39:31 +0100 Subject: [PATCH 54/65] moved parseAttribute method to parser support class --- .../support/RedissonDefinitionParser.java | 46 ++----------------- .../RedissonNamespaceParserSupport.java | 30 ++++++++++++ 2 files changed, 33 insertions(+), 43 deletions(-) diff --git a/redisson/src/main/java/org/redisson/spring/support/RedissonDefinitionParser.java b/redisson/src/main/java/org/redisson/spring/support/RedissonDefinitionParser.java index 911574b96..6fa573d11 100644 --- a/redisson/src/main/java/org/redisson/spring/support/RedissonDefinitionParser.java +++ b/redisson/src/main/java/org/redisson/spring/support/RedissonDefinitionParser.java @@ -15,7 +15,6 @@ */ package org.redisson.spring.support; -import java.net.URI; import java.util.List; import org.redisson.Redisson; @@ -124,7 +123,7 @@ public final class RedissonDefinitionParser String id = parserContext.getReaderContext().generateBeanName(bd); helper.registerBeanDefinition(builder, id, helper.parseAliase(element), parserContext); - parseAttributes(element, parserContext, builder); + helper.parseAttributes(element, parserContext, builder); redissonDef.addDependsOn(id); parseChildElements(element, id, null, redissonDef, parserContext); parserContext.getDelegate().parseQualifierElements(element, bd); @@ -140,45 +139,6 @@ public final class RedissonDefinitionParser redissonDef.addDependsOn(id); } - private void parseAttributes(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { - NamedNodeMap attributes = element.getAttributes(); - for (int x = 0; x < attributes.getLength(); x++) { - Attr attribute = (Attr) attributes.item(x); - if (helper.isEligibleAttribute(attribute)) { - String propertyName - = attribute.getLocalName().endsWith(REF_SUFFIX) - ? attribute.getLocalName() - .substring(0, attribute.getLocalName() - .length() - REF_SUFFIX.length()) - : attribute.getLocalName(); - propertyName = Conventions - .attributeNameToPropertyName(propertyName); - Assert.state(StringUtils.hasText(propertyName), - "Illegal property name returned from" - + " 'extractPropertyName(String)': cannot be" - + " null or empty."); - if (attribute.getLocalName().endsWith(REF_SUFFIX)) { - builder.addPropertyReference(propertyName, - attribute.getValue()); - } else { - Object value = attribute.getValue(); - String localName = helper.getName(element); - if ("masterAddress".equals(propertyName) - && ConfigType.masterSlaveServers.name() - .equals(localName)) { - try { - value = URI.create((String) value); - } catch (Exception e) { - //value may be a placeholder - value = "redis://" + value; - } - } - builder.addPropertyValue(propertyName, value); - } - } - } - } - @Override public BeanDefinition parse(Element element, ParserContext parserContext) { //Sort out the Config Class @@ -186,7 +146,7 @@ public final class RedissonDefinitionParser = helper.createBeanDefinitionBuilder(element, parserContext, Config.class); String configId = helper.getId(null, configBuilder, parserContext); - parseAttributes(element, parserContext, configBuilder); + helper.parseAttributes(element, parserContext, configBuilder); helper.registerBeanDefinition(configBuilder, configId, null, parserContext); @@ -200,7 +160,7 @@ public final class RedissonDefinitionParser parserContext.getDelegate().parseQualifierElements(element, builder.getRawBeanDefinition()); String id = helper.getId(element, builder, parserContext); - parseAttributes(element, parserContext, configBuilder); + helper.parseAttributes(element, parserContext, configBuilder); //Sort out all the nested elements parseChildElements(element, configId, id, builder, parserContext); diff --git a/redisson/src/main/java/org/redisson/spring/support/RedissonNamespaceParserSupport.java b/redisson/src/main/java/org/redisson/spring/support/RedissonNamespaceParserSupport.java index d7b2804aa..be259aeb0 100644 --- a/redisson/src/main/java/org/redisson/spring/support/RedissonNamespaceParserSupport.java +++ b/redisson/src/main/java/org/redisson/spring/support/RedissonNamespaceParserSupport.java @@ -25,9 +25,11 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.core.Conventions; +import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.w3c.dom.Attr; import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; /** @@ -39,6 +41,7 @@ public class RedissonNamespaceParserSupport { public final static String REDISSON_NAMESPACE = "http://redisson.org/schema/redisson"; + static final String REF_SUFFIX = "-ref"; static final String API_CLASS_PATH_PREFIX = "org.redisson.api.R"; static final String IMPL_CLASS_PATH_PREFIX = "org.redisson.Redisson"; @@ -93,6 +96,33 @@ public class RedissonNamespaceParserSupport { return aliases; } + public void parseAttributes(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { + NamedNodeMap attributes = element.getAttributes(); + for (int x = 0; x < attributes.getLength(); x++) { + Attr attribute = (Attr) attributes.item(x); + if (isEligibleAttribute(attribute)) { + String propertyName + = attribute.getLocalName().endsWith(REF_SUFFIX) + ? attribute.getLocalName() + .substring(0, attribute.getLocalName() + .length() - REF_SUFFIX.length()) + : attribute.getLocalName(); + propertyName = Conventions + .attributeNameToPropertyName(propertyName); + Assert.state(StringUtils.hasText(propertyName), + "Illegal property name returned from" + + " 'extractPropertyName(String)': cannot be" + + " null or empty."); + if (attribute.getLocalName().endsWith(REF_SUFFIX)) { + builder.addPropertyReference(propertyName, + attribute.getValue()); + } else { + builder.addPropertyValue(propertyName, attribute.getValue()); + } + } + } + } + public BeanDefinitionBuilder createBeanDefinitionBuilder(Element element, ParserContext parserContext, Class cls) { BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(); From 8477f1564078823841ebeb346bf14c06bc7279ba Mon Sep 17 00:00:00 2001 From: Rui Gu Date: Sat, 27 May 2017 00:41:31 +0100 Subject: [PATCH 55/65] added URIBuilder --- .../main/java/org/redisson/RedisNodes.java | 3 +- .../java/org/redisson/client/RedisClient.java | 3 +- .../redisson/client/RedisClientConfig.java | 5 ++- .../client/RedisRedirectException.java | 7 ++-- .../org/redisson/cluster/ClusterNodeInfo.java | 3 +- .../redisson/config/ClusterServersConfig.java | 3 +- .../config/MasterSlaveServersConfig.java | 5 ++- .../config/ReplicatedServersConfig.java | 3 +- .../config/SentinelServersConfig.java | 3 +- .../redisson/config/SingleServerConfig.java | 3 +- .../connection/SentinelConnectionManager.java | 9 +++-- .../balancer/WeightedRoundRobinBalancer.java | 3 +- .../java/org/redisson/misc/URIBuilder.java | 40 +++++++++++++++++++ 13 files changed, 71 insertions(+), 19 deletions(-) create mode 100644 redisson/src/main/java/org/redisson/misc/URIBuilder.java diff --git a/redisson/src/main/java/org/redisson/RedisNodes.java b/redisson/src/main/java/org/redisson/RedisNodes.java index e94bffdb0..10a5861a3 100644 --- a/redisson/src/main/java/org/redisson/RedisNodes.java +++ b/redisson/src/main/java/org/redisson/RedisNodes.java @@ -37,6 +37,7 @@ import org.redisson.connection.RedisClientEntry; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.FutureListener; +import org.redisson.misc.URIBuilder; /** * @@ -55,7 +56,7 @@ public class RedisNodes implements NodesGroup { @Override public N getNode(String address) { Collection clients = (Collection) connectionManager.getClients(); - URI uri = URI.create(address); + URI uri = URIBuilder.create(address); InetSocketAddress addr = new InetSocketAddress(uri.getHost(), uri.getPort()); for (N node : clients) { if (node.getAddr().equals(addr)) { diff --git a/redisson/src/main/java/org/redisson/client/RedisClient.java b/redisson/src/main/java/org/redisson/client/RedisClient.java index 077183eb1..e7e8a35ff 100644 --- a/redisson/src/main/java/org/redisson/client/RedisClient.java +++ b/redisson/src/main/java/org/redisson/client/RedisClient.java @@ -44,6 +44,7 @@ import io.netty.util.Timer; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.FutureListener; import io.netty.util.concurrent.GlobalEventExecutor; +import org.redisson.misc.URIBuilder; /** * Low-level Redis client @@ -101,7 +102,7 @@ public class RedisClient { */ @Deprecated public RedisClient(String address) { - this(URI.create(address)); + this(URIBuilder.create(address)); } /* diff --git a/redisson/src/main/java/org/redisson/client/RedisClientConfig.java b/redisson/src/main/java/org/redisson/client/RedisClientConfig.java index aaf8c29b1..957cc909f 100644 --- a/redisson/src/main/java/org/redisson/client/RedisClientConfig.java +++ b/redisson/src/main/java/org/redisson/client/RedisClientConfig.java @@ -26,6 +26,7 @@ import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.util.Timer; +import org.redisson.misc.URIBuilder; /** * @@ -56,11 +57,11 @@ public class RedisClientConfig { private String sslKeystorePassword; public RedisClientConfig setAddress(String host, int port) { - this.address = URI.create("redis://" + host + ":" + port); + this.address = URIBuilder.create("redis://" + host + ":" + port); return this; } public RedisClientConfig setAddress(String address) { - this.address = URI.create(address); + this.address = URIBuilder.create(address); return this; } public RedisClientConfig setAddress(URI address) { diff --git a/redisson/src/main/java/org/redisson/client/RedisRedirectException.java b/redisson/src/main/java/org/redisson/client/RedisRedirectException.java index 8042950f8..5f9f0d872 100644 --- a/redisson/src/main/java/org/redisson/client/RedisRedirectException.java +++ b/redisson/src/main/java/org/redisson/client/RedisRedirectException.java @@ -17,6 +17,7 @@ package org.redisson.client; import java.net.InetSocketAddress; import java.net.URI; +import org.redisson.misc.URIBuilder; /** * @@ -27,12 +28,12 @@ public class RedisRedirectException extends RedisException { private static final long serialVersionUID = 181505625075250011L; - private int slot; - private URI url; + private final int slot; + private final URI url; public RedisRedirectException(int slot, String url) { this.slot = slot; - this.url = URI.create("//" + url); + this.url = URIBuilder.create("//" + url); } public int getSlot() { diff --git a/redisson/src/main/java/org/redisson/cluster/ClusterNodeInfo.java b/redisson/src/main/java/org/redisson/cluster/ClusterNodeInfo.java index c98e23845..8019329d8 100644 --- a/redisson/src/main/java/org/redisson/cluster/ClusterNodeInfo.java +++ b/redisson/src/main/java/org/redisson/cluster/ClusterNodeInfo.java @@ -18,6 +18,7 @@ package org.redisson.cluster; import java.net.URI; import java.util.HashSet; import java.util.Set; +import org.redisson.misc.URIBuilder; /** * @@ -52,7 +53,7 @@ public class ClusterNodeInfo { return address; } public void setAddress(String address) { - this.address = URI.create(address); + this.address = URIBuilder.create(address); } public void addSlotRange(ClusterSlotRange range) { diff --git a/redisson/src/main/java/org/redisson/config/ClusterServersConfig.java b/redisson/src/main/java/org/redisson/config/ClusterServersConfig.java index 6a9476ce6..2ba803f6a 100644 --- a/redisson/src/main/java/org/redisson/config/ClusterServersConfig.java +++ b/redisson/src/main/java/org/redisson/config/ClusterServersConfig.java @@ -18,6 +18,7 @@ package org.redisson.config; import java.net.URI; import java.util.ArrayList; import java.util.List; +import org.redisson.misc.URIBuilder; /** * @@ -53,7 +54,7 @@ public class ClusterServersConfig extends BaseMasterSlaveServersConfig { */ public SingleServerConfig setAddress(String address) { if (address != null) { - this.address = URI.create(address); + this.address = URIBuilder.create(address); } return this; } diff --git a/redisson/src/main/java/org/redisson/connection/SentinelConnectionManager.java b/redisson/src/main/java/org/redisson/connection/SentinelConnectionManager.java index 261041b9c..e2d31ac0a 100755 --- a/redisson/src/main/java/org/redisson/connection/SentinelConnectionManager.java +++ b/redisson/src/main/java/org/redisson/connection/SentinelConnectionManager.java @@ -48,6 +48,7 @@ import org.slf4j.LoggerFactory; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.FutureListener; import io.netty.util.internal.PlatformDependent; +import org.redisson.misc.URIBuilder; /** * @@ -104,7 +105,7 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager { log.info("slave: {} added", host); if (flags.contains("s_down") || flags.contains("disconnected")) { - URI uri = URI.create(host); + URI uri = URIBuilder.create(host); disconnectedSlaves.add(uri); log.warn("slave: {} is down", host); } @@ -208,7 +209,7 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager { String port = parts[3]; String addr = "redis://" + ip + ":" + port; - URI uri = URI.create(addr); + URI uri = URIBuilder.create(addr); registerSentinel(cfg, uri, c); } } @@ -230,7 +231,7 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager { // to avoid addition twice if (slaves.putIfAbsent(slaveAddr, true) == null) { final MasterSlaveEntry entry = getEntry(singleSlotRange.getStartSlot()); - RFuture future = entry.addSlave(URI.create(slaveAddr)); + RFuture future = entry.addSlave(URIBuilder.create(slaveAddr)); future.addListener(new FutureListener() { @Override public void operationComplete(Future future) throws Exception { @@ -372,7 +373,7 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager { String newMaster = "redis://" + ip + ":" + port; if (!newMaster.equals(current) && currentMaster.compareAndSet(current, newMaster)) { - changeMaster(singleSlotRange.getStartSlot(), URI.create(newMaster)); + changeMaster(singleSlotRange.getStartSlot(), URIBuilder.create(newMaster)); log.info("master {} changed to {}", current, newMaster); } } diff --git a/redisson/src/main/java/org/redisson/connection/balancer/WeightedRoundRobinBalancer.java b/redisson/src/main/java/org/redisson/connection/balancer/WeightedRoundRobinBalancer.java index 3ad542023..76661abdb 100644 --- a/redisson/src/main/java/org/redisson/connection/balancer/WeightedRoundRobinBalancer.java +++ b/redisson/src/main/java/org/redisson/connection/balancer/WeightedRoundRobinBalancer.java @@ -30,6 +30,7 @@ import java.util.concurrent.atomic.AtomicInteger; import org.redisson.connection.ClientConnectionsEntry; import io.netty.util.internal.PlatformDependent; +import org.redisson.misc.URIBuilder; /** * Weighted Round Robin balancer. @@ -77,7 +78,7 @@ public class WeightedRoundRobinBalancer implements LoadBalancer { */ public WeightedRoundRobinBalancer(Map weights, int defaultWeight) { for (Entry entry : weights.entrySet()) { - URI uri = URI.create(entry.getKey()); + URI uri = URIBuilder.create(entry.getKey()); InetSocketAddress addr = new InetSocketAddress(uri.getHost(), uri.getPort()); if (entry.getValue() <= 0) { throw new IllegalArgumentException("Weight can't be less than or equal zero"); diff --git a/redisson/src/main/java/org/redisson/misc/URIBuilder.java b/redisson/src/main/java/org/redisson/misc/URIBuilder.java new file mode 100644 index 000000000..1d952b476 --- /dev/null +++ b/redisson/src/main/java/org/redisson/misc/URIBuilder.java @@ -0,0 +1,40 @@ +/** + * Copyright 2016 Nikita Koksharov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.redisson.misc; + +import java.net.URI; + +/** + * + * @author Rui Gu (https://github.com/jackygurui) + */ +public class URIBuilder { + + public static URI create(String uri) { + URI u = URI.create(uri); + //Let's assuming most of the time it is OK. + if (u.getHost() != null) { + return u; + } + String s = uri.substring(0, uri.lastIndexOf(":")) + .replaceFirst("redis://", "") + .replaceFirst("rediss://", ""); + //Assuming this is an IPv6 format, other situations will be handled by + //Netty at a later stage. + return URI.create(uri.replace(s, "[" + s + "]")); + } + +} From 1c7b2a251c3e850e21ff23e0b388cf3f301dd187 Mon Sep 17 00:00:00 2001 From: Rui Gu Date: Sat, 27 May 2017 00:47:06 +0100 Subject: [PATCH 56/65] added redisson-1.1.xsd to support SSL related changes changed the creation of RedisClient to use RedisClientConfig updated test xml to use 1.1 xsd updated wiki test xml to include SSL related configs in reflection to changes made in wiki --- .../spring/support/RedisDefinitionParser.java | 44 +- .../main/resources/META-INF/spring.schemas | 3 +- .../redisson/spring/support/redisson-1.1.xsd | 2429 +++++++++++++++++ .../spring/support/SpringNamespaceTest.java | 14 +- .../support/SpringNamespaceWikiTest.java | 32 + .../org/redisson/spring/support/namespace.xml | 2 +- .../spring/support/namespace_wiki_cluster.xml | 14 +- .../support/namespace_wiki_master_slave.xml | 14 +- .../support/namespace_wiki_redis_client.xml | 48 + .../support/namespace_wiki_replicated.xml | 14 +- .../support/namespace_wiki_sentinel.xml | 12 +- .../spring/support/namespace_wiki_single.xml | 12 +- ...namespace_wiki_single_with_placeholder.xml | 10 +- .../spring/support/redisson_objects.xml | 2 +- 14 files changed, 2606 insertions(+), 44 deletions(-) create mode 100644 redisson/src/main/resources/org/redisson/spring/support/redisson-1.1.xsd create mode 100644 redisson/src/test/resources/org/redisson/spring/support/namespace_wiki_redis_client.xml diff --git a/redisson/src/main/java/org/redisson/spring/support/RedisDefinitionParser.java b/redisson/src/main/java/org/redisson/spring/support/RedisDefinitionParser.java index 6c02eee29..ee164ee5d 100644 --- a/redisson/src/main/java/org/redisson/spring/support/RedisDefinitionParser.java +++ b/redisson/src/main/java/org/redisson/spring/support/RedisDefinitionParser.java @@ -16,6 +16,8 @@ package org.redisson.spring.support; import org.redisson.client.RedisClient; +import org.redisson.client.RedisClientConfig; +import org.springframework.beans.factory.parsing.BeanComponentDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; @@ -26,20 +28,21 @@ import org.w3c.dom.Element; * * @author Rui Gu (https://github.com/jackygurui) */ -public final class RedisDefinitionParser +public final class RedisDefinitionParser extends AbstractSimpleBeanDefinitionParser { - + + private static final String ADDRESS_ATTRIBUTE = "address"; private static final String HOST_ATTRIBUTE = "host"; private static final String PORT_ATTRIBUTE = "port"; private static final String CONNECTION_TIMEOUT_ATTRIBUTE = "connectionTimeout"; private static final String COMMAND_TIMEOUT_ATTRIBUTE = "commandTimeout"; - + private final RedissonNamespaceParserSupport helper; - + public RedisDefinitionParser(RedissonNamespaceParserSupport helper) { this.helper = helper; } - + @Override protected Class getBeanClass(Element element) { return RedisClient.class; @@ -48,14 +51,27 @@ public final class RedisDefinitionParser @Override protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { builder.getRawBeanDefinition().setBeanClass(RedisClient.class); - helper.addConstructorArgs(element, - HOST_ATTRIBUTE, String.class, builder); - helper.addConstructorArgs(element, - PORT_ATTRIBUTE, int.class, builder); - helper.addConstructorArgs(element, - CONNECTION_TIMEOUT_ATTRIBUTE, int.class, builder); - helper.addConstructorArgs(element, - COMMAND_TIMEOUT_ATTRIBUTE, int.class, builder); + if (helper.hasAttribute(element, HOST_ATTRIBUTE)) { + helper.addConstructorArgs(element, + HOST_ATTRIBUTE, String.class, builder); + helper.addConstructorArgs(element, + PORT_ATTRIBUTE, int.class, builder); + helper.addConstructorArgs(element, + CONNECTION_TIMEOUT_ATTRIBUTE, int.class, builder); + helper.addConstructorArgs(element, + COMMAND_TIMEOUT_ATTRIBUTE, int.class, builder); + } else { + BeanDefinitionBuilder b + = helper.createBeanDefinitionBuilder(element, + parserContext, + RedisClientConfig.class); + String configId = helper.getId(null, b, parserContext); + helper.parseAttributes(element, parserContext, b); + BeanComponentDefinition def + = helper.registerBeanDefinition(b, configId, + null, parserContext); + helper.addConstructorArgs(def, RedisClientConfig.class, builder); + } builder.setDestroyMethodName("shutdown"); parserContext.getDelegate().parseQualifierElements(element, builder.getRawBeanDefinition()); @@ -65,7 +81,7 @@ public final class RedisDefinitionParser protected boolean shouldGenerateIdAsFallback() { return true; } - + @Override protected boolean isEligibleAttribute(String attributeName) { return helper.isEligibleAttribute(attributeName); diff --git a/redisson/src/main/resources/META-INF/spring.schemas b/redisson/src/main/resources/META-INF/spring.schemas index 274331f67..f5503f254 100644 --- a/redisson/src/main/resources/META-INF/spring.schemas +++ b/redisson/src/main/resources/META-INF/spring.schemas @@ -1,2 +1,3 @@ -http\://redisson.org/schema/redisson/redisson.xsd=org/redisson/spring/support/redisson-1.0.xsd +http\://redisson.org/schema/redisson/redisson.xsd=org/redisson/spring/support/redisson-1.1.xsd http\://redisson.org/schema/redisson/redisson-1.0.xsd=org/redisson/spring/support/redisson-1.0.xsd +http\://redisson.org/schema/redisson/redisson-1.1.xsd=org/redisson/spring/support/redisson-1.1.xsd diff --git a/redisson/src/main/resources/org/redisson/spring/support/redisson-1.1.xsd b/redisson/src/main/resources/org/redisson/spring/support/redisson-1.1.xsd new file mode 100644 index 000000000..6cadaa351 --- /dev/null +++ b/redisson/src/main/resources/org/redisson/spring/support/redisson-1.1.xsd @@ -0,0 +1,2429 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + netty-tcnative lib is required to be in classpath. + ]]> + + + + + + + + + + + + + + + <qualifier> is not used. + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + timeout time + and current connections amount bigger than minimum idle connections pool + size, then it will closed and removed from pool. + Value in milliseconds. + + Default: 10000 + ]]> + + + + + Node.ping and Node.pingAll + operation. Value in milliseconds. + + Default: 1000 + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + failedAttempts. + + Default: 3 + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + each slave + node. + + Default: 10 + ]]> + + + + + each slave + node. + + Default: 64 + ]]> + + + + + each slave + node. + + Default: 10 + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + NB: applications must ensure the JVM DNS cache TTL is low enough to + support this. e.g., http://docs.aws.amazon.com/AWSSdkDocsJava/latest/DeveloperGuide/java-dg-jvm-ttl.html + + Default: false + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true then invalidation + message which removes corresponding entry from cache will be sent to all + other RLocalCachedMap instances on each entry update/remove operation. + if false then invalidation message won't be sent. + ]]> + + + + + LRU - uses cache with LRU (least recently used) eviction + policy. +

LFU - uses cache with LFU (least frequently used) + eviction policy. +

SOFT - uses cache with soft references. The garbage + collector will evict items from the cache when the JVM is + running out of memory. JVM flag -XX:SoftRefLRUPolicyMSPerMB=??? + is required to function. +

NONE - doesn't use eviction policy, but timeToLive and + maxIdleTime params are still working. + ]]> + + + + + 0 then local cache is unbounded. + ]]> + + + + + 0 then timeout is not applied. + + Default unit is MILLISECONDS + ]]> + + + + + + + + + + 0 then timeout is not applied. + + Default unit is MILLISECONDS + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + NOT mandatory + since the class will also be registered lazily when it is first used. + + All classed registered with the service is stored in a class cache. + + The cache is independent between different RedissonClient instances. When + a class is registered in one RLiveObjectService instance it is also + accessible in another RLiveObjectService instance so long as they are + created by the same RedissonClient instance. + ]]> + + + + + + + + + + + + + + + + + + NOT mandatory + since the class will also be registered lazily when it is first used. + + All classed registered with the service is stored in a class cache. + + The cache is independent between different RedissonClient instances. When + a class is registered in one RLiveObjectService instance it is also + accessible in another RLiveObjectService instance so long as they are + created by the same RedissonClient instance. + + One of "object-id" or "object-id-ref" attribute is required. + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Set eviction + + Redisson distributed Set for Java with eviction support implemented by + separate RSetCache object which extends RSet interface. It also + implements java.util.Set interface. + + Current redis implementation doesn't has set value eviction + functionality. Therefore expired values are cleaned by + org.redisson.EvictionScheduler. It removes 100 expired values at once. + Task launch time tuned automatically and depends on expired entries + amount deleted in previous time and varies between 1 second to 2 hours. + Thus if clean task deletes 100 values each time it will be executed + every second (minimum execution delay). But if current expired values + amount is lower than previous one then execution delay will be increased + by 1.5 times. + ]]> + + + + + + + + + + + Map eviction + + Redisson distributed Map for Java with eviction support implemented by + separate RMapCache object which extends RMap interface. It keeps + elements in insertion order and implements + java.util.concurrent.ConcurrentMap and java.util.Map interfaces. + Redisson has a Spring Cache integration which based on Map and MapCache + objects. + + Current redis implementation doesn't has map entry eviction + functionality. Therefore expired entries are cleaned by + org.redisson.EvictionScheduler. It removes 100 expired entries at once. + Task launch time tuned automatically and depends on expired entries + amount deleted in previous time and varies between 1 second to 2 hours. + Thus if clean task deletes 100 entries each time it will be executed + every second (minimum execution delay). But if current expired entries + amount is lower than previous one then execution delay will be increased + by 1.5 times. + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Map local cache + + In case when a Map is used mostly for read operations and/or network + roundtrips are undesirable. Redisson offers RLocalCachedMap object which + caches Map entries on Redisson side. + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + interface. + Keeps elements uniqueness via element state comparison. + ]]> + + + + + + + + + + + interface. + Keeps elements uniqueness via element state comparison. + ]]> + + + + + + + + + + + + + + + + + interface. + Keeps elements uniqueness via element state comparison. + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Live distributed object (also abbreviated as live object) refers to a + running instance of a distributed multi-party (or peer-to-peer) protocol, + viewed from the object-oriented perspective, as an entity that has a + distinct identity, may encapsulate internal state and threads of + execution, and that exhibits a well-defined externally visible behavior. + + + Redisson Live Object (RLO) realised this idea by mapping all the fields + inside a Java class to a redis hash through a runtime-constructed proxy + class. All the get/set methods of each field are translated to hget/hset + commands operated on the redis hash, making it accessable to/from any + clients connected to the same redis server. As we all know, the field + values of an object represent its state; having them stored in a remote + repository, redis, makes it a distributed object. This object is a + Redisson Live Object. + + By using RLO, sharing an object between applications and/or servers is + the same as sharing one in a standalone application. This removes the + need for serialization and deserialization, and at the same time reduces + the complexity of the programming model: Changes made to one field + is (almost^) immediately accessable to other processes, applications and + servers. (^Redis' eventual consistant replication rule still applies + when connected to slave nodes) + + Since the redis server is a single-threaded application, all field + access to the live object is automatically executed in atomic fashion: a + value will not be changed when you are reading it. + + With RLO, you can treat the redis server as a shared Heap space for all + connected JVMs. + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Define and create a Redisson instance. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Define and create a RedisClient instance. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/redisson/src/test/java/org/redisson/spring/support/SpringNamespaceTest.java b/redisson/src/test/java/org/redisson/spring/support/SpringNamespaceTest.java index 588dbbf24..c4e9d7ca0 100644 --- a/redisson/src/test/java/org/redisson/spring/support/SpringNamespaceTest.java +++ b/redisson/src/test/java/org/redisson/spring/support/SpringNamespaceTest.java @@ -61,7 +61,7 @@ public class SpringNamespaceTest extends BaseTest { } public static void startContext() throws Exception { - System.setProperty("redisAddress", RedisRunner.getDefaultRedisServerBindAddressAndPort()); + System.setProperty("redisAddress", "redis://" + RedisRunner.getDefaultRedisServerBindAddressAndPort()); //Needs a instance running on the default port, launch it if there isn't one already if (RedisRunner.isFreePort(6379)) { @@ -79,7 +79,7 @@ public class SpringNamespaceTest extends BaseTest { RedisRunner.getDefaultRedisServerInstance().getRedisServerBindAddress(), RedisRunner.getDefaultRedisServerInstance().getRedisServerPort()) .run(); - System.setProperty("slave1Address", slave1.getRedisServerAddressAndPort()); + System.setProperty("slave1Address", "redis://" + slave1.getRedisServerAddressAndPort()); RedisRunner.RedisProcess slave2 = new RedisRunner() .nosave() @@ -89,7 +89,7 @@ public class SpringNamespaceTest extends BaseTest { RedisRunner.getDefaultRedisServerInstance().getRedisServerBindAddress(), RedisRunner.getDefaultRedisServerInstance().getRedisServerPort()) .run(); - System.setProperty("slave2Address", slave2.getRedisServerAddressAndPort()); + System.setProperty("slave2Address", "redis://" + slave2.getRedisServerAddressAndPort()); RedisRunner.RedisProcess sentinel1 = new RedisRunner() .nosave() @@ -101,7 +101,7 @@ public class SpringNamespaceTest extends BaseTest { RedisRunner.getDefaultRedisServerInstance().getRedisServerBindAddress(), RedisRunner.getDefaultRedisServerInstance().getRedisServerPort(), 2).run(); - System.setProperty("sentinel1Address", sentinel1.getRedisServerAddressAndPort()); + System.setProperty("sentinel1Address", "redis://" + sentinel1.getRedisServerAddressAndPort()); RedisRunner.RedisProcess sentinel2 = new RedisRunner() .nosave() @@ -113,7 +113,7 @@ public class SpringNamespaceTest extends BaseTest { RedisRunner.getDefaultRedisServerInstance().getRedisServerBindAddress(), RedisRunner.getDefaultRedisServerInstance().getRedisServerPort(), 2).run(); - System.setProperty("sentinel2Address", sentinel2.getRedisServerAddressAndPort()); + System.setProperty("sentinel2Address", "redis://" + sentinel2.getRedisServerAddressAndPort()); RedisRunner.RedisProcess sentinel3 = new RedisRunner() .nosave() @@ -125,7 +125,7 @@ public class SpringNamespaceTest extends BaseTest { RedisRunner.getDefaultRedisServerInstance().getRedisServerBindAddress(), RedisRunner.getDefaultRedisServerInstance().getRedisServerPort(), 2).run(); - System.setProperty("sentinel3Address", sentinel3.getRedisServerAddressAndPort()); + System.setProperty("sentinel3Address", "redis://" + sentinel3.getRedisServerAddressAndPort()); RedisRunner slave = new RedisRunner().randomPort().randomDir().nosave(); ClusterRunner clusterRunner = new ClusterRunner() .addNode(new RedisRunner().randomPort().randomDir().nosave(),//master1 @@ -143,7 +143,7 @@ public class SpringNamespaceTest extends BaseTest { new RedisRunner().randomPort().randomDir().nosave());//slave1-3-2 final AtomicLong index = new AtomicLong(0); clusterRunner.run().getNodes().stream().forEach((node) -> { - System.setProperty("node" + (index.incrementAndGet()) + "Address", node.getRedisServerAddressAndPort()); + System.setProperty("node" + (index.incrementAndGet()) + "Address", "redis://" + node.getRedisServerAddressAndPort()); }); context = new ClassPathXmlApplicationContext("classpath:org/redisson/spring/support/namespace.xml"); diff --git a/redisson/src/test/java/org/redisson/spring/support/SpringNamespaceWikiTest.java b/redisson/src/test/java/org/redisson/spring/support/SpringNamespaceWikiTest.java index 861955096..2d4c07f61 100644 --- a/redisson/src/test/java/org/redisson/spring/support/SpringNamespaceWikiTest.java +++ b/redisson/src/test/java/org/redisson/spring/support/SpringNamespaceWikiTest.java @@ -2,7 +2,9 @@ package org.redisson.spring.support; import io.netty.channel.EventLoopGroup; import java.lang.reflect.Method; +import java.util.Map; import java.util.concurrent.Executor; +import static org.hamcrest.Matchers.*; import org.junit.Test; import org.redisson.ClusterRunner; import org.redisson.RedisRunner; @@ -11,7 +13,10 @@ import org.redisson.config.Config; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import static org.junit.Assert.*; +import org.redisson.client.RedisClient; +import org.redisson.client.RedisConnection; import org.redisson.client.codec.Codec; +import org.redisson.client.protocol.RedisCommands; import org.redisson.codec.CodecProvider; import org.redisson.config.SingleServerConfig; import org.redisson.liveobject.provider.ResolverProvider; @@ -38,6 +43,27 @@ public class SpringNamespaceWikiTest { } } + @Test + public void testRedisClient() throws Exception { + RedisRunner.RedisProcess run = new RedisRunner() + .requirepass("do_not_use_if_it_is_not_set") + .nosave() + .randomDir() + .run(); + try { + ClassPathXmlApplicationContext context + = new ClassPathXmlApplicationContext("classpath:org/redisson/spring/support/namespace_wiki_redis_client.xml"); + RedisClient redisClient = context.getBean(RedisClient.class); + RedisConnection connection = redisClient.connect(); + Map info = connection.sync(RedisCommands.INFO_ALL); + assertThat(info, notNullValue()); + assertThat(info, not(info.isEmpty())); + ((ConfigurableApplicationContext) context).close(); + } finally { + run.stop(); + } + } + @Test public void testSingleWithPlaceholder() throws Exception { RedisRunner.RedisProcess run = new RedisRunner() @@ -66,6 +92,12 @@ public class SpringNamespaceWikiTest { System.setProperty("redisson.password", "do_not_use_if_it_is_not_set"); System.setProperty("redisson.subscriptionsPerConnection", "10"); System.setProperty("redisson.clientName", "client_name"); + System.setProperty("redisson.sslEnableEndpointIdentification", "true"); + System.setProperty("redisson.sslProvider", "JDK"); + System.setProperty("redisson.sslTruststore", "/tmp/truststore.p12"); + System.setProperty("redisson.sslTruststorePassword", "not_set"); + System.setProperty("redisson.sslKeystore", "/tmp/keystore.p12"); + System.setProperty("redisson.sslKeystorePassword", "not_set"); System.setProperty("redisson.subscriptionConnectionMinimumIdleSize", "11"); System.setProperty("redisson.subscriptionConnectionPoolSize", "12"); System.setProperty("redisson.connectionMinimumIdleSize", "13"); diff --git a/redisson/src/test/resources/org/redisson/spring/support/namespace.xml b/redisson/src/test/resources/org/redisson/spring/support/namespace.xml index 928ee1847..33e544be3 100644 --- a/redisson/src/test/resources/org/redisson/spring/support/namespace.xml +++ b/redisson/src/test/resources/org/redisson/spring/support/namespace.xml @@ -6,7 +6,7 @@ xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd - http://redisson.org/schema/redisson classpath:org/redisson/spring/support/redisson-1.0.xsd + http://redisson.org/schema/redisson classpath:org/redisson/spring/support/redisson-1.1.xsd "> diff --git a/redisson/src/test/resources/org/redisson/spring/support/namespace_wiki_cluster.xml b/redisson/src/test/resources/org/redisson/spring/support/namespace_wiki_cluster.xml index 1689951e5..dd9957da7 100644 --- a/redisson/src/test/resources/org/redisson/spring/support/namespace_wiki_cluster.xml +++ b/redisson/src/test/resources/org/redisson/spring/support/namespace_wiki_cluster.xml @@ -6,7 +6,7 @@ xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd - http://redisson.org/schema/redisson classpath:org/redisson/spring/support/redisson-1.0.xsd + http://redisson.org/schema/redisson classpath:org/redisson/spring/support/redisson-1.1.xsd "> @@ -51,6 +51,12 @@ password="do_not_use_if_it_is_not_set" subscriptions-per-connection="5" client-name="none" + ssl-enable-endpoint-identification="true" + ssl-provider="JDK" + ssl-truststore="/tmp/truststore.p12" + ssl-truststore-password="no_pass" + ssl-keystore="/tmp/keystore.p12" + ssl-keystore-password="no_pass" load-balancer-ref="myLoadBalancer" subscription-connection-minimum-idle-size="1" subscription-connection-pool-size="50" @@ -62,9 +68,9 @@ subscription-mode="SLAVE" scan-interval="1000" > - - - + + + diff --git a/redisson/src/test/resources/org/redisson/spring/support/namespace_wiki_master_slave.xml b/redisson/src/test/resources/org/redisson/spring/support/namespace_wiki_master_slave.xml index 12003cbe3..857cafea3 100644 --- a/redisson/src/test/resources/org/redisson/spring/support/namespace_wiki_master_slave.xml +++ b/redisson/src/test/resources/org/redisson/spring/support/namespace_wiki_master_slave.xml @@ -6,7 +6,7 @@ xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd - http://redisson.org/schema/redisson classpath:org/redisson/spring/support/redisson-1.0.xsd + http://redisson.org/schema/redisson classpath:org/redisson/spring/support/redisson-1.1.xsd "> @@ -51,6 +51,12 @@ password="do_not_use_if_it_is_not_set" subscriptions-per-connection="5" client-name="none" + ssl-enable-endpoint-identification="true" + ssl-provider="JDK" + ssl-truststore="/tmp/truststore.p12" + ssl-truststore-password="no_pass" + ssl-keystore="/tmp/keystore.p12" + ssl-keystore-password="no_pass" load-balancer-ref="myLoadBalancer" subscription-connection-minimum-idle-size="1" subscription-connection-pool-size="50" @@ -60,11 +66,11 @@ master-connection-pool-size="64" read-mode="SLAVE" subscription-mode="SLAVE" - master-address="127.0.0.1:6379" + master-address="redis://127.0.0.1:6379" database="0" > - - + + diff --git a/redisson/src/test/resources/org/redisson/spring/support/namespace_wiki_redis_client.xml b/redisson/src/test/resources/org/redisson/spring/support/namespace_wiki_redis_client.xml new file mode 100644 index 000000000..738fe02e0 --- /dev/null +++ b/redisson/src/test/resources/org/redisson/spring/support/namespace_wiki_redis_client.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + diff --git a/redisson/src/test/resources/org/redisson/spring/support/namespace_wiki_replicated.xml b/redisson/src/test/resources/org/redisson/spring/support/namespace_wiki_replicated.xml index 450ea9d98..bd8cbaa5b 100644 --- a/redisson/src/test/resources/org/redisson/spring/support/namespace_wiki_replicated.xml +++ b/redisson/src/test/resources/org/redisson/spring/support/namespace_wiki_replicated.xml @@ -6,7 +6,7 @@ xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd - http://redisson.org/schema/redisson classpath:org/redisson/spring/support/redisson-1.0.xsd + http://redisson.org/schema/redisson classpath:org/redisson/spring/support/redisson-1.1.xsd "> @@ -51,6 +51,12 @@ password="do_not_use_if_it_is_not_set" subscriptions-per-connection="5" client-name="none" + ssl-enable-endpoint-identification="true" + ssl-provider="JDK" + ssl-truststore="/tmp/truststore.p12" + ssl-truststore-password="no_pass" + ssl-keystore="/tmp/keystore.p12" + ssl-keystore-password="no_pass" load-balancer-ref="myLoadBalancer" subscription-connection-minimum-idle-size="1" subscription-connection-pool-size="50" @@ -63,9 +69,9 @@ scan-interval="1000" database="0" > - - - + + + diff --git a/redisson/src/test/resources/org/redisson/spring/support/namespace_wiki_sentinel.xml b/redisson/src/test/resources/org/redisson/spring/support/namespace_wiki_sentinel.xml index 49d188775..3389317f2 100644 --- a/redisson/src/test/resources/org/redisson/spring/support/namespace_wiki_sentinel.xml +++ b/redisson/src/test/resources/org/redisson/spring/support/namespace_wiki_sentinel.xml @@ -6,7 +6,7 @@ xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd - http://redisson.org/schema/redisson classpath:org/redisson/spring/support/redisson-1.0.xsd + http://redisson.org/schema/redisson classpath:org/redisson/spring/support/redisson-1.1.xsd "> @@ -51,6 +51,12 @@ password="do_not_use_if_it_is_not_set" subscriptions-per-connection="5" client-name="none" + ssl-enable-endpoint-identification="true" + ssl-provider="JDK" + ssl-truststore="/tmp/truststore.p12" + ssl-truststore-password="no_pass" + ssl-keystore="/tmp/keystore.p12" + ssl-keystore-password="no_pass" load-balancer-ref="myLoadBalancer" subscription-connection-minimum-idle-size="1" subscription-connection-pool-size="50" @@ -63,8 +69,8 @@ master-name="myMaster" database="0" > - - + + diff --git a/redisson/src/test/resources/org/redisson/spring/support/namespace_wiki_single.xml b/redisson/src/test/resources/org/redisson/spring/support/namespace_wiki_single.xml index 4c49a82fe..a532b149d 100644 --- a/redisson/src/test/resources/org/redisson/spring/support/namespace_wiki_single.xml +++ b/redisson/src/test/resources/org/redisson/spring/support/namespace_wiki_single.xml @@ -6,7 +6,7 @@ xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd - http://redisson.org/schema/redisson classpath:org/redisson/spring/support/redisson-1.0.xsd + http://redisson.org/schema/redisson classpath:org/redisson/spring/support/redisson-1.1.xsd "> @@ -49,8 +49,14 @@ failed-attempts="3" password="do_not_use_if_it_is_not_set" subscriptions-per-connection="5" - client-name="none" - address="127.0.0.1:6379" + client-name="none" + ssl-enable-endpoint-identification="true" + ssl-provider="JDK" + ssl-truststore="/tmp/truststore.p12" + ssl-truststore-password="no_pass" + ssl-keystore="/tmp/keystore.p12" + ssl-keystore-password="no_pass" + address="redis://127.0.0.1:6379" subscription-connection-minimum-idle-size="1" subscription-connection-pool-size="50" connection-minimum-idle-size="10" diff --git a/redisson/src/test/resources/org/redisson/spring/support/namespace_wiki_single_with_placeholder.xml b/redisson/src/test/resources/org/redisson/spring/support/namespace_wiki_single_with_placeholder.xml index 01962d373..fb73fcb7d 100644 --- a/redisson/src/test/resources/org/redisson/spring/support/namespace_wiki_single_with_placeholder.xml +++ b/redisson/src/test/resources/org/redisson/spring/support/namespace_wiki_single_with_placeholder.xml @@ -6,7 +6,7 @@ xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd - http://redisson.org/schema/redisson classpath:org/redisson/spring/support/redisson-1.0.xsd + http://redisson.org/schema/redisson classpath:org/redisson/spring/support/redisson-1.1.xsd "> @@ -43,7 +43,13 @@ failed-attempts="${redisson.failedAttempts}" password="${redisson.password}" subscriptions-per-connection="${redisson.subscriptionsPerConnection}" - client-name="${redisson.clientName}" + client-name="${redisson.clientName}" + ssl-enable-endpoint-identification="${redisson.sslEnableEndpointIdentification}" + ssl-provider="${redisson.sslProvider}" + ssl-truststore="${redisson.sslTruststore}" + ssl-truststore-password="${redisson.sslTruststorePassword}" + ssl-keystore="${redisson.sslKeystore}" + ssl-keystore-password="${redisson.sslKeystorePassword}" address="${redisson.redisAddress}" subscription-connection-minimum-idle-size="${redisson.subscriptionConnectionMinimumIdleSize}" subscription-connection-pool-size="${redisson.subscriptionConnectionPoolSize}" diff --git a/redisson/src/test/resources/org/redisson/spring/support/redisson_objects.xml b/redisson/src/test/resources/org/redisson/spring/support/redisson_objects.xml index 3e3b64504..925eccf26 100644 --- a/redisson/src/test/resources/org/redisson/spring/support/redisson_objects.xml +++ b/redisson/src/test/resources/org/redisson/spring/support/redisson_objects.xml @@ -6,7 +6,7 @@ xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd - http://redisson.org/schema/redisson classpath:org/redisson/spring/support/redisson-1.0.xsd + http://redisson.org/schema/redisson classpath:org/redisson/spring/support/redisson-1.1.xsd "> From 48ddec70e245faac95b8f27b7abca159f0eae656 Mon Sep 17 00:00:00 2001 From: Nikita Date: Sat, 27 May 2017 11:24:18 +0300 Subject: [PATCH 57/65] unlocking of nested readLock deletes writeLock. #891 --- .../main/java/org/redisson/RedissonReadLock.java | 8 ++++++-- .../org/redisson/RedissonReadWriteLockTest.java | 16 ++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/redisson/src/main/java/org/redisson/RedissonReadLock.java b/redisson/src/main/java/org/redisson/RedissonReadLock.java index ebe650c3a..a55885116 100644 --- a/redisson/src/main/java/org/redisson/RedissonReadLock.java +++ b/redisson/src/main/java/org/redisson/RedissonReadLock.java @@ -97,7 +97,7 @@ public class RedissonReadLock extends RedissonLock implements RLock { "local counter = redis.call('hincrby', KEYS[1], ARGV[2], -1); " + "if (counter == 0) then " + - "redis.call('hdel', KEYS[1], ARGV[2]); " + + "redis.call('hdel', KEYS[1], ARGV[2]); " + "end;" + "redis.call('del', KEYS[1] .. ':' .. ARGV[2] .. ':rwlock_timeout:' .. (counter+1)); " + "if (redis.call('hlen', KEYS[1]) > 1) then " + @@ -114,9 +114,13 @@ public class RedissonReadLock extends RedissonLock implements RLock { "end; " + "if maxRemainTime > 0 then " + - "redis.call('pexpire', KEYS[1], maxRemainTime); " + + "redis.call('pexpire', KEYS[1], maxRemainTime); " + "return 0; " + "end;" + + + "if mode == 'write' then " + + "return 0;" + + "end; " + "end; " + "redis.call('del', KEYS[1]); " + diff --git a/redisson/src/test/java/org/redisson/RedissonReadWriteLockTest.java b/redisson/src/test/java/org/redisson/RedissonReadWriteLockTest.java index d6d903a2d..837a8d375 100644 --- a/redisson/src/test/java/org/redisson/RedissonReadWriteLockTest.java +++ b/redisson/src/test/java/org/redisson/RedissonReadWriteLockTest.java @@ -95,6 +95,22 @@ public class RedissonReadWriteLockTest extends BaseConcurrentTest { Assert.assertTrue(writeLock.tryLock()); } + @Test + public void testWR() throws InterruptedException { + RReadWriteLock rw = redisson.getReadWriteLock("my_read_write_lock"); + RLock writeLock = rw.writeLock(); + writeLock.lock(); + + rw.readLock().lock(); + assertThat(writeLock.isLocked()).isTrue(); + rw.readLock().unlock(); + + assertThat(writeLock.isLocked()).isTrue(); + writeLock.unlock(); + assertThat(writeLock.isLocked()).isFalse(); + } + + @Test public void testWriteReadReentrancy() throws InterruptedException { RReadWriteLock readWriteLock = redisson.getReadWriteLock("TEST"); From e2c9d178484a640d6350d3a9657ef7547593e10c Mon Sep 17 00:00:00 2001 From: Nikita Date: Sat, 27 May 2017 17:32:44 +0300 Subject: [PATCH 58/65] SentinelConnectionManager should use AUTH with Sentinel servers --- redisson/src/main/java/org/redisson/api/NodeType.java | 2 +- .../redisson/connection/MasterSlaveConnectionManager.java | 6 +++++- .../org/redisson/connection/SentinelConnectionManager.java | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/redisson/src/main/java/org/redisson/api/NodeType.java b/redisson/src/main/java/org/redisson/api/NodeType.java index 50b92390d..436d968c1 100644 --- a/redisson/src/main/java/org/redisson/api/NodeType.java +++ b/redisson/src/main/java/org/redisson/api/NodeType.java @@ -17,6 +17,6 @@ package org.redisson.api; public enum NodeType { - MASTER, SLAVE + MASTER, SLAVE, SENTINEL } diff --git a/redisson/src/main/java/org/redisson/connection/MasterSlaveConnectionManager.java b/redisson/src/main/java/org/redisson/connection/MasterSlaveConnectionManager.java index 17bb6460f..ddb46e020 100644 --- a/redisson/src/main/java/org/redisson/connection/MasterSlaveConnectionManager.java +++ b/redisson/src/main/java/org/redisson/connection/MasterSlaveConnectionManager.java @@ -373,9 +373,13 @@ public class MasterSlaveConnectionManager implements ConnectionManager { .setSslTruststorePassword(config.getSslTruststorePassword()) .setSslKeystore(config.getSslKeystore()) .setSslKeystorePassword(config.getSslKeystorePassword()) - .setPassword(config.getPassword()) .setDatabase(config.getDatabase()) .setClientName(config.getClientName()); + + if (type != NodeType.SENTINEL) { + redisConfig.setPassword(config.getPassword()); + } + return redisConfig; } diff --git a/redisson/src/main/java/org/redisson/connection/SentinelConnectionManager.java b/redisson/src/main/java/org/redisson/connection/SentinelConnectionManager.java index 2cbb7e64e..30bba5b01 100755 --- a/redisson/src/main/java/org/redisson/connection/SentinelConnectionManager.java +++ b/redisson/src/main/java/org/redisson/connection/SentinelConnectionManager.java @@ -71,7 +71,7 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager { initTimer(this.config); for (URI addr : cfg.getSentinelAddresses()) { - RedisClient client = createClient(NodeType.MASTER, addr, this.config.getConnectTimeout(), this.config.getRetryInterval() * this.config.getRetryAttempts()); + RedisClient client = createClient(NodeType.SENTINEL, addr, this.config.getConnectTimeout(), this.config.getRetryInterval() * this.config.getRetryAttempts()); try { RedisConnection connection = client.connect(); if (!connection.isActive()) { @@ -154,7 +154,7 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager { } private RFuture registerSentinel(final SentinelServersConfig cfg, final URI addr, final MasterSlaveServersConfig c) { - RedisClient client = createClient(NodeType.MASTER, addr, c.getConnectTimeout(), c.getRetryInterval() * c.getRetryAttempts()); + RedisClient client = createClient(NodeType.SENTINEL, addr, c.getConnectTimeout(), c.getRetryInterval() * c.getRetryAttempts()); RedisClient oldClient = sentinels.putIfAbsent(addr.getHost() + ":" + addr.getPort(), client); if (oldClient != null) { return newSucceededFuture(null); From 278b6d7ea17a12b49e67051fdf552e9886e6a8c8 Mon Sep 17 00:00:00 2001 From: Nikita Date: Tue, 6 Jun 2017 10:34:07 +0300 Subject: [PATCH 59/65] fixed RedissonBoundedBlockingQueue.pollAsync blocks if timeout is less than 1 second #896 --- .../main/java/org/redisson/RedissonBoundedBlockingQueue.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/redisson/src/main/java/org/redisson/RedissonBoundedBlockingQueue.java b/redisson/src/main/java/org/redisson/RedissonBoundedBlockingQueue.java index ac309c5a9..1a0186270 100644 --- a/redisson/src/main/java/org/redisson/RedissonBoundedBlockingQueue.java +++ b/redisson/src/main/java/org/redisson/RedissonBoundedBlockingQueue.java @@ -216,7 +216,7 @@ public class RedissonBoundedBlockingQueue extends RedissonQueue implements @Override public RFuture pollAsync(long timeout, TimeUnit unit) { - RFuture takeFuture = commandExecutor.writeAsync(getName(), codec, RedisCommands.BLPOP_VALUE, getName(), unit.toSeconds(timeout)); + RFuture takeFuture = commandExecutor.writeAsync(getName(), codec, RedisCommands.BLPOP_VALUE, getName(), toSeconds(timeout, unit)); return wrapTakeFuture(takeFuture); } From a575b5f4c5d1534d98b09143437d15fedde94bb3 Mon Sep 17 00:00:00 2001 From: Nikita Date: Tue, 6 Jun 2017 10:47:38 +0300 Subject: [PATCH 60/65] netty updated --- redisson-all/pom.xml | 2 +- redisson/pom.xml | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/redisson-all/pom.xml b/redisson-all/pom.xml index 8575da259..7290b8017 100644 --- a/redisson-all/pom.xml +++ b/redisson-all/pom.xml @@ -87,7 +87,7 @@ io.netty netty-transport-native-epoll linux-x86_64 - 4.1.10.Final + 4.1.11.Final com.esotericsoftware diff --git a/redisson/pom.xml b/redisson/pom.xml index 133e3b11d..cdc2f3de9 100644 --- a/redisson/pom.xml +++ b/redisson/pom.xml @@ -34,33 +34,33 @@ io.netty netty-transport-native-epoll - 4.1.10.Final + 4.1.11.Final provided io.netty netty-common - 4.1.10.Final + 4.1.11.Final io.netty netty-codec - 4.1.10.Final + 4.1.11.Final io.netty netty-buffer - 4.1.10.Final + 4.1.11.Final io.netty netty-transport - 4.1.10.Final + 4.1.11.Final io.netty netty-handler - 4.1.10.Final + 4.1.11.Final From ee3617be5d030acd797c3d6e8c5c9b8f6c8e9928 Mon Sep 17 00:00:00 2001 From: Nikita Date: Tue, 6 Jun 2017 13:02:05 +0300 Subject: [PATCH 61/65] Correct keyManagerFactory init with defined password. #842 --- .../client/handler/RedisChannelInitializer.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/redisson/src/main/java/org/redisson/client/handler/RedisChannelInitializer.java b/redisson/src/main/java/org/redisson/client/handler/RedisChannelInitializer.java index 6eefeef66..4ea2b5df0 100644 --- a/redisson/src/main/java/org/redisson/client/handler/RedisChannelInitializer.java +++ b/redisson/src/main/java/org/redisson/client/handler/RedisChannelInitializer.java @@ -123,18 +123,18 @@ public class RedisChannelInitializer extends ChannelInitializer { KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); InputStream stream = config.getSslKeystore().toURL().openStream(); + char[] password = null; + if (config.getSslKeystorePassword() != null) { + password = config.getSslKeystorePassword().toCharArray(); + } try { - char[] password = null; - if (config.getSslKeystorePassword() != null) { - password = config.getSslKeystorePassword().toCharArray(); - } keyStore.load(stream, password); } finally { stream.close(); } KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); - keyManagerFactory.init(keyStore, null); + keyManagerFactory.init(keyStore, password); sslContextBuilder.keyManager(keyManagerFactory); } From 4a37a5e4a4c022101556f9d4a6b4e28985b0c82f Mon Sep 17 00:00:00 2001 From: Nikita Date: Tue, 6 Jun 2017 13:14:43 +0300 Subject: [PATCH 62/65] dnsMonitoring turned on by default for SingleServerConfig --- .../redisson/config/SingleServerConfig.java | 10 +++--- .../connection/SingleConnectionManager.java | 36 +++++++++++-------- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/redisson/src/main/java/org/redisson/config/SingleServerConfig.java b/redisson/src/main/java/org/redisson/config/SingleServerConfig.java index 758c35422..03bc5a4dc 100644 --- a/redisson/src/main/java/org/redisson/config/SingleServerConfig.java +++ b/redisson/src/main/java/org/redisson/config/SingleServerConfig.java @@ -64,7 +64,7 @@ public class SingleServerConfig extends BaseConfig { * NB: applications must ensure the JVM DNS cache TTL is low enough to support this. * e.g., http://docs.aws.amazon.com/AWSSdkDocsJava/latest/DeveloperGuide/java-dg-jvm-ttl.html */ - private boolean dnsMonitoring = false; + private boolean dnsMonitoring = true; /** * Interval in milliseconds to check DNS @@ -144,8 +144,10 @@ public class SingleServerConfig extends BaseConfig { /** * Monitoring of the endpoint address for DNS changes. - * - * Default is false + *

+ * Applications must ensure the JVM DNS cache TTL is low enough to support this + *

+ * Default is true * * @param dnsMonitoring flag * @return config @@ -161,7 +163,7 @@ public class SingleServerConfig extends BaseConfig { /** * Interval in milliseconds to check the endpoint DNS if {@link #isDnsMonitoring()} is true. * - * Default is 5000 + * Default is 5000 * * @param dnsMonitoringInterval time * @return config diff --git a/redisson/src/main/java/org/redisson/connection/SingleConnectionManager.java b/redisson/src/main/java/org/redisson/connection/SingleConnectionManager.java index 71027b9e0..83d7c1e5c 100644 --- a/redisson/src/main/java/org/redisson/connection/SingleConnectionManager.java +++ b/redisson/src/main/java/org/redisson/connection/SingleConnectionManager.java @@ -93,27 +93,33 @@ public class SingleConnectionManager extends MasterSlaveConnectionManager { } private void monitorDnsChange(final SingleServerConfig cfg) { - monitorFuture = GlobalEventExecutor.INSTANCE.scheduleWithFixedDelay(new Runnable() { + monitorFuture = GlobalEventExecutor.INSTANCE.schedule(new Runnable() { @Override public void run() { - try { - InetAddress master = currentMaster.get(); - InetAddress now = InetAddress.getByName(cfg.getAddress().getHost()); - if (!now.getHostAddress().equals(master.getHostAddress())) { - log.info("Detected DNS change. {} has changed from {} to {}", cfg.getAddress().getHost(), master.getHostAddress(), now.getHostAddress()); - if (currentMaster.compareAndSet(master, now)) { - changeMaster(singleSlotRange.getStartSlot(), cfg.getAddress()); - log.info("Master has been changed"); + // As InetAddress.getByName call is blocking. Method should be run in dedicated thread + getExecutor().execute(new Runnable() { + @Override + public void run() { + try { + InetAddress master = currentMaster.get(); + InetAddress now = InetAddress.getByName(cfg.getAddress().getHost()); + if (!now.getHostAddress().equals(master.getHostAddress())) { + log.info("Detected DNS change. {} has changed from {} to {}", cfg.getAddress().getHost(), master.getHostAddress(), now.getHostAddress()); + if (currentMaster.compareAndSet(master, now)) { + changeMaster(singleSlotRange.getStartSlot(), cfg.getAddress()); + log.info("Master has been changed"); + } + } + } catch (Exception e) { + log.error(e.getMessage(), e); + } finally { + monitorDnsChange(cfg); } } - - } catch (Exception e) { - log.error(e.getMessage(), e); - } - + }); } - }, cfg.getDnsMonitoringInterval(), cfg.getDnsMonitoringInterval(), TimeUnit.MILLISECONDS); + }, cfg.getDnsMonitoringInterval(), TimeUnit.MILLISECONDS); } @Override From cf89ee70ada90e6ccb5b0371d3d51e12cd27b298 Mon Sep 17 00:00:00 2001 From: Diogo Nicoleti Date: Tue, 6 Jun 2017 15:02:14 -0300 Subject: [PATCH 63/65] bump jackson version to 2.7.6 --- redisson/pom.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/redisson/pom.xml b/redisson/pom.xml index cdc2f3de9..e6bfc7d77 100644 --- a/redisson/pom.xml +++ b/redisson/pom.xml @@ -186,37 +186,37 @@ com.fasterxml.jackson.dataformat jackson-dataformat-yaml - 2.6.7 + 2.7.6 com.fasterxml.jackson.core jackson-core - 2.6.7 + 2.7.6 com.fasterxml.jackson.core jackson-databind - 2.6.7 + 2.7.6 com.fasterxml.jackson.dataformat jackson-dataformat-cbor - 2.6.7 + 2.7.6 provided true com.fasterxml.jackson.dataformat jackson-dataformat-smile - 2.6.7 + 2.7.6 provided true com.fasterxml.jackson.dataformat jackson-dataformat-avro - 2.6.7 + 2.7.6 provided true From 0053bf325e201f7e647d7ba59a9da3e77bc2779c Mon Sep 17 00:00:00 2001 From: Nikita Date: Wed, 7 Jun 2017 14:01:25 +0300 Subject: [PATCH 64/65] MapCache listeners added. #879 --- .../src/main/java/org/redisson/Redisson.java | 12 +- .../main/java/org/redisson/RedissonBatch.java | 8 +- .../org/redisson/RedissonLocalCachedMap.java | 14 +- .../main/java/org/redisson/RedissonMap.java | 15 +- .../java/org/redisson/RedissonMapCache.java | 454 ++++++++++++++---- .../main/java/org/redisson/api/RMapCache.java | 24 + .../java/org/redisson/api/RMapCacheAsync.java | 10 +- .../api/map/event/EntryCreatedListener.java | 29 ++ .../redisson/api/map/event/EntryEvent.java | 66 +++ .../api/map/event/EntryExpiredListener.java | 29 ++ .../api/map/event/EntryRemovedListener.java | 29 ++ .../api/map/event/EntryUpdatedListener.java | 29 ++ .../api/map/event/MapEntryListener.java | 27 ++ .../codec/CustomObjectInputStream.java | 5 + .../redisson/codec/MapCacheEventCodec.java | 106 ++++ .../redisson/eviction/EvictionScheduler.java | 4 +- .../org/redisson/eviction/EvictionTask.java | 2 +- .../eviction/MapCacheEvictionTask.java | 22 +- .../reactive/RedissonMapCacheReactive.java | 4 +- .../reactive/RedissonMapReactive.java | 4 +- .../org/redisson/RedissonMapCacheTest.java | 164 ++++++- 21 files changed, 920 insertions(+), 137 deletions(-) create mode 100644 redisson/src/main/java/org/redisson/api/map/event/EntryCreatedListener.java create mode 100644 redisson/src/main/java/org/redisson/api/map/event/EntryEvent.java create mode 100644 redisson/src/main/java/org/redisson/api/map/event/EntryExpiredListener.java create mode 100644 redisson/src/main/java/org/redisson/api/map/event/EntryRemovedListener.java create mode 100644 redisson/src/main/java/org/redisson/api/map/event/EntryUpdatedListener.java create mode 100644 redisson/src/main/java/org/redisson/api/map/event/MapEntryListener.java create mode 100644 redisson/src/main/java/org/redisson/codec/MapCacheEventCodec.java diff --git a/redisson/src/main/java/org/redisson/Redisson.java b/redisson/src/main/java/org/redisson/Redisson.java index c8410d6e2..3189d2eca 100755 --- a/redisson/src/main/java/org/redisson/Redisson.java +++ b/redisson/src/main/java/org/redisson/Redisson.java @@ -253,17 +253,17 @@ public class Redisson implements RedissonClient { @Override public RLocalCachedMap getLocalCachedMap(String name, LocalCachedMapOptions options) { - return new RedissonLocalCachedMap(id, connectionManager.getCommandExecutor(), name, options, evictionScheduler, this); + return new RedissonLocalCachedMap(connectionManager.getCommandExecutor(), name, options, evictionScheduler, this); } @Override public RLocalCachedMap getLocalCachedMap(String name, Codec codec, LocalCachedMapOptions options) { - return new RedissonLocalCachedMap(id, codec, connectionManager.getCommandExecutor(), name, options, evictionScheduler, this); + return new RedissonLocalCachedMap(codec, connectionManager.getCommandExecutor(), name, options, evictionScheduler, this); } @Override public RMap getMap(String name) { - return new RedissonMap(id, connectionManager.getCommandExecutor(), name, this); + return new RedissonMap(connectionManager.getCommandExecutor(), name, this); } @Override @@ -308,17 +308,17 @@ public class Redisson implements RedissonClient { @Override public RMapCache getMapCache(String name) { - return new RedissonMapCache(id, evictionScheduler, connectionManager.getCommandExecutor(), name, this); + return new RedissonMapCache(evictionScheduler, connectionManager.getCommandExecutor(), name, this); } @Override public RMapCache getMapCache(String name, Codec codec) { - return new RedissonMapCache(id, codec, evictionScheduler, connectionManager.getCommandExecutor(), name, this); + return new RedissonMapCache(codec, evictionScheduler, connectionManager.getCommandExecutor(), name, this); } @Override public RMap getMap(String name, Codec codec) { - return new RedissonMap(id, codec, connectionManager.getCommandExecutor(), name, this); + return new RedissonMap(codec, connectionManager.getCommandExecutor(), name, this); } @Override diff --git a/redisson/src/main/java/org/redisson/RedissonBatch.java b/redisson/src/main/java/org/redisson/RedissonBatch.java index b25b07f50..3e7cc2509 100644 --- a/redisson/src/main/java/org/redisson/RedissonBatch.java +++ b/redisson/src/main/java/org/redisson/RedissonBatch.java @@ -102,12 +102,12 @@ public class RedissonBatch implements RBatch { @Override public RMapAsync getMap(String name) { - return new RedissonMap(id, executorService, name, null); + return new RedissonMap(executorService, name, null); } @Override public RMapAsync getMap(String name, Codec codec) { - return new RedissonMap(id, codec, executorService, name, null); + return new RedissonMap(codec, executorService, name, null); } @Override @@ -202,12 +202,12 @@ public class RedissonBatch implements RBatch { @Override public RMapCacheAsync getMapCache(String name, Codec codec) { - return new RedissonMapCache(id, codec, evictionScheduler, executorService, name, null); + return new RedissonMapCache(codec, evictionScheduler, executorService, name, null); } @Override public RMapCacheAsync getMapCache(String name) { - return new RedissonMapCache(id, evictionScheduler, executorService, name, null); + return new RedissonMapCache(evictionScheduler, executorService, name, null); } @Override diff --git a/redisson/src/main/java/org/redisson/RedissonLocalCachedMap.java b/redisson/src/main/java/org/redisson/RedissonLocalCachedMap.java index efb981356..2d018a3c4 100644 --- a/redisson/src/main/java/org/redisson/RedissonLocalCachedMap.java +++ b/redisson/src/main/java/org/redisson/RedissonLocalCachedMap.java @@ -208,17 +208,17 @@ public class RedissonLocalCachedMap extends RedissonMap implements R private int invalidationStatusListenerId; private volatile long lastInvalidate; - protected RedissonLocalCachedMap(UUID id, CommandAsyncExecutor commandExecutor, String name, LocalCachedMapOptions options, EvictionScheduler evictionScheduler, RedissonClient redisson) { - super(id, commandExecutor, name, redisson); - init(id, name, options, redisson, evictionScheduler); + protected RedissonLocalCachedMap(CommandAsyncExecutor commandExecutor, String name, LocalCachedMapOptions options, EvictionScheduler evictionScheduler, RedissonClient redisson) { + super(commandExecutor, name, redisson); + init(name, options, redisson, evictionScheduler); } - protected RedissonLocalCachedMap(UUID id, Codec codec, CommandAsyncExecutor connectionManager, String name, LocalCachedMapOptions options, EvictionScheduler evictionScheduler, RedissonClient redisson) { - super(id, codec, connectionManager, name, redisson); - init(id, name, options, redisson, evictionScheduler); + protected RedissonLocalCachedMap(Codec codec, CommandAsyncExecutor connectionManager, String name, LocalCachedMapOptions options, EvictionScheduler evictionScheduler, RedissonClient redisson) { + super(codec, connectionManager, name, redisson); + init(name, options, redisson, evictionScheduler); } - private void init(UUID id, String name, LocalCachedMapOptions options, RedissonClient redisson, EvictionScheduler evictionScheduler) { + private void init(String name, LocalCachedMapOptions options, RedissonClient redisson, EvictionScheduler evictionScheduler) { instanceId = generateId(); if (options.getInvalidationPolicy() == InvalidationPolicy.ON_CHANGE diff --git a/redisson/src/main/java/org/redisson/RedissonMap.java b/redisson/src/main/java/org/redisson/RedissonMap.java index 5eb7552a7..a1a71d9e5 100644 --- a/redisson/src/main/java/org/redisson/RedissonMap.java +++ b/redisson/src/main/java/org/redisson/RedissonMap.java @@ -28,7 +28,6 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.UUID; import org.redisson.api.RFuture; import org.redisson.api.RLock; @@ -47,7 +46,6 @@ import org.redisson.client.protocol.convertor.NumberConvertor; import org.redisson.client.protocol.decoder.MapScanResult; import org.redisson.client.protocol.decoder.ScanObjectEntry; import org.redisson.command.CommandAsyncExecutor; -import org.redisson.command.CommandExecutor; import org.redisson.connection.decoder.MapGetAllDecoder; import org.redisson.mapreduce.RedissonMapReduce; import org.redisson.misc.Hash; @@ -69,18 +67,15 @@ public class RedissonMap extends RedissonExpirable implements RMap { static final RedisCommand EVAL_REMOVE_VALUE = new RedisCommand("EVAL", new BooleanReplayConvertor(), 4, ValueType.MAP); static final RedisCommand EVAL_PUT = EVAL_REPLACE; - private final UUID id; - private final RedissonClient redisson; + final RedissonClient redisson; - protected RedissonMap(UUID id, CommandAsyncExecutor commandExecutor, String name, RedissonClient redisson) { + protected RedissonMap(CommandAsyncExecutor commandExecutor, String name, RedissonClient redisson) { super(commandExecutor, name); - this.id = id; this.redisson = redisson; } - public RedissonMap(UUID id, Codec codec, CommandAsyncExecutor commandExecutor, String name, RedissonClient redisson) { + public RedissonMap(Codec codec, CommandAsyncExecutor commandExecutor, String name, RedissonClient redisson) { super(codec, commandExecutor, name); - this.id = id; this.redisson = redisson; } @@ -92,13 +87,13 @@ public class RedissonMap extends RedissonExpirable implements RMap { @Override public RLock getLock(K key) { String lockName = getLockName(key); - return new RedissonLock((CommandExecutor)commandExecutor, lockName, id); + return redisson.getLock(lockName); } @Override public RReadWriteLock getReadWriteLock(K key) { String lockName = getLockName(key); - return new RedissonReadWriteLock((CommandExecutor)commandExecutor, lockName, id); + return redisson.getReadWriteLock(lockName); } private String getLockName(Object key) { diff --git a/redisson/src/main/java/org/redisson/RedissonMapCache.java b/redisson/src/main/java/org/redisson/RedissonMapCache.java index b7df19c49..c60f449bb 100644 --- a/redisson/src/main/java/org/redisson/RedissonMapCache.java +++ b/redisson/src/main/java/org/redisson/RedissonMapCache.java @@ -15,6 +15,8 @@ */ package org.redisson; +import java.io.IOException; +import java.math.BigDecimal; import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.Arrays; @@ -23,19 +25,27 @@ import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.UUID; import java.util.concurrent.TimeUnit; import org.redisson.api.RFuture; import org.redisson.api.RMapCache; +import org.redisson.api.RTopic; import org.redisson.api.RedissonClient; +import org.redisson.api.listener.MessageListener; +import org.redisson.api.map.event.EntryCreatedListener; +import org.redisson.api.map.event.EntryEvent; +import org.redisson.api.map.event.EntryExpiredListener; +import org.redisson.api.map.event.EntryRemovedListener; +import org.redisson.api.map.event.EntryUpdatedListener; +import org.redisson.api.map.event.MapEntryListener; import org.redisson.client.codec.Codec; import org.redisson.client.codec.LongCodec; import org.redisson.client.codec.MapScanCodec; +import org.redisson.client.codec.StringCodec; 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.BooleanReplayConvertor; +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; @@ -45,16 +55,13 @@ import org.redisson.client.protocol.decoder.MapScanResult; import org.redisson.client.protocol.decoder.ObjectListDecoder; import org.redisson.client.protocol.decoder.ObjectMapDecoder; import org.redisson.client.protocol.decoder.ScanObjectEntry; +import org.redisson.codec.MapCacheEventCodec; import org.redisson.command.CommandAsyncExecutor; import org.redisson.connection.decoder.MapGetAllDecoder; 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; /** *

Map-based cache with ability to set TTL for each entry via @@ -77,45 +84,39 @@ import org.redisson.client.protocol.convertor.NumberConvertor; */ public class RedissonMapCache extends RedissonMap implements RMapCache { - static final RedisCommand EVAL_PUT_IF_ABSENT = new RedisCommand("EVAL", new BooleanReplayConvertor(), 7, ValueType.MAP); - static final RedisCommand EVAL_HSET = new RedisCommand("EVAL", new BooleanReplayConvertor(), 4, ValueType.MAP); - static final RedisCommand EVAL_REPLACE = new RedisCommand("EVAL", 6, ValueType.MAP, ValueType.MAP_VALUE); - static final RedisCommand EVAL_REPLACE_VALUE = new RedisCommand("EVAL", new BooleanReplayConvertor(), 7, Arrays.asList(ValueType.MAP_KEY, ValueType.MAP_VALUE, ValueType.MAP_VALUE)); + static final RedisCommand EVAL_REPLACE = new RedisCommand("EVAL", 7, ValueType.MAP, ValueType.MAP_VALUE); static final RedisCommand EVAL_HMSET = new RedisCommand("EVAL", new VoidReplayConvertor(), 4, ValueType.MAP); - private static final RedisCommand EVAL_REMOVE = new RedisCommand("EVAL", 4, ValueType.MAP_KEY, ValueType.MAP_VALUE); - private static final RedisCommand EVAL_REMOVE_VALUE = new RedisCommand("EVAL", new BooleanReplayConvertor(), 5, ValueType.MAP); - private static final RedisCommand EVAL_PUT_TTL = new RedisCommand("EVAL", 9, ValueType.MAP, ValueType.MAP_VALUE); - private static final RedisCommand EVAL_PUT_TTL_IF_ABSENT = new RedisCommand("EVAL", 10, ValueType.MAP, ValueType.MAP_VALUE); - private static final RedisCommand EVAL_FAST_PUT_TTL = new RedisCommand("EVAL", new BooleanReplayConvertor(), 9, ValueType.MAP, ValueType.MAP_VALUE); - private static final RedisCommand EVAL_FAST_PUT_TTL_IF_ABSENT = new RedisCommand("EVAL", new BooleanReplayConvertor(), 10, ValueType.MAP, ValueType.MAP_VALUE); + private static final RedisCommand EVAL_REMOVE = new RedisCommand("EVAL", 7, ValueType.MAP_KEY, ValueType.MAP_VALUE); + private static final RedisCommand EVAL_PUT_TTL = new RedisCommand("EVAL", 12, ValueType.MAP, ValueType.MAP_VALUE); + private static final RedisCommand EVAL_PUT_TTL_IF_ABSENT = new RedisCommand("EVAL", 11, ValueType.MAP, ValueType.MAP_VALUE); private static final RedisCommand EVAL_GET_TTL = new RedisCommand("EVAL", 7, ValueType.MAP_KEY, ValueType.MAP_VALUE); - private static final RedisCommand EVAL_CONTAINS_KEY = new RedisCommand("EVAL", new BooleanReplayConvertor(), 7, ValueType.MAP_KEY); - static final RedisCommand EVAL_CONTAINS_VALUE = new RedisCommand("EVAL", new BooleanReplayConvertor(), 7, ValueType.MAP_VALUE); - static final RedisCommand EVAL_FAST_REMOVE = new RedisCommand("EVAL", 5, ValueType.MAP_KEY); + static final RedisCommand EVAL_FAST_REMOVE = new RedisCommand("EVAL", 7, ValueType.MAP_KEY); + static final RedisCommand EVAL_PUT = new RedisCommand("EVAL", 6, ValueType.MAP, ValueType.MAP_VALUE); + static final RedisCommand EVAL_PUT_IF_ABSENT = new RedisCommand("EVAL", 5, ValueType.MAP, ValueType.MAP_VALUE); - RedissonMapCache(UUID id, CommandAsyncExecutor commandExecutor, String name, RedissonClient redisson) { - super(id, commandExecutor, name, redisson); + RedissonMapCache(CommandAsyncExecutor commandExecutor, String name, RedissonClient redisson) { + super(commandExecutor, name, redisson); } - RedissonMapCache(UUID id, Codec codec, CommandAsyncExecutor commandExecutor, String name, RedissonClient redisson) { - super(id, codec, commandExecutor, name, redisson); + RedissonMapCache(Codec codec, CommandAsyncExecutor commandExecutor, String name, RedissonClient redisson) { + super(codec, commandExecutor, name, redisson); } - public RedissonMapCache(UUID id, EvictionScheduler evictionScheduler, CommandAsyncExecutor commandExecutor, String name, RedissonClient redisson) { - super(id, commandExecutor, name, redisson); - evictionScheduler.schedule(getName(), getTimeoutSetName(), getIdleSetName()); + public RedissonMapCache(EvictionScheduler evictionScheduler, CommandAsyncExecutor commandExecutor, String name, RedissonClient redisson) { + super(commandExecutor, name, redisson); + evictionScheduler.schedule(getName(), getTimeoutSetName(), getIdleSetName(), getExpiredChannelName()); } - public RedissonMapCache(UUID id, Codec codec, EvictionScheduler evictionScheduler, CommandAsyncExecutor commandExecutor, String name, RedissonClient redisson) { - super(id, codec, commandExecutor, name, redisson); - evictionScheduler.schedule(getName(), getTimeoutSetName(), getIdleSetName()); + public RedissonMapCache(Codec codec, EvictionScheduler evictionScheduler, CommandAsyncExecutor commandExecutor, String name, RedissonClient redisson) { + super(codec, commandExecutor, name, redisson); + evictionScheduler.schedule(getName(), getTimeoutSetName(), getIdleSetName(), getExpiredChannelName()); } @Override public RFuture containsKeyAsync(Object key) { checkKey(key); - return commandExecutor.evalWriteAsync(getName(key), codec, EVAL_CONTAINS_KEY, + return commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_BOOLEAN, "local value = redis.call('hget', KEYS[1], ARGV[2]); " + "local expireDate = 92233720368547758; " + "if value ~= false then " + @@ -141,14 +142,15 @@ public class RedissonMapCache extends RedissonMap implements RMapCac + "return 1;" + "end;" + "return 0; ", - Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key)), System.currentTimeMillis(), key); + Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key)), + System.currentTimeMillis(), encodeMapKey(key)); } @Override public RFuture containsValueAsync(Object value) { checkValue(value); - return commandExecutor.evalWriteAsync(getName(), codec, EVAL_CONTAINS_VALUE, + return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_BOOLEAN, "local s = redis.call('hgetall', KEYS[1]); " + "for i, v in ipairs(s) do " + "if i % 2 == 0 then " @@ -179,7 +181,7 @@ public class RedissonMapCache extends RedissonMap implements RMapCac + "end; " + "end;" + "return 0;", - Arrays.asList(getName(), getTimeoutSetName(), getIdleSetName()), System.currentTimeMillis(), value); + Arrays.asList(getName(), getTimeoutSetName(), getIdleSetName()), System.currentTimeMillis(), encodeMapValue(value)); } @Override @@ -287,23 +289,21 @@ public class RedissonMapCache extends RedissonMap implements RMapCac + "if value == false then " + "insertable = true; " + "else " - + "if insertable == false then " - + "local t, val = struct.unpack('dLc0', value); " - + "local expireDate = 92233720368547758; " - + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[5]); " - + "if expireDateScore ~= false then " - + "expireDate = tonumber(expireDateScore) " - + "end; " - + "if t ~= 0 then " - + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[5]); " - + "if expireIdle ~= false then " - + "expireDate = math.min(expireDate, tonumber(expireIdle)) " - + "end; " - + "end; " - + "if expireDate <= tonumber(ARGV[1]) then " - + "insertable = true; " - + "end; " - + "end; " + + "local t, val = struct.unpack('dLc0', value); " + + "local expireDate = 92233720368547758; " + + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[5]); " + + "if expireDateScore ~= false then " + + "expireDate = tonumber(expireDateScore) " + + "end; " + + "if t ~= 0 then " + + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[5]); " + + "if expireIdle ~= false then " + + "expireDate = math.min(expireDate, tonumber(expireIdle)) " + + "end; " + + "end; " + + "if expireDate <= tonumber(ARGV[1]) then " + + "insertable = true; " + + "end; " + "end; " + "if insertable == true then " @@ -322,16 +322,20 @@ public class RedissonMapCache extends RedissonMap implements RMapCac + "end; " // value - + "local val = struct.pack('dLc0', ARGV[4], string.len(ARGV[6]), ARGV[6]); " + + "local val = struct.pack('dLc0', tonumber(ARGV[4]), string.len(ARGV[6]), ARGV[6]); " + "redis.call('hset', KEYS[1], ARGV[5], val); " + + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[5]), ARGV[5], string.len(ARGV[6]), ARGV[6]); " + + "redis.call('publish', KEYS[4], msg); " + + "return nil;" + "else " + "local t, val = struct.unpack('dLc0', value); " + "redis.call('zadd', KEYS[3], t + ARGV[1], ARGV[5]); " + "return val;" + "end; ", - Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key)), System.currentTimeMillis(), ttlTimeout, maxIdleTimeout, maxIdleDelta, key, value); + Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelName()), + System.currentTimeMillis(), ttlTimeout, maxIdleTimeout, maxIdleDelta, key, value); } @Override @@ -339,7 +343,7 @@ public class RedissonMapCache extends RedissonMap implements RMapCac checkKey(key); checkValue(value); - return commandExecutor.evalWriteAsync(getName(key), codec, EVAL_REMOVE_VALUE, + return commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_BOOLEAN, "local value = redis.call('hget', KEYS[1], ARGV[1]); " + "if value == false then " + "return 0; " @@ -348,11 +352,15 @@ public class RedissonMapCache extends RedissonMap implements RMapCac + "if val == ARGV[2] then " + "redis.call('zrem', KEYS[2], ARGV[1]); " + "redis.call('zrem', KEYS[3], ARGV[1]); " - + "return redis.call('hdel', KEYS[1], ARGV[1]); " + + "redis.call('hdel', KEYS[1], ARGV[1]); " + + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[1]), ARGV[1], string.len(val), val); " + + "redis.call('publish', KEYS[4], msg); " + + "return 1; " + "else " - + "return 0 " + + "return 0; " + "end", - Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key)), key, value); + Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getRemovedChannelName()), + encodeMapKey(key), encodeMapValue(value)); } @Override @@ -403,11 +411,16 @@ public class RedissonMapCache extends RedissonMap implements RMapCac + "local value = struct.pack('dLc0', 0, string.len(ARGV[2]), ARGV[2]); " + "redis.call('hset', KEYS[1], ARGV[1], value); " + "if v == false then " + + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[1]), ARGV[1], string.len(ARGV[2]), ARGV[2]); " + + "redis.call('publish', KEYS[2], msg); " + "return nil; " + "end; " + "local t, val = struct.unpack('dLc0', v); " + + "local msg = struct.pack('Lc0Lc0Lc0', string.len(ARGV[1]), ARGV[1], string.len(ARGV[2]), ARGV[2], string.len(val), val); " + + "redis.call('publish', KEYS[3], msg); " + "return val; ", - Collections.singletonList(getName(key)), key, value); + Arrays.asList(getName(key), getCreatedChannelName(), getUpdatedChannelName()), + key, value); } @Override @@ -415,9 +428,11 @@ public class RedissonMapCache extends RedissonMap implements RMapCac checkKey(key); checkValue(value); - return commandExecutor.evalWriteAsync(getName(key), codec, EVAL_PUT, + return commandExecutor.evalWriteAsync(getName(key), codec, EVAL_PUT_IF_ABSENT, "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]); " + + "redis.call('publish', KEYS[2], msg); " + "return nil;" + "else " + "local v = redis.call('hget', KEYS[1], ARGV[1]); " @@ -427,7 +442,8 @@ public class RedissonMapCache extends RedissonMap implements RMapCac + "local t, val = struct.unpack('dLc0', v); " + "return val; " + "end", - Collections.singletonList(getName(key)), key, value); + Arrays.asList(getName(key), getCreatedChannelName()), + key, value); } @Override @@ -473,14 +489,22 @@ public class RedissonMapCache extends RedissonMap implements RMapCac + "end; " + "end; " + "end; " + + "local newValue = tonumber(ARGV[3]); " - + "if expireDate >= tonumber(ARGV[1]) then " + + "if value ~= false and expireDate > tonumber(ARGV[1]) then " + "newValue = tonumber(val) + newValue; " + + + "local msg = struct.pack('Lc0Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(newValue), newValue, string.len(val), val); " + + "redis.call('publish', KEYS[5], msg); " + + "else " + + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3]); " + + "redis.call('publish', KEYS[4], msg); " + "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.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key)), System.currentTimeMillis(), keyState, valueState); + Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelName(), getUpdatedChannelName()), + System.currentTimeMillis(), keyState, valueState); } @Override @@ -533,20 +557,53 @@ public class RedissonMapCache extends RedissonMap implements RMapCac maxIdleTimeout = System.currentTimeMillis() + maxIdleDelta; } - return commandExecutor.evalWriteAsync(getName(key), codec, EVAL_FAST_PUT_TTL, - "if tonumber(ARGV[1]) > 0 then " - + "redis.call('zadd', KEYS[2], ARGV[1], ARGV[4]); " + return commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_BOOLEAN, + "local insertable = false; " + + "local value = redis.call('hget', KEYS[1], ARGV[5]); " + + "local t, val;" + + "if value == false then " + + "insertable = true; " + + "else " + + "t, val = struct.unpack('dLc0', value); " + + "local expireDate = 92233720368547758; " + + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[5]); " + + "if expireDateScore ~= false then " + + "expireDate = tonumber(expireDateScore) " + + "end; " + + "if t ~= 0 then " + + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[5]); " + + "if expireIdle ~= false then " + + "expireDate = math.min(expireDate, tonumber(expireIdle)) " + + "end; " + + "end; " + + "if expireDate <= tonumber(ARGV[1]) then " + + "insertable = true; " + + "end; " + + "end; " + + + "if tonumber(ARGV[2]) > 0 then " + + "redis.call('zadd', KEYS[2], ARGV[2], ARGV[5]); " + "else " - + "redis.call('zrem', KEYS[2], ARGV[4]); " + + "redis.call('zrem', KEYS[2], ARGV[5]); " + "end; " - + "if tonumber(ARGV[2]) > 0 then " - + "redis.call('zadd', KEYS[3], ARGV[2], ARGV[4]); " + + "if tonumber(ARGV[3]) > 0 then " + + "redis.call('zadd', KEYS[3], ARGV[3], ARGV[5]); " + "else " - + "redis.call('zrem', KEYS[3], ARGV[4]); " + + "redis.call('zrem', KEYS[3], ARGV[5]); " + "end; " - + "local value = struct.pack('dLc0', ARGV[3], string.len(ARGV[5]), ARGV[5]); " + - "return redis.call('hset', KEYS[1], ARGV[4], value); ", - Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key)), ttlTimeout, maxIdleTimeout, maxIdleDelta, key, value); + + "local value = struct.pack('dLc0', ARGV[4], string.len(ARGV[6]), ARGV[6]); " + + "redis.call('hset', KEYS[1], ARGV[5], value); " + + "if insertable == true then " + + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[5]), ARGV[5], string.len(ARGV[6]), ARGV[6]); " + + "redis.call('publish', KEYS[4], msg); " + + "return 1;" + + "else " + + "local msg = struct.pack('Lc0Lc0Lc0', string.len(ARGV[5]), ARGV[5], string.len(ARGV[6]), ARGV[6], string.len(val), val); " + + "redis.call('publish', KEYS[5], msg); " + + "return 0;" + + "end;", + Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelName(), getUpdatedChannelName()), + System.currentTimeMillis(), ttlTimeout, maxIdleTimeout, maxIdleDelta, encodeMapKey(key), encodeMapValue(value)); } @Override @@ -595,25 +652,56 @@ public class RedissonMapCache extends RedissonMap implements RMapCac } return commandExecutor.evalWriteAsync(getName(key), codec, EVAL_PUT_TTL, - "local v = redis.call('hget', KEYS[1], ARGV[4]); " - + "if tonumber(ARGV[1]) > 0 then " - + "redis.call('zadd', KEYS[2], ARGV[1], ARGV[4]); " + "local insertable = false; " + + "local v = redis.call('hget', KEYS[1], ARGV[5]); " + + "if v == false then " + + "insertable = true; " + + "else " + + "local t, val = struct.unpack('dLc0', v); " + + "local expireDate = 92233720368547758; " + + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[5]); " + + "if expireDateScore ~= false then " + + "expireDate = tonumber(expireDateScore) " + + "end; " + + "if t ~= 0 then " + + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[5]); " + + "if expireIdle ~= false then " + + "expireDate = math.min(expireDate, tonumber(expireIdle)) " + + "end; " + + "end; " + + "if expireDate <= tonumber(ARGV[1]) then " + + "insertable = true; " + + "end; " + + "end; " + + + "if tonumber(ARGV[2]) > 0 then " + + "redis.call('zadd', KEYS[2], ARGV[2], ARGV[5]); " + "else " - + "redis.call('zrem', KEYS[2], ARGV[4]); " + + "redis.call('zrem', KEYS[2], ARGV[5]); " + "end; " - + "if tonumber(ARGV[2]) > 0 then " - + "redis.call('zadd', KEYS[3], ARGV[2], ARGV[4]); " + + "if tonumber(ARGV[3]) > 0 then " + + "redis.call('zadd', KEYS[3], ARGV[3], ARGV[5]); " + "else " - + "redis.call('zrem', KEYS[3], ARGV[4]); " + + "redis.call('zrem', KEYS[3], ARGV[5]); " + "end; " - + "local value = struct.pack('dLc0', ARGV[3], string.len(ARGV[5]), ARGV[5]); " - + "redis.call('hset', KEYS[1], ARGV[4], value); " - + "if v == false then " + + + "local value = struct.pack('dLc0', ARGV[4], string.len(ARGV[6]), ARGV[6]); " + + "redis.call('hset', KEYS[1], ARGV[5], value); " + + + "if insertable == true then " + + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[5]), ARGV[5], string.len(ARGV[6]), ARGV[6]); " + + "redis.call('publish', KEYS[4], msg); " + "return nil;" + "end; " + + "local t, val = struct.unpack('dLc0', v); " + + + "local msg = struct.pack('Lc0Lc0Lc0', string.len(ARGV[5]), ARGV[5], string.len(ARGV[6]), ARGV[6], string.len(val), val); " + + "redis.call('publish', KEYS[5], msg); " + + "return val", - Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key)), ttlTimeout, maxIdleTimeout, maxIdleDelta, key, value); + Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelName(), getUpdatedChannelName()), + System.currentTimeMillis(), ttlTimeout, maxIdleTimeout, maxIdleDelta, key, value); } String getTimeoutSetNameByKey(Object key) { @@ -640,6 +728,38 @@ public class RedissonMapCache extends RedissonMap implements RMapCac return prefixName("redisson__idle__set", getName()); } + String getCreatedChannelName(String name) { + return prefixName("redisson_map_cache_created", name); + } + + String getCreatedChannelName() { + return prefixName("redisson_map_cache_created", getName()); + } + + String getUpdatedChannelName(String name) { + return prefixName("redisson_map_cache_updated", name); + } + + String getUpdatedChannelName() { + return prefixName("redisson_map_cache_updated", getName()); + } + + String getExpiredChannelName(String name) { + return prefixName("redisson_map_cache_expired", name); + } + + String getExpiredChannelName() { + return prefixName("redisson_map_cache_expired", getName()); + } + + String getRemovedChannelName(String name) { + return prefixName("redisson_map_cache_removed", name); + } + + String getRemovedChannelName() { + return prefixName("redisson_map_cache_removed", getName()); + } + @Override public RFuture removeAsync(K key) { @@ -652,10 +772,13 @@ public class RedissonMapCache extends RedissonMap implements RMapCac + "redis.call('hdel', KEYS[1], ARGV[1]); " + "if v ~= false then " + "local t, val = struct.unpack('dLc0', v); " + + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[1]), ARGV[1], string.len(val), val); " + + "redis.call('publish', KEYS[4], msg); " + "return val; " + "end; " + "return v", - Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key)), key); + Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getRemovedChannelName()), + key); } @Override @@ -666,9 +789,18 @@ public class RedissonMapCache extends RedissonMap implements RMapCac return commandExecutor.evalWriteAsync(getName(), codec, EVAL_FAST_REMOVE, "redis.call('zrem', KEYS[3], unpack(ARGV)); " + - "redis.call('zrem', KEYS[2], 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;" + "return redis.call('hdel', KEYS[1], unpack(ARGV)); ", - Arrays.asList(getName(), getTimeoutSetName(), getIdleSetName()), keys); + Arrays.asList(getName(), getTimeoutSetName(), getIdleSetName(), getRemovedChannelName()), + keys); } @Override @@ -762,10 +894,44 @@ public class RedissonMapCache extends RedissonMap implements RMapCac checkKey(key); checkValue(value); - return commandExecutor.evalWriteAsync(getName(key), codec, EVAL_HSET, - "local val = struct.pack('dLc0', 0, string.len(ARGV[2]), ARGV[2]); " - + "return redis.call('hset', KEYS[1], ARGV[1], val); ", - Collections.singletonList(getName(key)), key, value); + return commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_BOOLEAN, + "local insertable = false; " + + "local v = redis.call('hget', KEYS[1], ARGV[2]); " + + "if v == false then " + + "insertable = true; " + + "else " + + "local t, val = struct.unpack('dLc0', v); " + + "local expireDate = 92233720368547758; " + + "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 " + + "expireDate = math.min(expireDate, tonumber(expireIdle)) " + + "end; " + + "end; " + + "if expireDate <= tonumber(ARGV[1]) then " + + "insertable = true; " + + "end; " + + "end; " + + + "local val = struct.pack('dLc0', 0, string.len(ARGV[3]), ARGV[3]); " + + "redis.call('hset', KEYS[1], ARGV[2], val); " + + + "if insertable == true then " + + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3]); " + + "redis.call('publish', KEYS[4], msg); " + + "return 1;" + + "else " + + "local t, val = struct.unpack('dLc0', v); " + + "local msg = struct.pack('Lc0Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3], string.len(val), val); " + + "redis.call('publish', KEYS[5], msg); " + + "return 0;" + + "end;", + Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelName(), getUpdatedChannelName()), + System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value)); } @Override @@ -773,11 +939,13 @@ public class RedissonMapCache extends RedissonMap implements RMapCac checkKey(key); checkValue(value); - return commandExecutor.evalWriteAsync(getName(key), codec, EVAL_PUT_IF_ABSENT, + return commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_BOOLEAN, "local value = redis.call('hget', KEYS[1], ARGV[2]); " + "if value == false then " + "local val = struct.pack('dLc0', 0, string.len(ARGV[3]), ARGV[3]); " + "redis.call('hset', KEYS[1], ARGV[2], val); " + + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3]); " + + "redis.call('publish', KEYS[4], msg); " + "return 1; " + "end; " + "local t, val = struct.unpack('dLc0', value); " @@ -805,8 +973,12 @@ public class RedissonMapCache extends RedissonMap implements RMapCac + "redis.call('zrem', KEYS[3], ARGV[2]); " + "local val = struct.pack('dLc0', 0, string.len(ARGV[3]), ARGV[3]); " + "redis.call('hset', KEYS[1], ARGV[2], val); " + + + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3]); " + + "redis.call('publish', KEYS[4], msg); " + "return 1; ", - Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key)), System.currentTimeMillis(), key, value); + Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelName()), + System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value)); } @Override @@ -854,7 +1026,7 @@ public class RedissonMapCache extends RedissonMap implements RMapCac maxIdleTimeout = System.currentTimeMillis() + maxIdleDelta; } - return commandExecutor.evalWriteAsync(getName(key), codec, EVAL_FAST_PUT_TTL_IF_ABSENT, + return commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_BOOLEAN, "local insertable = false; " + "local value = redis.call('hget', KEYS[1], ARGV[5]); " + "if value == false then " @@ -898,11 +1070,15 @@ public class RedissonMapCache extends RedissonMap implements RMapCac + "local val = struct.pack('dLc0', ARGV[4], string.len(ARGV[6]), ARGV[6]); " + "redis.call('hset', KEYS[1], ARGV[5], val); " + + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[5]), ARGV[5], string.len(ARGV[6]), ARGV[6]); " + + "redis.call('publish', KEYS[4], msg); " + + "return 1; " + "else " + "return 0; " + "end; ", - Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key)), System.currentTimeMillis(), ttlTimeout, maxIdleTimeout, maxIdleDelta, key, value); + Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelName()), + System.currentTimeMillis(), ttlTimeout, maxIdleTimeout, maxIdleDelta, encodeMapKey(key), encodeMapValue(value)); } @Override @@ -915,7 +1091,7 @@ public class RedissonMapCache extends RedissonMap implements RMapCac throw new NullPointerException("map new value can't be null"); } - return commandExecutor.evalWriteAsync(getName(key), codec, EVAL_REPLACE_VALUE, + return commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_BOOLEAN, "local v = redis.call('hget', KEYS[1], ARGV[2]); " + "if v == false then " + "return 0;" @@ -939,12 +1115,16 @@ public class RedissonMapCache extends RedissonMap implements RMapCac + "end; " + "end; " + "if expireDate > tonumber(ARGV[1]) and val == ARGV[3] then " + + "local msg = struct.pack('Lc0Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[4]), ARGV[4], string.len(ARGV[3]), ARGV[3]); " + + "redis.call('publish', KEYS[4], msg); " + + "local value = struct.pack('dLc0', t, string.len(ARGV[4]), ARGV[4]); " + "redis.call('hset', KEYS[1], ARGV[2], value); " + "return 1; " + "end; " + "return 0; ", - Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key)), System.currentTimeMillis(), key, oldValue, newValue); + Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getUpdatedChannelName()), + System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(oldValue), encodeMapValue(newValue)); } @Override @@ -961,11 +1141,16 @@ public class RedissonMapCache extends RedissonMap implements RMapCac + "end; " + "local value = struct.pack('dLc0', t, string.len(ARGV[3]), ARGV[3]); " + "redis.call('hset', KEYS[1], ARGV[2], value); " + + + "local msg = struct.pack('Lc0Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3], string.len(val), val); " + + "redis.call('publish', KEYS[3], msg); " + + "return val; " + "else " + "return nil; " + "end", - Arrays.asList(getName(key), getTimeoutSetNameByKey(key)), System.currentTimeMillis(), key, value); + Arrays.asList(getName(key), getTimeoutSetNameByKey(key), getUpdatedChannelName()), + System.currentTimeMillis(), key, value); } @Override @@ -992,10 +1177,85 @@ public class RedissonMapCache extends RedissonMap implements RMapCac + "if i % 2 == 0 then " + "local val = struct.pack('dLc0', 0, string.len(value), value); " + "ARGV[i] = val; " + + "local key = ARGV[i-1];" + + + "local msg = struct.pack('Lc0Lc0', string.len(key), key, string.len(value), value); " + + "redis.call('publish', KEYS[2], msg); " + "end;" + "end;" + "return redis.call('hmset', KEYS[1], unpack(ARGV)); ", - Collections.singletonList(getName()), params.toArray()); + Arrays.asList(getName(), getCreatedChannelName()), params.toArray()); + } + + @Override + public int addListener(final MapEntryListener listener) { + if (listener == null) { + throw new NullPointerException(); + } + + if (listener instanceof EntryRemovedListener) { + RTopic> topic = redisson.getTopic(getRemovedChannelName(), new MapCacheEventCodec(codec)); + return topic.addListener(new MessageListener>() { + @Override + public void onMessage(String channel, List msg) { + System.out.println("channel: " + channel); + System.out.println("msg: " + msg); + + EntryEvent event = new EntryEvent(RedissonMapCache.this, EntryEvent.Type.REMOVED, (K)msg.get(0), (V)msg.get(1), null); + ((EntryRemovedListener) listener).onRemoved(event); + } + }); + } + + if (listener instanceof EntryCreatedListener) { + RTopic> topic = redisson.getTopic(getCreatedChannelName(), new MapCacheEventCodec(codec)); + return topic.addListener(new MessageListener>() { + @Override + public void onMessage(String channel, List msg) { + EntryEvent event = new EntryEvent(RedissonMapCache.this, EntryEvent.Type.CREATED, (K)msg.get(0), (V)msg.get(1), null); + ((EntryCreatedListener) listener).onCreated(event); + } + }); + } + + if (listener instanceof EntryUpdatedListener) { + RTopic> topic = redisson.getTopic(getUpdatedChannelName(), new MapCacheEventCodec(codec)); + return topic.addListener(new MessageListener>() { + @Override + public void onMessage(String channel, List msg) { + EntryEvent event = new EntryEvent(RedissonMapCache.this, EntryEvent.Type.UPDATED, (K)msg.get(0), (V)msg.get(1), (V)msg.get(2)); + ((EntryUpdatedListener) listener).onUpdated(event); + } + }); + } + + if (listener instanceof EntryExpiredListener) { + RTopic> topic = redisson.getTopic(getExpiredChannelName(), new MapCacheEventCodec(codec)); + return topic.addListener(new MessageListener>() { + @Override + public void onMessage(String channel, List msg) { + EntryEvent event = new EntryEvent(RedissonMapCache.this, EntryEvent.Type.EXPIRED, (K)msg.get(0), (V)msg.get(1), null); + ((EntryExpiredListener) listener).onExpired(event); + } + }); + } + + throw new IllegalArgumentException("Wrong listener type " + listener.getClass()); + } + + @Override + public void removeListener(int listenerId) { + RTopic> removedTopic = redisson.getTopic(getRemovedChannelName(), new MapCacheEventCodec(codec)); + removedTopic.removeListener(listenerId); + + RTopic> createdTopic = redisson.getTopic(getCreatedChannelName(), new MapCacheEventCodec(codec)); + createdTopic.removeListener(listenerId); + + RTopic> updatedTopic = redisson.getTopic(getUpdatedChannelName(), new MapCacheEventCodec(codec)); + updatedTopic.removeListener(listenerId); + + RTopic> expiredTopic = redisson.getTopic(getExpiredChannelName(), new MapCacheEventCodec(codec)); + expiredTopic.removeListener(listenerId); } @Override diff --git a/redisson/src/main/java/org/redisson/api/RMapCache.java b/redisson/src/main/java/org/redisson/api/RMapCache.java index c59be9beb..9365f74b2 100644 --- a/redisson/src/main/java/org/redisson/api/RMapCache.java +++ b/redisson/src/main/java/org/redisson/api/RMapCache.java @@ -17,6 +17,8 @@ package org.redisson.api; import java.util.concurrent.TimeUnit; +import org.redisson.api.map.event.MapEntryListener; + /** *

Map-based cache with ability to set TTL for each entry via * {@link #put(Object, Object, long, TimeUnit)} or {@link #putIfAbsent(Object, Object, long, TimeUnit)} @@ -130,6 +132,7 @@ public interface RMapCache extends RMap, RMapCacheAsync { * @param ttl - time to live for key\value entry. * If 0 then stores infinitely. * @param ttlUnit - time unit + * * @return true if key is a new key in the hash and value was set. * false if key already exists in the hash and the value was updated. */ @@ -177,6 +180,7 @@ public interface RMapCache extends RMap, RMapCacheAsync { * @param ttl - time to live for key\value entry. * If 0 then stores infinitely. * @param ttlUnit - time unit + * * @return true if key is a new key in the hash and value was set. * false if key already exists in the hash */ @@ -218,4 +222,24 @@ public interface RMapCache extends RMap, RMapCacheAsync { @Override int size(); + /** + * Adds map entry listener + * + * @see org.redisson.api.map.event.EntryCreatedListener + * @see org.redisson.api.map.event.EntryUpdatedListener + * @see org.redisson.api.map.event.EntryRemovedListener + * @see org.redisson.api.map.event.EntryExpiredListener + * + * @param listener - entry listener + * @return listener id + */ + int addListener(MapEntryListener listener); + + /** + * Removes map entry listener + * + * @param listenerId - listener id + */ + void removeListener(int listenerId); + } diff --git a/redisson/src/main/java/org/redisson/api/RMapCacheAsync.java b/redisson/src/main/java/org/redisson/api/RMapCacheAsync.java index 8eb0a8698..0e7188cc6 100644 --- a/redisson/src/main/java/org/redisson/api/RMapCacheAsync.java +++ b/redisson/src/main/java/org/redisson/api/RMapCacheAsync.java @@ -134,7 +134,9 @@ public interface RMapCacheAsync extends RMapAsync { * @param ttl - time to live for key\value entry. * If 0 then stores infinitely. * @param unit - time unit - * @return true if value has been set successfully + * + * @return true if key is a new key in the hash and value was set. + * false if key already exists in the hash and the value was updated. */ RFuture fastPutAsync(K key, V value, long ttl, TimeUnit unit); @@ -160,7 +162,8 @@ public interface RMapCacheAsync extends RMapAsync { * if maxIdleTime and ttl params are equal to 0 * then entry stores infinitely. - * @return true if value has been set successfully + * @return true if key is a new key in the hash and value was set. + * false if key already exists in the hash and the value was updated. */ RFuture fastPutAsync(K key, V value, long ttl, TimeUnit ttlUnit, long maxIdleTime, TimeUnit maxIdleUnit); @@ -186,7 +189,8 @@ public interface RMapCacheAsync extends RMapAsync { * if maxIdleTime and ttl params are equal to 0 * then entry stores infinitely. * - * @return previous associated value + * @return true if key is a new key in the hash and value was set. + * false if key already exists in the hash */ RFuture fastPutIfAbsentAsync(K key, V value, long ttl, TimeUnit ttlUnit, long maxIdleTime, TimeUnit maxIdleUnit); diff --git a/redisson/src/main/java/org/redisson/api/map/event/EntryCreatedListener.java b/redisson/src/main/java/org/redisson/api/map/event/EntryCreatedListener.java new file mode 100644 index 000000000..460e426ec --- /dev/null +++ b/redisson/src/main/java/org/redisson/api/map/event/EntryCreatedListener.java @@ -0,0 +1,29 @@ +/** + * Copyright 2016 Nikita Koksharov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.redisson.api.map.event; + +/** + * + * @author Nikita Koksharov + * + * @param key type + * @param value type + */ +public interface EntryCreatedListener extends MapEntryListener { + + void onCreated(EntryEvent event); + +} diff --git a/redisson/src/main/java/org/redisson/api/map/event/EntryEvent.java b/redisson/src/main/java/org/redisson/api/map/event/EntryEvent.java new file mode 100644 index 000000000..0fadd3bce --- /dev/null +++ b/redisson/src/main/java/org/redisson/api/map/event/EntryEvent.java @@ -0,0 +1,66 @@ +/** + * Copyright 2016 Nikita Koksharov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.redisson.api.map.event; + +import org.redisson.api.RMapCache; + +/** + * + * @author Nikita Koksharov + * + * @param key type + * @param value type + */ +public class EntryEvent { + + public enum Type {CREATED, UPDATED, REMOVED, EXPIRED} + + private RMapCache source; + private Type type; + private K key; + private V value; + private V oldValue; + + public EntryEvent(RMapCache source, Type type, K key, V value, V oldValue) { + super(); + this.source = source; + this.type = type; + this.key = key; + this.value = value; + this.oldValue = oldValue; + } + + public RMapCache getSource() { + return source; + } + + public Type getType() { + return type; + } + + public K getKey() { + return key; + } + + public V getOldValue() { + return oldValue; + } + + public V getValue() { + return value; + } + +} diff --git a/redisson/src/main/java/org/redisson/api/map/event/EntryExpiredListener.java b/redisson/src/main/java/org/redisson/api/map/event/EntryExpiredListener.java new file mode 100644 index 000000000..d79c9ab63 --- /dev/null +++ b/redisson/src/main/java/org/redisson/api/map/event/EntryExpiredListener.java @@ -0,0 +1,29 @@ +/** + * Copyright 2016 Nikita Koksharov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.redisson.api.map.event; + +/** + * + * @author Nikita Koksharov + * + * @param key type + * @param value type + */ +public interface EntryExpiredListener extends MapEntryListener { + + void onExpired(EntryEvent event); + +} diff --git a/redisson/src/main/java/org/redisson/api/map/event/EntryRemovedListener.java b/redisson/src/main/java/org/redisson/api/map/event/EntryRemovedListener.java new file mode 100644 index 000000000..32be8ed24 --- /dev/null +++ b/redisson/src/main/java/org/redisson/api/map/event/EntryRemovedListener.java @@ -0,0 +1,29 @@ +/** + * Copyright 2016 Nikita Koksharov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.redisson.api.map.event; + +/** + * + * @author Nikita Koksharov + * + * @param key type + * @param value type + */ +public interface EntryRemovedListener extends MapEntryListener { + + void onRemoved(EntryEvent event); + +} diff --git a/redisson/src/main/java/org/redisson/api/map/event/EntryUpdatedListener.java b/redisson/src/main/java/org/redisson/api/map/event/EntryUpdatedListener.java new file mode 100644 index 000000000..897d2d82d --- /dev/null +++ b/redisson/src/main/java/org/redisson/api/map/event/EntryUpdatedListener.java @@ -0,0 +1,29 @@ +/** + * Copyright 2016 Nikita Koksharov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.redisson.api.map.event; + +/** + * + * @author Nikita Koksharov + * + * @param key type + * @param value type + */ +public interface EntryUpdatedListener extends MapEntryListener { + + void onUpdated(EntryEvent event); + +} diff --git a/redisson/src/main/java/org/redisson/api/map/event/MapEntryListener.java b/redisson/src/main/java/org/redisson/api/map/event/MapEntryListener.java new file mode 100644 index 000000000..4da2fe803 --- /dev/null +++ b/redisson/src/main/java/org/redisson/api/map/event/MapEntryListener.java @@ -0,0 +1,27 @@ +/** + * Copyright 2016 Nikita Koksharov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.redisson.api.map.event; + +import java.util.EventListener; + +/** + * + * @author Nikita Koksharov + * + */ +public interface MapEntryListener extends EventListener { + +} diff --git a/redisson/src/main/java/org/redisson/codec/CustomObjectInputStream.java b/redisson/src/main/java/org/redisson/codec/CustomObjectInputStream.java index 3947c1088..1329e513d 100644 --- a/redisson/src/main/java/org/redisson/codec/CustomObjectInputStream.java +++ b/redisson/src/main/java/org/redisson/codec/CustomObjectInputStream.java @@ -20,6 +20,11 @@ import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectStreamClass; +/** + * + * @author Nikita Koksharov + * + */ public class CustomObjectInputStream extends ObjectInputStream { private ClassLoader classLoader; diff --git a/redisson/src/main/java/org/redisson/codec/MapCacheEventCodec.java b/redisson/src/main/java/org/redisson/codec/MapCacheEventCodec.java new file mode 100644 index 000000000..0cad09901 --- /dev/null +++ b/redisson/src/main/java/org/redisson/codec/MapCacheEventCodec.java @@ -0,0 +1,106 @@ +/** + * Copyright 2016 Nikita Koksharov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.redisson.codec; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.redisson.client.codec.Codec; +import org.redisson.client.handler.State; +import org.redisson.client.protocol.Decoder; +import org.redisson.client.protocol.Encoder; + +import io.netty.buffer.ByteBuf; +import io.netty.util.internal.PlatformDependent; + +/** + * + * @author Nikita Koksharov + * + */ +public class MapCacheEventCodec implements Codec { + + private final Codec codec; + + private final Decoder decoder = new Decoder() { + @Override + public Object decode(ByteBuf buf, State state) throws IOException { + List result = new ArrayList(3); + + Object key = MapCacheEventCodec.this.decode(buf, state, codec.getMapKeyDecoder()); + result.add(key); + + Object value = MapCacheEventCodec.this.decode(buf, state, codec.getMapValueDecoder()); + result.add(value); + + if (buf.isReadable()) { + Object oldValue = MapCacheEventCodec.this.decode(buf, state, codec.getMapValueDecoder()); + result.add(oldValue); + } + + return result; + } + }; + + public MapCacheEventCodec(Codec codec) { + super(); + this.codec = codec; + } + + @Override + public Decoder getMapValueDecoder() { + throw new UnsupportedOperationException(); + } + + @Override + public Encoder getMapValueEncoder() { + throw new UnsupportedOperationException(); + } + + @Override + public Decoder getMapKeyDecoder() { + throw new UnsupportedOperationException(); + } + + @Override + public Encoder getMapKeyEncoder() { + throw new UnsupportedOperationException(); + } + + @Override + public Decoder getValueDecoder() { + return decoder; + } + + @Override + public Encoder getValueEncoder() { + throw new UnsupportedOperationException(); + } + + private Object decode(ByteBuf buf, State state, Decoder decoder) throws IOException { + int keyLen; + if (PlatformDependent.isWindows()) { + keyLen = buf.readIntLE(); + } else { + keyLen = (int) buf.readLongLE(); + } + ByteBuf keyBuf = buf.readSlice(keyLen); + Object key = decoder.decode(keyBuf, state); + return key; + } + +} diff --git a/redisson/src/main/java/org/redisson/eviction/EvictionScheduler.java b/redisson/src/main/java/org/redisson/eviction/EvictionScheduler.java index 6f229ff90..cb86f0760 100644 --- a/redisson/src/main/java/org/redisson/eviction/EvictionScheduler.java +++ b/redisson/src/main/java/org/redisson/eviction/EvictionScheduler.java @@ -63,8 +63,8 @@ public class EvictionScheduler { } } - public void schedule(String name, String timeoutSetName, String maxIdleSetName) { - EvictionTask task = new MapCacheEvictionTask(name, timeoutSetName, maxIdleSetName, executor); + public void schedule(String name, String timeoutSetName, String maxIdleSetName, String expiredChannelName) { + EvictionTask task = new MapCacheEvictionTask(name, timeoutSetName, maxIdleSetName, expiredChannelName, executor); EvictionTask prevTask = tasks.putIfAbsent(name, task); if (prevTask == null) { task.schedule(); diff --git a/redisson/src/main/java/org/redisson/eviction/EvictionTask.java b/redisson/src/main/java/org/redisson/eviction/EvictionTask.java index 346b1036c..8f3daccac 100644 --- a/redisson/src/main/java/org/redisson/eviction/EvictionTask.java +++ b/redisson/src/main/java/org/redisson/eviction/EvictionTask.java @@ -34,7 +34,7 @@ abstract class EvictionTask implements Runnable { final Deque sizeHistory = new LinkedList(); final int minDelay = 1; - final int maxDelay = 2*60*60; + final int maxDelay = 30*60; final int keysLimit = 300; int delay = 10; diff --git a/redisson/src/main/java/org/redisson/eviction/MapCacheEvictionTask.java b/redisson/src/main/java/org/redisson/eviction/MapCacheEvictionTask.java index 9c6e0341f..f40f43354 100644 --- a/redisson/src/main/java/org/redisson/eviction/MapCacheEvictionTask.java +++ b/redisson/src/main/java/org/redisson/eviction/MapCacheEvictionTask.java @@ -32,31 +32,49 @@ public class MapCacheEvictionTask extends EvictionTask { private final String name; private final String timeoutSetName; private final String maxIdleSetName; + private final String expiredChannelName; - public MapCacheEvictionTask(String name, String timeoutSetName, String maxIdleSetName, CommandAsyncExecutor executor) { + public MapCacheEvictionTask(String name, String timeoutSetName, String maxIdleSetName, String expiredChannelName, CommandAsyncExecutor executor) { super(executor); this.name = name; this.timeoutSetName = timeoutSetName; this.maxIdleSetName = maxIdleSetName; + this.expiredChannelName = expiredChannelName; } @Override RFuture execute() { return executor.evalWriteAsync(name, LongCodec.INSTANCE, RedisCommands.EVAL_INTEGER, "local expiredKeys1 = redis.call('zrangebyscore', KEYS[2], 0, ARGV[1], 'limit', 0, ARGV[2]); " + + "for i, key in ipairs(expiredKeys1) 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;" + "if #expiredKeys1 > 0 then " + "redis.call('zrem', KEYS[3], unpack(expiredKeys1)); " + "redis.call('zrem', KEYS[2], unpack(expiredKeys1)); " + "redis.call('hdel', KEYS[1], unpack(expiredKeys1)); " + "end; " + "local expiredKeys2 = redis.call('zrangebyscore', KEYS[3], 0, ARGV[1], 'limit', 0, ARGV[2]); " + + "for i, key in ipairs(expiredKeys2) 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;" + "if #expiredKeys2 > 0 then " + "redis.call('zrem', KEYS[3], unpack(expiredKeys2)); " + "redis.call('zrem', KEYS[2], unpack(expiredKeys2)); " + "redis.call('hdel', KEYS[1], unpack(expiredKeys2)); " + "end; " + "return #expiredKeys1 + #expiredKeys2;", - Arrays.asList(name, timeoutSetName, maxIdleSetName), System.currentTimeMillis(), keysLimit); + Arrays.asList(name, timeoutSetName, maxIdleSetName, expiredChannelName), System.currentTimeMillis(), keysLimit); } } diff --git a/redisson/src/main/java/org/redisson/reactive/RedissonMapCacheReactive.java b/redisson/src/main/java/org/redisson/reactive/RedissonMapCacheReactive.java index 94f0cd1c4..ad756c24d 100644 --- a/redisson/src/main/java/org/redisson/reactive/RedissonMapCacheReactive.java +++ b/redisson/src/main/java/org/redisson/reactive/RedissonMapCacheReactive.java @@ -70,12 +70,12 @@ public class RedissonMapCacheReactive extends RedissonExpirableReactive im public RedissonMapCacheReactive(UUID id, EvictionScheduler evictionScheduler, CommandReactiveExecutor commandExecutor, String name) { super(commandExecutor, name); - this.mapCache = new RedissonMapCache(id, evictionScheduler, commandExecutor, name, null); + this.mapCache = new RedissonMapCache(evictionScheduler, commandExecutor, name, null); } public RedissonMapCacheReactive(UUID id, EvictionScheduler evictionScheduler, Codec codec, CommandReactiveExecutor commandExecutor, String name) { super(codec, commandExecutor, name); - this.mapCache = new RedissonMapCache(id, codec, evictionScheduler, commandExecutor, name, null); + this.mapCache = new RedissonMapCache(codec, evictionScheduler, commandExecutor, name, null); } @Override diff --git a/redisson/src/main/java/org/redisson/reactive/RedissonMapReactive.java b/redisson/src/main/java/org/redisson/reactive/RedissonMapReactive.java index e291fcab4..360a39493 100644 --- a/redisson/src/main/java/org/redisson/reactive/RedissonMapReactive.java +++ b/redisson/src/main/java/org/redisson/reactive/RedissonMapReactive.java @@ -50,12 +50,12 @@ public class RedissonMapReactive extends RedissonExpirableReactive impleme public RedissonMapReactive(CommandReactiveExecutor commandExecutor, String name) { super(commandExecutor, name); - instance = new RedissonMap(null, codec, commandExecutor, name, null); + instance = new RedissonMap(codec, commandExecutor, name, null); } public RedissonMapReactive(Codec codec, CommandReactiveExecutor commandExecutor, String name) { super(codec, commandExecutor, name); - instance = new RedissonMap(null, codec, commandExecutor, name, null); + instance = new RedissonMap(codec, commandExecutor, name, null); } @Override diff --git a/redisson/src/test/java/org/redisson/RedissonMapCacheTest.java b/redisson/src/test/java/org/redisson/RedissonMapCacheTest.java index 541b893f8..1f687a65e 100644 --- a/redisson/src/test/java/org/redisson/RedissonMapCacheTest.java +++ b/redisson/src/test/java/org/redisson/RedissonMapCacheTest.java @@ -14,17 +14,26 @@ import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; import org.junit.Assert; 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.api.map.event.EntryCreatedListener; +import org.redisson.api.map.event.EntryEvent; +import org.redisson.api.map.event.EntryExpiredListener; +import org.redisson.api.map.event.EntryRemovedListener; +import org.redisson.api.map.event.EntryUpdatedListener; import org.redisson.client.codec.StringCodec; import org.redisson.codec.JsonJacksonCodec; import org.redisson.codec.MsgPackJacksonCodec; +import com.jayway.awaitility.Awaitility; +import com.jayway.awaitility.Duration; + public class RedissonMapCacheTest extends BaseTest { public static class SimpleKey implements Serializable { @@ -671,11 +680,164 @@ public class RedissonMapCacheTest extends BaseTest { } + @Test + public void testCreatedListener() { + RMapCache map = redisson.getMapCache("simple"); + + checkCreatedListener(map, 1, 2, () -> map.put(1, 2)); + checkCreatedListener(map, 10, 2, () -> map.put(10, 2, 2, TimeUnit.SECONDS)); + checkCreatedListener(map, 2, 5, () -> map.fastPut(2, 5)); + checkCreatedListener(map, 13, 2, () -> map.fastPut(13, 2, 2, TimeUnit.SECONDS)); + checkCreatedListener(map, 3, 2, () -> map.putIfAbsent(3, 2)); + checkCreatedListener(map, 14, 2, () -> map.putIfAbsent(14, 2, 2, TimeUnit.SECONDS)); + checkCreatedListener(map, 4, 1, () -> map.fastPutIfAbsent(4, 1)); + checkCreatedListener(map, 15, 2, () -> map.fastPutIfAbsent(15, 2, 2, TimeUnit.SECONDS)); + checkCreatedListener(map, 5, 0, () -> map.addAndGet(5, 0)); + } + + private void checkCreatedListener(RMapCache map, Integer key, Integer value, Runnable runnable) { + AtomicBoolean ref = new AtomicBoolean(); + int createListener1 = map.addListener(new EntryCreatedListener() { + + @Override + public void onCreated(EntryEvent event) { + assertThat(event.getKey()).isEqualTo(key); + assertThat(event.getValue()).isEqualTo(value); + + if (!ref.compareAndSet(false, true)) { + Assert.fail(); + } + } + + }); + runnable.run(); + + Awaitility.await().atMost(Duration.ONE_SECOND).untilTrue(ref); + map.removeListener(createListener1); + } + + @Test + public void testUpdatedListener() { + RMapCache map = redisson.getMapCache("simple"); + + map.put(1, 1); + checkUpdatedListener(map, 1, 3, 1, () -> map.put(1, 3)); + + map.put(10, 1); + checkUpdatedListener(map, 10, 2, 1, () -> map.put(10, 2, 2, TimeUnit.SECONDS)); + + map.put(2, 1); + checkUpdatedListener(map, 2, 5, 1, () -> map.fastPut(2, 5)); + + map.put(13, 1); + checkUpdatedListener(map, 13, 2, 1, () -> map.fastPut(13, 2, 2, TimeUnit.SECONDS)); + + map.put(14, 1); + checkUpdatedListener(map, 14, 2, 1, () -> map.replace(14, 2)); + checkUpdatedListener(map, 14, 3, 2, () -> map.replace(14, 2, 3)); + + map.put(5, 1); + checkUpdatedListener(map, 5, 4, 1, () -> map.addAndGet(5, 3)); + + } + + @Test + public void testExpiredListener() { + RMapCache map = redisson.getMapCache("simple"); + + checkExpiredListener(map, 10, 2, () -> map.put(10, 2, 2, TimeUnit.SECONDS)); + checkExpiredListener(map, 13, 2, () -> map.fastPut(13, 2, 2, TimeUnit.SECONDS)); + checkExpiredListener(map, 14, 2, () -> map.putIfAbsent(14, 2, 2, TimeUnit.SECONDS)); + checkExpiredListener(map, 15, 2, () -> map.fastPutIfAbsent(15, 2, 2, TimeUnit.SECONDS)); + } + + private void checkExpiredListener(RMapCache map, Integer key, Integer value, Runnable runnable) { + AtomicBoolean ref = new AtomicBoolean(); + int createListener1 = map.addListener(new EntryExpiredListener() { + + @Override + public void onExpired(EntryEvent event) { + assertThat(event.getKey()).isEqualTo(key); + assertThat(event.getValue()).isEqualTo(value); + + if (!ref.compareAndSet(false, true)) { + Assert.fail(); + } + } + + }); + runnable.run(); + + Awaitility.await().atMost(Duration.ONE_MINUTE).untilTrue(ref); + map.removeListener(createListener1); + } + + + private void checkUpdatedListener(RMapCache map, Integer key, Integer value, Integer oldValue, Runnable runnable) { + AtomicBoolean ref = new AtomicBoolean(); + int createListener1 = map.addListener(new EntryUpdatedListener() { + + @Override + public void onUpdated(EntryEvent event) { + assertThat(event.getKey()).isEqualTo(key); + assertThat(event.getValue()).isEqualTo(value); + assertThat(event.getOldValue()).isEqualTo(oldValue); + + if (!ref.compareAndSet(false, true)) { + Assert.fail(); + } + } + + }); + runnable.run(); + + Awaitility.await().atMost(Duration.ONE_SECOND).untilTrue(ref); + map.removeListener(createListener1); + } + + @Test + public void testRemovedListener() { + RMapCache map = redisson.getMapCache("simple"); + + map.put(1, 1); + checkRemovedListener(map, 1, 1, () -> map.remove(1, 1)); + + map.put(10, 1); + checkRemovedListener(map, 10, 1, () -> map.remove(10)); + + map.put(2, 1); + checkRemovedListener(map, 2, 1, () -> map.fastRemove(2)); + } + + private void checkRemovedListener(RMapCache map, Integer key, Integer value, Runnable runnable) { + AtomicBoolean ref = new AtomicBoolean(); + int createListener1 = map.addListener(new EntryRemovedListener() { + + @Override + public void onRemoved(EntryEvent event) { + assertThat(event.getKey()).isEqualTo(key); + assertThat(event.getValue()).isEqualTo(value); + + if (!ref.compareAndSet(false, true)) { + Assert.fail(); + } + } + + }); + runnable.run(); + + Awaitility.await().atMost(Duration.ONE_SECOND).untilTrue(ref); + map.removeListener(createListener1); + } + + @Test public void testFastPut() throws Exception { RMapCache map = redisson.getMapCache("simple"); Assert.assertTrue(map.fastPut(1, 2)); + assertThat(map.get(1)).isEqualTo(2); Assert.assertFalse(map.fastPut(1, 3)); + assertThat(map.get(1)).isEqualTo(3); Assert.assertEquals(1, map.size()); } From 68c9dc23fa7d680c54775abe8a872fef83ea725c Mon Sep 17 00:00:00 2001 From: Nikita Date: Wed, 7 Jun 2017 14:45:33 +0300 Subject: [PATCH 65/65] RedisConnection special constructor added --- .../src/main/java/org/redisson/client/RedisConnection.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/redisson/src/main/java/org/redisson/client/RedisConnection.java b/redisson/src/main/java/org/redisson/client/RedisConnection.java index eac5d2d52..ad67e1151 100644 --- a/redisson/src/main/java/org/redisson/client/RedisConnection.java +++ b/redisson/src/main/java/org/redisson/client/RedisConnection.java @@ -67,6 +67,10 @@ public class RedisConnection implements RedisCommands { lastUsageTime = System.currentTimeMillis(); } + protected RedisConnection(RedisClient redisClient) { + this.redisClient = redisClient; + } + public RPromise getConnectionPromise() { return (RPromise) connectionPromise; }