Skip to content

Commit

Permalink
Add sync and async clients both to tests. (#12)
Browse files Browse the repository at this point in the history
* Add sync and async clients both to tests.

Signed-off-by: Yury-Fridlyand <[email protected]>

* Minor fixes.

Signed-off-by: Yury-Fridlyand <[email protected]>

---------

Signed-off-by: Yury-Fridlyand <[email protected]>
  • Loading branch information
Yury-Fridlyand authored and acarbonetto committed Sep 25, 2023
1 parent 2b0beec commit bdca891
Show file tree
Hide file tree
Showing 11 changed files with 284 additions and 116 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package javabushka.client;

import java.util.concurrent.Future;

public interface AsyncClient extends Client {

long DEFAULT_TIMEOUT = 1000;

Future<?> asyncSet(String key, String value);

Future<String> asyncGet(String key);

<T> T waitForResult(Future<T> future);

<T> T waitForResult(Future<T> future, long timeout);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@
import java.io.FileWriter;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import javabushka.client.jedis.JedisClient;
import javabushka.client.jedis.JedisPseudoAsyncClient;
import javabushka.client.lettuce.LettuceAsyncClient;
import javabushka.client.lettuce.LettuceClient;
import javabushka.client.utils.Benchmarking;
import javabushka.client.utils.ChosenAction;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
Expand All @@ -37,26 +36,41 @@ public static void main(String[] args) {
System.err.println("Parsing failed. Reason: " + exp.getMessage());
}

try {
switch (runConfiguration.clients) {
for (ClientName client : runConfiguration.clients) {
switch (client) {
case ALL:
testJedisClientResourceSetGet(runConfiguration);
testLettuceClientResourceSetGet(runConfiguration);
testClientSetGet(new JedisClient(), runConfiguration);
testClientSetGet(new LettuceClient(), runConfiguration);
testAsyncClientSetGet(new JedisPseudoAsyncClient(), runConfiguration);
testAsyncClientSetGet(new LettuceAsyncClient(), runConfiguration);
System.out.println("Babushka not yet configured");
break;
case ALL_ASYNC:
testAsyncClientSetGet(new JedisPseudoAsyncClient(), runConfiguration);
testAsyncClientSetGet(new LettuceAsyncClient(), runConfiguration);
System.out.println("Babushka not yet configured");
break;
case ALL_SYNC:
testClientSetGet(new JedisClient(), runConfiguration);
testClientSetGet(new LettuceClient(), runConfiguration);
System.out.println("Babushka not yet configured");
break;
case JEDIS:
testJedisClientResourceSetGet(runConfiguration);
testClientSetGet(new JedisClient(), runConfiguration);
break;
case JEDIS_ASYNC:
testAsyncClientSetGet(new JedisPseudoAsyncClient(), runConfiguration);
break;
case LETTUCE:
testLettuceClientResourceSetGet(runConfiguration);
testClientSetGet(new LettuceClient(), runConfiguration);
break;
case LETTUCE_ASYNC:
testAsyncClientSetGet(new LettuceAsyncClient(), runConfiguration);
break;
case BABUSHKA:
System.out.println("Babushka not yet configured");
break;
}
} catch (IOException ioException) {
System.out.println("Error writing to results file");
ioException.printStackTrace();
}

if (runConfiguration.resultsFile.isPresent()) {
Expand Down Expand Up @@ -123,18 +137,11 @@ private static RunConfiguration verifyOptions(CommandLine line) throws ParseExce
}

if (line.hasOption("clients")) {
String clients = line.getOptionValue("clients");
if (ClientName.ALL.isEqual(clients)) {
runConfiguration.clients = ClientName.ALL;
} else if (ClientName.JEDIS.isEqual(clients)) {
runConfiguration.clients = ClientName.JEDIS;
} else if (ClientName.LETTUCE.isEqual(clients)) {
runConfiguration.clients = ClientName.LETTUCE;
} else if (ClientName.BABUSHKA.isEqual(clients)) {
runConfiguration.clients = ClientName.BABUSHKA;
} else {
throw new ParseException("Invalid clients option: all|jedis|lettuce|babushka");
}
String[] clients = line.getOptionValue("clients").split(",");
runConfiguration.clients =
Arrays.stream(clients)
.map(c -> Enum.valueOf(ClientName.class, c.toUpperCase()))
.toArray(ClientName[]::new);
}

if (line.hasOption("host")) {
Expand All @@ -152,66 +159,27 @@ private static RunConfiguration verifyOptions(CommandLine line) throws ParseExce
return runConfiguration;
}

private static void testJedisClientResourceSetGet(RunConfiguration runConfiguration)
throws IOException {
JedisClient jedisClient = new JedisClient();
jedisClient.connectToRedis(runConfiguration.host, runConfiguration.port);

int iterations = 100000;
String value = "my-value";

if (runConfiguration.resultsFile.isPresent()) {
runConfiguration.resultsFile.get().write("JEDIS client Benchmarking: ");
} else {
System.out.println("JEDIS client Benchmarking: ");
}

Map<ChosenAction, Benchmarking.Operation> actions = new HashMap<>();
actions.put(ChosenAction.GET_EXISTING, () -> jedisClient.get(Benchmarking.generateKeySet()));
actions.put(
ChosenAction.GET_NON_EXISTING, () -> jedisClient.get(Benchmarking.generateKeyGet()));
actions.put(ChosenAction.SET, () -> jedisClient.set(Benchmarking.generateKeySet(), value));

Benchmarking.printResults(
Benchmarking.calculateResults(Benchmarking.getLatencies(iterations, actions)),
runConfiguration.resultsFile);
private static void testClientSetGet(Client client, RunConfiguration runConfiguration) {
System.out.printf("%n =====> %s <===== %n%n", client.getName());
Benchmarking.printResults(Benchmarking.measurePerformance(client, runConfiguration, false));
System.out.println();
}

private static LettuceAsyncClient initializeLettuceClient() {
LettuceAsyncClient lettuceClient = new LettuceAsyncClient();
lettuceClient.connectToRedis();
return lettuceClient;
}

private static void testLettuceClientResourceSetGet(RunConfiguration runConfiguration)
throws IOException {
LettuceAsyncClient lettuceClient = initializeLettuceClient();

int iterations = 100000;
String value = "my-value";

if (runConfiguration.resultsFile.isPresent()) {
runConfiguration.resultsFile.get().write("LETTUCE client Benchmarking: ");
} else {
System.out.println("LETTUCE client Benchmarking: ");
}

HashMap<ChosenAction, Benchmarking.Operation> actions = new HashMap<>();
actions.put(ChosenAction.GET_EXISTING, () -> lettuceClient.get(Benchmarking.generateKeySet()));
actions.put(
ChosenAction.GET_NON_EXISTING, () -> lettuceClient.get(Benchmarking.generateKeyGet()));
actions.put(ChosenAction.SET, () -> lettuceClient.set(Benchmarking.generateKeySet(), value));

Benchmarking.printResults(
Benchmarking.calculateResults(Benchmarking.getLatencies(iterations, actions)),
runConfiguration.resultsFile);
private static void testAsyncClientSetGet(AsyncClient client, RunConfiguration runConfiguration) {
System.out.printf("%n =====> %s <===== %n%n", client.getName());
Benchmarking.printResults(Benchmarking.measurePerformance(client, runConfiguration, true));
System.out.println();
}

public enum ClientName {
JEDIS("Jedis"),
JEDIS_ASYNC("Jedis async"),
LETTUCE("Lettuce"),
LETTUCE_ASYNC("Lettuce async"),
BABUSHKA("Babushka"),
ALL("All");
ALL("All"),
ALL_SYNC("All sync"),
ALL_ASYNC("All async");

private String name;

Expand All @@ -233,7 +201,7 @@ public static class RunConfiguration {
public String configuration;
public Optional<FileWriter> resultsFile;
public List<Integer> concurrentTasks;
public ClientName clients;
public ClientName[] clients;
public String host;
public int port;
public int clientCount;
Expand All @@ -243,11 +211,11 @@ public RunConfiguration() {
configuration = "Release";
resultsFile = Optional.empty();
concurrentTasks = List.of(1, 10, 100);
clients = ClientName.ALL;
clients = new ClientName[] {ClientName.ALL};
host = "localhost";
port = 6379;
clientCount = 1;
tls = true;
tls = false;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package javabushka.client;

import javabushka.client.utils.ConnectionSettings;

public interface Client {
void connectToRedis();

void connectToRedis(ConnectionSettings connectionSettings);

default void closeConnection() {}

String getName();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package javabushka.client;

public interface SyncClient extends Client {
void set(String key, String value);

String get(String key);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,46 @@
*/
package javabushka.client.jedis;

import javabushka.client.SyncClient;
import javabushka.client.utils.ConnectionSettings;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

public class JedisClient {
public class JedisClient implements SyncClient {

public static final String DEFAULT_HOST = "localhost";
public static final int DEFAULT_PORT = 6379;

Jedis jedisResource;
protected Jedis jedisResource;

public boolean someLibraryMethod() {
return true;
}

public void connectToRedis(String host, int port) {
JedisPool pool = new JedisPool(host, port);
@Override
public void connectToRedis() {
JedisPool pool = new JedisPool(DEFAULT_HOST, DEFAULT_PORT);
jedisResource = pool.getResource();
}

public void connectToRedis() {
connectToRedis(DEFAULT_HOST, DEFAULT_PORT);
@Override
public void closeConnection() {
try {
jedisResource.close();
} catch (Exception ignored) {
}
}

@Override
public String getName() {
return "Jedis";
}

@Override
public void connectToRedis(ConnectionSettings connectionSettings) {
jedisResource =
new Jedis(connectionSettings.host, connectionSettings.port, connectionSettings.useSsl);
jedisResource.connect();
}

public String info() {
Expand All @@ -34,10 +53,12 @@ public String info(String section) {
return jedisResource.info(section);
}

@Override
public void set(String key, String value) {
jedisResource.set(key, value);
}

@Override
public String get(String key) {
return jedisResource.get(key);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package javabushka.client.jedis;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import javabushka.client.AsyncClient;

// Jedis doesn't provide async API
// https://github.com/redis/jedis/issues/241
public class JedisPseudoAsyncClient extends JedisClient implements AsyncClient {
@Override
public Future<?> asyncSet(String key, String value) {
return CompletableFuture.runAsync(() -> super.set(key, value));
}

@Override
public Future<String> asyncGet(String key) {
return CompletableFuture.supplyAsync(() -> super.get(key));
}

@Override
public <T> T waitForResult(Future<T> future) {
return waitForResult(future, DEFAULT_TIMEOUT);
}

@Override
public <T> T waitForResult(Future<T> future, long timeout) {
try {
return future.get(timeout, TimeUnit.MILLISECONDS);
} catch (Exception ignored) {
return null;
}
}

@Override
public String getName() {
return "Jedis pseudo-async";
}
}
Loading

0 comments on commit bdca891

Please sign in to comment.