Ver Fonte

New benchmark implementation for Helidon that includes Nima support (#7614)

* Initial changes to support Helidon 4 reactive and nima benchmarks running with ALPHA1 and JDK 19.

Signed-off-by: Santiago Pericasgeertsen <[email protected]>

* Renamed docker files, updated configuration and fixed returned media type.

Signed-off-by: Santiago Pericasgeertsen <[email protected]>

* Use 0.0.0.0 for IP to bind all interfaces (Docker network). Provide fake endpoints for unimplemented tests.

* Implemented all Db operations using pgclient and vertx (like the original implementation). There are still some failures with a large number of concurrent Db queries/updates.

* Created new internal Db methods for better handling of clients. Verification is now passing for all tests.

* Changes to pool SQL pool creation to fix latency problems. Now using single, shared pool whose size is configurable via config.

* Set write queue size to 1K to avoid OOM errors.

Signed-off-by: Santiago Pericasgeertsen <[email protected]>

* Updated test metadata and removed JVM options.

Signed-off-by: Santiago Pericasgeertsen <[email protected]>

* Set a larger SQL pool size.

Signed-off-by: Santiago Pericasgeertsen <[email protected]>

* Use a separate connection pool for updates.

Signed-off-by: Santiago Pericasgeertsen <[email protected]>

* Implementation of alternative Db repository using JDBC/Hikari. Default still set to pgclient.

Signed-off-by: Santiago Pericasgeertsen <[email protected]>

* Added support for batch updates with pgclient. See application.yaml for more info.

Signed-off-by: Santiago Pericasgeertsen <[email protected]>

* Adjusted timeout.

Signed-off-by: Santiago Pericasgeertsen <[email protected]>

* New implementation for query.

Signed-off-by: Santiago Pericasgeertsen <[email protected]>

* Small improvement for db test.

Signed-off-by: Santiago Pericasgeertsen <[email protected]>

* Improvements to fortune test.

Signed-off-by: Santiago Pericasgeertsen <[email protected]>

* Completed JDBC/Hikari implementation.

Signed-off-by: Santiago Pericasgeertsen <[email protected]>

* Remove unit tests in preparation for PR.

Signed-off-by: Santiago Pericasgeertsen <[email protected]>

* Switching reactive module to use version 3.0.1 of Helidon.

Signed-off-by: Santiago Pericasgeertsen <[email protected]>

* Updated README file.

Signed-off-by: Santiago Pericasgeertsen <[email protected]>

Signed-off-by: Santiago Pericasgeertsen <[email protected]>
Santiago Pericas-Geertsen há 2 anos atrás
pai
commit
b896bdf949
32 ficheiros alterados com 1245 adições e 137 exclusões
  1. 25 11
      frameworks/Java/helidon/README.md
  2. 25 2
      frameworks/Java/helidon/benchmark_config.json
  3. 18 1
      frameworks/Java/helidon/config.toml
  4. 32 0
      frameworks/Java/helidon/helidon-nima.dockerfile
  5. 23 10
      frameworks/Java/helidon/helidon.dockerfile
  6. 148 0
      frameworks/Java/helidon/nima/pom.xml
  7. 194 0
      frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/Main.java
  8. 47 0
      frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/DbRepository.java
  9. 2 1
      frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/Fortune.java
  10. 127 0
      frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/HikariJdbcRepository.java
  11. 197 0
      frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/PgClientRepository.java
  12. 6 4
      frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/World.java
  13. 76 0
      frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/services/DbService.java
  14. 40 0
      frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/services/FortuneHandler.java
  15. 49 0
      frameworks/Java/helidon/nima/src/main/resources/application.yaml
  16. 7 0
      frameworks/Java/helidon/nima/src/main/resources/config-profile.yaml
  17. 19 0
      frameworks/Java/helidon/nima/src/main/resources/logging.properties
  18. 1 1
      frameworks/Java/helidon/nima/src/main/resources/views/fortunes.rocker.html
  19. 6 82
      frameworks/Java/helidon/pom.xml
  20. 111 0
      frameworks/Java/helidon/reactive/pom.xml
  21. 8 7
      frameworks/Java/helidon/reactive/src/main/java/io/helidon/benchmark/reactive/Main.java
  22. 1 1
      frameworks/Java/helidon/reactive/src/main/java/io/helidon/benchmark/reactive/models/DbRepository.java
  23. 19 0
      frameworks/Java/helidon/reactive/src/main/java/io/helidon/benchmark/reactive/models/Fortune.java
  24. 1 1
      frameworks/Java/helidon/reactive/src/main/java/io/helidon/benchmark/reactive/models/JdbcRepository.java
  25. 25 0
      frameworks/Java/helidon/reactive/src/main/java/io/helidon/benchmark/reactive/models/World.java
  26. 6 7
      frameworks/Java/helidon/reactive/src/main/java/io/helidon/benchmark/reactive/services/DbService.java
  27. 4 5
      frameworks/Java/helidon/reactive/src/main/java/io/helidon/benchmark/reactive/services/FortuneService.java
  28. 3 3
      frameworks/Java/helidon/reactive/src/main/java/io/helidon/benchmark/reactive/services/JsonService.java
  29. 1 1
      frameworks/Java/helidon/reactive/src/main/java/io/helidon/benchmark/reactive/services/PlainTextService.java
  30. 0 0
      frameworks/Java/helidon/reactive/src/main/resources/application.yaml
  31. 0 0
      frameworks/Java/helidon/reactive/src/main/resources/logging.properties
  32. 24 0
      frameworks/Java/helidon/reactive/src/main/resources/views/fortunes.rocker.html

+ 25 - 11
frameworks/Java/helidon/README.md

@@ -1,37 +1,51 @@
 # Helidon Benchmarking Test
 
 This is the Helidon portion of a [benchmarking test suite](../) comparing a variety of web development platforms.
+Two Helidon APIs are implemented: Reactive and Nima. The Reactive API has been around since the first
+version of Helidon while Nima is a new, blocking API based on JDK 19 virtual threads. 
+
+The code is organized into two Maven modules, namely, *reactive* and *nima*. Both modules implement the
+same set of tests outlined below. 
 
-There is currently one repository implementation.
-* [JdbcRepository](src/main/java/io/helidon/benchmark/models/JdbcRepository.java) is using Vertx pg client.
 ### Plaintext Test
 
-* [Plaintext test source](src/main/java/io/helidon/benchmark/services/PlainTextService.java)
+* [Reactive](src/main/java/io/helidon/benchmark/reactive/services/PlainTextService.java)
+* [Nima](src/main/java/io/helidon/benchmark/nima/Main.java)
 
 ### JSON Serialization Test
 
-* [JSON test source](src/main/java/io/helidon/benchmark/services/JsonService.java)
+* [Reactive](src/main/java/io/helidon/benchmark/reactive/services/JsonService.java)
+* [Nima](src/main/java/io/helidon/benchmark/nima/Main.java)
 
 ### Database Query Test
 
-* [Database Query test source](src/main/java/io/helidon/benchmark/services/DbService.java)
+* [Reactive](src/main/java/io/helidon/benchmark/reactive/services/DbService.java)
+* [Nima](src/main/java/io/helidon/benchmark/nima/services/DbService.java)
 
 ### Database Queries Test
 
-* [Database Queries test source](src/main/java/io/helidon/benchmark/services/DbService.java)
+* [Reactive](src/main/java/io/helidon/benchmark/reactive/services/DbService.java)
+* [Nima](src/main/java/io/helidon/benchmark/nima/services/DbService.java)
 
 ### Database Update Test
 
-* [Database Update test source](src/main/java/io/helidon/benchmark/services/DbService.java)
+* [Reactive](src/main/java/io/helidon/benchmark/reactive/services/DbService.java)
+* [Nima](src/main/java/io/helidon/benchmark/nima/services/DbService.java)
 
-### Template rendering Test
+### Template Rendering Test
 
-* [Template rendering test source](src/main/java/io/helidon/benchmark/services/FortuneService.java)
+* [Reactive](src/main/java/io/helidon/benchmark/reactive/services/FortuneService.java)
+* [Nima](src/main/java/io/helidon/benchmark/nima/services/FortuneHandler.java)
 
 ## Versions
 
-* [Java OpenJDK 11](http://openjdk.java.net/)
-* [Helidon 2.4.0](http://helidon.io/)
+* Reactive
+  * [Java OpenJDK 11](http://openjdk.java.net/)
+  * [Helidon 3.0.1](http://helidon.io/)
+  
+* Nima
+  * [Java OpenJDK 19 w/Loom](http://openjdk.java.net/)
+  * [Helidon 4.0.0-ALPHA1](http://helidon.io/)
 
 ## Test URLs
 

+ 25 - 2
frameworks/Java/helidon/benchmark_config.json

@@ -13,7 +13,7 @@
         "approach": "Realistic",
         "classification": "Micro",
         "database": "Postgres",
-        "framework": "Helidon",
+        "framework": "Helidon Reactive",
         "language": "Java",
         "flavor": "None",
         "orm": "Raw",
@@ -21,7 +21,30 @@
         "webserver": "None",
         "os": "Linux",
         "database_os": "Linux",
-        "display_name": "Helidon",
+        "display_name": "Helidon Reactive",
+        "notes": "",
+        "versus": "Netty"
+      },
+      "nima": {
+        "json_url": "/json",
+        "plaintext_url": "/plaintext",
+        "db_url": "/db",
+        "query_url": "/queries?queries=",
+        "update_url": "/updates?queries=",
+        "fortune_url": "/fortunes",
+        "port": 8080,
+        "approach": "Realistic",
+        "classification": "Micro",
+        "database": "Postgres",
+        "framework": "Helidon Nima",
+        "language": "Java",
+        "flavor": "None",
+        "orm": "Raw",
+        "platform": "Nima",
+        "webserver": "None",
+        "os": "Linux",
+        "database_os": "Linux",
+        "display_name": "Helidon Nima",
         "notes": "",
         "versus": "Netty"
       }

+ 18 - 1
frameworks/Java/helidon/config.toml

@@ -1,7 +1,7 @@
 [framework]
 name = "helidon"
 
-[main]
+[reactive]
 urls.plaintext = "/plaintext"
 urls.json = "/json"
 urls.db = "/db"
@@ -17,3 +17,20 @@ orm = "Raw"
 platform = "Netty"
 webserver = "None"
 versus = "Netty"
+
+[nima]
+urls.plaintext = "/plaintext"
+urls.json = "/json"
+urls.db = "/db"
+urls.query = "/queries?queries="
+urls.update = "/updates?queries="
+urls.fortune = "/fortunes"
+approach = "Realistic"
+classification = "Micro"
+database = "Postgres"
+database_os = "Linux"
+os = "Linux"
+orm = "Raw"
+platform = "Nima"
+webserver = "None"
+versus = "Netty"

+ 32 - 0
frameworks/Java/helidon/helidon-nima.dockerfile

@@ -0,0 +1,32 @@
+FROM openjdk:19-jdk-slim as maven
+
+RUN apt-get update \
+  && apt-get install -y curl procps \
+  && rm -rf /var/lib/apt/lists/*
+ARG MAVEN_VERSION=3.8.6
+ARG USER_HOME_DIR="/root"
+ARG SHA=f790857f3b1f90ae8d16281f902c689e4f136ebe584aba45e4b1fa66c80cba826d3e0e52fdd04ed44b4c66f6d3fe3584a057c26dfcac544a60b301e6d0f91c26
+ARG BASE_URL=https://apache.osuosl.org/maven/maven-3/${MAVEN_VERSION}/binaries
+RUN mkdir -p /usr/share/maven /usr/share/maven/ref \
+  && curl -fsSL -o /tmp/apache-maven.tar.gz ${BASE_URL}/apache-maven-${MAVEN_VERSION}-bin.tar.gz \
+  && echo "${SHA}  /tmp/apache-maven.tar.gz" | sha512sum -c - \
+  && tar -xzf /tmp/apache-maven.tar.gz -C /usr/share/maven --strip-components=1 \
+  && rm -f /tmp/apache-maven.tar.gz \
+  && ln -s /usr/share/maven/bin/mvn /usr/bin/mvn
+ENV MAVEN_HOME /usr/share/maven
+ENV MAVEN_CONFIG "$USER_HOME_DIR/.m2"
+
+WORKDIR /helidon
+COPY nima/src src
+COPY nima/pom.xml pom.xml
+RUN mvn package -q
+
+FROM openjdk:19-jdk-slim
+WORKDIR /helidon
+COPY --from=maven /helidon/target/libs libs
+COPY --from=maven /helidon/target/benchmark-nima.jar app.jar
+
+EXPOSE 8080
+
+CMD java --enable-preview \
+    -jar app.jar

+ 23 - 10
frameworks/Java/helidon/helidon.dockerfile

@@ -1,21 +1,34 @@
-FROM maven:3.6.1-jdk-11-slim as maven
+FROM openjdk:19-jdk-slim as maven
+
+RUN apt-get update \
+  && apt-get install -y curl procps \
+  && rm -rf /var/lib/apt/lists/*
+ARG MAVEN_VERSION=3.8.6
+ARG USER_HOME_DIR="/root"
+ARG SHA=f790857f3b1f90ae8d16281f902c689e4f136ebe584aba45e4b1fa66c80cba826d3e0e52fdd04ed44b4c66f6d3fe3584a057c26dfcac544a60b301e6d0f91c26
+ARG BASE_URL=https://apache.osuosl.org/maven/maven-3/${MAVEN_VERSION}/binaries
+RUN mkdir -p /usr/share/maven /usr/share/maven/ref \
+  && curl -fsSL -o /tmp/apache-maven.tar.gz ${BASE_URL}/apache-maven-${MAVEN_VERSION}-bin.tar.gz \
+  && echo "${SHA}  /tmp/apache-maven.tar.gz" | sha512sum -c - \
+  && tar -xzf /tmp/apache-maven.tar.gz -C /usr/share/maven --strip-components=1 \
+  && rm -f /tmp/apache-maven.tar.gz \
+  && ln -s /usr/share/maven/bin/mvn /usr/bin/mvn
+ENV MAVEN_HOME /usr/share/maven
+ENV MAVEN_CONFIG "$USER_HOME_DIR/.m2"
+
 WORKDIR /helidon
-COPY src src
-COPY pom.xml pom.xml
+COPY reactive/src src
+COPY reactive/pom.xml pom.xml
 RUN mvn package -q
 
-FROM openjdk:11.0.3-jdk-slim
+FROM openjdk:19-jdk-slim
 WORKDIR /helidon
 COPY --from=maven /helidon/target/libs libs
-COPY --from=maven /helidon/target/benchmark.jar app.jar
+COPY --from=maven /helidon/target/benchmark-reactive.jar app.jar
 
 EXPOSE 8080
 
 CMD java -server \
-    -XX:-UseBiasedLocking \
-    -XX:+UseNUMA \
-    -XX:+AggressiveOpts \
-    -XX:+UseParallelGC \
     -Dio.netty.buffer.checkBounds=false \
     -Dio.netty.buffer.checkAccessible=false \
-    -jar app.jar
+    -jar app.jar

+ 148 - 0
frameworks/Java/helidon/nima/pom.xml

@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    Copyright (c) 2022 Oracle and/or its affiliates.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+  -->
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xmlns="http://maven.apache.org/POM/4.0.0"
+        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>io.helidon.applications</groupId>
+        <artifactId>helidon-se</artifactId>
+        <version>4.0.0-ALPHA1</version>
+        <relativePath/>
+    </parent>
+
+    <groupId>io.helidon</groupId>
+    <artifactId>benchmark-nima</artifactId>
+    <version>1.0-SNAPSHOT</version>
+    <packaging>jar</packaging>
+    <name>${project.artifactId}</name>
+
+    <properties>
+        <mainClass>io.helidon.benchmark.nima.Main</mainClass>
+        <version.java>19</version.java>
+        <version.plugin.compiler>3.8.1</version.plugin.compiler>
+        <rocker.version>1.3.0</rocker.version>
+        <vertx-pg-client.version>4.2.0</vertx-pg-client.version>
+        <jsoniter.version>0.9.23</jsoniter.version>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>io.helidon.nima.webserver</groupId>
+            <artifactId>helidon-nima-webserver</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.helidon.config</groupId>
+            <artifactId>helidon-config-yaml</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.helidon.nima.http.media</groupId>
+            <artifactId>helidon-nima-http-media-jsonp</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.helidon.common</groupId>
+            <artifactId>helidon-common-reactive</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.jsoniter</groupId>
+            <artifactId>jsoniter</artifactId>
+            <version>${jsoniter.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.vertx</groupId>
+            <artifactId>vertx-pg-client</artifactId>
+            <version>${vertx-pg-client.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.zaxxer</groupId>
+            <artifactId>HikariCP</artifactId>
+            <version>5.0.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.postgresql</groupId>
+            <artifactId>postgresql</artifactId>
+            <version>42.5.0</version>
+        </dependency>
+        <dependency>
+            <groupId>com.fizzed</groupId>
+            <artifactId>rocker-runtime</artifactId>
+            <version>${rocker.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.helidon.nima.testing.junit5</groupId>
+            <artifactId>helidon-nima-testing-junit5-webserver</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-api</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.hamcrest</groupId>
+            <artifactId>hamcrest-all</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>${version.plugin.compiler}</version>
+                <configuration>
+                    <source>${version.java}</source>
+                    <target>${version.java}</target>
+                    <release>${version.java}</release>
+                    <forceJavacCompilerUse>true</forceJavacCompilerUse>
+                    <compilerArgs>
+                        <arg>-Xlint:unchecked</arg>
+                        <arg>-Xpkginfo:always</arg>
+                        <arg>--enable-preview</arg>
+                    </compilerArgs>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>copy-libs</id>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>com.fizzed</groupId>
+                <artifactId>rocker-maven-plugin</artifactId>
+                <version>${rocker.version}</version>
+                <executions>
+                    <execution>
+                        <id>generate-rocker-templates</id>
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>generate</goal>
+                        </goals>
+                        <configuration>
+                            <templateDirectory>src/main/resources</templateDirectory>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 194 - 0
frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/Main.java

@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2022 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+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;
+import io.helidon.benchmark.nima.services.DbService;
+import io.helidon.benchmark.nima.services.FortuneHandler;
+import io.helidon.common.LogConfig;
+import io.helidon.common.http.Http;
+import io.helidon.common.http.Http.Header;
+import io.helidon.common.http.Http.HeaderValue;
+import io.helidon.common.http.Http.HeaderValues;
+import io.helidon.config.Config;
+import io.helidon.config.ConfigException;
+import io.helidon.nima.webserver.WebServer;
+import io.helidon.nima.webserver.http.Handler;
+import io.helidon.nima.webserver.http.HttpRules;
+import io.helidon.nima.webserver.http.ServerRequest;
+import io.helidon.nima.webserver.http.ServerResponse;
+
+/**
+ * Main class of the benchmark.
+ * Opens server on localhost:8080 and exposes {@code /plaintext} and {@code /json} endpoints adhering to the
+ * rules of TechEmpower benchmarking.
+ */
+public final class Main {
+    private static final Logger LOGGER = Logger.getLogger(Main.class.getName());
+
+    public static final Http.HeaderValue CONTENT_TYPE_HTML =
+            Http.HeaderValue.createCached(Http.Header.CONTENT_TYPE, "text/html; charset=UTF-8");
+    public static final Http.HeaderValue SERVER = Http.HeaderValue.createCached(Http.Header.SERVER, "Nima");
+
+    private Main() {
+    }
+
+    /**
+     * Start the server.
+     *
+     * @param args ignored
+     */
+    public static void main(String[] args) {
+        // logging and config
+        LogConfig.configureRuntime();
+
+        WebServer.builder()
+                .routing(Main::routing)
+                .start();
+    }
+
+    // exposed for tests
+    static void routing(HttpRules rules) {
+        Config config = Config.create();
+
+        DbRepository repository;
+        String name = config.get("db-repository").asString().orElse("pgclient");
+        LOGGER.info("Using '" + name + "' as DB repository");
+        if (name.equalsIgnoreCase("hikari")) {
+            repository = new HikariJdbcRepository(config);
+        } else if (name.equalsIgnoreCase("pgclient")) {
+            repository = new PgClientRepository(config);
+        } else {
+            throw new ConfigException("Allowed values for 'db-repository' are 'hikari' and 'pgclient'");
+        }
+
+        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 HeaderValue CONTENT_TYPE = HeaderValue.createCached(Header.CONTENT_TYPE,
+                "text/plain; charset=UTF-8");
+        static final HeaderValue CONTENT_LENGTH = HeaderValue.createCached(Header.CONTENT_LENGTH, "13");
+
+        private static final byte[] RESPONSE_BYTES = "Hello, World!".getBytes(StandardCharsets.UTF_8);
+
+        @Override
+        public void handle(ServerRequest req, ServerResponse res) {
+            res.header(CONTENT_LENGTH);
+            res.header(CONTENT_TYPE);
+            res.header(Main.SERVER);
+            res.send(RESPONSE_BYTES);
+        }
+    }
+
+    static class JsonHandler implements Handler {
+        private static final String MESSAGE = "Hello, World!";
+        private static final int JSON_LENGTH = serializeMsg(new Message(MESSAGE)).length;
+        static final HeaderValue CONTENT_LENGTH = HeaderValue.createCached(Header.CONTENT_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 HeaderValue contentLength;
+        private final String message;
+
+        JsonKHandler(int kilobytes) {
+            this.message = "a".repeat(1024 * kilobytes);
+            int length = serializeMsg(new Message(message)).length;
+            this.contentLength = HeaderValue.createCached(Header.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);
+        }
+    }
+
+    /**
+     * Message to be serialized as JSON.
+     */
+    public static final class Message {
+
+        private final String message;
+
+        /**
+         * Construct a new message.
+         *
+         * @param message message string
+         */
+        public Message(String message) {
+            super();
+            this.message = message;
+        }
+
+        /**
+         * Get message string.
+         *
+         * @return message string
+         */
+        public String getMessage() {
+            return message;
+        }
+    }
+}

+ 47 - 0
frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/DbRepository.java

@@ -0,0 +1,47 @@
+
+package io.helidon.benchmark.nima.models;
+
+import java.util.Collections;
+import java.util.List;
+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<World> 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<World> updateWorlds(int count);
+
+    List<Fortune> getFortunes();
+
+    static int randomWorldNumber() {
+        return 1 + ThreadLocalRandom.current().nextInt(10000);
+    }
+}

+ 2 - 1
frameworks/Java/helidon/src/main/java/io/helidon/benchmark/models/Fortune.java → frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/Fortune.java

@@ -1,4 +1,5 @@
-package io.helidon.benchmark.models;
+
+package io.helidon.benchmark.nima.models;
 
 public final class Fortune {
     public int id;

+ 127 - 0
frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/HikariJdbcRepository.java

@@ -0,0 +1,127 @@
+
+package io.helidon.benchmark.nima.models;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Logger;
+
+import com.zaxxer.hikari.HikariConfig;
+import com.zaxxer.hikari.HikariDataSource;
+import io.helidon.config.Config;
+
+import static io.helidon.benchmark.nima.models.DbRepository.randomWorldNumber;
+
+public class HikariJdbcRepository implements DbRepository {
+    private static final Logger LOGGER = Logger.getLogger(HikariJdbcRepository.class.getName());
+
+    private HikariDataSource ds;
+    private final HikariConfig hikariConfig;
+
+    public HikariJdbcRepository(Config config) {
+        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");
+
+        int poolSize = config.get("sql-pool-size").asInt().orElse(64);
+        hikariConfig.addDataSourceProperty("maximumPoolSize", poolSize);
+        LOGGER.info("Db pool size is set to " + poolSize);
+    }
+
+    private Connection getConnection() throws SQLException {
+        if (ds == null) {
+            ds = new HikariDataSource(hikariConfig);
+        }
+        return ds.getConnection();
+    }
+
+    @Override
+    public World getWorld(int id) {
+        try (Connection c = getConnection()) {
+            return getWorld(id, c);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public List<World> getWorlds(int count) {
+        try (Connection c = getConnection()) {
+            List<World> result = new ArrayList<>(count);
+            for (int i = 0; i < count; i++) {
+                result.add(getWorld(randomWorldNumber(), c));
+            }
+            return result;
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public World updateWorld(World world) {
+        try (Connection c = getConnection()) {
+            return updateWorld(world, c);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public List<World> updateWorlds(int count) {
+        try (Connection c = getConnection()) {
+            List<World> result = new ArrayList<>(count);
+            for (int i = 0; i < count; i++) {
+                World world = getWorld(randomWorldNumber(), c);
+                world.randomNumber = randomWorldNumber();
+                updateWorld(world, c);
+                result.add(world);
+            }
+            return result;
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public List<Fortune> getFortunes() {
+        try (Connection c = getConnection()) {
+            List<Fortune> result = new ArrayList<>();
+            PreparedStatement ps = c.prepareStatement("SELECT id, message FROM fortune");
+            ResultSet rs = ps.executeQuery();
+            while (rs.next()) {
+                result.add(new Fortune(rs.getInt(1), rs.getString(2)));
+            }
+            return result;
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private World getWorld(int id, Connection c) throws SQLException {
+        PreparedStatement ps = c.prepareStatement("SELECT id, randomnumber FROM world WHERE id = ?");
+        ps.setObject(1, id);
+        ResultSet rs = ps.executeQuery();
+        rs.next();
+        World w = new World(rs.getInt(1), rs.getInt(2));
+        rs.close();
+        return w;
+    }
+
+    private World updateWorld(World world, Connection c) throws SQLException {
+        PreparedStatement ps = c.prepareStatement("UPDATE world SET randomnumber = ? WHERE id = ?");
+        ps.setObject(1, world.randomNumber);
+        ps.setObject(2, world.id);
+        ps.executeUpdate();
+        return world;
+    }
+}

+ 197 - 0
frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/PgClientRepository.java

@@ -0,0 +1,197 @@
+package io.helidon.benchmark.nima.models;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+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.pgclient.PgConnectOptions;
+import io.vertx.pgclient.PgPool;
+import io.vertx.sqlclient.PoolOptions;
+import io.vertx.sqlclient.Row;
+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;
+
+    private final int batchSize;
+    private final long updateTimeout;
+    private final int maxRetries;
+
+    public PgClientRepository(Config config) {
+        Vertx vertx = Vertx.vertx(new VertxOptions()
+                .setPreferNativeTransport(true));
+        PgConnectOptions connectOptions = new PgConnectOptions()
+                .setPort(config.get("port").asInt().orElse(5432))
+                .setCachePreparedStatements(config.get("cache-prepared-statements").asBoolean().orElse(true))
+                .setHost(config.get("host").asString().orElse("tfb-database"))
+                .setDatabase(config.get("db").asString().orElse("hello_world"))
+                .setUser(config.get("username").asString().orElse("benchmarkdbuser"))
+                .setPassword(config.get("password").asString().orElse("benchmarkdbpass"));
+
+        int sqlPoolSize = config.get("sql-pool-size").asInt().orElse(64);
+        PoolOptions clientOptions = new PoolOptions().setMaxSize(sqlPoolSize);
+        LOGGER.info("sql-pool-size is " + sqlPoolSize);
+        batchSize = config.get("update-batch-size").asInt().orElse(20);
+        LOGGER.info("update-batch-size is " + batchSize);
+        updateTimeout = config.get("update-timeout-millis").asInt().orElse(5000);
+        LOGGER.info("update-timeout-millis is " + updateTimeout);
+        maxRetries = config.get("update-max-retries").asInt().orElse(3);
+        LOGGER.info("update-max-retries is " + maxRetries);
+
+        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();
+    }
+
+    @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();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public List<World> getWorlds(int count) {
+        try {
+            List<World> result = new ArrayList<>(count);
+            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);
+            }
+            return result;
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public World updateWorld(World world) {
+        try {
+            updateWorlds(List.of(world), 0, updatePool);
+            return world;
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public List<World> updateWorlds(int count) {
+        List<World> worlds = getWorlds(count);
+        for (World w : worlds) {
+            w.randomNumber = randomWorldNumber();
+        }
+        if (count <= batchSize) {
+            LOGGER.finest(() -> "Updating single batch of size " + count);
+            updateWorldsRetry(worlds, 0, 0);
+        } else {
+            int batches = count / batchSize + (count % batchSize == 0 ? 0 : 1);
+            for (int i = 0; i < batches; i++) {
+                final int from = i * batchSize;
+                LOGGER.finest(() -> "Updating batch from " + from + " to " + (from + batchSize));
+                updateWorldsRetry(worlds, from, 0);
+            }
+        }
+        return worlds;
+    }
+
+    private List<World> updateWorldsRetry(List<World> worlds, int from, int retries) {
+        if (retries > maxRetries) {
+            throw new RuntimeException("Too many transaction retries");
+        }
+        CompletableFuture<List<World>> cf = null;
+        try {
+            cf = updateWorlds(worlds, from, updatePool);
+            cf.get(updateTimeout, TimeUnit.MILLISECONDS);
+            return worlds;
+        } catch (ExecutionException | TimeoutException e) {
+            cf.cancel(true);
+            retries++;
+            final int finalRetries = retries;
+            LOGGER.fine(() -> "Retrying batch update after cancellation (retries=" + finalRetries + ")");
+            return updateWorldsRetry(worlds, from, retries);     // retry
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public List<Fortune> getFortunes() {
+        return Single.create(queryPool.preparedQuery("SELECT id, message FROM fortune")
+                .execute()
+                .map(rows -> {
+                    List<Fortune> 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<World> 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());
+
+    }
+
+    private CompletableFuture<List<World>> updateWorlds(List<World> worlds, int from, SqlClient pool) {
+        List<Tuple> tuples = new ArrayList<>();
+        int to = Math.min(from + batchSize, worlds.size());
+        for (int i = from; i < to; i++) {
+            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)
+                .toCompletionStage()
+                .thenApply(rows -> worlds)
+                .toCompletableFuture();
+    }
+}

+ 6 - 4
frameworks/Java/helidon/src/main/java/io/helidon/benchmark/models/World.java → frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/World.java

@@ -1,10 +1,12 @@
-package io.helidon.benchmark.models;
 
-import javax.json.Json;
-import javax.json.JsonBuilderFactory;
-import javax.json.JsonObject;
+package io.helidon.benchmark.nima.models;
+
 import java.util.Collections;
 
+import jakarta.json.Json;
+import jakarta.json.JsonBuilderFactory;
+import jakarta.json.JsonObject;
+
 public final class World {
 
     private static final String ID_KEY = "id";

+ 76 - 0
frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/services/DbService.java

@@ -0,0 +1,76 @@
+
+package io.helidon.benchmark.nima.services;
+
+import java.util.Collections;
+import java.util.List;
+
+import io.helidon.benchmark.nima.models.DbRepository;
+import io.helidon.benchmark.nima.models.World;
+import io.helidon.common.parameters.Parameters;
+import io.helidon.nima.webserver.http.HttpRules;
+import io.helidon.nima.webserver.http.HttpService;
+import io.helidon.nima.webserver.http.ServerRequest;
+import io.helidon.nima.webserver.http.ServerResponse;
+
+import jakarta.json.Json;
+import jakarta.json.JsonArrayBuilder;
+import jakarta.json.JsonBuilderFactory;
+import jakarta.json.JsonObject;
+
+import static io.helidon.benchmark.nima.Main.SERVER;
+import static io.helidon.benchmark.nima.models.DbRepository.randomWorldNumber;
+
+public class DbService implements HttpService {
+    private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap());
+
+    private final DbRepository repository;
+
+    public DbService(DbRepository repository) {
+        this.repository = repository;
+    }
+
+    @Override
+    public void routing(HttpRules httpRules) {
+        httpRules.get("/db", this::db);
+        httpRules.get("/queries", this::queries);
+        httpRules.get("/updates", this::updates);
+    }
+
+    private void db(ServerRequest req, ServerResponse res) {
+        res.header(SERVER);
+        res.send(repository.getWorldAsJson(randomWorldNumber()));
+    }
+
+    private void queries(ServerRequest req, ServerResponse res) {
+        res.header(SERVER);
+        int count = parseQueryCount(req.query());
+        res.send(repository.getWorldsAsJson(count));
+    }
+
+    private void updates(ServerRequest req, ServerResponse res) {
+        res.header(SERVER);
+        int count = parseQueryCount(req.query());
+        List<World> worlds = repository.updateWorlds(count);
+        JsonArrayBuilder arrayBuilder = JSON.createArrayBuilder();
+        for (World world : worlds) {
+            JsonObject json = world.toJson();
+            arrayBuilder.add(json);
+        }
+        res.send(arrayBuilder.build());
+    }
+
+    private int parseQueryCount(Parameters parameters) {
+        List<String> values = parameters.all("queries");
+        if (values.isEmpty()) {
+            return 1;
+        }
+        String first = values.get(0);
+        int parsedValue;
+        try {
+            parsedValue = Integer.parseInt(first, 10);
+        } catch (NumberFormatException e) {
+            return 1;
+        }
+        return Math.min(500, Math.max(1, parsedValue));
+    }
+}

+ 40 - 0
frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/services/FortuneHandler.java

@@ -0,0 +1,40 @@
+
+package io.helidon.benchmark.nima.services;
+
+import java.util.Comparator;
+import java.util.List;
+
+import com.fizzed.rocker.runtime.ArrayOfByteArraysOutput;
+import io.helidon.benchmark.nima.models.DbRepository;
+import io.helidon.benchmark.nima.models.Fortune;
+import io.helidon.nima.webserver.http.Handler;
+import io.helidon.nima.webserver.http.ServerRequest;
+import io.helidon.nima.webserver.http.ServerResponse;
+import views.fortunes;
+
+import static io.helidon.benchmark.nima.Main.CONTENT_TYPE_HTML;
+import static io.helidon.benchmark.nima.Main.SERVER;
+
+public class FortuneHandler implements Handler {
+
+    private static final Fortune ADDITIONAL_FORTUNE =
+            new Fortune(0, "Additional fortune added at request time.");
+
+    private final DbRepository repository;
+
+    public FortuneHandler(DbRepository repository) {
+        this.repository = repository;
+    }
+
+    @Override
+    public void handle(ServerRequest req, ServerResponse res) {
+        res.header(SERVER);
+        res.header(CONTENT_TYPE_HTML);
+        List<Fortune> fortuneList = repository.getFortunes();
+        fortuneList.add(ADDITIONAL_FORTUNE);
+        fortuneList.sort(Comparator.comparing(Fortune::getMessage));
+        res.send(fortunes.template(fortuneList)
+                .render(ArrayOfByteArraysOutput.FACTORY)
+                .toByteArray());
+    }
+}

+ 49 - 0
frameworks/Java/helidon/nima/src/main/resources/application.yaml

@@ -0,0 +1,49 @@
+#
+# Copyright (c) 2022 Oracle and/or its affiliates.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+server:
+  sockets:
+    - name: "@default"
+      host: 0.0.0.0
+      port: 8080
+      backlog: 8192
+      receive-buffer-size: 64000
+      # set write-queue-length to 0 to disable async writes
+      write-queue-length: 1024
+      connection-options:
+        read-timeout-seconds: 0
+        connect-timeout-seconds: 0
+        send-buffer-size: 64000
+        receive-buffer-size: 64000
+  connection-providers:
+    "http_1_1":
+      validate-headers: false
+      validate-path: false
+      recv-log: false
+      send-log: false
+
+host: "tfb-database"
+#host: "localhost"
+db: "hello_world"
+username: benchmarkdbuser
+password: benchmarkdbpass
+sql-pool-size: 256
+db-repository: "pgclient"     # "pgclient" (default) or "hikari"
+
+# The following for pgclient only
+update-batch-size: 10
+update-timeout-millis: 10000
+update-max-retries: 3

+ 7 - 0
frameworks/Java/helidon/nima/src/main/resources/config-profile.yaml

@@ -0,0 +1,7 @@
+sources:
+  # disabled env vars and sys props to reduce configuration keys
+  # - type: "environment-variables"
+  # - type: "system-properties"
+  - type: "classpath"
+    properties:
+      resource: "application.yaml"

+ 19 - 0
frameworks/Java/helidon/nima/src/main/resources/logging.properties

@@ -0,0 +1,19 @@
+#
+# Copyright (c) 2022 Oracle and/or its affiliates.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+handlers=java.util.logging.ConsoleHandler
+java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS.%1$tL %5$s%6$s%n
+# Global logging level. Can be overridden by specific loggers
+.level=INFO

+ 1 - 1
frameworks/Java/helidon/src/main/resources/views/fortunes.rocker.html → frameworks/Java/helidon/nima/src/main/resources/views/fortunes.rocker.html

@@ -1,4 +1,4 @@
-@import io.helidon.benchmark.models.Fortune
+@import io.helidon.benchmark.nima.models.Fortune
 @import java.util.List
 @args (List<Fortune> fortunes)
 

+ 6 - 82
frameworks/Java/helidon/pom.xml

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
-    Copyright (c) 2021 Oracle and/or its affiliates.
+    Copyright (c) 2022 Oracle and/or its affiliates.
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
@@ -18,90 +18,14 @@
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
-    <parent>
-        <groupId>io.helidon.applications</groupId>
-        <artifactId>helidon-se</artifactId>
-        <version>2.4.0</version>
-        <relativePath/>
-    </parent>
     <groupId>io.helidon</groupId>
     <artifactId>benchmark</artifactId>
     <version>1.0-SNAPSHOT</version>
-    <packaging>jar</packaging>
+    <packaging>pom</packaging>
     <name>${project.artifactId}</name>
 
-    <properties>
-        <mainClass>io.helidon.benchmark.Main</mainClass>
-        <rocker.version>1.3.0</rocker.version>
-        <vertx-pg-client.version>4.2.0</vertx-pg-client.version>
-    </properties>
-
-    <dependencyManagement>
-        <dependencies>
-            <dependency>
-                <groupId>io.vertx</groupId>
-                <artifactId>vertx-pg-client</artifactId>
-                <version>${vertx-pg-client.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>com.fizzed</groupId>
-                <artifactId>rocker-runtime</artifactId>
-                <version>${rocker.version}</version>
-            </dependency>
-        </dependencies>
-    </dependencyManagement>
-
-    <dependencies>
-        <dependency>
-            <groupId>io.helidon.webserver</groupId>
-            <artifactId>helidon-webserver</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>io.helidon.media</groupId>
-            <artifactId>helidon-media-jsonp</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>io.helidon.config</groupId>
-            <artifactId>helidon-config-yaml</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>io.vertx</groupId>
-            <artifactId>vertx-pg-client</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>com.fizzed</groupId>
-            <artifactId>rocker-runtime</artifactId>
-        </dependency>
-    </dependencies>
-
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-dependency-plugin</artifactId>
-                <executions>
-                    <execution>
-                        <id>copy-libs</id>
-                    </execution>
-                </executions>
-            </plugin>
-            <plugin>
-                <groupId>com.fizzed</groupId>
-                <artifactId>rocker-maven-plugin</artifactId>
-                <version>${rocker.version}</version>
-                <executions>
-                    <execution>
-                        <id>generate-rocker-templates</id>
-                        <phase>generate-sources</phase>
-                        <goals>
-                            <goal>generate</goal>
-                        </goals>
-                        <configuration>
-                            <templateDirectory>src/main/resources</templateDirectory>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
-        </plugins>
-    </build>
+    <modules>
+        <module>reactive</module>
+        <module>nima</module>
+    </modules>
 </project>

+ 111 - 0
frameworks/Java/helidon/reactive/pom.xml

@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    Copyright (c) 2021 Oracle and/or its affiliates.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>io.helidon.applications</groupId>
+        <artifactId>helidon-se</artifactId>
+        <version>3.0.1</version>
+        <relativePath/>
+    </parent>
+    <groupId>io.helidon</groupId>
+    <artifactId>benchmark-reactive</artifactId>
+    <version>1.0-SNAPSHOT</version>
+    <packaging>jar</packaging>
+    <name>${project.artifactId}</name>
+
+    <properties>
+        <mainClass>io.helidon.benchmark.reactive.Main</mainClass>
+        <version.java>19</version.java>
+        <version.plugin.compiler>3.8.1</version.plugin.compiler>
+        <rocker.version>1.3.0</rocker.version>
+        <vertx-pg-client.version>4.2.0</vertx-pg-client.version>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>io.helidon.webserver</groupId>
+            <artifactId>helidon-webserver</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.helidon.media</groupId>
+            <artifactId>helidon-media-jsonp</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.helidon.config</groupId>
+            <artifactId>helidon-config-yaml</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.vertx</groupId>
+            <artifactId>vertx-pg-client</artifactId>
+            <version>${vertx-pg-client.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.fizzed</groupId>
+            <artifactId>rocker-runtime</artifactId>
+            <version>${rocker.version}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>${version.plugin.compiler}</version>
+                <configuration>
+                    <source>${version.java}</source>
+                    <target>${version.java}</target>
+                    <release>${version.java}</release>
+                    <forceJavacCompilerUse>true</forceJavacCompilerUse>
+                    <compilerArgs>
+                        <arg>-Xlint:unchecked</arg>
+                        <arg>-Xpkginfo:always</arg>
+                    </compilerArgs>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>copy-libs</id>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>com.fizzed</groupId>
+                <artifactId>rocker-maven-plugin</artifactId>
+                <version>${rocker.version}</version>
+                <executions>
+                    <execution>
+                        <id>generate-rocker-templates</id>
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>generate</goal>
+                        </goals>
+                        <configuration>
+                            <templateDirectory>src/main/resources</templateDirectory>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 8 - 7
frameworks/Java/helidon/src/main/java/io/helidon/benchmark/Main.java → frameworks/Java/helidon/reactive/src/main/java/io/helidon/benchmark/reactive/Main.java

@@ -1,3 +1,4 @@
+
 /*
  * Copyright (c) 2018, 2021 Oracle and/or its affiliates.
  *
@@ -14,17 +15,17 @@
  * limitations under the License.
  */
 
-package io.helidon.benchmark;
+package io.helidon.benchmark.reactive;
 
 import java.io.IOException;
 import java.util.logging.LogManager;
 
-import io.helidon.benchmark.models.DbRepository;
-import io.helidon.benchmark.models.JdbcRepository;
-import io.helidon.benchmark.services.DbService;
-import io.helidon.benchmark.services.FortuneService;
-import io.helidon.benchmark.services.JsonService;
-import io.helidon.benchmark.services.PlainTextService;
+import io.helidon.benchmark.reactive.models.DbRepository;
+import io.helidon.benchmark.reactive.models.JdbcRepository;
+import io.helidon.benchmark.reactive.services.DbService;
+import io.helidon.benchmark.reactive.services.FortuneService;
+import io.helidon.benchmark.reactive.services.JsonService;
+import io.helidon.benchmark.reactive.services.PlainTextService;
 import io.helidon.config.Config;
 import io.helidon.media.jsonp.JsonpSupport;
 import io.helidon.webserver.Routing;

+ 1 - 1
frameworks/Java/helidon/src/main/java/io/helidon/benchmark/models/DbRepository.java → frameworks/Java/helidon/reactive/src/main/java/io/helidon/benchmark/reactive/models/DbRepository.java

@@ -1,4 +1,4 @@
-package io.helidon.benchmark.models;
+package io.helidon.benchmark.reactive.models;
 
 import java.util.List;
 

+ 19 - 0
frameworks/Java/helidon/reactive/src/main/java/io/helidon/benchmark/reactive/models/Fortune.java

@@ -0,0 +1,19 @@
+package io.helidon.benchmark.reactive.models;
+
+public final class Fortune {
+    public int id;
+    public String message;
+
+    public Fortune(int id, String message) {
+        this.id = id;
+        this.message = message;
+    }
+
+    public int getId() {
+        return id;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+}

+ 1 - 1
frameworks/Java/helidon/src/main/java/io/helidon/benchmark/models/JdbcRepository.java → frameworks/Java/helidon/reactive/src/main/java/io/helidon/benchmark/reactive/models/JdbcRepository.java

@@ -1,4 +1,4 @@
-package io.helidon.benchmark.models;
+package io.helidon.benchmark.reactive.models;
 
 import java.util.ArrayList;
 import java.util.List;

+ 25 - 0
frameworks/Java/helidon/reactive/src/main/java/io/helidon/benchmark/reactive/models/World.java

@@ -0,0 +1,25 @@
+package io.helidon.benchmark.reactive.models;
+
+import jakarta.json.Json;
+import jakarta.json.JsonBuilderFactory;
+import jakarta.json.JsonObject;
+import java.util.Collections;
+
+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());
+
+    public int id;
+    public int randomNumber;
+
+    public World(int id, int randomNumber) {
+        this.id = id;
+        this.randomNumber = randomNumber;
+    }
+
+    public JsonObject toJson() {
+        return JSON.createObjectBuilder().add(ID_KEY, id).add(ID_RANDOM_NUMBER, randomNumber).build();
+    }
+}

+ 6 - 7
frameworks/Java/helidon/src/main/java/io/helidon/benchmark/services/DbService.java → frameworks/Java/helidon/reactive/src/main/java/io/helidon/benchmark/reactive/services/DbService.java

@@ -1,16 +1,15 @@
-package io.helidon.benchmark.services;
+package io.helidon.benchmark.reactive.services;
 
 import java.util.Collections;
 import java.util.List;
-import java.util.Optional;
 import java.util.concurrent.ThreadLocalRandom;
 
-import javax.json.Json;
-import javax.json.JsonArrayBuilder;
-import javax.json.JsonBuilderFactory;
+import io.helidon.benchmark.reactive.models.DbRepository;
+import io.helidon.benchmark.reactive.models.World;
+import jakarta.json.Json;
+import jakarta.json.JsonArrayBuilder;
+import jakarta.json.JsonBuilderFactory;
 
-import io.helidon.benchmark.models.DbRepository;
-import io.helidon.benchmark.models.World;
 import io.helidon.common.http.Parameters;
 import io.helidon.common.reactive.Multi;
 import io.helidon.webserver.Routing;

+ 4 - 5
frameworks/Java/helidon/src/main/java/io/helidon/benchmark/services/FortuneService.java → frameworks/Java/helidon/reactive/src/main/java/io/helidon/benchmark/reactive/services/FortuneService.java

@@ -1,18 +1,17 @@
-package io.helidon.benchmark.services;
+package io.helidon.benchmark.reactive.services;
 
 import java.nio.charset.StandardCharsets;
 import java.util.Comparator;
 
-import io.helidon.benchmark.models.DbRepository;
-import io.helidon.benchmark.models.Fortune;
+import com.fizzed.rocker.runtime.ArrayOfByteArraysOutput;
+import io.helidon.benchmark.reactive.models.DbRepository;
+import io.helidon.benchmark.reactive.models.Fortune;
 import io.helidon.common.http.MediaType;
 import io.helidon.webserver.Handler;
 import io.helidon.webserver.Routing;
 import io.helidon.webserver.ServerRequest;
 import io.helidon.webserver.ServerResponse;
 import io.helidon.webserver.Service;
-
-import com.fizzed.rocker.runtime.ArrayOfByteArraysOutput;
 import views.fortunes;
 
 public class FortuneService implements Service, Handler {

+ 3 - 3
frameworks/Java/helidon/src/main/java/io/helidon/benchmark/services/JsonService.java → frameworks/Java/helidon/reactive/src/main/java/io/helidon/benchmark/reactive/services/JsonService.java

@@ -1,10 +1,10 @@
-package io.helidon.benchmark.services;
+package io.helidon.benchmark.reactive.services;
 
 import java.util.Collections;
 import java.util.Map;
 
-import javax.json.Json;
-import javax.json.JsonBuilderFactory;
+import jakarta.json.Json;
+import jakarta.json.JsonBuilderFactory;
 
 import io.helidon.webserver.Handler;
 import io.helidon.webserver.Routing;

+ 1 - 1
frameworks/Java/helidon/src/main/java/io/helidon/benchmark/services/PlainTextService.java → frameworks/Java/helidon/reactive/src/main/java/io/helidon/benchmark/reactive/services/PlainTextService.java

@@ -1,4 +1,4 @@
-package io.helidon.benchmark.services;
+package io.helidon.benchmark.reactive.services;
 
 import java.nio.charset.StandardCharsets;
 

+ 0 - 0
frameworks/Java/helidon/src/main/resources/application.yaml → frameworks/Java/helidon/reactive/src/main/resources/application.yaml


+ 0 - 0
frameworks/Java/helidon/src/main/resources/logging.properties → frameworks/Java/helidon/reactive/src/main/resources/logging.properties


+ 24 - 0
frameworks/Java/helidon/reactive/src/main/resources/views/fortunes.rocker.html

@@ -0,0 +1,24 @@
+@import io.helidon.benchmark.reactive.models.Fortune
+@import java.util.List
+@args (List<Fortune> fortunes)
+
+<!DOCTYPE html>
+<html>
+<head>
+<title>Fortunes</title>
+</head>
+<body>
+<table>
+    <tr>
+        <th>id</th>
+        <th>message</th>
+    </tr>
+    @for (f : fortunes) {
+    <tr>
+        <td>@f.getId()</td>
+        <td>@f.getMessage()</td>
+    </tr>
+    }
+</table>
+</body>
+</html>