diff --git a/java/README.md b/java/README.md index b7023d1716..07a5fc7b49 100644 --- a/java/README.md +++ b/java/README.md @@ -7,11 +7,16 @@ is a work in progress and is not yet complete or fully tested. Your contribution we work towards refining and improving this implementation. Thank you for your interest and understanding as we continue to develop this Java wrapper. +The Java client contains the following parts: + +1. A Java client (lib folder): wrapper to rust client. +2. A benchmark app: A dedicated benchmarking tool designed to evaluate and compare the performance of Babushka and other Java clients. + ## Installation and Setup ### Install from Gradle -At the moment, the Java client must be build from source. +At the moment, the Java client must be built from source. ### Build from source @@ -118,9 +123,3 @@ The following arguments are accepted: * `host`: redis server host url * `port`: redis server port number * `tls`: redis TLS configured - -### Troubleshooting - -* Connection Timeout: - * If you're unable to connect to redis, check that you are connecting to the correct host, port, and TLS configuration. -* Only server-side certificates are supported by the TLS configured redis. diff --git a/java/benchmarks/build.gradle b/java/benchmarks/build.gradle index 5ec8124134..2a641a307a 100644 --- a/java/benchmarks/build.gradle +++ b/java/benchmarks/build.gradle @@ -9,9 +9,6 @@ repositories { } dependencies { - // Use JUnit test framework. - testImplementation 'org.junit.jupiter:junit-jupiter:5.9.2' - // This dependency is used internally, and not exposed to consumers on their own compile classpath. implementation 'com.google.guava:guava:32.1.1-jre' implementation 'redis.clients:jedis:4.4.3' @@ -34,11 +31,3 @@ application { // Define the main class for the application. mainClass = 'babushka.benchmarks.BenchmarkingApp' } - -tasks.withType(Test) { - testLogging { - exceptionFormat "full" - events "started", "skipped", "passed", "failed" - showStandardStreams true - } -} diff --git a/java/benchmarks/src/main/java/babushka/benchmarks/BenchmarkingApp.java b/java/benchmarks/src/main/java/babushka/benchmarks/BenchmarkingApp.java index f9d043000a..963a8fc010 100644 --- a/java/benchmarks/src/main/java/babushka/benchmarks/BenchmarkingApp.java +++ b/java/benchmarks/src/main/java/babushka/benchmarks/BenchmarkingApp.java @@ -1,5 +1,9 @@ package babushka.benchmarks; +import static babushka.benchmarks.utils.Benchmarking.testClientSetGet; + +import babushka.benchmarks.clients.jedis.JedisClient; +import babushka.benchmarks.clients.lettuce.LettuceAsyncClient; import java.util.Arrays; import java.util.Optional; import java.util.stream.Stream; @@ -43,10 +47,12 @@ public static void main(String[] args) { case JEDIS: // run testClientSetGet on JEDIS sync client System.out.println("Run JEDIS sync client"); + testClientSetGet(JedisClient::new, runConfiguration, false); break; case LETTUCE: // run testClientSetGet on LETTUCE async client System.out.println("Run LETTUCE async client"); + testClientSetGet(LettuceAsyncClient::new, runConfiguration, true); break; case BABUSHKA: System.out.println("Babushka async not yet configured"); diff --git a/java/benchmarks/src/main/java/babushka/benchmarks/clients/jedis/JedisClient.java b/java/benchmarks/src/main/java/babushka/benchmarks/clients/jedis/JedisClient.java new file mode 100644 index 0000000000..764235df27 --- /dev/null +++ b/java/benchmarks/src/main/java/babushka/benchmarks/clients/jedis/JedisClient.java @@ -0,0 +1,52 @@ +package babushka.benchmarks.clients.jedis; + +import babushka.benchmarks.clients.SyncClient; +import babushka.benchmarks.utils.ConnectionSettings; +import java.util.Set; +import redis.clients.jedis.DefaultJedisClientConfig; +import redis.clients.jedis.HostAndPort; +import redis.clients.jedis.JedisCluster; +import redis.clients.jedis.JedisPool; +import redis.clients.jedis.commands.JedisCommands; + +/** A Jedis client with sync capabilities. See: https://github.com/redis/jedis */ +public class JedisClient implements SyncClient { + + private JedisCommands jedis; + + @Override + public void closeConnection() { + // nothing to do + } + + @Override + public String getName() { + return "Jedis"; + } + + @Override + public void connectToRedis(ConnectionSettings connectionSettings) { + if (connectionSettings.clusterMode) { + jedis = + new JedisCluster( + Set.of(new HostAndPort(connectionSettings.host, connectionSettings.port)), + DefaultJedisClientConfig.builder().ssl(connectionSettings.useSsl).build()); + } else { + try (JedisPool pool = + new JedisPool( + connectionSettings.host, connectionSettings.port, connectionSettings.useSsl)) { + jedis = pool.getResource(); + } + } + } + + @Override + public void set(String key, String value) { + jedis.set(key, value); + } + + @Override + public String get(String key) { + return jedis.get(key); + } +} diff --git a/java/benchmarks/src/main/java/babushka/benchmarks/clients/lettuce/LettuceAsyncClient.java b/java/benchmarks/src/main/java/babushka/benchmarks/clients/lettuce/LettuceAsyncClient.java new file mode 100644 index 0000000000..1290acbdfd --- /dev/null +++ b/java/benchmarks/src/main/java/babushka/benchmarks/clients/lettuce/LettuceAsyncClient.java @@ -0,0 +1,64 @@ +package babushka.benchmarks.clients.lettuce; + +import babushka.benchmarks.clients.AsyncClient; +import babushka.benchmarks.utils.ConnectionSettings; +import io.lettuce.core.AbstractRedisClient; +import io.lettuce.core.RedisClient; +import io.lettuce.core.RedisFuture; +import io.lettuce.core.RedisURI; +import io.lettuce.core.api.StatefulConnection; +import io.lettuce.core.api.StatefulRedisConnection; +import io.lettuce.core.api.async.RedisStringAsyncCommands; +import io.lettuce.core.cluster.RedisClusterClient; +import io.lettuce.core.cluster.api.StatefulRedisClusterConnection; +import java.time.Duration; + +/** A Lettuce client with async capabilities see: https://lettuce.io/ */ +public class LettuceAsyncClient implements AsyncClient { + static final int ASYNC_OPERATION_TIMEOUT_SEC = 1; + + private AbstractRedisClient client; + private RedisStringAsyncCommands asyncCommands; + private StatefulConnection connection; + + @Override + public void connectToRedis(ConnectionSettings connectionSettings) { + RedisURI uri = + RedisURI.builder() + .withHost(connectionSettings.host) + .withPort(connectionSettings.port) + .withSsl(connectionSettings.useSsl) + .build(); + if (connectionSettings.clusterMode) { + client = RedisClient.create(uri); + connection = ((RedisClient) client).connect(); + asyncCommands = ((StatefulRedisConnection) connection).async(); + } else { + client = RedisClusterClient.create(uri); + connection = ((RedisClusterClient) client).connect(); + asyncCommands = ((StatefulRedisClusterConnection) connection).async(); + } + connection.setTimeout(Duration.ofSeconds(ASYNC_OPERATION_TIMEOUT_SEC)); + } + + @Override + public RedisFuture asyncSet(String key, String value) { + return asyncCommands.set(key, value); + } + + @Override + public RedisFuture asyncGet(String key) { + return asyncCommands.get(key); + } + + @Override + public void closeConnection() { + connection.close(); + client.shutdown(); + } + + @Override + public String getName() { + return "Lettuce Async"; + } +}