diff --git a/frameworks/Java/inverno/README.md b/frameworks/Java/inverno/README.md index b205ef706b6..492cd60e430 100755 --- a/frameworks/Java/inverno/README.md +++ b/frameworks/Java/inverno/README.md @@ -2,20 +2,23 @@ ### Test Type Implementation Source Code -* [JSON](src/main/java/com/techempower/inverno/benchmark/internal/Handler.java) -* [PLAINTEXT](src/main/java/com/techempower/inverno/benchmark/internal/Handler.java) -* [DB](src/main/java/com/techempower/inverno/benchmark/internal/Handler.java) -* [QUERY](src/main/java/com/techempower/inverno/benchmark/internal/Handler.java) -* [CACHED QUERY](src/main/java/com/techempower/inverno/benchmark/internal/Handler.java) -* [UPDATE](src/main/java/com/techempower/inverno/benchmark/internal/Handler.java) -* [FORTUNES](src/main/java/com/techempower/inverno/benchmark/internal/Handler.java) +* [JSON](src/main/java/com/techempower/inverno/benchmark/internal/Controller.java) +* [PLAINTEXT](src/main/java/com/techempower/inverno/benchmark/internal/Controller.java) +* [DB](src/main/java/com/techempower/inverno/benchmark/internal/Controller.java) +* [QUERY](src/main/java/com/techempower/inverno/benchmark/internal/Controller.java) +* [CACHED QUERY](src/main/java/com/techempower/inverno/benchmark/internal/Controller.java) +* [UPDATE](src/main/java/com/techempower/inverno/benchmark/internal/Controller.java) +* [FORTUNES](src/main/java/com/techempower/inverno/benchmark/internal/Controller.java) ## Important Libraries + The tests were run with: -* [Java OpenJDK 16](https://openjdk.java.net/) -* [Inverno 1.4.1](https://inverno.io) +* [Java OpenJDK 21](https://openjdk.java.net/) +* [Inverno 1.12.0](https://inverno.io) +* [DSL-JSON 2.0.2](https://github.com/ngs-doo/dsl-json) ## Test URLs + ### JSON http://localhost:8080/json diff --git a/frameworks/Java/inverno/inverno-postgres.dockerfile b/frameworks/Java/inverno/inverno-postgres.dockerfile index 737cb434013..d1d333ef5a5 100644 --- a/frameworks/Java/inverno/inverno-postgres.dockerfile +++ b/frameworks/Java/inverno/inverno-postgres.dockerfile @@ -1,8 +1,7 @@ -FROM maven:3.9.6-amazoncorretto-21 as maven +FROM maven:3.9.9-eclipse-temurin-21 as maven WORKDIR /inverno COPY src src COPY pom.xml pom.xml -RUN yum -y install binutils RUN mvn package -q -Pio.inverno.io_uring EXPOSE 8080 diff --git a/frameworks/Java/inverno/inverno.dockerfile b/frameworks/Java/inverno/inverno.dockerfile index 1dd39d53b27..5f666a70a95 100644 --- a/frameworks/Java/inverno/inverno.dockerfile +++ b/frameworks/Java/inverno/inverno.dockerfile @@ -1,8 +1,7 @@ -FROM maven:3.9.6-amazoncorretto-21 as maven +FROM maven:3.9.9-eclipse-temurin-21 as maven WORKDIR /inverno COPY src src COPY pom.xml pom.xml -RUN yum -y install binutils RUN mvn package -q -Pio.inverno.io_uring EXPOSE 8080 diff --git a/frameworks/Java/inverno/pom.xml b/frameworks/Java/inverno/pom.xml index c91b31c2d37..3b11a165f97 100644 --- a/frameworks/Java/inverno/pom.xml +++ b/frameworks/Java/inverno/pom.xml @@ -6,7 +6,7 @@ io.inverno.dist inverno-parent - 1.10.0 + 1.12.0 com.techempower inverno-benchmark @@ -53,6 +53,11 @@ unbescape 1.1.6.RELEASE + + com.dslplatform + dsl-json + 2.0.2 + io.vertx vertx-pg-client @@ -82,7 +87,52 @@ log4j-core - + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + default-compile + + + + com.dslplatform + dsl-json + 2.0.2 + + + + + + + + + + + + io.inverno.tool + inverno-maven-plugin + + + + com.dslplatform.dsl.json + + + com.dslplatform.json.Configuration + + + + + -Dlog4j2.simplelogLevel=INFO -Dlog4j2.level=INFO --add-reads com.techempower.inverno.benchmark=com.dslplatform.dsl.json --add-opens com.techempower.inverno.benchmark/com.techempower.inverno.benchmark.model=com.dslplatform.dsl.json + + + + + + io.inverno.epoll @@ -110,7 +160,7 @@ inverno-benchmark - -Xms2g -Xmx2g -server -XX:+UseNUMA -XX:+UseParallelGC -Dlog4j2.level=OFF -Dio.netty.leakDetection.level=disabled -Dio.netty.buffer.checkBounds=false -Dio.netty.buffer.checkAccessible=false -Dvertx.disableHttpHeadersValidation=true -Dvertx.disableMetrics=true -Dvertx.disableH2c=true -Dvertx.disableWebsockets=true -Dvertx.flashPolicyHandler=false -Dvertx.threadChecks=false -Dvertx.disableContextTimings=true -Dvertx.disableTCCL=true --add-modules io.netty.transport.unix.common,io.netty.transport.classes.epoll,io.netty.transport.epoll.linux.x86_64 + -Xms2g -Xmx2g -server -XX:+UseNUMA -XX:+UseParallelGC -Dlog4j2.level=OFF -Dio.netty.leakDetection.level=disabled -Dio.netty.buffer.checkBounds=false -Dio.netty.buffer.checkAccessible=false -Dvertx.disableHttpHeadersValidation=true -Dvertx.disableMetrics=true -Dvertx.disableH2c=true -Dvertx.disableWebsockets=true -Dvertx.flashPolicyHandler=false -Dvertx.threadChecks=false -Dvertx.disableContextTimings=true -Dvertx.disableTCCL=true --add-modules io.netty.transport.unix.common,io.netty.transport.classes.epoll,io.netty.transport.epoll.linux.x86_64 --add-reads com.techempower.inverno.benchmark=com.dslplatform.dsl.json --add-opens com.techempower.inverno.benchmark/com.techempower.inverno.benchmark.model=com.dslplatform.dsl.json @@ -119,9 +169,6 @@ - - --add-modules io.netty.transport.unix.common,io.netty.transport.classes.epoll,io.netty.transport.epoll.linux.x86_64 - @@ -157,7 +204,7 @@ inverno-benchmark - -Xms2g -Xmx2g -server -XX:+UseNUMA -XX:+UseParallelGC -Dlog4j2.level=OFF -Dio.netty.leakDetection.level=disabled -Dio.netty.buffer.checkBounds=false -Dio.netty.buffer.checkAccessible=false -Dvertx.disableHttpHeadersValidation=true -Dvertx.disableMetrics=true -Dvertx.disableH2c=true -Dvertx.disableWebsockets=true -Dvertx.flashPolicyHandler=false -Dvertx.threadChecks=false -Dvertx.disableContextTimings=true -Dvertx.disableTCCL=true --add-modules io.netty.transport.unix.common,io.netty.incubator.transport.classes.io_uring,io.netty.incubator.transport.io_uring.linux.x86_64 + -Xms2g -Xmx2g -server -XX:+UseNUMA -XX:+UseParallelGC -Dlog4j2.level=OFF -Dio.netty.leakDetection.level=disabled -Dio.netty.buffer.checkBounds=false -Dio.netty.buffer.checkAccessible=false -Dvertx.disableHttpHeadersValidation=true -Dvertx.disableMetrics=true -Dvertx.disableH2c=true -Dvertx.disableWebsockets=true -Dvertx.flashPolicyHandler=false -Dvertx.threadChecks=false -Dvertx.disableContextTimings=true -Dvertx.disableTCCL=true --add-modules io.netty.transport.unix.common,io.netty.incubator.transport.classes.io_uring,io.netty.incubator.transport.io_uring.linux.x86_64 --add-reads com.techempower.inverno.benchmark=com.dslplatform.dsl.json --add-opens com.techempower.inverno.benchmark/com.techempower.inverno.benchmark.model=com.dslplatform.dsl.json @@ -166,9 +213,6 @@ - - --add-modules io.netty.transport.unix.common,io.netty.incubator.transport.classes.io_uring,io.netty.incubator.transport.io_uring.linux.x86_64 - diff --git a/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/Main.java b/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/Main.java index 74aaf730a7e..42695fc65e7 100644 --- a/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/Main.java +++ b/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/Main.java @@ -1,17 +1,16 @@ package com.techempower.inverno.benchmark; -import java.io.IOException; -import java.util.function.Supplier; - import io.inverno.core.annotation.Bean; import io.inverno.core.v1.Application; import io.inverno.mod.configuration.ConfigurationSource; import io.inverno.mod.configuration.source.BootstrapConfigurationSource; +import java.io.IOException; +import java.util.function.Supplier; public class Main { @Bean - public interface AppConfigurationSource extends Supplier> {} + public interface AppConfigurationSource extends Supplier {} public static void main(String[] args) throws IllegalStateException, IOException { Application.with(new Benchmark.Builder() diff --git a/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/internal/Controller.java b/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/internal/Controller.java index 33c94a5c7b4..c16e6d4d767 100644 --- a/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/internal/Controller.java +++ b/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/internal/Controller.java @@ -1,7 +1,5 @@ package com.techempower.inverno.benchmark.internal; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; import com.techempower.inverno.benchmark.model.Fortune; import com.techempower.inverno.benchmark.model.Message; import com.techempower.inverno.benchmark.model.World; @@ -14,15 +12,14 @@ import io.inverno.mod.base.concurrent.Reactor; import io.inverno.mod.base.concurrent.ReactorScope; import io.inverno.mod.base.converter.ConverterException; +import io.inverno.mod.base.reflect.Types; import io.inverno.mod.http.base.ExchangeContext; import io.inverno.mod.http.base.HttpException; -import io.inverno.mod.http.base.InternalServerErrorException; import io.inverno.mod.http.base.Parameter; import io.inverno.mod.http.base.Status; -import io.inverno.mod.http.server.Exchange; import io.inverno.mod.http.server.ErrorExchange; +import io.inverno.mod.http.server.Exchange; import io.inverno.mod.http.server.ServerController; -import io.inverno.mod.sql.SqlClient; import io.inverno.mod.sql.UnsafeSqlOperations; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; @@ -30,13 +27,14 @@ import io.netty.handler.codec.http.HttpHeaderNames; import io.netty.handler.codec.http.HttpHeaderValues; import io.netty.util.AsciiString; +import java.lang.reflect.Type; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.Collections; +import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; -import java.util.function.Supplier; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -51,36 +49,32 @@ public class Controller implements ServerController> sqlClient; + private final ReactorScope jsonSerializer; + private final ReactorScope> dbRepository; private EventLoopGroup dateEventLoopGroup; private CharSequence date; public Controller(Reactor reactor, - ObjectMapper mapper, - ReactorScope> sqlClient + ReactorScope jsonSerializer, + ReactorScope> dbRepository ) { this.reactor = reactor; - this.mapper = mapper; - this.sqlClient = sqlClient; + this.jsonSerializer = jsonSerializer; + this.dbRepository = dbRepository; } @Init public void init() { this.dateEventLoopGroup = this.reactor.createIoEventLoopGroup(1); - this.dateEventLoopGroup.scheduleAtFixedRate(() -> { - this.date = new AsciiString(DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.now())); - }, 0, 1000, TimeUnit.MILLISECONDS); - - + this.dateEventLoopGroup.scheduleAtFixedRate(() -> this.date = new AsciiString(DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.now())), 0, 1000, TimeUnit.MILLISECONDS); } @Destroy @@ -139,15 +133,8 @@ public void handle(Exchange exchange) throws HttpException { } private static final CharSequence STATIC_PLAINTEXT_LEN_VALUE = AsciiString.cached(String.valueOf(STATIC_PLAINTEXT_LEN)); - - private static class PlaintextSupplier implements Supplier { - @Override - public ByteBuf get() { - return STATIC_PLAINTEXT_BYTEBUF.duplicate(); - } - } - - private static final Mono PLAIN_TEXT_MONO = Mono.fromSupplier(new PlaintextSupplier()); + + private static final Mono PLAIN_TEXT_MONO = Mono.fromSupplier(STATIC_PLAINTEXT_BYTEBUF::duplicate); public void handle_plaintext(Exchange exchange) throws HttpException { exchange.response() @@ -163,20 +150,15 @@ public void handle_plaintext(Exchange exchange) throws HttpExce } public void handle_json(Exchange exchange) throws HttpException { - try { - exchange.response() - .headers(h -> h - .add(HttpHeaderNames.SERVER, STATIC_SERVER) - .add(HttpHeaderNames.DATE, this.date) - .add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON) - ) - .body() - .raw() - .value(Unpooled.wrappedBuffer(this.mapper.writeValueAsBytes(new Message("Hello, World!")))); - } - catch (JsonProcessingException | IllegalStateException e) { - throw new InternalServerErrorException("Error serializing message as JSON", e); - } + exchange.response() + .headers(h -> h + .add(HttpHeaderNames.SERVER, STATIC_SERVER) + .add(HttpHeaderNames.DATE, this.date) + .add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON) + ) + .body() + .raw() + .value(this.jsonSerializer.get().serialize(new Message("Hello, World!"), Message.class)); } private static int randomWorldId() { @@ -191,20 +173,10 @@ public void handle_db(Exchange exchange) throws HttpException { .add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON) ) .body() - .raw().stream(this.sqlClient.get().flatMap(client -> - client.queryForObject( - DB_SELECT_WORLD, - row -> { - try { - return Unpooled.wrappedBuffer(this.mapper.writeValueAsBytes(new World(row.getInteger(0), row.getInteger(1)))); - } - catch (JsonProcessingException e) { - throw new InternalServerErrorException(e); - } - }, - randomWorldId() - ) - )); + .raw().stream(this.dbRepository.get() + .flatMap(repository -> repository.getWorld(randomWorldId())) + .map(world -> this.jsonSerializer.get().serialize(world, World.class)) + ); } private static final String PARAMETER_QUERIES = "queries"; @@ -227,8 +199,8 @@ public void handle_queries(Exchange exchange) throws HttpExcept .add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON) ) .body() - .raw().stream(this.sqlClient.get() - .flatMapMany(client -> ((UnsafeSqlOperations)client) + .raw().stream(this.dbRepository.get() + .flatMapMany(repository -> ((UnsafeSqlOperations)repository.getSqlClient()) .batchQueries(ops -> Flux.range(0, queries) .map(ign -> ops.queryForObject( @@ -239,58 +211,39 @@ public void handle_queries(Exchange exchange) throws HttpExcept ) ) .collectList() - .map(worlds -> { - try { - return Unpooled.wrappedBuffer(this.mapper.writeValueAsBytes(worlds)); - } - catch (JsonProcessingException e) { - throw new InternalServerErrorException(e); - } - }) + .map(worlds -> this.jsonSerializer.get().serialize(worlds, LIST_WORLD_TYPE)) ); } public void handle_updates(Exchange exchange) throws HttpException { int queries = this.extractQueriesParameter(exchange); - exchange.response() - .headers(h -> h - .add(HttpHeaderNames.SERVER, STATIC_SERVER) - .add(HttpHeaderNames.DATE, this.date) - .add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON) - ) - .body() - .raw().stream(this.sqlClient.get() - .flatMapMany(client -> Flux.from(((UnsafeSqlOperations)client) - .batchQueries(ops -> - Flux.range(0, queries) - .map(ign -> ops.queryForObject( - DB_SELECT_WORLD, - row -> new World(row.getInteger(0), randomWorldId()), - randomWorldId() - )) - )) - .collectSortedList() - .delayUntil(worlds -> client.batchUpdate( - DB_UPDATE_WORLD, - worlds.stream().map(world -> new Object[] { world.getRandomNumber(), world.getId() }) - ) + .headers(h -> h + .add(HttpHeaderNames.SERVER, STATIC_SERVER) + .add(HttpHeaderNames.DATE, this.date) + .add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON) + ) + .body() + .raw().stream(this.dbRepository.get() + .flatMapMany(repository -> Flux.from(((UnsafeSqlOperations)repository.getSqlClient()) + .batchQueries(ops -> + Flux.range(0, queries) + .map(ign -> ops.queryForObject( + DB_SELECT_WORLD, + row -> new World(row.getInteger(0), randomWorldId()), + randomWorldId() + )) + )) + .collectSortedList() + .delayUntil(repository::updateWorlds) + .map(worlds -> this.jsonSerializer.get().serialize(worlds, LIST_WORLD_TYPE)) ) - .map(worlds -> { - try { - return Unpooled.wrappedBuffer(this.mapper.writeValueAsBytes(worlds)); - } - catch (JsonProcessingException e) { - throw new InternalServerErrorException(e); - } - }) - ) - ); + ); } private static final CharSequence MEDIA_TEXT_HTML_UTF8 = AsciiString.cached("text/html; charset=utf-8"); - private static final FortunesTemplate.Renderer> FORTUNES_RENDERER = FortunesTemplate.bytebuf(() -> Unpooled.buffer()); + private static final FortunesTemplate.Renderer> FORTUNES_RENDERER = FortunesTemplate.bytebuf(Unpooled::buffer); public void handle_fortunes(Exchange exchange) throws HttpException { exchange.response() @@ -300,12 +253,7 @@ public void handle_fortunes(Exchange exchange) throws HttpExcep .add(HttpHeaderNames.CONTENT_TYPE, MEDIA_TEXT_HTML_UTF8) ) .body() - .raw().stream(this.sqlClient.get().flatMapMany(client -> - client.query( - DB_SELECT_FORTUNE, - row -> new Fortune(row.getInteger(0), row.getString(1)) - ) - ) + .raw().stream(this.dbRepository.get().flatMapMany(DbRepository::listFortunes) .collectList() .flatMap(fortunes -> { fortunes.add(new Fortune(0, "Additional fortune added at request time.")); diff --git a/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/internal/DbRepository.java b/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/internal/DbRepository.java new file mode 100644 index 00000000000..28699e3c1d0 --- /dev/null +++ b/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/internal/DbRepository.java @@ -0,0 +1,132 @@ +package com.techempower.inverno.benchmark.internal; + +import com.techempower.inverno.benchmark.AppConfiguration; +import com.techempower.inverno.benchmark.model.Fortune; +import com.techempower.inverno.benchmark.model.World; +import io.inverno.core.annotation.Bean; +import io.inverno.core.annotation.Destroy; +import io.inverno.core.annotation.Init; +import io.inverno.mod.base.concurrent.Reactor; +import io.inverno.mod.base.concurrent.VertxReactor; +import io.inverno.mod.sql.PreparedStatement; +import io.inverno.mod.sql.SqlClient; +import io.inverno.mod.sql.vertx.ConnectionSqlClient; +import io.vertx.core.Vertx; +import io.vertx.core.VertxOptions; +import io.vertx.pgclient.PgConnectOptions; +import io.vertx.pgclient.PgConnection; +import java.util.ArrayList; +import java.util.List; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +public class DbRepository { + + public static final String DB_SELECT_WORLD = "SELECT id, randomnumber from WORLD where id = $1"; + public static final String DB_SELECT_FORTUNE = "SELECT id, message from FORTUNE"; + + private final SqlClient sqlClient; + + private final PreparedStatement selectWorldByIdQuery; + private final PreparedStatement selectFortuneQuery; + private final PreparedStatement[] updateWorldQueries; + + public DbRepository(SqlClient sqlClient) { + this.sqlClient = sqlClient; + + this.selectWorldByIdQuery = sqlClient.preparedStatement(DB_SELECT_WORLD); + this.selectFortuneQuery = sqlClient.preparedStatement(DB_SELECT_FORTUNE); + this.updateWorldQueries = new PreparedStatement[500]; + for(int i=0;i getWorld(int id) { + return Mono.from(this.selectWorldByIdQuery.bind(id).execute(row -> new World(row.getInteger(0), row.getInteger(1)))); + } + + public Flux listFortunes() { + return Flux.from(this.selectFortuneQuery.execute(row -> new Fortune(row.getInteger(0), row.getString(1)))); + } + + public Mono updateWorlds(List worlds) { + int len = worlds.size(); + List parameters = new ArrayList<>(len * 2); + for(World world : worlds) { + parameters.add(world.getId()); + parameters.add(world.getRandomNumber()); + } + return Mono.when(this.updateWorldQueries[len - 1].bind(parameters).execute()); + } + + @Bean( name = "dbRespository", visibility = Bean.Visibility.PRIVATE ) + public static class ReactorScope extends io.inverno.mod.base.concurrent.ReactorScope> { + + private final AppConfiguration configuration; + private final Reactor reactor; + + private Vertx vertx; + private PgConnectOptions connectOptions; + + public ReactorScope(AppConfiguration configuration, Reactor reactor) { + this.configuration = configuration; + this.reactor = reactor; + } + + @Init + public void init() { + if(this.reactor instanceof VertxReactor) { + this.vertx = ((VertxReactor)this.reactor).getVertx(); + } + else { + this.vertx = Vertx.vertx(new VertxOptions().setPreferNativeTransport(this.configuration.boot().prefer_native_transport())); + } + + this.connectOptions = new PgConnectOptions() + .setHost(this.configuration.db_host()) + .setPort(this.configuration.db_port()) + .setDatabase(this.configuration.db_database()) + .setUser(this.configuration.db_username()) + .setPassword(this.configuration.db_password()) + .setCachePreparedStatements(true) + .setPreparedStatementCacheMaxSize(1024) + .setPipeliningLimit(100_100); + } + + @Destroy + public void destroy() { + if(!(this.reactor instanceof VertxReactor)) { + this.vertx.close(); + } + } + + @Override + protected Mono create() { + return Mono.fromCompletionStage(() -> PgConnection.connect(this.vertx, this.connectOptions).toCompletionStage()) + .map(pgConn -> new DbRepository(new ConnectionSqlClient(pgConn))) + .cacheInvalidateWhen(repository -> ((ConnectionSqlClient)repository.getSqlClient()).onClose()); + } + } +} diff --git a/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/internal/JsonSerializer.java b/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/internal/JsonSerializer.java new file mode 100644 index 00000000000..24ce79eedd3 --- /dev/null +++ b/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/internal/JsonSerializer.java @@ -0,0 +1,38 @@ +package com.techempower.inverno.benchmark.internal; + +import com.dslplatform.json.DslJson; +import com.dslplatform.json.JsonWriter; +import io.inverno.core.annotation.Bean; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import java.lang.reflect.Type; + +public class JsonSerializer { + + private static final DslJson DSL_JSON = new DslJson<>(); + + private final JsonWriter jsonWriter; + + public JsonSerializer() { + this.jsonWriter = DSL_JSON.newWriter(); + } + + public ByteBuf serialize(T value, Type type) { + try { + DSL_JSON.serialize(this.jsonWriter, type, value); + return Unpooled.wrappedBuffer(this.jsonWriter.toByteArray()); + } + finally { + this.jsonWriter.reset(); + } + } + + @Bean( name = "jsonSerializer", visibility = Bean.Visibility.PRIVATE ) + public static class ReactorScope extends io.inverno.mod.base.concurrent.ReactorScope { + + @Override + protected JsonSerializer create() { + return new JsonSerializer(); + } + } +} diff --git a/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/internal/SqlClientReactorScope.java b/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/internal/SqlClientReactorScope.java deleted file mode 100644 index d3b8a463865..00000000000 --- a/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/internal/SqlClientReactorScope.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.techempower.inverno.benchmark.internal; - -import com.techempower.inverno.benchmark.AppConfiguration; - -import io.inverno.core.annotation.Bean; -import io.inverno.core.annotation.Bean.Visibility; -import io.inverno.core.annotation.Destroy; -import io.inverno.core.annotation.Init; -import io.inverno.mod.base.concurrent.Reactor; -import io.inverno.mod.base.concurrent.ReactorScope; -import io.inverno.mod.base.concurrent.VertxReactor; -import io.inverno.mod.sql.SqlClient; -import io.inverno.mod.sql.vertx.ConnectionSqlClient; -import io.vertx.core.Vertx; -import io.vertx.core.VertxOptions; -import io.vertx.pgclient.PgConnectOptions; -import io.vertx.pgclient.PgConnection; -import reactor.core.publisher.Mono; - -@Bean( name = "SqlClient", visibility = Visibility.PRIVATE ) -public class SqlClientReactorScope extends ReactorScope> { - - private final AppConfiguration configuration; - private final Reactor reactor; - - private Vertx vertx; - private PgConnectOptions connectOptions; - - public SqlClientReactorScope(AppConfiguration configuration, Reactor reactor) { - this.configuration = configuration; - this.reactor = reactor; - } - - @Init - public void init() { - if(this.reactor instanceof VertxReactor) { - this.vertx = ((VertxReactor)this.reactor).getVertx(); - } - else { - this.vertx = Vertx.vertx(new VertxOptions().setPreferNativeTransport(this.configuration.boot().prefer_native_transport())); - } - - this.connectOptions = new PgConnectOptions() - .setHost(this.configuration.db_host()) - .setPort(this.configuration.db_port()) - .setDatabase(this.configuration.db_database()) - .setUser(this.configuration.db_username()) - .setPassword(this.configuration.db_password()) - .setCachePreparedStatements(true) - .setPipeliningLimit(100_100); - } - - @Destroy - public void destroy() { - if(!(this.reactor instanceof VertxReactor)) { - this.vertx.close(); - } - } - - @Override - protected Mono create() { - return Mono.fromCompletionStage(() -> PgConnection.connect(this.vertx, this.connectOptions).toCompletionStage()) - .map(pgConn -> (SqlClient)new ConnectionSqlClient(pgConn)) - .cacheInvalidateWhen(client -> ((ConnectionSqlClient)client).onClose()); - } -} diff --git a/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/model/Fortune.java b/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/model/Fortune.java index de4017c3c0d..b00a8a9df9f 100644 --- a/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/model/Fortune.java +++ b/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/model/Fortune.java @@ -1,5 +1,8 @@ package com.techempower.inverno.benchmark.model; +import com.dslplatform.json.CompiledJson; + +@CompiledJson public final class Fortune implements Comparable { private final int id; diff --git a/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/model/Message.java b/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/model/Message.java index c9d554903d7..306d5c348d6 100644 --- a/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/model/Message.java +++ b/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/model/Message.java @@ -1,5 +1,8 @@ package com.techempower.inverno.benchmark.model; +import com.dslplatform.json.CompiledJson; + +@CompiledJson public final class Message { private final String message; diff --git a/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/model/World.java b/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/model/World.java index f0f1825f3b9..6defeb042a3 100644 --- a/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/model/World.java +++ b/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/model/World.java @@ -1,14 +1,15 @@ package com.techempower.inverno.benchmark.model; +import com.dslplatform.json.CompiledJson; + +@CompiledJson public final class World implements Comparable { - private final int id; + private int id; private int randomNumber; - public World(int id) { - this.id = id; - } - + public World() {} + public World(int id, int randomNumber) { this.id = id; this.randomNumber = randomNumber; diff --git a/frameworks/Java/inverno/src/main/java/module-info.java b/frameworks/Java/inverno/src/main/java/module-info.java index fefbf5c52a6..39d0224949b 100644 --- a/frameworks/Java/inverno/src/main/java/module-info.java +++ b/frameworks/Java/inverno/src/main/java/module-info.java @@ -10,16 +10,13 @@ requires io.netty.common; requires io.netty.codec.http; requires unbescape; - + requires static dsl.json; + requires io.vertx.client.sql.pg; requires io.vertx.client.sql; requires io.vertx.core; requires java.sql; - - //requires transitive io.netty.transport; - //requires static io.netty.transport.unix.common; - //requires static io.netty.transport.epoll; - + exports com.techempower.inverno.benchmark; exports com.techempower.inverno.benchmark.model; }