Skip to content

Commit

Permalink
Java: Add ExamplesApp and Update benchmarkingApp to both have Java/Gl…
Browse files Browse the repository at this point in the history
…ide-for-redis client (valkey-io#896)

* Java: Add ExamplesApp and Update benchmarkingApp to both have Java/Glide-for-redis client (valkey-io#896)

Signed-off-by: Andrew Carbonetto <[email protected]>

---------

Signed-off-by: Andrew Carbonetto <[email protected]>
Signed-off-by: Yury-Fridlyand <[email protected]>
Co-authored-by: Yury-Fridlyand <[email protected]>
  • Loading branch information
acarbonetto and Yury-Fridlyand authored Feb 15, 2024
1 parent 2c55611 commit 7292960
Show file tree
Hide file tree
Showing 10 changed files with 177 additions and 24 deletions.
9 changes: 4 additions & 5 deletions .github/workflows/java-benchmark.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
submodules: recursive

- name: Set up JDK ${{ matrix.java }}
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
distribution: "temurin"
java-version: ${{ matrix.java }}
Expand All @@ -42,16 +42,15 @@ jobs:

- name: benchmark
uses: ./.github/workflows/test-benchmark
# TODO - enable once benchmark works
if: ${{ false }}
with:
language-flag: -java

- name: Upload test reports
if: always()
continue-on-error: true
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: test-reports-${{ matrix.java }}
name: test-reports-java-${{ matrix.java }}-redis-${{ matrix.redis }}
path: |
java/benchmarks/build/reports/**
benchmarks/results/**
2 changes: 1 addition & 1 deletion benchmarks/install_and_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ function runCSharpBenchmark(){

function runJavaBenchmark(){
cd ${BENCH_FOLDER}/../java
./gradlew run --args="-resultsFile \"${BENCH_FOLDER}/$1\" -dataSize \"$2\" -concurrentTasks \"$concurrentTasks\" -clients \"$chosenClients\" -host $host $javaPortFlag -clientCount \"$clientCount\" $javaTlsFlag $javaClusterFlag"
./gradlew :benchmarks:run --args="-resultsFile \"${BENCH_FOLDER}/$1\" -dataSize \"$2\" -concurrentTasks \"$concurrentTasks\" -clients \"$chosenClients\" -host $host $javaPortFlag -clientCount \"$clientCount\" $javaTlsFlag $javaClusterFlag"
}

function runRustBenchmark(){
Expand Down
26 changes: 13 additions & 13 deletions java/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ 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 GLIDE for Redis and other Java clients.
1. `client`: A Java-wrapper around the rust-core client.
2. `examples`: An examples app to test the client against a Redis localhost
3. `benchmark`: A dedicated benchmarking tool designed to evaluate and compare the performance of GLIDE for Redis and other Java clients.
4. `integTest`: An integration test sub-project for API and E2E testing

## Installation and Setup

Expand Down Expand Up @@ -82,28 +84,26 @@ $ ./gradlew :client:test

Other useful gradle developer commands:
* `./gradlew :client:test` to run client unit tests
* `./gradlew :integTest:test` to run client examples
* `./gradlew spotlessCheck` to check for codestyle issues
* `./gradlew spotlessApply` to apply codestyle recommendations
* `./gradlew :examples:run` to run client examples
* `./gradlew :benchmarks:run` to run performance benchmarks

## Basic Examples

### Standalone Redis:

```java
import glide.Client;
import glide.Client.SingleResponse;
import glide.api.RedisClient;

Client client = new Client();
RedisClient client = RedisClient.CreateClient().get();

SingleResponse connect = client.asyncConnectToRedis("localhost", 6379);
connect.await().isSuccess();
CompletableFuture<String> setResponse = client.set("key", "foobar");
assert setResponse.get() == "OK" : "Failed on client.set("key", "foobar") request";

SingleResponse set = client.asyncSet("key", "foobar");
set.await().isSuccess();

SingleResponse get = client.asyncGet("key");
get.await().getValue() == "foobar";
CompletableFuture<String> getResponse = client.get("key");
assert getResponse.get() == "foobar" : "Failed on client.get("key") request";
```

### Benchmarks
Expand All @@ -115,7 +115,7 @@ You can run benchmarks using `./gradlew run`. You can set arguments using the ar
./gradlew run --args="-resultsFile=output -dataSize \"100 1000\" -concurrentTasks \"10 100\" -clients all -host localhost -port 6279 -clientCount \"1 5\" -tls"
```

The following arguments are accepted:
The following arguments are accepted:
* `resultsFile`: the results output file
* `concurrentTasks`: Number of concurrent tasks
* `clients`: one of: all|jedis|lettuce|glide
Expand Down
6 changes: 5 additions & 1 deletion java/benchmarks/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ repositories {
}

dependencies {
implementation project(':client')

// 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'
Expand All @@ -17,10 +19,12 @@ dependencies {
implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.13.0'
implementation group: 'org.apache.commons', name: 'commons-math3', version: '3.5'
implementation group: 'com.google.code.gson', name: 'gson', version: '2.10.1'

}

run.dependsOn ':client:buildRustRelease'

application {
// Define the main class for the application.
mainClass = 'glide.benchmarks.BenchmarkingApp'
applicationDefaultJvmArgs = ['-Djava.library.path=../target/release']
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import static glide.benchmarks.utils.Benchmarking.testClientSetGet;

import glide.benchmarks.clients.glide.GlideAsyncClient;
import glide.benchmarks.clients.jedis.JedisClient;
import glide.benchmarks.clients.lettuce.LettuceAsyncClient;
import java.util.Arrays;
Expand Down Expand Up @@ -46,17 +47,16 @@ public static void main(String[] args) {
for (ClientName client : runConfiguration.clients) {
switch (client) {
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 GLIDE:
System.out.println("GLIDE for Redis async not yet configured");
System.out.println("GLIDE for Redis async client");
testClientSetGet(GlideAsyncClient::new, runConfiguration, true);
break;
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/** Copyright GLIDE-for-Redis Project Contributors - SPDX Identifier: Apache-2.0 */
package glide.benchmarks.clients.glide;

import static java.util.concurrent.TimeUnit.SECONDS;

import glide.api.BaseClient;
import glide.api.RedisClient;
import glide.api.RedisClusterClient;
import glide.api.models.configuration.NodeAddress;
import glide.api.models.configuration.RedisClientConfiguration;
import glide.api.models.configuration.RedisClusterClientConfiguration;
import glide.benchmarks.clients.AsyncClient;
import glide.benchmarks.utils.ConnectionSettings;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;

/** A Glide client with async capabilities */
public class GlideAsyncClient implements AsyncClient<String> {
private BaseClient redisClient;

@Override
public void connectToRedis(ConnectionSettings connectionSettings) {

if (connectionSettings.clusterMode) {
RedisClusterClientConfiguration config =
RedisClusterClientConfiguration.builder()
.address(
NodeAddress.builder()
.host(connectionSettings.host)
.port(connectionSettings.port)
.build())
.useTLS(connectionSettings.useSsl)
.build();
try {
redisClient = RedisClusterClient.CreateClient(config).get(10, SECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
throw new RuntimeException(e);
}

} else {
RedisClientConfiguration config =
RedisClientConfiguration.builder()
.address(
NodeAddress.builder()
.host(connectionSettings.host)
.port(connectionSettings.port)
.build())
.useTLS(connectionSettings.useSsl)
.build();

try {
redisClient = RedisClient.CreateClient(config).get(10, SECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
throw new RuntimeException(e);
}
}
}

@Override
public CompletableFuture<String> asyncSet(String key, String value) {
return redisClient.set(key, value);
}

@Override
public CompletableFuture<String> asyncGet(String key) {
return redisClient.get(key);
}

@Override
public void closeConnection() {
try {
redisClient.close();
} catch (ExecutionException e) {
throw new RuntimeException(e);
}
}

@Override
public String getName() {
return "Glide Async";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public void connectToRedis(ConnectionSettings connectionSettings) {
.withPort(connectionSettings.port)
.withSsl(connectionSettings.useSsl)
.build();
if (connectionSettings.clusterMode) {
if (!connectionSettings.clusterMode) {
client = RedisClient.create(uri);
connection = ((RedisClient) client).connect();
asyncCommands = ((StatefulRedisConnection<String, String>) connection).async();
Expand Down
25 changes: 25 additions & 0 deletions java/examples/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
plugins {
// Apply the application plugin to add support for building a CLI application in Java.
id 'application'
}

repositories {
// Use Maven Central for resolving dependencies.
mavenCentral()
}

dependencies {
implementation project(':client')

implementation 'redis.clients:jedis:4.4.3'
implementation 'io.lettuce:lettuce-core:6.2.6.RELEASE'
implementation 'commons-cli:commons-cli:1.5.0'
}

run.dependsOn ':client:buildRustRelease'

application {
// Define the main class for the application.
mainClass = 'glide.examples.ExamplesApp'
applicationDefaultJvmArgs = ['-Djava.library.path=../target/release']
}
41 changes: 41 additions & 0 deletions java/examples/src/main/java/glide/examples/ExamplesApp.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/** Copyright GLIDE-for-Redis Project Contributors - SPDX Identifier: Apache-2.0 */
package glide.examples;

import glide.api.RedisClient;
import glide.api.models.configuration.NodeAddress;
import glide.api.models.configuration.RedisClientConfiguration;
import java.util.concurrent.ExecutionException;

public class ExamplesApp {

// main application entrypoint
public static void main(String[] args) {
runGlideExamples();
}

private static void runGlideExamples() {
String host = "localhost";
Integer port = 6379;
boolean useSsl = false;

RedisClientConfiguration config =
RedisClientConfiguration.builder()
.address(NodeAddress.builder().host(host).port(port).build())
.useTLS(useSsl)
.build();

try {
RedisClient client = RedisClient.CreateClient(config).get();

System.out.println("PING: " + client.ping().get());
System.out.println("PING(found you): " + client.ping("found you").get());

System.out.println("SET(apples, oranges): " + client.set("apples", "oranges").get());
System.out.println("GET(apples): " + client.get("apples").get());

} catch (ExecutionException | InterruptedException e) {
System.out.println("Glide example failed with an exception: ");
e.printStackTrace();
}
}
}
1 change: 1 addition & 0 deletions java/settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ rootProject.name = 'glide'

include 'client'
include 'integTest'
include 'examples'
include 'benchmarks'

0 comments on commit 7292960

Please sign in to comment.