From b754cb871b3966251f59f34a9e5c5bd0c1aed3d4 Mon Sep 17 00:00:00 2001 From: Santiago Pericas-Geertsen Date: Mon, 12 Aug 2024 18:17:01 -0400 Subject: [PATCH 1/6] Centralizes JSON serialization. Minor optimizations to pgclient repository implementation. Signed-off-by: Santiago Pericas-Geertsen --- frameworks/Java/helidon/nima/pom.xml | 2 +- .../benchmark/nima/JsonSerializer.java | 86 ++++++++++++++++++ .../java/io/helidon/benchmark/nima/Main.java | 58 ++---------- .../benchmark/nima/models/DbRepository.java | 19 ---- .../nima/models/PgClientRepository.java | 89 ++++++++----------- .../helidon/benchmark/nima/models/World.java | 6 +- .../benchmark/nima/services/DbService.java | 27 ++---- .../nima/src/main/resources/application.yaml | 1 + 8 files changed, 140 insertions(+), 148 deletions(-) create mode 100644 frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/JsonSerializer.java diff --git a/frameworks/Java/helidon/nima/pom.xml b/frameworks/Java/helidon/nima/pom.xml index c884659a0a0..354dd53acb0 100644 --- a/frameworks/Java/helidon/nima/pom.xml +++ b/frameworks/Java/helidon/nima/pom.xml @@ -21,7 +21,7 @@ io.helidon.applications helidon-se - 4.0.3 + 4.1.0-SNAPSHOT diff --git a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/JsonSerializer.java b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/JsonSerializer.java new file mode 100644 index 00000000000..f3fb0496b18 --- /dev/null +++ b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/JsonSerializer.java @@ -0,0 +1,86 @@ +package io.helidon.benchmark.nima; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Map; +import java.util.List; + +import com.jsoniter.output.JsonStream; +import com.jsoniter.output.JsonStreamPool; +import com.jsoniter.spi.JsonException; + +public class JsonSerializer { + + private JsonSerializer() { + } + + /** + * Serialize an instance into a JSON object and return it as a byte array. + * + * @param obj the instance + * @return the byte array + */ + public static byte[] serialize(Object obj) { + JsonStream stream = JsonStreamPool.borrowJsonStream(); + try { + stream.reset(null); + stream.writeVal(obj.getClass(), obj); + return Arrays.copyOfRange(stream.buffer().data(), 0, stream.buffer().tail()); + } catch (IOException e) { + throw new JsonException(e); + } finally { + JsonStreamPool.returnJsonStream(stream); + } + } + + /** + * Serialize a map of strings into a JSON object and return it as a byte array. + * + * @param map the map + * @return the byte array + */ + public static byte[] serialize(Map map) { + JsonStream stream = JsonStreamPool.borrowJsonStream(); + try { + stream.reset(null); + stream.writeObjectStart(); + map.forEach((k, v) -> { + try { + stream.writeObjectField(k); + stream.writeVal(v); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + stream.writeObjectEnd(); + return Arrays.copyOfRange(stream.buffer().data(), 0, stream.buffer().tail()); + } catch (IOException e) { + throw new JsonException(e); + } finally { + JsonStreamPool.returnJsonStream(stream); + } + } + + /** + * Serialize a list of objects into a JSON array and return it as a byte array. + * + * @param objs the list of objects + * @return the byte array + */ + public static byte[] serialize(List objs) { + JsonStream stream = JsonStreamPool.borrowJsonStream(); + try { + stream.reset(null); + stream.writeArrayStart(); + for (Object obj : objs) { + stream.writeVal(obj.getClass(), obj); + } + stream.writeArrayEnd(); + return Arrays.copyOfRange(stream.buffer().data(), 0, stream.buffer().tail()); + } catch (IOException e) { + throw new JsonException(e); + } finally { + JsonStreamPool.returnJsonStream(stream); + } + } +} diff --git a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/Main.java b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/Main.java index 92896867246..df669d8a7a7 100644 --- a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/Main.java +++ b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/Main.java @@ -16,14 +16,9 @@ package io.helidon.benchmark.nima; -import java.io.IOException; import java.nio.charset.StandardCharsets; -import java.util.Arrays; import java.util.logging.Logger; -import com.jsoniter.output.JsonStream; -import com.jsoniter.output.JsonStreamPool; -import com.jsoniter.spi.JsonException; import io.helidon.benchmark.nima.models.DbRepository; import io.helidon.benchmark.nima.models.HikariJdbcRepository; import io.helidon.benchmark.nima.models.PgClientRepository; @@ -41,6 +36,8 @@ import io.helidon.webserver.http.ServerRequest; import io.helidon.webserver.http.ServerResponse; +import static io.helidon.benchmark.nima.JsonSerializer.serialize; + /** * Main class of the benchmark. * Opens server on localhost:8080 and exposes {@code /plaintext} and {@code /json} endpoints adhering to the @@ -90,29 +87,14 @@ static void routing(HttpRules rules) { rules.get("/plaintext", new PlaintextHandler()) .get("/json", new JsonHandler()) - .get("/10k", new JsonKHandler(10)) .get("/fortunes", new FortuneHandler(repository)) .register("/", new DbService(repository)); } - private static byte[] serializeMsg(Message obj) { - JsonStream stream = JsonStreamPool.borrowJsonStream(); - try { - stream.reset(null); - stream.writeVal(Message.class, obj); - return Arrays.copyOfRange(stream.buffer().data(), 0, stream.buffer().tail()); - } catch (IOException e) { - throw new JsonException(e); - } finally { - JsonStreamPool.returnJsonStream(stream); - } - } - static class PlaintextHandler implements Handler { static final Header CONTENT_TYPE = HeaderValues.createCached(HeaderNames.CONTENT_TYPE, - "text/plain; charset=UTF-8"); + "text/plain; charset=UTF-8"); static final Header CONTENT_LENGTH = HeaderValues.createCached(HeaderNames.CONTENT_LENGTH, "13"); - private static final byte[] RESPONSE_BYTES = "Hello, World!".getBytes(StandardCharsets.UTF_8); @Override @@ -126,44 +108,16 @@ public void handle(ServerRequest req, ServerResponse res) { static class JsonHandler implements Handler { private static final String MESSAGE = "Hello, World!"; - private static final int JSON_LENGTH = serializeMsg(new Message(MESSAGE)).length; + private static final int JSON_LENGTH = serialize(new Message(MESSAGE)).length; static final Header CONTENT_LENGTH = HeaderValues.createCached(HeaderNames.CONTENT_LENGTH, - String.valueOf(JSON_LENGTH)); + String.valueOf(JSON_LENGTH)); @Override public void handle(ServerRequest req, ServerResponse res) { res.header(CONTENT_LENGTH); res.header(HeaderValues.CONTENT_TYPE_JSON); res.header(Main.SERVER); - res.send(serializeMsg(newMsg())); - } - - private static Message newMsg() { - return new Message("Hello, World!"); - } - } - - static class JsonKHandler implements Handler { - private final Header contentLength; - private final String message; - - JsonKHandler(int kilobytes) { - this.message = "a".repeat(1024 * kilobytes); - int length = serializeMsg(new Message(message)).length; - this.contentLength = HeaderValues.createCached(HeaderNames.CONTENT_LENGTH, - String.valueOf(length)); - } - - @Override - public void handle(ServerRequest req, ServerResponse res) { - res.header(contentLength); - res.header(HeaderValues.CONTENT_TYPE_JSON); - res.header(Main.SERVER); - res.send(serializeMsg(newMsg())); - } - - private Message newMsg() { - return new Message(message); + res.send(serialize(new Message(MESSAGE))); } } diff --git a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/DbRepository.java b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/DbRepository.java index 204c9ad5ad1..d1f75b558c3 100644 --- a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/DbRepository.java +++ b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/DbRepository.java @@ -6,35 +6,16 @@ import java.util.concurrent.ThreadLocalRandom; import jakarta.json.Json; -import jakarta.json.JsonArray; -import jakarta.json.JsonArrayBuilder; import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; public interface DbRepository { JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); - default World getWorld() { - return getWorld(randomWorldNumber()); - } - World getWorld(int id); - default JsonObject getWorldAsJson(int id) { - return getWorld().toJson(); - } - List getWorlds(int count); - default JsonArray getWorldsAsJson(int count) { - JsonArrayBuilder result = JSON.createArrayBuilder(); - for (World world : getWorlds(count)) { - result.add(world.toJson()); - } - return result.build(); - } - World updateWorld(World world); List updateWorlds(int count); diff --git a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/PgClientRepository.java b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/PgClientRepository.java index 7775a177537..bdd339c944a 100644 --- a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/PgClientRepository.java +++ b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/PgClientRepository.java @@ -8,27 +8,25 @@ import java.util.concurrent.TimeoutException; import java.util.logging.Logger; -import io.helidon.common.reactive.Multi; -import io.helidon.common.reactive.Single; import io.helidon.config.Config; + import io.vertx.core.Vertx; import io.vertx.core.VertxOptions; +import io.vertx.core.Future; import io.vertx.pgclient.PgConnectOptions; import io.vertx.pgclient.PgPool; import io.vertx.sqlclient.PoolOptions; +import io.vertx.sqlclient.PreparedQuery; import io.vertx.sqlclient.Row; +import io.vertx.sqlclient.RowSet; import io.vertx.sqlclient.SqlClient; import io.vertx.sqlclient.Tuple; -import jakarta.json.JsonArray; -import jakarta.json.JsonArrayBuilder; -import jakarta.json.JsonObject; import static io.helidon.benchmark.nima.models.DbRepository.randomWorldNumber; public class PgClientRepository implements DbRepository { private static final Logger LOGGER = Logger.getLogger(PgClientRepository.class.getName()); - private final SqlClient queryPool; private final SqlClient updatePool; @@ -36,9 +34,13 @@ public class PgClientRepository implements DbRepository { private final long updateTimeout; private final int maxRetries; + private final PreparedQuery> getFortuneQuery; + private final PreparedQuery> getWorldQuery; + private final PreparedQuery> updateWorldQuery; + public PgClientRepository(Config config) { Vertx vertx = Vertx.vertx(new VertxOptions() - .setPreferNativeTransport(true)); + .setPreferNativeTransport(true)); PgConnectOptions connectOptions = new PgConnectOptions() .setPort(config.get("port").asInt().orElse(5432)) .setCachePreparedStatements(config.get("cache-prepared-statements").asBoolean().orElse(true)) @@ -59,31 +61,20 @@ public PgClientRepository(Config config) { queryPool = PgPool.client(vertx, connectOptions, clientOptions); updatePool = PgPool.client(vertx, connectOptions, clientOptions); - } - @Override - public JsonObject getWorldAsJson(int id) { - return getWorld(id, queryPool).map(World::toJson).await(); + getWorldQuery = queryPool.preparedQuery("SELECT id, randomnumber FROM world WHERE id = $1"); + updateWorldQuery = queryPool.preparedQuery("UPDATE world SET randomnumber = $1 WHERE id = $2"); + getFortuneQuery = queryPool.preparedQuery("SELECT id, message FROM fortune"); } @Override public World getWorld(int id) { try { - return getWorld(id, queryPool).toCompletableFuture().get(); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - @Override - public JsonArray getWorldsAsJson(int count) { - try { - return Multi.range(0, count) - .flatMap(i -> getWorld(randomWorldNumber(), queryPool)) - .map(World::toJson) - .reduce(JSON::createArrayBuilder, JsonArrayBuilder::add) - .map(JsonArrayBuilder::build) - .await(); + return getWorldQuery.execute(Tuple.of(id)) + .map(rows -> { + Row r = rows.iterator().next(); + return new World(r.getInteger(0), r.getInteger(1)); + }).toCompletionStage().toCompletableFuture().get(); } catch (Exception e) { throw new RuntimeException(e); } @@ -92,17 +83,15 @@ public JsonArray getWorldsAsJson(int count) { @Override public List getWorlds(int count) { try { - List result = new ArrayList<>(count); + List> futures = new ArrayList<>(); for (int i = 0; i < count; i++) { - World world = queryPool.preparedQuery("SELECT id, randomnumber FROM world WHERE id = $1") - .execute(Tuple.of(randomWorldNumber())) - .map(rows -> { - Row r = rows.iterator().next(); - return new World(r.getInteger(0), r.getInteger(1)); - }).toCompletionStage().toCompletableFuture().get(); - result.add(world); + futures.add(getWorldQuery.execute(Tuple.of(randomWorldNumber())) + .map(rows -> { + Row r = rows.iterator().next(); + return new World(r.getInteger(0), r.getInteger(1)); + })); } - return result; + return Future.all(futures).toCompletionStage().toCompletableFuture().get().list(); } catch (Exception e) { throw new RuntimeException(e); } @@ -110,10 +99,14 @@ public List getWorlds(int count) { @Override public World updateWorld(World world) { - return Single.create(queryPool.preparedQuery("UPDATE world SET randomnumber = $1 WHERE id = $2") - .execute(Tuple.of(world.id, world.id)) - .toCompletionStage() - .thenApply(rows -> world)).await(); + try { + return updateWorldQuery.execute(Tuple.of(world.id, world.id)) + .toCompletionStage() + .thenApply(rows -> world) + .toCompletableFuture().get(); + } catch (Exception e) { + throw new RuntimeException(e); + } } @Override @@ -165,25 +158,14 @@ private List updateWorldsRetry(List worlds, int from, int retries) @Override public List getFortunes() { - return Single.create(queryPool.preparedQuery("SELECT id, message FROM fortune") - .execute() + return getFortuneQuery.execute() .map(rows -> { List fortunes = new ArrayList<>(rows.size() + 1); for (Row r : rows) { fortunes.add(new Fortune(r.getInteger(0), r.getString(1))); } return fortunes; - }).toCompletionStage()).await(); - } - - private static Single getWorld(int id, SqlClient pool) { - return Single.create(pool.preparedQuery("SELECT id, randomnumber FROM world WHERE id = $1") - .execute(Tuple.of(id)) - .map(rows -> { - Row r = rows.iterator().next(); - return new World(r.getInteger(0), r.getInteger(1)); - }).toCompletionStage()); - + }).result(); } private CompletableFuture> updateWorlds(List worlds, int from, SqlClient pool) { @@ -193,8 +175,7 @@ private CompletableFuture> updateWorlds(List worlds, int from World w = worlds.get(i); tuples.add(Tuple.of(w.randomNumber, w.id)); } - return pool.preparedQuery("UPDATE world SET randomnumber = $1 WHERE id = $2") - .executeBatch(tuples) + return updateWorldQuery.executeBatch(tuples) .toCompletionStage() .thenApply(rows -> worlds) .toCompletableFuture(); diff --git a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/World.java b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/World.java index ee8eb9194cd..39deafea11b 100644 --- a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/World.java +++ b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/World.java @@ -9,9 +9,9 @@ public final class World { - private static final String ID_KEY = "id"; - private static final String ID_RANDOM_NUMBER = "randomNumber"; - private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); + static final String ID_KEY = "id"; + static final String ID_RANDOM_NUMBER = "randomNumber"; + static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); public int id; public int randomNumber; diff --git a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/services/DbService.java b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/services/DbService.java index 46c244d96f5..8a9ae4fd314 100644 --- a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/services/DbService.java +++ b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/services/DbService.java @@ -1,7 +1,6 @@ package io.helidon.benchmark.nima.services; -import java.util.Collections; import java.util.List; import io.helidon.benchmark.nima.models.DbRepository; @@ -11,17 +10,13 @@ import io.helidon.webserver.http.HttpService; import io.helidon.webserver.http.ServerRequest; import io.helidon.webserver.http.ServerResponse; - -import jakarta.json.Json; -import jakarta.json.JsonArrayBuilder; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; +import io.helidon.common.mapper.OptionalValue; import static io.helidon.benchmark.nima.Main.SERVER; import static io.helidon.benchmark.nima.models.DbRepository.randomWorldNumber; +import static io.helidon.benchmark.nima.JsonSerializer.serialize; public class DbService implements HttpService { - private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); private final DbRepository repository; @@ -38,36 +33,30 @@ public void routing(HttpRules httpRules) { private void db(ServerRequest req, ServerResponse res) { res.header(SERVER); - res.send(repository.getWorldAsJson(randomWorldNumber())); + res.send(serialize(repository.getWorld(randomWorldNumber()))); } private void queries(ServerRequest req, ServerResponse res) { res.header(SERVER); int count = parseQueryCount(req.query()); - res.send(repository.getWorldsAsJson(count)); + res.send(serialize(repository.getWorlds(count))); } private void updates(ServerRequest req, ServerResponse res) { res.header(SERVER); int count = parseQueryCount(req.query()); List worlds = repository.updateWorlds(count); - JsonArrayBuilder arrayBuilder = JSON.createArrayBuilder(); - for (World world : worlds) { - JsonObject json = world.toJson(); - arrayBuilder.add(json); - } - res.send(arrayBuilder.build()); + res.send(serialize(worlds)); } private int parseQueryCount(Parameters parameters) { - List values = parameters.all("queries"); - if (values.isEmpty()) { + OptionalValue value = parameters.first("queries"); + if (value.isEmpty()) { return 1; } - String first = values.get(0); int parsedValue; try { - parsedValue = Integer.parseInt(first, 10); + parsedValue = Integer.parseInt(value.get(), 10); } catch (NumberFormatException e) { return 1; } diff --git a/frameworks/Java/helidon/nima/src/main/resources/application.yaml b/frameworks/Java/helidon/nima/src/main/resources/application.yaml index ff4aa100b67..41f4d64ec12 100644 --- a/frameworks/Java/helidon/nima/src/main/resources/application.yaml +++ b/frameworks/Java/helidon/nima/src/main/resources/application.yaml @@ -19,6 +19,7 @@ server: port: 8080 backlog: 8192 write-queue-length: 8192 + smart-async-writes: true connection-options: read-timeout: PT0S connect-timeout: PT0S From 1545951b1e7823ce541e971432507cbf32f7252c Mon Sep 17 00:00:00 2001 From: Santiago Pericas-Geertsen Date: Wed, 14 Aug 2024 09:39:21 -0400 Subject: [PATCH 2/6] Fixes problem in PgClientRepository.getFortunes(). Signed-off-by: Santiago Pericas-Geertsen --- .../nima/models/PgClientRepository.java | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/PgClientRepository.java b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/PgClientRepository.java index bdd339c944a..e5166b10fbc 100644 --- a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/PgClientRepository.java +++ b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/PgClientRepository.java @@ -158,14 +158,18 @@ private List updateWorldsRetry(List worlds, int from, int retries) @Override public List getFortunes() { - return getFortuneQuery.execute() - .map(rows -> { - List fortunes = new ArrayList<>(rows.size() + 1); - for (Row r : rows) { - fortunes.add(new Fortune(r.getInteger(0), r.getString(1))); - } - return fortunes; - }).result(); + try { + return getFortuneQuery.execute() + .map(rows -> { + List fortunes = new ArrayList<>(rows.size() + 1); + for (Row r : rows) { + fortunes.add(new Fortune(r.getInteger(0), r.getString(1))); + } + return fortunes; + }).toCompletionStage().toCompletableFuture().get(); + } catch (Exception e) { + throw new RuntimeException(e); + } } private CompletableFuture> updateWorlds(List worlds, int from, SqlClient pool) { From 8d9a6b90e9f8e6929045cb815eed128968f75a86 Mon Sep 17 00:00:00 2001 From: Santiago Pericas-Geertsen Date: Mon, 19 Aug 2024 11:30:47 -0400 Subject: [PATCH 3/6] Sets a VT factory for Hikari CP. Signed-off-by: Santiago Pericas-Geertsen --- .../benchmark/nima/models/HikariJdbcRepository.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/HikariJdbcRepository.java b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/HikariJdbcRepository.java index 686559b2fd9..bb37cd77b6c 100644 --- a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/HikariJdbcRepository.java +++ b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/HikariJdbcRepository.java @@ -7,6 +7,8 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; import java.util.logging.Logger; import com.zaxxer.hikari.HikariConfig; @@ -36,6 +38,11 @@ public HikariJdbcRepository(Config config) { int poolSize = config.get("sql-pool-size").asInt().orElse(64); hikariConfig.addDataSourceProperty("maximumPoolSize", poolSize); LOGGER.info("Db pool size is set to " + poolSize); + + // use VTs with Hikari + ThreadFactory vtThreadFactory = Thread.ofVirtual().factory(); + hikariConfig.setThreadFactory(vtThreadFactory); + hikariConfig.setScheduledExecutor(Executors.newScheduledThreadPool(poolSize, vtThreadFactory)); } private Connection getConnection() throws SQLException { From 94713baf8d381026af6855a4b2fc9e6eb61f1cdf Mon Sep 17 00:00:00 2001 From: Santiago Pericas-Geertsen Date: Tue, 20 Aug 2024 11:03:23 -0400 Subject: [PATCH 4/6] Additional configuration for Hikari CP. Signed-off-by: Santiago Pericas-Geertsen --- .../nima/models/HikariJdbcRepository.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/HikariJdbcRepository.java b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/HikariJdbcRepository.java index bb37cd77b6c..fd9760939df 100644 --- a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/HikariJdbcRepository.java +++ b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/HikariJdbcRepository.java @@ -24,25 +24,31 @@ public class HikariJdbcRepository implements DbRepository { private final HikariConfig hikariConfig; public HikariJdbcRepository(Config config) { + // hikari connection configuration String url = "jdbc:postgresql://" + config.get("host").asString().orElse("tfb-database") + ":" + config.get("port").asString().orElse("5432") + "/" + config.get("db").asString().orElse("hello_world"); - hikariConfig = new HikariConfig(); hikariConfig.setJdbcUrl(url); hikariConfig.setUsername(config.get("username").asString().orElse("benchmarkdbuser")); hikariConfig.setPassword(config.get("password").asString().orElse("benchmarkdbpass")); - hikariConfig.addDataSourceProperty("cachePrepStmts", "true"); + // hikari additional configuration int poolSize = config.get("sql-pool-size").asInt().orElse(64); - hikariConfig.addDataSourceProperty("maximumPoolSize", poolSize); - LOGGER.info("Db pool size is set to " + poolSize); - - // use VTs with Hikari + hikariConfig.setMaximumPoolSize(poolSize); + LOGGER.info("Hikari pool size is set to " + poolSize); ThreadFactory vtThreadFactory = Thread.ofVirtual().factory(); hikariConfig.setThreadFactory(vtThreadFactory); hikariConfig.setScheduledExecutor(Executors.newScheduledThreadPool(poolSize, vtThreadFactory)); + LOGGER.info("Set thread factory to VTs"); + + // data source properties + hikariConfig.addDataSourceProperty("cachePrepStmts","true"); + hikariConfig.addDataSourceProperty("prepStmtCacheSize","250"); + hikariConfig.addDataSourceProperty("prepStmtCacheSqlLimit","2048"); + hikariConfig.addDataSourceProperty("ssl", "false"); + hikariConfig.addDataSourceProperty("tcpKeepAlive", "true"); } private Connection getConnection() throws SQLException { From f9db8388c2656f85a64e0c537c1a29c42eb828f8 Mon Sep 17 00:00:00 2001 From: Santiago Pericas-Geertsen Date: Mon, 7 Oct 2024 09:59:35 -0400 Subject: [PATCH 5/6] Sets Helidon version to 4.1.2. Signed-off-by: Santiago Pericas-Geertsen --- frameworks/Java/helidon/nima/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/Java/helidon/nima/pom.xml b/frameworks/Java/helidon/nima/pom.xml index 354dd53acb0..c859b758cfc 100644 --- a/frameworks/Java/helidon/nima/pom.xml +++ b/frameworks/Java/helidon/nima/pom.xml @@ -21,7 +21,7 @@ io.helidon.applications helidon-se - 4.1.0-SNAPSHOT + 4.1.2 From 8bd1fe63f501d4f0922836692175c23590bc23bd Mon Sep 17 00:00:00 2001 From: Santiago Pericas-Geertsen Date: Tue, 8 Oct 2024 14:03:39 -0400 Subject: [PATCH 6/6] Set content type in response. Fixes problems with JSON serialization. Signed-off-by: Santiago Pericas-Geertsen --- .../main/java/io/helidon/benchmark/nima/JsonSerializer.java | 6 ++++++ .../java/io/helidon/benchmark/nima/services/DbService.java | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/JsonSerializer.java b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/JsonSerializer.java index f3fb0496b18..322a7cf030c 100644 --- a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/JsonSerializer.java +++ b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/JsonSerializer.java @@ -72,8 +72,14 @@ public static byte[] serialize(List objs) { try { stream.reset(null); stream.writeArrayStart(); + int i = 0; + int n = objs.size(); for (Object obj : objs) { stream.writeVal(obj.getClass(), obj); + if (i++ < n - 1) { + stream.writeMore(); + } + } stream.writeArrayEnd(); return Arrays.copyOfRange(stream.buffer().data(), 0, stream.buffer().tail()); diff --git a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/services/DbService.java b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/services/DbService.java index 8a9ae4fd314..e3bd1fe39fc 100644 --- a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/services/DbService.java +++ b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/services/DbService.java @@ -6,6 +6,7 @@ import io.helidon.benchmark.nima.models.DbRepository; import io.helidon.benchmark.nima.models.World; import io.helidon.common.parameters.Parameters; +import io.helidon.http.HeaderValues; import io.helidon.webserver.http.HttpRules; import io.helidon.webserver.http.HttpService; import io.helidon.webserver.http.ServerRequest; @@ -33,17 +34,20 @@ public void routing(HttpRules httpRules) { private void db(ServerRequest req, ServerResponse res) { res.header(SERVER); + res.header(HeaderValues.CONTENT_TYPE_JSON); res.send(serialize(repository.getWorld(randomWorldNumber()))); } private void queries(ServerRequest req, ServerResponse res) { res.header(SERVER); + res.header(HeaderValues.CONTENT_TYPE_JSON); int count = parseQueryCount(req.query()); res.send(serialize(repository.getWorlds(count))); } private void updates(ServerRequest req, ServerResponse res) { res.header(SERVER); + res.header(HeaderValues.CONTENT_TYPE_JSON); int count = parseQueryCount(req.query()); List worlds = repository.updateWorlds(count); res.send(serialize(worlds));