From 96b5701e586a5e0c52882a2740ca461b7f39f9af Mon Sep 17 00:00:00 2001 From: Paulo Lopes Date: Tue, 11 Oct 2022 16:05:11 +0200 Subject: [PATCH 1/3] Adding support for special doubles Signed-off-by: Paulo Lopes --- src/main/java/io/vertx/redis/client/Response.java | 12 +++++++++++- .../io/vertx/redis/client/impl/ReadableBuffer.java | 2 ++ .../java/io/vertx/test/redis/RedisClient7Test.java | 13 +++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/main/java/io/vertx/redis/client/Response.java b/src/main/java/io/vertx/redis/client/Response.java index 85ee1b5d..ab26c939 100644 --- a/src/main/java/io/vertx/redis/client/Response.java +++ b/src/main/java/io/vertx/redis/client/Response.java @@ -93,7 +93,17 @@ default Number toNumber() { default @Nullable Double toDouble() { final String msg = toString(); if (msg != null) { - return Double.parseDouble(msg); + switch (msg) { + case "-nan": + case "nan": + return Double.NaN; + case "inf": + return Double.POSITIVE_INFINITY; + case "-inf": + return Double.NEGATIVE_INFINITY; + default: + return Double.parseDouble(msg); + } } return null; } diff --git a/src/main/java/io/vertx/redis/client/impl/ReadableBuffer.java b/src/main/java/io/vertx/redis/client/impl/ReadableBuffer.java index b09b057e..ee7a20c4 100644 --- a/src/main/java/io/vertx/redis/client/impl/ReadableBuffer.java +++ b/src/main/java/io/vertx/redis/client/impl/ReadableBuffer.java @@ -113,6 +113,8 @@ Number readNumber(int end, NumericType type) { case DECIMAL: if (bytes.length == 3 && bytes[0] == 'i' && bytes[1] == 'n' && bytes[2] == 'f') { number = Double.POSITIVE_INFINITY; + } else if (bytes.length == 3 && bytes[0] == 'n' && bytes[1] == 'a' && bytes[2] == 'n') { + number = Double.NaN; } else if (bytes.length == 4 && bytes[0] == '-' && bytes[1] == 'i' && bytes[2] == 'n' && bytes[3] == 'f') { number = Double.NEGATIVE_INFINITY; } else { diff --git a/src/test/java/io/vertx/test/redis/RedisClient7Test.java b/src/test/java/io/vertx/test/redis/RedisClient7Test.java index 9432f9a0..b3401cf4 100644 --- a/src/test/java/io/vertx/test/redis/RedisClient7Test.java +++ b/src/test/java/io/vertx/test/redis/RedisClient7Test.java @@ -254,4 +254,17 @@ public void testBooleanVarArgs(TestContext should) { }); }); } + + @Test + public void testNaN(TestContext should) { + final Async test = should.async(); + final String key = makeKey(); + + client.send(cmd(EVAL).arg("return tostring(0/0)").arg(0)) + .onFailure(should::fail) + .onSuccess(ok -> { + should.assertTrue(Double.isNaN(ok.toDouble())); + test.complete(); + }); + } } From b8106c33d9dcf086561e23ddbc0420d2aa358f75 Mon Sep 17 00:00:00 2001 From: Paulo Lopes Date: Tue, 11 Oct 2022 16:07:10 +0200 Subject: [PATCH 2/3] Java doesn't support negative NaN but redis does seem to Signed-off-by: Paulo Lopes --- src/main/java/io/vertx/redis/client/impl/ReadableBuffer.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/io/vertx/redis/client/impl/ReadableBuffer.java b/src/main/java/io/vertx/redis/client/impl/ReadableBuffer.java index ee7a20c4..8c12666c 100644 --- a/src/main/java/io/vertx/redis/client/impl/ReadableBuffer.java +++ b/src/main/java/io/vertx/redis/client/impl/ReadableBuffer.java @@ -117,6 +117,8 @@ Number readNumber(int end, NumericType type) { number = Double.NaN; } else if (bytes.length == 4 && bytes[0] == '-' && bytes[1] == 'i' && bytes[2] == 'n' && bytes[3] == 'f') { number = Double.NEGATIVE_INFINITY; + } else if (bytes.length == 4 && bytes[0] == '-' && bytes[1] == 'n' && bytes[2] == 'a' && bytes[3] == 'n') { + number = Double.NaN; } else { number = Double.parseDouble(new String(bytes, StandardCharsets.US_ASCII)); } From 747695281f8164df603ae96f7f4b0c7356f74cee Mon Sep 17 00:00:00 2001 From: Paulo Lopes Date: Sat, 15 Oct 2022 14:03:52 +0200 Subject: [PATCH 3/3] Start collecting the initial set of servers from the DNS record Signed-off-by: Paulo Lopes --- .../java/io/vertx/redis/client/Redis.java | 2 +- .../redis/client/impl/RedisClusterClient.java | 19 ++++++- .../redis/client/test/RedisClusterTest.java | 49 +++++++++++++++++++ 3 files changed, 68 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/vertx/redis/client/Redis.java b/src/main/java/io/vertx/redis/client/Redis.java index 381d0c9d..717f2582 100644 --- a/src/main/java/io/vertx/redis/client/Redis.java +++ b/src/main/java/io/vertx/redis/client/Redis.java @@ -42,7 +42,7 @@ static Redis createClient(Vertx vertx) { } /** - * Create a new redis client using the default client options. Does not support rediss (redis over ssl scheme) for now. + * Create a new redis client using the default client options. * @param connectionString a string URI following the scheme: redis://[username:password@][host][:port][/database] * @param vertx the vertx instance * @return the client diff --git a/src/main/java/io/vertx/redis/client/impl/RedisClusterClient.java b/src/main/java/io/vertx/redis/client/impl/RedisClusterClient.java index 74cf885b..f58a2f0d 100644 --- a/src/main/java/io/vertx/redis/client/impl/RedisClusterClient.java +++ b/src/main/java/io/vertx/redis/client/impl/RedisClusterClient.java @@ -16,6 +16,7 @@ package io.vertx.redis.client.impl; import io.vertx.core.*; +import io.vertx.core.dns.DnsClient; import io.vertx.core.impl.logging.Logger; import io.vertx.core.impl.logging.LoggerFactory; import io.vertx.redis.client.*; @@ -120,10 +121,14 @@ public static void addMasterOnlyCommand(Command command) { } private final RedisOptions options; + private final DnsClient dns; public RedisClusterClient(Vertx vertx, RedisOptions options) { super(vertx, options); this.options = options; + // TODO: allow DNS options + this.dns = vertx.createDnsClient(); + // validate options if (options.getMaxPoolWaiting() < options.getMaxPoolSize()) { throw new IllegalStateException("Invalid options: maxPoolWaiting < maxPoolSize"); @@ -136,7 +141,19 @@ public RedisClusterClient(Vertx vertx, RedisOptions options) { public Future connect() { final Promise promise = vertx.promise(); // attempt to load the slots from the first good endpoint - connect(options.getEndpoints(), 0, promise); + List endpoints = options.getEndpoints(); + if (endpoints.size() == 1) { + dns.resolveA(endpoints.get(0)) + .onFailure(err -> { + // default to regular single node lookup + connect(options.getEndpoints(), 0, promise); + }) + .onSuccess(resolvedEndpoints -> { + connect(resolvedEndpoints, 0, promise); + }); + } else { + connect(options.getEndpoints(), 0, promise); + } return promise.future(); } diff --git a/src/test/java/io/vertx/redis/client/test/RedisClusterTest.java b/src/test/java/io/vertx/redis/client/test/RedisClusterTest.java index 663350f0..79cdbb23 100644 --- a/src/test/java/io/vertx/redis/client/test/RedisClusterTest.java +++ b/src/test/java/io/vertx/redis/client/test/RedisClusterTest.java @@ -1114,4 +1114,53 @@ public void testCommandWithoutReadOrWrite(TestContext should) { }); }); } + + @Test(timeout = 30_000) + public void autoFindNodesByName(TestContext should) { + final Async test = should.async(); + + final RedisOptions options = new RedisOptions() + .setType(RedisClientType.CLUSTER) + .setConnectionString("redis://localhost:7000") + // we will flood the redis server + .setMaxWaitingHandlers(128 * 1024) + .setMaxPoolSize(8) + .setMaxPoolWaiting(16); + + // we only provide 1 node + + final Redis client2 = Redis.createClient(rule.vertx(), options); + + client2 + .connect(onCreate -> { + should.assertTrue(onCreate.succeeded()); + + final RedisConnection cluster = onCreate.result(); + cluster.exceptionHandler(should::fail); + + final int len = (int) Math.pow(2, 17); + final AtomicInteger counter = new AtomicInteger(); + + for (int i = 0; i < len; i++) { + final String id = Integer.toString(i); + cluster.send(cmd(SET).arg(id).arg(id), set -> { + should.assertTrue(set.succeeded()); + cluster.send(cmd(GET).arg(id), get -> { + should.assertTrue(get.succeeded()); + should.assertEquals(id, get.result().toString()); + + final int cnt = counter.incrementAndGet(); + if (cnt % 1024 == 0) { + System.out.print('.'); + } + + if (cnt == len) { + client2.close(); + test.complete(); + } + }); + }); + } + }); + } }